From 085abc7a6620fcfbe4ef2dd22dcc9c3281413ead Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Sat, 21 Feb 2026 10:39:56 -0500 Subject: [PATCH] Fixes for all trees Signed-off-by: Sasha Levin --- ...r-sun5i-a13-utoo-p66-delete-power-gp.patch | 46 + ...add-clocks-property-to-motor-control.patch | 35 + ...set-motor-pwm-pwm-cells-property-val.patch | 47 + ...ut-__vdso_clock_getres-if-unavailabl.patch | 39 + ...gic-axg-assign-the-mmc-signal-clocks.patch | 52 + ...ic-g12-assign-the-mmc-a-signal-clock.patch | 42 + ...c-g12-assign-the-mmc-b-and-c-signal-.patch | 52 + ...ogic-gx-assign-the-mmc-signal-clocks.patch | 97 + ...-dts-qcom-sdm630-add-qfprom-subnodes.patch | 46 + ...m-sdm630-correct-qfprom-byte-offsets.patch | 53 + ...s-qcom-sdm630-fix-gpu_speed_bin-size.patch | 49 + ...dm845-db845c-specify-power-for-wifi-.patch | 50 + ...-charlcd-fix-release_mem_region-size.patch | 39 + ...-speed-duplex-to-unknown-if-getting-.patch | 74 + ...urn-correct-error-when-deleting-qgro.patch | 43 + ...imit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch | 87 + ...ve-restore-_context-to-common_clk-se.patch | 117 + ...dispcc-sdm845-convert-to-parent-data.patch | 532 ++ ...sdm845-enable-parents-for-pixel-cloc.patch | 49 + ...correct-error-code-in-qcom_cc_probe_.patch | 42 + ...etm3x-fix-cpulocked-warning-on-cpuhp.patch | 67 + ...pufreq-scmi-correct-scmi-explanation.patch | 37 + ...to-cavium-fix-dma_free_coherent-size.patch | 38 + .../crypto-ccp-add-an-s4-restore-flow.patch | 168 + ...-octeontx-fix-dma_free_coherent-size.patch | 38 + ...dma-axi-dmac-fix-sw-cyclic-transfers.patch | 57 + ...ek-uart-apdma-fix-above-4g-addressin.patch | 83 + ...050-use-dev_err_probe-for-regulator-.patch | 42 + ...xplicit-vcn-instance-0-in-sr-iov-ini.patch | 180 + .../edac-altera-remove-irqf_oneshot.patch | 74 + ...nprintf-size-calculation-in-calculat.patch | 40 + ...nprintf-limit-calculation-in-calcula.patch | 49 + ...parent-link-count-underflow-in-rmdir.patch | 74 + ...ix-a-memory-leak-in-au1200fb_drv_pro.patch | 43 + ...fs-add-linux-init_task.h-for-init_fs.patch | 40 + .../gfs2-add-metapath_dibh-helper.patch | 48 + .../gfs2-add-new-gfs2_iomap_get-helper.patch | 249 + ...rapper-for-iomap_file_buffered_write.patch | 82 + ...er-free-in-iomap-inline-data-write-p.patch | 84 + ...ode-glock-locking-to-gfs2_file_buffe.patch | 181 + ...s2_lblk_to_dblk-with-gfs2_get_extent.patch | 87 + ...xtent_map-into-gfs2_-get-alloc-_exte.patch | 194 + ...rror-when-node-already-exists-in-hfs.patch | 58 + queue-5.10/hrtimer-fix-trace-oddity.patch | 43 + ...e-name-assignment-after-i3c_bus_init.patch | 44 + ...ove-i2c-board-info-from-i2c_dev_desc.patch | 104 + ...fix-a-resource-leak-in-sca3000_probe.patch | 42 + ...sion-side-handling-of-completion-sid.patch | 49 + ...-cache-for-pasid-table-before-using-.patch | 55 + ...ate-limit-unknown-xcvr-type-messages.patch | 51 + ...y_working-flag-handling-in-raid10_sy.patch | 47 + ...regulator-resource-leak-on-wm5102_cl.patch | 43 + .../mfd-wm8350-core-use-irqf_oneshot.patch | 48 + ...-sd-express-mode-support-for-rts5261.patch | 162 + ...ial-support-for-sd-express-card-host.patch | 231 + ...mc-increase-power-on-settling-delay-.patch | 40 + ...nce-fix-return-type-of-cdma-send-and.patch | 40 + ...h-due-to-unvalidated-vcc-pointer-in-.patch | 154 + ...ncount-fix-tracking-of-connections-f.patch | 69 + ...ncount-increase-the-connection-clean.patch | 123 + ...ncount-make-nf_conncount_gc_list-to-.patch | 93 + ...t_hash-fix-get-operation-on-big-endi.patch | 57 + ...t_rbtree-check-for-partial-overlaps-.patch | 90 + ...r-defer-requests-during-idmap-lookup.patch | 152 + ...virtio_pmem-serialize-flush-requests.patch | 98 + ...-pf-driver-crash-with-kexec-kernel-b.patch | 62 + ...vl-fix-uninit-value-in-ovl_fill_real.patch | 58 + ...do-not-attempt-to-set-exttag-for-vfs.patch | 49 + ...ialize-rcb-from-pci_configure_device.patch | 90 + ...650sa-root-port-extended-tags-as-bro.patch | 56 + ...-irq-domain-leak-when-msi-allocation.patch | 45 + ...-portdrv-fix-potential-resource-leak.patch | 48 + ...ium-fix-device-node-reference-leak-i.patch | 44 + ...ix-refcount-leak-in-pcs_add_gpio_fun.patch | 50 + ...cros_ec_lightbar-fix-response-size-i.patch | 43 + ...ew-_pm_ops-macros-deprecate-old-ones.patch | 197 + .../pm-core-redefine-pm_ptr-macro.patch | 61 + ...-harden-dev_pm_clear_wake_irq-agains.patch | 65 + ...-empty-list-in-wakeup_sources_walk_s.patch | 44 + ...ng-wake-up-while-waiting-on-nfs_layo.patch | 61 + ...m-reboot-mode-respect-cell-size-for-.patch | 64 + ...8945a-fix-use-after-free-in-power_su.patch | 77 + ...5980-fix-use-after-free-in-power_sup.patch | 73 + ...7xxx-fix-wrong-errno-when-bus-ops-ar.patch | 61 + ...ap-battery-fix-use-after-free-in-pow.patch | 70 + ...dfish-fix-use-after-free-in-power_su.patch | 73 + ...455-fix-use-after-free-in-power_supp.patch | 78 + ...-battery-fix-use-after-free-in-power.patch | 101 + ...7xx-fix-null-pointer-dereference-in-.patch | 98 + ...7xx_battery-convert-to-gpio-descript.patch | 186 + ...recursive-pci_lock_rescan_remove-loc.patch | 275 + ...ng-rcu-protection-when-reading-real_.patch | 59 + ...uffer-overflow-in-persistent_ram_sav.patch | 92 + ...rdma_rw_max_sge-helper-for-sq-sizing.patch | 159 + ...-couple-of-obvious-typos-in-comments.patch | 50 + .../rdma-rtrs-server-remove-dead-code.patch | 57 + ...fix-double-free-in-rxe_srq_from_init.patch | 57 + ...__gfp_nowarn-to-ib_uverbs_unmarshall.patch | 39 + ...date-wqe_size-before-using-it-in-ib_.patch | 57 + ...ix-off-on-delay-us-for-always-on-boo.patch | 57 + ...lator-core-fix-off_on_delay-handling.patch | 117 + ...ove-supply-check-earlier-in-set_mach.patch | 121 + ...core-respect-off_on_delay-at-startup.patch | 46 + ...horten-off-on-delay-us-for-always-on.patch | 115 + ...se-ktime_get_boottime-to-determine-h.patch | 66 + ...ncontrollable-regulators-as-always_o.patch | 58 + ...pex-fix-use-after-free-in-high-low-s.patch | 89 + ...pci_sdmmc-increase-power-on-settling.patch | 39 + ...ice-lifecycle-handling-in-css_alloc_.patch | 49 + ...rrently-executing-cpu-in-rto_next_cp.patch | 87 + ...r-fix-dereference-of-null-pointer-rn.patch | 46 + ...use-after-free-in-caif_serial-ldisc_.patch | 152 + ...mx-change-serial_imx_console-to-bool.patch | 50 + ...al-sh_sci-improve-dma-support-prompt.patch | 39 + queue-5.10/series | 134 + ...ck-doi-accept-previously-used-values.patch | 233 + queue-5.10/smack-smack-doi-must-be-0.patch | 71 + ...use-devm_memremap-to-fix-memory-leak.patch | 53 + ...ols-add-include-folder-to-.gitignore.patch | 35 + ...ging-greybus-lights-avoid-null-deref.patch | 55 + ...dd-a-batch-receive-posting-mechanism.patch | 98 + ...-clean-up-comment-in-svc_rdma_accept.patch | 64 + ...rease-the-per-transport-rw_ctx-count.patch | 73 + ...vcrdma-maintain-a-receive-water-mark.patch | 100 + ...he-number-of-rdma_rw-contexts-per-qp.patch | 96 + ...dma-remove-queue-shortening-warnings.patch | 52 + ...svc_rdma_refresh_recvs-in-wc_receive.patch | 94 + ...timestamp-must-look-at-the-rtx-queue.patch | 44 + ...-missing-cleanup-on-get_burstcount-e.patch | 43 + ...neon-fix-locality-leak-on-get_burstc.patch | 44 + ...uplicate-enable_event_str-and-disabl.patch | 44 + ...-cap_sys_resource-using-ns_capable_n.patch | 51 + .../usb-bdc-fix-sleep-during-atomic.patch | 41 + ...-add-missing-lock-protection-in-ath1.patch | 62 + ...1-stop-nan-and-p2p-in-cfg80211_leave.patch | 47 + ...r-sun5i-a13-utoo-p66-delete-power-gp.patch | 46 + ...add-clocks-property-to-motor-control.patch | 35 + ...set-motor-pwm-pwm-cells-property-val.patch | 47 + ...ut-__vdso_clock_getres-if-unavailabl.patch | 39 + ...gic-axg-assign-the-mmc-signal-clocks.patch | 52 + ...ic-g12-assign-the-mmc-a-signal-clock.patch | 42 + ...c-g12-assign-the-mmc-b-and-c-signal-.patch | 52 + ...ogic-gx-assign-the-mmc-signal-clocks.patch | 97 + ...m-sdm630-correct-qfprom-byte-offsets.patch | 53 + ...s-qcom-sdm630-fix-gpu_speed_bin-size.patch | 49 + ...dm845-db845c-specify-power-for-wifi-.patch | 50 + ...dm845-oneplus-don-t-keep-panel-regul.patch | 39 + ...dm845-oneplus-don-t-mark-ts-supply-b.patch | 39 + ...dm845-oneplus-mark-l14a-regulator-as.patch | 38 + ...-charlcd-fix-release_mem_region-size.patch | 39 + ...-wled-support-ovp-values-for-pmi8994.patch | 94 + ...-speed-duplex-to-unknown-if-getting-.patch | 74 + ...urn-correct-error-when-deleting-qgro.patch | 43 + ...imit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch | 87 + ...ve-restore-_context-to-common_clk-se.patch | 117 + ...sdm845-enable-parents-for-pixel-cloc.patch | 49 + ...8953-remove-always_on-flag-from-cpp_.patch | 39 + ...mpute-2d-using-duty-fraction-directl.patch | 71 + ...correct-error-code-in-qcom_cc_probe_.patch | 42 + ...etm3x-fix-cpulocked-warning-on-cpuhp.patch | 67 + ...pufreq-scmi-correct-scmi-explanation.patch | 37 + ...to-cavium-fix-dma_free_coherent-size.patch | 38 + .../crypto-ccp-add-an-s4-restore-flow.patch | 168 + ...-trng-modifying-the-order-of-header-.patch | 56 + ...-trng-support-tfms-sharing-the-devic.patch | 258 + ...-octeontx-fix-dma_free_coherent-size.patch | 38 + ...dma-axi-dmac-fix-sw-cyclic-transfers.patch | 57 + ...ek-uart-apdma-fix-above-4g-addressin.patch | 83 + ...050-use-dev_err_probe-for-regulator-.patch | 42 + ...xplicit-vcn-instance-0-in-sr-iov-ini.patch | 180 + .../edac-altera-remove-irqf_oneshot.patch | 74 + ...nprintf-size-calculation-in-calculat.patch | 40 + ...nprintf-limit-calculation-in-calcula.patch | 49 + ...ort-to-set-get-tx-copybreak-buf-size.patch | 61 + ...parent-link-count-underflow-in-rmdir.patch | 74 + ...ix-a-memory-leak-in-au1200fb_drv_pro.patch | 43 + ...fs-add-linux-init_task.h-for-init_fs.patch | 40 + .../gfs2-add-metapath_dibh-helper.patch | 48 + ...er-free-in-iomap-inline-data-write-p.patch | 84 + ...rror-when-node-already-exists-in-hfs.patch | 58 + ...add-missing-check-for-input_ff_creat.patch | 41 + queue-5.15/hrtimer-fix-trace-oddity.patch | 43 + ...e-name-assignment-after-i3c_bus_init.patch | 44 + ...ove-i2c-board-info-from-i2c_dev_desc.patch | 104 + ...gid-cache-on-client-reregister-event.patch | 54 + ...fix-a-resource-leak-in-sca3000_probe.patch | 42 + ...sion-side-handling-of-completion-sid.patch | 49 + ...-cache-for-pasid-table-before-using-.patch | 55 + ...ate-limit-unknown-xcvr-type-messages.patch | 51 + ...bpf-fix-dumping-big-endian-bitfields.patch | 66 + ...-read-in-btf_dump_get_bitfield_value.patch | 59 + ...y_working-flag-handling-in-raid10_sy.patch | 47 + ...commodate-c-phy-into-the-calculation.patch | 53 + ...fix-allocation-for-small-frame-sizes.patch | 57 + ...regulator-resource-leak-on-wm5102_cl.patch | 43 + .../mfd-wm8350-core-use-irqf_oneshot.patch | 48 + ...mc-increase-power-on-settling-delay-.patch | 40 + ...rt-fix-of-node-refcount-leak-in-pars.patch | 84 + ...nce-fix-return-type-of-cdma-send-and.patch | 40 + ...h-due-to-unvalidated-vcc-pointer-in-.patch | 154 + ...-order-judgement-for-tx-spare-buffer.patch | 44 + ...port-to-set-get-tx-copybreak-buf-siz.patch | 154 + ...ouble-free-issue-for-tx-spare-buffer.patch | 74 + ...tool-tx-copybreak-buf-size-indicatin.patch | 111 + ...the-way-to-set-tx-spare-buf-via-modu.patch | 51 + ...ncount-fix-tracking-of-connections-f.patch | 69 + ...ncount-increase-the-connection-clean.patch | 123 + ...ncount-make-nf_conncount_gc_list-to-.patch | 93 + ...t_hash-fix-get-operation-on-big-endi.patch | 57 + ...t_rbtree-check-for-partial-overlaps-.patch | 90 + ...op-timers-and-work-before-freeing-co.patch | 52 + ...r-defer-requests-during-idmap-lookup.patch | 152 + ...virtio_pmem-serialize-flush-requests.patch | 98 + ...-pf-driver-crash-with-kexec-kernel-b.patch | 62 + ...-unregister-devlink-on-probe-failure.patch | 36 + ...vl-fix-uninit-value-in-ovl_fill_real.patch | 58 + ...do-not-attempt-to-set-exttag-for-vfs.patch | 49 + ...ialize-rcb-from-pci_configure_device.patch | 90 + ...650sa-root-port-extended-tags-as-bro.patch | 56 + ...-irq-domain-leak-when-msi-allocation.patch | 45 + ...-portdrv-fix-potential-resource-leak.patch | 48 + ...ium-fix-device-node-reference-leak-i.patch | 44 + ...extract-chip-specific-lpass-lpi-code.patch | 606 ++ ...250-lpass-lpi-fix-i2s2_data_groups-d.patch | 38 + ...ate-lpi-pin-group-custiom-functions-.patch | 205 + ...om-update-macro-name-to-lpi-specific.patch | 70 + ...ix-refcount-leak-in-pcs_add_gpio_fun.patch | 50 + ...cros_ec_lightbar-fix-response-size-i.patch | 43 + ...-harden-dev_pm_clear_wake_irq-agains.patch | 65 + ...-empty-list-in-wakeup_sources_walk_s.patch | 44 + ...ng-wake-up-while-waiting-on-nfs_layo.patch | 61 + ...m-reboot-mode-respect-cell-size-for-.patch | 64 + ...500-fix-use-after-free-in-power_supp.patch | 104 + ...upply-ab8500-use-core-battery-parser.patch | 147 + ...y-ab8500_bmdata-use-standard-phandle.patch | 39 + ...8945a-fix-use-after-free-in-power_su.patch | 77 + ...56xx-fix-use-after-free-in-power_sup.patch | 73 + ...5980-fix-use-after-free-in-power_sup.patch | 73 + ...7xxx-fix-wrong-errno-when-bus-ops-ar.patch | 61 + ...ap-battery-fix-use-after-free-in-pow.patch | 70 + ...dfish-fix-use-after-free-in-power_su.patch | 73 + ...455-fix-use-after-free-in-power_supp.patch | 78 + ...-battery-fix-use-after-free-in-power.patch | 101 + ...7xx-fix-null-pointer-dereference-in-.patch | 98 + ...recursive-pci_lock_rescan_remove-loc.patch | 275 + ...move-barrier_nospec-out-of-allow_rea.patch | 98 + ...ng-rcu-protection-when-reading-real_.patch | 59 + ...uffer-overflow-in-persistent_ram_sav.patch | 92 + ...rdma_rw_max_sge-helper-for-sq-sizing.patch | 159 + ...-couple-of-obvious-typos-in-comments.patch | 50 + ...ulp-of-remaining-soft-wcs-during-res.patch | 70 + .../rdma-rtrs-server-remove-dead-code.patch | 57 + ...correct-the-checking-of-ib_map_mr_sg.patch | 38 + queue-5.15/rdma-rtrs-srv-fix-sg-mapping.patch | 85 + ...factor-the-handling-of-failure-case-.patch | 108 + ...fix-double-free-in-rxe_srq_from_init.patch | 57 + ...__gfp_nowarn-to-ib_uverbs_unmarshall.patch | 39 + ...date-wqe_size-before-using-it-in-ib_.patch | 57 + ...ove-supply-check-earlier-in-set_mach.patch | 121 + ...pci_sdmmc-increase-power-on-settling.patch | 39 + ...ice-lifecycle-handling-in-css_alloc_.patch | 49 + ...rrently-executing-cpu-in-rto_next_cp.patch | 87 + ...r-fix-dereference-of-null-pointer-rn.patch | 46 + ...qf_oneshot-and-default-primary-handl.patch | 59 + ...use-after-free-in-caif_serial-ldisc_.patch | 152 + ...mx-change-serial_imx_console-to-bool.patch | 50 + ...al-sh_sci-improve-dma-support-prompt.patch | 39 + queue-5.15/series | 150 + ...ck-doi-accept-previously-used-values.patch | 233 + queue-5.15/smack-smack-doi-must-be-0.patch | 71 + ...use-devm_memremap-to-fix-memory-leak.patch | 53 + ...ols-add-include-folder-to-.gitignore.patch | 35 + ...ging-greybus-lights-avoid-null-deref.patch | 55 + ...-clean-up-comment-in-svc_rdma_accept.patch | 64 + ...rease-the-per-transport-rw_ctx-count.patch | 73 + ...he-number-of-rdma_rw-contexts-per-qp.patch | 96 + ...dma-remove-queue-shortening-warnings.patch | 52 + ...timestamp-must-look-at-the-rtx-queue.patch | 44 + ...imers-replace-in_irq-with-in_hardirq.patch | 38 + ...-missing-cleanup-on-get_burstcount-e.patch | 43 + ...neon-fix-locality-leak-on-get_burstc.patch | 44 + ...uplicate-enable_event_str-and-disabl.patch | 44 + ...-cap_sys_resource-using-ns_capable_n.patch | 51 + .../usb-bdc-fix-sleep-during-atomic.patch | 41 + ...-add-missing-lock-protection-in-ath1.patch | 62 + ...1-stop-nan-and-p2p-in-cfg80211_leave.patch | 47 + ...pointer-dereference-in-acpi_ev_addre.patch | 40 + ...r-sun5i-a13-utoo-p66-delete-power-gp.patch | 46 + ...add-clocks-property-to-motor-control.patch | 35 + ...set-motor-pwm-pwm-cells-property-val.patch | 47 + ...ut-__vdso_clock_getres-if-unavailabl.patch | 39 + ...gic-axg-assign-the-mmc-signal-clocks.patch | 52 + ...ic-g12-assign-the-mmc-a-signal-clock.patch | 42 + ...c-g12-assign-the-mmc-b-and-c-signal-.patch | 52 + ...ogic-gx-assign-the-mmc-signal-clocks.patch | 97 + ...s-qcom-sdm630-fix-gpu_speed_bin-size.patch | 49 + ...com-sdm845-db845c-drop-cs-from-spio0.patch | 40 + ...dm845-db845c-specify-power-for-wifi-.patch | 50 + ...dm845-oneplus-don-t-keep-panel-regul.patch | 39 + ...dm845-oneplus-don-t-mark-ts-supply-b.patch | 39 + ...dm845-oneplus-mark-l14a-regulator-as.patch | 38 + ...pql-mba8mpxl-fix-hdmi-cec-pad-contro.patch | 36 + ...id-unnecessary-blocking-in-irq-handl.patch | 121 + ...sistently-clear-interrupts-before-un.patch | 169 + ...821-fixup-nau8821_enable_jack_detect.patch | 84 + ...dit-avoid-missing-prototype-warnings.patch | 74 + ...ompat_xxx_class-extern-declarations-.patch | 77 + ...-charlcd-fix-release_mem_region-size.patch | 39 + ...-wled-support-ovp-values-for-pmi8994.patch | 94 + ...-speed-duplex-to-unknown-if-getting-.patch | 74 + ..._store_bytes-proto-for-read-only-arg.patch | 60 + ...fix-incorrect-copied_seq-calculation.patch | 178 + ...ock_group_tree-dirty_list-corruption.patch | 150 + ...urn-correct-error-when-deleting-qgro.patch | 43 + ...x-error-handling-in-runtime-pm-setup.patch | 66 + ...imit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch | 87 + ...ve-restore-_context-to-common_clk-se.patch | 117 + ...sdm845-enable-parents-for-pixel-cloc.patch | 49 + ...8953-remove-always_on-flag-from-cpp_.patch | 39 + ...x3d-add-parent-to-parent-request-map.patch | 67 + ...mpute-2d-using-duty-fraction-directl.patch | 71 + ...correct-error-code-in-qcom_cc_probe_.patch | 42 + ...etm3x-fix-cpulocked-warning-on-cpuhp.patch | 67 + ...pufreq-scmi-correct-scmi-explanation.patch | 37 + ...to-cavium-fix-dma_free_coherent-size.patch | 38 + .../crypto-ccp-add-an-s4-restore-flow.patch | 168 + ...-sec-fix-spelling-mistake-ckeck-chec.patch | 44 + ...isilicon-sec2-fix-for-sec-spec-check.patch | 278 + ...-sec2-support-skcipher-aead-fallback.patch | 220 + ...-trng-modifying-the-order-of-header-.patch | 56 + ...-trng-support-tfms-sharing-the-devic.patch | 258 + ...-zip-adjust-the-way-to-obtain-the-re.patch | 128 + ...o-hisilicon-zip-remove-zlib-and-gzip.patch | 489 ++ ...ilicon-zip-support-deflate-algorithm.patch | 192 + ...-octeontx-fix-dma_free_coherent-size.patch | 38 + ...t-fix-warning-on-adf_pfvf_pf_proto.c.patch | 63 + ...e-commit_end-increment-on-decoder-co.patch | 63 + .../dm-use-bio_clone_blkg_association.patch | 44 + ...dma-axi-dmac-fix-sw-cyclic-transfers.patch | 57 + ...ek-uart-apdma-fix-above-4g-addressin.patch | 83 + ...i-endpoint-fix-ntb-vntb-copy-paste-e.patch | 82 + ...050-use-dev_err_probe-for-regulator-.patch | 42 + ...xplicit-vcn-instance-0-in-sr-iov-ini.patch | 179 + ...sm-dpu-fix-cmd-panels-on-dpu-1.x-3.x.patch | 48 + .../edac-altera-remove-irqf_oneshot.patch | 74 + ...nprintf-size-calculation-in-calculat.patch | 40 + ...nprintf-limit-calculation-in-calcula.patch | 49 + ...parent-link-count-underflow-in-rmdir.patch | 74 + ...ix-a-memory-leak-in-au1200fb_drv_pro.patch | 43 + ..._timing-fix-device-node-reference-le.patch | 56 + ...fs-add-linux-init_task.h-for-init_fs.patch | 40 + ...fs-fix-readdir-slow-start-regression.patch | 54 + queue-6.1/gfs2-add-metapath_dibh-helper.patch | 48 + ...er-free-in-iomap-inline-data-write-p.patch | 84 + ...rror-when-node-already-exists-in-hfs.patch | 58 + ...add-missing-check-for-input_ff_creat.patch | 41 + queue-6.1/hrtimer-fix-trace-oddity.patch | 43 + ...update-hot-join-flag-only-on-success.patch | 39 + ...e-name-assignment-after-i3c_bus_init.patch | 46 + ...gid-cache-on-client-reregister-event.patch | 54 + ...fix-a-resource-leak-in-sca3000_probe.patch | 42 + ...el-abstract-out-request-match-helper.patch | 72 + ...cel-add-ioring_async_cancel_userdata.patch | 84 + ...de-unionize-file-and-user_data-in-st.patch | 45 + ...fix-sequence-matching-for-ioring_asy.patch | 47 + ...support-opcode-based-lookup-and-canc.patch | 143 + ...uring-sync-validate-passed-in-offset.patch | 36 + ...sion-side-handling-of-completion-sid.patch | 49 + ...-cache-for-pasid-table-before-using-.patch | 55 + ...ate-limit-unknown-xcvr-type-messages.patch | 51 + ...-capability-check-in-ipc_permissions.patch | 66 + ...set-module-buildid-in-ftrace_mod_add.patch | 100 + ...eck-the-return-value-of-regmap_bulk_.patch | 55 + ...-read-in-btf_dump_get_bitfield_value.patch | 59 + ...-initialise-event-handler-read-bytes.patch | 43 + ...y_working-flag-handling-in-raid10_sy.patch | 47 + ...commodate-c-phy-into-the-calculation.patch | 53 + ...fix-allocation-for-small-frame-sizes.patch | 57 + ...regulator-resource-leak-on-wm5102_cl.patch | 43 + .../mfd-wm8350-core-use-irqf_oneshot.patch | 48 + ...mc-increase-power-on-settling-delay-.patch | 40 + ...r-function-for-reading-module_buildi.patch | 80 + ...rt-fix-of-node-refcount-leak-in-pars.patch | 84 + ...nce-fix-return-type-of-cdma-send-and.patch | 40 + ..._dstref_steal-and-skb_dstref_restore.patch | 73 + ...h-due-to-unvalidated-vcc-pointer-in-.patch | 154 + ...ouble-free-issue-for-tx-spare-buffer.patch | 74 + ...-fix-duplicate-reception-of-old-data.patch | 49 + ...b_dstref_steal-skb_dstref_restore-fo.patch | 75 + ...ncount-fix-tracking-of-connections-f.patch | 69 + ...ncount-increase-the-connection-clean.patch | 123 + ...ncount-make-nf_conncount_gc_list-to-.patch | 93 + ...mpat-add-more-restrictions-on-netlin.patch | 71 + ...unter-fix-reset-of-counters-on-32bit.patch | 75 + ...t_hash-fix-get-operation-on-big-endi.patch | 57 + ...t_rbtree-check-for-partial-overlaps-.patch | 90 + ...op-timers-and-work-before-freeing-co.patch | 52 + ...r-defer-requests-during-idmap-lookup.patch | 152 + ...virtio_pmem-serialize-flush-requests.patch | 98 + ...-pf-driver-crash-with-kexec-kernel-b.patch | 62 + ...-unregister-devlink-on-probe-failure.patch | 36 + ...vl-fix-uninit-value-in-ovl_fill_real.patch | 58 + ...k-for-pericom-pi7c9x2g404-switches-1.patch | 46 + ...do-not-attempt-to-set-exttag-for-vfs.patch | 49 + ...ialize-rcb-from-pci_configure_device.patch | 90 + ...650sa-root-port-extended-tags-as-bro.patch | 56 + ...-irq-domain-leak-when-msi-allocation.patch | 45 + ...oid-redundant-delays-on-d3hot-d3cold.patch | 56 + ...-portdrv-fix-potential-resource-leak.patch | 48 + ...ium-fix-device-node-reference-leak-i.patch | 44 + ...250-lpass-lpi-fix-i2s2_data_groups-d.patch | 38 + ...ix-refcount-leak-in-pcs_add_gpio_fun.patch | 50 + ...cros_ec_lightbar-fix-response-size-i.patch | 43 + ...cros_typec_switch-don-t-touch-struct.patch | 54 + ...-harden-dev_pm_clear_wake_irq-agains.patch | 65 + ...-empty-list-in-wakeup_sources_walk_s.patch | 44 + ...ng-wake-up-while-waiting-on-nfs_layo.patch | 61 + ...m-reboot-mode-respect-cell-size-for-.patch | 64 + ...500-fix-use-after-free-in-power_supp.patch | 104 + ...8945a-fix-use-after-free-in-power_su.patch | 77 + ...56xx-fix-use-after-free-in-power_sup.patch | 73 + ...5980-fix-use-after-free-in-power_sup.patch | 73 + ...7xxx-fix-wrong-errno-when-bus-ops-ar.patch | 61 + ...ap-battery-fix-use-after-free-in-pow.patch | 70 + ...dfish-fix-use-after-free-in-power_su.patch | 73 + ...455-fix-use-after-free-in-power_supp.patch | 78 + ...-battery-fix-use-after-free-in-power.patch | 101 + ...7xx-fix-null-pointer-dereference-in-.patch | 98 + ...recursive-pci_lock_rescan_remove-loc.patch | 275 + ...move-barrier_nospec-out-of-allow_rea.patch | 98 + ...ng-rcu-protection-when-reading-real_.patch | 59 + ...uffer-overflow-in-persistent_ram_sav.patch | 92 + ...rdma_rw_max_sge-helper-for-sq-sizing.patch | 159 + ...-couple-of-obvious-typos-in-comments.patch | 50 + .../rdma-hns-fix-wq_mem_reclaim-warning.patch | 62 + ...ulp-of-remaining-soft-wcs-during-res.patch | 70 + .../rdma-rtrs-server-remove-dead-code.patch | 57 + ...correct-the-checking-of-ib_map_mr_sg.patch | 38 + queue-6.1/rdma-rtrs-srv-fix-sg-mapping.patch | 85 + ...factor-the-handling-of-failure-case-.patch | 108 + ...fix-double-free-in-rxe_srq_from_init.patch | 57 + ...__gfp_nowarn-to-ib_uverbs_unmarshall.patch | 39 + ...date-wqe_size-before-using-it-in-ib_.patch | 57 + ...ove-supply-check-earlier-in-set_mach.patch | 121 + ...pex-fix-use-after-free-in-high-low-s.patch | 89 + ...pci_sdmmc-increase-power-on-settling.patch | 39 + ...ice-lifecycle-handling-in-css_alloc_.patch | 49 + ...rrently-executing-cpu-in-rto_next_cp.patch | 87 + ...r-fix-dereference-of-null-pointer-rn.patch | 46 + ...qf_oneshot-and-default-primary-handl.patch | 59 + ...x-memory-leak-in-pqi_report_phys_lun.patch | 72 + ...place-one-element-arrays-with-flexib.patch | 79 + ...ristat-fix-printing-order-in-output_.patch | 46 + ...use-after-free-in-caif_serial-ldisc_.patch | 152 + ...mx-change-serial_imx_console-to-bool.patch | 50 + ...al-sh_sci-improve-dma-support-prompt.patch | 39 + queue-6.1/series | 199 + ...ck-doi-accept-previously-used-values.patch | 233 + queue-6.1/smack-smack-doi-must-be-0.patch | 71 + ...ct-value-for-smbd_max_fragmented_rec.patch | 78 + ...otential-uaf-and-double-free-in-smb2.patch | 41 + ...k-svs-add-explicit-include-for-cpu.h.patch | 39 + ...-fix-memory-leak-in-svs_enable_debug.patch | 59 + ...use-devm_memremap-to-fix-memory-leak.patch | 53 + ...mem-handle-enomem-error-during-probe.patch | 39 + ...ols-add-include-folder-to-.gitignore.patch | 35 + ...ging-greybus-lights-avoid-null-deref.patch | 55 + ...-clean-up-comment-in-svc_rdma_accept.patch | 64 + ...rease-the-per-transport-rw_ctx-count.patch | 73 + ...he-number-of-rdma_rw-contexts-per-qp.patch | 96 + ...dma-remove-queue-shortening-warnings.patch | 52 + ...timestamp-must-look-at-the-rtx-queue.patch | 44 + ...imers-replace-in_irq-with-in_hardirq.patch | 38 + ...-missing-cleanup-on-get_burstcount-e.patch | 43 + ...neon-fix-locality-leak-on-get_burstc.patch | 44 + ...-process-error-handling-in-event_his.patch | 51 + ...uplicate-enable_event_str-and-disabl.patch | 44 + ...sqe128-flag-before-accessing-the-cmd.patch | 47 + ...-cap_sys_resource-using-ns_capable_n.patch | 51 + .../usb-bdc-fix-sleep-during-atomic.patch | 41 + ...-add-missing-lock-protection-in-ath1.patch | 62 + ...1-stop-nan-and-p2p-in-cfg80211_leave.patch | 47 + ...-use-grant-dma-ops-when-running-as-d.patch | 45 + ...e-pci-devices-which-host-controller-.patch | 126 + ...ize-the-setup-of-xen-grant-dma-devic.patch | 232 + ...ug-race-in-icmp_route_lookup-reverse.patch | 100 + ...pointer-dereference-in-acpi_ev_addre.patch | 40 + ...m-relax-__free-variable-declarations.patch | 268 + ...sa-pcm-use-new-array-copying-wrapper.patch | 44 + ...r-relax-__free-variable-declarations.patch | 77 + ...r-sun5i-a13-utoo-p66-delete-power-gp.patch | 46 + ...add-clocks-property-to-motor-control.patch | 35 + ...set-motor-pwm-pwm-cells-property-val.patch | 47 + ...ut-__vdso_clock_getres-if-unavailabl.patch | 39 + ...gic-axg-assign-the-mmc-signal-clocks.patch | 52 + ...ogic-c3-assign-the-mmc-signal-clocks.patch | 53 + ...ic-g12-assign-the-mmc-a-signal-clock.patch | 42 + ...c-g12-assign-the-mmc-b-and-c-signal-.patch | 52 + ...ogic-gx-assign-the-mmc-signal-clocks.patch | 97 + ...logic-s4-assign-mmc-b-clock-to-24mhz.patch | 51 + ...-amlogic-s4-fix-mmc-clock-assignment.patch | 70 + ...ek-mt8183-jacuzzi-pico6-fix-typo-in-.patch | 36 + ...m-agatti-add-cx_mem-dbgc-gpu-regions.patch | 49 + ...sm8994-octagon-fix-analog-devices-ve.patch | 43 + ...rb4210-rb2-fix-uart3-wakeup-irq-stor.patch | 43 + ...s-qcom-sdm630-fix-gpu_speed_bin-size.patch | 49 + ...com-sdm845-db845c-drop-cs-from-spio0.patch | 40 + ...dm845-db845c-specify-power-for-wifi-.patch | 50 + ...dm845-oneplus-don-t-keep-panel-regul.patch | 39 + ...dm845-oneplus-don-t-mark-ts-supply-b.patch | 39 + ...dm845-oneplus-mark-l14a-regulator-as.patch | 38 + ...m-sm6115-add-cx_mem-dbgc-gpu-regions.patch | 49 + ...m-x1e-bus-is-40-bits-fix-64gb-models.patch | 42 + ...1e80100-fix-usb-combo-phys-ss1-and-s.patch | 61 + ...j784s4-j742s2-main-common.dtsi-refac.patch | 125 + ...j784s4-main.dtsi-move-c71_3-node-to-.patch | 73 + ...pql-mba8mp-ras314-fix-hdmi-cec-pad-c.patch | 37 + ...pql-mba8mpxl-fix-hdmi-cec-pad-contro.patch | 36 + ...id-unnecessary-blocking-in-irq-handl.patch | 121 + ...sistently-clear-interrupts-before-un.patch | 169 + ...821-fixup-nau8821_enable_jack_detect.patch | 84 + ...ompat_xxx_class-extern-declarations-.patch | 77 + ...-charlcd-fix-release_mem_region-size.patch | 39 + ...led-change-pm8950-wled-configuration.patch | 42 + ...-wled-support-ovp-values-for-pmi8994.patch | 94 + ...ock-add-a-bio_add_virt_nofail-helper.patch | 71 + ...l_pcie-use-irqf_oneshot-and-default-.patch | 61 + ...-speed-duplex-to-unknown-if-getting-.patch | 74 + ..._store_bytes-proto-for-read-only-arg.patch | 60 + ...e-id-of-register-in-sync_linked_regs.patch | 95 + ...bpf-sockmap-fix-fionread-for-sockmap.patch | 293 + ...fix-incorrect-copied_seq-calculation.patch | 178 + ...ock_group_tree-dirty_list-corruption.patch | 150 + ...urn-correct-error-when-deleting-qgro.patch | 43 + ...x-error-handling-in-runtime-pm-setup.patch | 66 + ...imit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch | 87 + ...ve-restore-_context-to-common_clk-se.patch | 117 + ...sdm845-enable-parents-for-pixel-cloc.patch | 49 + ...sm7150-fix-dispcc_mdss_pclk1_clk_src.patch | 37 + ...ipq5018-flag-sleep-clock-as-critical.patch | 37 + ...8917-remove-always_on-flag-from-cpp_.patch | 39 + ...8953-remove-always_on-flag-from-cpp_.patch | 39 + ...1000-update-the-sdcc-rcgs-to-use-sha.patch | 51 + ...75-update-the-sdcc-rcgs-to-use-share.patch | 52 + ...450-update-the-sdcc-rcgs-to-use-shar.patch | 61 + ...450-update-the-sdcc-rcgs-to-use-shar.patch | 52 + ...c-sm8550-use-floor-ops-for-sdcc-rcgs.patch | 55 + ...c-sm8650-use-floor-ops-for-sdcc-rcgs.patch | 55 + ...80100-update-the-sdcc-rcgs-to-use-sh.patch | 50 + ...x3d-add-parent-to-parent-request-map.patch | 67 + ...mpute-2d-using-duty-fraction-directl.patch | 71 + ...correct-error-code-in-qcom_cc_probe_.patch | 42 + ...etm3x-fix-cpulocked-warning-on-cpuhp.patch | 67 + ...tate-enable-asym-capacity-only-when-.patch | 51 + ...pufreq-scmi-correct-scmi-explanation.patch | 37 + ...-device_node-reference-leak-in-scmi_.patch | 36 + ...s-menu-always-check-timers-with-tick.patch | 88 + ...netdev-memory-leak-in-dpaa2_caam_pro.patch | 145 + ...to-cavium-fix-dma_free_coherent-size.patch | 38 + .../crypto-ccp-add-an-s4-restore-flow.patch | 168 + ...re-psp-dead-if-psp_cmd_tee_ring_init.patch | 43 + ...e-implicit-sev-snp-init-and-shutdown.patch | 361 ++ ...r-out-ring-destroy-handling-to-a-hel.patch | 90 + ...o-ccp-narrow-scope-of-snp_range_list.patch | 64 + ...psp_cmd_tee_ring_destroy-when-psp_cm.patch | 113 + ...-hpre-extend-tag-field-to-64-bits-fo.patch | 340 + ...-sec2-support-skcipher-aead-fallback.patch | 220 + ...-trng-support-tfms-sharing-the-devic.patch | 258 + ...-zip-adjust-the-way-to-obtain-the-re.patch | 128 + ...-octeontx-fix-dma_free_coherent-size.patch | 38 + ...t-fix-warning-on-adf_pfvf_pf_proto.c.patch | 63 + ...fix-memory-leak-in-starfive_aes_aead.patch | 60 + ...e-commit_end-increment-on-decoder-co.patch | 62 + ...ix-unlocked-test-for-dm_suspended_md.patch | 56 + .../dm-use-bio_clone_blkg_association.patch | 44 + ...use-read_once-in-dm_blk_report_zones.patch | 36 + ...-fix-hw-scatter-gather-not-looking-a.patch | 51 + ...dma-axi-dmac-fix-sw-cyclic-transfers.patch | 57 + ...ma-don-t-explicitly-disable-clocks-i.patch | 61 + ...ek-uart-apdma-fix-above-4g-addressin.patch | 83 + ...-document-not-included-in-any-toctre.patch | 36 + ...i-endpoint-fix-ntb-vntb-copy-paste-e.patch | 82 + ...documentation-trace-refactor-toctree.patch | 156 + ...acing-add-pci-tracepoint-documentati.patch | 125 + ...bd-always-set-blk_feat_stable_writes.patch | 94 + ...050-use-dev_err_probe-for-regulator-.patch | 42 + ...gpu-kernel-modesetting-enabled-messa.patch | 40 + ...xplicit-vcn-instance-0-in-sr-iov-ini.patch | 179 + ...ignal_eviction_fence-bool-return-val.patch | 79 + ...e-free_trees-array-on-buddy-mm-teard.patch | 63 + ...-a2xx-fix-pixel-shader-start-on-a225.patch | 42 + ...p-dpu-add-merge3d-support-for-sc7280.patch | 84 + ...-num_planes-to-1-for-interleaved-yuv.patch | 61 + ...sm-dpu-fix-cmd-panels-on-dpu-1.x-3.x.patch | 48 + ...dpu-fix-wd-timer-handling-on-dpu-8.x.patch | 198 + ...vsync-source-irrespective-of-mdp-top.patch | 68 + ...8-remove-manual-invocation-of-unprep.patch | 40 + ...r-evict-groups-before-vm-termination.patch | 90 + ...immediate-ticking-on-a-disabled-tick.patch | 61 + .../drm-panthor-fix-the-full_tick-check.patch | 64 + ...ix-the-group-priority-rotation-logic.patch | 140 + ...the-logic-that-decides-when-to-stop-.patch | 130 + ...-sure-we-resume-the-tick-when-new-jo.patch | 109 + ...ver-from-panthor_gpu_flush_caches-fa.patch | 108 + ...unregister-drm-device-on-probe-error.patch | 91 + .../edac-altera-remove-irqf_oneshot.patch | 74 + ...nprintf-size-calculation-in-calculat.patch | 40 + ...nprintf-limit-calculation-in-calcula.patch | 49 + ...erofs-get-rid-of-raw-bi_end_io-usage.patch | 71 + ...-of-filesystem-properly-for-file-bac.patch | 64 + ...xattrs-list-to-calculate-hmac-in-evm.patch | 70 + ...parent-link-count-underflow-in-rmdir.patch | 74 + ...on_cursor_noblink-fbcon_cursor_blink.patch | 63 + ...on-fbcon_is_inactive-fbcon_is_active.patch | 157 + .../fbcon-introduce-get_-fg-bg-_color.patch | 85 + ...n-callbacks-into-struct-fbcon_bitops.patch | 432 ++ ...struct-fbcon_ops-to-struct-fbcon_par.patch | 2478 ++++++++ ..._font-callback-with-related-callback.patch | 99 + ...ix-a-memory-leak-in-au1200fb_drv_pro.patch | 43 + ..._timing-fix-device-node-reference-le.patch | 56 + ...ace-fgraph_ret_regs-with-ftrace_regs.patch | 766 +++ ...-correct-32-bit-response-handling-in.patch | 119 + ...fs-add-linux-init_task.h-for-init_fs.patch | 40 + ...fs-fix-readdir-slow-start-regression.patch | 54 + ...op-duplicate-bprm_stack_limits-test-.patch | 48 + ...te-ftrace_regs-accessor-functions-fo.patch | 376 ++ ...ftrace_regs-abstract-from-direct-use.patch | 762 +++ ...race_regs_return_value-to-ftrace_reg.patch | 47 + ..._ftrace_regs-for-ftrace_regs_-macros.patch | 63 + ...rqf_cond_oneshot-in-devm_request_irq.patch | 43 + ...s2-fix-slab-use-after-free-in-qd_put.patch | 45 + ...er-free-in-iomap-inline-data-write-p.patch | 84 + ...ies-missing-in-gfs2_-rename-exchange.patch | 178 + ...rror-when-node-already-exists-in-hfs.patch | 58 + ...d-fix-null-ptr-deref-in-ishtp_bus_re.patch | 50 + ...add-missing-check-for-input_ff_creat.patch | 41 + queue-6.12/hrtimer-fix-trace-oddity.patch | 43 + ...bus-mpq8785-add-support-for-mpm82504.patch | 153 + ...785-fix-vout_mode-mismatch-during-id.patch | 81 + ...785-implement-vout-feedback-resistor.patch | 78 + ...785-prepare-driver-for-multiple-devi.patch | 94 + ...llow-runtime-disabling-of-the-hw-rng.patch | 95 + ...cu-and-work_struct-to-fix-race-condi.patch | 446 ++ ...handle-devm_pm_runtime_enable-errors.patch | 44 + ...mory-leak-in-dw_i3c_master_i2c_xfers.patch | 45 + ...e-spinlock-to-avoid-upsetting-lockde.patch | 39 + ...update-hot-join-flag-only-on-success.patch | 39 + ...e-name-assignment-after-i3c_bus_init.patch | 46 + ...gid-cache-on-client-reregister-event.patch | 54 + ...ix-port-speed-query-for-representors.patch | 63 + ...ssure-mprls0025pa-fix-interrupt-flag.patch | 40 + ...mprls0025pa-fix-pressure-calculation.patch | 110 + ...ure-mprls0025pa-fix-scan_type-struct.patch | 47 + ...rls0025pa-fix-spi-cs-delay-violation.patch | 71 + ...ls0025pa-fix-spi_transfer-struct-ini.patch | 36 + ...fix-a-resource-leak-in-sca3000_probe.patch | 42 + ...ngling-symbol-in-gain-time-scale-hel.patch | 36 + ...-using-ipproto_raw-must-drop-incomin.patch | 94 + ...iatek-aggregate-bandwidth-with-satur.patch | 54 + ...-mediatek-don-t-hijack-parent-device.patch | 53 + ...de-unionize-file-and-user_data-in-st.patch | 45 + ...uring-sync-validate-passed-in-offset.patch | 36 + ...ease-acquire-ordering-for-ioring_set.patch | 93 + ...sion-side-handling-of-completion-sid.patch | 49 + ...-draining-prq-in-sva-mm-release-path.patch | 61 + ...-present-bit-before-tearing-down-pas.patch | 104 + ...in-prqs-when-domain-removed-from-rid.patch | 117 + ...-cache-for-pasid-table-before-using-.patch | 55 + ...separate-page-request-queue-from-svm.patch | 996 +++ ...ate-limit-unknown-xcvr-type-messages.patch | 51 + ...-capability-check-in-ipc_permissions.patch | 66 + ...set-module-buildid-in-ftrace_mod_add.patch | 100 + ...eck-the-return-value-of-regmap_bulk_.patch | 55 + ...-read-in-btf_dump_get_bitfield_value.patch | 59 + ...-initialise-event-handler-read-bytes.patch | 43 + ...ory-leak-in-raid1_run-if-no-active-r.patch | 61 + ...d-raid1-fix-memory-leak-in-raid1_run.patch | 46 + ...y_working-flag-handling-in-raid10_sy.patch | 47 + ...d5_run-to-return-error-when-log_init.patch | 47 + ...commodate-c-phy-into-the-calculation.patch | 53 + ...a-wave5-fix-memory-leak-on-codec_inf.patch | 63 + .../media-pci-mg4b-use-irqf_no_thread.patch | 39 + ...fix-allocation-for-small-frame-sizes.patch | 57 + ...regulator-resource-leak-on-wm5102_cl.patch | 43 + ...2c-add-compatible-strings-for-layers.patch | 40 + ...mfd-i2c-add-delta-tn48m-cpld-support.patch | 67 + ...-simple-mfd-i2c-add-max77705-support.patch | 52 + ...mple-mfd-i2c-add-spacemit-p1-support.patch | 89 + ...2c-keep-compatible-strings-in-alphab.patch | 44 + .../mfd-wm8350-core-use-irqf_oneshot.patch | 48 + ...mc-increase-power-on-settling-delay-.patch | 40 + ...r-function-for-reading-module_buildi.patch | 80 + ...ceive-space-timestamp-initialization.patch | 92 + ...memory-leak-in-mtd_parser_tplink_saf.patch | 42 + ...rt-fix-of-node-refcount-leak-in-pars.patch | 84 + ...nce-fix-return-type-of-cdma-send-and.patch | 40 + queue-6.12/mtd-spinand-fix-kernel-doc.patch | 36 + ..._dstref_steal-and-skb_dstref_restore.patch | 73 + ...h-due-to-unvalidated-vcc-pointer-in-.patch | 154 + ...ouble-free-issue-for-tx-spare-buffer.patch | 74 + ...-fix-duplicate-reception-of-old-data.patch | 49 + .../net-sunhme-fix-sbus-regression.patch | 73 + ...b_dstref_steal-skb_dstref_restore-fo.patch | 75 + ...ncount-fix-tracking-of-connections-f.patch | 69 + ...ncount-increase-the-connection-clean.patch | 123 + ...ncount-make-nf_conncount_gc_list-to-.patch | 93 + ...les-reset-table-validation-state-on-.patch | 59 + ...ink_queue-do-shared-unconfirmed-chec.patch | 246 + ...ink_queue-optimize-verdict-lookup-wi.patch | 318 + ...mpat-add-more-restrictions-on-netlin.patch | 71 + ...unter-fix-reset-of-counters-on-32bit.patch | 75 + ...t_hash-fix-get-operation-on-big-endi.patch | 57 + ...t_rbtree-check-for-partial-overlaps-.patch | 90 + ...t_rbtree-fix-bogus-eexist-with-nlm_f.patch | 80 + ...op-timers-and-work-before-freeing-co.patch | 52 + ...inate-unnecessary-kref-in-nfs_local_.patch | 84 + ...gfp_noio-and-non-memreclaim-workqueu.patch | 80 + ...nfserr_inval-is-not-defined-by-nfsv2.patch | 78 + ...r-defer-requests-during-idmap-lookup.patch | 152 + ...virtio_pmem-serialize-flush-requests.patch | 98 + ...cteon_ep-disable-per-ring-interrupts.patch | 119 + ...cteon_ep-ensure-dbell-baddr-updation.patch | 186 + ...on_ep_vf-ensure-dbell-baddr-updation.patch | 174 + ...-pf-driver-crash-with-kexec-kernel-b.patch | 62 + ...-unregister-devlink-on-probe-failure.patch | 36 + ...possible-null-pointer-dereferences-i.patch | 49 + ...orrect-value-in-dev_pm_opp_get_level.patch | 40 + ...vl-fix-uninit-value-in-ovl_fill_real.patch | 58 + ...86-xen-fix-balloon-target-initializa.patch | 140 + ...strict-program_hpx_type2-to-aer-bits.patch | 200 + ...k-for-pericom-pi7c9x2g404-switches-1.patch | 46 + ...d-defines-for-bridge-window-indexing.patch | 69 + ...-for-null-in-of_pci_bus_release_doma.patch | 42 + ...do-not-attempt-to-set-exttag-for-vfs.patch | 49 + ...ialize-rcb-from-pci_configure_device.patch | 90 + ...650sa-root-port-extended-tags-as-bro.patch | 56 + ...-irq-domain-leak-when-msi-allocation.patch | 45 + ...se-per-cpu-pgmap-ref-when-vm_insert_.patch | 42 + ...oid-redundant-delays-on-d3hot-d3cold.patch | 56 + ...-portdrv-fix-potential-resource-leak.patch | 48 + ...pe-properly-set-hw.state-on-failures.patch | 108 + ...-not-set-bit-width-for-unavailable-c.patch | 46 + ...x8qm-hsio-fix-null-pointer-dereferen.patch | 41 + ...ium-fix-device-node-reference-leak-i.patch | 44 + ...250-lpass-lpi-fix-i2s2_data_groups-d.patch | 38 + ...ix-refcount-leak-in-pcs_add_gpio_fun.patch | 50 + ...cros_ec_lightbar-fix-response-size-i.patch | 43 + ...cros_typec_switch-don-t-touch-struct.patch | 54 + ...-pmf-prevent-tee-errors-after-hibern.patch | 193 + ...0002-remove-irqf_oneshot-from-reques.patch | 57 + ...-harden-dev_pm_clear_wake_irq-agains.patch | 65 + ...-empty-list-in-wakeup_sources_walk_s.patch | 44 + ...ng-wake-up-while-waiting-on-nfs_layo.patch | 61 + ...m-reboot-mode-respect-cell-size-for-.patch | 64 + ...500-fix-use-after-free-in-power_supp.patch | 104 + ...8945a-fix-use-after-free-in-power_su.patch | 77 + ...56xx-fix-use-after-free-in-power_sup.patch | 73 + ...5980-fix-use-after-free-in-power_sup.patch | 73 + ...7xxx-fix-wrong-errno-when-bus-ops-ar.patch | 61 + ...ap-battery-fix-use-after-free-in-pow.patch | 70 + ...dfish-fix-use-after-free-in-power_su.patch | 73 + ...916_bms_vm-fix-use-after-free-in-pow.patch | 81 + ...916_lbc-fix-use-after-free-for-extco.patch | 67 + ...916_lbc-fix-use-after-free-in-power_.patch | 81 + ...m_battmgr-recognize-lip-as-lithium-p.patch | 42 + ...455-fix-use-after-free-in-power_supp.patch | 78 + ...-battery-fix-use-after-free-in-power.patch | 101 + ...7xx-fix-null-pointer-dereference-in-.patch | 98 + ...recursive-pci_lock_rescan_remove-loc.patch | 275 + ...move-barrier_nospec-out-of-allow_rea.patch | 98 + ...-remove-console_conditional_schedule.patch | 176 + ...ng-rcu-protection-when-reading-real_.patch | 59 + ...uffer-overflow-in-persistent_ram_sav.patch | 92 + ...ck-between-quotactl-and-freeze_super.patch | 73 + ..._read_unlock-deadloop-due-to-softirq.patch | 168 + ...edited-handling-check-in-rcu_read_un.patch | 139 + ..._irq_save-restore-in-rcu_preempt_def.patch | 55 + ...rdma_rw_max_sge-helper-for-sq-sizing.patch | 159 + ...a-hns-fix-rocev1-failure-due-to-dscp.patch | 112 + .../rdma-hns-fix-wq_mem_reclaim-warning.patch | 62 + ...ulp-of-remaining-soft-wcs-during-res.patch | 70 + ...rkqueue-list-corruption-by-removing-.patch | 206 + ...mory-leak-in-get_data_direct_sysfs_p.patch | 57 + ...x-umr-hang-in-lag-error-state-unload.patch | 220 + .../rdma-rtrs-server-remove-dead-code.patch | 57 + queue-6.12/rdma-rtrs-srv-fix-sg-mapping.patch | 85 + ...fix-double-free-in-rxe_srq_from_init.patch | 67 + ...-race-condition-in-qp-timer-handlers.patch | 116 + ...__gfp_nowarn-to-ib_uverbs_unmarshall.patch | 39 + ...date-wqe_size-before-using-it-in-ib_.patch | 57 + ...ove-supply-check-earlier-in-set_mach.patch | 121 + ...pex-fix-use-after-free-in-high-low-s.patch | 89 + ...pci_sdmmc-increase-power-on-settling.patch | 39 + ...ver-side-setting-of-bi_size-for-spec.patch | 80 + .../rnbd-srv-use-bio_add_virt_nofail.patch | 45 + ...ice-lifecycle-handling-in-css_alloc_.patch | 49 + ...ched-deadline-clear-the-defer-params.patch | 43 + ...rrently-executing-cpu-in-rto_next_cp.patch | 87 + ...r-fix-dereference-of-null-pointer-rn.patch | 46 + ...qf_oneshot-and-default-primary-handl.patch | 59 + ...x-memory-leak-in-pqi_report_phys_lun.patch | 72 + ...-ufs-host-mediatek-require-config_pm.patch | 116 + ...x-resource-leak-in-serial_test_wq-on.patch | 60 + ...ristat-fix-printing-order-in-output_.patch | 46 + ...m-convert-page_size-to-unsigned-long.patch | 90 + ...-faulting-in-code-in-pagemap_ioctl-t.patch | 80 + ...emap_ioctl-fix-types-mismatches-show.patch | 406 ++ ...use-after-free-in-caif_serial-ldisc_.patch | 152 + ...mx-change-serial_imx_console-to-bool.patch | 50 + ...al-sh_sci-improve-dma-support-prompt.patch | 39 + queue-6.12/series | 362 ++ ...ck-doi-accept-previously-used-values.patch | 233 + queue-6.12/smack-smack-doi-must-be-0.patch | 71 + ...ct-value-for-smbd_max_fragmented_rec.patch | 78 + ...otential-uaf-and-double-free-in-smb2.patch | 41 + ...-fix-memory-leak-in-svs_enable_debug.patch | 59 + ...use-devm_memremap-to-fix-memory-leak.patch | 53 + ...mem-handle-enomem-error-during-probe.patch | 39 + ...el_ace2x-add-snd_hda_core-dependency.patch | 45 + ...ols-add-include-folder-to-.gitignore.patch | 35 + ...ging-greybus-lights-avoid-null-deref.patch | 55 + ...timestamp-must-look-at-the-rtx-queue.patch | 44 + ...6_pkg_temp_thermal-handle-invalid-te.patch | 43 + ...eference-leak-in-thermal_of_cm_looku.patch | 46 + ...intel-speed-select-fix-file-descript.patch | 50 + ...-missing-cleanup-on-get_burstcount-e.patch | 43 + ...neon-fix-locality-leak-on-get_burstc.patch | 44 + ...comment-about-ftrace_regs-definition.patch | 61 + ...ftrace_fill_perf_regs-for-perf-event.patch | 171 + ...ce_partial_regs-for-converting-ftrac.patch | 124 + ...-process-error-handling-in-event_his.patch | 51 + ...uplicate-enable_event_str-and-disabl.patch | 44 + ...sqe128-flag-before-accessing-the-cmd.patch | 47 + ...-cap_sys_resource-using-ns_capable_n.patch | 51 + .../usb-bdc-fix-sleep-during-atomic.patch | 41 + ...stream-bridge-for-vfio_pci_core_disa.patch | 74 + ...e-wdt-fix-pm-reference-leak-in-probe.patch | 45 + ...-add-missing-lock-protection-in-ath1.patch | 62 + ...x-use_for-flag-update-on-bss-refresh.patch | 54 + ...1-stop-nan-and-p2p-in-cfg80211_leave.patch | 47 + ...queue-factor-out-assign_rescuer_work.patch | 78 + ...ssign-rescuer-work-when-really-neede.patch | 39 + ...s-rescuer-work-items-one-by-one-usin.patch | 202 + ...ix-stack-orc-unwind-from-kprobe_mult.patch | 118 + ...witch-kprobe_multi-program-stack-unw.patch | 111 + ...t-prefix-for-typedef-types-in-progra.patch | 83 + ...e-data-pointer-for-zero-length-items.patch | 70 + ...-use-grant-dma-ops-when-running-as-d.patch | 45 + ...ug-race-in-icmp_route_lookup-reverse.patch | 100 + ...x-incorrect-error-code-returned-for-.patch | 40 + ...-fix-memory-leak-in-amdxdna_ubuf_map.patch | 55 + ...dna-fix-notifier_wq-flushing-warning.patch | 39 + ...x-race-where-send-ring-appears-full-.patch | 92 + ...ld-mm-structure-across-iommu_sva_unb.patch | 64 + ...op-job-scheduling-across-aie2_releas.patch | 54 + ...pdate-cpuidle-driver-check-in-__acpi.patch | 48 + ...pointer-dereference-in-acpi_ev_addre.patch | 40 + ...leak-of-newsk-in-unix_stream_connect.patch | 56 + ...m-relax-__free-variable-declarations.patch | 268 + ...r-relax-__free-variable-declarations.patch | 77 + ...r-sun5i-a13-utoo-p66-delete-power-gp.patch | 46 + ...add-clocks-property-to-motor-control.patch | 35 + ...ut-__vdso_clock_getres-if-unavailabl.patch | 39 + ...gic-axg-assign-the-mmc-signal-clocks.patch | 52 + ...ogic-c3-assign-the-mmc-signal-clocks.patch | 53 + ...ic-g12-assign-the-mmc-a-signal-clock.patch | 42 + ...c-g12-assign-the-mmc-b-and-c-signal-.patch | 52 + ...ogic-gx-assign-the-mmc-signal-clocks.patch | 97 + ...logic-s4-assign-mmc-b-clock-to-24mhz.patch | 51 + ...-amlogic-s4-fix-mmc-clock-assignment.patch | 70 + ...ek-mt8183-jacuzzi-pico6-fix-typo-in-.patch | 36 + ...m-agatti-add-cx_mem-dbgc-gpu-regions.patch | 49 + ...sm8994-octagon-fix-analog-devices-ve.patch | 43 + ...rb4210-rb2-fix-uart3-wakeup-irq-stor.patch | 43 + ...s-qcom-sdm630-fix-gpu_speed_bin-size.patch | 49 + ...com-sdm845-db845c-drop-cs-from-spio0.patch | 40 + ...dm845-db845c-specify-power-for-wifi-.patch | 50 + ...dm845-oneplus-don-t-keep-panel-regul.patch | 39 + ...dm845-oneplus-don-t-mark-ts-supply-b.patch | 39 + ...dm845-oneplus-mark-l14a-regulator-as.patch | 38 + ...m-sm6115-add-cx_mem-dbgc-gpu-regions.patch | 49 + ...alos-drop-opp-shared-from-qup-opp-ta.patch | 43 + ...m-x1e-bus-is-40-bits-fix-64gb-models.patch | 42 + ...1e80100-fix-usb-combo-phys-ss1-and-s.patch | 61 + ...s-r9a09g047e57-smarc-remove-duplicat.patch | 34 + ...s-rzt2h-n2h-evk-common-use-gpio-for-.patch | 54 + ...j784s4-j742s2-main-common.dtsi-refac.patch | 125 + ...j784s4-main.dtsi-move-c71_3-node-to-.patch | 73 + ...pql-mba8mp-ras314-fix-hdmi-cec-pad-c.patch | 37 + ...pql-mba8mpxl-fix-hdmi-cec-pad-contro.patch | 36 + ...ror-handling-in-arch_set_shadow_stac.patch | 45 + ...821-fixup-nau8821_enable_jack_detect.patch | 84 + ...sample-width-wild-cards-in-set_usage.patch | 39 + ...ce-some-sdca-controls-to-be-volatile.patch | 139 + ...a-handle-volatile-controls-correctly.patch | 108 + ...oc-sdca-remove-outdated-todo-comment.patch | 41 + ...-add-ahub-writeable_reg-for-rx-holes.patch | 151 + ...ompat_xxx_class-extern-declarations-.patch | 77 + ...-charlcd-fix-release_mem_region-size.patch | 39 + ...led-change-pm8950-wled-configuration.patch | 42 + ...-wled-support-ovp-values-for-pmi8994.patch | 94 + ...l_pcie-use-irqf_oneshot-and-default-.patch | 61 + ...-speed-duplex-to-unknown-if-getting-.patch | 74 + ..._store_bytes-proto-for-read-only-arg.patch | 60 + ...ry-access-flags-in-helper-prototypes.patch | 179 + ...it-detach-permissions-when-prog-fd-i.patch | 88 + ...ifier_bug_if-to-account-for-bpf_call.patch | 108 + ...bpf-limit-bpf-program-signature-size.patch | 48 + ...e-id-of-register-in-sync_linked_regs.patch | 95 + ...-frozen-map-for-calculating-map-hash.patch | 51 + ...bpf-sockmap-fix-fionread-for-sockmap.patch | 293 + ...fix-incorrect-copied_seq-calculation.patch | 178 + ..._logical-to-btrfs_bio-for-encryption.patch | 98 + ...ock_group_tree-dirty_list-corruption.patch | 150 + ...-abort-due-to-non-consecutive-gaps-i.patch | 496 ++ ...eanup-to-remove-unnecessary-local-in.patch | 368 ++ ...btrfs-introduce-btrfs_bio-async_csum.patch | 262 + ...all-btrfs_bio-end_io-are-called-in-t.patch | 200 + ...urn-correct-error-when-deleting-qgro.patch | 43 + ...fs_bio-fs_info-by-extracting-it-from.patch | 584 ++ ...n-t-zone-append-to-conventional-zone.patch | 117 + ...se-is_err-for-filp_open-return-value.patch | 43 + ...composite-convert-from-owl_divider_h.patch | 49 + ...divider-convert-from-divider_round_r.patch | 84 + ...rt-from-divider_round_rate-to-divide.patch | 49 + ...kdivider-hi6220-convert-from-divider.patch | 49 + ...nvert-from-divider_round_rate-to-div.patch | 50 + ...-mfg_eb-as-parent-to-mt8196-mfgpll-c.patch | 101 + ...mediatek-drop-__initconst-from-gates.patch | 72 + ...x-error-handling-in-runtime-pm-setup.patch | 66 + ...eson-g12a-limit-the-hdmi-pll-od-to-4.patch | 86 + ...imit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch | 87 + ...re-remove-duplicate-determine_rate-o.patch | 65 + ...vert-from-divider_round_rate-to-divi.patch | 48 + ...ve-restore-_context-to-common_clk-se.patch | 117 + ...d1-divider-convert-from-divider_roun.patch | 50 + ...convert-from-divider_round_rate-to-d.patch | 51 + ...ll-convert-from-divider_round_rate-t.patch | 82 + ...sdm845-enable-parents-for-pixel-cloc.patch | 49 + ...sm7150-fix-dispcc_mdss_pclk1_clk_src.patch | 37 + ...mur-update-the-sdcc-rcgs-to-use-shar.patch | 51 + ...ipq5018-flag-sleep-clock-as-critical.patch | 37 + ...os-update-the-sdcc-rcgs-to-use-share.patch | 59 + ...8917-remove-always_on-flag-from-cpp_.patch | 39 + ...8953-remove-always_on-flag-from-cpp_.patch | 39 + ...1000-update-the-sdcc-rcgs-to-use-sha.patch | 51 + ...75-update-the-sdcc-rcgs-to-use-share.patch | 52 + ...450-update-the-sdcc-rcgs-to-use-shar.patch | 61 + ...450-update-the-sdcc-rcgs-to-use-shar.patch | 52 + ...c-sm8550-use-floor-ops-for-sdcc-rcgs.patch | 55 + ...c-sm8650-use-floor-ops-for-sdcc-rcgs.patch | 55 + ...750-update-the-sdcc-rcgs-to-use-shar.patch | 52 + ...80100-update-the-sdcc-rcgs-to-use-sh.patch | 50 + ...x3d-add-parent-to-parent-request-map.patch | 67 + ...mpute-2d-using-duty-fraction-directl.patch | 71 + ...divider-convert-from-divider_ro_roun.patch | 55 + ...divider-convert-from-divider_round_r.patch | 55 + ...correct-error-code-in-qcom_cc_probe_.patch | 42 + ...-error-pointer-check-after-rockchip_.patch | 39 + ...2-clkgen-convert-from-divider_round_.patch | 72 + ...pect-kconfig-setting-when-building-m.patch | 166 + ...vert-from-divider_round_rate-to-divi.patch | 49 + ...core-convert-from-divider_ro_round_r.patch | 72 + ...core-convert-from-divider_round_rate.patch | 77 + ...-ap-poll-for-pll-lock-and-wait-for-s.patch | 150 + ...convert-from-divider_round_rate-to-d.patch | 50 + ...ert-from-divider_round_rate-to-divid.patch | 49 + ...er-convert-from-divider_round_rate-t.patch | 48 + ...er-fix-zynqmp_clk_divider_determine_.patch | 44 + ...ix-zynqmp_clk_divider_determine_rate.patch | 44 + ...etm3x-fix-cpulocked-warning-on-cpuhp.patch | 67 + ...r-fix-race-condition-between-sysfs-a.patch | 97 + ...tate-enable-asym-capacity-only-when-.patch | 51 + ...pufreq-scmi-correct-scmi-explanation.patch | 37 + ...-device_node-reference-leak-in-scmi_.patch | 36 + ...s-menu-always-check-timers-with-tick.patch | 88 + ...netdev-memory-leak-in-dpaa2_caam_pro.patch | 145 + ...to-cavium-fix-dma_free_coherent-size.patch | 38 + .../crypto-ccp-add-an-s4-restore-flow.patch | 168 + ...re-psp-dead-if-psp_cmd_tee_ring_init.patch | 43 + ...r-out-ring-destroy-handling-to-a-hel.patch | 90 + ...-a-case-where-snp_shutdown-is-missed.patch | 110 + ...-crash-due-to-incorrect-cleanup-usag.patch | 43 + ...o-ccp-narrow-scope-of-snp_range_list.patch | 64 + ...psp_cmd_tee_ring_destroy-when-psp_cm.patch | 113 + ...-consolidate-qp-creation-and-start-i.patch | 356 ++ ...-hpre-extend-tag-field-to-64-bits-fo.patch | 340 + ...-hpre-support-the-hpre-algorithm-fal.patch | 527 ++ ...-qm-centralize-the-sending-locks-of-.patch | 143 + ...-qm-enhance-the-configuration-of-req.patch | 248 + ...-sec-move-backlog-management-to-qp-a.patch | 365 ++ ...-sec2-support-skcipher-aead-fallback.patch | 220 + ...-sgl-fix-inconsistent-map-unmap-dire.patch | 37 + ...-trng-support-tfms-sharing-the-devic.patch | 258 + ...-zip-adjust-the-way-to-obtain-the-re.patch | 128 + ...silicon-zip-support-fallback-for-zip.patch | 152 + ...cure-eip93-fix-kernel-panic-in-drive.patch | 37 + ...cure-eip93-unregister-only-available.patch | 164 + ...-octeontx-fix-dma_free_coherent-size.patch | 38 + ...t-fix-warning-on-adf_pfvf_pf_proto.c.patch | 63 + ...fix-memory-leak-in-starfive_aes_aead.patch | 60 + ...e-fix-cxl_dport-debugfs-einj-entries.patch | 61 + ...e-commit_end-increment-on-decoder-co.patch | 62 + ...vm_cxl_memdev_edac_release-confusion.patch | 178 + ...move-branch-hint-after-code-refactor.patch | 59 + ...ix-unlocked-test-for-dm_suspended_md.patch | 56 + .../dm-use-bio_clone_blkg_association.patch | 44 + ...use-read_once-in-dm_blk_report_zones.patch | 36 + ...-fix-hw-scatter-gather-not-looking-a.patch | 51 + ...dma-axi-dmac-fix-sw-cyclic-transfers.patch | 57 + ...ma-don-t-explicitly-disable-clocks-i.patch | 61 + ...ek-uart-apdma-fix-above-4g-addressin.patch | 83 + ...i-endpoint-fix-ntb-vntb-copy-paste-e.patch | 82 + ...acing-add-pci-tracepoint-documentati.patch | 125 + ...-add-phase-adjust-gran-pin-attribute.patch | 175 + ...he-all-output-properties-in-zl3073x_.patch | 773 +++ ...fix-output-pin-phase-adjustment-sign.patch | 67 + ...cify-phase-adjustment-granularity-fo.patch | 173 + ...it-ref-out-and-synth-logic-from-core.patch | 1314 ++++ ...re-raw-register-values-instead-of-pa.patch | 371 ++ ...bd-always-set-blk_feat_stable_writes.patch | 94 + ...050-use-dev_err_probe-for-regulator-.patch | 42 + ...gpu-kernel-modesetting-enabled-messa.patch | 40 + ...xplicit-vcn-instance-0-in-sr-iov-ini.patch | 179 + ...ignal_eviction_fence-bool-return-val.patch | 79 + ...e-free_trees-array-on-buddy-mm-teard.patch | 63 + ...ilicon-hibmc-add-dp-mode-valid-check.patch | 115 + ...bmc-adding-reset-colorbar-cfg-in-dp-.patch | 42 + ...bmc-fix-dp-probabilistical-detect-er.patch | 219 + ...bmc-fix-no-showing-problem-with-load.patch | 56 + ...-a2xx-fix-pixel-shader-start-on-a225.patch | 42 + ...p-dpu-add-merge3d-support-for-sc7280.patch | 83 + ...-num_planes-to-1-for-interleaved-yuv.patch | 61 + ...-division-by-zero-in-msm_dp_ctrl_con.patch | 90 + ...te-msm_dp_controller-ids-for-sa8775p.patch | 41 + ...sm-dpu-fix-cmd-panels-on-dpu-1.x-3.x.patch | 48 + ...dpu-fix-wd-timer-handling-on-dpu-8.x.patch | 198 + ...fset-hbb-values-written-to-dpu-by-13.patch | 68 + ...ram-correct-register-for-ubwc-config.patch | 109 + ...vsync-source-irrespective-of-mdp-top.patch | 68 + ...14nm-convert-from-divider_round_rate.patch | 55 + ...rect-hbb-programmed-on-ubwc-5.x-and-.patch | 41 + ...8-remove-manual-invocation-of-unprep.patch | 40 + ...r-evict-groups-before-vm-termination.patch | 90 + ...immediate-ticking-on-a-disabled-tick.patch | 61 + ...anthor-fix-panthor_gpu_coherency_set.patch | 57 + .../drm-panthor-fix-the-full_tick-check.patch | 64 + ...ix-the-group-priority-rotation-logic.patch | 140 + ...the-logic-that-decides-when-to-stop-.patch | 130 + ...-sure-we-resume-the-tick-when-new-jo.patch | 109 + ...ver-from-panthor_gpu_flush_caches-fa.patch | 108 + ...hdmi_qp-fix-rk3576-hpd-interrupt-han.patch | 54 + .../drm-xe-ptl-disable-dcc-on-ptl.patch | 87 + ...unregister-drm-device-on-probe-error.patch | 91 + .../edac-altera-remove-irqf_oneshot.patch | 74 + ...nprintf-size-calculation-in-calculat.patch | 40 + ...nprintf-limit-calculation-in-calcula.patch | 49 + ...-data-read-failure-for-ztailpacking-.patch | 128 + ...erofs-get-rid-of-raw-bi_end_io-usage.patch | 71 + ...-of-filesystem-properly-for-file-bac.patch | 64 + ...xattrs-list-to-calculate-hmac-in-evm.patch | 70 + ...t-commit-make-s_fc_lock-reclaim-safe.patch | 301 + ...parent-link-count-underflow-in-rmdir.patch | 74 + ...n-callbacks-into-struct-fbcon_bitops.patch | 432 ++ ...struct-fbcon_ops-to-struct-fbcon_par.patch | 2478 ++++++++ ..._font-callback-with-related-callback.patch | 99 + ...ix-a-memory-leak-in-au1200fb_drv_pro.patch | 43 + ..._timing-fix-device-node-reference-le.patch | 56 + ...-correct-32-bit-response-handling-in.patch | 119 + ...fs-add-linux-init_task.h-for-init_fs.patch | 40 + ...ializing-f_mode-before-file_ref_init.patch | 56 + ...fs-fix-readdir-slow-start-regression.patch | 54 + ...op-duplicate-bprm_stack_limits-test-.patch | 48 + ...rqf_cond_oneshot-in-devm_request_irq.patch | 43 + ...s2-fix-slab-use-after-free-in-qd_put.patch | 45 + ...er-free-in-iomap-inline-data-write-p.patch | 84 + ...ies-missing-in-gfs2_-rename-exchange.patch | 178 + .../gpib-fix-error-code-in-ibonline.patch | 42 + ...error-code-in-ni_usb_write_registers.patch | 37 + .../gpib-fix-memory-leak-in-ni_usb_init.patch | 67 + ...ply-the-one-use-item-per-line-policy.patch | 803 +++ ...re-check-for-overflow-to-dmatrfbase1.patch | 57 + ...place-as-with-from-conversions-where.patch | 197 + ...place-wait_on-with-kernel-equivalent.patch | 312 + ...ios-use-frombytes-for-pmulookuptable.patch | 115 + ...rror-when-node-already-exists-in-hfs.patch | 58 + ...d-fix-null-ptr-deref-in-ishtp_bus_re.patch | 50 + ...add-missing-check-for-input_ff_creat.patch | 41 + ..._vfio_pci-fix-vf-reset-timeout-issue.patch | 93 + queue-6.18/hrtimer-fix-trace-oddity.patch | 43 + ...785-fix-vout_mode-mismatch-during-id.patch | 81 + .../hwrng-airoha-set-rng-quality-to-900.patch | 67 + ...llow-runtime-disabling-of-the-hw-rng.patch | 95 + ...cu-and-work_struct-to-fix-race-condi.patch | 446 ++ ...handle-devm_pm_runtime_enable-errors.patch | 44 + ...mory-leak-in-dw_i3c_master_i2c_xfers.patch | 45 + ...e-spinlock-to-avoid-upsetting-lockde.patch | 39 + ...update-hot-join-flag-only-on-success.patch | 39 + ...e-name-assignment-after-i3c_bus_init.patch | 46 + ...gid-cache-on-client-reregister-event.patch | 54 + ...ix-port-speed-query-for-representors.patch | 63 + ...ssure-mprls0025pa-fix-interrupt-flag.patch | 40 + ...mprls0025pa-fix-pressure-calculation.patch | 110 + ...ure-mprls0025pa-fix-scan_type-struct.patch | 47 + ...rls0025pa-fix-spi-cs-delay-violation.patch | 71 + ...ls0025pa-fix-spi_transfer-struct-ini.patch | 36 + ...fix-a-resource-leak-in-sca3000_probe.patch | 42 + ...ngling-symbol-in-gain-time-scale-hel.patch | 36 + ...-using-ipproto_raw-must-drop-incomin.patch | 94 + ...dp5589-remove-a-leftover-header-file.patch | 217 + ...iatek-aggregate-bandwidth-with-satur.patch | 54 + ...-mediatek-don-t-hijack-parent-device.patch | 53 + ...de-unionize-file-and-user_data-in-st.patch | 45 + ...ay-sqarray-static-branch-disablement.patch | 66 + ...-remove-unused-ctx-evfd_last_cq_tail.patch | 47 + ...x-memory-leak-if-io_buffer_add_list-.patch | 43 + ...uring-sync-validate-passed-in-offset.patch | 36 + ...ease-acquire-ordering-for-ioring_set.patch | 93 + ...sion-side-handling-of-completion-sid.patch | 49 + ...re-s-primary-handler-and-set-irqf_on.patch | 95 + ...-present-bit-before-tearing-down-con.patch | 128 + ...-present-bit-before-tearing-down-pas.patch | 104 + ...-cache-for-pasid-table-before-using-.patch | 55 + ...ate-limit-unknown-xcvr-type-messages.patch | 51 + ...-capability-check-in-ipc_permissions.patch | 66 + ...logical-constant-out-of-range-compar.patch | 56 + ...ame-__bpf_address_lookup-to-bpf_addr.patch | 186 + ...set-module-buildid-in-ftrace_mod_add.patch | 100 + ...-expresswire-fix-chip-state-breakage.patch | 129 + ...eck-the-return-value-of-regmap_bulk_.patch | 55 + ...kstrtobool-docstring-to-mention-enab.patch | 44 + ...-read-in-btf_dump_get_bitfield_value.patch | 59 + .../mcb-fix-incorrect-sanity-check.patch | 62 + ...-initialise-event-handler-read-bytes.patch | 43 + ...md-fix-return-value-of-mddev_trylock.patch | 43 + ...ix-percpu_ref-not-resurrected-on-sus.patch | 47 + ...d-raid1-fix-memory-leak-in-raid1_run.patch | 46 + ...y_working-flag-handling-in-raid10_sy.patch | 47 + ...hang-with-degraded-array-with-llbitm.patch | 48 + ...d5_run-to-return-error-when-log_init.patch | 47 + ...commodate-c-phy-into-the-calculation.patch | 53 + ...a-wave5-fix-memory-leak-on-codec_inf.patch | 63 + .../media-pci-mg4b-use-irqf_no_thread.patch | 39 + ...fix-allocation-for-small-frame-sizes.patch | 57 + ...x-struct-intel_lb_component_ops-kern.patch | 46 + ...regulator-resource-leak-on-wm5102_cl.patch | 43 + ...mfd-i2c-add-delta-tn48m-cpld-support.patch | 67 + .../mfd-wm8350-core-use-irqf_oneshot.patch | 48 + ...son32-drop-a-dangling-kconfig-symbol.patch | 36 + ...e-lockdep-warning-in-__kfree_rcu_she.patch | 130 + ...mc-increase-power-on-settling-delay-.patch | 40 + ...r-function-for-reading-module_buildi.patch | 80 + ...account-for-ooo-in-mptcp_rcvbuf_grow.patch | 63 + ...ceive-space-timestamp-initialization.patch | 92 + ...-accessing-regions-before-setting-nr.patch | 66 + ...memory-leak-in-mtd_parser_tplink_saf.patch | 42 + ...rt-fix-of-node-refcount-leak-in-pars.patch | 84 + ...nce-fix-return-type-of-cdma-send-and.patch | 40 + queue-6.18/mtd-spinand-fix-kernel-doc.patch | 36 + ...h-due-to-unvalidated-vcc-pointer-in-.patch | 154 + ...ouble-free-issue-for-tx-spare-buffer.patch | 74 + ...-fix-duplicate-reception-of-old-data.patch | 49 + ...tch-fix-forwarding-offload-statemach.patch | 73 + .../net-sunhme-fix-sbus-regression.patch | 73 + ...ncount-fix-tracking-of-connections-f.patch | 69 + ...ncount-increase-the-connection-clean.patch | 123 + ...ncount-make-nf_conncount_gc_list-to-.patch | 93 + ...les-reset-table-validation-state-on-.patch | 59 + ...ink_queue-do-shared-unconfirmed-chec.patch | 246 + ...ink_queue-optimize-verdict-lookup-wi.patch | 318 + ...mpat-add-more-restrictions-on-netlin.patch | 71 + ...unter-fix-reset-of-counters-on-32bit.patch | 75 + ...t_hash-fix-get-operation-on-big-endi.patch | 57 + ...t_rbtree-check-for-partial-overlaps-.patch | 90 + ...t_rbtree-don-t-gc-elements-on-insert.patch | 301 + ...t_rbtree-fix-bogus-eexist-with-nlm_f.patch | 80 + ..._set_rbtree-remove-seqcount_rwlock_t.patch | 63 + ...t_rbtree-translate-rbtree-to-array-f.patch | 508 ++ ...t_rbtree-use-binary-search-array-in-.patch | 198 + ...t_rbtree-validate-element-belonging-.patch | 294 + ...t_rbtree-validate-open-interval-over.patch | 308 + ...le-increment-of-retry_count-in-subre.patch | 38 + ...op-timers-and-work-before-freeing-co.patch | 52 + ...alio-handle-short-writes-by-retrying.patch | 121 + ...ent-direct-reclaim-recursion-into-nf.patch | 77 + ...ve-eagain-handling-in-nfs_local_doio.patch | 43 + ...gfp_noio-and-non-memreclaim-workqueu.patch | 80 + ...nfserr_inval-is-not-defined-by-nfsv2.patch | 78 + ...r-defer-requests-during-idmap-lookup.patch | 152 + ...virtio_pmem-serialize-flush-requests.patch | 98 + ...an8855-drop-an-unused-kconfig-symbol.patch | 38 + ...cteon_ep-disable-per-ring-interrupts.patch | 119 + ...cteon_ep-ensure-dbell-baddr-updation.patch | 186 + ...on_ep_vf-ensure-dbell-baddr-updation.patch | 174 + ...-pf-driver-crash-with-kexec-kernel-b.patch | 62 + ...-unregister-devlink-on-probe-failure.patch | 36 + ...possible-null-pointer-dereferences-i.patch | 49 + ...orrect-value-in-dev_pm_opp_get_level.patch | 40 + ...vl-fix-uninit-value-in-ovl_fill_real.patch | 58 + ...86-xen-fix-balloon-target-initializa.patch | 140 + ...strict-program_hpx_type2-to-aer-bits.patch | 200 + ...k-for-pericom-pi7c9x2g404-switches-1.patch | 46 + ...-for-null-in-of_pci_bus_release_doma.patch | 42 + ...do-not-attempt-to-set-exttag-for-vfs.patch | 49 + ...ialize-rcb-from-pci_configure_device.patch | 90 + ...650sa-root-port-extended-tags-as-bro.patch | 56 + ...-irq-domain-leak-when-msi-allocation.patch | 45 + ...-p2pmem_alloc_mmap-warning-condition.patch | 52 + ...se-per-cpu-pgmap-ref-when-vm_insert_.patch | 42 + ...-page-reference-count-when-page-mapp.patch | 57 + ...oid-redundant-delays-on-d3hot-d3cold.patch | 56 + ...-portdrv-fix-potential-resource-leak.patch | 48 + ...-pcie_ptm_create_debugfs-memory-leak.patch | 55 + ...size-limit-from-bridge-window-sizing.patch | 117 + ...ridge-window-head-alignment-function.patch | 174 + ...le-l0s-and-l1-on-sophgo-2044-pcie-ro.patch | 68 + ...p-over-estimating-bridge-window-size.patch | 173 + ...-intx-irq-domain-leak-in-error-paths.patch | 70 + ...pe-properly-set-hw.state-on-failures.patch | 108 + ...-not-set-bit-width-for-unavailable-c.patch | 46 + ...x8qm-hsio-fix-null-pointer-dereferen.patch | 41 + ...sung-hdptx-pre-compute-hdmi-pll-conf.patch | 62 + ...mote-when-pidfd_get_info-is-called-o.patch | 47 + ...230-fix-null-pointer-dereference-whe.patch | 76 + ...ium-fix-device-node-reference-leak-i.patch | 44 + ...logic-a4-fix-device-node-reference-l.patch | 57 + ...250-lpass-lpi-fix-i2s2_data_groups-d.patch | 38 + ...ix-refcount-leak-in-pcs_add_gpio_fun.patch | 50 + ...cros_ec_lightbar-fix-response-size-i.patch | 43 + ...cros_typec_switch-don-t-touch-struct.patch | 54 + ...-pmf-prevent-tee-errors-after-hibern.patch | 193 + ...wmi-fix-platform-profile-values-for-.patch | 306 + ...0002-remove-irqf_oneshot-from-reques.patch | 57 + ...-harden-dev_pm_clear_wake_irq-agains.patch | 65 + ...-empty-list-in-wakeup_sources_walk_s.patch | 44 + ...ng-wake-up-while-waiting-on-nfs_layo.patch | 61 + ...m-reboot-mode-respect-cell-size-for-.patch | 64 + ...500-fix-use-after-free-in-power_supp.patch | 104 + ...8945a-fix-use-after-free-in-power_su.patch | 77 + ...56xx-fix-use-after-free-in-power_sup.patch | 73 + ...5980-fix-use-after-free-in-power_sup.patch | 73 + ...7xxx-fix-wrong-errno-when-bus-ops-ar.patch | 61 + ...ap-battery-fix-use-after-free-in-pow.patch | 70 + ...dfish-fix-use-after-free-in-power_su.patch | 73 + ...916_bms_vm-fix-use-after-free-in-pow.patch | 81 + ...916_lbc-fix-use-after-free-for-extco.patch | 67 + ...916_lbc-fix-use-after-free-in-power_.patch | 81 + ...m_battmgr-recognize-lip-as-lithium-p.patch | 42 + ...455-fix-use-after-free-in-power_supp.patch | 78 + ...-battery-fix-use-after-free-in-power.patch | 101 + ...7xx-fix-null-pointer-dereference-in-.patch | 98 + ...recursive-pci_lock_rescan_remove-loc.patch | 275 + ...move-barrier_nospec-out-of-allow_rea.patch | 98 + ...-remove-console_conditional_schedule.patch | 176 + ...ng-rcu-protection-when-reading-real_.patch | 59 + ...uffer-overflow-in-persistent_ram_sav.patch | 92 + ...ble-pwmchip-s-parent-device-before-s.patch | 69 + ...ck-between-quotactl-and-freeze_super.patch | 73 + ..._read_unlock-deadloop-due-to-softirq.patch | 168 + ...rdma_rw_max_sge-helper-for-sq-sizing.patch | 159 + ...a-hns-fix-rocev1-failure-due-to-dscp.patch | 112 + .../rdma-hns-fix-wq_mem_reclaim-warning.patch | 62 + ...ulp-of-remaining-soft-wcs-during-res.patch | 70 + ...rkqueue-list-corruption-by-removing-.patch | 206 + ...mory-leak-in-get_data_direct_sysfs_p.patch | 57 + .../rdma-mlx5-fix-ucaps-init-error-flow.patch | 52 + ...x-umr-hang-in-lag-error-state-unload.patch | 220 + .../rdma-rtrs-server-remove-dead-code.patch | 57 + queue-6.18/rdma-rtrs-srv-fix-sg-mapping.patch | 85 + ...fix-double-free-in-rxe_srq_from_init.patch | 67 + ...a-to-va-conversion-for-mr-page-sizes.patch | 553 ++ ...-race-condition-in-qp-timer-handlers.patch | 116 + ...__gfp_nowarn-to-ib_uverbs_unmarshall.patch | 39 + ...date-wqe_size-before-using-it-in-ib_.patch | 57 + ...ove-supply-check-earlier-in-set_mach.patch | 121 + ...sp_rproc-only-reset-carveout-memory-.patch | 47 + ...0-drop-of-dependency-and-enable-by-d.patch | 36 + ...pex-fix-use-after-free-in-high-low-s.patch | 89 + ...cc-support-mailbox-management-of-the.patch | 254 + ...pci_sdmmc-increase-power-on-settling.patch | 39 + ...ver-side-setting-of-bi_size-for-spec.patch | 80 + ...fix-tas-fallback-lock-entry-creation.patch | 67 + .../rtc-amlogic-a4-remove-irqf_oneshot.patch | 45 + ...estrict-task-group_leader-to-current.patch | 102 + ...ice-lifecycle-handling-in-css_alloc_.patch | 49 + ...ched-deadline-clear-the-defer-params.patch | 43 + ...export-hidden-tracepoints-to-modules.patch | 48 + ...for-modules-using-set_tsk_need_resch.patch | 44 + ...rrently-executing-cpu-in-rto_next_cp.patch | 87 + ...r-fix-dereference-of-null-pointer-rn.patch | 46 + ...qf_oneshot-and-default-primary-handl.patch | 59 + ...x-memory-leak-in-pqi_report_phys_lun.patch | 72 + ...-ufs-host-mediatek-require-config_pm.patch | 116 + ...fix-kprobe-multi-stacktrace_ips-test.patch | 54 + ...x-resource-leak-in-serial_test_wq-on.patch | 60 + ...ftests-bpf-test_xsk-split-xskxceiver.patch | 5596 +++++++++++++++++ ...ristat-fix-printing-order-in-output_.patch | 46 + ...-faulting-in-code-in-pagemap_ioctl-t.patch | 80 + ...fix-usage-of-force_read-in-cow-tests.patch | 96 + ...l-fix-a-division-by-zero-error-on-hy.patch | 67 + ...x-number-of-tx-frags-in-invalid-pack.patch | 59 + ...operly-handle-batch-ending-in-the-mi.patch | 43 + ...use-after-free-in-caif_serial-ldisc_.patch | 152 + ...mx-change-serial_imx_console-to-bool.patch | 50 + ...al-sh_sci-improve-dma-support-prompt.patch | 39 + queue-6.18/series | 507 ++ ...ck-doi-accept-previously-used-values.patch | 233 + queue-6.18/smack-smack-doi-must-be-0.patch | 71 + ...ct-value-for-smbd_max_fragmented_rec.patch | 78 + ...otential-uaf-and-double-free-in-smb2.patch | 41 + ...-fix-memory-leak-in-svs_enable_debug.patch | 59 + ...use-devm_memremap-to-fix-memory-leak.patch | 53 + ...mem-handle-enomem-error-during-probe.patch | 39 + .../soc-qcom-ubwc-add-missing-include.patch | 37 + ...el_ace2x-add-snd_hda_core-dependency.patch | 45 + ...ols-add-include-folder-to-.gitignore.patch | 35 + ...ging-greybus-lights-avoid-null-deref.patch | 55 + ...e-unexpected-accecn-negotiation-feed.patch | 117 + ...168-fallback-identifier-for-cc-modul.patch | 135 + ...tiation-and-needs_accecn-identifiers.patch | 207 + ...timestamp-must-look-at-the-rtx-queue.patch | 44 + ...6_pkg_temp_thermal-handle-invalid-te.patch | 43 + ...eference-leak-in-thermal_of_cm_looku.patch | 46 + ...-use-access_private-to-evaluate-hrti.patch | 38 + ...intel-speed-select-fix-file-descript.patch | 50 + ...-missing-cleanup-on-get_burstcount-e.patch | 43 + ...neon-fix-locality-leak-on-get_burstc.patch | 44 + ...-process-error-handling-in-event_his.patch | 51 + ...uplicate-enable_event_str-and-disabl.patch | 44 + ...o-buf-unregister-refcount-optimizati.patch | 52 + ...sqe128-flag-before-accessing-the-cmd.patch | 47 + ...-cap_sys_resource-using-ns_capable_n.patch | 51 + .../usb-bdc-fix-sleep-during-atomic.patch | 41 + ...sb-typec-fusb302-remove-irqf_oneshot.patch | 47 + ...c-ucsi-drop-an-unused-kconfig-symbol.patch | 40 + ...stream-bridge-for-vfio_pci_core_disa.patch | 74 + ...e-wdt-fix-pm-reference-leak-in-probe.patch | 45 + ...-add-missing-lock-protection-in-ath1.patch | 62 + ...usecase-firmware-handling-based-on-d.patch | 101 + ...r-stale-link-mapping-of-ahvif-links_.patch | 68 + ...do-wow-offloads-only-on-primary-link.patch | 86 + ...index-decrement-when-array_len-is-ze.patch | 56 + .../wifi-ath9k-add-of-dependency-to-ahb.patch | 40 + ...x-use_for-flag-update-on-bss-refresh.patch | 54 + ...1-stop-nan-and-p2p-in-cfg80211_leave.patch | 47 + ...-fix-memory-leak-in-__print_txpwr_ma.patch | 59 + ...queue-factor-out-assign_rescuer_work.patch | 78 + ...ssign-rescuer-work-when-really-neede.patch | 39 + ...s-rescuer-work-items-one-by-one-usin.patch | 202 + ...ect-the-microcode-table-for-zenbleed.patch | 84 + ...witch-kprobe_multi-program-stack-unw.patch | 111 + ...fix-return_to_handler-regs.rsp-value.patch | 66 + ...t-prefix-for-typedef-types-in-progra.patch | 83 + ...e-data-pointer-for-zero-length-items.patch | 70 + ...en-remove-inclusion-of-nlm4.h-header.patch | 35 + ...-use-grant-dma-ops-when-running-as-d.patch | 45 + ...ug-race-in-icmp_route_lookup-reverse.patch | 100 + ...na-enable-temporal-sharing-only-mode.patch | 130 + ...x-cu_idx-being-cleared-by-memset-dur.patch | 98 + ...x-incorrect-dpm-level-after-suspend-.patch | 70 + ...x-incorrect-error-code-returned-for-.patch | 40 + ...-fix-memory-leak-in-amdxdna_ubuf_map.patch | 55 + ...dna-fix-notifier_wq-flushing-warning.patch | 39 + ...x-potential-null-pointer-dereference.patch | 134 + ...x-race-condition-when-checking-rpm_o.patch | 295 + ...x-race-where-send-ring-appears-full-.patch | 92 + ...ld-mm-structure-across-iommu_sva_unb.patch | 64 + ...ove-rpm-resume-into-job-run-function.patch | 103 + ...dxdna-remove-hardware-context-status.patch | 153 + ...op-job-scheduling-across-aie2_releas.patch | 54 + ...pdate-cpuidle-driver-check-in-__acpi.patch | 48 + ...pointer-dereference-in-acpi_ev_addre.patch | 40 + ...leak-of-newsk-in-unix_stream_connect.patch | 56 + ...fload-relax-__free-variable-declarat.patch | 132 + ...l-relax-__free-variable-declarations.patch | 199 + ...ction-names-missing-function-paramet.patch | 63 + ...a-relax-__free-variable-declarations.patch | 139 + .../alsa-oss-delete-self-assignment.patch | 36 + ...s-relax-__free-variable-declarations.patch | 268 + ...m-relax-__free-variable-declarations.patch | 268 + ...s-relax-__free-variable-declarations.patch | 267 + ...q-relax-__free-variable-declarations.patch | 769 +++ ...r-relax-__free-variable-declarations.patch | 81 + ...o-relax-__free-variable-declarations.patch | 284 + ...y-relax-__free-variable-declarations.patch | 99 + ...r-relax-__free-variable-declarations.patch | 77 + ...select-net_selftests-when-inet-is-di.patch | 42 + ...r-sun5i-a13-utoo-p66-delete-power-gp.patch | 46 + ...add-clocks-property-to-motor-control.patch | 35 + ...ut-__vdso_clock_getres-if-unavailabl.patch | 39 + ...gic-axg-assign-the-mmc-signal-clocks.patch | 52 + ...ogic-c3-assign-the-mmc-signal-clocks.patch | 53 + ...ic-g12-assign-the-mmc-a-signal-clock.patch | 42 + ...c-g12-assign-the-mmc-b-and-c-signal-.patch | 52 + ...ogic-gx-assign-the-mmc-signal-clocks.patch | 97 + ...c-meson-sm1-odroid-eliminate-odroid-.patch | 109 + ...logic-s4-assign-mmc-b-clock-to-24mhz.patch | 51 + ...-amlogic-s4-fix-mmc-clock-assignment.patch | 70 + ...95-use-gpu_cgc-as-core-clock-for-gpu.patch | 57 + ...ek-mt8183-jacuzzi-pico6-fix-typo-in-.patch | 36 + ...m-agatti-add-cx_mem-dbgc-gpu-regions.patch | 49 + ...sm8994-octagon-fix-analog-devices-ve.patch | 43 + ...rb4210-rb2-fix-uart3-wakeup-irq-stor.patch | 43 + ...s-qcom-sdm630-fix-gpu_speed_bin-size.patch | 49 + ...com-sdm845-db845c-drop-cs-from-spio0.patch | 40 + ...dm845-db845c-specify-power-for-wifi-.patch | 50 + ...dm845-oneplus-don-t-keep-panel-regul.patch | 39 + ...dm845-oneplus-don-t-mark-ts-supply-b.patch | 39 + ...dm845-oneplus-mark-l14a-regulator-as.patch | 38 + ...dm850-huawei-matebook-e-2019-correct.patch | 46 + ...dm850-huawei-matebook-e-2019-remove-.patch | 61 + ...m-sm6115-add-cx_mem-dbgc-gpu-regions.patch | 49 + ...m8150-hdk-mtp-specify-zap-firmware-n.patch | 58 + ...sm8250-hdk-specify-zap-firmware-name.patch | 42 + ...alos-drop-opp-shared-from-qup-opp-ta.patch | 43 + ...m-x1e-bus-is-40-bits-fix-64gb-models.patch | 42 + ...1e80100-fix-usb-combo-phys-ss1-and-s.patch | 61 + ...s-r9a09g047e57-smarc-remove-duplicat.patch | 34 + ...s-rzt2h-n2h-evk-common-use-gpio-for-.patch | 54 + ...am67a-kontron-sa67-base-fix-cma-node.patch | 38 + ...am67a-kontron-sa67-base-fix-sd-card-.patch | 36 + ...am69-aquila-clover-fix-usb-c-sink-pd.patch | 40 + ...3-am69-aquila-dev-fix-usb-c-sink-pdo.patch | 40 + ...j784s4-j742s2-main-common.dtsi-refac.patch | 125 + ...j784s4-main.dtsi-move-c71_3-node-to-.patch | 73 + ...pql-mba8mp-ras314-fix-hdmi-cec-pad-c.patch | 37 + ...pql-mba8mpxl-fix-hdmi-cec-pad-contro.patch | 36 + ...ror-handling-in-arch_set_shadow_stac.patch | 45 + ...x-resource-leak-in-cs4271_soc_resume.patch | 70 + ...cel-delayed-work-on-component-remove.patch | 72 + ...1-cancel-pending-work-before-suspend.patch | 46 + ...821-fixup-nau8821_enable_jack_detect.patch | 84 + ...ility-to-connect-sdca-jacks-to-asoc-.patch | 185 + ...sample-width-wild-cards-in-set_usage.patch | 39 + ...or-out-jack-handling-into-new-c-file.patch | 342 + ...a-handle-volatile-controls-correctly.patch | 108 + ...oc-sdca-remove-outdated-todo-comment.patch | 41 + ...process-most-of-the-jack-detect-if-c.patch | 130 + ...-add-ahub-writeable_reg-for-rx-holes.patch | 151 + ...ta_quirk_max_sec-and-convert-all-dev.patch | 203 + ...quirk-intel-ssdsc2kg480g8-max_sector.patch | 54 + ...ompat_xxx_class-extern-declarations-.patch | 77 + ...-charlcd-fix-release_mem_region-size.patch | 39 + ...6-fix-build-errors-caused-by-wrong-g.patch | 50 + ...led-change-pm8950-wled-configuration.patch | 42 + ...-wled-support-ovp-values-for-pmi8994.patch | 94 + ...c_pr_read_-ioctls-with-blk_open_read.patch | 146 + ...n-t-use-strcpy-to-copy-blockdev-name.patch | 43 + ...l_pcie-use-irqf_oneshot-and-default-.patch | 61 + ...nn-fix-using-conn-le_-tx-rx-_phy-as-.patch | 135 + ...-speed-duplex-to-unknown-if-getting-.patch | 74 + ...t-instance-and-backedges-accumulatio.patch | 76 + ..._store_bytes-proto-for-read-only-arg.patch | 60 + ...ry-access-flags-in-helper-prototypes.patch | 179 + ...it-detach-permissions-when-prog-fd-i.patch | 88 + ...ifier_bug_if-to-account-for-bpf_call.patch | 108 + ...bpf-limit-bpf-program-signature-size.patch | 48 + ...e-id-of-register-in-sync_linked_regs.patch | 95 + ...-frozen-map-for-calculating-map-hash.patch | 51 + ...r-address-for-non-zero-offsets-in-in.patch | 41 + ...bpf-sockmap-fix-fionread-for-sockmap.patch | 293 + ...fix-incorrect-copied_seq-calculation.patch | 178 + ...ock_group_tree-dirty_list-corruption.patch | 150 + ...-abort-due-to-non-consecutive-gaps-i.patch | 496 ++ ...urn-correct-error-when-deleting-qgro.patch | 43 + ...n-t-zone-append-to-conventional-zone.patch | 117 + ...se-is_err-for-filp_open-return-value.patch | 43 + ...composite-convert-from-owl_divider_h.patch | 49 + ...divider-convert-from-divider_round_r.patch | 84 + ...rt-from-divider_round_rate-to-divide.patch | 49 + ...kdivider-hi6220-convert-from-divider.patch | 49 + ...nvert-from-divider_round_rate-to-div.patch | 50 + ...-mfg_eb-as-parent-to-mt8196-mfgpll-c.patch | 101 + ...mediatek-drop-__initconst-from-gates.patch | 72 + ...x-error-handling-in-runtime-pm-setup.patch | 66 + ...eson-g12a-limit-the-hdmi-pll-od-to-4.patch | 86 + ...imit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch | 87 + ...re-remove-duplicate-determine_rate-o.patch | 65 + ...vert-from-divider_round_rate-to-divi.patch | 48 + ...ve-restore-_context-to-common_clk-se.patch | 117 + ...d1-divider-convert-from-divider_roun.patch | 50 + ...convert-from-divider_round_rate-to-d.patch | 51 + ...ll-convert-from-divider_round_rate-t.patch | 82 + ...sdm845-enable-parents-for-pixel-cloc.patch | 49 + ...sm7150-fix-dispcc_mdss_pclk1_clk_src.patch | 37 + ...mur-update-the-sdcc-rcgs-to-use-shar.patch | 51 + ...ipq5018-flag-sleep-clock-as-critical.patch | 37 + ...os-update-the-sdcc-rcgs-to-use-share.patch | 59 + ...8917-remove-always_on-flag-from-cpp_.patch | 39 + ...8953-remove-always_on-flag-from-cpp_.patch | 39 + ...1000-update-the-sdcc-rcgs-to-use-sha.patch | 51 + ...75-update-the-sdcc-rcgs-to-use-share.patch | 52 + ...450-update-the-sdcc-rcgs-to-use-shar.patch | 61 + ...450-update-the-sdcc-rcgs-to-use-shar.patch | 52 + ...c-sm8550-use-floor-ops-for-sdcc-rcgs.patch | 55 + ...c-sm8650-use-floor-ops-for-sdcc-rcgs.patch | 55 + ...750-update-the-sdcc-rcgs-to-use-shar.patch | 52 + ...80100-update-the-sdcc-rcgs-to-use-sh.patch | 50 + ...x3d-add-parent-to-parent-request-map.patch | 67 + ...mpute-2d-using-duty-fraction-directl.patch | 71 + ...divider-convert-from-divider_ro_roun.patch | 55 + ...divider-convert-from-divider_round_r.patch | 55 + ...correct-error-code-in-qcom_cc_probe_.patch | 42 + ...-clk_ops_parent_enable-during-recalc.patch | 69 + ...-error-pointer-check-after-rockchip_.patch | 39 + ...2-clkgen-convert-from-divider_round_.patch | 72 + ...pect-kconfig-setting-when-building-m.patch | 166 + ...vert-from-divider_round_rate-to-divi.patch | 49 + ...core-convert-from-divider_ro_round_r.patch | 72 + ...core-convert-from-divider_round_rate.patch | 77 + ...-ap-poll-for-pll-lock-and-wait-for-s.patch | 150 + ...convert-from-divider_round_rate-to-d.patch | 50 + ...ert-from-divider_round_rate-to-divid.patch | 49 + ...er-convert-from-divider_round_rate-t.patch | 48 + ...er-fix-zynqmp_clk_divider_determine_.patch | 44 + ...ix-zynqmp_clk_divider_determine_rate.patch | 44 + ...ers-timer-sp804-fix-an-oops-when-rea.patch | 90 + ...etm3x-fix-cpulocked-warning-on-cpuhp.patch | 67 + ...r-fix-race-condition-between-sysfs-a.patch | 97 + ...tate-enable-asym-capacity-only-when-.patch | 51 + ...pufreq-scmi-correct-scmi-explanation.patch | 37 + ...-device_node-reference-leak-in-scmi_.patch | 36 + ...s-menu-always-check-timers-with-tick.patch | 88 + ...netdev-memory-leak-in-dpaa2_caam_pro.patch | 145 + ...to-cavium-fix-dma_free_coherent-size.patch | 38 + .../crypto-ccp-add-an-s4-restore-flow.patch | 168 + ...re-psp-dead-if-psp_cmd_tee_ring_init.patch | 43 + ...r-out-ring-destroy-handling-to-a-hel.patch | 90 + ...-a-case-where-snp_shutdown-is-missed.patch | 110 + ...-crash-due-to-incorrect-cleanup-usag.patch | 43 + ...o-ccp-narrow-scope-of-snp_range_list.patch | 64 + ...psp_cmd_tee_ring_destroy-when-psp_cm.patch | 113 + ...-consolidate-qp-creation-and-start-i.patch | 356 ++ ...-hpre-extend-tag-field-to-64-bits-fo.patch | 340 + ...-hpre-support-the-hpre-algorithm-fal.patch | 527 ++ ...-qm-centralize-the-sending-locks-of-.patch | 143 + ...-qm-enhance-the-configuration-of-req.patch | 248 + ...-sec-move-backlog-management-to-qp-a.patch | 365 ++ ...-sec2-support-skcipher-aead-fallback.patch | 220 + ...-sgl-fix-inconsistent-map-unmap-dire.patch | 37 + ...-trng-support-tfms-sharing-the-devic.patch | 258 + ...-zip-adjust-the-way-to-obtain-the-re.patch | 128 + ...silicon-zip-support-fallback-for-zip.patch | 152 + ...cure-eip93-fix-kernel-panic-in-drive.patch | 37 + ...cure-eip93-unregister-only-available.patch | 164 + ...-octeontx-fix-dma_free_coherent-size.patch | 38 + ...arameter-order-used-in-icp_qat_fw_co.patch | 79 + ...t-fix-warning-on-adf_pfvf_pf_proto.c.patch | 63 + ...fix-memory-leak-in-starfive_aes_aead.patch | 60 + ...e-fix-cxl_dport-debugfs-einj-entries.patch | 61 + ...e-commit_end-increment-on-decoder-co.patch | 62 + ...ewline-character-in-dev_err-messages.patch | 52 + ...vm_cxl_memdev_edac_release-confusion.patch | 178 + ...move-branch-hint-after-code-refactor.patch | 59 + ...ix-unlocked-test-for-dm_suspended_md.patch | 56 + .../dm-use-bio_clone_blkg_association.patch | 44 + ...use-read_once-in-dm_blk_report_zones.patch | 36 + ...-fix-hw-scatter-gather-not-looking-a.patch | 51 + ...dma-axi-dmac-fix-sw-cyclic-transfers.patch | 57 + ...ma-don-t-explicitly-disable-clocks-i.patch | 61 + ...ek-uart-apdma-fix-above-4g-addressin.patch | 83 + ...unused-docs.sh-fixup-directory-usage.patch | 44 + ...i-endpoint-fix-ntb-vntb-copy-paste-e.patch | 82 + ...acing-add-pci-tracepoint-documentati.patch | 125 + ...fix-output-pin-phase-adjustment-sign.patch | 67 + ...bd-always-set-blk_feat_stable_writes.patch | 94 + ...050-use-dev_err_probe-for-regulator-.patch | 42 + ...play-don-t-repeat-dac-load-detection.patch | 49 + ...don-t-use-kernel-doc-comment-in-dc_r.patch | 41 + ...-pass-proper-dac-encoder-id-to-vbios.patch | 140 + ...-display-remove-unused-encoder-types.patch | 130 + ...update-dc_connection_dac_load-to-dc_.patch | 94 + ...use-local-variable-for-analog_engine.patch | 59 + ...gpu-kernel-modesetting-enabled-messa.patch | 40 + ...md-pm-fix-unneeded-semicolon-warning.patch | 39 + ...n-eopnotsupp-when-can-t-read-power-l.patch | 43 + ...ibe-amd_ip_block_type_ras-in-amd_ip_.patch | 38 + ...pu-don-t-attach-the-tlb-fence-for-si.patch | 43 + ...mmio_remap-domain-bit-and-keep-it-in.patch | 322 + ...in-4k-mmio_remap-singleton-bo-at-ini.patch | 100 + ...xplicit-vcn-instance-0-in-sr-iov-ini.patch | 179 + ...ignal_eviction_fence-bool-return-val.patch | 79 + ...rt-drm_atomic_get_-old-new-_colorop_.patch | 213 + ...e-free_trees-array-on-buddy-mm-teard.patch | 63 + ...dp_mst-add-protection-against-0-vcpi.patch | 97 + ...ilicon-hibmc-add-dp-mode-valid-check.patch | 115 + ...bmc-adding-reset-colorbar-cfg-in-dp-.patch | 42 + ...bmc-fix-dp-probabilistical-detect-er.patch | 219 + ...bmc-fix-no-showing-problem-with-load.patch | 56 + ...-do-not-include-headers-from-headers.patch | 57 + ...-fix-the-pixel-normalization-handlin.patch | 161 + ...-a2xx-fix-pixel-shader-start-on-a225.patch | 42 + ...p-dpu-add-merge3d-support-for-sc7280.patch | 83 + ...-num_planes-to-1-for-interleaved-yuv.patch | 61 + ...-division-by-zero-in-msm_dp_ctrl_con.patch | 90 + ...te-msm_dp_controller-ids-for-sa8775p.patch | 41 + ...-intr_start-from-dpu-3.x-catalog-fil.patch | 115 + ...sm-dpu-fix-cmd-panels-on-dpu-1.x-3.x.patch | 48 + ...sspp_ubwc_static_ctrl-programming-on.patch | 93 + ...dpu-fix-wd-timer-handling-on-dpu-8.x.patch | 198 + ...fset-hbb-values-written-to-dpu-by-13.patch | 68 + ...ram-correct-register-for-ubwc-config.patch | 109 + ...vsync-source-irrespective-of-mdp-top.patch | 68 + ...14nm-convert-from-divider_round_rate.patch | 55 + .../drm-msm-fix-gmem_base-for-gen8.patch | 39 + ...drm-msm-fix-x2-85-tpl1_dbg_eco_cntl1.patch | 37 + ...rect-hbb-programmed-on-ubwc-5.x-and-.patch | 41 + ...8-remove-manual-invocation-of-unprep.patch | 40 + ...r-evict-groups-before-vm-termination.patch | 90 + ...immediate-ticking-on-a-disabled-tick.patch | 61 + ...null-pointer-dereference-on-panthor_.patch | 47 + ...anthor-fix-panthor_gpu_coherency_set.patch | 57 + ...nthor-fix-queue_reset_timeout_locked.patch | 67 + .../drm-panthor-fix-the-full_tick-check.patch | 64 + ...ix-the-group-priority-rotation-logic.patch | 140 + ...the-logic-that-decides-when-to-stop-.patch | 130 + ...-sure-we-resume-the-tick-when-new-jo.patch | 109 + ...ver-from-panthor_gpu_flush_caches-fa.patch | 108 + ...ve-redundant-call-to-disable-the-mcu.patch | 36 + ..._err-vs-null-bug-drm_plane_create_co.patch | 41 + ...hdmi_qp-fix-rk3576-hpd-interrupt-han.patch | 54 + ...ulk_profile-sched_priority-descripti.patch | 41 + .../drm-xe-ptl-disable-dcc-on-ptl.patch | 87 + ...unregister-drm-device-on-probe-error.patch | 91 + .../edac-altera-remove-irqf_oneshot.patch | 74 + ...d64-avoid-a-wformat-security-warning.patch | 47 + ...nprintf-size-calculation-in-calculat.patch | 40 + ...nprintf-limit-calculation-in-calcula.patch | 49 + ...-noisy-messages-for-transient-enomem.patch | 54 + ...-data-read-failure-for-ztailpacking-.patch | 128 + ...-of-filesystem-properly-for-file-bac.patch | 64 + ...-format-specifier-for-error-pointers.patch | 40 + ...xattrs-list-to-calculate-hmac-in-evm.patch | 70 + ...t-commit-make-s_fc_lock-reclaim-safe.patch | 301 + ...parent-link-count-underflow-in-rmdir.patch | 74 + ...ix-a-memory-leak-in-au1200fb_drv_pro.patch | 43 + ..._timing-fix-device-node-reference-le.patch | 56 + ...-correct-32-bit-response-handling-in.patch | 119 + ...don-t-use-__free-in-cs_dsp_load-and-.patch | 74 + ...remove-__free-from-cs_dsp_debugfs_st.patch | 68 + ...fs-add-linux-init_task.h-for-init_fs.patch | 40 + ...ializing-f_mode-before-file_ref_init.patch | 56 + ...fs-fix-readdir-slow-start-regression.patch | 54 + ...op-duplicate-bprm_stack_limits-test-.patch | 48 + ...ve-ftrace_ops_fl_jmp-ftrace_ops-flag.patch | 175 + ...rqf_cond_oneshot-in-devm_request_irq.patch | 43 + ...-leaks-in-gfs2_fill_super-error-path.patch | 95 + ...s2-fix-slab-use-after-free-in-qd_put.patch | 45 + ...er-free-in-iomap-inline-data-write-p.patch | 84 + .../gfs2-initialize-bio-bi_opf-early.patch | 214 + ...s2-rename-gfs2_log_submit_-bio-write.patch | 90 + ...ies-missing-in-gfs2_-rename-exchange.patch | 178 + .../gpib-fix-error-code-in-ibonline.patch | 42 + ...error-code-in-ni_usb_write_registers.patch | 37 + .../gpib-fix-memory-leak-in-ni_usb_init.patch | 67 + ...re-check-for-overflow-to-dmatrfbase1.patch | 57 + ...rror-when-node-already-exists-in-hfs.patch | 58 + ...d-fix-null-ptr-deref-in-ishtp_bus_re.patch | 50 + ...d-intel-thc-fix-wrong-register-field.patch | 46 + ...add-missing-check-for-input_ff_creat.patch | 41 + ..._vfio_pci-fix-vf-reset-timeout-issue.patch | 93 + queue-6.19/hrtimer-fix-trace-oddity.patch | 43 + ...785-fix-vout_mode-mismatch-during-id.patch | 81 + .../hwrng-airoha-set-rng-quality-to-900.patch | 67 + ...cu-and-work_struct-to-fix-race-condi.patch | 446 ++ ...handle-devm_pm_runtime_enable-errors.patch | 44 + ...mory-leak-in-dw_i3c_master_i2c_xfers.patch | 45 + ...e-spinlock-to-avoid-upsetting-lockde.patch | 39 + ...update-hot-join-flag-only-on-success.patch | 39 + ...e-name-assignment-after-i3c_bus_init.patch | 46 + ...gid-cache-on-client-reregister-event.patch | 54 + ...ix-port-speed-query-for-representors.patch | 63 + ...ssure-mprls0025pa-fix-interrupt-flag.patch | 40 + ...mprls0025pa-fix-pressure-calculation.patch | 110 + ...ure-mprls0025pa-fix-scan_type-struct.patch | 47 + ...rls0025pa-fix-spi-cs-delay-violation.patch | 71 + ...ls0025pa-fix-spi_transfer-struct-ini.patch | 36 + ...fix-a-resource-leak-in-sca3000_probe.patch | 42 + ...ngling-symbol-in-gain-time-scale-hel.patch | 36 + ...t-of-bounds-in-is_bprm_creds_for_exe.patch | 196 + ...-using-ipproto_raw-must-drop-incomin.patch | 94 + ...dp5589-remove-a-leftover-header-file.patch | 217 + ...iatek-aggregate-bandwidth-with-satur.patch | 54 + ...-mediatek-don-t-hijack-parent-device.patch | 53 + ...m-qcs8300-fix-the-num_links-for-nsp-.patch | 47 + ...de-unionize-file-and-user_data-in-st.patch | 45 + ...ay-sqarray-static-branch-disablement.patch | 66 + ...-remove-unused-ctx-evfd_last_cq_tail.patch | 47 + ...x-memory-leak-if-io_buffer_add_list-.patch | 43 + ...uring-sync-validate-passed-in-offset.patch | 36 + ...ease-acquire-ordering-for-ioring_set.patch | 93 + ...id-folio-access-after-folio_end_read.patch | 165 + ...sion-side-handling-of-completion-sid.patch | 49 + ...re-s-primary-handler-and-set-irqf_on.patch | 95 + ...-present-bit-before-tearing-down-con.patch | 128 + ...-present-bit-before-tearing-down-pas.patch | 104 + ...ace-condition-during-pasid-entry-rep.patch | 365 ++ ...-cache-for-pasid-table-before-using-.patch | 55 + ...do-not-set-c-bit-on-mmio-backed-ptes.patch | 70 + ...ate-limit-unknown-xcvr-type-messages.patch | 51 + ...-capability-check-in-ipc_permissions.patch | 68 + ...lic-handle-number-of-hardware-interr.patch | 231 + ...logical-constant-out-of-range-compar.patch | 56 + ...ame-__bpf_address_lookup-to-bpf_addr.patch | 186 + ...set-module-buildid-in-ftrace_mod_add.patch | 100 + ...-expresswire-fix-chip-state-breakage.patch | 129 + ...eck-the-return-value-of-regmap_bulk_.patch | 55 + ...g-fix-bootparam_hung_task_panic-comm.patch | 51 + ...kstrtobool-docstring-to-mention-enab.patch | 44 + ...-read-in-btf_dump_get_bitfield_value.patch | 59 + .../mcb-fix-incorrect-sanity-check.patch | 62 + ...-initialise-event-handler-read-bytes.patch | 43 + ...md-fix-return-value-of-mddev_trylock.patch | 43 + ...ix-percpu_ref-not-resurrected-on-sus.patch | 47 + ...d-raid1-fix-memory-leak-in-raid1_run.patch | 46 + ...y_working-flag-handling-in-raid10_sy.patch | 47 + ...hang-with-degraded-array-with-llbitm.patch | 48 + ...d5_run-to-return-error-when-log_init.patch | 47 + ...commodate-c-phy-into-the-calculation.patch | 53 + ...a-wave5-fix-memory-leak-on-codec_inf.patch | 63 + .../media-pci-mg4b-use-irqf_no_thread.patch | 39 + ...fix-allocation-for-small-frame-sizes.patch | 57 + ...x-struct-intel_lb_component_ops-kern.patch | 46 + ...regulator-resource-leak-on-wm5102_cl.patch | 43 + ...sec-fix-irq-domain-names-duplication.patch | 43 + ...mfd-i2c-add-delta-tn48m-cpld-support.patch | 67 + .../mfd-wm8350-core-use-irqf_oneshot.patch | 48 + ...son32-drop-a-dangling-kconfig-symbol.patch | 36 + ...e-lockdep-warning-in-__kfree_rcu_she.patch | 130 + ...mc-increase-power-on-settling-delay-.patch | 40 + ...r-function-for-reading-module_buildi.patch | 80 + ...account-for-ooo-in-mptcp_rcvbuf_grow.patch | 63 + ...ceive-space-timestamp-initialization.patch | 92 + ...-accessing-regions-before-setting-nr.patch | 66 + ...memory-leak-in-mtd_parser_tplink_saf.patch | 42 + ...rt-fix-of-node-refcount-leak-in-pars.patch | 84 + ...nce-fix-return-type-of-cdma-send-and.patch | 40 + queue-6.19/mtd-spinand-fix-kernel-doc.patch | 36 + ...h-due-to-unvalidated-vcc-pointer-in-.patch | 154 + ...ouble-free-issue-for-tx-spare-buffer.patch | 74 + ...-fix-duplicate-reception-of-old-data.patch | 49 + ...tch-fix-forwarding-offload-statemach.patch | 73 + .../net-sunhme-fix-sbus-regression.patch | 73 + ...ncount-fix-tracking-of-connections-f.patch | 69 + ...ncount-increase-the-connection-clean.patch | 123 + ...les-reset-table-validation-state-on-.patch | 59 + ...ink_queue-do-shared-unconfirmed-chec.patch | 246 + ...ink_queue-optimize-verdict-lookup-wi.patch | 318 + ...mpat-add-more-restrictions-on-netlin.patch | 71 + ...unter-fix-reset-of-counters-on-32bit.patch | 75 + ...t_hash-fix-get-operation-on-big-endi.patch | 57 + ...t_rbtree-check-for-partial-overlaps-.patch | 90 + ...t_rbtree-don-t-gc-elements-on-insert.patch | 301 + ...t_rbtree-fix-bogus-eexist-with-nlm_f.patch | 80 + ..._set_rbtree-remove-seqcount_rwlock_t.patch | 63 + ...t_rbtree-translate-rbtree-to-array-f.patch | 508 ++ ...t_rbtree-use-binary-search-array-in-.patch | 198 + ...t_rbtree-validate-element-belonging-.patch | 294 + ...t_rbtree-validate-open-interval-over.patch | 308 + ...le-increment-of-retry_count-in-subre.patch | 38 + ...op-timers-and-work-before-freeing-co.patch | 52 + ...alio-handle-short-writes-by-retrying.patch | 121 + ...ent-direct-reclaim-recursion-into-nf.patch | 77 + ...ve-eagain-handling-in-nfs_local_doio.patch | 43 + ...gfp_noio-and-non-memreclaim-workqueu.patch | 80 + ...nfserr_inval-is-not-defined-by-nfsv2.patch | 78 + ...w-exporting-of-special-kernel-filesy.patch | 81 + ...r-defer-requests-during-idmap-lookup.patch | 152 + ...virtio_pmem-serialize-flush-requests.patch | 98 + ...an8855-drop-an-unused-kconfig-symbol.patch | 38 + ...cteon_ep-disable-per-ring-interrupts.patch | 119 + ...cteon_ep-ensure-dbell-baddr-updation.patch | 186 + ...on_ep_vf-ensure-dbell-baddr-updation.patch | 174 + ...-pf-driver-crash-with-kexec-kernel-b.patch | 62 + ...-unregister-devlink-on-probe-failure.patch | 36 + ...possible-null-pointer-dereferences-i.patch | 49 + ...orrect-value-in-dev_pm_opp_get_level.patch | 40 + ...vl-fix-uninit-value-in-ovl_fill_real.patch | 58 + ...86-xen-fix-balloon-target-initializa.patch | 140 + ...strict-program_hpx_type2-to-aer-bits.patch | 200 + ...k-for-pericom-pi7c9x2g404-switches-1.patch | 46 + ...g-capability-position-support-in-pci.patch | 236 + ...d-wq_percpu-to-alloc_workqueue-users.patch | 144 + ...-for-null-in-of_pci_bus_release_doma.patch | 42 + ...do-not-attempt-to-set-exttag-for-vfs.patch | 49 + ...apis-to-remove-standard-and-extended.patch | 111 + ...tise-dynamic-inbound-mapping-support.patch | 239 + ...er-pf-bar-and-inbound-atu-mapping-su.patch | 310 + ...c-ep-cache-msi-outbound-iatu-mapping.patch | 151 + ...esizable-bar-support-for-multi-pf-co.patch | 173 + ...rt-bar-subrange-inbound-mapping-via-.patch | 337 + ...uplicate-dw_pcie_ep_hide_ext_capabil.patch | 121 + ...int-add-bar-subrange-mapping-support.patch | 135 + ...-dynamic_inbound_mapping-epc-feature.patch | 56 + ...-missing-null-check-for-alloc_workqu.patch | 65 + ...ialize-rcb-from-pci_configure_device.patch | 90 + ...650sa-root-port-extended-tags-as-bro.patch | 56 + ...-irq-domain-leak-when-msi-allocation.patch | 45 + ...-p2pmem_alloc_mmap-warning-condition.patch | 52 + ...se-per-cpu-pgmap-ref-when-vm_insert_.patch | 42 + ...-page-reference-count-when-page-mapp.patch | 57 + ...oid-redundant-delays-on-d3hot-d3cold.patch | 56 + ...-portdrv-fix-potential-resource-leak.patch | 48 + ...-pcie_ptm_create_debugfs-memory-leak.patch | 55 + ...63-use-put_device-instead-of-i2c_put.patch | 57 + ...size-limit-from-bridge-window-sizing.patch | 117 + ...ridge-window-head-alignment-function.patch | 174 + ...ix-device-node-reference-leak-in-rzg.patch | 47 + ...se-pci_generic_config_write-for-the-.patch | 92 + ...kip-root-port-removal-during-success.patch | 49 + ...le-l0s-and-l1-on-sophgo-2044-pcie-ro.patch | 68 + ...p-over-estimating-bridge-window-size.patch | 173 + ...-intx-irq-domain-leak-in-error-paths.patch | 70 + ...pe-properly-set-hw.state-on-failures.patch | 108 + ...-not-set-bit-width-for-unavailable-c.patch | 46 + ...x8qm-hsio-fix-null-pointer-dereferen.patch | 41 + ...sung-hdptx-pre-compute-hdmi-pll-conf.patch | 62 + ...mote-when-pidfd_get_info-is-called-o.patch | 47 + ...230-fix-null-pointer-dereference-whe.patch | 76 + ...ium-fix-device-node-reference-leak-i.patch | 44 + ...logic-a4-fix-device-node-reference-l.patch | 57 + ...250-lpass-lpi-fix-i2s2_data_groups-d.patch | 38 + ...ix-refcount-leak-in-pcs_add_gpio_fun.patch | 50 + ...cros_ec_lightbar-fix-response-size-i.patch | 43 + ...cros_typec_switch-don-t-touch-struct.patch | 54 + ...-pmf-prevent-tee-errors-after-hibern.patch | 193 + ...wmi-fix-platform-profile-values-for-.patch | 306 + ...0002-remove-irqf_oneshot-from-reques.patch | 57 + ...-harden-dev_pm_clear_wake_irq-agains.patch | 65 + ...-empty-list-in-wakeup_sources_walk_s.patch | 44 + ...ng-wake-up-while-waiting-on-nfs_layo.patch | 61 + ...m-reboot-mode-respect-cell-size-for-.patch | 64 + ...500-fix-use-after-free-in-power_supp.patch | 104 + ...8945a-fix-use-after-free-in-power_su.patch | 77 + ...56xx-fix-use-after-free-in-power_sup.patch | 73 + ...5980-fix-use-after-free-in-power_sup.patch | 73 + ...7xxx-fix-wrong-errno-when-bus-ops-ar.patch | 61 + ...ap-battery-fix-use-after-free-in-pow.patch | 70 + ...dfish-fix-use-after-free-in-power_su.patch | 73 + ...550-fix-use-after-free-in-power_supp.patch | 94 + ...916_bms_vm-fix-use-after-free-in-pow.patch | 81 + ...916_lbc-fix-use-after-free-for-extco.patch | 67 + ...916_lbc-fix-use-after-free-in-power_.patch | 81 + ...m_battmgr-recognize-lip-as-lithium-p.patch | 42 + ...455-fix-use-after-free-in-power_supp.patch | 78 + ...-battery-fix-use-after-free-in-power.patch | 101 + ...7xx-fix-null-pointer-dereference-in-.patch | 98 + ...recursive-pci_lock_rescan_remove-loc.patch | 275 + ...move-barrier_nospec-out-of-allow_rea.patch | 98 + ...-remove-console_conditional_schedule.patch | 176 + ...ng-rcu-protection-when-reading-real_.patch | 59 + ...uffer-overflow-in-persistent_ram_sav.patch | 92 + ...ble-pwmchip-s-parent-device-before-s.patch | 69 + ...ck-between-quotactl-and-freeze_super.patch | 73 + ..._read_unlock-deadloop-due-to-softirq.patch | 168 + ...ctly-compute-probability-to-invoke-e.patch | 49 + ...rdma_rw_max_sge-helper-for-sq-sizing.patch | 159 + ...a-hns-fix-rocev1-failure-due-to-dscp.patch | 112 + .../rdma-hns-fix-wq_mem_reclaim-warning.patch | 62 + ...ulp-of-remaining-soft-wcs-during-res.patch | 70 + ...actual-error-code-instead-of-fixed-e.patch | 47 + ...rkqueue-list-corruption-by-removing-.patch | 206 + ...mory-leak-in-get_data_direct_sysfs_p.patch | 57 + .../rdma-mlx5-fix-ucaps-init-error-flow.patch | 52 + ...x-umr-hang-in-lag-error-state-unload.patch | 220 + .../rdma-rtrs-server-remove-dead-code.patch | 57 + queue-6.19/rdma-rtrs-srv-fix-sg-mapping.patch | 85 + ...fix-double-free-in-rxe_srq_from_init.patch | 67 + ...a-to-va-conversion-for-mr-page-sizes.patch | 553 ++ ...-race-condition-in-qp-timer-handlers.patch | 116 + ...__gfp_nowarn-to-ib_uverbs_unmarshall.patch | 39 + ...date-wqe_size-before-using-it-in-ib_.patch | 57 + ...on-t-ignore-errors-from-event-forwar.patch | 58 + ...ix-locking-in-regulator_resolve_supp.patch | 70 + ...ove-supply-check-earlier-in-set_mach.patch | 121 + ...sp_rproc-fix-multiple-start-stop-ope.patch | 128 + ...sp_rproc-only-reset-carveout-memory-.patch | 47 + ...proc-use-strstarts-for-rsc-table-che.patch | 44 + ...0-drop-of-dependency-and-enable-by-d.patch | 36 + ...pex-fix-use-after-free-in-high-low-s.patch | 89 + ...cc-support-mailbox-management-of-the.patch | 254 + ...pci_sdmmc-increase-power-on-settling.patch | 39 + ...rt-net-smc-introduce-tcp-ulp-support.patch | 195 + ...ophgo-cv180x-fix-usb-dwc2-fifo-sizes.patch | 51 + ...ver-side-setting-of-bi_size-for-spec.patch | 80 + ...fix-tas-fallback-lock-entry-creation.patch | 67 + .../rtc-amlogic-a4-remove-irqf_oneshot.patch | 45 + ...es-fix-race-condition-due-to-nesting.patch | 304 + ...-use-kernel-vertical-style-for-impor.patch | 119 + ...-potential-memory-leak-on-init-error.patch | 48 + ...estrict-task-group_leader-to-current.patch | 102 + ...ice-lifecycle-handling-in-css_alloc_.patch | 49 + ...ched-deadline-clear-the-defer-params.patch | 43 + ...export-hidden-tracepoints-to-modules.patch | 48 + ...for-modules-using-set_tsk_need_resch.patch | 44 + ...e-scheduling-when-migrating-queued-t.patch | 93 + ...rrently-executing-cpu-in-rto_next_cp.patch | 87 + ...r-fix-dereference-of-null-pointer-rn.patch | 46 + ...qf_oneshot-and-default-primary-handl.patch | 59 + ...x-memory-leak-in-pqi_report_phys_lun.patch | 72 + ...-ufs-host-mediatek-require-config_pm.patch | 116 + ...fix-kprobe-multi-stacktrace_ips-test.patch | 54 + ...x-resource-leak-in-serial_test_wq-on.patch | 60 + ...ristat-fix-printing-order-in-output_.patch | 46 + ...-faulting-in-code-in-pagemap_ioctl-t.patch | 80 + ...fix-usage-of-force_read-in-cow-tests.patch | 96 + ...l-fix-a-division-by-zero-error-on-hy.patch | 67 + ...x-number-of-tx-frags-in-invalid-pack.patch | 59 + ...operly-handle-batch-ending-in-the-mi.patch | 43 + ...k-fix-scoped_seqlock_read-kernel-doc.patch | 64 + ...use-after-free-in-caif_serial-ldisc_.patch | 152 + ...mx-change-serial_imx_console-to-bool.patch | 50 + ...al-sh_sci-improve-dma-support-prompt.patch | 39 + queue-6.19/series | 615 ++ ...ck-doi-accept-previously-used-values.patch | 233 + queue-6.19/smack-smack-doi-must-be-0.patch | 71 + ...ct-value-for-smbd_max_fragmented_rec.patch | 78 + ...otential-uaf-and-double-free-in-smb2.patch | 41 + ...-fix-memory-leak-in-svs_enable_debug.patch | 59 + ...use-devm_memremap-to-fix-memory-leak.patch | 53 + ...mem-handle-enomem-error-during-probe.patch | 39 + .../soc-qcom-ubwc-add-missing-include.patch | 37 + ...el_ace2x-add-snd_hda_core-dependency.patch | 45 + ...-remove-redundant-pm_runtime_mark_la.patch | 47 + ...re-use-xor-instead-of-andnot-to-fix-.patch | 46 + ...ols-add-include-folder-to-.gitignore.patch | 35 + ...ging-greybus-lights-avoid-null-deref.patch | 55 + ...tm-class-kconfig-correct-symbol-name.patch | 48 + ...e-unexpected-accecn-negotiation-feed.patch | 117 + ...168-fallback-identifier-for-cc-modul.patch | 135 + ...tiation-and-needs_accecn-identifiers.patch | 207 + ...timestamp-must-look-at-the-rtx-queue.patch | 44 + ...6_pkg_temp_thermal-handle-invalid-te.patch | 43 + ...eference-leak-in-thermal_of_cm_looku.patch | 46 + ...-use-access_private-to-evaluate-hrti.patch | 38 + ...ays-use-64-bit-mode-for-s390-header-.patch | 48 + ...intel-speed-select-fix-file-descript.patch | 50 + ...-missing-cleanup-on-get_burstcount-e.patch | 43 + ...neon-fix-locality-leak-on-get_burstc.patch | 44 + ...-process-error-handling-in-event_his.patch | 51 + ...uplicate-enable_event_str-and-disabl.patch | 44 + ...o-buf-unregister-refcount-optimizati.patch | 52 + ...once-to-read-struct-ublksrv_ctrl_cmd.patch | 194 + ...sqe128-flag-before-accessing-the-cmd.patch | 47 + ...-cap_sys_resource-using-ns_capable_n.patch | 51 + .../usb-bdc-fix-sleep-during-atomic.patch | 41 + ...sb-typec-fusb302-remove-irqf_oneshot.patch | 47 + ...c-ucsi-drop-an-unused-kconfig-symbol.patch | 40 + ...stream-bridge-for-vfio_pci_core_disa.patch | 74 + ..._printf-attributes-on-binary-printin.patch | 77 + ...e-wdt-fix-pm-reference-leak-in-probe.patch | 45 + ...-add-missing-lock-protection-in-ath1.patch | 62 + ...usecase-firmware-handling-based-on-d.patch | 101 + ...r-stale-link-mapping-of-ahvif-links_.patch | 68 + ...do-wow-offloads-only-on-primary-link.patch | 86 + ...index-decrement-when-array_len-is-ze.patch | 56 + .../wifi-ath9k-add-of-dependency-to-ahb.patch | 40 + ....h-fix-kernel-doc-bad-lines-and-stru.patch | 88 + ...ernel-doc-warnings-in-common-debug.h.patch | 60 + ...x-use_for-flag-update-on-bss-refresh.patch | 54 + ...1-stop-nan-and-p2p-in-cfg80211_leave.patch | 47 + ...ct-use-sequence-of-driver_data-in-sk.patch | 75 + ...-fix-memory-leak-in-__print_txpwr_ma.patch | 59 + ...s-rescuer-work-items-one-by-one-usin.patch | 202 + ...ect-the-microcode-table-for-zenbleed.patch | 84 + ...witch-kprobe_multi-program-stack-unw.patch | 111 + ...fix-return_to_handler-regs.rsp-value.patch | 66 + ...-smp_ops-build-failure-on-up-kernels.patch | 57 + ...t-prefix-for-typedef-types-in-progra.patch | 83 + ...e-data-pointer-for-zero-length-items.patch | 70 + ...en-remove-inclusion-of-nlm4.h-header.patch | 35 + ...-use-grant-dma-ops-when-running-as-d.patch | 45 + ...ug-race-in-icmp_route_lookup-reverse.patch | 100 + ...pointer-dereference-in-acpi_ev_addre.patch | 40 + ...r-sun5i-a13-utoo-p66-delete-power-gp.patch | 46 + ...add-clocks-property-to-motor-control.patch | 35 + ...set-motor-pwm-pwm-cells-property-val.patch | 47 + ...ut-__vdso_clock_getres-if-unavailabl.patch | 39 + ...gic-axg-assign-the-mmc-signal-clocks.patch | 52 + ...ic-g12-assign-the-mmc-a-signal-clock.patch | 42 + ...c-g12-assign-the-mmc-b-and-c-signal-.patch | 52 + ...ogic-gx-assign-the-mmc-signal-clocks.patch | 97 + ...s-qcom-sdm630-fix-gpu_speed_bin-size.patch | 49 + ...com-sdm845-db845c-drop-cs-from-spio0.patch | 40 + ...dm845-db845c-specify-power-for-wifi-.patch | 50 + ...dm845-oneplus-don-t-keep-panel-regul.patch | 39 + ...dm845-oneplus-don-t-mark-ts-supply-b.patch | 39 + ...dm845-oneplus-mark-l14a-regulator-as.patch | 38 + ...m-sm6115-add-cx_mem-dbgc-gpu-regions.patch | 49 + ...pql-mba8mpxl-fix-hdmi-cec-pad-contro.patch | 36 + ...id-unnecessary-blocking-in-irq-handl.patch | 121 + ...sistently-clear-interrupts-before-un.patch | 169 + ...821-fixup-nau8821_enable_jack_detect.patch | 84 + ...ompat_xxx_class-extern-declarations-.patch | 77 + ...-charlcd-fix-release_mem_region-size.patch | 39 + ...led-change-pm8950-wled-configuration.patch | 42 + ...-wled-support-ovp-values-for-pmi8994.patch | 94 + ...-speed-duplex-to-unknown-if-getting-.patch | 74 + ..._store_bytes-proto-for-read-only-arg.patch | 60 + ...bpf-sockmap-fix-fionread-for-sockmap.patch | 293 + ...fix-incorrect-copied_seq-calculation.patch | 178 + ...ock_group_tree-dirty_list-corruption.patch | 150 + ...urn-correct-error-when-deleting-qgro.patch | 43 + ...x-error-handling-in-runtime-pm-setup.patch | 66 + ...imit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch | 87 + ...ve-restore-_context-to-common_clk-se.patch | 117 + ...sdm845-enable-parents-for-pixel-cloc.patch | 49 + ...ipq5018-flag-sleep-clock-as-critical.patch | 37 + ...8917-remove-always_on-flag-from-cpp_.patch | 39 + ...8953-remove-always_on-flag-from-cpp_.patch | 39 + ...1000-update-the-sdcc-rcgs-to-use-sha.patch | 51 + ...75-update-the-sdcc-rcgs-to-use-share.patch | 52 + ...450-update-the-sdcc-rcgs-to-use-shar.patch | 52 + ...c-sm8550-use-floor-ops-for-sdcc-rcgs.patch | 55 + ...x3d-add-parent-to-parent-request-map.patch | 67 + ...mpute-2d-using-duty-fraction-directl.patch | 71 + ...correct-error-code-in-qcom_cc_probe_.patch | 42 + ...etm3x-fix-cpulocked-warning-on-cpuhp.patch | 67 + ...pufreq-scmi-correct-scmi-explanation.patch | 37 + ...s-menu-always-check-timers-with-tick.patch | 88 + ...e-menu-cleanup-after-loadavg-removal.patch | 60 + ...to-cavium-fix-dma_free_coherent-size.patch | 38 + .../crypto-ccp-add-an-s4-restore-flow.patch | 168 + ...r-out-ring-destroy-handling-to-a-hel.patch | 90 + ...direct-access-to-some-psp-registers-.patch | 357 ++ ...psp_cmd_tee_ring_destroy-when-psp_cm.patch | 113 + ...-sec2-support-skcipher-aead-fallback.patch | 220 + ...-trng-modifying-the-order-of-header-.patch | 56 + ...-trng-support-tfms-sharing-the-devic.patch | 258 + ...-zip-adjust-the-way-to-obtain-the-re.patch | 128 + ...o-hisilicon-zip-remove-zlib-and-gzip.patch | 489 ++ ...ilicon-zip-support-deflate-algorithm.patch | 192 + ...-octeontx-fix-dma_free_coherent-size.patch | 38 + ...t-fix-warning-on-adf_pfvf_pf_proto.c.patch | 63 + ...e-commit_end-increment-on-decoder-co.patch | 62 + .../dm-use-bio_clone_blkg_association.patch | 44 + ...dma-axi-dmac-fix-sw-cyclic-transfers.patch | 57 + ...ma-don-t-explicitly-disable-clocks-i.patch | 61 + ...ma-main-convert-to-platform-remove-c.patch | 68 + ...ek-uart-apdma-fix-above-4g-addressin.patch | 83 + ...-document-not-included-in-any-toctre.patch | 36 + ...i-endpoint-fix-ntb-vntb-copy-paste-e.patch | 82 + ...documentation-trace-refactor-toctree.patch | 156 + ...acing-add-pci-tracepoint-documentati.patch | 125 + ...tion-tracing-add-ring-buffer-mapping.patch | 151 + ...050-use-dev_err_probe-for-regulator-.patch | 42 + ...xplicit-vcn-instance-0-in-sr-iov-ini.patch | 179 + ...-a2xx-fix-pixel-shader-start-on-a225.patch | 42 + ...p-dpu-add-merge3d-support-for-sc7280.patch | 86 + ...sm-dpu-fix-cmd-panels-on-dpu-1.x-3.x.patch | 48 + .../edac-altera-remove-irqf_oneshot.patch | 74 + ...nprintf-size-calculation-in-calculat.patch | 40 + ...nprintf-limit-calculation-in-calcula.patch | 49 + ...parent-link-count-underflow-in-rmdir.patch | 74 + ...ix-a-memory-leak-in-au1200fb_drv_pro.patch | 43 + ..._timing-fix-device-node-reference-le.patch | 56 + ...fs-add-linux-init_task.h-for-init_fs.patch | 40 + ...fs-fix-readdir-slow-start-regression.patch | 54 + queue-6.6/gfs2-add-metapath_dibh-helper.patch | 48 + ...s2-fix-slab-use-after-free-in-qd_put.patch | 45 + ...er-free-in-iomap-inline-data-write-p.patch | 84 + ...ies-missing-in-gfs2_-rename-exchange.patch | 178 + ...rror-when-node-already-exists-in-hfs.patch | 58 + ...add-missing-check-for-input_ff_creat.patch | 41 + queue-6.6/hrtimer-fix-trace-oddity.patch | 43 + ...e-spinlock-to-avoid-upsetting-lockde.patch | 39 + ...update-hot-join-flag-only-on-success.patch | 39 + ...e-name-assignment-after-i3c_bus_init.patch | 46 + ...gid-cache-on-client-reregister-event.patch | 54 + ...ure-mprls0025pa-fix-scan_type-struct.patch | 47 + ...fix-a-resource-leak-in-sca3000_probe.patch | 42 + ...-using-ipproto_raw-must-drop-incomin.patch | 94 + ...de-unionize-file-and-user_data-in-st.patch | 45 + ...uring-sync-validate-passed-in-offset.patch | 36 + ...sion-side-handling-of-completion-sid.patch | 49 + ...-cache-for-pasid-table-before-using-.patch | 55 + ...ate-limit-unknown-xcvr-type-messages.patch | 51 + ...-capability-check-in-ipc_permissions.patch | 66 + ...set-module-buildid-in-ftrace_mod_add.patch | 100 + ...eck-the-return-value-of-regmap_bulk_.patch | 55 + ...-read-in-btf_dump_get_bitfield_value.patch | 59 + ...-initialise-event-handler-read-bytes.patch | 43 + ...y_working-flag-handling-in-raid10_sy.patch | 47 + ...commodate-c-phy-into-the-calculation.patch | 53 + ...fix-allocation-for-small-frame-sizes.patch | 57 + ...regulator-resource-leak-on-wm5102_cl.patch | 43 + ...2c-add-compatible-strings-for-layers.patch | 40 + ...mfd-i2c-add-delta-tn48m-cpld-support.patch | 67 + ...-simple-mfd-i2c-add-max77705-support.patch | 52 + ...mple-mfd-i2c-add-spacemit-p1-support.patch | 89 + ...2c-keep-compatible-strings-in-alphab.patch | 44 + .../mfd-wm8350-core-use-irqf_oneshot.patch | 48 + ...te-kernel-documentation-to-follow-th.patch | 145 + ...mc-increase-power-on-settling-delay-.patch | 40 + ...r-function-for-reading-module_buildi.patch | 80 + ...ceive-space-timestamp-initialization.patch | 92 + ...memory-leak-in-mtd_parser_tplink_saf.patch | 42 + ...rt-fix-of-node-refcount-leak-in-pars.patch | 84 + ...nce-fix-return-type-of-cdma-send-and.patch | 40 + queue-6.6/mtd-spinand-fix-kernel-doc.patch | 36 + ..._dstref_steal-and-skb_dstref_restore.patch | 73 + ...h-due-to-unvalidated-vcc-pointer-in-.patch | 154 + ...ouble-free-issue-for-tx-spare-buffer.patch | 74 + ...-fix-duplicate-reception-of-old-data.patch | 49 + .../net-sunhme-fix-sbus-regression.patch | 73 + ...b_dstref_steal-skb_dstref_restore-fo.patch | 75 + ...ncount-fix-tracking-of-connections-f.patch | 69 + ...ncount-increase-the-connection-clean.patch | 123 + ...ncount-make-nf_conncount_gc_list-to-.patch | 93 + ...les-reset-table-validation-state-on-.patch | 59 + ...mpat-add-more-restrictions-on-netlin.patch | 71 + ...unter-fix-reset-of-counters-on-32bit.patch | 75 + ...t_hash-fix-get-operation-on-big-endi.patch | 57 + ...t_rbtree-check-for-partial-overlaps-.patch | 90 + ...op-timers-and-work-before-freeing-co.patch | 52 + ...r-defer-requests-during-idmap-lookup.patch | 152 + ...virtio_pmem-serialize-flush-requests.patch | 98 + ...cteon_ep-disable-per-ring-interrupts.patch | 119 + ...cteon_ep-ensure-dbell-baddr-updation.patch | 186 + ...n_ep-restructured-interrupt-handlers.patch | 546 ++ ...backpressure-watermark-for-rx-queues.patch | 102 + ...teon_ep-support-octeon-cn10k-devices.patch | 1431 +++++ ...on_ep-support-to-fetch-firmware-info.patch | 251 + ...-pf-driver-crash-with-kexec-kernel-b.patch | 62 + ...-unregister-devlink-on-probe-failure.patch | 36 + ...possible-null-pointer-dereferences-i.patch | 49 + ...vl-fix-uninit-value-in-ovl_fill_real.patch | 58 + ...86-xen-fix-balloon-target-initializa.patch | 140 + ...strict-program_hpx_type2-to-aer-bits.patch | 200 + ...k-for-pericom-pi7c9x2g404-switches-1.patch | 46 + ...d-defines-for-bridge-window-indexing.patch | 69 + ..._msg_code_assert_intx-message-macros.patch | 62 + ...do-not-attempt-to-set-exttag-for-vfs.patch | 49 + ...ialize-rcb-from-pci_configure_device.patch | 90 + ...e-info-when-first-enumerating-bridge.patch | 100 + ...pci-log-bridge-windows-conditionally.patch | 94 + ...650sa-root-port-extended-tags-as-bro.patch | 56 + ...-irq-domain-leak-when-msi-allocation.patch | 45 + ...d_bridge_windows-below-individual-wi.patch | 143 + ...se-per-cpu-pgmap-ref-when-vm_insert_.patch | 42 + ...oid-redundant-delays-on-d3hot-d3cold.patch | 56 + ...-portdrv-fix-potential-resource-leak.patch | 48 + ...e-device-not-secondary-bus-to-read-w.patch | 119 + ...pe-properly-set-hw.state-on-failures.patch | 108 + ...ium-fix-device-node-reference-leak-i.patch | 44 + ...250-lpass-lpi-fix-i2s2_data_groups-d.patch | 38 + ...ix-refcount-leak-in-pcs_add_gpio_fun.patch | 50 + ...cros_ec_lightbar-fix-response-size-i.patch | 43 + ...cros_typec_switch-don-t-touch-struct.patch | 54 + ...-harden-dev_pm_clear_wake_irq-agains.patch | 65 + ...-empty-list-in-wakeup_sources_walk_s.patch | 44 + ...ng-wake-up-while-waiting-on-nfs_layo.patch | 61 + ...m-reboot-mode-respect-cell-size-for-.patch | 64 + ...500-fix-use-after-free-in-power_supp.patch | 104 + ...8945a-fix-use-after-free-in-power_su.patch | 77 + ...56xx-fix-use-after-free-in-power_sup.patch | 73 + ...5980-fix-use-after-free-in-power_sup.patch | 73 + ...7xxx-fix-wrong-errno-when-bus-ops-ar.patch | 61 + ...ap-battery-fix-use-after-free-in-pow.patch | 70 + ...dfish-fix-use-after-free-in-power_su.patch | 73 + ...m_battmgr-recognize-lip-as-lithium-p.patch | 42 + ...455-fix-use-after-free-in-power_supp.patch | 78 + ...-battery-fix-use-after-free-in-power.patch | 101 + ...7xx-fix-null-pointer-dereference-in-.patch | 98 + ...recursive-pci_lock_rescan_remove-loc.patch | 275 + ...move-barrier_nospec-out-of-allow_rea.patch | 98 + ...ng-rcu-protection-when-reading-real_.patch | 59 + ...uffer-overflow-in-persistent_ram_sav.patch | 92 + ...ck-between-quotactl-and-freeze_super.patch | 73 + ...edited-kthread-worker-creation-funct.patch | 148 + ..._read_unlock-deadloop-due-to-softirq.patch | 168 + ...edited-handling-check-in-rcu_read_un.patch | 139 + ..._irq_save-restore-in-rcu_preempt_def.patch | 55 + ...-s-boost_kthread_mutex-kthread_mutex.patch | 109 + ...rdma_rw_max_sge-helper-for-sq-sizing.patch | 159 + ...-couple-of-obvious-typos-in-comments.patch | 50 + .../rdma-hns-fix-wq_mem_reclaim-warning.patch | 62 + ...ulp-of-remaining-soft-wcs-during-res.patch | 70 + .../rdma-rtrs-server-remove-dead-code.patch | 57 + queue-6.6/rdma-rtrs-srv-fix-sg-mapping.patch | 85 + ...fix-double-free-in-rxe_srq_from_init.patch | 67 + ...-race-condition-in-qp-timer-handlers.patch | 116 + ...__gfp_nowarn-to-ib_uverbs_unmarshall.patch | 39 + ...date-wqe_size-before-using-it-in-ib_.patch | 57 + ...ove-supply-check-earlier-in-set_mach.patch | 121 + ...pex-fix-use-after-free-in-high-low-s.patch | 89 + ...pci_sdmmc-increase-power-on-settling.patch | 39 + ...ice-lifecycle-handling-in-css_alloc_.patch | 49 + ...rrently-executing-cpu-in-rto_next_cp.patch | 87 + ...r-fix-dereference-of-null-pointer-rn.patch | 46 + ...qf_oneshot-and-default-primary-handl.patch | 59 + ...x-memory-leak-in-pqi_report_phys_lun.patch | 72 + ...-ufs-host-mediatek-require-config_pm.patch | 116 + ...ristat-fix-printing-order-in-output_.patch | 46 + ...use-after-free-in-caif_serial-ldisc_.patch | 152 + ...mx-change-serial_imx_console-to-bool.patch | 50 + ...al-sh_sci-improve-dma-support-prompt.patch | 39 + queue-6.6/series | 255 + ...ck-doi-accept-previously-used-values.patch | 233 + queue-6.6/smack-smack-doi-must-be-0.patch | 71 + ...ct-value-for-smbd_max_fragmented_rec.patch | 78 + ...otential-uaf-and-double-free-in-smb2.patch | 41 + ...-fix-memory-leak-in-svs_enable_debug.patch | 59 + ...use-devm_memremap-to-fix-memory-leak.patch | 53 + ...mem-handle-enomem-error-during-probe.patch | 39 + ...ols-add-include-folder-to-.gitignore.patch | 35 + ...ging-greybus-lights-avoid-null-deref.patch | 55 + ...-clean-up-comment-in-svc_rdma_accept.patch | 64 + ...rease-the-per-transport-rw_ctx-count.patch | 73 + ...he-number-of-rdma_rw-contexts-per-qp.patch | 96 + ...dma-remove-queue-shortening-warnings.patch | 52 + ...timestamp-must-look-at-the-rtx-queue.patch | 44 + ...intel-speed-select-fix-file-descript.patch | 50 + ...-missing-cleanup-on-get_burstcount-e.patch | 43 + ...neon-fix-locality-leak-on-get_burstc.patch | 44 + ...-process-error-handling-in-event_his.patch | 51 + ...uplicate-enable_event_str-and-disabl.patch | 44 + ...sqe128-flag-before-accessing-the-cmd.patch | 47 + ...-cap_sys_resource-using-ns_capable_n.patch | 51 + .../usb-bdc-fix-sleep-during-atomic.patch | 41 + ...e-wdt-fix-pm-reference-leak-in-probe.patch | 45 + ...-add-missing-lock-protection-in-ath1.patch | 62 + ...1-stop-nan-and-p2p-in-cfg80211_leave.patch | 47 + ...queue-factor-out-assign_rescuer_work.patch | 78 + ...ssign-rescuer-work-when-really-neede.patch | 39 + ...s-rescuer-work-items-one-by-one-usin.patch | 202 + .../x86-xen-make-some-functions-static.patch | 89 + ...-use-grant-dma-ops-when-running-as-d.patch | 45 + ...ug-race-in-icmp_route_lookup-reverse.patch | 100 + 2229 files changed, 205124 insertions(+) create mode 100644 queue-5.10/arm-dts-allwinner-sun5i-a13-utoo-p66-delete-power-gp.patch create mode 100644 queue-5.10/arm-dts-lpc32xx-add-clocks-property-to-motor-control.patch create mode 100644 queue-5.10/arm-dts-lpc32xx-set-motor-pwm-pwm-cells-property-val.patch create mode 100644 queue-5.10/arm-vdso-patch-out-__vdso_clock_getres-if-unavailabl.patch create mode 100644 queue-5.10/arm64-dts-amlogic-axg-assign-the-mmc-signal-clocks.patch create mode 100644 queue-5.10/arm64-dts-amlogic-g12-assign-the-mmc-a-signal-clock.patch create mode 100644 queue-5.10/arm64-dts-amlogic-g12-assign-the-mmc-b-and-c-signal-.patch create mode 100644 queue-5.10/arm64-dts-amlogic-gx-assign-the-mmc-signal-clocks.patch create mode 100644 queue-5.10/arm64-dts-qcom-sdm630-add-qfprom-subnodes.patch create mode 100644 queue-5.10/arm64-dts-qcom-sdm630-correct-qfprom-byte-offsets.patch create mode 100644 queue-5.10/arm64-dts-qcom-sdm630-fix-gpu_speed_bin-size.patch create mode 100644 queue-5.10/arm64-dts-qcom-sdm845-db845c-specify-power-for-wifi-.patch create mode 100644 queue-5.10/auxdisplay-arm-charlcd-fix-release_mem_region-size.patch create mode 100644 queue-5.10/bonding-only-set-speed-duplex-to-unknown-if-getting-.patch create mode 100644 queue-5.10/btrfs-qgroup-return-correct-error-when-deleting-qgro.patch create mode 100644 queue-5.10/clk-meson-gxbb-limit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch create mode 100644 queue-5.10/clk-move-clk_-save-restore-_context-to-common_clk-se.patch create mode 100644 queue-5.10/clk-qcom-dispcc-sdm845-convert-to-parent-data.patch create mode 100644 queue-5.10/clk-qcom-dispcc-sdm845-enable-parents-for-pixel-cloc.patch create mode 100644 queue-5.10/clk-qcom-return-correct-error-code-in-qcom_cc_probe_.patch create mode 100644 queue-5.10/coresight-etm3x-fix-cpulocked-warning-on-cpuhp.patch create mode 100644 queue-5.10/cpufreq-scmi-correct-scmi-explanation.patch create mode 100644 queue-5.10/crypto-cavium-fix-dma_free_coherent-size.patch create mode 100644 queue-5.10/crypto-ccp-add-an-s4-restore-flow.patch create mode 100644 queue-5.10/crypto-octeontx-fix-dma_free_coherent-size.patch create mode 100644 queue-5.10/dma-dma-axi-dmac-fix-sw-cyclic-transfers.patch create mode 100644 queue-5.10/dmaengine-mediatek-uart-apdma-fix-above-4g-addressin.patch create mode 100644 queue-5.10/drivers-iio-mpu3050-use-dev_err_probe-for-regulator-.patch create mode 100644 queue-5.10/drm-amdgpu-use-explicit-vcn-instance-0-in-sr-iov-ini.patch create mode 100644 queue-5.10/edac-altera-remove-irqf_oneshot.patch create mode 100644 queue-5.10/edac-i5000-fix-snprintf-size-calculation-in-calculat.patch create mode 100644 queue-5.10/edac-i5400-fix-snprintf-limit-calculation-in-calcula.patch create mode 100644 queue-5.10/fat-avoid-parent-link-count-underflow-in-rmdir.patch create mode 100644 queue-5.10/fbdev-au1200fb-fix-a-memory-leak-in-au1200fb_drv_pro.patch create mode 100644 queue-5.10/fs-add-linux-init_task.h-for-init_fs.patch create mode 100644 queue-5.10/gfs2-add-metapath_dibh-helper.patch create mode 100644 queue-5.10/gfs2-add-new-gfs2_iomap_get-helper.patch create mode 100644 queue-5.10/gfs2-add-wrapper-for-iomap_file_buffered_write.patch create mode 100644 queue-5.10/gfs2-fix-use-after-free-in-iomap-inline-data-write-p.patch create mode 100644 queue-5.10/gfs2-move-the-inode-glock-locking-to-gfs2_file_buffe.patch create mode 100644 queue-5.10/gfs2-replace-gfs2_lblk_to_dblk-with-gfs2_get_extent.patch create mode 100644 queue-5.10/gfs2-turn-gfs2_extent_map-into-gfs2_-get-alloc-_exte.patch create mode 100644 queue-5.10/hfsplus-return-error-when-node-already-exists-in-hfs.patch create mode 100644 queue-5.10/hrtimer-fix-trace-oddity.patch create mode 100644 queue-5.10/i3c-move-device-name-assignment-after-i3c_bus_init.patch create mode 100644 queue-5.10/i3c-remove-i2c-board-info-from-i2c_dev_desc.patch create mode 100644 queue-5.10/iio-sca3000-fix-a-resource-leak-in-sca3000_probe.patch create mode 100644 queue-5.10/iomap-fix-submission-side-handling-of-completion-sid.patch create mode 100644 queue-5.10/iommu-vt-d-flush-cache-for-pasid-table-before-using-.patch create mode 100644 queue-5.10/ionic-rate-limit-unknown-xcvr-type-messages.patch create mode 100644 queue-5.10/md-raid10-fix-any_working-flag-handling-in-raid10_sy.patch create mode 100644 queue-5.10/mfd-arizona-fix-regulator-resource-leak-on-wm5102_cl.patch create mode 100644 queue-5.10/mfd-wm8350-core-use-irqf_oneshot.patch create mode 100644 queue-5.10/misc-rtsx-add-sd-express-mode-support-for-rts5261.patch create mode 100644 queue-5.10/mmc-core-initial-support-for-sd-express-card-host.patch create mode 100644 queue-5.10/mmc-rtsx_pci_sdmmc-increase-power-on-settling-delay-.patch create mode 100644 queue-5.10/mtd-rawnand-cadence-fix-return-type-of-cdma-send-and.patch create mode 100644 queue-5.10/net-atm-fix-crash-due-to-unvalidated-vcc-pointer-in-.patch create mode 100644 queue-5.10/netfilter-nf_conncount-fix-tracking-of-connections-f.patch create mode 100644 queue-5.10/netfilter-nf_conncount-increase-the-connection-clean.patch create mode 100644 queue-5.10/netfilter-nf_conncount-make-nf_conncount_gc_list-to-.patch create mode 100644 queue-5.10/netfilter-nft_set_hash-fix-get-operation-on-big-endi.patch create mode 100644 queue-5.10/netfilter-nft_set_rbtree-check-for-partial-overlaps-.patch create mode 100644 queue-5.10/nfsd-never-defer-requests-during-idmap-lookup.patch create mode 100644 queue-5.10/nvdimm-virtio_pmem-serialize-flush-requests.patch create mode 100644 queue-5.10/octeontx2-af-fix-pf-driver-crash-with-kexec-kernel-b.patch create mode 100644 queue-5.10/ovl-fix-uninit-value-in-ovl_fill_real.patch create mode 100644 queue-5.10/pci-do-not-attempt-to-set-exttag-for-vfs.patch create mode 100644 queue-5.10/pci-initialize-rcb-from-pci_configure_device.patch create mode 100644 queue-5.10/pci-mark-3ware-9650sa-root-port-extended-tags-as-bro.patch create mode 100644 queue-5.10/pci-mediatek-fix-irq-domain-leak-when-msi-allocation.patch create mode 100644 queue-5.10/pci-portdrv-fix-potential-resource-leak.patch create mode 100644 queue-5.10/pinctrl-equilibrium-fix-device-node-reference-leak-i.patch create mode 100644 queue-5.10/pinctrl-single-fix-refcount-leak-in-pcs_add_gpio_fun.patch create mode 100644 queue-5.10/platform-chrome-cros_ec_lightbar-fix-response-size-i.patch create mode 100644 queue-5.10/pm-core-add-new-_pm_ops-macros-deprecate-old-ones.patch create mode 100644 queue-5.10/pm-core-redefine-pm_ptr-macro.patch create mode 100644 queue-5.10/pm-sleep-wakeirq-harden-dev_pm_clear_wake_irq-agains.patch create mode 100644 queue-5.10/pm-wakeup-handle-empty-list-in-wakeup_sources_walk_s.patch create mode 100644 queue-5.10/pnfs-fix-a-missing-wake-up-while-waiting-on-nfs_layo.patch create mode 100644 queue-5.10/power-reset-nvmem-reboot-mode-respect-cell-size-for-.patch create mode 100644 queue-5.10/power-supply-act8945a-fix-use-after-free-in-power_su.patch create mode 100644 queue-5.10/power-supply-bq25980-fix-use-after-free-in-power_sup.patch create mode 100644 queue-5.10/power-supply-bq27xxx-fix-wrong-errno-when-bus-ops-ar.patch create mode 100644 queue-5.10/power-supply-cpcap-battery-fix-use-after-free-in-pow.patch create mode 100644 queue-5.10/power-supply-goldfish-fix-use-after-free-in-power_su.patch create mode 100644 queue-5.10/power-supply-rt9455-fix-use-after-free-in-power_supp.patch create mode 100644 queue-5.10/power-supply-sbs-battery-fix-use-after-free-in-power.patch create mode 100644 queue-5.10/power-supply-wm97xx-fix-null-pointer-dereference-in-.patch create mode 100644 queue-5.10/power-supply-wm97xx_battery-convert-to-gpio-descript.patch create mode 100644 queue-5.10/powerpc-eeh-fix-recursive-pci_lock_rescan_remove-loc.patch create mode 100644 queue-5.10/procfs-fix-missing-rcu-protection-when-reading-real_.patch create mode 100644 queue-5.10/pstore-ram-fix-buffer-overflow-in-persistent_ram_sav.patch create mode 100644 queue-5.10/rdma-core-add-rdma_rw_max_sge-helper-for-sq-sizing.patch create mode 100644 queue-5.10/rdma-core-fix-a-couple-of-obvious-typos-in-comments.patch create mode 100644 queue-5.10/rdma-rtrs-server-remove-dead-code.patch create mode 100644 queue-5.10/rdma-rxe-fix-double-free-in-rxe_srq_from_init.patch create mode 100644 queue-5.10/rdma-uverbs-add-__gfp_nowarn-to-ib_uverbs_unmarshall.patch create mode 100644 queue-5.10/rdma-uverbs-validate-wqe_size-before-using-it-in-ib_.patch create mode 100644 queue-5.10/regulator-core-fix-off-on-delay-us-for-always-on-boo.patch create mode 100644 queue-5.10/regulator-core-fix-off_on_delay-handling.patch create mode 100644 queue-5.10/regulator-core-move-supply-check-earlier-in-set_mach.patch create mode 100644 queue-5.10/regulator-core-respect-off_on_delay-at-startup.patch create mode 100644 queue-5.10/regulator-core-shorten-off-on-delay-us-for-always-on.patch create mode 100644 queue-5.10/regulator-core-use-ktime_get_boottime-to-determine-h.patch create mode 100644 queue-5.10/regulator-flag-uncontrollable-regulators-as-always_o.patch create mode 100644 queue-5.10/revert-hwmon-ibmpex-fix-use-after-free-in-high-low-s.patch create mode 100644 queue-5.10/revert-mmc-rtsx_pci_sdmmc-increase-power-on-settling.patch create mode 100644 queue-5.10/s390-cio-fix-device-lifecycle-handling-in-css_alloc_.patch create mode 100644 queue-5.10/sched-rt-skip-currently-executing-cpu-in-rto_next_cp.patch create mode 100644 queue-5.10/scsi-csiostor-fix-dereference-of-null-pointer-rn.patch create mode 100644 queue-5.10/serial-caif-fix-use-after-free-in-caif_serial-ldisc_.patch create mode 100644 queue-5.10/serial-imx-change-serial_imx_console-to-bool.patch create mode 100644 queue-5.10/serial-sh_sci-improve-dma-support-prompt.patch create mode 100644 queue-5.10/smack-smack-doi-accept-previously-used-values.patch create mode 100644 queue-5.10/smack-smack-doi-must-be-0.patch create mode 100644 queue-5.10/soc-qcom-cmd-db-use-devm_memremap-to-fix-memory-leak.patch create mode 100644 queue-5.10/spi-tools-add-include-folder-to-.gitignore.patch create mode 100644 queue-5.10/staging-greybus-lights-avoid-null-deref.patch create mode 100644 queue-5.10/svcrdma-add-a-batch-receive-posting-mechanism.patch create mode 100644 queue-5.10/svcrdma-clean-up-comment-in-svc_rdma_accept.patch create mode 100644 queue-5.10/svcrdma-increase-the-per-transport-rw_ctx-count.patch create mode 100644 queue-5.10/svcrdma-maintain-a-receive-water-mark.patch create mode 100644 queue-5.10/svcrdma-reduce-the-number-of-rdma_rw-contexts-per-qp.patch create mode 100644 queue-5.10/svcrdma-remove-queue-shortening-warnings.patch create mode 100644 queue-5.10/svcrdma-use-svc_rdma_refresh_recvs-in-wc_receive.patch create mode 100644 queue-5.10/tcp-tcp_tx_timestamp-must-look-at-the-rtx-queue.patch create mode 100644 queue-5.10/tpm-st33zp24-fix-missing-cleanup-on-get_burstcount-e.patch create mode 100644 queue-5.10/tpm-tpm_i2c_infineon-fix-locality-leak-on-get_burstc.patch create mode 100644 queue-5.10/tracing-remove-duplicate-enable_event_str-and-disabl.patch create mode 100644 queue-5.10/ucount-check-for-cap_sys_resource-using-ns_capable_n.patch create mode 100644 queue-5.10/usb-bdc-fix-sleep-during-atomic.patch create mode 100644 queue-5.10/wifi-ath10k-sdio-add-missing-lock-protection-in-ath1.patch create mode 100644 queue-5.10/wifi-cfg80211-stop-nan-and-p2p-in-cfg80211_leave.patch create mode 100644 queue-5.15/arm-dts-allwinner-sun5i-a13-utoo-p66-delete-power-gp.patch create mode 100644 queue-5.15/arm-dts-lpc32xx-add-clocks-property-to-motor-control.patch create mode 100644 queue-5.15/arm-dts-lpc32xx-set-motor-pwm-pwm-cells-property-val.patch create mode 100644 queue-5.15/arm-vdso-patch-out-__vdso_clock_getres-if-unavailabl.patch create mode 100644 queue-5.15/arm64-dts-amlogic-axg-assign-the-mmc-signal-clocks.patch create mode 100644 queue-5.15/arm64-dts-amlogic-g12-assign-the-mmc-a-signal-clock.patch create mode 100644 queue-5.15/arm64-dts-amlogic-g12-assign-the-mmc-b-and-c-signal-.patch create mode 100644 queue-5.15/arm64-dts-amlogic-gx-assign-the-mmc-signal-clocks.patch create mode 100644 queue-5.15/arm64-dts-qcom-sdm630-correct-qfprom-byte-offsets.patch create mode 100644 queue-5.15/arm64-dts-qcom-sdm630-fix-gpu_speed_bin-size.patch create mode 100644 queue-5.15/arm64-dts-qcom-sdm845-db845c-specify-power-for-wifi-.patch create mode 100644 queue-5.15/arm64-dts-qcom-sdm845-oneplus-don-t-keep-panel-regul.patch create mode 100644 queue-5.15/arm64-dts-qcom-sdm845-oneplus-don-t-mark-ts-supply-b.patch create mode 100644 queue-5.15/arm64-dts-qcom-sdm845-oneplus-mark-l14a-regulator-as.patch create mode 100644 queue-5.15/auxdisplay-arm-charlcd-fix-release_mem_region-size.patch create mode 100644 queue-5.15/backlight-qcom-wled-support-ovp-values-for-pmi8994.patch create mode 100644 queue-5.15/bonding-only-set-speed-duplex-to-unknown-if-getting-.patch create mode 100644 queue-5.15/btrfs-qgroup-return-correct-error-when-deleting-qgro.patch create mode 100644 queue-5.15/clk-meson-gxbb-limit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch create mode 100644 queue-5.15/clk-move-clk_-save-restore-_context-to-common_clk-se.patch create mode 100644 queue-5.15/clk-qcom-dispcc-sdm845-enable-parents-for-pixel-cloc.patch create mode 100644 queue-5.15/clk-qcom-gcc-msm8953-remove-always_on-flag-from-cpp_.patch create mode 100644 queue-5.15/clk-qcom-rcg2-compute-2d-using-duty-fraction-directl.patch create mode 100644 queue-5.15/clk-qcom-return-correct-error-code-in-qcom_cc_probe_.patch create mode 100644 queue-5.15/coresight-etm3x-fix-cpulocked-warning-on-cpuhp.patch create mode 100644 queue-5.15/cpufreq-scmi-correct-scmi-explanation.patch create mode 100644 queue-5.15/crypto-cavium-fix-dma_free_coherent-size.patch create mode 100644 queue-5.15/crypto-ccp-add-an-s4-restore-flow.patch create mode 100644 queue-5.15/crypto-hisilicon-trng-modifying-the-order-of-header-.patch create mode 100644 queue-5.15/crypto-hisilicon-trng-support-tfms-sharing-the-devic.patch create mode 100644 queue-5.15/crypto-octeontx-fix-dma_free_coherent-size.patch create mode 100644 queue-5.15/dma-dma-axi-dmac-fix-sw-cyclic-transfers.patch create mode 100644 queue-5.15/dmaengine-mediatek-uart-apdma-fix-above-4g-addressin.patch create mode 100644 queue-5.15/drivers-iio-mpu3050-use-dev_err_probe-for-regulator-.patch create mode 100644 queue-5.15/drm-amdgpu-use-explicit-vcn-instance-0-in-sr-iov-ini.patch create mode 100644 queue-5.15/edac-altera-remove-irqf_oneshot.patch create mode 100644 queue-5.15/edac-i5000-fix-snprintf-size-calculation-in-calculat.patch create mode 100644 queue-5.15/edac-i5400-fix-snprintf-limit-calculation-in-calcula.patch create mode 100644 queue-5.15/ethtool-add-support-to-set-get-tx-copybreak-buf-size.patch create mode 100644 queue-5.15/fat-avoid-parent-link-count-underflow-in-rmdir.patch create mode 100644 queue-5.15/fbdev-au1200fb-fix-a-memory-leak-in-au1200fb_drv_pro.patch create mode 100644 queue-5.15/fs-add-linux-init_task.h-for-init_fs.patch create mode 100644 queue-5.15/gfs2-add-metapath_dibh-helper.patch create mode 100644 queue-5.15/gfs2-fix-use-after-free-in-iomap-inline-data-write-p.patch create mode 100644 queue-5.15/hfsplus-return-error-when-node-already-exists-in-hfs.patch create mode 100644 queue-5.15/hid-playstation-add-missing-check-for-input_ff_creat.patch create mode 100644 queue-5.15/hrtimer-fix-trace-oddity.patch create mode 100644 queue-5.15/i3c-move-device-name-assignment-after-i3c_bus_init.patch create mode 100644 queue-5.15/i3c-remove-i2c-board-info-from-i2c_dev_desc.patch create mode 100644 queue-5.15/ib-cache-update-gid-cache-on-client-reregister-event.patch create mode 100644 queue-5.15/iio-sca3000-fix-a-resource-leak-in-sca3000_probe.patch create mode 100644 queue-5.15/iomap-fix-submission-side-handling-of-completion-sid.patch create mode 100644 queue-5.15/iommu-vt-d-flush-cache-for-pasid-table-before-using-.patch create mode 100644 queue-5.15/ionic-rate-limit-unknown-xcvr-type-messages.patch create mode 100644 queue-5.15/libbpf-fix-dumping-big-endian-bitfields.patch create mode 100644 queue-5.15/libbpf-fix-oob-read-in-btf_dump_get_bitfield_value.patch create mode 100644 queue-5.15/md-raid10-fix-any_working-flag-handling-in-raid10_sy.patch create mode 100644 queue-5.15/media-ccs-accommodate-c-phy-into-the-calculation.patch create mode 100644 queue-5.15/media-uvcvideo-fix-allocation-for-small-frame-sizes.patch create mode 100644 queue-5.15/mfd-arizona-fix-regulator-resource-leak-on-wm5102_cl.patch create mode 100644 queue-5.15/mfd-wm8350-core-use-irqf_oneshot.patch create mode 100644 queue-5.15/mmc-rtsx_pci_sdmmc-increase-power-on-settling-delay-.patch create mode 100644 queue-5.15/mtd-parsers-ofpart-fix-of-node-refcount-leak-in-pars.patch create mode 100644 queue-5.15/mtd-rawnand-cadence-fix-return-type-of-cdma-send-and.patch create mode 100644 queue-5.15/net-atm-fix-crash-due-to-unvalidated-vcc-pointer-in-.patch create mode 100644 queue-5.15/net-hns3-add-max-order-judgement-for-tx-spare-buffer.patch create mode 100644 queue-5.15/net-hns3-add-support-to-set-get-tx-copybreak-buf-siz.patch create mode 100644 queue-5.15/net-hns3-fix-double-free-issue-for-tx-spare-buffer.patch create mode 100644 queue-5.15/net-hns3-fix-ethtool-tx-copybreak-buf-size-indicatin.patch create mode 100644 queue-5.15/net-hns3-remove-the-way-to-set-tx-spare-buf-via-modu.patch create mode 100644 queue-5.15/netfilter-nf_conncount-fix-tracking-of-connections-f.patch create mode 100644 queue-5.15/netfilter-nf_conncount-increase-the-connection-clean.patch create mode 100644 queue-5.15/netfilter-nf_conncount-make-nf_conncount_gc_list-to-.patch create mode 100644 queue-5.15/netfilter-nft_set_hash-fix-get-operation-on-big-endi.patch create mode 100644 queue-5.15/netfilter-nft_set_rbtree-check-for-partial-overlaps-.patch create mode 100644 queue-5.15/nfc-hci-shdlc-stop-timers-and-work-before-freeing-co.patch create mode 100644 queue-5.15/nfsd-never-defer-requests-during-idmap-lookup.patch create mode 100644 queue-5.15/nvdimm-virtio_pmem-serialize-flush-requests.patch create mode 100644 queue-5.15/octeontx2-af-fix-pf-driver-crash-with-kexec-kernel-b.patch create mode 100644 queue-5.15/octeontx2-pf-unregister-devlink-on-probe-failure.patch create mode 100644 queue-5.15/ovl-fix-uninit-value-in-ovl_fill_real.patch create mode 100644 queue-5.15/pci-do-not-attempt-to-set-exttag-for-vfs.patch create mode 100644 queue-5.15/pci-initialize-rcb-from-pci_configure_device.patch create mode 100644 queue-5.15/pci-mark-3ware-9650sa-root-port-extended-tags-as-bro.patch create mode 100644 queue-5.15/pci-mediatek-fix-irq-domain-leak-when-msi-allocation.patch create mode 100644 queue-5.15/pci-portdrv-fix-potential-resource-leak.patch create mode 100644 queue-5.15/pinctrl-equilibrium-fix-device-node-reference-leak-i.patch create mode 100644 queue-5.15/pinctrl-qcom-extract-chip-specific-lpass-lpi-code.patch create mode 100644 queue-5.15/pinctrl-qcom-sm8250-lpass-lpi-fix-i2s2_data_groups-d.patch create mode 100644 queue-5.15/pinctrl-qcom-update-lpi-pin-group-custiom-functions-.patch create mode 100644 queue-5.15/pinctrl-qcom-update-macro-name-to-lpi-specific.patch create mode 100644 queue-5.15/pinctrl-single-fix-refcount-leak-in-pcs_add_gpio_fun.patch create mode 100644 queue-5.15/platform-chrome-cros_ec_lightbar-fix-response-size-i.patch create mode 100644 queue-5.15/pm-sleep-wakeirq-harden-dev_pm_clear_wake_irq-agains.patch create mode 100644 queue-5.15/pm-wakeup-handle-empty-list-in-wakeup_sources_walk_s.patch create mode 100644 queue-5.15/pnfs-fix-a-missing-wake-up-while-waiting-on-nfs_layo.patch create mode 100644 queue-5.15/power-reset-nvmem-reboot-mode-respect-cell-size-for-.patch create mode 100644 queue-5.15/power-supply-ab8500-fix-use-after-free-in-power_supp.patch create mode 100644 queue-5.15/power-supply-ab8500-use-core-battery-parser.patch create mode 100644 queue-5.15/power-supply-ab8500_bmdata-use-standard-phandle.patch create mode 100644 queue-5.15/power-supply-act8945a-fix-use-after-free-in-power_su.patch create mode 100644 queue-5.15/power-supply-bq256xx-fix-use-after-free-in-power_sup.patch create mode 100644 queue-5.15/power-supply-bq25980-fix-use-after-free-in-power_sup.patch create mode 100644 queue-5.15/power-supply-bq27xxx-fix-wrong-errno-when-bus-ops-ar.patch create mode 100644 queue-5.15/power-supply-cpcap-battery-fix-use-after-free-in-pow.patch create mode 100644 queue-5.15/power-supply-goldfish-fix-use-after-free-in-power_su.patch create mode 100644 queue-5.15/power-supply-rt9455-fix-use-after-free-in-power_supp.patch create mode 100644 queue-5.15/power-supply-sbs-battery-fix-use-after-free-in-power.patch create mode 100644 queue-5.15/power-supply-wm97xx-fix-null-pointer-dereference-in-.patch create mode 100644 queue-5.15/powerpc-eeh-fix-recursive-pci_lock_rescan_remove-loc.patch create mode 100644 queue-5.15/powerpc-uaccess-move-barrier_nospec-out-of-allow_rea.patch create mode 100644 queue-5.15/procfs-fix-missing-rcu-protection-when-reading-real_.patch create mode 100644 queue-5.15/pstore-ram-fix-buffer-overflow-in-persistent_ram_sav.patch create mode 100644 queue-5.15/rdma-core-add-rdma_rw_max_sge-helper-for-sq-sizing.patch create mode 100644 queue-5.15/rdma-core-fix-a-couple-of-obvious-typos-in-comments.patch create mode 100644 queue-5.15/rdma-hns-notify-ulp-of-remaining-soft-wcs-during-res.patch create mode 100644 queue-5.15/rdma-rtrs-server-remove-dead-code.patch create mode 100644 queue-5.15/rdma-rtrs-srv-correct-the-checking-of-ib_map_mr_sg.patch create mode 100644 queue-5.15/rdma-rtrs-srv-fix-sg-mapping.patch create mode 100644 queue-5.15/rdma-rtrs-srv-refactor-the-handling-of-failure-case-.patch create mode 100644 queue-5.15/rdma-rxe-fix-double-free-in-rxe_srq_from_init.patch create mode 100644 queue-5.15/rdma-uverbs-add-__gfp_nowarn-to-ib_uverbs_unmarshall.patch create mode 100644 queue-5.15/rdma-uverbs-validate-wqe_size-before-using-it-in-ib_.patch create mode 100644 queue-5.15/regulator-core-move-supply-check-earlier-in-set_mach.patch create mode 100644 queue-5.15/revert-mmc-rtsx_pci_sdmmc-increase-power-on-settling.patch create mode 100644 queue-5.15/s390-cio-fix-device-lifecycle-handling-in-css_alloc_.patch create mode 100644 queue-5.15/sched-rt-skip-currently-executing-cpu-in-rto_next_cp.patch create mode 100644 queue-5.15/scsi-csiostor-fix-dereference-of-null-pointer-rn.patch create mode 100644 queue-5.15/scsi-efct-use-irqf_oneshot-and-default-primary-handl.patch create mode 100644 queue-5.15/serial-caif-fix-use-after-free-in-caif_serial-ldisc_.patch create mode 100644 queue-5.15/serial-imx-change-serial_imx_console-to-bool.patch create mode 100644 queue-5.15/serial-sh_sci-improve-dma-support-prompt.patch create mode 100644 queue-5.15/smack-smack-doi-accept-previously-used-values.patch create mode 100644 queue-5.15/smack-smack-doi-must-be-0.patch create mode 100644 queue-5.15/soc-qcom-cmd-db-use-devm_memremap-to-fix-memory-leak.patch create mode 100644 queue-5.15/spi-tools-add-include-folder-to-.gitignore.patch create mode 100644 queue-5.15/staging-greybus-lights-avoid-null-deref.patch create mode 100644 queue-5.15/svcrdma-clean-up-comment-in-svc_rdma_accept.patch create mode 100644 queue-5.15/svcrdma-increase-the-per-transport-rw_ctx-count.patch create mode 100644 queue-5.15/svcrdma-reduce-the-number-of-rdma_rw-contexts-per-qp.patch create mode 100644 queue-5.15/svcrdma-remove-queue-shortening-warnings.patch create mode 100644 queue-5.15/tcp-tcp_tx_timestamp-must-look-at-the-rtx-queue.patch create mode 100644 queue-5.15/timers-replace-in_irq-with-in_hardirq.patch create mode 100644 queue-5.15/tpm-st33zp24-fix-missing-cleanup-on-get_burstcount-e.patch create mode 100644 queue-5.15/tpm-tpm_i2c_infineon-fix-locality-leak-on-get_burstc.patch create mode 100644 queue-5.15/tracing-remove-duplicate-enable_event_str-and-disabl.patch create mode 100644 queue-5.15/ucount-check-for-cap_sys_resource-using-ns_capable_n.patch create mode 100644 queue-5.15/usb-bdc-fix-sleep-during-atomic.patch create mode 100644 queue-5.15/wifi-ath10k-sdio-add-missing-lock-protection-in-ath1.patch create mode 100644 queue-5.15/wifi-cfg80211-stop-nan-and-p2p-in-cfg80211_leave.patch create mode 100644 queue-6.1/acpica-fix-null-pointer-dereference-in-acpi_ev_addre.patch create mode 100644 queue-6.1/arm-dts-allwinner-sun5i-a13-utoo-p66-delete-power-gp.patch create mode 100644 queue-6.1/arm-dts-lpc32xx-add-clocks-property-to-motor-control.patch create mode 100644 queue-6.1/arm-dts-lpc32xx-set-motor-pwm-pwm-cells-property-val.patch create mode 100644 queue-6.1/arm-vdso-patch-out-__vdso_clock_getres-if-unavailabl.patch create mode 100644 queue-6.1/arm64-dts-amlogic-axg-assign-the-mmc-signal-clocks.patch create mode 100644 queue-6.1/arm64-dts-amlogic-g12-assign-the-mmc-a-signal-clock.patch create mode 100644 queue-6.1/arm64-dts-amlogic-g12-assign-the-mmc-b-and-c-signal-.patch create mode 100644 queue-6.1/arm64-dts-amlogic-gx-assign-the-mmc-signal-clocks.patch create mode 100644 queue-6.1/arm64-dts-qcom-sdm630-fix-gpu_speed_bin-size.patch create mode 100644 queue-6.1/arm64-dts-qcom-sdm845-db845c-drop-cs-from-spio0.patch create mode 100644 queue-6.1/arm64-dts-qcom-sdm845-db845c-specify-power-for-wifi-.patch create mode 100644 queue-6.1/arm64-dts-qcom-sdm845-oneplus-don-t-keep-panel-regul.patch create mode 100644 queue-6.1/arm64-dts-qcom-sdm845-oneplus-don-t-mark-ts-supply-b.patch create mode 100644 queue-6.1/arm64-dts-qcom-sdm845-oneplus-mark-l14a-regulator-as.patch create mode 100644 queue-6.1/arm64-dts-tqma8mpql-mba8mpxl-fix-hdmi-cec-pad-contro.patch create mode 100644 queue-6.1/asoc-nau8821-avoid-unnecessary-blocking-in-irq-handl.patch create mode 100644 queue-6.1/asoc-nau8821-consistently-clear-interrupts-before-un.patch create mode 100644 queue-6.1/asoc-nau8821-fixup-nau8821_enable_jack_detect.patch create mode 100644 queue-6.1/audit-avoid-missing-prototype-warnings.patch create mode 100644 queue-6.1/audit-move-the-compat_xxx_class-extern-declarations-.patch create mode 100644 queue-6.1/auxdisplay-arm-charlcd-fix-release_mem_region-size.patch create mode 100644 queue-6.1/backlight-qcom-wled-support-ovp-values-for-pmi8994.patch create mode 100644 queue-6.1/bonding-only-set-speed-duplex-to-unknown-if-getting-.patch create mode 100644 queue-6.1/bpf-fix-bpf_xdp_store_bytes-proto-for-read-only-arg.patch create mode 100644 queue-6.1/bpf-sockmap-fix-incorrect-copied_seq-calculation.patch create mode 100644 queue-6.1/btrfs-fix-block_group_tree-dirty_list-corruption.patch create mode 100644 queue-6.1/btrfs-qgroup-return-correct-error-when-deleting-qgro.patch create mode 100644 queue-6.1/clk-mediatek-fix-error-handling-in-runtime-pm-setup.patch create mode 100644 queue-6.1/clk-meson-gxbb-limit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch create mode 100644 queue-6.1/clk-move-clk_-save-restore-_context-to-common_clk-se.patch create mode 100644 queue-6.1/clk-qcom-dispcc-sdm845-enable-parents-for-pixel-cloc.patch create mode 100644 queue-6.1/clk-qcom-gcc-msm8953-remove-always_on-flag-from-cpp_.patch create mode 100644 queue-6.1/clk-qcom-gfx3d-add-parent-to-parent-request-map.patch create mode 100644 queue-6.1/clk-qcom-rcg2-compute-2d-using-duty-fraction-directl.patch create mode 100644 queue-6.1/clk-qcom-return-correct-error-code-in-qcom_cc_probe_.patch create mode 100644 queue-6.1/coresight-etm3x-fix-cpulocked-warning-on-cpuhp.patch create mode 100644 queue-6.1/cpufreq-scmi-correct-scmi-explanation.patch create mode 100644 queue-6.1/crypto-cavium-fix-dma_free_coherent-size.patch create mode 100644 queue-6.1/crypto-ccp-add-an-s4-restore-flow.patch create mode 100644 queue-6.1/crypto-hisilicon-sec-fix-spelling-mistake-ckeck-chec.patch create mode 100644 queue-6.1/crypto-hisilicon-sec2-fix-for-sec-spec-check.patch create mode 100644 queue-6.1/crypto-hisilicon-sec2-support-skcipher-aead-fallback.patch create mode 100644 queue-6.1/crypto-hisilicon-trng-modifying-the-order-of-header-.patch create mode 100644 queue-6.1/crypto-hisilicon-trng-support-tfms-sharing-the-devic.patch create mode 100644 queue-6.1/crypto-hisilicon-zip-adjust-the-way-to-obtain-the-re.patch create mode 100644 queue-6.1/crypto-hisilicon-zip-remove-zlib-and-gzip.patch create mode 100644 queue-6.1/crypto-hisilicon-zip-support-deflate-algorithm.patch create mode 100644 queue-6.1/crypto-octeontx-fix-dma_free_coherent-size.patch create mode 100644 queue-6.1/crypto-qat-fix-warning-on-adf_pfvf_pf_proto.c.patch create mode 100644 queue-6.1/cxl-fix-premature-commit_end-increment-on-decoder-co.patch create mode 100644 queue-6.1/dm-use-bio_clone_blkg_association.patch create mode 100644 queue-6.1/dma-dma-axi-dmac-fix-sw-cyclic-transfers.patch create mode 100644 queue-6.1/dmaengine-mediatek-uart-apdma-fix-above-4g-addressin.patch create mode 100644 queue-6.1/documentation-pci-endpoint-fix-ntb-vntb-copy-paste-e.patch create mode 100644 queue-6.1/drivers-iio-mpu3050-use-dev_err_probe-for-regulator-.patch create mode 100644 queue-6.1/drm-amdgpu-use-explicit-vcn-instance-0-in-sr-iov-ini.patch create mode 100644 queue-6.1/drm-msm-dpu-fix-cmd-panels-on-dpu-1.x-3.x.patch create mode 100644 queue-6.1/edac-altera-remove-irqf_oneshot.patch create mode 100644 queue-6.1/edac-i5000-fix-snprintf-size-calculation-in-calculat.patch create mode 100644 queue-6.1/edac-i5400-fix-snprintf-limit-calculation-in-calcula.patch create mode 100644 queue-6.1/fat-avoid-parent-link-count-underflow-in-rmdir.patch create mode 100644 queue-6.1/fbdev-au1200fb-fix-a-memory-leak-in-au1200fb_drv_pro.patch create mode 100644 queue-6.1/fbdev-of_display_timing-fix-device-node-reference-le.patch create mode 100644 queue-6.1/fs-add-linux-init_task.h-for-init_fs.patch create mode 100644 queue-6.1/fs-nfs-fix-readdir-slow-start-regression.patch create mode 100644 queue-6.1/gfs2-add-metapath_dibh-helper.patch create mode 100644 queue-6.1/gfs2-fix-use-after-free-in-iomap-inline-data-write-p.patch create mode 100644 queue-6.1/hfsplus-return-error-when-node-already-exists-in-hfs.patch create mode 100644 queue-6.1/hid-playstation-add-missing-check-for-input_ff_creat.patch create mode 100644 queue-6.1/hrtimer-fix-trace-oddity.patch create mode 100644 queue-6.1/i3c-master-update-hot-join-flag-only-on-success.patch create mode 100644 queue-6.1/i3c-move-device-name-assignment-after-i3c_bus_init.patch create mode 100644 queue-6.1/ib-cache-update-gid-cache-on-client-reregister-event.patch create mode 100644 queue-6.1/iio-sca3000-fix-a-resource-leak-in-sca3000_probe.patch create mode 100644 queue-6.1/io_uring-cancel-abstract-out-request-match-helper.patch create mode 100644 queue-6.1/io_uring-cancel-add-ioring_async_cancel_userdata.patch create mode 100644 queue-6.1/io_uring-cancel-de-unionize-file-and-user_data-in-st.patch create mode 100644 queue-6.1/io_uring-cancel-fix-sequence-matching-for-ioring_asy.patch create mode 100644 queue-6.1/io_uring-cancel-support-opcode-based-lookup-and-canc.patch create mode 100644 queue-6.1/io_uring-sync-validate-passed-in-offset.patch create mode 100644 queue-6.1/iomap-fix-submission-side-handling-of-completion-sid.patch create mode 100644 queue-6.1/iommu-vt-d-flush-cache-for-pasid-table-before-using-.patch create mode 100644 queue-6.1/ionic-rate-limit-unknown-xcvr-type-messages.patch create mode 100644 queue-6.1/ipc-don-t-audit-capability-check-in-ipc_permissions.patch create mode 100644 queue-6.1/kallsyms-ftrace-set-module-buildid-in-ftrace_mod_add.patch create mode 100644 queue-6.1/leds-qcom-lpg-check-the-return-value-of-regmap_bulk_.patch create mode 100644 queue-6.1/libbpf-fix-oob-read-in-btf_dump_get_bitfield_value.patch create mode 100644 queue-6.1/mctp-i2c-initialise-event-handler-read-bytes.patch create mode 100644 queue-6.1/md-raid10-fix-any_working-flag-handling-in-raid10_sy.patch create mode 100644 queue-6.1/media-ccs-accommodate-c-phy-into-the-calculation.patch create mode 100644 queue-6.1/media-uvcvideo-fix-allocation-for-small-frame-sizes.patch create mode 100644 queue-6.1/mfd-arizona-fix-regulator-resource-leak-on-wm5102_cl.patch create mode 100644 queue-6.1/mfd-wm8350-core-use-irqf_oneshot.patch create mode 100644 queue-6.1/mmc-rtsx_pci_sdmmc-increase-power-on-settling-delay-.patch create mode 100644 queue-6.1/module-add-helper-function-for-reading-module_buildi.patch create mode 100644 queue-6.1/mtd-parsers-ofpart-fix-of-node-refcount-leak-in-pars.patch create mode 100644 queue-6.1/mtd-rawnand-cadence-fix-return-type-of-cdma-send-and.patch create mode 100644 queue-6.1/net-add-skb_dstref_steal-and-skb_dstref_restore.patch create mode 100644 queue-6.1/net-atm-fix-crash-due-to-unvalidated-vcc-pointer-in-.patch create mode 100644 queue-6.1/net-hns3-fix-double-free-issue-for-tx-spare-buffer.patch create mode 100644 queue-6.1/net-mctp-i2c-fix-duplicate-reception-of-old-data.patch create mode 100644 queue-6.1/net-switch-to-skb_dstref_steal-skb_dstref_restore-fo.patch create mode 100644 queue-6.1/netfilter-nf_conncount-fix-tracking-of-connections-f.patch create mode 100644 queue-6.1/netfilter-nf_conncount-increase-the-connection-clean.patch create mode 100644 queue-6.1/netfilter-nf_conncount-make-nf_conncount_gc_list-to-.patch create mode 100644 queue-6.1/netfilter-nft_compat-add-more-restrictions-on-netlin.patch create mode 100644 queue-6.1/netfilter-nft_counter-fix-reset-of-counters-on-32bit.patch create mode 100644 queue-6.1/netfilter-nft_set_hash-fix-get-operation-on-big-endi.patch create mode 100644 queue-6.1/netfilter-nft_set_rbtree-check-for-partial-overlaps-.patch create mode 100644 queue-6.1/nfc-hci-shdlc-stop-timers-and-work-before-freeing-co.patch create mode 100644 queue-6.1/nfsd-never-defer-requests-during-idmap-lookup.patch create mode 100644 queue-6.1/nvdimm-virtio_pmem-serialize-flush-requests.patch create mode 100644 queue-6.1/octeontx2-af-fix-pf-driver-crash-with-kexec-kernel-b.patch create mode 100644 queue-6.1/octeontx2-pf-unregister-devlink-on-probe-failure.patch create mode 100644 queue-6.1/ovl-fix-uninit-value-in-ovl_fill_real.patch create mode 100644 queue-6.1/pci-add-acs-quirk-for-pericom-pi7c9x2g404-switches-1.patch create mode 100644 queue-6.1/pci-do-not-attempt-to-set-exttag-for-vfs.patch create mode 100644 queue-6.1/pci-initialize-rcb-from-pci_configure_device.patch create mode 100644 queue-6.1/pci-mark-3ware-9650sa-root-port-extended-tags-as-bro.patch create mode 100644 queue-6.1/pci-mediatek-fix-irq-domain-leak-when-msi-allocation.patch create mode 100644 queue-6.1/pci-pm-avoid-redundant-delays-on-d3hot-d3cold.patch create mode 100644 queue-6.1/pci-portdrv-fix-potential-resource-leak.patch create mode 100644 queue-6.1/pinctrl-equilibrium-fix-device-node-reference-leak-i.patch create mode 100644 queue-6.1/pinctrl-qcom-sm8250-lpass-lpi-fix-i2s2_data_groups-d.patch create mode 100644 queue-6.1/pinctrl-single-fix-refcount-leak-in-pcs_add_gpio_fun.patch create mode 100644 queue-6.1/platform-chrome-cros_ec_lightbar-fix-response-size-i.patch create mode 100644 queue-6.1/platform-chrome-cros_typec_switch-don-t-touch-struct.patch create mode 100644 queue-6.1/pm-sleep-wakeirq-harden-dev_pm_clear_wake_irq-agains.patch create mode 100644 queue-6.1/pm-wakeup-handle-empty-list-in-wakeup_sources_walk_s.patch create mode 100644 queue-6.1/pnfs-fix-a-missing-wake-up-while-waiting-on-nfs_layo.patch create mode 100644 queue-6.1/power-reset-nvmem-reboot-mode-respect-cell-size-for-.patch create mode 100644 queue-6.1/power-supply-ab8500-fix-use-after-free-in-power_supp.patch create mode 100644 queue-6.1/power-supply-act8945a-fix-use-after-free-in-power_su.patch create mode 100644 queue-6.1/power-supply-bq256xx-fix-use-after-free-in-power_sup.patch create mode 100644 queue-6.1/power-supply-bq25980-fix-use-after-free-in-power_sup.patch create mode 100644 queue-6.1/power-supply-bq27xxx-fix-wrong-errno-when-bus-ops-ar.patch create mode 100644 queue-6.1/power-supply-cpcap-battery-fix-use-after-free-in-pow.patch create mode 100644 queue-6.1/power-supply-goldfish-fix-use-after-free-in-power_su.patch create mode 100644 queue-6.1/power-supply-rt9455-fix-use-after-free-in-power_supp.patch create mode 100644 queue-6.1/power-supply-sbs-battery-fix-use-after-free-in-power.patch create mode 100644 queue-6.1/power-supply-wm97xx-fix-null-pointer-dereference-in-.patch create mode 100644 queue-6.1/powerpc-eeh-fix-recursive-pci_lock_rescan_remove-loc.patch create mode 100644 queue-6.1/powerpc-uaccess-move-barrier_nospec-out-of-allow_rea.patch create mode 100644 queue-6.1/procfs-fix-missing-rcu-protection-when-reading-real_.patch create mode 100644 queue-6.1/pstore-ram-fix-buffer-overflow-in-persistent_ram_sav.patch create mode 100644 queue-6.1/rdma-core-add-rdma_rw_max_sge-helper-for-sq-sizing.patch create mode 100644 queue-6.1/rdma-core-fix-a-couple-of-obvious-typos-in-comments.patch create mode 100644 queue-6.1/rdma-hns-fix-wq_mem_reclaim-warning.patch create mode 100644 queue-6.1/rdma-hns-notify-ulp-of-remaining-soft-wcs-during-res.patch create mode 100644 queue-6.1/rdma-rtrs-server-remove-dead-code.patch create mode 100644 queue-6.1/rdma-rtrs-srv-correct-the-checking-of-ib_map_mr_sg.patch create mode 100644 queue-6.1/rdma-rtrs-srv-fix-sg-mapping.patch create mode 100644 queue-6.1/rdma-rtrs-srv-refactor-the-handling-of-failure-case-.patch create mode 100644 queue-6.1/rdma-rxe-fix-double-free-in-rxe_srq_from_init.patch create mode 100644 queue-6.1/rdma-uverbs-add-__gfp_nowarn-to-ib_uverbs_unmarshall.patch create mode 100644 queue-6.1/rdma-uverbs-validate-wqe_size-before-using-it-in-ib_.patch create mode 100644 queue-6.1/regulator-core-move-supply-check-earlier-in-set_mach.patch create mode 100644 queue-6.1/revert-hwmon-ibmpex-fix-use-after-free-in-high-low-s.patch create mode 100644 queue-6.1/revert-mmc-rtsx_pci_sdmmc-increase-power-on-settling.patch create mode 100644 queue-6.1/s390-cio-fix-device-lifecycle-handling-in-css_alloc_.patch create mode 100644 queue-6.1/sched-rt-skip-currently-executing-cpu-in-rto_next_cp.patch create mode 100644 queue-6.1/scsi-csiostor-fix-dereference-of-null-pointer-rn.patch create mode 100644 queue-6.1/scsi-efct-use-irqf_oneshot-and-default-primary-handl.patch create mode 100644 queue-6.1/scsi-smartpqi-fix-memory-leak-in-pqi_report_phys_lun.patch create mode 100644 queue-6.1/scsi-smartpqi-replace-one-element-arrays-with-flexib.patch create mode 100644 queue-6.1/selftests-bpf-veristat-fix-printing-order-in-output_.patch create mode 100644 queue-6.1/serial-caif-fix-use-after-free-in-caif_serial-ldisc_.patch create mode 100644 queue-6.1/serial-imx-change-serial_imx_console-to-bool.patch create mode 100644 queue-6.1/serial-sh_sci-improve-dma-support-prompt.patch create mode 100644 queue-6.1/smack-smack-doi-accept-previously-used-values.patch create mode 100644 queue-6.1/smack-smack-doi-must-be-0.patch create mode 100644 queue-6.1/smb-client-correct-value-for-smbd_max_fragmented_rec.patch create mode 100644 queue-6.1/smb-client-fix-potential-uaf-and-double-free-in-smb2.patch create mode 100644 queue-6.1/soc-mediatek-mtk-svs-add-explicit-include-for-cpu.h.patch create mode 100644 queue-6.1/soc-mediatek-svs-fix-memory-leak-in-svs_enable_debug.patch create mode 100644 queue-6.1/soc-qcom-cmd-db-use-devm_memremap-to-fix-memory-leak.patch create mode 100644 queue-6.1/soc-qcom-smem-handle-enomem-error-during-probe.patch create mode 100644 queue-6.1/spi-tools-add-include-folder-to-.gitignore.patch create mode 100644 queue-6.1/staging-greybus-lights-avoid-null-deref.patch create mode 100644 queue-6.1/svcrdma-clean-up-comment-in-svc_rdma_accept.patch create mode 100644 queue-6.1/svcrdma-increase-the-per-transport-rw_ctx-count.patch create mode 100644 queue-6.1/svcrdma-reduce-the-number-of-rdma_rw-contexts-per-qp.patch create mode 100644 queue-6.1/svcrdma-remove-queue-shortening-warnings.patch create mode 100644 queue-6.1/tcp-tcp_tx_timestamp-must-look-at-the-rtx-queue.patch create mode 100644 queue-6.1/timers-replace-in_irq-with-in_hardirq.patch create mode 100644 queue-6.1/tpm-st33zp24-fix-missing-cleanup-on-get_burstcount-e.patch create mode 100644 queue-6.1/tpm-tpm_i2c_infineon-fix-locality-leak-on-get_burstc.patch create mode 100644 queue-6.1/tracing-properly-process-error-handling-in-event_his.patch create mode 100644 queue-6.1/tracing-remove-duplicate-enable_event_str-and-disabl.patch create mode 100644 queue-6.1/ublk-validate-sqe128-flag-before-accessing-the-cmd.patch create mode 100644 queue-6.1/ucount-check-for-cap_sys_resource-using-ns_capable_n.patch create mode 100644 queue-6.1/usb-bdc-fix-sleep-during-atomic.patch create mode 100644 queue-6.1/wifi-ath10k-sdio-add-missing-lock-protection-in-ath1.patch create mode 100644 queue-6.1/wifi-cfg80211-stop-nan-and-p2p-in-cfg80211_leave.patch create mode 100644 queue-6.1/xen-virtio-don-t-use-grant-dma-ops-when-running-as-d.patch create mode 100644 queue-6.1/xen-virtio-handle-pci-devices-which-host-controller-.patch create mode 100644 queue-6.1/xen-virtio-optimize-the-setup-of-xen-grant-dma-devic.patch create mode 100644 queue-6.1/xfrm-fix-ip_rt_bug-race-in-icmp_route_lookup-reverse.patch create mode 100644 queue-6.12/acpica-fix-null-pointer-dereference-in-acpi_ev_addre.patch create mode 100644 queue-6.12/alsa-pcm-relax-__free-variable-declarations.patch create mode 100644 queue-6.12/alsa-pcm-use-new-array-copying-wrapper.patch create mode 100644 queue-6.12/alsa-vmaster-relax-__free-variable-declarations.patch create mode 100644 queue-6.12/arm-dts-allwinner-sun5i-a13-utoo-p66-delete-power-gp.patch create mode 100644 queue-6.12/arm-dts-lpc32xx-add-clocks-property-to-motor-control.patch create mode 100644 queue-6.12/arm-dts-lpc32xx-set-motor-pwm-pwm-cells-property-val.patch create mode 100644 queue-6.12/arm-vdso-patch-out-__vdso_clock_getres-if-unavailabl.patch create mode 100644 queue-6.12/arm64-dts-amlogic-axg-assign-the-mmc-signal-clocks.patch create mode 100644 queue-6.12/arm64-dts-amlogic-c3-assign-the-mmc-signal-clocks.patch create mode 100644 queue-6.12/arm64-dts-amlogic-g12-assign-the-mmc-a-signal-clock.patch create mode 100644 queue-6.12/arm64-dts-amlogic-g12-assign-the-mmc-b-and-c-signal-.patch create mode 100644 queue-6.12/arm64-dts-amlogic-gx-assign-the-mmc-signal-clocks.patch create mode 100644 queue-6.12/arm64-dts-amlogic-s4-assign-mmc-b-clock-to-24mhz.patch create mode 100644 queue-6.12/arm64-dts-amlogic-s4-fix-mmc-clock-assignment.patch create mode 100644 queue-6.12/arm64-dts-mediatek-mt8183-jacuzzi-pico6-fix-typo-in-.patch create mode 100644 queue-6.12/arm64-dts-qcom-agatti-add-cx_mem-dbgc-gpu-regions.patch create mode 100644 queue-6.12/arm64-dts-qcom-msm8994-octagon-fix-analog-devices-ve.patch create mode 100644 queue-6.12/arm64-dts-qcom-qrb4210-rb2-fix-uart3-wakeup-irq-stor.patch create mode 100644 queue-6.12/arm64-dts-qcom-sdm630-fix-gpu_speed_bin-size.patch create mode 100644 queue-6.12/arm64-dts-qcom-sdm845-db845c-drop-cs-from-spio0.patch create mode 100644 queue-6.12/arm64-dts-qcom-sdm845-db845c-specify-power-for-wifi-.patch create mode 100644 queue-6.12/arm64-dts-qcom-sdm845-oneplus-don-t-keep-panel-regul.patch create mode 100644 queue-6.12/arm64-dts-qcom-sdm845-oneplus-don-t-mark-ts-supply-b.patch create mode 100644 queue-6.12/arm64-dts-qcom-sdm845-oneplus-mark-l14a-regulator-as.patch create mode 100644 queue-6.12/arm64-dts-qcom-sm6115-add-cx_mem-dbgc-gpu-regions.patch create mode 100644 queue-6.12/arm64-dts-qcom-x1e-bus-is-40-bits-fix-64gb-models.patch create mode 100644 queue-6.12/arm64-dts-qcom-x1e80100-fix-usb-combo-phys-ss1-and-s.patch create mode 100644 queue-6.12/arm64-dts-ti-k3-j784s4-j742s2-main-common.dtsi-refac.patch create mode 100644 queue-6.12/arm64-dts-ti-k3-j784s4-main.dtsi-move-c71_3-node-to-.patch create mode 100644 queue-6.12/arm64-dts-tqma8mpql-mba8mp-ras314-fix-hdmi-cec-pad-c.patch create mode 100644 queue-6.12/arm64-dts-tqma8mpql-mba8mpxl-fix-hdmi-cec-pad-contro.patch create mode 100644 queue-6.12/asoc-nau8821-avoid-unnecessary-blocking-in-irq-handl.patch create mode 100644 queue-6.12/asoc-nau8821-consistently-clear-interrupts-before-un.patch create mode 100644 queue-6.12/asoc-nau8821-fixup-nau8821_enable_jack_detect.patch create mode 100644 queue-6.12/audit-move-the-compat_xxx_class-extern-declarations-.patch create mode 100644 queue-6.12/auxdisplay-arm-charlcd-fix-release_mem_region-size.patch create mode 100644 queue-6.12/backlight-qcom-wled-change-pm8950-wled-configuration.patch create mode 100644 queue-6.12/backlight-qcom-wled-support-ovp-values-for-pmi8994.patch create mode 100644 queue-6.12/block-add-a-bio_add_virt_nofail-helper.patch create mode 100644 queue-6.12/bluetooth-btintel_pcie-use-irqf_oneshot-and-default-.patch create mode 100644 queue-6.12/bonding-only-set-speed-duplex-to-unknown-if-getting-.patch create mode 100644 queue-6.12/bpf-fix-bpf_xdp_store_bytes-proto-for-read-only-arg.patch create mode 100644 queue-6.12/bpf-preserve-id-of-register-in-sync_linked_regs.patch create mode 100644 queue-6.12/bpf-sockmap-fix-fionread-for-sockmap.patch create mode 100644 queue-6.12/bpf-sockmap-fix-incorrect-copied_seq-calculation.patch create mode 100644 queue-6.12/btrfs-fix-block_group_tree-dirty_list-corruption.patch create mode 100644 queue-6.12/btrfs-qgroup-return-correct-error-when-deleting-qgro.patch create mode 100644 queue-6.12/clk-mediatek-fix-error-handling-in-runtime-pm-setup.patch create mode 100644 queue-6.12/clk-meson-gxbb-limit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch create mode 100644 queue-6.12/clk-move-clk_-save-restore-_context-to-common_clk-se.patch create mode 100644 queue-6.12/clk-qcom-dispcc-sdm845-enable-parents-for-pixel-cloc.patch create mode 100644 queue-6.12/clk-qcom-dispcc-sm7150-fix-dispcc_mdss_pclk1_clk_src.patch create mode 100644 queue-6.12/clk-qcom-gcc-ipq5018-flag-sleep-clock-as-critical.patch create mode 100644 queue-6.12/clk-qcom-gcc-msm8917-remove-always_on-flag-from-cpp_.patch create mode 100644 queue-6.12/clk-qcom-gcc-msm8953-remove-always_on-flag-from-cpp_.patch create mode 100644 queue-6.12/clk-qcom-gcc-qdu1000-update-the-sdcc-rcgs-to-use-sha.patch create mode 100644 queue-6.12/clk-qcom-gcc-sdx75-update-the-sdcc-rcgs-to-use-share.patch create mode 100644 queue-6.12/clk-qcom-gcc-sm4450-update-the-sdcc-rcgs-to-use-shar.patch create mode 100644 queue-6.12/clk-qcom-gcc-sm8450-update-the-sdcc-rcgs-to-use-shar.patch create mode 100644 queue-6.12/clk-qcom-gcc-sm8550-use-floor-ops-for-sdcc-rcgs.patch create mode 100644 queue-6.12/clk-qcom-gcc-sm8650-use-floor-ops-for-sdcc-rcgs.patch create mode 100644 queue-6.12/clk-qcom-gcc-x1e80100-update-the-sdcc-rcgs-to-use-sh.patch create mode 100644 queue-6.12/clk-qcom-gfx3d-add-parent-to-parent-request-map.patch create mode 100644 queue-6.12/clk-qcom-rcg2-compute-2d-using-duty-fraction-directl.patch create mode 100644 queue-6.12/clk-qcom-return-correct-error-code-in-qcom_cc_probe_.patch create mode 100644 queue-6.12/coresight-etm3x-fix-cpulocked-warning-on-cpuhp.patch create mode 100644 queue-6.12/cpufreq-intel_pstate-enable-asym-capacity-only-when-.patch create mode 100644 queue-6.12/cpufreq-scmi-correct-scmi-explanation.patch create mode 100644 queue-6.12/cpufreq-scmi-fix-device_node-reference-leak-in-scmi_.patch create mode 100644 queue-6.12/cpuidle-governors-menu-always-check-timers-with-tick.patch create mode 100644 queue-6.12/crypto-caam-fix-netdev-memory-leak-in-dpaa2_caam_pro.patch create mode 100644 queue-6.12/crypto-cavium-fix-dma_free_coherent-size.patch create mode 100644 queue-6.12/crypto-ccp-add-an-s4-restore-flow.patch create mode 100644 queue-6.12/crypto-ccp-declare-psp-dead-if-psp_cmd_tee_ring_init.patch create mode 100644 queue-6.12/crypto-ccp-ensure-implicit-sev-snp-init-and-shutdown.patch create mode 100644 queue-6.12/crypto-ccp-factor-out-ring-destroy-handling-to-a-hel.patch create mode 100644 queue-6.12/crypto-ccp-narrow-scope-of-snp_range_list.patch create mode 100644 queue-6.12/crypto-ccp-send-psp_cmd_tee_ring_destroy-when-psp_cm.patch create mode 100644 queue-6.12/crypto-hisilicon-hpre-extend-tag-field-to-64-bits-fo.patch create mode 100644 queue-6.12/crypto-hisilicon-sec2-support-skcipher-aead-fallback.patch create mode 100644 queue-6.12/crypto-hisilicon-trng-support-tfms-sharing-the-devic.patch create mode 100644 queue-6.12/crypto-hisilicon-zip-adjust-the-way-to-obtain-the-re.patch create mode 100644 queue-6.12/crypto-octeontx-fix-dma_free_coherent-size.patch create mode 100644 queue-6.12/crypto-qat-fix-warning-on-adf_pfvf_pf_proto.c.patch create mode 100644 queue-6.12/crypto-starfive-fix-memory-leak-in-starfive_aes_aead.patch create mode 100644 queue-6.12/cxl-fix-premature-commit_end-increment-on-decoder-co.patch create mode 100644 queue-6.12/dm-fix-unlocked-test-for-dm_suspended_md.patch create mode 100644 queue-6.12/dm-use-bio_clone_blkg_association.patch create mode 100644 queue-6.12/dm-use-read_once-in-dm_blk_report_zones.patch create mode 100644 queue-6.12/dma-dma-axi-dmac-fix-hw-scatter-gather-not-looking-a.patch create mode 100644 queue-6.12/dma-dma-axi-dmac-fix-sw-cyclic-transfers.patch create mode 100644 queue-6.12/dmaengine-fsl-edma-don-t-explicitly-disable-clocks-i.patch create mode 100644 queue-6.12/dmaengine-mediatek-uart-apdma-fix-above-4g-addressin.patch create mode 100644 queue-6.12/docs-fix-warning-document-not-included-in-any-toctre.patch create mode 100644 queue-6.12/documentation-pci-endpoint-fix-ntb-vntb-copy-paste-e.patch create mode 100644 queue-6.12/documentation-trace-refactor-toctree.patch create mode 100644 queue-6.12/documentation-tracing-add-pci-tracepoint-documentati.patch create mode 100644 queue-6.12/drbd-always-set-blk_feat_stable_writes.patch create mode 100644 queue-6.12/drivers-iio-mpu3050-use-dev_err_probe-for-regulator-.patch create mode 100644 queue-6.12/drm-amd-drop-amdgpu-kernel-modesetting-enabled-messa.patch create mode 100644 queue-6.12/drm-amdgpu-use-explicit-vcn-instance-0-in-sr-iov-ini.patch create mode 100644 queue-6.12/drm-amdkfd-fix-signal_eviction_fence-bool-return-val.patch create mode 100644 queue-6.12/drm-buddy-release-free_trees-array-on-buddy-mm-teard.patch create mode 100644 queue-6.12/drm-msm-a2xx-fix-pixel-shader-start-on-a225.patch create mode 100644 queue-6.12/drm-msm-disp-dpu-add-merge3d-support-for-sc7280.patch create mode 100644 queue-6.12/drm-msm-disp-set-num_planes-to-1-for-interleaved-yuv.patch create mode 100644 queue-6.12/drm-msm-dpu-fix-cmd-panels-on-dpu-1.x-3.x.patch create mode 100644 queue-6.12/drm-msm-dpu-fix-wd-timer-handling-on-dpu-8.x.patch create mode 100644 queue-6.12/drm-msm-dpu-set-vsync-source-irrespective-of-mdp-top.patch create mode 100644 queue-6.12/drm-panel-sw43408-remove-manual-invocation-of-unprep.patch create mode 100644 queue-6.12/drm-panthor-evict-groups-before-vm-termination.patch create mode 100644 queue-6.12/drm-panthor-fix-immediate-ticking-on-a-disabled-tick.patch create mode 100644 queue-6.12/drm-panthor-fix-the-full_tick-check.patch create mode 100644 queue-6.12/drm-panthor-fix-the-group-priority-rotation-logic.patch create mode 100644 queue-6.12/drm-panthor-fix-the-logic-that-decides-when-to-stop-.patch create mode 100644 queue-6.12/drm-panthor-make-sure-we-resume-the-tick-when-new-jo.patch create mode 100644 queue-6.12/drm-panthor-recover-from-panthor_gpu_flush_caches-fa.patch create mode 100644 queue-6.12/drm-xe-unregister-drm-device-on-probe-error.patch create mode 100644 queue-6.12/edac-altera-remove-irqf_oneshot.patch create mode 100644 queue-6.12/edac-i5000-fix-snprintf-size-calculation-in-calculat.patch create mode 100644 queue-6.12/edac-i5400-fix-snprintf-limit-calculation-in-calcula.patch create mode 100644 queue-6.12/erofs-get-rid-of-raw-bi_end_io-usage.patch create mode 100644 queue-6.12/erofs-handle-end-of-filesystem-properly-for-file-bac.patch create mode 100644 queue-6.12/evm-use-ordered-xattrs-list-to-calculate-hmac-in-evm.patch create mode 100644 queue-6.12/fat-avoid-parent-link-count-underflow-in-rmdir.patch create mode 100644 queue-6.12/fbcon-fbcon_cursor_noblink-fbcon_cursor_blink.patch create mode 100644 queue-6.12/fbcon-fbcon_is_inactive-fbcon_is_active.patch create mode 100644 queue-6.12/fbcon-introduce-get_-fg-bg-_color.patch create mode 100644 queue-6.12/fbcon-move-fbcon-callbacks-into-struct-fbcon_bitops.patch create mode 100644 queue-6.12/fbcon-rename-struct-fbcon_ops-to-struct-fbcon_par.patch create mode 100644 queue-6.12/fbcon-set-rotate_font-callback-with-related-callback.patch create mode 100644 queue-6.12/fbdev-au1200fb-fix-a-memory-leak-in-au1200fb_drv_pro.patch create mode 100644 queue-6.12/fbdev-of_display_timing-fix-device-node-reference-le.patch create mode 100644 queue-6.12/fgraph-replace-fgraph_ret_regs-with-ftrace_regs.patch create mode 100644 queue-6.12/firmware-arm_ffa-correct-32-bit-response-handling-in.patch create mode 100644 queue-6.12/fs-add-linux-init_task.h-for-init_fs.patch create mode 100644 queue-6.12/fs-nfs-fix-readdir-slow-start-regression.patch create mode 100644 queue-6.12/fs-tests-exec-drop-duplicate-bprm_stack_limits-test-.patch create mode 100644 queue-6.12/ftrace-consolidate-ftrace_regs-accessor-functions-fo.patch create mode 100644 queue-6.12/ftrace-make-ftrace_regs-abstract-from-direct-use.patch create mode 100644 queue-6.12/ftrace-rename-ftrace_regs_return_value-to-ftrace_reg.patch create mode 100644 queue-6.12/ftrace-use-arch_ftrace_regs-for-ftrace_regs_-macros.patch create mode 100644 queue-6.12/genirq-set-irqf_cond_oneshot-in-devm_request_irq.patch create mode 100644 queue-6.12/gfs2-fix-slab-use-after-free-in-qd_put.patch create mode 100644 queue-6.12/gfs2-fix-use-after-free-in-iomap-inline-data-write-p.patch create mode 100644 queue-6.12/gfs2-retries-missing-in-gfs2_-rename-exchange.patch create mode 100644 queue-6.12/hfsplus-return-error-when-node-already-exists-in-hfs.patch create mode 100644 queue-6.12/hid-intel-ish-hid-fix-null-ptr-deref-in-ishtp_bus_re.patch create mode 100644 queue-6.12/hid-playstation-add-missing-check-for-input_ff_creat.patch create mode 100644 queue-6.12/hrtimer-fix-trace-oddity.patch create mode 100644 queue-6.12/hwmon-pmbus-mpq8785-add-support-for-mpm82504.patch create mode 100644 queue-6.12/hwmon-pmbus-mpq8785-fix-vout_mode-mismatch-during-id.patch create mode 100644 queue-6.12/hwmon-pmbus-mpq8785-implement-vout-feedback-resistor.patch create mode 100644 queue-6.12/hwmon-pmbus-mpq8785-prepare-driver-for-multiple-devi.patch create mode 100644 queue-6.12/hwrng-core-allow-runtime-disabling-of-the-hw-rng.patch create mode 100644 queue-6.12/hwrng-core-use-rcu-and-work_struct-to-fix-race-condi.patch create mode 100644 queue-6.12/hwspinlock-omap-handle-devm_pm_runtime_enable-errors.patch create mode 100644 queue-6.12/i3c-dw-fix-memory-leak-in-dw_i3c_master_i2c_xfers.patch create mode 100644 queue-6.12/i3c-dw-initialize-spinlock-to-avoid-upsetting-lockde.patch create mode 100644 queue-6.12/i3c-master-update-hot-join-flag-only-on-success.patch create mode 100644 queue-6.12/i3c-move-device-name-assignment-after-i3c_bus_init.patch create mode 100644 queue-6.12/ib-cache-update-gid-cache-on-client-reregister-event.patch create mode 100644 queue-6.12/ib-mlx5-fix-port-speed-query-for-representors.patch create mode 100644 queue-6.12/iio-pressure-mprls0025pa-fix-interrupt-flag.patch create mode 100644 queue-6.12/iio-pressure-mprls0025pa-fix-pressure-calculation.patch create mode 100644 queue-6.12/iio-pressure-mprls0025pa-fix-scan_type-struct.patch create mode 100644 queue-6.12/iio-pressure-mprls0025pa-fix-spi-cs-delay-violation.patch create mode 100644 queue-6.12/iio-pressure-mprls0025pa-fix-spi_transfer-struct-ini.patch create mode 100644 queue-6.12/iio-sca3000-fix-a-resource-leak-in-sca3000_probe.patch create mode 100644 queue-6.12/iio-test-drop-dangling-symbol-in-gain-time-scale-hel.patch create mode 100644 queue-6.12/inet-raw-sockets-using-ipproto_raw-must-drop-incomin.patch create mode 100644 queue-6.12/interconnect-mediatek-aggregate-bandwidth-with-satur.patch create mode 100644 queue-6.12/interconnect-mediatek-don-t-hijack-parent-device.patch create mode 100644 queue-6.12/io_uring-cancel-de-unionize-file-and-user_data-in-st.patch create mode 100644 queue-6.12/io_uring-sync-validate-passed-in-offset.patch create mode 100644 queue-6.12/io_uring-use-release-acquire-ordering-for-ioring_set.patch create mode 100644 queue-6.12/iomap-fix-submission-side-handling-of-completion-sid.patch create mode 100644 queue-6.12/iommu-vt-d-avoid-draining-prq-in-sva-mm-release-path.patch create mode 100644 queue-6.12/iommu-vt-d-clear-present-bit-before-tearing-down-pas.patch create mode 100644 queue-6.12/iommu-vt-d-drain-prqs-when-domain-removed-from-rid.patch create mode 100644 queue-6.12/iommu-vt-d-flush-cache-for-pasid-table-before-using-.patch create mode 100644 queue-6.12/iommu-vt-d-separate-page-request-queue-from-svm.patch create mode 100644 queue-6.12/ionic-rate-limit-unknown-xcvr-type-messages.patch create mode 100644 queue-6.12/ipc-don-t-audit-capability-check-in-ipc_permissions.patch create mode 100644 queue-6.12/kallsyms-ftrace-set-module-buildid-in-ftrace_mod_add.patch create mode 100644 queue-6.12/leds-qcom-lpg-check-the-return-value-of-regmap_bulk_.patch create mode 100644 queue-6.12/libbpf-fix-oob-read-in-btf_dump_get_bitfield_value.patch create mode 100644 queue-6.12/mctp-i2c-initialise-event-handler-read-bytes.patch create mode 100644 queue-6.12/md-raid1-fix-memory-leak-in-raid1_run-if-no-active-r.patch create mode 100644 queue-6.12/md-raid1-fix-memory-leak-in-raid1_run.patch create mode 100644 queue-6.12/md-raid10-fix-any_working-flag-handling-in-raid10_sy.patch create mode 100644 queue-6.12/md-raid5-fix-raid5_run-to-return-error-when-log_init.patch create mode 100644 queue-6.12/media-ccs-accommodate-c-phy-into-the-calculation.patch create mode 100644 queue-6.12/media-chips-media-wave5-fix-memory-leak-on-codec_inf.patch create mode 100644 queue-6.12/media-pci-mg4b-use-irqf_no_thread.patch create mode 100644 queue-6.12/media-uvcvideo-fix-allocation-for-small-frame-sizes.patch create mode 100644 queue-6.12/mfd-arizona-fix-regulator-resource-leak-on-wm5102_cl.patch create mode 100644 queue-6.12/mfd-simple-mfd-i2c-add-compatible-strings-for-layers.patch create mode 100644 queue-6.12/mfd-simple-mfd-i2c-add-delta-tn48m-cpld-support.patch create mode 100644 queue-6.12/mfd-simple-mfd-i2c-add-max77705-support.patch create mode 100644 queue-6.12/mfd-simple-mfd-i2c-add-spacemit-p1-support.patch create mode 100644 queue-6.12/mfd-simple-mfd-i2c-keep-compatible-strings-in-alphab.patch create mode 100644 queue-6.12/mfd-wm8350-core-use-irqf_oneshot.patch create mode 100644 queue-6.12/mmc-rtsx_pci_sdmmc-increase-power-on-settling-delay-.patch create mode 100644 queue-6.12/module-add-helper-function-for-reading-module_buildi.patch create mode 100644 queue-6.12/mptcp-fix-receive-space-timestamp-initialization.patch create mode 100644 queue-6.12/mtd-parsers-fix-memory-leak-in-mtd_parser_tplink_saf.patch create mode 100644 queue-6.12/mtd-parsers-ofpart-fix-of-node-refcount-leak-in-pars.patch create mode 100644 queue-6.12/mtd-rawnand-cadence-fix-return-type-of-cdma-send-and.patch create mode 100644 queue-6.12/mtd-spinand-fix-kernel-doc.patch create mode 100644 queue-6.12/net-add-skb_dstref_steal-and-skb_dstref_restore.patch create mode 100644 queue-6.12/net-atm-fix-crash-due-to-unvalidated-vcc-pointer-in-.patch create mode 100644 queue-6.12/net-hns3-fix-double-free-issue-for-tx-spare-buffer.patch create mode 100644 queue-6.12/net-mctp-i2c-fix-duplicate-reception-of-old-data.patch create mode 100644 queue-6.12/net-sunhme-fix-sbus-regression.patch create mode 100644 queue-6.12/net-switch-to-skb_dstref_steal-skb_dstref_restore-fo.patch create mode 100644 queue-6.12/netfilter-nf_conncount-fix-tracking-of-connections-f.patch create mode 100644 queue-6.12/netfilter-nf_conncount-increase-the-connection-clean.patch create mode 100644 queue-6.12/netfilter-nf_conncount-make-nf_conncount_gc_list-to-.patch create mode 100644 queue-6.12/netfilter-nf_tables-reset-table-validation-state-on-.patch create mode 100644 queue-6.12/netfilter-nfnetlink_queue-do-shared-unconfirmed-chec.patch create mode 100644 queue-6.12/netfilter-nfnetlink_queue-optimize-verdict-lookup-wi.patch create mode 100644 queue-6.12/netfilter-nft_compat-add-more-restrictions-on-netlin.patch create mode 100644 queue-6.12/netfilter-nft_counter-fix-reset-of-counters-on-32bit.patch create mode 100644 queue-6.12/netfilter-nft_set_hash-fix-get-operation-on-big-endi.patch create mode 100644 queue-6.12/netfilter-nft_set_rbtree-check-for-partial-overlaps-.patch create mode 100644 queue-6.12/netfilter-nft_set_rbtree-fix-bogus-eexist-with-nlm_f.patch create mode 100644 queue-6.12/nfc-hci-shdlc-stop-timers-and-work-before-freeing-co.patch create mode 100644 queue-6.12/nfs-localio-eliminate-unnecessary-kref-in-nfs_local_.patch create mode 100644 queue-6.12/nfs-localio-use-gfp_noio-and-non-memreclaim-workqueu.patch create mode 100644 queue-6.12/nfs-nfserr_inval-is-not-defined-by-nfsv2.patch create mode 100644 queue-6.12/nfsd-never-defer-requests-during-idmap-lookup.patch create mode 100644 queue-6.12/nvdimm-virtio_pmem-serialize-flush-requests.patch create mode 100644 queue-6.12/octeon_ep-disable-per-ring-interrupts.patch create mode 100644 queue-6.12/octeon_ep-ensure-dbell-baddr-updation.patch create mode 100644 queue-6.12/octeon_ep_vf-ensure-dbell-baddr-updation.patch create mode 100644 queue-6.12/octeontx2-af-fix-pf-driver-crash-with-kexec-kernel-b.patch create mode 100644 queue-6.12/octeontx2-pf-unregister-devlink-on-probe-failure.patch create mode 100644 queue-6.12/of-unittest-fix-possible-null-pointer-dereferences-i.patch create mode 100644 queue-6.12/opp-return-correct-value-in-dev_pm_opp_get_level.patch create mode 100644 queue-6.12/ovl-fix-uninit-value-in-ovl_fill_real.patch create mode 100644 queue-6.12/partial-revert-x86-xen-fix-balloon-target-initializa.patch create mode 100644 queue-6.12/pci-acpi-restrict-program_hpx_type2-to-aer-bits.patch create mode 100644 queue-6.12/pci-add-acs-quirk-for-pericom-pi7c9x2g404-switches-1.patch create mode 100644 queue-6.12/pci-add-defines-for-bridge-window-indexing.patch create mode 100644 queue-6.12/pci-check-parent-for-null-in-of_pci_bus_release_doma.patch create mode 100644 queue-6.12/pci-do-not-attempt-to-set-exttag-for-vfs.patch create mode 100644 queue-6.12/pci-initialize-rcb-from-pci_configure_device.patch create mode 100644 queue-6.12/pci-mark-3ware-9650sa-root-port-extended-tags-as-bro.patch create mode 100644 queue-6.12/pci-mediatek-fix-irq-domain-leak-when-msi-allocation.patch create mode 100644 queue-6.12/pci-p2pdma-release-per-cpu-pgmap-ref-when-vm_insert_.patch create mode 100644 queue-6.12/pci-pm-avoid-redundant-delays-on-d3hot-d3cold.patch create mode 100644 queue-6.12/pci-portdrv-fix-potential-resource-leak.patch create mode 100644 queue-6.12/perf-arm_spe-properly-set-hw.state-on-failures.patch create mode 100644 queue-6.12/perf-x86-core-do-not-set-bit-width-for-unavailable-c.patch create mode 100644 queue-6.12/phy-freescale-imx8qm-hsio-fix-null-pointer-dereferen.patch create mode 100644 queue-6.12/pinctrl-equilibrium-fix-device-node-reference-leak-i.patch create mode 100644 queue-6.12/pinctrl-qcom-sm8250-lpass-lpi-fix-i2s2_data_groups-d.patch create mode 100644 queue-6.12/pinctrl-single-fix-refcount-leak-in-pcs_add_gpio_fun.patch create mode 100644 queue-6.12/platform-chrome-cros_ec_lightbar-fix-response-size-i.patch create mode 100644 queue-6.12/platform-chrome-cros_typec_switch-don-t-touch-struct.patch create mode 100644 queue-6.12/platform-x86-amd-pmf-prevent-tee-errors-after-hibern.patch create mode 100644 queue-6.12/platform-x86-int0002-remove-irqf_oneshot-from-reques.patch create mode 100644 queue-6.12/pm-sleep-wakeirq-harden-dev_pm_clear_wake_irq-agains.patch create mode 100644 queue-6.12/pm-wakeup-handle-empty-list-in-wakeup_sources_walk_s.patch create mode 100644 queue-6.12/pnfs-fix-a-missing-wake-up-while-waiting-on-nfs_layo.patch create mode 100644 queue-6.12/power-reset-nvmem-reboot-mode-respect-cell-size-for-.patch create mode 100644 queue-6.12/power-supply-ab8500-fix-use-after-free-in-power_supp.patch create mode 100644 queue-6.12/power-supply-act8945a-fix-use-after-free-in-power_su.patch create mode 100644 queue-6.12/power-supply-bq256xx-fix-use-after-free-in-power_sup.patch create mode 100644 queue-6.12/power-supply-bq25980-fix-use-after-free-in-power_sup.patch create mode 100644 queue-6.12/power-supply-bq27xxx-fix-wrong-errno-when-bus-ops-ar.patch create mode 100644 queue-6.12/power-supply-cpcap-battery-fix-use-after-free-in-pow.patch create mode 100644 queue-6.12/power-supply-goldfish-fix-use-after-free-in-power_su.patch create mode 100644 queue-6.12/power-supply-pm8916_bms_vm-fix-use-after-free-in-pow.patch create mode 100644 queue-6.12/power-supply-pm8916_lbc-fix-use-after-free-for-extco.patch create mode 100644 queue-6.12/power-supply-pm8916_lbc-fix-use-after-free-in-power_.patch create mode 100644 queue-6.12/power-supply-qcom_battmgr-recognize-lip-as-lithium-p.patch create mode 100644 queue-6.12/power-supply-rt9455-fix-use-after-free-in-power_supp.patch create mode 100644 queue-6.12/power-supply-sbs-battery-fix-use-after-free-in-power.patch create mode 100644 queue-6.12/power-supply-wm97xx-fix-null-pointer-dereference-in-.patch create mode 100644 queue-6.12/powerpc-eeh-fix-recursive-pci_lock_rescan_remove-loc.patch create mode 100644 queue-6.12/powerpc-uaccess-move-barrier_nospec-out-of-allow_rea.patch create mode 100644 queue-6.12/printk-vt-fbcon-remove-console_conditional_schedule.patch create mode 100644 queue-6.12/procfs-fix-missing-rcu-protection-when-reading-real_.patch create mode 100644 queue-6.12/pstore-ram-fix-buffer-overflow-in-persistent_ram_sav.patch create mode 100644 queue-6.12/quota-fix-livelock-between-quotactl-and-freeze_super.patch create mode 100644 queue-6.12/rcu-fix-rcu_read_unlock-deadloop-due-to-softirq.patch create mode 100644 queue-6.12/rcu-refactor-expedited-handling-check-in-rcu_read_un.patch create mode 100644 queue-6.12/rcu-remove-local_irq_save-restore-in-rcu_preempt_def.patch create mode 100644 queue-6.12/rdma-core-add-rdma_rw_max_sge-helper-for-sq-sizing.patch create mode 100644 queue-6.12/rdma-hns-fix-rocev1-failure-due-to-dscp.patch create mode 100644 queue-6.12/rdma-hns-fix-wq_mem_reclaim-warning.patch create mode 100644 queue-6.12/rdma-hns-notify-ulp-of-remaining-soft-wcs-during-res.patch create mode 100644 queue-6.12/rdma-iwcm-fix-workqueue-list-corruption-by-removing-.patch create mode 100644 queue-6.12/rdma-mlx5-fix-memory-leak-in-get_data_direct_sysfs_p.patch create mode 100644 queue-6.12/rdma-mlx5-fix-umr-hang-in-lag-error-state-unload.patch create mode 100644 queue-6.12/rdma-rtrs-server-remove-dead-code.patch create mode 100644 queue-6.12/rdma-rtrs-srv-fix-sg-mapping.patch create mode 100644 queue-6.12/rdma-rxe-fix-double-free-in-rxe_srq_from_init.patch create mode 100644 queue-6.12/rdma-rxe-fix-race-condition-in-qp-timer-handlers.patch create mode 100644 queue-6.12/rdma-uverbs-add-__gfp_nowarn-to-ib_uverbs_unmarshall.patch create mode 100644 queue-6.12/rdma-uverbs-validate-wqe_size-before-using-it-in-ib_.patch create mode 100644 queue-6.12/regulator-core-move-supply-check-earlier-in-set_mach.patch create mode 100644 queue-6.12/revert-hwmon-ibmpex-fix-use-after-free-in-high-low-s.patch create mode 100644 queue-6.12/revert-mmc-rtsx_pci_sdmmc-increase-power-on-settling.patch create mode 100644 queue-6.12/rnbd-srv-fix-server-side-setting-of-bi_size-for-spec.patch create mode 100644 queue-6.12/rnbd-srv-use-bio_add_virt_nofail.patch create mode 100644 queue-6.12/s390-cio-fix-device-lifecycle-handling-in-css_alloc_.patch create mode 100644 queue-6.12/sched-deadline-clear-the-defer-params.patch create mode 100644 queue-6.12/sched-rt-skip-currently-executing-cpu-in-rto_next_cp.patch create mode 100644 queue-6.12/scsi-csiostor-fix-dereference-of-null-pointer-rn.patch create mode 100644 queue-6.12/scsi-efct-use-irqf_oneshot-and-default-primary-handl.patch create mode 100644 queue-6.12/scsi-smartpqi-fix-memory-leak-in-pqi_report_phys_lun.patch create mode 100644 queue-6.12/scsi-ufs-host-mediatek-require-config_pm.patch create mode 100644 queue-6.12/selftests-bpf-fix-resource-leak-in-serial_test_wq-on.patch create mode 100644 queue-6.12/selftests-bpf-veristat-fix-printing-order-in-output_.patch create mode 100644 queue-6.12/selftests-mm-convert-page_size-to-unsigned-long.patch create mode 100644 queue-6.12/selftests-mm-fix-faulting-in-code-in-pagemap_ioctl-t.patch create mode 100644 queue-6.12/selftests-mm-pagemap_ioctl-fix-types-mismatches-show.patch create mode 100644 queue-6.12/serial-caif-fix-use-after-free-in-caif_serial-ldisc_.patch create mode 100644 queue-6.12/serial-imx-change-serial_imx_console-to-bool.patch create mode 100644 queue-6.12/serial-sh_sci-improve-dma-support-prompt.patch create mode 100644 queue-6.12/smack-smack-doi-accept-previously-used-values.patch create mode 100644 queue-6.12/smack-smack-doi-must-be-0.patch create mode 100644 queue-6.12/smb-client-correct-value-for-smbd_max_fragmented_rec.patch create mode 100644 queue-6.12/smb-client-fix-potential-uaf-and-double-free-in-smb2.patch create mode 100644 queue-6.12/soc-mediatek-svs-fix-memory-leak-in-svs_enable_debug.patch create mode 100644 queue-6.12/soc-qcom-cmd-db-use-devm_memremap-to-fix-memory-leak.patch create mode 100644 queue-6.12/soc-qcom-smem-handle-enomem-error-during-probe.patch create mode 100644 queue-6.12/soundwire-intel_ace2x-add-snd_hda_core-dependency.patch create mode 100644 queue-6.12/spi-tools-add-include-folder-to-.gitignore.patch create mode 100644 queue-6.12/staging-greybus-lights-avoid-null-deref.patch create mode 100644 queue-6.12/tcp-tcp_tx_timestamp-must-look-at-the-rtx-queue.patch create mode 100644 queue-6.12/thermal-intel-x86_pkg_temp_thermal-handle-invalid-te.patch create mode 100644 queue-6.12/thermal-of-fix-reference-leak-in-thermal_of_cm_looku.patch create mode 100644 queue-6.12/tools-power-x86-intel-speed-select-fix-file-descript.patch create mode 100644 queue-6.12/tpm-st33zp24-fix-missing-cleanup-on-get_burstcount-e.patch create mode 100644 queue-6.12/tpm-tpm_i2c_infineon-fix-locality-leak-on-get_burstc.patch create mode 100644 queue-6.12/tracing-add-a-comment-about-ftrace_regs-definition.patch create mode 100644 queue-6.12/tracing-add-ftrace_fill_perf_regs-for-perf-event.patch create mode 100644 queue-6.12/tracing-add-ftrace_partial_regs-for-converting-ftrac.patch create mode 100644 queue-6.12/tracing-properly-process-error-handling-in-event_his.patch create mode 100644 queue-6.12/tracing-remove-duplicate-enable_event_str-and-disabl.patch create mode 100644 queue-6.12/ublk-validate-sqe128-flag-before-accessing-the-cmd.patch create mode 100644 queue-6.12/ucount-check-for-cap_sys_resource-using-ns_capable_n.patch create mode 100644 queue-6.12/usb-bdc-fix-sleep-during-atomic.patch create mode 100644 queue-6.12/vfio-pci-lock-upstream-bridge-for-vfio_pci_core_disa.patch create mode 100644 queue-6.12/watchdog-starfive-wdt-fix-pm-reference-leak-in-probe.patch create mode 100644 queue-6.12/wifi-ath10k-sdio-add-missing-lock-protection-in-ath1.patch create mode 100644 queue-6.12/wifi-cfg80211-fix-use_for-flag-update-on-bss-refresh.patch create mode 100644 queue-6.12/wifi-cfg80211-stop-nan-and-p2p-in-cfg80211_leave.patch create mode 100644 queue-6.12/workqueue-factor-out-assign_rescuer_work.patch create mode 100644 queue-6.12/workqueue-only-assign-rescuer-work-when-really-neede.patch create mode 100644 queue-6.12/workqueue-process-rescuer-work-items-one-by-one-usin.patch create mode 100644 queue-6.12/x86-fgraph-bpf-fix-stack-orc-unwind-from-kprobe_mult.patch create mode 100644 queue-6.12/x86-fgraph-bpf-switch-kprobe_multi-program-stack-unw.patch create mode 100644 queue-6.12/xdrgen-fix-struct-prefix-for-typedef-types-in-progra.patch create mode 100644 queue-6.12/xdrgen-initialize-data-pointer-for-zero-length-items.patch create mode 100644 queue-6.12/xen-virtio-don-t-use-grant-dma-ops-when-running-as-d.patch create mode 100644 queue-6.12/xfrm-fix-ip_rt_bug-race-in-icmp_route_lookup-reverse.patch create mode 100644 queue-6.18/accel-amdxdna-fix-incorrect-error-code-returned-for-.patch create mode 100644 queue-6.18/accel-amdxdna-fix-memory-leak-in-amdxdna_ubuf_map.patch create mode 100644 queue-6.18/accel-amdxdna-fix-notifier_wq-flushing-warning.patch create mode 100644 queue-6.18/accel-amdxdna-fix-race-where-send-ring-appears-full-.patch create mode 100644 queue-6.18/accel-amdxdna-hold-mm-structure-across-iommu_sva_unb.patch create mode 100644 queue-6.18/accel-amdxdna-stop-job-scheduling-across-aie2_releas.patch create mode 100644 queue-6.18/acpi-processor-update-cpuidle-driver-check-in-__acpi.patch create mode 100644 queue-6.18/acpica-fix-null-pointer-dereference-in-acpi_ev_addre.patch create mode 100644 queue-6.18/af_unix-fix-memleak-of-newsk-in-unix_stream_connect.patch create mode 100644 queue-6.18/alsa-pcm-relax-__free-variable-declarations.patch create mode 100644 queue-6.18/alsa-vmaster-relax-__free-variable-declarations.patch create mode 100644 queue-6.18/arm-dts-allwinner-sun5i-a13-utoo-p66-delete-power-gp.patch create mode 100644 queue-6.18/arm-dts-lpc32xx-add-clocks-property-to-motor-control.patch create mode 100644 queue-6.18/arm-vdso-patch-out-__vdso_clock_getres-if-unavailabl.patch create mode 100644 queue-6.18/arm64-dts-amlogic-axg-assign-the-mmc-signal-clocks.patch create mode 100644 queue-6.18/arm64-dts-amlogic-c3-assign-the-mmc-signal-clocks.patch create mode 100644 queue-6.18/arm64-dts-amlogic-g12-assign-the-mmc-a-signal-clock.patch create mode 100644 queue-6.18/arm64-dts-amlogic-g12-assign-the-mmc-b-and-c-signal-.patch create mode 100644 queue-6.18/arm64-dts-amlogic-gx-assign-the-mmc-signal-clocks.patch create mode 100644 queue-6.18/arm64-dts-amlogic-s4-assign-mmc-b-clock-to-24mhz.patch create mode 100644 queue-6.18/arm64-dts-amlogic-s4-fix-mmc-clock-assignment.patch create mode 100644 queue-6.18/arm64-dts-mediatek-mt8183-jacuzzi-pico6-fix-typo-in-.patch create mode 100644 queue-6.18/arm64-dts-qcom-agatti-add-cx_mem-dbgc-gpu-regions.patch create mode 100644 queue-6.18/arm64-dts-qcom-msm8994-octagon-fix-analog-devices-ve.patch create mode 100644 queue-6.18/arm64-dts-qcom-qrb4210-rb2-fix-uart3-wakeup-irq-stor.patch create mode 100644 queue-6.18/arm64-dts-qcom-sdm630-fix-gpu_speed_bin-size.patch create mode 100644 queue-6.18/arm64-dts-qcom-sdm845-db845c-drop-cs-from-spio0.patch create mode 100644 queue-6.18/arm64-dts-qcom-sdm845-db845c-specify-power-for-wifi-.patch create mode 100644 queue-6.18/arm64-dts-qcom-sdm845-oneplus-don-t-keep-panel-regul.patch create mode 100644 queue-6.18/arm64-dts-qcom-sdm845-oneplus-don-t-mark-ts-supply-b.patch create mode 100644 queue-6.18/arm64-dts-qcom-sdm845-oneplus-mark-l14a-regulator-as.patch create mode 100644 queue-6.18/arm64-dts-qcom-sm6115-add-cx_mem-dbgc-gpu-regions.patch create mode 100644 queue-6.18/arm64-dts-qcom-talos-drop-opp-shared-from-qup-opp-ta.patch create mode 100644 queue-6.18/arm64-dts-qcom-x1e-bus-is-40-bits-fix-64gb-models.patch create mode 100644 queue-6.18/arm64-dts-qcom-x1e80100-fix-usb-combo-phys-ss1-and-s.patch create mode 100644 queue-6.18/arm64-dts-renesas-r9a09g047e57-smarc-remove-duplicat.patch create mode 100644 queue-6.18/arm64-dts-renesas-rzt2h-n2h-evk-common-use-gpio-for-.patch create mode 100644 queue-6.18/arm64-dts-ti-k3-j784s4-j742s2-main-common.dtsi-refac.patch create mode 100644 queue-6.18/arm64-dts-ti-k3-j784s4-main.dtsi-move-c71_3-node-to-.patch create mode 100644 queue-6.18/arm64-dts-tqma8mpql-mba8mp-ras314-fix-hdmi-cec-pad-c.patch create mode 100644 queue-6.18/arm64-dts-tqma8mpql-mba8mpxl-fix-hdmi-cec-pad-contro.patch create mode 100644 queue-6.18/arm64-gcs-fix-error-handling-in-arch_set_shadow_stac.patch create mode 100644 queue-6.18/asoc-nau8821-fixup-nau8821_enable_jack_detect.patch create mode 100644 queue-6.18/asoc-sdca-allow-sample-width-wild-cards-in-set_usage.patch create mode 100644 queue-6.18/asoc-sdca-force-some-sdca-controls-to-be-volatile.patch create mode 100644 queue-6.18/asoc-sdca-handle-volatile-controls-correctly.patch create mode 100644 queue-6.18/asoc-sdca-remove-outdated-todo-comment.patch create mode 100644 queue-6.18/asoc-tegra-add-ahub-writeable_reg-for-rx-holes.patch create mode 100644 queue-6.18/audit-move-the-compat_xxx_class-extern-declarations-.patch create mode 100644 queue-6.18/auxdisplay-arm-charlcd-fix-release_mem_region-size.patch create mode 100644 queue-6.18/backlight-qcom-wled-change-pm8950-wled-configuration.patch create mode 100644 queue-6.18/backlight-qcom-wled-support-ovp-values-for-pmi8994.patch create mode 100644 queue-6.18/bluetooth-btintel_pcie-use-irqf_oneshot-and-default-.patch create mode 100644 queue-6.18/bonding-only-set-speed-duplex-to-unknown-if-getting-.patch create mode 100644 queue-6.18/bpf-fix-bpf_xdp_store_bytes-proto-for-read-only-arg.patch create mode 100644 queue-6.18/bpf-fix-memory-access-flags-in-helper-prototypes.patch create mode 100644 queue-6.18/bpf-fix-tcx-netkit-detach-permissions-when-prog-fd-i.patch create mode 100644 queue-6.18/bpf-fix-verifier_bug_if-to-account-for-bpf_call.patch create mode 100644 queue-6.18/bpf-limit-bpf-program-signature-size.patch create mode 100644 queue-6.18/bpf-preserve-id-of-register-in-sync_linked_regs.patch create mode 100644 queue-6.18/bpf-require-frozen-map-for-calculating-map-hash.patch create mode 100644 queue-6.18/bpf-sockmap-fix-fionread-for-sockmap.patch create mode 100644 queue-6.18/bpf-sockmap-fix-incorrect-copied_seq-calculation.patch create mode 100644 queue-6.18/btrfs-add-orig_logical-to-btrfs_bio-for-encryption.patch create mode 100644 queue-6.18/btrfs-fix-block_group_tree-dirty_list-corruption.patch create mode 100644 queue-6.18/btrfs-fix-eexist-abort-due-to-non-consecutive-gaps-i.patch create mode 100644 queue-6.18/btrfs-headers-cleanup-to-remove-unnecessary-local-in.patch create mode 100644 queue-6.18/btrfs-introduce-btrfs_bio-async_csum.patch create mode 100644 queue-6.18/btrfs-make-sure-all-btrfs_bio-end_io-are-called-in-t.patch create mode 100644 queue-6.18/btrfs-qgroup-return-correct-error-when-deleting-qgro.patch create mode 100644 queue-6.18/btrfs-remove-btrfs_bio-fs_info-by-extracting-it-from.patch create mode 100644 queue-6.18/btrfs-zoned-don-t-zone-append-to-conventional-zone.patch create mode 100644 queue-6.18/char-misc-use-is_err-for-filp_open-return-value.patch create mode 100644 queue-6.18/clk-actions-owl-composite-convert-from-owl_divider_h.patch create mode 100644 queue-6.18/clk-actions-owl-divider-convert-from-divider_round_r.patch create mode 100644 queue-6.18/clk-bm1880-convert-from-divider_round_rate-to-divide.patch create mode 100644 queue-6.18/clk-hisilicon-clkdivider-hi6220-convert-from-divider.patch create mode 100644 queue-6.18/clk-loongson1-convert-from-divider_round_rate-to-div.patch create mode 100644 queue-6.18/clk-mediatek-add-mfg_eb-as-parent-to-mt8196-mfgpll-c.patch create mode 100644 queue-6.18/clk-mediatek-drop-__initconst-from-gates.patch create mode 100644 queue-6.18/clk-mediatek-fix-error-handling-in-runtime-pm-setup.patch create mode 100644 queue-6.18/clk-meson-g12a-limit-the-hdmi-pll-od-to-4.patch create mode 100644 queue-6.18/clk-meson-gxbb-limit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch create mode 100644 queue-6.18/clk-microchip-core-remove-duplicate-determine_rate-o.patch create mode 100644 queue-6.18/clk-milbeaut-convert-from-divider_round_rate-to-divi.patch create mode 100644 queue-6.18/clk-move-clk_-save-restore-_context-to-common_clk-se.patch create mode 100644 queue-6.18/clk-nuvoton-ma35d1-divider-convert-from-divider_roun.patch create mode 100644 queue-6.18/clk-nxp-lpc32xx-convert-from-divider_round_rate-to-d.patch create mode 100644 queue-6.18/clk-qcom-alpha-pll-convert-from-divider_round_rate-t.patch create mode 100644 queue-6.18/clk-qcom-dispcc-sdm845-enable-parents-for-pixel-cloc.patch create mode 100644 queue-6.18/clk-qcom-dispcc-sm7150-fix-dispcc_mdss_pclk1_clk_src.patch create mode 100644 queue-6.18/clk-qcom-gcc-glymur-update-the-sdcc-rcgs-to-use-shar.patch create mode 100644 queue-6.18/clk-qcom-gcc-ipq5018-flag-sleep-clock-as-critical.patch create mode 100644 queue-6.18/clk-qcom-gcc-milos-update-the-sdcc-rcgs-to-use-share.patch create mode 100644 queue-6.18/clk-qcom-gcc-msm8917-remove-always_on-flag-from-cpp_.patch create mode 100644 queue-6.18/clk-qcom-gcc-msm8953-remove-always_on-flag-from-cpp_.patch create mode 100644 queue-6.18/clk-qcom-gcc-qdu1000-update-the-sdcc-rcgs-to-use-sha.patch create mode 100644 queue-6.18/clk-qcom-gcc-sdx75-update-the-sdcc-rcgs-to-use-share.patch create mode 100644 queue-6.18/clk-qcom-gcc-sm4450-update-the-sdcc-rcgs-to-use-shar.patch create mode 100644 queue-6.18/clk-qcom-gcc-sm8450-update-the-sdcc-rcgs-to-use-shar.patch create mode 100644 queue-6.18/clk-qcom-gcc-sm8550-use-floor-ops-for-sdcc-rcgs.patch create mode 100644 queue-6.18/clk-qcom-gcc-sm8650-use-floor-ops-for-sdcc-rcgs.patch create mode 100644 queue-6.18/clk-qcom-gcc-sm8750-update-the-sdcc-rcgs-to-use-shar.patch create mode 100644 queue-6.18/clk-qcom-gcc-x1e80100-update-the-sdcc-rcgs-to-use-sh.patch create mode 100644 queue-6.18/clk-qcom-gfx3d-add-parent-to-parent-request-map.patch create mode 100644 queue-6.18/clk-qcom-rcg2-compute-2d-using-duty-fraction-directl.patch create mode 100644 queue-6.18/clk-qcom-regmap-divider-convert-from-divider_ro_roun.patch create mode 100644 queue-6.18/clk-qcom-regmap-divider-convert-from-divider_round_r.patch create mode 100644 queue-6.18/clk-qcom-return-correct-error-code-in-qcom_cc_probe_.patch create mode 100644 queue-6.18/clk-rockchip-fix-error-pointer-check-after-rockchip_.patch create mode 100644 queue-6.18/clk-sophgo-sg2042-clkgen-convert-from-divider_round_.patch create mode 100644 queue-6.18/clk-spacemit-respect-kconfig-setting-when-building-m.patch create mode 100644 queue-6.18/clk-sprd-div-convert-from-divider_round_rate-to-divi.patch create mode 100644 queue-6.18/clk-stm32-stm32-core-convert-from-divider_ro_round_r.patch create mode 100644 queue-6.18/clk-stm32-stm32-core-convert-from-divider_round_rate.patch create mode 100644 queue-6.18/clk-thead-th1520-ap-poll-for-pll-lock-and-wait-for-s.patch create mode 100644 queue-6.18/clk-versaclock3-convert-from-divider_round_rate-to-d.patch create mode 100644 queue-6.18/clk-x86-cgu-convert-from-divider_round_rate-to-divid.patch create mode 100644 queue-6.18/clk-zynqmp-divider-convert-from-divider_round_rate-t.patch create mode 100644 queue-6.18/clk-zynqmp-divider-fix-zynqmp_clk_divider_determine_.patch create mode 100644 queue-6.18/clk-zynqmp-pll-fix-zynqmp_clk_divider_determine_rate.patch create mode 100644 queue-6.18/coresight-etm3x-fix-cpulocked-warning-on-cpuhp.patch create mode 100644 queue-6.18/coresight-tmc-etr-fix-race-condition-between-sysfs-a.patch create mode 100644 queue-6.18/cpufreq-intel_pstate-enable-asym-capacity-only-when-.patch create mode 100644 queue-6.18/cpufreq-scmi-correct-scmi-explanation.patch create mode 100644 queue-6.18/cpufreq-scmi-fix-device_node-reference-leak-in-scmi_.patch create mode 100644 queue-6.18/cpuidle-governors-menu-always-check-timers-with-tick.patch create mode 100644 queue-6.18/crypto-caam-fix-netdev-memory-leak-in-dpaa2_caam_pro.patch create mode 100644 queue-6.18/crypto-cavium-fix-dma_free_coherent-size.patch create mode 100644 queue-6.18/crypto-ccp-add-an-s4-restore-flow.patch create mode 100644 queue-6.18/crypto-ccp-declare-psp-dead-if-psp_cmd_tee_ring_init.patch create mode 100644 queue-6.18/crypto-ccp-factor-out-ring-destroy-handling-to-a-hel.patch create mode 100644 queue-6.18/crypto-ccp-fix-a-case-where-snp_shutdown-is-missed.patch create mode 100644 queue-6.18/crypto-ccp-fix-a-crash-due-to-incorrect-cleanup-usag.patch create mode 100644 queue-6.18/crypto-ccp-narrow-scope-of-snp_range_list.patch create mode 100644 queue-6.18/crypto-ccp-send-psp_cmd_tee_ring_destroy-when-psp_cm.patch create mode 100644 queue-6.18/crypto-hisilicon-consolidate-qp-creation-and-start-i.patch create mode 100644 queue-6.18/crypto-hisilicon-hpre-extend-tag-field-to-64-bits-fo.patch create mode 100644 queue-6.18/crypto-hisilicon-hpre-support-the-hpre-algorithm-fal.patch create mode 100644 queue-6.18/crypto-hisilicon-qm-centralize-the-sending-locks-of-.patch create mode 100644 queue-6.18/crypto-hisilicon-qm-enhance-the-configuration-of-req.patch create mode 100644 queue-6.18/crypto-hisilicon-sec-move-backlog-management-to-qp-a.patch create mode 100644 queue-6.18/crypto-hisilicon-sec2-support-skcipher-aead-fallback.patch create mode 100644 queue-6.18/crypto-hisilicon-sgl-fix-inconsistent-map-unmap-dire.patch create mode 100644 queue-6.18/crypto-hisilicon-trng-support-tfms-sharing-the-devic.patch create mode 100644 queue-6.18/crypto-hisilicon-zip-adjust-the-way-to-obtain-the-re.patch create mode 100644 queue-6.18/crypto-hisilicon-zip-support-fallback-for-zip.patch create mode 100644 queue-6.18/crypto-inside-secure-eip93-fix-kernel-panic-in-drive.patch create mode 100644 queue-6.18/crypto-inside-secure-eip93-unregister-only-available.patch create mode 100644 queue-6.18/crypto-octeontx-fix-dma_free_coherent-size.patch create mode 100644 queue-6.18/crypto-qat-fix-warning-on-adf_pfvf_pf_proto.c.patch create mode 100644 queue-6.18/crypto-starfive-fix-memory-leak-in-starfive_aes_aead.patch create mode 100644 queue-6.18/cxl-core-fix-cxl_dport-debugfs-einj-entries.patch create mode 100644 queue-6.18/cxl-fix-premature-commit_end-increment-on-decoder-co.patch create mode 100644 queue-6.18/cxl-mem-fix-devm_cxl_memdev_edac_release-confusion.patch create mode 100644 queue-6.18/device_cgroup-remove-branch-hint-after-code-refactor.patch create mode 100644 queue-6.18/dm-fix-unlocked-test-for-dm_suspended_md.patch create mode 100644 queue-6.18/dm-use-bio_clone_blkg_association.patch create mode 100644 queue-6.18/dm-use-read_once-in-dm_blk_report_zones.patch create mode 100644 queue-6.18/dma-dma-axi-dmac-fix-hw-scatter-gather-not-looking-a.patch create mode 100644 queue-6.18/dma-dma-axi-dmac-fix-sw-cyclic-transfers.patch create mode 100644 queue-6.18/dmaengine-fsl-edma-don-t-explicitly-disable-clocks-i.patch create mode 100644 queue-6.18/dmaengine-mediatek-uart-apdma-fix-above-4g-addressin.patch create mode 100644 queue-6.18/documentation-pci-endpoint-fix-ntb-vntb-copy-paste-e.patch create mode 100644 queue-6.18/documentation-tracing-add-pci-tracepoint-documentati.patch create mode 100644 queue-6.18/dpll-add-phase-adjust-gran-pin-attribute.patch create mode 100644 queue-6.18/dpll-zl3073x-cache-all-output-properties-in-zl3073x_.patch create mode 100644 queue-6.18/dpll-zl3073x-fix-output-pin-phase-adjustment-sign.patch create mode 100644 queue-6.18/dpll-zl3073x-specify-phase-adjustment-granularity-fo.patch create mode 100644 queue-6.18/dpll-zl3073x-split-ref-out-and-synth-logic-from-core.patch create mode 100644 queue-6.18/dpll-zl3073x-store-raw-register-values-instead-of-pa.patch create mode 100644 queue-6.18/drbd-always-set-blk_feat_stable_writes.patch create mode 100644 queue-6.18/drivers-iio-mpu3050-use-dev_err_probe-for-regulator-.patch create mode 100644 queue-6.18/drm-amd-drop-amdgpu-kernel-modesetting-enabled-messa.patch create mode 100644 queue-6.18/drm-amdgpu-use-explicit-vcn-instance-0-in-sr-iov-ini.patch create mode 100644 queue-6.18/drm-amdkfd-fix-signal_eviction_fence-bool-return-val.patch create mode 100644 queue-6.18/drm-buddy-release-free_trees-array-on-buddy-mm-teard.patch create mode 100644 queue-6.18/drm-hisilicon-hibmc-add-dp-mode-valid-check.patch create mode 100644 queue-6.18/drm-hisilicon-hibmc-adding-reset-colorbar-cfg-in-dp-.patch create mode 100644 queue-6.18/drm-hisilicon-hibmc-fix-dp-probabilistical-detect-er.patch create mode 100644 queue-6.18/drm-hisilicon-hibmc-fix-no-showing-problem-with-load.patch create mode 100644 queue-6.18/drm-msm-a2xx-fix-pixel-shader-start-on-a225.patch create mode 100644 queue-6.18/drm-msm-disp-dpu-add-merge3d-support-for-sc7280.patch create mode 100644 queue-6.18/drm-msm-disp-set-num_planes-to-1-for-interleaved-yuv.patch create mode 100644 queue-6.18/drm-msm-dp-avoid-division-by-zero-in-msm_dp_ctrl_con.patch create mode 100644 queue-6.18/drm-msm-dp-update-msm_dp_controller-ids-for-sa8775p.patch create mode 100644 queue-6.18/drm-msm-dpu-fix-cmd-panels-on-dpu-1.x-3.x.patch create mode 100644 queue-6.18/drm-msm-dpu-fix-wd-timer-handling-on-dpu-8.x.patch create mode 100644 queue-6.18/drm-msm-dpu-offset-hbb-values-written-to-dpu-by-13.patch create mode 100644 queue-6.18/drm-msm-dpu-program-correct-register-for-ubwc-config.patch create mode 100644 queue-6.18/drm-msm-dpu-set-vsync-source-irrespective-of-mdp-top.patch create mode 100644 queue-6.18/drm-msm-dsi_phy_14nm-convert-from-divider_round_rate.patch create mode 100644 queue-6.18/drm-msm-mdss-correct-hbb-programmed-on-ubwc-5.x-and-.patch create mode 100644 queue-6.18/drm-panel-sw43408-remove-manual-invocation-of-unprep.patch create mode 100644 queue-6.18/drm-panthor-evict-groups-before-vm-termination.patch create mode 100644 queue-6.18/drm-panthor-fix-immediate-ticking-on-a-disabled-tick.patch create mode 100644 queue-6.18/drm-panthor-fix-panthor_gpu_coherency_set.patch create mode 100644 queue-6.18/drm-panthor-fix-the-full_tick-check.patch create mode 100644 queue-6.18/drm-panthor-fix-the-group-priority-rotation-logic.patch create mode 100644 queue-6.18/drm-panthor-fix-the-logic-that-decides-when-to-stop-.patch create mode 100644 queue-6.18/drm-panthor-make-sure-we-resume-the-tick-when-new-jo.patch create mode 100644 queue-6.18/drm-panthor-recover-from-panthor_gpu_flush_caches-fa.patch create mode 100644 queue-6.18/drm-rockchip-dw_hdmi_qp-fix-rk3576-hpd-interrupt-han.patch create mode 100644 queue-6.18/drm-xe-ptl-disable-dcc-on-ptl.patch create mode 100644 queue-6.18/drm-xe-unregister-drm-device-on-probe-error.patch create mode 100644 queue-6.18/edac-altera-remove-irqf_oneshot.patch create mode 100644 queue-6.18/edac-i5000-fix-snprintf-size-calculation-in-calculat.patch create mode 100644 queue-6.18/edac-i5400-fix-snprintf-limit-calculation-in-calcula.patch create mode 100644 queue-6.18/erofs-fix-inline-data-read-failure-for-ztailpacking-.patch create mode 100644 queue-6.18/erofs-get-rid-of-raw-bi_end_io-usage.patch create mode 100644 queue-6.18/erofs-handle-end-of-filesystem-properly-for-file-bac.patch create mode 100644 queue-6.18/evm-use-ordered-xattrs-list-to-calculate-hmac-in-evm.patch create mode 100644 queue-6.18/ext4-fast-commit-make-s_fc_lock-reclaim-safe.patch create mode 100644 queue-6.18/fat-avoid-parent-link-count-underflow-in-rmdir.patch create mode 100644 queue-6.18/fbcon-move-fbcon-callbacks-into-struct-fbcon_bitops.patch create mode 100644 queue-6.18/fbcon-rename-struct-fbcon_ops-to-struct-fbcon_par.patch create mode 100644 queue-6.18/fbcon-set-rotate_font-callback-with-related-callback.patch create mode 100644 queue-6.18/fbdev-au1200fb-fix-a-memory-leak-in-au1200fb_drv_pro.patch create mode 100644 queue-6.18/fbdev-of_display_timing-fix-device-node-reference-le.patch create mode 100644 queue-6.18/firmware-arm_ffa-correct-32-bit-response-handling-in.patch create mode 100644 queue-6.18/fs-add-linux-init_task.h-for-init_fs.patch create mode 100644 queue-6.18/fs-move-initializing-f_mode-before-file_ref_init.patch create mode 100644 queue-6.18/fs-nfs-fix-readdir-slow-start-regression.patch create mode 100644 queue-6.18/fs-tests-exec-drop-duplicate-bprm_stack_limits-test-.patch create mode 100644 queue-6.18/genirq-set-irqf_cond_oneshot-in-devm_request_irq.patch create mode 100644 queue-6.18/gfs2-fix-slab-use-after-free-in-qd_put.patch create mode 100644 queue-6.18/gfs2-fix-use-after-free-in-iomap-inline-data-write-p.patch create mode 100644 queue-6.18/gfs2-retries-missing-in-gfs2_-rename-exchange.patch create mode 100644 queue-6.18/gpib-fix-error-code-in-ibonline.patch create mode 100644 queue-6.18/gpib-fix-error-code-in-ni_usb_write_registers.patch create mode 100644 queue-6.18/gpib-fix-memory-leak-in-ni_usb_init.patch create mode 100644 queue-6.18/gpu-nova-core-apply-the-one-use-item-per-line-policy.patch create mode 100644 queue-6.18/gpu-nova-core-check-for-overflow-to-dmatrfbase1.patch create mode 100644 queue-6.18/gpu-nova-core-replace-as-with-from-conversions-where.patch create mode 100644 queue-6.18/gpu-nova-core-replace-wait_on-with-kernel-equivalent.patch create mode 100644 queue-6.18/gpu-nova-core-vbios-use-frombytes-for-pmulookuptable.patch create mode 100644 queue-6.18/hfsplus-return-error-when-node-already-exists-in-hfs.patch create mode 100644 queue-6.18/hid-intel-ish-hid-fix-null-ptr-deref-in-ishtp_bus_re.patch create mode 100644 queue-6.18/hid-playstation-add-missing-check-for-input_ff_creat.patch create mode 100644 queue-6.18/hisi_acc_vfio_pci-fix-vf-reset-timeout-issue.patch create mode 100644 queue-6.18/hrtimer-fix-trace-oddity.patch create mode 100644 queue-6.18/hwmon-pmbus-mpq8785-fix-vout_mode-mismatch-during-id.patch create mode 100644 queue-6.18/hwrng-airoha-set-rng-quality-to-900.patch create mode 100644 queue-6.18/hwrng-core-allow-runtime-disabling-of-the-hw-rng.patch create mode 100644 queue-6.18/hwrng-core-use-rcu-and-work_struct-to-fix-race-condi.patch create mode 100644 queue-6.18/hwspinlock-omap-handle-devm_pm_runtime_enable-errors.patch create mode 100644 queue-6.18/i3c-dw-fix-memory-leak-in-dw_i3c_master_i2c_xfers.patch create mode 100644 queue-6.18/i3c-dw-initialize-spinlock-to-avoid-upsetting-lockde.patch create mode 100644 queue-6.18/i3c-master-update-hot-join-flag-only-on-success.patch create mode 100644 queue-6.18/i3c-move-device-name-assignment-after-i3c_bus_init.patch create mode 100644 queue-6.18/ib-cache-update-gid-cache-on-client-reregister-event.patch create mode 100644 queue-6.18/ib-mlx5-fix-port-speed-query-for-representors.patch create mode 100644 queue-6.18/iio-pressure-mprls0025pa-fix-interrupt-flag.patch create mode 100644 queue-6.18/iio-pressure-mprls0025pa-fix-pressure-calculation.patch create mode 100644 queue-6.18/iio-pressure-mprls0025pa-fix-scan_type-struct.patch create mode 100644 queue-6.18/iio-pressure-mprls0025pa-fix-spi-cs-delay-violation.patch create mode 100644 queue-6.18/iio-pressure-mprls0025pa-fix-spi_transfer-struct-ini.patch create mode 100644 queue-6.18/iio-sca3000-fix-a-resource-leak-in-sca3000_probe.patch create mode 100644 queue-6.18/iio-test-drop-dangling-symbol-in-gain-time-scale-hel.patch create mode 100644 queue-6.18/inet-raw-sockets-using-ipproto_raw-must-drop-incomin.patch create mode 100644 queue-6.18/input-adp5589-remove-a-leftover-header-file.patch create mode 100644 queue-6.18/interconnect-mediatek-aggregate-bandwidth-with-satur.patch create mode 100644 queue-6.18/interconnect-mediatek-don-t-hijack-parent-device.patch create mode 100644 queue-6.18/io_uring-cancel-de-unionize-file-and-user_data-in-st.patch create mode 100644 queue-6.18/io_uring-delay-sqarray-static-branch-disablement.patch create mode 100644 queue-6.18/io_uring-eventfd-remove-unused-ctx-evfd_last_cq_tail.patch create mode 100644 queue-6.18/io_uring-kbuf-fix-memory-leak-if-io_buffer_add_list-.patch create mode 100644 queue-6.18/io_uring-sync-validate-passed-in-offset.patch create mode 100644 queue-6.18/io_uring-use-release-acquire-ordering-for-ioring_set.patch create mode 100644 queue-6.18/iomap-fix-submission-side-handling-of-completion-sid.patch create mode 100644 queue-6.18/iommu-amd-use-core-s-primary-handler-and-set-irqf_on.patch create mode 100644 queue-6.18/iommu-vt-d-clear-present-bit-before-tearing-down-con.patch create mode 100644 queue-6.18/iommu-vt-d-clear-present-bit-before-tearing-down-pas.patch create mode 100644 queue-6.18/iommu-vt-d-flush-cache-for-pasid-table-before-using-.patch create mode 100644 queue-6.18/ionic-rate-limit-unknown-xcvr-type-messages.patch create mode 100644 queue-6.18/ipc-don-t-audit-capability-check-in-ipc_permissions.patch create mode 100644 queue-6.18/jfs-avoid-wtautological-constant-out-of-range-compar.patch create mode 100644 queue-6.18/kallsyms-bpf-rename-__bpf_address_lookup-to-bpf_addr.patch create mode 100644 queue-6.18/kallsyms-ftrace-set-module-buildid-in-ftrace_mod_add.patch create mode 100644 queue-6.18/leds-expresswire-fix-chip-state-breakage.patch create mode 100644 queue-6.18/leds-qcom-lpg-check-the-return-value-of-regmap_bulk_.patch create mode 100644 queue-6.18/lib-kstrtox-fix-kstrtobool-docstring-to-mention-enab.patch create mode 100644 queue-6.18/libbpf-fix-oob-read-in-btf_dump_get_bitfield_value.patch create mode 100644 queue-6.18/mcb-fix-incorrect-sanity-check.patch create mode 100644 queue-6.18/mctp-i2c-initialise-event-handler-read-bytes.patch create mode 100644 queue-6.18/md-fix-return-value-of-mddev_trylock.patch create mode 100644 queue-6.18/md-md-llbitmap-fix-percpu_ref-not-resurrected-on-sus.patch create mode 100644 queue-6.18/md-raid1-fix-memory-leak-in-raid1_run.patch create mode 100644 queue-6.18/md-raid10-fix-any_working-flag-handling-in-raid10_sy.patch create mode 100644 queue-6.18/md-raid5-fix-io-hang-with-degraded-array-with-llbitm.patch create mode 100644 queue-6.18/md-raid5-fix-raid5_run-to-return-error-when-log_init.patch create mode 100644 queue-6.18/media-ccs-accommodate-c-phy-into-the-calculation.patch create mode 100644 queue-6.18/media-chips-media-wave5-fix-memory-leak-on-codec_inf.patch create mode 100644 queue-6.18/media-pci-mg4b-use-irqf_no_thread.patch create mode 100644 queue-6.18/media-uvcvideo-fix-allocation-for-small-frame-sizes.patch create mode 100644 queue-6.18/mei-late_bind-fix-struct-intel_lb_component_ops-kern.patch create mode 100644 queue-6.18/mfd-arizona-fix-regulator-resource-leak-on-wm5102_cl.patch create mode 100644 queue-6.18/mfd-simple-mfd-i2c-add-delta-tn48m-cpld-support.patch create mode 100644 queue-6.18/mfd-wm8350-core-use-irqf_oneshot.patch create mode 100644 queue-6.18/mips-loongson32-drop-a-dangling-kconfig-symbol.patch create mode 100644 queue-6.18/mm-slab-fix-false-lockdep-warning-in-__kfree_rcu_she.patch create mode 100644 queue-6.18/mmc-rtsx_pci_sdmmc-increase-power-on-settling-delay-.patch create mode 100644 queue-6.18/module-add-helper-function-for-reading-module_buildi.patch create mode 100644 queue-6.18/mptcp-do-not-account-for-ooo-in-mptcp_rcvbuf_grow.patch create mode 100644 queue-6.18/mptcp-fix-receive-space-timestamp-initialization.patch create mode 100644 queue-6.18/mtd-intel-dg-fix-accessing-regions-before-setting-nr.patch create mode 100644 queue-6.18/mtd-parsers-fix-memory-leak-in-mtd_parser_tplink_saf.patch create mode 100644 queue-6.18/mtd-parsers-ofpart-fix-of-node-refcount-leak-in-pars.patch create mode 100644 queue-6.18/mtd-rawnand-cadence-fix-return-type-of-cdma-send-and.patch create mode 100644 queue-6.18/mtd-spinand-fix-kernel-doc.patch create mode 100644 queue-6.18/net-atm-fix-crash-due-to-unvalidated-vcc-pointer-in-.patch create mode 100644 queue-6.18/net-hns3-fix-double-free-issue-for-tx-spare-buffer.patch create mode 100644 queue-6.18/net-mctp-i2c-fix-duplicate-reception-of-old-data.patch create mode 100644 queue-6.18/net-renesas-rswitch-fix-forwarding-offload-statemach.patch create mode 100644 queue-6.18/net-sunhme-fix-sbus-regression.patch create mode 100644 queue-6.18/netfilter-nf_conncount-fix-tracking-of-connections-f.patch create mode 100644 queue-6.18/netfilter-nf_conncount-increase-the-connection-clean.patch create mode 100644 queue-6.18/netfilter-nf_conncount-make-nf_conncount_gc_list-to-.patch create mode 100644 queue-6.18/netfilter-nf_tables-reset-table-validation-state-on-.patch create mode 100644 queue-6.18/netfilter-nfnetlink_queue-do-shared-unconfirmed-chec.patch create mode 100644 queue-6.18/netfilter-nfnetlink_queue-optimize-verdict-lookup-wi.patch create mode 100644 queue-6.18/netfilter-nft_compat-add-more-restrictions-on-netlin.patch create mode 100644 queue-6.18/netfilter-nft_counter-fix-reset-of-counters-on-32bit.patch create mode 100644 queue-6.18/netfilter-nft_set_hash-fix-get-operation-on-big-endi.patch create mode 100644 queue-6.18/netfilter-nft_set_rbtree-check-for-partial-overlaps-.patch create mode 100644 queue-6.18/netfilter-nft_set_rbtree-don-t-gc-elements-on-insert.patch create mode 100644 queue-6.18/netfilter-nft_set_rbtree-fix-bogus-eexist-with-nlm_f.patch create mode 100644 queue-6.18/netfilter-nft_set_rbtree-remove-seqcount_rwlock_t.patch create mode 100644 queue-6.18/netfilter-nft_set_rbtree-translate-rbtree-to-array-f.patch create mode 100644 queue-6.18/netfilter-nft_set_rbtree-use-binary-search-array-in-.patch create mode 100644 queue-6.18/netfilter-nft_set_rbtree-validate-element-belonging-.patch create mode 100644 queue-6.18/netfilter-nft_set_rbtree-validate-open-interval-over.patch create mode 100644 queue-6.18/netfs-avoid-double-increment-of-retry_count-in-subre.patch create mode 100644 queue-6.18/nfc-hci-shdlc-stop-timers-and-work-before-freeing-co.patch create mode 100644 queue-6.18/nfs-localio-handle-short-writes-by-retrying.patch create mode 100644 queue-6.18/nfs-localio-prevent-direct-reclaim-recursion-into-nf.patch create mode 100644 queue-6.18/nfs-localio-remove-eagain-handling-in-nfs_local_doio.patch create mode 100644 queue-6.18/nfs-localio-use-gfp_noio-and-non-memreclaim-workqueu.patch create mode 100644 queue-6.18/nfs-nfserr_inval-is-not-defined-by-nfsv2.patch create mode 100644 queue-6.18/nfsd-never-defer-requests-during-idmap-lookup.patch create mode 100644 queue-6.18/nvdimm-virtio_pmem-serialize-flush-requests.patch create mode 100644 queue-6.18/nvmem-an8855-drop-an-unused-kconfig-symbol.patch create mode 100644 queue-6.18/octeon_ep-disable-per-ring-interrupts.patch create mode 100644 queue-6.18/octeon_ep-ensure-dbell-baddr-updation.patch create mode 100644 queue-6.18/octeon_ep_vf-ensure-dbell-baddr-updation.patch create mode 100644 queue-6.18/octeontx2-af-fix-pf-driver-crash-with-kexec-kernel-b.patch create mode 100644 queue-6.18/octeontx2-pf-unregister-devlink-on-probe-failure.patch create mode 100644 queue-6.18/of-unittest-fix-possible-null-pointer-dereferences-i.patch create mode 100644 queue-6.18/opp-return-correct-value-in-dev_pm_opp_get_level.patch create mode 100644 queue-6.18/ovl-fix-uninit-value-in-ovl_fill_real.patch create mode 100644 queue-6.18/partial-revert-x86-xen-fix-balloon-target-initializa.patch create mode 100644 queue-6.18/pci-acpi-restrict-program_hpx_type2-to-aer-bits.patch create mode 100644 queue-6.18/pci-add-acs-quirk-for-pericom-pi7c9x2g404-switches-1.patch create mode 100644 queue-6.18/pci-check-parent-for-null-in-of_pci_bus_release_doma.patch create mode 100644 queue-6.18/pci-do-not-attempt-to-set-exttag-for-vfs.patch create mode 100644 queue-6.18/pci-initialize-rcb-from-pci_configure_device.patch create mode 100644 queue-6.18/pci-mark-3ware-9650sa-root-port-extended-tags-as-bro.patch create mode 100644 queue-6.18/pci-mediatek-fix-irq-domain-leak-when-msi-allocation.patch create mode 100644 queue-6.18/pci-p2pdma-fix-p2pmem_alloc_mmap-warning-condition.patch create mode 100644 queue-6.18/pci-p2pdma-release-per-cpu-pgmap-ref-when-vm_insert_.patch create mode 100644 queue-6.18/pci-p2pdma-reset-page-reference-count-when-page-mapp.patch create mode 100644 queue-6.18/pci-pm-avoid-redundant-delays-on-d3hot-d3cold.patch create mode 100644 queue-6.18/pci-portdrv-fix-potential-resource-leak.patch create mode 100644 queue-6.18/pci-ptm-fix-pcie_ptm_create_debugfs-memory-leak.patch create mode 100644 queue-6.18/pci-remove-old_size-limit-from-bridge-window-sizing.patch create mode 100644 queue-6.18/pci-rewrite-bridge-window-head-alignment-function.patch create mode 100644 queue-6.18/pci-sophgo-disable-l0s-and-l1-on-sophgo-2044-pcie-ro.patch create mode 100644 queue-6.18/pci-stop-over-estimating-bridge-window-size.patch create mode 100644 queue-6.18/pci-xilinx-fix-intx-irq-domain-leak-in-error-paths.patch create mode 100644 queue-6.18/perf-arm_spe-properly-set-hw.state-on-failures.patch create mode 100644 queue-6.18/perf-x86-core-do-not-set-bit-width-for-unavailable-c.patch create mode 100644 queue-6.18/phy-freescale-imx8qm-hsio-fix-null-pointer-dereferen.patch create mode 100644 queue-6.18/phy-rockchip-samsung-hdptx-pre-compute-hdmi-pll-conf.patch create mode 100644 queue-6.18/pidfs-return-eremote-when-pidfd_get_info-is-called-o.patch create mode 100644 queue-6.18/pinctrl-canaan-k230-fix-null-pointer-dereference-whe.patch create mode 100644 queue-6.18/pinctrl-equilibrium-fix-device-node-reference-leak-i.patch create mode 100644 queue-6.18/pinctrl-meson-amlogic-a4-fix-device-node-reference-l.patch create mode 100644 queue-6.18/pinctrl-qcom-sm8250-lpass-lpi-fix-i2s2_data_groups-d.patch create mode 100644 queue-6.18/pinctrl-single-fix-refcount-leak-in-pcs_add_gpio_fun.patch create mode 100644 queue-6.18/platform-chrome-cros_ec_lightbar-fix-response-size-i.patch create mode 100644 queue-6.18/platform-chrome-cros_typec_switch-don-t-touch-struct.patch create mode 100644 queue-6.18/platform-x86-amd-pmf-prevent-tee-errors-after-hibern.patch create mode 100644 queue-6.18/platform-x86-hp-wmi-fix-platform-profile-values-for-.patch create mode 100644 queue-6.18/platform-x86-int0002-remove-irqf_oneshot-from-reques.patch create mode 100644 queue-6.18/pm-sleep-wakeirq-harden-dev_pm_clear_wake_irq-agains.patch create mode 100644 queue-6.18/pm-wakeup-handle-empty-list-in-wakeup_sources_walk_s.patch create mode 100644 queue-6.18/pnfs-fix-a-missing-wake-up-while-waiting-on-nfs_layo.patch create mode 100644 queue-6.18/power-reset-nvmem-reboot-mode-respect-cell-size-for-.patch create mode 100644 queue-6.18/power-supply-ab8500-fix-use-after-free-in-power_supp.patch create mode 100644 queue-6.18/power-supply-act8945a-fix-use-after-free-in-power_su.patch create mode 100644 queue-6.18/power-supply-bq256xx-fix-use-after-free-in-power_sup.patch create mode 100644 queue-6.18/power-supply-bq25980-fix-use-after-free-in-power_sup.patch create mode 100644 queue-6.18/power-supply-bq27xxx-fix-wrong-errno-when-bus-ops-ar.patch create mode 100644 queue-6.18/power-supply-cpcap-battery-fix-use-after-free-in-pow.patch create mode 100644 queue-6.18/power-supply-goldfish-fix-use-after-free-in-power_su.patch create mode 100644 queue-6.18/power-supply-pm8916_bms_vm-fix-use-after-free-in-pow.patch create mode 100644 queue-6.18/power-supply-pm8916_lbc-fix-use-after-free-for-extco.patch create mode 100644 queue-6.18/power-supply-pm8916_lbc-fix-use-after-free-in-power_.patch create mode 100644 queue-6.18/power-supply-qcom_battmgr-recognize-lip-as-lithium-p.patch create mode 100644 queue-6.18/power-supply-rt9455-fix-use-after-free-in-power_supp.patch create mode 100644 queue-6.18/power-supply-sbs-battery-fix-use-after-free-in-power.patch create mode 100644 queue-6.18/power-supply-wm97xx-fix-null-pointer-dereference-in-.patch create mode 100644 queue-6.18/powerpc-eeh-fix-recursive-pci_lock_rescan_remove-loc.patch create mode 100644 queue-6.18/powerpc-uaccess-move-barrier_nospec-out-of-allow_rea.patch create mode 100644 queue-6.18/printk-vt-fbcon-remove-console_conditional_schedule.patch create mode 100644 queue-6.18/procfs-fix-missing-rcu-protection-when-reading-real_.patch create mode 100644 queue-6.18/pstore-ram-fix-buffer-overflow-in-persistent_ram_sav.patch create mode 100644 queue-6.18/pwm-tiehrpwm-enable-pwmchip-s-parent-device-before-s.patch create mode 100644 queue-6.18/quota-fix-livelock-between-quotactl-and-freeze_super.patch create mode 100644 queue-6.18/rcu-fix-rcu_read_unlock-deadloop-due-to-softirq.patch create mode 100644 queue-6.18/rdma-core-add-rdma_rw_max_sge-helper-for-sq-sizing.patch create mode 100644 queue-6.18/rdma-hns-fix-rocev1-failure-due-to-dscp.patch create mode 100644 queue-6.18/rdma-hns-fix-wq_mem_reclaim-warning.patch create mode 100644 queue-6.18/rdma-hns-notify-ulp-of-remaining-soft-wcs-during-res.patch create mode 100644 queue-6.18/rdma-iwcm-fix-workqueue-list-corruption-by-removing-.patch create mode 100644 queue-6.18/rdma-mlx5-fix-memory-leak-in-get_data_direct_sysfs_p.patch create mode 100644 queue-6.18/rdma-mlx5-fix-ucaps-init-error-flow.patch create mode 100644 queue-6.18/rdma-mlx5-fix-umr-hang-in-lag-error-state-unload.patch create mode 100644 queue-6.18/rdma-rtrs-server-remove-dead-code.patch create mode 100644 queue-6.18/rdma-rtrs-srv-fix-sg-mapping.patch create mode 100644 queue-6.18/rdma-rxe-fix-double-free-in-rxe_srq_from_init.patch create mode 100644 queue-6.18/rdma-rxe-fix-iova-to-va-conversion-for-mr-page-sizes.patch create mode 100644 queue-6.18/rdma-rxe-fix-race-condition-in-qp-timer-handlers.patch create mode 100644 queue-6.18/rdma-uverbs-add-__gfp_nowarn-to-ib_uverbs_unmarshall.patch create mode 100644 queue-6.18/rdma-uverbs-validate-wqe_size-before-using-it-in-ib_.patch create mode 100644 queue-6.18/regulator-core-move-supply-check-earlier-in-set_mach.patch create mode 100644 queue-6.18/remoteproc-imx_dsp_rproc-only-reset-carveout-memory-.patch create mode 100644 queue-6.18/reset-canaan-k230-drop-of-dependency-and-enable-by-d.patch create mode 100644 queue-6.18/revert-hwmon-ibmpex-fix-use-after-free-in-high-low-s.patch create mode 100644 queue-6.18/revert-mailbox-pcc-support-mailbox-management-of-the.patch create mode 100644 queue-6.18/revert-mmc-rtsx_pci_sdmmc-increase-power-on-settling.patch create mode 100644 queue-6.18/rnbd-srv-fix-server-side-setting-of-bi_size-for-spec.patch create mode 100644 queue-6.18/rqspinlock-fix-tas-fallback-lock-entry-creation.patch create mode 100644 queue-6.18/rtc-amlogic-a4-remove-irqf_oneshot.patch create mode 100644 queue-6.18/rust-task-restrict-task-group_leader-to-current.patch create mode 100644 queue-6.18/s390-cio-fix-device-lifecycle-handling-in-css_alloc_.patch create mode 100644 queue-6.18/sched-deadline-clear-the-defer-params.patch create mode 100644 queue-6.18/sched-export-hidden-tracepoints-to-modules.patch create mode 100644 queue-6.18/sched-fix-build-for-modules-using-set_tsk_need_resch.patch create mode 100644 queue-6.18/sched-rt-skip-currently-executing-cpu-in-rto_next_cp.patch create mode 100644 queue-6.18/scsi-csiostor-fix-dereference-of-null-pointer-rn.patch create mode 100644 queue-6.18/scsi-efct-use-irqf_oneshot-and-default-primary-handl.patch create mode 100644 queue-6.18/scsi-smartpqi-fix-memory-leak-in-pqi_report_phys_lun.patch create mode 100644 queue-6.18/scsi-ufs-host-mediatek-require-config_pm.patch create mode 100644 queue-6.18/selftests-bpf-fix-kprobe-multi-stacktrace_ips-test.patch create mode 100644 queue-6.18/selftests-bpf-fix-resource-leak-in-serial_test_wq-on.patch create mode 100644 queue-6.18/selftests-bpf-test_xsk-split-xskxceiver.patch create mode 100644 queue-6.18/selftests-bpf-veristat-fix-printing-order-in-output_.patch create mode 100644 queue-6.18/selftests-mm-fix-faulting-in-code-in-pagemap_ioctl-t.patch create mode 100644 queue-6.18/selftests-mm-fix-usage-of-force_read-in-cow-tests.patch create mode 100644 queue-6.18/selftests-resctrl-fix-a-division-by-zero-error-on-hy.patch create mode 100644 queue-6.18/selftests-xsk-fix-number-of-tx-frags-in-invalid-pack.patch create mode 100644 queue-6.18/selftests-xsk-properly-handle-batch-ending-in-the-mi.patch create mode 100644 queue-6.18/serial-caif-fix-use-after-free-in-caif_serial-ldisc_.patch create mode 100644 queue-6.18/serial-imx-change-serial_imx_console-to-bool.patch create mode 100644 queue-6.18/serial-sh_sci-improve-dma-support-prompt.patch create mode 100644 queue-6.18/smack-smack-doi-accept-previously-used-values.patch create mode 100644 queue-6.18/smack-smack-doi-must-be-0.patch create mode 100644 queue-6.18/smb-client-correct-value-for-smbd_max_fragmented_rec.patch create mode 100644 queue-6.18/smb-client-fix-potential-uaf-and-double-free-in-smb2.patch create mode 100644 queue-6.18/soc-mediatek-svs-fix-memory-leak-in-svs_enable_debug.patch create mode 100644 queue-6.18/soc-qcom-cmd-db-use-devm_memremap-to-fix-memory-leak.patch create mode 100644 queue-6.18/soc-qcom-smem-handle-enomem-error-during-probe.patch create mode 100644 queue-6.18/soc-qcom-ubwc-add-missing-include.patch create mode 100644 queue-6.18/soundwire-intel_ace2x-add-snd_hda_core-dependency.patch create mode 100644 queue-6.18/spi-tools-add-include-folder-to-.gitignore.patch create mode 100644 queue-6.18/staging-greybus-lights-avoid-null-deref.patch create mode 100644 queue-6.18/tcp-accecn-handle-unexpected-accecn-negotiation-feed.patch create mode 100644 queue-6.18/tcp-disable-rfc3168-fallback-identifier-for-cc-modul.patch create mode 100644 queue-6.18/tcp-ect_1_negotiation-and-needs_accecn-identifiers.patch create mode 100644 queue-6.18/tcp-tcp_tx_timestamp-must-look-at-the-rtx-queue.patch create mode 100644 queue-6.18/thermal-intel-x86_pkg_temp_thermal-handle-invalid-te.patch create mode 100644 queue-6.18/thermal-of-fix-reference-leak-in-thermal_of_cm_looku.patch create mode 100644 queue-6.18/time-sched_clock-use-access_private-to-evaluate-hrti.patch create mode 100644 queue-6.18/tools-power-x86-intel-speed-select-fix-file-descript.patch create mode 100644 queue-6.18/tpm-st33zp24-fix-missing-cleanup-on-get_burstcount-e.patch create mode 100644 queue-6.18/tpm-tpm_i2c_infineon-fix-locality-leak-on-get_burstc.patch create mode 100644 queue-6.18/tracing-properly-process-error-handling-in-event_his.patch create mode 100644 queue-6.18/tracing-remove-duplicate-enable_event_str-and-disabl.patch create mode 100644 queue-6.18/ublk-restore-auto-buf-unregister-refcount-optimizati.patch create mode 100644 queue-6.18/ublk-validate-sqe128-flag-before-accessing-the-cmd.patch create mode 100644 queue-6.18/ucount-check-for-cap_sys_resource-using-ns_capable_n.patch create mode 100644 queue-6.18/usb-bdc-fix-sleep-during-atomic.patch create mode 100644 queue-6.18/usb-typec-fusb302-remove-irqf_oneshot.patch create mode 100644 queue-6.18/usb-typec-ucsi-drop-an-unused-kconfig-symbol.patch create mode 100644 queue-6.18/vfio-pci-lock-upstream-bridge-for-vfio_pci_core_disa.patch create mode 100644 queue-6.18/watchdog-starfive-wdt-fix-pm-reference-leak-in-probe.patch create mode 100644 queue-6.18/wifi-ath10k-sdio-add-missing-lock-protection-in-ath1.patch create mode 100644 queue-6.18/wifi-ath11k-add-usecase-firmware-handling-based-on-d.patch create mode 100644 queue-6.18/wifi-ath12k-clear-stale-link-mapping-of-ahvif-links_.patch create mode 100644 queue-6.18/wifi-ath12k-do-wow-offloads-only-on-primary-link.patch create mode 100644 queue-6.18/wifi-ath12k-fix-index-decrement-when-array_len-is-ze.patch create mode 100644 queue-6.18/wifi-ath9k-add-of-dependency-to-ahb.patch create mode 100644 queue-6.18/wifi-cfg80211-fix-use_for-flag-update-on-bss-refresh.patch create mode 100644 queue-6.18/wifi-cfg80211-stop-nan-and-p2p-in-cfg80211_leave.patch create mode 100644 queue-6.18/wifi-rtw89-debug-fix-memory-leak-in-__print_txpwr_ma.patch create mode 100644 queue-6.18/workqueue-factor-out-assign_rescuer_work.patch create mode 100644 queue-6.18/workqueue-only-assign-rescuer-work-when-really-neede.patch create mode 100644 queue-6.18/workqueue-process-rescuer-work-items-one-by-one-usin.patch create mode 100644 queue-6.18/x86-cpu-amd-correct-the-microcode-table-for-zenbleed.patch create mode 100644 queue-6.18/x86-fgraph-bpf-switch-kprobe_multi-program-stack-unw.patch create mode 100644 queue-6.18/x86-fgraph-fix-return_to_handler-regs.rsp-value.patch create mode 100644 queue-6.18/xdrgen-fix-struct-prefix-for-typedef-types-in-progra.patch create mode 100644 queue-6.18/xdrgen-initialize-data-pointer-for-zero-length-items.patch create mode 100644 queue-6.18/xdrgen-remove-inclusion-of-nlm4.h-header.patch create mode 100644 queue-6.18/xen-virtio-don-t-use-grant-dma-ops-when-running-as-d.patch create mode 100644 queue-6.18/xfrm-fix-ip_rt_bug-race-in-icmp_route_lookup-reverse.patch create mode 100644 queue-6.19/accel-amdxdna-enable-temporal-sharing-only-mode.patch create mode 100644 queue-6.19/accel-amdxdna-fix-cu_idx-being-cleared-by-memset-dur.patch create mode 100644 queue-6.19/accel-amdxdna-fix-incorrect-dpm-level-after-suspend-.patch create mode 100644 queue-6.19/accel-amdxdna-fix-incorrect-error-code-returned-for-.patch create mode 100644 queue-6.19/accel-amdxdna-fix-memory-leak-in-amdxdna_ubuf_map.patch create mode 100644 queue-6.19/accel-amdxdna-fix-notifier_wq-flushing-warning.patch create mode 100644 queue-6.19/accel-amdxdna-fix-potential-null-pointer-dereference.patch create mode 100644 queue-6.19/accel-amdxdna-fix-race-condition-when-checking-rpm_o.patch create mode 100644 queue-6.19/accel-amdxdna-fix-race-where-send-ring-appears-full-.patch create mode 100644 queue-6.19/accel-amdxdna-hold-mm-structure-across-iommu_sva_unb.patch create mode 100644 queue-6.19/accel-amdxdna-move-rpm-resume-into-job-run-function.patch create mode 100644 queue-6.19/accel-amdxdna-remove-hardware-context-status.patch create mode 100644 queue-6.19/accel-amdxdna-stop-job-scheduling-across-aie2_releas.patch create mode 100644 queue-6.19/acpi-processor-update-cpuidle-driver-check-in-__acpi.patch create mode 100644 queue-6.19/acpica-fix-null-pointer-dereference-in-acpi_ev_addre.patch create mode 100644 queue-6.19/af_unix-fix-memleak-of-newsk-in-unix_stream_connect.patch create mode 100644 queue-6.19/alsa-compress_offload-relax-__free-variable-declarat.patch create mode 100644 queue-6.19/alsa-control-relax-__free-variable-declarations.patch create mode 100644 queue-6.19/alsa-hda-fix-function-names-missing-function-paramet.patch create mode 100644 queue-6.19/alsa-hda-relax-__free-variable-declarations.patch create mode 100644 queue-6.19/alsa-oss-delete-self-assignment.patch create mode 100644 queue-6.19/alsa-oss-relax-__free-variable-declarations.patch create mode 100644 queue-6.19/alsa-pcm-relax-__free-variable-declarations.patch create mode 100644 queue-6.19/alsa-seq-oss-relax-__free-variable-declarations.patch create mode 100644 queue-6.19/alsa-seq-relax-__free-variable-declarations.patch create mode 100644 queue-6.19/alsa-timer-relax-__free-variable-declarations.patch create mode 100644 queue-6.19/alsa-usb-audio-relax-__free-variable-declarations.patch create mode 100644 queue-6.19/alsa-usx2y-relax-__free-variable-declarations.patch create mode 100644 queue-6.19/alsa-vmaster-relax-__free-variable-declarations.patch create mode 100644 queue-6.19/amd-xgbe-do-not-select-net_selftests-when-inet-is-di.patch create mode 100644 queue-6.19/arm-dts-allwinner-sun5i-a13-utoo-p66-delete-power-gp.patch create mode 100644 queue-6.19/arm-dts-lpc32xx-add-clocks-property-to-motor-control.patch create mode 100644 queue-6.19/arm-vdso-patch-out-__vdso_clock_getres-if-unavailabl.patch create mode 100644 queue-6.19/arm64-dts-amlogic-axg-assign-the-mmc-signal-clocks.patch create mode 100644 queue-6.19/arm64-dts-amlogic-c3-assign-the-mmc-signal-clocks.patch create mode 100644 queue-6.19/arm64-dts-amlogic-g12-assign-the-mmc-a-signal-clock.patch create mode 100644 queue-6.19/arm64-dts-amlogic-g12-assign-the-mmc-b-and-c-signal-.patch create mode 100644 queue-6.19/arm64-dts-amlogic-gx-assign-the-mmc-signal-clocks.patch create mode 100644 queue-6.19/arm64-dts-amlogic-meson-sm1-odroid-eliminate-odroid-.patch create mode 100644 queue-6.19/arm64-dts-amlogic-s4-assign-mmc-b-clock-to-24mhz.patch create mode 100644 queue-6.19/arm64-dts-amlogic-s4-fix-mmc-clock-assignment.patch create mode 100644 queue-6.19/arm64-dts-imx95-use-gpu_cgc-as-core-clock-for-gpu.patch create mode 100644 queue-6.19/arm64-dts-mediatek-mt8183-jacuzzi-pico6-fix-typo-in-.patch create mode 100644 queue-6.19/arm64-dts-qcom-agatti-add-cx_mem-dbgc-gpu-regions.patch create mode 100644 queue-6.19/arm64-dts-qcom-msm8994-octagon-fix-analog-devices-ve.patch create mode 100644 queue-6.19/arm64-dts-qcom-qrb4210-rb2-fix-uart3-wakeup-irq-stor.patch create mode 100644 queue-6.19/arm64-dts-qcom-sdm630-fix-gpu_speed_bin-size.patch create mode 100644 queue-6.19/arm64-dts-qcom-sdm845-db845c-drop-cs-from-spio0.patch create mode 100644 queue-6.19/arm64-dts-qcom-sdm845-db845c-specify-power-for-wifi-.patch create mode 100644 queue-6.19/arm64-dts-qcom-sdm845-oneplus-don-t-keep-panel-regul.patch create mode 100644 queue-6.19/arm64-dts-qcom-sdm845-oneplus-don-t-mark-ts-supply-b.patch create mode 100644 queue-6.19/arm64-dts-qcom-sdm845-oneplus-mark-l14a-regulator-as.patch create mode 100644 queue-6.19/arm64-dts-qcom-sdm850-huawei-matebook-e-2019-correct.patch create mode 100644 queue-6.19/arm64-dts-qcom-sdm850-huawei-matebook-e-2019-remove-.patch create mode 100644 queue-6.19/arm64-dts-qcom-sm6115-add-cx_mem-dbgc-gpu-regions.patch create mode 100644 queue-6.19/arm64-dts-qcom-sm8150-hdk-mtp-specify-zap-firmware-n.patch create mode 100644 queue-6.19/arm64-dts-qcom-sm8250-hdk-specify-zap-firmware-name.patch create mode 100644 queue-6.19/arm64-dts-qcom-talos-drop-opp-shared-from-qup-opp-ta.patch create mode 100644 queue-6.19/arm64-dts-qcom-x1e-bus-is-40-bits-fix-64gb-models.patch create mode 100644 queue-6.19/arm64-dts-qcom-x1e80100-fix-usb-combo-phys-ss1-and-s.patch create mode 100644 queue-6.19/arm64-dts-renesas-r9a09g047e57-smarc-remove-duplicat.patch create mode 100644 queue-6.19/arm64-dts-renesas-rzt2h-n2h-evk-common-use-gpio-for-.patch create mode 100644 queue-6.19/arm64-dts-ti-k3-am67a-kontron-sa67-base-fix-cma-node.patch create mode 100644 queue-6.19/arm64-dts-ti-k3-am67a-kontron-sa67-base-fix-sd-card-.patch create mode 100644 queue-6.19/arm64-dts-ti-k3-am69-aquila-clover-fix-usb-c-sink-pd.patch create mode 100644 queue-6.19/arm64-dts-ti-k3-am69-aquila-dev-fix-usb-c-sink-pdo.patch create mode 100644 queue-6.19/arm64-dts-ti-k3-j784s4-j742s2-main-common.dtsi-refac.patch create mode 100644 queue-6.19/arm64-dts-ti-k3-j784s4-main.dtsi-move-c71_3-node-to-.patch create mode 100644 queue-6.19/arm64-dts-tqma8mpql-mba8mp-ras314-fix-hdmi-cec-pad-c.patch create mode 100644 queue-6.19/arm64-dts-tqma8mpql-mba8mpxl-fix-hdmi-cec-pad-contro.patch create mode 100644 queue-6.19/arm64-gcs-fix-error-handling-in-arch_set_shadow_stac.patch create mode 100644 queue-6.19/asoc-cs4271-fix-resource-leak-in-cs4271_soc_resume.patch create mode 100644 queue-6.19/asoc-nau8821-cancel-delayed-work-on-component-remove.patch create mode 100644 queue-6.19/asoc-nau8821-cancel-pending-work-before-suspend.patch create mode 100644 queue-6.19/asoc-nau8821-fixup-nau8821_enable_jack_detect.patch create mode 100644 queue-6.19/asoc-sdca-add-ability-to-connect-sdca-jacks-to-asoc-.patch create mode 100644 queue-6.19/asoc-sdca-allow-sample-width-wild-cards-in-set_usage.patch create mode 100644 queue-6.19/asoc-sdca-factor-out-jack-handling-into-new-c-file.patch create mode 100644 queue-6.19/asoc-sdca-handle-volatile-controls-correctly.patch create mode 100644 queue-6.19/asoc-sdca-remove-outdated-todo-comment.patch create mode 100644 queue-6.19/asoc-sdca-still-process-most-of-the-jack-detect-if-c.patch create mode 100644 queue-6.19/asoc-tegra-add-ahub-writeable_reg-for-rx-holes.patch create mode 100644 queue-6.19/ata-libata-add-ata_quirk_max_sec-and-convert-all-dev.patch create mode 100644 queue-6.19/ata-libata-core-quirk-intel-ssdsc2kg480g8-max_sector.patch create mode 100644 queue-6.19/audit-move-the-compat_xxx_class-extern-declarations-.patch create mode 100644 queue-6.19/auxdisplay-arm-charlcd-fix-release_mem_region-size.patch create mode 100644 queue-6.19/backlight-aw99706-fix-build-errors-caused-by-wrong-g.patch create mode 100644 queue-6.19/backlight-qcom-wled-change-pm8950-wled-configuration.patch create mode 100644 queue-6.19/backlight-qcom-wled-support-ovp-values-for-pmi8994.patch create mode 100644 queue-6.19/block-allow-ioc_pr_read_-ioctls-with-blk_open_read.patch create mode 100644 queue-6.19/block-don-t-use-strcpy-to-copy-blockdev-name.patch create mode 100644 queue-6.19/bluetooth-btintel_pcie-use-irqf_oneshot-and-default-.patch create mode 100644 queue-6.19/bluetooth-hci_conn-fix-using-conn-le_-tx-rx-_phy-as-.patch create mode 100644 queue-6.19/bonding-only-set-speed-duplex-to-unknown-if-getting-.patch create mode 100644 queue-6.19/bpf-bpf_scc_visit-instance-and-backedges-accumulatio.patch create mode 100644 queue-6.19/bpf-fix-bpf_xdp_store_bytes-proto-for-read-only-arg.patch create mode 100644 queue-6.19/bpf-fix-memory-access-flags-in-helper-prototypes.patch create mode 100644 queue-6.19/bpf-fix-tcx-netkit-detach-permissions-when-prog-fd-i.patch create mode 100644 queue-6.19/bpf-fix-verifier_bug_if-to-account-for-bpf_call.patch create mode 100644 queue-6.19/bpf-limit-bpf-program-signature-size.patch create mode 100644 queue-6.19/bpf-preserve-id-of-register-in-sync_linked_regs.patch create mode 100644 queue-6.19/bpf-require-frozen-map-for-calculating-map-hash.patch create mode 100644 queue-6.19/bpf-return-proper-address-for-non-zero-offsets-in-in.patch create mode 100644 queue-6.19/bpf-sockmap-fix-fionread-for-sockmap.patch create mode 100644 queue-6.19/bpf-sockmap-fix-incorrect-copied_seq-calculation.patch create mode 100644 queue-6.19/btrfs-fix-block_group_tree-dirty_list-corruption.patch create mode 100644 queue-6.19/btrfs-fix-eexist-abort-due-to-non-consecutive-gaps-i.patch create mode 100644 queue-6.19/btrfs-qgroup-return-correct-error-when-deleting-qgro.patch create mode 100644 queue-6.19/btrfs-zoned-don-t-zone-append-to-conventional-zone.patch create mode 100644 queue-6.19/char-misc-use-is_err-for-filp_open-return-value.patch create mode 100644 queue-6.19/clk-actions-owl-composite-convert-from-owl_divider_h.patch create mode 100644 queue-6.19/clk-actions-owl-divider-convert-from-divider_round_r.patch create mode 100644 queue-6.19/clk-bm1880-convert-from-divider_round_rate-to-divide.patch create mode 100644 queue-6.19/clk-hisilicon-clkdivider-hi6220-convert-from-divider.patch create mode 100644 queue-6.19/clk-loongson1-convert-from-divider_round_rate-to-div.patch create mode 100644 queue-6.19/clk-mediatek-add-mfg_eb-as-parent-to-mt8196-mfgpll-c.patch create mode 100644 queue-6.19/clk-mediatek-drop-__initconst-from-gates.patch create mode 100644 queue-6.19/clk-mediatek-fix-error-handling-in-runtime-pm-setup.patch create mode 100644 queue-6.19/clk-meson-g12a-limit-the-hdmi-pll-od-to-4.patch create mode 100644 queue-6.19/clk-meson-gxbb-limit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch create mode 100644 queue-6.19/clk-microchip-core-remove-duplicate-determine_rate-o.patch create mode 100644 queue-6.19/clk-milbeaut-convert-from-divider_round_rate-to-divi.patch create mode 100644 queue-6.19/clk-move-clk_-save-restore-_context-to-common_clk-se.patch create mode 100644 queue-6.19/clk-nuvoton-ma35d1-divider-convert-from-divider_roun.patch create mode 100644 queue-6.19/clk-nxp-lpc32xx-convert-from-divider_round_rate-to-d.patch create mode 100644 queue-6.19/clk-qcom-alpha-pll-convert-from-divider_round_rate-t.patch create mode 100644 queue-6.19/clk-qcom-dispcc-sdm845-enable-parents-for-pixel-cloc.patch create mode 100644 queue-6.19/clk-qcom-dispcc-sm7150-fix-dispcc_mdss_pclk1_clk_src.patch create mode 100644 queue-6.19/clk-qcom-gcc-glymur-update-the-sdcc-rcgs-to-use-shar.patch create mode 100644 queue-6.19/clk-qcom-gcc-ipq5018-flag-sleep-clock-as-critical.patch create mode 100644 queue-6.19/clk-qcom-gcc-milos-update-the-sdcc-rcgs-to-use-share.patch create mode 100644 queue-6.19/clk-qcom-gcc-msm8917-remove-always_on-flag-from-cpp_.patch create mode 100644 queue-6.19/clk-qcom-gcc-msm8953-remove-always_on-flag-from-cpp_.patch create mode 100644 queue-6.19/clk-qcom-gcc-qdu1000-update-the-sdcc-rcgs-to-use-sha.patch create mode 100644 queue-6.19/clk-qcom-gcc-sdx75-update-the-sdcc-rcgs-to-use-share.patch create mode 100644 queue-6.19/clk-qcom-gcc-sm4450-update-the-sdcc-rcgs-to-use-shar.patch create mode 100644 queue-6.19/clk-qcom-gcc-sm8450-update-the-sdcc-rcgs-to-use-shar.patch create mode 100644 queue-6.19/clk-qcom-gcc-sm8550-use-floor-ops-for-sdcc-rcgs.patch create mode 100644 queue-6.19/clk-qcom-gcc-sm8650-use-floor-ops-for-sdcc-rcgs.patch create mode 100644 queue-6.19/clk-qcom-gcc-sm8750-update-the-sdcc-rcgs-to-use-shar.patch create mode 100644 queue-6.19/clk-qcom-gcc-x1e80100-update-the-sdcc-rcgs-to-use-sh.patch create mode 100644 queue-6.19/clk-qcom-gfx3d-add-parent-to-parent-request-map.patch create mode 100644 queue-6.19/clk-qcom-rcg2-compute-2d-using-duty-fraction-directl.patch create mode 100644 queue-6.19/clk-qcom-regmap-divider-convert-from-divider_ro_roun.patch create mode 100644 queue-6.19/clk-qcom-regmap-divider-convert-from-divider_round_r.patch create mode 100644 queue-6.19/clk-qcom-return-correct-error-code-in-qcom_cc_probe_.patch create mode 100644 queue-6.19/clk-respect-clk_ops_parent_enable-during-recalc.patch create mode 100644 queue-6.19/clk-rockchip-fix-error-pointer-check-after-rockchip_.patch create mode 100644 queue-6.19/clk-sophgo-sg2042-clkgen-convert-from-divider_round_.patch create mode 100644 queue-6.19/clk-spacemit-respect-kconfig-setting-when-building-m.patch create mode 100644 queue-6.19/clk-sprd-div-convert-from-divider_round_rate-to-divi.patch create mode 100644 queue-6.19/clk-stm32-stm32-core-convert-from-divider_ro_round_r.patch create mode 100644 queue-6.19/clk-stm32-stm32-core-convert-from-divider_round_rate.patch create mode 100644 queue-6.19/clk-thead-th1520-ap-poll-for-pll-lock-and-wait-for-s.patch create mode 100644 queue-6.19/clk-versaclock3-convert-from-divider_round_rate-to-d.patch create mode 100644 queue-6.19/clk-x86-cgu-convert-from-divider_round_rate-to-divid.patch create mode 100644 queue-6.19/clk-zynqmp-divider-convert-from-divider_round_rate-t.patch create mode 100644 queue-6.19/clk-zynqmp-divider-fix-zynqmp_clk_divider_determine_.patch create mode 100644 queue-6.19/clk-zynqmp-pll-fix-zynqmp_clk_divider_determine_rate.patch create mode 100644 queue-6.19/clocksource-drivers-timer-sp804-fix-an-oops-when-rea.patch create mode 100644 queue-6.19/coresight-etm3x-fix-cpulocked-warning-on-cpuhp.patch create mode 100644 queue-6.19/coresight-tmc-etr-fix-race-condition-between-sysfs-a.patch create mode 100644 queue-6.19/cpufreq-intel_pstate-enable-asym-capacity-only-when-.patch create mode 100644 queue-6.19/cpufreq-scmi-correct-scmi-explanation.patch create mode 100644 queue-6.19/cpufreq-scmi-fix-device_node-reference-leak-in-scmi_.patch create mode 100644 queue-6.19/cpuidle-governors-menu-always-check-timers-with-tick.patch create mode 100644 queue-6.19/crypto-caam-fix-netdev-memory-leak-in-dpaa2_caam_pro.patch create mode 100644 queue-6.19/crypto-cavium-fix-dma_free_coherent-size.patch create mode 100644 queue-6.19/crypto-ccp-add-an-s4-restore-flow.patch create mode 100644 queue-6.19/crypto-ccp-declare-psp-dead-if-psp_cmd_tee_ring_init.patch create mode 100644 queue-6.19/crypto-ccp-factor-out-ring-destroy-handling-to-a-hel.patch create mode 100644 queue-6.19/crypto-ccp-fix-a-case-where-snp_shutdown-is-missed.patch create mode 100644 queue-6.19/crypto-ccp-fix-a-crash-due-to-incorrect-cleanup-usag.patch create mode 100644 queue-6.19/crypto-ccp-narrow-scope-of-snp_range_list.patch create mode 100644 queue-6.19/crypto-ccp-send-psp_cmd_tee_ring_destroy-when-psp_cm.patch create mode 100644 queue-6.19/crypto-hisilicon-consolidate-qp-creation-and-start-i.patch create mode 100644 queue-6.19/crypto-hisilicon-hpre-extend-tag-field-to-64-bits-fo.patch create mode 100644 queue-6.19/crypto-hisilicon-hpre-support-the-hpre-algorithm-fal.patch create mode 100644 queue-6.19/crypto-hisilicon-qm-centralize-the-sending-locks-of-.patch create mode 100644 queue-6.19/crypto-hisilicon-qm-enhance-the-configuration-of-req.patch create mode 100644 queue-6.19/crypto-hisilicon-sec-move-backlog-management-to-qp-a.patch create mode 100644 queue-6.19/crypto-hisilicon-sec2-support-skcipher-aead-fallback.patch create mode 100644 queue-6.19/crypto-hisilicon-sgl-fix-inconsistent-map-unmap-dire.patch create mode 100644 queue-6.19/crypto-hisilicon-trng-support-tfms-sharing-the-devic.patch create mode 100644 queue-6.19/crypto-hisilicon-zip-adjust-the-way-to-obtain-the-re.patch create mode 100644 queue-6.19/crypto-hisilicon-zip-support-fallback-for-zip.patch create mode 100644 queue-6.19/crypto-inside-secure-eip93-fix-kernel-panic-in-drive.patch create mode 100644 queue-6.19/crypto-inside-secure-eip93-unregister-only-available.patch create mode 100644 queue-6.19/crypto-octeontx-fix-dma_free_coherent-size.patch create mode 100644 queue-6.19/crypto-qat-fix-parameter-order-used-in-icp_qat_fw_co.patch create mode 100644 queue-6.19/crypto-qat-fix-warning-on-adf_pfvf_pf_proto.c.patch create mode 100644 queue-6.19/crypto-starfive-fix-memory-leak-in-starfive_aes_aead.patch create mode 100644 queue-6.19/cxl-core-fix-cxl_dport-debugfs-einj-entries.patch create mode 100644 queue-6.19/cxl-fix-premature-commit_end-increment-on-decoder-co.patch create mode 100644 queue-6.19/cxl-hdm-fix-newline-character-in-dev_err-messages.patch create mode 100644 queue-6.19/cxl-mem-fix-devm_cxl_memdev_edac_release-confusion.patch create mode 100644 queue-6.19/device_cgroup-remove-branch-hint-after-code-refactor.patch create mode 100644 queue-6.19/dm-fix-unlocked-test-for-dm_suspended_md.patch create mode 100644 queue-6.19/dm-use-bio_clone_blkg_association.patch create mode 100644 queue-6.19/dm-use-read_once-in-dm_blk_report_zones.patch create mode 100644 queue-6.19/dma-dma-axi-dmac-fix-hw-scatter-gather-not-looking-a.patch create mode 100644 queue-6.19/dma-dma-axi-dmac-fix-sw-cyclic-transfers.patch create mode 100644 queue-6.19/dmaengine-fsl-edma-don-t-explicitly-disable-clocks-i.patch create mode 100644 queue-6.19/dmaengine-mediatek-uart-apdma-fix-above-4g-addressin.patch create mode 100644 queue-6.19/docs-find-unused-docs.sh-fixup-directory-usage.patch create mode 100644 queue-6.19/documentation-pci-endpoint-fix-ntb-vntb-copy-paste-e.patch create mode 100644 queue-6.19/documentation-tracing-add-pci-tracepoint-documentati.patch create mode 100644 queue-6.19/dpll-zl3073x-fix-output-pin-phase-adjustment-sign.patch create mode 100644 queue-6.19/drbd-always-set-blk_feat_stable_writes.patch create mode 100644 queue-6.19/drivers-iio-mpu3050-use-dev_err_probe-for-regulator-.patch create mode 100644 queue-6.19/drm-amd-display-don-t-repeat-dac-load-detection.patch create mode 100644 queue-6.19/drm-amd-display-don-t-use-kernel-doc-comment-in-dc_r.patch create mode 100644 queue-6.19/drm-amd-display-pass-proper-dac-encoder-id-to-vbios.patch create mode 100644 queue-6.19/drm-amd-display-remove-unused-encoder-types.patch create mode 100644 queue-6.19/drm-amd-display-update-dc_connection_dac_load-to-dc_.patch create mode 100644 queue-6.19/drm-amd-display-use-local-variable-for-analog_engine.patch create mode 100644 queue-6.19/drm-amd-drop-amdgpu-kernel-modesetting-enabled-messa.patch create mode 100644 queue-6.19/drm-amd-pm-fix-unneeded-semicolon-warning.patch create mode 100644 queue-6.19/drm-amd-pm-return-eopnotsupp-when-can-t-read-power-l.patch create mode 100644 queue-6.19/drm-amdgpu-describe-amd_ip_block_type_ras-in-amd_ip_.patch create mode 100644 queue-6.19/drm-amdgpu-don-t-attach-the-tlb-fence-for-si.patch create mode 100644 queue-6.19/drm-amdgpu-drop-mmio_remap-domain-bit-and-keep-it-in.patch create mode 100644 queue-6.19/drm-amdgpu-ttm-pin-4k-mmio_remap-singleton-bo-at-ini.patch create mode 100644 queue-6.19/drm-amdgpu-use-explicit-vcn-instance-0-in-sr-iov-ini.patch create mode 100644 queue-6.19/drm-amdkfd-fix-signal_eviction_fence-bool-return-val.patch create mode 100644 queue-6.19/drm-atomic-convert-drm_atomic_get_-old-new-_colorop_.patch create mode 100644 queue-6.19/drm-buddy-release-free_trees-array-on-buddy-mm-teard.patch create mode 100644 queue-6.19/drm-display-dp_mst-add-protection-against-0-vcpi.patch create mode 100644 queue-6.19/drm-hisilicon-hibmc-add-dp-mode-valid-check.patch create mode 100644 queue-6.19/drm-hisilicon-hibmc-adding-reset-colorbar-cfg-in-dp-.patch create mode 100644 queue-6.19/drm-hisilicon-hibmc-fix-dp-probabilistical-detect-er.patch create mode 100644 queue-6.19/drm-hisilicon-hibmc-fix-no-showing-problem-with-load.patch create mode 100644 queue-6.19/drm-i915-colorop-do-not-include-headers-from-headers.patch create mode 100644 queue-6.19/drm-i915-display-fix-the-pixel-normalization-handlin.patch create mode 100644 queue-6.19/drm-msm-a2xx-fix-pixel-shader-start-on-a225.patch create mode 100644 queue-6.19/drm-msm-disp-dpu-add-merge3d-support-for-sc7280.patch create mode 100644 queue-6.19/drm-msm-disp-set-num_planes-to-1-for-interleaved-yuv.patch create mode 100644 queue-6.19/drm-msm-dp-avoid-division-by-zero-in-msm_dp_ctrl_con.patch create mode 100644 queue-6.19/drm-msm-dp-update-msm_dp_controller-ids-for-sa8775p.patch create mode 100644 queue-6.19/drm-msm-dpu-drop-intr_start-from-dpu-3.x-catalog-fil.patch create mode 100644 queue-6.19/drm-msm-dpu-fix-cmd-panels-on-dpu-1.x-3.x.patch create mode 100644 queue-6.19/drm-msm-dpu-fix-sspp_ubwc_static_ctrl-programming-on.patch create mode 100644 queue-6.19/drm-msm-dpu-fix-wd-timer-handling-on-dpu-8.x.patch create mode 100644 queue-6.19/drm-msm-dpu-offset-hbb-values-written-to-dpu-by-13.patch create mode 100644 queue-6.19/drm-msm-dpu-program-correct-register-for-ubwc-config.patch create mode 100644 queue-6.19/drm-msm-dpu-set-vsync-source-irrespective-of-mdp-top.patch create mode 100644 queue-6.19/drm-msm-dsi_phy_14nm-convert-from-divider_round_rate.patch create mode 100644 queue-6.19/drm-msm-fix-gmem_base-for-gen8.patch create mode 100644 queue-6.19/drm-msm-fix-x2-85-tpl1_dbg_eco_cntl1.patch create mode 100644 queue-6.19/drm-msm-mdss-correct-hbb-programmed-on-ubwc-5.x-and-.patch create mode 100644 queue-6.19/drm-panel-sw43408-remove-manual-invocation-of-unprep.patch create mode 100644 queue-6.19/drm-panthor-evict-groups-before-vm-termination.patch create mode 100644 queue-6.19/drm-panthor-fix-immediate-ticking-on-a-disabled-tick.patch create mode 100644 queue-6.19/drm-panthor-fix-null-pointer-dereference-on-panthor_.patch create mode 100644 queue-6.19/drm-panthor-fix-panthor_gpu_coherency_set.patch create mode 100644 queue-6.19/drm-panthor-fix-queue_reset_timeout_locked.patch create mode 100644 queue-6.19/drm-panthor-fix-the-full_tick-check.patch create mode 100644 queue-6.19/drm-panthor-fix-the-group-priority-rotation-logic.patch create mode 100644 queue-6.19/drm-panthor-fix-the-logic-that-decides-when-to-stop-.patch create mode 100644 queue-6.19/drm-panthor-make-sure-we-resume-the-tick-when-new-jo.patch create mode 100644 queue-6.19/drm-panthor-recover-from-panthor_gpu_flush_caches-fa.patch create mode 100644 queue-6.19/drm-panthor-remove-redundant-call-to-disable-the-mcu.patch create mode 100644 queue-6.19/drm-plane-fix-is_err-vs-null-bug-drm_plane_create_co.patch create mode 100644 queue-6.19/drm-rockchip-dw_hdmi_qp-fix-rk3576-hpd-interrupt-han.patch create mode 100644 queue-6.19/drm-xe-pf-fix-.bulk_profile-sched_priority-descripti.patch create mode 100644 queue-6.19/drm-xe-ptl-disable-dcc-on-ptl.patch create mode 100644 queue-6.19/drm-xe-unregister-drm-device-on-probe-error.patch create mode 100644 queue-6.19/edac-altera-remove-irqf_oneshot.patch create mode 100644 queue-6.19/edac-amd64-avoid-a-wformat-security-warning.patch create mode 100644 queue-6.19/edac-i5000-fix-snprintf-size-calculation-in-calculat.patch create mode 100644 queue-6.19/edac-i5400-fix-snprintf-limit-calculation-in-calcula.patch create mode 100644 queue-6.19/erofs-avoid-noisy-messages-for-transient-enomem.patch create mode 100644 queue-6.19/erofs-fix-inline-data-read-failure-for-ztailpacking-.patch create mode 100644 queue-6.19/erofs-handle-end-of-filesystem-properly-for-file-bac.patch create mode 100644 queue-6.19/erofs-use-pe-format-specifier-for-error-pointers.patch create mode 100644 queue-6.19/evm-use-ordered-xattrs-list-to-calculate-hmac-in-evm.patch create mode 100644 queue-6.19/ext4-fast-commit-make-s_fc_lock-reclaim-safe.patch create mode 100644 queue-6.19/fat-avoid-parent-link-count-underflow-in-rmdir.patch create mode 100644 queue-6.19/fbdev-au1200fb-fix-a-memory-leak-in-au1200fb_drv_pro.patch create mode 100644 queue-6.19/fbdev-of_display_timing-fix-device-node-reference-le.patch create mode 100644 queue-6.19/firmware-arm_ffa-correct-32-bit-response-handling-in.patch create mode 100644 queue-6.19/firmware-cs_dsp-don-t-use-__free-in-cs_dsp_load-and-.patch create mode 100644 queue-6.19/firmware-cs_dsp-remove-__free-from-cs_dsp_debugfs_st.patch create mode 100644 queue-6.19/fs-add-linux-init_task.h-for-init_fs.patch create mode 100644 queue-6.19/fs-move-initializing-f_mode-before-file_ref_init.patch create mode 100644 queue-6.19/fs-nfs-fix-readdir-slow-start-regression.patch create mode 100644 queue-6.19/fs-tests-exec-drop-duplicate-bprm_stack_limits-test-.patch create mode 100644 queue-6.19/ftrace-bpf-remove-ftrace_ops_fl_jmp-ftrace_ops-flag.patch create mode 100644 queue-6.19/genirq-set-irqf_cond_oneshot-in-devm_request_irq.patch create mode 100644 queue-6.19/gfs2-fix-memory-leaks-in-gfs2_fill_super-error-path.patch create mode 100644 queue-6.19/gfs2-fix-slab-use-after-free-in-qd_put.patch create mode 100644 queue-6.19/gfs2-fix-use-after-free-in-iomap-inline-data-write-p.patch create mode 100644 queue-6.19/gfs2-initialize-bio-bi_opf-early.patch create mode 100644 queue-6.19/gfs2-rename-gfs2_log_submit_-bio-write.patch create mode 100644 queue-6.19/gfs2-retries-missing-in-gfs2_-rename-exchange.patch create mode 100644 queue-6.19/gpib-fix-error-code-in-ibonline.patch create mode 100644 queue-6.19/gpib-fix-error-code-in-ni_usb_write_registers.patch create mode 100644 queue-6.19/gpib-fix-memory-leak-in-ni_usb_init.patch create mode 100644 queue-6.19/gpu-nova-core-check-for-overflow-to-dmatrfbase1.patch create mode 100644 queue-6.19/hfsplus-return-error-when-node-already-exists-in-hfs.patch create mode 100644 queue-6.19/hid-intel-ish-hid-fix-null-ptr-deref-in-ishtp_bus_re.patch create mode 100644 queue-6.19/hid-intel-thc-hid-intel-thc-fix-wrong-register-field.patch create mode 100644 queue-6.19/hid-playstation-add-missing-check-for-input_ff_creat.patch create mode 100644 queue-6.19/hisi_acc_vfio_pci-fix-vf-reset-timeout-issue.patch create mode 100644 queue-6.19/hrtimer-fix-trace-oddity.patch create mode 100644 queue-6.19/hwmon-pmbus-mpq8785-fix-vout_mode-mismatch-during-id.patch create mode 100644 queue-6.19/hwrng-airoha-set-rng-quality-to-900.patch create mode 100644 queue-6.19/hwrng-core-use-rcu-and-work_struct-to-fix-race-condi.patch create mode 100644 queue-6.19/hwspinlock-omap-handle-devm_pm_runtime_enable-errors.patch create mode 100644 queue-6.19/i3c-dw-fix-memory-leak-in-dw_i3c_master_i2c_xfers.patch create mode 100644 queue-6.19/i3c-dw-initialize-spinlock-to-avoid-upsetting-lockde.patch create mode 100644 queue-6.19/i3c-master-update-hot-join-flag-only-on-success.patch create mode 100644 queue-6.19/i3c-move-device-name-assignment-after-i3c_bus_init.patch create mode 100644 queue-6.19/ib-cache-update-gid-cache-on-client-reregister-event.patch create mode 100644 queue-6.19/ib-mlx5-fix-port-speed-query-for-representors.patch create mode 100644 queue-6.19/iio-pressure-mprls0025pa-fix-interrupt-flag.patch create mode 100644 queue-6.19/iio-pressure-mprls0025pa-fix-pressure-calculation.patch create mode 100644 queue-6.19/iio-pressure-mprls0025pa-fix-scan_type-struct.patch create mode 100644 queue-6.19/iio-pressure-mprls0025pa-fix-spi-cs-delay-violation.patch create mode 100644 queue-6.19/iio-pressure-mprls0025pa-fix-spi_transfer-struct-ini.patch create mode 100644 queue-6.19/iio-sca3000-fix-a-resource-leak-in-sca3000_probe.patch create mode 100644 queue-6.19/iio-test-drop-dangling-symbol-in-gain-time-scale-hel.patch create mode 100644 queue-6.19/ima-fix-stack-out-of-bounds-in-is_bprm_creds_for_exe.patch create mode 100644 queue-6.19/inet-raw-sockets-using-ipproto_raw-must-drop-incomin.patch create mode 100644 queue-6.19/input-adp5589-remove-a-leftover-header-file.patch create mode 100644 queue-6.19/interconnect-mediatek-aggregate-bandwidth-with-satur.patch create mode 100644 queue-6.19/interconnect-mediatek-don-t-hijack-parent-device.patch create mode 100644 queue-6.19/interconnect-qcom-qcs8300-fix-the-num_links-for-nsp-.patch create mode 100644 queue-6.19/io_uring-cancel-de-unionize-file-and-user_data-in-st.patch create mode 100644 queue-6.19/io_uring-delay-sqarray-static-branch-disablement.patch create mode 100644 queue-6.19/io_uring-eventfd-remove-unused-ctx-evfd_last_cq_tail.patch create mode 100644 queue-6.19/io_uring-kbuf-fix-memory-leak-if-io_buffer_add_list-.patch create mode 100644 queue-6.19/io_uring-sync-validate-passed-in-offset.patch create mode 100644 queue-6.19/io_uring-use-release-acquire-ordering-for-ioring_set.patch create mode 100644 queue-6.19/iomap-fix-invalid-folio-access-after-folio_end_read.patch create mode 100644 queue-6.19/iomap-fix-submission-side-handling-of-completion-sid.patch create mode 100644 queue-6.19/iommu-amd-use-core-s-primary-handler-and-set-irqf_on.patch create mode 100644 queue-6.19/iommu-vt-d-clear-present-bit-before-tearing-down-con.patch create mode 100644 queue-6.19/iommu-vt-d-clear-present-bit-before-tearing-down-pas.patch create mode 100644 queue-6.19/iommu-vt-d-fix-race-condition-during-pasid-entry-rep.patch create mode 100644 queue-6.19/iommu-vt-d-flush-cache-for-pasid-table-before-using-.patch create mode 100644 queue-6.19/iommupt-do-not-set-c-bit-on-mmio-backed-ptes.patch create mode 100644 queue-6.19/ionic-rate-limit-unknown-xcvr-type-messages.patch create mode 100644 queue-6.19/ipc-don-t-audit-capability-check-in-ipc_permissions.patch create mode 100644 queue-6.19/irqchip-sifive-plic-handle-number-of-hardware-interr.patch create mode 100644 queue-6.19/jfs-avoid-wtautological-constant-out-of-range-compar.patch create mode 100644 queue-6.19/kallsyms-bpf-rename-__bpf_address_lookup-to-bpf_addr.patch create mode 100644 queue-6.19/kallsyms-ftrace-set-module-buildid-in-ftrace_mod_add.patch create mode 100644 queue-6.19/leds-expresswire-fix-chip-state-breakage.patch create mode 100644 queue-6.19/leds-qcom-lpg-check-the-return-value-of-regmap_bulk_.patch create mode 100644 queue-6.19/lib-kconfig.debug-fix-bootparam_hung_task_panic-comm.patch create mode 100644 queue-6.19/lib-kstrtox-fix-kstrtobool-docstring-to-mention-enab.patch create mode 100644 queue-6.19/libbpf-fix-oob-read-in-btf_dump_get_bitfield_value.patch create mode 100644 queue-6.19/mcb-fix-incorrect-sanity-check.patch create mode 100644 queue-6.19/mctp-i2c-initialise-event-handler-read-bytes.patch create mode 100644 queue-6.19/md-fix-return-value-of-mddev_trylock.patch create mode 100644 queue-6.19/md-md-llbitmap-fix-percpu_ref-not-resurrected-on-sus.patch create mode 100644 queue-6.19/md-raid1-fix-memory-leak-in-raid1_run.patch create mode 100644 queue-6.19/md-raid10-fix-any_working-flag-handling-in-raid10_sy.patch create mode 100644 queue-6.19/md-raid5-fix-io-hang-with-degraded-array-with-llbitm.patch create mode 100644 queue-6.19/md-raid5-fix-raid5_run-to-return-error-when-log_init.patch create mode 100644 queue-6.19/media-ccs-accommodate-c-phy-into-the-calculation.patch create mode 100644 queue-6.19/media-chips-media-wave5-fix-memory-leak-on-codec_inf.patch create mode 100644 queue-6.19/media-pci-mg4b-use-irqf_no_thread.patch create mode 100644 queue-6.19/media-uvcvideo-fix-allocation-for-small-frame-sizes.patch create mode 100644 queue-6.19/mei-late_bind-fix-struct-intel_lb_component_ops-kern.patch create mode 100644 queue-6.19/mfd-arizona-fix-regulator-resource-leak-on-wm5102_cl.patch create mode 100644 queue-6.19/mfd-sec-fix-irq-domain-names-duplication.patch create mode 100644 queue-6.19/mfd-simple-mfd-i2c-add-delta-tn48m-cpld-support.patch create mode 100644 queue-6.19/mfd-wm8350-core-use-irqf_oneshot.patch create mode 100644 queue-6.19/mips-loongson32-drop-a-dangling-kconfig-symbol.patch create mode 100644 queue-6.19/mm-slab-fix-false-lockdep-warning-in-__kfree_rcu_she.patch create mode 100644 queue-6.19/mmc-rtsx_pci_sdmmc-increase-power-on-settling-delay-.patch create mode 100644 queue-6.19/module-add-helper-function-for-reading-module_buildi.patch create mode 100644 queue-6.19/mptcp-do-not-account-for-ooo-in-mptcp_rcvbuf_grow.patch create mode 100644 queue-6.19/mptcp-fix-receive-space-timestamp-initialization.patch create mode 100644 queue-6.19/mtd-intel-dg-fix-accessing-regions-before-setting-nr.patch create mode 100644 queue-6.19/mtd-parsers-fix-memory-leak-in-mtd_parser_tplink_saf.patch create mode 100644 queue-6.19/mtd-parsers-ofpart-fix-of-node-refcount-leak-in-pars.patch create mode 100644 queue-6.19/mtd-rawnand-cadence-fix-return-type-of-cdma-send-and.patch create mode 100644 queue-6.19/mtd-spinand-fix-kernel-doc.patch create mode 100644 queue-6.19/net-atm-fix-crash-due-to-unvalidated-vcc-pointer-in-.patch create mode 100644 queue-6.19/net-hns3-fix-double-free-issue-for-tx-spare-buffer.patch create mode 100644 queue-6.19/net-mctp-i2c-fix-duplicate-reception-of-old-data.patch create mode 100644 queue-6.19/net-renesas-rswitch-fix-forwarding-offload-statemach.patch create mode 100644 queue-6.19/net-sunhme-fix-sbus-regression.patch create mode 100644 queue-6.19/netfilter-nf_conncount-fix-tracking-of-connections-f.patch create mode 100644 queue-6.19/netfilter-nf_conncount-increase-the-connection-clean.patch create mode 100644 queue-6.19/netfilter-nf_tables-reset-table-validation-state-on-.patch create mode 100644 queue-6.19/netfilter-nfnetlink_queue-do-shared-unconfirmed-chec.patch create mode 100644 queue-6.19/netfilter-nfnetlink_queue-optimize-verdict-lookup-wi.patch create mode 100644 queue-6.19/netfilter-nft_compat-add-more-restrictions-on-netlin.patch create mode 100644 queue-6.19/netfilter-nft_counter-fix-reset-of-counters-on-32bit.patch create mode 100644 queue-6.19/netfilter-nft_set_hash-fix-get-operation-on-big-endi.patch create mode 100644 queue-6.19/netfilter-nft_set_rbtree-check-for-partial-overlaps-.patch create mode 100644 queue-6.19/netfilter-nft_set_rbtree-don-t-gc-elements-on-insert.patch create mode 100644 queue-6.19/netfilter-nft_set_rbtree-fix-bogus-eexist-with-nlm_f.patch create mode 100644 queue-6.19/netfilter-nft_set_rbtree-remove-seqcount_rwlock_t.patch create mode 100644 queue-6.19/netfilter-nft_set_rbtree-translate-rbtree-to-array-f.patch create mode 100644 queue-6.19/netfilter-nft_set_rbtree-use-binary-search-array-in-.patch create mode 100644 queue-6.19/netfilter-nft_set_rbtree-validate-element-belonging-.patch create mode 100644 queue-6.19/netfilter-nft_set_rbtree-validate-open-interval-over.patch create mode 100644 queue-6.19/netfs-avoid-double-increment-of-retry_count-in-subre.patch create mode 100644 queue-6.19/nfc-hci-shdlc-stop-timers-and-work-before-freeing-co.patch create mode 100644 queue-6.19/nfs-localio-handle-short-writes-by-retrying.patch create mode 100644 queue-6.19/nfs-localio-prevent-direct-reclaim-recursion-into-nf.patch create mode 100644 queue-6.19/nfs-localio-remove-eagain-handling-in-nfs_local_doio.patch create mode 100644 queue-6.19/nfs-localio-use-gfp_noio-and-non-memreclaim-workqueu.patch create mode 100644 queue-6.19/nfs-nfserr_inval-is-not-defined-by-nfsv2.patch create mode 100644 queue-6.19/nfsd-do-not-allow-exporting-of-special-kernel-filesy.patch create mode 100644 queue-6.19/nfsd-never-defer-requests-during-idmap-lookup.patch create mode 100644 queue-6.19/nvdimm-virtio_pmem-serialize-flush-requests.patch create mode 100644 queue-6.19/nvmem-an8855-drop-an-unused-kconfig-symbol.patch create mode 100644 queue-6.19/octeon_ep-disable-per-ring-interrupts.patch create mode 100644 queue-6.19/octeon_ep-ensure-dbell-baddr-updation.patch create mode 100644 queue-6.19/octeon_ep_vf-ensure-dbell-baddr-updation.patch create mode 100644 queue-6.19/octeontx2-af-fix-pf-driver-crash-with-kexec-kernel-b.patch create mode 100644 queue-6.19/octeontx2-pf-unregister-devlink-on-probe-failure.patch create mode 100644 queue-6.19/of-unittest-fix-possible-null-pointer-dereferences-i.patch create mode 100644 queue-6.19/opp-return-correct-value-in-dev_pm_opp_get_level.patch create mode 100644 queue-6.19/ovl-fix-uninit-value-in-ovl_fill_real.patch create mode 100644 queue-6.19/partial-revert-x86-xen-fix-balloon-target-initializa.patch create mode 100644 queue-6.19/pci-acpi-restrict-program_hpx_type2-to-aer-bits.patch create mode 100644 queue-6.19/pci-add-acs-quirk-for-pericom-pi7c9x2g404-switches-1.patch create mode 100644 queue-6.19/pci-add-preceding-capability-position-support-in-pci.patch create mode 100644 queue-6.19/pci-add-wq_percpu-to-alloc_workqueue-users.patch create mode 100644 queue-6.19/pci-check-parent-for-null-in-of_pci_bus_release_doma.patch create mode 100644 queue-6.19/pci-do-not-attempt-to-set-exttag-for-vfs.patch create mode 100644 queue-6.19/pci-dwc-add-new-apis-to-remove-standard-and-extended.patch create mode 100644 queue-6.19/pci-dwc-advertise-dynamic-inbound-mapping-support.patch create mode 100644 queue-6.19/pci-dwc-ep-add-per-pf-bar-and-inbound-atu-mapping-su.patch create mode 100644 queue-6.19/pci-dwc-ep-cache-msi-outbound-iatu-mapping.patch create mode 100644 queue-6.19/pci-dwc-ep-fix-resizable-bar-support-for-multi-pf-co.patch create mode 100644 queue-6.19/pci-dwc-ep-support-bar-subrange-inbound-mapping-via-.patch create mode 100644 queue-6.19/pci-dwc-remove-duplicate-dw_pcie_ep_hide_ext_capabil.patch create mode 100644 queue-6.19/pci-endpoint-add-bar-subrange-mapping-support.patch create mode 100644 queue-6.19/pci-endpoint-add-dynamic_inbound_mapping-epc-feature.patch create mode 100644 queue-6.19/pci-endpoint-add-missing-null-check-for-alloc_workqu.patch create mode 100644 queue-6.19/pci-initialize-rcb-from-pci_configure_device.patch create mode 100644 queue-6.19/pci-mark-3ware-9650sa-root-port-extended-tags-as-bro.patch create mode 100644 queue-6.19/pci-mediatek-fix-irq-domain-leak-when-msi-allocation.patch create mode 100644 queue-6.19/pci-p2pdma-fix-p2pmem_alloc_mmap-warning-condition.patch create mode 100644 queue-6.19/pci-p2pdma-release-per-cpu-pgmap-ref-when-vm_insert_.patch create mode 100644 queue-6.19/pci-p2pdma-reset-page-reference-count-when-page-mapp.patch create mode 100644 queue-6.19/pci-pm-avoid-redundant-delays-on-d3hot-d3cold.patch create mode 100644 queue-6.19/pci-portdrv-fix-potential-resource-leak.patch create mode 100644 queue-6.19/pci-ptm-fix-pcie_ptm_create_debugfs-memory-leak.patch create mode 100644 queue-6.19/pci-pwrctrl-tc9563-use-put_device-instead-of-i2c_put.patch create mode 100644 queue-6.19/pci-remove-old_size-limit-from-bridge-window-sizing.patch create mode 100644 queue-6.19/pci-rewrite-bridge-window-head-alignment-function.patch create mode 100644 queue-6.19/pci-rzg3s-host-fix-device-node-reference-leak-in-rzg.patch create mode 100644 queue-6.19/pci-rzg3s-host-use-pci_generic_config_write-for-the-.patch create mode 100644 queue-6.19/pci-s32g-skip-root-port-removal-during-success.patch create mode 100644 queue-6.19/pci-sophgo-disable-l0s-and-l1-on-sophgo-2044-pcie-ro.patch create mode 100644 queue-6.19/pci-stop-over-estimating-bridge-window-size.patch create mode 100644 queue-6.19/pci-xilinx-fix-intx-irq-domain-leak-in-error-paths.patch create mode 100644 queue-6.19/perf-arm_spe-properly-set-hw.state-on-failures.patch create mode 100644 queue-6.19/perf-x86-core-do-not-set-bit-width-for-unavailable-c.patch create mode 100644 queue-6.19/phy-freescale-imx8qm-hsio-fix-null-pointer-dereferen.patch create mode 100644 queue-6.19/phy-rockchip-samsung-hdptx-pre-compute-hdmi-pll-conf.patch create mode 100644 queue-6.19/pidfs-return-eremote-when-pidfd_get_info-is-called-o.patch create mode 100644 queue-6.19/pinctrl-canaan-k230-fix-null-pointer-dereference-whe.patch create mode 100644 queue-6.19/pinctrl-equilibrium-fix-device-node-reference-leak-i.patch create mode 100644 queue-6.19/pinctrl-meson-amlogic-a4-fix-device-node-reference-l.patch create mode 100644 queue-6.19/pinctrl-qcom-sm8250-lpass-lpi-fix-i2s2_data_groups-d.patch create mode 100644 queue-6.19/pinctrl-single-fix-refcount-leak-in-pcs_add_gpio_fun.patch create mode 100644 queue-6.19/platform-chrome-cros_ec_lightbar-fix-response-size-i.patch create mode 100644 queue-6.19/platform-chrome-cros_typec_switch-don-t-touch-struct.patch create mode 100644 queue-6.19/platform-x86-amd-pmf-prevent-tee-errors-after-hibern.patch create mode 100644 queue-6.19/platform-x86-hp-wmi-fix-platform-profile-values-for-.patch create mode 100644 queue-6.19/platform-x86-int0002-remove-irqf_oneshot-from-reques.patch create mode 100644 queue-6.19/pm-sleep-wakeirq-harden-dev_pm_clear_wake_irq-agains.patch create mode 100644 queue-6.19/pm-wakeup-handle-empty-list-in-wakeup_sources_walk_s.patch create mode 100644 queue-6.19/pnfs-fix-a-missing-wake-up-while-waiting-on-nfs_layo.patch create mode 100644 queue-6.19/power-reset-nvmem-reboot-mode-respect-cell-size-for-.patch create mode 100644 queue-6.19/power-supply-ab8500-fix-use-after-free-in-power_supp.patch create mode 100644 queue-6.19/power-supply-act8945a-fix-use-after-free-in-power_su.patch create mode 100644 queue-6.19/power-supply-bq256xx-fix-use-after-free-in-power_sup.patch create mode 100644 queue-6.19/power-supply-bq25980-fix-use-after-free-in-power_sup.patch create mode 100644 queue-6.19/power-supply-bq27xxx-fix-wrong-errno-when-bus-ops-ar.patch create mode 100644 queue-6.19/power-supply-cpcap-battery-fix-use-after-free-in-pow.patch create mode 100644 queue-6.19/power-supply-goldfish-fix-use-after-free-in-power_su.patch create mode 100644 queue-6.19/power-supply-pf1550-fix-use-after-free-in-power_supp.patch create mode 100644 queue-6.19/power-supply-pm8916_bms_vm-fix-use-after-free-in-pow.patch create mode 100644 queue-6.19/power-supply-pm8916_lbc-fix-use-after-free-for-extco.patch create mode 100644 queue-6.19/power-supply-pm8916_lbc-fix-use-after-free-in-power_.patch create mode 100644 queue-6.19/power-supply-qcom_battmgr-recognize-lip-as-lithium-p.patch create mode 100644 queue-6.19/power-supply-rt9455-fix-use-after-free-in-power_supp.patch create mode 100644 queue-6.19/power-supply-sbs-battery-fix-use-after-free-in-power.patch create mode 100644 queue-6.19/power-supply-wm97xx-fix-null-pointer-dereference-in-.patch create mode 100644 queue-6.19/powerpc-eeh-fix-recursive-pci_lock_rescan_remove-loc.patch create mode 100644 queue-6.19/powerpc-uaccess-move-barrier_nospec-out-of-allow_rea.patch create mode 100644 queue-6.19/printk-vt-fbcon-remove-console_conditional_schedule.patch create mode 100644 queue-6.19/procfs-fix-missing-rcu-protection-when-reading-real_.patch create mode 100644 queue-6.19/pstore-ram-fix-buffer-overflow-in-persistent_ram_sav.patch create mode 100644 queue-6.19/pwm-tiehrpwm-enable-pwmchip-s-parent-device-before-s.patch create mode 100644 queue-6.19/quota-fix-livelock-between-quotactl-and-freeze_super.patch create mode 100644 queue-6.19/rcu-fix-rcu_read_unlock-deadloop-due-to-softirq.patch create mode 100644 queue-6.19/rcutorture-correctly-compute-probability-to-invoke-e.patch create mode 100644 queue-6.19/rdma-core-add-rdma_rw_max_sge-helper-for-sq-sizing.patch create mode 100644 queue-6.19/rdma-hns-fix-rocev1-failure-due-to-dscp.patch create mode 100644 queue-6.19/rdma-hns-fix-wq_mem_reclaim-warning.patch create mode 100644 queue-6.19/rdma-hns-notify-ulp-of-remaining-soft-wcs-during-res.patch create mode 100644 queue-6.19/rdma-hns-return-actual-error-code-instead-of-fixed-e.patch create mode 100644 queue-6.19/rdma-iwcm-fix-workqueue-list-corruption-by-removing-.patch create mode 100644 queue-6.19/rdma-mlx5-fix-memory-leak-in-get_data_direct_sysfs_p.patch create mode 100644 queue-6.19/rdma-mlx5-fix-ucaps-init-error-flow.patch create mode 100644 queue-6.19/rdma-mlx5-fix-umr-hang-in-lag-error-state-unload.patch create mode 100644 queue-6.19/rdma-rtrs-server-remove-dead-code.patch create mode 100644 queue-6.19/rdma-rtrs-srv-fix-sg-mapping.patch create mode 100644 queue-6.19/rdma-rxe-fix-double-free-in-rxe_srq_from_init.patch create mode 100644 queue-6.19/rdma-rxe-fix-iova-to-va-conversion-for-mr-page-sizes.patch create mode 100644 queue-6.19/rdma-rxe-fix-race-condition-in-qp-timer-handlers.patch create mode 100644 queue-6.19/rdma-uverbs-add-__gfp_nowarn-to-ib_uverbs_unmarshall.patch create mode 100644 queue-6.19/rdma-uverbs-validate-wqe_size-before-using-it-in-ib_.patch create mode 100644 queue-6.19/regulator-core-don-t-ignore-errors-from-event-forwar.patch create mode 100644 queue-6.19/regulator-core-fix-locking-in-regulator_resolve_supp.patch create mode 100644 queue-6.19/regulator-core-move-supply-check-earlier-in-set_mach.patch create mode 100644 queue-6.19/remoteproc-imx_dsp_rproc-fix-multiple-start-stop-ope.patch create mode 100644 queue-6.19/remoteproc-imx_dsp_rproc-only-reset-carveout-memory-.patch create mode 100644 queue-6.19/remoteproc-imx_rproc-use-strstarts-for-rsc-table-che.patch create mode 100644 queue-6.19/reset-canaan-k230-drop-of-dependency-and-enable-by-d.patch create mode 100644 queue-6.19/revert-hwmon-ibmpex-fix-use-after-free-in-high-low-s.patch create mode 100644 queue-6.19/revert-mailbox-pcc-support-mailbox-management-of-the.patch create mode 100644 queue-6.19/revert-mmc-rtsx_pci_sdmmc-increase-power-on-settling.patch create mode 100644 queue-6.19/revert-net-smc-introduce-tcp-ulp-support.patch create mode 100644 queue-6.19/riscv-dts-sophgo-cv180x-fix-usb-dwc2-fifo-sizes.patch create mode 100644 queue-6.19/rnbd-srv-fix-server-side-setting-of-bi_size-for-spec.patch create mode 100644 queue-6.19/rqspinlock-fix-tas-fallback-lock-entry-creation.patch create mode 100644 queue-6.19/rtc-amlogic-a4-remove-irqf_oneshot.patch create mode 100644 queue-6.19/rust-devres-fix-race-condition-due-to-nesting.patch create mode 100644 queue-6.19/rust-driver-core-use-kernel-vertical-style-for-impor.patch create mode 100644 queue-6.19/rust-pwm-fix-potential-memory-leak-on-init-error.patch create mode 100644 queue-6.19/rust-task-restrict-task-group_leader-to-current.patch create mode 100644 queue-6.19/s390-cio-fix-device-lifecycle-handling-in-css_alloc_.patch create mode 100644 queue-6.19/sched-deadline-clear-the-defer-params.patch create mode 100644 queue-6.19/sched-export-hidden-tracepoints-to-modules.patch create mode 100644 queue-6.19/sched-fix-build-for-modules-using-set_tsk_need_resch.patch create mode 100644 queue-6.19/sched-re-evaluate-scheduling-when-migrating-queued-t.patch create mode 100644 queue-6.19/sched-rt-skip-currently-executing-cpu-in-rto_next_cp.patch create mode 100644 queue-6.19/scsi-csiostor-fix-dereference-of-null-pointer-rn.patch create mode 100644 queue-6.19/scsi-efct-use-irqf_oneshot-and-default-primary-handl.patch create mode 100644 queue-6.19/scsi-smartpqi-fix-memory-leak-in-pqi_report_phys_lun.patch create mode 100644 queue-6.19/scsi-ufs-host-mediatek-require-config_pm.patch create mode 100644 queue-6.19/selftests-bpf-fix-kprobe-multi-stacktrace_ips-test.patch create mode 100644 queue-6.19/selftests-bpf-fix-resource-leak-in-serial_test_wq-on.patch create mode 100644 queue-6.19/selftests-bpf-veristat-fix-printing-order-in-output_.patch create mode 100644 queue-6.19/selftests-mm-fix-faulting-in-code-in-pagemap_ioctl-t.patch create mode 100644 queue-6.19/selftests-mm-fix-usage-of-force_read-in-cow-tests.patch create mode 100644 queue-6.19/selftests-resctrl-fix-a-division-by-zero-error-on-hy.patch create mode 100644 queue-6.19/selftests-xsk-fix-number-of-tx-frags-in-invalid-pack.patch create mode 100644 queue-6.19/selftests-xsk-properly-handle-batch-ending-in-the-mi.patch create mode 100644 queue-6.19/seqlock-fix-scoped_seqlock_read-kernel-doc.patch create mode 100644 queue-6.19/serial-caif-fix-use-after-free-in-caif_serial-ldisc_.patch create mode 100644 queue-6.19/serial-imx-change-serial_imx_console-to-bool.patch create mode 100644 queue-6.19/serial-sh_sci-improve-dma-support-prompt.patch create mode 100644 queue-6.19/smack-smack-doi-accept-previously-used-values.patch create mode 100644 queue-6.19/smack-smack-doi-must-be-0.patch create mode 100644 queue-6.19/smb-client-correct-value-for-smbd_max_fragmented_rec.patch create mode 100644 queue-6.19/smb-client-fix-potential-uaf-and-double-free-in-smb2.patch create mode 100644 queue-6.19/soc-mediatek-svs-fix-memory-leak-in-svs_enable_debug.patch create mode 100644 queue-6.19/soc-qcom-cmd-db-use-devm_memremap-to-fix-memory-leak.patch create mode 100644 queue-6.19/soc-qcom-smem-handle-enomem-error-during-probe.patch create mode 100644 queue-6.19/soc-qcom-ubwc-add-missing-include.patch create mode 100644 queue-6.19/soundwire-intel_ace2x-add-snd_hda_core-dependency.patch create mode 100644 queue-6.19/spi-cadence-qspi-remove-redundant-pm_runtime_mark_la.patch create mode 100644 queue-6.19/spi-microchip-core-use-xor-instead-of-andnot-to-fix-.patch create mode 100644 queue-6.19/spi-tools-add-include-folder-to-.gitignore.patch create mode 100644 queue-6.19/staging-greybus-lights-avoid-null-deref.patch create mode 100644 queue-6.19/stm-class-kconfig-correct-symbol-name.patch create mode 100644 queue-6.19/tcp-accecn-handle-unexpected-accecn-negotiation-feed.patch create mode 100644 queue-6.19/tcp-disable-rfc3168-fallback-identifier-for-cc-modul.patch create mode 100644 queue-6.19/tcp-ect_1_negotiation-and-needs_accecn-identifiers.patch create mode 100644 queue-6.19/tcp-tcp_tx_timestamp-must-look-at-the-rtx-queue.patch create mode 100644 queue-6.19/thermal-intel-x86_pkg_temp_thermal-handle-invalid-te.patch create mode 100644 queue-6.19/thermal-of-fix-reference-leak-in-thermal_of_cm_looku.patch create mode 100644 queue-6.19/time-sched_clock-use-access_private-to-evaluate-hrti.patch create mode 100644 queue-6.19/tools-nolibc-always-use-64-bit-mode-for-s390-header-.patch create mode 100644 queue-6.19/tools-power-x86-intel-speed-select-fix-file-descript.patch create mode 100644 queue-6.19/tpm-st33zp24-fix-missing-cleanup-on-get_burstcount-e.patch create mode 100644 queue-6.19/tpm-tpm_i2c_infineon-fix-locality-leak-on-get_burstc.patch create mode 100644 queue-6.19/tracing-properly-process-error-handling-in-event_his.patch create mode 100644 queue-6.19/tracing-remove-duplicate-enable_event_str-and-disabl.patch create mode 100644 queue-6.19/ublk-restore-auto-buf-unregister-refcount-optimizati.patch create mode 100644 queue-6.19/ublk-use-read_once-to-read-struct-ublksrv_ctrl_cmd.patch create mode 100644 queue-6.19/ublk-validate-sqe128-flag-before-accessing-the-cmd.patch create mode 100644 queue-6.19/ucount-check-for-cap_sys_resource-using-ns_capable_n.patch create mode 100644 queue-6.19/usb-bdc-fix-sleep-during-atomic.patch create mode 100644 queue-6.19/usb-typec-fusb302-remove-irqf_oneshot.patch create mode 100644 queue-6.19/usb-typec-ucsi-drop-an-unused-kconfig-symbol.patch create mode 100644 queue-6.19/vfio-pci-lock-upstream-bridge-for-vfio_pci_core_disa.patch create mode 100644 queue-6.19/vsnprintf-drop-__printf-attributes-on-binary-printin.patch create mode 100644 queue-6.19/watchdog-starfive-wdt-fix-pm-reference-leak-in-probe.patch create mode 100644 queue-6.19/wifi-ath10k-sdio-add-missing-lock-protection-in-ath1.patch create mode 100644 queue-6.19/wifi-ath11k-add-usecase-firmware-handling-based-on-d.patch create mode 100644 queue-6.19/wifi-ath12k-clear-stale-link-mapping-of-ahvif-links_.patch create mode 100644 queue-6.19/wifi-ath12k-do-wow-offloads-only-on-primary-link.patch create mode 100644 queue-6.19/wifi-ath12k-fix-index-decrement-when-array_len-is-ze.patch create mode 100644 queue-6.19/wifi-ath9k-add-of-dependency-to-ahb.patch create mode 100644 queue-6.19/wifi-ath9k-debug.h-fix-kernel-doc-bad-lines-and-stru.patch create mode 100644 queue-6.19/wifi-ath9k-fix-kernel-doc-warnings-in-common-debug.h.patch create mode 100644 queue-6.19/wifi-cfg80211-fix-use_for-flag-update-on-bss-refresh.patch create mode 100644 queue-6.19/wifi-cfg80211-stop-nan-and-p2p-in-cfg80211_leave.patch create mode 100644 queue-6.19/wifi-rtw89-correct-use-sequence-of-driver_data-in-sk.patch create mode 100644 queue-6.19/wifi-rtw89-debug-fix-memory-leak-in-__print_txpwr_ma.patch create mode 100644 queue-6.19/workqueue-process-rescuer-work-items-one-by-one-usin.patch create mode 100644 queue-6.19/x86-cpu-amd-correct-the-microcode-table-for-zenbleed.patch create mode 100644 queue-6.19/x86-fgraph-bpf-switch-kprobe_multi-program-stack-unw.patch create mode 100644 queue-6.19/x86-fgraph-fix-return_to_handler-regs.rsp-value.patch create mode 100644 queue-6.19/x86-hyperv-fix-smp_ops-build-failure-on-up-kernels.patch create mode 100644 queue-6.19/xdrgen-fix-struct-prefix-for-typedef-types-in-progra.patch create mode 100644 queue-6.19/xdrgen-initialize-data-pointer-for-zero-length-items.patch create mode 100644 queue-6.19/xdrgen-remove-inclusion-of-nlm4.h-header.patch create mode 100644 queue-6.19/xen-virtio-don-t-use-grant-dma-ops-when-running-as-d.patch create mode 100644 queue-6.19/xfrm-fix-ip_rt_bug-race-in-icmp_route_lookup-reverse.patch create mode 100644 queue-6.6/acpica-fix-null-pointer-dereference-in-acpi_ev_addre.patch create mode 100644 queue-6.6/arm-dts-allwinner-sun5i-a13-utoo-p66-delete-power-gp.patch create mode 100644 queue-6.6/arm-dts-lpc32xx-add-clocks-property-to-motor-control.patch create mode 100644 queue-6.6/arm-dts-lpc32xx-set-motor-pwm-pwm-cells-property-val.patch create mode 100644 queue-6.6/arm-vdso-patch-out-__vdso_clock_getres-if-unavailabl.patch create mode 100644 queue-6.6/arm64-dts-amlogic-axg-assign-the-mmc-signal-clocks.patch create mode 100644 queue-6.6/arm64-dts-amlogic-g12-assign-the-mmc-a-signal-clock.patch create mode 100644 queue-6.6/arm64-dts-amlogic-g12-assign-the-mmc-b-and-c-signal-.patch create mode 100644 queue-6.6/arm64-dts-amlogic-gx-assign-the-mmc-signal-clocks.patch create mode 100644 queue-6.6/arm64-dts-qcom-sdm630-fix-gpu_speed_bin-size.patch create mode 100644 queue-6.6/arm64-dts-qcom-sdm845-db845c-drop-cs-from-spio0.patch create mode 100644 queue-6.6/arm64-dts-qcom-sdm845-db845c-specify-power-for-wifi-.patch create mode 100644 queue-6.6/arm64-dts-qcom-sdm845-oneplus-don-t-keep-panel-regul.patch create mode 100644 queue-6.6/arm64-dts-qcom-sdm845-oneplus-don-t-mark-ts-supply-b.patch create mode 100644 queue-6.6/arm64-dts-qcom-sdm845-oneplus-mark-l14a-regulator-as.patch create mode 100644 queue-6.6/arm64-dts-qcom-sm6115-add-cx_mem-dbgc-gpu-regions.patch create mode 100644 queue-6.6/arm64-dts-tqma8mpql-mba8mpxl-fix-hdmi-cec-pad-contro.patch create mode 100644 queue-6.6/asoc-nau8821-avoid-unnecessary-blocking-in-irq-handl.patch create mode 100644 queue-6.6/asoc-nau8821-consistently-clear-interrupts-before-un.patch create mode 100644 queue-6.6/asoc-nau8821-fixup-nau8821_enable_jack_detect.patch create mode 100644 queue-6.6/audit-move-the-compat_xxx_class-extern-declarations-.patch create mode 100644 queue-6.6/auxdisplay-arm-charlcd-fix-release_mem_region-size.patch create mode 100644 queue-6.6/backlight-qcom-wled-change-pm8950-wled-configuration.patch create mode 100644 queue-6.6/backlight-qcom-wled-support-ovp-values-for-pmi8994.patch create mode 100644 queue-6.6/bonding-only-set-speed-duplex-to-unknown-if-getting-.patch create mode 100644 queue-6.6/bpf-fix-bpf_xdp_store_bytes-proto-for-read-only-arg.patch create mode 100644 queue-6.6/bpf-sockmap-fix-fionread-for-sockmap.patch create mode 100644 queue-6.6/bpf-sockmap-fix-incorrect-copied_seq-calculation.patch create mode 100644 queue-6.6/btrfs-fix-block_group_tree-dirty_list-corruption.patch create mode 100644 queue-6.6/btrfs-qgroup-return-correct-error-when-deleting-qgro.patch create mode 100644 queue-6.6/clk-mediatek-fix-error-handling-in-runtime-pm-setup.patch create mode 100644 queue-6.6/clk-meson-gxbb-limit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch create mode 100644 queue-6.6/clk-move-clk_-save-restore-_context-to-common_clk-se.patch create mode 100644 queue-6.6/clk-qcom-dispcc-sdm845-enable-parents-for-pixel-cloc.patch create mode 100644 queue-6.6/clk-qcom-gcc-ipq5018-flag-sleep-clock-as-critical.patch create mode 100644 queue-6.6/clk-qcom-gcc-msm8917-remove-always_on-flag-from-cpp_.patch create mode 100644 queue-6.6/clk-qcom-gcc-msm8953-remove-always_on-flag-from-cpp_.patch create mode 100644 queue-6.6/clk-qcom-gcc-qdu1000-update-the-sdcc-rcgs-to-use-sha.patch create mode 100644 queue-6.6/clk-qcom-gcc-sdx75-update-the-sdcc-rcgs-to-use-share.patch create mode 100644 queue-6.6/clk-qcom-gcc-sm8450-update-the-sdcc-rcgs-to-use-shar.patch create mode 100644 queue-6.6/clk-qcom-gcc-sm8550-use-floor-ops-for-sdcc-rcgs.patch create mode 100644 queue-6.6/clk-qcom-gfx3d-add-parent-to-parent-request-map.patch create mode 100644 queue-6.6/clk-qcom-rcg2-compute-2d-using-duty-fraction-directl.patch create mode 100644 queue-6.6/clk-qcom-return-correct-error-code-in-qcom_cc_probe_.patch create mode 100644 queue-6.6/coresight-etm3x-fix-cpulocked-warning-on-cpuhp.patch create mode 100644 queue-6.6/cpufreq-scmi-correct-scmi-explanation.patch create mode 100644 queue-6.6/cpuidle-governors-menu-always-check-timers-with-tick.patch create mode 100644 queue-6.6/cpuidle-menu-cleanup-after-loadavg-removal.patch create mode 100644 queue-6.6/crypto-cavium-fix-dma_free_coherent-size.patch create mode 100644 queue-6.6/crypto-ccp-add-an-s4-restore-flow.patch create mode 100644 queue-6.6/crypto-ccp-factor-out-ring-destroy-handling-to-a-hel.patch create mode 100644 queue-6.6/crypto-ccp-move-direct-access-to-some-psp-registers-.patch create mode 100644 queue-6.6/crypto-ccp-send-psp_cmd_tee_ring_destroy-when-psp_cm.patch create mode 100644 queue-6.6/crypto-hisilicon-sec2-support-skcipher-aead-fallback.patch create mode 100644 queue-6.6/crypto-hisilicon-trng-modifying-the-order-of-header-.patch create mode 100644 queue-6.6/crypto-hisilicon-trng-support-tfms-sharing-the-devic.patch create mode 100644 queue-6.6/crypto-hisilicon-zip-adjust-the-way-to-obtain-the-re.patch create mode 100644 queue-6.6/crypto-hisilicon-zip-remove-zlib-and-gzip.patch create mode 100644 queue-6.6/crypto-hisilicon-zip-support-deflate-algorithm.patch create mode 100644 queue-6.6/crypto-octeontx-fix-dma_free_coherent-size.patch create mode 100644 queue-6.6/crypto-qat-fix-warning-on-adf_pfvf_pf_proto.c.patch create mode 100644 queue-6.6/cxl-fix-premature-commit_end-increment-on-decoder-co.patch create mode 100644 queue-6.6/dm-use-bio_clone_blkg_association.patch create mode 100644 queue-6.6/dma-dma-axi-dmac-fix-sw-cyclic-transfers.patch create mode 100644 queue-6.6/dmaengine-fsl-edma-don-t-explicitly-disable-clocks-i.patch create mode 100644 queue-6.6/dmaengine-fsl-edma-main-convert-to-platform-remove-c.patch create mode 100644 queue-6.6/dmaengine-mediatek-uart-apdma-fix-above-4g-addressin.patch create mode 100644 queue-6.6/docs-fix-warning-document-not-included-in-any-toctre.patch create mode 100644 queue-6.6/documentation-pci-endpoint-fix-ntb-vntb-copy-paste-e.patch create mode 100644 queue-6.6/documentation-trace-refactor-toctree.patch create mode 100644 queue-6.6/documentation-tracing-add-pci-tracepoint-documentati.patch create mode 100644 queue-6.6/documentation-tracing-add-ring-buffer-mapping.patch create mode 100644 queue-6.6/drivers-iio-mpu3050-use-dev_err_probe-for-regulator-.patch create mode 100644 queue-6.6/drm-amdgpu-use-explicit-vcn-instance-0-in-sr-iov-ini.patch create mode 100644 queue-6.6/drm-msm-a2xx-fix-pixel-shader-start-on-a225.patch create mode 100644 queue-6.6/drm-msm-disp-dpu-add-merge3d-support-for-sc7280.patch create mode 100644 queue-6.6/drm-msm-dpu-fix-cmd-panels-on-dpu-1.x-3.x.patch create mode 100644 queue-6.6/edac-altera-remove-irqf_oneshot.patch create mode 100644 queue-6.6/edac-i5000-fix-snprintf-size-calculation-in-calculat.patch create mode 100644 queue-6.6/edac-i5400-fix-snprintf-limit-calculation-in-calcula.patch create mode 100644 queue-6.6/fat-avoid-parent-link-count-underflow-in-rmdir.patch create mode 100644 queue-6.6/fbdev-au1200fb-fix-a-memory-leak-in-au1200fb_drv_pro.patch create mode 100644 queue-6.6/fbdev-of_display_timing-fix-device-node-reference-le.patch create mode 100644 queue-6.6/fs-add-linux-init_task.h-for-init_fs.patch create mode 100644 queue-6.6/fs-nfs-fix-readdir-slow-start-regression.patch create mode 100644 queue-6.6/gfs2-add-metapath_dibh-helper.patch create mode 100644 queue-6.6/gfs2-fix-slab-use-after-free-in-qd_put.patch create mode 100644 queue-6.6/gfs2-fix-use-after-free-in-iomap-inline-data-write-p.patch create mode 100644 queue-6.6/gfs2-retries-missing-in-gfs2_-rename-exchange.patch create mode 100644 queue-6.6/hfsplus-return-error-when-node-already-exists-in-hfs.patch create mode 100644 queue-6.6/hid-playstation-add-missing-check-for-input_ff_creat.patch create mode 100644 queue-6.6/hrtimer-fix-trace-oddity.patch create mode 100644 queue-6.6/i3c-dw-initialize-spinlock-to-avoid-upsetting-lockde.patch create mode 100644 queue-6.6/i3c-master-update-hot-join-flag-only-on-success.patch create mode 100644 queue-6.6/i3c-move-device-name-assignment-after-i3c_bus_init.patch create mode 100644 queue-6.6/ib-cache-update-gid-cache-on-client-reregister-event.patch create mode 100644 queue-6.6/iio-pressure-mprls0025pa-fix-scan_type-struct.patch create mode 100644 queue-6.6/iio-sca3000-fix-a-resource-leak-in-sca3000_probe.patch create mode 100644 queue-6.6/inet-raw-sockets-using-ipproto_raw-must-drop-incomin.patch create mode 100644 queue-6.6/io_uring-cancel-de-unionize-file-and-user_data-in-st.patch create mode 100644 queue-6.6/io_uring-sync-validate-passed-in-offset.patch create mode 100644 queue-6.6/iomap-fix-submission-side-handling-of-completion-sid.patch create mode 100644 queue-6.6/iommu-vt-d-flush-cache-for-pasid-table-before-using-.patch create mode 100644 queue-6.6/ionic-rate-limit-unknown-xcvr-type-messages.patch create mode 100644 queue-6.6/ipc-don-t-audit-capability-check-in-ipc_permissions.patch create mode 100644 queue-6.6/kallsyms-ftrace-set-module-buildid-in-ftrace_mod_add.patch create mode 100644 queue-6.6/leds-qcom-lpg-check-the-return-value-of-regmap_bulk_.patch create mode 100644 queue-6.6/libbpf-fix-oob-read-in-btf_dump_get_bitfield_value.patch create mode 100644 queue-6.6/mctp-i2c-initialise-event-handler-read-bytes.patch create mode 100644 queue-6.6/md-raid10-fix-any_working-flag-handling-in-raid10_sy.patch create mode 100644 queue-6.6/media-ccs-accommodate-c-phy-into-the-calculation.patch create mode 100644 queue-6.6/media-uvcvideo-fix-allocation-for-small-frame-sizes.patch create mode 100644 queue-6.6/mfd-arizona-fix-regulator-resource-leak-on-wm5102_cl.patch create mode 100644 queue-6.6/mfd-simple-mfd-i2c-add-compatible-strings-for-layers.patch create mode 100644 queue-6.6/mfd-simple-mfd-i2c-add-delta-tn48m-cpld-support.patch create mode 100644 queue-6.6/mfd-simple-mfd-i2c-add-max77705-support.patch create mode 100644 queue-6.6/mfd-simple-mfd-i2c-add-spacemit-p1-support.patch create mode 100644 queue-6.6/mfd-simple-mfd-i2c-keep-compatible-strings-in-alphab.patch create mode 100644 queue-6.6/mfd-wm8350-core-use-irqf_oneshot.patch create mode 100644 queue-6.6/mm-list_lru-update-kernel-documentation-to-follow-th.patch create mode 100644 queue-6.6/mmc-rtsx_pci_sdmmc-increase-power-on-settling-delay-.patch create mode 100644 queue-6.6/module-add-helper-function-for-reading-module_buildi.patch create mode 100644 queue-6.6/mptcp-fix-receive-space-timestamp-initialization.patch create mode 100644 queue-6.6/mtd-parsers-fix-memory-leak-in-mtd_parser_tplink_saf.patch create mode 100644 queue-6.6/mtd-parsers-ofpart-fix-of-node-refcount-leak-in-pars.patch create mode 100644 queue-6.6/mtd-rawnand-cadence-fix-return-type-of-cdma-send-and.patch create mode 100644 queue-6.6/mtd-spinand-fix-kernel-doc.patch create mode 100644 queue-6.6/net-add-skb_dstref_steal-and-skb_dstref_restore.patch create mode 100644 queue-6.6/net-atm-fix-crash-due-to-unvalidated-vcc-pointer-in-.patch create mode 100644 queue-6.6/net-hns3-fix-double-free-issue-for-tx-spare-buffer.patch create mode 100644 queue-6.6/net-mctp-i2c-fix-duplicate-reception-of-old-data.patch create mode 100644 queue-6.6/net-sunhme-fix-sbus-regression.patch create mode 100644 queue-6.6/net-switch-to-skb_dstref_steal-skb_dstref_restore-fo.patch create mode 100644 queue-6.6/netfilter-nf_conncount-fix-tracking-of-connections-f.patch create mode 100644 queue-6.6/netfilter-nf_conncount-increase-the-connection-clean.patch create mode 100644 queue-6.6/netfilter-nf_conncount-make-nf_conncount_gc_list-to-.patch create mode 100644 queue-6.6/netfilter-nf_tables-reset-table-validation-state-on-.patch create mode 100644 queue-6.6/netfilter-nft_compat-add-more-restrictions-on-netlin.patch create mode 100644 queue-6.6/netfilter-nft_counter-fix-reset-of-counters-on-32bit.patch create mode 100644 queue-6.6/netfilter-nft_set_hash-fix-get-operation-on-big-endi.patch create mode 100644 queue-6.6/netfilter-nft_set_rbtree-check-for-partial-overlaps-.patch create mode 100644 queue-6.6/nfc-hci-shdlc-stop-timers-and-work-before-freeing-co.patch create mode 100644 queue-6.6/nfsd-never-defer-requests-during-idmap-lookup.patch create mode 100644 queue-6.6/nvdimm-virtio_pmem-serialize-flush-requests.patch create mode 100644 queue-6.6/octeon_ep-disable-per-ring-interrupts.patch create mode 100644 queue-6.6/octeon_ep-ensure-dbell-baddr-updation.patch create mode 100644 queue-6.6/octeon_ep-restructured-interrupt-handlers.patch create mode 100644 queue-6.6/octeon_ep-set-backpressure-watermark-for-rx-queues.patch create mode 100644 queue-6.6/octeon_ep-support-octeon-cn10k-devices.patch create mode 100644 queue-6.6/octeon_ep-support-to-fetch-firmware-info.patch create mode 100644 queue-6.6/octeontx2-af-fix-pf-driver-crash-with-kexec-kernel-b.patch create mode 100644 queue-6.6/octeontx2-pf-unregister-devlink-on-probe-failure.patch create mode 100644 queue-6.6/of-unittest-fix-possible-null-pointer-dereferences-i.patch create mode 100644 queue-6.6/ovl-fix-uninit-value-in-ovl_fill_real.patch create mode 100644 queue-6.6/partial-revert-x86-xen-fix-balloon-target-initializa.patch create mode 100644 queue-6.6/pci-acpi-restrict-program_hpx_type2-to-aer-bits.patch create mode 100644 queue-6.6/pci-add-acs-quirk-for-pericom-pi7c9x2g404-switches-1.patch create mode 100644 queue-6.6/pci-add-defines-for-bridge-window-indexing.patch create mode 100644 queue-6.6/pci-add-pcie_msg_code_assert_intx-message-macros.patch create mode 100644 queue-6.6/pci-do-not-attempt-to-set-exttag-for-vfs.patch create mode 100644 queue-6.6/pci-initialize-rcb-from-pci_configure_device.patch create mode 100644 queue-6.6/pci-log-bridge-info-when-first-enumerating-bridge.patch create mode 100644 queue-6.6/pci-log-bridge-windows-conditionally.patch create mode 100644 queue-6.6/pci-mark-3ware-9650sa-root-port-extended-tags-as-bro.patch create mode 100644 queue-6.6/pci-mediatek-fix-irq-domain-leak-when-msi-allocation.patch create mode 100644 queue-6.6/pci-move-pci_read_bridge_windows-below-individual-wi.patch create mode 100644 queue-6.6/pci-p2pdma-release-per-cpu-pgmap-ref-when-vm_insert_.patch create mode 100644 queue-6.6/pci-pm-avoid-redundant-delays-on-d3hot-d3cold.patch create mode 100644 queue-6.6/pci-portdrv-fix-potential-resource-leak.patch create mode 100644 queue-6.6/pci-supply-bridge-device-not-secondary-bus-to-read-w.patch create mode 100644 queue-6.6/perf-arm_spe-properly-set-hw.state-on-failures.patch create mode 100644 queue-6.6/pinctrl-equilibrium-fix-device-node-reference-leak-i.patch create mode 100644 queue-6.6/pinctrl-qcom-sm8250-lpass-lpi-fix-i2s2_data_groups-d.patch create mode 100644 queue-6.6/pinctrl-single-fix-refcount-leak-in-pcs_add_gpio_fun.patch create mode 100644 queue-6.6/platform-chrome-cros_ec_lightbar-fix-response-size-i.patch create mode 100644 queue-6.6/platform-chrome-cros_typec_switch-don-t-touch-struct.patch create mode 100644 queue-6.6/pm-sleep-wakeirq-harden-dev_pm_clear_wake_irq-agains.patch create mode 100644 queue-6.6/pm-wakeup-handle-empty-list-in-wakeup_sources_walk_s.patch create mode 100644 queue-6.6/pnfs-fix-a-missing-wake-up-while-waiting-on-nfs_layo.patch create mode 100644 queue-6.6/power-reset-nvmem-reboot-mode-respect-cell-size-for-.patch create mode 100644 queue-6.6/power-supply-ab8500-fix-use-after-free-in-power_supp.patch create mode 100644 queue-6.6/power-supply-act8945a-fix-use-after-free-in-power_su.patch create mode 100644 queue-6.6/power-supply-bq256xx-fix-use-after-free-in-power_sup.patch create mode 100644 queue-6.6/power-supply-bq25980-fix-use-after-free-in-power_sup.patch create mode 100644 queue-6.6/power-supply-bq27xxx-fix-wrong-errno-when-bus-ops-ar.patch create mode 100644 queue-6.6/power-supply-cpcap-battery-fix-use-after-free-in-pow.patch create mode 100644 queue-6.6/power-supply-goldfish-fix-use-after-free-in-power_su.patch create mode 100644 queue-6.6/power-supply-qcom_battmgr-recognize-lip-as-lithium-p.patch create mode 100644 queue-6.6/power-supply-rt9455-fix-use-after-free-in-power_supp.patch create mode 100644 queue-6.6/power-supply-sbs-battery-fix-use-after-free-in-power.patch create mode 100644 queue-6.6/power-supply-wm97xx-fix-null-pointer-dereference-in-.patch create mode 100644 queue-6.6/powerpc-eeh-fix-recursive-pci_lock_rescan_remove-loc.patch create mode 100644 queue-6.6/powerpc-uaccess-move-barrier_nospec-out-of-allow_rea.patch create mode 100644 queue-6.6/procfs-fix-missing-rcu-protection-when-reading-real_.patch create mode 100644 queue-6.6/pstore-ram-fix-buffer-overflow-in-persistent_ram_sav.patch create mode 100644 queue-6.6/quota-fix-livelock-between-quotactl-and-freeze_super.patch create mode 100644 queue-6.6/rcu-exp-move-expedited-kthread-worker-creation-funct.patch create mode 100644 queue-6.6/rcu-fix-rcu_read_unlock-deadloop-due-to-softirq.patch create mode 100644 queue-6.6/rcu-refactor-expedited-handling-check-in-rcu_read_un.patch create mode 100644 queue-6.6/rcu-remove-local_irq_save-restore-in-rcu_preempt_def.patch create mode 100644 queue-6.6/rcu-s-boost_kthread_mutex-kthread_mutex.patch create mode 100644 queue-6.6/rdma-core-add-rdma_rw_max_sge-helper-for-sq-sizing.patch create mode 100644 queue-6.6/rdma-core-fix-a-couple-of-obvious-typos-in-comments.patch create mode 100644 queue-6.6/rdma-hns-fix-wq_mem_reclaim-warning.patch create mode 100644 queue-6.6/rdma-hns-notify-ulp-of-remaining-soft-wcs-during-res.patch create mode 100644 queue-6.6/rdma-rtrs-server-remove-dead-code.patch create mode 100644 queue-6.6/rdma-rtrs-srv-fix-sg-mapping.patch create mode 100644 queue-6.6/rdma-rxe-fix-double-free-in-rxe_srq_from_init.patch create mode 100644 queue-6.6/rdma-rxe-fix-race-condition-in-qp-timer-handlers.patch create mode 100644 queue-6.6/rdma-uverbs-add-__gfp_nowarn-to-ib_uverbs_unmarshall.patch create mode 100644 queue-6.6/rdma-uverbs-validate-wqe_size-before-using-it-in-ib_.patch create mode 100644 queue-6.6/regulator-core-move-supply-check-earlier-in-set_mach.patch create mode 100644 queue-6.6/revert-hwmon-ibmpex-fix-use-after-free-in-high-low-s.patch create mode 100644 queue-6.6/revert-mmc-rtsx_pci_sdmmc-increase-power-on-settling.patch create mode 100644 queue-6.6/s390-cio-fix-device-lifecycle-handling-in-css_alloc_.patch create mode 100644 queue-6.6/sched-rt-skip-currently-executing-cpu-in-rto_next_cp.patch create mode 100644 queue-6.6/scsi-csiostor-fix-dereference-of-null-pointer-rn.patch create mode 100644 queue-6.6/scsi-efct-use-irqf_oneshot-and-default-primary-handl.patch create mode 100644 queue-6.6/scsi-smartpqi-fix-memory-leak-in-pqi_report_phys_lun.patch create mode 100644 queue-6.6/scsi-ufs-host-mediatek-require-config_pm.patch create mode 100644 queue-6.6/selftests-bpf-veristat-fix-printing-order-in-output_.patch create mode 100644 queue-6.6/serial-caif-fix-use-after-free-in-caif_serial-ldisc_.patch create mode 100644 queue-6.6/serial-imx-change-serial_imx_console-to-bool.patch create mode 100644 queue-6.6/serial-sh_sci-improve-dma-support-prompt.patch create mode 100644 queue-6.6/smack-smack-doi-accept-previously-used-values.patch create mode 100644 queue-6.6/smack-smack-doi-must-be-0.patch create mode 100644 queue-6.6/smb-client-correct-value-for-smbd_max_fragmented_rec.patch create mode 100644 queue-6.6/smb-client-fix-potential-uaf-and-double-free-in-smb2.patch create mode 100644 queue-6.6/soc-mediatek-svs-fix-memory-leak-in-svs_enable_debug.patch create mode 100644 queue-6.6/soc-qcom-cmd-db-use-devm_memremap-to-fix-memory-leak.patch create mode 100644 queue-6.6/soc-qcom-smem-handle-enomem-error-during-probe.patch create mode 100644 queue-6.6/spi-tools-add-include-folder-to-.gitignore.patch create mode 100644 queue-6.6/staging-greybus-lights-avoid-null-deref.patch create mode 100644 queue-6.6/svcrdma-clean-up-comment-in-svc_rdma_accept.patch create mode 100644 queue-6.6/svcrdma-increase-the-per-transport-rw_ctx-count.patch create mode 100644 queue-6.6/svcrdma-reduce-the-number-of-rdma_rw-contexts-per-qp.patch create mode 100644 queue-6.6/svcrdma-remove-queue-shortening-warnings.patch create mode 100644 queue-6.6/tcp-tcp_tx_timestamp-must-look-at-the-rtx-queue.patch create mode 100644 queue-6.6/tools-power-x86-intel-speed-select-fix-file-descript.patch create mode 100644 queue-6.6/tpm-st33zp24-fix-missing-cleanup-on-get_burstcount-e.patch create mode 100644 queue-6.6/tpm-tpm_i2c_infineon-fix-locality-leak-on-get_burstc.patch create mode 100644 queue-6.6/tracing-properly-process-error-handling-in-event_his.patch create mode 100644 queue-6.6/tracing-remove-duplicate-enable_event_str-and-disabl.patch create mode 100644 queue-6.6/ublk-validate-sqe128-flag-before-accessing-the-cmd.patch create mode 100644 queue-6.6/ucount-check-for-cap_sys_resource-using-ns_capable_n.patch create mode 100644 queue-6.6/usb-bdc-fix-sleep-during-atomic.patch create mode 100644 queue-6.6/watchdog-starfive-wdt-fix-pm-reference-leak-in-probe.patch create mode 100644 queue-6.6/wifi-ath10k-sdio-add-missing-lock-protection-in-ath1.patch create mode 100644 queue-6.6/wifi-cfg80211-stop-nan-and-p2p-in-cfg80211_leave.patch create mode 100644 queue-6.6/workqueue-factor-out-assign_rescuer_work.patch create mode 100644 queue-6.6/workqueue-only-assign-rescuer-work-when-really-neede.patch create mode 100644 queue-6.6/workqueue-process-rescuer-work-items-one-by-one-usin.patch create mode 100644 queue-6.6/x86-xen-make-some-functions-static.patch create mode 100644 queue-6.6/xen-virtio-don-t-use-grant-dma-ops-when-running-as-d.patch create mode 100644 queue-6.6/xfrm-fix-ip_rt_bug-race-in-icmp_route_lookup-reverse.patch diff --git a/queue-5.10/arm-dts-allwinner-sun5i-a13-utoo-p66-delete-power-gp.patch b/queue-5.10/arm-dts-allwinner-sun5i-a13-utoo-p66-delete-power-gp.patch new file mode 100644 index 0000000000..55527fedd9 --- /dev/null +++ b/queue-5.10/arm-dts-allwinner-sun5i-a13-utoo-p66-delete-power-gp.patch @@ -0,0 +1,46 @@ +From 02dbfc13556dbd5912504506e88022fc39a31993 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 25 Dec 2025 18:36:14 +0800 +Subject: ARM: dts: allwinner: sun5i-a13-utoo-p66: delete "power-gpios" + property + +From: Chen-Yu Tsai + +[ Upstream commit 0b2761eb1287bd9f62367cccf6626eb3107cef6f ] + +The P66's device tree includes the reference design dtsi files, which +defines a node and properties for the touchpanel in the common design. +The P66 dts file then overrides all the properties to match its own +design, but as the touchpanel model is different, a different schema +is matched. This other schema uses a different name for the GPIO. + +The original submission added the correct GPIO property, but did not +delete the one inherited from the reference design, causing validation +errors. + +Explicitly delete the incorrect GPIO property. + +Fixes: 2a53aff27236 ("ARM: dts: sun5i: Enable touchscreen on Utoo P66") +Reviewed-by: Jernej Skrabec +Link: https://patch.msgid.link/20251225103616.3203473-4-wens@kernel.org +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Sasha Levin +--- + arch/arm/boot/dts/sun5i-a13-utoo-p66.dts | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/boot/dts/sun5i-a13-utoo-p66.dts b/arch/arm/boot/dts/sun5i-a13-utoo-p66.dts +index be486d28d04fa..428cab5a0e906 100644 +--- a/arch/arm/boot/dts/sun5i-a13-utoo-p66.dts ++++ b/arch/arm/boot/dts/sun5i-a13-utoo-p66.dts +@@ -102,6 +102,7 @@ &touchscreen { + /* The P66 uses a different EINT then the reference design */ + interrupts = <6 9 IRQ_TYPE_EDGE_FALLING>; /* EINT9 (PG9) */ + /* The icn8318 binding expects wake-gpios instead of power-gpios */ ++ /delete-property/ power-gpios; + wake-gpios = <&pio 1 3 GPIO_ACTIVE_HIGH>; /* PB3 */ + touchscreen-size-x = <800>; + touchscreen-size-y = <480>; +-- +2.51.0 + diff --git a/queue-5.10/arm-dts-lpc32xx-add-clocks-property-to-motor-control.patch b/queue-5.10/arm-dts-lpc32xx-add-clocks-property-to-motor-control.patch new file mode 100644 index 0000000000..5b30b2fba7 --- /dev/null +++ b/queue-5.10/arm-dts-lpc32xx-add-clocks-property-to-motor-control.patch @@ -0,0 +1,35 @@ +From 87d81dcc4e5de24ce1ce5d900eff33e907b56433 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Dec 2025 00:49:07 +0200 +Subject: arm: dts: lpc32xx: add clocks property to Motor Control PWM device + tree node + +From: Vladimir Zapolskiy + +[ Upstream commit 71630e581a0e34c03757f5c1706f57c853b92555 ] + +Motor Control PWM depends on its own supply clock, the clock gate control +is present in TIMCLK_CTRL1 register. + +Fixes: b7d41c937ed7 ("ARM: LPC32xx: Add the motor PWM to base dts file") +Signed-off-by: Vladimir Zapolskiy +Signed-off-by: Sasha Levin +--- + arch/arm/boot/dts/lpc32xx.dtsi | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/boot/dts/lpc32xx.dtsi b/arch/arm/boot/dts/lpc32xx.dtsi +index da9a891b38c5e..bb99c09fca96a 100644 +--- a/arch/arm/boot/dts/lpc32xx.dtsi ++++ b/arch/arm/boot/dts/lpc32xx.dtsi +@@ -304,6 +304,7 @@ i2c2: i2c@400a8000 { + mpwm: mpwm@400e8000 { + compatible = "nxp,lpc3220-motor-pwm"; + reg = <0x400e8000 0x78>; ++ clocks = <&clk LPC32XX_CLK_MCPWM>; + #pwm-cells = <3>; + status = "disabled"; + }; +-- +2.51.0 + diff --git a/queue-5.10/arm-dts-lpc32xx-set-motor-pwm-pwm-cells-property-val.patch b/queue-5.10/arm-dts-lpc32xx-set-motor-pwm-pwm-cells-property-val.patch new file mode 100644 index 0000000000..4a26eef437 --- /dev/null +++ b/queue-5.10/arm-dts-lpc32xx-set-motor-pwm-pwm-cells-property-val.patch @@ -0,0 +1,47 @@ +From cc697cf50298e5ed7216674760954636df0adc63 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Sep 2025 21:46:42 +0300 +Subject: ARM: dts: lpc32xx: Set motor PWM #pwm-cells property value to 3 cells +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Vladimir Zapolskiy + +[ Upstream commit 65ae9ea77e1f2a20ad2866f99596df7ccdbd3b95 ] + +Since commit 4cd2f417a0ac ("dt-bindings: pwm: Convert lpc32xx-pwm.txt +to yaml format") both types of PWM controlles on NXP LPC32xx SoC +fairly gained 3 cells, reflect it in the platform dtsi file. + +The change removes a dt binding checker warning: + + mpwm@400e8000: #pwm-cells:0:0: 3 was expected + +Cc: Uwe Kleine-König +Acked-by: Uwe Kleine-König +Reviewed-by: Frank Li +Signed-off-by: Vladimir Zapolskiy +Stable-dep-of: 71630e581a0e ("arm: dts: lpc32xx: add clocks property to Motor Control PWM device tree node") +Signed-off-by: Sasha Levin +--- + arch/arm/boot/dts/lpc32xx.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/lpc32xx.dtsi b/arch/arm/boot/dts/lpc32xx.dtsi +index 824393e1bcfb7..da9a891b38c5e 100644 +--- a/arch/arm/boot/dts/lpc32xx.dtsi ++++ b/arch/arm/boot/dts/lpc32xx.dtsi +@@ -304,8 +304,8 @@ i2c2: i2c@400a8000 { + mpwm: mpwm@400e8000 { + compatible = "nxp,lpc3220-motor-pwm"; + reg = <0x400e8000 0x78>; ++ #pwm-cells = <3>; + status = "disabled"; +- #pwm-cells = <2>; + }; + }; + +-- +2.51.0 + diff --git a/queue-5.10/arm-vdso-patch-out-__vdso_clock_getres-if-unavailabl.patch b/queue-5.10/arm-vdso-patch-out-__vdso_clock_getres-if-unavailabl.patch new file mode 100644 index 0000000000..305e8c6bbd --- /dev/null +++ b/queue-5.10/arm-vdso-patch-out-__vdso_clock_getres-if-unavailabl.patch @@ -0,0 +1,39 @@ +From 927a7d8937fc1243686be08a5aa46e11df836ae8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 23 Dec 2025 07:59:17 +0100 +Subject: ARM: VDSO: Patch out __vdso_clock_getres() if unavailable +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh + +[ Upstream commit b9fecf0dddfc55cd7d02b0011494da3c613f7cde ] + +The vDSO code hides symbols which are non-functional. +__vdso_clock_getres() was not added to this list when it got introduced. + +Fixes: 052e76a31b4a ("ARM: 8931/1: Add clock_getres entry point") +Signed-off-by: Thomas Weißschuh +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20251223-vdso-compat-time32-v1-6-97ea7a06a543@linutronix.de +Signed-off-by: Sasha Levin +--- + arch/arm/kernel/vdso.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/kernel/vdso.c b/arch/arm/kernel/vdso.c +index fddd08a6e063e..5a64bbf119e22 100644 +--- a/arch/arm/kernel/vdso.c ++++ b/arch/arm/kernel/vdso.c +@@ -185,6 +185,7 @@ static void __init patch_vdso(void *ehdr) + vdso_nullpatch_one(&einfo, "__vdso_gettimeofday"); + vdso_nullpatch_one(&einfo, "__vdso_clock_gettime"); + vdso_nullpatch_one(&einfo, "__vdso_clock_gettime64"); ++ vdso_nullpatch_one(&einfo, "__vdso_clock_getres"); + } + } + +-- +2.51.0 + diff --git a/queue-5.10/arm64-dts-amlogic-axg-assign-the-mmc-signal-clocks.patch b/queue-5.10/arm64-dts-amlogic-axg-assign-the-mmc-signal-clocks.patch new file mode 100644 index 0000000000..7777f51a60 --- /dev/null +++ b/queue-5.10/arm64-dts-amlogic-axg-assign-the-mmc-signal-clocks.patch @@ -0,0 +1,52 @@ +From ba4445c2749dfddef10555377098ff9d24630f60 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:08:50 +0100 +Subject: arm64: dts: amlogic: axg: assign the MMC signal clocks + +From: Jerome Brunet + +[ Upstream commit 13d3fe2318ef6e46d6fcfe13bc373827fdf2aeac ] + +The amlogic MMC driver operate with the assumption that MMC clock +is configured to provide 24MHz. It uses this path for low +rates such as 400kHz. + +Assign the clocks to make sure they are properly configured + +Fixes: 221cf34bac54 ("ARM64: dts: meson-axg: enable the eMMC controller") +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Link: https://patch.msgid.link/20260114-amlogic-mmc-clocks-followup-v1-3-a999fafbe0aa@baylibre.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-axg.dtsi | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi +index c892b252e5b0c..18e705169201b 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi +@@ -1761,6 +1761,9 @@ sd_emmc_b: sd@5000 { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_B>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_B_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + sd_emmc_c: mmc@7000 { +@@ -1773,6 +1776,9 @@ sd_emmc_c: mmc@7000 { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_C>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_C_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + usb2_phy1: phy@9020 { +-- +2.51.0 + diff --git a/queue-5.10/arm64-dts-amlogic-g12-assign-the-mmc-a-signal-clock.patch b/queue-5.10/arm64-dts-amlogic-g12-assign-the-mmc-a-signal-clock.patch new file mode 100644 index 0000000000..52138cac20 --- /dev/null +++ b/queue-5.10/arm64-dts-amlogic-g12-assign-the-mmc-a-signal-clock.patch @@ -0,0 +1,42 @@ +From 76b3e99f66eacaa1b5342a7a30a4b0fdfb4b369a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:08:53 +0100 +Subject: arm64: dts: amlogic: g12: assign the MMC A signal clock + +From: Jerome Brunet + +[ Upstream commit 3c941feaa363f1573a501452391ddf513394c84b ] + +The amlogic MMC driver operate with the assumption that MMC clock +is configured to provide 24MHz. It uses this path for low +rates such as 400kHz. + +Assign the clock to make sure it is properly configured + +Fixes: 8a6b3ca2d361 ("arm64: dts: meson: g12a: add SDIO controller") +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Link: https://patch.msgid.link/20260114-amlogic-mmc-clocks-followup-v1-6-a999fafbe0aa@baylibre.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +index ff764f7b017d7..27ebe5cc4f39c 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +@@ -2323,6 +2323,9 @@ sd_emmc_a: sd@ffe03000 { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_A>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_A_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + sd_emmc_b: sd@ffe05000 { +-- +2.51.0 + diff --git a/queue-5.10/arm64-dts-amlogic-g12-assign-the-mmc-b-and-c-signal-.patch b/queue-5.10/arm64-dts-amlogic-g12-assign-the-mmc-b-and-c-signal-.patch new file mode 100644 index 0000000000..b3f7b9c806 --- /dev/null +++ b/queue-5.10/arm64-dts-amlogic-g12-assign-the-mmc-b-and-c-signal-.patch @@ -0,0 +1,52 @@ +From 58ee6c5c54b6c1cbc6d56f8d9532fbd78aba904a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:08:52 +0100 +Subject: arm64: dts: amlogic: g12: assign the MMC B and C signal clocks + +From: Jerome Brunet + +[ Upstream commit be2ff5fdb0e83e32d4ec4e68a69875cec0d14621 ] + +The amlogic MMC driver operate with the assumption that MMC clock +is configured to provide 24MHz. It uses this path for low +rates such as 400kHz. + +Assign the clocks to make sure they are properly configured + +Fixes: 4759fd87b928 ("arm64: dts: meson: g12a: add mmc nodes") +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Link: https://patch.msgid.link/20260114-amlogic-mmc-clocks-followup-v1-5-a999fafbe0aa@baylibre.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +index 9dd9f7715fbe6..ff764f7b017d7 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +@@ -2335,6 +2335,9 @@ sd_emmc_b: sd@ffe05000 { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_B>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_B_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + sd_emmc_c: mmc@ffe07000 { +@@ -2347,6 +2350,9 @@ sd_emmc_c: mmc@ffe07000 { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_C>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_C_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + usb: usb@ffe09000 { +-- +2.51.0 + diff --git a/queue-5.10/arm64-dts-amlogic-gx-assign-the-mmc-signal-clocks.patch b/queue-5.10/arm64-dts-amlogic-gx-assign-the-mmc-signal-clocks.patch new file mode 100644 index 0000000000..db8d95a880 --- /dev/null +++ b/queue-5.10/arm64-dts-amlogic-gx-assign-the-mmc-signal-clocks.patch @@ -0,0 +1,97 @@ +From 0d92a70d818388ca882c3bc3e9c10fc69d0fa67f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:08:51 +0100 +Subject: arm64: dts: amlogic: gx: assign the MMC signal clocks + +From: Jerome Brunet + +[ Upstream commit 406706559046eebc09a31e8ae5e78620bfd746fe ] + +The amlogic MMC driver operate with the assumption that MMC clock +is configured to provide 24MHz. It uses this path for low +rates such as 400kHz. + +Assign the clocks to make sure they are properly configured + +Fixes: 50662499f911 ("ARM64: dts: meson-gx: Use correct mmc clock source 0") +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Link: https://patch.msgid.link/20260114-amlogic-mmc-clocks-followup-v1-4-a999fafbe0aa@baylibre.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 9 +++++++++ + arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 9 +++++++++ + 2 files changed, 18 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi +index 256c46771db78..c57a6f37bc2af 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi +@@ -779,6 +779,9 @@ &sd_emmc_a { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_A>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_A_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &sd_emmc_b { +@@ -787,6 +790,9 @@ &sd_emmc_b { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_B>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_B_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &sd_emmc_c { +@@ -795,6 +801,9 @@ &sd_emmc_c { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_C>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_C_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &simplefb_hdmi { +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi +index a689bd14ece99..fb6e8c466811f 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi +@@ -848,6 +848,9 @@ &sd_emmc_a { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_A>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_A_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &sd_emmc_b { +@@ -856,6 +859,9 @@ &sd_emmc_b { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_B>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_B_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &sd_emmc_c { +@@ -864,6 +870,9 @@ &sd_emmc_c { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_C>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_C_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &simplefb_hdmi { +-- +2.51.0 + diff --git a/queue-5.10/arm64-dts-qcom-sdm630-add-qfprom-subnodes.patch b/queue-5.10/arm64-dts-qcom-sdm630-add-qfprom-subnodes.patch new file mode 100644 index 0000000000..e201213c0c --- /dev/null +++ b/queue-5.10/arm64-dts-qcom-sdm630-add-qfprom-subnodes.patch @@ -0,0 +1,46 @@ +From 7c04455f9e8afeb4c4093e9d2985828d33a51b98 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jul 2021 00:25:09 +0200 +Subject: arm64: dts: qcom: sdm630: Add qfprom subnodes + +From: AngeloGioacchino Del Regno + +[ Upstream commit 142662f8f43c1725418ff13a2c83fb218d2b0911 ] + +These will be required for USB and Adreno support. + +Signed-off-by: AngeloGioacchino Del Regno +Signed-off-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20210728222542.54269-7-konrad.dybcio@somainline.org +[bjorn: y/_/-/ in gpu_speed_bin] +Signed-off-by: Bjorn Andersson +Stable-dep-of: e814796dfcae ("arm64: dts: qcom: sdm630: fix gpu_speed_bin size") +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm630.dtsi | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/arch/arm64/boot/dts/qcom/sdm630.dtsi b/arch/arm64/boot/dts/qcom/sdm630.dtsi +index 79d260c2b3c32..d810ab74204c5 100644 +--- a/arch/arm64/boot/dts/qcom/sdm630.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm630.dtsi +@@ -460,6 +460,16 @@ qfprom: qfprom@780000 { + reg = <0x00780000 0x621c>; + #address-cells = <1>; + #size-cells = <1>; ++ ++ qusb2_hstx_trim: hstx-trim@240 { ++ reg = <0x240 0x1>; ++ bits = <25 3>; ++ }; ++ ++ gpu_speed_bin: gpu-speed-bin@41a0 { ++ reg = <0x41a0 0x1>; ++ bits = <21 7>; ++ }; + }; + + rng: rng@793000 { +-- +2.51.0 + diff --git a/queue-5.10/arm64-dts-qcom-sdm630-correct-qfprom-byte-offsets.patch b/queue-5.10/arm64-dts-qcom-sdm630-correct-qfprom-byte-offsets.patch new file mode 100644 index 0000000000..140e30a30d --- /dev/null +++ b/queue-5.10/arm64-dts-qcom-sdm630-correct-qfprom-byte-offsets.patch @@ -0,0 +1,53 @@ +From 914fabf9ed8aa9c561a41771a8fd54d630be4cdd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 May 2022 13:38:02 +0200 +Subject: arm64: dts: qcom: sdm630: correct QFPROM byte offsets + +From: Krzysztof Kozlowski + +[ Upstream commit 74b0fbd6048f8f4caaed712ceeca52c6034e9ad6 ] + +The NVMEM bindings expect that 'bits' property holds offset and size of +region within a byte, so it applies a constraint of <0, 7> for the +offset. Using 25 as HSTX trim offset is within 4-byte QFPROM word, but +outside of the byte: + + sdm630-sony-xperia-nile-discovery.dtb: qfprom@780000: hstx-trim@240:bits:0:0: 25 is greater than the maximum of 7 + sdm630-sony-xperia-nile-discovery.dtb: qfprom@780000: gpu-speed-bin@41a0:bits:0:0: 21 is greater than the maximum of 7 + +Align the offsets to match the bindings. + +Signed-off-by: Krzysztof Kozlowski +Signed-off-by: Bjorn Andersson +Link: https://lore.kernel.org/r/20220505113802.243301-6-krzysztof.kozlowski@linaro.org +Stable-dep-of: e814796dfcae ("arm64: dts: qcom: sdm630: fix gpu_speed_bin size") +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm630.dtsi | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/sdm630.dtsi b/arch/arm64/boot/dts/qcom/sdm630.dtsi +index d810ab74204c5..c39e67fa64650 100644 +--- a/arch/arm64/boot/dts/qcom/sdm630.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm630.dtsi +@@ -462,13 +462,13 @@ qfprom: qfprom@780000 { + #size-cells = <1>; + + qusb2_hstx_trim: hstx-trim@240 { +- reg = <0x240 0x1>; +- bits = <25 3>; ++ reg = <0x243 0x1>; ++ bits = <1 3>; + }; + + gpu_speed_bin: gpu-speed-bin@41a0 { +- reg = <0x41a0 0x1>; +- bits = <21 7>; ++ reg = <0x41a2 0x1>; ++ bits = <5 7>; + }; + }; + +-- +2.51.0 + diff --git a/queue-5.10/arm64-dts-qcom-sdm630-fix-gpu_speed_bin-size.patch b/queue-5.10/arm64-dts-qcom-sdm630-fix-gpu_speed_bin-size.patch new file mode 100644 index 0000000000..0cf7e11c08 --- /dev/null +++ b/queue-5.10/arm64-dts-qcom-sdm630-fix-gpu_speed_bin-size.patch @@ -0,0 +1,49 @@ +From d5efcca8265aea0fb91052f20ea09943ae2f864d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 11 Dec 2025 03:27:45 +0200 +Subject: arm64: dts: qcom: sdm630: fix gpu_speed_bin size + +From: Dmitry Baryshkov + +[ Upstream commit e814796dfcae8905682ac3ac2dd57f512a9f6726 ] + +Historically sdm630.dtsi has used 1 byte length for the gpu_speed_bin +cell, although it spans two bytes (offset 5, size 7 bits). It was being +accepted by the kernel because before the commit 7a06ef751077 ("nvmem: +core: fix bit offsets of more than one byte") the kernel didn't have +length check. After this commit nvmem core rejects QFPROM on sdm630 / +sdm660, making GPU and USB unusable on those platforms. + +Set the size of the gpu_speed_bin cell to 2 bytes, fixing the parsing +error. While we are at it, update the length to 8 bits as pointed out by +Alexey Minnekhanov. + +Fixes: b190fb010664 ("arm64: dts: qcom: sdm630: Add sdm630 dts file") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Reviewed-by: Alexey Minnekhanov +Link: https://lore.kernel.org/r/20251211-sdm630-fix-gpu-v2-1-92f0e736dba0@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm630.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/sdm630.dtsi b/arch/arm64/boot/dts/qcom/sdm630.dtsi +index c39e67fa64650..cc43d014c5038 100644 +--- a/arch/arm64/boot/dts/qcom/sdm630.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm630.dtsi +@@ -467,8 +467,8 @@ qusb2_hstx_trim: hstx-trim@240 { + }; + + gpu_speed_bin: gpu-speed-bin@41a0 { +- reg = <0x41a2 0x1>; +- bits = <5 7>; ++ reg = <0x41a2 0x2>; ++ bits = <5 8>; + }; + }; + +-- +2.51.0 + diff --git a/queue-5.10/arm64-dts-qcom-sdm845-db845c-specify-power-for-wifi-.patch b/queue-5.10/arm64-dts-qcom-sdm845-db845c-specify-power-for-wifi-.patch new file mode 100644 index 0000000000..f8d90be0b3 --- /dev/null +++ b/queue-5.10/arm64-dts-qcom-sdm845-db845c-specify-power-for-wifi-.patch @@ -0,0 +1,50 @@ +From 07a7028bd63869a6f835e4eb541bda7c09393e5a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Jan 2026 03:01:18 +0200 +Subject: arm64: dts: qcom: sdm845-db845c: specify power for WiFi CH1 + +From: Dmitry Baryshkov + +[ Upstream commit c303e89f7f17c29981d09f8beaaf60937ae8b1f2 ] + +Specify power supply for the second chain / antenna output of the +onboard WiFi chip. + +Fixes: 3f72e2d3e682 ("arm64: dts: qcom: Add Dragonboard 845c") +Reviewed-by: Konrad Dybcio +Signed-off-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260106-wcn3990-pwrctl-v2-8-0386204328be@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm845-db845c.dts | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts +index 31f4f05750940..e327e398d99ed 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts ++++ b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts +@@ -342,6 +342,12 @@ vreg_l21a_2p95: ldo21 { + regulator-initial-mode = ; + }; + ++ vreg_l23a_3p3: ldo23 { ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3312000>; ++ regulator-initial-mode = ; ++ }; ++ + vreg_l24a_3p075: ldo24 { + regulator-min-microvolt = <3088000>; + regulator-max-microvolt = <3088000>; +@@ -1039,6 +1045,7 @@ &wifi { + vdd-1.8-xo-supply = <&vreg_l7a_1p8>; + vdd-1.3-rfa-supply = <&vreg_l17a_1p3>; + vdd-3.3-ch0-supply = <&vreg_l25a_3p3>; ++ vdd-3.3-ch1-supply = <&vreg_l23a_3p3>; + + qcom,snoc-host-cap-8bit-quirk; + }; +-- +2.51.0 + diff --git a/queue-5.10/auxdisplay-arm-charlcd-fix-release_mem_region-size.patch b/queue-5.10/auxdisplay-arm-charlcd-fix-release_mem_region-size.patch new file mode 100644 index 0000000000..26cf34b40a --- /dev/null +++ b/queue-5.10/auxdisplay-arm-charlcd-fix-release_mem_region-size.patch @@ -0,0 +1,39 @@ +From 6c35e110517edd15878f1b6201f8e5e86dfdcb13 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Dec 2025 18:47:13 +0100 +Subject: auxdisplay: arm-charlcd: fix release_mem_region() size + +From: Thomas Fourier + +[ Upstream commit b5c23a4d291d2ac1dfdd574a68a3a68c8da3069e ] + +It seems like, after the request_mem_region(), the corresponding +release_mem_region() must take the same size. This was done +in (now removed due to previous refactoring) charlcd_remove() +but not in the error path in charlcd_probe(). + +Fixes: ce8962455e90 ("ARM: 6214/2: driver for the character LCD found in ARM refdesigns") +Signed-off-by: Thomas Fourier +Reviewed-by: Geert Uytterhoeven +Signed-off-by: Andy Shevchenko +Signed-off-by: Sasha Levin +--- + drivers/auxdisplay/arm-charlcd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/auxdisplay/arm-charlcd.c b/drivers/auxdisplay/arm-charlcd.c +index 0b1c99cca7334..f418b133ee752 100644 +--- a/drivers/auxdisplay/arm-charlcd.c ++++ b/drivers/auxdisplay/arm-charlcd.c +@@ -323,7 +323,7 @@ static int __init charlcd_probe(struct platform_device *pdev) + out_no_irq: + iounmap(lcd->virtbase); + out_no_memregion: +- release_mem_region(lcd->phybase, SZ_4K); ++ release_mem_region(lcd->phybase, lcd->physize); + out_no_resource: + kfree(lcd); + return ret; +-- +2.51.0 + diff --git a/queue-5.10/bonding-only-set-speed-duplex-to-unknown-if-getting-.patch b/queue-5.10/bonding-only-set-speed-duplex-to-unknown-if-getting-.patch new file mode 100644 index 0000000000..999866a509 --- /dev/null +++ b/queue-5.10/bonding-only-set-speed-duplex-to-unknown-if-getting-.patch @@ -0,0 +1,74 @@ +From 43bcab2e0ce90a3d6e8ef1fb42a98537c793affa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 15:11:52 +0100 +Subject: bonding: only set speed/duplex to unknown, if getting speed failed + +From: Thomas Bogendoerfer + +[ Upstream commit 48dec8d88af96039a4a17b8c2f148f2a4066e195 ] + +bond_update_speed_duplex() first set speed/duplex to unknown and +then asks slave driver for current speed/duplex. Since getting +speed/duplex might take longer there is a race, where this false state +is visible by /proc/net/bonding. With commit 691b2bf14946 ("bonding: + update port speed when getting bond speed") this race gets more visible, +if user space is calling ethtool on a regular base. + +Fix this by only setting speed/duplex to unknown, if link speed is +really unknown/unusable. + +Fixes: 98f41f694f46 ("bonding:update speed/duplex for NETDEV_CHANGE") +Signed-off-by: Thomas Bogendoerfer +Acked-by: Jay Vosburgh +Reviewed-by: Nikolay Aleksandrov +Reviewed-by: Hangbin Liu +Link: https://patch.msgid.link/20260203141153.51581-1-tbogendoerfer@suse.de +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/bonding/bond_main.c | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c +index a6d552a83ca43..1d8a6690527aa 100644 +--- a/drivers/net/bonding/bond_main.c ++++ b/drivers/net/bonding/bond_main.c +@@ -638,26 +638,29 @@ static int bond_update_speed_duplex(struct slave *slave) + struct ethtool_link_ksettings ecmd; + int res; + +- slave->speed = SPEED_UNKNOWN; +- slave->duplex = DUPLEX_UNKNOWN; +- + res = __ethtool_get_link_ksettings(slave_dev, &ecmd); + if (res < 0) +- return 1; ++ goto speed_duplex_unknown; + if (ecmd.base.speed == 0 || ecmd.base.speed == ((__u32)-1)) +- return 1; ++ goto speed_duplex_unknown; + switch (ecmd.base.duplex) { + case DUPLEX_FULL: + case DUPLEX_HALF: + break; + default: +- return 1; ++ goto speed_duplex_unknown; + } + + slave->speed = ecmd.base.speed; + slave->duplex = ecmd.base.duplex; + + return 0; ++ ++speed_duplex_unknown: ++ slave->speed = SPEED_UNKNOWN; ++ slave->duplex = DUPLEX_UNKNOWN; ++ ++ return 1; + } + + const char *bond_slave_link_status(s8 link) +-- +2.51.0 + diff --git a/queue-5.10/btrfs-qgroup-return-correct-error-when-deleting-qgro.patch b/queue-5.10/btrfs-qgroup-return-correct-error-when-deleting-qgro.patch new file mode 100644 index 0000000000..c994c998fb --- /dev/null +++ b/queue-5.10/btrfs-qgroup-return-correct-error-when-deleting-qgro.patch @@ -0,0 +1,43 @@ +From 96e5e1563fadb40ee3b3c432b06910d3b0193143 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 19:35:23 +0000 +Subject: btrfs: qgroup: return correct error when deleting qgroup relation + item + +From: Filipe Manana + +[ Upstream commit 51b1fcf71c88c3c89e7dcf07869c5de837b1f428 ] + +If we fail to delete the second qgroup relation item, we end up returning +success or -ENOENT in case the first item does not exist, instead of +returning the error from the second item deletion. + +Fixes: 73798c465b66 ("btrfs: qgroup: Try our best to delete qgroup relations") +Reviewed-by: Johannes Thumshirn +Signed-off-by: Filipe Manana +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/qgroup.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c +index bc1feb97698c9..647feb72c8b0a 100644 +--- a/fs/btrfs/qgroup.c ++++ b/fs/btrfs/qgroup.c +@@ -1540,8 +1540,10 @@ static int __del_qgroup_relation(struct btrfs_trans_handle *trans, u64 src, + if (ret < 0 && ret != -ENOENT) + goto out; + ret2 = del_qgroup_relation_item(trans, dst, src); +- if (ret2 < 0 && ret2 != -ENOENT) ++ if (ret2 < 0 && ret2 != -ENOENT) { ++ ret = ret2; + goto out; ++ } + + /* At least one deletion succeeded, return 0 */ + if (!ret || !ret2) +-- +2.51.0 + diff --git a/queue-5.10/clk-meson-gxbb-limit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch b/queue-5.10/clk-meson-gxbb-limit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch new file mode 100644 index 0000000000..9daa0f08d0 --- /dev/null +++ b/queue-5.10/clk-meson-gxbb-limit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch @@ -0,0 +1,87 @@ +From c30430e4cf6f915f6fb01dc8e4bc6f1bba308c6b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Jan 2026 21:47:08 +0100 +Subject: clk: meson: gxbb: Limit the HDMI PLL OD to /4 on GXL/GXM SoCs + +From: Martin Blumenstingl + +[ Upstream commit 5b1a43950fd3162af0ce52b13c14a2d29b179d4f ] + +GXBB has the HDMI PLL OD in the HHI_HDMI_PLL_CNTL2 register while for +GXL/GXM the OD has moved to HHI_HDMI_PLL_CNTL3. At first glance the rest +of the OD setup seems identical. + +However, looking at the downstream kernel sources as well as testing +shows that GXL only supports three OD values: +- register value 0 means: divide by 1 +- register value 1 means: divide by 2 +- register value 2 means: divide by 4 + +Using register value 3 (which on GXBB means: divide by 8) still divides +by 4 as verified using meson-clk-measure. Downstream sources are also +only using OD register values 0, 1 and 2 for GXL (while for GXBB the +downstream kernel sources are also using value 3). + +Add clk_div_table and have it replace the CLK_DIVIDER_POWER_OF_TWO flag +to make the kernel's view of this register match with how the hardware +actually works. + +Fixes: 69d92293274b ("clk: meson: add the gxl hdmi pll") +Signed-off-by: Martin Blumenstingl +Link: https://lore.kernel.org/r/20260105204710.447779-2-martin.blumenstingl@googlemail.com +Signed-off-by: Jerome Brunet +Signed-off-by: Sasha Levin +--- + drivers/clk/meson/gxbb.c | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c +index cfdb1ce6d361c..cc99a828eb4d2 100644 +--- a/drivers/clk/meson/gxbb.c ++++ b/drivers/clk/meson/gxbb.c +@@ -315,12 +315,23 @@ static struct clk_regmap gxbb_hdmi_pll = { + }, + }; + ++/* ++ * GXL hdmi OD dividers are POWER_OF_TWO dividers but limited to /4. ++ * A divider value of 3 should map to /8 but instead map /4 so ignore it. ++ */ ++static const struct clk_div_table gxl_hdmi_pll_od_div_table[] = { ++ { .val = 0, .div = 1 }, ++ { .val = 1, .div = 2 }, ++ { .val = 2, .div = 4 }, ++ { /* sentinel */ } ++}; ++ + static struct clk_regmap gxl_hdmi_pll_od = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL + 8, + .shift = 21, + .width = 2, +- .flags = CLK_DIVIDER_POWER_OF_TWO, ++ .table = gxl_hdmi_pll_od_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od", +@@ -338,7 +349,7 @@ static struct clk_regmap gxl_hdmi_pll_od2 = { + .offset = HHI_HDMI_PLL_CNTL + 8, + .shift = 23, + .width = 2, +- .flags = CLK_DIVIDER_POWER_OF_TWO, ++ .table = gxl_hdmi_pll_od_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od2", +@@ -356,7 +367,7 @@ static struct clk_regmap gxl_hdmi_pll = { + .offset = HHI_HDMI_PLL_CNTL + 8, + .shift = 19, + .width = 2, +- .flags = CLK_DIVIDER_POWER_OF_TWO, ++ .table = gxl_hdmi_pll_od_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll", +-- +2.51.0 + diff --git a/queue-5.10/clk-move-clk_-save-restore-_context-to-common_clk-se.patch b/queue-5.10/clk-move-clk_-save-restore-_context-to-common_clk-se.patch new file mode 100644 index 0000000000..3135bed3c5 --- /dev/null +++ b/queue-5.10/clk-move-clk_-save-restore-_context-to-common_clk-se.patch @@ -0,0 +1,117 @@ +From 885c21324166f6eca52a2606abdd707d22415791 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Dec 2025 10:42:26 +0100 +Subject: clk: Move clk_{save,restore}_context() to COMMON_CLK section + +From: Geert Uytterhoeven + +[ Upstream commit f47c1b77d0a2a9c0d49ec14302e74f933398d1a3 ] + +The clk_save_context() and clk_restore_context() helpers are only +implemented by the Common Clock Framework. They are not available when +using legacy clock frameworks. Dummy implementations are provided, but +only if no clock support is available at all. + +Hence when CONFIG_HAVE_CLK=y, but CONFIG_COMMON_CLK is not enabled: + + m68k-linux-gnu-ld: drivers/net/phy/air_en8811h.o: in function `en8811h_resume': + air_en8811h.c:(.text+0x83e): undefined reference to `clk_restore_context' + m68k-linux-gnu-ld: drivers/net/phy/air_en8811h.o: in function `en8811h_suspend': + air_en8811h.c:(.text+0x856): undefined reference to `clk_save_context' + +Fix this by moving forward declarations and dummy implementions from the +HAVE_CLK to the COMMON_CLK section. + +Fixes: 8b95d1ce3300c411 ("clk: Add functions to save/restore clock context en-masse") +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202511301553.eaEz1nEW-lkp@intel.com/ +Signed-off-by: Geert Uytterhoeven +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + include/linux/clk.h | 48 ++++++++++++++++++++++----------------------- + 1 file changed, 24 insertions(+), 24 deletions(-) + +diff --git a/include/linux/clk.h b/include/linux/clk.h +index 12c85ba606ec5..cfa53819276ec 100644 +--- a/include/linux/clk.h ++++ b/include/linux/clk.h +@@ -205,6 +205,23 @@ int clk_rate_exclusive_get(struct clk *clk); + */ + void clk_rate_exclusive_put(struct clk *clk); + ++/** ++ * clk_save_context - save clock context for poweroff ++ * ++ * Saves the context of the clock register for powerstates in which the ++ * contents of the registers will be lost. Occurs deep within the suspend ++ * code so locking is not necessary. ++ */ ++int clk_save_context(void); ++ ++/** ++ * clk_restore_context - restore clock context after poweroff ++ * ++ * This occurs with all clocks enabled. Occurs deep within the resume code ++ * so locking is not necessary. ++ */ ++void clk_restore_context(void); ++ + #else + + static inline int clk_notifier_register(struct clk *clk, +@@ -258,6 +275,13 @@ static inline int clk_rate_exclusive_get(struct clk *clk) + + static inline void clk_rate_exclusive_put(struct clk *clk) {} + ++static inline int clk_save_context(void) ++{ ++ return 0; ++} ++ ++static inline void clk_restore_context(void) {} ++ + #endif + + /** +@@ -819,23 +843,6 @@ struct clk *clk_get_parent(struct clk *clk); + */ + struct clk *clk_get_sys(const char *dev_id, const char *con_id); + +-/** +- * clk_save_context - save clock context for poweroff +- * +- * Saves the context of the clock register for powerstates in which the +- * contents of the registers will be lost. Occurs deep within the suspend +- * code so locking is not necessary. +- */ +-int clk_save_context(void); +- +-/** +- * clk_restore_context - restore clock context after poweroff +- * +- * This occurs with all clocks enabled. Occurs deep within the resume code +- * so locking is not necessary. +- */ +-void clk_restore_context(void); +- + #else /* !CONFIG_HAVE_CLK */ + + static inline struct clk *clk_get(struct device *dev, const char *id) +@@ -1002,13 +1009,6 @@ static inline struct clk *clk_get_sys(const char *dev_id, const char *con_id) + return NULL; + } + +-static inline int clk_save_context(void) +-{ +- return 0; +-} +- +-static inline void clk_restore_context(void) {} +- + #endif + + /* clk_prepare_enable helps cases using clk_enable in non-atomic context. */ +-- +2.51.0 + diff --git a/queue-5.10/clk-qcom-dispcc-sdm845-convert-to-parent-data.patch b/queue-5.10/clk-qcom-dispcc-sdm845-convert-to-parent-data.patch new file mode 100644 index 0000000000..d674df123f --- /dev/null +++ b/queue-5.10/clk-qcom-dispcc-sdm845-convert-to-parent-data.patch @@ -0,0 +1,532 @@ +From 341958a042c83521bc83dbeaaa4ca20b2a76680d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Apr 2021 01:47:21 +0300 +Subject: clk: qcom: dispcc-sdm845: convert to parent data + +From: Dmitry Baryshkov + +[ Upstream commit 7acd22512907c3afe07cfd759d47a5f8eb8fb04f ] + +Convert the clock driver to specify parent data rather than parent +names, to actually bind using 'clock-names' specified in the DTS rather +than global clock names. + +Signed-off-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20210405224743.590029-12-dmitry.baryshkov@linaro.org +Signed-off-by: Stephen Boyd +Stable-dep-of: a1d63493634e ("clk: qcom: dispcc-sdm845: Enable parents for pixel clocks") +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sdm845.c | 216 ++++++++++++++++--------------- + 1 file changed, 109 insertions(+), 107 deletions(-) + +diff --git a/drivers/clk/qcom/dispcc-sdm845.c b/drivers/clk/qcom/dispcc-sdm845.c +index 8cd8174ac9aa7..a71e103553bbb 100644 +--- a/drivers/clk/qcom/dispcc-sdm845.c ++++ b/drivers/clk/qcom/dispcc-sdm845.c +@@ -33,6 +33,21 @@ enum { + P_DP_PHY_PLL_VCO_DIV_CLK, + }; + ++static struct clk_alpha_pll disp_cc_pll0 = { ++ .offset = 0x0, ++ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], ++ .clkr = { ++ .hw.init = &(struct clk_init_data){ ++ .name = "disp_cc_pll0", ++ .parent_data = &(const struct clk_parent_data){ ++ .fw_name = "bi_tcxo", .name = "bi_tcxo", ++ }, ++ .num_parents = 1, ++ .ops = &clk_alpha_pll_fabia_ops, ++ }, ++ }, ++}; ++ + static const struct parent_map disp_cc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_DSI0_PHY_PLL_OUT_BYTECLK, 1 }, +@@ -40,11 +55,11 @@ static const struct parent_map disp_cc_parent_map_0[] = { + { P_CORE_BI_PLL_TEST_SE, 7 }, + }; + +-static const char * const disp_cc_parent_names_0[] = { +- "bi_tcxo", +- "dsi0_phy_pll_out_byteclk", +- "dsi1_phy_pll_out_byteclk", +- "core_bi_pll_test_se", ++static const struct clk_parent_data disp_cc_parent_data_0[] = { ++ { .fw_name = "bi_tcxo", .name = "bi_tcxo" }, ++ { .fw_name = "dsi0_phy_pll_out_byteclk", .name = "dsi0_phy_pll_out_byteclk" }, ++ { .fw_name = "dsi1_phy_pll_out_byteclk", .name = "dsi1_phy_pll_out_byteclk" }, ++ { .fw_name = "core_bi_pll_test_se", .name = "core_bi_pll_test_se" }, + }; + + static const struct parent_map disp_cc_parent_map_1[] = { +@@ -54,11 +69,11 @@ static const struct parent_map disp_cc_parent_map_1[] = { + { P_CORE_BI_PLL_TEST_SE, 7 }, + }; + +-static const char * const disp_cc_parent_names_1[] = { +- "bi_tcxo", +- "dp_link_clk_divsel_ten", +- "dp_vco_divided_clk_src_mux", +- "core_bi_pll_test_se", ++static const struct clk_parent_data disp_cc_parent_data_1[] = { ++ { .fw_name = "bi_tcxo", .name = "bi_tcxo" }, ++ { .fw_name = "dp_link_clk_divsel_ten", .name = "dp_link_clk_divsel_ten" }, ++ { .fw_name = "dp_vco_divided_clk_src_mux", .name = "dp_vco_divided_clk_src_mux" }, ++ { .fw_name = "core_bi_pll_test_se", .name = "core_bi_pll_test_se" }, + }; + + static const struct parent_map disp_cc_parent_map_2[] = { +@@ -66,9 +81,9 @@ static const struct parent_map disp_cc_parent_map_2[] = { + { P_CORE_BI_PLL_TEST_SE, 7 }, + }; + +-static const char * const disp_cc_parent_names_2[] = { +- "bi_tcxo", +- "core_bi_pll_test_se", ++static const struct clk_parent_data disp_cc_parent_data_2[] = { ++ { .fw_name = "bi_tcxo", .name = "bi_tcxo" }, ++ { .fw_name = "core_bi_pll_test_se", .name = "core_bi_pll_test_se" }, + }; + + static const struct parent_map disp_cc_parent_map_3[] = { +@@ -79,12 +94,12 @@ static const struct parent_map disp_cc_parent_map_3[] = { + { P_CORE_BI_PLL_TEST_SE, 7 }, + }; + +-static const char * const disp_cc_parent_names_3[] = { +- "bi_tcxo", +- "disp_cc_pll0", +- "gcc_disp_gpll0_clk_src", +- "gcc_disp_gpll0_div_clk_src", +- "core_bi_pll_test_se", ++static const struct clk_parent_data disp_cc_parent_data_3[] = { ++ { .fw_name = "bi_tcxo", .name = "bi_tcxo" }, ++ { .hw = &disp_cc_pll0.clkr.hw }, ++ { .fw_name = "gcc_disp_gpll0_clk_src", .name = "gcc_disp_gpll0_clk_src" }, ++ { .fw_name = "gcc_disp_gpll0_div_clk_src", .name = "gcc_disp_gpll0_div_clk_src" }, ++ { .fw_name = "core_bi_pll_test_se", .name = "core_bi_pll_test_se" }, + }; + + static const struct parent_map disp_cc_parent_map_4[] = { +@@ -94,24 +109,11 @@ static const struct parent_map disp_cc_parent_map_4[] = { + { P_CORE_BI_PLL_TEST_SE, 7 }, + }; + +-static const char * const disp_cc_parent_names_4[] = { +- "bi_tcxo", +- "dsi0_phy_pll_out_dsiclk", +- "dsi1_phy_pll_out_dsiclk", +- "core_bi_pll_test_se", +-}; +- +-static struct clk_alpha_pll disp_cc_pll0 = { +- .offset = 0x0, +- .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], +- .clkr = { +- .hw.init = &(struct clk_init_data){ +- .name = "disp_cc_pll0", +- .parent_names = (const char *[]){ "bi_tcxo" }, +- .num_parents = 1, +- .ops = &clk_alpha_pll_fabia_ops, +- }, +- }, ++static const struct clk_parent_data disp_cc_parent_data_4[] = { ++ { .fw_name = "bi_tcxo", .name = "bi_tcxo" }, ++ { .fw_name = "dsi0_phy_pll_out_dsiclk", .name = "dsi0_phy_pll_out_dsiclk" }, ++ { .fw_name = "dsi1_phy_pll_out_dsiclk", .name = "dsi1_phy_pll_out_dsiclk" }, ++ { .fw_name = "core_bi_pll_test_se", .name = "core_bi_pll_test_se" }, + }; + + /* Return the HW recalc rate for idle use case */ +@@ -122,8 +124,8 @@ static struct clk_rcg2 disp_cc_mdss_byte0_clk_src = { + .parent_map = disp_cc_parent_map_0, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_byte0_clk_src", +- .parent_names = disp_cc_parent_names_0, +- .num_parents = 4, ++ .parent_data = disp_cc_parent_data_0, ++ .num_parents = ARRAY_SIZE(disp_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_byte2_ops, + }, +@@ -137,8 +139,8 @@ static struct clk_rcg2 disp_cc_mdss_byte1_clk_src = { + .parent_map = disp_cc_parent_map_0, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_byte1_clk_src", +- .parent_names = disp_cc_parent_names_0, +- .num_parents = 4, ++ .parent_data = disp_cc_parent_data_0, ++ .num_parents = ARRAY_SIZE(disp_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_byte2_ops, + }, +@@ -157,8 +159,8 @@ static struct clk_rcg2 disp_cc_mdss_dp_aux_clk_src = { + .freq_tbl = ftbl_disp_cc_mdss_dp_aux_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_aux_clk_src", +- .parent_names = disp_cc_parent_names_2, +- .num_parents = 2, ++ .parent_data = disp_cc_parent_data_2, ++ .num_parents = ARRAY_SIZE(disp_cc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + }, +@@ -171,8 +173,8 @@ static struct clk_rcg2 disp_cc_mdss_dp_crypto_clk_src = { + .parent_map = disp_cc_parent_map_1, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_crypto_clk_src", +- .parent_names = disp_cc_parent_names_1, +- .num_parents = 4, ++ .parent_data = disp_cc_parent_data_1, ++ .num_parents = ARRAY_SIZE(disp_cc_parent_data_1), + .ops = &clk_byte2_ops, + }, + }; +@@ -184,8 +186,8 @@ static struct clk_rcg2 disp_cc_mdss_dp_link_clk_src = { + .parent_map = disp_cc_parent_map_1, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_link_clk_src", +- .parent_names = disp_cc_parent_names_1, +- .num_parents = 4, ++ .parent_data = disp_cc_parent_data_1, ++ .num_parents = ARRAY_SIZE(disp_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_byte2_ops, + }, +@@ -198,8 +200,8 @@ static struct clk_rcg2 disp_cc_mdss_dp_pixel1_clk_src = { + .parent_map = disp_cc_parent_map_1, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_pixel1_clk_src", +- .parent_names = disp_cc_parent_names_1, +- .num_parents = 4, ++ .parent_data = disp_cc_parent_data_1, ++ .num_parents = ARRAY_SIZE(disp_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_dp_ops, + }, +@@ -212,8 +214,8 @@ static struct clk_rcg2 disp_cc_mdss_dp_pixel_clk_src = { + .parent_map = disp_cc_parent_map_1, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_pixel_clk_src", +- .parent_names = disp_cc_parent_names_1, +- .num_parents = 4, ++ .parent_data = disp_cc_parent_data_1, ++ .num_parents = ARRAY_SIZE(disp_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_dp_ops, + }, +@@ -232,8 +234,8 @@ static struct clk_rcg2 disp_cc_mdss_esc0_clk_src = { + .freq_tbl = ftbl_disp_cc_mdss_esc0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_esc0_clk_src", +- .parent_names = disp_cc_parent_names_0, +- .num_parents = 4, ++ .parent_data = disp_cc_parent_data_0, ++ .num_parents = ARRAY_SIZE(disp_cc_parent_data_0), + .ops = &clk_rcg2_ops, + }, + }; +@@ -246,8 +248,8 @@ static struct clk_rcg2 disp_cc_mdss_esc1_clk_src = { + .freq_tbl = ftbl_disp_cc_mdss_esc0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_esc1_clk_src", +- .parent_names = disp_cc_parent_names_0, +- .num_parents = 4, ++ .parent_data = disp_cc_parent_data_0, ++ .num_parents = ARRAY_SIZE(disp_cc_parent_data_0), + .ops = &clk_rcg2_ops, + }, + }; +@@ -273,8 +275,8 @@ static struct clk_rcg2 disp_cc_mdss_mdp_clk_src = { + .freq_tbl = ftbl_disp_cc_mdss_mdp_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_mdp_clk_src", +- .parent_names = disp_cc_parent_names_3, +- .num_parents = 5, ++ .parent_data = disp_cc_parent_data_3, ++ .num_parents = ARRAY_SIZE(disp_cc_parent_data_3), + .ops = &clk_rcg2_shared_ops, + }, + }; +@@ -287,8 +289,8 @@ static struct clk_rcg2 disp_cc_mdss_pclk0_clk_src = { + .parent_map = disp_cc_parent_map_4, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_pclk0_clk_src", +- .parent_names = disp_cc_parent_names_4, +- .num_parents = 4, ++ .parent_data = disp_cc_parent_data_4, ++ .num_parents = ARRAY_SIZE(disp_cc_parent_data_4), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_pixel_ops, + }, +@@ -302,8 +304,8 @@ static struct clk_rcg2 disp_cc_mdss_pclk1_clk_src = { + .parent_map = disp_cc_parent_map_4, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_pclk1_clk_src", +- .parent_names = disp_cc_parent_names_4, +- .num_parents = 4, ++ .parent_data = disp_cc_parent_data_4, ++ .num_parents = ARRAY_SIZE(disp_cc_parent_data_4), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_pixel_ops, + }, +@@ -326,8 +328,8 @@ static struct clk_rcg2 disp_cc_mdss_rot_clk_src = { + .freq_tbl = ftbl_disp_cc_mdss_rot_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_rot_clk_src", +- .parent_names = disp_cc_parent_names_3, +- .num_parents = 5, ++ .parent_data = disp_cc_parent_data_3, ++ .num_parents = ARRAY_SIZE(disp_cc_parent_data_3), + .ops = &clk_rcg2_shared_ops, + }, + }; +@@ -340,8 +342,8 @@ static struct clk_rcg2 disp_cc_mdss_vsync_clk_src = { + .freq_tbl = ftbl_disp_cc_mdss_esc0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_vsync_clk_src", +- .parent_names = disp_cc_parent_names_2, +- .num_parents = 2, ++ .parent_data = disp_cc_parent_data_2, ++ .num_parents = ARRAY_SIZE(disp_cc_parent_data_2), + .ops = &clk_rcg2_ops, + }, + }; +@@ -381,8 +383,8 @@ static struct clk_branch disp_cc_mdss_byte0_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_byte0_clk", +- .parent_names = (const char *[]){ +- "disp_cc_mdss_byte0_clk_src", ++ .parent_hws = (const struct clk_hw*[]){ ++ &disp_cc_mdss_byte0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, +@@ -399,8 +401,8 @@ static struct clk_regmap_div disp_cc_mdss_byte0_div_clk_src = { + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_byte0_div_clk_src", +- .parent_names = (const char *[]){ +- "disp_cc_mdss_byte0_clk_src", ++ .parent_hws = (const struct clk_hw*[]){ ++ &disp_cc_mdss_byte0_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_regmap_div_ops, +@@ -417,8 +419,8 @@ static struct clk_branch disp_cc_mdss_byte0_intf_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_byte0_intf_clk", +- .parent_names = (const char *[]){ +- "disp_cc_mdss_byte0_div_clk_src", ++ .parent_hws = (const struct clk_hw*[]){ ++ &disp_cc_mdss_byte0_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, +@@ -436,8 +438,8 @@ static struct clk_branch disp_cc_mdss_byte1_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_byte1_clk", +- .parent_names = (const char *[]){ +- "disp_cc_mdss_byte1_clk_src", ++ .parent_hws = (const struct clk_hw*[]){ ++ &disp_cc_mdss_byte1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, +@@ -454,8 +456,8 @@ static struct clk_regmap_div disp_cc_mdss_byte1_div_clk_src = { + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_byte1_div_clk_src", +- .parent_names = (const char *[]){ +- "disp_cc_mdss_byte1_clk_src", ++ .parent_hws = (const struct clk_hw*[]){ ++ &disp_cc_mdss_byte1_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_regmap_div_ops, +@@ -472,8 +474,8 @@ static struct clk_branch disp_cc_mdss_byte1_intf_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_byte1_intf_clk", +- .parent_names = (const char *[]){ +- "disp_cc_mdss_byte1_div_clk_src", ++ .parent_hws = (const struct clk_hw*[]){ ++ &disp_cc_mdss_byte1_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, +@@ -490,8 +492,8 @@ static struct clk_branch disp_cc_mdss_dp_aux_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_aux_clk", +- .parent_names = (const char *[]){ +- "disp_cc_mdss_dp_aux_clk_src", ++ .parent_hws = (const struct clk_hw*[]){ ++ &disp_cc_mdss_dp_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, +@@ -508,8 +510,8 @@ static struct clk_branch disp_cc_mdss_dp_crypto_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_crypto_clk", +- .parent_names = (const char *[]){ +- "disp_cc_mdss_dp_crypto_clk_src", ++ .parent_hws = (const struct clk_hw*[]){ ++ &disp_cc_mdss_dp_crypto_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, +@@ -526,8 +528,8 @@ static struct clk_branch disp_cc_mdss_dp_link_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_link_clk", +- .parent_names = (const char *[]){ +- "disp_cc_mdss_dp_link_clk_src", ++ .parent_hws = (const struct clk_hw*[]){ ++ &disp_cc_mdss_dp_link_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, +@@ -545,8 +547,8 @@ static struct clk_branch disp_cc_mdss_dp_link_intf_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_link_intf_clk", +- .parent_names = (const char *[]){ +- "disp_cc_mdss_dp_link_clk_src", ++ .parent_hws = (const struct clk_hw*[]){ ++ &disp_cc_mdss_dp_link_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, +@@ -562,8 +564,8 @@ static struct clk_branch disp_cc_mdss_dp_pixel1_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_pixel1_clk", +- .parent_names = (const char *[]){ +- "disp_cc_mdss_dp_pixel1_clk_src", ++ .parent_hws = (const struct clk_hw*[]){ ++ &disp_cc_mdss_dp_pixel1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, +@@ -580,8 +582,8 @@ static struct clk_branch disp_cc_mdss_dp_pixel_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_pixel_clk", +- .parent_names = (const char *[]){ +- "disp_cc_mdss_dp_pixel_clk_src", ++ .parent_hws = (const struct clk_hw*[]){ ++ &disp_cc_mdss_dp_pixel_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, +@@ -598,8 +600,8 @@ static struct clk_branch disp_cc_mdss_esc0_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_esc0_clk", +- .parent_names = (const char *[]){ +- "disp_cc_mdss_esc0_clk_src", ++ .parent_hws = (const struct clk_hw*[]){ ++ &disp_cc_mdss_esc0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, +@@ -616,8 +618,8 @@ static struct clk_branch disp_cc_mdss_esc1_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_esc1_clk", +- .parent_names = (const char *[]){ +- "disp_cc_mdss_esc1_clk_src", ++ .parent_hws = (const struct clk_hw*[]){ ++ &disp_cc_mdss_esc1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, +@@ -634,8 +636,8 @@ static struct clk_branch disp_cc_mdss_mdp_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_mdp_clk", +- .parent_names = (const char *[]){ +- "disp_cc_mdss_mdp_clk_src", ++ .parent_hws = (const struct clk_hw*[]){ ++ &disp_cc_mdss_mdp_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, +@@ -652,8 +654,8 @@ static struct clk_branch disp_cc_mdss_mdp_lut_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_mdp_lut_clk", +- .parent_names = (const char *[]){ +- "disp_cc_mdss_mdp_clk_src", ++ .parent_hws = (const struct clk_hw*[]){ ++ &disp_cc_mdss_mdp_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, +@@ -670,8 +672,8 @@ static struct clk_branch disp_cc_mdss_pclk0_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_pclk0_clk", +- .parent_names = (const char *[]){ +- "disp_cc_mdss_pclk0_clk_src", ++ .parent_hws = (const struct clk_hw*[]){ ++ &disp_cc_mdss_pclk0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, +@@ -689,8 +691,8 @@ static struct clk_branch disp_cc_mdss_pclk1_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_pclk1_clk", +- .parent_names = (const char *[]){ +- "disp_cc_mdss_pclk1_clk_src", ++ .parent_hws = (const struct clk_hw*[]){ ++ &disp_cc_mdss_pclk1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, +@@ -707,8 +709,8 @@ static struct clk_branch disp_cc_mdss_rot_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_rot_clk", +- .parent_names = (const char *[]){ +- "disp_cc_mdss_rot_clk_src", ++ .parent_hws = (const struct clk_hw*[]){ ++ &disp_cc_mdss_rot_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, +@@ -738,8 +740,8 @@ static struct clk_branch disp_cc_mdss_rscc_vsync_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_rscc_vsync_clk", +- .parent_names = (const char *[]){ +- "disp_cc_mdss_vsync_clk_src", ++ .parent_hws = (const struct clk_hw*[]){ ++ &disp_cc_mdss_vsync_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, +@@ -756,8 +758,8 @@ static struct clk_branch disp_cc_mdss_vsync_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_vsync_clk", +- .parent_names = (const char *[]){ +- "disp_cc_mdss_vsync_clk_src", ++ .parent_hws = (const struct clk_hw*[]){ ++ &disp_cc_mdss_vsync_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, +-- +2.51.0 + diff --git a/queue-5.10/clk-qcom-dispcc-sdm845-enable-parents-for-pixel-cloc.patch b/queue-5.10/clk-qcom-dispcc-sdm845-enable-parents-for-pixel-cloc.patch new file mode 100644 index 0000000000..cf78ffb4ff --- /dev/null +++ b/queue-5.10/clk-qcom-dispcc-sdm845-enable-parents-for-pixel-cloc.patch @@ -0,0 +1,49 @@ +From 480e2795b16effedfd421c03cc7433d2904a12fc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 12:44:43 +0100 +Subject: clk: qcom: dispcc-sdm845: Enable parents for pixel clocks + +From: Petr Hodina + +[ Upstream commit a1d63493634e98360140027fef49d82b1ff0a267 ] + +Add CLK_OPS_PARENT_ENABLE to MDSS pixel clock sources to ensure parent +clocks are enabled during clock operations, preventing potential +stability issues during display configuration. + +Fixes: 81351776c9fb ("clk: qcom: Add display clock controller driver for SDM845") +Signed-off-by: Petr Hodina +Reviewed-by: Dmitry Baryshkov +Reviewed-by: David Heidelberg +Link: https://lore.kernel.org/r/20260107-stability-discussion-v2-1-ef7717b435ff@protonmail.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sdm845.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/dispcc-sdm845.c b/drivers/clk/qcom/dispcc-sdm845.c +index a71e103553bbb..8263723099019 100644 +--- a/drivers/clk/qcom/dispcc-sdm845.c ++++ b/drivers/clk/qcom/dispcc-sdm845.c +@@ -291,7 +291,7 @@ static struct clk_rcg2 disp_cc_mdss_pclk0_clk_src = { + .name = "disp_cc_mdss_pclk0_clk_src", + .parent_data = disp_cc_parent_data_4, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_4), +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .ops = &clk_pixel_ops, + }, + }; +@@ -306,7 +306,7 @@ static struct clk_rcg2 disp_cc_mdss_pclk1_clk_src = { + .name = "disp_cc_mdss_pclk1_clk_src", + .parent_data = disp_cc_parent_data_4, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_4), +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .ops = &clk_pixel_ops, + }, + }; +-- +2.51.0 + diff --git a/queue-5.10/clk-qcom-return-correct-error-code-in-qcom_cc_probe_.patch b/queue-5.10/clk-qcom-return-correct-error-code-in-qcom_cc_probe_.patch new file mode 100644 index 0000000000..9050d1e2f2 --- /dev/null +++ b/queue-5.10/clk-qcom-return-correct-error-code-in-qcom_cc_probe_.patch @@ -0,0 +1,42 @@ +From 56191d01e1880f3c1b33d137e89a30ee7831e0e5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 17 Dec 2025 12:13:38 +0800 +Subject: clk: qcom: Return correct error code in qcom_cc_probe_by_index() + +From: Haotian Zhang + +[ Upstream commit 1e07ebe744fb522983bd52a4a6148601675330c7 ] + +When devm_platform_ioremap_resource() fails, it returns various +error codes. Returning a hardcoded -ENOMEM masks the actual +failure reason. + +Use PTR_ERR() to propagate the actual error code returned by +devm_platform_ioremap_resource() instead of -ENOMEM. + +Fixes: 75e0a1e30191 ("clk: qcom: define probe by index API as common API") +Signed-off-by: Haotian Zhang +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251217041338.2432-1-vulab@iscas.ac.cn +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/common.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c +index 2af04fc4abfa9..8aef7749f167d 100644 +--- a/drivers/clk/qcom/common.c ++++ b/drivers/clk/qcom/common.c +@@ -331,7 +331,7 @@ int qcom_cc_probe_by_index(struct platform_device *pdev, int index, + res = platform_get_resource(pdev, IORESOURCE_MEM, index); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) +- return -ENOMEM; ++ return PTR_ERR(base); + + regmap = devm_regmap_init_mmio(&pdev->dev, base, desc->config); + if (IS_ERR(regmap)) +-- +2.51.0 + diff --git a/queue-5.10/coresight-etm3x-fix-cpulocked-warning-on-cpuhp.patch b/queue-5.10/coresight-etm3x-fix-cpulocked-warning-on-cpuhp.patch new file mode 100644 index 0000000000..bec5c17a43 --- /dev/null +++ b/queue-5.10/coresight-etm3x-fix-cpulocked-warning-on-cpuhp.patch @@ -0,0 +1,67 @@ +From 6d20c043b3f8c4ac7fe139b2b6302c1c7daa478d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:24:27 +0100 +Subject: coresight: etm3x: Fix cpulocked warning on cpuhp + +From: Antonio Borneo + +[ Upstream commit 1feb0377b9b816f89a04fc381eb19fc6bac9f4a4 ] + +When changes [1] and [2] have been applied to the driver etm4x, the +same modifications have been also collapsed in [3] and applied in +one shot to the driver etm3x. +While doing this, the driver etm3x has not been aligned to etm4x on +the use of non cpuslocked version of cpuhp callback setup APIs. + +The current code triggers two run-time warnings when the kernel is +compiled with CONFIG_PROVE_LOCKING=y. + +Use non cpuslocked version of cpuhp callback setup APIs in driver +etm3x, aligning it to the driver etm4x. + +[1] commit 2d1a8bfb61ec ("coresight: etm4x: Fix etm4_count race by + moving cpuhp callbacks to init") +[2] commit 22a550a306ad ("coresight: etm4x: Allow etm4x to be built + as a module") +[3] commit 97fe626ce64c ("coresight: etm3x: Allow etm3x to be built + as a module") + +Fixes: 97fe626ce64c ("coresight: etm3x: Allow etm3x to be built as a module") +Signed-off-by: Antonio Borneo +Signed-off-by: Suzuki K Poulose +Link: https://lore.kernel.org/r/20260108152427.357379-1-antonio.borneo@foss.st.com +Signed-off-by: Sasha Levin +--- + drivers/hwtracing/coresight/coresight-etm3x-core.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c +index 683a69e88efda..721b2129bf1e9 100644 +--- a/drivers/hwtracing/coresight/coresight-etm3x-core.c ++++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c +@@ -784,16 +784,16 @@ static int __init etm_hp_setup(void) + { + int ret; + +- ret = cpuhp_setup_state_nocalls_cpuslocked(CPUHP_AP_ARM_CORESIGHT_STARTING, +- "arm/coresight:starting", +- etm_starting_cpu, etm_dying_cpu); ++ ret = cpuhp_setup_state_nocalls(CPUHP_AP_ARM_CORESIGHT_STARTING, ++ "arm/coresight:starting", ++ etm_starting_cpu, etm_dying_cpu); + + if (ret) + return ret; + +- ret = cpuhp_setup_state_nocalls_cpuslocked(CPUHP_AP_ONLINE_DYN, +- "arm/coresight:online", +- etm_online_cpu, NULL); ++ ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, ++ "arm/coresight:online", ++ etm_online_cpu, NULL); + + /* HP dyn state ID returned in ret on success */ + if (ret > 0) { +-- +2.51.0 + diff --git a/queue-5.10/cpufreq-scmi-correct-scmi-explanation.patch b/queue-5.10/cpufreq-scmi-correct-scmi-explanation.patch new file mode 100644 index 0000000000..5950eaecc8 --- /dev/null +++ b/queue-5.10/cpufreq-scmi-correct-scmi-explanation.patch @@ -0,0 +1,37 @@ +From 2dce6616600a5525a3eb1196aa6bbe2ef0d7d83b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Jan 2026 22:33:30 +0300 +Subject: cpufreq: scmi: correct SCMI explanation + +From: Sergey Shtylyov + +[ Upstream commit 8c376f337a7e31c42949247e24eaad9a30d6c62c ] + +SCMI stands for System Control and Management Interface, not System Control +and Power Interface -- apparently, Sudeep Holla copied this line from his +SCPI driver and then just forgot to update the acronym explanation... :-) + +Fixes: 99d6bdf33877 ("cpufreq: add support for CPU DVFS based on SCMI message protocol") +Signed-off-by: Sergey Shtylyov +Reviewed-by: Sudeep Holla +Signed-off-by: Viresh Kumar +Signed-off-by: Sasha Levin +--- + drivers/cpufreq/scmi-cpufreq.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c +index 6b65d537c95c2..a6d36ebdf44c5 100644 +--- a/drivers/cpufreq/scmi-cpufreq.c ++++ b/drivers/cpufreq/scmi-cpufreq.c +@@ -1,6 +1,6 @@ + // SPDX-License-Identifier: GPL-2.0 + /* +- * System Control and Power Interface (SCMI) based CPUFreq Interface driver ++ * System Control and Management Interface (SCMI) based CPUFreq Interface driver + * + * Copyright (C) 2018 ARM Ltd. + * Sudeep Holla +-- +2.51.0 + diff --git a/queue-5.10/crypto-cavium-fix-dma_free_coherent-size.patch b/queue-5.10/crypto-cavium-fix-dma_free_coherent-size.patch new file mode 100644 index 0000000000..dc1f19af76 --- /dev/null +++ b/queue-5.10/crypto-cavium-fix-dma_free_coherent-size.patch @@ -0,0 +1,38 @@ +From b6f3314478884aad63b158a9a319c3538acdc528 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 10:56:45 +0100 +Subject: crypto: cavium - fix dma_free_coherent() size + +From: Thomas Fourier + +[ Upstream commit 941676c30ba5b40a01bed92448f457ce62fd1f07 ] + +The size of the buffer in alloc_command_queues() is +curr->size + CPT_NEXT_CHUNK_PTR_SIZE, so used that length for +dma_free_coherent(). + +Fixes: c694b233295b ("crypto: cavium - Add the Virtual Function driver for CPT") +Signed-off-by: Thomas Fourier +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/cavium/cpt/cptvf_main.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/crypto/cavium/cpt/cptvf_main.c b/drivers/crypto/cavium/cpt/cptvf_main.c +index a15245992cf99..cbd0c111057fd 100644 +--- a/drivers/crypto/cavium/cpt/cptvf_main.c ++++ b/drivers/crypto/cavium/cpt/cptvf_main.c +@@ -183,7 +183,8 @@ static void free_command_queues(struct cpt_vf *cptvf, + + hlist_for_each_entry_safe(chunk, node, &cqinfo->queue[i].chead, + nextchunk) { +- dma_free_coherent(&pdev->dev, chunk->size, ++ dma_free_coherent(&pdev->dev, ++ chunk->size + CPT_NEXT_CHUNK_PTR_SIZE, + chunk->head, + chunk->dma_addr); + chunk->head = NULL; +-- +2.51.0 + diff --git a/queue-5.10/crypto-ccp-add-an-s4-restore-flow.patch b/queue-5.10/crypto-ccp-add-an-s4-restore-flow.patch new file mode 100644 index 0000000000..15b513658d --- /dev/null +++ b/queue-5.10/crypto-ccp-add-an-s4-restore-flow.patch @@ -0,0 +1,168 @@ +From 7d1e8ec0366e942e503bae4f6b1cc4200808641b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 22:11:30 -0600 +Subject: crypto: ccp - Add an S4 restore flow +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Mario Limonciello (AMD) + +[ Upstream commit 0ba2035026d0ab6c7c7e65ad8b418dc73d5700d9 ] + +The system will have lost power during S4. The ring used for TEE +communications needs to be initialized before use. + +Fixes: f892a21f51162 ("crypto: ccp - use generic power management") +Reported-by: Lars Francke +Closes: https://lore.kernel.org/platform-driver-x86/CAD-Ua_gfJnQSo8ucS_7ZwzuhoBRJ14zXP7s8b-zX3ZcxcyWePw@mail.gmail.com/ +Tested-by: Yijun Shen +Signed-off-by: Mario Limonciello (AMD) +Reviewed-by: Shyam Sundar S K +Reviewed-by: Tom Lendacky +Link: https://patch.msgid.link/20260116041132.153674-4-superm1@kernel.org +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/crypto/ccp/psp-dev.c | 11 +++++++++++ + drivers/crypto/ccp/sp-dev.c | 12 ++++++++++++ + drivers/crypto/ccp/sp-dev.h | 3 +++ + drivers/crypto/ccp/sp-pci.c | 16 +++++++++++++++- + drivers/crypto/ccp/tee-dev.c | 5 +++++ + drivers/crypto/ccp/tee-dev.h | 1 + + 6 files changed, 47 insertions(+), 1 deletion(-) + +diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c +index 4bf9eaab4456f..61f5302e7cf1a 100644 +--- a/drivers/crypto/ccp/psp-dev.c ++++ b/drivers/crypto/ccp/psp-dev.c +@@ -251,6 +251,17 @@ struct psp_device *psp_get_master_device(void) + return sp ? sp->psp_data : NULL; + } + ++int psp_restore(struct sp_device *sp) ++{ ++ struct psp_device *psp = sp->psp_data; ++ int ret = 0; ++ ++ if (psp->tee_data) ++ ret = tee_restore(psp); ++ ++ return ret; ++} ++ + void psp_pci_init(void) + { + psp_master = psp_get_master_device(); +diff --git a/drivers/crypto/ccp/sp-dev.c b/drivers/crypto/ccp/sp-dev.c +index 6284a15e50472..26f8e0a7865f9 100644 +--- a/drivers/crypto/ccp/sp-dev.c ++++ b/drivers/crypto/ccp/sp-dev.c +@@ -237,6 +237,18 @@ int sp_resume(struct sp_device *sp) + return 0; + } + ++int sp_restore(struct sp_device *sp) ++{ ++ if (sp->psp_data) { ++ int ret = psp_restore(sp); ++ ++ if (ret) ++ return ret; ++ } ++ ++ return sp_resume(sp); ++} ++ + struct sp_device *sp_get_psp_master_device(void) + { + struct sp_device *i, *ret = NULL; +diff --git a/drivers/crypto/ccp/sp-dev.h b/drivers/crypto/ccp/sp-dev.h +index 0218d0670eeef..c8f6e53702f7f 100644 +--- a/drivers/crypto/ccp/sp-dev.h ++++ b/drivers/crypto/ccp/sp-dev.h +@@ -121,6 +121,7 @@ struct sp_device *sp_get_master(void); + + int sp_suspend(struct sp_device *sp); + int sp_resume(struct sp_device *sp); ++int sp_restore(struct sp_device *sp); + int sp_request_ccp_irq(struct sp_device *sp, irq_handler_t handler, + const char *name, void *data); + void sp_free_ccp_irq(struct sp_device *sp, void *data); +@@ -161,6 +162,7 @@ int psp_dev_init(struct sp_device *sp); + void psp_pci_init(void); + void psp_dev_destroy(struct sp_device *sp); + void psp_pci_exit(void); ++int psp_restore(struct sp_device *sp); + + #else /* !CONFIG_CRYPTO_DEV_SP_PSP */ + +@@ -168,6 +170,7 @@ static inline int psp_dev_init(struct sp_device *sp) { return 0; } + static inline void psp_pci_init(void) { } + static inline void psp_dev_destroy(struct sp_device *sp) { } + static inline void psp_pci_exit(void) { } ++static inline int psp_restore(struct sp_device *sp) { return 0; } + + #endif /* CONFIG_CRYPTO_DEV_SP_PSP */ + +diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c +index 8efcdd6a2eab9..16dd40e266a82 100644 +--- a/drivers/crypto/ccp/sp-pci.c ++++ b/drivers/crypto/ccp/sp-pci.c +@@ -282,6 +282,13 @@ static int __maybe_unused sp_pci_resume(struct device *dev) + return sp_resume(sp); + } + ++static int __maybe_unused sp_pci_restore(struct device *dev) ++{ ++ struct sp_device *sp = dev_get_drvdata(dev); ++ ++ return sp_restore(sp); ++} ++ + #ifdef CONFIG_CRYPTO_DEV_SP_PSP + static const struct sev_vdata sevv1 = { + .cmdresp_reg = 0x10580, +@@ -377,7 +384,14 @@ static const struct pci_device_id sp_pci_table[] = { + }; + MODULE_DEVICE_TABLE(pci, sp_pci_table); + +-static SIMPLE_DEV_PM_OPS(sp_pci_pm_ops, sp_pci_suspend, sp_pci_resume); ++static const struct dev_pm_ops sp_pci_pm_ops = { ++ .suspend = pm_sleep_ptr(sp_pci_suspend), ++ .resume = pm_sleep_ptr(sp_pci_resume), ++ .freeze = pm_sleep_ptr(sp_pci_suspend), ++ .thaw = pm_sleep_ptr(sp_pci_resume), ++ .poweroff = pm_sleep_ptr(sp_pci_suspend), ++ .restore_early = pm_sleep_ptr(sp_pci_restore), ++}; + + static struct pci_driver sp_pci_driver = { + .name = "ccp", +diff --git a/drivers/crypto/ccp/tee-dev.c b/drivers/crypto/ccp/tee-dev.c +index bcb81fef42118..ff49ecbcf003e 100644 +--- a/drivers/crypto/ccp/tee-dev.c ++++ b/drivers/crypto/ccp/tee-dev.c +@@ -394,3 +394,8 @@ int psp_check_tee_status(void) + return 0; + } + EXPORT_SYMBOL(psp_check_tee_status); ++ ++int tee_restore(struct psp_device *psp) ++{ ++ return tee_init_ring(psp->tee_data); ++} +diff --git a/drivers/crypto/ccp/tee-dev.h b/drivers/crypto/ccp/tee-dev.h +index 49d26158b71e3..b0bf1de94ea6f 100644 +--- a/drivers/crypto/ccp/tee-dev.h ++++ b/drivers/crypto/ccp/tee-dev.h +@@ -122,5 +122,6 @@ struct tee_ring_cmd { + + int tee_dev_init(struct psp_device *psp); + void tee_dev_destroy(struct psp_device *psp); ++int tee_restore(struct psp_device *psp); + + #endif /* __TEE_DEV_H__ */ +-- +2.51.0 + diff --git a/queue-5.10/crypto-octeontx-fix-dma_free_coherent-size.patch b/queue-5.10/crypto-octeontx-fix-dma_free_coherent-size.patch new file mode 100644 index 0000000000..64db0b1221 --- /dev/null +++ b/queue-5.10/crypto-octeontx-fix-dma_free_coherent-size.patch @@ -0,0 +1,38 @@ +From aab0e82c0dd3a2b5b0e3ed6e1c1e22e82e81c0e0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 11:12:57 +0100 +Subject: crypto: octeontx - fix dma_free_coherent() size + +From: Thomas Fourier + +[ Upstream commit 624a6760bf8464965c17c8df10b40b557eaa3002 ] + +The size of the buffer in alloc_command_queues() is +curr->size + OTX_CPT_NEXT_CHUNK_PTR_SIZE, so used that length for +dma_free_coherent(). + +Fixes: 10b4f09491bf ("crypto: marvell - add the Virtual Function driver for CPT") +Signed-off-by: Thomas Fourier +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/marvell/octeontx/otx_cptvf_main.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/crypto/marvell/octeontx/otx_cptvf_main.c b/drivers/crypto/marvell/octeontx/otx_cptvf_main.c +index 228fe8e47e0ed..ba9fa4defdba3 100644 +--- a/drivers/crypto/marvell/octeontx/otx_cptvf_main.c ++++ b/drivers/crypto/marvell/octeontx/otx_cptvf_main.c +@@ -170,7 +170,8 @@ static void free_command_queues(struct otx_cptvf *cptvf, + chunk = list_first_entry(&cqinfo->queue[i].chead, + struct otx_cpt_cmd_chunk, nextchunk); + +- dma_free_coherent(&pdev->dev, chunk->size, ++ dma_free_coherent(&pdev->dev, ++ chunk->size + OTX_CPT_NEXT_CHUNK_PTR_SIZE, + chunk->head, + chunk->dma_addr); + chunk->head = NULL; +-- +2.51.0 + diff --git a/queue-5.10/dma-dma-axi-dmac-fix-sw-cyclic-transfers.patch b/queue-5.10/dma-dma-axi-dmac-fix-sw-cyclic-transfers.patch new file mode 100644 index 0000000000..cfd751d0af --- /dev/null +++ b/queue-5.10/dma-dma-axi-dmac-fix-sw-cyclic-transfers.patch @@ -0,0 +1,57 @@ +From 5b160d4f56641ca9108662d55c91df1c4043bcaa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Nov 2025 16:22:25 +0000 +Subject: dma: dma-axi-dmac: fix SW cyclic transfers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Nuno Sá + +[ Upstream commit 9bd257181fd5c996d922e9991500ad27987cfbf4 ] + +If 'hw_cyclic' is false we should still be able to do cyclic transfers in +"software". That was not working for the case where 'desc->num_sgs' is 1 +because 'chan->next_desc' is never set with the current desc which means +that the cyclic transfer only runs once and in the next SOT interrupt we +do nothing since vchan_next_desc() will return NULL. + +Fix it by setting 'chan->next_desc' as soon as we get a new desc via +vchan_next_desc(). + +Fixes: 0e3b67b348b8 ("dmaengine: Add support for the Analog Devices AXI-DMAC DMA controller") +Signed-off-by: Nuno Sá +base-commit: 398035178503bf662281bbffb4bebce1460a4bc5 +change-id: 20251104-axi-dmac-fixes-and-improvs-e3ad512a329c +Acked-by: Michael Hennerich +Link: https://patch.msgid.link/20251104-axi-dmac-fixes-and-improvs-v1-1-3e6fd9328f72@analog.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/dma/dma-axi-dmac.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c +index e91aeec71c811..6194ef0ac17f6 100644 +--- a/drivers/dma/dma-axi-dmac.c ++++ b/drivers/dma/dma-axi-dmac.c +@@ -221,6 +221,7 @@ static void axi_dmac_start_transfer(struct axi_dmac_chan *chan) + return; + list_move_tail(&vdesc->node, &chan->active_descs); + desc = to_axi_dmac_desc(vdesc); ++ chan->next_desc = desc; + } + sg = &desc->sg[desc->num_submitted]; + +@@ -238,8 +239,6 @@ static void axi_dmac_start_transfer(struct axi_dmac_chan *chan) + else + chan->next_desc = NULL; + flags |= AXI_DMAC_FLAG_LAST; +- } else { +- chan->next_desc = desc; + } + + sg->id = axi_dmac_read(dmac, AXI_DMAC_REG_TRANSFER_ID); +-- +2.51.0 + diff --git a/queue-5.10/dmaengine-mediatek-uart-apdma-fix-above-4g-addressin.patch b/queue-5.10/dmaengine-mediatek-uart-apdma-fix-above-4g-addressin.patch new file mode 100644 index 0000000000..5d649f4ab6 --- /dev/null +++ b/queue-5.10/dmaengine-mediatek-uart-apdma-fix-above-4g-addressin.patch @@ -0,0 +1,83 @@ +From b27fc8635722ef41bb8745429f48ab7daf49cafe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 13 Nov 2025 13:22:26 +0100 +Subject: dmaengine: mediatek: uart-apdma: Fix above 4G addressing TX/RX + +From: AngeloGioacchino Del Regno + +[ Upstream commit 58ab9d7b6651d21e1cff1777529f2d3dd0b4e851 ] + +The VFF_4G_SUPPORT register is named differently in datasheets, +and its name is "VFF_ADDR2"; was this named correctly from the +beginning it would've been clearer that there was a mistake in +the programming sequence. + +This register is supposed to hold the high bits to support the +DMA addressing above 4G (so, more than 32 bits) and not a bit +to "enable" the support for VFF 4G. + +Fix the name of this register, and also fix its usage by writing +the upper 32 bits of the dma_addr_t on it when the SoC supports +such feature. + +Fixes: 9135408c3ace ("dmaengine: mediatek: Add MediaTek UART APDMA support") +Signed-off-by: AngeloGioacchino Del Regno +Link: https://patch.msgid.link/20251113122229.23998-6-angelogioacchino.delregno@collabora.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/dma/mediatek/mtk-uart-apdma.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/dma/mediatek/mtk-uart-apdma.c b/drivers/dma/mediatek/mtk-uart-apdma.c +index 0acf6a92a4ad3..c1e132a110ffb 100644 +--- a/drivers/dma/mediatek/mtk-uart-apdma.c ++++ b/drivers/dma/mediatek/mtk-uart-apdma.c +@@ -42,7 +42,7 @@ + #define VFF_STOP_CLR_B 0 + #define VFF_EN_CLR_B 0 + #define VFF_INT_EN_CLR_B 0 +-#define VFF_4G_SUPPORT_CLR_B 0 ++#define VFF_ADDR2_CLR_B 0 + + /* + * interrupt trigger level for tx +@@ -73,7 +73,7 @@ + /* TX: the buffer size SW can write. RX: the buffer size HW can write. */ + #define VFF_LEFT_SIZE 0x40 + #define VFF_DEBUG_STATUS 0x50 +-#define VFF_4G_SUPPORT 0x54 ++#define VFF_ADDR2 0x54 + + struct mtk_uart_apdmadev { + struct dma_device ddev; +@@ -150,7 +150,7 @@ static void mtk_uart_apdma_start_tx(struct mtk_chan *c) + mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_TX_INT_CLR_B); + + if (mtkd->support_33bits) +- mtk_uart_apdma_write(c, VFF_4G_SUPPORT, VFF_4G_EN_B); ++ mtk_uart_apdma_write(c, VFF_ADDR2, upper_32_bits(d->addr)); + } + + mtk_uart_apdma_write(c, VFF_EN, VFF_EN_B); +@@ -193,7 +193,7 @@ static void mtk_uart_apdma_start_rx(struct mtk_chan *c) + mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_RX_INT_CLR_B); + + if (mtkd->support_33bits) +- mtk_uart_apdma_write(c, VFF_4G_SUPPORT, VFF_4G_EN_B); ++ mtk_uart_apdma_write(c, VFF_ADDR2, upper_32_bits(d->addr)); + } + + mtk_uart_apdma_write(c, VFF_INT_EN, VFF_RX_INT_EN_B); +@@ -299,7 +299,7 @@ static int mtk_uart_apdma_alloc_chan_resources(struct dma_chan *chan) + } + + if (mtkd->support_33bits) +- mtk_uart_apdma_write(c, VFF_4G_SUPPORT, VFF_4G_SUPPORT_CLR_B); ++ mtk_uart_apdma_write(c, VFF_ADDR2, VFF_ADDR2_CLR_B); + + err_pm: + pm_runtime_put_noidle(mtkd->ddev.dev); +-- +2.51.0 + diff --git a/queue-5.10/drivers-iio-mpu3050-use-dev_err_probe-for-regulator-.patch b/queue-5.10/drivers-iio-mpu3050-use-dev_err_probe-for-regulator-.patch new file mode 100644 index 0000000000..a959ddb499 --- /dev/null +++ b/queue-5.10/drivers-iio-mpu3050-use-dev_err_probe-for-regulator-.patch @@ -0,0 +1,42 @@ +From 1da395e58d68abae74da5bc6981c33e519f62716 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 17:34:25 +0200 +Subject: drivers: iio: mpu3050: use dev_err_probe for regulator request + +From: Svyatoslav Ryhel + +[ Upstream commit b010880b9936da14f8035585ab57577aa05be23a ] + +Regulator requesting may result in deferred probing error which will +abort driver probing. To avoid this just use dev_err_probe which handles +deferred probing. + +Fixes: 3904b28efb2c ("iio: gyro: Add driver for the MPU-3050 gyroscope") +Signed-off-by: Svyatoslav Ryhel +Reviewed-by: Andy Shevchenko +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/gyro/mpu3050-core.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/iio/gyro/mpu3050-core.c b/drivers/iio/gyro/mpu3050-core.c +index 84c6ad4bcccba..7803173c50639 100644 +--- a/drivers/iio/gyro/mpu3050-core.c ++++ b/drivers/iio/gyro/mpu3050-core.c +@@ -1170,10 +1170,8 @@ int mpu3050_common_probe(struct device *dev, + mpu3050->regs[1].supply = mpu3050_reg_vlogic; + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(mpu3050->regs), + mpu3050->regs); +- if (ret) { +- dev_err(dev, "Cannot get regulators\n"); +- return ret; +- } ++ if (ret) ++ return dev_err_probe(dev, ret, "Cannot get regulators\n"); + + ret = mpu3050_power_up(mpu3050); + if (ret) +-- +2.51.0 + diff --git a/queue-5.10/drm-amdgpu-use-explicit-vcn-instance-0-in-sr-iov-ini.patch b/queue-5.10/drm-amdgpu-use-explicit-vcn-instance-0-in-sr-iov-ini.patch new file mode 100644 index 0000000000..39dcf2d21e --- /dev/null +++ b/queue-5.10/drm-amdgpu-use-explicit-vcn-instance-0-in-sr-iov-ini.patch @@ -0,0 +1,180 @@ +From 2b5b818e718a5f9312afec10dc478a0edaf0422c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 15:25:25 +0530 +Subject: drm/amdgpu: Use explicit VCN instance 0 in SR-IOV init +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Srinivasan Shanmugam + +[ Upstream commit af26fa751c2eef66916acbf0d3c3e9159da56186 ] + +vcn_v2_0_start_sriov() declares a local variable "i" initialized to zero +and uses it only as the instance index in SOC15_REG_OFFSET(UVD, i, ...). +The value is never changed and all other fields are taken from +adev->vcn.inst[0], so this path only ever programs VCN instance 0. + +This triggered a Smatch: +warn: iterator 'i' not incremented + +Replace the dummy iterator with an explicit instance index of 0 in +SOC15_REG_OFFSET() calls. + +Fixes: dd26858a9cd8 ("drm/amdgpu: implement initialization part on VCN2.0 for SRIOV") +Reported by: Dan Carpenter +Cc: darlington Opara +Cc: Jinage Zhao +Cc: Monk Liu +Cc: Emily Deng +Cc: Christian König +Cc: Alex Deucher +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Emily Deng +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c | 45 ++++++++++++++------------- + 1 file changed, 23 insertions(+), 22 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c +index 79bcc78f77045..e2744f172610a 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c +@@ -1852,7 +1852,8 @@ static int vcn_v2_0_start_sriov(struct amdgpu_device *adev) + struct mmsch_v2_0_cmd_end end = { {0} }; + struct mmsch_v2_0_init_header *header; + uint32_t *init_table = adev->virt.mm_table.cpu_addr; +- uint8_t i = 0; ++ ++ /* This path only programs VCN instance 0. */ + + header = (struct mmsch_v2_0_init_header *)init_table; + direct_wt.cmd_header.command_type = MMSCH_COMMAND__DIRECT_REG_WRITE; +@@ -1871,94 +1872,94 @@ static int vcn_v2_0_start_sriov(struct amdgpu_device *adev) + size = AMDGPU_GPU_PAGE_ALIGN(adev->vcn.fw->size + 4); + + MMSCH_V2_0_INSERT_DIRECT_RD_MOD_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_STATUS), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_STATUS), + 0xFFFFFFFF, 0x00000004); + + /* mc resume*/ + if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { + tmp = AMDGPU_UCODE_ID_VCN; + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW), + adev->firmware.ucode[tmp].tmr_mc_addr_lo); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE_64BIT_BAR_HIGH), + adev->firmware.ucode[tmp].tmr_mc_addr_hi); + offset = 0; + } else { + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW), + lower_32_bits(adev->vcn.inst->gpu_addr)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE_64BIT_BAR_HIGH), + upper_32_bits(adev->vcn.inst->gpu_addr)); + offset = size; + } + + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_OFFSET0), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_OFFSET0), + 0); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_SIZE0), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_SIZE0), + size); + + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE1_64BIT_BAR_LOW), + lower_32_bits(adev->vcn.inst->gpu_addr + offset)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE1_64BIT_BAR_HIGH), + upper_32_bits(adev->vcn.inst->gpu_addr + offset)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_OFFSET1), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_OFFSET1), + 0); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_SIZE1), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_SIZE1), + AMDGPU_VCN_STACK_SIZE); + + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE2_64BIT_BAR_LOW), + lower_32_bits(adev->vcn.inst->gpu_addr + offset + + AMDGPU_VCN_STACK_SIZE)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE2_64BIT_BAR_HIGH), + upper_32_bits(adev->vcn.inst->gpu_addr + offset + + AMDGPU_VCN_STACK_SIZE)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_OFFSET2), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_OFFSET2), + 0); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_SIZE2), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_SIZE2), + AMDGPU_VCN_CONTEXT_SIZE); + + for (r = 0; r < adev->vcn.num_enc_rings; ++r) { + ring = &adev->vcn.inst->ring_enc[r]; + ring->wptr = 0; + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_RB_BASE_LO), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_RB_BASE_LO), + lower_32_bits(ring->gpu_addr)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_RB_BASE_HI), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_RB_BASE_HI), + upper_32_bits(ring->gpu_addr)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_RB_SIZE), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_RB_SIZE), + ring->ring_size / 4); + } + + ring = &adev->vcn.inst->ring_dec; + ring->wptr = 0; + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_RBC_RB_64BIT_BAR_LOW), + lower_32_bits(ring->gpu_addr)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH), + upper_32_bits(ring->gpu_addr)); + /* force RBC into idle state */ +@@ -1969,7 +1970,7 @@ static int vcn_v2_0_start_sriov(struct amdgpu_device *adev) + tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1); + tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_RBC_RB_CNTL), tmp); ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_RBC_RB_CNTL), tmp); + + /* add end packet */ + tmp = sizeof(struct mmsch_v2_0_cmd_end); +-- +2.51.0 + diff --git a/queue-5.10/edac-altera-remove-irqf_oneshot.patch b/queue-5.10/edac-altera-remove-irqf_oneshot.patch new file mode 100644 index 0000000000..4ab9c8c460 --- /dev/null +++ b/queue-5.10/edac-altera-remove-irqf_oneshot.patch @@ -0,0 +1,74 @@ +From 67c79f18d71a192c1238cc5986c8475269e85255 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:55:30 +0100 +Subject: EDAC/altera: Remove IRQF_ONESHOT + +From: Sebastian Andrzej Siewior + +[ Upstream commit 5c858d6c66304b4c7579582ec5235f02d43578ea ] + +Passing IRQF_ONESHOT ensures that the interrupt source is masked until +the secondary (threaded) handler is done. If only a primary handler is +used then the flag makes no sense because the interrupt can not fire +(again) while its handler is running. + +The flag also prevents force-threading of the primary handler and the +irq-core will warn about this. + +Remove IRQF_ONESHOT from irqflags. + +Fixes: a29d64a45eed1 ("EDAC, altera: Add IRQ Flags to disable IRQ while handling") +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260128095540.863589-11-bigeasy@linutronix.de +Signed-off-by: Sasha Levin +--- + drivers/edac/altera_edac.c | 11 ++++------- + 1 file changed, 4 insertions(+), 7 deletions(-) + +diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c +index 681ffb9db8438..63fea769b99ac 100644 +--- a/drivers/edac/altera_edac.c ++++ b/drivers/edac/altera_edac.c +@@ -1521,8 +1521,7 @@ static int altr_portb_setup(struct altr_edac_device_dev *device) + goto err_release_group_1; + } + rc = devm_request_irq(&altdev->ddev, altdev->sb_irq, +- prv->ecc_irq_handler, +- IRQF_ONESHOT | IRQF_TRIGGER_HIGH, ++ prv->ecc_irq_handler, IRQF_TRIGGER_HIGH, + ecc_name, altdev); + if (rc) { + edac_printk(KERN_ERR, EDAC_DEVICE, "PortB SBERR IRQ error\n"); +@@ -1545,8 +1544,7 @@ static int altr_portb_setup(struct altr_edac_device_dev *device) + goto err_release_group_1; + } + rc = devm_request_irq(&altdev->ddev, altdev->db_irq, +- prv->ecc_irq_handler, +- IRQF_ONESHOT | IRQF_TRIGGER_HIGH, ++ prv->ecc_irq_handler, IRQF_TRIGGER_HIGH, + ecc_name, altdev); + if (rc) { + edac_printk(KERN_ERR, EDAC_DEVICE, "PortB DBERR IRQ error\n"); +@@ -1932,8 +1930,7 @@ static int altr_edac_a10_device_add(struct altr_arria10_edac *edac, + goto err_release_group1; + } + rc = devm_request_irq(edac->dev, altdev->sb_irq, prv->ecc_irq_handler, +- IRQF_ONESHOT | IRQF_TRIGGER_HIGH, +- ecc_name, altdev); ++ IRQF_TRIGGER_HIGH, ecc_name, altdev); + if (rc) { + edac_printk(KERN_ERR, EDAC_DEVICE, "No SBERR IRQ resource\n"); + goto err_release_group1; +@@ -1955,7 +1952,7 @@ static int altr_edac_a10_device_add(struct altr_arria10_edac *edac, + goto err_release_group1; + } + rc = devm_request_irq(edac->dev, altdev->db_irq, prv->ecc_irq_handler, +- IRQF_ONESHOT | IRQF_TRIGGER_HIGH, ++ IRQF_TRIGGER_HIGH, + ecc_name, altdev); + if (rc) { + edac_printk(KERN_ERR, EDAC_DEVICE, "No DBERR IRQ resource\n"); +-- +2.51.0 + diff --git a/queue-5.10/edac-i5000-fix-snprintf-size-calculation-in-calculat.patch b/queue-5.10/edac-i5000-fix-snprintf-size-calculation-in-calculat.patch new file mode 100644 index 0000000000..60b67f9159 --- /dev/null +++ b/queue-5.10/edac-i5000-fix-snprintf-size-calculation-in-calculat.patch @@ -0,0 +1,40 @@ +From 0d3e1543fcae28f90b83a11a26f14cc833991856 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 17:36:59 +0300 +Subject: EDAC/i5000: Fix snprintf() size calculation in calculate_dimm_size() + +From: Dan Carpenter + +[ Upstream commit 7b5c7e83ac405ff9ecbdd92b37a477f4288f8814 ] + +The snprintf() can't really overflow because we're writing a max of 42 +bytes to a PAGE_SIZE buffer. But the limit calculation doesn't take +the first 11 bytes that we wrote into consideration so the limit is +not correct. Just fix it for correctness even though it doesn't +affect runtime. + +Fixes: 64e1fdaf55d6 ("i5000_edac: Fix the logic that retrieves memory information") +Signed-off-by: Dan Carpenter +Signed-off-by: Tony Luck +Reviewed-by: Qiuxu Zhuo +Link: https://patch.msgid.link/07cd652c51e77aad5a8350e1a7cd9407e5bbe373.1765290801.git.dan.carpenter@linaro.org +Signed-off-by: Sasha Levin +--- + drivers/edac/i5000_edac.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c +index 1a6f69c859ab9..bee3877b76e4c 100644 +--- a/drivers/edac/i5000_edac.c ++++ b/drivers/edac/i5000_edac.c +@@ -1111,6 +1111,7 @@ static void calculate_dimm_size(struct i5000_pvt *pvt) + + n = snprintf(p, space, " "); + p += n; ++ space -= n; + for (branch = 0; branch < MAX_BRANCHES; branch++) { + n = snprintf(p, space, " branch %d | ", branch); + p += n; +-- +2.51.0 + diff --git a/queue-5.10/edac-i5400-fix-snprintf-limit-calculation-in-calcula.patch b/queue-5.10/edac-i5400-fix-snprintf-limit-calculation-in-calcula.patch new file mode 100644 index 0000000000..c2028c4055 --- /dev/null +++ b/queue-5.10/edac-i5400-fix-snprintf-limit-calculation-in-calcula.patch @@ -0,0 +1,49 @@ +From 24f0c91371a48d2567fee414f084c1506b477c8a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 17:37:04 +0300 +Subject: EDAC/i5400: Fix snprintf() limit calculation in calculate_dimm_size() + +From: Dan Carpenter + +[ Upstream commit 72f12683611344853ab030fe7d19b23970ed2bd8 ] + +The snprintf() can't really overflow because we're writing a max of 42 +bytes to a PAGE_SIZE buffer. But my static checker complains because +the limit calculation doesn't take the first 11 space characters that +we wrote into the buffer into consideration. Fix this for the sake of +correctness even though it doesn't affect runtime. + +Also delete an earlier "space -= n;" which was not used. + +Fixes: 68d086f89b80 ("i5400_edac: improve debug messages to better represent the filled memory") +Signed-off-by: Dan Carpenter +Signed-off-by: Tony Luck +Reviewed-by: Qiuxu Zhuo +Link: https://patch.msgid.link/ccd06b91748e7ed8e33eeb2ff1e7b98700879304.1765290801.git.dan.carpenter@linaro.org +Signed-off-by: Sasha Levin +--- + drivers/edac/i5400_edac.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/edac/i5400_edac.c b/drivers/edac/i5400_edac.c +index 92d63eb533aee..9f11b15397c36 100644 +--- a/drivers/edac/i5400_edac.c ++++ b/drivers/edac/i5400_edac.c +@@ -1024,13 +1024,13 @@ static void calculate_dimm_size(struct i5400_pvt *pvt) + space -= n; + } + +- space -= n; + edac_dbg(2, "%s\n", mem_buffer); + p = mem_buffer; + space = PAGE_SIZE; + + n = snprintf(p, space, " "); + p += n; ++ space -= n; + for (branch = 0; branch < MAX_BRANCHES; branch++) { + n = snprintf(p, space, " branch %d | ", branch); + p += n; +-- +2.51.0 + diff --git a/queue-5.10/fat-avoid-parent-link-count-underflow-in-rmdir.patch b/queue-5.10/fat-avoid-parent-link-count-underflow-in-rmdir.patch new file mode 100644 index 0000000000..6931da5b21 --- /dev/null +++ b/queue-5.10/fat-avoid-parent-link-count-underflow-in-rmdir.patch @@ -0,0 +1,74 @@ +From 688812448c2b34bda0fa1349c0b849a822c97e7f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 1 Jan 2026 19:11:48 +0800 +Subject: fat: avoid parent link count underflow in rmdir + +From: Zhiyu Zhang + +[ Upstream commit 8cafcb881364af5ef3a8b9fed4db254054033d8a ] + +Corrupted FAT images can leave a directory inode with an incorrect +i_nlink (e.g. 2 even though subdirectories exist). rmdir then +unconditionally calls drop_nlink(dir) and can drive i_nlink to 0, +triggering the WARN_ON in drop_nlink(). + +Add a sanity check in vfat_rmdir() and msdos_rmdir(): only drop the +parent link count when it is at least 3, otherwise report a filesystem +error. + +Link: https://lkml.kernel.org/r/20260101111148.1437-1-zhiyuzhang999@gmail.com +Fixes: 9a53c3a783c2 ("[PATCH] r/o bind mounts: unlink: monitor i_nlink") +Signed-off-by: Zhiyu Zhang +Reported-by: Zhiyu Zhang +Closes: https://lore.kernel.org/linux-fsdevel/aVN06OKsKxZe6-Kv@casper.infradead.org/T/#t +Tested-by: Zhiyu Zhang +Acked-by: OGAWA Hirofumi +Cc: Al Viro +Cc: Christian Brauner +Cc: Jan Kara +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/fat/namei_msdos.c | 7 ++++++- + fs/fat/namei_vfat.c | 7 ++++++- + 2 files changed, 12 insertions(+), 2 deletions(-) + +diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c +index 9d062886fbc19..63a323be9179d 100644 +--- a/fs/fat/namei_msdos.c ++++ b/fs/fat/namei_msdos.c +@@ -325,7 +325,12 @@ static int msdos_rmdir(struct inode *dir, struct dentry *dentry) + err = fat_remove_entries(dir, &sinfo); /* and releases bh */ + if (err) + goto out; +- drop_nlink(dir); ++ if (dir->i_nlink >= 3) ++ drop_nlink(dir); ++ else { ++ fat_fs_error(sb, "parent dir link count too low (%u)", ++ dir->i_nlink); ++ } + + clear_nlink(inode); + fat_truncate_time(inode, NULL, S_CTIME); +diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c +index 9bc7d1602c15b..2a0d9a9c2c8f7 100644 +--- a/fs/fat/namei_vfat.c ++++ b/fs/fat/namei_vfat.c +@@ -808,7 +808,12 @@ static int vfat_rmdir(struct inode *dir, struct dentry *dentry) + err = fat_remove_entries(dir, &sinfo); /* and releases bh */ + if (err) + goto out; +- drop_nlink(dir); ++ if (dir->i_nlink >= 3) ++ drop_nlink(dir); ++ else { ++ fat_fs_error(sb, "parent dir link count too low (%u)", ++ dir->i_nlink); ++ } + + clear_nlink(inode); + fat_truncate_time(inode, NULL, S_ATIME|S_MTIME); +-- +2.51.0 + diff --git a/queue-5.10/fbdev-au1200fb-fix-a-memory-leak-in-au1200fb_drv_pro.patch b/queue-5.10/fbdev-au1200fb-fix-a-memory-leak-in-au1200fb_drv_pro.patch new file mode 100644 index 0000000000..d98858055a --- /dev/null +++ b/queue-5.10/fbdev-au1200fb-fix-a-memory-leak-in-au1200fb_drv_pro.patch @@ -0,0 +1,43 @@ +From e011c0b092e5add5280e8a0529d90080338ea382 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 20:14:58 +0800 +Subject: fbdev: au1200fb: Fix a memory leak in au1200fb_drv_probe() + +From: Felix Gu + +[ Upstream commit ce4e25198a6aaaaf36248edf8daf3d744ec8e309 ] + +In au1200fb_drv_probe(), when platform_get_irq fails(), it directly +returns from the function with an error code, which causes a memory +leak. + +Replace it with a goto label to ensure proper cleanup. + +Fixes: 4e88761f5f8c ("fbdev: au1200fb: Fix missing IRQ check in au1200fb_drv_probe") +Signed-off-by: Felix Gu +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/au1200fb.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/video/fbdev/au1200fb.c b/drivers/video/fbdev/au1200fb.c +index 80f54111baec1..ec1d86f253904 100644 +--- a/drivers/video/fbdev/au1200fb.c ++++ b/drivers/video/fbdev/au1200fb.c +@@ -1732,8 +1732,10 @@ static int au1200fb_drv_probe(struct platform_device *dev) + + /* Now hook interrupt too */ + irq = platform_get_irq(dev, 0); +- if (irq < 0) +- return irq; ++ if (irq < 0) { ++ ret = irq; ++ goto failed; ++ } + + ret = request_irq(irq, au1200fb_handle_irq, + IRQF_SHARED, "lcd", (void *)dev); +-- +2.51.0 + diff --git a/queue-5.10/fs-add-linux-init_task.h-for-init_fs.patch b/queue-5.10/fs-add-linux-init_task.h-for-init_fs.patch new file mode 100644 index 0000000000..b450fe99d4 --- /dev/null +++ b/queue-5.10/fs-add-linux-init_task.h-for-init_fs.patch @@ -0,0 +1,40 @@ +From a9d5414e2d3f381c61b354026e45fedce009de11 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 11:58:56 +0000 +Subject: fs: add for 'init_fs' + +From: Ben Dooks + +[ Upstream commit 589cff4975afe1a4eaaa1d961652f50b1628d78d ] + +The init_fs symbol is defined in but was +not included in fs/fs_struct.c so fix by adding the include. + +Fixes the following sparse warning: +fs/fs_struct.c:150:18: warning: symbol 'init_fs' was not declared. Should it be static? + +Fixes: 3e93cd671813e ("Take fs_struct handling to new file") +Signed-off-by: Ben Dooks +Link: https://patch.msgid.link/20260108115856.238027-1-ben.dooks@codethink.co.uk +Reviewed-by: Jan Kara +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/fs_struct.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/fs_struct.c b/fs/fs_struct.c +index 04b3f5b9c6295..0b0f88259cc60 100644 +--- a/fs/fs_struct.c ++++ b/fs/fs_struct.c +@@ -6,6 +6,7 @@ + #include + #include + #include ++#include + #include "internal.h" + + /* +-- +2.51.0 + diff --git a/queue-5.10/gfs2-add-metapath_dibh-helper.patch b/queue-5.10/gfs2-add-metapath_dibh-helper.patch new file mode 100644 index 0000000000..c64c01faee --- /dev/null +++ b/queue-5.10/gfs2-add-metapath_dibh-helper.patch @@ -0,0 +1,48 @@ +From 284a2539499cd9698789bae7e74ba2f549700fa6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Oct 2023 01:32:15 +0200 +Subject: gfs2: Add metapath_dibh helper + +From: Andreas Gruenbacher + +[ Upstream commit 92099f0c92270c8c7a79e6bc6e0312ad248ea331 ] + +Add a metapath_dibh() helper for extracting the inode's buffer head from +a metapath. + +Signed-off-by: Andreas Gruenbacher +Stable-dep-of: faddeb848305 ("gfs2: Fix use-after-free in iomap inline data write path") +Signed-off-by: Sasha Levin +--- + fs/gfs2/bmap.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c +index f7d51dd6559c2..1e0e350b5a5a5 100644 +--- a/fs/gfs2/bmap.c ++++ b/fs/gfs2/bmap.c +@@ -318,6 +318,12 @@ static void gfs2_metapath_ra(struct gfs2_glock *gl, __be64 *start, __be64 *end) + } + } + ++static inline struct buffer_head * ++metapath_dibh(struct metapath *mp) ++{ ++ return mp->mp_bh[0]; ++} ++ + static int __fillup_metapath(struct gfs2_inode *ip, struct metapath *mp, + unsigned int x, unsigned int h) + { +@@ -662,7 +668,7 @@ static int __gfs2_iomap_alloc(struct inode *inode, struct iomap *iomap, + { + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); +- struct buffer_head *dibh = mp->mp_bh[0]; ++ struct buffer_head *dibh = metapath_dibh(mp); + u64 bn; + unsigned n, i, blks, alloced = 0, iblks = 0, branch_start = 0; + size_t dblks = iomap->length >> inode->i_blkbits; +-- +2.51.0 + diff --git a/queue-5.10/gfs2-add-new-gfs2_iomap_get-helper.patch b/queue-5.10/gfs2-add-new-gfs2_iomap_get-helper.patch new file mode 100644 index 0000000000..fae77f16f2 --- /dev/null +++ b/queue-5.10/gfs2-add-new-gfs2_iomap_get-helper.patch @@ -0,0 +1,249 @@ +From cfd965a3da5cd2fe388ca8f93cec8c5856a27d66 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 27 Mar 2021 21:56:40 +0100 +Subject: gfs2: Add new gfs2_iomap_get helper + +From: Andreas Gruenbacher + +[ Upstream commit 54992257fe4bb9f76f66b3863492aa8cc5567790 ] + +Rename the current gfs2_iomap_get and gfs2_iomap_alloc functions to __*. +Add a new gfs2_iomap_get helper that doesn't expose struct metapath. +Rename gfs2_iomap_get_alloc to gfs2_iomap_alloc. Use the new helpers +where they make sense. + +Signed-off-by: Andreas Gruenbacher +Stable-dep-of: faddeb848305 ("gfs2: Fix use-after-free in iomap inline data write path") +Signed-off-by: Sasha Levin +--- + fs/gfs2/bmap.c | 65 +++++++++++++++++++++++++++----------------------- + fs/gfs2/bmap.h | 6 +++-- + fs/gfs2/file.c | 5 ++-- + 3 files changed, 41 insertions(+), 35 deletions(-) + +diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c +index 3d60ad9982c87..8ec1114ab452c 100644 +--- a/fs/gfs2/bmap.c ++++ b/fs/gfs2/bmap.c +@@ -629,7 +629,7 @@ enum alloc_state { + }; + + /** +- * gfs2_iomap_alloc - Build a metadata tree of the requested height ++ * __gfs2_iomap_alloc - Build a metadata tree of the requested height + * @inode: The GFS2 inode + * @iomap: The iomap structure + * @mp: The metapath, with proper height information calculated +@@ -639,7 +639,7 @@ enum alloc_state { + * ii) Indirect blocks to fill in lower part of the metadata tree + * iii) Data blocks + * +- * This function is called after gfs2_iomap_get, which works out the ++ * This function is called after __gfs2_iomap_get, which works out the + * total number of blocks which we need via gfs2_alloc_size. + * + * We then do the actual allocation asking for an extent at a time (if +@@ -657,8 +657,8 @@ enum alloc_state { + * Returns: errno on error + */ + +-static int gfs2_iomap_alloc(struct inode *inode, struct iomap *iomap, +- struct metapath *mp) ++static int __gfs2_iomap_alloc(struct inode *inode, struct iomap *iomap, ++ struct metapath *mp) + { + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); +@@ -799,10 +799,10 @@ static u64 gfs2_alloc_size(struct inode *inode, struct metapath *mp, u64 size) + + /* + * For writes to stuffed files, this function is called twice via +- * gfs2_iomap_get, before and after unstuffing. The size we return the ++ * __gfs2_iomap_get, before and after unstuffing. The size we return the + * first time needs to be large enough to get the reservation and + * allocation sizes right. The size we return the second time must +- * be exact or else gfs2_iomap_alloc won't do the right thing. ++ * be exact or else __gfs2_iomap_alloc won't do the right thing. + */ + + if (gfs2_is_stuffed(ip) || mp->mp_fheight != mp->mp_aheight) { +@@ -826,7 +826,7 @@ static u64 gfs2_alloc_size(struct inode *inode, struct metapath *mp, u64 size) + } + + /** +- * gfs2_iomap_get - Map blocks from an inode to disk blocks ++ * __gfs2_iomap_get - Map blocks from an inode to disk blocks + * @inode: The inode + * @pos: Starting position in bytes + * @length: Length to map, in bytes +@@ -836,9 +836,9 @@ static u64 gfs2_alloc_size(struct inode *inode, struct metapath *mp, u64 size) + * + * Returns: errno + */ +-static int gfs2_iomap_get(struct inode *inode, loff_t pos, loff_t length, +- unsigned flags, struct iomap *iomap, +- struct metapath *mp) ++static int __gfs2_iomap_get(struct inode *inode, loff_t pos, loff_t length, ++ unsigned flags, struct iomap *iomap, ++ struct metapath *mp) + { + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); +@@ -972,12 +972,10 @@ static int gfs2_iomap_get(struct inode *inode, loff_t pos, loff_t length, + int gfs2_lblk_to_dblk(struct inode *inode, u32 lblock, u64 *dblock) + { + struct iomap iomap = { }; +- struct metapath mp = { .mp_aheight = 1, }; + loff_t pos = (loff_t)lblock << inode->i_blkbits; + int ret; + +- ret = gfs2_iomap_get(inode, pos, i_blocksize(inode), 0, &iomap, &mp); +- release_metapath(&mp); ++ ret = gfs2_iomap_get(inode, pos, i_blocksize(inode), &iomap); + if (ret == 0) + *dblock = iomap.addr >> inode->i_blkbits; + +@@ -1106,14 +1104,14 @@ static int gfs2_iomap_begin_write(struct inode *inode, loff_t pos, + if (ret) + goto out_trans_end; + release_metapath(mp); +- ret = gfs2_iomap_get(inode, iomap->offset, +- iomap->length, flags, iomap, mp); ++ ret = __gfs2_iomap_get(inode, iomap->offset, ++ iomap->length, flags, iomap, mp); + if (ret) + goto out_trans_end; + } + + if (iomap->type == IOMAP_HOLE) { +- ret = gfs2_iomap_alloc(inode, iomap, mp); ++ ret = __gfs2_iomap_alloc(inode, iomap, mp); + if (ret) { + gfs2_trans_end(sdp); + gfs2_inplace_release(ip); +@@ -1165,7 +1163,7 @@ static int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length, + goto out; + } + +- ret = gfs2_iomap_get(inode, pos, length, flags, iomap, &mp); ++ ret = __gfs2_iomap_get(inode, pos, length, flags, iomap, &mp); + if (ret) + goto out_unlock; + +@@ -1286,9 +1284,7 @@ int gfs2_block_map(struct inode *inode, sector_t lblock, + struct gfs2_inode *ip = GFS2_I(inode); + loff_t pos = (loff_t)lblock << inode->i_blkbits; + loff_t length = bh_map->b_size; +- struct metapath mp = { .mp_aheight = 1, }; + struct iomap iomap = { }; +- int flags = create ? IOMAP_WRITE : 0; + int ret; + + clear_buffer_mapped(bh_map); +@@ -1296,10 +1292,10 @@ int gfs2_block_map(struct inode *inode, sector_t lblock, + clear_buffer_boundary(bh_map); + trace_gfs2_bmap(ip, bh_map, lblock, create, 1); + +- ret = gfs2_iomap_get(inode, pos, length, flags, &iomap, &mp); +- if (create && !ret && iomap.type == IOMAP_HOLE) +- ret = gfs2_iomap_alloc(inode, &iomap, &mp); +- release_metapath(&mp); ++ if (!create) ++ ret = gfs2_iomap_get(inode, pos, length, &iomap); ++ else ++ ret = gfs2_iomap_alloc(inode, pos, length, &iomap); + if (ret) + goto out; + +@@ -1457,15 +1453,26 @@ static int trunc_start(struct inode *inode, u64 newsize) + return error; + } + +-int gfs2_iomap_get_alloc(struct inode *inode, loff_t pos, loff_t length, +- struct iomap *iomap) ++int gfs2_iomap_get(struct inode *inode, loff_t pos, loff_t length, ++ struct iomap *iomap) ++{ ++ struct metapath mp = { .mp_aheight = 1, }; ++ int ret; ++ ++ ret = __gfs2_iomap_get(inode, pos, length, 0, iomap, &mp); ++ release_metapath(&mp); ++ return ret; ++} ++ ++int gfs2_iomap_alloc(struct inode *inode, loff_t pos, loff_t length, ++ struct iomap *iomap) + { + struct metapath mp = { .mp_aheight = 1, }; + int ret; + +- ret = gfs2_iomap_get(inode, pos, length, IOMAP_WRITE, iomap, &mp); ++ ret = __gfs2_iomap_get(inode, pos, length, IOMAP_WRITE, iomap, &mp); + if (!ret && iomap->type == IOMAP_HOLE) +- ret = gfs2_iomap_alloc(inode, iomap, &mp); ++ ret = __gfs2_iomap_alloc(inode, iomap, &mp); + release_metapath(&mp); + return ret; + } +@@ -2516,7 +2523,6 @@ int __gfs2_punch_hole(struct file *file, loff_t offset, loff_t length) + static int gfs2_map_blocks(struct iomap_writepage_ctx *wpc, struct inode *inode, + loff_t offset) + { +- struct metapath mp = { .mp_aheight = 1, }; + int ret; + + if (WARN_ON_ONCE(gfs2_is_stuffed(GFS2_I(inode)))) +@@ -2527,8 +2533,7 @@ static int gfs2_map_blocks(struct iomap_writepage_ctx *wpc, struct inode *inode, + return 0; + + memset(&wpc->iomap, 0, sizeof(wpc->iomap)); +- ret = gfs2_iomap_get(inode, offset, INT_MAX, 0, &wpc->iomap, &mp); +- release_metapath(&mp); ++ ret = gfs2_iomap_get(inode, offset, INT_MAX, &wpc->iomap); + return ret; + } + +diff --git a/fs/gfs2/bmap.h b/fs/gfs2/bmap.h +index aed4632d47d30..c63efee8aaa43 100644 +--- a/fs/gfs2/bmap.h ++++ b/fs/gfs2/bmap.h +@@ -49,8 +49,10 @@ extern const struct iomap_writeback_ops gfs2_writeback_ops; + extern int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page); + extern int gfs2_block_map(struct inode *inode, sector_t lblock, + struct buffer_head *bh, int create); +-extern int gfs2_iomap_get_alloc(struct inode *inode, loff_t pos, loff_t length, +- struct iomap *iomap); ++extern int gfs2_iomap_get(struct inode *inode, loff_t pos, loff_t length, ++ struct iomap *iomap); ++extern int gfs2_iomap_alloc(struct inode *inode, loff_t pos, loff_t length, ++ struct iomap *iomap); + extern int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, + u64 *dblock, unsigned *extlen); + extern int gfs2_setattr_size(struct inode *inode, u64 size); +diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c +index 5e2fe456ed922..ec5000e13bb70 100644 +--- a/fs/gfs2/file.c ++++ b/fs/gfs2/file.c +@@ -422,7 +422,7 @@ static int gfs2_allocate_page_backing(struct page *page, unsigned int length) + do { + struct iomap iomap = { }; + +- if (gfs2_iomap_get_alloc(page->mapping->host, pos, length, &iomap)) ++ if (gfs2_iomap_alloc(page->mapping->host, pos, length, &iomap)) + return -EIO; + + if (length < iomap.length) +@@ -1001,8 +1001,7 @@ static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len, + while (offset < end) { + struct iomap iomap = { }; + +- error = gfs2_iomap_get_alloc(inode, offset, end - offset, +- &iomap); ++ error = gfs2_iomap_alloc(inode, offset, end - offset, &iomap); + if (error) + goto out; + offset = iomap.offset + iomap.length; +-- +2.51.0 + diff --git a/queue-5.10/gfs2-add-wrapper-for-iomap_file_buffered_write.patch b/queue-5.10/gfs2-add-wrapper-for-iomap_file_buffered_write.patch new file mode 100644 index 0000000000..1b6c67d3ef --- /dev/null +++ b/queue-5.10/gfs2-add-wrapper-for-iomap_file_buffered_write.patch @@ -0,0 +1,82 @@ +From a68823d250d4fecb1431d73157c3858fc25cc55a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 13 May 2021 16:13:54 +0200 +Subject: gfs2: Add wrapper for iomap_file_buffered_write + +From: Andreas Gruenbacher + +[ Upstream commit 2eb7509a05443048fb4df60b782de3f03c6c298b ] + +Add a wrapper around iomap_file_buffered_write. We'll add code for when +the operation needs to be retried here later. + +Signed-off-by: Andreas Gruenbacher +Stable-dep-of: faddeb848305 ("gfs2: Fix use-after-free in iomap inline data write path") +Signed-off-by: Sasha Levin +--- + fs/gfs2/file.c | 27 +++++++++++++++++---------- + 1 file changed, 17 insertions(+), 10 deletions(-) + +diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c +index ec5000e13bb70..0ef9bf81fde0a 100644 +--- a/fs/gfs2/file.c ++++ b/fs/gfs2/file.c +@@ -888,6 +888,20 @@ static ssize_t gfs2_file_read_iter(struct kiocb *iocb, struct iov_iter *to) + return written ? written : ret; + } + ++static ssize_t gfs2_file_buffered_write(struct kiocb *iocb, struct iov_iter *from) ++{ ++ struct file *file = iocb->ki_filp; ++ struct inode *inode = file_inode(file); ++ ssize_t ret; ++ ++ current->backing_dev_info = inode_to_bdi(inode); ++ ret = iomap_file_buffered_write(iocb, from, &gfs2_iomap_ops); ++ current->backing_dev_info = NULL; ++ if (ret > 0) ++ iocb->ki_pos += ret; ++ return ret; ++} ++ + /** + * gfs2_file_write_iter - Perform a write to a file + * @iocb: The io context +@@ -939,9 +953,7 @@ static ssize_t gfs2_file_write_iter(struct kiocb *iocb, struct iov_iter *from) + goto out_unlock; + + iocb->ki_flags |= IOCB_DSYNC; +- current->backing_dev_info = inode_to_bdi(inode); +- buffered = iomap_file_buffered_write(iocb, from, &gfs2_iomap_ops); +- current->backing_dev_info = NULL; ++ buffered = gfs2_file_buffered_write(iocb, from); + if (unlikely(buffered <= 0)) { + if (!ret) + ret = buffered; +@@ -955,7 +967,6 @@ static ssize_t gfs2_file_write_iter(struct kiocb *iocb, struct iov_iter *from) + * the direct I/O range as we don't know if the buffered pages + * made it to disk. + */ +- iocb->ki_pos += buffered; + ret2 = generic_write_sync(iocb, buffered); + invalidate_mapping_pages(mapping, + (iocb->ki_pos - buffered) >> PAGE_SHIFT, +@@ -963,13 +974,9 @@ static ssize_t gfs2_file_write_iter(struct kiocb *iocb, struct iov_iter *from) + if (!ret || ret2 > 0) + ret += ret2; + } else { +- current->backing_dev_info = inode_to_bdi(inode); +- ret = iomap_file_buffered_write(iocb, from, &gfs2_iomap_ops); +- current->backing_dev_info = NULL; +- if (likely(ret > 0)) { +- iocb->ki_pos += ret; ++ ret = gfs2_file_buffered_write(iocb, from); ++ if (likely(ret > 0)) + ret = generic_write_sync(iocb, ret); +- } + } + + out_unlock: +-- +2.51.0 + diff --git a/queue-5.10/gfs2-fix-use-after-free-in-iomap-inline-data-write-p.patch b/queue-5.10/gfs2-fix-use-after-free-in-iomap-inline-data-write-p.patch new file mode 100644 index 0000000000..cfc60ac2b4 --- /dev/null +++ b/queue-5.10/gfs2-fix-use-after-free-in-iomap-inline-data-write-p.patch @@ -0,0 +1,84 @@ +From 1a418b50745db56ee716bb886b6ad75e9687d32e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 14:51:34 +0530 +Subject: gfs2: Fix use-after-free in iomap inline data write path + +From: Deepanshu Kartikey + +[ Upstream commit faddeb848305e79db89ee0479bb0e33380656321 ] + +The inline data buffer head (dibh) is being released prematurely in +gfs2_iomap_begin() via release_metapath() while iomap->inline_data +still points to dibh->b_data. This causes a use-after-free when +iomap_write_end_inline() later attempts to write to the inline data +area. + +The bug sequence: +1. gfs2_iomap_begin() calls gfs2_meta_inode_buffer() to read inode + metadata into dibh +2. Sets iomap->inline_data = dibh->b_data + sizeof(struct gfs2_dinode) +3. Calls release_metapath() which calls brelse(dibh), dropping refcount + to 0 +4. kswapd reclaims the page (~39ms later in the syzbot report) +5. iomap_write_end_inline() tries to memcpy() to iomap->inline_data +6. KASAN detects use-after-free write to freed memory + +Fix by storing dibh in iomap->private and incrementing its refcount +with get_bh() in gfs2_iomap_begin(). The buffer is then properly +released in gfs2_iomap_end() after the inline write completes, +ensuring the page stays alive for the entire iomap operation. + +Note: A C reproducer is not available for this issue. The fix is based +on analysis of the KASAN report and code review showing the buffer head +is freed before use. + +[agruenba: Take buffer head reference in gfs2_iomap_begin() to avoid +leaks in gfs2_iomap_get() and gfs2_iomap_alloc().] + +Reported-by: syzbot+ea1cd4aa4d1e98458a55@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=ea1cd4aa4d1e98458a55 +Fixes: d0a22a4b03b8 ("gfs2: Fix iomap write page reclaim deadlock") +Signed-off-by: Deepanshu Kartikey +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Sasha Levin +--- + fs/gfs2/bmap.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c +index 1e0e350b5a5a5..10b0151b2789d 100644 +--- a/fs/gfs2/bmap.c ++++ b/fs/gfs2/bmap.c +@@ -1115,10 +1115,18 @@ static int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length, + goto out_unlock; + break; + default: +- goto out_unlock; ++ goto out; + } + + ret = gfs2_iomap_begin_write(inode, pos, length, flags, iomap, &mp); ++ if (ret) ++ goto out_unlock; ++ ++out: ++ if (iomap->type == IOMAP_INLINE) { ++ iomap->private = metapath_dibh(&mp); ++ get_bh(iomap->private); ++ } + + out_unlock: + release_metapath(&mp); +@@ -1132,6 +1140,9 @@ static int gfs2_iomap_end(struct inode *inode, loff_t pos, loff_t length, + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); + ++ if (iomap->private) ++ brelse(iomap->private); ++ + switch (flags & (IOMAP_WRITE | IOMAP_ZERO)) { + case IOMAP_WRITE: + if (flags & IOMAP_DIRECT) +-- +2.51.0 + diff --git a/queue-5.10/gfs2-move-the-inode-glock-locking-to-gfs2_file_buffe.patch b/queue-5.10/gfs2-move-the-inode-glock-locking-to-gfs2_file_buffe.patch new file mode 100644 index 0000000000..b39a452702 --- /dev/null +++ b/queue-5.10/gfs2-move-the-inode-glock-locking-to-gfs2_file_buffe.patch @@ -0,0 +1,181 @@ +From b39550e352afdf1c9ecbdeff457c5de1faf22e0e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Aug 2021 21:50:14 +0200 +Subject: gfs2: Move the inode glock locking to gfs2_file_buffered_write + +From: Andreas Gruenbacher + +[ Upstream commit b924bdab7445946e2ed364a0e6e249d36f1f1158 ] + +So far, for buffered writes, we were taking the inode glock in +gfs2_iomap_begin and dropping it in gfs2_iomap_end with the intention of +not holding the inode glock while iomap_write_actor faults in user +pages. It turns out that iomap_write_actor is called inside iomap_begin +... iomap_end, so the user pages were still faulted in while holding the +inode glock and the locking code in iomap_begin / iomap_end was +completely pointless. + +Move the locking into gfs2_file_buffered_write instead. We'll take care +of the potential deadlocks due to faulting in user pages while holding a +glock in a subsequent patch. + +Signed-off-by: Andreas Gruenbacher +Stable-dep-of: faddeb848305 ("gfs2: Fix use-after-free in iomap inline data write path") +Signed-off-by: Sasha Levin +--- + fs/gfs2/bmap.c | 60 +------------------------------------------------- + fs/gfs2/file.c | 27 +++++++++++++++++++++++ + 2 files changed, 28 insertions(+), 59 deletions(-) + +diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c +index 4514d9a8d3cd4..f7d51dd6559c2 100644 +--- a/fs/gfs2/bmap.c ++++ b/fs/gfs2/bmap.c +@@ -958,46 +958,6 @@ static int __gfs2_iomap_get(struct inode *inode, loff_t pos, loff_t length, + goto out; + } + +-static int gfs2_write_lock(struct inode *inode) +-{ +- struct gfs2_inode *ip = GFS2_I(inode); +- struct gfs2_sbd *sdp = GFS2_SB(inode); +- int error; +- +- gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &ip->i_gh); +- error = gfs2_glock_nq(&ip->i_gh); +- if (error) +- goto out_uninit; +- if (&ip->i_inode == sdp->sd_rindex) { +- struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode); +- +- error = gfs2_glock_nq_init(m_ip->i_gl, LM_ST_EXCLUSIVE, +- GL_NOCACHE, &m_ip->i_gh); +- if (error) +- goto out_unlock; +- } +- return 0; +- +-out_unlock: +- gfs2_glock_dq(&ip->i_gh); +-out_uninit: +- gfs2_holder_uninit(&ip->i_gh); +- return error; +-} +- +-static void gfs2_write_unlock(struct inode *inode) +-{ +- struct gfs2_inode *ip = GFS2_I(inode); +- struct gfs2_sbd *sdp = GFS2_SB(inode); +- +- if (&ip->i_inode == sdp->sd_rindex) { +- struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode); +- +- gfs2_glock_dq_uninit(&m_ip->i_gh); +- } +- gfs2_glock_dq_uninit(&ip->i_gh); +-} +- + static int gfs2_iomap_page_prepare(struct inode *inode, loff_t pos, + unsigned len, struct iomap *iomap) + { +@@ -1116,11 +1076,6 @@ static int gfs2_iomap_begin_write(struct inode *inode, loff_t pos, + return ret; + } + +-static inline bool gfs2_iomap_need_write_lock(unsigned flags) +-{ +- return (flags & IOMAP_WRITE) && !(flags & IOMAP_DIRECT); +-} +- + static int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length, + unsigned flags, struct iomap *iomap, + struct iomap *srcmap) +@@ -1133,12 +1088,6 @@ static int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length, + iomap->flags |= IOMAP_F_BUFFER_HEAD; + + trace_gfs2_iomap_start(ip, pos, length, flags); +- if (gfs2_iomap_need_write_lock(flags)) { +- ret = gfs2_write_lock(inode); +- if (ret) +- goto out; +- } +- + ret = __gfs2_iomap_get(inode, pos, length, flags, iomap, &mp); + if (ret) + goto out_unlock; +@@ -1166,10 +1115,7 @@ static int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length, + ret = gfs2_iomap_begin_write(inode, pos, length, flags, iomap, &mp); + + out_unlock: +- if (ret && gfs2_iomap_need_write_lock(flags)) +- gfs2_write_unlock(inode); + release_metapath(&mp); +-out: + trace_gfs2_iomap_end(ip, iomap, ret); + return ret; + } +@@ -1216,15 +1162,11 @@ static int gfs2_iomap_end(struct inode *inode, loff_t pos, loff_t length, + } + + if (unlikely(!written)) +- goto out_unlock; ++ return 0; + + if (iomap->flags & IOMAP_F_SIZE_CHANGED) + mark_inode_dirty(inode); + set_bit(GLF_DIRTY, &ip->i_gl->gl_flags); +- +-out_unlock: +- if (gfs2_iomap_need_write_lock(flags)) +- gfs2_write_unlock(inode); + return 0; + } + +diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c +index 0ef9bf81fde0a..91dbda72b5a03 100644 +--- a/fs/gfs2/file.c ++++ b/fs/gfs2/file.c +@@ -892,13 +892,40 @@ static ssize_t gfs2_file_buffered_write(struct kiocb *iocb, struct iov_iter *fro + { + struct file *file = iocb->ki_filp; + struct inode *inode = file_inode(file); ++ struct gfs2_inode *ip = GFS2_I(inode); ++ struct gfs2_sbd *sdp = GFS2_SB(inode); + ssize_t ret; + ++ gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &ip->i_gh); ++ ret = gfs2_glock_nq(&ip->i_gh); ++ if (ret) ++ goto out_uninit; ++ ++ if (inode == sdp->sd_rindex) { ++ struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode); ++ ++ ret = gfs2_glock_nq_init(m_ip->i_gl, LM_ST_EXCLUSIVE, ++ GL_NOCACHE, &m_ip->i_gh); ++ if (ret) ++ goto out_unlock; ++ } ++ + current->backing_dev_info = inode_to_bdi(inode); + ret = iomap_file_buffered_write(iocb, from, &gfs2_iomap_ops); + current->backing_dev_info = NULL; + if (ret > 0) + iocb->ki_pos += ret; ++ ++ if (inode == sdp->sd_rindex) { ++ struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode); ++ ++ gfs2_glock_dq_uninit(&m_ip->i_gh); ++ } ++ ++out_unlock: ++ gfs2_glock_dq(&ip->i_gh); ++out_uninit: ++ gfs2_holder_uninit(&ip->i_gh); + return ret; + } + +-- +2.51.0 + diff --git a/queue-5.10/gfs2-replace-gfs2_lblk_to_dblk-with-gfs2_get_extent.patch b/queue-5.10/gfs2-replace-gfs2_lblk_to_dblk-with-gfs2_get_extent.patch new file mode 100644 index 0000000000..6465e31d52 --- /dev/null +++ b/queue-5.10/gfs2-replace-gfs2_lblk_to_dblk-with-gfs2_get_extent.patch @@ -0,0 +1,87 @@ +From 798f41992c1ac29d28682b2a7c5a5f2c4009a262 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 27 Mar 2021 22:05:14 +0100 +Subject: gfs2: Replace gfs2_lblk_to_dblk with gfs2_get_extent + +From: Andreas Gruenbacher + +[ Upstream commit 152f58c9af21abf913699e671b425fd38447b170 ] + +We don't need two very similar functions for mapping logical blocks to physical +blocks. + +Signed-off-by: Andreas Gruenbacher +Stable-dep-of: faddeb848305 ("gfs2: Fix use-after-free in iomap inline data write path") +Signed-off-by: Sasha Levin +--- + fs/gfs2/bmap.c | 24 ------------------------ + fs/gfs2/bmap.h | 1 - + fs/gfs2/log.c | 6 +++++- + 3 files changed, 5 insertions(+), 26 deletions(-) + +diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c +index 41e98499862db..4514d9a8d3cd4 100644 +--- a/fs/gfs2/bmap.c ++++ b/fs/gfs2/bmap.c +@@ -958,30 +958,6 @@ static int __gfs2_iomap_get(struct inode *inode, loff_t pos, loff_t length, + goto out; + } + +-/** +- * gfs2_lblk_to_dblk - convert logical block to disk block +- * @inode: the inode of the file we're mapping +- * @lblock: the block relative to the start of the file +- * @dblock: the returned dblock, if no error +- * +- * This function maps a single block from a file logical block (relative to +- * the start of the file) to a file system absolute block using iomap. +- * +- * Returns: the absolute file system block, or an error +- */ +-int gfs2_lblk_to_dblk(struct inode *inode, u32 lblock, u64 *dblock) +-{ +- struct iomap iomap = { }; +- loff_t pos = (loff_t)lblock << inode->i_blkbits; +- int ret; +- +- ret = gfs2_iomap_get(inode, pos, i_blocksize(inode), &iomap); +- if (ret == 0) +- *dblock = iomap.addr >> inode->i_blkbits; +- +- return ret; +-} +- + static int gfs2_write_lock(struct inode *inode) + { + struct gfs2_inode *ip = GFS2_I(inode); +diff --git a/fs/gfs2/bmap.h b/fs/gfs2/bmap.h +index 67ef7cf7fdacc..6676d863faef0 100644 +--- a/fs/gfs2/bmap.h ++++ b/fs/gfs2/bmap.h +@@ -66,6 +66,5 @@ extern int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset, + extern int gfs2_map_journal_extents(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd); + extern void gfs2_free_journal_extents(struct gfs2_jdesc *jd); + extern int __gfs2_punch_hole(struct file *file, loff_t offset, loff_t length); +-extern int gfs2_lblk_to_dblk(struct inode *inode, u32 lblock, u64 *dblock); + + #endif /* __BMAP_DOT_H__ */ +diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c +index 7473b894e3c6c..a667d315b1568 100644 +--- a/fs/gfs2/log.c ++++ b/fs/gfs2/log.c +@@ -793,7 +793,11 @@ void gfs2_write_log_header(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd, + if (!list_empty(&jd->extent_list)) + dblock = gfs2_log_bmap(jd, lblock); + else { +- int ret = gfs2_lblk_to_dblk(jd->jd_inode, lblock, &dblock); ++ unsigned int extlen; ++ int ret; ++ ++ extlen = 1; ++ ret = gfs2_get_extent(jd->jd_inode, lblock, &dblock, &extlen); + if (gfs2_assert_withdraw(sdp, ret == 0)) + return; + } +-- +2.51.0 + diff --git a/queue-5.10/gfs2-turn-gfs2_extent_map-into-gfs2_-get-alloc-_exte.patch b/queue-5.10/gfs2-turn-gfs2_extent_map-into-gfs2_-get-alloc-_exte.patch new file mode 100644 index 0000000000..f18493d686 --- /dev/null +++ b/queue-5.10/gfs2-turn-gfs2_extent_map-into-gfs2_-get-alloc-_exte.patch @@ -0,0 +1,194 @@ +From 8bdf4ca3c3b6a036cca4ecd22d71a0d52af38305 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 31 Mar 2021 23:17:38 +0200 +Subject: gfs2: Turn gfs2_extent_map into gfs2_{get,alloc}_extent + +From: Andreas Gruenbacher + +[ Upstream commit 9153dac13a6966b63183bac450d5cd39b07cc85c ] + +Convert gfs2_extent_map to iomap and split it into gfs2_get_extent and +gfs2_alloc_extent. Instead of hardcoding the extent size, pass it in +via the extlen parameter. + +Signed-off-by: Andreas Gruenbacher +Stable-dep-of: faddeb848305 ("gfs2: Fix use-after-free in iomap inline data write path") +Signed-off-by: Sasha Levin +--- + fs/gfs2/bmap.c | 59 ++++++++++++++++++++++++++++++---------------- + fs/gfs2/bmap.h | 6 +++-- + fs/gfs2/dir.c | 13 +++++----- + fs/gfs2/quota.c | 4 ++-- + fs/gfs2/recovery.c | 4 ++-- + 5 files changed, 53 insertions(+), 33 deletions(-) + +diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c +index 8ec1114ab452c..41e98499862db 100644 +--- a/fs/gfs2/bmap.c ++++ b/fs/gfs2/bmap.c +@@ -1316,28 +1316,47 @@ int gfs2_block_map(struct inode *inode, sector_t lblock, + return ret; + } + +-/* +- * Deprecated: do not use in new code +- */ +-int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen) ++int gfs2_get_extent(struct inode *inode, u64 lblock, u64 *dblock, ++ unsigned int *extlen) + { +- struct buffer_head bh = { .b_state = 0, .b_blocknr = 0 }; ++ unsigned int blkbits = inode->i_blkbits; ++ struct iomap iomap = { }; ++ unsigned int len; + int ret; +- int create = *new; +- +- BUG_ON(!extlen); +- BUG_ON(!dblock); +- BUG_ON(!new); +- +- bh.b_size = BIT(inode->i_blkbits + (create ? 0 : 5)); +- ret = gfs2_block_map(inode, lblock, &bh, create); +- *extlen = bh.b_size >> inode->i_blkbits; +- *dblock = bh.b_blocknr; +- if (buffer_new(&bh)) +- *new = 1; +- else +- *new = 0; +- return ret; ++ ++ ret = gfs2_iomap_get(inode, lblock << blkbits, *extlen << blkbits, ++ &iomap); ++ if (ret) ++ return ret; ++ if (iomap.type != IOMAP_MAPPED) ++ return -EIO; ++ *dblock = iomap.addr >> blkbits; ++ len = iomap.length >> blkbits; ++ if (len < *extlen) ++ *extlen = len; ++ return 0; ++} ++ ++int gfs2_alloc_extent(struct inode *inode, u64 lblock, u64 *dblock, ++ unsigned int *extlen, bool *new) ++{ ++ unsigned int blkbits = inode->i_blkbits; ++ struct iomap iomap = { }; ++ unsigned int len; ++ int ret; ++ ++ ret = gfs2_iomap_alloc(inode, lblock << blkbits, *extlen << blkbits, ++ &iomap); ++ if (ret) ++ return ret; ++ if (iomap.type != IOMAP_MAPPED) ++ return -EIO; ++ *dblock = iomap.addr >> blkbits; ++ len = iomap.length >> blkbits; ++ if (len < *extlen) ++ *extlen = len; ++ *new = iomap.flags & IOMAP_F_NEW; ++ return 0; + } + + /* +diff --git a/fs/gfs2/bmap.h b/fs/gfs2/bmap.h +index c63efee8aaa43..67ef7cf7fdacc 100644 +--- a/fs/gfs2/bmap.h ++++ b/fs/gfs2/bmap.h +@@ -53,8 +53,10 @@ extern int gfs2_iomap_get(struct inode *inode, loff_t pos, loff_t length, + struct iomap *iomap); + extern int gfs2_iomap_alloc(struct inode *inode, loff_t pos, loff_t length, + struct iomap *iomap); +-extern int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, +- u64 *dblock, unsigned *extlen); ++extern int gfs2_get_extent(struct inode *inode, u64 lblock, u64 *dblock, ++ unsigned int *extlen); ++extern int gfs2_alloc_extent(struct inode *inode, u64 lblock, u64 *dblock, ++ unsigned *extlen, bool *new); + extern int gfs2_setattr_size(struct inode *inode, u64 size); + extern void gfs2_trim_blocks(struct inode *inode); + extern int gfs2_truncatei_resume(struct gfs2_inode *ip); +diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c +index c0f2875c946c9..4517ffb7c13d2 100644 +--- a/fs/gfs2/dir.c ++++ b/fs/gfs2/dir.c +@@ -159,7 +159,7 @@ static int gfs2_dir_write_data(struct gfs2_inode *ip, const char *buf, + unsigned int o; + int copied = 0; + int error = 0; +- int new = 0; ++ bool new = false; + + if (!size) + return 0; +@@ -189,9 +189,9 @@ static int gfs2_dir_write_data(struct gfs2_inode *ip, const char *buf, + amount = sdp->sd_sb.sb_bsize - o; + + if (!extlen) { +- new = 1; +- error = gfs2_extent_map(&ip->i_inode, lblock, &new, +- &dblock, &extlen); ++ extlen = 1; ++ error = gfs2_alloc_extent(&ip->i_inode, lblock, &dblock, ++ &extlen, &new); + if (error) + goto fail; + error = -EIO; +@@ -286,15 +286,14 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, __be64 *buf, + while (copied < size) { + unsigned int amount; + struct buffer_head *bh; +- int new; + + amount = size - copied; + if (amount > sdp->sd_sb.sb_bsize - o) + amount = sdp->sd_sb.sb_bsize - o; + + if (!extlen) { +- new = 0; +- error = gfs2_extent_map(&ip->i_inode, lblock, &new, ++ extlen = 32; ++ error = gfs2_get_extent(&ip->i_inode, lblock, + &dblock, &extlen); + if (error || !dblock) + goto fail; +diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c +index 8c226aa286336..984ca5057d9d5 100644 +--- a/fs/gfs2/quota.c ++++ b/fs/gfs2/quota.c +@@ -1394,8 +1394,8 @@ int gfs2_quota_init(struct gfs2_sbd *sdp) + unsigned int y; + + if (!extlen) { +- int new = 0; +- error = gfs2_extent_map(&ip->i_inode, x, &new, &dblock, &extlen); ++ extlen = 32; ++ error = gfs2_get_extent(&ip->i_inode, x, &dblock, &extlen); + if (error) + goto fail; + } +diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c +index 8f9c6480a5df4..b925ba068af50 100644 +--- a/fs/gfs2/recovery.c ++++ b/fs/gfs2/recovery.c +@@ -34,12 +34,12 @@ int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk, + { + struct gfs2_inode *ip = GFS2_I(jd->jd_inode); + struct gfs2_glock *gl = ip->i_gl; +- int new = 0; + u64 dblock; + u32 extlen; + int error; + +- error = gfs2_extent_map(&ip->i_inode, blk, &new, &dblock, &extlen); ++ extlen = 32; ++ error = gfs2_get_extent(&ip->i_inode, blk, &dblock, &extlen); + if (error) + return error; + if (!dblock) { +-- +2.51.0 + diff --git a/queue-5.10/hfsplus-return-error-when-node-already-exists-in-hfs.patch b/queue-5.10/hfsplus-return-error-when-node-already-exists-in-hfs.patch new file mode 100644 index 0000000000..648c3c4d95 --- /dev/null +++ b/queue-5.10/hfsplus-return-error-when-node-already-exists-in-hfs.patch @@ -0,0 +1,58 @@ +From 6d583e8ca67bb6ebddb33ddd836f4eb63e66f662 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Dec 2025 02:19:38 +0530 +Subject: hfsplus: return error when node already exists in hfs_bnode_create + +From: Shardul Bankar + +[ Upstream commit d8a73cc46c8462a969a7516131feb3096f4c49d3 ] + +When hfs_bnode_create() finds that a node is already hashed (which should +not happen in normal operation), it currently returns the existing node +without incrementing its reference count. This causes a reference count +inconsistency that leads to a kernel panic when the node is later freed +in hfs_bnode_put(): + + kernel BUG at fs/hfsplus/bnode.c:676! + BUG_ON(!atomic_read(&node->refcnt)) + +This scenario can occur when hfs_bmap_alloc() attempts to allocate a node +that is already in use (e.g., when node 0's bitmap bit is incorrectly +unset), or due to filesystem corruption. + +Returning an existing node from a create path is not normal operation. + +Fix this by returning ERR_PTR(-EEXIST) instead of the node when it's +already hashed. This properly signals the error condition to callers, +which already check for IS_ERR() return values. + +Reported-by: syzbot+1c8ff72d0cd8a50dfeaa@syzkaller.appspotmail.com +Link: https://syzkaller.appspot.com/bug?extid=1c8ff72d0cd8a50dfeaa +Link: https://lore.kernel.org/all/784415834694f39902088fa8946850fc1779a318.camel@ibm.com/ +Fixes: 634725a92938 ("[PATCH] hfs: cleanup HFS+ prints") +Signed-off-by: Shardul Bankar +Reviewed-by: Viacheslav Dubeyko +Signed-off-by: Viacheslav Dubeyko +Link: https://lore.kernel.org/r/20251229204938.1907089-1-shardul.b@mpiricsoftware.com +Signed-off-by: Viacheslav Dubeyko +Signed-off-by: Sasha Levin +--- + fs/hfsplus/bnode.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/hfsplus/bnode.c b/fs/hfsplus/bnode.c +index 7c127922ac0c7..1fa4a1d18b7b2 100644 +--- a/fs/hfsplus/bnode.c ++++ b/fs/hfsplus/bnode.c +@@ -640,7 +640,7 @@ struct hfs_bnode *hfs_bnode_create(struct hfs_btree *tree, u32 num) + if (node) { + pr_crit("new node %u already hashed?\n", num); + WARN_ON(1); +- return node; ++ return ERR_PTR(-EEXIST); + } + node = __hfs_bnode_create(tree, num); + if (!node) +-- +2.51.0 + diff --git a/queue-5.10/hrtimer-fix-trace-oddity.patch b/queue-5.10/hrtimer-fix-trace-oddity.patch new file mode 100644 index 0000000000..7ed00f3df6 --- /dev/null +++ b/queue-5.10/hrtimer-fix-trace-oddity.patch @@ -0,0 +1,43 @@ +From af764757b8eebc34b0b0c083a00722e904667e5f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 11:38:34 +0100 +Subject: hrtimer: Fix trace oddity + +From: Thomas Gleixner + +[ Upstream commit 5d6446f409da00e5a389125ddb5ce09f5bc404c9 ] + +It turns out that __run_hrtimer() will trace like: + + -0 [032] d.h2. 20705.474563: hrtimer_cancel: hrtimer=0xff2db8f77f8226e8 + -0 [032] d.h1. 20705.474563: hrtimer_expire_entry: hrtimer=0xff2db8f77f8226e8 now=20699452001850 function=tick_nohz_handler/0x0 + +Which is a bit nonsensical, the timer doesn't get canceled on +expiration. The cause is the use of the incorrect debug helper. + +Fixes: c6a2a1770245 ("hrtimer: Add tracepoint for hrtimers") +Reported-by: Peter Zijlstra (Intel) +Signed-off-by: Thomas Gleixner +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260121143208.219595606@infradead.org +Signed-off-by: Sasha Levin +--- + kernel/time/hrtimer.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c +index c202488695c46..cf928eb8f2f8d 100644 +--- a/kernel/time/hrtimer.c ++++ b/kernel/time/hrtimer.c +@@ -1553,7 +1553,7 @@ static void __run_hrtimer(struct hrtimer_cpu_base *cpu_base, + + lockdep_assert_held(&cpu_base->lock); + +- debug_deactivate(timer); ++ debug_hrtimer_deactivate(timer); + base->running = timer; + + /* +-- +2.51.0 + diff --git a/queue-5.10/i3c-move-device-name-assignment-after-i3c_bus_init.patch b/queue-5.10/i3c-move-device-name-assignment-after-i3c_bus_init.patch new file mode 100644 index 0000000000..28fc96cb02 --- /dev/null +++ b/queue-5.10/i3c-move-device-name-assignment-after-i3c_bus_init.patch @@ -0,0 +1,44 @@ +From 2774b43cfb56c03935fdf1dc075615f2204cf5bb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 14:07:22 +0800 +Subject: i3c: Move device name assignment after i3c_bus_init + +From: Billy Tsai + +[ Upstream commit 3502cea99c7ceb331458cbd34ef6792c83144687 ] + +Move device name initialization to occur after i3c_bus_init() +so that i3cbus->id is guaranteed to be assigned before it is used. + +Fixes: 9d4f219807d5 ("i3c: fix refcount inconsistency in i3c_master_register") +Signed-off-by: Billy Tsai +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260112-upstream_i3c_fix-v1-1-cbbf2cb71809@aspeedtech.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c +index 1f4a7902ec4ea..e47cfef8c9920 100644 +--- a/drivers/i3c/master.c ++++ b/drivers/i3c/master.c +@@ -2539,12 +2539,13 @@ int i3c_master_register(struct i3c_master_controller *master, + INIT_LIST_HEAD(&master->boardinfo.i3c); + + device_initialize(&master->dev); +- dev_set_name(&master->dev, "i3c-%d", i3cbus->id); + + ret = i3c_bus_init(i3cbus); + if (ret) + goto err_put_dev; + ++ dev_set_name(&master->dev, "i3c-%d", i3cbus->id); ++ + ret = of_populate_i3c_bus(master); + if (ret) + goto err_put_dev; +-- +2.51.0 + diff --git a/queue-5.10/i3c-remove-i2c-board-info-from-i2c_dev_desc.patch b/queue-5.10/i3c-remove-i2c-board-info-from-i2c_dev_desc.patch new file mode 100644 index 0000000000..0cf3e5430a --- /dev/null +++ b/queue-5.10/i3c-remove-i2c-board-info-from-i2c_dev_desc.patch @@ -0,0 +1,104 @@ +From dd772159fe9579bf1effbdd9a8d8db94178a4de2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 17 Jan 2022 17:48:15 +0000 +Subject: i3c: remove i2c board info from i2c_dev_desc + +From: Jamie Iles + +[ Upstream commit 31b9887c7258ca47d9c665a80f19f006c86756b1 ] + +I2C board info is only required during adapter setup so there is no +requirement to keeping a pointer to it once running. To support dynamic +device addition we can't rely on board info - user-space creation +through sysfs won't have a boardinfo. + +Cc: Alexandre Belloni +Signed-off-by: Jamie Iles +Signed-off-by: Alexandre Belloni +Link: https://lore.kernel.org/r/20220117174816.1963463-2-quic_jiles@quicinc.com +Stable-dep-of: 3502cea99c7c ("i3c: Move device name assignment after i3c_bus_init") +Signed-off-by: Sasha Levin +--- + drivers/i3c/master.c | 18 ++++++++++-------- + include/linux/i3c/master.h | 1 - + 2 files changed, 10 insertions(+), 9 deletions(-) + +diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c +index aff869854ef06..1f4a7902ec4ea 100644 +--- a/drivers/i3c/master.c ++++ b/drivers/i3c/master.c +@@ -656,7 +656,7 @@ static void i3c_master_free_i2c_dev(struct i2c_dev_desc *dev) + + static struct i2c_dev_desc * + i3c_master_alloc_i2c_dev(struct i3c_master_controller *master, +- const struct i2c_dev_boardinfo *boardinfo) ++ u16 addr, u8 lvr) + { + struct i2c_dev_desc *dev; + +@@ -665,9 +665,8 @@ i3c_master_alloc_i2c_dev(struct i3c_master_controller *master, + return ERR_PTR(-ENOMEM); + + dev->common.master = master; +- dev->boardinfo = boardinfo; +- dev->addr = boardinfo->base.addr; +- dev->lvr = boardinfo->lvr; ++ dev->addr = addr; ++ dev->lvr = lvr; + + return dev; + } +@@ -741,7 +740,7 @@ i3c_master_find_i2c_dev_by_addr(const struct i3c_master_controller *master, + struct i2c_dev_desc *dev; + + i3c_bus_for_each_i2cdev(&master->bus, dev) { +- if (dev->boardinfo->base.addr == addr) ++ if (dev->addr == addr) + return dev; + } + +@@ -1731,7 +1730,9 @@ static int i3c_master_bus_init(struct i3c_master_controller *master) + i2cboardinfo->base.addr, + I3C_ADDR_SLOT_I2C_DEV); + +- i2cdev = i3c_master_alloc_i2c_dev(master, i2cboardinfo); ++ i2cdev = i3c_master_alloc_i2c_dev(master, ++ i2cboardinfo->base.addr, ++ i2cboardinfo->lvr); + if (IS_ERR(i2cdev)) { + ret = PTR_ERR(i2cdev); + goto err_detach_devs; +@@ -2220,6 +2221,7 @@ static int i3c_master_i2c_adapter_init(struct i3c_master_controller *master) + { + struct i2c_adapter *adap = i3c_master_to_i2c_adapter(master); + struct i2c_dev_desc *i2cdev; ++ struct i2c_dev_boardinfo *i2cboardinfo; + int ret; + + adap->dev.parent = master->dev.parent; +@@ -2239,8 +2241,8 @@ static int i3c_master_i2c_adapter_init(struct i3c_master_controller *master) + * We silently ignore failures here. The bus should keep working + * correctly even if one or more i2c devices are not registered. + */ +- i3c_bus_for_each_i2cdev(&master->bus, i2cdev) +- i2cdev->dev = i2c_new_client_device(adap, &i2cdev->boardinfo->base); ++ list_for_each_entry(i2cboardinfo, &master->boardinfo.i2c, node) ++ i2cdev->dev = i2c_new_client_device(adap, &i2cboardinfo->base); + + return 0; + } +diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h +index ea3781d730064..b31170e37655f 100644 +--- a/include/linux/i3c/master.h ++++ b/include/linux/i3c/master.h +@@ -85,7 +85,6 @@ struct i2c_dev_boardinfo { + */ + struct i2c_dev_desc { + struct i3c_i2c_dev_desc common; +- const struct i2c_dev_boardinfo *boardinfo; + struct i2c_client *dev; + u16 addr; + u8 lvr; +-- +2.51.0 + diff --git a/queue-5.10/iio-sca3000-fix-a-resource-leak-in-sca3000_probe.patch b/queue-5.10/iio-sca3000-fix-a-resource-leak-in-sca3000_probe.patch new file mode 100644 index 0000000000..8ae40d384b --- /dev/null +++ b/queue-5.10/iio-sca3000-fix-a-resource-leak-in-sca3000_probe.patch @@ -0,0 +1,42 @@ +From aa2077cab24daf583dcc68c066520f8fd0a87976 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 22:49:49 -0800 +Subject: iio: sca3000: Fix a resource leak in sca3000_probe() + +From: Harshit Mogalapalli + +[ Upstream commit 62b44ebc1f2c71db3ca2d4737c52e433f6f03038 ] + +spi->irq from request_threaded_irq() not released when +iio_device_register() fails. Add an return value check and jump to a +common error handler when iio_device_register() fails. + +Fixes: 9a4936dc89a3 ("staging:iio:accel:sca3000 Tidy up probe order to avoid a race.") +Signed-off-by: Harshit Mogalapalli +Reviewed-by: Andy Shevchenko +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/accel/sca3000.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/iio/accel/sca3000.c b/drivers/iio/accel/sca3000.c +index 194738660523d..10a4bf32918a7 100644 +--- a/drivers/iio/accel/sca3000.c ++++ b/drivers/iio/accel/sca3000.c +@@ -1502,7 +1502,11 @@ static int sca3000_probe(struct spi_device *spi) + if (ret) + goto error_free_irq; + +- return iio_device_register(indio_dev); ++ ret = iio_device_register(indio_dev); ++ if (ret) ++ goto error_free_irq; ++ ++ return 0; + + error_free_irq: + if (spi->irq) +-- +2.51.0 + diff --git a/queue-5.10/iomap-fix-submission-side-handling-of-completion-sid.patch b/queue-5.10/iomap-fix-submission-side-handling-of-completion-sid.patch new file mode 100644 index 0000000000..f060d5a3d7 --- /dev/null +++ b/queue-5.10/iomap-fix-submission-side-handling-of-completion-sid.patch @@ -0,0 +1,49 @@ +From 6f390314695849fe93d84997659a950ff2355f77 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 06:53:38 +0100 +Subject: iomap: fix submission side handling of completion side errors + +From: Christoph Hellwig + +[ Upstream commit 4ad357e39b2ecd5da7bcc7e840ee24d179593cd5 ] + +The "if (dio->error)" in iomap_dio_bio_iter exists to stop submitting +more bios when a completion already return an error. Commit cfe057f7db1f +("iomap_dio_actor(): fix iov_iter bugs") made it revert the iov by +"copied", which is very wrong given that we've already consumed that +range and submitted a bio for it. + +Fixes: cfe057f7db1f ("iomap_dio_actor(): fix iov_iter bugs") +Signed-off-by: Christoph Hellwig +Reviewed-by: Damien Le Moal +Reviewed-by: Darrick J. Wong +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + fs/iomap/direct-io.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/fs/iomap/direct-io.c b/fs/iomap/direct-io.c +index 8a49c0d3a7b46..d3aa7ddbd0774 100644 +--- a/fs/iomap/direct-io.c ++++ b/fs/iomap/direct-io.c +@@ -267,9 +267,13 @@ iomap_dio_bio_actor(struct inode *inode, loff_t pos, loff_t length, + + do { + size_t n; +- if (dio->error) { +- iov_iter_revert(dio->submit.iter, copied); +- copied = ret = 0; ++ ++ /* ++ * If completions already occurred and reported errors, give up now and ++ * don't bother submitting more bios. ++ */ ++ if (unlikely(data_race(dio->error))) { ++ ret = 0; + goto out; + } + +-- +2.51.0 + diff --git a/queue-5.10/iommu-vt-d-flush-cache-for-pasid-table-before-using-.patch b/queue-5.10/iommu-vt-d-flush-cache-for-pasid-table-before-using-.patch new file mode 100644 index 0000000000..eca74efce9 --- /dev/null +++ b/queue-5.10/iommu-vt-d-flush-cache-for-pasid-table-before-using-.patch @@ -0,0 +1,55 @@ +From a2b09e7faf5016f3cb54e94dfc1fb8104dce120c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 09:48:52 +0800 +Subject: iommu/vt-d: Flush cache for PASID table before using it + +From: Dmytro Maluka + +[ Upstream commit 22d169bdd2849fe6bd18c2643742e1c02be6451c ] + +When writing the address of a freshly allocated zero-initialized PASID +table to a PASID directory entry, do that after the CPU cache flush for +this PASID table, not before it, to avoid the time window when this +PASID table may be already used by non-coherent IOMMU hardware while +its contents in RAM is still some random old data, not zero-initialized. + +Fixes: 194b3348bdbb ("iommu/vt-d: Fix PASID directory pointer coherency") +Signed-off-by: Dmytro Maluka +Reviewed-by: Kevin Tian +Link: https://lore.kernel.org/r/20251221123508.37495-1-dmaluka@chromium.org +Signed-off-by: Lu Baolu +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/intel/pasid.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c +index 586b289cf468d..8c973481521e6 100644 +--- a/drivers/iommu/intel/pasid.c ++++ b/drivers/iommu/intel/pasid.c +@@ -268,6 +268,9 @@ struct pasid_entry *intel_pasid_get_entry(struct device *dev, u32 pasid) + if (!entries) + return NULL; + ++ if (!ecap_coherent(info->iommu->ecap)) ++ clflush_cache_range(entries, VTD_PAGE_SIZE); ++ + /* + * The pasid directory table entry won't be freed after + * allocation. No worry about the race with free and +@@ -279,10 +282,8 @@ struct pasid_entry *intel_pasid_get_entry(struct device *dev, u32 pasid) + free_pgtable_page(entries); + goto retry; + } +- if (!ecap_coherent(info->iommu->ecap)) { +- clflush_cache_range(entries, VTD_PAGE_SIZE); ++ if (!ecap_coherent(info->iommu->ecap)) + clflush_cache_range(&dir[dir_index].val, sizeof(*dir)); +- } + } + + return &entries[index]; +-- +2.51.0 + diff --git a/queue-5.10/ionic-rate-limit-unknown-xcvr-type-messages.patch b/queue-5.10/ionic-rate-limit-unknown-xcvr-type-messages.patch new file mode 100644 index 0000000000..c7f4a95b7c --- /dev/null +++ b/queue-5.10/ionic-rate-limit-unknown-xcvr-type-messages.patch @@ -0,0 +1,51 @@ +From a9357145273358ef4d7818e0cffcdd7da107759e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 14:46:51 -0800 +Subject: ionic: Rate limit unknown xcvr type messages + +From: Eric Joyner + +[ Upstream commit cdb1634de3bf197c0d86487d1fb84c128a79cc7c ] + +Running ethtool repeatedly with a transceiver unknown to the driver or +firmware will cause the driver to spam the kernel logs with "unknown +xcvr type" messages which can distract from real issues; and this isn't +interesting information outside of debugging. Fix this by rate limiting +the output so that there are still notifications but not so many that +they flood the log. + +Using dev_dbg_once() would reduce the number of messages further, but +this would miss the case where a different unknown transceiver type is +plugged in, and its status is requested. + +Fixes: 4d03e00a2140 ("ionic: Add initial ethtool support") +Signed-off-by: Eric Joyner +Reviewed-by: Brett Creeley +Link: https://patch.msgid.link/20260206224651.1491-1-eric.joyner@amd.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/pensando/ionic/ionic_ethtool.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c +index d0a613fac9ff3..02858e8881549 100644 +--- a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c ++++ b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c +@@ -213,9 +213,10 @@ static int ionic_get_link_ksettings(struct net_device *netdev, + /* This means there's no module plugged in */ + break; + default: +- dev_info(lif->ionic->dev, "unknown xcvr type pid=%d / 0x%x\n", +- idev->port_info->status.xcvr.pid, +- idev->port_info->status.xcvr.pid); ++ dev_dbg_ratelimited(lif->ionic->dev, ++ "unknown xcvr type pid=%d / 0x%x\n", ++ idev->port_info->status.xcvr.pid, ++ idev->port_info->status.xcvr.pid); + break; + } + +-- +2.51.0 + diff --git a/queue-5.10/md-raid10-fix-any_working-flag-handling-in-raid10_sy.patch b/queue-5.10/md-raid10-fix-any_working-flag-handling-in-raid10_sy.patch new file mode 100644 index 0000000000..701ee28210 --- /dev/null +++ b/queue-5.10/md-raid10-fix-any_working-flag-handling-in-raid10_sy.patch @@ -0,0 +1,47 @@ +From 2d08c9c2afb5f4f7a2dac69cc9a5178fb9996602 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Jan 2026 19:02:58 +0800 +Subject: md/raid10: fix any_working flag handling in raid10_sync_request + +From: Li Nan + +[ Upstream commit 99582edb3f62e8ee6c34512021368f53f9b091f2 ] + +In raid10_sync_request(), 'any_working' indicates if any IO will +be submitted. When there's only one In_sync disk with badblocks, +'any_working' might be set to 1 but no IO is submitted. Fix it by +setting 'any_working' after badblock checks. + +Link: https://lore.kernel.org/linux-raid/20260105110300.1442509-11-linan666@huaweicloud.com +Fixes: e875ecea266a ("md/raid10 record bad blocks as needed during recovery.") +Signed-off-by: Li Nan +Reviewed-by: Yu Kuai +Signed-off-by: Yu Kuai +Signed-off-by: Sasha Levin +--- + drivers/md/raid10.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c +index 177cfc9f45d0c..94d3e7b27d6bf 100644 +--- a/drivers/md/raid10.c ++++ b/drivers/md/raid10.c +@@ -3148,7 +3148,6 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr, + !test_bit(In_sync, &rdev->flags)) + continue; + /* This is where we read from */ +- any_working = 1; + sector = r10_bio->devs[j].addr; + + if (is_badblock(rdev, sector, max_sync, +@@ -3163,6 +3162,7 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr, + continue; + } + } ++ any_working = 1; + bio = r10_bio->devs[0].bio; + bio->bi_next = biolist; + biolist = bio; +-- +2.51.0 + diff --git a/queue-5.10/mfd-arizona-fix-regulator-resource-leak-on-wm5102_cl.patch b/queue-5.10/mfd-arizona-fix-regulator-resource-leak-on-wm5102_cl.patch new file mode 100644 index 0000000000..f345fa82c5 --- /dev/null +++ b/queue-5.10/mfd-arizona-fix-regulator-resource-leak-on-wm5102_cl.patch @@ -0,0 +1,43 @@ +From 0c356b70ac23dc53b26d7332a7168063769f8adb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 14 Dec 2025 22:58:03 +0800 +Subject: mfd: arizona: Fix regulator resource leak on + wm5102_clear_write_sequencer() failure + +From: Haotian Zhang + +[ Upstream commit 4feb753ba6e5e5bbaba868b841a2db41c21e56fa ] + +The wm5102_clear_write_sequencer() helper may return an error +and just return, bypassing the cleanup sequence and causing +regulators to remain enabled, leading to a resource leak. + +Change the direct return to jump to the err_reset label to +properly free the resources. + +Fixes: 1c1c6bba57f5 ("mfd: wm5102: Ensure we always boot the device fully") +Signed-off-by: Haotian Zhang +Reviewed-by: Charles Keepax +Link: https://patch.msgid.link/20251214145804.2037-1-vulab@iscas.ac.cn +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/mfd/arizona-core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c +index afdc490836255..18f448fa33328 100644 +--- a/drivers/mfd/arizona-core.c ++++ b/drivers/mfd/arizona-core.c +@@ -1150,7 +1150,7 @@ int arizona_dev_init(struct arizona *arizona) + } else if (val & 0x01) { + ret = wm5102_clear_write_sequencer(arizona); + if (ret) +- return ret; ++ goto err_reset; + } + break; + default: +-- +2.51.0 + diff --git a/queue-5.10/mfd-wm8350-core-use-irqf_oneshot.patch b/queue-5.10/mfd-wm8350-core-use-irqf_oneshot.patch new file mode 100644 index 0000000000..a81bcc1656 --- /dev/null +++ b/queue-5.10/mfd-wm8350-core-use-irqf_oneshot.patch @@ -0,0 +1,48 @@ +From a4f0ff10d3e893c8acb445ba221236165fa074de Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:55:35 +0100 +Subject: mfd: wm8350-core: Use IRQF_ONESHOT + +From: Sebastian Andrzej Siewior + +[ Upstream commit 553b4999cbe231b5011cb8db05a3092dec168aca ] + +Using a threaded interrupt without a dedicated primary handler mandates +the IRQF_ONESHOT flag to mask the interrupt source while the threaded +handler is active. Otherwise the interrupt can fire again before the +threaded handler had a chance to run. + +Mark explained that this should not happen with this hardware since it +is a slow irqchip which is behind an I2C/ SPI bus but the IRQ-core will +refuse to accept such a handler. + +Set IRQF_ONESHOT so the interrupt source is masked until the secondary +handler is done. + +Fixes: 1c6c69525b40e ("genirq: Reject bogus threaded irq requests") +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Reviewed-by: Charles Keepax +Reviewed-by: Andy Shevchenko +Link: https://patch.msgid.link/20260128095540.863589-16-bigeasy@linutronix.de +Signed-off-by: Sasha Levin +--- + include/linux/mfd/wm8350/core.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/linux/mfd/wm8350/core.h b/include/linux/mfd/wm8350/core.h +index a3241e4d75486..4816d4f472101 100644 +--- a/include/linux/mfd/wm8350/core.h ++++ b/include/linux/mfd/wm8350/core.h +@@ -663,7 +663,7 @@ static inline int wm8350_register_irq(struct wm8350 *wm8350, int irq, + return -ENODEV; + + return request_threaded_irq(irq + wm8350->irq_base, NULL, +- handler, flags, name, data); ++ handler, flags | IRQF_ONESHOT, name, data); + } + + static inline void wm8350_free_irq(struct wm8350 *wm8350, int irq, void *data) +-- +2.51.0 + diff --git a/queue-5.10/misc-rtsx-add-sd-express-mode-support-for-rts5261.patch b/queue-5.10/misc-rtsx-add-sd-express-mode-support-for-rts5261.patch new file mode 100644 index 0000000000..b4ee8416e9 --- /dev/null +++ b/queue-5.10/misc-rtsx-add-sd-express-mode-support-for-rts5261.patch @@ -0,0 +1,162 @@ +From 8c57b7750518c0a0847d89693b7ec7d6b9ed0a0a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Oct 2020 09:57:48 +0800 +Subject: misc: rtsx: Add SD Express mode support for RTS5261 + +From: Rui Feng + +[ Upstream commit 5afe802132f242f5520d2acac09ea05d31e3c7cf ] + +RTS5261 support SD mode and PCIe/NVMe mode. The workflow is as follows. +1.RTS5261 work in SD mode and set MMC_CAPS2_SD_EXP flag. +2.If card is plugged in, Host send CMD8 to ask card's PCIe availability. +3.If the card has PCIe availability and WP is not set, init_sd_express() will be invoked, +RTS5261 switch to PCIe/NVMe mode. +4.Mmc driver handover it to NVMe driver. +5.If card is unplugged, RTS5261 will switch to SD mode. + +Signed-off-by: Rui Feng +Acked-by: Greg Kroah-Hartman +Link: https://lore.kernel.org/r/1603936668-3363-1-git-send-email-rui_feng@realsil.com.cn +Signed-off-by: Ulf Hansson +Stable-dep-of: aced969e9bf3 ("mmc: rtsx_pci_sdmmc: increase power-on settling delay to 5ms") +Signed-off-by: Sasha Levin +--- + drivers/misc/cardreader/rts5261.c | 4 ++++ + drivers/misc/cardreader/rts5261.h | 23 ----------------------- + drivers/misc/cardreader/rtsx_pcr.c | 5 +++++ + include/linux/rtsx_pci.h | 23 +++++++++++++++++++++++ + 4 files changed, 32 insertions(+), 23 deletions(-) + +diff --git a/drivers/misc/cardreader/rts5261.c b/drivers/misc/cardreader/rts5261.c +index 471961487ff8f..536c90d4fd763 100644 +--- a/drivers/misc/cardreader/rts5261.c ++++ b/drivers/misc/cardreader/rts5261.c +@@ -738,8 +738,12 @@ void rts5261_init_params(struct rtsx_pcr *pcr) + { + struct rtsx_cr_option *option = &pcr->option; + struct rtsx_hw_param *hw_param = &pcr->hw_param; ++ u8 val; + + pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104; ++ rtsx_pci_read_register(pcr, RTS5261_FW_STATUS, &val); ++ if (!(val & RTS5261_EXPRESS_LINK_FAIL_MASK)) ++ pcr->extra_caps |= EXTRA_CAPS_SD_EXPRESS; + pcr->num_slots = 1; + pcr->ops = &rts5261_pcr_ops; + +diff --git a/drivers/misc/cardreader/rts5261.h b/drivers/misc/cardreader/rts5261.h +index ebfdd236a553e..8d80f0d5d5d63 100644 +--- a/drivers/misc/cardreader/rts5261.h ++++ b/drivers/misc/cardreader/rts5261.h +@@ -65,23 +65,6 @@ + #define RTS5261_FW_EXPRESS_TEST_MASK (0x01<<0) + #define RTS5261_FW_EA_MODE_MASK (0x01<<5) + +-/* FW config register */ +-#define RTS5261_FW_CFG0 0xFF54 +-#define RTS5261_FW_ENTER_EXPRESS (0x01<<0) +- +-#define RTS5261_FW_CFG1 0xFF55 +-#define RTS5261_SYS_CLK_SEL_MCU_CLK (0x01<<7) +-#define RTS5261_CRC_CLK_SEL_MCU_CLK (0x01<<6) +-#define RTS5261_FAKE_MCU_CLOCK_GATING (0x01<<5) +-/*MCU_bus_mode_sel: 0=real 8051 1=fake mcu*/ +-#define RTS5261_MCU_BUS_SEL_MASK (0x01<<4) +-/*MCU_clock_sel:VerA 00=aux16M 01=aux400K 1x=REFCLK100M*/ +-/*MCU_clock_sel:VerB 00=aux400K 01=aux16M 10=REFCLK100M*/ +-#define RTS5261_MCU_CLOCK_SEL_MASK (0x03<<2) +-#define RTS5261_MCU_CLOCK_SEL_16M (0x01<<2) +-#define RTS5261_MCU_CLOCK_GATING (0x01<<1) +-#define RTS5261_DRIVER_ENABLE_FW (0x01<<0) +- + /* FW status register */ + #define RTS5261_FW_STATUS 0xFF56 + #define RTS5261_EXPRESS_LINK_FAIL_MASK (0x01<<7) +@@ -121,12 +104,6 @@ + #define RTS5261_DV3318_19 (0x04<<4) + #define RTS5261_DV3318_33 (0x07<<4) + +-#define RTS5261_LDO1_CFG0 0xFF72 +-#define RTS5261_LDO1_OCP_THD_MASK (0x07<<5) +-#define RTS5261_LDO1_OCP_EN (0x01<<4) +-#define RTS5261_LDO1_OCP_LMT_THD_MASK (0x03<<2) +-#define RTS5261_LDO1_OCP_LMT_EN (0x01<<1) +- + /* CRD6603-433 190319 request changed */ + #define RTS5261_LDO1_OCP_THD_740 (0x00<<5) + #define RTS5261_LDO1_OCP_THD_800 (0x01<<5) +diff --git a/drivers/misc/cardreader/rtsx_pcr.c b/drivers/misc/cardreader/rtsx_pcr.c +index 358b000b3a552..4c57ecb2be404 100644 +--- a/drivers/misc/cardreader/rtsx_pcr.c ++++ b/drivers/misc/cardreader/rtsx_pcr.c +@@ -990,6 +990,11 @@ static irqreturn_t rtsx_pci_isr(int irq, void *dev_id) + } else { + pcr->card_removed |= SD_EXIST; + pcr->card_inserted &= ~SD_EXIST; ++ if (PCI_PID(pcr) == PID_5261) { ++ rtsx_pci_write_register(pcr, RTS5261_FW_STATUS, ++ RTS5261_EXPRESS_LINK_FAIL_MASK, 0); ++ pcr->extra_caps |= EXTRA_CAPS_SD_EXPRESS; ++ } + } + pcr->dma_error_count = 0; + } +diff --git a/include/linux/rtsx_pci.h b/include/linux/rtsx_pci.h +index 745f5e73f99ac..b47959f48ccd4 100644 +--- a/include/linux/rtsx_pci.h ++++ b/include/linux/rtsx_pci.h +@@ -658,6 +658,19 @@ + #define PM_WAKE_EN 0x01 + #define PM_CTRL4 0xFF47 + ++#define RTS5261_FW_CFG0 0xFF54 ++#define RTS5261_FW_ENTER_EXPRESS (0x01 << 0) ++ ++#define RTS5261_FW_CFG1 0xFF55 ++#define RTS5261_SYS_CLK_SEL_MCU_CLK (0x01 << 7) ++#define RTS5261_CRC_CLK_SEL_MCU_CLK (0x01 << 6) ++#define RTS5261_FAKE_MCU_CLOCK_GATING (0x01 << 5) ++#define RTS5261_MCU_BUS_SEL_MASK (0x01 << 4) ++#define RTS5261_MCU_CLOCK_SEL_MASK (0x03 << 2) ++#define RTS5261_MCU_CLOCK_SEL_16M (0x01 << 2) ++#define RTS5261_MCU_CLOCK_GATING (0x01 << 1) ++#define RTS5261_DRIVER_ENABLE_FW (0x01 << 0) ++ + #define REG_CFG_OOBS_OFF_TIMER 0xFEA6 + #define REG_CFG_OOBS_ON_TIMER 0xFEA7 + #define REG_CFG_VCM_ON_TIMER 0xFEA8 +@@ -701,6 +714,13 @@ + #define RTS5260_DVCC_TUNE_MASK 0x70 + #define RTS5260_DVCC_33 0x70 + ++/*RTS5261*/ ++#define RTS5261_LDO1_CFG0 0xFF72 ++#define RTS5261_LDO1_OCP_THD_MASK (0x07 << 5) ++#define RTS5261_LDO1_OCP_EN (0x01 << 4) ++#define RTS5261_LDO1_OCP_LMT_THD_MASK (0x03 << 2) ++#define RTS5261_LDO1_OCP_LMT_EN (0x01 << 1) ++ + #define LDO_VCC_CFG1 0xFF73 + #define LDO_VCC_REF_TUNE_MASK 0x30 + #define LDO_VCC_REF_1V2 0x20 +@@ -741,6 +761,8 @@ + + #define RTS5260_AUTOLOAD_CFG4 0xFF7F + #define RTS5260_MIMO_DISABLE 0x8A ++/*RTS5261*/ ++#define RTS5261_AUX_CLK_16M_EN (1 << 5) + + #define RTS5260_REG_GPIO_CTL0 0xFC1A + #define RTS5260_REG_GPIO_MASK 0x01 +@@ -1191,6 +1213,7 @@ struct rtsx_pcr { + #define EXTRA_CAPS_MMC_HS200 (1 << 4) + #define EXTRA_CAPS_MMC_8BIT (1 << 5) + #define EXTRA_CAPS_NO_MMC (1 << 7) ++#define EXTRA_CAPS_SD_EXPRESS (1 << 8) + u32 extra_caps; + + #define IC_VER_A 0 +-- +2.51.0 + diff --git a/queue-5.10/mmc-core-initial-support-for-sd-express-card-host.patch b/queue-5.10/mmc-core-initial-support-for-sd-express-card-host.patch new file mode 100644 index 0000000000..d663749fd4 --- /dev/null +++ b/queue-5.10/mmc-core-initial-support-for-sd-express-card-host.patch @@ -0,0 +1,231 @@ +From 38c3e35116c44a08b6023625f7f887395a0f5d06 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Oct 2020 09:57:16 +0800 +Subject: mmc: core: Initial support for SD express card/host + +From: Ulf Hansson + +[ Upstream commit ead49373d2916080509f51fc6a4ee8f9bc021b9b ] + +In the SD specification v7.10 the SD express card has been added. This new +type of removable SD card, can be managed via a PCIe/NVMe based interface, +while also allowing backwards compatibility towards the legacy SD +interface. + +To keep the backwards compatibility, it's required to start the +initialization through the legacy SD interface. If it turns out that the +mmc host and the SD card, both supports the PCIe/NVMe interface, then a +switch should be allowed. + +Therefore, let's introduce some basic support for this type of SD cards to +the mmc core. The mmc host, should set MMC_CAP2_SD_EXP if it supports this +interface and MMC_CAP2_SD_EXP_1_2V, if also 1.2V is supported, as to inform +the core about it. + +To deal with the switch to the PCIe/NVMe interface, the mmc host is +required to implement a new host ops, ->init_sd_express(). Based on the +initial communication between the host and the card, host->ios.timing is +set to either MMC_TIMING_SD_EXP or MMC_TIMING_SD_EXP_1_2V, depending on if +1.2V is supported or not. In this way, the mmc host can check these values +in its ->init_sd_express() ops, to know how to proceed with the handover. + +Note that, to manage card insert/removal, the mmc core sticks with using +the ->get_cd() callback, which means it's the host's responsibility to make +sure it provides valid data, even if the card may be managed by PCIe/NVMe +at the moment. As long as the card seems to be present, the mmc core keeps +the card powered on. + +Cc: Greg Kroah-Hartman +Cc: Arnd Bergmann +Cc: Christoph Hellwig +Cc: Rui Feng +Signed-off-by: Ulf Hansson +Reviewed-by: Greg Kroah-Hartman +Link: https://lore.kernel.org/r/1603936636-3126-1-git-send-email-rui_feng@realsil.com.cn +Stable-dep-of: aced969e9bf3 ("mmc: rtsx_pci_sdmmc: increase power-on settling delay to 5ms") +Signed-off-by: Sasha Levin +--- + drivers/mmc/core/core.c | 15 ++++++++++-- + drivers/mmc/core/host.h | 6 +++++ + drivers/mmc/core/sd_ops.c | 49 +++++++++++++++++++++++++++++++++++++-- + drivers/mmc/core/sd_ops.h | 1 + + include/linux/mmc/host.h | 7 ++++++ + 5 files changed, 74 insertions(+), 4 deletions(-) + +diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c +index 0f73ee841574a..d8169c8c3f405 100644 +--- a/drivers/mmc/core/core.c ++++ b/drivers/mmc/core/core.c +@@ -2166,8 +2166,12 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) + + mmc_go_idle(host); + +- if (!(host->caps2 & MMC_CAP2_NO_SD)) +- mmc_send_if_cond(host, host->ocr_avail); ++ if (!(host->caps2 & MMC_CAP2_NO_SD)) { ++ if (mmc_send_if_cond_pcie(host, host->ocr_avail)) ++ goto out; ++ if (mmc_card_sd_express(host)) ++ return 0; ++ } + + /* Order's important: probe SDIO, then SD, then MMC */ + if (!(host->caps2 & MMC_CAP2_NO_SDIO)) +@@ -2182,6 +2186,7 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) + if (!mmc_attach_mmc(host)) + return 0; + ++out: + mmc_power_off(host); + return -EIO; + } +@@ -2309,6 +2314,12 @@ void mmc_rescan(struct work_struct *work) + goto out; + } + ++ /* If an SD express card is present, then leave it as is. */ ++ if (mmc_card_sd_express(host)) { ++ mmc_release_host(host); ++ goto out; ++ } ++ + for (i = 0; i < ARRAY_SIZE(freqs); i++) { + unsigned int freq = freqs[i]; + if (freq > host->f_max) { +diff --git a/drivers/mmc/core/host.h b/drivers/mmc/core/host.h +index 5e3b9534ffb23..ba407617ed23a 100644 +--- a/drivers/mmc/core/host.h ++++ b/drivers/mmc/core/host.h +@@ -77,5 +77,11 @@ static inline bool mmc_card_hs400es(struct mmc_card *card) + return card->host->ios.enhanced_strobe; + } + ++static inline bool mmc_card_sd_express(struct mmc_host *host) ++{ ++ return host->ios.timing == MMC_TIMING_SD_EXP || ++ host->ios.timing == MMC_TIMING_SD_EXP_1_2V; ++} ++ + #endif + +diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c +index 22bf528294b90..d61ff811218ce 100644 +--- a/drivers/mmc/core/sd_ops.c ++++ b/drivers/mmc/core/sd_ops.c +@@ -158,7 +158,8 @@ int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) + return err; + } + +-int mmc_send_if_cond(struct mmc_host *host, u32 ocr) ++static int __mmc_send_if_cond(struct mmc_host *host, u32 ocr, u8 pcie_bits, ++ u32 *resp) + { + struct mmc_command cmd = {}; + int err; +@@ -171,7 +172,7 @@ int mmc_send_if_cond(struct mmc_host *host, u32 ocr) + * SD 1.0 cards. + */ + cmd.opcode = SD_SEND_IF_COND; +- cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern; ++ cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | pcie_bits << 8 | test_pattern; + cmd.flags = MMC_RSP_SPI_R7 | MMC_RSP_R7 | MMC_CMD_BCR; + + err = mmc_wait_for_cmd(host, &cmd, 0); +@@ -186,6 +187,50 @@ int mmc_send_if_cond(struct mmc_host *host, u32 ocr) + if (result_pattern != test_pattern) + return -EIO; + ++ if (resp) ++ *resp = cmd.resp[0]; ++ ++ return 0; ++} ++ ++int mmc_send_if_cond(struct mmc_host *host, u32 ocr) ++{ ++ return __mmc_send_if_cond(host, ocr, 0, NULL); ++} ++ ++int mmc_send_if_cond_pcie(struct mmc_host *host, u32 ocr) ++{ ++ u32 resp = 0; ++ u8 pcie_bits = 0; ++ int ret; ++ ++ if (host->caps2 & MMC_CAP2_SD_EXP) { ++ /* Probe card for SD express support via PCIe. */ ++ pcie_bits = 0x10; ++ if (host->caps2 & MMC_CAP2_SD_EXP_1_2V) ++ /* Probe also for 1.2V support. */ ++ pcie_bits = 0x30; ++ } ++ ++ ret = __mmc_send_if_cond(host, ocr, pcie_bits, &resp); ++ if (ret) ++ return 0; ++ ++ /* Continue with the SD express init, if the card supports it. */ ++ resp &= 0x3000; ++ if (pcie_bits && resp) { ++ if (resp == 0x3000) ++ host->ios.timing = MMC_TIMING_SD_EXP_1_2V; ++ else ++ host->ios.timing = MMC_TIMING_SD_EXP; ++ ++ /* ++ * According to the spec the clock shall also be gated, but ++ * let's leave this to the host driver for more flexibility. ++ */ ++ return host->ops->init_sd_express(host, &host->ios); ++ } ++ + return 0; + } + +diff --git a/drivers/mmc/core/sd_ops.h b/drivers/mmc/core/sd_ops.h +index 2194cabfcfc57..3ba7b3cf46520 100644 +--- a/drivers/mmc/core/sd_ops.h ++++ b/drivers/mmc/core/sd_ops.h +@@ -16,6 +16,7 @@ struct mmc_host; + int mmc_app_set_bus_width(struct mmc_card *card, int width); + int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr); + int mmc_send_if_cond(struct mmc_host *host, u32 ocr); ++int mmc_send_if_cond_pcie(struct mmc_host *host, u32 ocr); + int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca); + int mmc_app_send_scr(struct mmc_card *card); + int mmc_sd_switch(struct mmc_card *card, int mode, int group, +diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h +index fb08b86acdbf3..dd3492f377d00 100644 +--- a/include/linux/mmc/host.h ++++ b/include/linux/mmc/host.h +@@ -60,6 +60,8 @@ struct mmc_ios { + #define MMC_TIMING_MMC_DDR52 8 + #define MMC_TIMING_MMC_HS200 9 + #define MMC_TIMING_MMC_HS400 10 ++#define MMC_TIMING_SD_EXP 11 ++#define MMC_TIMING_SD_EXP_1_2V 12 + + unsigned char signal_voltage; /* signalling voltage (1.8V or 3.3V) */ + +@@ -173,6 +175,9 @@ struct mmc_host_ops { + */ + int (*multi_io_quirk)(struct mmc_card *card, + unsigned int direction, int blk_size); ++ ++ /* Initialize an SD express card, mandatory for MMC_CAP2_SD_EXP. */ ++ int (*init_sd_express)(struct mmc_host *host, struct mmc_ios *ios); + }; + + struct mmc_cqe_ops { +@@ -355,6 +360,8 @@ struct mmc_host { + #define MMC_CAP2_HS200_1_2V_SDR (1 << 6) /* can support */ + #define MMC_CAP2_HS200 (MMC_CAP2_HS200_1_8V_SDR | \ + MMC_CAP2_HS200_1_2V_SDR) ++#define MMC_CAP2_SD_EXP (1 << 7) /* SD express via PCIe */ ++#define MMC_CAP2_SD_EXP_1_2V (1 << 8) /* SD express 1.2V */ + #define MMC_CAP2_CD_ACTIVE_HIGH (1 << 10) /* Card-detect signal active high */ + #define MMC_CAP2_RO_ACTIVE_HIGH (1 << 11) /* Write-protect signal active high */ + #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14) /* Don't power up before scan */ +-- +2.51.0 + diff --git a/queue-5.10/mmc-rtsx_pci_sdmmc-increase-power-on-settling-delay-.patch b/queue-5.10/mmc-rtsx_pci_sdmmc-increase-power-on-settling-delay-.patch new file mode 100644 index 0000000000..061fffa89e --- /dev/null +++ b/queue-5.10/mmc-rtsx_pci_sdmmc-increase-power-on-settling-delay-.patch @@ -0,0 +1,40 @@ +From b0514f73f4fed114c7ddc9e33cd6004af70f3fc1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 4 Jan 2026 22:02:36 -0800 +Subject: mmc: rtsx_pci_sdmmc: increase power-on settling delay to 5ms + +From: Matthew Schwartz + +[ Upstream commit aced969e9bf3701dc75cfca57c78c031b7875b9d ] + +The existing 1ms delay in sd_power_on is insufficient and causes resume +errors around 4% of the time. + +Increasing the delay to 5ms resolves this issue after testing 300 +s2idle cycles. + +Fixes: 1f311c94aabd ("mmc: rtsx: add 74 Clocks in power on flow") +Signed-off-by: Matthew Schwartz +Link: https://patch.msgid.link/20260105060236.400366-3-matthew.schwartz@linux.dev +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/mmc/host/rtsx_pci_sdmmc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c +index f0e9a76679945..97f194afcc643 100644 +--- a/drivers/mmc/host/rtsx_pci_sdmmc.c ++++ b/drivers/mmc/host/rtsx_pci_sdmmc.c +@@ -932,7 +932,7 @@ static int sd_power_on(struct realtek_pci_sdmmc *host, unsigned char power_mode) + if (err < 0) + return err; + +- mdelay(1); ++ mdelay(5); + + err = rtsx_pci_write_register(pcr, CARD_OE, SD_OUTPUT_EN, SD_OUTPUT_EN); + if (err < 0) +-- +2.51.0 + diff --git a/queue-5.10/mtd-rawnand-cadence-fix-return-type-of-cdma-send-and.patch b/queue-5.10/mtd-rawnand-cadence-fix-return-type-of-cdma-send-and.patch new file mode 100644 index 0000000000..a08d6f0efd --- /dev/null +++ b/queue-5.10/mtd-rawnand-cadence-fix-return-type-of-cdma-send-and.patch @@ -0,0 +1,40 @@ +From a77173e95404efcca76e3c5e022ee7e6fd42c1b9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 19 Dec 2025 03:09:30 -0800 +Subject: mtd: rawnand: cadence: Fix return type of CDMA send-and-wait helper + +From: Alok Tiwari + +[ Upstream commit 6d8226cbbf124bb5613b532216b74c886a4361b7 ] + +cadence_nand_cdma_send_and_wait() propagates negative errno values +from cadence_nand_cdma_send(), returns -ETIMEDOUT on failure and -EIO +when the CDMA engine reports a command failure. + +However, it is declared as u32, causing error codes to wrap. +Change the return type to int to correctly propagate errors. + +Fixes: ec4ba01e894d ("mtd: rawnand: Add new Cadence NAND driver to MTD subsystem") +Signed-off-by: Alok Tiwari +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/nand/raw/cadence-nand-controller.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/nand/raw/cadence-nand-controller.c b/drivers/mtd/nand/raw/cadence-nand-controller.c +index db565a0edcfd0..544cf5fe946a7 100644 +--- a/drivers/mtd/nand/raw/cadence-nand-controller.c ++++ b/drivers/mtd/nand/raw/cadence-nand-controller.c +@@ -1018,7 +1018,7 @@ static int cadence_nand_cdma_send(struct cdns_nand_ctrl *cdns_ctrl, + } + + /* Send SDMA command and wait for finish. */ +-static u32 ++static int + cadence_nand_cdma_send_and_wait(struct cdns_nand_ctrl *cdns_ctrl, + u8 thread) + { +-- +2.51.0 + diff --git a/queue-5.10/net-atm-fix-crash-due-to-unvalidated-vcc-pointer-in-.patch b/queue-5.10/net-atm-fix-crash-due-to-unvalidated-vcc-pointer-in-.patch new file mode 100644 index 0000000000..94264c9ebd --- /dev/null +++ b/queue-5.10/net-atm-fix-crash-due-to-unvalidated-vcc-pointer-in-.patch @@ -0,0 +1,154 @@ +From 187569509171d0b00363a6b488714615e1abd268 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 17:54:51 +0800 +Subject: net: atm: fix crash due to unvalidated vcc pointer in sigd_send() + +From: Jiayuan Chen + +[ Upstream commit ae88a5d2f29b69819dc7b04086734439d074a643 ] + +Reproducer available at [1]. + +The ATM send path (sendmsg -> vcc_sendmsg -> sigd_send) reads the vcc +pointer from msg->vcc and uses it directly without any validation. This +pointer comes from userspace via sendmsg() and can be arbitrarily forged: + + int fd = socket(AF_ATMSVC, SOCK_DGRAM, 0); + ioctl(fd, ATMSIGD_CTRL); // become ATM signaling daemon + struct msghdr msg = { .msg_iov = &iov, ... }; + *(unsigned long *)(buf + 4) = 0xdeadbeef; // fake vcc pointer + sendmsg(fd, &msg, 0); // kernel dereferences 0xdeadbeef + +In normal operation, the kernel sends the vcc pointer to the signaling +daemon via sigd_enq() when processing operations like connect(), bind(), +or listen(). The daemon is expected to return the same pointer when +responding. However, a malicious daemon can send arbitrary pointer values. + +Fix this by introducing find_get_vcc() which validates the pointer by +searching through vcc_hash (similar to how sigd_close() iterates over +all VCCs), and acquires a reference via sock_hold() if found. + +Since struct atm_vcc embeds struct sock as its first member, they share +the same lifetime. Therefore using sock_hold/sock_put is sufficient to +keep the vcc alive while it is being used. + +Note that there may be a race with sigd_close() which could mark the vcc +with various flags (e.g., ATM_VF_RELEASED) after find_get_vcc() returns. +However, sock_hold() guarantees the memory remains valid, so this race +only affects the logical state, not memory safety. + +[1]: https://gist.github.com/mrpre/1ba5949c45529c511152e2f4c755b0f3 +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: syzbot+1f22cb1769f249df9fa0@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/69039850.a70a0220.5b2ed.005d.GAE@google.com/T/ +Signed-off-by: Jiayuan Chen +Link: https://patch.msgid.link/20260205095501.131890-1-jiayuan.chen@linux.dev +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/atm/signaling.c | 56 +++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 54 insertions(+), 2 deletions(-) + +diff --git a/net/atm/signaling.c b/net/atm/signaling.c +index 5de06ab8ed752..5a5d8b1fa8be8 100644 +--- a/net/atm/signaling.c ++++ b/net/atm/signaling.c +@@ -22,6 +22,36 @@ + + struct atm_vcc *sigd = NULL; + ++/* ++ * find_get_vcc - validate and get a reference to a vcc pointer ++ * @vcc: the vcc pointer to validate ++ * ++ * This function validates that @vcc points to a registered VCC in vcc_hash. ++ * If found, it increments the socket reference count and returns the vcc. ++ * The caller must call sock_put(sk_atm(vcc)) when done. ++ * ++ * Returns the vcc pointer if valid, NULL otherwise. ++ */ ++static struct atm_vcc *find_get_vcc(struct atm_vcc *vcc) ++{ ++ int i; ++ ++ read_lock(&vcc_sklist_lock); ++ for (i = 0; i < VCC_HTABLE_SIZE; i++) { ++ struct sock *s; ++ ++ sk_for_each(s, &vcc_hash[i]) { ++ if (atm_sk(s) == vcc) { ++ sock_hold(s); ++ read_unlock(&vcc_sklist_lock); ++ return vcc; ++ } ++ } ++ } ++ read_unlock(&vcc_sklist_lock); ++ return NULL; ++} ++ + static void sigd_put_skb(struct sk_buff *skb) + { + if (!sigd) { +@@ -69,7 +99,14 @@ static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb) + + msg = (struct atmsvc_msg *) skb->data; + WARN_ON(refcount_sub_and_test(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc)); +- vcc = *(struct atm_vcc **) &msg->vcc; ++ ++ vcc = find_get_vcc(*(struct atm_vcc **)&msg->vcc); ++ if (!vcc) { ++ pr_debug("invalid vcc pointer in msg\n"); ++ dev_kfree_skb(skb); ++ return -EINVAL; ++ } ++ + pr_debug("%d (0x%lx)\n", (int)msg->type, (unsigned long)vcc); + sk = sk_atm(vcc); + +@@ -100,7 +137,16 @@ static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb) + clear_bit(ATM_VF_WAITING, &vcc->flags); + break; + case as_indicate: +- vcc = *(struct atm_vcc **)&msg->listen_vcc; ++ /* Release the reference from msg->vcc, we'll use msg->listen_vcc instead */ ++ sock_put(sk); ++ ++ vcc = find_get_vcc(*(struct atm_vcc **)&msg->listen_vcc); ++ if (!vcc) { ++ pr_debug("invalid listen_vcc pointer in msg\n"); ++ dev_kfree_skb(skb); ++ return -EINVAL; ++ } ++ + sk = sk_atm(vcc); + pr_debug("as_indicate!!!\n"); + lock_sock(sk); +@@ -115,6 +161,8 @@ static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb) + sk->sk_state_change(sk); + as_indicate_complete: + release_sock(sk); ++ /* Paired with find_get_vcc(msg->listen_vcc) above */ ++ sock_put(sk); + return 0; + case as_close: + set_bit(ATM_VF_RELEASED, &vcc->flags); +@@ -131,11 +179,15 @@ static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb) + break; + default: + pr_alert("bad message type %d\n", (int)msg->type); ++ /* Paired with find_get_vcc(msg->vcc) above */ ++ sock_put(sk); + return -EINVAL; + } + sk->sk_state_change(sk); + out: + dev_kfree_skb(skb); ++ /* Paired with find_get_vcc(msg->vcc) above */ ++ sock_put(sk); + return 0; + } + +-- +2.51.0 + diff --git a/queue-5.10/netfilter-nf_conncount-fix-tracking-of-connections-f.patch b/queue-5.10/netfilter-nf_conncount-fix-tracking-of-connections-f.patch new file mode 100644 index 0000000000..5fe907727f --- /dev/null +++ b/queue-5.10/netfilter-nf_conncount-fix-tracking-of-connections-f.patch @@ -0,0 +1,69 @@ +From 37703636e8dbc11a4948ee789600c860ac0ebfe3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 21:35:46 +0100 +Subject: netfilter: nf_conncount: fix tracking of connections from localhost + +From: Fernando Fernandez Mancera + +[ Upstream commit de8a70cefcb26cdceaafdc5ac144712681419c29 ] + +Since commit be102eb6a0e7 ("netfilter: nf_conncount: rework API to use +sk_buff directly"), we skip the adding and trigger a GC when the ct is +confirmed. For connections originated from local to local it doesn't +work because the connection is confirmed on POSTROUTING, therefore +tracking on the INPUT hook is always skipped. + +In order to fix this, we check whether skb input ifindex is set to +loopback ifindex. If it is then we fallback on a GC plus track operation +skipping the optimization. This fallback is necessary to avoid +duplicated tracking of a packet train e.g 10 UDP datagrams sent on a +burst when initiating the connection. + +Tested with xt_connlimit/nft_connlimit and OVS limit and with a HTTP +server and iperf3 on UDP mode. + +Fixes: be102eb6a0e7 ("netfilter: nf_conncount: rework API to use sk_buff directly") +Reported-by: Michal Slabihoudek +Closes: https://lore.kernel.org/netfilter/6989BD9F-8C24-4397-9AD7-4613B28BF0DB@gooddata.com/ +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_conncount.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +diff --git a/net/netfilter/nf_conncount.c b/net/netfilter/nf_conncount.c +index 47bdd8d121bb5..ae9ad439449fa 100644 +--- a/net/netfilter/nf_conncount.c ++++ b/net/netfilter/nf_conncount.c +@@ -179,14 +179,25 @@ static int __nf_conncount_add(struct net *net, + return -ENOENT; + + if (ct && nf_ct_is_confirmed(ct)) { +- err = -EEXIST; +- goto out_put; ++ /* local connections are confirmed in postrouting so confirmation ++ * might have happened before hitting connlimit ++ */ ++ if (skb->skb_iif != LOOPBACK_IFINDEX) { ++ err = -EEXIST; ++ goto out_put; ++ } ++ ++ /* this is likely a local connection, skip optimization to avoid ++ * adding duplicates from a 'packet train' ++ */ ++ goto check_connections; + } + + if ((u32)jiffies == list->last_gc && + (list->count - list->last_gc_count) < CONNCOUNT_GC_MAX_COLLECT) + goto add_new_node; + ++check_connections: + /* check the saved connections */ + list_for_each_entry_safe(conn, conn_n, &list->head, node) { + if (collect > CONNCOUNT_GC_MAX_COLLECT) +-- +2.51.0 + diff --git a/queue-5.10/netfilter-nf_conncount-increase-the-connection-clean.patch b/queue-5.10/netfilter-nf_conncount-increase-the-connection-clean.patch new file mode 100644 index 0000000000..a765313351 --- /dev/null +++ b/queue-5.10/netfilter-nf_conncount-increase-the-connection-clean.patch @@ -0,0 +1,123 @@ +From 5c3f1dabfee6520a732f0b114146700bf1062fcf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 17 Dec 2025 15:46:41 +0100 +Subject: netfilter: nf_conncount: increase the connection clean up limit to 64 + +From: Fernando Fernandez Mancera + +[ Upstream commit 21d033e472735ecec677f1ae46d6740b5e47a4f3 ] + +After the optimization to only perform one GC per jiffy, a new problem +was introduced. If more than 8 new connections are tracked per jiffy the +list won't be cleaned up fast enough possibly reaching the limit +wrongly. + +In order to prevent this issue, only skip the GC if it was already +triggered during the same jiffy and the increment is lower than the +clean up limit. In addition, increase the clean up limit to 64 +connections to avoid triggering GC too often and do more effective GCs. + +This has been tested using a HTTP server and several +performance tools while having nft_connlimit/xt_connlimit or OVS limit +configured. + +Output of slowhttptest + OVS limit at 52000 connections: + + slow HTTP test status on 340th second: + initializing: 0 + pending: 432 + connected: 51998 + error: 0 + closed: 0 + service available: YES + +Fixes: d265929930e2 ("netfilter: nf_conncount: reduce unnecessary GC") +Reported-by: Aleksandra Rukomoinikova +Closes: https://lore.kernel.org/netfilter/b2064e7b-0776-4e14-adb6-c68080987471@k2.cloud/ +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + include/net/netfilter/nf_conntrack_count.h | 1 + + net/netfilter/nf_conncount.c | 15 ++++++++++----- + 2 files changed, 11 insertions(+), 5 deletions(-) + +diff --git a/include/net/netfilter/nf_conntrack_count.h b/include/net/netfilter/nf_conntrack_count.h +index 115bb7e572f7d..bf22661925b81 100644 +--- a/include/net/netfilter/nf_conntrack_count.h ++++ b/include/net/netfilter/nf_conntrack_count.h +@@ -13,6 +13,7 @@ struct nf_conncount_list { + u32 last_gc; /* jiffies at most recent gc */ + struct list_head head; /* connections with the same filtering key */ + unsigned int count; /* length of list */ ++ unsigned int last_gc_count; /* length of list at most recent gc */ + }; + + struct nf_conncount_data *nf_conncount_init(struct net *net, unsigned int family, +diff --git a/net/netfilter/nf_conncount.c b/net/netfilter/nf_conncount.c +index 70e9662fe1777..47bdd8d121bb5 100644 +--- a/net/netfilter/nf_conncount.c ++++ b/net/netfilter/nf_conncount.c +@@ -34,8 +34,9 @@ + + #define CONNCOUNT_SLOTS 256U + +-#define CONNCOUNT_GC_MAX_NODES 8 +-#define MAX_KEYLEN 5 ++#define CONNCOUNT_GC_MAX_NODES 8 ++#define CONNCOUNT_GC_MAX_COLLECT 64 ++#define MAX_KEYLEN 5 + + /* we will save the tuples of all connections we care about */ + struct nf_conncount_tuple { +@@ -182,12 +183,13 @@ static int __nf_conncount_add(struct net *net, + goto out_put; + } + +- if ((u32)jiffies == list->last_gc) ++ if ((u32)jiffies == list->last_gc && ++ (list->count - list->last_gc_count) < CONNCOUNT_GC_MAX_COLLECT) + goto add_new_node; + + /* check the saved connections */ + list_for_each_entry_safe(conn, conn_n, &list->head, node) { +- if (collect > CONNCOUNT_GC_MAX_NODES) ++ if (collect > CONNCOUNT_GC_MAX_COLLECT) + break; + + found = find_or_evict(net, list, conn); +@@ -230,6 +232,7 @@ static int __nf_conncount_add(struct net *net, + nf_ct_put(found_ct); + } + list->last_gc = (u32)jiffies; ++ list->last_gc_count = list->count; + + add_new_node: + if (WARN_ON_ONCE(list->count > INT_MAX)) { +@@ -277,6 +280,7 @@ void nf_conncount_list_init(struct nf_conncount_list *list) + spin_lock_init(&list->list_lock); + INIT_LIST_HEAD(&list->head); + list->count = 0; ++ list->last_gc_count = 0; + list->last_gc = (u32)jiffies; + } + EXPORT_SYMBOL_GPL(nf_conncount_list_init); +@@ -316,13 +320,14 @@ static bool __nf_conncount_gc_list(struct net *net, + } + + nf_ct_put(found_ct); +- if (collected > CONNCOUNT_GC_MAX_NODES) ++ if (collected > CONNCOUNT_GC_MAX_COLLECT) + break; + } + + if (!list->count) + ret = true; + list->last_gc = (u32)jiffies; ++ list->last_gc_count = list->count; + + return ret; + } +-- +2.51.0 + diff --git a/queue-5.10/netfilter-nf_conncount-make-nf_conncount_gc_list-to-.patch b/queue-5.10/netfilter-nf_conncount-make-nf_conncount_gc_list-to-.patch new file mode 100644 index 0000000000..d8cd665c4d --- /dev/null +++ b/queue-5.10/netfilter-nf_conncount-make-nf_conncount_gc_list-to-.patch @@ -0,0 +1,93 @@ +From 5e0028c5f1ffe0a36d92d4c0c7cfb8a6486575d3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 21 Nov 2025 01:14:31 +0100 +Subject: netfilter: nf_conncount: make nf_conncount_gc_list() to disable BH + +From: Fernando Fernandez Mancera + +[ Upstream commit c0362b5748282e22fa1592a8d3474f726ad964c2 ] + +For convenience when performing GC over the connection list, make +nf_conncount_gc_list() to disable BH. This unifies the behavior with +nf_conncount_add() and nf_conncount_count(). + +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: 21d033e47273 ("netfilter: nf_conncount: increase the connection clean up limit to 64") +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_conncount.c | 24 +++++++++++++++++------- + net/netfilter/nft_connlimit.c | 7 +------ + 2 files changed, 18 insertions(+), 13 deletions(-) + +diff --git a/net/netfilter/nf_conncount.c b/net/netfilter/nf_conncount.c +index a2c5a7ba0c6fc..70e9662fe1777 100644 +--- a/net/netfilter/nf_conncount.c ++++ b/net/netfilter/nf_conncount.c +@@ -282,8 +282,8 @@ void nf_conncount_list_init(struct nf_conncount_list *list) + EXPORT_SYMBOL_GPL(nf_conncount_list_init); + + /* Return true if the list is empty. Must be called with BH disabled. */ +-bool nf_conncount_gc_list(struct net *net, +- struct nf_conncount_list *list) ++static bool __nf_conncount_gc_list(struct net *net, ++ struct nf_conncount_list *list) + { + const struct nf_conntrack_tuple_hash *found; + struct nf_conncount_tuple *conn, *conn_n; +@@ -295,10 +295,6 @@ bool nf_conncount_gc_list(struct net *net, + if ((u32)jiffies == READ_ONCE(list->last_gc)) + return false; + +- /* don't bother if other cpu is already doing GC */ +- if (!spin_trylock(&list->list_lock)) +- return false; +- + list_for_each_entry_safe(conn, conn_n, &list->head, node) { + found = find_or_evict(net, list, conn); + if (IS_ERR(found)) { +@@ -327,7 +323,21 @@ bool nf_conncount_gc_list(struct net *net, + if (!list->count) + ret = true; + list->last_gc = (u32)jiffies; +- spin_unlock(&list->list_lock); ++ ++ return ret; ++} ++ ++bool nf_conncount_gc_list(struct net *net, ++ struct nf_conncount_list *list) ++{ ++ bool ret; ++ ++ /* don't bother if other cpu is already doing GC */ ++ if (!spin_trylock_bh(&list->list_lock)) ++ return false; ++ ++ ret = __nf_conncount_gc_list(net, list); ++ spin_unlock_bh(&list->list_lock); + + return ret; + } +diff --git a/net/netfilter/nft_connlimit.c b/net/netfilter/nft_connlimit.c +index 548dd5adbe971..a2bf79bf3a893 100644 +--- a/net/netfilter/nft_connlimit.c ++++ b/net/netfilter/nft_connlimit.c +@@ -231,13 +231,8 @@ static void nft_connlimit_destroy_clone(const struct nft_ctx *ctx, + static bool nft_connlimit_gc(struct net *net, const struct nft_expr *expr) + { + struct nft_connlimit *priv = nft_expr_priv(expr); +- bool ret; + +- local_bh_disable(); +- ret = nf_conncount_gc_list(net, priv->list); +- local_bh_enable(); +- +- return ret; ++ return nf_conncount_gc_list(net, priv->list); + } + + static struct nft_expr_type nft_connlimit_type; +-- +2.51.0 + diff --git a/queue-5.10/netfilter-nft_set_hash-fix-get-operation-on-big-endi.patch b/queue-5.10/netfilter-nft_set_hash-fix-get-operation-on-big-endi.patch new file mode 100644 index 0000000000..f99948206d --- /dev/null +++ b/queue-5.10/netfilter-nft_set_hash-fix-get-operation-on-big-endi.patch @@ -0,0 +1,57 @@ +From 68ed805924bcb2051afe67d69899a1165fb47b8a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 20:13:45 +0100 +Subject: netfilter: nft_set_hash: fix get operation on big endian + +From: Florian Westphal + +[ Upstream commit 2f635adbe2642d398a0be3ab245accd2987be0c3 ] + +tests/shell/testcases/packetpath/set_match_nomatch_hash_fast +fails on big endian with: + +Error: Could not process rule: No such file or directory +reset element ip test s { 244.147.90.126 } +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Fatal: Cannot fetch element "244.147.90.126" + +... because the wrong bucket is searched, jhash() and jhash1_word are +not interchangeable on big endian. + +Fixes: 3b02b0adc242 ("netfilter: nft_set_hash: fix lookups with fixed size hash on big endian") +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_set_hash.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/net/netfilter/nft_set_hash.c b/net/netfilter/nft_set_hash.c +index 8656cb61dd211..3a0d3fd4e42cd 100644 +--- a/net/netfilter/nft_set_hash.c ++++ b/net/netfilter/nft_set_hash.c +@@ -511,15 +511,20 @@ static bool nft_hash_lookup(const struct net *net, const struct nft_set *set, + static void *nft_hash_get(const struct net *net, const struct nft_set *set, + const struct nft_set_elem *elem, unsigned int flags) + { ++ const u32 *key = (const u32 *)&elem->key.val; + struct nft_hash *priv = nft_set_priv(set); + u8 genmask = nft_genmask_cur(net); + struct nft_hash_elem *he; + u32 hash; + +- hash = jhash(elem->key.val.data, set->klen, priv->seed); ++ if (set->klen == 4) ++ hash = jhash_1word(*key, priv->seed); ++ else ++ hash = jhash(key, set->klen, priv->seed); ++ + hash = reciprocal_scale(hash, priv->buckets); + hlist_for_each_entry_rcu(he, &priv->table[hash], node) { +- if (!memcmp(nft_set_ext_key(&he->ext), elem->key.val.data, set->klen) && ++ if (!memcmp(nft_set_ext_key(&he->ext), key, set->klen) && + nft_set_elem_active(&he->ext, genmask)) + return he; + } +-- +2.51.0 + diff --git a/queue-5.10/netfilter-nft_set_rbtree-check-for-partial-overlaps-.patch b/queue-5.10/netfilter-nft_set_rbtree-check-for-partial-overlaps-.patch new file mode 100644 index 0000000000..54f1ae9e01 --- /dev/null +++ b/queue-5.10/netfilter-nft_set_rbtree-check-for-partial-overlaps-.patch @@ -0,0 +1,90 @@ +From 33e3c64aa714511bd98463b2c9f252011ccc73a1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 13:33:44 +0100 +Subject: netfilter: nft_set_rbtree: check for partial overlaps in anonymous + sets + +From: Pablo Neira Ayuso + +[ Upstream commit 4780ec142cbb24b794129d3080eee5cac2943ffc ] + +Userspace provides an optimized representation in case intervals are +adjacent, where the end element is omitted. + +The existing partial overlap detection logic skips anonymous set checks +on start elements for this reason. + +However, it is possible to add intervals that overlap to this anonymous +where two start elements with the same, eg. A-B, A-C where C < B. + + start end + A B + start end + A C + +Restore the check on overlapping start elements to report an overlap. + +Fixes: c9e6978e2725 ("netfilter: nft_set_rbtree: Switch to node list walk for overlap detection") +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_set_rbtree.c | 30 +++++++++++++++++++++++++----- + 1 file changed, 25 insertions(+), 5 deletions(-) + +diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c +index bbced30113e4e..e3cd66260c2d6 100644 +--- a/net/netfilter/nft_set_rbtree.c ++++ b/net/netfilter/nft_set_rbtree.c +@@ -307,11 +307,23 @@ static bool nft_rbtree_update_first(const struct nft_set *set, + return false; + } + ++/* Only for anonymous sets which do not allow updates, all element are active. */ ++static struct nft_rbtree_elem *nft_rbtree_prev_active(struct nft_rbtree_elem *rbe) ++{ ++ struct rb_node *node; ++ ++ node = rb_prev(&rbe->node); ++ if (!node) ++ return NULL; ++ ++ return rb_entry(node, struct nft_rbtree_elem, node); ++} ++ + static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set, + struct nft_rbtree_elem *new, + struct nft_set_ext **ext) + { +- struct nft_rbtree_elem *rbe, *rbe_le = NULL, *rbe_ge = NULL; ++ struct nft_rbtree_elem *rbe, *rbe_le = NULL, *rbe_ge = NULL, *rbe_prev; + struct rb_node *node, *next, *parent, **p, *first = NULL; + struct nft_rbtree *priv = nft_set_priv(set); + u8 cur_genmask = nft_genmask_cur(net); +@@ -443,11 +455,19 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set, + /* - new start element with existing closest, less or equal key value + * being a start element: partial overlap, reported as -ENOTEMPTY. + * Anonymous sets allow for two consecutive start element since they +- * are constant, skip them to avoid bogus overlap reports. ++ * are constant, but validate that this new start element does not ++ * sit in between an existing start and end elements: partial overlap, ++ * reported as -ENOTEMPTY. + */ +- if (!nft_set_is_anonymous(set) && rbe_le && +- nft_rbtree_interval_start(rbe_le) && nft_rbtree_interval_start(new)) +- return -ENOTEMPTY; ++ if (rbe_le && ++ nft_rbtree_interval_start(rbe_le) && nft_rbtree_interval_start(new)) { ++ if (!nft_set_is_anonymous(set)) ++ return -ENOTEMPTY; ++ ++ rbe_prev = nft_rbtree_prev_active(rbe_le); ++ if (rbe_prev && nft_rbtree_interval_end(rbe_prev)) ++ return -ENOTEMPTY; ++ } + + /* - new end element with existing closest, less or equal key value + * being a end element: partial overlap, reported as -ENOTEMPTY. +-- +2.51.0 + diff --git a/queue-5.10/nfsd-never-defer-requests-during-idmap-lookup.patch b/queue-5.10/nfsd-never-defer-requests-during-idmap-lookup.patch new file mode 100644 index 0000000000..25e972917c --- /dev/null +++ b/queue-5.10/nfsd-never-defer-requests-during-idmap-lookup.patch @@ -0,0 +1,152 @@ +From f94e7881608bfdfd5013951e1ce59afcb491c91d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 22 Dec 2025 14:30:04 -0500 +Subject: nfsd: never defer requests during idmap lookup + +From: Anthony Iliopoulos + +[ Upstream commit f9c206cdc4266caad6a9a7f46341420a10f03ccb ] + +During v4 request compound arg decoding, some ops (e.g. SETATTR) +can trigger idmap lookup upcalls. When those upcall responses get +delayed beyond the allowed time limit, cache_check() will mark the +request for deferral and cause it to be dropped. + +This prevents nfs4svc_encode_compoundres from being executed, and +thus the session slot flag NFSD4_SLOT_INUSE never gets cleared. +Subsequent client requests will fail with NFSERR_JUKEBOX, given +that the slot will be marked as in-use, making the SEQUENCE op +fail. + +Fix this by making sure that the RQ_USEDEFERRAL flag is always +clear during nfs4svc_decode_compoundargs(), since no v4 request +should ever be deferred. + +Fixes: 2f425878b6a7 ("nfsd: don't use the deferral service, return NFS4ERR_DELAY") +Signed-off-by: Anthony Iliopoulos +Reviewed-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4idmap.c | 48 +++++++++++++++++++++++++++++++++++++++------ + fs/nfsd/nfs4proc.c | 2 -- + fs/nfsd/nfs4xdr.c | 16 +++++++++++++++ + 3 files changed, 58 insertions(+), 8 deletions(-) + +diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c +index 717e400b16b86..21e5b4c990ef3 100644 +--- a/fs/nfsd/nfs4idmap.c ++++ b/fs/nfsd/nfs4idmap.c +@@ -643,13 +643,31 @@ static __be32 encode_name_from_id(struct xdr_stream *xdr, + return idmap_id_to_name(xdr, rqstp, type, id); + } + +-__be32 +-nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen, +- kuid_t *uid) ++/** ++ * nfsd_map_name_to_uid - Map user@domain to local UID ++ * @rqstp: RPC execution context ++ * @name: user@domain name to be mapped ++ * @namelen: length of name, in bytes ++ * @uid: OUT: mapped local UID value ++ * ++ * Returns nfs_ok on success or an NFSv4 status code on failure. ++ */ ++__be32 nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, ++ size_t namelen, kuid_t *uid) + { + __be32 status; + u32 id = -1; + ++ /* ++ * The idmap lookup below triggers an upcall that invokes ++ * cache_check(). RQ_USEDEFERRAL must be clear to prevent ++ * cache_check() from setting RQ_DROPME via svc_defer(). ++ * NFSv4 servers are not permitted to drop requests. Also ++ * RQ_DROPME will force NFSv4.1 session slot processing to ++ * be skipped. ++ */ ++ WARN_ON_ONCE(test_bit(RQ_USEDEFERRAL, &rqstp->rq_flags)); ++ + if (name == NULL || namelen == 0) + return nfserr_inval; + +@@ -660,13 +678,31 @@ nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen, + return status; + } + +-__be32 +-nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, size_t namelen, +- kgid_t *gid) ++/** ++ * nfsd_map_name_to_gid - Map user@domain to local GID ++ * @rqstp: RPC execution context ++ * @name: user@domain name to be mapped ++ * @namelen: length of name, in bytes ++ * @gid: OUT: mapped local GID value ++ * ++ * Returns nfs_ok on success or an NFSv4 status code on failure. ++ */ ++__be32 nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, ++ size_t namelen, kgid_t *gid) + { + __be32 status; + u32 id = -1; + ++ /* ++ * The idmap lookup below triggers an upcall that invokes ++ * cache_check(). RQ_USEDEFERRAL must be clear to prevent ++ * cache_check() from setting RQ_DROPME via svc_defer(). ++ * NFSv4 servers are not permitted to drop requests. Also ++ * RQ_DROPME will force NFSv4.1 session slot processing to ++ * be skipped. ++ */ ++ WARN_ON_ONCE(test_bit(RQ_USEDEFERRAL, &rqstp->rq_flags)); ++ + if (name == NULL || namelen == 0) + return nfserr_inval; + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index ffd79abd99ea7..a4c7cab1679bd 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -2717,8 +2717,6 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) + BUG_ON(cstate->replay_owner); + out: + cstate->status = status; +- /* Reset deferral mechanism for RPC deferrals */ +- set_bit(RQ_USEDEFERRAL, &rqstp->rq_flags); + return rpc_success; + } + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 4253778a97477..7022ae52b1f20 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -5499,6 +5499,22 @@ nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + args->ops = args->iops; + args->rqstp = rqstp; + ++ /* ++ * NFSv4 operation decoders can invoke svc cache lookups ++ * that trigger svc_defer() when RQ_USEDEFERRAL is set, ++ * setting RQ_DROPME. This creates two problems: ++ * ++ * 1. Non-idempotency: Compounds make it too hard to avoid ++ * problems if a request is deferred and replayed. ++ * ++ * 2. Session slot leakage (NFSv4.1+): If RQ_DROPME is set ++ * during decode but SEQUENCE executes successfully, the ++ * session slot will be marked INUSE. The request is then ++ * dropped before encoding, so the slot is never released, ++ * rendering it permanently unusable by the client. ++ */ ++ clear_bit(RQ_USEDEFERRAL, &rqstp->rq_flags); ++ + return nfsd4_decode_compound(args); + } + +-- +2.51.0 + diff --git a/queue-5.10/nvdimm-virtio_pmem-serialize-flush-requests.patch b/queue-5.10/nvdimm-virtio_pmem-serialize-flush-requests.patch new file mode 100644 index 0000000000..a3b8c15fda --- /dev/null +++ b/queue-5.10/nvdimm-virtio_pmem-serialize-flush-requests.patch @@ -0,0 +1,98 @@ +From 9efcb76e57894e0ce6e1a0e43d128d29337033ba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 10:13:51 +0800 +Subject: nvdimm: virtio_pmem: serialize flush requests + +From: Li Chen + +[ Upstream commit a9ba6733c7f1096c4506bf4e34a546e07242df74 ] + +Under heavy concurrent flush traffic, virtio-pmem can overflow its request +virtqueue (req_vq): virtqueue_add_sgs() starts returning -ENOSPC and the +driver logs "no free slots in the virtqueue". Shortly after that the +device enters VIRTIO_CONFIG_S_NEEDS_RESET and flush requests fail with +"virtio pmem device needs a reset". + +Serialize virtio_pmem_flush() with a per-device mutex so only one flush +request is in-flight at a time. This prevents req_vq descriptor overflow +under high concurrency. + +Reproducer (guest with virtio-pmem): + - mkfs.ext4 -F /dev/pmem0 + - mount -t ext4 -o dax,noatime /dev/pmem0 /mnt/bench + - fio: ioengine=io_uring rw=randwrite bs=4k iodepth=64 numjobs=64 + direct=1 fsync=1 runtime=30s time_based=1 + - dmesg: "no free slots in the virtqueue" + "virtio pmem device needs a reset" + +Fixes: 6e84200c0a29 ("virtio-pmem: Add virtio pmem driver") +Signed-off-by: Li Chen +Acked-by: Pankaj Gupta +Acked-by: Michael S. Tsirkin +Link: https://patch.msgid.link/20260203021353.121091-1-me@linux.beauty +Signed-off-by: Ira Weiny +Signed-off-by: Sasha Levin +--- + drivers/nvdimm/nd_virtio.c | 3 ++- + drivers/nvdimm/virtio_pmem.c | 1 + + drivers/nvdimm/virtio_pmem.h | 4 ++++ + 3 files changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/nvdimm/nd_virtio.c b/drivers/nvdimm/nd_virtio.c +index 41e97c6567cf9..204d1a05f8e32 100644 +--- a/drivers/nvdimm/nd_virtio.c ++++ b/drivers/nvdimm/nd_virtio.c +@@ -44,6 +44,8 @@ static int virtio_pmem_flush(struct nd_region *nd_region) + unsigned long flags; + int err, err1; + ++ guard(mutex)(&vpmem->flush_lock); ++ + /* + * Don't bother to submit the request to the device if the device is + * not activated. +@@ -53,7 +55,6 @@ static int virtio_pmem_flush(struct nd_region *nd_region) + return -EIO; + } + +- might_sleep(); + req_data = kmalloc(sizeof(*req_data), GFP_KERNEL); + if (!req_data) + return -ENOMEM; +diff --git a/drivers/nvdimm/virtio_pmem.c b/drivers/nvdimm/virtio_pmem.c +index 726c7354d4659..23ce47b67df50 100644 +--- a/drivers/nvdimm/virtio_pmem.c ++++ b/drivers/nvdimm/virtio_pmem.c +@@ -50,6 +50,7 @@ static int virtio_pmem_probe(struct virtio_device *vdev) + goto out_err; + } + ++ mutex_init(&vpmem->flush_lock); + vpmem->vdev = vdev; + vdev->priv = vpmem; + err = init_vq(vpmem); +diff --git a/drivers/nvdimm/virtio_pmem.h b/drivers/nvdimm/virtio_pmem.h +index 0dddefe594c46..f72cf17f9518f 100644 +--- a/drivers/nvdimm/virtio_pmem.h ++++ b/drivers/nvdimm/virtio_pmem.h +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + #include + + struct virtio_pmem_request { +@@ -35,6 +36,9 @@ struct virtio_pmem { + /* Virtio pmem request queue */ + struct virtqueue *req_vq; + ++ /* Serialize flush requests to the device. */ ++ struct mutex flush_lock; ++ + /* nvdimm bus registers virtio pmem device */ + struct nvdimm_bus *nvdimm_bus; + struct nvdimm_bus_descriptor nd_desc; +-- +2.51.0 + diff --git a/queue-5.10/octeontx2-af-fix-pf-driver-crash-with-kexec-kernel-b.patch b/queue-5.10/octeontx2-af-fix-pf-driver-crash-with-kexec-kernel-b.patch new file mode 100644 index 0000000000..126c88e74f --- /dev/null +++ b/queue-5.10/octeontx2-af-fix-pf-driver-crash-with-kexec-kernel-b.patch @@ -0,0 +1,62 @@ +From 581a963e2ccdbc27a02d324b1b20f43c340082ee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 10:37:01 +0530 +Subject: octeontx2-af: Fix PF driver crash with kexec kernel booting + +From: Anshumali Gaur + +[ Upstream commit 2d2d574309e3ae84ee794869a5da8b4c38753a94 ] + +During a kexec reboot the hardware is not power-cycled, so AF state from +the old kernel can persist into the new kernel. When AF and PF drivers +are built as modules, the PF driver may probe before AF reinitializes +the hardware. + +The PF driver treats the RVUM block revision as an indication that AF +initialization is complete. If this value is left uncleared at shutdown, +PF may incorrectly assume AF is ready and access stale hardware state, +leading to a crash. + +Clear the RVUM block revision during AF shutdown to avoid PF +mis-detecting AF readiness after kexec. + +Fixes: 54494aa5d1e6 ("octeontx2-af: Add Marvell OcteonTX2 RVU AF driver") +Signed-off-by: Anshumali Gaur +Reviewed-by: Jacob Keller +Link: https://patch.msgid.link/20260203050701.2616685-1-agaur@marvell.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/octeontx2/af/rvu.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +index 3514564e2cc60..217b6873a64c6 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +@@ -2880,11 +2880,22 @@ static void rvu_remove(struct pci_dev *pdev) + devm_kfree(&pdev->dev, rvu); + } + ++static void rvu_shutdown(struct pci_dev *pdev) ++{ ++ struct rvu *rvu = pci_get_drvdata(pdev); ++ ++ if (!rvu) ++ return; ++ ++ rvu_clear_rvum_blk_revid(rvu); ++} ++ + static struct pci_driver rvu_driver = { + .name = DRV_NAME, + .id_table = rvu_id_table, + .probe = rvu_probe, + .remove = rvu_remove, ++ .shutdown = rvu_shutdown, + }; + + static int __init rvu_init_module(void) +-- +2.51.0 + diff --git a/queue-5.10/ovl-fix-uninit-value-in-ovl_fill_real.patch b/queue-5.10/ovl-fix-uninit-value-in-ovl_fill_real.patch new file mode 100644 index 0000000000..7407387863 --- /dev/null +++ b/queue-5.10/ovl-fix-uninit-value-in-ovl_fill_real.patch @@ -0,0 +1,58 @@ +From 2792a1e4c766dd1e9eefc7fd74bf829ca0a01efc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 14:24:04 +0100 +Subject: ovl: Fix uninit-value in ovl_fill_real + +From: Qing Wang + +[ Upstream commit 1992330d90dd766fcf1730fd7bf2d6af65370ac4 ] + +Syzbot reported a KMSAN uninit-value issue in ovl_fill_real. + +This iusse's call chain is: +__do_sys_getdents64() + -> iterate_dir() + ... + -> ext4_readdir() + -> fscrypt_fname_alloc_buffer() // alloc + -> fscrypt_fname_disk_to_usr // write without tail '\0' + -> dir_emit() + -> ovl_fill_real() // read by strcmp() + +The string is used to store the decrypted directory entry name for an +encrypted inode. As shown in the call chain, fscrypt_fname_disk_to_usr() +write it without null-terminate. However, ovl_fill_real() uses strcmp() to +compare the name against "..", which assumes a null-terminated string and +may trigger a KMSAN uninit-value warning when the buffer tail contains +uninit data. + +Reported-by: syzbot+d130f98b2c265fae5297@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=d130f98b2c265fae5297 +Fixes: 4edb83bb1041 ("ovl: constant d_ino for non-merge dirs") +Signed-off-by: Qing Wang +Signed-off-by: Amir Goldstein +Link: https://patch.msgid.link/20260128132406.23768-2-amir73il@gmail.com +Acked-by: Miklos Szeredi +Reviewed-by: Eric Biggers +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/overlayfs/readdir.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c +index cc1e802570644..09a5542723787 100644 +--- a/fs/overlayfs/readdir.c ++++ b/fs/overlayfs/readdir.c +@@ -654,7 +654,7 @@ static int ovl_fill_real(struct dir_context *ctx, const char *name, + container_of(ctx, struct ovl_readdir_translate, ctx); + struct dir_context *orig_ctx = rdt->orig_ctx; + +- if (rdt->parent_ino && strcmp(name, "..") == 0) { ++ if (rdt->parent_ino && namelen == 2 && !strncmp(name, "..", 2)) { + ino = rdt->parent_ino; + } else if (rdt->cache) { + struct ovl_cache_entry *p; +-- +2.51.0 + diff --git a/queue-5.10/pci-do-not-attempt-to-set-exttag-for-vfs.patch b/queue-5.10/pci-do-not-attempt-to-set-exttag-for-vfs.patch new file mode 100644 index 0000000000..c95c1915e7 --- /dev/null +++ b/queue-5.10/pci-do-not-attempt-to-set-exttag-for-vfs.patch @@ -0,0 +1,49 @@ +From 8dec1a43d2137d0b1c0b3fe8295a58512b67b372 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 12 Nov 2025 10:54:40 +0100 +Subject: PCI: Do not attempt to set ExtTag for VFs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Håkon Bugge + +[ Upstream commit 73711730a1128d91ebca1a6994ceeb18f36cb0cd ] + +The bit for enabling extended tags is Reserved and Preserved (RsvdP) for +VFs, according to PCIe r7.0 section 7.5.3.4 table 7.21. Hence, bail out +early from pci_configure_extended_tags() if the device is a VF. + +Otherwise, we may see incorrect log messages such as: + + kernel: pci 0000:af:00.2: enabling Extended Tags + +(af:00.2 is a VF) + +Fixes: 60db3a4d8cc9 ("PCI: Enable PCIe Extended Tags if supported") +Signed-off-by: Håkon Bugge +Signed-off-by: Bjorn Helgaas +Reviewed-by: Zhu Yanjun +Link: https://patch.msgid.link/20251112095442.1913258-1-haakon.bugge@oracle.com +Signed-off-by: Sasha Levin +--- + drivers/pci/probe.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c +index 0b1ef4f2c90dd..50a7fd09b068e 100644 +--- a/drivers/pci/probe.c ++++ b/drivers/pci/probe.c +@@ -2069,7 +2069,8 @@ int pci_configure_extended_tags(struct pci_dev *dev, void *ign) + u16 ctl; + int ret; + +- if (!pci_is_pcie(dev)) ++ /* PCI_EXP_DEVCTL_EXT_TAG is RsvdP in VFs */ ++ if (!pci_is_pcie(dev) || dev->is_virtfn) + return 0; + + ret = pcie_capability_read_dword(dev, PCI_EXP_DEVCAP, &cap); +-- +2.51.0 + diff --git a/queue-5.10/pci-initialize-rcb-from-pci_configure_device.patch b/queue-5.10/pci-initialize-rcb-from-pci_configure_device.patch new file mode 100644 index 0000000000..0e5093dbda --- /dev/null +++ b/queue-5.10/pci-initialize-rcb-from-pci_configure_device.patch @@ -0,0 +1,90 @@ +From 6ceef66430ea379a606ba55e7a7cda28c27fa936 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 18:52:32 +0100 +Subject: PCI: Initialize RCB from pci_configure_device() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Håkon Bugge + +[ Upstream commit 1a6845aaa6de81f95959b380b45de8f10d6a8502 ] + +Commit e42010d8207f ("PCI: Set Read Completion Boundary to 128 iff Root +Port supports it (_HPX)") worked around a bogus _HPX type 2 record, which +caused program_hpx_type2() to set the RCB in an endpoint even though the +Root Port did not have the RCB bit set. + +e42010d8207f fixed that by setting the RCB in the endpoint only when it was +set in the Root Port. + +In retrospect, program_hpx_type2() is intended for AER-related settings, +and the RCB should be configured elsewhere so it doesn't depend on the +presence or contents of an _HPX record. + +Explicitly program the RCB from pci_configure_device() so it matches the +Root Port's RCB. The Root Port may not be visible to virtualized guests; +in that case, leave RCB alone. + +Fixes: e42010d8207f ("PCI: Set Read Completion Boundary to 128 iff Root Port supports it (_HPX)") +Signed-off-by: Håkon Bugge +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260129175237.727059-2-haakon.bugge@oracle.com +Signed-off-by: Sasha Levin +--- + drivers/pci/probe.c | 32 ++++++++++++++++++++++++++++++++ + 1 file changed, 32 insertions(+) + +diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c +index 50a7fd09b068e..c8dc988df4c39 100644 +--- a/drivers/pci/probe.c ++++ b/drivers/pci/probe.c +@@ -2244,6 +2244,37 @@ static void pci_configure_serr(struct pci_dev *dev) + } + } + ++static void pci_configure_rcb(struct pci_dev *dev) ++{ ++ struct pci_dev *rp; ++ u16 rp_lnkctl; ++ ++ /* ++ * Per PCIe r7.0, sec 7.5.3.7, RCB is only meaningful in Root Ports ++ * (where it is read-only), Endpoints, and Bridges. It may only be ++ * set for Endpoints and Bridges if it is set in the Root Port. For ++ * Endpoints, it is 'RsvdP' for Virtual Functions. ++ */ ++ if (!pci_is_pcie(dev) || ++ pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT || ++ pci_pcie_type(dev) == PCI_EXP_TYPE_UPSTREAM || ++ pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM || ++ pci_pcie_type(dev) == PCI_EXP_TYPE_RC_EC || ++ dev->is_virtfn) ++ return; ++ ++ /* Root Port often not visible to virtualized guests */ ++ rp = pcie_find_root_port(dev); ++ if (!rp) ++ return; ++ ++ pcie_capability_read_word(rp, PCI_EXP_LNKCTL, &rp_lnkctl); ++ pcie_capability_clear_and_set_word(dev, PCI_EXP_LNKCTL, ++ PCI_EXP_LNKCTL_RCB, ++ (rp_lnkctl & PCI_EXP_LNKCTL_RCB) ? ++ PCI_EXP_LNKCTL_RCB : 0); ++} ++ + static void pci_configure_device(struct pci_dev *dev) + { + pci_configure_mps(dev); +@@ -2252,6 +2283,7 @@ static void pci_configure_device(struct pci_dev *dev) + pci_configure_ltr(dev); + pci_configure_eetlp_prefix(dev); + pci_configure_serr(dev); ++ pci_configure_rcb(dev); + + pci_acpi_program_hp_params(dev); + } +-- +2.51.0 + diff --git a/queue-5.10/pci-mark-3ware-9650sa-root-port-extended-tags-as-bro.patch b/queue-5.10/pci-mark-3ware-9650sa-root-port-extended-tags-as-bro.patch new file mode 100644 index 0000000000..0214ac8e58 --- /dev/null +++ b/queue-5.10/pci-mark-3ware-9650sa-root-port-extended-tags-as-bro.patch @@ -0,0 +1,56 @@ +From c66c966d0694e9dd13073511d39f234051b7e312 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 15:31:10 +0100 +Subject: PCI: Mark 3ware-9650SA Root Port Extended Tags as broken +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jörg Wedekind + +[ Upstream commit 959ac08a2c2811305be8c2779779e8b0932e5a99 ] + +Per PCIe r7.0, sec 2.2.6.2.1 and 7.5.3.4, a Requester may not use 8-bit Tags +unless its Extended Tag Field Enable is set, but all Receivers/Completers +must handle 8-bit Tags correctly regardless of their Extended Tag Field +Enable. + +Some devices do not handle 8-bit Tags as Completers, so add a quirk for +them. If we find such a device, we disable Extended Tags for the entire +hierarchy to make peer-to-peer DMA possible. + +The 3ware 9650SA seems to have issues with handling 8-bit tags. Mark it as +broken. + +This fixes PCI Parity Errors like : + + 3w-9xxx: scsi0: ERROR: (0x06:0x000C): PCI Parity Error: clearing. + 3w-9xxx: scsi0: ERROR: (0x06:0x000D): PCI Abort: clearing. + 3w-9xxx: scsi0: ERROR: (0x06:0x000E): Controller Queue Error: clearing. + 3w-9xxx: scsi0: ERROR: (0x06:0x0010): Microcontroller Error: clearing. + +Fixes: 60db3a4d8cc9 ("PCI: Enable PCIe Extended Tags if supported") +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=202425 +Signed-off-by: Jörg Wedekind +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260119143114.21948-1-joerg@wedekind.de +Signed-off-by: Sasha Levin +--- + drivers/pci/quirks.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index ac355ae17bfee..c925e0be5f476 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -5405,6 +5405,7 @@ static void quirk_no_ext_tags(struct pci_dev *pdev) + pci_walk_bus(bridge->bus, pci_configure_extended_tags, NULL); + } + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_3WARE, 0x1004, quirk_no_ext_tags); ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_3WARE, 0x1005, quirk_no_ext_tags); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0132, quirk_no_ext_tags); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0140, quirk_no_ext_tags); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0141, quirk_no_ext_tags); +-- +2.51.0 + diff --git a/queue-5.10/pci-mediatek-fix-irq-domain-leak-when-msi-allocation.patch b/queue-5.10/pci-mediatek-fix-irq-domain-leak-when-msi-allocation.patch new file mode 100644 index 0000000000..e953265e41 --- /dev/null +++ b/queue-5.10/pci-mediatek-fix-irq-domain-leak-when-msi-allocation.patch @@ -0,0 +1,45 @@ +From cddb453124c3f294b4ca5e924116f233678168c9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 19 Nov 2025 10:33:08 +0800 +Subject: PCI: mediatek: Fix IRQ domain leak when MSI allocation fails + +From: Haotian Zhang + +[ Upstream commit 7f0cdcddf8bef1c8c18f9be6708073fd3790a20f ] + +In mtk_pcie_init_irq_domain(), if mtk_pcie_allocate_msi_domains() +fails after port->irq_domain has been successfully created via +irq_domain_create_linear(), the function returns directly without +cleaning up the allocated IRQ domain, resulting in a resource leak. + +Add irq_domain_remove() call in the error path to properly release the +INTx IRQ domain before returning the error. + +Fixes: 43e6409db64d ("PCI: mediatek: Add MSI support for MT2712 and MT7622") +Signed-off-by: Haotian Zhang +Signed-off-by: Manivannan Sadhasivam +Link: https://patch.msgid.link/20251119023308.476-1-vulab@iscas.ac.cn +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/pcie-mediatek.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c +index ea91d63c8be15..bab962ec7ab46 100644 +--- a/drivers/pci/controller/pcie-mediatek.c ++++ b/drivers/pci/controller/pcie-mediatek.c +@@ -588,8 +588,10 @@ static int mtk_pcie_init_irq_domain(struct mtk_pcie_port *port, + + if (IS_ENABLED(CONFIG_PCI_MSI)) { + ret = mtk_pcie_allocate_msi_domains(port); +- if (ret) ++ if (ret) { ++ irq_domain_remove(port->irq_domain); + return ret; ++ } + } + + return 0; +-- +2.51.0 + diff --git a/queue-5.10/pci-portdrv-fix-potential-resource-leak.patch b/queue-5.10/pci-portdrv-fix-potential-resource-leak.patch new file mode 100644 index 0000000000..d6f1b06e11 --- /dev/null +++ b/queue-5.10/pci-portdrv-fix-potential-resource-leak.patch @@ -0,0 +1,48 @@ +From 8b4e578bdba8403525843f4e00b9cbe428b9e5bb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Dec 2025 16:13:49 +0100 +Subject: PCI/portdrv: Fix potential resource leak +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Uwe Kleine-König + +[ Upstream commit 01464a3fdf91c041a381d93a1b6fefbdb819a46f ] + +pcie_port_probe_service() unconditionally calls get_device() (unless it +fails). So drop that reference also unconditionally as it's fine for a +PCIe driver to not have a remove callback. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Uwe Kleine-König +Signed-off-by: Bjorn Helgaas +Reviewed-by: Ilpo Järvinen +Reviewed-by: Jonathan Cameron +Link: https://patch.msgid.link/e1c68c3b3f1af8427e98ca5e2c79f8bf0ebe2ce4.1764688034.git.u.kleine-koenig@baylibre.com +Signed-off-by: Sasha Levin +--- + drivers/pci/pcie/portdrv_core.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c +index e3d998173433f..0ebf3b2674036 100644 +--- a/drivers/pci/pcie/portdrv_core.c ++++ b/drivers/pci/pcie/portdrv_core.c +@@ -550,10 +550,10 @@ static int pcie_port_remove_service(struct device *dev) + + pciedev = to_pcie_device(dev); + driver = to_service_driver(dev->driver); +- if (driver && driver->remove) { ++ if (driver && driver->remove) + driver->remove(pciedev); +- put_device(dev); +- } ++ ++ put_device(dev); + return 0; + } + +-- +2.51.0 + diff --git a/queue-5.10/pinctrl-equilibrium-fix-device-node-reference-leak-i.patch b/queue-5.10/pinctrl-equilibrium-fix-device-node-reference-leak-i.patch new file mode 100644 index 0000000000..ecececbaa8 --- /dev/null +++ b/queue-5.10/pinctrl-equilibrium-fix-device-node-reference-leak-i.patch @@ -0,0 +1,44 @@ +From c14e74bed45367915ead3411fcad9da7fb828e17 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 01:30:07 +0800 +Subject: pinctrl: equilibrium: Fix device node reference leak in + pinbank_init() + +From: Felix Gu + +[ Upstream commit c0b4a4feeb43305a754893d8d9c6b2b5a52d45ac ] + +When calling of_parse_phandle_with_fixed_args(), the caller is +responsible to call of_node_put() to release the reference of device +node. + +In pinbank_init(), the reference of the node obtained from the +"gpio-ranges" property is never released, resulting in a reference +count leak. + +Add the missing of_node_put() call to fix the leak. + +Fixes: 1948d5c51dba ("pinctrl: Add pinmux & GPIO controller driver for a new SoC") +Signed-off-by: Felix Gu +Acked-by: Andy Shevchenko +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-equilibrium.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/pinctrl/pinctrl-equilibrium.c b/drivers/pinctrl/pinctrl-equilibrium.c +index 3b6dcaa80e000..55fc9aa61f55a 100644 +--- a/drivers/pinctrl/pinctrl-equilibrium.c ++++ b/drivers/pinctrl/pinctrl-equilibrium.c +@@ -835,6 +835,7 @@ static int pinbank_init(struct device_node *np, + + bank->pin_base = spec.args[1]; + bank->nr_pins = spec.args[2]; ++ of_node_put(spec.np); + + bank->aval_pinmap = readl(bank->membase + REG_AVAIL); + bank->id = id; +-- +2.51.0 + diff --git a/queue-5.10/pinctrl-single-fix-refcount-leak-in-pcs_add_gpio_fun.patch b/queue-5.10/pinctrl-single-fix-refcount-leak-in-pcs_add_gpio_fun.patch new file mode 100644 index 0000000000..dc0d582a3f --- /dev/null +++ b/queue-5.10/pinctrl-single-fix-refcount-leak-in-pcs_add_gpio_fun.patch @@ -0,0 +1,50 @@ +From 93802c26a2da4df9a746767a4fda324d3da7c61a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 08:07:35 +0000 +Subject: pinctrl: single: fix refcount leak in pcs_add_gpio_func() + +From: Wei Li + +[ Upstream commit 353353309b0f7afa407df29e455f9d15b5acc296 ] + +of_parse_phandle_with_args() returns a device_node pointer with refcount +incremented in gpiospec.np. The loop iterates through all phandles but +never releases the reference, causing a refcount leak on each iteration. + +Add of_node_put() calls to release the reference after extracting the +needed arguments and on the error path when devm_kzalloc() fails. + +This bug was detected by our static analysis tool and verified by my +code review. + +Fixes: a1a277eb76b3 ("pinctrl: single: create new gpio function range") +Signed-off-by: Wei Li +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-single.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c +index 07bf090420453..491a46e330b30 100644 +--- a/drivers/pinctrl/pinctrl-single.c ++++ b/drivers/pinctrl/pinctrl-single.c +@@ -1368,6 +1368,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) + } + range = devm_kzalloc(pcs->dev, sizeof(*range), GFP_KERNEL); + if (!range) { ++ of_node_put(gpiospec.np); + ret = -ENOMEM; + break; + } +@@ -1377,6 +1378,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) + mutex_lock(&pcs->mutex); + list_add_tail(&range->node, &pcs->gpiofuncs); + mutex_unlock(&pcs->mutex); ++ of_node_put(gpiospec.np); + } + return ret; + } +-- +2.51.0 + diff --git a/queue-5.10/platform-chrome-cros_ec_lightbar-fix-response-size-i.patch b/queue-5.10/platform-chrome-cros_ec_lightbar-fix-response-size-i.patch new file mode 100644 index 0000000000..409d869050 --- /dev/null +++ b/queue-5.10/platform-chrome-cros_ec_lightbar-fix-response-size-i.patch @@ -0,0 +1,43 @@ +From 24b736a7ae3ce467e08c0fd222141f37dde57ccf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 04:03:35 +0000 +Subject: platform/chrome: cros_ec_lightbar: Fix response size initialization + +From: Tzung-Bi Shih + +[ Upstream commit ec0dd36dbf8b0b209e63d0cd795451fa2203c736 ] + +Commit 1e7913ff5f9f ("platform/chrome: cros_ec_lightbar: Reduce +ligthbar get version command") meant to set smaller values for both +request and response sizes. + +However, it incorrectly assigned the response size to the `result` field +instead of `insize`. Fix it. + +Reported-by: Gwendal Grignou +Closes: https://lore.kernel.org/chrome-platform/CAMHSBOVrrYaB=1nEqZk09VkczCrj=6B-P8Fe29TpPdSDgT2CCQ@mail.gmail.com +Fixes: 1e7913ff5f9f ("platform/chrome: cros_ec_lightbar: Reduce ligthbar get version command") +Link: https://lore.kernel.org/r/20260130040335.361997-1-tzungbi@kernel.org +Reviewed-by: Gwendal Grignou +Signed-off-by: Tzung-Bi Shih +Signed-off-by: Sasha Levin +--- + drivers/platform/chrome/cros_ec_lightbar.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/platform/chrome/cros_ec_lightbar.c b/drivers/platform/chrome/cros_ec_lightbar.c +index de8dfb12e4863..235326f217a48 100644 +--- a/drivers/platform/chrome/cros_ec_lightbar.c ++++ b/drivers/platform/chrome/cros_ec_lightbar.c +@@ -117,7 +117,7 @@ static int get_lightbar_version(struct cros_ec_dev *ec, + param = (struct ec_params_lightbar *)msg->data; + param->cmd = LIGHTBAR_CMD_VERSION; + msg->outsize = sizeof(param->cmd); +- msg->result = sizeof(resp->version); ++ msg->insize = sizeof(resp->version); + ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg); + if (ret < 0 && ret != -EINVAL) { + ret = 0; +-- +2.51.0 + diff --git a/queue-5.10/pm-core-add-new-_pm_ops-macros-deprecate-old-ones.patch b/queue-5.10/pm-core-add-new-_pm_ops-macros-deprecate-old-ones.patch new file mode 100644 index 0000000000..d31229b801 --- /dev/null +++ b/queue-5.10/pm-core-add-new-_pm_ops-macros-deprecate-old-ones.patch @@ -0,0 +1,197 @@ +From 204d38b9df4027e14b1de879d6f34e7d4667babe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Dec 2021 00:21:00 +0000 +Subject: PM: core: Add new *_PM_OPS macros, deprecate old ones + +From: Paul Cercueil + +[ Upstream commit 1a3c7bb088266fa2db017be299f91f1c1894c857 ] + +This commit introduces the following macros: + +SYSTEM_SLEEP_PM_OPS() +LATE_SYSTEM_SLEEP_PM_OPS() +NOIRQ_SYSTEM_SLEEP_PM_OPS() +RUNTIME_PM_OPS() + +These new macros are very similar to their SET_*_PM_OPS() equivalent. +They however differ in the fact that the callbacks they set will always +be seen as referenced by the compiler. This means that the callback +functions don't need to be wrapped with a #ifdef CONFIG_PM guard, or +tagged with __maybe_unused, to prevent the compiler from complaining +about unused static symbols. The compiler will then simply evaluate at +compile time whether or not these symbols are dead code. + +The callbacks that are only useful with CONFIG_PM_SLEEP is enabled, are +now also wrapped with a new pm_sleep_ptr() macro, which is inspired from +pm_ptr(). This is needed for drivers that use different callbacks for +sleep and runtime PM, to handle the case where CONFIG_PM is set and +CONFIG_PM_SLEEP is not. + +This commit also deprecates the following macros: + +SIMPLE_DEV_PM_OPS() +UNIVERSAL_DEV_PM_OPS() + +And introduces the following macros: + +DEFINE_SIMPLE_DEV_PM_OPS() +DEFINE_UNIVERSAL_DEV_PM_OPS() + +These macros are similar to the functions they were created to replace, +with the following differences: + + - They use the new macros introduced above, and as such always + reference the provided callback functions. + + - They are not tagged with __maybe_unused. They are meant to be used + with pm_ptr() or pm_sleep_ptr() for DEFINE_UNIVERSAL_DEV_PM_OPS() + and DEFINE_SIMPLE_DEV_PM_OPS() respectively. + + - They declare the symbol static, since every driver seems to do that + anyway; and if a non-static use-case is needed an indirection pointer + could be used. + +The point of this change, is to progressively switch from a code model +where PM callbacks are all protected behind CONFIG_PM guards, to a code +model where the PM callbacks are always seen by the compiler, but +discarded if not used. + +Signed-off-by: Paul Cercueil +Reviewed-by: Jonathan Cameron +Signed-off-by: Rafael J. Wysocki +Stable-dep-of: 0ba2035026d0 ("crypto: ccp - Add an S4 restore flow") +Signed-off-by: Sasha Levin +--- + include/linux/pm.h | 74 +++++++++++++++++++++++++++++++--------------- + 1 file changed, 50 insertions(+), 24 deletions(-) + +diff --git a/include/linux/pm.h b/include/linux/pm.h +index 5ac2c9ba5baf7..b4974dc837032 100644 +--- a/include/linux/pm.h ++++ b/include/linux/pm.h +@@ -301,47 +301,59 @@ struct dev_pm_ops { + int (*runtime_idle)(struct device *dev); + }; + ++#define SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ ++ .suspend = pm_sleep_ptr(suspend_fn), \ ++ .resume = pm_sleep_ptr(resume_fn), \ ++ .freeze = pm_sleep_ptr(suspend_fn), \ ++ .thaw = pm_sleep_ptr(resume_fn), \ ++ .poweroff = pm_sleep_ptr(suspend_fn), \ ++ .restore = pm_sleep_ptr(resume_fn), ++ ++#define LATE_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ ++ .suspend_late = pm_sleep_ptr(suspend_fn), \ ++ .resume_early = pm_sleep_ptr(resume_fn), \ ++ .freeze_late = pm_sleep_ptr(suspend_fn), \ ++ .thaw_early = pm_sleep_ptr(resume_fn), \ ++ .poweroff_late = pm_sleep_ptr(suspend_fn), \ ++ .restore_early = pm_sleep_ptr(resume_fn), ++ ++#define NOIRQ_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ ++ .suspend_noirq = pm_sleep_ptr(suspend_fn), \ ++ .resume_noirq = pm_sleep_ptr(resume_fn), \ ++ .freeze_noirq = pm_sleep_ptr(suspend_fn), \ ++ .thaw_noirq = pm_sleep_ptr(resume_fn), \ ++ .poweroff_noirq = pm_sleep_ptr(suspend_fn), \ ++ .restore_noirq = pm_sleep_ptr(resume_fn), ++ ++#define RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) \ ++ .runtime_suspend = suspend_fn, \ ++ .runtime_resume = resume_fn, \ ++ .runtime_idle = idle_fn, ++ + #ifdef CONFIG_PM_SLEEP + #define SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ +- .suspend = suspend_fn, \ +- .resume = resume_fn, \ +- .freeze = suspend_fn, \ +- .thaw = resume_fn, \ +- .poweroff = suspend_fn, \ +- .restore = resume_fn, ++ SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) + #else + #define SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) + #endif + + #ifdef CONFIG_PM_SLEEP + #define SET_LATE_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ +- .suspend_late = suspend_fn, \ +- .resume_early = resume_fn, \ +- .freeze_late = suspend_fn, \ +- .thaw_early = resume_fn, \ +- .poweroff_late = suspend_fn, \ +- .restore_early = resume_fn, ++ LATE_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) + #else + #define SET_LATE_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) + #endif + + #ifdef CONFIG_PM_SLEEP + #define SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ +- .suspend_noirq = suspend_fn, \ +- .resume_noirq = resume_fn, \ +- .freeze_noirq = suspend_fn, \ +- .thaw_noirq = resume_fn, \ +- .poweroff_noirq = suspend_fn, \ +- .restore_noirq = resume_fn, ++ NOIRQ_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) + #else + #define SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) + #endif + + #ifdef CONFIG_PM + #define SET_RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) \ +- .runtime_suspend = suspend_fn, \ +- .runtime_resume = resume_fn, \ +- .runtime_idle = idle_fn, ++ RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) + #else + #define SET_RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) + #endif +@@ -350,9 +362,9 @@ struct dev_pm_ops { + * Use this if you want to use the same suspend and resume callbacks for suspend + * to RAM and hibernation. + */ +-#define SIMPLE_DEV_PM_OPS(name, suspend_fn, resume_fn) \ +-const struct dev_pm_ops __maybe_unused name = { \ +- SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ ++#define DEFINE_SIMPLE_DEV_PM_OPS(name, suspend_fn, resume_fn) \ ++static const struct dev_pm_ops name = { \ ++ SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ + } + + /* +@@ -368,6 +380,19 @@ const struct dev_pm_ops __maybe_unused name = { \ + * .resume_early(), to the same routines as .runtime_suspend() and + * .runtime_resume(), respectively (and analogously for hibernation). + */ ++#define DEFINE_UNIVERSAL_DEV_PM_OPS(name, suspend_fn, resume_fn, idle_fn) \ ++static const struct dev_pm_ops name = { \ ++ SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ ++ RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) \ ++} ++ ++/* Deprecated. Use DEFINE_SIMPLE_DEV_PM_OPS() instead. */ ++#define SIMPLE_DEV_PM_OPS(name, suspend_fn, resume_fn) \ ++const struct dev_pm_ops __maybe_unused name = { \ ++ SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ ++} ++ ++/* Deprecated. Use DEFINE_UNIVERSAL_DEV_PM_OPS() instead. */ + #define UNIVERSAL_DEV_PM_OPS(name, suspend_fn, resume_fn, idle_fn) \ + const struct dev_pm_ops __maybe_unused name = { \ + SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ +@@ -375,6 +400,7 @@ const struct dev_pm_ops __maybe_unused name = { \ + } + + #define pm_ptr(_ptr) PTR_IF(IS_ENABLED(CONFIG_PM), (_ptr)) ++#define pm_sleep_ptr(_ptr) PTR_IF(IS_ENABLED(CONFIG_PM_SLEEP), (_ptr)) + + /* + * PM_EVENT_ messages +-- +2.51.0 + diff --git a/queue-5.10/pm-core-redefine-pm_ptr-macro.patch b/queue-5.10/pm-core-redefine-pm_ptr-macro.patch new file mode 100644 index 0000000000..1f70257c61 --- /dev/null +++ b/queue-5.10/pm-core-redefine-pm_ptr-macro.patch @@ -0,0 +1,61 @@ +From e363f44e783d15cdd4d2ce30e5d1e1c857853064 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Dec 2021 00:20:59 +0000 +Subject: PM: core: Redefine pm_ptr() macro + +From: Paul Cercueil + +[ Upstream commit c06ef740d401d0f4ab188882bf6f8d9cf0f75eaf ] + +The pm_ptr() macro was previously conditionally defined, according to +the value of the CONFIG_PM option. This meant that the pointed structure +was either referenced (if CONFIG_PM was set), or never referenced (if +CONFIG_PM was not set), causing it to be detected as unused by the +compiler. + +This worked fine, but required the __maybe_unused compiler attribute to +be used to every symbol pointed to by a pointer wrapped with pm_ptr(). + +We can do better. With this change, the pm_ptr() is now defined the +same, independently of the value of CONFIG_PM. It now uses the (?:) +ternary operator to conditionally resolve to its argument. Since the +condition is known at compile time, the compiler will then choose to +discard the unused symbols, which won't need to be tagged with +__maybe_unused anymore. + +This pm_ptr() macro is usually used with pointers to dev_pm_ops +structures created with SIMPLE_DEV_PM_OPS() or similar macros. These do +use a __maybe_unused flag, which is now useless with this change, so it +later can be removed. However in the meantime it causes no harm, and all +the drivers still compile fine with the new pm_ptr() macro. + +Signed-off-by: Paul Cercueil +Reviewed-by: Jonathan Cameron +Reviewed-by: Arnd Bergmann +Signed-off-by: Rafael J. Wysocki +Stable-dep-of: 0ba2035026d0 ("crypto: ccp - Add an S4 restore flow") +Signed-off-by: Sasha Levin +--- + include/linux/pm.h | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/include/linux/pm.h b/include/linux/pm.h +index 52d9724db9dc6..5ac2c9ba5baf7 100644 +--- a/include/linux/pm.h ++++ b/include/linux/pm.h +@@ -374,11 +374,7 @@ const struct dev_pm_ops __maybe_unused name = { \ + SET_RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) \ + } + +-#ifdef CONFIG_PM +-#define pm_ptr(_ptr) (_ptr) +-#else +-#define pm_ptr(_ptr) NULL +-#endif ++#define pm_ptr(_ptr) PTR_IF(IS_ENABLED(CONFIG_PM), (_ptr)) + + /* + * PM_EVENT_ messages +-- +2.51.0 + diff --git a/queue-5.10/pm-sleep-wakeirq-harden-dev_pm_clear_wake_irq-agains.patch b/queue-5.10/pm-sleep-wakeirq-harden-dev_pm_clear_wake_irq-agains.patch new file mode 100644 index 0000000000..a40b0865cc --- /dev/null +++ b/queue-5.10/pm-sleep-wakeirq-harden-dev_pm_clear_wake_irq-agains.patch @@ -0,0 +1,65 @@ +From b40b9132cf1ae428930363eccc279b672bae046f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 11:19:43 +0800 +Subject: PM: sleep: wakeirq: harden dev_pm_clear_wake_irq() against races + +From: Gui-Dong Han + +[ Upstream commit 5c9ecd8e6437cd55a38ea4f1e1d19cee8e226cb8 ] + +dev_pm_clear_wake_irq() currently uses a dangerous pattern where +dev->power.wakeirq is read and checked for NULL outside the lock. +If two callers invoke this function concurrently, both might see +a valid pointer and proceed. This could result in a double-free +when the second caller acquires the lock and tries to release the +same object. + +Address this by removing the lockless check of dev->power.wakeirq. +Instead, acquire dev->power.lock immediately to ensure the check and +the subsequent operations are atomic. If dev->power.wakeirq is NULL +under the lock, simply unlock and return. This guarantees that +concurrent calls cannot race to free the same object. + +Based on a quick scan of current users, I did not find an actual bug as +drivers seem to rely on their own synchronization. However, since +asynchronous usage patterns exist (e.g., in +drivers/net/wireless/ti/wlcore), I believe a race is theoretically +possible if the API is used less carefully in the future. This change +hardens the API to be robust against such cases. + +Fixes: 4990d4fe327b ("PM / Wakeirq: Add automated device wake IRQ handling") +Signed-off-by: Gui-Dong Han +Link: https://patch.msgid.link/20260203031943.1924-1-hanguidong02@gmail.com +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/base/power/wakeirq.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/drivers/base/power/wakeirq.c b/drivers/base/power/wakeirq.c +index 4f4310724fee5..d22fc66a387d7 100644 +--- a/drivers/base/power/wakeirq.c ++++ b/drivers/base/power/wakeirq.c +@@ -86,13 +86,16 @@ EXPORT_SYMBOL_GPL(dev_pm_set_wake_irq); + */ + void dev_pm_clear_wake_irq(struct device *dev) + { +- struct wake_irq *wirq = dev->power.wakeirq; ++ struct wake_irq *wirq; + unsigned long flags; + +- if (!wirq) ++ spin_lock_irqsave(&dev->power.lock, flags); ++ wirq = dev->power.wakeirq; ++ if (!wirq) { ++ spin_unlock_irqrestore(&dev->power.lock, flags); + return; ++ } + +- spin_lock_irqsave(&dev->power.lock, flags); + device_wakeup_detach_irq(dev); + dev->power.wakeirq = NULL; + spin_unlock_irqrestore(&dev->power.lock, flags); +-- +2.51.0 + diff --git a/queue-5.10/pm-wakeup-handle-empty-list-in-wakeup_sources_walk_s.patch b/queue-5.10/pm-wakeup-handle-empty-list-in-wakeup_sources_walk_s.patch new file mode 100644 index 0000000000..4169e853ca --- /dev/null +++ b/queue-5.10/pm-wakeup-handle-empty-list-in-wakeup_sources_walk_s.patch @@ -0,0 +1,44 @@ +From a721a51b2407fae13b7da42460b15a7f35e82faa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 17:21:29 -0800 +Subject: PM: wakeup: Handle empty list in wakeup_sources_walk_start() + +From: Samuel Wu + +[ Upstream commit 75ce02f4bc9a8b8350b6b1b01872467b0cc960cc ] + +In the case of an empty wakeup_sources list, wakeup_sources_walk_start() +will return an invalid but non-NULL address. This also affects wrappers +of the aforementioned function, like for_each_wakeup_source(). + +Update wakeup_sources_walk_start() to return NULL in case of an empty +list. + +Fixes: b4941adb24c0 ("PM: wakeup: Add routine to help fetch wakeup source object.") +Signed-off-by: Samuel Wu +[ rjw: Subject and changelog edits ] +Link: https://patch.msgid.link/20260124012133.2451708-2-wusamuel@google.com +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/base/power/wakeup.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c +index 8997e0227eb9d..e3b0a2db32e9b 100644 +--- a/drivers/base/power/wakeup.c ++++ b/drivers/base/power/wakeup.c +@@ -285,9 +285,7 @@ EXPORT_SYMBOL_GPL(wakeup_sources_read_unlock); + */ + struct wakeup_source *wakeup_sources_walk_start(void) + { +- struct list_head *ws_head = &wakeup_sources; +- +- return list_entry_rcu(ws_head->next, struct wakeup_source, entry); ++ return list_first_or_null_rcu(&wakeup_sources, struct wakeup_source, entry); + } + EXPORT_SYMBOL_GPL(wakeup_sources_walk_start); + +-- +2.51.0 + diff --git a/queue-5.10/pnfs-fix-a-missing-wake-up-while-waiting-on-nfs_layo.patch b/queue-5.10/pnfs-fix-a-missing-wake-up-while-waiting-on-nfs_layo.patch new file mode 100644 index 0000000000..06bb217b89 --- /dev/null +++ b/queue-5.10/pnfs-fix-a-missing-wake-up-while-waiting-on-nfs_layo.patch @@ -0,0 +1,61 @@ +From ff18f70259f1c24bbe91164a5d8e427d2d3152a7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 14:15:39 -0500 +Subject: pNFS: fix a missing wake up while waiting on NFS_LAYOUT_DRAIN + +From: Olga Kornievskaia + +[ Upstream commit 5248d8474e594d156bee1ed10339cc16e207a28b ] + +It is possible to have a task get stuck on waiting on the +NFS_LAYOUT_DRAIN in the following scenario + +1. cpu a: waiter test NFS_LAYOUT_DRAIN (1) and plh_outstanding (1) +2. cpu b: atomic_dec_and_test() -> clear bit -> wake up +3. cpu c: sets NFS_LAYOUT_DRAIN again +4. cpu a: calls wait_on_bit() sleeps forever. + +To expand on this we have say 2 outstanding pnfs write IO that get +ESTALE which causes both to call pnfs_destroy_layout() and set the +NFS_LAYOUT_DRAIN bit but the 1st one doesn't call the +pnfs_put_layout_hdr() yet (as that would prevent the 2nd ESTALE write +from trying to call pnfs_destroy_layout()). If the 1st ESTALE write +is the one that initially sets the NFS_LAYOUT_DRAIN so that new IO +on this file initiates new LAYOUTGET. Another new write would find +NFS_LAYOUT_DRAIN set and phl_outstanding>0 (step 1) and would +wait_on_bit(). LAYOUTGET completes doing step 2. Now, the 2nd of +ESTALE writes is calling pnfs_destory_layout() and set the +NFS_LAYOUT_DRAIN bit (step 3). Finally, the waiting write wakes up +to check the bit and goes back to sleep. + +The problem revolves around the fact that if NFS_LAYOUT_INVALID_STID +was already set, it should not do the work of +pnfs_mark_layout_stateid_invalid(), thus NFS_LAYOUT_DRAIN will not +be set more than once for an invalid layout. + +Suggested-by: Trond Myklebust +Fixes: 880265c77ac4 ("pNFS: Avoid a live lock condition in pnfs_update_layout()") +Signed-off-by: Olga Kornievskaia +Signed-off-by: Anna Schumaker +Signed-off-by: Sasha Levin +--- + fs/nfs/pnfs.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c +index c5dd301c43d7b..e0317a889a3af 100644 +--- a/fs/nfs/pnfs.c ++++ b/fs/nfs/pnfs.c +@@ -464,7 +464,8 @@ pnfs_mark_layout_stateid_invalid(struct pnfs_layout_hdr *lo, + }; + struct pnfs_layout_segment *lseg, *next; + +- set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags); ++ if (test_and_set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags)) ++ return !list_empty(&lo->plh_segs); + clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(lo->plh_inode)->flags); + list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list) + pnfs_clear_lseg_state(lseg, lseg_list); +-- +2.51.0 + diff --git a/queue-5.10/power-reset-nvmem-reboot-mode-respect-cell-size-for-.patch b/queue-5.10/power-reset-nvmem-reboot-mode-respect-cell-size-for-.patch new file mode 100644 index 0000000000..d35291e8b5 --- /dev/null +++ b/queue-5.10/power-reset-nvmem-reboot-mode-respect-cell-size-for-.patch @@ -0,0 +1,64 @@ +From d6f345f60fa1354f5a182fb6a4bf7ab0c6573476 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 14 Dec 2025 19:16:18 +0000 +Subject: power: reset: nvmem-reboot-mode: respect cell size for + nvmem_cell_write + +From: Alexander Koskovich + +[ Upstream commit 36b05629226413836cfbb3fbe6689cd188bca156 ] + +Some platforms expose reboot mode cells that are smaller than an +unsigned int, in which cases lead to write failures. Read the cell +first to determine actual size and only write the number of bytes the +cell can hold. + +Fixes: 7a78a7f7695b ("power: reset: nvmem-reboot-mode: use NVMEM as reboot mode write interface") +Signed-off-by: Alexander Koskovich +Link: https://patch.msgid.link/20251214191529.2470580-1-akoskovich@pm.me +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/reset/nvmem-reboot-mode.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +diff --git a/drivers/power/reset/nvmem-reboot-mode.c b/drivers/power/reset/nvmem-reboot-mode.c +index e229308d43e25..819f11bae788b 100644 +--- a/drivers/power/reset/nvmem-reboot-mode.c ++++ b/drivers/power/reset/nvmem-reboot-mode.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + + struct nvmem_reboot_mode { + struct reboot_mode_driver reboot; +@@ -19,12 +20,22 @@ struct nvmem_reboot_mode { + static int nvmem_reboot_mode_write(struct reboot_mode_driver *reboot, + unsigned int magic) + { +- int ret; + struct nvmem_reboot_mode *nvmem_rbm; ++ size_t buf_len; ++ void *buf; ++ int ret; + + nvmem_rbm = container_of(reboot, struct nvmem_reboot_mode, reboot); + +- ret = nvmem_cell_write(nvmem_rbm->cell, &magic, sizeof(magic)); ++ buf = nvmem_cell_read(nvmem_rbm->cell, &buf_len); ++ if (IS_ERR(buf)) ++ return PTR_ERR(buf); ++ kfree(buf); ++ ++ if (buf_len > sizeof(magic)) ++ return -EINVAL; ++ ++ ret = nvmem_cell_write(nvmem_rbm->cell, &magic, buf_len); + if (ret < 0) + dev_err(reboot->dev, "update reboot mode bits failed\n"); + +-- +2.51.0 + diff --git a/queue-5.10/power-supply-act8945a-fix-use-after-free-in-power_su.patch b/queue-5.10/power-supply-act8945a-fix-use-after-free-in-power_su.patch new file mode 100644 index 0000000000..e4ce9344a6 --- /dev/null +++ b/queue-5.10/power-supply-act8945a-fix-use-after-free-in-power_su.patch @@ -0,0 +1,77 @@ +From cbe5d3d91ee14503603da9b58f7ee5e368b6b018 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:35:59 +0100 +Subject: power: supply: act8945a: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 3291c51d4684d048dd2eb91b5b65fcfdaf72141f ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: a09209acd6a8 ("power: supply: act8945a_charger: Add status change update support") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/bcf3a23b5187df0bba54a8c8fe09f8b8a0031dee.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/act8945a_charger.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/drivers/power/supply/act8945a_charger.c b/drivers/power/supply/act8945a_charger.c +index 5f3eb6941d058..a12cbfeca1123 100644 +--- a/drivers/power/supply/act8945a_charger.c ++++ b/drivers/power/supply/act8945a_charger.c +@@ -597,14 +597,6 @@ static int act8945a_charger_probe(struct platform_device *pdev) + return irq ?: -ENXIO; + } + +- ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, +- IRQF_TRIGGER_FALLING, "act8945a_interrupt", +- charger); +- if (ret) { +- dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); +- return ret; +- } +- + charger->desc.name = "act8945a-charger"; + charger->desc.get_property = act8945a_charger_get_property; + charger->desc.properties = act8945a_charger_props; +@@ -625,6 +617,14 @@ static int act8945a_charger_probe(struct platform_device *pdev) + return PTR_ERR(charger->psy); + } + ++ ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, ++ IRQF_TRIGGER_FALLING, "act8945a_interrupt", ++ charger); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); ++ return ret; ++ } ++ + platform_set_drvdata(pdev, charger); + + INIT_WORK(&charger->work, act8945a_work); +-- +2.51.0 + diff --git a/queue-5.10/power-supply-bq25980-fix-use-after-free-in-power_sup.patch b/queue-5.10/power-supply-bq25980-fix-use-after-free-in-power_sup.patch new file mode 100644 index 0000000000..52327ce053 --- /dev/null +++ b/queue-5.10/power-supply-bq25980-fix-use-after-free-in-power_sup.patch @@ -0,0 +1,73 @@ +From 3032a266469b71e7159d976a990ae66c4355bccd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:35:59 +0100 +Subject: power: supply: bq25980: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 5f0b1cb41906e86b64bf69f5ededb83b0d757c27 ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: 5069185fc18e ("power: supply: bq25980: Add support for the BQ259xx family") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/8763035cadb959e14787b3837f2d3db61f6e1c34.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/bq25980_charger.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/power/supply/bq25980_charger.c b/drivers/power/supply/bq25980_charger.c +index b94ecf814e434..98950e4456c38 100644 +--- a/drivers/power/supply/bq25980_charger.c ++++ b/drivers/power/supply/bq25980_charger.c +@@ -1241,6 +1241,12 @@ static int bq25980_probe(struct i2c_client *client, + return ret; + } + ++ ret = bq25980_power_supply_init(bq, dev); ++ if (ret) { ++ dev_err(dev, "Failed to register power supply\n"); ++ return ret; ++ } ++ + if (client->irq) { + ret = devm_request_threaded_irq(dev, client->irq, NULL, + bq25980_irq_handler_thread, +@@ -1251,12 +1257,6 @@ static int bq25980_probe(struct i2c_client *client, + return ret; + } + +- ret = bq25980_power_supply_init(bq, dev); +- if (ret) { +- dev_err(dev, "Failed to register power supply\n"); +- return ret; +- } +- + ret = bq25980_hw_init(bq); + if (ret) { + dev_err(dev, "Cannot initialize the chip.\n"); +-- +2.51.0 + diff --git a/queue-5.10/power-supply-bq27xxx-fix-wrong-errno-when-bus-ops-ar.patch b/queue-5.10/power-supply-bq27xxx-fix-wrong-errno-when-bus-ops-ar.patch new file mode 100644 index 0000000000..69cc5a9b0f --- /dev/null +++ b/queue-5.10/power-supply-bq27xxx-fix-wrong-errno-when-bus-ops-ar.patch @@ -0,0 +1,61 @@ +From 083835ba1d199f3091fffac767a7b7dfdf0395c0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Dec 2025 16:34:36 +0800 +Subject: power: supply: bq27xxx: fix wrong errno when bus ops are unsupported + +From: Haotian Zhang + +[ Upstream commit 688364a11647dc09ba1e4429313e0008066ec790 ] + +bq27xxx_write(), bq27xxx_read_block(), and bq27xxx_write_block() +return -EPERM when the bus callback pointer is NULL. A NULL callback +indicates the operation is not supported by the bus/driver, +not that permission is denied. + +Return -EOPNOTSUPP instead of -EPERM when di->bus.write/ +read_bulk/write_bulk is NULL. + +Fixes: 14073f6614f6 ("power: supply: bq27xxx: Add bulk transfer bus methods") +Signed-off-by: Haotian Zhang +Reviewed-by: Matt Ranostay +Link: https://patch.msgid.link/20251204083436.1367-1-vulab@iscas.ac.cn +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/bq27xxx_battery.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c +index 1bd48e4e26d49..44198b181c962 100644 +--- a/drivers/power/supply/bq27xxx_battery.c ++++ b/drivers/power/supply/bq27xxx_battery.c +@@ -1118,7 +1118,7 @@ static inline int bq27xxx_write(struct bq27xxx_device_info *di, int reg_index, + return -EINVAL; + + if (!di->bus.write) +- return -EPERM; ++ return -EOPNOTSUPP; + + ret = di->bus.write(di, di->regs[reg_index], value, single); + if (ret < 0) +@@ -1137,7 +1137,7 @@ static inline int bq27xxx_read_block(struct bq27xxx_device_info *di, int reg_ind + return -EINVAL; + + if (!di->bus.read_bulk) +- return -EPERM; ++ return -EOPNOTSUPP; + + ret = di->bus.read_bulk(di, di->regs[reg_index], data, len); + if (ret < 0) +@@ -1156,7 +1156,7 @@ static inline int bq27xxx_write_block(struct bq27xxx_device_info *di, int reg_in + return -EINVAL; + + if (!di->bus.write_bulk) +- return -EPERM; ++ return -EOPNOTSUPP; + + ret = di->bus.write_bulk(di, di->regs[reg_index], data, len); + if (ret < 0) +-- +2.51.0 + diff --git a/queue-5.10/power-supply-cpcap-battery-fix-use-after-free-in-pow.patch b/queue-5.10/power-supply-cpcap-battery-fix-use-after-free-in-pow.patch new file mode 100644 index 0000000000..3d4361f4b9 --- /dev/null +++ b/queue-5.10/power-supply-cpcap-battery-fix-use-after-free-in-pow.patch @@ -0,0 +1,70 @@ +From dde6cd4e7d28fca5b13af730b8fd35181d69df86 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:36:00 +0100 +Subject: power: supply: cpcap-battery: Fix use-after-free in + power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 642f33e34b969eedec334738fd5df95d2dc42742 ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: 874b2adbed12 ("power: supply: cpcap-battery: Add a battery driver") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/81db58d610c9a51a68184f856cd431a934cccee2.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/cpcap-battery.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/power/supply/cpcap-battery.c b/drivers/power/supply/cpcap-battery.c +index 793d4ca52f8a1..e39f7f7414cb9 100644 +--- a/drivers/power/supply/cpcap-battery.c ++++ b/drivers/power/supply/cpcap-battery.c +@@ -888,10 +888,6 @@ static int cpcap_battery_probe(struct platform_device *pdev) + + platform_set_drvdata(pdev, ddata); + +- error = cpcap_battery_init_interrupts(pdev, ddata); +- if (error) +- return error; +- + error = cpcap_battery_init_iio(ddata); + if (error) + return error; +@@ -919,6 +915,10 @@ static int cpcap_battery_probe(struct platform_device *pdev) + return error; + } + ++ error = cpcap_battery_init_interrupts(pdev, ddata); ++ if (error) ++ return error; ++ + atomic_set(&ddata->active, 1); + + error = cpcap_battery_calibrate(ddata); +-- +2.51.0 + diff --git a/queue-5.10/power-supply-goldfish-fix-use-after-free-in-power_su.patch b/queue-5.10/power-supply-goldfish-fix-use-after-free-in-power_su.patch new file mode 100644 index 0000000000..c5210712a9 --- /dev/null +++ b/queue-5.10/power-supply-goldfish-fix-use-after-free-in-power_su.patch @@ -0,0 +1,73 @@ +From 82c320fb3c105621351a6e311cfd22e1503ca6ab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:36:00 +0100 +Subject: power: supply: goldfish: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit b2ce982e2e0c888dc55c888ad0e20ea04daf2e6b ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: 84d7b7687489 ("power: Add battery driver for goldfish emulator") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/500a606bb6fb6f2bb8d797e19a00cea9dd7b03c1.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/goldfish_battery.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/power/supply/goldfish_battery.c b/drivers/power/supply/goldfish_battery.c +index bf1754355c9fc..c7502fa8efa7b 100644 +--- a/drivers/power/supply/goldfish_battery.c ++++ b/drivers/power/supply/goldfish_battery.c +@@ -226,12 +226,6 @@ static int goldfish_battery_probe(struct platform_device *pdev) + return -ENODEV; + } + +- ret = devm_request_irq(&pdev->dev, data->irq, +- goldfish_battery_interrupt, +- IRQF_SHARED, pdev->name, data); +- if (ret) +- return ret; +- + psy_cfg.drv_data = data; + + data->ac = power_supply_register(&pdev->dev, &ac_desc, &psy_cfg); +@@ -247,6 +241,12 @@ static int goldfish_battery_probe(struct platform_device *pdev) + + platform_set_drvdata(pdev, data); + ++ ret = devm_request_irq(&pdev->dev, data->irq, ++ goldfish_battery_interrupt, ++ IRQF_SHARED, pdev->name, data); ++ if (ret) ++ return ret; ++ + GOLDFISH_BATTERY_WRITE(data, BATTERY_INT_ENABLE, BATTERY_INT_MASK); + return 0; + } +-- +2.51.0 + diff --git a/queue-5.10/power-supply-rt9455-fix-use-after-free-in-power_supp.patch b/queue-5.10/power-supply-rt9455-fix-use-after-free-in-power_supp.patch new file mode 100644 index 0000000000..2586f0fa5c --- /dev/null +++ b/queue-5.10/power-supply-rt9455-fix-use-after-free-in-power_supp.patch @@ -0,0 +1,78 @@ +From c5d9177aeda8ada90b455d166a83780dc5283090 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:36:02 +0100 +Subject: power: supply: rt9455: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit e2febe375e5ea5afed92f4cd9711bde8f24ee6d2 ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: e86d69dd786e ("power_supply: Add support for Richtek RT9455 battery charger") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/1567d831e04c3e2fcb9e18dd36b7bcba4634581a.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/rt9455_charger.c | 17 +++++++++-------- + 1 file changed, 9 insertions(+), 8 deletions(-) + +diff --git a/drivers/power/supply/rt9455_charger.c b/drivers/power/supply/rt9455_charger.c +index a84afccd509f1..89b414fac6c3a 100644 +--- a/drivers/power/supply/rt9455_charger.c ++++ b/drivers/power/supply/rt9455_charger.c +@@ -1665,6 +1665,15 @@ static int rt9455_probe(struct i2c_client *client, + rt9455_charger_config.supplied_to = rt9455_charger_supplied_to; + rt9455_charger_config.num_supplicants = + ARRAY_SIZE(rt9455_charger_supplied_to); ++ ++ info->charger = devm_power_supply_register(dev, &rt9455_charger_desc, ++ &rt9455_charger_config); ++ if (IS_ERR(info->charger)) { ++ dev_err(dev, "Failed to register charger\n"); ++ ret = PTR_ERR(info->charger); ++ goto put_usb_notifier; ++ } ++ + ret = devm_request_threaded_irq(dev, client->irq, NULL, + rt9455_irq_handler_thread, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, +@@ -1680,14 +1689,6 @@ static int rt9455_probe(struct i2c_client *client, + goto put_usb_notifier; + } + +- info->charger = devm_power_supply_register(dev, &rt9455_charger_desc, +- &rt9455_charger_config); +- if (IS_ERR(info->charger)) { +- dev_err(dev, "Failed to register charger\n"); +- ret = PTR_ERR(info->charger); +- goto put_usb_notifier; +- } +- + return 0; + + put_usb_notifier: +-- +2.51.0 + diff --git a/queue-5.10/power-supply-sbs-battery-fix-use-after-free-in-power.patch b/queue-5.10/power-supply-sbs-battery-fix-use-after-free-in-power.patch new file mode 100644 index 0000000000..e65422dbe7 --- /dev/null +++ b/queue-5.10/power-supply-sbs-battery-fix-use-after-free-in-power.patch @@ -0,0 +1,101 @@ +From dca0ca0fad6d3eb2e36e1a28aa9206807f10315b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:36:02 +0100 +Subject: power: supply: sbs-battery: Fix use-after-free in + power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 8d59cf3887fbabacef53bfba473e33e8a8d9d07b ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. Keep the old behavior of +just printing a warning in case of any failures during the IRQ request +and finishing the probe successfully. + +Fixes: d2cec82c2880 ("power: sbs-battery: Request threaded irq and fix dev callback cookie") +Signed-off-by: Waqar Hameed +Reviewed-by: Phil Reid +Link: https://patch.msgid.link/0ef896e002495e615157b482d18a437af19ddcd0.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/sbs-battery.c | 36 +++++++++++++++--------------- + 1 file changed, 18 insertions(+), 18 deletions(-) + +diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c +index b6a538ebb378f..ee8816ce0b800 100644 +--- a/drivers/power/supply/sbs-battery.c ++++ b/drivers/power/supply/sbs-battery.c +@@ -1131,24 +1131,6 @@ static int sbs_probe(struct i2c_client *client) + + i2c_set_clientdata(client, chip); + +- if (!chip->gpio_detect) +- goto skip_gpio; +- +- irq = gpiod_to_irq(chip->gpio_detect); +- if (irq <= 0) { +- dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq); +- goto skip_gpio; +- } +- +- rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq, +- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, +- dev_name(&client->dev), chip); +- if (rc) { +- dev_warn(&client->dev, "Failed to request irq: %d\n", rc); +- goto skip_gpio; +- } +- +-skip_gpio: + /* + * Before we register, we might need to make sure we can actually talk + * to the battery. +@@ -1176,6 +1158,24 @@ static int sbs_probe(struct i2c_client *client) + goto exit_psupply; + } + ++ if (!chip->gpio_detect) ++ goto out; ++ ++ irq = gpiod_to_irq(chip->gpio_detect); ++ if (irq <= 0) { ++ dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq); ++ goto out; ++ } ++ ++ rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq, ++ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, ++ dev_name(&client->dev), chip); ++ if (rc) { ++ dev_warn(&client->dev, "Failed to request irq: %d\n", rc); ++ goto out; ++ } ++ ++out: + dev_info(&client->dev, + "%s: battery gas gauge device registered\n", client->name); + +-- +2.51.0 + diff --git a/queue-5.10/power-supply-wm97xx-fix-null-pointer-dereference-in-.patch b/queue-5.10/power-supply-wm97xx-fix-null-pointer-dereference-in-.patch new file mode 100644 index 0000000000..d1b52d41c3 --- /dev/null +++ b/queue-5.10/power-supply-wm97xx-fix-null-pointer-dereference-in-.patch @@ -0,0 +1,98 @@ +From 8c045c07e9718b6f29dae64a1bc4859fc3d8da9f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:46:24 +0100 +Subject: power: supply: wm97xx: Fix NULL pointer dereference in + power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 39fe0eac6d755ef215026518985fcf8de9360e9e ] + +In `probe()`, `request_irq()` is called before allocating/registering a +`power_supply` handle. If an interrupt is fired between the call to +`request_irq()` and `power_supply_register()`, the `power_supply` handle +will be used uninitialized in `power_supply_changed()` in +`wm97xx_bat_update()` (triggered from the interrupt handler). This will +lead to a `NULL` pointer dereference since + +Fix this racy `NULL` pointer dereference by making sure the IRQ is +requested _after_ the registration of the `power_supply` handle. Since +the IRQ is the last thing requests in the `probe()` now, remove the +error path for freeing it. Instead add one for unregistering the +`power_supply` handle when IRQ request fails. + +Fixes: 7c87942aef52 ("wm97xx_battery: Use irq to detect charger state") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/97b55f0479a932eea7213844bf66f28a974e27a2.1766270196.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/wm97xx_battery.c | 34 +++++++++++++++------------ + 1 file changed, 19 insertions(+), 15 deletions(-) + +diff --git a/drivers/power/supply/wm97xx_battery.c b/drivers/power/supply/wm97xx_battery.c +index a0e1eaa25d93e..e2a41f9c903c5 100644 +--- a/drivers/power/supply/wm97xx_battery.c ++++ b/drivers/power/supply/wm97xx_battery.c +@@ -178,12 +178,6 @@ static int wm97xx_bat_probe(struct platform_device *dev) + "failed to get charge GPIO\n"); + if (charge_gpiod) { + gpiod_set_consumer_name(charge_gpiod, "BATT CHRG"); +- ret = request_irq(gpiod_to_irq(charge_gpiod), +- wm97xx_chrg_irq, 0, +- "AC Detect", dev); +- if (ret) +- return dev_err_probe(&dev->dev, ret, +- "failed to request GPIO irq\n"); + props++; /* POWER_SUPPLY_PROP_STATUS */ + } + +@@ -199,10 +193,8 @@ static int wm97xx_bat_probe(struct platform_device *dev) + props++; /* POWER_SUPPLY_PROP_VOLTAGE_MIN */ + + prop = kcalloc(props, sizeof(*prop), GFP_KERNEL); +- if (!prop) { +- ret = -ENOMEM; +- goto err3; +- } ++ if (!prop) ++ return -ENOMEM; + + prop[i++] = POWER_SUPPLY_PROP_PRESENT; + if (charge_gpiod) +@@ -236,15 +228,27 @@ static int wm97xx_bat_probe(struct platform_device *dev) + schedule_work(&bat_work); + } else { + ret = PTR_ERR(bat_psy); +- goto err4; ++ goto free; ++ } ++ ++ if (charge_gpiod) { ++ ret = request_irq(gpiod_to_irq(charge_gpiod), wm97xx_chrg_irq, ++ 0, "AC Detect", dev); ++ if (ret) { ++ dev_err_probe(&dev->dev, ret, ++ "failed to request GPIO irq\n"); ++ goto unregister; ++ } + } + + return 0; +-err4: ++ ++unregister: ++ power_supply_unregister(bat_psy); ++ ++free: + kfree(prop); +-err3: +- if (charge_gpiod) +- free_irq(gpiod_to_irq(charge_gpiod), dev); ++ + return ret; + } + +-- +2.51.0 + diff --git a/queue-5.10/power-supply-wm97xx_battery-convert-to-gpio-descript.patch b/queue-5.10/power-supply-wm97xx_battery-convert-to-gpio-descript.patch new file mode 100644 index 0000000000..93cc390eda --- /dev/null +++ b/queue-5.10/power-supply-wm97xx_battery-convert-to-gpio-descript.patch @@ -0,0 +1,186 @@ +From e35653f1cd1d6ebc16c85544b31929acdf5bc7ef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 Jan 2021 00:45:08 +0100 +Subject: power: supply: wm97xx_battery: Convert to GPIO descriptor + +From: Linus Walleij + +[ Upstream commit cb6d6918c56ffd98e88164d5471f692d33dabf2b ] + +This converts the WM97xx driver to use a GPIO descriptor +instead of passing a GPIO number thru platform data. + +Like everything else in the driver, use a simple local +variable for the descriptor, it can only ever appear in +one instance anyway so it should not hurt. + +After converting the driver I noticed that none of the +boardfiles actually define a meaningful GPIO line for +this, but hey, it is converted. + +Cc: Haojian Zhuang +Cc: Robert Jarzmik +Cc: linux-arm-kernel@lists.infradead.org +Signed-off-by: Linus Walleij +Reviewed-by: Daniel Mack +Signed-off-by: Sebastian Reichel +Stable-dep-of: 39fe0eac6d75 ("power: supply: wm97xx: Fix NULL pointer dereference in power_supply_changed()") +Signed-off-by: Sasha Levin +--- + arch/arm/mach-pxa/mioa701.c | 1 - + arch/arm/mach-pxa/palm27x.c | 1 - + arch/arm/mach-pxa/palmte2.c | 1 - + drivers/power/supply/wm97xx_battery.c | 45 +++++++++++---------------- + include/linux/wm97xx.h | 1 - + 5 files changed, 19 insertions(+), 30 deletions(-) + +diff --git a/arch/arm/mach-pxa/mioa701.c b/arch/arm/mach-pxa/mioa701.c +index d3af80317f2da..a79f296e81e02 100644 +--- a/arch/arm/mach-pxa/mioa701.c ++++ b/arch/arm/mach-pxa/mioa701.c +@@ -577,7 +577,6 @@ static struct platform_device power_dev = { + static struct wm97xx_batt_pdata mioa701_battery_data = { + .batt_aux = WM97XX_AUX_ID1, + .temp_aux = -1, +- .charge_gpio = -1, + .min_voltage = 0xc00, + .max_voltage = 0xfc0, + .batt_tech = POWER_SUPPLY_TECHNOLOGY_LION, +diff --git a/arch/arm/mach-pxa/palm27x.c b/arch/arm/mach-pxa/palm27x.c +index 0d246a1aebbcd..6230381a7ca0c 100644 +--- a/arch/arm/mach-pxa/palm27x.c ++++ b/arch/arm/mach-pxa/palm27x.c +@@ -212,7 +212,6 @@ void __init palm27x_irda_init(int pwdn) + static struct wm97xx_batt_pdata palm27x_batt_pdata = { + .batt_aux = WM97XX_AUX_ID3, + .temp_aux = WM97XX_AUX_ID2, +- .charge_gpio = -1, + .batt_mult = 1000, + .batt_div = 414, + .temp_mult = 1, +diff --git a/arch/arm/mach-pxa/palmte2.c b/arch/arm/mach-pxa/palmte2.c +index e3bcf58b4e639..a2b10db4aacc4 100644 +--- a/arch/arm/mach-pxa/palmte2.c ++++ b/arch/arm/mach-pxa/palmte2.c +@@ -273,7 +273,6 @@ static struct platform_device power_supply = { + static struct wm97xx_batt_pdata palmte2_batt_pdata = { + .batt_aux = WM97XX_AUX_ID3, + .temp_aux = WM97XX_AUX_ID2, +- .charge_gpio = -1, + .max_voltage = PALMTE2_BAT_MAX_VOLTAGE, + .min_voltage = PALMTE2_BAT_MIN_VOLTAGE, + .batt_mult = 1000, +diff --git a/drivers/power/supply/wm97xx_battery.c b/drivers/power/supply/wm97xx_battery.c +index 58f01659daa5f..a0e1eaa25d93e 100644 +--- a/drivers/power/supply/wm97xx_battery.c ++++ b/drivers/power/supply/wm97xx_battery.c +@@ -15,11 +15,12 @@ + #include + #include + #include +-#include ++#include + #include + #include + + static struct work_struct bat_work; ++static struct gpio_desc *charge_gpiod; + static DEFINE_MUTEX(work_lock); + static int bat_status = POWER_SUPPLY_STATUS_UNKNOWN; + static enum power_supply_property *prop; +@@ -96,12 +97,11 @@ static void wm97xx_bat_external_power_changed(struct power_supply *bat_ps) + static void wm97xx_bat_update(struct power_supply *bat_ps) + { + int old_status = bat_status; +- struct wm97xx_batt_pdata *pdata = power_supply_get_drvdata(bat_ps); + + mutex_lock(&work_lock); + +- bat_status = (pdata->charge_gpio >= 0) ? +- (gpio_get_value(pdata->charge_gpio) ? ++ bat_status = (charge_gpiod) ? ++ (gpiod_get_value(charge_gpiod) ? + POWER_SUPPLY_STATUS_DISCHARGING : + POWER_SUPPLY_STATUS_CHARGING) : + POWER_SUPPLY_STATUS_UNKNOWN; +@@ -171,18 +171,19 @@ static int wm97xx_bat_probe(struct platform_device *dev) + if (dev->id != -1) + return -EINVAL; + +- if (gpio_is_valid(pdata->charge_gpio)) { +- ret = gpio_request(pdata->charge_gpio, "BATT CHRG"); +- if (ret) +- goto err; +- ret = gpio_direction_input(pdata->charge_gpio); +- if (ret) +- goto err2; +- ret = request_irq(gpio_to_irq(pdata->charge_gpio), ++ charge_gpiod = devm_gpiod_get_optional(&dev->dev, NULL, GPIOD_IN); ++ if (IS_ERR(charge_gpiod)) ++ return dev_err_probe(&dev->dev, ++ PTR_ERR(charge_gpiod), ++ "failed to get charge GPIO\n"); ++ if (charge_gpiod) { ++ gpiod_set_consumer_name(charge_gpiod, "BATT CHRG"); ++ ret = request_irq(gpiod_to_irq(charge_gpiod), + wm97xx_chrg_irq, 0, + "AC Detect", dev); + if (ret) +- goto err2; ++ return dev_err_probe(&dev->dev, ret, ++ "failed to request GPIO irq\n"); + props++; /* POWER_SUPPLY_PROP_STATUS */ + } + +@@ -204,7 +205,7 @@ static int wm97xx_bat_probe(struct platform_device *dev) + } + + prop[i++] = POWER_SUPPLY_PROP_PRESENT; +- if (pdata->charge_gpio >= 0) ++ if (charge_gpiod) + prop[i++] = POWER_SUPPLY_PROP_STATUS; + if (pdata->batt_tech >= 0) + prop[i++] = POWER_SUPPLY_PROP_TECHNOLOGY; +@@ -242,23 +243,15 @@ static int wm97xx_bat_probe(struct platform_device *dev) + err4: + kfree(prop); + err3: +- if (gpio_is_valid(pdata->charge_gpio)) +- free_irq(gpio_to_irq(pdata->charge_gpio), dev); +-err2: +- if (gpio_is_valid(pdata->charge_gpio)) +- gpio_free(pdata->charge_gpio); +-err: ++ if (charge_gpiod) ++ free_irq(gpiod_to_irq(charge_gpiod), dev); + return ret; + } + + static int wm97xx_bat_remove(struct platform_device *dev) + { +- struct wm97xx_batt_pdata *pdata = dev->dev.platform_data; +- +- if (pdata && gpio_is_valid(pdata->charge_gpio)) { +- free_irq(gpio_to_irq(pdata->charge_gpio), dev); +- gpio_free(pdata->charge_gpio); +- } ++ if (charge_gpiod) ++ free_irq(gpiod_to_irq(charge_gpiod), dev); + cancel_work_sync(&bat_work); + power_supply_unregister(bat_psy); + kfree(prop); +diff --git a/include/linux/wm97xx.h b/include/linux/wm97xx.h +index 58e082dadc683..462854f4f286c 100644 +--- a/include/linux/wm97xx.h ++++ b/include/linux/wm97xx.h +@@ -294,7 +294,6 @@ struct wm97xx { + struct wm97xx_batt_pdata { + int batt_aux; + int temp_aux; +- int charge_gpio; + int min_voltage; + int max_voltage; + int batt_div; +-- +2.51.0 + diff --git a/queue-5.10/powerpc-eeh-fix-recursive-pci_lock_rescan_remove-loc.patch b/queue-5.10/powerpc-eeh-fix-recursive-pci_lock_rescan_remove-loc.patch new file mode 100644 index 0000000000..6dbd3b27e0 --- /dev/null +++ b/queue-5.10/powerpc-eeh-fix-recursive-pci_lock_rescan_remove-loc.patch @@ -0,0 +1,275 @@ +From 6b5428ef1e062ab83d07bd69f3bddccfe1ada02c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 10 Dec 2025 08:25:59 -0600 +Subject: powerpc/eeh: fix recursive pci_lock_rescan_remove locking in EEH + event handling +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Narayana Murty N + +[ Upstream commit 815a8d2feb5615ae7f0b5befd206af0b0160614c ] + +The recent commit 1010b4c012b0 ("powerpc/eeh: Make EEH driver device +hotplug safe") restructured the EEH driver to improve synchronization +with the PCI hotplug layer. + +However, it inadvertently moved pci_lock_rescan_remove() outside its +intended scope in eeh_handle_normal_event(), leading to broken PCI +error reporting and improper EEH event triggering. Specifically, +eeh_handle_normal_event() acquired pci_lock_rescan_remove() before +calling eeh_pe_bus_get(), but eeh_pe_bus_get() itself attempts to +acquire the same lock internally, causing nested locking and disrupting +normal EEH event handling paths. + +This patch adds a boolean parameter do_lock to _eeh_pe_bus_get(), +with two public wrappers: + eeh_pe_bus_get() with locking enabled. + eeh_pe_bus_get_nolock() that skips locking. + +Callers that already hold pci_lock_rescan_remove() now use +eeh_pe_bus_get_nolock() to avoid recursive lock acquisition. + +Additionally, pci_lock_rescan_remove() calls are restored to the correct +position—after eeh_pe_bus_get() and immediately before iterating affected +PEs and devices. This ensures EEH-triggered PCI removes occur under proper +bus rescan locking without recursive lock contention. + +The eeh_pe_loc_get() function has been split into two functions: + eeh_pe_loc_get(struct eeh_pe *pe) which retrieves the loc for given PE. + eeh_pe_loc_get_bus(struct pci_bus *bus) which retrieves the location + code for given bus. + +This resolves lockdep warnings such as: + +[ 84.964298] [ T928] ============================================ +[ 84.964304] [ T928] WARNING: possible recursive locking detected +[ 84.964311] [ T928] 6.18.0-rc3 #51 Not tainted +[ 84.964315] [ T928] -------------------------------------------- +[ 84.964320] [ T928] eehd/928 is trying to acquire lock: +[ 84.964324] [ T928] c000000003b29d58 (pci_rescan_remove_lock){+.+.}-{3:3}, at: pci_lock_rescan_remove+0x28/0x40 +[ 84.964342] [ T928] + but task is already holding lock: +[ 84.964347] [ T928] c000000003b29d58 (pci_rescan_remove_lock){+.+.}-{3:3}, at: pci_lock_rescan_remove+0x28/0x40 +[ 84.964357] [ T928] + other info that might help us debug this: +[ 84.964363] [ T928] Possible unsafe locking scenario: + +[ 84.964367] [ T928] CPU0 +[ 84.964370] [ T928] ---- +[ 84.964373] [ T928] lock(pci_rescan_remove_lock); +[ 84.964378] [ T928] lock(pci_rescan_remove_lock); +[ 84.964383] [ T928] + *** DEADLOCK *** + +[ 84.964388] [ T928] May be due to missing lock nesting notation + +[ 84.964393] [ T928] 1 lock held by eehd/928: +[ 84.964397] [ T928] #0: c000000003b29d58 (pci_rescan_remove_lock){+.+.}-{3:3}, at: pci_lock_rescan_remove+0x28/0x40 +[ 84.964408] [ T928] + stack backtrace: +[ 84.964414] [ T928] CPU: 2 UID: 0 PID: 928 Comm: eehd Not tainted 6.18.0-rc3 #51 VOLUNTARY +[ 84.964417] [ T928] Hardware name: IBM,9080-HEX POWER10 (architected) 0x800200 0xf000006 of:IBM,FW1060.00 (NH1060_022) hv:phyp pSeries +[ 84.964419] [ T928] Call Trace: +[ 84.964420] [ T928] [c0000011a7157990] [c000000001705de4] dump_stack_lvl+0xc8/0x130 (unreliable) +[ 84.964424] [ T928] [c0000011a71579d0] [c0000000002f66e0] print_deadlock_bug+0x430/0x440 +[ 84.964428] [ T928] [c0000011a7157a70] [c0000000002fd0c0] __lock_acquire+0x1530/0x2d80 +[ 84.964431] [ T928] [c0000011a7157ba0] [c0000000002fea54] lock_acquire+0x144/0x410 +[ 84.964433] [ T928] [c0000011a7157cb0] [c0000011a7157cb0] __mutex_lock+0xf4/0x1050 +[ 84.964436] [ T928] [c0000011a7157e00] [c000000000de21d8] pci_lock_rescan_remove+0x28/0x40 +[ 84.964439] [ T928] [c0000011a7157e20] [c00000000004ed98] eeh_pe_bus_get+0x48/0xc0 +[ 84.964442] [ T928] [c0000011a7157e50] [c000000000050434] eeh_handle_normal_event+0x64/0xa60 +[ 84.964446] [ T928] [c0000011a7157f30] [c000000000051de8] eeh_event_handler+0xf8/0x190 +[ 84.964450] [ T928] [c0000011a7157f90] [c0000000002747ac] kthread+0x16c/0x180 +[ 84.964453] [ T928] [c0000011a7157fe0] [c00000000000ded8] start_kernel_thread+0x14/0x18 + + +Fixes: 1010b4c012b0 ("powerpc/eeh: Make EEH driver device hotplug safe") +Signed-off-by: Narayana Murty N +Reviewed-by: Sourabh Jain +Reviewed-by: Mahesh Salgaonkar +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/20251210142559.8874-1-nnmlinux@linux.ibm.com +Signed-off-by: Sasha Levin +--- + arch/powerpc/include/asm/eeh.h | 2 + + arch/powerpc/kernel/eeh_driver.c | 11 ++--- + arch/powerpc/kernel/eeh_pe.c | 74 ++++++++++++++++++++++++++++++-- + 3 files changed, 78 insertions(+), 9 deletions(-) + +diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h +index b1a5bba2e0b94..2c9dc733accfd 100644 +--- a/arch/powerpc/include/asm/eeh.h ++++ b/arch/powerpc/include/asm/eeh.h +@@ -289,6 +289,8 @@ void eeh_pe_dev_traverse(struct eeh_pe *root, + void eeh_pe_restore_bars(struct eeh_pe *pe); + const char *eeh_pe_loc_get(struct eeh_pe *pe); + struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe); ++const char *eeh_pe_loc_get_bus(struct pci_bus *bus); ++struct pci_bus *eeh_pe_bus_get_nolock(struct eeh_pe *pe); + + void eeh_show_enabled(void); + int __init eeh_init(struct eeh_ops *ops); +diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c +index 2f13d906e1fcb..20106e490b9c6 100644 +--- a/arch/powerpc/kernel/eeh_driver.c ++++ b/arch/powerpc/kernel/eeh_driver.c +@@ -847,7 +847,7 @@ void eeh_handle_normal_event(struct eeh_pe *pe) + + pci_lock_rescan_remove(); + +- bus = eeh_pe_bus_get(pe); ++ bus = eeh_pe_bus_get_nolock(pe); + if (!bus) { + pr_err("%s: Cannot find PCI bus for PHB#%x-PE#%x\n", + __func__, pe->phb->global_number, pe->addr); +@@ -878,14 +878,15 @@ void eeh_handle_normal_event(struct eeh_pe *pe) + /* Log the event */ + if (pe->type & EEH_PE_PHB) { + pr_err("EEH: Recovering PHB#%x, location: %s\n", +- pe->phb->global_number, eeh_pe_loc_get(pe)); ++ pe->phb->global_number, eeh_pe_loc_get_bus(bus)); + } else { + struct eeh_pe *phb_pe = eeh_phb_pe_get(pe->phb); + + pr_err("EEH: Recovering PHB#%x-PE#%x\n", + pe->phb->global_number, pe->addr); + pr_err("EEH: PE location: %s, PHB location: %s\n", +- eeh_pe_loc_get(pe), eeh_pe_loc_get(phb_pe)); ++ eeh_pe_loc_get_bus(bus), ++ eeh_pe_loc_get_bus(eeh_pe_bus_get_nolock(phb_pe))); + } + + #ifdef CONFIG_STACKTRACE +@@ -1093,7 +1094,7 @@ void eeh_handle_normal_event(struct eeh_pe *pe) + eeh_pe_state_clear(pe, EEH_PE_PRI_BUS, true); + eeh_pe_dev_mode_mark(pe, EEH_DEV_REMOVED); + +- bus = eeh_pe_bus_get(pe); ++ bus = eeh_pe_bus_get_nolock(pe); + if (bus) + pci_hp_remove_devices(bus); + else +@@ -1217,7 +1218,7 @@ void eeh_handle_special_event(void) + (phb_pe->state & EEH_PE_RECOVERING)) + continue; + +- bus = eeh_pe_bus_get(phb_pe); ++ bus = eeh_pe_bus_get_nolock(phb_pe); + if (!bus) { + pr_err("%s: Cannot find PCI bus for " + "PHB#%x-PE#%x\n", +diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c +index fea58e9546f98..6f69242142e0d 100644 +--- a/arch/powerpc/kernel/eeh_pe.c ++++ b/arch/powerpc/kernel/eeh_pe.c +@@ -811,6 +811,24 @@ void eeh_pe_restore_bars(struct eeh_pe *pe) + const char *eeh_pe_loc_get(struct eeh_pe *pe) + { + struct pci_bus *bus = eeh_pe_bus_get(pe); ++ return eeh_pe_loc_get_bus(bus); ++} ++ ++/** ++ * eeh_pe_loc_get_bus - Retrieve location code binding to the given PCI bus ++ * @bus: PCI bus ++ * ++ * Retrieve the location code associated with the given PCI bus. If the bus ++ * is a root bus, the location code is fetched from the PHB device tree node ++ * or root port. Otherwise, the location code is obtained from the device ++ * tree node of the upstream bridge of the bus. The function walks up the ++ * bus hierarchy if necessary, checking each node for the appropriate ++ * location code property ("ibm,io-base-loc-code" for root buses, ++ * "ibm,slot-location-code" for others). If no location code is found, ++ * returns "N/A". ++ */ ++const char *eeh_pe_loc_get_bus(struct pci_bus *bus) ++{ + struct device_node *dn; + const char *loc = NULL; + +@@ -837,8 +855,9 @@ const char *eeh_pe_loc_get(struct eeh_pe *pe) + } + + /** +- * eeh_pe_bus_get - Retrieve PCI bus according to the given PE ++ * _eeh_pe_bus_get - Retrieve PCI bus according to the given PE + * @pe: EEH PE ++ * @do_lock: Is the caller already held the pci_lock_rescan_remove? + * + * Retrieve the PCI bus according to the given PE. Basically, + * there're 3 types of PEs: PHB/Bus/Device. For PHB PE, the +@@ -846,7 +865,7 @@ const char *eeh_pe_loc_get(struct eeh_pe *pe) + * returned for BUS PE. However, we don't have associated PCI + * bus for DEVICE PE. + */ +-struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe) ++static struct pci_bus *_eeh_pe_bus_get(struct eeh_pe *pe, bool do_lock) + { + struct eeh_dev *edev; + struct pci_dev *pdev; +@@ -861,11 +880,58 @@ struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe) + + /* Retrieve the parent PCI bus of first (top) PCI device */ + edev = list_first_entry_or_null(&pe->edevs, struct eeh_dev, entry); +- pci_lock_rescan_remove(); ++ if (do_lock) ++ pci_lock_rescan_remove(); + pdev = eeh_dev_to_pci_dev(edev); + if (pdev) + bus = pdev->bus; +- pci_unlock_rescan_remove(); ++ if (do_lock) ++ pci_unlock_rescan_remove(); + + return bus; + } ++ ++/** ++ * eeh_pe_bus_get - Retrieve PCI bus associated with the given EEH PE, locking ++ * if needed ++ * @pe: Pointer to the EEH PE ++ * ++ * This function is a wrapper around _eeh_pe_bus_get(), which retrieves the PCI ++ * bus associated with the provided EEH PE structure. It acquires the PCI ++ * rescans lock to ensure safe access to shared data during the retrieval ++ * process. This function should be used when the caller requires the PCI bus ++ * while holding the rescan/remove lock, typically during operations that modify ++ * or inspect PCIe device state in a safe manner. ++ * ++ * RETURNS: ++ * A pointer to the PCI bus associated with the EEH PE, or NULL if none found. ++ */ ++ ++struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe) ++{ ++ return _eeh_pe_bus_get(pe, true); ++} ++ ++/** ++ * eeh_pe_bus_get_nolock - Retrieve PCI bus associated with the given EEH PE ++ * without locking ++ * @pe: Pointer to the EEH PE ++ * ++ * This function is a variant of _eeh_pe_bus_get() that retrieves the PCI bus ++ * associated with the specified EEH PE without acquiring the ++ * pci_lock_rescan_remove lock. It should only be used when the caller can ++ * guarantee safe access to PE structures without the need for that lock, ++ * typically in contexts where the lock is already held locking is otherwise ++ * managed. ++ * ++ * RETURNS: ++ * pointer to the PCI bus associated with the EEH PE, or NULL if none is found. ++ * ++ * NOTE: ++ * Use this function carefully to avoid race conditions and data corruption. ++ */ ++ ++struct pci_bus *eeh_pe_bus_get_nolock(struct eeh_pe *pe) ++{ ++ return _eeh_pe_bus_get(pe, false); ++} +-- +2.51.0 + diff --git a/queue-5.10/procfs-fix-missing-rcu-protection-when-reading-real_.patch b/queue-5.10/procfs-fix-missing-rcu-protection-when-reading-real_.patch new file mode 100644 index 0000000000..7750e9ec47 --- /dev/null +++ b/queue-5.10/procfs-fix-missing-rcu-protection-when-reading-real_.patch @@ -0,0 +1,59 @@ +From 1c64b24b68b6129053ee97995e871b10e76f0bac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 16:30:07 +0800 +Subject: procfs: fix missing RCU protection when reading real_parent in + do_task_stat() + +From: Jinliang Zheng + +[ Upstream commit 76149d53502cf17ef3ae454ff384551236fba867 ] + +When reading /proc/[pid]/stat, do_task_stat() accesses task->real_parent +without proper RCU protection, which leads to: + + cpu 0 cpu 1 + ----- ----- + do_task_stat + var = task->real_parent + release_task + call_rcu(delayed_put_task_struct) + task_tgid_nr_ns(var) + rcu_read_lock <--- Too late to protect task->real_parent! + task_pid_ptr <--- UAF! + rcu_read_unlock + +This patch uses task_ppid_nr_ns() instead of task_tgid_nr_ns() to add +proper RCU protection for accessing task->real_parent. + +Link: https://lkml.kernel.org/r/20260128083007.3173016-1-alexjlzheng@tencent.com +Fixes: 06fffb1267c9 ("do_task_stat: don't take rcu_read_lock()") +Signed-off-by: Jinliang Zheng +Acked-by: Oleg Nesterov +Cc: David Hildenbrand +Cc: Ingo Molnar +Cc: Lorenzo Stoakes +Cc: Mateusz Guzik +Cc: ruippan +Cc: Usama Arif +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/proc/array.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/proc/array.c b/fs/proc/array.c +index 77b94c04e4aff..e97ad2bd7a9dc 100644 +--- a/fs/proc/array.c ++++ b/fs/proc/array.c +@@ -492,7 +492,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, + rsslim = READ_ONCE(sig->rlim[RLIMIT_RSS].rlim_cur); + + sid = task_session_nr_ns(task, ns); +- ppid = task_tgid_nr_ns(task->real_parent, ns); ++ ppid = task_ppid_nr_ns(task, ns); + pgid = task_pgrp_nr_ns(task, ns); + + unlock_task_sighand(task, &flags); +-- +2.51.0 + diff --git a/queue-5.10/pstore-ram-fix-buffer-overflow-in-persistent_ram_sav.patch b/queue-5.10/pstore-ram-fix-buffer-overflow-in-persistent_ram_sav.patch new file mode 100644 index 0000000000..7fa26fe4c4 --- /dev/null +++ b/queue-5.10/pstore-ram-fix-buffer-overflow-in-persistent_ram_sav.patch @@ -0,0 +1,92 @@ +From 6db57e79e54303666fe7431447a1e14a98db1123 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 1 Feb 2026 13:22:40 +0000 +Subject: pstore/ram: fix buffer overflow in persistent_ram_save_old() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Sai Ritvik Tanksalkar + +[ Upstream commit 5669645c052f235726a85f443769b6fc02f66762 ] + +persistent_ram_save_old() can be called multiple times for the same +persistent_ram_zone (e.g., via ramoops_pstore_read -> ramoops_get_next_prz +for PSTORE_TYPE_DMESG records). + +Currently, the function only allocates prz->old_log when it is NULL, +but it unconditionally updates prz->old_log_size to the current buffer +size and then performs memcpy_fromio() using this new size. If the +buffer size has grown since the first allocation (which can happen +across different kernel boot cycles), this leads to: + +1. A heap buffer overflow (OOB write) in the memcpy_fromio() calls +2. A subsequent OOB read when ramoops_pstore_read() accesses the buffer + using the incorrect (larger) old_log_size + +The KASAN splat would look similar to: + BUG: KASAN: slab-out-of-bounds in ramoops_pstore_read+0x... + Read of size N at addr ... by task ... + +The conditions are likely extremely hard to hit: + + 0. Crash with a ramoops write of less-than-record-max-size bytes. + 1. Reboot: ramoops registers, pstore_get_records(0) reads old crash, + allocates old_log with size X + 2. Crash handler registered, timer started (if pstore_update_ms >= 0) + 3. Oops happens (non-fatal, system continues) + 4. pstore_dump() writes oops via ramoops_pstore_write() size Y (>X) + 5. pstore_new_entry = 1, pstore_timer_kick() called + 6. System continues running (not a panic oops) + 7. Timer fires after pstore_update_ms milliseconds + 8. pstore_timefunc() → schedule_work() → pstore_dowork() → pstore_get_records(1) + 9. ramoops_get_next_prz() → persistent_ram_save_old() + 10. buffer_size() returns Y, but old_log is X bytes + 11. Y > X: memcpy_fromio() overflows heap + + Requirements: + - a prior crash record exists that did not fill the record size + (almost impossible since the crash handler writes as much as it + can possibly fit into the record, capped by max record size and + the kmsg buffer almost always exceeds the max record size) + - pstore_update_ms >= 0 (disabled by default) + - Non-fatal oops (system survives) + +Free and reallocate the buffer when the new size differs from the +previously allocated size. This ensures old_log always has sufficient +space for the data being copied. + +Fixes: 201e4aca5aa1 ("pstore/ram: Should update old dmesg buffer before reading") +Signed-off-by: Sai Ritvik Tanksalkar +Link: https://patch.msgid.link/20260201132240.2948732-1-stanksal@purdue.edu +Signed-off-by: Kees Cook +Signed-off-by: Sasha Levin +--- + fs/pstore/ram_core.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c +index 5ac9b1f155a81..97ec9041b9b98 100644 +--- a/fs/pstore/ram_core.c ++++ b/fs/pstore/ram_core.c +@@ -298,6 +298,17 @@ void persistent_ram_save_old(struct persistent_ram_zone *prz) + if (!size) + return; + ++ /* ++ * If the existing buffer is differently sized, free it so a new ++ * one is allocated. This can happen when persistent_ram_save_old() ++ * is called early in boot and later for a timer-triggered ++ * survivable crash when the crash dumps don't match in size ++ * (which would be extremely unlikely given kmsg buffers usually ++ * exceed prz buffer sizes). ++ */ ++ if (prz->old_log && prz->old_log_size != size) ++ persistent_ram_free_old(prz); ++ + if (!prz->old_log) { + persistent_ram_ecc_old(prz); + prz->old_log = kmalloc(size, GFP_KERNEL); +-- +2.51.0 + diff --git a/queue-5.10/rdma-core-add-rdma_rw_max_sge-helper-for-sq-sizing.patch b/queue-5.10/rdma-core-add-rdma_rw_max_sge-helper-for-sq-sizing.patch new file mode 100644 index 0000000000..d89d8118a5 --- /dev/null +++ b/queue-5.10/rdma-core-add-rdma_rw_max_sge-helper-for-sq-sizing.patch @@ -0,0 +1,159 @@ +From b10a9c3a234d081af8385978e20100f6b93eec0d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 19:53:59 -0500 +Subject: RDMA/core: add rdma_rw_max_sge() helper for SQ sizing + +From: Chuck Lever + +[ Upstream commit afcae7d7b8a278a6c29e064f99e5bafd4ac1fb37 ] + +svc_rdma_accept() computes sc_sq_depth as the sum of rq_depth and the +number of rdma_rw contexts (ctxts). This value is used to allocate the +Send CQ and to initialize the sc_sq_avail credit pool. + +However, when the device uses memory registration for RDMA operations, +rdma_rw_init_qp() inflates the QP's max_send_wr by a factor of three +per context to account for REG and INV work requests. The Send CQ and +credit pool remain sized for only one work request per context, +causing Send Queue exhaustion under heavy NFS WRITE workloads. + +Introduce rdma_rw_max_sge() to compute the actual number of Send Queue +entries required for a given number of rdma_rw contexts. Upper layer +protocols call this helper before creating a Queue Pair so that their +Send CQs and credit accounting match the QP's true capacity. + +Update svc_rdma_accept() to use rdma_rw_max_sge() when computing +sc_sq_depth, ensuring the credit pool reflects the work requests +that rdma_rw_init_qp() will reserve. + +Reviewed-by: Christoph Hellwig +Fixes: 00bd1439f464 ("RDMA/rw: Support threshold for registration vs scattering to local pages") +Signed-off-by: Chuck Lever +Link: https://patch.msgid.link/20260128005400.25147-5-cel@kernel.org +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/rw.c | 53 +++++++++++++++++------- + include/rdma/rw.h | 2 + + net/sunrpc/xprtrdma/svc_rdma_transport.c | 8 +++- + 3 files changed, 46 insertions(+), 17 deletions(-) + +diff --git a/drivers/infiniband/core/rw.c b/drivers/infiniband/core/rw.c +index 3cc5ed902976b..d479408a2cf73 100644 +--- a/drivers/infiniband/core/rw.c ++++ b/drivers/infiniband/core/rw.c +@@ -660,34 +660,57 @@ unsigned int rdma_rw_mr_factor(struct ib_device *device, u8 port_num, + } + EXPORT_SYMBOL(rdma_rw_mr_factor); + ++/** ++ * rdma_rw_max_send_wr - compute max Send WRs needed for RDMA R/W contexts ++ * @dev: RDMA device ++ * @port_num: port number ++ * @max_rdma_ctxs: number of rdma_rw_ctx structures ++ * @create_flags: QP create flags (pass IB_QP_CREATE_INTEGRITY_EN if ++ * data integrity will be enabled on the QP) ++ * ++ * Returns the total number of Send Queue entries needed for ++ * @max_rdma_ctxs. The result accounts for memory registration and ++ * invalidation work requests when the device requires them. ++ * ++ * ULPs use this to size Send Queues and Send CQs before creating a ++ * Queue Pair. ++ */ ++unsigned int rdma_rw_max_send_wr(struct ib_device *dev, u32 port_num, ++ unsigned int max_rdma_ctxs, u32 create_flags) ++{ ++ unsigned int factor = 1; ++ unsigned int result; ++ ++ if (create_flags & IB_QP_CREATE_INTEGRITY_EN || ++ rdma_rw_can_use_mr(dev, port_num)) ++ factor += 2; /* reg + inv */ ++ ++ if (check_mul_overflow(factor, max_rdma_ctxs, &result)) ++ return UINT_MAX; ++ return result; ++} ++EXPORT_SYMBOL(rdma_rw_max_send_wr); ++ + void rdma_rw_init_qp(struct ib_device *dev, struct ib_qp_init_attr *attr) + { +- u32 factor; ++ unsigned int factor = 1; + + WARN_ON_ONCE(attr->port_num == 0); + + /* +- * Each context needs at least one RDMA READ or WRITE WR. +- * +- * For some hardware we might need more, eventually we should ask the +- * HCA driver for a multiplier here. +- */ +- factor = 1; +- +- /* +- * If the device needs MRs to perform RDMA READ or WRITE operations, +- * we'll need two additional MRs for the registrations and the +- * invalidation. ++ * If the device uses MRs to perform RDMA READ or WRITE operations, ++ * or if data integrity is enabled, account for registration and ++ * invalidation work requests. + */ + if (attr->create_flags & IB_QP_CREATE_INTEGRITY_EN || + rdma_rw_can_use_mr(dev, attr->port_num)) +- factor += 2; /* inv + reg */ ++ factor += 2; /* reg + inv */ + + attr->cap.max_send_wr += factor * attr->cap.max_rdma_ctxs; + + /* +- * But maybe we were just too high in the sky and the device doesn't +- * even support all we need, and we'll have to live with what we get.. ++ * The device might not support all we need, and we'll have to ++ * live with what we get. + */ + attr->cap.max_send_wr = + min_t(u32, attr->cap.max_send_wr, dev->attrs.max_qp_wr); +diff --git a/include/rdma/rw.h b/include/rdma/rw.h +index 6ad9dc836c107..b7249929109dd 100644 +--- a/include/rdma/rw.h ++++ b/include/rdma/rw.h +@@ -66,6 +66,8 @@ int rdma_rw_ctx_post(struct rdma_rw_ctx *ctx, struct ib_qp *qp, u8 port_num, + + unsigned int rdma_rw_mr_factor(struct ib_device *device, u8 port_num, + unsigned int maxpages); ++unsigned int rdma_rw_max_send_wr(struct ib_device *dev, u32 port_num, ++ unsigned int max_rdma_ctxs, u32 create_flags); + void rdma_rw_init_qp(struct ib_device *dev, struct ib_qp_init_attr *attr); + int rdma_rw_init_mrs(struct ib_qp *qp, struct ib_qp_init_attr *attr); + void rdma_rw_cleanup_mrs(struct ib_qp *qp); +diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c +index 7b7d2add99a4c..1041ea72b3613 100644 +--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c ++++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c +@@ -418,7 +418,10 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + newxprt->sc_max_bc_requests = 2; + } + +- /* Arbitrary estimate of the needed number of rdma_rw contexts. ++ /* Estimate the needed number of rdma_rw contexts. The maximum ++ * Read and Write chunks have one segment each. Each request ++ * can involve one Read chunk and either a Write chunk or Reply ++ * chunk; thus a factor of three. + */ + maxpayload = min(xprt->xpt_server->sv_max_payload, + RPCSVC_MAXPAYLOAD_RDMA); +@@ -426,7 +429,8 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + rdma_rw_mr_factor(dev, newxprt->sc_port_num, + maxpayload >> PAGE_SHIFT); + +- newxprt->sc_sq_depth = rq_depth + ctxts; ++ newxprt->sc_sq_depth = rq_depth + ++ rdma_rw_max_send_wr(dev, newxprt->sc_port_num, ctxts, 0); + if (newxprt->sc_sq_depth > dev->attrs.max_qp_wr) + newxprt->sc_sq_depth = dev->attrs.max_qp_wr; + atomic_set(&newxprt->sc_sq_avail, newxprt->sc_sq_depth); +-- +2.51.0 + diff --git a/queue-5.10/rdma-core-fix-a-couple-of-obvious-typos-in-comments.patch b/queue-5.10/rdma-core-fix-a-couple-of-obvious-typos-in-comments.patch new file mode 100644 index 0000000000..ebf388e8d2 --- /dev/null +++ b/queue-5.10/rdma-core-fix-a-couple-of-obvious-typos-in-comments.patch @@ -0,0 +1,50 @@ +From f5f36151f8d3e33998ce66e2287590f3bb904b97 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Oct 2023 11:29:41 -0400 +Subject: RDMA/core: Fix a couple of obvious typos in comments + +From: Chuck Lever + +[ Upstream commit 0aa44595d61ca9e61239f321fec799518884feb3 ] + +Fix typos. + +Signed-off-by: Chuck Lever +Link: https://lore.kernel.org/r/169643338101.8035.6826446669479247727.stgit@manet.1015granger.net +Signed-off-by: Leon Romanovsky +Stable-dep-of: afcae7d7b8a2 ("RDMA/core: add rdma_rw_max_sge() helper for SQ sizing") +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/rw.c | 2 +- + include/rdma/ib_verbs.h | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/infiniband/core/rw.c b/drivers/infiniband/core/rw.c +index a96030b784eb2..3cc5ed902976b 100644 +--- a/drivers/infiniband/core/rw.c ++++ b/drivers/infiniband/core/rw.c +@@ -675,7 +675,7 @@ void rdma_rw_init_qp(struct ib_device *dev, struct ib_qp_init_attr *attr) + factor = 1; + + /* +- * If the devices needs MRs to perform RDMA READ or WRITE operations, ++ * If the device needs MRs to perform RDMA READ or WRITE operations, + * we'll need two additional MRs for the registrations and the + * invalidation. + */ +diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h +index ac6ffa5618843..495bf66620a6f 100644 +--- a/include/rdma/ib_verbs.h ++++ b/include/rdma/ib_verbs.h +@@ -1070,7 +1070,7 @@ struct ib_qp_cap { + + /* + * Maximum number of rdma_rw_ctx structures in flight at a time. +- * ib_create_qp() will calculate the right amount of neededed WRs ++ * ib_create_qp() will calculate the right amount of needed WRs + * and MRs based on this. + */ + u32 max_rdma_ctxs; +-- +2.51.0 + diff --git a/queue-5.10/rdma-rtrs-server-remove-dead-code.patch b/queue-5.10/rdma-rtrs-server-remove-dead-code.patch new file mode 100644 index 0000000000..400e4a43c0 --- /dev/null +++ b/queue-5.10/rdma-rtrs-server-remove-dead-code.patch @@ -0,0 +1,57 @@ +From dbff82870ae043489d9af5dd06f37e1d0b923493 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Dec 2025 10:38:19 +0800 +Subject: RDMA/rtrs: server: remove dead code + +From: Honggang LI + +[ Upstream commit a3572bdc3a028ca47f77d7166ac95b719cf77d50 ] + +As rkey had been initialized to zero, the WARN_ON_ONCE should never been +triggered. Remove it. + +Fixes: 9cb837480424 ("RDMA/rtrs: server: main functionality") +Signed-off-by: Honggang LI +Link: https://patch.msgid.link/20251224023819.138846-1-honggangli@163.com +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/ulp/rtrs/rtrs-srv.c | 8 +------- + 1 file changed, 1 insertion(+), 7 deletions(-) + +diff --git a/drivers/infiniband/ulp/rtrs/rtrs-srv.c b/drivers/infiniband/ulp/rtrs/rtrs-srv.c +index 3e6f12f98a890..bb19bbc564413 100644 +--- a/drivers/infiniband/ulp/rtrs/rtrs-srv.c ++++ b/drivers/infiniband/ulp/rtrs/rtrs-srv.c +@@ -239,7 +239,6 @@ static int rdma_write_sg(struct rtrs_srv_op *id) + size_t sg_cnt; + int err, offset; + bool need_inval; +- u32 rkey = 0; + struct ib_reg_wr rwr; + struct ib_sge *plist; + struct ib_sge list; +@@ -271,11 +270,6 @@ static int rdma_write_sg(struct rtrs_srv_op *id) + wr->wr.num_sge = 1; + wr->remote_addr = le64_to_cpu(id->rd_msg->desc[0].addr); + wr->rkey = le32_to_cpu(id->rd_msg->desc[0].key); +- if (rkey == 0) +- rkey = wr->rkey; +- else +- /* Only one key is actually used */ +- WARN_ON_ONCE(rkey != wr->rkey); + + wr->wr.opcode = IB_WR_RDMA_WRITE; + wr->wr.wr_cqe = &io_comp_cqe; +@@ -308,7 +302,7 @@ static int rdma_write_sg(struct rtrs_srv_op *id) + inv_wr.opcode = IB_WR_SEND_WITH_INV; + inv_wr.wr_cqe = &io_comp_cqe; + inv_wr.send_flags = 0; +- inv_wr.ex.invalidate_rkey = rkey; ++ inv_wr.ex.invalidate_rkey = wr->rkey; + } + + imm_wr.wr.next = NULL; +-- +2.51.0 + diff --git a/queue-5.10/rdma-rxe-fix-double-free-in-rxe_srq_from_init.patch b/queue-5.10/rdma-rxe-fix-double-free-in-rxe_srq_from_init.patch new file mode 100644 index 0000000000..fe7ce32f63 --- /dev/null +++ b/queue-5.10/rdma-rxe-fix-double-free-in-rxe_srq_from_init.patch @@ -0,0 +1,57 @@ +From 93b7a1966daffd4ebaa937b67822d37650a7d82e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 01:54:12 +0000 +Subject: RDMA/rxe: Fix double free in rxe_srq_from_init + +From: Jiasheng Jiang + +[ Upstream commit 0beefd0e15d962f497aad750b2d5e9c3570b66d1 ] + +In rxe_srq_from_init(), the queue pointer 'q' is assigned to +'srq->rq.queue' before copying the SRQ number to user space. +If copy_to_user() fails, the function calls rxe_queue_cleanup() +to free the queue, but leaves the now-invalid pointer in +'srq->rq.queue'. + +The caller of rxe_srq_from_init() (rxe_create_srq) eventually +calls rxe_srq_cleanup() upon receiving the error, which triggers +a second rxe_queue_cleanup() on the same memory, leading to a +double free. + +The call trace looks like this: + kmem_cache_free+0x.../0x... + rxe_queue_cleanup+0x1a/0x30 [rdma_rxe] + rxe_srq_cleanup+0x42/0x60 [rdma_rxe] + rxe_elem_release+0x31/0x70 [rdma_rxe] + rxe_create_srq+0x12b/0x1a0 [rdma_rxe] + ib_create_srq_user+0x9a/0x150 [ib_core] + +Fix this by moving 'srq->rq.queue = q' after copy_to_user. + +Fixes: aae0484e15f0 ("IB/rxe: avoid srq memory leak") +Signed-off-by: Jiasheng Jiang +Link: https://patch.msgid.link/20260112015412.29458-1-jiashengjiangcool@gmail.com +Reviewed-by: Zhu Yanjun +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/sw/rxe/rxe_srq.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/infiniband/sw/rxe/rxe_srq.c b/drivers/infiniband/sw/rxe/rxe_srq.c +index 41b0d1e11bafd..9d9baca269499 100644 +--- a/drivers/infiniband/sw/rxe/rxe_srq.c ++++ b/drivers/infiniband/sw/rxe/rxe_srq.c +@@ -116,6 +116,9 @@ int rxe_srq_from_init(struct rxe_dev *rxe, struct rxe_srq *srq, + } + } + ++ srq->rq.queue = q; ++ init->attr.max_wr = srq->rq.max_wr; ++ + return 0; + } + +-- +2.51.0 + diff --git a/queue-5.10/rdma-uverbs-add-__gfp_nowarn-to-ib_uverbs_unmarshall.patch b/queue-5.10/rdma-uverbs-add-__gfp_nowarn-to-ib_uverbs_unmarshall.patch new file mode 100644 index 0000000000..551e7973e6 --- /dev/null +++ b/queue-5.10/rdma-uverbs-add-__gfp_nowarn-to-ib_uverbs_unmarshall.patch @@ -0,0 +1,39 @@ +From 40f587496a437818dbdda6855a2f57b18fc1a2b3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 17:49:00 +0800 +Subject: RDMA/uverbs: Add __GFP_NOWARN to ib_uverbs_unmarshall_recv() kmalloc + +From: Yi Liu + +[ Upstream commit 58b604dfc7bb753f91bc0ccd3fa705e14e6edfb4 ] + +Since wqe_size in ib_uverbs_unmarshall_recv() is user-provided and already +validated, but can still be large, add __GFP_NOWARN to suppress memory +allocation warnings for large sizes, consistent with the similar fix in +ib_uverbs_post_send(). + +Fixes: 67cdb40ca444 ("[IB] uverbs: Implement more commands") +Signed-off-by: Yi Liu +Link: https://patch.msgid.link/20260129094900.3517706-1-liuy22@mails.tsinghua.edu.cn +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/uverbs_cmd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c +index cdcdafee07f68..732940483811a 100644 +--- a/drivers/infiniband/core/uverbs_cmd.c ++++ b/drivers/infiniband/core/uverbs_cmd.c +@@ -2210,7 +2210,7 @@ ib_uverbs_unmarshall_recv(struct uverbs_req_iter *iter, u32 wr_count, + if (ret) + return ERR_PTR(ret); + +- user_wr = kmalloc(wqe_size, GFP_KERNEL); ++ user_wr = kmalloc(wqe_size, GFP_KERNEL | __GFP_NOWARN); + if (!user_wr) + return ERR_PTR(-ENOMEM); + +-- +2.51.0 + diff --git a/queue-5.10/rdma-uverbs-validate-wqe_size-before-using-it-in-ib_.patch b/queue-5.10/rdma-uverbs-validate-wqe_size-before-using-it-in-ib_.patch new file mode 100644 index 0000000000..dcf740c214 --- /dev/null +++ b/queue-5.10/rdma-uverbs-validate-wqe_size-before-using-it-in-ib_.patch @@ -0,0 +1,57 @@ +From 8d8d547931b782784cbd40ff1f014b4987282af2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 22:29:00 +0800 +Subject: RDMA/uverbs: Validate wqe_size before using it in ib_uverbs_post_send + +From: Yi Liu + +[ Upstream commit 1956f0a74ccf5dc9c3ef717f2985c3ed3400aab0 ] + +ib_uverbs_post_send() uses cmd.wqe_size from userspace without any +validation before passing it to kmalloc() and using the allocated +buffer as struct ib_uverbs_send_wr. + +If a user provides a small wqe_size value (e.g., 1), kmalloc() will +succeed, but subsequent accesses to user_wr->opcode, user_wr->num_sge, +and other fields will read beyond the allocated buffer, resulting in +an out-of-bounds read from kernel heap memory. This could potentially +leak sensitive kernel information to userspace. + +Additionally, providing an excessively large wqe_size can trigger a +WARNING in the memory allocation path, as reported by syzkaller. + +This is inconsistent with ib_uverbs_unmarshall_recv() which properly +validates that wqe_size >= sizeof(struct ib_uverbs_recv_wr) before +proceeding. + +Add the same validation for ib_uverbs_post_send() to ensure wqe_size +is at least sizeof(struct ib_uverbs_send_wr). + +Fixes: c3bea3d2dc53 ("RDMA/uverbs: Use the iterator for ib_uverbs_unmarshall_recv()") +Signed-off-by: Yi Liu +Link: https://patch.msgid.link/20260122142900.2356276-2-liuy22@mails.tsinghua.edu.cn +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/uverbs_cmd.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c +index 6658de58b5144..cdcdafee07f68 100644 +--- a/drivers/infiniband/core/uverbs_cmd.c ++++ b/drivers/infiniband/core/uverbs_cmd.c +@@ -2017,7 +2017,10 @@ static int ib_uverbs_post_send(struct uverbs_attr_bundle *attrs) + if (ret) + return ret; + +- user_wr = kmalloc(cmd.wqe_size, GFP_KERNEL); ++ if (cmd.wqe_size < sizeof(struct ib_uverbs_send_wr)) ++ return -EINVAL; ++ ++ user_wr = kmalloc(cmd.wqe_size, GFP_KERNEL | __GFP_NOWARN); + if (!user_wr) + return -ENOMEM; + +-- +2.51.0 + diff --git a/queue-5.10/regulator-core-fix-off-on-delay-us-for-always-on-boo.patch b/queue-5.10/regulator-core-fix-off-on-delay-us-for-always-on-boo.patch new file mode 100644 index 0000000000..7c5f97f5af --- /dev/null +++ b/queue-5.10/regulator-core-fix-off-on-delay-us-for-always-on-boo.patch @@ -0,0 +1,57 @@ +From 266979e63f81b7f5ed3817c63b38be18239c69ca Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 Jul 2022 16:02:00 +0200 +Subject: regulator: core: Fix off-on-delay-us for always-on/boot-on regulators +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Christian Kohlschütter + +[ Upstream commit 218320fec29430438016f88dd4fbebfa1b95ad8d ] + +Regulators marked with "regulator-always-on" or "regulator-boot-on" +as well as an "off-on-delay-us", may run into cycling issues that are +hard to detect. + +This is caused by the "last_off" state not being initialized in this +case. + +Fix the "last_off" initialization by setting it to the current kernel +time upon initialization, regardless of always_on/boot_on state. + +Signed-off-by: Christian Kohlschütter +Link: https://lore.kernel.org/r/FAFD5B39-E9C4-47C7-ACF1-2A04CD59758D@kohlschutter.com +Signed-off-by: Mark Brown +Stable-dep-of: 86a8eeb0e913 ("regulator: core: move supply check earlier in set_machine_constraints()") +Signed-off-by: Sasha Levin +--- + drivers/regulator/core.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c +index c7c82e958a7d4..84578a107fef2 100644 +--- a/drivers/regulator/core.c ++++ b/drivers/regulator/core.c +@@ -1509,6 +1509,9 @@ static int set_machine_constraints(struct regulator_dev *rdev) + rdev->constraints->always_on = true; + } + ++ if (rdev->desc->off_on_delay) ++ rdev->last_off = ktime_get(); ++ + /* If the constraints say the regulator should be on at this point + * and we have control then make sure it is enabled. + */ +@@ -1547,8 +1550,6 @@ static int set_machine_constraints(struct regulator_dev *rdev) + + if (rdev->constraints->always_on) + rdev->use_count++; +- } else if (rdev->desc->off_on_delay) { +- rdev->last_off = ktime_get(); + } + + print_constraints(rdev); +-- +2.51.0 + diff --git a/queue-5.10/regulator-core-fix-off_on_delay-handling.patch b/queue-5.10/regulator-core-fix-off_on_delay-handling.patch new file mode 100644 index 0000000000..0a9eb3cb3e --- /dev/null +++ b/queue-5.10/regulator-core-fix-off_on_delay-handling.patch @@ -0,0 +1,117 @@ +From ee59992f7b42174d74e93fc5c2e17cdb069f526d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Apr 2021 13:45:24 +0200 +Subject: regulator: core: Fix off_on_delay handling + +From: Vincent Whitchurch + +[ Upstream commit a8ce7bd89689997537dd22dcbced46cf23dc19da ] + +The jiffies-based off_on_delay implementation has a couple of problems +that cause it to sometimes not actually delay for the required time: + + (1) If, for example, the off_on_delay time is equivalent to one jiffy, + and the ->last_off_jiffy is set just before a new jiffy starts, + then _regulator_do_enable() does not wait at all since it checks + using time_before(). + + (2) When jiffies overflows, the value of "remaining" becomes higher + than "max_delay" and the code simply proceeds without waiting. + +Fix these problems by changing it to use ktime_t instead. + +[Note that since jiffies doesn't start at zero but at INITIAL_JIFFIES + ("-5 minutes"), (2) above also led to the code not delaying if + the first regulator_enable() is called when the ->last_off_jiffy is not + initialised, such as for regulators with ->constraints->boot_on set. + It's not clear to me if this was intended or not, but I've preserved + this behaviour explicitly with the check for a non-zero ->last_off.] + +Signed-off-by: Vincent Whitchurch +Link: https://lore.kernel.org/r/20210423114524.26414-1-vincent.whitchurch@axis.com +Signed-off-by: Mark Brown +Stable-dep-of: 86a8eeb0e913 ("regulator: core: move supply check earlier in set_machine_constraints()") +Signed-off-by: Sasha Levin +--- + drivers/regulator/core.c | 33 ++++++++------------------------ + include/linux/regulator/driver.h | 2 +- + 2 files changed, 9 insertions(+), 26 deletions(-) + +diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c +index 38c01516d2ed0..3147498948373 100644 +--- a/drivers/regulator/core.c ++++ b/drivers/regulator/core.c +@@ -1530,7 +1530,7 @@ static int set_machine_constraints(struct regulator_dev *rdev) + if (rdev->constraints->always_on) + rdev->use_count++; + } else if (rdev->desc->off_on_delay) { +- rdev->last_off_jiffy = jiffies; ++ rdev->last_off = ktime_get(); + } + + print_constraints(rdev); +@@ -2604,29 +2604,15 @@ static int _regulator_do_enable(struct regulator_dev *rdev) + + trace_regulator_enable(rdev_get_name(rdev)); + +- if (rdev->desc->off_on_delay) { ++ if (rdev->desc->off_on_delay && rdev->last_off) { + /* if needed, keep a distance of off_on_delay from last time + * this regulator was disabled. + */ +- unsigned long start_jiffy = jiffies; +- unsigned long intended, max_delay, remaining; +- +- max_delay = usecs_to_jiffies(rdev->desc->off_on_delay); +- intended = rdev->last_off_jiffy + max_delay; +- +- if (time_before(start_jiffy, intended)) { +- /* calc remaining jiffies to deal with one-time +- * timer wrapping. +- * in case of multiple timer wrapping, either it can be +- * detected by out-of-range remaining, or it cannot be +- * detected and we get a penalty of +- * _regulator_enable_delay(). +- */ +- remaining = intended - start_jiffy; +- if (remaining <= max_delay) +- _regulator_enable_delay( +- jiffies_to_usecs(remaining)); +- } ++ ktime_t end = ktime_add_us(rdev->last_off, rdev->desc->off_on_delay); ++ s64 remaining = ktime_us_delta(end, ktime_get()); ++ ++ if (remaining > 0) ++ _regulator_enable_delay(remaining); + } + + if (rdev->ena_pin) { +@@ -2858,11 +2844,8 @@ static int _regulator_do_disable(struct regulator_dev *rdev) + return ret; + } + +- /* cares about last_off_jiffy only if off_on_delay is required by +- * device. +- */ + if (rdev->desc->off_on_delay) +- rdev->last_off_jiffy = jiffies; ++ rdev->last_off = ktime_get(); + + trace_regulator_disable_complete(rdev_get_name(rdev)); + +diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h +index 633e7a2ab01d0..a465350427087 100644 +--- a/include/linux/regulator/driver.h ++++ b/include/linux/regulator/driver.h +@@ -473,7 +473,7 @@ struct regulator_dev { + unsigned int is_switch:1; + + /* time when this regulator was disabled last time */ +- unsigned long last_off_jiffy; ++ ktime_t last_off; + }; + + struct regulator_dev * +-- +2.51.0 + diff --git a/queue-5.10/regulator-core-move-supply-check-earlier-in-set_mach.patch b/queue-5.10/regulator-core-move-supply-check-earlier-in-set_mach.patch new file mode 100644 index 0000000000..0a93ce1b74 --- /dev/null +++ b/queue-5.10/regulator-core-move-supply-check-earlier-in-set_mach.patch @@ -0,0 +1,121 @@ +From a246ceb51ae30a4093a930ab221f82069ffe77fe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 08:38:39 +0000 +Subject: regulator: core: move supply check earlier in + set_machine_constraints() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: André Draszik + +[ Upstream commit 86a8eeb0e913f4b6a55dabba5122098d4e805e55 ] + +Since commit 98e48cd9283d ("regulator: core: resolve supply for +boot-on/always-on regulators"), set_machine_constraints() can return +-EPROBE_DEFER very late, after it has done a lot of work and +configuration of the regulator. + +This means that configuration will happen multiple times for no +benefit in that case. Furthermore, this can lead to timing-dependent +voltage glitches as mentioned e.g. in commit 8a866d527ac0 ("regulator: +core: Resolve supply name earlier to prevent double-init"). + +We can know that it's going to fail very early, in particular before +going through the complete regulator configuration by moving some code +around a little. + +Do so to avoid re-configuring the regulator multiple times, also +avoiding the voltage glitches if we can. + +Fixes: 98e48cd9283d ("regulator: core: resolve supply for boot-on/always-on regulators") +Signed-off-by: André Draszik +Link: https://patch.msgid.link/20260109-regulators-defer-v2-3-1a25dc968e60@linaro.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/regulator/core.c | 55 ++++++++++++++++++++++------------------ + 1 file changed, 30 insertions(+), 25 deletions(-) + +diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c +index dfc03a2d70959..a04356a644f39 100644 +--- a/drivers/regulator/core.c ++++ b/drivers/regulator/core.c +@@ -1400,6 +1400,33 @@ static int set_machine_constraints(struct regulator_dev *rdev) + int ret = 0; + const struct regulator_ops *ops = rdev->desc->ops; + ++ /* ++ * If there is no mechanism for controlling the regulator then ++ * flag it as always_on so we don't end up duplicating checks ++ * for this so much. Note that we could control the state of ++ * a supply to control the output on a regulator that has no ++ * direct control. ++ */ ++ if (!rdev->ena_pin && !ops->enable) { ++ if (rdev->supply_name && !rdev->supply) ++ return -EPROBE_DEFER; ++ ++ if (rdev->supply) ++ rdev->constraints->always_on = ++ rdev->supply->rdev->constraints->always_on; ++ else ++ rdev->constraints->always_on = true; ++ } ++ ++ /* ++ * If we want to enable this regulator, make sure that we know the ++ * supplying regulator. ++ */ ++ if (rdev->constraints->always_on || rdev->constraints->boot_on) { ++ if (rdev->supply_name && !rdev->supply) ++ return -EPROBE_DEFER; ++ } ++ + ret = machine_constraints_voltage(rdev, rdev->constraints); + if (ret != 0) + return ret; +@@ -1491,37 +1518,15 @@ static int set_machine_constraints(struct regulator_dev *rdev) + } + } + +- /* +- * If there is no mechanism for controlling the regulator then +- * flag it as always_on so we don't end up duplicating checks +- * for this so much. Note that we could control the state of +- * a supply to control the output on a regulator that has no +- * direct control. +- */ +- if (!rdev->ena_pin && !ops->enable) { +- if (rdev->supply_name && !rdev->supply) +- return -EPROBE_DEFER; +- +- if (rdev->supply) +- rdev->constraints->always_on = +- rdev->supply->rdev->constraints->always_on; +- else +- rdev->constraints->always_on = true; +- } +- + /* If the constraints say the regulator should be on at this point + * and we have control then make sure it is enabled. + */ + if (rdev->constraints->always_on || rdev->constraints->boot_on) { + bool supply_enabled = false; + +- /* If we want to enable this regulator, make sure that we know +- * the supplying regulator. +- */ +- if (rdev->supply_name && !rdev->supply) +- return -EPROBE_DEFER; +- +- /* If supplying regulator has already been enabled, ++ /* We have ensured a potential supply has been resolved above. ++ * ++ * If supplying regulator has already been enabled, + * it's not intended to have use_count increment + * when rdev is only boot-on. + */ +-- +2.51.0 + diff --git a/queue-5.10/regulator-core-respect-off_on_delay-at-startup.patch b/queue-5.10/regulator-core-respect-off_on_delay-at-startup.patch new file mode 100644 index 0000000000..f047d8266d --- /dev/null +++ b/queue-5.10/regulator-core-respect-off_on_delay-at-startup.patch @@ -0,0 +1,46 @@ +From 10463da20fbfe106abee4d826e29401896098f37 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Apr 2021 10:30:44 +0200 +Subject: regulator: core: Respect off_on_delay at startup + +From: Vincent Whitchurch + +[ Upstream commit a5ccccb3ec0b052804d03df90c0d08689be54170 ] + +We currently do not respect off_on_delay the first time we turn on a +regulator. This is problematic since the regulator could have been +turned off by the bootloader, or it could it have been turned off during +the probe of the regulator driver (such as when regulator-fixed requests +the enable GPIO), either of which could potentially have happened less +than off_on_delay microseconds ago before the first time a client +requests for the regulator to be turned on. + +We can't know exactly when the regulator was turned off, but initialise +off_on_delay to the current time when registering the regulator, so that +we guarantee that we respect the off_on_delay in all cases. + +Signed-off-by: Vincent Whitchurch +Link: https://lore.kernel.org/r/20210422083044.11479-1-vincent.whitchurch@axis.com +Signed-off-by: Mark Brown +Stable-dep-of: 86a8eeb0e913 ("regulator: core: move supply check earlier in set_machine_constraints()") +Signed-off-by: Sasha Levin +--- + drivers/regulator/core.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c +index 0e2129be02265..38c01516d2ed0 100644 +--- a/drivers/regulator/core.c ++++ b/drivers/regulator/core.c +@@ -1529,6 +1529,8 @@ static int set_machine_constraints(struct regulator_dev *rdev) + + if (rdev->constraints->always_on) + rdev->use_count++; ++ } else if (rdev->desc->off_on_delay) { ++ rdev->last_off_jiffy = jiffies; + } + + print_constraints(rdev); +-- +2.51.0 + diff --git a/queue-5.10/regulator-core-shorten-off-on-delay-us-for-always-on.patch b/queue-5.10/regulator-core-shorten-off-on-delay-us-for-always-on.patch new file mode 100644 index 0000000000..ef1b876980 --- /dev/null +++ b/queue-5.10/regulator-core-shorten-off-on-delay-us-for-always-on.patch @@ -0,0 +1,115 @@ +From daf3fd489c1f3f9c338034d3121a6e3c6665ae51 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Mar 2023 11:18:19 -0700 +Subject: regulator: core: Shorten off-on-delay-us for always-on/boot-on by + time since booted +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Douglas Anderson + +[ Upstream commit 691c1fcda5351ed98a44610b7dccc0e3ee920020 ] + +This is very close to a straight revert of commit 218320fec294 +("regulator: core: Fix off-on-delay-us for always-on/boot-on +regulators"). We've identified that patch as causing a boot speed +regression on sc7180-trogdor boards. While boot speed certainly isn't +more important than making sure that power sequencing is correct, +looking closely at the original change it doesn't seem to have been +fully justified. It mentions "cycling issues" without describing +exactly what the issues were. That means it's possible that the +cycling issues were really a problem that should be fixed in a +different way. + +Let's take a careful look at how we should handle regulators that have +an off-on-delay and that are boot-on or always-on. Linux currently +doesn't have any way to identify whether a GPIO regulator was already +on when the kernel booted. That means that when the kernel boots we +probe a regulator, see that it wants boot-on / always-on we, and then +turn the regulator on. We could be in one of two cases when we do +this: + +a) The regulator might have been left on by the bootloader and we're + ensuring that it stays on. +b) The regulator might have been left off by the bootloader and we're + just now turning it on. + +For case a) we definitely don't need any sort of delay. For case b) we +_might_ need some delay in case the bootloader turned the regulator +off _right_ before booting the kernel. To get the proper delay for +case b) then we can just assume a `last_off` of 0, which is what it +gets initialized to by default. + +As per above, we can't tell whether we're in case a) or case b) so +we'll assume the longer delay (case b). This basically puts the code +to how it was before commit 218320fec294 ("regulator: core: Fix +off-on-delay-us for always-on/boot-on regulators"). However, we add +one important change: we make sure that the delay is actually honored +if `last_off` is 0. Though the original "cycling issues" cited were +vague, I'm hopeful that this important extra change will be enough to +fix the issues that the initial commit mentioned. + +With this fix, I've confined that on a sc7180-trogdor board the delay +at boot goes down from 500 ms to ~250 ms. That's not as good as the 0 +ms that we had prior to commit 218320fec294 ("regulator: core: Fix +off-on-delay-us for always-on/boot-on regulators"), but it's probably +safer because we don't know if the bootloader turned the regulator off +right before booting. + +One note is that it's possible that we could be in a state that's not +a) or b) if there are other issues in the kernel. The only one I can +think of is related to pinctrl. If the pinctrl driver being used on a +board isn't careful about avoiding glitches when setting up a pin then +it's possible that setting up a pin could cause the regulator to "turn +off" briefly immediately before the regulator probes. If this is +indeed causing problems then the pinctrl driver should be fixed, +perhaps in a similar way to what was done in commit d21f4b7ffc22 +("pinctrl: qcom: Avoid glitching lines when we first mux to output") + +Fixes: 218320fec294 ("regulator: core: Fix off-on-delay-us for always-on/boot-on regulators") +Cc: Christian Kohlschütter +Signed-off-by: Douglas Anderson +Link: https://lore.kernel.org/r/20230313111806.1.I2eaad872be0932a805c239a7c7a102233fb0b03b@changeid +Signed-off-by: Mark Brown +Stable-dep-of: 86a8eeb0e913 ("regulator: core: move supply check earlier in set_machine_constraints()") +Signed-off-by: Sasha Levin +--- + drivers/regulator/core.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c +index 6d413f936e0f2..dfc03a2d70959 100644 +--- a/drivers/regulator/core.c ++++ b/drivers/regulator/core.c +@@ -1509,9 +1509,6 @@ static int set_machine_constraints(struct regulator_dev *rdev) + rdev->constraints->always_on = true; + } + +- if (rdev->desc->off_on_delay) +- rdev->last_off = ktime_get_boottime(); +- + /* If the constraints say the regulator should be on at this point + * and we have control then make sure it is enabled. + */ +@@ -1550,6 +1547,8 @@ static int set_machine_constraints(struct regulator_dev *rdev) + + if (rdev->constraints->always_on) + rdev->use_count++; ++ } else if (rdev->desc->off_on_delay) { ++ rdev->last_off = ktime_get(); + } + + print_constraints(rdev); +@@ -2623,7 +2622,7 @@ static int _regulator_do_enable(struct regulator_dev *rdev) + + trace_regulator_enable(rdev_get_name(rdev)); + +- if (rdev->desc->off_on_delay && rdev->last_off) { ++ if (rdev->desc->off_on_delay) { + /* if needed, keep a distance of off_on_delay from last time + * this regulator was disabled. + */ +-- +2.51.0 + diff --git a/queue-5.10/regulator-core-use-ktime_get_boottime-to-determine-h.patch b/queue-5.10/regulator-core-use-ktime_get_boottime-to-determine-h.patch new file mode 100644 index 0000000000..5693d7c20f --- /dev/null +++ b/queue-5.10/regulator-core-use-ktime_get_boottime-to-determine-h.patch @@ -0,0 +1,66 @@ +From 47f3e0bd2d066bc45ca542f98ebcc899ddee68a4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Feb 2023 00:33:30 +0000 +Subject: regulator: core: Use ktime_get_boottime() to determine how long a + regulator was off + +From: Matthias Kaehlcke + +[ Upstream commit 80d2c29e09e663761c2778167a625b25ffe01b6f ] + +For regulators with 'off-on-delay-us' the regulator framework currently +uses ktime_get() to determine how long the regulator has been off +before re-enabling it (after a delay if needed). A problem with using +ktime_get() is that it doesn't account for the time the system is +suspended. As a result a regulator with a longer 'off-on-delay' (e.g. +500ms) that was switched off during suspend might still incurr in a +delay on resume before it is re-enabled, even though the regulator +might have been off for hours. ktime_get_boottime() accounts for +suspend time, use it instead of ktime_get(). + +Fixes: a8ce7bd89689 ("regulator: core: Fix off_on_delay handling") +Cc: stable@vger.kernel.org # 5.13+ +Signed-off-by: Matthias Kaehlcke +Reviewed-by: Stephen Boyd +Link: https://lore.kernel.org/r/20230223003301.v2.1.I9719661b8eb0a73b8c416f9c26cf5bd8c0563f99@changeid +Signed-off-by: Mark Brown +Stable-dep-of: 86a8eeb0e913 ("regulator: core: move supply check earlier in set_machine_constraints()") +Signed-off-by: Sasha Levin +--- + drivers/regulator/core.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c +index 84578a107fef2..6d413f936e0f2 100644 +--- a/drivers/regulator/core.c ++++ b/drivers/regulator/core.c +@@ -1510,7 +1510,7 @@ static int set_machine_constraints(struct regulator_dev *rdev) + } + + if (rdev->desc->off_on_delay) +- rdev->last_off = ktime_get(); ++ rdev->last_off = ktime_get_boottime(); + + /* If the constraints say the regulator should be on at this point + * and we have control then make sure it is enabled. +@@ -2628,7 +2628,7 @@ static int _regulator_do_enable(struct regulator_dev *rdev) + * this regulator was disabled. + */ + ktime_t end = ktime_add_us(rdev->last_off, rdev->desc->off_on_delay); +- s64 remaining = ktime_us_delta(end, ktime_get()); ++ s64 remaining = ktime_us_delta(end, ktime_get_boottime()); + + if (remaining > 0) + _regulator_enable_delay(remaining); +@@ -2864,7 +2864,7 @@ static int _regulator_do_disable(struct regulator_dev *rdev) + } + + if (rdev->desc->off_on_delay) +- rdev->last_off = ktime_get(); ++ rdev->last_off = ktime_get_boottime(); + + trace_regulator_disable_complete(rdev_get_name(rdev)); + +-- +2.51.0 + diff --git a/queue-5.10/regulator-flag-uncontrollable-regulators-as-always_o.patch b/queue-5.10/regulator-flag-uncontrollable-regulators-as-always_o.patch new file mode 100644 index 0000000000..ff5e4afe24 --- /dev/null +++ b/queue-5.10/regulator-flag-uncontrollable-regulators-as-always_o.patch @@ -0,0 +1,58 @@ +From b1aa4464d492037f65b459294176edafca1d9ef9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 25 Mar 2022 14:46:37 +0000 +Subject: regulator: Flag uncontrollable regulators as always_on + +From: Mark Brown + +[ Upstream commit 261f06315cf7c3744731e36bfd8d4434949e3389 ] + +While we currently assume that regulators with no control available are +just uncontionally enabled this isn't always as clearly displayed to +users as is desirable, for example the code for disabling unused +regulators will log that it is about to disable them. Clean this up a +bit by setting always_on during constraint evaluation if we have no +available mechanism for controlling the regualtor so things that check +the constraint will do the right thing. + +Signed-off-by: Mark Brown +Link: https://lore.kernel.org/r/20220325144637.1543496-1-broonie@kernel.org +Signed-off-by: Mark Brown +Stable-dep-of: 86a8eeb0e913 ("regulator: core: move supply check earlier in set_machine_constraints()") +Signed-off-by: Sasha Levin +--- + drivers/regulator/core.c | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c +index 3147498948373..c7c82e958a7d4 100644 +--- a/drivers/regulator/core.c ++++ b/drivers/regulator/core.c +@@ -1491,6 +1491,24 @@ static int set_machine_constraints(struct regulator_dev *rdev) + } + } + ++ /* ++ * If there is no mechanism for controlling the regulator then ++ * flag it as always_on so we don't end up duplicating checks ++ * for this so much. Note that we could control the state of ++ * a supply to control the output on a regulator that has no ++ * direct control. ++ */ ++ if (!rdev->ena_pin && !ops->enable) { ++ if (rdev->supply_name && !rdev->supply) ++ return -EPROBE_DEFER; ++ ++ if (rdev->supply) ++ rdev->constraints->always_on = ++ rdev->supply->rdev->constraints->always_on; ++ else ++ rdev->constraints->always_on = true; ++ } ++ + /* If the constraints say the regulator should be on at this point + * and we have control then make sure it is enabled. + */ +-- +2.51.0 + diff --git a/queue-5.10/revert-hwmon-ibmpex-fix-use-after-free-in-high-low-s.patch b/queue-5.10/revert-hwmon-ibmpex-fix-use-after-free-in-high-low-s.patch new file mode 100644 index 0000000000..5b011d7b0e --- /dev/null +++ b/queue-5.10/revert-hwmon-ibmpex-fix-use-after-free-in-high-low-s.patch @@ -0,0 +1,89 @@ +From 3361abde9c10bf2e60657db0b6aeb513852847c1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Feb 2026 08:12:25 -0800 +Subject: Revert "hwmon: (ibmpex) fix use-after-free in high/low store" + +From: Guenter Roeck + +[ Upstream commit 8bde3e395a85017f12af2b0ba5c3684f5af9c006 ] + +This reverts commit 6946c726c3f4c36f0f049e6f97e88c510b15f65d. + +Jean Delvare points out that the patch does not completely +fix the reported problem, that it in fact introduces a +(new) race condition, and that it may actually not be needed in +the first place. + +Various AI reviews agree. Specific and relevant AI feedback: + +" +This reordering sets the driver data to NULL before removing the sensor +attributes in the loop below. + +ibmpex_show_sensor() retrieves this driver data via dev_get_drvdata() but +does not check if it is NULL before dereferencing it to access +data->sensors[]. + +If a userspace process reads a sensor file (like temp1_input) while this +delete function is running, could it race with the dev_set_drvdata(..., +NULL) call here and crash in ibmpex_show_sensor()? + +Would it be safer to keep the original order where device_remove_file() is +called before clearing the driver data? device_remove_file() should wait +for any active sysfs callbacks to complete, which might already prevent the +use-after-free this patch intends to fix. +" + +Revert the offending patch. If it can be shown that the originally reported +alleged race condition does indeed exist, it can always be re-introduced +with a complete fix. + +Reported-by: Jean Delvare +Closes: https://lore.kernel.org/linux-hwmon/20260121095342.73e723cb@endymion/ +Cc: Jean Delvare +Cc: Junrui Luo +Fixes: 6946c726c3f4 ("hwmon: (ibmpex) fix use-after-free in high/low store") +Reviewed-by: Jean Delvare +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + drivers/hwmon/ibmpex.c | 9 ++------- + 1 file changed, 2 insertions(+), 7 deletions(-) + +diff --git a/drivers/hwmon/ibmpex.c b/drivers/hwmon/ibmpex.c +index 235d56e96879c..fe90f0536d76c 100644 +--- a/drivers/hwmon/ibmpex.c ++++ b/drivers/hwmon/ibmpex.c +@@ -282,9 +282,6 @@ static ssize_t ibmpex_high_low_store(struct device *dev, + { + struct ibmpex_bmc_data *data = dev_get_drvdata(dev); + +- if (!data) +- return -ENODEV; +- + ibmpex_reset_high_low_data(data); + + return count; +@@ -517,9 +514,6 @@ static void ibmpex_bmc_delete(struct ibmpex_bmc_data *data) + { + int i, j; + +- hwmon_device_unregister(data->hwmon_dev); +- dev_set_drvdata(data->bmc_device, NULL); +- + device_remove_file(data->bmc_device, + &sensor_dev_attr_reset_high_low.dev_attr); + device_remove_file(data->bmc_device, &sensor_dev_attr_name.dev_attr); +@@ -533,7 +527,8 @@ static void ibmpex_bmc_delete(struct ibmpex_bmc_data *data) + } + + list_del(&data->list); +- ++ dev_set_drvdata(data->bmc_device, NULL); ++ hwmon_device_unregister(data->hwmon_dev); + ipmi_destroy_user(data->user); + kfree(data->sensors); + kfree(data); +-- +2.51.0 + diff --git a/queue-5.10/revert-mmc-rtsx_pci_sdmmc-increase-power-on-settling.patch b/queue-5.10/revert-mmc-rtsx_pci_sdmmc-increase-power-on-settling.patch new file mode 100644 index 0000000000..bd1370dcbc --- /dev/null +++ b/queue-5.10/revert-mmc-rtsx_pci_sdmmc-increase-power-on-settling.patch @@ -0,0 +1,39 @@ +From 21d202b197b9da34514d4e5da737a382fda3ec8c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 15:49:31 +0100 +Subject: Revert "mmc: rtsx_pci_sdmmc: increase power-on settling delay to 5ms" + +From: Greg Kroah-Hartman + +[ Upstream commit ff112f1ecd10b72004eac05bae395e1c65f0c63c ] + +This reverts commit aced969e9bf3701dc75cfca57c78c031b7875b9d. + +It was determined that this was not the correct "fix", so should be +reverted. + +Fixes: aced969e9bf3 ("mmc: rtsx_pci_sdmmc: increase power-on settling delay to 5ms") +Cc: Matthew Schwartz +Cc: Ulf Hansson +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/mmc/host/rtsx_pci_sdmmc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c +index 97f194afcc643..f0e9a76679945 100644 +--- a/drivers/mmc/host/rtsx_pci_sdmmc.c ++++ b/drivers/mmc/host/rtsx_pci_sdmmc.c +@@ -932,7 +932,7 @@ static int sd_power_on(struct realtek_pci_sdmmc *host, unsigned char power_mode) + if (err < 0) + return err; + +- mdelay(5); ++ mdelay(1); + + err = rtsx_pci_write_register(pcr, CARD_OE, SD_OUTPUT_EN, SD_OUTPUT_EN); + if (err < 0) +-- +2.51.0 + diff --git a/queue-5.10/s390-cio-fix-device-lifecycle-handling-in-css_alloc_.patch b/queue-5.10/s390-cio-fix-device-lifecycle-handling-in-css_alloc_.patch new file mode 100644 index 0000000000..7ea57f3f2c --- /dev/null +++ b/queue-5.10/s390-cio-fix-device-lifecycle-handling-in-css_alloc_.patch @@ -0,0 +1,49 @@ +From c8e6a19f132898ddd28d0ccafd63121f3f8472f6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 21:47:59 +0100 +Subject: s390/cio: Fix device lifecycle handling in css_alloc_subchannel() + +From: Salah Triki + +[ Upstream commit f65c75b0b9b5a390bc3beadcde0a6fbc3ad118f7 ] + +`css_alloc_subchannel()` calls `device_initialize()` before setting up +the DMA masks. If `dma_set_coherent_mask()` or `dma_set_mask()` fails, +the error path frees the subchannel structure directly, bypassing +the device model reference counting. + +Once `device_initialize()` has been called, the embedded struct device +must be released via `put_device()`, allowing the release callback to +free the container structure. + +Fix the error path by dropping the initial device reference with +`put_device()` instead of calling `kfree()` directly. + +This ensures correct device lifetime handling and avoids potential +use-after-free or double-free issues. + +Fixes: e5dcf0025d7af ("s390/css: move subchannel lock allocation") +Signed-off-by: Salah Triki +Reviewed-by: Vineeth Vijayan +Signed-off-by: Heiko Carstens +Signed-off-by: Sasha Levin +--- + drivers/s390/cio/css.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c +index cf2c3c4c590f9..e5e20ea850aad 100644 +--- a/drivers/s390/cio/css.c ++++ b/drivers/s390/cio/css.c +@@ -241,7 +241,7 @@ struct subchannel *css_alloc_subchannel(struct subchannel_id schid, + return sch; + + err: +- kfree(sch); ++ put_device(&sch->dev); + return ERR_PTR(ret); + } + +-- +2.51.0 + diff --git a/queue-5.10/sched-rt-skip-currently-executing-cpu-in-rto_next_cp.patch b/queue-5.10/sched-rt-skip-currently-executing-cpu-in-rto_next_cp.patch new file mode 100644 index 0000000000..0254511157 --- /dev/null +++ b/queue-5.10/sched-rt-skip-currently-executing-cpu-in-rto_next_cp.patch @@ -0,0 +1,87 @@ +From d9266ae52eb27c9b1733bdcb99555f0abca60ce3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 01:25:33 +0000 +Subject: sched/rt: Skip currently executing CPU in rto_next_cpu() + +From: Chen Jinghuang + +[ Upstream commit 94894c9c477e53bcea052e075c53f89df3d2a33e ] + +CPU0 becomes overloaded when hosting a CPU-bound RT task, a non-CPU-bound +RT task, and a CFS task stuck in kernel space. When other CPUs switch from +RT to non-RT tasks, RT load balancing (LB) is triggered; with +HAVE_RT_PUSH_IPI enabled, they send IPIs to CPU0 to drive the execution +of rto_push_irq_work_func. During push_rt_task on CPU0, +if next_task->prio < rq->donor->prio, resched_curr() sets NEED_RESCHED +and after the push operation completes, CPU0 calls rto_next_cpu(). +Since only CPU0 is overloaded in this scenario, rto_next_cpu() should +ideally return -1 (no further IPI needed). + +However, multiple CPUs invoking tell_cpu_to_push() during LB increments +rd->rto_loop_next. Even when rd->rto_cpu is set to -1, the mismatch between +rd->rto_loop and rd->rto_loop_next forces rto_next_cpu() to restart its +search from -1. With CPU0 remaining overloaded (satisfying rt_nr_migratory +&& rt_nr_total > 1), it gets reselected, causing CPU0 to queue irq_work to +itself and send self-IPIs repeatedly. As long as CPU0 stays overloaded and +other CPUs run pull_rt_tasks(), it falls into an infinite self-IPI loop, +which triggers a CPU hardlockup due to continuous self-interrupts. + +The trigging scenario is as follows: + + cpu0 cpu1 cpu2 + pull_rt_task + tell_cpu_to_push + <------------irq_work_queue_on +rto_push_irq_work_func + push_rt_task + resched_curr(rq) pull_rt_task + rto_next_cpu tell_cpu_to_push + <-------------------------- atomic_inc(rto_loop_next) +rd->rto_loop != next + rto_next_cpu + irq_work_queue_on +rto_push_irq_work_func + +Fix redundant self-IPI by filtering the initiating CPU in rto_next_cpu(). +This solution has been verified to effectively eliminate spurious self-IPIs +and prevent CPU hardlockup scenarios. + +Fixes: 4bdced5c9a29 ("sched/rt: Simplify the IPI based RT balancing logic") +Suggested-by: Steven Rostedt (Google) +Suggested-by: K Prateek Nayak +Signed-off-by: Chen Jinghuang +Signed-off-by: Peter Zijlstra (Intel) +Reviewed-by: Steven Rostedt (Google) +Reviewed-by: Valentin Schneider +Link: https://patch.msgid.link/20260122012533.673768-1-chenjinghuang2@huawei.com +Signed-off-by: Sasha Levin +--- + kernel/sched/rt.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c +index 1289991c970e1..cc6950fc6061e 100644 +--- a/kernel/sched/rt.c ++++ b/kernel/sched/rt.c +@@ -2005,6 +2005,7 @@ static void push_rt_tasks(struct rq *rq) + */ + static int rto_next_cpu(struct root_domain *rd) + { ++ int this_cpu = smp_processor_id(); + int next; + int cpu; + +@@ -2028,6 +2029,10 @@ static int rto_next_cpu(struct root_domain *rd) + + rd->rto_cpu = cpu; + ++ /* Do not send IPI to self */ ++ if (cpu == this_cpu) ++ continue; ++ + if (cpu < nr_cpu_ids) + return cpu; + +-- +2.51.0 + diff --git a/queue-5.10/scsi-csiostor-fix-dereference-of-null-pointer-rn.patch b/queue-5.10/scsi-csiostor-fix-dereference-of-null-pointer-rn.patch new file mode 100644 index 0000000000..9322dc6676 --- /dev/null +++ b/queue-5.10/scsi-csiostor-fix-dereference-of-null-pointer-rn.patch @@ -0,0 +1,46 @@ +From b642e8c947e9de8aa9092e836239c7259afb4fe0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 15:53:32 +0000 +Subject: scsi: csiostor: Fix dereference of null pointer rn + +From: Colin Ian King + +[ Upstream commit 1982257570b84dc33753d536dd969fd357a014e9 ] + +The error exit path when rn is NULL ends up deferencing the null pointer rn +via the use of the macro CSIO_INC_STATS. Fix this by adding a new error +return path label after the use of the macro to avoid the deference. + +Fixes: a3667aaed569 ("[SCSI] csiostor: Chelsio FCoE offload driver") +Signed-off-by: Colin Ian King +Link: https://patch.msgid.link/20260129155332.196338-1-colin.i.king@gmail.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/csiostor/csio_scsi.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/scsi/csiostor/csio_scsi.c b/drivers/scsi/csiostor/csio_scsi.c +index 55e74da2f3cbe..e320ca2911e0c 100644 +--- a/drivers/scsi/csiostor/csio_scsi.c ++++ b/drivers/scsi/csiostor/csio_scsi.c +@@ -2070,7 +2070,7 @@ csio_eh_lun_reset_handler(struct scsi_cmnd *cmnd) + struct csio_scsi_level_data sld; + + if (!rn) +- goto fail; ++ goto fail_ret; + + csio_dbg(hw, "Request to reset LUN:%llu (ssni:0x%x tgtid:%d)\n", + cmnd->device->lun, rn->flowid, rn->scsi_id); +@@ -2215,6 +2215,7 @@ csio_eh_lun_reset_handler(struct scsi_cmnd *cmnd) + csio_put_scsi_ioreq_lock(hw, scsim, ioreq); + fail: + CSIO_INC_STATS(rn, n_lun_rst_fail); ++fail_ret: + return FAILED; + } + +-- +2.51.0 + diff --git a/queue-5.10/serial-caif-fix-use-after-free-in-caif_serial-ldisc_.patch b/queue-5.10/serial-caif-fix-use-after-free-in-caif_serial-ldisc_.patch new file mode 100644 index 0000000000..43f967045b --- /dev/null +++ b/queue-5.10/serial-caif-fix-use-after-free-in-caif_serial-ldisc_.patch @@ -0,0 +1,152 @@ +From 86b11ae13132896c8ca73dd60e2f563f1d795ed2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 15:44:44 +0800 +Subject: serial: caif: fix use-after-free in caif_serial ldisc_close() + +From: Jiayuan Chen + +[ Upstream commit 308e7e4d0a846359685f40aade023aee7b27284c ] + +There is a use-after-free bug in caif_serial where handle_tx() may +access ser->tty after the tty has been freed. + +The race condition occurs between ldisc_close() and packet transmission: + + CPU 0 (close) CPU 1 (xmit) + ------------- ------------ + ldisc_close() + tty_kref_put(ser->tty) + [tty may be freed here] + <-- race window --> + caif_xmit() + handle_tx() + tty = ser->tty // dangling ptr + tty->ops->write() // UAF! + schedule_work() + ser_release() + unregister_netdevice() + +The root cause is that tty_kref_put() is called in ldisc_close() while +the network device is still active and can receive packets. + +Since ser and tty have a 1:1 binding relationship with consistent +lifecycles (ser is allocated in ldisc_open and freed in ser_release +via unregister_netdevice, and each ser binds exactly one tty), we can +safely defer the tty reference release to ser_release() where the +network device is unregistered. + +Fix this by moving tty_kref_put() from ldisc_close() to ser_release(), +after unregister_netdevice(). This ensures the tty reference is held +as long as the network device exists, preventing the UAF. + +Note: We save ser->tty before unregister_netdevice() because ser is +embedded in netdev's private data and will be freed along with netdev +(needs_free_netdev = true). + +How to reproduce: Add mdelay(500) at the beginning of ldisc_close() +to widen the race window, then run the reproducer program [1]. + +Note: There is a separate deadloop issue in handle_tx() when using +PORT_UNKNOWN serial ports (e.g., /dev/ttyS3 in QEMU without proper +serial backend). This deadloop exists even without this patch, +and is likely caused by inconsistency between uart_write_room() and +uart_write() in serial core. It has been addressed in a separate +patch [2]. + +KASAN report: + +================================================================== +BUG: KASAN: slab-use-after-free in handle_tx+0x5d1/0x620 +Read of size 1 at addr ffff8881131e1490 by task caif_uaf_trigge/9929 + +Call Trace: + + dump_stack_lvl+0x10e/0x1f0 + print_report+0xd0/0x630 + kasan_report+0xe4/0x120 + handle_tx+0x5d1/0x620 + dev_hard_start_xmit+0x9d/0x6c0 + __dev_queue_xmit+0x6e2/0x4410 + packet_xmit+0x243/0x360 + packet_sendmsg+0x26cf/0x5500 + __sys_sendto+0x4a3/0x520 + __x64_sys_sendto+0xe0/0x1c0 + do_syscall_64+0xc9/0xf80 + entry_SYSCALL_64_after_hwframe+0x77/0x7f +RIP: 0033:0x7f615df2c0d7 + +Allocated by task 9930: + +Freed by task 64: + +Last potentially related work creation: + +The buggy address belongs to the object at ffff8881131e1000 + which belongs to the cache kmalloc-cg-2k of size 2048 +The buggy address is located 1168 bytes inside of + freed 2048-byte region [ffff8881131e1000, ffff8881131e1800) + +The buggy address belongs to the physical page: +page_owner tracks the page as allocated +page last free pid 9778 tgid 9778 stack trace: + +Memory state around the buggy address: + ffff8881131e1380: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb + ffff8881131e1400: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb +>ffff8881131e1480: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb + ^ + ffff8881131e1500: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb + ffff8881131e1580: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb +================================================================== +[1]: https://gist.github.com/mrpre/f683f244544f7b11e7fa87df9e6c2eeb +[2]: https://lore.kernel.org/linux-serial/20260204074327.226165-1-jiayuan.chen@linux.dev/T/#u + +Reported-by: syzbot+827272712bd6d12c79a4@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/000000000000a4a7550611e234f5@google.com/T/ +Fixes: 56e0ef527b18 ("drivers/net: caif: fix wrong rtnl_is_locked() usage") +Reviewed-by: Greg Kroah-Hartman +Signed-off-by: Jiayuan Chen +Reviewed-by: Jijie Shao +Link: https://patch.msgid.link/20260206074450.154267-1-jiayuan.chen@linux.dev +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/caif/caif_serial.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c +index 39fbd0be179c2..1b6a696182f72 100644 +--- a/drivers/net/caif/caif_serial.c ++++ b/drivers/net/caif/caif_serial.c +@@ -299,6 +299,7 @@ static void ser_release(struct work_struct *work) + { + struct list_head list; + struct ser_device *ser, *tmp; ++ struct tty_struct *tty; + + spin_lock(&ser_lock); + list_replace_init(&ser_release_list, &list); +@@ -307,9 +308,11 @@ static void ser_release(struct work_struct *work) + if (!list_empty(&list)) { + rtnl_lock(); + list_for_each_entry_safe(ser, tmp, &list, node) { ++ tty = ser->tty; + dev_close(ser->dev); + unregister_netdevice(ser->dev); + debugfs_deinit(ser); ++ tty_kref_put(tty); + } + rtnl_unlock(); + } +@@ -370,8 +373,6 @@ static void ldisc_close(struct tty_struct *tty) + { + struct ser_device *ser = tty->disc_data; + +- tty_kref_put(ser->tty); +- + spin_lock(&ser_lock); + list_move(&ser->node, &ser_release_list); + spin_unlock(&ser_lock); +-- +2.51.0 + diff --git a/queue-5.10/serial-imx-change-serial_imx_console-to-bool.patch b/queue-5.10/serial-imx-change-serial_imx_console-to-bool.patch new file mode 100644 index 0000000000..4cdf870608 --- /dev/null +++ b/queue-5.10/serial-imx-change-serial_imx_console-to-bool.patch @@ -0,0 +1,50 @@ +From a145c5df99d9a8c6883a8590040823e75137d509 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 10 Jan 2026 15:26:40 -0800 +Subject: serial: imx: change SERIAL_IMX_CONSOLE to bool + +From: Randy Dunlap + +[ Upstream commit 79527d86ba91c2d9354832d19fd12b3baa66bd10 ] + +SERIAL_IMX_CONSOLE is a build option for the imx driver (SERIAL_IMX). +It does not build a separate console driver file, so it can't be built +as a module since it isn't built at all. + +Change the Kconfig symbol from tristate to bool and update the help +text accordingly. + +Fixes: 0db4f9b91c86 ("tty: serial: imx: enable imx serial console port as module") +Signed-off-by: Randy Dunlap +Link: https://patch.msgid.link/20260110232643.3533351-2-rdunlap@infradead.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/Kconfig | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig +index 1ddaa5e7d4906..324787c2616c5 100644 +--- a/drivers/tty/serial/Kconfig ++++ b/drivers/tty/serial/Kconfig +@@ -504,14 +504,14 @@ config SERIAL_IMX + can enable its onboard serial port by enabling this option. + + config SERIAL_IMX_CONSOLE +- tristate "Console on IMX serial port" ++ bool "Console on IMX serial port" + depends on SERIAL_IMX + select SERIAL_CORE_CONSOLE + help + If you have enabled the serial port on the Freescale IMX +- CPU you can make it the console by answering Y/M to this option. ++ CPU you can make it the console by answering Y to this option. + +- Even if you say Y/M here, the currently visible virtual console ++ Even if you say Y here, the currently visible virtual console + (/dev/tty0) will still be used as the system console by default, but + you can alter that using a kernel command line option such as + "console=ttymxc0". (Try "man bootparam" or see the documentation of +-- +2.51.0 + diff --git a/queue-5.10/serial-sh_sci-improve-dma-support-prompt.patch b/queue-5.10/serial-sh_sci-improve-dma-support-prompt.patch new file mode 100644 index 0000000000..8b43b94dc8 --- /dev/null +++ b/queue-5.10/serial-sh_sci-improve-dma-support-prompt.patch @@ -0,0 +1,39 @@ +From 6bd283bc583e1c589690053f87b7b8aabf4a51ce Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 10 Jan 2026 15:26:43 -0800 +Subject: serial: SH_SCI: improve "DMA support" prompt + +From: Randy Dunlap + +[ Upstream commit 93bb95a11238d66a4c9aa6eabf9774b073a5895c ] + +Having a prompt of "DMA support" suddenly appear during a +"make oldconfig" can be confusing. Add a little helpful text to +the prompt message. + +Fixes: 73a19e4c0301 ("serial: sh-sci: Add DMA support.") +Signed-off-by: Randy Dunlap +Reviewed-by: Geert Uytterhoeven +Link: https://patch.msgid.link/20260110232643.3533351-5-rdunlap@infradead.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig +index 324787c2616c5..b8b0af95925ed 100644 +--- a/drivers/tty/serial/Kconfig ++++ b/drivers/tty/serial/Kconfig +@@ -701,7 +701,7 @@ config SERIAL_SH_SCI_EARLYCON + default ARCH_RENESAS || H8300 + + config SERIAL_SH_SCI_DMA +- bool "DMA support" if EXPERT ++ bool "Support for DMA on SuperH SCI(F)" if EXPERT + depends on SERIAL_SH_SCI && DMA_ENGINE + default ARCH_RENESAS + +-- +2.51.0 + diff --git a/queue-5.10/series b/queue-5.10/series index 0b63edc9fd..63629a00fc 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -1,2 +1,136 @@ rdma-siw-fix-potential-null-pointer-dereference-in-header-processing.patch rdma-umad-reject-negative-data_len-in-ib_umad_write.patch +auxdisplay-arm-charlcd-fix-release_mem_region-size.patch +hfsplus-return-error-when-node-already-exists-in-hfs.patch +i3c-remove-i2c-board-info-from-i2c_dev_desc.patch +i3c-move-device-name-assignment-after-i3c_bus_init.patch +fs-add-linux-init_task.h-for-init_fs.patch +gfs2-add-new-gfs2_iomap_get-helper.patch +gfs2-turn-gfs2_extent_map-into-gfs2_-get-alloc-_exte.patch +gfs2-replace-gfs2_lblk_to_dblk-with-gfs2_get_extent.patch +gfs2-add-wrapper-for-iomap_file_buffered_write.patch +gfs2-move-the-inode-glock-locking-to-gfs2_file_buffe.patch +gfs2-add-metapath_dibh-helper.patch +gfs2-fix-use-after-free-in-iomap-inline-data-write-p.patch +tpm-tpm_i2c_infineon-fix-locality-leak-on-get_burstc.patch +tpm-st33zp24-fix-missing-cleanup-on-get_burstcount-e.patch +btrfs-qgroup-return-correct-error-when-deleting-qgro.patch +md-raid10-fix-any_working-flag-handling-in-raid10_sy.patch +cpufreq-scmi-correct-scmi-explanation.patch +iomap-fix-submission-side-handling-of-completion-sid.patch +pm-wakeup-handle-empty-list-in-wakeup_sources_walk_s.patch +pm-sleep-wakeirq-harden-dev_pm_clear_wake_irq-agains.patch +s390-cio-fix-device-lifecycle-handling-in-css_alloc_.patch +arm-vdso-patch-out-__vdso_clock_getres-if-unavailabl.patch +crypto-cavium-fix-dma_free_coherent-size.patch +crypto-octeontx-fix-dma_free_coherent-size.patch +hrtimer-fix-trace-oddity.patch +edac-altera-remove-irqf_oneshot.patch +mfd-wm8350-core-use-irqf_oneshot.patch +sched-rt-skip-currently-executing-cpu-in-rto_next_cp.patch +pstore-ram-fix-buffer-overflow-in-persistent_ram_sav.patch +edac-i5000-fix-snprintf-size-calculation-in-calculat.patch +edac-i5400-fix-snprintf-limit-calculation-in-calcula.patch +clk-qcom-return-correct-error-code-in-qcom_cc_probe_.patch +arm64-dts-qcom-sdm630-add-qfprom-subnodes.patch +arm64-dts-qcom-sdm630-correct-qfprom-byte-offsets.patch +arm64-dts-qcom-sdm630-fix-gpu_speed_bin-size.patch +arm-dts-allwinner-sun5i-a13-utoo-p66-delete-power-gp.patch +soc-qcom-cmd-db-use-devm_memremap-to-fix-memory-leak.patch +powerpc-eeh-fix-recursive-pci_lock_rescan_remove-loc.patch +arm-dts-lpc32xx-set-motor-pwm-pwm-cells-property-val.patch +arm-dts-lpc32xx-add-clocks-property-to-motor-control.patch +arm64-dts-amlogic-axg-assign-the-mmc-signal-clocks.patch +arm64-dts-amlogic-gx-assign-the-mmc-signal-clocks.patch +arm64-dts-amlogic-g12-assign-the-mmc-b-and-c-signal-.patch +arm64-dts-amlogic-g12-assign-the-mmc-a-signal-clock.patch +arm64-dts-qcom-sdm845-db845c-specify-power-for-wifi-.patch +smack-smack-doi-must-be-0.patch +smack-smack-doi-accept-previously-used-values.patch +drm-amdgpu-use-explicit-vcn-instance-0-in-sr-iov-ini.patch +regulator-core-respect-off_on_delay-at-startup.patch +regulator-core-fix-off_on_delay-handling.patch +regulator-flag-uncontrollable-regulators-as-always_o.patch +regulator-core-fix-off-on-delay-us-for-always-on-boo.patch +regulator-core-use-ktime_get_boottime-to-determine-h.patch +regulator-core-shorten-off-on-delay-us-for-always-on.patch +regulator-core-move-supply-check-earlier-in-set_mach.patch +platform-chrome-cros_ec_lightbar-fix-response-size-i.patch +spi-tools-add-include-folder-to-.gitignore.patch +revert-hwmon-ibmpex-fix-use-after-free-in-high-low-s.patch +pci-mediatek-fix-irq-domain-leak-when-msi-allocation.patch +pci-do-not-attempt-to-set-exttag-for-vfs.patch +pci-portdrv-fix-potential-resource-leak.patch +wifi-cfg80211-stop-nan-and-p2p-in-cfg80211_leave.patch +netfilter-nf_conncount-make-nf_conncount_gc_list-to-.patch +netfilter-nf_conncount-increase-the-connection-clean.patch +netfilter-nf_conncount-fix-tracking-of-connections-f.patch +pci-mark-3ware-9650sa-root-port-extended-tags-as-bro.patch +iommu-vt-d-flush-cache-for-pasid-table-before-using-.patch +nfsd-never-defer-requests-during-idmap-lookup.patch +fat-avoid-parent-link-count-underflow-in-rmdir.patch +tcp-tcp_tx_timestamp-must-look-at-the-rtx-queue.patch +wifi-ath10k-sdio-add-missing-lock-protection-in-ath1.patch +pci-initialize-rcb-from-pci_configure_device.patch +ucount-check-for-cap_sys_resource-using-ns_capable_n.patch +octeontx2-af-fix-pf-driver-crash-with-kexec-kernel-b.patch +bonding-only-set-speed-duplex-to-unknown-if-getting-.patch +netfilter-nft_set_hash-fix-get-operation-on-big-endi.patch +netfilter-nft_set_rbtree-check-for-partial-overlaps-.patch +procfs-fix-missing-rcu-protection-when-reading-real_.patch +net-atm-fix-crash-due-to-unvalidated-vcc-pointer-in-.patch +serial-caif-fix-use-after-free-in-caif_serial-ldisc_.patch +ionic-rate-limit-unknown-xcvr-type-messages.patch +rdma-rtrs-server-remove-dead-code.patch +power-supply-act8945a-fix-use-after-free-in-power_su.patch +power-supply-bq25980-fix-use-after-free-in-power_sup.patch +power-supply-cpcap-battery-fix-use-after-free-in-pow.patch +power-supply-goldfish-fix-use-after-free-in-power_su.patch +power-supply-rt9455-fix-use-after-free-in-power_supp.patch +power-supply-sbs-battery-fix-use-after-free-in-power.patch +power-reset-nvmem-reboot-mode-respect-cell-size-for-.patch +power-supply-bq27xxx-fix-wrong-errno-when-bus-ops-ar.patch +power-supply-wm97xx_battery-convert-to-gpio-descript.patch +power-supply-wm97xx-fix-null-pointer-dereference-in-.patch +rdma-rxe-fix-double-free-in-rxe_srq_from_init.patch +mtd-rawnand-cadence-fix-return-type-of-cdma-send-and.patch +pm-core-redefine-pm_ptr-macro.patch +pm-core-add-new-_pm_ops-macros-deprecate-old-ones.patch +crypto-ccp-add-an-s4-restore-flow.patch +rdma-uverbs-validate-wqe_size-before-using-it-in-ib_.patch +svcrdma-add-a-batch-receive-posting-mechanism.patch +svcrdma-use-svc_rdma_refresh_recvs-in-wc_receive.patch +svcrdma-maintain-a-receive-water-mark.patch +rdma-core-fix-a-couple-of-obvious-typos-in-comments.patch +svcrdma-remove-queue-shortening-warnings.patch +svcrdma-clean-up-comment-in-svc_rdma_accept.patch +svcrdma-increase-the-per-transport-rw_ctx-count.patch +svcrdma-reduce-the-number-of-rdma_rw-contexts-per-qp.patch +rdma-core-add-rdma_rw_max_sge-helper-for-sq-sizing.patch +rdma-uverbs-add-__gfp_nowarn-to-ib_uverbs_unmarshall.patch +pnfs-fix-a-missing-wake-up-while-waiting-on-nfs_layo.patch +scsi-csiostor-fix-dereference-of-null-pointer-rn.patch +nvdimm-virtio_pmem-serialize-flush-requests.patch +tracing-remove-duplicate-enable_event_str-and-disabl.patch +fbdev-au1200fb-fix-a-memory-leak-in-au1200fb_drv_pro.patch +clk-meson-gxbb-limit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch +clk-move-clk_-save-restore-_context-to-common_clk-se.patch +clk-qcom-dispcc-sdm845-convert-to-parent-data.patch +clk-qcom-dispcc-sdm845-enable-parents-for-pixel-cloc.patch +dmaengine-mediatek-uart-apdma-fix-above-4g-addressin.patch +dma-dma-axi-dmac-fix-sw-cyclic-transfers.patch +staging-greybus-lights-avoid-null-deref.patch +serial-imx-change-serial_imx_console-to-bool.patch +serial-sh_sci-improve-dma-support-prompt.patch +mmc-core-initial-support-for-sd-express-card-host.patch +misc-rtsx-add-sd-express-mode-support-for-rts5261.patch +mmc-rtsx_pci_sdmmc-increase-power-on-settling-delay-.patch +coresight-etm3x-fix-cpulocked-warning-on-cpuhp.patch +revert-mmc-rtsx_pci_sdmmc-increase-power-on-settling.patch +mfd-arizona-fix-regulator-resource-leak-on-wm5102_cl.patch +drivers-iio-mpu3050-use-dev_err_probe-for-regulator-.patch +usb-bdc-fix-sleep-during-atomic.patch +pinctrl-equilibrium-fix-device-node-reference-leak-i.patch +ovl-fix-uninit-value-in-ovl_fill_real.patch +iio-sca3000-fix-a-resource-leak-in-sca3000_probe.patch +pinctrl-single-fix-refcount-leak-in-pcs_add_gpio_fun.patch diff --git a/queue-5.10/smack-smack-doi-accept-previously-used-values.patch b/queue-5.10/smack-smack-doi-accept-previously-used-values.patch new file mode 100644 index 0000000000..085878644d --- /dev/null +++ b/queue-5.10/smack-smack-doi-accept-previously-used-values.patch @@ -0,0 +1,233 @@ +From 5aec8c430be586900ad0bf5edc6cdd8081cb8db4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Sep 2025 15:31:53 +0300 +Subject: smack: /smack/doi: accept previously used values +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Konstantin Andreev + +[ Upstream commit 33d589ed60ae433b483761987b85e0d24e54584e ] + +Writing to /smack/doi a value that has ever been +written there in the past disables networking for +non-ambient labels. +E.g. + + # cat /smack/doi + 3 + # netlabelctl -p cipso list + Configured CIPSO mappings (1) + DOI value : 3 + mapping type : PASS_THROUGH + # netlabelctl -p map list + Configured NetLabel domain mappings (3) + domain: "_" (IPv4) + protocol: UNLABELED + domain: DEFAULT (IPv4) + protocol: CIPSO, DOI = 3 + domain: DEFAULT (IPv6) + protocol: UNLABELED + + # cat /smack/ambient + _ + # cat /proc/$$/attr/smack/current + _ + # ping -c1 10.1.95.12 + 64 bytes from 10.1.95.12: icmp_seq=1 ttl=64 time=0.964 ms + # echo foo >/proc/$$/attr/smack/current + # ping -c1 10.1.95.12 + 64 bytes from 10.1.95.12: icmp_seq=1 ttl=64 time=0.956 ms + unknown option 86 + + # echo 4 >/smack/doi + # echo 3 >/smack/doi +!> [ 214.050395] smk_cipso_doi:691 cipso add rc = -17 + # echo 3 >/smack/doi +!> [ 249.402261] smk_cipso_doi:678 remove rc = -2 +!> [ 249.402261] smk_cipso_doi:691 cipso add rc = -17 + + # ping -c1 10.1.95.12 +!!> ping: 10.1.95.12: Address family for hostname not supported + + # echo _ >/proc/$$/attr/smack/current + # ping -c1 10.1.95.12 + 64 bytes from 10.1.95.12: icmp_seq=1 ttl=64 time=0.617 ms + +This happens because Smack keeps decommissioned DOIs, +fails to re-add them, and consequently refuses to add +the “default” domain map: + + # netlabelctl -p cipso list + Configured CIPSO mappings (2) + DOI value : 3 + mapping type : PASS_THROUGH + DOI value : 4 + mapping type : PASS_THROUGH + # netlabelctl -p map list + Configured NetLabel domain mappings (2) + domain: "_" (IPv4) + protocol: UNLABELED +!> (no ipv4 map for default domain here) + domain: DEFAULT (IPv6) + protocol: UNLABELED + +Fix by clearing decommissioned DOI definitions and +serializing concurrent DOI updates with a new lock. + +Also: +- allow /smack/doi to live unconfigured, since + adding a map (netlbl_cfg_cipsov4_map_add) may fail. + CIPSO_V4_DOI_UNKNOWN(0) indicates the unconfigured DOI +- add new DOI before removing the old default map, + so the old map remains if the add fails + +(2008-02-04, Casey Schaufler) +Fixes: e114e473771c ("Smack: Simplified Mandatory Access Control Kernel") + +Signed-off-by: Konstantin Andreev +Signed-off-by: Casey Schaufler +Signed-off-by: Sasha Levin +--- + security/smack/smackfs.c | 71 +++++++++++++++++++++++++--------------- + 1 file changed, 45 insertions(+), 26 deletions(-) + +diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c +index c9de9e9bfe63e..73138b8c83831 100644 +--- a/security/smack/smackfs.c ++++ b/security/smack/smackfs.c +@@ -67,6 +67,7 @@ enum smk_inos { + static DEFINE_MUTEX(smack_cipso_lock); + static DEFINE_MUTEX(smack_ambient_lock); + static DEFINE_MUTEX(smk_net4addr_lock); ++static DEFINE_MUTEX(smk_cipso_doi_lock); + #if IS_ENABLED(CONFIG_IPV6) + static DEFINE_MUTEX(smk_net6addr_lock); + #endif /* CONFIG_IPV6 */ +@@ -138,7 +139,7 @@ struct smack_parsed_rule { + int smk_access2; + }; + +-static u32 smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; ++static u32 smk_cipso_doi_value = CIPSO_V4_DOI_UNKNOWN; + + /* + * Values for parsing cipso rules +@@ -678,43 +679,60 @@ static const struct file_operations smk_load_ops = { + }; + + /** +- * smk_cipso_doi - initialize the CIPSO domain ++ * smk_cipso_doi - set netlabel maps ++ * @ndoi: new value for our CIPSO DOI ++ * @gfp_flags: kmalloc allocation context + */ +-static void smk_cipso_doi(void) ++static int ++smk_cipso_doi(u32 ndoi, gfp_t gfp_flags) + { +- int rc; ++ int rc = 0; + struct cipso_v4_doi *doip; + struct netlbl_audit nai; + +- smk_netlabel_audit_set(&nai); ++ mutex_lock(&smk_cipso_doi_lock); + +- rc = netlbl_cfg_map_del(NULL, PF_INET, NULL, NULL, &nai); +- if (rc != 0) +- printk(KERN_WARNING "%s:%d remove rc = %d\n", +- __func__, __LINE__, rc); ++ if (smk_cipso_doi_value == ndoi) ++ goto clr_doi_lock; ++ ++ smk_netlabel_audit_set(&nai); + +- doip = kmalloc(sizeof(struct cipso_v4_doi), GFP_KERNEL | __GFP_NOFAIL); ++ doip = kmalloc(sizeof(struct cipso_v4_doi), gfp_flags); ++ if (!doip) { ++ rc = -ENOMEM; ++ goto clr_doi_lock; ++ } + doip->map.std = NULL; +- doip->doi = smk_cipso_doi_value; ++ doip->doi = ndoi; + doip->type = CIPSO_V4_MAP_PASS; + doip->tags[0] = CIPSO_V4_TAG_RBITMAP; + for (rc = 1; rc < CIPSO_V4_TAG_MAXCNT; rc++) + doip->tags[rc] = CIPSO_V4_TAG_INVALID; + + rc = netlbl_cfg_cipsov4_add(doip, &nai); +- if (rc != 0) { +- printk(KERN_WARNING "%s:%d cipso add rc = %d\n", +- __func__, __LINE__, rc); ++ if (rc) { + kfree(doip); +- return; ++ goto clr_doi_lock; + } +- rc = netlbl_cfg_cipsov4_map_add(doip->doi, NULL, NULL, NULL, &nai); +- if (rc != 0) { +- printk(KERN_WARNING "%s:%d map add rc = %d\n", +- __func__, __LINE__, rc); +- netlbl_cfg_cipsov4_del(doip->doi, &nai); +- return; ++ ++ if (smk_cipso_doi_value != CIPSO_V4_DOI_UNKNOWN) { ++ rc = netlbl_cfg_map_del(NULL, PF_INET, NULL, NULL, &nai); ++ if (rc && rc != -ENOENT) ++ goto clr_ndoi_def; ++ ++ netlbl_cfg_cipsov4_del(smk_cipso_doi_value, &nai); + } ++ ++ rc = netlbl_cfg_cipsov4_map_add(ndoi, NULL, NULL, NULL, &nai); ++ if (rc) { ++ smk_cipso_doi_value = CIPSO_V4_DOI_UNKNOWN; // no default map ++clr_ndoi_def: netlbl_cfg_cipsov4_del(ndoi, &nai); ++ } else ++ smk_cipso_doi_value = ndoi; ++ ++clr_doi_lock: ++ mutex_unlock(&smk_cipso_doi_lock); ++ return rc; + } + + /** +@@ -1617,11 +1635,8 @@ static ssize_t smk_write_doi(struct file *file, const char __user *buf, + + if (u == CIPSO_V4_DOI_UNKNOWN || u > U32_MAX) + return -EINVAL; +- smk_cipso_doi_value = u; +- +- smk_cipso_doi(); + +- return count; ++ return smk_cipso_doi(u, GFP_KERNEL) ? : count; + } + + static const struct file_operations smk_doi_ops = { +@@ -2997,6 +3012,7 @@ static int __init init_smk_fs(void) + { + int err; + int rc; ++ struct netlbl_audit nai; + + if (smack_enabled == 0) + return 0; +@@ -3015,7 +3031,10 @@ static int __init init_smk_fs(void) + } + } + +- smk_cipso_doi(); ++ smk_netlabel_audit_set(&nai); ++ (void) netlbl_cfg_map_del(NULL, PF_INET, NULL, NULL, &nai); ++ (void) smk_cipso_doi(SMACK_CIPSO_DOI_DEFAULT, ++ GFP_KERNEL | __GFP_NOFAIL); + smk_unlbl_ambient(NULL); + + rc = smack_populate_secattr(&smack_known_floor); +-- +2.51.0 + diff --git a/queue-5.10/smack-smack-doi-must-be-0.patch b/queue-5.10/smack-smack-doi-must-be-0.patch new file mode 100644 index 0000000000..e5c3acf355 --- /dev/null +++ b/queue-5.10/smack-smack-doi-must-be-0.patch @@ -0,0 +1,71 @@ +From 967e7bae00dc0c64dc4d164d4e98d981e17cd5f1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Sep 2025 15:16:02 +0300 +Subject: smack: /smack/doi must be > 0 + +From: Konstantin Andreev + +[ Upstream commit 19c013e1551bf51e1493da1270841d60e4fd3f15 ] + +/smack/doi allows writing and keeping negative doi values. +Correct values are 0 < doi <= (max 32-bit positive integer) + +(2008-02-04, Casey Schaufler) +Fixes: e114e473771c ("Smack: Simplified Mandatory Access Control Kernel") + +Signed-off-by: Konstantin Andreev +Signed-off-by: Casey Schaufler +Signed-off-by: Sasha Levin +--- + security/smack/smackfs.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c +index 6402626e47c69..c9de9e9bfe63e 100644 +--- a/security/smack/smackfs.c ++++ b/security/smack/smackfs.c +@@ -138,7 +138,7 @@ struct smack_parsed_rule { + int smk_access2; + }; + +-static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; ++static u32 smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; + + /* + * Values for parsing cipso rules +@@ -1580,7 +1580,7 @@ static ssize_t smk_read_doi(struct file *filp, char __user *buf, + if (*ppos != 0) + return 0; + +- sprintf(temp, "%d", smk_cipso_doi_value); ++ sprintf(temp, "%lu", (unsigned long)smk_cipso_doi_value); + rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp)); + + return rc; +@@ -1599,7 +1599,7 @@ static ssize_t smk_write_doi(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) + { + char temp[80]; +- int i; ++ unsigned long u; + + if (!smack_privileged(CAP_MAC_ADMIN)) + return -EPERM; +@@ -1612,10 +1612,12 @@ static ssize_t smk_write_doi(struct file *file, const char __user *buf, + + temp[count] = '\0'; + +- if (sscanf(temp, "%d", &i) != 1) ++ if (kstrtoul(temp, 10, &u)) + return -EINVAL; + +- smk_cipso_doi_value = i; ++ if (u == CIPSO_V4_DOI_UNKNOWN || u > U32_MAX) ++ return -EINVAL; ++ smk_cipso_doi_value = u; + + smk_cipso_doi(); + +-- +2.51.0 + diff --git a/queue-5.10/soc-qcom-cmd-db-use-devm_memremap-to-fix-memory-leak.patch b/queue-5.10/soc-qcom-cmd-db-use-devm_memremap-to-fix-memory-leak.patch new file mode 100644 index 0000000000..f251e8acc9 --- /dev/null +++ b/queue-5.10/soc-qcom-cmd-db-use-devm_memremap-to-fix-memory-leak.patch @@ -0,0 +1,53 @@ +From 18ff28d8f86bae085ef617415162b08097c9135c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Dec 2025 09:39:32 +0800 +Subject: soc: qcom: cmd-db: Use devm_memremap() to fix memory leak in + cmd_db_dev_probe + +From: Haotian Zhang + +[ Upstream commit 0da7824734d8d83e6a844dd0207f071cb0c50cf4 ] + +If cmd_db_magic_matches() fails after memremap() succeeds, the function +returns -EINVAL without unmapping the memory region, causing a +potential resource leak. + +Switch to devm_memremap to automatically manage the map resource. + +Fixes: 312416d9171a ("drivers: qcom: add command DB driver") +Suggested-by: Dmitry Baryshkov +Signed-off-by: Haotian Zhang +Link: https://lore.kernel.org/r/20251216013933.773-1-vulab@iscas.ac.cn +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/cmd-db.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/soc/qcom/cmd-db.c b/drivers/soc/qcom/cmd-db.c +index 006bb28e2a6e5..f9bbd5cab0a05 100644 +--- a/drivers/soc/qcom/cmd-db.c ++++ b/drivers/soc/qcom/cmd-db.c +@@ -319,15 +319,16 @@ static int cmd_db_dev_probe(struct platform_device *pdev) + return -EINVAL; + } + +- cmd_db_header = memremap(rmem->base, rmem->size, MEMREMAP_WC); +- if (!cmd_db_header) { +- ret = -ENOMEM; ++ cmd_db_header = devm_memremap(&pdev->dev, rmem->base, rmem->size, MEMREMAP_WC); ++ if (IS_ERR(cmd_db_header)) { ++ ret = PTR_ERR(cmd_db_header); + cmd_db_header = NULL; + return ret; + } + + if (!cmd_db_magic_matches(cmd_db_header)) { + dev_err(&pdev->dev, "Invalid Command DB Magic\n"); ++ cmd_db_header = NULL; + return -EINVAL; + } + +-- +2.51.0 + diff --git a/queue-5.10/spi-tools-add-include-folder-to-.gitignore.patch b/queue-5.10/spi-tools-add-include-folder-to-.gitignore.patch new file mode 100644 index 0000000000..e7f4741191 --- /dev/null +++ b/queue-5.10/spi-tools-add-include-folder-to-.gitignore.patch @@ -0,0 +1,35 @@ +From 294235ff0c8680abd62286214322cffa8fa6bf4a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 10:50:01 +0100 +Subject: spi: tools: Add include folder to .gitignore + +From: Francesco Lavra + +[ Upstream commit 5af56f30c4fcbade4a92f94dadfea517d1db9703 ] + +The Makefile for the SPI tools creates an include/linux/spi folder and some +symlinks inside it. After running `make -C spi/tools`, this folder shows up +as untracked in the git status. +Add the above folder to the .gitignore file. + +Fixes: f325b73dc4db ("spi: tools: move to tools buildsystem") +Signed-off-by: Francesco Lavra +Link: https://patch.msgid.link/20260209095001.556495-1-flavra@baylibre.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + tools/spi/.gitignore | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/tools/spi/.gitignore b/tools/spi/.gitignore +index 14ddba3d21957..038261b34ed83 100644 +--- a/tools/spi/.gitignore ++++ b/tools/spi/.gitignore +@@ -1,3 +1,4 @@ + # SPDX-License-Identifier: GPL-2.0-only + spidev_fdx + spidev_test ++include/ +-- +2.51.0 + diff --git a/queue-5.10/staging-greybus-lights-avoid-null-deref.patch b/queue-5.10/staging-greybus-lights-avoid-null-deref.patch new file mode 100644 index 0000000000..d773113fc7 --- /dev/null +++ b/queue-5.10/staging-greybus-lights-avoid-null-deref.patch @@ -0,0 +1,55 @@ +From b616c3c48d38b70e679ef775cf5f4e7821d28be7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 20:42:54 +0530 +Subject: staging: greybus: lights: avoid NULL deref + +From: Chaitanya Mishra + +[ Upstream commit efcffd9a6ad8d190651498d5eda53bfc7cf683a7 ] + +gb_lights_light_config() stores channel_count before allocating the +channels array. If kcalloc() fails, gb_lights_release() iterates the +non-zero count and dereferences light->channels, which is NULL. + +Allocate channels first and only then publish channels_count so the +cleanup path can't walk a NULL pointer. + +Fixes: 2870b52bae4c ("greybus: lights: add lights implementation") +Link: https://lore.kernel.org/all/20260108103700.15384-1-chaitanyamishra.ai@gmail.com/ +Reviewed-by: Rui Miguel Silva +Signed-off-by: Chaitanya Mishra +Link: https://patch.msgid.link/20260108151254.81553-1-chaitanyamishra.ai@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/staging/greybus/light.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/drivers/staging/greybus/light.c b/drivers/staging/greybus/light.c +index 7352d7deb8ba0..af91913794ee6 100644 +--- a/drivers/staging/greybus/light.c ++++ b/drivers/staging/greybus/light.c +@@ -1030,14 +1030,18 @@ static int gb_lights_light_config(struct gb_lights *glights, u8 id) + if (!strlen(conf.name)) + return -EINVAL; + +- light->channels_count = conf.channel_count; + light->name = kstrndup(conf.name, NAMES_MAX, GFP_KERNEL); + if (!light->name) + return -ENOMEM; +- light->channels = kcalloc(light->channels_count, ++ light->channels = kcalloc(conf.channel_count, + sizeof(struct gb_channel), GFP_KERNEL); + if (!light->channels) + return -ENOMEM; ++ /* ++ * Publish channels_count only after channels allocation so cleanup ++ * doesn't walk a NULL channels pointer on allocation failure. ++ */ ++ light->channels_count = conf.channel_count; + + /* First we collect all the configurations for all channels */ + for (i = 0; i < light->channels_count; i++) { +-- +2.51.0 + diff --git a/queue-5.10/svcrdma-add-a-batch-receive-posting-mechanism.patch b/queue-5.10/svcrdma-add-a-batch-receive-posting-mechanism.patch new file mode 100644 index 0000000000..8a38d3fc08 --- /dev/null +++ b/queue-5.10/svcrdma-add-a-batch-receive-posting-mechanism.patch @@ -0,0 +1,98 @@ +From ec0faeca6178a5cb5e72178ae0f2ed8ca866b9f4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 11 Mar 2021 13:54:34 -0500 +Subject: svcrdma: Add a batch Receive posting mechanism + +From: Chuck Lever + +[ Upstream commit 77f0a2aa5cdde0524eab745f7a117706d3e3014f ] + +Introduce a server-side mechanism similar to commit e340c2d6ef2a +("xprtrdma: Reduce the doorbell rate (Receive)") to post Receive +WRs in batch. Its first consumer is svc_rdma_post_recvs(), which +posts the initial set of Receive WRs. + +Signed-off-by: Chuck Lever +Stable-dep-of: afcae7d7b8a2 ("RDMA/core: add rdma_rw_max_sge() helper for SQ sizing") +Signed-off-by: Sasha Levin +--- + net/sunrpc/xprtrdma/svc_rdma_recvfrom.c | 56 ++++++++++++++++++------- + 1 file changed, 42 insertions(+), 14 deletions(-) + +diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c +index c6ea2903c21a4..4129a2d5cc715 100644 +--- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c ++++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c +@@ -252,6 +252,47 @@ void svc_rdma_release_rqst(struct svc_rqst *rqstp) + svc_rdma_recv_ctxt_put(rdma, ctxt); + } + ++static bool svc_rdma_refresh_recvs(struct svcxprt_rdma *rdma, ++ unsigned int wanted, bool temp) ++{ ++ const struct ib_recv_wr *bad_wr = NULL; ++ struct svc_rdma_recv_ctxt *ctxt; ++ struct ib_recv_wr *recv_chain; ++ int ret; ++ ++ if (test_bit(XPT_CLOSE, &rdma->sc_xprt.xpt_flags)) ++ return false; ++ ++ recv_chain = NULL; ++ while (wanted--) { ++ ctxt = svc_rdma_recv_ctxt_get(rdma); ++ if (!ctxt) ++ break; ++ ++ trace_svcrdma_post_recv(ctxt); ++ ctxt->rc_temp = temp; ++ ctxt->rc_recv_wr.next = recv_chain; ++ recv_chain = &ctxt->rc_recv_wr; ++ } ++ if (!recv_chain) ++ return false; ++ ++ ret = ib_post_recv(rdma->sc_qp, recv_chain, &bad_wr); ++ if (ret) ++ goto err_free; ++ return true; ++ ++err_free: ++ trace_svcrdma_rq_post_err(rdma, ret); ++ while (bad_wr) { ++ ctxt = container_of(bad_wr, struct svc_rdma_recv_ctxt, ++ rc_recv_wr); ++ bad_wr = bad_wr->next; ++ svc_rdma_recv_ctxt_put(rdma, ctxt); ++ } ++ return false; ++} ++ + static int __svc_rdma_post_recv(struct svcxprt_rdma *rdma, + struct svc_rdma_recv_ctxt *ctxt) + { +@@ -289,20 +330,7 @@ static int svc_rdma_post_recv(struct svcxprt_rdma *rdma) + */ + bool svc_rdma_post_recvs(struct svcxprt_rdma *rdma) + { +- struct svc_rdma_recv_ctxt *ctxt; +- unsigned int i; +- int ret; +- +- for (i = 0; i < rdma->sc_max_requests; i++) { +- ctxt = svc_rdma_recv_ctxt_get(rdma); +- if (!ctxt) +- return false; +- ctxt->rc_temp = true; +- ret = __svc_rdma_post_recv(rdma, ctxt); +- if (ret) +- return false; +- } +- return true; ++ return svc_rdma_refresh_recvs(rdma, rdma->sc_max_requests, true); + } + + /** +-- +2.51.0 + diff --git a/queue-5.10/svcrdma-clean-up-comment-in-svc_rdma_accept.patch b/queue-5.10/svcrdma-clean-up-comment-in-svc_rdma_accept.patch new file mode 100644 index 0000000000..9c374784e0 --- /dev/null +++ b/queue-5.10/svcrdma-clean-up-comment-in-svc_rdma_accept.patch @@ -0,0 +1,64 @@ +From 264113180f4b4b95b7f50f3f274085df2e2e3adb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 Dec 2023 10:24:34 -0500 +Subject: svcrdma: Clean up comment in svc_rdma_accept() + +From: Chuck Lever + +[ Upstream commit fc2e69db82c1ac506cd7f539a3ab66d51d3380dc ] + +The comment that starts "Qualify ..." applies to only some of the +following code paragraph. Re-arrange the lines so the comment makes +more sense. + +Signed-off-by: Chuck Lever +Stable-dep-of: afcae7d7b8a2 ("RDMA/core: add rdma_rw_max_sge() helper for SQ sizing") +Signed-off-by: Sasha Levin +--- + net/sunrpc/xprtrdma/svc_rdma_transport.c | 17 ++++++++++------- + 1 file changed, 10 insertions(+), 7 deletions(-) + +diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c +index d6c9814644c6a..429ed159e9251 100644 +--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c ++++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c +@@ -393,18 +393,22 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + dev = newxprt->sc_cm_id->device; + newxprt->sc_port_num = newxprt->sc_cm_id->port_num; + +- /* Qualify the transport resource defaults with the +- * capabilities of this particular device */ ++ newxprt->sc_max_req_size = svcrdma_max_req_size; ++ newxprt->sc_max_requests = svcrdma_max_requests; ++ newxprt->sc_max_bc_requests = svcrdma_max_bc_requests; ++ newxprt->sc_recv_batch = RPCRDMA_MAX_RECV_BATCH; ++ newxprt->sc_fc_credits = cpu_to_be32(newxprt->sc_max_requests); ++ ++ /* Qualify the transport's resource defaults with the ++ * capabilities of this particular device. ++ */ ++ + /* Transport header, head iovec, tail iovec */ + newxprt->sc_max_send_sges = 3; + /* Add one SGE per page list entry */ + newxprt->sc_max_send_sges += (svcrdma_max_req_size / PAGE_SIZE) + 1; + if (newxprt->sc_max_send_sges > dev->attrs.max_send_sge) + newxprt->sc_max_send_sges = dev->attrs.max_send_sge; +- newxprt->sc_max_req_size = svcrdma_max_req_size; +- newxprt->sc_max_requests = svcrdma_max_requests; +- newxprt->sc_max_bc_requests = svcrdma_max_bc_requests; +- newxprt->sc_recv_batch = RPCRDMA_MAX_RECV_BATCH; + rq_depth = newxprt->sc_max_requests + newxprt->sc_max_bc_requests + + newxprt->sc_recv_batch; + if (rq_depth > dev->attrs.max_qp_wr) { +@@ -413,7 +417,6 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + newxprt->sc_max_requests = rq_depth - 2; + newxprt->sc_max_bc_requests = 2; + } +- newxprt->sc_fc_credits = cpu_to_be32(newxprt->sc_max_requests); + ctxts = rdma_rw_mr_factor(dev, newxprt->sc_port_num, RPCSVC_MAXPAGES); + ctxts *= newxprt->sc_max_requests; + newxprt->sc_sq_depth = rq_depth + ctxts; +-- +2.51.0 + diff --git a/queue-5.10/svcrdma-increase-the-per-transport-rw_ctx-count.patch b/queue-5.10/svcrdma-increase-the-per-transport-rw_ctx-count.patch new file mode 100644 index 0000000000..190b51e903 --- /dev/null +++ b/queue-5.10/svcrdma-increase-the-per-transport-rw_ctx-count.patch @@ -0,0 +1,73 @@ +From f4e890c269754ef9cd41b2bfbafe0a8e048db01b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 4 Feb 2024 18:16:56 -0500 +Subject: svcrdma: Increase the per-transport rw_ctx count + +From: Chuck Lever + +[ Upstream commit 2da0f610e733606e06284ac3c1f188b9dec75d68 ] + +rdma_rw_mr_factor() returns the smallest number of MRs needed to +move a particular number of pages. svcrdma currently asks for the +number of MRs needed to move RPCSVC_MAXPAGES (a little over one +megabyte), as that is the number of pages in the largest r/wsize +the server supports. + +This call assumes that the client's NIC can bundle a full one +megabyte payload in a single rdma_segment. In fact, most NICs cannot +handle a full megabyte with a single rkey / rdma_segment. Clients +will typically split even a single Read chunk into many segments. + +The server needs one MR to read each rdma_segment in a Read chunk, +and thus each one needs an rw_ctx. + +svcrdma has been vastly underestimating the number of rw_ctxs needed +to handle 64 RPC requests with large Read chunks using small +rdma_segments. + +Unfortunately there doesn't seem to be a good way to estimate this +number without knowing the client NIC's capabilities. Even then, +the client RPC/RDMA implementation is still free to split a chunk +into smaller segments (for example, it might be using physical +registration, which needs an rdma_segment per page). + +The best we can do for now is choose a number that will guarantee +forward progress in the worst case (one page per segment). + +At some later point, we could add some mechanisms to make this +much less of a problem: +- Add a core API to add more rw_ctxs to an already-established QP +- svcrdma could treat rw_ctx exhaustion as a temporary error and + try again +- Limit the number of Reads in flight + +Signed-off-by: Chuck Lever +Stable-dep-of: afcae7d7b8a2 ("RDMA/core: add rdma_rw_max_sge() helper for SQ sizing") +Signed-off-by: Sasha Levin +--- + net/sunrpc/xprtrdma/svc_rdma_transport.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c +index 429ed159e9251..9f66b57125042 100644 +--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c ++++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c +@@ -417,8 +417,13 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + newxprt->sc_max_requests = rq_depth - 2; + newxprt->sc_max_bc_requests = 2; + } +- ctxts = rdma_rw_mr_factor(dev, newxprt->sc_port_num, RPCSVC_MAXPAGES); +- ctxts *= newxprt->sc_max_requests; ++ ++ /* Arbitrarily estimate the number of rw_ctxs needed for ++ * this transport. This is enough rw_ctxs to make forward ++ * progress even if the client is using one rkey per page ++ * in each Read chunk. ++ */ ++ ctxts = 3 * RPCSVC_MAXPAGES; + newxprt->sc_sq_depth = rq_depth + ctxts; + if (newxprt->sc_sq_depth > dev->attrs.max_qp_wr) + newxprt->sc_sq_depth = dev->attrs.max_qp_wr; +-- +2.51.0 + diff --git a/queue-5.10/svcrdma-maintain-a-receive-water-mark.patch b/queue-5.10/svcrdma-maintain-a-receive-water-mark.patch new file mode 100644 index 0000000000..f0a07dc63a --- /dev/null +++ b/queue-5.10/svcrdma-maintain-a-receive-water-mark.patch @@ -0,0 +1,100 @@ +From 71968732e8368ba427c7064f44a953a1c5594cab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 11 Mar 2021 18:32:30 -0500 +Subject: svcrdma: Maintain a Receive water mark + +From: Chuck Lever + +[ Upstream commit c558d47596867ff1082fd7475b63670f63f7f5cf ] + +Post more Receives when the number of pending Receives drops below +a water mark. The batch mechanism is disabled if the underlying +device cannot support a reasonably-sized Receive Queue. + +Signed-off-by: Chuck Lever +Stable-dep-of: afcae7d7b8a2 ("RDMA/core: add rdma_rw_max_sge() helper for SQ sizing") +Signed-off-by: Sasha Levin +--- + include/linux/sunrpc/svc_rdma.h | 2 ++ + net/sunrpc/xprtrdma/svc_rdma_recvfrom.c | 10 ++++++++-- + net/sunrpc/xprtrdma/svc_rdma_transport.c | 5 ++++- + 3 files changed, 14 insertions(+), 3 deletions(-) + +diff --git a/include/linux/sunrpc/svc_rdma.h b/include/linux/sunrpc/svc_rdma.h +index 2b870a3f391b1..e2f316f52df66 100644 +--- a/include/linux/sunrpc/svc_rdma.h ++++ b/include/linux/sunrpc/svc_rdma.h +@@ -96,6 +96,8 @@ struct svcxprt_rdma { + spinlock_t sc_rw_ctxt_lock; + struct list_head sc_rw_ctxts; + ++ u32 sc_pending_recvs; ++ u32 sc_recv_batch; + struct list_head sc_rq_dto_q; + spinlock_t sc_rq_dto_lock; + struct ib_qp *sc_qp; +diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c +index f2264179d9000..d5d15d1012302 100644 +--- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c ++++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c +@@ -273,6 +273,7 @@ static bool svc_rdma_refresh_recvs(struct svcxprt_rdma *rdma, + ctxt->rc_temp = temp; + ctxt->rc_recv_wr.next = recv_chain; + recv_chain = &ctxt->rc_recv_wr; ++ rdma->sc_pending_recvs++; + } + if (!recv_chain) + return false; +@@ -290,6 +291,8 @@ static bool svc_rdma_refresh_recvs(struct svcxprt_rdma *rdma, + bad_wr = bad_wr->next; + svc_rdma_recv_ctxt_put(rdma, ctxt); + } ++ /* Since we're destroying the xprt, no need to reset ++ * sc_pending_recvs. */ + return false; + } + +@@ -318,6 +321,8 @@ static void svc_rdma_wc_receive(struct ib_cq *cq, struct ib_wc *wc) + struct ib_cqe *cqe = wc->wr_cqe; + struct svc_rdma_recv_ctxt *ctxt; + ++ rdma->sc_pending_recvs--; ++ + /* WARNING: Only wc->wr_cqe and wc->status are reliable */ + ctxt = container_of(cqe, struct svc_rdma_recv_ctxt, rc_cqe); + +@@ -334,8 +339,9 @@ static void svc_rdma_wc_receive(struct ib_cq *cq, struct ib_wc *wc) + * to reduce the likelihood of replayed requests once the + * client reconnects. + */ +- if (!svc_rdma_refresh_recvs(rdma, 1, false)) +- goto flushed; ++ if (rdma->sc_pending_recvs < rdma->sc_max_requests) ++ if (!svc_rdma_refresh_recvs(rdma, rdma->sc_recv_batch, false)) ++ goto flushed; + + /* All wc fields are now known to be valid */ + ctxt->rc_byte_len = wc->byte_len; +diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c +index c895f80df659c..b00ea4dbe7d40 100644 +--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c ++++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c +@@ -404,11 +404,14 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + newxprt->sc_max_req_size = svcrdma_max_req_size; + newxprt->sc_max_requests = svcrdma_max_requests; + newxprt->sc_max_bc_requests = svcrdma_max_bc_requests; +- rq_depth = newxprt->sc_max_requests + newxprt->sc_max_bc_requests; ++ newxprt->sc_recv_batch = RPCRDMA_MAX_RECV_BATCH; ++ rq_depth = newxprt->sc_max_requests + newxprt->sc_max_bc_requests + ++ newxprt->sc_recv_batch; + if (rq_depth > dev->attrs.max_qp_wr) { + pr_warn("svcrdma: reducing receive depth to %d\n", + dev->attrs.max_qp_wr); + rq_depth = dev->attrs.max_qp_wr; ++ newxprt->sc_recv_batch = 1; + newxprt->sc_max_requests = rq_depth - 2; + newxprt->sc_max_bc_requests = 2; + } +-- +2.51.0 + diff --git a/queue-5.10/svcrdma-reduce-the-number-of-rdma_rw-contexts-per-qp.patch b/queue-5.10/svcrdma-reduce-the-number-of-rdma_rw-contexts-per-qp.patch new file mode 100644 index 0000000000..124c1aff1e --- /dev/null +++ b/queue-5.10/svcrdma-reduce-the-number-of-rdma_rw-contexts-per-qp.patch @@ -0,0 +1,96 @@ +From 30b10fe3ff164e89fbbea2ae87ea08ee9b774c62 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 28 Apr 2025 15:36:49 -0400 +Subject: svcrdma: Reduce the number of rdma_rw contexts per-QP + +From: Chuck Lever + +[ Upstream commit 59243315890578a040a2d50ae9e001a2ef2fcb62 ] + +There is an upper bound on the number of rdma_rw contexts that can +be created per QP. + +This invisible upper bound is because rdma_create_qp() adds one or +more additional SQEs for each ctxt that the ULP requests via +qp_attr.cap.max_rdma_ctxs. The QP's actual Send Queue length is on +the order of the sum of qp_attr.cap.max_send_wr and a factor times +qp_attr.cap.max_rdma_ctxs. The factor can be up to three, depending +on whether MR operations are required before RDMA Reads. + +This limit is not visible to RDMA consumers via dev->attrs. When the +limit is surpassed, QP creation fails with -ENOMEM. For example: + +svcrdma's estimate of the number of rdma_rw contexts it needs is +three times the number of pages in RPCSVC_MAXPAGES. When MAXPAGES +is about 260, the internally-computed SQ length should be: + +64 credits + 10 backlog + 3 * (3 * 260) = 2414 + +Which is well below the advertised qp_max_wr of 32768. + +If RPCSVC_MAXPAGES is increased to 4MB, that's 1040 pages: + +64 credits + 10 backlog + 3 * (3 * 1040) = 9434 + +However, QP creation fails. Dynamic printk for mlx5 shows: + +calc_sq_size:618:(pid 1514): send queue size (9326 * 256 / 64 -> 65536) exceeds limits(32768) + +Although 9326 is still far below qp_max_wr, QP creation still +fails. + +Because the total SQ length calculation is opaque to RDMA consumers, +there doesn't seem to be much that can be done about this except for +consumers to try to keep the requested rdma_rw ctxt count low. + +Fixes: 2da0f610e733 ("svcrdma: Increase the per-transport rw_ctx count") +Reviewed-by: NeilBrown +Reviewed-by: Christoph Hellwig +Signed-off-by: Chuck Lever +Stable-dep-of: afcae7d7b8a2 ("RDMA/core: add rdma_rw_max_sge() helper for SQ sizing") +Signed-off-by: Sasha Levin +--- + net/sunrpc/xprtrdma/svc_rdma_transport.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c +index 9f66b57125042..7b7d2add99a4c 100644 +--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c ++++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c +@@ -365,12 +365,12 @@ static struct svc_xprt *svc_rdma_create(struct svc_serv *serv, + */ + static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + { ++ unsigned int ctxts, rq_depth, maxpayload; + struct svcxprt_rdma *listen_rdma; + struct svcxprt_rdma *newxprt = NULL; + struct rdma_conn_param conn_param; + struct rpcrdma_connect_private pmsg; + struct ib_qp_init_attr qp_attr; +- unsigned int ctxts, rq_depth; + struct ib_device *dev; + int ret = 0; + RPC_IFDEBUG(struct sockaddr *sap); +@@ -418,12 +418,14 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + newxprt->sc_max_bc_requests = 2; + } + +- /* Arbitrarily estimate the number of rw_ctxs needed for +- * this transport. This is enough rw_ctxs to make forward +- * progress even if the client is using one rkey per page +- * in each Read chunk. ++ /* Arbitrary estimate of the needed number of rdma_rw contexts. + */ +- ctxts = 3 * RPCSVC_MAXPAGES; ++ maxpayload = min(xprt->xpt_server->sv_max_payload, ++ RPCSVC_MAXPAYLOAD_RDMA); ++ ctxts = newxprt->sc_max_requests * 3 * ++ rdma_rw_mr_factor(dev, newxprt->sc_port_num, ++ maxpayload >> PAGE_SHIFT); ++ + newxprt->sc_sq_depth = rq_depth + ctxts; + if (newxprt->sc_sq_depth > dev->attrs.max_qp_wr) + newxprt->sc_sq_depth = dev->attrs.max_qp_wr; +-- +2.51.0 + diff --git a/queue-5.10/svcrdma-remove-queue-shortening-warnings.patch b/queue-5.10/svcrdma-remove-queue-shortening-warnings.patch new file mode 100644 index 0000000000..26f90a4744 --- /dev/null +++ b/queue-5.10/svcrdma-remove-queue-shortening-warnings.patch @@ -0,0 +1,52 @@ +From 1f6252bbd524720411b847f646a2c4911a3bb0b3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 Dec 2023 10:24:28 -0500 +Subject: svcrdma: Remove queue-shortening warnings + +From: Chuck Lever + +[ Upstream commit b918bfcf370c92ea3b82fa9bb3d017702b5fa4cb ] + +These won't have much diagnostic value for site administrators. +Since they can't be disabled, they become noise. + +What's more, the subsequent rdma_create_qp() call adjusts the Send +Queue size (possibly downward) without warning, making the size +reported by these pr_warns inaccurate. + +Signed-off-by: Chuck Lever +Stable-dep-of: afcae7d7b8a2 ("RDMA/core: add rdma_rw_max_sge() helper for SQ sizing") +Signed-off-by: Sasha Levin +--- + net/sunrpc/xprtrdma/svc_rdma_transport.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c +index b00ea4dbe7d40..d6c9814644c6a 100644 +--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c ++++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c +@@ -408,8 +408,6 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + rq_depth = newxprt->sc_max_requests + newxprt->sc_max_bc_requests + + newxprt->sc_recv_batch; + if (rq_depth > dev->attrs.max_qp_wr) { +- pr_warn("svcrdma: reducing receive depth to %d\n", +- dev->attrs.max_qp_wr); + rq_depth = dev->attrs.max_qp_wr; + newxprt->sc_recv_batch = 1; + newxprt->sc_max_requests = rq_depth - 2; +@@ -419,11 +417,8 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + ctxts = rdma_rw_mr_factor(dev, newxprt->sc_port_num, RPCSVC_MAXPAGES); + ctxts *= newxprt->sc_max_requests; + newxprt->sc_sq_depth = rq_depth + ctxts; +- if (newxprt->sc_sq_depth > dev->attrs.max_qp_wr) { +- pr_warn("svcrdma: reducing send depth to %d\n", +- dev->attrs.max_qp_wr); ++ if (newxprt->sc_sq_depth > dev->attrs.max_qp_wr) + newxprt->sc_sq_depth = dev->attrs.max_qp_wr; +- } + atomic_set(&newxprt->sc_sq_avail, newxprt->sc_sq_depth); + + newxprt->sc_pd = ib_alloc_pd(dev, 0); +-- +2.51.0 + diff --git a/queue-5.10/svcrdma-use-svc_rdma_refresh_recvs-in-wc_receive.patch b/queue-5.10/svcrdma-use-svc_rdma_refresh_recvs-in-wc_receive.patch new file mode 100644 index 0000000000..88fa121262 --- /dev/null +++ b/queue-5.10/svcrdma-use-svc_rdma_refresh_recvs-in-wc_receive.patch @@ -0,0 +1,94 @@ +From 6ebe96a6039881160c1924bd602777f07e85a7b3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 11 Mar 2021 16:15:22 -0500 +Subject: svcrdma: Use svc_rdma_refresh_recvs() in wc_receive + +From: Chuck Lever + +[ Upstream commit 7b748c30cc046056a24c459de415844a856ea54b ] + +Replace svc_rdma_post_recv() with the new batch receive mechanism. +For the moment it is posting just a single Receive WR at a time, +so no change in behavior is expected. + +Since svc_rdma_wc_receive() was the last call site for +svc_rdma_post_recv(), it is removed. + +Signed-off-by: Chuck Lever +Stable-dep-of: afcae7d7b8a2 ("RDMA/core: add rdma_rw_max_sge() helper for SQ sizing") +Signed-off-by: Sasha Levin +--- + net/sunrpc/xprtrdma/svc_rdma_recvfrom.c | 43 +++++++------------------ + 1 file changed, 11 insertions(+), 32 deletions(-) + +diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c +index 4129a2d5cc715..f2264179d9000 100644 +--- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c ++++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c +@@ -293,35 +293,6 @@ static bool svc_rdma_refresh_recvs(struct svcxprt_rdma *rdma, + return false; + } + +-static int __svc_rdma_post_recv(struct svcxprt_rdma *rdma, +- struct svc_rdma_recv_ctxt *ctxt) +-{ +- int ret; +- +- trace_svcrdma_post_recv(ctxt); +- ret = ib_post_recv(rdma->sc_qp, &ctxt->rc_recv_wr, NULL); +- if (ret) +- goto err_post; +- return 0; +- +-err_post: +- trace_svcrdma_rq_post_err(rdma, ret); +- svc_rdma_recv_ctxt_put(rdma, ctxt); +- return ret; +-} +- +-static int svc_rdma_post_recv(struct svcxprt_rdma *rdma) +-{ +- struct svc_rdma_recv_ctxt *ctxt; +- +- if (test_bit(XPT_CLOSE, &rdma->sc_xprt.xpt_flags)) +- return 0; +- ctxt = svc_rdma_recv_ctxt_get(rdma); +- if (!ctxt) +- return -ENOMEM; +- return __svc_rdma_post_recv(rdma, ctxt); +-} +- + /** + * svc_rdma_post_recvs - Post initial set of Recv WRs + * @rdma: fresh svcxprt_rdma +@@ -354,8 +325,17 @@ static void svc_rdma_wc_receive(struct ib_cq *cq, struct ib_wc *wc) + if (wc->status != IB_WC_SUCCESS) + goto flushed; + +- if (svc_rdma_post_recv(rdma)) +- goto post_err; ++ /* If receive posting fails, the connection is about to be ++ * lost anyway. The server will not be able to send a reply ++ * for this RPC, and the client will retransmit this RPC ++ * anyway when it reconnects. ++ * ++ * Therefore we drop the Receive, even if status was SUCCESS ++ * to reduce the likelihood of replayed requests once the ++ * client reconnects. ++ */ ++ if (!svc_rdma_refresh_recvs(rdma, 1, false)) ++ goto flushed; + + /* All wc fields are now known to be valid */ + ctxt->rc_byte_len = wc->byte_len; +@@ -373,7 +353,6 @@ static void svc_rdma_wc_receive(struct ib_cq *cq, struct ib_wc *wc) + return; + + flushed: +-post_err: + svc_rdma_recv_ctxt_put(rdma, ctxt); + set_bit(XPT_CLOSE, &rdma->sc_xprt.xpt_flags); + svc_xprt_enqueue(&rdma->sc_xprt); +-- +2.51.0 + diff --git a/queue-5.10/tcp-tcp_tx_timestamp-must-look-at-the-rtx-queue.patch b/queue-5.10/tcp-tcp_tx_timestamp-must-look-at-the-rtx-queue.patch new file mode 100644 index 0000000000..dd0ef5fb7b --- /dev/null +++ b/queue-5.10/tcp-tcp_tx_timestamp-must-look-at-the-rtx-queue.patch @@ -0,0 +1,44 @@ +From 255dff69d941f321a009d8178108fa3bd7987ffc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 12:38:27 +0000 +Subject: tcp: tcp_tx_timestamp() must look at the rtx queue + +From: Eric Dumazet + +[ Upstream commit 838eb9687691d29915797a885b861fd09353386e ] + +tcp_tx_timestamp() is only called at the end of tcp_sendmsg_locked() +before the final tcp_push(). + +By the time it is called, it is possible all the copied data +has been sent already (transmit queue is empty). + +If this is the case, use the last skb in the rtx queue. + +Fixes: 75c119afe14f ("tcp: implement rb-tree based retransmit queue") +Signed-off-by: Eric Dumazet +Reviewed-by: Jason Xing +Link: https://patch.msgid.link/20260127123828.4098577-2-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 6ffda70e7e58e..5998e2b6f5ec7 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -464,6 +464,9 @@ static void tcp_tx_timestamp(struct sock *sk, u16 tsflags) + { + struct sk_buff *skb = tcp_write_queue_tail(sk); + ++ if (unlikely(!skb)) ++ skb = skb_rb_last(&sk->tcp_rtx_queue); ++ + if (tsflags && skb) { + struct skb_shared_info *shinfo = skb_shinfo(skb); + struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); +-- +2.51.0 + diff --git a/queue-5.10/tpm-st33zp24-fix-missing-cleanup-on-get_burstcount-e.patch b/queue-5.10/tpm-st33zp24-fix-missing-cleanup-on-get_burstcount-e.patch new file mode 100644 index 0000000000..6d4318461b --- /dev/null +++ b/queue-5.10/tpm-st33zp24-fix-missing-cleanup-on-get_burstcount-e.patch @@ -0,0 +1,43 @@ +From eca942dca5d19044895abe473f17e6b480db5e4e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Dec 2025 15:09:27 +0300 +Subject: tpm: st33zp24: Fix missing cleanup on get_burstcount() error + +From: Alper Ak + +[ Upstream commit 3e91b44c93ad2871f89fc2a98c5e4fe6ca5db3d9 ] + +get_burstcount() can return -EBUSY on timeout. When this happens, +st33zp24_send() returns directly without releasing the locality +acquired earlier. + +Use goto out_err to ensure proper cleanup when get_burstcount() fails. + +Fixes: bf38b8710892 ("tpm/tpm_i2c_stm_st33: Split tpm_i2c_tpm_st33 in 2 layers (core + phy)") +Signed-off-by: Alper Ak +Signed-off-by: Jarkko Sakkinen +Signed-off-by: Sasha Levin +--- + drivers/char/tpm/st33zp24/st33zp24.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/char/tpm/st33zp24/st33zp24.c b/drivers/char/tpm/st33zp24/st33zp24.c +index 4ec10ab5e5766..33ee4fe693796 100644 +--- a/drivers/char/tpm/st33zp24/st33zp24.c ++++ b/drivers/char/tpm/st33zp24/st33zp24.c +@@ -381,8 +381,10 @@ static int st33zp24_send(struct tpm_chip *chip, unsigned char *buf, + + for (i = 0; i < len - 1;) { + burstcnt = get_burstcount(chip); +- if (burstcnt < 0) +- return burstcnt; ++ if (burstcnt < 0) { ++ ret = burstcnt; ++ goto out_err; ++ } + size = min_t(int, len - i - 1, burstcnt); + ret = tpm_dev->ops->send(tpm_dev->phy_id, TPM_DATA_FIFO, + buf + i, size); +-- +2.51.0 + diff --git a/queue-5.10/tpm-tpm_i2c_infineon-fix-locality-leak-on-get_burstc.patch b/queue-5.10/tpm-tpm_i2c_infineon-fix-locality-leak-on-get_burstc.patch new file mode 100644 index 0000000000..da96af3ef8 --- /dev/null +++ b/queue-5.10/tpm-tpm_i2c_infineon-fix-locality-leak-on-get_burstc.patch @@ -0,0 +1,44 @@ +From 98b9505662d0f3e1d18dedbde894575c3329837d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Dec 2025 13:23:38 +0300 +Subject: tpm: tpm_i2c_infineon: Fix locality leak on get_burstcount() failure + +From: Alper Ak + +[ Upstream commit bbd6e97c836cbeb9606d7b7e5dcf8a1d89525713 ] + +get_burstcount() can return -EBUSY on timeout. When this happens, the +function returns directly without releasing the locality that was +acquired at the beginning of tpm_tis_i2c_send(). + +Use goto out_err to ensure proper cleanup when get_burstcount() fails. + +Fixes: aad628c1d91a ("char/tpm: Add new driver for Infineon I2C TIS TPM") +Signed-off-by: Alper Ak +Reviewed-by: Jarkko Sakkinen +Signed-off-by: Jarkko Sakkinen +Signed-off-by: Sasha Levin +--- + drivers/char/tpm/tpm_i2c_infineon.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c +index a19d32cb4e942..cabc9e1b49321 100644 +--- a/drivers/char/tpm/tpm_i2c_infineon.c ++++ b/drivers/char/tpm/tpm_i2c_infineon.c +@@ -543,8 +543,10 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len) + burstcnt = get_burstcount(chip); + + /* burstcnt < 0 = TPM is busy */ +- if (burstcnt < 0) +- return burstcnt; ++ if (burstcnt < 0) { ++ rc = burstcnt; ++ goto out_err; ++ } + + if (burstcnt > (len - 1 - count)) + burstcnt = len - 1 - count; +-- +2.51.0 + diff --git a/queue-5.10/tracing-remove-duplicate-enable_event_str-and-disabl.patch b/queue-5.10/tracing-remove-duplicate-enable_event_str-and-disabl.patch new file mode 100644 index 0000000000..8b2e2b0c7a --- /dev/null +++ b/queue-5.10/tracing-remove-duplicate-enable_event_str-and-disabl.patch @@ -0,0 +1,44 @@ +From 355cf2ac0d15cfcd1a2395d1366b40ade6255c65 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 13:00:37 -0500 +Subject: tracing: Remove duplicate ENABLE_EVENT_STR and DISABLE_EVENT_STR + macros + +From: Steven Rostedt + +[ Upstream commit 9df0e49c5b9b8d051529be9994e4f92f2d20be6f ] + +The macros ENABLE_EVENT_STR and DISABLE_EVENT_STR were added to trace.h so +that more than one file can have access to them, but was never removed +from their original location. Remove the duplicates. + +Cc: Masami Hiramatsu +Cc: Mathieu Desnoyers +Cc: Tom Zanussi +Link: https://patch.msgid.link/20260126130037.4ba201f9@gandalf.local.home +Fixes: d0bad49bb0a09 ("tracing: Add enable_hist/disable_hist triggers") +Signed-off-by: Steven Rostedt (Google) +Signed-off-by: Sasha Levin +--- + kernel/trace/trace_events.c | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c +index c9fc3c442681a..da4a69e1929c5 100644 +--- a/kernel/trace/trace_events.c ++++ b/kernel/trace/trace_events.c +@@ -2848,11 +2848,6 @@ void trace_put_event_file(struct trace_event_file *file) + EXPORT_SYMBOL_GPL(trace_put_event_file); + + #ifdef CONFIG_DYNAMIC_FTRACE +- +-/* Avoid typos */ +-#define ENABLE_EVENT_STR "enable_event" +-#define DISABLE_EVENT_STR "disable_event" +- + struct event_probe_data { + struct trace_event_file *file; + unsigned long count; +-- +2.51.0 + diff --git a/queue-5.10/ucount-check-for-cap_sys_resource-using-ns_capable_n.patch b/queue-5.10/ucount-check-for-cap_sys_resource-using-ns_capable_n.patch new file mode 100644 index 0000000000..7f14f2488e --- /dev/null +++ b/queue-5.10/ucount-check-for-cap_sys_resource-using-ns_capable_n.patch @@ -0,0 +1,51 @@ +From 19d0eb0c1a75aade52a9038470fc6510ab3cb8fa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 15:07:45 +0100 +Subject: ucount: check for CAP_SYS_RESOURCE using ns_capable_noaudit() + +From: Ondrej Mosnacek + +[ Upstream commit 0895a000e4fff9e950a7894210db45973e485c35 ] + +The user.* sysctls implement the ctl_table_root::permissions hook and they +override the file access mode based on the CAP_SYS_RESOURCE capability (at +most rwx if capable, at most r-- if not). The capability is being checked +unconditionally, so if an LSM denies the capability, an audit record may +be logged even when access is in fact granted. + +Given the logic in the set_permissions() function in kernel/ucount.c and +the unfortunate way the permission checking is implemented, it doesn't +seem viable to avoid false positive denials by deferring the capability +check. Thus, do the same as in net_ctl_permissions() (net/sysctl_net.c) - +switch from ns_capable() to ns_capable_noaudit(), so that the check never +logs an audit record. + +Link: https://lkml.kernel.org/r/20260122140745.239428-1-omosnace@redhat.com +Fixes: dbec28460a89 ("userns: Add per user namespace sysctls.") +Signed-off-by: Ondrej Mosnacek +Reviewed-by: Paul Moore +Acked-by: Serge Hallyn +Cc: Eric Biederman +Cc: Alexey Gladkov +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + kernel/ucount.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/ucount.c b/kernel/ucount.c +index 8d8874f1c35e2..a1e900aa1fe4a 100644 +--- a/kernel/ucount.c ++++ b/kernel/ucount.c +@@ -39,7 +39,7 @@ static int set_permissions(struct ctl_table_header *head, + int mode; + + /* Allow users with CAP_SYS_RESOURCE unrestrained access */ +- if (ns_capable(user_ns, CAP_SYS_RESOURCE)) ++ if (ns_capable_noaudit(user_ns, CAP_SYS_RESOURCE)) + mode = (table->mode & S_IRWXU) >> 6; + else + /* Allow all others at most read-only access */ +-- +2.51.0 + diff --git a/queue-5.10/usb-bdc-fix-sleep-during-atomic.patch b/queue-5.10/usb-bdc-fix-sleep-during-atomic.patch new file mode 100644 index 0000000000..e8ab0d1a75 --- /dev/null +++ b/queue-5.10/usb-bdc-fix-sleep-during-atomic.patch @@ -0,0 +1,41 @@ +From 02b8e0f5fecda5c255c965cae062b35fa77e236a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 12:07:54 -0800 +Subject: usb: bdc: fix sleep during atomic + +From: Justin Chen + +[ Upstream commit f1195ca3b4bbd001d3f1264dce91f83dec7777f5 ] + +bdc_run() can be ran during atomic context leading to a sleep during +atomic warning. Fix this by replacing read_poll_timeout() with +read_poll_timeout_atomic(). + +Fixes: 75ae051efc9b ("usb: gadget: bdc: use readl_poll_timeout() to simplify code") +Signed-off-by: Justin Chen +Reviewed-by: Florian Fainelli +Link: https://patch.msgid.link/20260120200754.2488765-1-justin.chen@broadcom.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/gadget/udc/bdc/bdc_core.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/usb/gadget/udc/bdc/bdc_core.c b/drivers/usb/gadget/udc/bdc/bdc_core.c +index fa1a3908ec3bb..69d11b703c8d0 100644 +--- a/drivers/usb/gadget/udc/bdc/bdc_core.c ++++ b/drivers/usb/gadget/udc/bdc/bdc_core.c +@@ -35,8 +35,8 @@ static int poll_oip(struct bdc *bdc, u32 usec) + u32 status; + int ret; + +- ret = readl_poll_timeout(bdc->regs + BDC_BDCSC, status, +- (BDC_CSTS(status) != BDC_OIP), 10, usec); ++ ret = readl_poll_timeout_atomic(bdc->regs + BDC_BDCSC, status, ++ (BDC_CSTS(status) != BDC_OIP), 10, usec); + if (ret) + dev_err(bdc->dev, "operation timedout BDCSC: 0x%08x\n", status); + else +-- +2.51.0 + diff --git a/queue-5.10/wifi-ath10k-sdio-add-missing-lock-protection-in-ath1.patch b/queue-5.10/wifi-ath10k-sdio-add-missing-lock-protection-in-ath1.patch new file mode 100644 index 0000000000..217b397e08 --- /dev/null +++ b/queue-5.10/wifi-ath10k-sdio-add-missing-lock-protection-in-ath1.patch @@ -0,0 +1,62 @@ +From c90f895ed9384147589d06247a37a2f7d141756c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 04:58:22 +0000 +Subject: wifi: ath10k: sdio: add missing lock protection in + ath10k_sdio_fw_crashed_dump() + +From: Ziyi Guo + +[ Upstream commit e55ac348089e579fc224569c7bd90340bf2439f9 ] + +ath10k_sdio_fw_crashed_dump() calls ath10k_coredump_new() which requires +ar->dump_mutex to be held, as indicated by lockdep_assert_held() in that +function. However, the SDIO implementation does not acquire this lock, +unlike the PCI and SNOC implementations which properly hold the mutex. + +Additionally, ar->stats.fw_crash_counter is documented as protected by +ar->data_lock in core.h, but the SDIO implementation modifies it without +holding this spinlock. + +Add the missing mutex_lock()/mutex_unlock() around the coredump +operations, and add spin_lock_bh()/spin_unlock_bh() around the +fw_crash_counter increment, following the pattern used in +ath10k_pci_fw_dump_work() and ath10k_snoc_fw_crashed_dump(). + +Fixes: 3c45f21af84e ("ath10k: sdio: add firmware coredump support") +Signed-off-by: Ziyi Guo +Reviewed-by: Baochen Qiang +Link: https://patch.msgid.link/20260123045822.2221549-1-n7l8m4@u.northwestern.edu +Signed-off-by: Jeff Johnson +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/ath/ath10k/sdio.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c +index 7cb1bc8d6e01c..d87bb3275b392 100644 +--- a/drivers/net/wireless/ath/ath10k/sdio.c ++++ b/drivers/net/wireless/ath/ath10k/sdio.c +@@ -2486,7 +2486,11 @@ void ath10k_sdio_fw_crashed_dump(struct ath10k *ar) + if (fast_dump) + ath10k_bmi_start(ar); + ++ mutex_lock(&ar->dump_mutex); ++ ++ spin_lock_bh(&ar->data_lock); + ar->stats.fw_crash_counter++; ++ spin_unlock_bh(&ar->data_lock); + + ath10k_sdio_disable_intrs(ar); + +@@ -2504,6 +2508,8 @@ void ath10k_sdio_fw_crashed_dump(struct ath10k *ar) + + ath10k_sdio_enable_intrs(ar); + ++ mutex_unlock(&ar->dump_mutex); ++ + ath10k_core_start_recovery(ar); + } + +-- +2.51.0 + diff --git a/queue-5.10/wifi-cfg80211-stop-nan-and-p2p-in-cfg80211_leave.patch b/queue-5.10/wifi-cfg80211-stop-nan-and-p2p-in-cfg80211_leave.patch new file mode 100644 index 0000000000..1aec1a2d38 --- /dev/null +++ b/queue-5.10/wifi-cfg80211-stop-nan-and-p2p-in-cfg80211_leave.patch @@ -0,0 +1,47 @@ +From b4063a6e6b86ea98a1cc8e207ea2582fe473d4ea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 14:04:51 +0200 +Subject: wifi: cfg80211: stop NAN and P2P in cfg80211_leave + +From: Miri Korenblit + +[ Upstream commit e1696c8bd0056bc1a5f7766f58ac333adc203e8a ] + +Seems that there is an assumption that this function should be called +only for netdev interfaces, but it can also be called in suspend, or +from nl80211_netlink_notify (indirectly). +Note that the documentation of NL80211_ATTR_SOCKET_OWNER explicitly +says that NAN interfaces would be destroyed as well in the +nl80211_netlink_notify case. + +Fix this by also stopping P2P and NAN. + +Fixes: cb3b7d87652a ("cfg80211: add start / stop NAN commands") +Reviewed-by: Johannes Berg +Signed-off-by: Miri Korenblit +Link: https://patch.msgid.link/20260107140430.dab142cbef0b.I290cc47836d56dd7e35012ce06bec36c6da688cd@changeid +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/wireless/core.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/net/wireless/core.c b/net/wireless/core.c +index 3b25b78896a28..cc2093f75468f 100644 +--- a/net/wireless/core.c ++++ b/net/wireless/core.c +@@ -1207,8 +1207,10 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev, + /* must be handled by mac80211/driver, has no APIs */ + break; + case NL80211_IFTYPE_P2P_DEVICE: ++ cfg80211_stop_p2p_device(rdev, wdev); ++ break; + case NL80211_IFTYPE_NAN: +- /* cannot happen, has no netdev */ ++ cfg80211_stop_nan(rdev, wdev); + break; + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_MONITOR: +-- +2.51.0 + diff --git a/queue-5.15/arm-dts-allwinner-sun5i-a13-utoo-p66-delete-power-gp.patch b/queue-5.15/arm-dts-allwinner-sun5i-a13-utoo-p66-delete-power-gp.patch new file mode 100644 index 0000000000..cf30218eeb --- /dev/null +++ b/queue-5.15/arm-dts-allwinner-sun5i-a13-utoo-p66-delete-power-gp.patch @@ -0,0 +1,46 @@ +From 6282f030bdfe883e42a359ad674d7b100d2485bc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 25 Dec 2025 18:36:14 +0800 +Subject: ARM: dts: allwinner: sun5i-a13-utoo-p66: delete "power-gpios" + property + +From: Chen-Yu Tsai + +[ Upstream commit 0b2761eb1287bd9f62367cccf6626eb3107cef6f ] + +The P66's device tree includes the reference design dtsi files, which +defines a node and properties for the touchpanel in the common design. +The P66 dts file then overrides all the properties to match its own +design, but as the touchpanel model is different, a different schema +is matched. This other schema uses a different name for the GPIO. + +The original submission added the correct GPIO property, but did not +delete the one inherited from the reference design, causing validation +errors. + +Explicitly delete the incorrect GPIO property. + +Fixes: 2a53aff27236 ("ARM: dts: sun5i: Enable touchscreen on Utoo P66") +Reviewed-by: Jernej Skrabec +Link: https://patch.msgid.link/20251225103616.3203473-4-wens@kernel.org +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Sasha Levin +--- + arch/arm/boot/dts/sun5i-a13-utoo-p66.dts | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/boot/dts/sun5i-a13-utoo-p66.dts b/arch/arm/boot/dts/sun5i-a13-utoo-p66.dts +index be486d28d04fa..428cab5a0e906 100644 +--- a/arch/arm/boot/dts/sun5i-a13-utoo-p66.dts ++++ b/arch/arm/boot/dts/sun5i-a13-utoo-p66.dts +@@ -102,6 +102,7 @@ &touchscreen { + /* The P66 uses a different EINT then the reference design */ + interrupts = <6 9 IRQ_TYPE_EDGE_FALLING>; /* EINT9 (PG9) */ + /* The icn8318 binding expects wake-gpios instead of power-gpios */ ++ /delete-property/ power-gpios; + wake-gpios = <&pio 1 3 GPIO_ACTIVE_HIGH>; /* PB3 */ + touchscreen-size-x = <800>; + touchscreen-size-y = <480>; +-- +2.51.0 + diff --git a/queue-5.15/arm-dts-lpc32xx-add-clocks-property-to-motor-control.patch b/queue-5.15/arm-dts-lpc32xx-add-clocks-property-to-motor-control.patch new file mode 100644 index 0000000000..f21c4153a7 --- /dev/null +++ b/queue-5.15/arm-dts-lpc32xx-add-clocks-property-to-motor-control.patch @@ -0,0 +1,35 @@ +From 1fa9fdf60122c801fe4f917801ad85c0e5ed5f71 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Dec 2025 00:49:07 +0200 +Subject: arm: dts: lpc32xx: add clocks property to Motor Control PWM device + tree node + +From: Vladimir Zapolskiy + +[ Upstream commit 71630e581a0e34c03757f5c1706f57c853b92555 ] + +Motor Control PWM depends on its own supply clock, the clock gate control +is present in TIMCLK_CTRL1 register. + +Fixes: b7d41c937ed7 ("ARM: LPC32xx: Add the motor PWM to base dts file") +Signed-off-by: Vladimir Zapolskiy +Signed-off-by: Sasha Levin +--- + arch/arm/boot/dts/lpc32xx.dtsi | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/boot/dts/lpc32xx.dtsi b/arch/arm/boot/dts/lpc32xx.dtsi +index 4fb5d9dae1850..0e856de14e49a 100644 +--- a/arch/arm/boot/dts/lpc32xx.dtsi ++++ b/arch/arm/boot/dts/lpc32xx.dtsi +@@ -301,6 +301,7 @@ i2c2: i2c@400a8000 { + mpwm: mpwm@400e8000 { + compatible = "nxp,lpc3220-motor-pwm"; + reg = <0x400e8000 0x78>; ++ clocks = <&clk LPC32XX_CLK_MCPWM>; + #pwm-cells = <3>; + status = "disabled"; + }; +-- +2.51.0 + diff --git a/queue-5.15/arm-dts-lpc32xx-set-motor-pwm-pwm-cells-property-val.patch b/queue-5.15/arm-dts-lpc32xx-set-motor-pwm-pwm-cells-property-val.patch new file mode 100644 index 0000000000..692a9b3a43 --- /dev/null +++ b/queue-5.15/arm-dts-lpc32xx-set-motor-pwm-pwm-cells-property-val.patch @@ -0,0 +1,47 @@ +From 2dec623fd38375365c8b425f3a767398579eb2f0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Sep 2025 21:46:42 +0300 +Subject: ARM: dts: lpc32xx: Set motor PWM #pwm-cells property value to 3 cells +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Vladimir Zapolskiy + +[ Upstream commit 65ae9ea77e1f2a20ad2866f99596df7ccdbd3b95 ] + +Since commit 4cd2f417a0ac ("dt-bindings: pwm: Convert lpc32xx-pwm.txt +to yaml format") both types of PWM controlles on NXP LPC32xx SoC +fairly gained 3 cells, reflect it in the platform dtsi file. + +The change removes a dt binding checker warning: + + mpwm@400e8000: #pwm-cells:0:0: 3 was expected + +Cc: Uwe Kleine-König +Acked-by: Uwe Kleine-König +Reviewed-by: Frank Li +Signed-off-by: Vladimir Zapolskiy +Stable-dep-of: 71630e581a0e ("arm: dts: lpc32xx: add clocks property to Motor Control PWM device tree node") +Signed-off-by: Sasha Levin +--- + arch/arm/boot/dts/lpc32xx.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/lpc32xx.dtsi b/arch/arm/boot/dts/lpc32xx.dtsi +index c87066d6c9950..4fb5d9dae1850 100644 +--- a/arch/arm/boot/dts/lpc32xx.dtsi ++++ b/arch/arm/boot/dts/lpc32xx.dtsi +@@ -301,8 +301,8 @@ i2c2: i2c@400a8000 { + mpwm: mpwm@400e8000 { + compatible = "nxp,lpc3220-motor-pwm"; + reg = <0x400e8000 0x78>; ++ #pwm-cells = <3>; + status = "disabled"; +- #pwm-cells = <2>; + }; + }; + +-- +2.51.0 + diff --git a/queue-5.15/arm-vdso-patch-out-__vdso_clock_getres-if-unavailabl.patch b/queue-5.15/arm-vdso-patch-out-__vdso_clock_getres-if-unavailabl.patch new file mode 100644 index 0000000000..742e9be988 --- /dev/null +++ b/queue-5.15/arm-vdso-patch-out-__vdso_clock_getres-if-unavailabl.patch @@ -0,0 +1,39 @@ +From b05a57a38520db399f67fca12ba62d2db403a928 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 23 Dec 2025 07:59:17 +0100 +Subject: ARM: VDSO: Patch out __vdso_clock_getres() if unavailable +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh + +[ Upstream commit b9fecf0dddfc55cd7d02b0011494da3c613f7cde ] + +The vDSO code hides symbols which are non-functional. +__vdso_clock_getres() was not added to this list when it got introduced. + +Fixes: 052e76a31b4a ("ARM: 8931/1: Add clock_getres entry point") +Signed-off-by: Thomas Weißschuh +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20251223-vdso-compat-time32-v1-6-97ea7a06a543@linutronix.de +Signed-off-by: Sasha Levin +--- + arch/arm/kernel/vdso.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/kernel/vdso.c b/arch/arm/kernel/vdso.c +index 3408269d19c7d..b38f4a1bc9b8a 100644 +--- a/arch/arm/kernel/vdso.c ++++ b/arch/arm/kernel/vdso.c +@@ -176,6 +176,7 @@ static void __init patch_vdso(void *ehdr) + vdso_nullpatch_one(&einfo, "__vdso_gettimeofday"); + vdso_nullpatch_one(&einfo, "__vdso_clock_gettime"); + vdso_nullpatch_one(&einfo, "__vdso_clock_gettime64"); ++ vdso_nullpatch_one(&einfo, "__vdso_clock_getres"); + } + } + +-- +2.51.0 + diff --git a/queue-5.15/arm64-dts-amlogic-axg-assign-the-mmc-signal-clocks.patch b/queue-5.15/arm64-dts-amlogic-axg-assign-the-mmc-signal-clocks.patch new file mode 100644 index 0000000000..04096971cd --- /dev/null +++ b/queue-5.15/arm64-dts-amlogic-axg-assign-the-mmc-signal-clocks.patch @@ -0,0 +1,52 @@ +From 93acba0e3e0d7839e484c7c4a7949c8cac2734cb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:08:50 +0100 +Subject: arm64: dts: amlogic: axg: assign the MMC signal clocks + +From: Jerome Brunet + +[ Upstream commit 13d3fe2318ef6e46d6fcfe13bc373827fdf2aeac ] + +The amlogic MMC driver operate with the assumption that MMC clock +is configured to provide 24MHz. It uses this path for low +rates such as 400kHz. + +Assign the clocks to make sure they are properly configured + +Fixes: 221cf34bac54 ("ARM64: dts: meson-axg: enable the eMMC controller") +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Link: https://patch.msgid.link/20260114-amlogic-mmc-clocks-followup-v1-3-a999fafbe0aa@baylibre.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-axg.dtsi | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi +index db5a1f4653135..280fe16b68fe0 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi +@@ -1892,6 +1892,9 @@ sd_emmc_b: sd@5000 { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_B>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_B_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + sd_emmc_c: mmc@7000 { +@@ -1904,6 +1907,9 @@ sd_emmc_c: mmc@7000 { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_C>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_C_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + usb2_phy1: phy@9020 { +-- +2.51.0 + diff --git a/queue-5.15/arm64-dts-amlogic-g12-assign-the-mmc-a-signal-clock.patch b/queue-5.15/arm64-dts-amlogic-g12-assign-the-mmc-a-signal-clock.patch new file mode 100644 index 0000000000..09e56b7e53 --- /dev/null +++ b/queue-5.15/arm64-dts-amlogic-g12-assign-the-mmc-a-signal-clock.patch @@ -0,0 +1,42 @@ +From f6e32ddc38aa4b24f93d02bbbe31e06cce69c175 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:08:53 +0100 +Subject: arm64: dts: amlogic: g12: assign the MMC A signal clock + +From: Jerome Brunet + +[ Upstream commit 3c941feaa363f1573a501452391ddf513394c84b ] + +The amlogic MMC driver operate with the assumption that MMC clock +is configured to provide 24MHz. It uses this path for low +rates such as 400kHz. + +Assign the clock to make sure it is properly configured + +Fixes: 8a6b3ca2d361 ("arm64: dts: meson: g12a: add SDIO controller") +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Link: https://patch.msgid.link/20260114-amlogic-mmc-clocks-followup-v1-6-a999fafbe0aa@baylibre.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +index 64bf34c9d769d..20b4575594a03 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +@@ -2336,6 +2336,9 @@ sd_emmc_a: sd@ffe03000 { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_A>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_A_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + sd_emmc_b: sd@ffe05000 { +-- +2.51.0 + diff --git a/queue-5.15/arm64-dts-amlogic-g12-assign-the-mmc-b-and-c-signal-.patch b/queue-5.15/arm64-dts-amlogic-g12-assign-the-mmc-b-and-c-signal-.patch new file mode 100644 index 0000000000..e680a67f28 --- /dev/null +++ b/queue-5.15/arm64-dts-amlogic-g12-assign-the-mmc-b-and-c-signal-.patch @@ -0,0 +1,52 @@ +From 95d21cc0de7d93b50b41f110ef6aead8c493b508 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:08:52 +0100 +Subject: arm64: dts: amlogic: g12: assign the MMC B and C signal clocks + +From: Jerome Brunet + +[ Upstream commit be2ff5fdb0e83e32d4ec4e68a69875cec0d14621 ] + +The amlogic MMC driver operate with the assumption that MMC clock +is configured to provide 24MHz. It uses this path for low +rates such as 400kHz. + +Assign the clocks to make sure they are properly configured + +Fixes: 4759fd87b928 ("arm64: dts: meson: g12a: add mmc nodes") +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Link: https://patch.msgid.link/20260114-amlogic-mmc-clocks-followup-v1-5-a999fafbe0aa@baylibre.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +index 369334076467a..64bf34c9d769d 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +@@ -2348,6 +2348,9 @@ sd_emmc_b: sd@ffe05000 { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_B>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_B_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + sd_emmc_c: mmc@ffe07000 { +@@ -2360,6 +2363,9 @@ sd_emmc_c: mmc@ffe07000 { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_C>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_C_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + usb: usb@ffe09000 { +-- +2.51.0 + diff --git a/queue-5.15/arm64-dts-amlogic-gx-assign-the-mmc-signal-clocks.patch b/queue-5.15/arm64-dts-amlogic-gx-assign-the-mmc-signal-clocks.patch new file mode 100644 index 0000000000..209c6678b7 --- /dev/null +++ b/queue-5.15/arm64-dts-amlogic-gx-assign-the-mmc-signal-clocks.patch @@ -0,0 +1,97 @@ +From ba250081cabee9d15341c1041683c802539f65f5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:08:51 +0100 +Subject: arm64: dts: amlogic: gx: assign the MMC signal clocks + +From: Jerome Brunet + +[ Upstream commit 406706559046eebc09a31e8ae5e78620bfd746fe ] + +The amlogic MMC driver operate with the assumption that MMC clock +is configured to provide 24MHz. It uses this path for low +rates such as 400kHz. + +Assign the clocks to make sure they are properly configured + +Fixes: 50662499f911 ("ARM64: dts: meson-gx: Use correct mmc clock source 0") +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Link: https://patch.msgid.link/20260114-amlogic-mmc-clocks-followup-v1-4-a999fafbe0aa@baylibre.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 9 +++++++++ + arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 9 +++++++++ + 2 files changed, 18 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi +index 256c46771db78..c57a6f37bc2af 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi +@@ -779,6 +779,9 @@ &sd_emmc_a { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_A>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_A_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &sd_emmc_b { +@@ -787,6 +790,9 @@ &sd_emmc_b { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_B>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_B_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &sd_emmc_c { +@@ -795,6 +801,9 @@ &sd_emmc_c { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_C>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_C_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &simplefb_hdmi { +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi +index a689bd14ece99..fb6e8c466811f 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi +@@ -848,6 +848,9 @@ &sd_emmc_a { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_A>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_A_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &sd_emmc_b { +@@ -856,6 +859,9 @@ &sd_emmc_b { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_B>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_B_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &sd_emmc_c { +@@ -864,6 +870,9 @@ &sd_emmc_c { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_C>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_C_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &simplefb_hdmi { +-- +2.51.0 + diff --git a/queue-5.15/arm64-dts-qcom-sdm630-correct-qfprom-byte-offsets.patch b/queue-5.15/arm64-dts-qcom-sdm630-correct-qfprom-byte-offsets.patch new file mode 100644 index 0000000000..c63ad843ab --- /dev/null +++ b/queue-5.15/arm64-dts-qcom-sdm630-correct-qfprom-byte-offsets.patch @@ -0,0 +1,53 @@ +From 28e9774bc93456ba5fed23389e4976c434d2d25a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 May 2022 13:38:02 +0200 +Subject: arm64: dts: qcom: sdm630: correct QFPROM byte offsets + +From: Krzysztof Kozlowski + +[ Upstream commit 74b0fbd6048f8f4caaed712ceeca52c6034e9ad6 ] + +The NVMEM bindings expect that 'bits' property holds offset and size of +region within a byte, so it applies a constraint of <0, 7> for the +offset. Using 25 as HSTX trim offset is within 4-byte QFPROM word, but +outside of the byte: + + sdm630-sony-xperia-nile-discovery.dtb: qfprom@780000: hstx-trim@240:bits:0:0: 25 is greater than the maximum of 7 + sdm630-sony-xperia-nile-discovery.dtb: qfprom@780000: gpu-speed-bin@41a0:bits:0:0: 21 is greater than the maximum of 7 + +Align the offsets to match the bindings. + +Signed-off-by: Krzysztof Kozlowski +Signed-off-by: Bjorn Andersson +Link: https://lore.kernel.org/r/20220505113802.243301-6-krzysztof.kozlowski@linaro.org +Stable-dep-of: e814796dfcae ("arm64: dts: qcom: sdm630: fix gpu_speed_bin size") +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm630.dtsi | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/sdm630.dtsi b/arch/arm64/boot/dts/qcom/sdm630.dtsi +index 70dfde9d24ec5..e6527652a1245 100644 +--- a/arch/arm64/boot/dts/qcom/sdm630.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm630.dtsi +@@ -554,13 +554,13 @@ qfprom: qfprom@780000 { + #size-cells = <1>; + + qusb2_hstx_trim: hstx-trim@240 { +- reg = <0x240 0x1>; +- bits = <25 3>; ++ reg = <0x243 0x1>; ++ bits = <1 3>; + }; + + gpu_speed_bin: gpu-speed-bin@41a0 { +- reg = <0x41a0 0x1>; +- bits = <21 7>; ++ reg = <0x41a2 0x1>; ++ bits = <5 7>; + }; + }; + +-- +2.51.0 + diff --git a/queue-5.15/arm64-dts-qcom-sdm630-fix-gpu_speed_bin-size.patch b/queue-5.15/arm64-dts-qcom-sdm630-fix-gpu_speed_bin-size.patch new file mode 100644 index 0000000000..4df34ea677 --- /dev/null +++ b/queue-5.15/arm64-dts-qcom-sdm630-fix-gpu_speed_bin-size.patch @@ -0,0 +1,49 @@ +From 7dccd91b69c33e1ca79d6b11009ef18e94b514db Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 11 Dec 2025 03:27:45 +0200 +Subject: arm64: dts: qcom: sdm630: fix gpu_speed_bin size + +From: Dmitry Baryshkov + +[ Upstream commit e814796dfcae8905682ac3ac2dd57f512a9f6726 ] + +Historically sdm630.dtsi has used 1 byte length for the gpu_speed_bin +cell, although it spans two bytes (offset 5, size 7 bits). It was being +accepted by the kernel because before the commit 7a06ef751077 ("nvmem: +core: fix bit offsets of more than one byte") the kernel didn't have +length check. After this commit nvmem core rejects QFPROM on sdm630 / +sdm660, making GPU and USB unusable on those platforms. + +Set the size of the gpu_speed_bin cell to 2 bytes, fixing the parsing +error. While we are at it, update the length to 8 bits as pointed out by +Alexey Minnekhanov. + +Fixes: b190fb010664 ("arm64: dts: qcom: sdm630: Add sdm630 dts file") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Reviewed-by: Alexey Minnekhanov +Link: https://lore.kernel.org/r/20251211-sdm630-fix-gpu-v2-1-92f0e736dba0@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm630.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/sdm630.dtsi b/arch/arm64/boot/dts/qcom/sdm630.dtsi +index e6527652a1245..5a1069cb696e9 100644 +--- a/arch/arm64/boot/dts/qcom/sdm630.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm630.dtsi +@@ -559,8 +559,8 @@ qusb2_hstx_trim: hstx-trim@240 { + }; + + gpu_speed_bin: gpu-speed-bin@41a0 { +- reg = <0x41a2 0x1>; +- bits = <5 7>; ++ reg = <0x41a2 0x2>; ++ bits = <5 8>; + }; + }; + +-- +2.51.0 + diff --git a/queue-5.15/arm64-dts-qcom-sdm845-db845c-specify-power-for-wifi-.patch b/queue-5.15/arm64-dts-qcom-sdm845-db845c-specify-power-for-wifi-.patch new file mode 100644 index 0000000000..721435f303 --- /dev/null +++ b/queue-5.15/arm64-dts-qcom-sdm845-db845c-specify-power-for-wifi-.patch @@ -0,0 +1,50 @@ +From e8f8951cb0236c57adaf0dd78afcf2cc50486ab0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Jan 2026 03:01:18 +0200 +Subject: arm64: dts: qcom: sdm845-db845c: specify power for WiFi CH1 + +From: Dmitry Baryshkov + +[ Upstream commit c303e89f7f17c29981d09f8beaaf60937ae8b1f2 ] + +Specify power supply for the second chain / antenna output of the +onboard WiFi chip. + +Fixes: 3f72e2d3e682 ("arm64: dts: qcom: Add Dragonboard 845c") +Reviewed-by: Konrad Dybcio +Signed-off-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260106-wcn3990-pwrctl-v2-8-0386204328be@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm845-db845c.dts | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts +index 62877311e5c24..cf2df9e2ccf30 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts ++++ b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts +@@ -342,6 +342,12 @@ vreg_l21a_2p95: ldo21 { + regulator-initial-mode = ; + }; + ++ vreg_l23a_3p3: ldo23 { ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3312000>; ++ regulator-initial-mode = ; ++ }; ++ + vreg_l24a_3p075: ldo24 { + regulator-min-microvolt = <3088000>; + regulator-max-microvolt = <3088000>; +@@ -1039,6 +1045,7 @@ &wifi { + vdd-1.8-xo-supply = <&vreg_l7a_1p8>; + vdd-1.3-rfa-supply = <&vreg_l17a_1p3>; + vdd-3.3-ch0-supply = <&vreg_l25a_3p3>; ++ vdd-3.3-ch1-supply = <&vreg_l23a_3p3>; + + qcom,snoc-host-cap-8bit-quirk; + }; +-- +2.51.0 + diff --git a/queue-5.15/arm64-dts-qcom-sdm845-oneplus-don-t-keep-panel-regul.patch b/queue-5.15/arm64-dts-qcom-sdm845-oneplus-don-t-keep-panel-regul.patch new file mode 100644 index 0000000000..95f66306e8 --- /dev/null +++ b/queue-5.15/arm64-dts-qcom-sdm845-oneplus-don-t-keep-panel-regul.patch @@ -0,0 +1,39 @@ +From 6a5dadf3fa140f18328bb27518cb04e3ed9f2852 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 18 Nov 2025 15:52:26 +0100 +Subject: arm64: dts: qcom: sdm845-oneplus: Don't keep panel regulator always + on + +From: Casey Connolly + +[ Upstream commit 45d1f42d3e84b5880cf9fab1eb24a7818320eeb7 ] + +The panel regulator doesn't need to be always on, so remove this +property. + +Fixes: 288ef8a42612 ("arm64: dts: sdm845: add oneplus6/6t devices") +Signed-off-by: Casey Connolly +Signed-off-by: David Heidelberg +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251118-dts-oneplus-regulators-v2-2-3e67cea1e4e7@ixit.cz +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +index 66b86dd292c8a..1a1e344f870ef 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +@@ -232,7 +232,6 @@ vreg_l14a_1p88: ldo14 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; +- regulator-always-on; + }; + + vreg_l17a_1p3: ldo17 { +-- +2.51.0 + diff --git a/queue-5.15/arm64-dts-qcom-sdm845-oneplus-don-t-mark-ts-supply-b.patch b/queue-5.15/arm64-dts-qcom-sdm845-oneplus-don-t-mark-ts-supply-b.patch new file mode 100644 index 0000000000..90f4a2f843 --- /dev/null +++ b/queue-5.15/arm64-dts-qcom-sdm845-oneplus-don-t-mark-ts-supply-b.patch @@ -0,0 +1,39 @@ +From 101314ef6e4498c0fbcbfe54a16624747332eb86 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 18 Nov 2025 15:52:25 +0100 +Subject: arm64: dts: qcom: sdm845-oneplus: Don't mark ts supply boot-on + +From: Casey Connolly + +[ Upstream commit c9b98b9dad9749bf2eb7336a6fca31a6af1039d7 ] + +The touchscreen isn't enabled by bootloader and doesn't need to be +enabled at boot, only when the driver probes, thus remove the +regulator-boot-on property. + +Fixes: 288ef8a42612 ("arm64: dts: sdm845: add oneplus6/6t devices") +Signed-off-by: Casey Connolly +Signed-off-by: David Heidelberg +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251118-dts-oneplus-regulators-v2-1-3e67cea1e4e7@ixit.cz +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +index d4355522374a1..66b86dd292c8a 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +@@ -136,7 +136,6 @@ ts_1p8_supply: ts-1p8-regulator { + + gpio = <&tlmm 88 0>; + enable-active-high; +- regulator-boot-on; + }; + }; + +-- +2.51.0 + diff --git a/queue-5.15/arm64-dts-qcom-sdm845-oneplus-mark-l14a-regulator-as.patch b/queue-5.15/arm64-dts-qcom-sdm845-oneplus-mark-l14a-regulator-as.patch new file mode 100644 index 0000000000..b12a47f353 --- /dev/null +++ b/queue-5.15/arm64-dts-qcom-sdm845-oneplus-mark-l14a-regulator-as.patch @@ -0,0 +1,38 @@ +From b70cf0e92592e0e039b3a42ee1bf12befe0761af Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 18 Nov 2025 15:52:27 +0100 +Subject: arm64: dts: qcom: sdm845-oneplus: Mark l14a regulator as boot-on + +From: Casey Connolly + +[ Upstream commit ad33ee060be46794a03d033894c9db3a9d6c1a0f ] + +This regulator is used only for the display, which is enabled by the +bootloader and left on for continuous splash. Mark it as such. + +Fixes: 288ef8a42612 ("arm64: dts: sdm845: add oneplus6/6t devices") +Signed-off-by: Casey Connolly +Signed-off-by: David Heidelberg +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251118-dts-oneplus-regulators-v2-3-3e67cea1e4e7@ixit.cz +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +index 1a1e344f870ef..a079706f1829d 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +@@ -232,6 +232,7 @@ vreg_l14a_1p88: ldo14 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; ++ regulator-boot-on; + }; + + vreg_l17a_1p3: ldo17 { +-- +2.51.0 + diff --git a/queue-5.15/auxdisplay-arm-charlcd-fix-release_mem_region-size.patch b/queue-5.15/auxdisplay-arm-charlcd-fix-release_mem_region-size.patch new file mode 100644 index 0000000000..bd5f2c6470 --- /dev/null +++ b/queue-5.15/auxdisplay-arm-charlcd-fix-release_mem_region-size.patch @@ -0,0 +1,39 @@ +From dead76695729b5bbd7f8b0750b7319306310811e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Dec 2025 18:47:13 +0100 +Subject: auxdisplay: arm-charlcd: fix release_mem_region() size + +From: Thomas Fourier + +[ Upstream commit b5c23a4d291d2ac1dfdd574a68a3a68c8da3069e ] + +It seems like, after the request_mem_region(), the corresponding +release_mem_region() must take the same size. This was done +in (now removed due to previous refactoring) charlcd_remove() +but not in the error path in charlcd_probe(). + +Fixes: ce8962455e90 ("ARM: 6214/2: driver for the character LCD found in ARM refdesigns") +Signed-off-by: Thomas Fourier +Reviewed-by: Geert Uytterhoeven +Signed-off-by: Andy Shevchenko +Signed-off-by: Sasha Levin +--- + drivers/auxdisplay/arm-charlcd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/auxdisplay/arm-charlcd.c b/drivers/auxdisplay/arm-charlcd.c +index 0b1c99cca7334..f418b133ee752 100644 +--- a/drivers/auxdisplay/arm-charlcd.c ++++ b/drivers/auxdisplay/arm-charlcd.c +@@ -323,7 +323,7 @@ static int __init charlcd_probe(struct platform_device *pdev) + out_no_irq: + iounmap(lcd->virtbase); + out_no_memregion: +- release_mem_region(lcd->phybase, SZ_4K); ++ release_mem_region(lcd->phybase, lcd->physize); + out_no_resource: + kfree(lcd); + return ret; +-- +2.51.0 + diff --git a/queue-5.15/backlight-qcom-wled-support-ovp-values-for-pmi8994.patch b/queue-5.15/backlight-qcom-wled-support-ovp-values-for-pmi8994.patch new file mode 100644 index 0000000000..e316848606 --- /dev/null +++ b/queue-5.15/backlight-qcom-wled-support-ovp-values-for-pmi8994.patch @@ -0,0 +1,94 @@ +From 79593aa52562650ff10af41ad89783cdb76440ba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 08:07:34 +0100 +Subject: backlight: qcom-wled: Support ovp values for PMI8994 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Czémán + +[ Upstream commit f29f972a6e7e3f187ea4d89b98a76c1981ca4d53 ] + +WLED4 found in PMI8994 supports different ovp values. + +Fixes: 6fc632d3e3e0 ("video: backlight: qcom-wled: Add PMI8994 compatible") +Signed-off-by: Barnabás Czémán +Reviewed-by: Konrad Dybcio +Reviewed-by: Daniel Thompson (RISCstar) +Link: https://patch.msgid.link/20260116-pmi8950-wled-v3-2-e6c93de84079@mainlining.org +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/video/backlight/qcom-wled.c | 41 +++++++++++++++++++++++++++-- + 1 file changed, 39 insertions(+), 2 deletions(-) + +diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c +index 21c1fba64ad5d..2ecfbe1b0d3d4 100644 +--- a/drivers/video/backlight/qcom-wled.c ++++ b/drivers/video/backlight/qcom-wled.c +@@ -1242,6 +1242,15 @@ static const struct wled_var_cfg wled4_ovp_cfg = { + .size = ARRAY_SIZE(wled4_ovp_values), + }; + ++static const u32 pmi8994_wled_ovp_values[] = { ++ 31000, 29500, 19400, 17800, ++}; ++ ++static const struct wled_var_cfg pmi8994_wled_ovp_cfg = { ++ .values = pmi8994_wled_ovp_values, ++ .size = ARRAY_SIZE(pmi8994_wled_ovp_values), ++}; ++ + static inline u32 wled5_ovp_values_fn(u32 idx) + { + /* +@@ -1355,6 +1364,29 @@ static int wled_configure(struct wled *wled) + }, + }; + ++ const struct wled_u32_opts pmi8994_wled_opts[] = { ++ { ++ .name = "qcom,current-boost-limit", ++ .val_ptr = &cfg->boost_i_limit, ++ .cfg = &wled4_boost_i_limit_cfg, ++ }, ++ { ++ .name = "qcom,current-limit-microamp", ++ .val_ptr = &cfg->string_i_limit, ++ .cfg = &wled4_string_i_limit_cfg, ++ }, ++ { ++ .name = "qcom,ovp-millivolt", ++ .val_ptr = &cfg->ovp, ++ .cfg = &pmi8994_wled_ovp_cfg, ++ }, ++ { ++ .name = "qcom,switching-freq", ++ .val_ptr = &cfg->switch_freq, ++ .cfg = &wled3_switch_freq_cfg, ++ }, ++ }; ++ + const struct wled_u32_opts wled5_opts[] = { + { + .name = "qcom,current-boost-limit", +@@ -1421,8 +1453,13 @@ static int wled_configure(struct wled *wled) + break; + + case 4: +- u32_opts = wled4_opts; +- size = ARRAY_SIZE(wled4_opts); ++ if (of_device_is_compatible(dev->of_node, "qcom,pmi8994-wled")) { ++ u32_opts = pmi8994_wled_opts; ++ size = ARRAY_SIZE(pmi8994_wled_opts); ++ } else { ++ u32_opts = wled4_opts; ++ size = ARRAY_SIZE(wled4_opts); ++ } + *cfg = wled4_config_defaults; + wled->wled_set_brightness = wled4_set_brightness; + wled->wled_sync_toggle = wled3_sync_toggle; +-- +2.51.0 + diff --git a/queue-5.15/bonding-only-set-speed-duplex-to-unknown-if-getting-.patch b/queue-5.15/bonding-only-set-speed-duplex-to-unknown-if-getting-.patch new file mode 100644 index 0000000000..0b857cecfd --- /dev/null +++ b/queue-5.15/bonding-only-set-speed-duplex-to-unknown-if-getting-.patch @@ -0,0 +1,74 @@ +From c2411c4d0684b131668ac65eaba6af57f5005cdf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 15:11:52 +0100 +Subject: bonding: only set speed/duplex to unknown, if getting speed failed + +From: Thomas Bogendoerfer + +[ Upstream commit 48dec8d88af96039a4a17b8c2f148f2a4066e195 ] + +bond_update_speed_duplex() first set speed/duplex to unknown and +then asks slave driver for current speed/duplex. Since getting +speed/duplex might take longer there is a race, where this false state +is visible by /proc/net/bonding. With commit 691b2bf14946 ("bonding: + update port speed when getting bond speed") this race gets more visible, +if user space is calling ethtool on a regular base. + +Fix this by only setting speed/duplex to unknown, if link speed is +really unknown/unusable. + +Fixes: 98f41f694f46 ("bonding:update speed/duplex for NETDEV_CHANGE") +Signed-off-by: Thomas Bogendoerfer +Acked-by: Jay Vosburgh +Reviewed-by: Nikolay Aleksandrov +Reviewed-by: Hangbin Liu +Link: https://patch.msgid.link/20260203141153.51581-1-tbogendoerfer@suse.de +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/bonding/bond_main.c | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c +index e6394fd45f6df..27ed164375411 100644 +--- a/drivers/net/bonding/bond_main.c ++++ b/drivers/net/bonding/bond_main.c +@@ -673,26 +673,29 @@ static int bond_update_speed_duplex(struct slave *slave) + struct ethtool_link_ksettings ecmd; + int res; + +- slave->speed = SPEED_UNKNOWN; +- slave->duplex = DUPLEX_UNKNOWN; +- + res = __ethtool_get_link_ksettings(slave_dev, &ecmd); + if (res < 0) +- return 1; ++ goto speed_duplex_unknown; + if (ecmd.base.speed == 0 || ecmd.base.speed == ((__u32)-1)) +- return 1; ++ goto speed_duplex_unknown; + switch (ecmd.base.duplex) { + case DUPLEX_FULL: + case DUPLEX_HALF: + break; + default: +- return 1; ++ goto speed_duplex_unknown; + } + + slave->speed = ecmd.base.speed; + slave->duplex = ecmd.base.duplex; + + return 0; ++ ++speed_duplex_unknown: ++ slave->speed = SPEED_UNKNOWN; ++ slave->duplex = DUPLEX_UNKNOWN; ++ ++ return 1; + } + + const char *bond_slave_link_status(s8 link) +-- +2.51.0 + diff --git a/queue-5.15/btrfs-qgroup-return-correct-error-when-deleting-qgro.patch b/queue-5.15/btrfs-qgroup-return-correct-error-when-deleting-qgro.patch new file mode 100644 index 0000000000..5216e4b8ac --- /dev/null +++ b/queue-5.15/btrfs-qgroup-return-correct-error-when-deleting-qgro.patch @@ -0,0 +1,43 @@ +From 39d1c39475d65c893ec4f92f1671e1ab06857b06 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 19:35:23 +0000 +Subject: btrfs: qgroup: return correct error when deleting qgroup relation + item + +From: Filipe Manana + +[ Upstream commit 51b1fcf71c88c3c89e7dcf07869c5de837b1f428 ] + +If we fail to delete the second qgroup relation item, we end up returning +success or -ENOENT in case the first item does not exist, instead of +returning the error from the second item deletion. + +Fixes: 73798c465b66 ("btrfs: qgroup: Try our best to delete qgroup relations") +Reviewed-by: Johannes Thumshirn +Signed-off-by: Filipe Manana +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/qgroup.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c +index 6cff41c46d02e..4593ca523490f 100644 +--- a/fs/btrfs/qgroup.c ++++ b/fs/btrfs/qgroup.c +@@ -1540,8 +1540,10 @@ static int __del_qgroup_relation(struct btrfs_trans_handle *trans, u64 src, + if (ret < 0 && ret != -ENOENT) + goto out; + ret2 = del_qgroup_relation_item(trans, dst, src); +- if (ret2 < 0 && ret2 != -ENOENT) ++ if (ret2 < 0 && ret2 != -ENOENT) { ++ ret = ret2; + goto out; ++ } + + /* At least one deletion succeeded, return 0 */ + if (!ret || !ret2) +-- +2.51.0 + diff --git a/queue-5.15/clk-meson-gxbb-limit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch b/queue-5.15/clk-meson-gxbb-limit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch new file mode 100644 index 0000000000..375b37b42f --- /dev/null +++ b/queue-5.15/clk-meson-gxbb-limit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch @@ -0,0 +1,87 @@ +From ff10cdf106e0961d72a5a3397753d7d6405b4ee0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Jan 2026 21:47:08 +0100 +Subject: clk: meson: gxbb: Limit the HDMI PLL OD to /4 on GXL/GXM SoCs + +From: Martin Blumenstingl + +[ Upstream commit 5b1a43950fd3162af0ce52b13c14a2d29b179d4f ] + +GXBB has the HDMI PLL OD in the HHI_HDMI_PLL_CNTL2 register while for +GXL/GXM the OD has moved to HHI_HDMI_PLL_CNTL3. At first glance the rest +of the OD setup seems identical. + +However, looking at the downstream kernel sources as well as testing +shows that GXL only supports three OD values: +- register value 0 means: divide by 1 +- register value 1 means: divide by 2 +- register value 2 means: divide by 4 + +Using register value 3 (which on GXBB means: divide by 8) still divides +by 4 as verified using meson-clk-measure. Downstream sources are also +only using OD register values 0, 1 and 2 for GXL (while for GXBB the +downstream kernel sources are also using value 3). + +Add clk_div_table and have it replace the CLK_DIVIDER_POWER_OF_TWO flag +to make the kernel's view of this register match with how the hardware +actually works. + +Fixes: 69d92293274b ("clk: meson: add the gxl hdmi pll") +Signed-off-by: Martin Blumenstingl +Link: https://lore.kernel.org/r/20260105204710.447779-2-martin.blumenstingl@googlemail.com +Signed-off-by: Jerome Brunet +Signed-off-by: Sasha Levin +--- + drivers/clk/meson/gxbb.c | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c +index 35bc13e73c0dd..6f3918f0a7826 100644 +--- a/drivers/clk/meson/gxbb.c ++++ b/drivers/clk/meson/gxbb.c +@@ -316,12 +316,23 @@ static struct clk_regmap gxbb_hdmi_pll = { + }, + }; + ++/* ++ * GXL hdmi OD dividers are POWER_OF_TWO dividers but limited to /4. ++ * A divider value of 3 should map to /8 but instead map /4 so ignore it. ++ */ ++static const struct clk_div_table gxl_hdmi_pll_od_div_table[] = { ++ { .val = 0, .div = 1 }, ++ { .val = 1, .div = 2 }, ++ { .val = 2, .div = 4 }, ++ { /* sentinel */ } ++}; ++ + static struct clk_regmap gxl_hdmi_pll_od = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL + 8, + .shift = 21, + .width = 2, +- .flags = CLK_DIVIDER_POWER_OF_TWO, ++ .table = gxl_hdmi_pll_od_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od", +@@ -339,7 +350,7 @@ static struct clk_regmap gxl_hdmi_pll_od2 = { + .offset = HHI_HDMI_PLL_CNTL + 8, + .shift = 23, + .width = 2, +- .flags = CLK_DIVIDER_POWER_OF_TWO, ++ .table = gxl_hdmi_pll_od_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od2", +@@ -357,7 +368,7 @@ static struct clk_regmap gxl_hdmi_pll = { + .offset = HHI_HDMI_PLL_CNTL + 8, + .shift = 19, + .width = 2, +- .flags = CLK_DIVIDER_POWER_OF_TWO, ++ .table = gxl_hdmi_pll_od_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll", +-- +2.51.0 + diff --git a/queue-5.15/clk-move-clk_-save-restore-_context-to-common_clk-se.patch b/queue-5.15/clk-move-clk_-save-restore-_context-to-common_clk-se.patch new file mode 100644 index 0000000000..7993fa149d --- /dev/null +++ b/queue-5.15/clk-move-clk_-save-restore-_context-to-common_clk-se.patch @@ -0,0 +1,117 @@ +From 4469b95d9aa0fc5a67e9dedfe3a73d52b8d9ce39 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Dec 2025 10:42:26 +0100 +Subject: clk: Move clk_{save,restore}_context() to COMMON_CLK section + +From: Geert Uytterhoeven + +[ Upstream commit f47c1b77d0a2a9c0d49ec14302e74f933398d1a3 ] + +The clk_save_context() and clk_restore_context() helpers are only +implemented by the Common Clock Framework. They are not available when +using legacy clock frameworks. Dummy implementations are provided, but +only if no clock support is available at all. + +Hence when CONFIG_HAVE_CLK=y, but CONFIG_COMMON_CLK is not enabled: + + m68k-linux-gnu-ld: drivers/net/phy/air_en8811h.o: in function `en8811h_resume': + air_en8811h.c:(.text+0x83e): undefined reference to `clk_restore_context' + m68k-linux-gnu-ld: drivers/net/phy/air_en8811h.o: in function `en8811h_suspend': + air_en8811h.c:(.text+0x856): undefined reference to `clk_save_context' + +Fix this by moving forward declarations and dummy implementions from the +HAVE_CLK to the COMMON_CLK section. + +Fixes: 8b95d1ce3300c411 ("clk: Add functions to save/restore clock context en-masse") +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202511301553.eaEz1nEW-lkp@intel.com/ +Signed-off-by: Geert Uytterhoeven +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + include/linux/clk.h | 48 ++++++++++++++++++++++----------------------- + 1 file changed, 24 insertions(+), 24 deletions(-) + +diff --git a/include/linux/clk.h b/include/linux/clk.h +index 05ab315aa84bc..47ab2d1adc4a1 100644 +--- a/include/linux/clk.h ++++ b/include/linux/clk.h +@@ -216,6 +216,23 @@ int clk_rate_exclusive_get(struct clk *clk); + */ + void clk_rate_exclusive_put(struct clk *clk); + ++/** ++ * clk_save_context - save clock context for poweroff ++ * ++ * Saves the context of the clock register for powerstates in which the ++ * contents of the registers will be lost. Occurs deep within the suspend ++ * code so locking is not necessary. ++ */ ++int clk_save_context(void); ++ ++/** ++ * clk_restore_context - restore clock context after poweroff ++ * ++ * This occurs with all clocks enabled. Occurs deep within the resume code ++ * so locking is not necessary. ++ */ ++void clk_restore_context(void); ++ + #else + + static inline int clk_notifier_register(struct clk *clk, +@@ -276,6 +293,13 @@ static inline int clk_rate_exclusive_get(struct clk *clk) + + static inline void clk_rate_exclusive_put(struct clk *clk) {} + ++static inline int clk_save_context(void) ++{ ++ return 0; ++} ++ ++static inline void clk_restore_context(void) {} ++ + #endif + + #ifdef CONFIG_HAVE_CLK_PREPARE +@@ -859,23 +883,6 @@ struct clk *clk_get_parent(struct clk *clk); + */ + struct clk *clk_get_sys(const char *dev_id, const char *con_id); + +-/** +- * clk_save_context - save clock context for poweroff +- * +- * Saves the context of the clock register for powerstates in which the +- * contents of the registers will be lost. Occurs deep within the suspend +- * code so locking is not necessary. +- */ +-int clk_save_context(void); +- +-/** +- * clk_restore_context - restore clock context after poweroff +- * +- * This occurs with all clocks enabled. Occurs deep within the resume code +- * so locking is not necessary. +- */ +-void clk_restore_context(void); +- + #else /* !CONFIG_HAVE_CLK */ + + static inline struct clk *clk_get(struct device *dev, const char *id) +@@ -1042,13 +1049,6 @@ static inline struct clk *clk_get_sys(const char *dev_id, const char *con_id) + return NULL; + } + +-static inline int clk_save_context(void) +-{ +- return 0; +-} +- +-static inline void clk_restore_context(void) {} +- + #endif + + /* clk_prepare_enable helps cases using clk_enable in non-atomic context. */ +-- +2.51.0 + diff --git a/queue-5.15/clk-qcom-dispcc-sdm845-enable-parents-for-pixel-cloc.patch b/queue-5.15/clk-qcom-dispcc-sdm845-enable-parents-for-pixel-cloc.patch new file mode 100644 index 0000000000..0b04567cab --- /dev/null +++ b/queue-5.15/clk-qcom-dispcc-sdm845-enable-parents-for-pixel-cloc.patch @@ -0,0 +1,49 @@ +From c9820fe75d9bff791e0dd333ee7e7d134e2d94f3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 12:44:43 +0100 +Subject: clk: qcom: dispcc-sdm845: Enable parents for pixel clocks + +From: Petr Hodina + +[ Upstream commit a1d63493634e98360140027fef49d82b1ff0a267 ] + +Add CLK_OPS_PARENT_ENABLE to MDSS pixel clock sources to ensure parent +clocks are enabled during clock operations, preventing potential +stability issues during display configuration. + +Fixes: 81351776c9fb ("clk: qcom: Add display clock controller driver for SDM845") +Signed-off-by: Petr Hodina +Reviewed-by: Dmitry Baryshkov +Reviewed-by: David Heidelberg +Link: https://lore.kernel.org/r/20260107-stability-discussion-v2-1-ef7717b435ff@protonmail.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sdm845.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/dispcc-sdm845.c b/drivers/clk/qcom/dispcc-sdm845.c +index e792e0b130d33..eae6dcff18da5 100644 +--- a/drivers/clk/qcom/dispcc-sdm845.c ++++ b/drivers/clk/qcom/dispcc-sdm845.c +@@ -280,7 +280,7 @@ static struct clk_rcg2 disp_cc_mdss_pclk0_clk_src = { + .name = "disp_cc_mdss_pclk0_clk_src", + .parent_data = disp_cc_parent_data_4, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_4), +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .ops = &clk_pixel_ops, + }, + }; +@@ -295,7 +295,7 @@ static struct clk_rcg2 disp_cc_mdss_pclk1_clk_src = { + .name = "disp_cc_mdss_pclk1_clk_src", + .parent_data = disp_cc_parent_data_4, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_4), +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .ops = &clk_pixel_ops, + }, + }; +-- +2.51.0 + diff --git a/queue-5.15/clk-qcom-gcc-msm8953-remove-always_on-flag-from-cpp_.patch b/queue-5.15/clk-qcom-gcc-msm8953-remove-always_on-flag-from-cpp_.patch new file mode 100644 index 0000000000..ef1fe7cdbe --- /dev/null +++ b/queue-5.15/clk-qcom-gcc-msm8953-remove-always_on-flag-from-cpp_.patch @@ -0,0 +1,39 @@ +From cd794db04762870deb4645c77cf7f081184391a9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 17 Nov 2025 18:58:47 +0100 +Subject: clk: qcom: gcc-msm8953: Remove ALWAYS_ON flag from cpp_gdsc +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Czémán + +[ Upstream commit 5f613e7034187179a9d088ff5fd02b1089d0cf20 ] + +cpp_gdsc should not be always on, ALWAYS_ON flag was set accidentally. + +Fixes: 9bb6cfc3c77e ("clk: qcom: Add Global Clock Controller driver for MSM8953") +Signed-off-by: Barnabás Czémán +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251117-fix-gdsc-cpp-msm8917-msm8953-v1-1-db33adcff28a@mainlining.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-msm8953.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/clk/qcom/gcc-msm8953.c b/drivers/clk/qcom/gcc-msm8953.c +index 9d11f993843db..0d7235e1fd9e4 100644 +--- a/drivers/clk/qcom/gcc-msm8953.c ++++ b/drivers/clk/qcom/gcc-msm8953.c +@@ -3947,7 +3947,6 @@ static struct gdsc cpp_gdsc = { + .pd = { + .name = "cpp_gdsc", + }, +- .flags = ALWAYS_ON, + .pwrsts = PWRSTS_OFF_ON, + }; + +-- +2.51.0 + diff --git a/queue-5.15/clk-qcom-rcg2-compute-2d-using-duty-fraction-directl.patch b/queue-5.15/clk-qcom-rcg2-compute-2d-using-duty-fraction-directl.patch new file mode 100644 index 0000000000..bd27843c52 --- /dev/null +++ b/queue-5.15/clk-qcom-rcg2-compute-2d-using-duty-fraction-directl.patch @@ -0,0 +1,71 @@ +From 9a3010f8ffd0da0555e12d23221f250e5bff86ef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Jan 2026 16:09:50 +0530 +Subject: clk: qcom: rcg2: compute 2d using duty fraction directly +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Taniya Das + +[ Upstream commit d6205a1878dd4cc9664c4b4829b68a29c0426efc ] + +The duty-cycle calculation in clk_rcg2_set_duty_cycle() currently +derives an intermediate percentage `duty_per = (num * 100) / den` and +then computes: + + d = DIV_ROUND_CLOSEST(n * duty_per * 2, 100); + +This introduces integer truncation at the percentage step (division by +`den`) and a redundant scaling by 100, which can reduce precision for +large `den` and skew the final rounding. + +Compute `2d` directly from the duty fraction to preserve precision and +avoid the unnecessary scaling: + + d = DIV_ROUND_CLOSEST(n * duty->num * 2, duty->den); + +This keeps the intended formula `d ≈ n * 2 * (num/den)` while performing +a single, final rounded division, improving accuracy especially for small +duty cycles or large denominators. It also removes the unused `duty_per` +variable, simplifying the code. + +There is no functional changes beyond improved numerical accuracy. + +Fixes: 7f891faf596ed ("clk: qcom: clk-rcg2: Add support for duty-cycle for RCG") +Signed-off-by: Taniya Das +Link: https://lore.kernel.org/r/20260105-duty_cycle_precision-v2-1-d1d466a6330a@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/clk-rcg2.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c +index f3c225ed57377..05aa831ac7a44 100644 +--- a/drivers/clk/qcom/clk-rcg2.c ++++ b/drivers/clk/qcom/clk-rcg2.c +@@ -400,7 +400,7 @@ static int clk_rcg2_get_duty_cycle(struct clk_hw *hw, struct clk_duty *duty) + static int clk_rcg2_set_duty_cycle(struct clk_hw *hw, struct clk_duty *duty) + { + struct clk_rcg2 *rcg = to_clk_rcg2(hw); +- u32 notn_m, n, m, d, not2d, mask, duty_per, cfg; ++ u32 notn_m, n, m, d, not2d, mask, cfg; + int ret; + + /* Duty-cycle cannot be modified for non-MND RCGs */ +@@ -419,10 +419,8 @@ static int clk_rcg2_set_duty_cycle(struct clk_hw *hw, struct clk_duty *duty) + + n = (~(notn_m) + m) & mask; + +- duty_per = (duty->num * 100) / duty->den; +- + /* Calculate 2d value */ +- d = DIV_ROUND_CLOSEST(n * duty_per * 2, 100); ++ d = DIV_ROUND_CLOSEST(n * duty->num * 2, duty->den); + + /* + * Check bit widths of 2d. If D is too big reduce duty cycle. +-- +2.51.0 + diff --git a/queue-5.15/clk-qcom-return-correct-error-code-in-qcom_cc_probe_.patch b/queue-5.15/clk-qcom-return-correct-error-code-in-qcom_cc_probe_.patch new file mode 100644 index 0000000000..3d60d66b06 --- /dev/null +++ b/queue-5.15/clk-qcom-return-correct-error-code-in-qcom_cc_probe_.patch @@ -0,0 +1,42 @@ +From 257d14a49cb5577d9fd5a7090fa82c9c6a50d32c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 17 Dec 2025 12:13:38 +0800 +Subject: clk: qcom: Return correct error code in qcom_cc_probe_by_index() + +From: Haotian Zhang + +[ Upstream commit 1e07ebe744fb522983bd52a4a6148601675330c7 ] + +When devm_platform_ioremap_resource() fails, it returns various +error codes. Returning a hardcoded -ENOMEM masks the actual +failure reason. + +Use PTR_ERR() to propagate the actual error code returned by +devm_platform_ioremap_resource() instead of -ENOMEM. + +Fixes: 75e0a1e30191 ("clk: qcom: define probe by index API as common API") +Signed-off-by: Haotian Zhang +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251217041338.2432-1-vulab@iscas.ac.cn +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/common.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c +index 2af04fc4abfa9..8aef7749f167d 100644 +--- a/drivers/clk/qcom/common.c ++++ b/drivers/clk/qcom/common.c +@@ -331,7 +331,7 @@ int qcom_cc_probe_by_index(struct platform_device *pdev, int index, + res = platform_get_resource(pdev, IORESOURCE_MEM, index); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) +- return -ENOMEM; ++ return PTR_ERR(base); + + regmap = devm_regmap_init_mmio(&pdev->dev, base, desc->config); + if (IS_ERR(regmap)) +-- +2.51.0 + diff --git a/queue-5.15/coresight-etm3x-fix-cpulocked-warning-on-cpuhp.patch b/queue-5.15/coresight-etm3x-fix-cpulocked-warning-on-cpuhp.patch new file mode 100644 index 0000000000..0336b5578a --- /dev/null +++ b/queue-5.15/coresight-etm3x-fix-cpulocked-warning-on-cpuhp.patch @@ -0,0 +1,67 @@ +From e77e6447b7ab1f93debe8b7d6d4809cc585feeeb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:24:27 +0100 +Subject: coresight: etm3x: Fix cpulocked warning on cpuhp + +From: Antonio Borneo + +[ Upstream commit 1feb0377b9b816f89a04fc381eb19fc6bac9f4a4 ] + +When changes [1] and [2] have been applied to the driver etm4x, the +same modifications have been also collapsed in [3] and applied in +one shot to the driver etm3x. +While doing this, the driver etm3x has not been aligned to etm4x on +the use of non cpuslocked version of cpuhp callback setup APIs. + +The current code triggers two run-time warnings when the kernel is +compiled with CONFIG_PROVE_LOCKING=y. + +Use non cpuslocked version of cpuhp callback setup APIs in driver +etm3x, aligning it to the driver etm4x. + +[1] commit 2d1a8bfb61ec ("coresight: etm4x: Fix etm4_count race by + moving cpuhp callbacks to init") +[2] commit 22a550a306ad ("coresight: etm4x: Allow etm4x to be built + as a module") +[3] commit 97fe626ce64c ("coresight: etm3x: Allow etm3x to be built + as a module") + +Fixes: 97fe626ce64c ("coresight: etm3x: Allow etm3x to be built as a module") +Signed-off-by: Antonio Borneo +Signed-off-by: Suzuki K Poulose +Link: https://lore.kernel.org/r/20260108152427.357379-1-antonio.borneo@foss.st.com +Signed-off-by: Sasha Levin +--- + drivers/hwtracing/coresight/coresight-etm3x-core.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c +index cf64ce73a7412..436e65437f535 100644 +--- a/drivers/hwtracing/coresight/coresight-etm3x-core.c ++++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c +@@ -786,16 +786,16 @@ static int __init etm_hp_setup(void) + { + int ret; + +- ret = cpuhp_setup_state_nocalls_cpuslocked(CPUHP_AP_ARM_CORESIGHT_STARTING, +- "arm/coresight:starting", +- etm_starting_cpu, etm_dying_cpu); ++ ret = cpuhp_setup_state_nocalls(CPUHP_AP_ARM_CORESIGHT_STARTING, ++ "arm/coresight:starting", ++ etm_starting_cpu, etm_dying_cpu); + + if (ret) + return ret; + +- ret = cpuhp_setup_state_nocalls_cpuslocked(CPUHP_AP_ONLINE_DYN, +- "arm/coresight:online", +- etm_online_cpu, NULL); ++ ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, ++ "arm/coresight:online", ++ etm_online_cpu, NULL); + + /* HP dyn state ID returned in ret on success */ + if (ret > 0) { +-- +2.51.0 + diff --git a/queue-5.15/cpufreq-scmi-correct-scmi-explanation.patch b/queue-5.15/cpufreq-scmi-correct-scmi-explanation.patch new file mode 100644 index 0000000000..72df4c7ad4 --- /dev/null +++ b/queue-5.15/cpufreq-scmi-correct-scmi-explanation.patch @@ -0,0 +1,37 @@ +From 3cea3da5f0d9c7bc02647d947e36c65f7ec97b02 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Jan 2026 22:33:30 +0300 +Subject: cpufreq: scmi: correct SCMI explanation + +From: Sergey Shtylyov + +[ Upstream commit 8c376f337a7e31c42949247e24eaad9a30d6c62c ] + +SCMI stands for System Control and Management Interface, not System Control +and Power Interface -- apparently, Sudeep Holla copied this line from his +SCPI driver and then just forgot to update the acronym explanation... :-) + +Fixes: 99d6bdf33877 ("cpufreq: add support for CPU DVFS based on SCMI message protocol") +Signed-off-by: Sergey Shtylyov +Reviewed-by: Sudeep Holla +Signed-off-by: Viresh Kumar +Signed-off-by: Sasha Levin +--- + drivers/cpufreq/scmi-cpufreq.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c +index 35287ab0148a2..9ad5154ad66af 100644 +--- a/drivers/cpufreq/scmi-cpufreq.c ++++ b/drivers/cpufreq/scmi-cpufreq.c +@@ -1,6 +1,6 @@ + // SPDX-License-Identifier: GPL-2.0 + /* +- * System Control and Power Interface (SCMI) based CPUFreq Interface driver ++ * System Control and Management Interface (SCMI) based CPUFreq Interface driver + * + * Copyright (C) 2018-2021 ARM Ltd. + * Sudeep Holla +-- +2.51.0 + diff --git a/queue-5.15/crypto-cavium-fix-dma_free_coherent-size.patch b/queue-5.15/crypto-cavium-fix-dma_free_coherent-size.patch new file mode 100644 index 0000000000..38a2b715a3 --- /dev/null +++ b/queue-5.15/crypto-cavium-fix-dma_free_coherent-size.patch @@ -0,0 +1,38 @@ +From 9f88d186091512de21c3c58fe7435307d178bb1c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 10:56:45 +0100 +Subject: crypto: cavium - fix dma_free_coherent() size + +From: Thomas Fourier + +[ Upstream commit 941676c30ba5b40a01bed92448f457ce62fd1f07 ] + +The size of the buffer in alloc_command_queues() is +curr->size + CPT_NEXT_CHUNK_PTR_SIZE, so used that length for +dma_free_coherent(). + +Fixes: c694b233295b ("crypto: cavium - Add the Virtual Function driver for CPT") +Signed-off-by: Thomas Fourier +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/cavium/cpt/cptvf_main.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/crypto/cavium/cpt/cptvf_main.c b/drivers/crypto/cavium/cpt/cptvf_main.c +index 112b12a32542b..aaf54cab19cc1 100644 +--- a/drivers/crypto/cavium/cpt/cptvf_main.c ++++ b/drivers/crypto/cavium/cpt/cptvf_main.c +@@ -183,7 +183,8 @@ static void free_command_queues(struct cpt_vf *cptvf, + + hlist_for_each_entry_safe(chunk, node, &cqinfo->queue[i].chead, + nextchunk) { +- dma_free_coherent(&pdev->dev, chunk->size, ++ dma_free_coherent(&pdev->dev, ++ chunk->size + CPT_NEXT_CHUNK_PTR_SIZE, + chunk->head, + chunk->dma_addr); + chunk->head = NULL; +-- +2.51.0 + diff --git a/queue-5.15/crypto-ccp-add-an-s4-restore-flow.patch b/queue-5.15/crypto-ccp-add-an-s4-restore-flow.patch new file mode 100644 index 0000000000..663de0f4e3 --- /dev/null +++ b/queue-5.15/crypto-ccp-add-an-s4-restore-flow.patch @@ -0,0 +1,168 @@ +From 868729f29d565c728dac5f3759981bc9362f8fd9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 22:11:30 -0600 +Subject: crypto: ccp - Add an S4 restore flow +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Mario Limonciello (AMD) + +[ Upstream commit 0ba2035026d0ab6c7c7e65ad8b418dc73d5700d9 ] + +The system will have lost power during S4. The ring used for TEE +communications needs to be initialized before use. + +Fixes: f892a21f51162 ("crypto: ccp - use generic power management") +Reported-by: Lars Francke +Closes: https://lore.kernel.org/platform-driver-x86/CAD-Ua_gfJnQSo8ucS_7ZwzuhoBRJ14zXP7s8b-zX3ZcxcyWePw@mail.gmail.com/ +Tested-by: Yijun Shen +Signed-off-by: Mario Limonciello (AMD) +Reviewed-by: Shyam Sundar S K +Reviewed-by: Tom Lendacky +Link: https://patch.msgid.link/20260116041132.153674-4-superm1@kernel.org +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/crypto/ccp/psp-dev.c | 11 +++++++++++ + drivers/crypto/ccp/sp-dev.c | 12 ++++++++++++ + drivers/crypto/ccp/sp-dev.h | 3 +++ + drivers/crypto/ccp/sp-pci.c | 16 +++++++++++++++- + drivers/crypto/ccp/tee-dev.c | 5 +++++ + drivers/crypto/ccp/tee-dev.h | 1 + + 6 files changed, 47 insertions(+), 1 deletion(-) + +diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c +index 4bf9eaab4456f..61f5302e7cf1a 100644 +--- a/drivers/crypto/ccp/psp-dev.c ++++ b/drivers/crypto/ccp/psp-dev.c +@@ -251,6 +251,17 @@ struct psp_device *psp_get_master_device(void) + return sp ? sp->psp_data : NULL; + } + ++int psp_restore(struct sp_device *sp) ++{ ++ struct psp_device *psp = sp->psp_data; ++ int ret = 0; ++ ++ if (psp->tee_data) ++ ret = tee_restore(psp); ++ ++ return ret; ++} ++ + void psp_pci_init(void) + { + psp_master = psp_get_master_device(); +diff --git a/drivers/crypto/ccp/sp-dev.c b/drivers/crypto/ccp/sp-dev.c +index 7eb3e46682860..ccbe009ad6e58 100644 +--- a/drivers/crypto/ccp/sp-dev.c ++++ b/drivers/crypto/ccp/sp-dev.c +@@ -229,6 +229,18 @@ int sp_resume(struct sp_device *sp) + return 0; + } + ++int sp_restore(struct sp_device *sp) ++{ ++ if (sp->psp_data) { ++ int ret = psp_restore(sp); ++ ++ if (ret) ++ return ret; ++ } ++ ++ return sp_resume(sp); ++} ++ + struct sp_device *sp_get_psp_master_device(void) + { + struct sp_device *i, *ret = NULL; +diff --git a/drivers/crypto/ccp/sp-dev.h b/drivers/crypto/ccp/sp-dev.h +index 20377e67f65df..731e34a65b640 100644 +--- a/drivers/crypto/ccp/sp-dev.h ++++ b/drivers/crypto/ccp/sp-dev.h +@@ -121,6 +121,7 @@ struct sp_device *sp_get_master(void); + + int sp_suspend(struct sp_device *sp); + int sp_resume(struct sp_device *sp); ++int sp_restore(struct sp_device *sp); + int sp_request_ccp_irq(struct sp_device *sp, irq_handler_t handler, + const char *name, void *data); + void sp_free_ccp_irq(struct sp_device *sp, void *data); +@@ -154,6 +155,7 @@ int psp_dev_init(struct sp_device *sp); + void psp_pci_init(void); + void psp_dev_destroy(struct sp_device *sp); + void psp_pci_exit(void); ++int psp_restore(struct sp_device *sp); + + #else /* !CONFIG_CRYPTO_DEV_SP_PSP */ + +@@ -161,6 +163,7 @@ static inline int psp_dev_init(struct sp_device *sp) { return 0; } + static inline void psp_pci_init(void) { } + static inline void psp_dev_destroy(struct sp_device *sp) { } + static inline void psp_pci_exit(void) { } ++static inline int psp_restore(struct sp_device *sp) { return 0; } + + #endif /* CONFIG_CRYPTO_DEV_SP_PSP */ + +diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c +index f9178821023da..3971702835a27 100644 +--- a/drivers/crypto/ccp/sp-pci.c ++++ b/drivers/crypto/ccp/sp-pci.c +@@ -282,6 +282,13 @@ static int __maybe_unused sp_pci_resume(struct device *dev) + return sp_resume(sp); + } + ++static int __maybe_unused sp_pci_restore(struct device *dev) ++{ ++ struct sp_device *sp = dev_get_drvdata(dev); ++ ++ return sp_restore(sp); ++} ++ + #ifdef CONFIG_CRYPTO_DEV_SP_PSP + static const struct sev_vdata sevv1 = { + .cmdresp_reg = 0x10580, +@@ -394,7 +401,14 @@ static const struct pci_device_id sp_pci_table[] = { + }; + MODULE_DEVICE_TABLE(pci, sp_pci_table); + +-static SIMPLE_DEV_PM_OPS(sp_pci_pm_ops, sp_pci_suspend, sp_pci_resume); ++static const struct dev_pm_ops sp_pci_pm_ops = { ++ .suspend = pm_sleep_ptr(sp_pci_suspend), ++ .resume = pm_sleep_ptr(sp_pci_resume), ++ .freeze = pm_sleep_ptr(sp_pci_suspend), ++ .thaw = pm_sleep_ptr(sp_pci_resume), ++ .poweroff = pm_sleep_ptr(sp_pci_suspend), ++ .restore_early = pm_sleep_ptr(sp_pci_restore), ++}; + + static struct pci_driver sp_pci_driver = { + .name = "ccp", +diff --git a/drivers/crypto/ccp/tee-dev.c b/drivers/crypto/ccp/tee-dev.c +index 5c9d47f3be375..c0dc462a94288 100644 +--- a/drivers/crypto/ccp/tee-dev.c ++++ b/drivers/crypto/ccp/tee-dev.c +@@ -394,3 +394,8 @@ int psp_check_tee_status(void) + return 0; + } + EXPORT_SYMBOL(psp_check_tee_status); ++ ++int tee_restore(struct psp_device *psp) ++{ ++ return tee_init_ring(psp->tee_data); ++} +diff --git a/drivers/crypto/ccp/tee-dev.h b/drivers/crypto/ccp/tee-dev.h +index 49d26158b71e3..b0bf1de94ea6f 100644 +--- a/drivers/crypto/ccp/tee-dev.h ++++ b/drivers/crypto/ccp/tee-dev.h +@@ -122,5 +122,6 @@ struct tee_ring_cmd { + + int tee_dev_init(struct psp_device *psp); + void tee_dev_destroy(struct psp_device *psp); ++int tee_restore(struct psp_device *psp); + + #endif /* __TEE_DEV_H__ */ +-- +2.51.0 + diff --git a/queue-5.15/crypto-hisilicon-trng-modifying-the-order-of-header-.patch b/queue-5.15/crypto-hisilicon-trng-modifying-the-order-of-header-.patch new file mode 100644 index 0000000000..099fe34741 --- /dev/null +++ b/queue-5.15/crypto-hisilicon-trng-modifying-the-order-of-header-.patch @@ -0,0 +1,56 @@ +From 97a5ff2e4b3b1002e646672933c7775f09750b2f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Aug 2024 17:50:09 +0800 +Subject: crypto: hisilicon/trng - modifying the order of header files + +From: Chenghai Huang + +[ Upstream commit f5dd7c43022799ac5c4e3a0d445f9c293a198413 ] + +Header files is included Order-ref: standard library headers, +OS library headers, and project-specific headers. This patch +modifies the order of header files according to suggestions. + +In addition, use %u to print unsigned int variables to prevent +overflow. + +Signed-off-by: Chenghai Huang +Signed-off-by: Herbert Xu +Stable-dep-of: 3d3135057ff5 ("crypto: hisilicon/trng - support tfms sharing the device") +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/trng/trng.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/crypto/hisilicon/trng/trng.c b/drivers/crypto/hisilicon/trng/trng.c +index 829f2caf0f67f..71cf7c9e9a338 100644 +--- a/drivers/crypto/hisilicon/trng/trng.c ++++ b/drivers/crypto/hisilicon/trng/trng.c +@@ -1,6 +1,7 @@ + // SPDX-License-Identifier: GPL-2.0 + /* Copyright (c) 2019 HiSilicon Limited. */ + ++#include + #include + #include + #include +@@ -13,7 +14,6 @@ + #include + #include + #include +-#include + + #define HISI_TRNG_REG 0x00F0 + #define HISI_TRNG_BYTES 4 +@@ -121,7 +121,7 @@ static int hisi_trng_generate(struct crypto_rng *tfm, const u8 *src, + u32 i; + + if (dlen > SW_DRBG_BLOCKS_NUM * SW_DRBG_BYTES || dlen == 0) { +- pr_err("dlen(%d) exceeds limit(%d)!\n", dlen, ++ pr_err("dlen(%u) exceeds limit(%d)!\n", dlen, + SW_DRBG_BLOCKS_NUM * SW_DRBG_BYTES); + return -EINVAL; + } +-- +2.51.0 + diff --git a/queue-5.15/crypto-hisilicon-trng-support-tfms-sharing-the-devic.patch b/queue-5.15/crypto-hisilicon-trng-support-tfms-sharing-the-devic.patch new file mode 100644 index 0000000000..678d1a7a4c --- /dev/null +++ b/queue-5.15/crypto-hisilicon-trng-support-tfms-sharing-the-devic.patch @@ -0,0 +1,258 @@ +From a6da8b01a66aac1b9b375e1bd9b2b2fb28f8872e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 17 Jan 2026 15:18:21 +0800 +Subject: crypto: hisilicon/trng - support tfms sharing the device + +From: Weili Qian + +[ Upstream commit 3d3135057ff567d5c09fff4c9ef6391a684e8042 ] + +Since the number of devices is limited, and the number +of tfms may exceed the number of devices, to ensure that +tfms can be successfully allocated, support tfms +sharing the same device. + +Fixes: e4d9d10ef4be ("crypto: hisilicon/trng - add support for PRNG") +Signed-off-by: Weili Qian +Signed-off-by: Chenghai Huang +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/trng/trng.c | 121 +++++++++++++++++++-------- + 1 file changed, 86 insertions(+), 35 deletions(-) + +diff --git a/drivers/crypto/hisilicon/trng/trng.c b/drivers/crypto/hisilicon/trng/trng.c +index 71cf7c9e9a338..687705ae50ab5 100644 +--- a/drivers/crypto/hisilicon/trng/trng.c ++++ b/drivers/crypto/hisilicon/trng/trng.c +@@ -40,6 +40,7 @@ + #define SEED_SHIFT_24 24 + #define SEED_SHIFT_16 16 + #define SEED_SHIFT_8 8 ++#define SW_MAX_RANDOM_BYTES 65520 + + struct hisi_trng_list { + struct mutex lock; +@@ -53,8 +54,10 @@ struct hisi_trng { + struct list_head list; + struct hwrng rng; + u32 ver; +- bool is_used; +- struct mutex mutex; ++ u32 ctx_num; ++ /* The bytes of the random number generated since the last seeding. */ ++ u32 random_bytes; ++ struct mutex lock; + }; + + struct hisi_trng_ctx { +@@ -63,10 +66,14 @@ struct hisi_trng_ctx { + + static atomic_t trng_active_devs; + static struct hisi_trng_list trng_devices; ++static int hisi_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait); + +-static void hisi_trng_set_seed(struct hisi_trng *trng, const u8 *seed) ++static int hisi_trng_set_seed(struct hisi_trng *trng, const u8 *seed) + { + u32 val, seed_reg, i; ++ int ret; ++ ++ writel(0x0, trng->base + SW_DRBG_BLOCKS); + + for (i = 0; i < SW_DRBG_SEED_SIZE; + i += SW_DRBG_SEED_SIZE / SW_DRBG_SEED_REGS_NUM) { +@@ -78,6 +85,20 @@ static void hisi_trng_set_seed(struct hisi_trng *trng, const u8 *seed) + seed_reg = (i >> SW_DRBG_NUM_SHIFT) % SW_DRBG_SEED_REGS_NUM; + writel(val, trng->base + SW_DRBG_SEED(seed_reg)); + } ++ ++ writel(SW_DRBG_BLOCKS_NUM | (0x1 << SW_DRBG_ENABLE_SHIFT), ++ trng->base + SW_DRBG_BLOCKS); ++ writel(0x1, trng->base + SW_DRBG_INIT); ++ ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS, ++ val, val & BIT(0), SLEEP_US, TIMEOUT_US); ++ if (ret) { ++ pr_err("failed to init trng(%d)\n", ret); ++ return -EIO; ++ } ++ ++ trng->random_bytes = 0; ++ ++ return 0; + } + + static int hisi_trng_seed(struct crypto_rng *tfm, const u8 *seed, +@@ -85,8 +106,7 @@ static int hisi_trng_seed(struct crypto_rng *tfm, const u8 *seed, + { + struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm); + struct hisi_trng *trng = ctx->trng; +- u32 val = 0; +- int ret = 0; ++ int ret; + + if (slen < SW_DRBG_SEED_SIZE) { + pr_err("slen(%u) is not matched with trng(%d)\n", slen, +@@ -94,43 +114,45 @@ static int hisi_trng_seed(struct crypto_rng *tfm, const u8 *seed, + return -EINVAL; + } + +- writel(0x0, trng->base + SW_DRBG_BLOCKS); +- hisi_trng_set_seed(trng, seed); ++ mutex_lock(&trng->lock); ++ ret = hisi_trng_set_seed(trng, seed); ++ mutex_unlock(&trng->lock); + +- writel(SW_DRBG_BLOCKS_NUM | (0x1 << SW_DRBG_ENABLE_SHIFT), +- trng->base + SW_DRBG_BLOCKS); +- writel(0x1, trng->base + SW_DRBG_INIT); ++ return ret; ++} + +- ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS, +- val, val & BIT(0), SLEEP_US, TIMEOUT_US); +- if (ret) +- pr_err("fail to init trng(%d)\n", ret); ++static int hisi_trng_reseed(struct hisi_trng *trng) ++{ ++ u8 seed[SW_DRBG_SEED_SIZE]; ++ int size; + +- return ret; ++ if (!trng->random_bytes) ++ return 0; ++ ++ size = hisi_trng_read(&trng->rng, seed, SW_DRBG_SEED_SIZE, false); ++ if (size != SW_DRBG_SEED_SIZE) ++ return -EIO; ++ ++ return hisi_trng_set_seed(trng, seed); + } + +-static int hisi_trng_generate(struct crypto_rng *tfm, const u8 *src, +- unsigned int slen, u8 *dstn, unsigned int dlen) ++static int hisi_trng_get_bytes(struct hisi_trng *trng, u8 *dstn, unsigned int dlen) + { +- struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm); +- struct hisi_trng *trng = ctx->trng; + u32 data[SW_DRBG_DATA_NUM]; + u32 currsize = 0; + u32 val = 0; + int ret; + u32 i; + +- if (dlen > SW_DRBG_BLOCKS_NUM * SW_DRBG_BYTES || dlen == 0) { +- pr_err("dlen(%u) exceeds limit(%d)!\n", dlen, +- SW_DRBG_BLOCKS_NUM * SW_DRBG_BYTES); +- return -EINVAL; +- } ++ ret = hisi_trng_reseed(trng); ++ if (ret) ++ return ret; + + do { + ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS, +- val, val & BIT(1), SLEEP_US, TIMEOUT_US); ++ val, val & BIT(1), SLEEP_US, TIMEOUT_US); + if (ret) { +- pr_err("fail to generate random number(%d)!\n", ret); ++ pr_err("failed to generate random number(%d)!\n", ret); + break; + } + +@@ -145,30 +167,57 @@ static int hisi_trng_generate(struct crypto_rng *tfm, const u8 *src, + currsize = dlen; + } + ++ trng->random_bytes += SW_DRBG_BYTES; + writel(0x1, trng->base + SW_DRBG_GEN); + } while (currsize < dlen); + + return ret; + } + ++static int hisi_trng_generate(struct crypto_rng *tfm, const u8 *src, ++ unsigned int slen, u8 *dstn, unsigned int dlen) ++{ ++ struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm); ++ struct hisi_trng *trng = ctx->trng; ++ unsigned int currsize = 0; ++ unsigned int block_size; ++ int ret; ++ ++ if (!dstn || !dlen) { ++ pr_err("output is error, dlen %u!\n", dlen); ++ return -EINVAL; ++ } ++ ++ do { ++ block_size = min_t(unsigned int, dlen - currsize, SW_MAX_RANDOM_BYTES); ++ mutex_lock(&trng->lock); ++ ret = hisi_trng_get_bytes(trng, dstn + currsize, block_size); ++ mutex_unlock(&trng->lock); ++ if (ret) ++ return ret; ++ currsize += block_size; ++ } while (currsize < dlen); ++ ++ return 0; ++} ++ + static int hisi_trng_init(struct crypto_tfm *tfm) + { + struct hisi_trng_ctx *ctx = crypto_tfm_ctx(tfm); + struct hisi_trng *trng; +- int ret = -EBUSY; ++ u32 ctx_num = ~0; + + mutex_lock(&trng_devices.lock); + list_for_each_entry(trng, &trng_devices.list, list) { +- if (!trng->is_used) { +- trng->is_used = true; ++ if (trng->ctx_num < ctx_num) { ++ ctx_num = trng->ctx_num; + ctx->trng = trng; +- ret = 0; +- break; + } + } ++ ctx->trng->ctx_num++; + mutex_unlock(&trng_devices.lock); + +- return ret; ++ return 0; + } + + static void hisi_trng_exit(struct crypto_tfm *tfm) +@@ -176,7 +225,7 @@ static void hisi_trng_exit(struct crypto_tfm *tfm) + struct hisi_trng_ctx *ctx = crypto_tfm_ctx(tfm); + + mutex_lock(&trng_devices.lock); +- ctx->trng->is_used = false; ++ ctx->trng->ctx_num--; + mutex_unlock(&trng_devices.lock); + } + +@@ -238,7 +287,7 @@ static int hisi_trng_del_from_list(struct hisi_trng *trng) + int ret = -EBUSY; + + mutex_lock(&trng_devices.lock); +- if (!trng->is_used) { ++ if (!trng->ctx_num) { + list_del(&trng->list); + ret = 0; + } +@@ -262,7 +311,9 @@ static int hisi_trng_probe(struct platform_device *pdev) + if (IS_ERR(trng->base)) + return PTR_ERR(trng->base); + +- trng->is_used = false; ++ trng->ctx_num = 0; ++ trng->random_bytes = SW_MAX_RANDOM_BYTES; ++ mutex_init(&trng->lock); + trng->ver = readl(trng->base + HISI_TRNG_VERSION); + if (!trng_devices.is_init) { + INIT_LIST_HEAD(&trng_devices.list); +-- +2.51.0 + diff --git a/queue-5.15/crypto-octeontx-fix-dma_free_coherent-size.patch b/queue-5.15/crypto-octeontx-fix-dma_free_coherent-size.patch new file mode 100644 index 0000000000..dd0dc40d9f --- /dev/null +++ b/queue-5.15/crypto-octeontx-fix-dma_free_coherent-size.patch @@ -0,0 +1,38 @@ +From c5f878862ef9d772c9bee4ce98a936fd140e9f95 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 11:12:57 +0100 +Subject: crypto: octeontx - fix dma_free_coherent() size + +From: Thomas Fourier + +[ Upstream commit 624a6760bf8464965c17c8df10b40b557eaa3002 ] + +The size of the buffer in alloc_command_queues() is +curr->size + OTX_CPT_NEXT_CHUNK_PTR_SIZE, so used that length for +dma_free_coherent(). + +Fixes: 10b4f09491bf ("crypto: marvell - add the Virtual Function driver for CPT") +Signed-off-by: Thomas Fourier +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/marvell/octeontx/otx_cptvf_main.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/crypto/marvell/octeontx/otx_cptvf_main.c b/drivers/crypto/marvell/octeontx/otx_cptvf_main.c +index c076d0b3ad5f1..bbac7778201d2 100644 +--- a/drivers/crypto/marvell/octeontx/otx_cptvf_main.c ++++ b/drivers/crypto/marvell/octeontx/otx_cptvf_main.c +@@ -170,7 +170,8 @@ static void free_command_queues(struct otx_cptvf *cptvf, + chunk = list_first_entry(&cqinfo->queue[i].chead, + struct otx_cpt_cmd_chunk, nextchunk); + +- dma_free_coherent(&pdev->dev, chunk->size, ++ dma_free_coherent(&pdev->dev, ++ chunk->size + OTX_CPT_NEXT_CHUNK_PTR_SIZE, + chunk->head, + chunk->dma_addr); + chunk->head = NULL; +-- +2.51.0 + diff --git a/queue-5.15/dma-dma-axi-dmac-fix-sw-cyclic-transfers.patch b/queue-5.15/dma-dma-axi-dmac-fix-sw-cyclic-transfers.patch new file mode 100644 index 0000000000..de4a179c20 --- /dev/null +++ b/queue-5.15/dma-dma-axi-dmac-fix-sw-cyclic-transfers.patch @@ -0,0 +1,57 @@ +From 94cc28b1f30209bc6291bfc84016bd5a3f1d1a11 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Nov 2025 16:22:25 +0000 +Subject: dma: dma-axi-dmac: fix SW cyclic transfers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Nuno Sá + +[ Upstream commit 9bd257181fd5c996d922e9991500ad27987cfbf4 ] + +If 'hw_cyclic' is false we should still be able to do cyclic transfers in +"software". That was not working for the case where 'desc->num_sgs' is 1 +because 'chan->next_desc' is never set with the current desc which means +that the cyclic transfer only runs once and in the next SOT interrupt we +do nothing since vchan_next_desc() will return NULL. + +Fix it by setting 'chan->next_desc' as soon as we get a new desc via +vchan_next_desc(). + +Fixes: 0e3b67b348b8 ("dmaengine: Add support for the Analog Devices AXI-DMAC DMA controller") +Signed-off-by: Nuno Sá +base-commit: 398035178503bf662281bbffb4bebce1460a4bc5 +change-id: 20251104-axi-dmac-fixes-and-improvs-e3ad512a329c +Acked-by: Michael Hennerich +Link: https://patch.msgid.link/20251104-axi-dmac-fixes-and-improvs-v1-1-3e6fd9328f72@analog.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/dma/dma-axi-dmac.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c +index e91aeec71c811..6194ef0ac17f6 100644 +--- a/drivers/dma/dma-axi-dmac.c ++++ b/drivers/dma/dma-axi-dmac.c +@@ -221,6 +221,7 @@ static void axi_dmac_start_transfer(struct axi_dmac_chan *chan) + return; + list_move_tail(&vdesc->node, &chan->active_descs); + desc = to_axi_dmac_desc(vdesc); ++ chan->next_desc = desc; + } + sg = &desc->sg[desc->num_submitted]; + +@@ -238,8 +239,6 @@ static void axi_dmac_start_transfer(struct axi_dmac_chan *chan) + else + chan->next_desc = NULL; + flags |= AXI_DMAC_FLAG_LAST; +- } else { +- chan->next_desc = desc; + } + + sg->id = axi_dmac_read(dmac, AXI_DMAC_REG_TRANSFER_ID); +-- +2.51.0 + diff --git a/queue-5.15/dmaengine-mediatek-uart-apdma-fix-above-4g-addressin.patch b/queue-5.15/dmaengine-mediatek-uart-apdma-fix-above-4g-addressin.patch new file mode 100644 index 0000000000..973da26878 --- /dev/null +++ b/queue-5.15/dmaengine-mediatek-uart-apdma-fix-above-4g-addressin.patch @@ -0,0 +1,83 @@ +From bb40b8fb0d98d0dda994aae90a0ee09de0c2f0d7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 13 Nov 2025 13:22:26 +0100 +Subject: dmaengine: mediatek: uart-apdma: Fix above 4G addressing TX/RX + +From: AngeloGioacchino Del Regno + +[ Upstream commit 58ab9d7b6651d21e1cff1777529f2d3dd0b4e851 ] + +The VFF_4G_SUPPORT register is named differently in datasheets, +and its name is "VFF_ADDR2"; was this named correctly from the +beginning it would've been clearer that there was a mistake in +the programming sequence. + +This register is supposed to hold the high bits to support the +DMA addressing above 4G (so, more than 32 bits) and not a bit +to "enable" the support for VFF 4G. + +Fix the name of this register, and also fix its usage by writing +the upper 32 bits of the dma_addr_t on it when the SoC supports +such feature. + +Fixes: 9135408c3ace ("dmaengine: mediatek: Add MediaTek UART APDMA support") +Signed-off-by: AngeloGioacchino Del Regno +Link: https://patch.msgid.link/20251113122229.23998-6-angelogioacchino.delregno@collabora.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/dma/mediatek/mtk-uart-apdma.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/dma/mediatek/mtk-uart-apdma.c b/drivers/dma/mediatek/mtk-uart-apdma.c +index 0acf6a92a4ad3..c1e132a110ffb 100644 +--- a/drivers/dma/mediatek/mtk-uart-apdma.c ++++ b/drivers/dma/mediatek/mtk-uart-apdma.c +@@ -42,7 +42,7 @@ + #define VFF_STOP_CLR_B 0 + #define VFF_EN_CLR_B 0 + #define VFF_INT_EN_CLR_B 0 +-#define VFF_4G_SUPPORT_CLR_B 0 ++#define VFF_ADDR2_CLR_B 0 + + /* + * interrupt trigger level for tx +@@ -73,7 +73,7 @@ + /* TX: the buffer size SW can write. RX: the buffer size HW can write. */ + #define VFF_LEFT_SIZE 0x40 + #define VFF_DEBUG_STATUS 0x50 +-#define VFF_4G_SUPPORT 0x54 ++#define VFF_ADDR2 0x54 + + struct mtk_uart_apdmadev { + struct dma_device ddev; +@@ -150,7 +150,7 @@ static void mtk_uart_apdma_start_tx(struct mtk_chan *c) + mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_TX_INT_CLR_B); + + if (mtkd->support_33bits) +- mtk_uart_apdma_write(c, VFF_4G_SUPPORT, VFF_4G_EN_B); ++ mtk_uart_apdma_write(c, VFF_ADDR2, upper_32_bits(d->addr)); + } + + mtk_uart_apdma_write(c, VFF_EN, VFF_EN_B); +@@ -193,7 +193,7 @@ static void mtk_uart_apdma_start_rx(struct mtk_chan *c) + mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_RX_INT_CLR_B); + + if (mtkd->support_33bits) +- mtk_uart_apdma_write(c, VFF_4G_SUPPORT, VFF_4G_EN_B); ++ mtk_uart_apdma_write(c, VFF_ADDR2, upper_32_bits(d->addr)); + } + + mtk_uart_apdma_write(c, VFF_INT_EN, VFF_RX_INT_EN_B); +@@ -299,7 +299,7 @@ static int mtk_uart_apdma_alloc_chan_resources(struct dma_chan *chan) + } + + if (mtkd->support_33bits) +- mtk_uart_apdma_write(c, VFF_4G_SUPPORT, VFF_4G_SUPPORT_CLR_B); ++ mtk_uart_apdma_write(c, VFF_ADDR2, VFF_ADDR2_CLR_B); + + err_pm: + pm_runtime_put_noidle(mtkd->ddev.dev); +-- +2.51.0 + diff --git a/queue-5.15/drivers-iio-mpu3050-use-dev_err_probe-for-regulator-.patch b/queue-5.15/drivers-iio-mpu3050-use-dev_err_probe-for-regulator-.patch new file mode 100644 index 0000000000..7bc3cf83e4 --- /dev/null +++ b/queue-5.15/drivers-iio-mpu3050-use-dev_err_probe-for-regulator-.patch @@ -0,0 +1,42 @@ +From 7b0fa5fe31eb7d6b2232bc42f2359b4e09dfb6bc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 17:34:25 +0200 +Subject: drivers: iio: mpu3050: use dev_err_probe for regulator request + +From: Svyatoslav Ryhel + +[ Upstream commit b010880b9936da14f8035585ab57577aa05be23a ] + +Regulator requesting may result in deferred probing error which will +abort driver probing. To avoid this just use dev_err_probe which handles +deferred probing. + +Fixes: 3904b28efb2c ("iio: gyro: Add driver for the MPU-3050 gyroscope") +Signed-off-by: Svyatoslav Ryhel +Reviewed-by: Andy Shevchenko +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/gyro/mpu3050-core.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/iio/gyro/mpu3050-core.c b/drivers/iio/gyro/mpu3050-core.c +index 5311bee5475ff..dcbc719275ceb 100644 +--- a/drivers/iio/gyro/mpu3050-core.c ++++ b/drivers/iio/gyro/mpu3050-core.c +@@ -1174,10 +1174,8 @@ int mpu3050_common_probe(struct device *dev, + mpu3050->regs[1].supply = mpu3050_reg_vlogic; + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(mpu3050->regs), + mpu3050->regs); +- if (ret) { +- dev_err(dev, "Cannot get regulators\n"); +- return ret; +- } ++ if (ret) ++ return dev_err_probe(dev, ret, "Cannot get regulators\n"); + + ret = mpu3050_power_up(mpu3050); + if (ret) +-- +2.51.0 + diff --git a/queue-5.15/drm-amdgpu-use-explicit-vcn-instance-0-in-sr-iov-ini.patch b/queue-5.15/drm-amdgpu-use-explicit-vcn-instance-0-in-sr-iov-ini.patch new file mode 100644 index 0000000000..e1c0374910 --- /dev/null +++ b/queue-5.15/drm-amdgpu-use-explicit-vcn-instance-0-in-sr-iov-ini.patch @@ -0,0 +1,180 @@ +From 9038d4a0b549aa9034ee6dad9ae64c6be42f29ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 15:25:25 +0530 +Subject: drm/amdgpu: Use explicit VCN instance 0 in SR-IOV init +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Srinivasan Shanmugam + +[ Upstream commit af26fa751c2eef66916acbf0d3c3e9159da56186 ] + +vcn_v2_0_start_sriov() declares a local variable "i" initialized to zero +and uses it only as the instance index in SOC15_REG_OFFSET(UVD, i, ...). +The value is never changed and all other fields are taken from +adev->vcn.inst[0], so this path only ever programs VCN instance 0. + +This triggered a Smatch: +warn: iterator 'i' not incremented + +Replace the dummy iterator with an explicit instance index of 0 in +SOC15_REG_OFFSET() calls. + +Fixes: dd26858a9cd8 ("drm/amdgpu: implement initialization part on VCN2.0 for SRIOV") +Reported by: Dan Carpenter +Cc: darlington Opara +Cc: Jinage Zhao +Cc: Monk Liu +Cc: Emily Deng +Cc: Christian König +Cc: Alex Deucher +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Emily Deng +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c | 45 ++++++++++++++------------- + 1 file changed, 23 insertions(+), 22 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c +index c405075a572c1..02ae3e7a8a552 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c +@@ -1859,7 +1859,8 @@ static int vcn_v2_0_start_sriov(struct amdgpu_device *adev) + struct mmsch_v2_0_cmd_end end = { {0} }; + struct mmsch_v2_0_init_header *header; + uint32_t *init_table = adev->virt.mm_table.cpu_addr; +- uint8_t i = 0; ++ ++ /* This path only programs VCN instance 0. */ + + header = (struct mmsch_v2_0_init_header *)init_table; + direct_wt.cmd_header.command_type = MMSCH_COMMAND__DIRECT_REG_WRITE; +@@ -1878,94 +1879,94 @@ static int vcn_v2_0_start_sriov(struct amdgpu_device *adev) + size = AMDGPU_GPU_PAGE_ALIGN(adev->vcn.fw->size + 4); + + MMSCH_V2_0_INSERT_DIRECT_RD_MOD_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_STATUS), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_STATUS), + 0xFFFFFFFF, 0x00000004); + + /* mc resume*/ + if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { + tmp = AMDGPU_UCODE_ID_VCN; + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW), + adev->firmware.ucode[tmp].tmr_mc_addr_lo); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE_64BIT_BAR_HIGH), + adev->firmware.ucode[tmp].tmr_mc_addr_hi); + offset = 0; + } else { + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW), + lower_32_bits(adev->vcn.inst->gpu_addr)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE_64BIT_BAR_HIGH), + upper_32_bits(adev->vcn.inst->gpu_addr)); + offset = size; + } + + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_OFFSET0), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_OFFSET0), + 0); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_SIZE0), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_SIZE0), + size); + + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE1_64BIT_BAR_LOW), + lower_32_bits(adev->vcn.inst->gpu_addr + offset)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE1_64BIT_BAR_HIGH), + upper_32_bits(adev->vcn.inst->gpu_addr + offset)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_OFFSET1), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_OFFSET1), + 0); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_SIZE1), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_SIZE1), + AMDGPU_VCN_STACK_SIZE); + + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE2_64BIT_BAR_LOW), + lower_32_bits(adev->vcn.inst->gpu_addr + offset + + AMDGPU_VCN_STACK_SIZE)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE2_64BIT_BAR_HIGH), + upper_32_bits(adev->vcn.inst->gpu_addr + offset + + AMDGPU_VCN_STACK_SIZE)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_OFFSET2), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_OFFSET2), + 0); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_SIZE2), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_SIZE2), + AMDGPU_VCN_CONTEXT_SIZE); + + for (r = 0; r < adev->vcn.num_enc_rings; ++r) { + ring = &adev->vcn.inst->ring_enc[r]; + ring->wptr = 0; + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_RB_BASE_LO), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_RB_BASE_LO), + lower_32_bits(ring->gpu_addr)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_RB_BASE_HI), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_RB_BASE_HI), + upper_32_bits(ring->gpu_addr)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_RB_SIZE), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_RB_SIZE), + ring->ring_size / 4); + } + + ring = &adev->vcn.inst->ring_dec; + ring->wptr = 0; + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_RBC_RB_64BIT_BAR_LOW), + lower_32_bits(ring->gpu_addr)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH), + upper_32_bits(ring->gpu_addr)); + /* force RBC into idle state */ +@@ -1976,7 +1977,7 @@ static int vcn_v2_0_start_sriov(struct amdgpu_device *adev) + tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1); + tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_RBC_RB_CNTL), tmp); ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_RBC_RB_CNTL), tmp); + + /* add end packet */ + tmp = sizeof(struct mmsch_v2_0_cmd_end); +-- +2.51.0 + diff --git a/queue-5.15/edac-altera-remove-irqf_oneshot.patch b/queue-5.15/edac-altera-remove-irqf_oneshot.patch new file mode 100644 index 0000000000..5207023941 --- /dev/null +++ b/queue-5.15/edac-altera-remove-irqf_oneshot.patch @@ -0,0 +1,74 @@ +From 9196dbae61f248985da727491704c8cadfc7d59e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:55:30 +0100 +Subject: EDAC/altera: Remove IRQF_ONESHOT + +From: Sebastian Andrzej Siewior + +[ Upstream commit 5c858d6c66304b4c7579582ec5235f02d43578ea ] + +Passing IRQF_ONESHOT ensures that the interrupt source is masked until +the secondary (threaded) handler is done. If only a primary handler is +used then the flag makes no sense because the interrupt can not fire +(again) while its handler is running. + +The flag also prevents force-threading of the primary handler and the +irq-core will warn about this. + +Remove IRQF_ONESHOT from irqflags. + +Fixes: a29d64a45eed1 ("EDAC, altera: Add IRQ Flags to disable IRQ while handling") +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260128095540.863589-11-bigeasy@linutronix.de +Signed-off-by: Sasha Levin +--- + drivers/edac/altera_edac.c | 11 ++++------- + 1 file changed, 4 insertions(+), 7 deletions(-) + +diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c +index f1f8c34638339..ff65779b5d657 100644 +--- a/drivers/edac/altera_edac.c ++++ b/drivers/edac/altera_edac.c +@@ -1535,8 +1535,7 @@ static int altr_portb_setup(struct altr_edac_device_dev *device) + goto err_release_group_1; + } + rc = devm_request_irq(&altdev->ddev, altdev->sb_irq, +- prv->ecc_irq_handler, +- IRQF_ONESHOT | IRQF_TRIGGER_HIGH, ++ prv->ecc_irq_handler, IRQF_TRIGGER_HIGH, + ecc_name, altdev); + if (rc) { + edac_printk(KERN_ERR, EDAC_DEVICE, "PortB SBERR IRQ error\n"); +@@ -1559,8 +1558,7 @@ static int altr_portb_setup(struct altr_edac_device_dev *device) + goto err_release_group_1; + } + rc = devm_request_irq(&altdev->ddev, altdev->db_irq, +- prv->ecc_irq_handler, +- IRQF_ONESHOT | IRQF_TRIGGER_HIGH, ++ prv->ecc_irq_handler, IRQF_TRIGGER_HIGH, + ecc_name, altdev); + if (rc) { + edac_printk(KERN_ERR, EDAC_DEVICE, "PortB DBERR IRQ error\n"); +@@ -1943,8 +1941,7 @@ static int altr_edac_a10_device_add(struct altr_arria10_edac *edac, + goto err_release_group1; + } + rc = devm_request_irq(edac->dev, altdev->sb_irq, prv->ecc_irq_handler, +- IRQF_ONESHOT | IRQF_TRIGGER_HIGH, +- ecc_name, altdev); ++ IRQF_TRIGGER_HIGH, ecc_name, altdev); + if (rc) { + edac_printk(KERN_ERR, EDAC_DEVICE, "No SBERR IRQ resource\n"); + goto err_release_group1; +@@ -1966,7 +1963,7 @@ static int altr_edac_a10_device_add(struct altr_arria10_edac *edac, + goto err_release_group1; + } + rc = devm_request_irq(edac->dev, altdev->db_irq, prv->ecc_irq_handler, +- IRQF_ONESHOT | IRQF_TRIGGER_HIGH, ++ IRQF_TRIGGER_HIGH, + ecc_name, altdev); + if (rc) { + edac_printk(KERN_ERR, EDAC_DEVICE, "No DBERR IRQ resource\n"); +-- +2.51.0 + diff --git a/queue-5.15/edac-i5000-fix-snprintf-size-calculation-in-calculat.patch b/queue-5.15/edac-i5000-fix-snprintf-size-calculation-in-calculat.patch new file mode 100644 index 0000000000..06f5909f13 --- /dev/null +++ b/queue-5.15/edac-i5000-fix-snprintf-size-calculation-in-calculat.patch @@ -0,0 +1,40 @@ +From 9def84c4eca150de65c9ee7716f5efd7e459b113 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 17:36:59 +0300 +Subject: EDAC/i5000: Fix snprintf() size calculation in calculate_dimm_size() + +From: Dan Carpenter + +[ Upstream commit 7b5c7e83ac405ff9ecbdd92b37a477f4288f8814 ] + +The snprintf() can't really overflow because we're writing a max of 42 +bytes to a PAGE_SIZE buffer. But the limit calculation doesn't take +the first 11 bytes that we wrote into consideration so the limit is +not correct. Just fix it for correctness even though it doesn't +affect runtime. + +Fixes: 64e1fdaf55d6 ("i5000_edac: Fix the logic that retrieves memory information") +Signed-off-by: Dan Carpenter +Signed-off-by: Tony Luck +Reviewed-by: Qiuxu Zhuo +Link: https://patch.msgid.link/07cd652c51e77aad5a8350e1a7cd9407e5bbe373.1765290801.git.dan.carpenter@linaro.org +Signed-off-by: Sasha Levin +--- + drivers/edac/i5000_edac.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c +index ba46057d42207..3d82ab8eb2c71 100644 +--- a/drivers/edac/i5000_edac.c ++++ b/drivers/edac/i5000_edac.c +@@ -1111,6 +1111,7 @@ static void calculate_dimm_size(struct i5000_pvt *pvt) + + n = snprintf(p, space, " "); + p += n; ++ space -= n; + for (branch = 0; branch < MAX_BRANCHES; branch++) { + n = snprintf(p, space, " branch %d | ", branch); + p += n; +-- +2.51.0 + diff --git a/queue-5.15/edac-i5400-fix-snprintf-limit-calculation-in-calcula.patch b/queue-5.15/edac-i5400-fix-snprintf-limit-calculation-in-calcula.patch new file mode 100644 index 0000000000..34e4387951 --- /dev/null +++ b/queue-5.15/edac-i5400-fix-snprintf-limit-calculation-in-calcula.patch @@ -0,0 +1,49 @@ +From 07e030325473714961f8b10aa875d5c335007624 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 17:37:04 +0300 +Subject: EDAC/i5400: Fix snprintf() limit calculation in calculate_dimm_size() + +From: Dan Carpenter + +[ Upstream commit 72f12683611344853ab030fe7d19b23970ed2bd8 ] + +The snprintf() can't really overflow because we're writing a max of 42 +bytes to a PAGE_SIZE buffer. But my static checker complains because +the limit calculation doesn't take the first 11 space characters that +we wrote into the buffer into consideration. Fix this for the sake of +correctness even though it doesn't affect runtime. + +Also delete an earlier "space -= n;" which was not used. + +Fixes: 68d086f89b80 ("i5400_edac: improve debug messages to better represent the filled memory") +Signed-off-by: Dan Carpenter +Signed-off-by: Tony Luck +Reviewed-by: Qiuxu Zhuo +Link: https://patch.msgid.link/ccd06b91748e7ed8e33eeb2ff1e7b98700879304.1765290801.git.dan.carpenter@linaro.org +Signed-off-by: Sasha Levin +--- + drivers/edac/i5400_edac.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/edac/i5400_edac.c b/drivers/edac/i5400_edac.c +index f76624ee82ef7..5b1188f1b5705 100644 +--- a/drivers/edac/i5400_edac.c ++++ b/drivers/edac/i5400_edac.c +@@ -1024,13 +1024,13 @@ static void calculate_dimm_size(struct i5400_pvt *pvt) + space -= n; + } + +- space -= n; + edac_dbg(2, "%s\n", mem_buffer); + p = mem_buffer; + space = PAGE_SIZE; + + n = snprintf(p, space, " "); + p += n; ++ space -= n; + for (branch = 0; branch < MAX_BRANCHES; branch++) { + n = snprintf(p, space, " branch %d | ", branch); + p += n; +-- +2.51.0 + diff --git a/queue-5.15/ethtool-add-support-to-set-get-tx-copybreak-buf-size.patch b/queue-5.15/ethtool-add-support-to-set-get-tx-copybreak-buf-size.patch new file mode 100644 index 0000000000..f62a9f5231 --- /dev/null +++ b/queue-5.15/ethtool-add-support-to-set-get-tx-copybreak-buf-size.patch @@ -0,0 +1,61 @@ +From 1577bf9655961fb08158c1d2fbb3683d74d68cd6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Nov 2021 20:12:40 +0800 +Subject: ethtool: add support to set/get tx copybreak buf size via ethtool + +From: Hao Chen + +[ Upstream commit 448f413a8bdc727d25d9a786ccbdb974fb85d973 ] + +Add support for ethtool to set/get tx copybreak buf size. + +Signed-off-by: Hao Chen +Signed-off-by: Guangbin Huang +Signed-off-by: David S. Miller +Stable-dep-of: 6d2f142b1e4b ("net: hns3: fix double free issue for tx spare buffer") +Signed-off-by: Sasha Levin +--- + include/uapi/linux/ethtool.h | 1 + + net/ethtool/common.c | 1 + + net/ethtool/ioctl.c | 1 + + 3 files changed, 3 insertions(+) + +diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h +index b6db6590baf0a..266e95e4fb33d 100644 +--- a/include/uapi/linux/ethtool.h ++++ b/include/uapi/linux/ethtool.h +@@ -231,6 +231,7 @@ enum tunable_id { + ETHTOOL_RX_COPYBREAK, + ETHTOOL_TX_COPYBREAK, + ETHTOOL_PFC_PREVENTION_TOUT, /* timeout in msecs */ ++ ETHTOOL_TX_COPYBREAK_BUF_SIZE, + /* + * Add your fresh new tunable attribute above and remember to update + * tunable_strings[] in net/ethtool/common.c +diff --git a/net/ethtool/common.c b/net/ethtool/common.c +index c63e0739dc6ac..0c52100159111 100644 +--- a/net/ethtool/common.c ++++ b/net/ethtool/common.c +@@ -89,6 +89,7 @@ tunable_strings[__ETHTOOL_TUNABLE_COUNT][ETH_GSTRING_LEN] = { + [ETHTOOL_RX_COPYBREAK] = "rx-copybreak", + [ETHTOOL_TX_COPYBREAK] = "tx-copybreak", + [ETHTOOL_PFC_PREVENTION_TOUT] = "pfc-prevention-tout", ++ [ETHTOOL_TX_COPYBREAK_BUF_SIZE] = "tx-copybreak-buf-size", + }; + + const char +diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c +index 8f44bdae78bf7..fd26baf6e6ea8 100644 +--- a/net/ethtool/ioctl.c ++++ b/net/ethtool/ioctl.c +@@ -2432,6 +2432,7 @@ static int ethtool_tunable_valid(const struct ethtool_tunable *tuna) + switch (tuna->id) { + case ETHTOOL_RX_COPYBREAK: + case ETHTOOL_TX_COPYBREAK: ++ case ETHTOOL_TX_COPYBREAK_BUF_SIZE: + if (tuna->len != sizeof(u32) || + tuna->type_id != ETHTOOL_TUNABLE_U32) + return -EINVAL; +-- +2.51.0 + diff --git a/queue-5.15/fat-avoid-parent-link-count-underflow-in-rmdir.patch b/queue-5.15/fat-avoid-parent-link-count-underflow-in-rmdir.patch new file mode 100644 index 0000000000..a2092bbcc1 --- /dev/null +++ b/queue-5.15/fat-avoid-parent-link-count-underflow-in-rmdir.patch @@ -0,0 +1,74 @@ +From 168abe2c14e365243622118a679d74c4db7f2053 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 1 Jan 2026 19:11:48 +0800 +Subject: fat: avoid parent link count underflow in rmdir + +From: Zhiyu Zhang + +[ Upstream commit 8cafcb881364af5ef3a8b9fed4db254054033d8a ] + +Corrupted FAT images can leave a directory inode with an incorrect +i_nlink (e.g. 2 even though subdirectories exist). rmdir then +unconditionally calls drop_nlink(dir) and can drive i_nlink to 0, +triggering the WARN_ON in drop_nlink(). + +Add a sanity check in vfat_rmdir() and msdos_rmdir(): only drop the +parent link count when it is at least 3, otherwise report a filesystem +error. + +Link: https://lkml.kernel.org/r/20260101111148.1437-1-zhiyuzhang999@gmail.com +Fixes: 9a53c3a783c2 ("[PATCH] r/o bind mounts: unlink: monitor i_nlink") +Signed-off-by: Zhiyu Zhang +Reported-by: Zhiyu Zhang +Closes: https://lore.kernel.org/linux-fsdevel/aVN06OKsKxZe6-Kv@casper.infradead.org/T/#t +Tested-by: Zhiyu Zhang +Acked-by: OGAWA Hirofumi +Cc: Al Viro +Cc: Christian Brauner +Cc: Jan Kara +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/fat/namei_msdos.c | 7 ++++++- + fs/fat/namei_vfat.c | 7 ++++++- + 2 files changed, 12 insertions(+), 2 deletions(-) + +diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c +index efba301d68aec..fba3a07d39478 100644 +--- a/fs/fat/namei_msdos.c ++++ b/fs/fat/namei_msdos.c +@@ -325,7 +325,12 @@ static int msdos_rmdir(struct inode *dir, struct dentry *dentry) + err = fat_remove_entries(dir, &sinfo); /* and releases bh */ + if (err) + goto out; +- drop_nlink(dir); ++ if (dir->i_nlink >= 3) ++ drop_nlink(dir); ++ else { ++ fat_fs_error(sb, "parent dir link count too low (%u)", ++ dir->i_nlink); ++ } + + clear_nlink(inode); + fat_truncate_time(inode, NULL, S_CTIME); +diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c +index e69e2a4f99b92..d8e328e390d6b 100644 +--- a/fs/fat/namei_vfat.c ++++ b/fs/fat/namei_vfat.c +@@ -808,7 +808,12 @@ static int vfat_rmdir(struct inode *dir, struct dentry *dentry) + err = fat_remove_entries(dir, &sinfo); /* and releases bh */ + if (err) + goto out; +- drop_nlink(dir); ++ if (dir->i_nlink >= 3) ++ drop_nlink(dir); ++ else { ++ fat_fs_error(sb, "parent dir link count too low (%u)", ++ dir->i_nlink); ++ } + + clear_nlink(inode); + fat_truncate_time(inode, NULL, S_ATIME|S_MTIME); +-- +2.51.0 + diff --git a/queue-5.15/fbdev-au1200fb-fix-a-memory-leak-in-au1200fb_drv_pro.patch b/queue-5.15/fbdev-au1200fb-fix-a-memory-leak-in-au1200fb_drv_pro.patch new file mode 100644 index 0000000000..59534f6223 --- /dev/null +++ b/queue-5.15/fbdev-au1200fb-fix-a-memory-leak-in-au1200fb_drv_pro.patch @@ -0,0 +1,43 @@ +From b66fc646036aef4f40ab6bbaa0917d010f403d85 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 20:14:58 +0800 +Subject: fbdev: au1200fb: Fix a memory leak in au1200fb_drv_probe() + +From: Felix Gu + +[ Upstream commit ce4e25198a6aaaaf36248edf8daf3d744ec8e309 ] + +In au1200fb_drv_probe(), when platform_get_irq fails(), it directly +returns from the function with an error code, which causes a memory +leak. + +Replace it with a goto label to ensure proper cleanup. + +Fixes: 4e88761f5f8c ("fbdev: au1200fb: Fix missing IRQ check in au1200fb_drv_probe") +Signed-off-by: Felix Gu +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/au1200fb.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/video/fbdev/au1200fb.c b/drivers/video/fbdev/au1200fb.c +index 80f54111baec1..ec1d86f253904 100644 +--- a/drivers/video/fbdev/au1200fb.c ++++ b/drivers/video/fbdev/au1200fb.c +@@ -1732,8 +1732,10 @@ static int au1200fb_drv_probe(struct platform_device *dev) + + /* Now hook interrupt too */ + irq = platform_get_irq(dev, 0); +- if (irq < 0) +- return irq; ++ if (irq < 0) { ++ ret = irq; ++ goto failed; ++ } + + ret = request_irq(irq, au1200fb_handle_irq, + IRQF_SHARED, "lcd", (void *)dev); +-- +2.51.0 + diff --git a/queue-5.15/fs-add-linux-init_task.h-for-init_fs.patch b/queue-5.15/fs-add-linux-init_task.h-for-init_fs.patch new file mode 100644 index 0000000000..b3b24ca2c6 --- /dev/null +++ b/queue-5.15/fs-add-linux-init_task.h-for-init_fs.patch @@ -0,0 +1,40 @@ +From 6e0a10aebb756d308fc76c01db97c833d40fd2dd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 11:58:56 +0000 +Subject: fs: add for 'init_fs' + +From: Ben Dooks + +[ Upstream commit 589cff4975afe1a4eaaa1d961652f50b1628d78d ] + +The init_fs symbol is defined in but was +not included in fs/fs_struct.c so fix by adding the include. + +Fixes the following sparse warning: +fs/fs_struct.c:150:18: warning: symbol 'init_fs' was not declared. Should it be static? + +Fixes: 3e93cd671813e ("Take fs_struct handling to new file") +Signed-off-by: Ben Dooks +Link: https://patch.msgid.link/20260108115856.238027-1-ben.dooks@codethink.co.uk +Reviewed-by: Jan Kara +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/fs_struct.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/fs_struct.c b/fs/fs_struct.c +index 04b3f5b9c6295..0b0f88259cc60 100644 +--- a/fs/fs_struct.c ++++ b/fs/fs_struct.c +@@ -6,6 +6,7 @@ + #include + #include + #include ++#include + #include "internal.h" + + /* +-- +2.51.0 + diff --git a/queue-5.15/gfs2-add-metapath_dibh-helper.patch b/queue-5.15/gfs2-add-metapath_dibh-helper.patch new file mode 100644 index 0000000000..f7fa932cb2 --- /dev/null +++ b/queue-5.15/gfs2-add-metapath_dibh-helper.patch @@ -0,0 +1,48 @@ +From b0af0d8c79922ac633d11ff9671f5f7f5e72477a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Oct 2023 01:32:15 +0200 +Subject: gfs2: Add metapath_dibh helper + +From: Andreas Gruenbacher + +[ Upstream commit 92099f0c92270c8c7a79e6bc6e0312ad248ea331 ] + +Add a metapath_dibh() helper for extracting the inode's buffer head from +a metapath. + +Signed-off-by: Andreas Gruenbacher +Stable-dep-of: faddeb848305 ("gfs2: Fix use-after-free in iomap inline data write path") +Signed-off-by: Sasha Levin +--- + fs/gfs2/bmap.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c +index d2011c3c33fc2..7425c90e47eb5 100644 +--- a/fs/gfs2/bmap.c ++++ b/fs/gfs2/bmap.c +@@ -318,6 +318,12 @@ static void gfs2_metapath_ra(struct gfs2_glock *gl, __be64 *start, __be64 *end) + } + } + ++static inline struct buffer_head * ++metapath_dibh(struct metapath *mp) ++{ ++ return mp->mp_bh[0]; ++} ++ + static int __fillup_metapath(struct gfs2_inode *ip, struct metapath *mp, + unsigned int x, unsigned int h) + { +@@ -662,7 +668,7 @@ static int __gfs2_iomap_alloc(struct inode *inode, struct iomap *iomap, + { + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); +- struct buffer_head *dibh = mp->mp_bh[0]; ++ struct buffer_head *dibh = metapath_dibh(mp); + u64 bn; + unsigned n, i, blks, alloced = 0, iblks = 0, branch_start = 0; + size_t dblks = iomap->length >> inode->i_blkbits; +-- +2.51.0 + diff --git a/queue-5.15/gfs2-fix-use-after-free-in-iomap-inline-data-write-p.patch b/queue-5.15/gfs2-fix-use-after-free-in-iomap-inline-data-write-p.patch new file mode 100644 index 0000000000..de60ae7784 --- /dev/null +++ b/queue-5.15/gfs2-fix-use-after-free-in-iomap-inline-data-write-p.patch @@ -0,0 +1,84 @@ +From 3a7771f3bdb3acbfb0ba42efd94ec02c38310fc1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 14:51:34 +0530 +Subject: gfs2: Fix use-after-free in iomap inline data write path + +From: Deepanshu Kartikey + +[ Upstream commit faddeb848305e79db89ee0479bb0e33380656321 ] + +The inline data buffer head (dibh) is being released prematurely in +gfs2_iomap_begin() via release_metapath() while iomap->inline_data +still points to dibh->b_data. This causes a use-after-free when +iomap_write_end_inline() later attempts to write to the inline data +area. + +The bug sequence: +1. gfs2_iomap_begin() calls gfs2_meta_inode_buffer() to read inode + metadata into dibh +2. Sets iomap->inline_data = dibh->b_data + sizeof(struct gfs2_dinode) +3. Calls release_metapath() which calls brelse(dibh), dropping refcount + to 0 +4. kswapd reclaims the page (~39ms later in the syzbot report) +5. iomap_write_end_inline() tries to memcpy() to iomap->inline_data +6. KASAN detects use-after-free write to freed memory + +Fix by storing dibh in iomap->private and incrementing its refcount +with get_bh() in gfs2_iomap_begin(). The buffer is then properly +released in gfs2_iomap_end() after the inline write completes, +ensuring the page stays alive for the entire iomap operation. + +Note: A C reproducer is not available for this issue. The fix is based +on analysis of the KASAN report and code review showing the buffer head +is freed before use. + +[agruenba: Take buffer head reference in gfs2_iomap_begin() to avoid +leaks in gfs2_iomap_get() and gfs2_iomap_alloc().] + +Reported-by: syzbot+ea1cd4aa4d1e98458a55@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=ea1cd4aa4d1e98458a55 +Fixes: d0a22a4b03b8 ("gfs2: Fix iomap write page reclaim deadlock") +Signed-off-by: Deepanshu Kartikey +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Sasha Levin +--- + fs/gfs2/bmap.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c +index 7425c90e47eb5..1e95d777f6737 100644 +--- a/fs/gfs2/bmap.c ++++ b/fs/gfs2/bmap.c +@@ -1114,10 +1114,18 @@ static int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length, + goto out_unlock; + break; + default: +- goto out_unlock; ++ goto out; + } + + ret = gfs2_iomap_begin_write(inode, pos, length, flags, iomap, &mp); ++ if (ret) ++ goto out_unlock; ++ ++out: ++ if (iomap->type == IOMAP_INLINE) { ++ iomap->private = metapath_dibh(&mp); ++ get_bh(iomap->private); ++ } + + out_unlock: + release_metapath(&mp); +@@ -1131,6 +1139,9 @@ static int gfs2_iomap_end(struct inode *inode, loff_t pos, loff_t length, + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); + ++ if (iomap->private) ++ brelse(iomap->private); ++ + switch (flags & (IOMAP_WRITE | IOMAP_ZERO)) { + case IOMAP_WRITE: + if (flags & IOMAP_DIRECT) +-- +2.51.0 + diff --git a/queue-5.15/hfsplus-return-error-when-node-already-exists-in-hfs.patch b/queue-5.15/hfsplus-return-error-when-node-already-exists-in-hfs.patch new file mode 100644 index 0000000000..ff30e64364 --- /dev/null +++ b/queue-5.15/hfsplus-return-error-when-node-already-exists-in-hfs.patch @@ -0,0 +1,58 @@ +From 03ff40d23d3fb7fd06d84ee4eeb0ac4d530e9f2a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Dec 2025 02:19:38 +0530 +Subject: hfsplus: return error when node already exists in hfs_bnode_create + +From: Shardul Bankar + +[ Upstream commit d8a73cc46c8462a969a7516131feb3096f4c49d3 ] + +When hfs_bnode_create() finds that a node is already hashed (which should +not happen in normal operation), it currently returns the existing node +without incrementing its reference count. This causes a reference count +inconsistency that leads to a kernel panic when the node is later freed +in hfs_bnode_put(): + + kernel BUG at fs/hfsplus/bnode.c:676! + BUG_ON(!atomic_read(&node->refcnt)) + +This scenario can occur when hfs_bmap_alloc() attempts to allocate a node +that is already in use (e.g., when node 0's bitmap bit is incorrectly +unset), or due to filesystem corruption. + +Returning an existing node from a create path is not normal operation. + +Fix this by returning ERR_PTR(-EEXIST) instead of the node when it's +already hashed. This properly signals the error condition to callers, +which already check for IS_ERR() return values. + +Reported-by: syzbot+1c8ff72d0cd8a50dfeaa@syzkaller.appspotmail.com +Link: https://syzkaller.appspot.com/bug?extid=1c8ff72d0cd8a50dfeaa +Link: https://lore.kernel.org/all/784415834694f39902088fa8946850fc1779a318.camel@ibm.com/ +Fixes: 634725a92938 ("[PATCH] hfs: cleanup HFS+ prints") +Signed-off-by: Shardul Bankar +Reviewed-by: Viacheslav Dubeyko +Signed-off-by: Viacheslav Dubeyko +Link: https://lore.kernel.org/r/20251229204938.1907089-1-shardul.b@mpiricsoftware.com +Signed-off-by: Viacheslav Dubeyko +Signed-off-by: Sasha Levin +--- + fs/hfsplus/bnode.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/hfsplus/bnode.c b/fs/hfsplus/bnode.c +index 7c127922ac0c7..1fa4a1d18b7b2 100644 +--- a/fs/hfsplus/bnode.c ++++ b/fs/hfsplus/bnode.c +@@ -640,7 +640,7 @@ struct hfs_bnode *hfs_bnode_create(struct hfs_btree *tree, u32 num) + if (node) { + pr_crit("new node %u already hashed?\n", num); + WARN_ON(1); +- return node; ++ return ERR_PTR(-EEXIST); + } + node = __hfs_bnode_create(tree, num); + if (!node) +-- +2.51.0 + diff --git a/queue-5.15/hid-playstation-add-missing-check-for-input_ff_creat.patch b/queue-5.15/hid-playstation-add-missing-check-for-input_ff_creat.patch new file mode 100644 index 0000000000..16532dd8de --- /dev/null +++ b/queue-5.15/hid-playstation-add-missing-check-for-input_ff_creat.patch @@ -0,0 +1,41 @@ +From f98cd31493e4e8fd4d2d9e3a0fdfcb3ab0df606d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 17 Nov 2025 16:28:08 +0800 +Subject: HID: playstation: Add missing check for input_ff_create_memless + +From: Haotian Zhang + +[ Upstream commit e6807641ac94e832988655a1c0e60ccc806b76dc ] + +The ps_gamepad_create() function calls input_ff_create_memless() +without verifying its return value, which can lead to incorrect +behavior or potential crashes when FF effects are triggered. + +Add a check for the return value of input_ff_create_memless(). + +Fixes: 51151098d7ab ("HID: playstation: add DualSense classic rumble support.") +Signed-off-by: Haotian Zhang +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-playstation.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c +index 69c16c9b8c5c9..5e4c329a43414 100644 +--- a/drivers/hid/hid-playstation.c ++++ b/drivers/hid/hid-playstation.c +@@ -484,7 +484,9 @@ static struct input_dev *ps_gamepad_create(struct hid_device *hdev, + #if IS_ENABLED(CONFIG_PLAYSTATION_FF) + if (play_effect) { + input_set_capability(gamepad, EV_FF, FF_RUMBLE); +- input_ff_create_memless(gamepad, NULL, play_effect); ++ ret = input_ff_create_memless(gamepad, NULL, play_effect); ++ if (ret) ++ return ERR_PTR(ret); + } + #endif + +-- +2.51.0 + diff --git a/queue-5.15/hrtimer-fix-trace-oddity.patch b/queue-5.15/hrtimer-fix-trace-oddity.patch new file mode 100644 index 0000000000..b50f0b496c --- /dev/null +++ b/queue-5.15/hrtimer-fix-trace-oddity.patch @@ -0,0 +1,43 @@ +From 78c59e0a9a46b13ea921bc764f68c14fe9ad7165 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 11:38:34 +0100 +Subject: hrtimer: Fix trace oddity + +From: Thomas Gleixner + +[ Upstream commit 5d6446f409da00e5a389125ddb5ce09f5bc404c9 ] + +It turns out that __run_hrtimer() will trace like: + + -0 [032] d.h2. 20705.474563: hrtimer_cancel: hrtimer=0xff2db8f77f8226e8 + -0 [032] d.h1. 20705.474563: hrtimer_expire_entry: hrtimer=0xff2db8f77f8226e8 now=20699452001850 function=tick_nohz_handler/0x0 + +Which is a bit nonsensical, the timer doesn't get canceled on +expiration. The cause is the use of the incorrect debug helper. + +Fixes: c6a2a1770245 ("hrtimer: Add tracepoint for hrtimers") +Reported-by: Peter Zijlstra (Intel) +Signed-off-by: Thomas Gleixner +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260121143208.219595606@infradead.org +Signed-off-by: Sasha Levin +--- + kernel/time/hrtimer.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c +index abb375816e4c1..0246b32e907d2 100644 +--- a/kernel/time/hrtimer.c ++++ b/kernel/time/hrtimer.c +@@ -1650,7 +1650,7 @@ static void __run_hrtimer(struct hrtimer_cpu_base *cpu_base, + + lockdep_assert_held(&cpu_base->lock); + +- debug_deactivate(timer); ++ debug_hrtimer_deactivate(timer); + base->running = timer; + + /* +-- +2.51.0 + diff --git a/queue-5.15/i3c-move-device-name-assignment-after-i3c_bus_init.patch b/queue-5.15/i3c-move-device-name-assignment-after-i3c_bus_init.patch new file mode 100644 index 0000000000..64db1302f3 --- /dev/null +++ b/queue-5.15/i3c-move-device-name-assignment-after-i3c_bus_init.patch @@ -0,0 +1,44 @@ +From 2cc9b39a2ef55acf01b44b6928389c8f45beb3f7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 14:07:22 +0800 +Subject: i3c: Move device name assignment after i3c_bus_init + +From: Billy Tsai + +[ Upstream commit 3502cea99c7ceb331458cbd34ef6792c83144687 ] + +Move device name initialization to occur after i3c_bus_init() +so that i3cbus->id is guaranteed to be assigned before it is used. + +Fixes: 9d4f219807d5 ("i3c: fix refcount inconsistency in i3c_master_register") +Signed-off-by: Billy Tsai +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260112-upstream_i3c_fix-v1-1-cbbf2cb71809@aspeedtech.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c +index a99c727a23042..dee694024f280 100644 +--- a/drivers/i3c/master.c ++++ b/drivers/i3c/master.c +@@ -2497,12 +2497,13 @@ int i3c_master_register(struct i3c_master_controller *master, + INIT_LIST_HEAD(&master->boardinfo.i3c); + + device_initialize(&master->dev); +- dev_set_name(&master->dev, "i3c-%d", i3cbus->id); + + ret = i3c_bus_init(i3cbus); + if (ret) + goto err_put_dev; + ++ dev_set_name(&master->dev, "i3c-%d", i3cbus->id); ++ + ret = of_populate_i3c_bus(master); + if (ret) + goto err_put_dev; +-- +2.51.0 + diff --git a/queue-5.15/i3c-remove-i2c-board-info-from-i2c_dev_desc.patch b/queue-5.15/i3c-remove-i2c-board-info-from-i2c_dev_desc.patch new file mode 100644 index 0000000000..2498f5338e --- /dev/null +++ b/queue-5.15/i3c-remove-i2c-board-info-from-i2c_dev_desc.patch @@ -0,0 +1,104 @@ +From 6d4960695fdcd0ba557b8bdfee69957753bc53d6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 17 Jan 2022 17:48:15 +0000 +Subject: i3c: remove i2c board info from i2c_dev_desc + +From: Jamie Iles + +[ Upstream commit 31b9887c7258ca47d9c665a80f19f006c86756b1 ] + +I2C board info is only required during adapter setup so there is no +requirement to keeping a pointer to it once running. To support dynamic +device addition we can't rely on board info - user-space creation +through sysfs won't have a boardinfo. + +Cc: Alexandre Belloni +Signed-off-by: Jamie Iles +Signed-off-by: Alexandre Belloni +Link: https://lore.kernel.org/r/20220117174816.1963463-2-quic_jiles@quicinc.com +Stable-dep-of: 3502cea99c7c ("i3c: Move device name assignment after i3c_bus_init") +Signed-off-by: Sasha Levin +--- + drivers/i3c/master.c | 18 ++++++++++-------- + include/linux/i3c/master.h | 1 - + 2 files changed, 10 insertions(+), 9 deletions(-) + +diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c +index e2777db13762f..a99c727a23042 100644 +--- a/drivers/i3c/master.c ++++ b/drivers/i3c/master.c +@@ -610,7 +610,7 @@ static void i3c_master_free_i2c_dev(struct i2c_dev_desc *dev) + + static struct i2c_dev_desc * + i3c_master_alloc_i2c_dev(struct i3c_master_controller *master, +- const struct i2c_dev_boardinfo *boardinfo) ++ u16 addr, u8 lvr) + { + struct i2c_dev_desc *dev; + +@@ -619,9 +619,8 @@ i3c_master_alloc_i2c_dev(struct i3c_master_controller *master, + return ERR_PTR(-ENOMEM); + + dev->common.master = master; +- dev->boardinfo = boardinfo; +- dev->addr = boardinfo->base.addr; +- dev->lvr = boardinfo->lvr; ++ dev->addr = addr; ++ dev->lvr = lvr; + + return dev; + } +@@ -695,7 +694,7 @@ i3c_master_find_i2c_dev_by_addr(const struct i3c_master_controller *master, + struct i2c_dev_desc *dev; + + i3c_bus_for_each_i2cdev(&master->bus, dev) { +- if (dev->boardinfo->base.addr == addr) ++ if (dev->addr == addr) + return dev; + } + +@@ -1692,7 +1691,9 @@ static int i3c_master_bus_init(struct i3c_master_controller *master) + i2cboardinfo->base.addr, + I3C_ADDR_SLOT_I2C_DEV); + +- i2cdev = i3c_master_alloc_i2c_dev(master, i2cboardinfo); ++ i2cdev = i3c_master_alloc_i2c_dev(master, ++ i2cboardinfo->base.addr, ++ i2cboardinfo->lvr); + if (IS_ERR(i2cdev)) { + ret = PTR_ERR(i2cdev); + goto err_detach_devs; +@@ -2178,6 +2179,7 @@ static int i3c_master_i2c_adapter_init(struct i3c_master_controller *master) + { + struct i2c_adapter *adap = i3c_master_to_i2c_adapter(master); + struct i2c_dev_desc *i2cdev; ++ struct i2c_dev_boardinfo *i2cboardinfo; + int ret; + + adap->dev.parent = master->dev.parent; +@@ -2197,8 +2199,8 @@ static int i3c_master_i2c_adapter_init(struct i3c_master_controller *master) + * We silently ignore failures here. The bus should keep working + * correctly even if one or more i2c devices are not registered. + */ +- i3c_bus_for_each_i2cdev(&master->bus, i2cdev) +- i2cdev->dev = i2c_new_client_device(adap, &i2cdev->boardinfo->base); ++ list_for_each_entry(i2cboardinfo, &master->boardinfo.i2c, node) ++ i2cdev->dev = i2c_new_client_device(adap, &i2cboardinfo->base); + + return 0; + } +diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h +index 9cb39d901cd5f..604a126b78c83 100644 +--- a/include/linux/i3c/master.h ++++ b/include/linux/i3c/master.h +@@ -85,7 +85,6 @@ struct i2c_dev_boardinfo { + */ + struct i2c_dev_desc { + struct i3c_i2c_dev_desc common; +- const struct i2c_dev_boardinfo *boardinfo; + struct i2c_client *dev; + u16 addr; + u8 lvr; +-- +2.51.0 + diff --git a/queue-5.15/ib-cache-update-gid-cache-on-client-reregister-event.patch b/queue-5.15/ib-cache-update-gid-cache-on-client-reregister-event.patch new file mode 100644 index 0000000000..20d261109a --- /dev/null +++ b/queue-5.15/ib-cache-update-gid-cache-on-client-reregister-event.patch @@ -0,0 +1,54 @@ +From f5ffedb9f6d4db51ab86e79f5b1750eb00a3433e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 31 Dec 2025 14:07:45 +0100 +Subject: IB/cache: update gid cache on client reregister event +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Etienne AUJAMES + +[ Upstream commit ddd6c8c873e912cb1ead79def54de5e24ff71c80 ] + +Some HCAs (e.g: ConnectX4) do not trigger a IB_EVENT_GID_CHANGE on +subnet prefix update from SM (PortInfo). + +Since the commit d58c23c92548 ("IB/core: Only update PKEY and GID caches +on respective events"), the GID cache is updated exclusively on +IB_EVENT_GID_CHANGE. If this event is not emitted, the subnet prefix in the +IPoIB interface’s hardware address remains set to its default value +(0xfe80000000000000). + +Then rdma_bind_addr() failed because it relies on hardware address to +find the port GID (subnet_prefix + port GUID). + +This patch fixes this issue by updating the GID cache on +IB_EVENT_CLIENT_REREGISTER event (emitted on PortInfo::ClientReregister=1). + +Fixes: d58c23c92548 ("IB/core: Only update PKEY and GID caches on respective events") +Signed-off-by: Etienne AUJAMES +Link: https://patch.msgid.link/aVUfsO58QIDn5bGX@eaujamesFR0130 +Reviewed-by: Parav Pandit +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/cache.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c +index 91ee3e823a9fe..d43a005a18d37 100644 +--- a/drivers/infiniband/core/cache.c ++++ b/drivers/infiniband/core/cache.c +@@ -1549,7 +1549,8 @@ static void ib_cache_event_task(struct work_struct *_work) + * the cache. + */ + ret = ib_cache_update(work->event.device, work->event.element.port_num, +- work->event.event == IB_EVENT_GID_CHANGE, ++ work->event.event == IB_EVENT_GID_CHANGE || ++ work->event.event == IB_EVENT_CLIENT_REREGISTER, + work->event.event == IB_EVENT_PKEY_CHANGE, + work->enforce_security); + +-- +2.51.0 + diff --git a/queue-5.15/iio-sca3000-fix-a-resource-leak-in-sca3000_probe.patch b/queue-5.15/iio-sca3000-fix-a-resource-leak-in-sca3000_probe.patch new file mode 100644 index 0000000000..d14905f593 --- /dev/null +++ b/queue-5.15/iio-sca3000-fix-a-resource-leak-in-sca3000_probe.patch @@ -0,0 +1,42 @@ +From cc42cdc4aa3737e02b73f19a2938e9b6d7857e28 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 22:49:49 -0800 +Subject: iio: sca3000: Fix a resource leak in sca3000_probe() + +From: Harshit Mogalapalli + +[ Upstream commit 62b44ebc1f2c71db3ca2d4737c52e433f6f03038 ] + +spi->irq from request_threaded_irq() not released when +iio_device_register() fails. Add an return value check and jump to a +common error handler when iio_device_register() fails. + +Fixes: 9a4936dc89a3 ("staging:iio:accel:sca3000 Tidy up probe order to avoid a race.") +Signed-off-by: Harshit Mogalapalli +Reviewed-by: Andy Shevchenko +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/accel/sca3000.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/iio/accel/sca3000.c b/drivers/iio/accel/sca3000.c +index cb753a43533cd..9174269c7653b 100644 +--- a/drivers/iio/accel/sca3000.c ++++ b/drivers/iio/accel/sca3000.c +@@ -1489,7 +1489,11 @@ static int sca3000_probe(struct spi_device *spi) + if (ret) + goto error_free_irq; + +- return iio_device_register(indio_dev); ++ ret = iio_device_register(indio_dev); ++ if (ret) ++ goto error_free_irq; ++ ++ return 0; + + error_free_irq: + if (spi->irq) +-- +2.51.0 + diff --git a/queue-5.15/iomap-fix-submission-side-handling-of-completion-sid.patch b/queue-5.15/iomap-fix-submission-side-handling-of-completion-sid.patch new file mode 100644 index 0000000000..4075ae1799 --- /dev/null +++ b/queue-5.15/iomap-fix-submission-side-handling-of-completion-sid.patch @@ -0,0 +1,49 @@ +From 7ac809ca9c28701de2d3d4405b354c6174051e04 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 06:53:38 +0100 +Subject: iomap: fix submission side handling of completion side errors + +From: Christoph Hellwig + +[ Upstream commit 4ad357e39b2ecd5da7bcc7e840ee24d179593cd5 ] + +The "if (dio->error)" in iomap_dio_bio_iter exists to stop submitting +more bios when a completion already return an error. Commit cfe057f7db1f +("iomap_dio_actor(): fix iov_iter bugs") made it revert the iov by +"copied", which is very wrong given that we've already consumed that +range and submitted a bio for it. + +Fixes: cfe057f7db1f ("iomap_dio_actor(): fix iov_iter bugs") +Signed-off-by: Christoph Hellwig +Reviewed-by: Damien Le Moal +Reviewed-by: Darrick J. Wong +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + fs/iomap/direct-io.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/fs/iomap/direct-io.c b/fs/iomap/direct-io.c +index 4ee7790f7b2ea..f5b36732b89b3 100644 +--- a/fs/iomap/direct-io.c ++++ b/fs/iomap/direct-io.c +@@ -303,9 +303,13 @@ static loff_t iomap_dio_bio_iter(const struct iomap_iter *iter, + nr_pages = bio_iov_vecs_to_alloc(dio->submit.iter, BIO_MAX_VECS); + do { + size_t n; +- if (dio->error) { +- iov_iter_revert(dio->submit.iter, copied); +- copied = ret = 0; ++ ++ /* ++ * If completions already occurred and reported errors, give up now and ++ * don't bother submitting more bios. ++ */ ++ if (unlikely(data_race(dio->error))) { ++ ret = 0; + goto out; + } + +-- +2.51.0 + diff --git a/queue-5.15/iommu-vt-d-flush-cache-for-pasid-table-before-using-.patch b/queue-5.15/iommu-vt-d-flush-cache-for-pasid-table-before-using-.patch new file mode 100644 index 0000000000..d74966750d --- /dev/null +++ b/queue-5.15/iommu-vt-d-flush-cache-for-pasid-table-before-using-.patch @@ -0,0 +1,55 @@ +From f11328c2f774be22310f0705f08c0fd9ea69ad36 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 09:48:52 +0800 +Subject: iommu/vt-d: Flush cache for PASID table before using it + +From: Dmytro Maluka + +[ Upstream commit 22d169bdd2849fe6bd18c2643742e1c02be6451c ] + +When writing the address of a freshly allocated zero-initialized PASID +table to a PASID directory entry, do that after the CPU cache flush for +this PASID table, not before it, to avoid the time window when this +PASID table may be already used by non-coherent IOMMU hardware while +its contents in RAM is still some random old data, not zero-initialized. + +Fixes: 194b3348bdbb ("iommu/vt-d: Fix PASID directory pointer coherency") +Signed-off-by: Dmytro Maluka +Reviewed-by: Kevin Tian +Link: https://lore.kernel.org/r/20251221123508.37495-1-dmaluka@chromium.org +Signed-off-by: Lu Baolu +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/intel/pasid.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c +index 589b97ff5433c..fd60e7ec625ea 100644 +--- a/drivers/iommu/intel/pasid.c ++++ b/drivers/iommu/intel/pasid.c +@@ -268,6 +268,9 @@ static struct pasid_entry *intel_pasid_get_entry(struct device *dev, u32 pasid) + if (!entries) + return NULL; + ++ if (!ecap_coherent(info->iommu->ecap)) ++ clflush_cache_range(entries, VTD_PAGE_SIZE); ++ + /* + * The pasid directory table entry won't be freed after + * allocation. No worry about the race with free and +@@ -279,10 +282,8 @@ static struct pasid_entry *intel_pasid_get_entry(struct device *dev, u32 pasid) + free_pgtable_page(entries); + goto retry; + } +- if (!ecap_coherent(info->iommu->ecap)) { +- clflush_cache_range(entries, VTD_PAGE_SIZE); ++ if (!ecap_coherent(info->iommu->ecap)) + clflush_cache_range(&dir[dir_index].val, sizeof(*dir)); +- } + } + + return &entries[index]; +-- +2.51.0 + diff --git a/queue-5.15/ionic-rate-limit-unknown-xcvr-type-messages.patch b/queue-5.15/ionic-rate-limit-unknown-xcvr-type-messages.patch new file mode 100644 index 0000000000..38153021e0 --- /dev/null +++ b/queue-5.15/ionic-rate-limit-unknown-xcvr-type-messages.patch @@ -0,0 +1,51 @@ +From b5633be360a3b4c05cba5ce9ffcd178745063970 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 14:46:51 -0800 +Subject: ionic: Rate limit unknown xcvr type messages + +From: Eric Joyner + +[ Upstream commit cdb1634de3bf197c0d86487d1fb84c128a79cc7c ] + +Running ethtool repeatedly with a transceiver unknown to the driver or +firmware will cause the driver to spam the kernel logs with "unknown +xcvr type" messages which can distract from real issues; and this isn't +interesting information outside of debugging. Fix this by rate limiting +the output so that there are still notifications but not so many that +they flood the log. + +Using dev_dbg_once() would reduce the number of messages further, but +this would miss the case where a different unknown transceiver type is +plugged in, and its status is requested. + +Fixes: 4d03e00a2140 ("ionic: Add initial ethtool support") +Signed-off-by: Eric Joyner +Reviewed-by: Brett Creeley +Link: https://patch.msgid.link/20260206224651.1491-1-eric.joyner@amd.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/pensando/ionic/ionic_ethtool.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c +index 8d459d5634160..b14fd0310ed92 100644 +--- a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c ++++ b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c +@@ -222,9 +222,10 @@ static int ionic_get_link_ksettings(struct net_device *netdev, + /* This means there's no module plugged in */ + break; + default: +- dev_info(lif->ionic->dev, "unknown xcvr type pid=%d / 0x%x\n", +- idev->port_info->status.xcvr.pid, +- idev->port_info->status.xcvr.pid); ++ dev_dbg_ratelimited(lif->ionic->dev, ++ "unknown xcvr type pid=%d / 0x%x\n", ++ idev->port_info->status.xcvr.pid, ++ idev->port_info->status.xcvr.pid); + break; + } + +-- +2.51.0 + diff --git a/queue-5.15/libbpf-fix-dumping-big-endian-bitfields.patch b/queue-5.15/libbpf-fix-dumping-big-endian-bitfields.patch new file mode 100644 index 0000000000..1bf8bb2350 --- /dev/null +++ b/queue-5.15/libbpf-fix-dumping-big-endian-bitfields.patch @@ -0,0 +1,66 @@ +From 834d1dd24d7b8fe1aa486e7242ab3b94398e169d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 Oct 2021 18:09:00 +0200 +Subject: libbpf: Fix dumping big-endian bitfields + +From: Ilya Leoshkevich + +[ Upstream commit c9e982b879465ca74e3593ce82808aa259265a71 ] + +On big-endian arches not only bytes, but also bits are numbered in +reverse order (see e.g. S/390 ELF ABI Supplement, but this is also true +for other big-endian arches as well). + +Signed-off-by: Ilya Leoshkevich +Signed-off-by: Andrii Nakryiko +Link: https://lore.kernel.org/bpf/20211013160902.428340-3-iii@linux.ibm.com +Stable-dep-of: 5714ca8cba5e ("libbpf: Fix OOB read in btf_dump_get_bitfield_value") +Signed-off-by: Sasha Levin +--- + tools/lib/bpf/btf_dump.c | 15 +++++++-------- + 1 file changed, 7 insertions(+), 8 deletions(-) + +diff --git a/tools/lib/bpf/btf_dump.c b/tools/lib/bpf/btf_dump.c +index d62b2d2e8aacb..91ab07901a1bc 100644 +--- a/tools/lib/bpf/btf_dump.c ++++ b/tools/lib/bpf/btf_dump.c +@@ -1656,29 +1656,28 @@ static int btf_dump_get_bitfield_value(struct btf_dump *d, + __u64 *value) + { + __u16 left_shift_bits, right_shift_bits; +- __u8 nr_copy_bits, nr_copy_bytes; + const __u8 *bytes = data; +- int sz = t->size; ++ __u8 nr_copy_bits; + __u64 num = 0; + int i; + + /* Maximum supported bitfield size is 64 bits */ +- if (sz > 8) { +- pr_warn("unexpected bitfield size %d\n", sz); ++ if (t->size > 8) { ++ pr_warn("unexpected bitfield size %d\n", t->size); + return -EINVAL; + } + + /* Bitfield value retrieval is done in two steps; first relevant bytes are + * stored in num, then we left/right shift num to eliminate irrelevant bits. + */ +- nr_copy_bits = bit_sz + bits_offset; +- nr_copy_bytes = t->size; + #if __BYTE_ORDER == __LITTLE_ENDIAN +- for (i = nr_copy_bytes - 1; i >= 0; i--) ++ for (i = t->size - 1; i >= 0; i--) + num = num * 256 + bytes[i]; ++ nr_copy_bits = bit_sz + bits_offset; + #elif __BYTE_ORDER == __BIG_ENDIAN +- for (i = 0; i < nr_copy_bytes; i++) ++ for (i = 0; i < t->size; i++) + num = num * 256 + bytes[i]; ++ nr_copy_bits = t->size * 8 - bits_offset; + #else + # error "Unrecognized __BYTE_ORDER__" + #endif +-- +2.51.0 + diff --git a/queue-5.15/libbpf-fix-oob-read-in-btf_dump_get_bitfield_value.patch b/queue-5.15/libbpf-fix-oob-read-in-btf_dump_get_bitfield_value.patch new file mode 100644 index 0000000000..80aed9faaf --- /dev/null +++ b/queue-5.15/libbpf-fix-oob-read-in-btf_dump_get_bitfield_value.patch @@ -0,0 +1,59 @@ +From 074d1d62488febbe29d3bf74b692d0a43482e063 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 05:05:27 +0530 +Subject: libbpf: Fix OOB read in btf_dump_get_bitfield_value + +From: Varun R Mallya + +[ Upstream commit 5714ca8cba5ed736f3733663c446cbee63a10a64 ] + +When dumping bitfield data, btf_dump_get_bitfield_value() reads data +based on the underlying type's size (t->size). However, it does not +verify that the provided data buffer (data_sz) is large enough to +contain these bytes. + +If btf_dump__dump_type_data() is called with a buffer smaller than +the type's size, this leads to an out-of-bounds read. This was +confirmed by AddressSanitizer in the linked issue. + +Fix this by ensuring we do not read past the provided data_sz limit. + +Fixes: a1d3cc3c5eca ("libbpf: Avoid use of __int128 in typed dump display") +Reported-by: Harrison Green +Suggested-by: Alan Maguire +Signed-off-by: Varun R Mallya +Signed-off-by: Andrii Nakryiko +Link: https://lore.kernel.org/bpf/20260106233527.163487-1-varunrmallya@gmail.com + +Closes: https://github.com/libbpf/libbpf/issues/928 +Signed-off-by: Sasha Levin +--- + tools/lib/bpf/btf_dump.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/tools/lib/bpf/btf_dump.c b/tools/lib/bpf/btf_dump.c +index 91ab07901a1bc..fc329c2cf9df2 100644 +--- a/tools/lib/bpf/btf_dump.c ++++ b/tools/lib/bpf/btf_dump.c +@@ -1658,9 +1658,18 @@ static int btf_dump_get_bitfield_value(struct btf_dump *d, + __u16 left_shift_bits, right_shift_bits; + const __u8 *bytes = data; + __u8 nr_copy_bits; ++ __u8 start_bit, nr_bytes; + __u64 num = 0; + int i; + ++ /* Calculate how many bytes cover the bitfield */ ++ start_bit = bits_offset % 8; ++ nr_bytes = (start_bit + bit_sz + 7) / 8; ++ ++ /* Bound check */ ++ if (data + nr_bytes > d->typed_dump->data_end) ++ return -E2BIG; ++ + /* Maximum supported bitfield size is 64 bits */ + if (t->size > 8) { + pr_warn("unexpected bitfield size %d\n", t->size); +-- +2.51.0 + diff --git a/queue-5.15/md-raid10-fix-any_working-flag-handling-in-raid10_sy.patch b/queue-5.15/md-raid10-fix-any_working-flag-handling-in-raid10_sy.patch new file mode 100644 index 0000000000..2499bc16bf --- /dev/null +++ b/queue-5.15/md-raid10-fix-any_working-flag-handling-in-raid10_sy.patch @@ -0,0 +1,47 @@ +From b7e9b1d6a649a2456236c68873221aec2de048c8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Jan 2026 19:02:58 +0800 +Subject: md/raid10: fix any_working flag handling in raid10_sync_request + +From: Li Nan + +[ Upstream commit 99582edb3f62e8ee6c34512021368f53f9b091f2 ] + +In raid10_sync_request(), 'any_working' indicates if any IO will +be submitted. When there's only one In_sync disk with badblocks, +'any_working' might be set to 1 but no IO is submitted. Fix it by +setting 'any_working' after badblock checks. + +Link: https://lore.kernel.org/linux-raid/20260105110300.1442509-11-linan666@huaweicloud.com +Fixes: e875ecea266a ("md/raid10 record bad blocks as needed during recovery.") +Signed-off-by: Li Nan +Reviewed-by: Yu Kuai +Signed-off-by: Yu Kuai +Signed-off-by: Sasha Levin +--- + drivers/md/raid10.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c +index 5b0f38e7c8f13..c6429ef37f9e2 100644 +--- a/drivers/md/raid10.c ++++ b/drivers/md/raid10.c +@@ -3546,7 +3546,6 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr, + !test_bit(In_sync, &rdev->flags)) + continue; + /* This is where we read from */ +- any_working = 1; + sector = r10_bio->devs[j].addr; + + if (is_badblock(rdev, sector, max_sync, +@@ -3561,6 +3560,7 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr, + continue; + } + } ++ any_working = 1; + bio = r10_bio->devs[0].bio; + bio->bi_next = biolist; + biolist = bio; +-- +2.51.0 + diff --git a/queue-5.15/media-ccs-accommodate-c-phy-into-the-calculation.patch b/queue-5.15/media-ccs-accommodate-c-phy-into-the-calculation.patch new file mode 100644 index 0000000000..49a5748e42 --- /dev/null +++ b/queue-5.15/media-ccs-accommodate-c-phy-into-the-calculation.patch @@ -0,0 +1,53 @@ +From 436d920fa42b0462810f4871e6ed4abf08d589fb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 18:57:07 +0100 +Subject: media: ccs: Accommodate C-PHY into the calculation + +From: David Heidelberg + +[ Upstream commit 3085977e734dab74adebb1dda195befce25addff ] + +We need to set correct mode for PLL to calculate correct frequency. +Signalling mode is known at this point, so use it for that. + +Fixes: 47b6eaf36eba ("media: ccs-pll: Differentiate between CSI-2 D-PHY and C-PHY") +Reviewed-by: Mehdi Djait +Signed-off-by: David Heidelberg +[Sakari Ailus: Drop extra newline.] +Signed-off-by: Sakari Ailus +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/i2c/ccs/ccs-core.c | 16 +++++++++++++++- + 1 file changed, 15 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c +index 789f288bd1ed8..97123d8b326a5 100644 +--- a/drivers/media/i2c/ccs/ccs-core.c ++++ b/drivers/media/i2c/ccs/ccs-core.c +@@ -3524,7 +3524,21 @@ static int ccs_probe(struct i2c_client *client) + sensor->scale_m = CCS_LIM(sensor, SCALER_N_MIN); + + /* prepare PLL configuration input values */ +- sensor->pll.bus_type = CCS_PLL_BUS_TYPE_CSI2_DPHY; ++ switch (sensor->hwcfg.csi_signalling_mode) { ++ case CCS_CSI_SIGNALING_MODE_CSI_2_CPHY: ++ sensor->pll.bus_type = CCS_PLL_BUS_TYPE_CSI2_CPHY; ++ break; ++ case CCS_CSI_SIGNALING_MODE_CSI_2_DPHY: ++ case SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK: ++ case SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_STROBE: ++ sensor->pll.bus_type = CCS_PLL_BUS_TYPE_CSI2_DPHY; ++ break; ++ default: ++ dev_err(&client->dev, "unsupported signalling mode %u\n", ++ sensor->hwcfg.csi_signalling_mode); ++ rval = -EINVAL; ++ goto out_cleanup; ++ } + sensor->pll.csi2.lanes = sensor->hwcfg.lanes; + if (CCS_LIM(sensor, CLOCK_CALCULATION) & + CCS_CLOCK_CALCULATION_LANE_SPEED) { +-- +2.51.0 + diff --git a/queue-5.15/media-uvcvideo-fix-allocation-for-small-frame-sizes.patch b/queue-5.15/media-uvcvideo-fix-allocation-for-small-frame-sizes.patch new file mode 100644 index 0000000000..ef60fc1e39 --- /dev/null +++ b/queue-5.15/media-uvcvideo-fix-allocation-for-small-frame-sizes.patch @@ -0,0 +1,57 @@ +From 9ee59a0ccc24bb410357ccbb9a84b49ec64240f9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 10:32:13 +0000 +Subject: media: uvcvideo: Fix allocation for small frame sizes + +From: Ricardo Ribalda + +[ Upstream commit 40d3ac25c11310bfaa50ed7614846ef75cb69a1e ] + +If a frame has size of less or equal than one packet size +uvc_alloc_urb_buffers() is unable to allocate memory for it due to a +off-by-one error. + +Fix the off-by-one-error and now that we are at it, make sure that +stream->urb_size has always a valid value when we return from the +function, even when an error happens. + +Fixes: efdc8a9585ce ("V4L/DVB (10295): uvcvideo: Retry URB buffers allocation when the system is low on memory.") +Reported-by: Itay Chamiel +Closes: https://lore.kernel.org/linux-media/CANiDSCsSoZf2LsCCoWAUbCg6tJT-ypXR1B85aa6rAdMVYr2iBQ@mail.gmail.com/T/#t +Co-developed-by: Itay Chamiel +Signed-off-by: Itay Chamiel +Signed-off-by: Ricardo Ribalda +Reviewed-by: Laurent Pinchart +Tested-by: Itay Chamiel +Link: https://patch.msgid.link/20260114-uvc-alloc-urb-v1-1-cedf3fb66711@chromium.org +Signed-off-by: Laurent Pinchart +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/usb/uvc/uvc_video.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c +index 4739633e30879..f868a13280a1e 100644 +--- a/drivers/media/usb/uvc/uvc_video.c ++++ b/drivers/media/usb/uvc/uvc_video.c +@@ -1736,7 +1736,7 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream, + npackets = UVC_MAX_PACKETS; + + /* Retry allocations until one succeed. */ +- for (; npackets > 1; npackets /= 2) { ++ for (; npackets > 0; npackets /= 2) { + stream->urb_size = psize * npackets; + + for (i = 0; i < UVC_URBS; ++i) { +@@ -1761,6 +1761,7 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream, + uvc_dbg(stream->dev, VIDEO, + "Failed to allocate URB buffers (%u bytes per packet)\n", + psize); ++ stream->urb_size = 0; + return 0; + } + +-- +2.51.0 + diff --git a/queue-5.15/mfd-arizona-fix-regulator-resource-leak-on-wm5102_cl.patch b/queue-5.15/mfd-arizona-fix-regulator-resource-leak-on-wm5102_cl.patch new file mode 100644 index 0000000000..15d8d1f0a7 --- /dev/null +++ b/queue-5.15/mfd-arizona-fix-regulator-resource-leak-on-wm5102_cl.patch @@ -0,0 +1,43 @@ +From 40b59d55548d13e78f53f660303446574838b639 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 14 Dec 2025 22:58:03 +0800 +Subject: mfd: arizona: Fix regulator resource leak on + wm5102_clear_write_sequencer() failure + +From: Haotian Zhang + +[ Upstream commit 4feb753ba6e5e5bbaba868b841a2db41c21e56fa ] + +The wm5102_clear_write_sequencer() helper may return an error +and just return, bypassing the cleanup sequence and causing +regulators to remain enabled, leading to a resource leak. + +Change the direct return to jump to the err_reset label to +properly free the resources. + +Fixes: 1c1c6bba57f5 ("mfd: wm5102: Ensure we always boot the device fully") +Signed-off-by: Haotian Zhang +Reviewed-by: Charles Keepax +Link: https://patch.msgid.link/20251214145804.2037-1-vulab@iscas.ac.cn +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/mfd/arizona-core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c +index 5c8317bd4d98b..6ec50eb1544c0 100644 +--- a/drivers/mfd/arizona-core.c ++++ b/drivers/mfd/arizona-core.c +@@ -1119,7 +1119,7 @@ int arizona_dev_init(struct arizona *arizona) + } else if (val & 0x01) { + ret = wm5102_clear_write_sequencer(arizona); + if (ret) +- return ret; ++ goto err_reset; + } + break; + default: +-- +2.51.0 + diff --git a/queue-5.15/mfd-wm8350-core-use-irqf_oneshot.patch b/queue-5.15/mfd-wm8350-core-use-irqf_oneshot.patch new file mode 100644 index 0000000000..3c113ce087 --- /dev/null +++ b/queue-5.15/mfd-wm8350-core-use-irqf_oneshot.patch @@ -0,0 +1,48 @@ +From 90c3e54fa08c910351b0baaafcf358800e4537d0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:55:35 +0100 +Subject: mfd: wm8350-core: Use IRQF_ONESHOT + +From: Sebastian Andrzej Siewior + +[ Upstream commit 553b4999cbe231b5011cb8db05a3092dec168aca ] + +Using a threaded interrupt without a dedicated primary handler mandates +the IRQF_ONESHOT flag to mask the interrupt source while the threaded +handler is active. Otherwise the interrupt can fire again before the +threaded handler had a chance to run. + +Mark explained that this should not happen with this hardware since it +is a slow irqchip which is behind an I2C/ SPI bus but the IRQ-core will +refuse to accept such a handler. + +Set IRQF_ONESHOT so the interrupt source is masked until the secondary +handler is done. + +Fixes: 1c6c69525b40e ("genirq: Reject bogus threaded irq requests") +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Reviewed-by: Charles Keepax +Reviewed-by: Andy Shevchenko +Link: https://patch.msgid.link/20260128095540.863589-16-bigeasy@linutronix.de +Signed-off-by: Sasha Levin +--- + include/linux/mfd/wm8350/core.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/linux/mfd/wm8350/core.h b/include/linux/mfd/wm8350/core.h +index a3241e4d75486..4816d4f472101 100644 +--- a/include/linux/mfd/wm8350/core.h ++++ b/include/linux/mfd/wm8350/core.h +@@ -663,7 +663,7 @@ static inline int wm8350_register_irq(struct wm8350 *wm8350, int irq, + return -ENODEV; + + return request_threaded_irq(irq + wm8350->irq_base, NULL, +- handler, flags, name, data); ++ handler, flags | IRQF_ONESHOT, name, data); + } + + static inline void wm8350_free_irq(struct wm8350 *wm8350, int irq, void *data) +-- +2.51.0 + diff --git a/queue-5.15/mmc-rtsx_pci_sdmmc-increase-power-on-settling-delay-.patch b/queue-5.15/mmc-rtsx_pci_sdmmc-increase-power-on-settling-delay-.patch new file mode 100644 index 0000000000..6396f54a1a --- /dev/null +++ b/queue-5.15/mmc-rtsx_pci_sdmmc-increase-power-on-settling-delay-.patch @@ -0,0 +1,40 @@ +From 7a764b4ce49a82d2663748a7b5a85da09930c867 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 4 Jan 2026 22:02:36 -0800 +Subject: mmc: rtsx_pci_sdmmc: increase power-on settling delay to 5ms + +From: Matthew Schwartz + +[ Upstream commit aced969e9bf3701dc75cfca57c78c031b7875b9d ] + +The existing 1ms delay in sd_power_on is insufficient and causes resume +errors around 4% of the time. + +Increasing the delay to 5ms resolves this issue after testing 300 +s2idle cycles. + +Fixes: 1f311c94aabd ("mmc: rtsx: add 74 Clocks in power on flow") +Signed-off-by: Matthew Schwartz +Link: https://patch.msgid.link/20260105060236.400366-3-matthew.schwartz@linux.dev +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/mmc/host/rtsx_pci_sdmmc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c +index d063d50d69feb..02da9016245bd 100644 +--- a/drivers/mmc/host/rtsx_pci_sdmmc.c ++++ b/drivers/mmc/host/rtsx_pci_sdmmc.c +@@ -938,7 +938,7 @@ static int sd_power_on(struct realtek_pci_sdmmc *host, unsigned char power_mode) + if (err < 0) + return err; + +- mdelay(1); ++ mdelay(5); + + err = rtsx_pci_write_register(pcr, CARD_OE, SD_OUTPUT_EN, SD_OUTPUT_EN); + if (err < 0) +-- +2.51.0 + diff --git a/queue-5.15/mtd-parsers-ofpart-fix-of-node-refcount-leak-in-pars.patch b/queue-5.15/mtd-parsers-ofpart-fix-of-node-refcount-leak-in-pars.patch new file mode 100644 index 0000000000..d8a447a585 --- /dev/null +++ b/queue-5.15/mtd-parsers-ofpart-fix-of-node-refcount-leak-in-pars.patch @@ -0,0 +1,84 @@ +From 4d27140453037565913e01446a1403d9e5e472ee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 05:26:08 +0000 +Subject: mtd: parsers: ofpart: fix OF node refcount leak in + parse_fixed_partitions() + +From: Weigang He + +[ Upstream commit 7cce81df7d26d44123bd7620715c8349d96793d7 ] + +of_get_child_by_name() returns a node pointer with refcount incremented, +which must be released with of_node_put() when done. However, in +parse_fixed_partitions(), when dedicated is true (i.e., a "partitions" +subnode was found), the ofpart_node obtained from of_get_child_by_name() +is never released on any code path. + +Add of_node_put(ofpart_node) calls on all exit paths when dedicated is +true to fix the reference count leak. + +This bug was detected by our static analysis tool. + +Fixes: 562b4e91d3b2 ("mtd: parsers: ofpart: fix parsing subpartitions") +Signed-off-by: Weigang He +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/parsers/ofpart_core.c | 16 ++++++++++++++-- + 1 file changed, 14 insertions(+), 2 deletions(-) + +diff --git a/drivers/mtd/parsers/ofpart_core.c b/drivers/mtd/parsers/ofpart_core.c +index 192190c42fc84..20af45a7270d5 100644 +--- a/drivers/mtd/parsers/ofpart_core.c ++++ b/drivers/mtd/parsers/ofpart_core.c +@@ -77,6 +77,7 @@ static int parse_fixed_partitions(struct mtd_info *master, + of_id = of_match_node(parse_ofpart_match_table, ofpart_node); + if (dedicated && !of_id) { + /* The 'partitions' subnode might be used by another parser */ ++ of_node_put(ofpart_node); + return 0; + } + +@@ -91,12 +92,18 @@ static int parse_fixed_partitions(struct mtd_info *master, + nr_parts++; + } + +- if (nr_parts == 0) ++ if (nr_parts == 0) { ++ if (dedicated) ++ of_node_put(ofpart_node); + return 0; ++ } + + parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL); +- if (!parts) ++ if (!parts) { ++ if (dedicated) ++ of_node_put(ofpart_node); + return -ENOMEM; ++ } + + i = 0; + for_each_child_of_node(ofpart_node, pp) { +@@ -156,6 +163,9 @@ static int parse_fixed_partitions(struct mtd_info *master, + if (quirks && quirks->post_parse) + quirks->post_parse(master, parts, nr_parts); + ++ if (dedicated) ++ of_node_put(ofpart_node); ++ + *pparts = parts; + return nr_parts; + +@@ -164,6 +174,8 @@ static int parse_fixed_partitions(struct mtd_info *master, + master->name, pp, mtd_node); + ret = -EINVAL; + ofpart_none: ++ if (dedicated) ++ of_node_put(ofpart_node); + of_node_put(pp); + kfree(parts); + return ret; +-- +2.51.0 + diff --git a/queue-5.15/mtd-rawnand-cadence-fix-return-type-of-cdma-send-and.patch b/queue-5.15/mtd-rawnand-cadence-fix-return-type-of-cdma-send-and.patch new file mode 100644 index 0000000000..931eca5876 --- /dev/null +++ b/queue-5.15/mtd-rawnand-cadence-fix-return-type-of-cdma-send-and.patch @@ -0,0 +1,40 @@ +From 07d449136cdabec6866b4cba325ae05e9077da4f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 19 Dec 2025 03:09:30 -0800 +Subject: mtd: rawnand: cadence: Fix return type of CDMA send-and-wait helper + +From: Alok Tiwari + +[ Upstream commit 6d8226cbbf124bb5613b532216b74c886a4361b7 ] + +cadence_nand_cdma_send_and_wait() propagates negative errno values +from cadence_nand_cdma_send(), returns -ETIMEDOUT on failure and -EIO +when the CDMA engine reports a command failure. + +However, it is declared as u32, causing error codes to wrap. +Change the return type to int to correctly propagate errors. + +Fixes: ec4ba01e894d ("mtd: rawnand: Add new Cadence NAND driver to MTD subsystem") +Signed-off-by: Alok Tiwari +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/nand/raw/cadence-nand-controller.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/nand/raw/cadence-nand-controller.c b/drivers/mtd/nand/raw/cadence-nand-controller.c +index 8c8d21af1d9b7..6ba4601681cef 100644 +--- a/drivers/mtd/nand/raw/cadence-nand-controller.c ++++ b/drivers/mtd/nand/raw/cadence-nand-controller.c +@@ -1018,7 +1018,7 @@ static int cadence_nand_cdma_send(struct cdns_nand_ctrl *cdns_ctrl, + } + + /* Send SDMA command and wait for finish. */ +-static u32 ++static int + cadence_nand_cdma_send_and_wait(struct cdns_nand_ctrl *cdns_ctrl, + u8 thread) + { +-- +2.51.0 + diff --git a/queue-5.15/net-atm-fix-crash-due-to-unvalidated-vcc-pointer-in-.patch b/queue-5.15/net-atm-fix-crash-due-to-unvalidated-vcc-pointer-in-.patch new file mode 100644 index 0000000000..bc217b1676 --- /dev/null +++ b/queue-5.15/net-atm-fix-crash-due-to-unvalidated-vcc-pointer-in-.patch @@ -0,0 +1,154 @@ +From 912f72c5d666027194d06881d097c2dd9ea8b956 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 17:54:51 +0800 +Subject: net: atm: fix crash due to unvalidated vcc pointer in sigd_send() + +From: Jiayuan Chen + +[ Upstream commit ae88a5d2f29b69819dc7b04086734439d074a643 ] + +Reproducer available at [1]. + +The ATM send path (sendmsg -> vcc_sendmsg -> sigd_send) reads the vcc +pointer from msg->vcc and uses it directly without any validation. This +pointer comes from userspace via sendmsg() and can be arbitrarily forged: + + int fd = socket(AF_ATMSVC, SOCK_DGRAM, 0); + ioctl(fd, ATMSIGD_CTRL); // become ATM signaling daemon + struct msghdr msg = { .msg_iov = &iov, ... }; + *(unsigned long *)(buf + 4) = 0xdeadbeef; // fake vcc pointer + sendmsg(fd, &msg, 0); // kernel dereferences 0xdeadbeef + +In normal operation, the kernel sends the vcc pointer to the signaling +daemon via sigd_enq() when processing operations like connect(), bind(), +or listen(). The daemon is expected to return the same pointer when +responding. However, a malicious daemon can send arbitrary pointer values. + +Fix this by introducing find_get_vcc() which validates the pointer by +searching through vcc_hash (similar to how sigd_close() iterates over +all VCCs), and acquires a reference via sock_hold() if found. + +Since struct atm_vcc embeds struct sock as its first member, they share +the same lifetime. Therefore using sock_hold/sock_put is sufficient to +keep the vcc alive while it is being used. + +Note that there may be a race with sigd_close() which could mark the vcc +with various flags (e.g., ATM_VF_RELEASED) after find_get_vcc() returns. +However, sock_hold() guarantees the memory remains valid, so this race +only affects the logical state, not memory safety. + +[1]: https://gist.github.com/mrpre/1ba5949c45529c511152e2f4c755b0f3 +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: syzbot+1f22cb1769f249df9fa0@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/69039850.a70a0220.5b2ed.005d.GAE@google.com/T/ +Signed-off-by: Jiayuan Chen +Link: https://patch.msgid.link/20260205095501.131890-1-jiayuan.chen@linux.dev +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/atm/signaling.c | 56 +++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 54 insertions(+), 2 deletions(-) + +diff --git a/net/atm/signaling.c b/net/atm/signaling.c +index 5de06ab8ed752..5a5d8b1fa8be8 100644 +--- a/net/atm/signaling.c ++++ b/net/atm/signaling.c +@@ -22,6 +22,36 @@ + + struct atm_vcc *sigd = NULL; + ++/* ++ * find_get_vcc - validate and get a reference to a vcc pointer ++ * @vcc: the vcc pointer to validate ++ * ++ * This function validates that @vcc points to a registered VCC in vcc_hash. ++ * If found, it increments the socket reference count and returns the vcc. ++ * The caller must call sock_put(sk_atm(vcc)) when done. ++ * ++ * Returns the vcc pointer if valid, NULL otherwise. ++ */ ++static struct atm_vcc *find_get_vcc(struct atm_vcc *vcc) ++{ ++ int i; ++ ++ read_lock(&vcc_sklist_lock); ++ for (i = 0; i < VCC_HTABLE_SIZE; i++) { ++ struct sock *s; ++ ++ sk_for_each(s, &vcc_hash[i]) { ++ if (atm_sk(s) == vcc) { ++ sock_hold(s); ++ read_unlock(&vcc_sklist_lock); ++ return vcc; ++ } ++ } ++ } ++ read_unlock(&vcc_sklist_lock); ++ return NULL; ++} ++ + static void sigd_put_skb(struct sk_buff *skb) + { + if (!sigd) { +@@ -69,7 +99,14 @@ static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb) + + msg = (struct atmsvc_msg *) skb->data; + WARN_ON(refcount_sub_and_test(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc)); +- vcc = *(struct atm_vcc **) &msg->vcc; ++ ++ vcc = find_get_vcc(*(struct atm_vcc **)&msg->vcc); ++ if (!vcc) { ++ pr_debug("invalid vcc pointer in msg\n"); ++ dev_kfree_skb(skb); ++ return -EINVAL; ++ } ++ + pr_debug("%d (0x%lx)\n", (int)msg->type, (unsigned long)vcc); + sk = sk_atm(vcc); + +@@ -100,7 +137,16 @@ static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb) + clear_bit(ATM_VF_WAITING, &vcc->flags); + break; + case as_indicate: +- vcc = *(struct atm_vcc **)&msg->listen_vcc; ++ /* Release the reference from msg->vcc, we'll use msg->listen_vcc instead */ ++ sock_put(sk); ++ ++ vcc = find_get_vcc(*(struct atm_vcc **)&msg->listen_vcc); ++ if (!vcc) { ++ pr_debug("invalid listen_vcc pointer in msg\n"); ++ dev_kfree_skb(skb); ++ return -EINVAL; ++ } ++ + sk = sk_atm(vcc); + pr_debug("as_indicate!!!\n"); + lock_sock(sk); +@@ -115,6 +161,8 @@ static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb) + sk->sk_state_change(sk); + as_indicate_complete: + release_sock(sk); ++ /* Paired with find_get_vcc(msg->listen_vcc) above */ ++ sock_put(sk); + return 0; + case as_close: + set_bit(ATM_VF_RELEASED, &vcc->flags); +@@ -131,11 +179,15 @@ static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb) + break; + default: + pr_alert("bad message type %d\n", (int)msg->type); ++ /* Paired with find_get_vcc(msg->vcc) above */ ++ sock_put(sk); + return -EINVAL; + } + sk->sk_state_change(sk); + out: + dev_kfree_skb(skb); ++ /* Paired with find_get_vcc(msg->vcc) above */ ++ sock_put(sk); + return 0; + } + +-- +2.51.0 + diff --git a/queue-5.15/net-hns3-add-max-order-judgement-for-tx-spare-buffer.patch b/queue-5.15/net-hns3-add-max-order-judgement-for-tx-spare-buffer.patch new file mode 100644 index 0000000000..4ccf99a5ea --- /dev/null +++ b/queue-5.15/net-hns3-add-max-order-judgement-for-tx-spare-buffer.patch @@ -0,0 +1,44 @@ +From 13ba2e3d3be45495eee04421a40dbca7030bde8d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 26 Mar 2022 17:51:01 +0800 +Subject: net: hns3: add max order judgement for tx spare buffer + +From: Hao Chen + +[ Upstream commit a89cbb16995bf15582e0d1bdb922ad1a54a2fa8c ] + +Add max order judgement for tx spare buffer to avoid triggering +call trace, print related fail information instead, when user +set tx spare buf size to a large value which causes order +exceeding 10. + +Fixes: e445f08af2b1 ("net: hns3: add support to set/get tx copybreak buf size via ethtool for hns3 driver") +Signed-off-by: Hao Chen +Signed-off-by: Guangbin Huang +Signed-off-by: David S. Miller +Stable-dep-of: 6d2f142b1e4b ("net: hns3: fix double free issue for tx spare buffer") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +index b907d693631c2..ac5d7ea206bb2 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +@@ -1044,6 +1044,12 @@ static void hns3_init_tx_spare_buffer(struct hns3_enet_ring *ring) + return; + + order = get_order(alloc_size); ++ if (order >= MAX_ORDER) { ++ if (net_ratelimit()) ++ dev_warn(ring_to_dev(ring), "failed to allocate tx spare buffer, exceed to max order\n"); ++ return; ++ } ++ + tx_spare = devm_kzalloc(ring_to_dev(ring), sizeof(*tx_spare), + GFP_KERNEL); + if (!tx_spare) { +-- +2.51.0 + diff --git a/queue-5.15/net-hns3-add-support-to-set-get-tx-copybreak-buf-siz.patch b/queue-5.15/net-hns3-add-support-to-set-get-tx-copybreak-buf-siz.patch new file mode 100644 index 0000000000..eb30ea2656 --- /dev/null +++ b/queue-5.15/net-hns3-add-support-to-set-get-tx-copybreak-buf-siz.patch @@ -0,0 +1,154 @@ +From 0a3520ec3f4aa82f4d6050d9aa3671dd60f62a76 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Nov 2021 20:12:41 +0800 +Subject: net: hns3: add support to set/get tx copybreak buf size via ethtool + for hns3 driver + +From: Hao Chen + +[ Upstream commit e445f08af2b15035474439fbbb8649f466ad2501 ] + +Tx copybreak buf size is used for tx copybreak feature, the feature is +used for small size packet or frag. It adds a queue based tx shared +bounce buffer to memcpy the small packet when the len of xmitted skb is +below tx_copybreak(value to distinguish small size and normal size), +and reduce the overhead of dma map and unmap when IOMMU is on. + +Support setting it via ethtool --set-tunable parameter and getting +it via ethtool --get-tunable parameter. + +Signed-off-by: Hao Chen +Signed-off-by: Guangbin Huang +Signed-off-by: David S. Miller +Stable-dep-of: 6d2f142b1e4b ("net: hns3: fix double free issue for tx spare buffer") +Signed-off-by: Sasha Levin +--- + .../net/ethernet/hisilicon/hns3/hns3_enet.c | 4 +- + .../net/ethernet/hisilicon/hns3/hns3_enet.h | 2 + + .../ethernet/hisilicon/hns3/hns3_ethtool.c | 56 +++++++++++++++++++ + 3 files changed, 60 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +index adc2f1e34e32a..84c724df2e405 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +@@ -5535,8 +5535,8 @@ static int hns3_reset_notify_uninit_enet(struct hnae3_handle *handle) + return 0; + } + +-static int hns3_reset_notify(struct hnae3_handle *handle, +- enum hnae3_reset_notify_type type) ++int hns3_reset_notify(struct hnae3_handle *handle, ++ enum hnae3_reset_notify_type type) + { + int ret = 0; + +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h +index f3f7f370807f0..83c4b9856e171 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h +@@ -713,6 +713,8 @@ void hns3_set_vector_coalesce_tx_ql(struct hns3_enet_tqp_vector *tqp_vector, + u32 ql_value); + + void hns3_request_update_promisc_mode(struct hnae3_handle *handle); ++int hns3_reset_notify(struct hnae3_handle *handle, ++ enum hnae3_reset_notify_type type); + + #ifdef CONFIG_HNS3_DCB + void hns3_dcbnl_setup(struct hnae3_handle *handle); +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +index b01ce4fd6bc43..53f6cb3b43664 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +@@ -1726,6 +1726,7 @@ static int hns3_get_tunable(struct net_device *netdev, + void *data) + { + struct hns3_nic_priv *priv = netdev_priv(netdev); ++ struct hnae3_handle *h = priv->ae_handle; + int ret = 0; + + switch (tuna->id) { +@@ -1736,6 +1737,9 @@ static int hns3_get_tunable(struct net_device *netdev, + case ETHTOOL_RX_COPYBREAK: + *(u32 *)data = priv->rx_copybreak; + break; ++ case ETHTOOL_TX_COPYBREAK_BUF_SIZE: ++ *(u32 *)data = h->kinfo.tx_spare_buf_size; ++ break; + default: + ret = -EOPNOTSUPP; + break; +@@ -1744,11 +1748,43 @@ static int hns3_get_tunable(struct net_device *netdev, + return ret; + } + ++static int hns3_set_tx_spare_buf_size(struct net_device *netdev, ++ u32 data) ++{ ++ struct hns3_nic_priv *priv = netdev_priv(netdev); ++ struct hnae3_handle *h = priv->ae_handle; ++ int ret; ++ ++ if (hns3_nic_resetting(netdev)) ++ return -EBUSY; ++ ++ h->kinfo.tx_spare_buf_size = data; ++ ++ ret = hns3_reset_notify(h, HNAE3_DOWN_CLIENT); ++ if (ret) ++ return ret; ++ ++ ret = hns3_reset_notify(h, HNAE3_UNINIT_CLIENT); ++ if (ret) ++ return ret; ++ ++ ret = hns3_reset_notify(h, HNAE3_INIT_CLIENT); ++ if (ret) ++ return ret; ++ ++ ret = hns3_reset_notify(h, HNAE3_UP_CLIENT); ++ if (ret) ++ hns3_reset_notify(h, HNAE3_UNINIT_CLIENT); ++ ++ return ret; ++} ++ + static int hns3_set_tunable(struct net_device *netdev, + const struct ethtool_tunable *tuna, + const void *data) + { + struct hns3_nic_priv *priv = netdev_priv(netdev); ++ u32 old_tx_spare_buf_size, new_tx_spare_buf_size; + struct hnae3_handle *h = priv->ae_handle; + int i, ret = 0; + +@@ -1766,6 +1802,26 @@ static int hns3_set_tunable(struct net_device *netdev, + for (i = h->kinfo.num_tqps; i < h->kinfo.num_tqps * 2; i++) + priv->ring[i].rx_copybreak = priv->rx_copybreak; + ++ break; ++ case ETHTOOL_TX_COPYBREAK_BUF_SIZE: ++ old_tx_spare_buf_size = h->kinfo.tx_spare_buf_size; ++ new_tx_spare_buf_size = *(u32 *)data; ++ ret = hns3_set_tx_spare_buf_size(netdev, new_tx_spare_buf_size); ++ if (ret) { ++ int ret1; ++ ++ netdev_warn(netdev, ++ "change tx spare buf size fail, revert to old value\n"); ++ ret1 = hns3_set_tx_spare_buf_size(netdev, ++ old_tx_spare_buf_size); ++ if (ret1) { ++ netdev_err(netdev, ++ "revert to old tx spare buf size fail\n"); ++ return ret1; ++ } ++ ++ return ret; ++ } + break; + default: + ret = -EOPNOTSUPP; +-- +2.51.0 + diff --git a/queue-5.15/net-hns3-fix-double-free-issue-for-tx-spare-buffer.patch b/queue-5.15/net-hns3-fix-double-free-issue-for-tx-spare-buffer.patch new file mode 100644 index 0000000000..90ad465ebf --- /dev/null +++ b/queue-5.15/net-hns3-fix-double-free-issue-for-tx-spare-buffer.patch @@ -0,0 +1,74 @@ +From 1efe6a96426e754022669e48f02c1cac52e9746a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 20:17:19 +0800 +Subject: net: hns3: fix double free issue for tx spare buffer + +From: Jian Shen + +[ Upstream commit 6d2f142b1e4b203387a92519d9d2e34752a79dbb ] + +In hns3_set_ringparam(), a temporary copy (tmp_rings) of the ring structure +is created for rollback. However, the tx_spare pointer in the original +ring handle is incorrectly left pointing to the old backup memory. + +Later, if memory allocation fails in hns3_init_all_ring() during the setup, +the error path attempts to free all newly allocated rings. Since tx_spare +contains a stale (non-NULL) pointer from the backup, it is mistaken for +a newly allocated buffer and is erroneously freed, leading to a double-free +of the backup memory. + +The root cause is that the tx_spare field was not cleared after its value +was saved in tmp_rings, leaving a dangling pointer. + +Fix this by setting tx_spare to NULL in the original ring structure +when the creation of the new `tx_spare` fails. This ensures the +error cleanup path only frees genuinely newly allocated buffers. + +Fixes: 907676b130711 ("net: hns3: use tx bounce buffer for small packets") +Signed-off-by: Jian Shen +Signed-off-by: Jijie Shao +Reviewed-by: Jacob Keller +Link: https://patch.msgid.link/20260205121719.3285730-1-shaojijie@huawei.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +index ac5d7ea206bb2..309593ae2d073 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +@@ -1041,13 +1041,13 @@ static void hns3_init_tx_spare_buffer(struct hns3_enet_ring *ring) + int order; + + if (!alloc_size) +- return; ++ goto not_init; + + order = get_order(alloc_size); + if (order >= MAX_ORDER) { + if (net_ratelimit()) + dev_warn(ring_to_dev(ring), "failed to allocate tx spare buffer, exceed to max order\n"); +- return; ++ goto not_init; + } + + tx_spare = devm_kzalloc(ring_to_dev(ring), sizeof(*tx_spare), +@@ -1084,6 +1084,13 @@ static void hns3_init_tx_spare_buffer(struct hns3_enet_ring *ring) + devm_kfree(ring_to_dev(ring), tx_spare); + devm_kzalloc_error: + ring->tqp->handle->kinfo.tx_spare_buf_size = 0; ++not_init: ++ /* When driver init or reset_init, the ring->tx_spare is always NULL; ++ * but when called from hns3_set_ringparam, it's usually not NULL, and ++ * will be restored if hns3_init_all_ring() failed. So it's safe to set ++ * ring->tx_spare to NULL here. ++ */ ++ ring->tx_spare = NULL; + } + + /* Use hns3_tx_spare_space() to make sure there is enough buffer +-- +2.51.0 + diff --git a/queue-5.15/net-hns3-fix-ethtool-tx-copybreak-buf-size-indicatin.patch b/queue-5.15/net-hns3-fix-ethtool-tx-copybreak-buf-size-indicatin.patch new file mode 100644 index 0000000000..3efa0f1761 --- /dev/null +++ b/queue-5.15/net-hns3-fix-ethtool-tx-copybreak-buf-size-indicatin.patch @@ -0,0 +1,111 @@ +From d20857b4e1f066d01bdf5c597dd6ef27fd506996 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 26 Mar 2022 17:51:00 +0800 +Subject: net: hns3: fix ethtool tx copybreak buf size indicating not aligned + issue + +From: Hao Chen + +[ Upstream commit 8778372118023e2258612c03573c47efef41d755 ] + +When use ethtoool set tx copybreak buf size to a large value +which causes order exceeding 10 or memory is not enough, +it causes allocating tx copybreak buffer failed and print +"the active tx spare buf is 0, not enabled tx spare buffer", +however, use --get-tunable parameter query tx copybreak buf +size and it indicates setting value not 0. + +So, it's necessary to change the print value from setting +value to 0. + +Set kinfo.tx_spare_buf_size to 0 when set tx copybreak buf size failed. + +Fixes: e445f08af2b1 ("net: hns3: add support to set/get tx copybreak buf size via ethtool for hns3 driver") +Signed-off-by: Hao Chen +Signed-off-by: Guangbin Huang +Signed-off-by: David S. Miller +Stable-dep-of: 6d2f142b1e4b ("net: hns3: fix double free issue for tx spare buffer") +Signed-off-by: Sasha Levin +--- + .../net/ethernet/hisilicon/hns3/hns3_enet.c | 20 +++++++++++-------- + .../ethernet/hisilicon/hns3/hns3_ethtool.c | 3 ++- + 2 files changed, 14 insertions(+), 9 deletions(-) + +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +index 5d410eacce081..b907d693631c2 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +@@ -1034,13 +1034,12 @@ static bool hns3_can_use_tx_sgl(struct hns3_enet_ring *ring, + + static void hns3_init_tx_spare_buffer(struct hns3_enet_ring *ring) + { ++ u32 alloc_size = ring->tqp->handle->kinfo.tx_spare_buf_size; + struct hns3_tx_spare *tx_spare; + struct page *page; +- u32 alloc_size; + dma_addr_t dma; + int order; + +- alloc_size = ring->tqp->handle->kinfo.tx_spare_buf_size; + if (!alloc_size) + return; + +@@ -1050,30 +1049,35 @@ static void hns3_init_tx_spare_buffer(struct hns3_enet_ring *ring) + if (!tx_spare) { + /* The driver still work without the tx spare buffer */ + dev_warn(ring_to_dev(ring), "failed to allocate hns3_tx_spare\n"); +- return; ++ goto devm_kzalloc_error; + } + + page = alloc_pages_node(dev_to_node(ring_to_dev(ring)), + GFP_KERNEL, order); + if (!page) { + dev_warn(ring_to_dev(ring), "failed to allocate tx spare pages\n"); +- devm_kfree(ring_to_dev(ring), tx_spare); +- return; ++ goto alloc_pages_error; + } + + dma = dma_map_page(ring_to_dev(ring), page, 0, + PAGE_SIZE << order, DMA_TO_DEVICE); + if (dma_mapping_error(ring_to_dev(ring), dma)) { + dev_warn(ring_to_dev(ring), "failed to map pages for tx spare\n"); +- put_page(page); +- devm_kfree(ring_to_dev(ring), tx_spare); +- return; ++ goto dma_mapping_error; + } + + tx_spare->dma = dma; + tx_spare->buf = page_address(page); + tx_spare->len = PAGE_SIZE << order; + ring->tx_spare = tx_spare; ++ return; ++ ++dma_mapping_error: ++ put_page(page); ++alloc_pages_error: ++ devm_kfree(ring_to_dev(ring), tx_spare); ++devm_kzalloc_error: ++ ring->tqp->handle->kinfo.tx_spare_buf_size = 0; + } + + /* Use hns3_tx_spare_space() to make sure there is enough buffer +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +index 53f6cb3b43664..4c8f4ff66f0ec 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +@@ -1807,7 +1807,8 @@ static int hns3_set_tunable(struct net_device *netdev, + old_tx_spare_buf_size = h->kinfo.tx_spare_buf_size; + new_tx_spare_buf_size = *(u32 *)data; + ret = hns3_set_tx_spare_buf_size(netdev, new_tx_spare_buf_size); +- if (ret) { ++ if (ret || ++ (!priv->ring->tx_spare && new_tx_spare_buf_size != 0)) { + int ret1; + + netdev_warn(netdev, +-- +2.51.0 + diff --git a/queue-5.15/net-hns3-remove-the-way-to-set-tx-spare-buf-via-modu.patch b/queue-5.15/net-hns3-remove-the-way-to-set-tx-spare-buf-via-modu.patch new file mode 100644 index 0000000000..887ba7e586 --- /dev/null +++ b/queue-5.15/net-hns3-remove-the-way-to-set-tx-spare-buf-via-modu.patch @@ -0,0 +1,51 @@ +From d8a606961aaccef823541c056262cd462d0abe09 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Nov 2021 20:12:45 +0800 +Subject: net: hns3: remove the way to set tx spare buf via module parameter + +From: Hao Chen + +[ Upstream commit e175eb5fb05462398452e31df5019d780badf45d ] + +The way to set tx spare buf via module parameter is not such +convenient as the way to set it via ethtool. + +So,remove the way to set tx spare buf via module parameter. + +Signed-off-by: Hao Chen +Signed-off-by: Guangbin Huang +Signed-off-by: David S. Miller +Stable-dep-of: 6d2f142b1e4b ("net: hns3: fix double free issue for tx spare buffer") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +index 84c724df2e405..5d410eacce081 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +@@ -53,10 +53,6 @@ static int debug = -1; + module_param(debug, int, 0); + MODULE_PARM_DESC(debug, " Network interface message level setting"); + +-static unsigned int tx_spare_buf_size; +-module_param(tx_spare_buf_size, uint, 0400); +-MODULE_PARM_DESC(tx_spare_buf_size, "Size used to allocate tx spare buffer"); +- + static unsigned int tx_sgl = 1; + module_param(tx_sgl, uint, 0600); + MODULE_PARM_DESC(tx_sgl, "Minimum number of frags when using dma_map_sg() to optimize the IOMMU mapping"); +@@ -1044,8 +1040,7 @@ static void hns3_init_tx_spare_buffer(struct hns3_enet_ring *ring) + dma_addr_t dma; + int order; + +- alloc_size = tx_spare_buf_size ? tx_spare_buf_size : +- ring->tqp->handle->kinfo.tx_spare_buf_size; ++ alloc_size = ring->tqp->handle->kinfo.tx_spare_buf_size; + if (!alloc_size) + return; + +-- +2.51.0 + diff --git a/queue-5.15/netfilter-nf_conncount-fix-tracking-of-connections-f.patch b/queue-5.15/netfilter-nf_conncount-fix-tracking-of-connections-f.patch new file mode 100644 index 0000000000..a9a143c9aa --- /dev/null +++ b/queue-5.15/netfilter-nf_conncount-fix-tracking-of-connections-f.patch @@ -0,0 +1,69 @@ +From 50b1fdf116485c29186e042b6cdb7b6131664ad7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 21:35:46 +0100 +Subject: netfilter: nf_conncount: fix tracking of connections from localhost + +From: Fernando Fernandez Mancera + +[ Upstream commit de8a70cefcb26cdceaafdc5ac144712681419c29 ] + +Since commit be102eb6a0e7 ("netfilter: nf_conncount: rework API to use +sk_buff directly"), we skip the adding and trigger a GC when the ct is +confirmed. For connections originated from local to local it doesn't +work because the connection is confirmed on POSTROUTING, therefore +tracking on the INPUT hook is always skipped. + +In order to fix this, we check whether skb input ifindex is set to +loopback ifindex. If it is then we fallback on a GC plus track operation +skipping the optimization. This fallback is necessary to avoid +duplicated tracking of a packet train e.g 10 UDP datagrams sent on a +burst when initiating the connection. + +Tested with xt_connlimit/nft_connlimit and OVS limit and with a HTTP +server and iperf3 on UDP mode. + +Fixes: be102eb6a0e7 ("netfilter: nf_conncount: rework API to use sk_buff directly") +Reported-by: Michal Slabihoudek +Closes: https://lore.kernel.org/netfilter/6989BD9F-8C24-4397-9AD7-4613B28BF0DB@gooddata.com/ +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_conncount.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +diff --git a/net/netfilter/nf_conncount.c b/net/netfilter/nf_conncount.c +index 47bdd8d121bb5..ae9ad439449fa 100644 +--- a/net/netfilter/nf_conncount.c ++++ b/net/netfilter/nf_conncount.c +@@ -179,14 +179,25 @@ static int __nf_conncount_add(struct net *net, + return -ENOENT; + + if (ct && nf_ct_is_confirmed(ct)) { +- err = -EEXIST; +- goto out_put; ++ /* local connections are confirmed in postrouting so confirmation ++ * might have happened before hitting connlimit ++ */ ++ if (skb->skb_iif != LOOPBACK_IFINDEX) { ++ err = -EEXIST; ++ goto out_put; ++ } ++ ++ /* this is likely a local connection, skip optimization to avoid ++ * adding duplicates from a 'packet train' ++ */ ++ goto check_connections; + } + + if ((u32)jiffies == list->last_gc && + (list->count - list->last_gc_count) < CONNCOUNT_GC_MAX_COLLECT) + goto add_new_node; + ++check_connections: + /* check the saved connections */ + list_for_each_entry_safe(conn, conn_n, &list->head, node) { + if (collect > CONNCOUNT_GC_MAX_COLLECT) +-- +2.51.0 + diff --git a/queue-5.15/netfilter-nf_conncount-increase-the-connection-clean.patch b/queue-5.15/netfilter-nf_conncount-increase-the-connection-clean.patch new file mode 100644 index 0000000000..8a898a9a2f --- /dev/null +++ b/queue-5.15/netfilter-nf_conncount-increase-the-connection-clean.patch @@ -0,0 +1,123 @@ +From 012d9394fcf1e18bb1648f0c0c0337b59819edf1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 17 Dec 2025 15:46:41 +0100 +Subject: netfilter: nf_conncount: increase the connection clean up limit to 64 + +From: Fernando Fernandez Mancera + +[ Upstream commit 21d033e472735ecec677f1ae46d6740b5e47a4f3 ] + +After the optimization to only perform one GC per jiffy, a new problem +was introduced. If more than 8 new connections are tracked per jiffy the +list won't be cleaned up fast enough possibly reaching the limit +wrongly. + +In order to prevent this issue, only skip the GC if it was already +triggered during the same jiffy and the increment is lower than the +clean up limit. In addition, increase the clean up limit to 64 +connections to avoid triggering GC too often and do more effective GCs. + +This has been tested using a HTTP server and several +performance tools while having nft_connlimit/xt_connlimit or OVS limit +configured. + +Output of slowhttptest + OVS limit at 52000 connections: + + slow HTTP test status on 340th second: + initializing: 0 + pending: 432 + connected: 51998 + error: 0 + closed: 0 + service available: YES + +Fixes: d265929930e2 ("netfilter: nf_conncount: reduce unnecessary GC") +Reported-by: Aleksandra Rukomoinikova +Closes: https://lore.kernel.org/netfilter/b2064e7b-0776-4e14-adb6-c68080987471@k2.cloud/ +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + include/net/netfilter/nf_conntrack_count.h | 1 + + net/netfilter/nf_conncount.c | 15 ++++++++++----- + 2 files changed, 11 insertions(+), 5 deletions(-) + +diff --git a/include/net/netfilter/nf_conntrack_count.h b/include/net/netfilter/nf_conntrack_count.h +index 115bb7e572f7d..bf22661925b81 100644 +--- a/include/net/netfilter/nf_conntrack_count.h ++++ b/include/net/netfilter/nf_conntrack_count.h +@@ -13,6 +13,7 @@ struct nf_conncount_list { + u32 last_gc; /* jiffies at most recent gc */ + struct list_head head; /* connections with the same filtering key */ + unsigned int count; /* length of list */ ++ unsigned int last_gc_count; /* length of list at most recent gc */ + }; + + struct nf_conncount_data *nf_conncount_init(struct net *net, unsigned int family, +diff --git a/net/netfilter/nf_conncount.c b/net/netfilter/nf_conncount.c +index 70e9662fe1777..47bdd8d121bb5 100644 +--- a/net/netfilter/nf_conncount.c ++++ b/net/netfilter/nf_conncount.c +@@ -34,8 +34,9 @@ + + #define CONNCOUNT_SLOTS 256U + +-#define CONNCOUNT_GC_MAX_NODES 8 +-#define MAX_KEYLEN 5 ++#define CONNCOUNT_GC_MAX_NODES 8 ++#define CONNCOUNT_GC_MAX_COLLECT 64 ++#define MAX_KEYLEN 5 + + /* we will save the tuples of all connections we care about */ + struct nf_conncount_tuple { +@@ -182,12 +183,13 @@ static int __nf_conncount_add(struct net *net, + goto out_put; + } + +- if ((u32)jiffies == list->last_gc) ++ if ((u32)jiffies == list->last_gc && ++ (list->count - list->last_gc_count) < CONNCOUNT_GC_MAX_COLLECT) + goto add_new_node; + + /* check the saved connections */ + list_for_each_entry_safe(conn, conn_n, &list->head, node) { +- if (collect > CONNCOUNT_GC_MAX_NODES) ++ if (collect > CONNCOUNT_GC_MAX_COLLECT) + break; + + found = find_or_evict(net, list, conn); +@@ -230,6 +232,7 @@ static int __nf_conncount_add(struct net *net, + nf_ct_put(found_ct); + } + list->last_gc = (u32)jiffies; ++ list->last_gc_count = list->count; + + add_new_node: + if (WARN_ON_ONCE(list->count > INT_MAX)) { +@@ -277,6 +280,7 @@ void nf_conncount_list_init(struct nf_conncount_list *list) + spin_lock_init(&list->list_lock); + INIT_LIST_HEAD(&list->head); + list->count = 0; ++ list->last_gc_count = 0; + list->last_gc = (u32)jiffies; + } + EXPORT_SYMBOL_GPL(nf_conncount_list_init); +@@ -316,13 +320,14 @@ static bool __nf_conncount_gc_list(struct net *net, + } + + nf_ct_put(found_ct); +- if (collected > CONNCOUNT_GC_MAX_NODES) ++ if (collected > CONNCOUNT_GC_MAX_COLLECT) + break; + } + + if (!list->count) + ret = true; + list->last_gc = (u32)jiffies; ++ list->last_gc_count = list->count; + + return ret; + } +-- +2.51.0 + diff --git a/queue-5.15/netfilter-nf_conncount-make-nf_conncount_gc_list-to-.patch b/queue-5.15/netfilter-nf_conncount-make-nf_conncount_gc_list-to-.patch new file mode 100644 index 0000000000..d5bc3991b1 --- /dev/null +++ b/queue-5.15/netfilter-nf_conncount-make-nf_conncount_gc_list-to-.patch @@ -0,0 +1,93 @@ +From 7ffc9ba7f7bf9db5fe5ce55995cc91a663825729 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 21 Nov 2025 01:14:31 +0100 +Subject: netfilter: nf_conncount: make nf_conncount_gc_list() to disable BH + +From: Fernando Fernandez Mancera + +[ Upstream commit c0362b5748282e22fa1592a8d3474f726ad964c2 ] + +For convenience when performing GC over the connection list, make +nf_conncount_gc_list() to disable BH. This unifies the behavior with +nf_conncount_add() and nf_conncount_count(). + +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: 21d033e47273 ("netfilter: nf_conncount: increase the connection clean up limit to 64") +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_conncount.c | 24 +++++++++++++++++------- + net/netfilter/nft_connlimit.c | 7 +------ + 2 files changed, 18 insertions(+), 13 deletions(-) + +diff --git a/net/netfilter/nf_conncount.c b/net/netfilter/nf_conncount.c +index a2c5a7ba0c6fc..70e9662fe1777 100644 +--- a/net/netfilter/nf_conncount.c ++++ b/net/netfilter/nf_conncount.c +@@ -282,8 +282,8 @@ void nf_conncount_list_init(struct nf_conncount_list *list) + EXPORT_SYMBOL_GPL(nf_conncount_list_init); + + /* Return true if the list is empty. Must be called with BH disabled. */ +-bool nf_conncount_gc_list(struct net *net, +- struct nf_conncount_list *list) ++static bool __nf_conncount_gc_list(struct net *net, ++ struct nf_conncount_list *list) + { + const struct nf_conntrack_tuple_hash *found; + struct nf_conncount_tuple *conn, *conn_n; +@@ -295,10 +295,6 @@ bool nf_conncount_gc_list(struct net *net, + if ((u32)jiffies == READ_ONCE(list->last_gc)) + return false; + +- /* don't bother if other cpu is already doing GC */ +- if (!spin_trylock(&list->list_lock)) +- return false; +- + list_for_each_entry_safe(conn, conn_n, &list->head, node) { + found = find_or_evict(net, list, conn); + if (IS_ERR(found)) { +@@ -327,7 +323,21 @@ bool nf_conncount_gc_list(struct net *net, + if (!list->count) + ret = true; + list->last_gc = (u32)jiffies; +- spin_unlock(&list->list_lock); ++ ++ return ret; ++} ++ ++bool nf_conncount_gc_list(struct net *net, ++ struct nf_conncount_list *list) ++{ ++ bool ret; ++ ++ /* don't bother if other cpu is already doing GC */ ++ if (!spin_trylock_bh(&list->list_lock)) ++ return false; ++ ++ ret = __nf_conncount_gc_list(net, list); ++ spin_unlock_bh(&list->list_lock); + + return ret; + } +diff --git a/net/netfilter/nft_connlimit.c b/net/netfilter/nft_connlimit.c +index ef5099441a822..e2ddb55968531 100644 +--- a/net/netfilter/nft_connlimit.c ++++ b/net/netfilter/nft_connlimit.c +@@ -231,13 +231,8 @@ static void nft_connlimit_destroy_clone(const struct nft_ctx *ctx, + static bool nft_connlimit_gc(struct net *net, const struct nft_expr *expr) + { + struct nft_connlimit *priv = nft_expr_priv(expr); +- bool ret; + +- local_bh_disable(); +- ret = nf_conncount_gc_list(net, priv->list); +- local_bh_enable(); +- +- return ret; ++ return nf_conncount_gc_list(net, priv->list); + } + + static struct nft_expr_type nft_connlimit_type; +-- +2.51.0 + diff --git a/queue-5.15/netfilter-nft_set_hash-fix-get-operation-on-big-endi.patch b/queue-5.15/netfilter-nft_set_hash-fix-get-operation-on-big-endi.patch new file mode 100644 index 0000000000..287ed709a8 --- /dev/null +++ b/queue-5.15/netfilter-nft_set_hash-fix-get-operation-on-big-endi.patch @@ -0,0 +1,57 @@ +From ff54af43af3d3b23a02baa3c64c22b90b9bc594d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 20:13:45 +0100 +Subject: netfilter: nft_set_hash: fix get operation on big endian + +From: Florian Westphal + +[ Upstream commit 2f635adbe2642d398a0be3ab245accd2987be0c3 ] + +tests/shell/testcases/packetpath/set_match_nomatch_hash_fast +fails on big endian with: + +Error: Could not process rule: No such file or directory +reset element ip test s { 244.147.90.126 } +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Fatal: Cannot fetch element "244.147.90.126" + +... because the wrong bucket is searched, jhash() and jhash1_word are +not interchangeable on big endian. + +Fixes: 3b02b0adc242 ("netfilter: nft_set_hash: fix lookups with fixed size hash on big endian") +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_set_hash.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/net/netfilter/nft_set_hash.c b/net/netfilter/nft_set_hash.c +index a592cca7a61f9..9ea4a09903186 100644 +--- a/net/netfilter/nft_set_hash.c ++++ b/net/netfilter/nft_set_hash.c +@@ -527,15 +527,20 @@ bool nft_hash_lookup(const struct net *net, const struct nft_set *set, + static void *nft_hash_get(const struct net *net, const struct nft_set *set, + const struct nft_set_elem *elem, unsigned int flags) + { ++ const u32 *key = (const u32 *)&elem->key.val; + struct nft_hash *priv = nft_set_priv(set); + u8 genmask = nft_genmask_cur(net); + struct nft_hash_elem *he; + u32 hash; + +- hash = jhash(elem->key.val.data, set->klen, priv->seed); ++ if (set->klen == 4) ++ hash = jhash_1word(*key, priv->seed); ++ else ++ hash = jhash(key, set->klen, priv->seed); ++ + hash = reciprocal_scale(hash, priv->buckets); + hlist_for_each_entry_rcu(he, &priv->table[hash], node) { +- if (!memcmp(nft_set_ext_key(&he->ext), elem->key.val.data, set->klen) && ++ if (!memcmp(nft_set_ext_key(&he->ext), key, set->klen) && + nft_set_elem_active(&he->ext, genmask)) + return he; + } +-- +2.51.0 + diff --git a/queue-5.15/netfilter-nft_set_rbtree-check-for-partial-overlaps-.patch b/queue-5.15/netfilter-nft_set_rbtree-check-for-partial-overlaps-.patch new file mode 100644 index 0000000000..d7adb759be --- /dev/null +++ b/queue-5.15/netfilter-nft_set_rbtree-check-for-partial-overlaps-.patch @@ -0,0 +1,90 @@ +From 02245feb76b9be4f653d8c85df8b16fd3b59717b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 13:33:44 +0100 +Subject: netfilter: nft_set_rbtree: check for partial overlaps in anonymous + sets + +From: Pablo Neira Ayuso + +[ Upstream commit 4780ec142cbb24b794129d3080eee5cac2943ffc ] + +Userspace provides an optimized representation in case intervals are +adjacent, where the end element is omitted. + +The existing partial overlap detection logic skips anonymous set checks +on start elements for this reason. + +However, it is possible to add intervals that overlap to this anonymous +where two start elements with the same, eg. A-B, A-C where C < B. + + start end + A B + start end + A C + +Restore the check on overlapping start elements to report an overlap. + +Fixes: c9e6978e2725 ("netfilter: nft_set_rbtree: Switch to node list walk for overlap detection") +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_set_rbtree.c | 30 +++++++++++++++++++++++++----- + 1 file changed, 25 insertions(+), 5 deletions(-) + +diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c +index 021d9e76129a5..426becaad1b94 100644 +--- a/net/netfilter/nft_set_rbtree.c ++++ b/net/netfilter/nft_set_rbtree.c +@@ -305,11 +305,23 @@ static bool nft_rbtree_update_first(const struct nft_set *set, + return false; + } + ++/* Only for anonymous sets which do not allow updates, all element are active. */ ++static struct nft_rbtree_elem *nft_rbtree_prev_active(struct nft_rbtree_elem *rbe) ++{ ++ struct rb_node *node; ++ ++ node = rb_prev(&rbe->node); ++ if (!node) ++ return NULL; ++ ++ return rb_entry(node, struct nft_rbtree_elem, node); ++} ++ + static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set, + struct nft_rbtree_elem *new, + struct nft_set_ext **ext) + { +- struct nft_rbtree_elem *rbe, *rbe_le = NULL, *rbe_ge = NULL; ++ struct nft_rbtree_elem *rbe, *rbe_le = NULL, *rbe_ge = NULL, *rbe_prev; + struct rb_node *node, *next, *parent, **p, *first = NULL; + struct nft_rbtree *priv = nft_set_priv(set); + u8 cur_genmask = nft_genmask_cur(net); +@@ -441,11 +453,19 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set, + /* - new start element with existing closest, less or equal key value + * being a start element: partial overlap, reported as -ENOTEMPTY. + * Anonymous sets allow for two consecutive start element since they +- * are constant, skip them to avoid bogus overlap reports. ++ * are constant, but validate that this new start element does not ++ * sit in between an existing start and end elements: partial overlap, ++ * reported as -ENOTEMPTY. + */ +- if (!nft_set_is_anonymous(set) && rbe_le && +- nft_rbtree_interval_start(rbe_le) && nft_rbtree_interval_start(new)) +- return -ENOTEMPTY; ++ if (rbe_le && ++ nft_rbtree_interval_start(rbe_le) && nft_rbtree_interval_start(new)) { ++ if (!nft_set_is_anonymous(set)) ++ return -ENOTEMPTY; ++ ++ rbe_prev = nft_rbtree_prev_active(rbe_le); ++ if (rbe_prev && nft_rbtree_interval_end(rbe_prev)) ++ return -ENOTEMPTY; ++ } + + /* - new end element with existing closest, less or equal key value + * being a end element: partial overlap, reported as -ENOTEMPTY. +-- +2.51.0 + diff --git a/queue-5.15/nfc-hci-shdlc-stop-timers-and-work-before-freeing-co.patch b/queue-5.15/nfc-hci-shdlc-stop-timers-and-work-before-freeing-co.patch new file mode 100644 index 0000000000..b42f3432b6 --- /dev/null +++ b/queue-5.15/nfc-hci-shdlc-stop-timers-and-work-before-freeing-co.patch @@ -0,0 +1,52 @@ +From 631210632b48a7a8b1d076cc5fb5fabea0cbeaea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 14:31:57 +0300 +Subject: nfc: hci: shdlc: Stop timers and work before freeing context + +From: Votokina Victoria + +[ Upstream commit c9efde1e537baed7648a94022b43836a348a074f ] + +llc_shdlc_deinit() purges SHDLC skb queues and frees the llc_shdlc +structure while its timers and state machine work may still be active. + +Timer callbacks can schedule sm_work, and sm_work accesses SHDLC state +and the skb queues. If teardown happens in parallel with a queued/running +work item, it can lead to UAF and other shutdown races. + +Stop all SHDLC timers and cancel sm_work synchronously before purging the +queues and freeing the context. + +Found by Linux Verification Center (linuxtesting.org) with SVACE. + +Fixes: 4a61cd6687fc ("NFC: Add an shdlc llc module to llc core") +Signed-off-by: Votokina Victoria +Link: https://patch.msgid.link/20260203113158.2008723-1-Victoria.Votokina@kaspersky.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/nfc/hci/llc_shdlc.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/net/nfc/hci/llc_shdlc.c b/net/nfc/hci/llc_shdlc.c +index aef750d7787c8..948cf4d210bde 100644 +--- a/net/nfc/hci/llc_shdlc.c ++++ b/net/nfc/hci/llc_shdlc.c +@@ -779,6 +779,14 @@ static void llc_shdlc_deinit(struct nfc_llc *llc) + { + struct llc_shdlc *shdlc = nfc_llc_get_data(llc); + ++ timer_shutdown_sync(&shdlc->connect_timer); ++ timer_shutdown_sync(&shdlc->t1_timer); ++ timer_shutdown_sync(&shdlc->t2_timer); ++ shdlc->t1_active = false; ++ shdlc->t2_active = false; ++ ++ cancel_work_sync(&shdlc->sm_work); ++ + skb_queue_purge(&shdlc->rcv_q); + skb_queue_purge(&shdlc->send_q); + skb_queue_purge(&shdlc->ack_pending_q); +-- +2.51.0 + diff --git a/queue-5.15/nfsd-never-defer-requests-during-idmap-lookup.patch b/queue-5.15/nfsd-never-defer-requests-during-idmap-lookup.patch new file mode 100644 index 0000000000..a66e0cf993 --- /dev/null +++ b/queue-5.15/nfsd-never-defer-requests-during-idmap-lookup.patch @@ -0,0 +1,152 @@ +From bc956ca340ebfd0f8a01c141caf07137eb7b1af8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 22 Dec 2025 14:30:04 -0500 +Subject: nfsd: never defer requests during idmap lookup + +From: Anthony Iliopoulos + +[ Upstream commit f9c206cdc4266caad6a9a7f46341420a10f03ccb ] + +During v4 request compound arg decoding, some ops (e.g. SETATTR) +can trigger idmap lookup upcalls. When those upcall responses get +delayed beyond the allowed time limit, cache_check() will mark the +request for deferral and cause it to be dropped. + +This prevents nfs4svc_encode_compoundres from being executed, and +thus the session slot flag NFSD4_SLOT_INUSE never gets cleared. +Subsequent client requests will fail with NFSERR_JUKEBOX, given +that the slot will be marked as in-use, making the SEQUENCE op +fail. + +Fix this by making sure that the RQ_USEDEFERRAL flag is always +clear during nfs4svc_decode_compoundargs(), since no v4 request +should ever be deferred. + +Fixes: 2f425878b6a7 ("nfsd: don't use the deferral service, return NFS4ERR_DELAY") +Signed-off-by: Anthony Iliopoulos +Reviewed-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4idmap.c | 48 +++++++++++++++++++++++++++++++++++++++------ + fs/nfsd/nfs4proc.c | 2 -- + fs/nfsd/nfs4xdr.c | 16 +++++++++++++++ + 3 files changed, 58 insertions(+), 8 deletions(-) + +diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c +index 717e400b16b86..21e5b4c990ef3 100644 +--- a/fs/nfsd/nfs4idmap.c ++++ b/fs/nfsd/nfs4idmap.c +@@ -643,13 +643,31 @@ static __be32 encode_name_from_id(struct xdr_stream *xdr, + return idmap_id_to_name(xdr, rqstp, type, id); + } + +-__be32 +-nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen, +- kuid_t *uid) ++/** ++ * nfsd_map_name_to_uid - Map user@domain to local UID ++ * @rqstp: RPC execution context ++ * @name: user@domain name to be mapped ++ * @namelen: length of name, in bytes ++ * @uid: OUT: mapped local UID value ++ * ++ * Returns nfs_ok on success or an NFSv4 status code on failure. ++ */ ++__be32 nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, ++ size_t namelen, kuid_t *uid) + { + __be32 status; + u32 id = -1; + ++ /* ++ * The idmap lookup below triggers an upcall that invokes ++ * cache_check(). RQ_USEDEFERRAL must be clear to prevent ++ * cache_check() from setting RQ_DROPME via svc_defer(). ++ * NFSv4 servers are not permitted to drop requests. Also ++ * RQ_DROPME will force NFSv4.1 session slot processing to ++ * be skipped. ++ */ ++ WARN_ON_ONCE(test_bit(RQ_USEDEFERRAL, &rqstp->rq_flags)); ++ + if (name == NULL || namelen == 0) + return nfserr_inval; + +@@ -660,13 +678,31 @@ nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen, + return status; + } + +-__be32 +-nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, size_t namelen, +- kgid_t *gid) ++/** ++ * nfsd_map_name_to_gid - Map user@domain to local GID ++ * @rqstp: RPC execution context ++ * @name: user@domain name to be mapped ++ * @namelen: length of name, in bytes ++ * @gid: OUT: mapped local GID value ++ * ++ * Returns nfs_ok on success or an NFSv4 status code on failure. ++ */ ++__be32 nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, ++ size_t namelen, kgid_t *gid) + { + __be32 status; + u32 id = -1; + ++ /* ++ * The idmap lookup below triggers an upcall that invokes ++ * cache_check(). RQ_USEDEFERRAL must be clear to prevent ++ * cache_check() from setting RQ_DROPME via svc_defer(). ++ * NFSv4 servers are not permitted to drop requests. Also ++ * RQ_DROPME will force NFSv4.1 session slot processing to ++ * be skipped. ++ */ ++ WARN_ON_ONCE(test_bit(RQ_USEDEFERRAL, &rqstp->rq_flags)); ++ + if (name == NULL || namelen == 0) + return nfserr_inval; + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 2d6e88f3370bf..7a85817fa5bfe 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -2717,8 +2717,6 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) + BUG_ON(cstate->replay_owner); + out: + cstate->status = status; +- /* Reset deferral mechanism for RPC deferrals */ +- set_bit(RQ_USEDEFERRAL, &rqstp->rq_flags); + return rpc_success; + } + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 9e25079804732..46a7fd731ba0a 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -5500,6 +5500,22 @@ nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + args->ops = args->iops; + args->rqstp = rqstp; + ++ /* ++ * NFSv4 operation decoders can invoke svc cache lookups ++ * that trigger svc_defer() when RQ_USEDEFERRAL is set, ++ * setting RQ_DROPME. This creates two problems: ++ * ++ * 1. Non-idempotency: Compounds make it too hard to avoid ++ * problems if a request is deferred and replayed. ++ * ++ * 2. Session slot leakage (NFSv4.1+): If RQ_DROPME is set ++ * during decode but SEQUENCE executes successfully, the ++ * session slot will be marked INUSE. The request is then ++ * dropped before encoding, so the slot is never released, ++ * rendering it permanently unusable by the client. ++ */ ++ clear_bit(RQ_USEDEFERRAL, &rqstp->rq_flags); ++ + return nfsd4_decode_compound(args); + } + +-- +2.51.0 + diff --git a/queue-5.15/nvdimm-virtio_pmem-serialize-flush-requests.patch b/queue-5.15/nvdimm-virtio_pmem-serialize-flush-requests.patch new file mode 100644 index 0000000000..652906e3b2 --- /dev/null +++ b/queue-5.15/nvdimm-virtio_pmem-serialize-flush-requests.patch @@ -0,0 +1,98 @@ +From ea9abb1c4d1d1730d2cae69e73e52eb1097e2c30 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 10:13:51 +0800 +Subject: nvdimm: virtio_pmem: serialize flush requests + +From: Li Chen + +[ Upstream commit a9ba6733c7f1096c4506bf4e34a546e07242df74 ] + +Under heavy concurrent flush traffic, virtio-pmem can overflow its request +virtqueue (req_vq): virtqueue_add_sgs() starts returning -ENOSPC and the +driver logs "no free slots in the virtqueue". Shortly after that the +device enters VIRTIO_CONFIG_S_NEEDS_RESET and flush requests fail with +"virtio pmem device needs a reset". + +Serialize virtio_pmem_flush() with a per-device mutex so only one flush +request is in-flight at a time. This prevents req_vq descriptor overflow +under high concurrency. + +Reproducer (guest with virtio-pmem): + - mkfs.ext4 -F /dev/pmem0 + - mount -t ext4 -o dax,noatime /dev/pmem0 /mnt/bench + - fio: ioengine=io_uring rw=randwrite bs=4k iodepth=64 numjobs=64 + direct=1 fsync=1 runtime=30s time_based=1 + - dmesg: "no free slots in the virtqueue" + "virtio pmem device needs a reset" + +Fixes: 6e84200c0a29 ("virtio-pmem: Add virtio pmem driver") +Signed-off-by: Li Chen +Acked-by: Pankaj Gupta +Acked-by: Michael S. Tsirkin +Link: https://patch.msgid.link/20260203021353.121091-1-me@linux.beauty +Signed-off-by: Ira Weiny +Signed-off-by: Sasha Levin +--- + drivers/nvdimm/nd_virtio.c | 3 ++- + drivers/nvdimm/virtio_pmem.c | 1 + + drivers/nvdimm/virtio_pmem.h | 4 ++++ + 3 files changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/nvdimm/nd_virtio.c b/drivers/nvdimm/nd_virtio.c +index 41e97c6567cf9..204d1a05f8e32 100644 +--- a/drivers/nvdimm/nd_virtio.c ++++ b/drivers/nvdimm/nd_virtio.c +@@ -44,6 +44,8 @@ static int virtio_pmem_flush(struct nd_region *nd_region) + unsigned long flags; + int err, err1; + ++ guard(mutex)(&vpmem->flush_lock); ++ + /* + * Don't bother to submit the request to the device if the device is + * not activated. +@@ -53,7 +55,6 @@ static int virtio_pmem_flush(struct nd_region *nd_region) + return -EIO; + } + +- might_sleep(); + req_data = kmalloc(sizeof(*req_data), GFP_KERNEL); + if (!req_data) + return -ENOMEM; +diff --git a/drivers/nvdimm/virtio_pmem.c b/drivers/nvdimm/virtio_pmem.c +index 726c7354d4659..23ce47b67df50 100644 +--- a/drivers/nvdimm/virtio_pmem.c ++++ b/drivers/nvdimm/virtio_pmem.c +@@ -50,6 +50,7 @@ static int virtio_pmem_probe(struct virtio_device *vdev) + goto out_err; + } + ++ mutex_init(&vpmem->flush_lock); + vpmem->vdev = vdev; + vdev->priv = vpmem; + err = init_vq(vpmem); +diff --git a/drivers/nvdimm/virtio_pmem.h b/drivers/nvdimm/virtio_pmem.h +index 0dddefe594c46..f72cf17f9518f 100644 +--- a/drivers/nvdimm/virtio_pmem.h ++++ b/drivers/nvdimm/virtio_pmem.h +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + #include + + struct virtio_pmem_request { +@@ -35,6 +36,9 @@ struct virtio_pmem { + /* Virtio pmem request queue */ + struct virtqueue *req_vq; + ++ /* Serialize flush requests to the device. */ ++ struct mutex flush_lock; ++ + /* nvdimm bus registers virtio pmem device */ + struct nvdimm_bus *nvdimm_bus; + struct nvdimm_bus_descriptor nd_desc; +-- +2.51.0 + diff --git a/queue-5.15/octeontx2-af-fix-pf-driver-crash-with-kexec-kernel-b.patch b/queue-5.15/octeontx2-af-fix-pf-driver-crash-with-kexec-kernel-b.patch new file mode 100644 index 0000000000..69640626ff --- /dev/null +++ b/queue-5.15/octeontx2-af-fix-pf-driver-crash-with-kexec-kernel-b.patch @@ -0,0 +1,62 @@ +From 223b7fd6f277b0566a5feff04d017930351fd881 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 10:37:01 +0530 +Subject: octeontx2-af: Fix PF driver crash with kexec kernel booting + +From: Anshumali Gaur + +[ Upstream commit 2d2d574309e3ae84ee794869a5da8b4c38753a94 ] + +During a kexec reboot the hardware is not power-cycled, so AF state from +the old kernel can persist into the new kernel. When AF and PF drivers +are built as modules, the PF driver may probe before AF reinitializes +the hardware. + +The PF driver treats the RVUM block revision as an indication that AF +initialization is complete. If this value is left uncleared at shutdown, +PF may incorrectly assume AF is ready and access stale hardware state, +leading to a crash. + +Clear the RVUM block revision during AF shutdown to avoid PF +mis-detecting AF readiness after kexec. + +Fixes: 54494aa5d1e6 ("octeontx2-af: Add Marvell OcteonTX2 RVU AF driver") +Signed-off-by: Anshumali Gaur +Reviewed-by: Jacob Keller +Link: https://patch.msgid.link/20260203050701.2616685-1-agaur@marvell.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/octeontx2/af/rvu.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +index 53f742a507dbe..187c66fb2458c 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +@@ -3331,11 +3331,22 @@ static void rvu_remove(struct pci_dev *pdev) + devm_kfree(&pdev->dev, rvu); + } + ++static void rvu_shutdown(struct pci_dev *pdev) ++{ ++ struct rvu *rvu = pci_get_drvdata(pdev); ++ ++ if (!rvu) ++ return; ++ ++ rvu_clear_rvum_blk_revid(rvu); ++} ++ + static struct pci_driver rvu_driver = { + .name = DRV_NAME, + .id_table = rvu_id_table, + .probe = rvu_probe, + .remove = rvu_remove, ++ .shutdown = rvu_shutdown, + }; + + static int __init rvu_init_module(void) +-- +2.51.0 + diff --git a/queue-5.15/octeontx2-pf-unregister-devlink-on-probe-failure.patch b/queue-5.15/octeontx2-pf-unregister-devlink-on-probe-failure.patch new file mode 100644 index 0000000000..04467c6bab --- /dev/null +++ b/queue-5.15/octeontx2-pf-unregister-devlink-on-probe-failure.patch @@ -0,0 +1,36 @@ +From 5c9a2a4fa35d4f4273304f724b177dfbd1c130e4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 23:56:45 +0530 +Subject: octeontx2-pf: Unregister devlink on probe failure + +From: Hariprasad Kelam + +[ Upstream commit 943f3b8bfbf297cf74392b50a7108ce1fe4cbd8c ] + +When probe fails after devlink registration, the missing devlink unregister +call causing a memory leak. + +Fixes: 2da489432747 ("octeontx2-pf: devlink params support to set mcam entry count") +Signed-off-by: Hariprasad Kelam +Link: https://patch.msgid.link/20260206182645.4032737-1-hkelam@marvell.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +index 5f093b34db698..803f40a2bdc19 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c ++++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +@@ -2777,6 +2777,7 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id) + return 0; + + err_pf_sriov_init: ++ otx2_unregister_dl(pf); + otx2_shutdown_tc(pf); + err_mcam_flow_del: + otx2_mcam_flow_del(pf); +-- +2.51.0 + diff --git a/queue-5.15/ovl-fix-uninit-value-in-ovl_fill_real.patch b/queue-5.15/ovl-fix-uninit-value-in-ovl_fill_real.patch new file mode 100644 index 0000000000..49a38b5b3b --- /dev/null +++ b/queue-5.15/ovl-fix-uninit-value-in-ovl_fill_real.patch @@ -0,0 +1,58 @@ +From 8d585f5cb07bcd5521108500d8d36582964e432f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 14:24:04 +0100 +Subject: ovl: Fix uninit-value in ovl_fill_real + +From: Qing Wang + +[ Upstream commit 1992330d90dd766fcf1730fd7bf2d6af65370ac4 ] + +Syzbot reported a KMSAN uninit-value issue in ovl_fill_real. + +This iusse's call chain is: +__do_sys_getdents64() + -> iterate_dir() + ... + -> ext4_readdir() + -> fscrypt_fname_alloc_buffer() // alloc + -> fscrypt_fname_disk_to_usr // write without tail '\0' + -> dir_emit() + -> ovl_fill_real() // read by strcmp() + +The string is used to store the decrypted directory entry name for an +encrypted inode. As shown in the call chain, fscrypt_fname_disk_to_usr() +write it without null-terminate. However, ovl_fill_real() uses strcmp() to +compare the name against "..", which assumes a null-terminated string and +may trigger a KMSAN uninit-value warning when the buffer tail contains +uninit data. + +Reported-by: syzbot+d130f98b2c265fae5297@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=d130f98b2c265fae5297 +Fixes: 4edb83bb1041 ("ovl: constant d_ino for non-merge dirs") +Signed-off-by: Qing Wang +Signed-off-by: Amir Goldstein +Link: https://patch.msgid.link/20260128132406.23768-2-amir73il@gmail.com +Acked-by: Miklos Szeredi +Reviewed-by: Eric Biggers +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/overlayfs/readdir.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c +index 9c580ef8cd6fc..666cc62578f65 100644 +--- a/fs/overlayfs/readdir.c ++++ b/fs/overlayfs/readdir.c +@@ -656,7 +656,7 @@ static int ovl_fill_real(struct dir_context *ctx, const char *name, + container_of(ctx, struct ovl_readdir_translate, ctx); + struct dir_context *orig_ctx = rdt->orig_ctx; + +- if (rdt->parent_ino && strcmp(name, "..") == 0) { ++ if (rdt->parent_ino && namelen == 2 && !strncmp(name, "..", 2)) { + ino = rdt->parent_ino; + } else if (rdt->cache) { + struct ovl_cache_entry *p; +-- +2.51.0 + diff --git a/queue-5.15/pci-do-not-attempt-to-set-exttag-for-vfs.patch b/queue-5.15/pci-do-not-attempt-to-set-exttag-for-vfs.patch new file mode 100644 index 0000000000..9dbccac444 --- /dev/null +++ b/queue-5.15/pci-do-not-attempt-to-set-exttag-for-vfs.patch @@ -0,0 +1,49 @@ +From 518458c33c57038aeadbfaa455a3dbd799e03c82 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 12 Nov 2025 10:54:40 +0100 +Subject: PCI: Do not attempt to set ExtTag for VFs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Håkon Bugge + +[ Upstream commit 73711730a1128d91ebca1a6994ceeb18f36cb0cd ] + +The bit for enabling extended tags is Reserved and Preserved (RsvdP) for +VFs, according to PCIe r7.0 section 7.5.3.4 table 7.21. Hence, bail out +early from pci_configure_extended_tags() if the device is a VF. + +Otherwise, we may see incorrect log messages such as: + + kernel: pci 0000:af:00.2: enabling Extended Tags + +(af:00.2 is a VF) + +Fixes: 60db3a4d8cc9 ("PCI: Enable PCIe Extended Tags if supported") +Signed-off-by: Håkon Bugge +Signed-off-by: Bjorn Helgaas +Reviewed-by: Zhu Yanjun +Link: https://patch.msgid.link/20251112095442.1913258-1-haakon.bugge@oracle.com +Signed-off-by: Sasha Levin +--- + drivers/pci/probe.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c +index a8d431731d22b..b54474ae17477 100644 +--- a/drivers/pci/probe.c ++++ b/drivers/pci/probe.c +@@ -2103,7 +2103,8 @@ int pci_configure_extended_tags(struct pci_dev *dev, void *ign) + u16 ctl; + int ret; + +- if (!pci_is_pcie(dev)) ++ /* PCI_EXP_DEVCTL_EXT_TAG is RsvdP in VFs */ ++ if (!pci_is_pcie(dev) || dev->is_virtfn) + return 0; + + ret = pcie_capability_read_dword(dev, PCI_EXP_DEVCAP, &cap); +-- +2.51.0 + diff --git a/queue-5.15/pci-initialize-rcb-from-pci_configure_device.patch b/queue-5.15/pci-initialize-rcb-from-pci_configure_device.patch new file mode 100644 index 0000000000..23a58cc39e --- /dev/null +++ b/queue-5.15/pci-initialize-rcb-from-pci_configure_device.patch @@ -0,0 +1,90 @@ +From d81e7d08d804dc7bb377e1a5c4ba3309986ce760 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 18:52:32 +0100 +Subject: PCI: Initialize RCB from pci_configure_device() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Håkon Bugge + +[ Upstream commit 1a6845aaa6de81f95959b380b45de8f10d6a8502 ] + +Commit e42010d8207f ("PCI: Set Read Completion Boundary to 128 iff Root +Port supports it (_HPX)") worked around a bogus _HPX type 2 record, which +caused program_hpx_type2() to set the RCB in an endpoint even though the +Root Port did not have the RCB bit set. + +e42010d8207f fixed that by setting the RCB in the endpoint only when it was +set in the Root Port. + +In retrospect, program_hpx_type2() is intended for AER-related settings, +and the RCB should be configured elsewhere so it doesn't depend on the +presence or contents of an _HPX record. + +Explicitly program the RCB from pci_configure_device() so it matches the +Root Port's RCB. The Root Port may not be visible to virtualized guests; +in that case, leave RCB alone. + +Fixes: e42010d8207f ("PCI: Set Read Completion Boundary to 128 iff Root Port supports it (_HPX)") +Signed-off-by: Håkon Bugge +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260129175237.727059-2-haakon.bugge@oracle.com +Signed-off-by: Sasha Levin +--- + drivers/pci/probe.c | 32 ++++++++++++++++++++++++++++++++ + 1 file changed, 32 insertions(+) + +diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c +index b54474ae17477..2180013a1a65a 100644 +--- a/drivers/pci/probe.c ++++ b/drivers/pci/probe.c +@@ -2278,6 +2278,37 @@ static void pci_configure_serr(struct pci_dev *dev) + } + } + ++static void pci_configure_rcb(struct pci_dev *dev) ++{ ++ struct pci_dev *rp; ++ u16 rp_lnkctl; ++ ++ /* ++ * Per PCIe r7.0, sec 7.5.3.7, RCB is only meaningful in Root Ports ++ * (where it is read-only), Endpoints, and Bridges. It may only be ++ * set for Endpoints and Bridges if it is set in the Root Port. For ++ * Endpoints, it is 'RsvdP' for Virtual Functions. ++ */ ++ if (!pci_is_pcie(dev) || ++ pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT || ++ pci_pcie_type(dev) == PCI_EXP_TYPE_UPSTREAM || ++ pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM || ++ pci_pcie_type(dev) == PCI_EXP_TYPE_RC_EC || ++ dev->is_virtfn) ++ return; ++ ++ /* Root Port often not visible to virtualized guests */ ++ rp = pcie_find_root_port(dev); ++ if (!rp) ++ return; ++ ++ pcie_capability_read_word(rp, PCI_EXP_LNKCTL, &rp_lnkctl); ++ pcie_capability_clear_and_set_word(dev, PCI_EXP_LNKCTL, ++ PCI_EXP_LNKCTL_RCB, ++ (rp_lnkctl & PCI_EXP_LNKCTL_RCB) ? ++ PCI_EXP_LNKCTL_RCB : 0); ++} ++ + static void pci_configure_device(struct pci_dev *dev) + { + pci_configure_mps(dev); +@@ -2286,6 +2317,7 @@ static void pci_configure_device(struct pci_dev *dev) + pci_configure_ltr(dev); + pci_configure_eetlp_prefix(dev); + pci_configure_serr(dev); ++ pci_configure_rcb(dev); + + pci_acpi_program_hp_params(dev); + } +-- +2.51.0 + diff --git a/queue-5.15/pci-mark-3ware-9650sa-root-port-extended-tags-as-bro.patch b/queue-5.15/pci-mark-3ware-9650sa-root-port-extended-tags-as-bro.patch new file mode 100644 index 0000000000..b224db837e --- /dev/null +++ b/queue-5.15/pci-mark-3ware-9650sa-root-port-extended-tags-as-bro.patch @@ -0,0 +1,56 @@ +From 9575bd43ecfdbcb0379cd65c3180469dee3aa294 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 15:31:10 +0100 +Subject: PCI: Mark 3ware-9650SA Root Port Extended Tags as broken +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jörg Wedekind + +[ Upstream commit 959ac08a2c2811305be8c2779779e8b0932e5a99 ] + +Per PCIe r7.0, sec 2.2.6.2.1 and 7.5.3.4, a Requester may not use 8-bit Tags +unless its Extended Tag Field Enable is set, but all Receivers/Completers +must handle 8-bit Tags correctly regardless of their Extended Tag Field +Enable. + +Some devices do not handle 8-bit Tags as Completers, so add a quirk for +them. If we find such a device, we disable Extended Tags for the entire +hierarchy to make peer-to-peer DMA possible. + +The 3ware 9650SA seems to have issues with handling 8-bit tags. Mark it as +broken. + +This fixes PCI Parity Errors like : + + 3w-9xxx: scsi0: ERROR: (0x06:0x000C): PCI Parity Error: clearing. + 3w-9xxx: scsi0: ERROR: (0x06:0x000D): PCI Abort: clearing. + 3w-9xxx: scsi0: ERROR: (0x06:0x000E): Controller Queue Error: clearing. + 3w-9xxx: scsi0: ERROR: (0x06:0x0010): Microcontroller Error: clearing. + +Fixes: 60db3a4d8cc9 ("PCI: Enable PCIe Extended Tags if supported") +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=202425 +Signed-off-by: Jörg Wedekind +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260119143114.21948-1-joerg@wedekind.de +Signed-off-by: Sasha Levin +--- + drivers/pci/quirks.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index 7597aedc05c37..88922e21d440a 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -5431,6 +5431,7 @@ static void quirk_no_ext_tags(struct pci_dev *pdev) + pci_walk_bus(bridge->bus, pci_configure_extended_tags, NULL); + } + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_3WARE, 0x1004, quirk_no_ext_tags); ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_3WARE, 0x1005, quirk_no_ext_tags); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0132, quirk_no_ext_tags); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0140, quirk_no_ext_tags); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0141, quirk_no_ext_tags); +-- +2.51.0 + diff --git a/queue-5.15/pci-mediatek-fix-irq-domain-leak-when-msi-allocation.patch b/queue-5.15/pci-mediatek-fix-irq-domain-leak-when-msi-allocation.patch new file mode 100644 index 0000000000..feb1b70c14 --- /dev/null +++ b/queue-5.15/pci-mediatek-fix-irq-domain-leak-when-msi-allocation.patch @@ -0,0 +1,45 @@ +From bacb8727076e1ea14315bda06e61aac0b2fcb31a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 19 Nov 2025 10:33:08 +0800 +Subject: PCI: mediatek: Fix IRQ domain leak when MSI allocation fails + +From: Haotian Zhang + +[ Upstream commit 7f0cdcddf8bef1c8c18f9be6708073fd3790a20f ] + +In mtk_pcie_init_irq_domain(), if mtk_pcie_allocate_msi_domains() +fails after port->irq_domain has been successfully created via +irq_domain_create_linear(), the function returns directly without +cleaning up the allocated IRQ domain, resulting in a resource leak. + +Add irq_domain_remove() call in the error path to properly release the +INTx IRQ domain before returning the error. + +Fixes: 43e6409db64d ("PCI: mediatek: Add MSI support for MT2712 and MT7622") +Signed-off-by: Haotian Zhang +Signed-off-by: Manivannan Sadhasivam +Link: https://patch.msgid.link/20251119023308.476-1-vulab@iscas.ac.cn +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/pcie-mediatek.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c +index 3200d776e34d8..787783345129f 100644 +--- a/drivers/pci/controller/pcie-mediatek.c ++++ b/drivers/pci/controller/pcie-mediatek.c +@@ -594,8 +594,10 @@ static int mtk_pcie_init_irq_domain(struct mtk_pcie_port *port, + + if (IS_ENABLED(CONFIG_PCI_MSI)) { + ret = mtk_pcie_allocate_msi_domains(port); +- if (ret) ++ if (ret) { ++ irq_domain_remove(port->irq_domain); + return ret; ++ } + } + + return 0; +-- +2.51.0 + diff --git a/queue-5.15/pci-portdrv-fix-potential-resource-leak.patch b/queue-5.15/pci-portdrv-fix-potential-resource-leak.patch new file mode 100644 index 0000000000..40e8947ae8 --- /dev/null +++ b/queue-5.15/pci-portdrv-fix-potential-resource-leak.patch @@ -0,0 +1,48 @@ +From 536c5a04bfb20d8621afe0c2efce618b8d8106ab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Dec 2025 16:13:49 +0100 +Subject: PCI/portdrv: Fix potential resource leak +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Uwe Kleine-König + +[ Upstream commit 01464a3fdf91c041a381d93a1b6fefbdb819a46f ] + +pcie_port_probe_service() unconditionally calls get_device() (unless it +fails). So drop that reference also unconditionally as it's fine for a +PCIe driver to not have a remove callback. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Uwe Kleine-König +Signed-off-by: Bjorn Helgaas +Reviewed-by: Ilpo Järvinen +Reviewed-by: Jonathan Cameron +Link: https://patch.msgid.link/e1c68c3b3f1af8427e98ca5e2c79f8bf0ebe2ce4.1764688034.git.u.kleine-koenig@baylibre.com +Signed-off-by: Sasha Levin +--- + drivers/pci/pcie/portdrv_core.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c +index 3e5274ad60f10..4c57ddfd6275d 100644 +--- a/drivers/pci/pcie/portdrv_core.c ++++ b/drivers/pci/pcie/portdrv_core.c +@@ -547,10 +547,10 @@ static int pcie_port_remove_service(struct device *dev) + + pciedev = to_pcie_device(dev); + driver = to_service_driver(dev->driver); +- if (driver && driver->remove) { ++ if (driver && driver->remove) + driver->remove(pciedev); +- put_device(dev); +- } ++ ++ put_device(dev); + return 0; + } + +-- +2.51.0 + diff --git a/queue-5.15/pinctrl-equilibrium-fix-device-node-reference-leak-i.patch b/queue-5.15/pinctrl-equilibrium-fix-device-node-reference-leak-i.patch new file mode 100644 index 0000000000..4727c9e9ce --- /dev/null +++ b/queue-5.15/pinctrl-equilibrium-fix-device-node-reference-leak-i.patch @@ -0,0 +1,44 @@ +From 8444eda40ad60ed3b66e5be37490f48c92198575 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 01:30:07 +0800 +Subject: pinctrl: equilibrium: Fix device node reference leak in + pinbank_init() + +From: Felix Gu + +[ Upstream commit c0b4a4feeb43305a754893d8d9c6b2b5a52d45ac ] + +When calling of_parse_phandle_with_fixed_args(), the caller is +responsible to call of_node_put() to release the reference of device +node. + +In pinbank_init(), the reference of the node obtained from the +"gpio-ranges" property is never released, resulting in a reference +count leak. + +Add the missing of_node_put() call to fix the leak. + +Fixes: 1948d5c51dba ("pinctrl: Add pinmux & GPIO controller driver for a new SoC") +Signed-off-by: Felix Gu +Acked-by: Andy Shevchenko +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-equilibrium.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/pinctrl/pinctrl-equilibrium.c b/drivers/pinctrl/pinctrl-equilibrium.c +index 3f0143087cc77..5de9c7dfe5555 100644 +--- a/drivers/pinctrl/pinctrl-equilibrium.c ++++ b/drivers/pinctrl/pinctrl-equilibrium.c +@@ -845,6 +845,7 @@ static int pinbank_init(struct device_node *np, + + bank->pin_base = spec.args[1]; + bank->nr_pins = spec.args[2]; ++ of_node_put(spec.np); + + bank->aval_pinmap = readl(bank->membase + REG_AVAIL); + bank->id = id; +-- +2.51.0 + diff --git a/queue-5.15/pinctrl-qcom-extract-chip-specific-lpass-lpi-code.patch b/queue-5.15/pinctrl-qcom-extract-chip-specific-lpass-lpi-code.patch new file mode 100644 index 0000000000..43549df968 --- /dev/null +++ b/queue-5.15/pinctrl-qcom-extract-chip-specific-lpass-lpi-code.patch @@ -0,0 +1,606 @@ +From 2af6b60bfe6b3becd4e42203b48cf7f671133887 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 18 Apr 2022 18:07:05 +0530 +Subject: pinctrl: qcom: Extract chip specific LPASS LPI code + +From: Srinivasa Rao Mandadapu + +[ Upstream commit 9ce49018c6928263d41b783c9e4928c6af05db43 ] + +Extract the chip specific SM8250 data from the LPASS LPI pinctrl driver +to allow reusing the common code in the addition of subsequent +platforms. + +Signed-off-by: Srinivasa Rao Mandadapu +Co-developed-by: Venkata Prasad Potturu +Signed-off-by: Venkata Prasad Potturu +Reviewed-by: Matthias Kaehlcke +Link: https://lore.kernel.org/r/1650285427-19752-6-git-send-email-quic_srivasam@quicinc.com +Signed-off-by: Linus Walleij +Stable-dep-of: eabf273c8466 ("pinctrl: qcom: sm8250-lpass-lpi: Fix i2s2_data_groups definition") +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/qcom/Kconfig | 9 + + drivers/pinctrl/qcom/Makefile | 1 + + drivers/pinctrl/qcom/pinctrl-lpass-lpi.c | 233 +----------------- + drivers/pinctrl/qcom/pinctrl-lpass-lpi.h | 85 +++++++ + .../pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c | 163 ++++++++++++ + 5 files changed, 263 insertions(+), 228 deletions(-) + create mode 100644 drivers/pinctrl/qcom/pinctrl-lpass-lpi.h + create mode 100644 drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c + +diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig +index 254018c5b3bcc..7d70a7854a403 100644 +--- a/drivers/pinctrl/qcom/Kconfig ++++ b/drivers/pinctrl/qcom/Kconfig +@@ -303,6 +303,15 @@ config PINCTRL_SM8250 + Qualcomm Technologies Inc TLMM block found on the Qualcomm + Technologies Inc SM8250 platform. + ++config PINCTRL_SM8250_LPASS_LPI ++ tristate "Qualcomm Technologies Inc SM8250 LPASS LPI pin controller driver" ++ depends on GPIOLIB ++ depends on PINCTRL_LPASS_LPI ++ help ++ This is the pinctrl, pinmux, pinconf and gpiolib driver for the ++ Qualcomm Technologies Inc LPASS (Low Power Audio SubSystem) LPI ++ (Low Power Island) found on the Qualcomm Technologies Inc SM8250 platform. ++ + config PINCTRL_SM8350 + tristate "Qualcomm Technologies Inc SM8350 pin controller driver" + depends on PINCTRL_MSM +diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile +index 7a12e8cd2fbac..6dcee8eed1d23 100644 +--- a/drivers/pinctrl/qcom/Makefile ++++ b/drivers/pinctrl/qcom/Makefile +@@ -35,5 +35,6 @@ obj-$(CONFIG_PINCTRL_SM6115) += pinctrl-sm6115.o + obj-$(CONFIG_PINCTRL_SM6125) += pinctrl-sm6125.o + obj-$(CONFIG_PINCTRL_SM8150) += pinctrl-sm8150.o + obj-$(CONFIG_PINCTRL_SM8250) += pinctrl-sm8250.o ++obj-$(CONFIG_PINCTRL_SM8250_LPASS_LPI) += pinctrl-sm8250-lpass-lpi.o + obj-$(CONFIG_PINCTRL_SM8350) += pinctrl-sm8350.o + obj-$(CONFIG_PINCTRL_LPASS_LPI) += pinctrl-lpass-lpi.o +diff --git a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c +index d253787f09f1d..60a84a757ac33 100644 +--- a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c ++++ b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c +@@ -4,91 +4,15 @@ + * Copyright (c) 2020 Linaro Ltd. + */ + +-#include +-#include + #include + #include +-#include + #include + #include +-#include + #include + #include + #include +-#include +-#include +-#include +-#include "../core.h" + #include "../pinctrl-utils.h" +- +-#define LPI_SLEW_RATE_CTL_REG 0xa000 +-#define LPI_TLMM_REG_OFFSET 0x1000 +-#define LPI_SLEW_RATE_MAX 0x03 +-#define LPI_SLEW_BITS_SIZE 0x02 +-#define LPI_SLEW_RATE_MASK GENMASK(1, 0) +-#define LPI_GPIO_CFG_REG 0x00 +-#define LPI_GPIO_PULL_MASK GENMASK(1, 0) +-#define LPI_GPIO_FUNCTION_MASK GENMASK(5, 2) +-#define LPI_GPIO_OUT_STRENGTH_MASK GENMASK(8, 6) +-#define LPI_GPIO_OE_MASK BIT(9) +-#define LPI_GPIO_VALUE_REG 0x04 +-#define LPI_GPIO_VALUE_IN_MASK BIT(0) +-#define LPI_GPIO_VALUE_OUT_MASK BIT(1) +- +-#define LPI_GPIO_BIAS_DISABLE 0x0 +-#define LPI_GPIO_PULL_DOWN 0x1 +-#define LPI_GPIO_KEEPER 0x2 +-#define LPI_GPIO_PULL_UP 0x3 +-#define LPI_GPIO_DS_TO_VAL(v) (v / 2 - 1) +-#define LPI_NO_SLEW -1 +- +-#define LPI_FUNCTION(fname) \ +- [LPI_MUX_##fname] = { \ +- .name = #fname, \ +- .groups = fname##_groups, \ +- .ngroups = ARRAY_SIZE(fname##_groups), \ +- } +- +-#define LPI_PINGROUP(id, soff, f1, f2, f3, f4) \ +- { \ +- .group.name = "gpio" #id, \ +- .group.pins = gpio##id##_pins, \ +- .pin = id, \ +- .slew_offset = soff, \ +- .group.num_pins = ARRAY_SIZE(gpio##id##_pins), \ +- .funcs = (int[]){ \ +- LPI_MUX_gpio, \ +- LPI_MUX_##f1, \ +- LPI_MUX_##f2, \ +- LPI_MUX_##f3, \ +- LPI_MUX_##f4, \ +- }, \ +- .nfuncs = 5, \ +- } +- +-struct lpi_pingroup { +- struct group_desc group; +- unsigned int pin; +- /* Bit offset in slew register for SoundWire pins only */ +- int slew_offset; +- unsigned int *funcs; +- unsigned int nfuncs; +-}; +- +-struct lpi_function { +- const char *name; +- const char * const *groups; +- unsigned int ngroups; +-}; +- +-struct lpi_pinctrl_variant_data { +- const struct pinctrl_pin_desc *pins; +- int npins; +- const struct lpi_pingroup *groups; +- int ngroups; +- const struct lpi_function *functions; +- int nfunctions; +-}; ++#include "pinctrl-lpass-lpi.h" + + #define MAX_LPI_NUM_CLKS 2 + +@@ -105,136 +29,6 @@ struct lpi_pinctrl { + const struct lpi_pinctrl_variant_data *data; + }; + +-/* sm8250 variant specific data */ +-static const struct pinctrl_pin_desc sm8250_lpi_pins[] = { +- PINCTRL_PIN(0, "gpio0"), +- PINCTRL_PIN(1, "gpio1"), +- PINCTRL_PIN(2, "gpio2"), +- PINCTRL_PIN(3, "gpio3"), +- PINCTRL_PIN(4, "gpio4"), +- PINCTRL_PIN(5, "gpio5"), +- PINCTRL_PIN(6, "gpio6"), +- PINCTRL_PIN(7, "gpio7"), +- PINCTRL_PIN(8, "gpio8"), +- PINCTRL_PIN(9, "gpio9"), +- PINCTRL_PIN(10, "gpio10"), +- PINCTRL_PIN(11, "gpio11"), +- PINCTRL_PIN(12, "gpio12"), +- PINCTRL_PIN(13, "gpio13"), +-}; +- +-enum sm8250_lpi_functions { +- LPI_MUX_dmic1_clk, +- LPI_MUX_dmic1_data, +- LPI_MUX_dmic2_clk, +- LPI_MUX_dmic2_data, +- LPI_MUX_dmic3_clk, +- LPI_MUX_dmic3_data, +- LPI_MUX_i2s1_clk, +- LPI_MUX_i2s1_data, +- LPI_MUX_i2s1_ws, +- LPI_MUX_i2s2_clk, +- LPI_MUX_i2s2_data, +- LPI_MUX_i2s2_ws, +- LPI_MUX_qua_mi2s_data, +- LPI_MUX_qua_mi2s_sclk, +- LPI_MUX_qua_mi2s_ws, +- LPI_MUX_swr_rx_clk, +- LPI_MUX_swr_rx_data, +- LPI_MUX_swr_tx_clk, +- LPI_MUX_swr_tx_data, +- LPI_MUX_wsa_swr_clk, +- LPI_MUX_wsa_swr_data, +- LPI_MUX_gpio, +- LPI_MUX__, +-}; +- +-static int gpio0_pins[] = { 0 }; +-static int gpio1_pins[] = { 1 }; +-static int gpio2_pins[] = { 2 }; +-static int gpio3_pins[] = { 3 }; +-static int gpio4_pins[] = { 4 }; +-static int gpio5_pins[] = { 5 }; +-static int gpio6_pins[] = { 6 }; +-static int gpio7_pins[] = { 7 }; +-static int gpio8_pins[] = { 8 }; +-static int gpio9_pins[] = { 9 }; +-static int gpio10_pins[] = { 10 }; +-static int gpio11_pins[] = { 11 }; +-static int gpio12_pins[] = { 12 }; +-static int gpio13_pins[] = { 13 }; +-static const char * const swr_tx_clk_groups[] = { "gpio0" }; +-static const char * const swr_tx_data_groups[] = { "gpio1", "gpio2", "gpio5" }; +-static const char * const swr_rx_clk_groups[] = { "gpio3" }; +-static const char * const swr_rx_data_groups[] = { "gpio4", "gpio5" }; +-static const char * const dmic1_clk_groups[] = { "gpio6" }; +-static const char * const dmic1_data_groups[] = { "gpio7" }; +-static const char * const dmic2_clk_groups[] = { "gpio8" }; +-static const char * const dmic2_data_groups[] = { "gpio9" }; +-static const char * const i2s2_clk_groups[] = { "gpio10" }; +-static const char * const i2s2_ws_groups[] = { "gpio11" }; +-static const char * const dmic3_clk_groups[] = { "gpio12" }; +-static const char * const dmic3_data_groups[] = { "gpio13" }; +-static const char * const qua_mi2s_sclk_groups[] = { "gpio0" }; +-static const char * const qua_mi2s_ws_groups[] = { "gpio1" }; +-static const char * const qua_mi2s_data_groups[] = { "gpio2", "gpio3", "gpio4" }; +-static const char * const i2s1_clk_groups[] = { "gpio6" }; +-static const char * const i2s1_ws_groups[] = { "gpio7" }; +-static const char * const i2s1_data_groups[] = { "gpio8", "gpio9" }; +-static const char * const wsa_swr_clk_groups[] = { "gpio10" }; +-static const char * const wsa_swr_data_groups[] = { "gpio11" }; +-static const char * const i2s2_data_groups[] = { "gpio12", "gpio12" }; +- +-static const struct lpi_pingroup sm8250_groups[] = { +- LPI_PINGROUP(0, 0, swr_tx_clk, qua_mi2s_sclk, _, _), +- LPI_PINGROUP(1, 2, swr_tx_data, qua_mi2s_ws, _, _), +- LPI_PINGROUP(2, 4, swr_tx_data, qua_mi2s_data, _, _), +- LPI_PINGROUP(3, 8, swr_rx_clk, qua_mi2s_data, _, _), +- LPI_PINGROUP(4, 10, swr_rx_data, qua_mi2s_data, _, _), +- LPI_PINGROUP(5, 12, swr_tx_data, swr_rx_data, _, _), +- LPI_PINGROUP(6, LPI_NO_SLEW, dmic1_clk, i2s1_clk, _, _), +- LPI_PINGROUP(7, LPI_NO_SLEW, dmic1_data, i2s1_ws, _, _), +- LPI_PINGROUP(8, LPI_NO_SLEW, dmic2_clk, i2s1_data, _, _), +- LPI_PINGROUP(9, LPI_NO_SLEW, dmic2_data, i2s1_data, _, _), +- LPI_PINGROUP(10, 16, i2s2_clk, wsa_swr_clk, _, _), +- LPI_PINGROUP(11, 18, i2s2_ws, wsa_swr_data, _, _), +- LPI_PINGROUP(12, LPI_NO_SLEW, dmic3_clk, i2s2_data, _, _), +- LPI_PINGROUP(13, LPI_NO_SLEW, dmic3_data, i2s2_data, _, _), +-}; +- +-static const struct lpi_function sm8250_functions[] = { +- LPI_FUNCTION(dmic1_clk), +- LPI_FUNCTION(dmic1_data), +- LPI_FUNCTION(dmic2_clk), +- LPI_FUNCTION(dmic2_data), +- LPI_FUNCTION(dmic3_clk), +- LPI_FUNCTION(dmic3_data), +- LPI_FUNCTION(i2s1_clk), +- LPI_FUNCTION(i2s1_data), +- LPI_FUNCTION(i2s1_ws), +- LPI_FUNCTION(i2s2_clk), +- LPI_FUNCTION(i2s2_data), +- LPI_FUNCTION(i2s2_ws), +- LPI_FUNCTION(qua_mi2s_data), +- LPI_FUNCTION(qua_mi2s_sclk), +- LPI_FUNCTION(qua_mi2s_ws), +- LPI_FUNCTION(swr_rx_clk), +- LPI_FUNCTION(swr_rx_data), +- LPI_FUNCTION(swr_tx_clk), +- LPI_FUNCTION(swr_tx_data), +- LPI_FUNCTION(wsa_swr_clk), +- LPI_FUNCTION(wsa_swr_data), +-}; +- +-static struct lpi_pinctrl_variant_data sm8250_lpi_data = { +- .pins = sm8250_lpi_pins, +- .npins = ARRAY_SIZE(sm8250_lpi_pins), +- .groups = sm8250_groups, +- .ngroups = ARRAY_SIZE(sm8250_groups), +- .functions = sm8250_functions, +- .nfunctions = ARRAY_SIZE(sm8250_functions), +-}; +- + static int lpi_gpio_read(struct lpi_pinctrl *state, unsigned int pin, + unsigned int addr) + { +@@ -600,7 +394,7 @@ static int lpi_build_pin_desc_groups(struct lpi_pinctrl *pctrl) + return ret; + } + +-static int lpi_pinctrl_probe(struct platform_device *pdev) ++int lpi_pinctrl_probe(struct platform_device *pdev) + { + const struct lpi_pinctrl_variant_data *data; + struct device *dev = &pdev->dev; +@@ -682,8 +476,9 @@ static int lpi_pinctrl_probe(struct platform_device *pdev) + + return ret; + } ++EXPORT_SYMBOL_GPL(lpi_pinctrl_probe); + +-static int lpi_pinctrl_remove(struct platform_device *pdev) ++int lpi_pinctrl_remove(struct platform_device *pdev) + { + struct lpi_pinctrl *pctrl = platform_get_drvdata(pdev); + int i; +@@ -696,25 +491,7 @@ static int lpi_pinctrl_remove(struct platform_device *pdev) + + return 0; + } ++EXPORT_SYMBOL_GPL(lpi_pinctrl_remove); + +-static const struct of_device_id lpi_pinctrl_of_match[] = { +- { +- .compatible = "qcom,sm8250-lpass-lpi-pinctrl", +- .data = &sm8250_lpi_data, +- }, +- { } +-}; +-MODULE_DEVICE_TABLE(of, lpi_pinctrl_of_match); +- +-static struct platform_driver lpi_pinctrl_driver = { +- .driver = { +- .name = "qcom-lpass-lpi-pinctrl", +- .of_match_table = lpi_pinctrl_of_match, +- }, +- .probe = lpi_pinctrl_probe, +- .remove = lpi_pinctrl_remove, +-}; +- +-module_platform_driver(lpi_pinctrl_driver); + MODULE_DESCRIPTION("QTI LPI GPIO pin control driver"); + MODULE_LICENSE("GPL"); +diff --git a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.h b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.h +new file mode 100644 +index 0000000000000..afbac2a6c82ca +--- /dev/null ++++ b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.h +@@ -0,0 +1,85 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2020 Linaro Ltd. ++ */ ++#ifndef __PINCTRL_LPASS_LPI_H__ ++#define __PINCTRL_LPASS_LPI_H__ ++ ++#include ++#include ++#include "../core.h" ++ ++#define LPI_SLEW_RATE_CTL_REG 0xa000 ++#define LPI_TLMM_REG_OFFSET 0x1000 ++#define LPI_SLEW_RATE_MAX 0x03 ++#define LPI_SLEW_BITS_SIZE 0x02 ++#define LPI_SLEW_RATE_MASK GENMASK(1, 0) ++#define LPI_GPIO_CFG_REG 0x00 ++#define LPI_GPIO_PULL_MASK GENMASK(1, 0) ++#define LPI_GPIO_FUNCTION_MASK GENMASK(5, 2) ++#define LPI_GPIO_OUT_STRENGTH_MASK GENMASK(8, 6) ++#define LPI_GPIO_OE_MASK BIT(9) ++#define LPI_GPIO_VALUE_REG 0x04 ++#define LPI_GPIO_VALUE_IN_MASK BIT(0) ++#define LPI_GPIO_VALUE_OUT_MASK BIT(1) ++ ++#define LPI_GPIO_BIAS_DISABLE 0x0 ++#define LPI_GPIO_PULL_DOWN 0x1 ++#define LPI_GPIO_KEEPER 0x2 ++#define LPI_GPIO_PULL_UP 0x3 ++#define LPI_GPIO_DS_TO_VAL(v) (v / 2 - 1) ++#define LPI_NO_SLEW -1 ++ ++#define LPI_FUNCTION(fname) \ ++ [LPI_MUX_##fname] = { \ ++ .name = #fname, \ ++ .groups = fname##_groups, \ ++ .ngroups = ARRAY_SIZE(fname##_groups), \ ++ } ++ ++#define LPI_PINGROUP(id, soff, f1, f2, f3, f4) \ ++ { \ ++ .group.name = "gpio" #id, \ ++ .group.pins = gpio##id##_pins, \ ++ .pin = id, \ ++ .slew_offset = soff, \ ++ .group.num_pins = ARRAY_SIZE(gpio##id##_pins), \ ++ .funcs = (int[]){ \ ++ LPI_MUX_gpio, \ ++ LPI_MUX_##f1, \ ++ LPI_MUX_##f2, \ ++ LPI_MUX_##f3, \ ++ LPI_MUX_##f4, \ ++ }, \ ++ .nfuncs = 5, \ ++ } ++ ++struct lpi_pingroup { ++ struct group_desc group; ++ unsigned int pin; ++ /* Bit offset in slew register for SoundWire pins only */ ++ int slew_offset; ++ unsigned int *funcs; ++ unsigned int nfuncs; ++}; ++ ++struct lpi_function { ++ const char *name; ++ const char * const *groups; ++ unsigned int ngroups; ++}; ++ ++struct lpi_pinctrl_variant_data { ++ const struct pinctrl_pin_desc *pins; ++ int npins; ++ const struct lpi_pingroup *groups; ++ int ngroups; ++ const struct lpi_function *functions; ++ int nfunctions; ++}; ++ ++int lpi_pinctrl_probe(struct platform_device *pdev); ++int lpi_pinctrl_remove(struct platform_device *pdev); ++ ++#endif /*__PINCTRL_LPASS_LPI_H__*/ +diff --git a/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c +new file mode 100644 +index 0000000000000..ddbc6317f2a74 +--- /dev/null ++++ b/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c +@@ -0,0 +1,163 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2020 Linaro Ltd. ++ */ ++ ++#include ++#include ++#include ++ ++#include "pinctrl-lpass-lpi.h" ++ ++enum lpass_lpi_functions { ++ LPI_MUX_dmic1_clk, ++ LPI_MUX_dmic1_data, ++ LPI_MUX_dmic2_clk, ++ LPI_MUX_dmic2_data, ++ LPI_MUX_dmic3_clk, ++ LPI_MUX_dmic3_data, ++ LPI_MUX_i2s1_clk, ++ LPI_MUX_i2s1_data, ++ LPI_MUX_i2s1_ws, ++ LPI_MUX_i2s2_clk, ++ LPI_MUX_i2s2_data, ++ LPI_MUX_i2s2_ws, ++ LPI_MUX_qua_mi2s_data, ++ LPI_MUX_qua_mi2s_sclk, ++ LPI_MUX_qua_mi2s_ws, ++ LPI_MUX_swr_rx_clk, ++ LPI_MUX_swr_rx_data, ++ LPI_MUX_swr_tx_clk, ++ LPI_MUX_swr_tx_data, ++ LPI_MUX_wsa_swr_clk, ++ LPI_MUX_wsa_swr_data, ++ LPI_MUX_gpio, ++ LPI_MUX__, ++}; ++ ++static int gpio0_pins[] = { 0 }; ++static int gpio1_pins[] = { 1 }; ++static int gpio2_pins[] = { 2 }; ++static int gpio3_pins[] = { 3 }; ++static int gpio4_pins[] = { 4 }; ++static int gpio5_pins[] = { 5 }; ++static int gpio6_pins[] = { 6 }; ++static int gpio7_pins[] = { 7 }; ++static int gpio8_pins[] = { 8 }; ++static int gpio9_pins[] = { 9 }; ++static int gpio10_pins[] = { 10 }; ++static int gpio11_pins[] = { 11 }; ++static int gpio12_pins[] = { 12 }; ++static int gpio13_pins[] = { 13 }; ++ ++static const struct pinctrl_pin_desc sm8250_lpi_pins[] = { ++ PINCTRL_PIN(0, "gpio0"), ++ PINCTRL_PIN(1, "gpio1"), ++ PINCTRL_PIN(2, "gpio2"), ++ PINCTRL_PIN(3, "gpio3"), ++ PINCTRL_PIN(4, "gpio4"), ++ PINCTRL_PIN(5, "gpio5"), ++ PINCTRL_PIN(6, "gpio6"), ++ PINCTRL_PIN(7, "gpio7"), ++ PINCTRL_PIN(8, "gpio8"), ++ PINCTRL_PIN(9, "gpio9"), ++ PINCTRL_PIN(10, "gpio10"), ++ PINCTRL_PIN(11, "gpio11"), ++ PINCTRL_PIN(12, "gpio12"), ++ PINCTRL_PIN(13, "gpio13"), ++}; ++ ++static const char * const swr_tx_clk_groups[] = { "gpio0" }; ++static const char * const swr_tx_data_groups[] = { "gpio1", "gpio2", "gpio5" }; ++static const char * const swr_rx_clk_groups[] = { "gpio3" }; ++static const char * const swr_rx_data_groups[] = { "gpio4", "gpio5" }; ++static const char * const dmic1_clk_groups[] = { "gpio6" }; ++static const char * const dmic1_data_groups[] = { "gpio7" }; ++static const char * const dmic2_clk_groups[] = { "gpio8" }; ++static const char * const dmic2_data_groups[] = { "gpio9" }; ++static const char * const i2s2_clk_groups[] = { "gpio10" }; ++static const char * const i2s2_ws_groups[] = { "gpio11" }; ++static const char * const dmic3_clk_groups[] = { "gpio12" }; ++static const char * const dmic3_data_groups[] = { "gpio13" }; ++static const char * const qua_mi2s_sclk_groups[] = { "gpio0" }; ++static const char * const qua_mi2s_ws_groups[] = { "gpio1" }; ++static const char * const qua_mi2s_data_groups[] = { "gpio2", "gpio3", "gpio4" }; ++static const char * const i2s1_clk_groups[] = { "gpio6" }; ++static const char * const i2s1_ws_groups[] = { "gpio7" }; ++static const char * const i2s1_data_groups[] = { "gpio8", "gpio9" }; ++static const char * const wsa_swr_clk_groups[] = { "gpio10" }; ++static const char * const wsa_swr_data_groups[] = { "gpio11" }; ++static const char * const i2s2_data_groups[] = { "gpio12", "gpio12" }; ++ ++static const struct lpi_pingroup sm8250_groups[] = { ++ LPI_PINGROUP(0, 0, swr_tx_clk, qua_mi2s_sclk, _, _), ++ LPI_PINGROUP(1, 2, swr_tx_data, qua_mi2s_ws, _, _), ++ LPI_PINGROUP(2, 4, swr_tx_data, qua_mi2s_data, _, _), ++ LPI_PINGROUP(3, 8, swr_rx_clk, qua_mi2s_data, _, _), ++ LPI_PINGROUP(4, 10, swr_rx_data, qua_mi2s_data, _, _), ++ LPI_PINGROUP(5, 12, swr_tx_data, swr_rx_data, _, _), ++ LPI_PINGROUP(6, LPI_NO_SLEW, dmic1_clk, i2s1_clk, _, _), ++ LPI_PINGROUP(7, LPI_NO_SLEW, dmic1_data, i2s1_ws, _, _), ++ LPI_PINGROUP(8, LPI_NO_SLEW, dmic2_clk, i2s1_data, _, _), ++ LPI_PINGROUP(9, LPI_NO_SLEW, dmic2_data, i2s1_data, _, _), ++ LPI_PINGROUP(10, 16, i2s2_clk, wsa_swr_clk, _, _), ++ LPI_PINGROUP(11, 18, i2s2_ws, wsa_swr_data, _, _), ++ LPI_PINGROUP(12, LPI_NO_SLEW, dmic3_clk, i2s2_data, _, _), ++ LPI_PINGROUP(13, LPI_NO_SLEW, dmic3_data, i2s2_data, _, _), ++}; ++ ++static const struct lpi_function sm8250_functions[] = { ++ LPI_FUNCTION(dmic1_clk), ++ LPI_FUNCTION(dmic1_data), ++ LPI_FUNCTION(dmic2_clk), ++ LPI_FUNCTION(dmic2_data), ++ LPI_FUNCTION(dmic3_clk), ++ LPI_FUNCTION(dmic3_data), ++ LPI_FUNCTION(i2s1_clk), ++ LPI_FUNCTION(i2s1_data), ++ LPI_FUNCTION(i2s1_ws), ++ LPI_FUNCTION(i2s2_clk), ++ LPI_FUNCTION(i2s2_data), ++ LPI_FUNCTION(i2s2_ws), ++ LPI_FUNCTION(qua_mi2s_data), ++ LPI_FUNCTION(qua_mi2s_sclk), ++ LPI_FUNCTION(qua_mi2s_ws), ++ LPI_FUNCTION(swr_rx_clk), ++ LPI_FUNCTION(swr_rx_data), ++ LPI_FUNCTION(swr_tx_clk), ++ LPI_FUNCTION(swr_tx_data), ++ LPI_FUNCTION(wsa_swr_clk), ++ LPI_FUNCTION(wsa_swr_data), ++}; ++ ++static const struct lpi_pinctrl_variant_data sm8250_lpi_data = { ++ .pins = sm8250_lpi_pins, ++ .npins = ARRAY_SIZE(sm8250_lpi_pins), ++ .groups = sm8250_groups, ++ .ngroups = ARRAY_SIZE(sm8250_groups), ++ .functions = sm8250_functions, ++ .nfunctions = ARRAY_SIZE(sm8250_functions), ++}; ++ ++static const struct of_device_id lpi_pinctrl_of_match[] = { ++ { ++ .compatible = "qcom,sm8250-lpass-lpi-pinctrl", ++ .data = &sm8250_lpi_data, ++ }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, lpi_pinctrl_of_match); ++ ++static struct platform_driver lpi_pinctrl_driver = { ++ .driver = { ++ .name = "qcom-sm8250-lpass-lpi-pinctrl", ++ .of_match_table = lpi_pinctrl_of_match, ++ }, ++ .probe = lpi_pinctrl_probe, ++ .remove = lpi_pinctrl_remove, ++}; ++ ++module_platform_driver(lpi_pinctrl_driver); ++MODULE_DESCRIPTION("QTI SM8250 LPI GPIO pin control driver"); ++MODULE_LICENSE("GPL"); +-- +2.51.0 + diff --git a/queue-5.15/pinctrl-qcom-sm8250-lpass-lpi-fix-i2s2_data_groups-d.patch b/queue-5.15/pinctrl-qcom-sm8250-lpass-lpi-fix-i2s2_data_groups-d.patch new file mode 100644 index 0000000000..87b08a9faa --- /dev/null +++ b/queue-5.15/pinctrl-qcom-sm8250-lpass-lpi-fix-i2s2_data_groups-d.patch @@ -0,0 +1,38 @@ +From b6e93ecd90c5eb41e264b6ade7131e4219ca856f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 12:22:28 +0100 +Subject: pinctrl: qcom: sm8250-lpass-lpi: Fix i2s2_data_groups definition + +From: Luca Weiss + +[ Upstream commit eabf273c8466af3f033473c2d2267a6ea7946d57 ] + +The i2s2_data function is available on both gpio12 and gpio13. Fix the +groups definition. + +Fixes: 6e261d1090d6 ("pinctrl: qcom: Add sm8250 lpass lpi pinctrl driver") +Signed-off-by: Luca Weiss +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c +index ddbc6317f2a74..422ef44b86423 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c ++++ b/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c +@@ -88,7 +88,7 @@ static const char * const i2s1_ws_groups[] = { "gpio7" }; + static const char * const i2s1_data_groups[] = { "gpio8", "gpio9" }; + static const char * const wsa_swr_clk_groups[] = { "gpio10" }; + static const char * const wsa_swr_data_groups[] = { "gpio11" }; +-static const char * const i2s2_data_groups[] = { "gpio12", "gpio12" }; ++static const char * const i2s2_data_groups[] = { "gpio12", "gpio13" }; + + static const struct lpi_pingroup sm8250_groups[] = { + LPI_PINGROUP(0, 0, swr_tx_clk, qua_mi2s_sclk, _, _), +-- +2.51.0 + diff --git a/queue-5.15/pinctrl-qcom-update-lpi-pin-group-custiom-functions-.patch b/queue-5.15/pinctrl-qcom-update-lpi-pin-group-custiom-functions-.patch new file mode 100644 index 0000000000..0c81aafc87 --- /dev/null +++ b/queue-5.15/pinctrl-qcom-update-lpi-pin-group-custiom-functions-.patch @@ -0,0 +1,205 @@ +From b858ee7f9515321b29320966140f566f26743c0e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 18 Apr 2022 18:07:04 +0530 +Subject: pinctrl: qcom: Update lpi pin group custiom functions with framework + generic functions + +From: Srinivasa Rao Mandadapu + +[ Upstream commit be73368d535614b351c13a10680b4cdd06db2417 ] + +Update custom pin group structure members with framework generic +group_desc structure and replace the driver's custom pinctrl_ops +with framework provided generic pin control group functions to avoid +redundant code written in lpass lpi driver. + +Signed-off-by: Srinivasa Rao Mandadapu +Co-developed-by: Venkata Prasad Potturu +Signed-off-by: Venkata Prasad Potturu +Reviewed-by: Matthias Kaehlcke +Link: https://lore.kernel.org/r/1650285427-19752-5-git-send-email-quic_srivasam@quicinc.com +Signed-off-by: Linus Walleij +Stable-dep-of: eabf273c8466 ("pinctrl: qcom: sm8250-lpass-lpi: Fix i2s2_data_groups definition") +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/qcom/Kconfig | 1 + + drivers/pinctrl/qcom/pinctrl-lpass-lpi.c | 102 +++++++++++------------ + 2 files changed, 52 insertions(+), 51 deletions(-) + +diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig +index f1b5176a5085b..254018c5b3bcc 100644 +--- a/drivers/pinctrl/qcom/Kconfig ++++ b/drivers/pinctrl/qcom/Kconfig +@@ -316,6 +316,7 @@ config PINCTRL_LPASS_LPI + select PINMUX + select PINCONF + select GENERIC_PINCONF ++ select GENERIC_PINCTRL_GROUPS + depends on GPIOLIB + help + This is the pinctrl, pinmux, pinconf and gpiolib driver for the +diff --git a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c +index 5e89fa4176a2c..d253787f09f1d 100644 +--- a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c ++++ b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c +@@ -51,11 +51,11 @@ + + #define LPI_PINGROUP(id, soff, f1, f2, f3, f4) \ + { \ +- .name = "gpio" #id, \ +- .pins = gpio##id##_pins, \ ++ .group.name = "gpio" #id, \ ++ .group.pins = gpio##id##_pins, \ + .pin = id, \ + .slew_offset = soff, \ +- .npins = ARRAY_SIZE(gpio##id##_pins), \ ++ .group.num_pins = ARRAY_SIZE(gpio##id##_pins), \ + .funcs = (int[]){ \ + LPI_MUX_gpio, \ + LPI_MUX_##f1, \ +@@ -67,9 +67,7 @@ + } + + struct lpi_pingroup { +- const char *name; +- const unsigned int *pins; +- unsigned int npins; ++ struct group_desc group; + unsigned int pin; + /* Bit offset in slew register for SoundWire pins only */ + int slew_offset; +@@ -151,20 +149,20 @@ enum sm8250_lpi_functions { + LPI_MUX__, + }; + +-static const unsigned int gpio0_pins[] = { 0 }; +-static const unsigned int gpio1_pins[] = { 1 }; +-static const unsigned int gpio2_pins[] = { 2 }; +-static const unsigned int gpio3_pins[] = { 3 }; +-static const unsigned int gpio4_pins[] = { 4 }; +-static const unsigned int gpio5_pins[] = { 5 }; +-static const unsigned int gpio6_pins[] = { 6 }; +-static const unsigned int gpio7_pins[] = { 7 }; +-static const unsigned int gpio8_pins[] = { 8 }; +-static const unsigned int gpio9_pins[] = { 9 }; +-static const unsigned int gpio10_pins[] = { 10 }; +-static const unsigned int gpio11_pins[] = { 11 }; +-static const unsigned int gpio12_pins[] = { 12 }; +-static const unsigned int gpio13_pins[] = { 13 }; ++static int gpio0_pins[] = { 0 }; ++static int gpio1_pins[] = { 1 }; ++static int gpio2_pins[] = { 2 }; ++static int gpio3_pins[] = { 3 }; ++static int gpio4_pins[] = { 4 }; ++static int gpio5_pins[] = { 5 }; ++static int gpio6_pins[] = { 6 }; ++static int gpio7_pins[] = { 7 }; ++static int gpio8_pins[] = { 8 }; ++static int gpio9_pins[] = { 9 }; ++static int gpio10_pins[] = { 10 }; ++static int gpio11_pins[] = { 11 }; ++static int gpio12_pins[] = { 12 }; ++static int gpio13_pins[] = { 13 }; + static const char * const swr_tx_clk_groups[] = { "gpio0" }; + static const char * const swr_tx_data_groups[] = { "gpio1", "gpio2", "gpio5" }; + static const char * const swr_rx_clk_groups[] = { "gpio3" }; +@@ -251,38 +249,10 @@ static int lpi_gpio_write(struct lpi_pinctrl *state, unsigned int pin, + return 0; + } + +-static int lpi_gpio_get_groups_count(struct pinctrl_dev *pctldev) +-{ +- struct lpi_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); +- +- return pctrl->data->ngroups; +-} +- +-static const char *lpi_gpio_get_group_name(struct pinctrl_dev *pctldev, +- unsigned int group) +-{ +- struct lpi_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); +- +- return pctrl->data->groups[group].name; +-} +- +-static int lpi_gpio_get_group_pins(struct pinctrl_dev *pctldev, +- unsigned int group, +- const unsigned int **pins, +- unsigned int *num_pins) +-{ +- struct lpi_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); +- +- *pins = pctrl->data->groups[group].pins; +- *num_pins = pctrl->data->groups[group].npins; +- +- return 0; +-} +- + static const struct pinctrl_ops lpi_gpio_pinctrl_ops = { +- .get_groups_count = lpi_gpio_get_groups_count, +- .get_group_name = lpi_gpio_get_group_name, +- .get_group_pins = lpi_gpio_get_group_pins, ++ .get_groups_count = pinctrl_generic_get_group_count, ++ .get_group_name = pinctrl_generic_get_group_name, ++ .get_group_pins = pinctrl_generic_get_group_pins, + .dt_node_to_map = pinconf_generic_dt_node_to_map_group, + .dt_free_map = pinctrl_utils_free_map, + }; +@@ -608,6 +578,28 @@ static const struct gpio_chip lpi_gpio_template = { + .dbg_show = lpi_gpio_dbg_show, + }; + ++static int lpi_build_pin_desc_groups(struct lpi_pinctrl *pctrl) ++{ ++ int i, ret; ++ ++ for (i = 0; i < pctrl->data->npins; i++) { ++ const struct pinctrl_pin_desc *pin_info = pctrl->desc.pins + i; ++ ++ ret = pinctrl_generic_add_group(pctrl->ctrl, pin_info->name, ++ (int *)&pin_info->number, 1, NULL); ++ if (ret < 0) ++ goto err_pinctrl; ++ } ++ ++ return 0; ++ ++err_pinctrl: ++ for (; i > 0; i--) ++ pinctrl_generic_remove_group(pctrl->ctrl, i - 1); ++ ++ return ret; ++} ++ + static int lpi_pinctrl_probe(struct platform_device *pdev) + { + const struct lpi_pinctrl_variant_data *data; +@@ -672,6 +664,10 @@ static int lpi_pinctrl_probe(struct platform_device *pdev) + goto err_pinctrl; + } + ++ ret = lpi_build_pin_desc_groups(pctrl); ++ if (ret) ++ goto err_pinctrl; ++ + ret = devm_gpiochip_add_data(dev, &pctrl->chip, pctrl); + if (ret) { + dev_err(pctrl->dev, "can't add gpio chip\n"); +@@ -690,10 +686,14 @@ static int lpi_pinctrl_probe(struct platform_device *pdev) + static int lpi_pinctrl_remove(struct platform_device *pdev) + { + struct lpi_pinctrl *pctrl = platform_get_drvdata(pdev); ++ int i; + + mutex_destroy(&pctrl->lock); + clk_bulk_disable_unprepare(MAX_LPI_NUM_CLKS, pctrl->clks); + ++ for (i = 0; i < pctrl->data->npins; i++) ++ pinctrl_generic_remove_group(pctrl->ctrl, i); ++ + return 0; + } + +-- +2.51.0 + diff --git a/queue-5.15/pinctrl-qcom-update-macro-name-to-lpi-specific.patch b/queue-5.15/pinctrl-qcom-update-macro-name-to-lpi-specific.patch new file mode 100644 index 0000000000..be9149027d --- /dev/null +++ b/queue-5.15/pinctrl-qcom-update-macro-name-to-lpi-specific.patch @@ -0,0 +1,70 @@ +From f5f3c36a55a56ae22c5c291827cdfe4b94326cc0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 18 Apr 2022 18:07:03 +0530 +Subject: pinctrl: qcom: Update macro name to LPI specific + +From: Srinivasa Rao Mandadapu + +[ Upstream commit 6454711015267fe38b6f05aba232e01be2cb9693 ] + +Update NO_SLEW macro to LPI_NO_SLEW macro as this driver lpi specific. + +Signed-off-by: Srinivasa Rao Mandadapu +Co-developed-by: Venkata Prasad Potturu +Signed-off-by: Venkata Prasad Potturu +Reviewed-by: Stephen Boyd +Reviewed-by: Bjorn Andersson +Link: https://lore.kernel.org/r/1650285427-19752-4-git-send-email-quic_srivasam@quicinc.com +Signed-off-by: Linus Walleij +Stable-dep-of: eabf273c8466 ("pinctrl: qcom: sm8250-lpass-lpi: Fix i2s2_data_groups definition") +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/qcom/pinctrl-lpass-lpi.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c +index 586c5b70cba13..5e89fa4176a2c 100644 +--- a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c ++++ b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c +@@ -40,7 +40,7 @@ + #define LPI_GPIO_KEEPER 0x2 + #define LPI_GPIO_PULL_UP 0x3 + #define LPI_GPIO_DS_TO_VAL(v) (v / 2 - 1) +-#define NO_SLEW -1 ++#define LPI_NO_SLEW -1 + + #define LPI_FUNCTION(fname) \ + [LPI_MUX_##fname] = { \ +@@ -194,14 +194,14 @@ static const struct lpi_pingroup sm8250_groups[] = { + LPI_PINGROUP(3, 8, swr_rx_clk, qua_mi2s_data, _, _), + LPI_PINGROUP(4, 10, swr_rx_data, qua_mi2s_data, _, _), + LPI_PINGROUP(5, 12, swr_tx_data, swr_rx_data, _, _), +- LPI_PINGROUP(6, NO_SLEW, dmic1_clk, i2s1_clk, _, _), +- LPI_PINGROUP(7, NO_SLEW, dmic1_data, i2s1_ws, _, _), +- LPI_PINGROUP(8, NO_SLEW, dmic2_clk, i2s1_data, _, _), +- LPI_PINGROUP(9, NO_SLEW, dmic2_data, i2s1_data, _, _), ++ LPI_PINGROUP(6, LPI_NO_SLEW, dmic1_clk, i2s1_clk, _, _), ++ LPI_PINGROUP(7, LPI_NO_SLEW, dmic1_data, i2s1_ws, _, _), ++ LPI_PINGROUP(8, LPI_NO_SLEW, dmic2_clk, i2s1_data, _, _), ++ LPI_PINGROUP(9, LPI_NO_SLEW, dmic2_data, i2s1_data, _, _), + LPI_PINGROUP(10, 16, i2s2_clk, wsa_swr_clk, _, _), + LPI_PINGROUP(11, 18, i2s2_ws, wsa_swr_data, _, _), +- LPI_PINGROUP(12, NO_SLEW, dmic3_clk, i2s2_data, _, _), +- LPI_PINGROUP(13, NO_SLEW, dmic3_data, i2s2_data, _, _), ++ LPI_PINGROUP(12, LPI_NO_SLEW, dmic3_clk, i2s2_data, _, _), ++ LPI_PINGROUP(13, LPI_NO_SLEW, dmic3_data, i2s2_data, _, _), + }; + + static const struct lpi_function sm8250_functions[] = { +@@ -438,7 +438,7 @@ static int lpi_config_set(struct pinctrl_dev *pctldev, unsigned int group, + } + + slew_offset = g->slew_offset; +- if (slew_offset == NO_SLEW) ++ if (slew_offset == LPI_NO_SLEW) + break; + + mutex_lock(&pctrl->lock); +-- +2.51.0 + diff --git a/queue-5.15/pinctrl-single-fix-refcount-leak-in-pcs_add_gpio_fun.patch b/queue-5.15/pinctrl-single-fix-refcount-leak-in-pcs_add_gpio_fun.patch new file mode 100644 index 0000000000..d9b24621e6 --- /dev/null +++ b/queue-5.15/pinctrl-single-fix-refcount-leak-in-pcs_add_gpio_fun.patch @@ -0,0 +1,50 @@ +From ecc19d1bda830b3579efbf564df03775751f87e7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 08:07:35 +0000 +Subject: pinctrl: single: fix refcount leak in pcs_add_gpio_func() + +From: Wei Li + +[ Upstream commit 353353309b0f7afa407df29e455f9d15b5acc296 ] + +of_parse_phandle_with_args() returns a device_node pointer with refcount +incremented in gpiospec.np. The loop iterates through all phandles but +never releases the reference, causing a refcount leak on each iteration. + +Add of_node_put() calls to release the reference after extracting the +needed arguments and on the error path when devm_kzalloc() fails. + +This bug was detected by our static analysis tool and verified by my +code review. + +Fixes: a1a277eb76b3 ("pinctrl: single: create new gpio function range") +Signed-off-by: Wei Li +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-single.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c +index 0659cd3aa3a5a..2c5b5ce60248e 100644 +--- a/drivers/pinctrl/pinctrl-single.c ++++ b/drivers/pinctrl/pinctrl-single.c +@@ -1364,6 +1364,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) + } + range = devm_kzalloc(pcs->dev, sizeof(*range), GFP_KERNEL); + if (!range) { ++ of_node_put(gpiospec.np); + ret = -ENOMEM; + break; + } +@@ -1373,6 +1374,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) + mutex_lock(&pcs->mutex); + list_add_tail(&range->node, &pcs->gpiofuncs); + mutex_unlock(&pcs->mutex); ++ of_node_put(gpiospec.np); + } + return ret; + } +-- +2.51.0 + diff --git a/queue-5.15/platform-chrome-cros_ec_lightbar-fix-response-size-i.patch b/queue-5.15/platform-chrome-cros_ec_lightbar-fix-response-size-i.patch new file mode 100644 index 0000000000..314d1c0b6e --- /dev/null +++ b/queue-5.15/platform-chrome-cros_ec_lightbar-fix-response-size-i.patch @@ -0,0 +1,43 @@ +From 1ebb97c5c218c7e7274b162da189002ec8af8fab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 04:03:35 +0000 +Subject: platform/chrome: cros_ec_lightbar: Fix response size initialization + +From: Tzung-Bi Shih + +[ Upstream commit ec0dd36dbf8b0b209e63d0cd795451fa2203c736 ] + +Commit 1e7913ff5f9f ("platform/chrome: cros_ec_lightbar: Reduce +ligthbar get version command") meant to set smaller values for both +request and response sizes. + +However, it incorrectly assigned the response size to the `result` field +instead of `insize`. Fix it. + +Reported-by: Gwendal Grignou +Closes: https://lore.kernel.org/chrome-platform/CAMHSBOVrrYaB=1nEqZk09VkczCrj=6B-P8Fe29TpPdSDgT2CCQ@mail.gmail.com +Fixes: 1e7913ff5f9f ("platform/chrome: cros_ec_lightbar: Reduce ligthbar get version command") +Link: https://lore.kernel.org/r/20260130040335.361997-1-tzungbi@kernel.org +Reviewed-by: Gwendal Grignou +Signed-off-by: Tzung-Bi Shih +Signed-off-by: Sasha Levin +--- + drivers/platform/chrome/cros_ec_lightbar.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/platform/chrome/cros_ec_lightbar.c b/drivers/platform/chrome/cros_ec_lightbar.c +index 469dfc7a4a030..e2365788d4590 100644 +--- a/drivers/platform/chrome/cros_ec_lightbar.c ++++ b/drivers/platform/chrome/cros_ec_lightbar.c +@@ -117,7 +117,7 @@ static int get_lightbar_version(struct cros_ec_dev *ec, + param = (struct ec_params_lightbar *)msg->data; + param->cmd = LIGHTBAR_CMD_VERSION; + msg->outsize = sizeof(param->cmd); +- msg->result = sizeof(resp->version); ++ msg->insize = sizeof(resp->version); + ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg); + if (ret < 0 && ret != -EINVAL) { + ret = 0; +-- +2.51.0 + diff --git a/queue-5.15/pm-sleep-wakeirq-harden-dev_pm_clear_wake_irq-agains.patch b/queue-5.15/pm-sleep-wakeirq-harden-dev_pm_clear_wake_irq-agains.patch new file mode 100644 index 0000000000..ed59450ba2 --- /dev/null +++ b/queue-5.15/pm-sleep-wakeirq-harden-dev_pm_clear_wake_irq-agains.patch @@ -0,0 +1,65 @@ +From 38fb070d4d89219f4f474eae2621782f2d27efc0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 11:19:43 +0800 +Subject: PM: sleep: wakeirq: harden dev_pm_clear_wake_irq() against races + +From: Gui-Dong Han + +[ Upstream commit 5c9ecd8e6437cd55a38ea4f1e1d19cee8e226cb8 ] + +dev_pm_clear_wake_irq() currently uses a dangerous pattern where +dev->power.wakeirq is read and checked for NULL outside the lock. +If two callers invoke this function concurrently, both might see +a valid pointer and proceed. This could result in a double-free +when the second caller acquires the lock and tries to release the +same object. + +Address this by removing the lockless check of dev->power.wakeirq. +Instead, acquire dev->power.lock immediately to ensure the check and +the subsequent operations are atomic. If dev->power.wakeirq is NULL +under the lock, simply unlock and return. This guarantees that +concurrent calls cannot race to free the same object. + +Based on a quick scan of current users, I did not find an actual bug as +drivers seem to rely on their own synchronization. However, since +asynchronous usage patterns exist (e.g., in +drivers/net/wireless/ti/wlcore), I believe a race is theoretically +possible if the API is used less carefully in the future. This change +hardens the API to be robust against such cases. + +Fixes: 4990d4fe327b ("PM / Wakeirq: Add automated device wake IRQ handling") +Signed-off-by: Gui-Dong Han +Link: https://patch.msgid.link/20260203031943.1924-1-hanguidong02@gmail.com +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/base/power/wakeirq.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/drivers/base/power/wakeirq.c b/drivers/base/power/wakeirq.c +index ab6eced7f5762..0328ee03c1bfc 100644 +--- a/drivers/base/power/wakeirq.c ++++ b/drivers/base/power/wakeirq.c +@@ -83,13 +83,16 @@ EXPORT_SYMBOL_GPL(dev_pm_set_wake_irq); + */ + void dev_pm_clear_wake_irq(struct device *dev) + { +- struct wake_irq *wirq = dev->power.wakeirq; ++ struct wake_irq *wirq; + unsigned long flags; + +- if (!wirq) ++ spin_lock_irqsave(&dev->power.lock, flags); ++ wirq = dev->power.wakeirq; ++ if (!wirq) { ++ spin_unlock_irqrestore(&dev->power.lock, flags); + return; ++ } + +- spin_lock_irqsave(&dev->power.lock, flags); + device_wakeup_detach_irq(dev); + dev->power.wakeirq = NULL; + spin_unlock_irqrestore(&dev->power.lock, flags); +-- +2.51.0 + diff --git a/queue-5.15/pm-wakeup-handle-empty-list-in-wakeup_sources_walk_s.patch b/queue-5.15/pm-wakeup-handle-empty-list-in-wakeup_sources_walk_s.patch new file mode 100644 index 0000000000..5e6a5e34e2 --- /dev/null +++ b/queue-5.15/pm-wakeup-handle-empty-list-in-wakeup_sources_walk_s.patch @@ -0,0 +1,44 @@ +From 748573cb68804da4095a13801723922e8d784e9c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 17:21:29 -0800 +Subject: PM: wakeup: Handle empty list in wakeup_sources_walk_start() + +From: Samuel Wu + +[ Upstream commit 75ce02f4bc9a8b8350b6b1b01872467b0cc960cc ] + +In the case of an empty wakeup_sources list, wakeup_sources_walk_start() +will return an invalid but non-NULL address. This also affects wrappers +of the aforementioned function, like for_each_wakeup_source(). + +Update wakeup_sources_walk_start() to return NULL in case of an empty +list. + +Fixes: b4941adb24c0 ("PM: wakeup: Add routine to help fetch wakeup source object.") +Signed-off-by: Samuel Wu +[ rjw: Subject and changelog edits ] +Link: https://patch.msgid.link/20260124012133.2451708-2-wusamuel@google.com +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/base/power/wakeup.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c +index 8666590201c9a..4ef4c8dfd2bc7 100644 +--- a/drivers/base/power/wakeup.c ++++ b/drivers/base/power/wakeup.c +@@ -285,9 +285,7 @@ EXPORT_SYMBOL_GPL(wakeup_sources_read_unlock); + */ + struct wakeup_source *wakeup_sources_walk_start(void) + { +- struct list_head *ws_head = &wakeup_sources; +- +- return list_entry_rcu(ws_head->next, struct wakeup_source, entry); ++ return list_first_or_null_rcu(&wakeup_sources, struct wakeup_source, entry); + } + EXPORT_SYMBOL_GPL(wakeup_sources_walk_start); + +-- +2.51.0 + diff --git a/queue-5.15/pnfs-fix-a-missing-wake-up-while-waiting-on-nfs_layo.patch b/queue-5.15/pnfs-fix-a-missing-wake-up-while-waiting-on-nfs_layo.patch new file mode 100644 index 0000000000..061721e6b0 --- /dev/null +++ b/queue-5.15/pnfs-fix-a-missing-wake-up-while-waiting-on-nfs_layo.patch @@ -0,0 +1,61 @@ +From 8bd0ee36de9a2e91ef59e46abe7b06a05625ba1b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 14:15:39 -0500 +Subject: pNFS: fix a missing wake up while waiting on NFS_LAYOUT_DRAIN + +From: Olga Kornievskaia + +[ Upstream commit 5248d8474e594d156bee1ed10339cc16e207a28b ] + +It is possible to have a task get stuck on waiting on the +NFS_LAYOUT_DRAIN in the following scenario + +1. cpu a: waiter test NFS_LAYOUT_DRAIN (1) and plh_outstanding (1) +2. cpu b: atomic_dec_and_test() -> clear bit -> wake up +3. cpu c: sets NFS_LAYOUT_DRAIN again +4. cpu a: calls wait_on_bit() sleeps forever. + +To expand on this we have say 2 outstanding pnfs write IO that get +ESTALE which causes both to call pnfs_destroy_layout() and set the +NFS_LAYOUT_DRAIN bit but the 1st one doesn't call the +pnfs_put_layout_hdr() yet (as that would prevent the 2nd ESTALE write +from trying to call pnfs_destroy_layout()). If the 1st ESTALE write +is the one that initially sets the NFS_LAYOUT_DRAIN so that new IO +on this file initiates new LAYOUTGET. Another new write would find +NFS_LAYOUT_DRAIN set and phl_outstanding>0 (step 1) and would +wait_on_bit(). LAYOUTGET completes doing step 2. Now, the 2nd of +ESTALE writes is calling pnfs_destory_layout() and set the +NFS_LAYOUT_DRAIN bit (step 3). Finally, the waiting write wakes up +to check the bit and goes back to sleep. + +The problem revolves around the fact that if NFS_LAYOUT_INVALID_STID +was already set, it should not do the work of +pnfs_mark_layout_stateid_invalid(), thus NFS_LAYOUT_DRAIN will not +be set more than once for an invalid layout. + +Suggested-by: Trond Myklebust +Fixes: 880265c77ac4 ("pNFS: Avoid a live lock condition in pnfs_update_layout()") +Signed-off-by: Olga Kornievskaia +Signed-off-by: Anna Schumaker +Signed-off-by: Sasha Levin +--- + fs/nfs/pnfs.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c +index 50d608f6c6906..041cb7a96e8d9 100644 +--- a/fs/nfs/pnfs.c ++++ b/fs/nfs/pnfs.c +@@ -464,7 +464,8 @@ pnfs_mark_layout_stateid_invalid(struct pnfs_layout_hdr *lo, + }; + struct pnfs_layout_segment *lseg, *next; + +- set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags); ++ if (test_and_set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags)) ++ return !list_empty(&lo->plh_segs); + clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(lo->plh_inode)->flags); + list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list) + pnfs_clear_lseg_state(lseg, lseg_list); +-- +2.51.0 + diff --git a/queue-5.15/power-reset-nvmem-reboot-mode-respect-cell-size-for-.patch b/queue-5.15/power-reset-nvmem-reboot-mode-respect-cell-size-for-.patch new file mode 100644 index 0000000000..12a6acff08 --- /dev/null +++ b/queue-5.15/power-reset-nvmem-reboot-mode-respect-cell-size-for-.patch @@ -0,0 +1,64 @@ +From b73194f4487558c7a718606899f7a34023ce5615 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 14 Dec 2025 19:16:18 +0000 +Subject: power: reset: nvmem-reboot-mode: respect cell size for + nvmem_cell_write + +From: Alexander Koskovich + +[ Upstream commit 36b05629226413836cfbb3fbe6689cd188bca156 ] + +Some platforms expose reboot mode cells that are smaller than an +unsigned int, in which cases lead to write failures. Read the cell +first to determine actual size and only write the number of bytes the +cell can hold. + +Fixes: 7a78a7f7695b ("power: reset: nvmem-reboot-mode: use NVMEM as reboot mode write interface") +Signed-off-by: Alexander Koskovich +Link: https://patch.msgid.link/20251214191529.2470580-1-akoskovich@pm.me +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/reset/nvmem-reboot-mode.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +diff --git a/drivers/power/reset/nvmem-reboot-mode.c b/drivers/power/reset/nvmem-reboot-mode.c +index e229308d43e25..819f11bae788b 100644 +--- a/drivers/power/reset/nvmem-reboot-mode.c ++++ b/drivers/power/reset/nvmem-reboot-mode.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + + struct nvmem_reboot_mode { + struct reboot_mode_driver reboot; +@@ -19,12 +20,22 @@ struct nvmem_reboot_mode { + static int nvmem_reboot_mode_write(struct reboot_mode_driver *reboot, + unsigned int magic) + { +- int ret; + struct nvmem_reboot_mode *nvmem_rbm; ++ size_t buf_len; ++ void *buf; ++ int ret; + + nvmem_rbm = container_of(reboot, struct nvmem_reboot_mode, reboot); + +- ret = nvmem_cell_write(nvmem_rbm->cell, &magic, sizeof(magic)); ++ buf = nvmem_cell_read(nvmem_rbm->cell, &buf_len); ++ if (IS_ERR(buf)) ++ return PTR_ERR(buf); ++ kfree(buf); ++ ++ if (buf_len > sizeof(magic)) ++ return -EINVAL; ++ ++ ret = nvmem_cell_write(nvmem_rbm->cell, &magic, buf_len); + if (ret < 0) + dev_err(reboot->dev, "update reboot mode bits failed\n"); + +-- +2.51.0 + diff --git a/queue-5.15/power-supply-ab8500-fix-use-after-free-in-power_supp.patch b/queue-5.15/power-supply-ab8500-fix-use-after-free-in-power_supp.patch new file mode 100644 index 0000000000..79b45ab24b --- /dev/null +++ b/queue-5.15/power-supply-ab8500-fix-use-after-free-in-power_supp.patch @@ -0,0 +1,104 @@ +From 1945766e7b8e69602908b572df8d3e04ac0a2f68 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:35:58 +0100 +Subject: power: supply: ab8500: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit c4af8a98bb52825a5331ae1d0604c0ea6956ba4b ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Commit 1c1f13a006ed ("power: supply: ab8500: Move to componentized +binding") introduced this issue during a refactorization. Fix this racy +use-after-free by making sure the IRQ is requested _after_ the +registration of the `power_supply` handle. + +Fixes: 1c1f13a006ed ("power: supply: ab8500: Move to componentized binding") +Signed-off-by: Waqar Hameed +Reviewed-by: Linus Walleij +Link: https://patch.msgid.link/ccf83a09942cb8dda3dff70b2682f2c2e9cb97f2.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/ab8500_charger.c | 40 +++++++++++++-------------- + 1 file changed, 20 insertions(+), 20 deletions(-) + +diff --git a/drivers/power/supply/ab8500_charger.c b/drivers/power/supply/ab8500_charger.c +index 6af946ca06a94..cce2f3c13b797 100644 +--- a/drivers/power/supply/ab8500_charger.c ++++ b/drivers/power/supply/ab8500_charger.c +@@ -3457,26 +3457,6 @@ static int ab8500_charger_probe(struct platform_device *pdev) + return ret; + } + +- /* Request interrupts */ +- for (i = 0; i < ARRAY_SIZE(ab8500_charger_irq); i++) { +- irq = platform_get_irq_byname(pdev, ab8500_charger_irq[i].name); +- if (irq < 0) +- return irq; +- +- ret = devm_request_threaded_irq(dev, +- irq, NULL, ab8500_charger_irq[i].isr, +- IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT, +- ab8500_charger_irq[i].name, di); +- +- if (ret != 0) { +- dev_err(dev, "failed to request %s IRQ %d: %d\n" +- , ab8500_charger_irq[i].name, irq, ret); +- return ret; +- } +- dev_dbg(dev, "Requested %s IRQ %d: %d\n", +- ab8500_charger_irq[i].name, irq, ret); +- } +- + /* initialize lock */ + spin_lock_init(&di->usb_state.usb_lock); + mutex_init(&di->usb_ipt_crnt_lock); +@@ -3607,6 +3587,26 @@ static int ab8500_charger_probe(struct platform_device *pdev) + return PTR_ERR(di->usb_chg.psy); + } + ++ /* Request interrupts */ ++ for (i = 0; i < ARRAY_SIZE(ab8500_charger_irq); i++) { ++ irq = platform_get_irq_byname(pdev, ab8500_charger_irq[i].name); ++ if (irq < 0) ++ return irq; ++ ++ ret = devm_request_threaded_irq(dev, ++ irq, NULL, ab8500_charger_irq[i].isr, ++ IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT, ++ ab8500_charger_irq[i].name, di); ++ ++ if (ret != 0) { ++ dev_err(dev, "failed to request %s IRQ %d: %d\n" ++ , ab8500_charger_irq[i].name, irq, ret); ++ return ret; ++ } ++ dev_dbg(dev, "Requested %s IRQ %d: %d\n", ++ ab8500_charger_irq[i].name, irq, ret); ++ } ++ + /* + * Check what battery we have, since we always have the USB + * psy, use that as a handle. +-- +2.51.0 + diff --git a/queue-5.15/power-supply-ab8500-use-core-battery-parser.patch b/queue-5.15/power-supply-ab8500-use-core-battery-parser.patch new file mode 100644 index 0000000000..14367560b7 --- /dev/null +++ b/queue-5.15/power-supply-ab8500-use-core-battery-parser.patch @@ -0,0 +1,147 @@ +From 5bd6e95aad44485d9d499ddec0659fca44c799ba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Nov 2021 16:53:11 +0100 +Subject: power: supply: ab8500: Use core battery parser + +From: Linus Walleij + +[ Upstream commit 59f1b854706d4d6830a3ed0f6b535a2ba5d425a6 ] + +This deploys the core battery DT parser to read the basic properties +of the battery. We only use very little of it as we start out, but +we will improve as we go along. + +Signed-off-by: Linus Walleij +Signed-off-by: Sebastian Reichel +Stable-dep-of: c4af8a98bb52 ("power: supply: ab8500: Fix use-after-free in power_supply_changed()") +Signed-off-by: Sasha Levin +--- + drivers/power/supply/ab8500-bm.h | 3 +-- + drivers/power/supply/ab8500_bmdata.c | 31 +++++++++++---------------- + drivers/power/supply/ab8500_charger.c | 16 +++++++++----- + 3 files changed, 24 insertions(+), 26 deletions(-) + +diff --git a/drivers/power/supply/ab8500-bm.h b/drivers/power/supply/ab8500-bm.h +index d11405b7ee1aa..33c7e15f5d96e 100644 +--- a/drivers/power/supply/ab8500-bm.h ++++ b/drivers/power/supply/ab8500-bm.h +@@ -570,8 +570,7 @@ int ab8500_fg_inst_curr_start(struct ab8500_fg *di); + int ab8500_fg_inst_curr_finalize(struct ab8500_fg *di, int *res); + int ab8500_fg_inst_curr_started(struct ab8500_fg *di); + int ab8500_fg_inst_curr_done(struct ab8500_fg *di); +-int ab8500_bm_of_probe(struct device *dev, +- struct device_node *np, ++int ab8500_bm_of_probe(struct power_supply *psy, + struct ab8500_bm_data *bm); + + extern struct platform_driver ab8500_fg_driver; +diff --git a/drivers/power/supply/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c +index bfc1245d79123..a515dfad4c3fd 100644 +--- a/drivers/power/supply/ab8500_bmdata.c ++++ b/drivers/power/supply/ab8500_bmdata.c +@@ -488,29 +488,22 @@ struct ab8500_bm_data ab8500_bm_data = { + .n_chg_in_curr = ARRAY_SIZE(ab8500_charge_input_curr_map), + }; + +-int ab8500_bm_of_probe(struct device *dev, +- struct device_node *np, ++int ab8500_bm_of_probe(struct power_supply *psy, + struct ab8500_bm_data *bm) + { + const struct batres_vs_temp *tmp_batres_tbl; +- struct device_node *battery_node; +- const char *btech; ++ struct power_supply_battery_info info; ++ struct device *dev = &psy->dev; ++ int ret; + int i; + +- battery_node = of_parse_phandle(np, "monitored-battery", 0); +- if (!battery_node) { +- dev_err(dev, "battery node or reference missing\n"); +- return -EINVAL; ++ ret = power_supply_get_battery_info(psy, &info); ++ if (ret) { ++ dev_err(dev, "cannot retrieve battery info\n"); ++ return ret; + } + +- btech = of_get_property(battery_node, "stericsson,battery-type", NULL); +- if (!btech) { +- dev_warn(dev, "missing property battery-name/type\n"); +- of_node_put(battery_node); +- return -EINVAL; +- } +- +- if (strncmp(btech, "LION", 4) == 0) { ++ if (info.technology == POWER_SUPPLY_TECHNOLOGY_LION) { + bm->no_maintenance = true; + bm->chg_unknown_bat = true; + bm->bat_type[BATTERY_UNKNOWN].charge_full_design = 2600; +@@ -520,8 +513,8 @@ int ab8500_bm_of_probe(struct device *dev, + bm->bat_type[BATTERY_UNKNOWN].normal_vol_lvl = 4200; + } + +- if (of_property_read_bool(battery_node, "thermistor-on-batctrl")) { +- if (strncmp(btech, "LION", 4) == 0) ++ if (of_property_read_bool(psy->of_node, "thermistor-on-batctrl")) { ++ if (info.technology == POWER_SUPPLY_TECHNOLOGY_LION) + tmp_batres_tbl = temp_to_batres_tbl_9100; + else + tmp_batres_tbl = temp_to_batres_tbl_thermistor; +@@ -536,7 +529,7 @@ int ab8500_bm_of_probe(struct device *dev, + for (i = 0; i < bm->n_btypes; ++i) + bm->bat_type[i].batres_tbl = tmp_batres_tbl; + +- of_node_put(battery_node); ++ power_supply_put_battery_info(psy, &info); + + return 0; + } +diff --git a/drivers/power/supply/ab8500_charger.c b/drivers/power/supply/ab8500_charger.c +index a4f766fc7c9d7..6af946ca06a94 100644 +--- a/drivers/power/supply/ab8500_charger.c ++++ b/drivers/power/supply/ab8500_charger.c +@@ -3413,11 +3413,6 @@ static int ab8500_charger_probe(struct platform_device *pdev) + + di->bm = &ab8500_bm_data; + +- ret = ab8500_bm_of_probe(dev, np, di->bm); +- if (ret) { +- dev_err(dev, "failed to get battery information\n"); +- return ret; +- } + di->autopower_cfg = of_property_read_bool(np, "autopower_cfg"); + + /* get parent data */ +@@ -3490,9 +3485,11 @@ static int ab8500_charger_probe(struct platform_device *pdev) + di->invalid_charger_detect_state = 0; + + /* AC and USB supply config */ ++ ac_psy_cfg.of_node = np; + ac_psy_cfg.supplied_to = supply_interface; + ac_psy_cfg.num_supplicants = ARRAY_SIZE(supply_interface); + ac_psy_cfg.drv_data = &di->ac_chg; ++ usb_psy_cfg.of_node = np; + usb_psy_cfg.supplied_to = supply_interface; + usb_psy_cfg.num_supplicants = ARRAY_SIZE(supply_interface); + usb_psy_cfg.drv_data = &di->usb_chg; +@@ -3610,6 +3607,15 @@ static int ab8500_charger_probe(struct platform_device *pdev) + return PTR_ERR(di->usb_chg.psy); + } + ++ /* ++ * Check what battery we have, since we always have the USB ++ * psy, use that as a handle. ++ */ ++ ret = ab8500_bm_of_probe(di->usb_chg.psy, di->bm); ++ if (ret) ++ return dev_err_probe(dev, ret, ++ "failed to get battery information\n"); ++ + /* Identify the connected charger types during startup */ + charger_status = ab8500_charger_detect_chargers(di, true); + if (charger_status & AC_PW_CONN) { +-- +2.51.0 + diff --git a/queue-5.15/power-supply-ab8500_bmdata-use-standard-phandle.patch b/queue-5.15/power-supply-ab8500_bmdata-use-standard-phandle.patch new file mode 100644 index 0000000000..fa2be3cc66 --- /dev/null +++ b/queue-5.15/power-supply-ab8500_bmdata-use-standard-phandle.patch @@ -0,0 +1,39 @@ +From 83df36c05c9321e72e63e74eb05908be9701f042 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 7 Oct 2021 00:40:07 +0200 +Subject: power: supply: ab8500_bmdata: Use standard phandle + +From: Linus Walleij + +[ Upstream commit 1a6784359540dcfbf4fa73c07868b80c8405cc14 ] + +Look up the battery using the "monitored-battery" phandle +as is nowadays a standard DT binding. The actual bindings +for these charger elements are not upstream so let's sort +out this mess by conforming to the standard. + +Signed-off-by: Linus Walleij +Signed-off-by: Sebastian Reichel +Stable-dep-of: c4af8a98bb52 ("power: supply: ab8500: Fix use-after-free in power_supply_changed()") +Signed-off-by: Sasha Levin +--- + drivers/power/supply/ab8500_bmdata.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/power/supply/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c +index 6f5fb794042ce..bfc1245d79123 100644 +--- a/drivers/power/supply/ab8500_bmdata.c ++++ b/drivers/power/supply/ab8500_bmdata.c +@@ -497,8 +497,7 @@ int ab8500_bm_of_probe(struct device *dev, + const char *btech; + int i; + +- /* get phandle to 'battery-info' node */ +- battery_node = of_parse_phandle(np, "battery", 0); ++ battery_node = of_parse_phandle(np, "monitored-battery", 0); + if (!battery_node) { + dev_err(dev, "battery node or reference missing\n"); + return -EINVAL; +-- +2.51.0 + diff --git a/queue-5.15/power-supply-act8945a-fix-use-after-free-in-power_su.patch b/queue-5.15/power-supply-act8945a-fix-use-after-free-in-power_su.patch new file mode 100644 index 0000000000..ac4960b6a9 --- /dev/null +++ b/queue-5.15/power-supply-act8945a-fix-use-after-free-in-power_su.patch @@ -0,0 +1,77 @@ +From 587e7bc73646ea2222332afa887939017c7cfd62 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:35:59 +0100 +Subject: power: supply: act8945a: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 3291c51d4684d048dd2eb91b5b65fcfdaf72141f ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: a09209acd6a8 ("power: supply: act8945a_charger: Add status change update support") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/bcf3a23b5187df0bba54a8c8fe09f8b8a0031dee.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/act8945a_charger.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/drivers/power/supply/act8945a_charger.c b/drivers/power/supply/act8945a_charger.c +index e9b5f42837729..e9cb06daecea9 100644 +--- a/drivers/power/supply/act8945a_charger.c ++++ b/drivers/power/supply/act8945a_charger.c +@@ -597,14 +597,6 @@ static int act8945a_charger_probe(struct platform_device *pdev) + return irq ?: -ENXIO; + } + +- ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, +- IRQF_TRIGGER_FALLING, "act8945a_interrupt", +- charger); +- if (ret) { +- dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); +- return ret; +- } +- + charger->desc.name = "act8945a-charger"; + charger->desc.get_property = act8945a_charger_get_property; + charger->desc.properties = act8945a_charger_props; +@@ -625,6 +617,14 @@ static int act8945a_charger_probe(struct platform_device *pdev) + return PTR_ERR(charger->psy); + } + ++ ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, ++ IRQF_TRIGGER_FALLING, "act8945a_interrupt", ++ charger); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); ++ return ret; ++ } ++ + platform_set_drvdata(pdev, charger); + + INIT_WORK(&charger->work, act8945a_work); +-- +2.51.0 + diff --git a/queue-5.15/power-supply-bq256xx-fix-use-after-free-in-power_sup.patch b/queue-5.15/power-supply-bq256xx-fix-use-after-free-in-power_sup.patch new file mode 100644 index 0000000000..f0ad79c03c --- /dev/null +++ b/queue-5.15/power-supply-bq256xx-fix-use-after-free-in-power_sup.patch @@ -0,0 +1,73 @@ +From 07d3333f28673ec58f0a917ee34ad4f222d102bf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:35:59 +0100 +Subject: power: supply: bq256xx: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 8005843369723d9c8975b7c4202d1b85d6125302 ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: 32e4978bb920 ("power: supply: bq256xx: Introduce the BQ256XX charger driver") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/39da6da8cc060fa0382ca859f65071e791cb6119.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/bq256xx_charger.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/power/supply/bq256xx_charger.c b/drivers/power/supply/bq256xx_charger.c +index 9fb7b44e890af..86f8ce4035209 100644 +--- a/drivers/power/supply/bq256xx_charger.c ++++ b/drivers/power/supply/bq256xx_charger.c +@@ -1675,6 +1675,12 @@ static int bq256xx_probe(struct i2c_client *client, + usb_register_notifier(bq->usb3_phy, &bq->usb_nb); + } + ++ ret = bq256xx_power_supply_init(bq, &psy_cfg, dev); ++ if (ret) { ++ dev_err(dev, "Failed to register power supply\n"); ++ return ret; ++ } ++ + if (client->irq) { + ret = devm_request_threaded_irq(dev, client->irq, NULL, + bq256xx_irq_handler_thread, +@@ -1687,12 +1693,6 @@ static int bq256xx_probe(struct i2c_client *client, + } + } + +- ret = bq256xx_power_supply_init(bq, &psy_cfg, dev); +- if (ret) { +- dev_err(dev, "Failed to register power supply\n"); +- return ret; +- } +- + ret = bq256xx_hw_init(bq); + if (ret) { + dev_err(dev, "Cannot initialize the chip.\n"); +-- +2.51.0 + diff --git a/queue-5.15/power-supply-bq25980-fix-use-after-free-in-power_sup.patch b/queue-5.15/power-supply-bq25980-fix-use-after-free-in-power_sup.patch new file mode 100644 index 0000000000..875c3a24a0 --- /dev/null +++ b/queue-5.15/power-supply-bq25980-fix-use-after-free-in-power_sup.patch @@ -0,0 +1,73 @@ +From babc62fa4c794cbf79e71ca3298d0c4bf8a3f6d4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:35:59 +0100 +Subject: power: supply: bq25980: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 5f0b1cb41906e86b64bf69f5ededb83b0d757c27 ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: 5069185fc18e ("power: supply: bq25980: Add support for the BQ259xx family") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/8763035cadb959e14787b3837f2d3db61f6e1c34.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/bq25980_charger.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/power/supply/bq25980_charger.c b/drivers/power/supply/bq25980_charger.c +index 0008c229fd9c7..a93919c4ea275 100644 +--- a/drivers/power/supply/bq25980_charger.c ++++ b/drivers/power/supply/bq25980_charger.c +@@ -1241,6 +1241,12 @@ static int bq25980_probe(struct i2c_client *client, + return ret; + } + ++ ret = bq25980_power_supply_init(bq, dev); ++ if (ret) { ++ dev_err(dev, "Failed to register power supply\n"); ++ return ret; ++ } ++ + if (client->irq) { + ret = devm_request_threaded_irq(dev, client->irq, NULL, + bq25980_irq_handler_thread, +@@ -1251,12 +1257,6 @@ static int bq25980_probe(struct i2c_client *client, + return ret; + } + +- ret = bq25980_power_supply_init(bq, dev); +- if (ret) { +- dev_err(dev, "Failed to register power supply\n"); +- return ret; +- } +- + ret = bq25980_hw_init(bq); + if (ret) { + dev_err(dev, "Cannot initialize the chip.\n"); +-- +2.51.0 + diff --git a/queue-5.15/power-supply-bq27xxx-fix-wrong-errno-when-bus-ops-ar.patch b/queue-5.15/power-supply-bq27xxx-fix-wrong-errno-when-bus-ops-ar.patch new file mode 100644 index 0000000000..e3e63ac65e --- /dev/null +++ b/queue-5.15/power-supply-bq27xxx-fix-wrong-errno-when-bus-ops-ar.patch @@ -0,0 +1,61 @@ +From 064900a485cff15106be86c32d4f601e15fa4c5b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Dec 2025 16:34:36 +0800 +Subject: power: supply: bq27xxx: fix wrong errno when bus ops are unsupported + +From: Haotian Zhang + +[ Upstream commit 688364a11647dc09ba1e4429313e0008066ec790 ] + +bq27xxx_write(), bq27xxx_read_block(), and bq27xxx_write_block() +return -EPERM when the bus callback pointer is NULL. A NULL callback +indicates the operation is not supported by the bus/driver, +not that permission is denied. + +Return -EOPNOTSUPP instead of -EPERM when di->bus.write/ +read_bulk/write_bulk is NULL. + +Fixes: 14073f6614f6 ("power: supply: bq27xxx: Add bulk transfer bus methods") +Signed-off-by: Haotian Zhang +Reviewed-by: Matt Ranostay +Link: https://patch.msgid.link/20251204083436.1367-1-vulab@iscas.ac.cn +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/bq27xxx_battery.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c +index 2b45187234001..844d8fef014f1 100644 +--- a/drivers/power/supply/bq27xxx_battery.c ++++ b/drivers/power/supply/bq27xxx_battery.c +@@ -1162,7 +1162,7 @@ static inline int bq27xxx_write(struct bq27xxx_device_info *di, int reg_index, + return -EINVAL; + + if (!di->bus.write) +- return -EPERM; ++ return -EOPNOTSUPP; + + ret = di->bus.write(di, di->regs[reg_index], value, single); + if (ret < 0) +@@ -1181,7 +1181,7 @@ static inline int bq27xxx_read_block(struct bq27xxx_device_info *di, int reg_ind + return -EINVAL; + + if (!di->bus.read_bulk) +- return -EPERM; ++ return -EOPNOTSUPP; + + ret = di->bus.read_bulk(di, di->regs[reg_index], data, len); + if (ret < 0) +@@ -1200,7 +1200,7 @@ static inline int bq27xxx_write_block(struct bq27xxx_device_info *di, int reg_in + return -EINVAL; + + if (!di->bus.write_bulk) +- return -EPERM; ++ return -EOPNOTSUPP; + + ret = di->bus.write_bulk(di, di->regs[reg_index], data, len); + if (ret < 0) +-- +2.51.0 + diff --git a/queue-5.15/power-supply-cpcap-battery-fix-use-after-free-in-pow.patch b/queue-5.15/power-supply-cpcap-battery-fix-use-after-free-in-pow.patch new file mode 100644 index 0000000000..0f63a4a99d --- /dev/null +++ b/queue-5.15/power-supply-cpcap-battery-fix-use-after-free-in-pow.patch @@ -0,0 +1,70 @@ +From 6a4c01b8bf2218238cebd34c86eb7bb8eab8da24 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:36:00 +0100 +Subject: power: supply: cpcap-battery: Fix use-after-free in + power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 642f33e34b969eedec334738fd5df95d2dc42742 ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: 874b2adbed12 ("power: supply: cpcap-battery: Add a battery driver") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/81db58d610c9a51a68184f856cd431a934cccee2.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/cpcap-battery.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/power/supply/cpcap-battery.c b/drivers/power/supply/cpcap-battery.c +index 8d62d4241da3d..053d376700447 100644 +--- a/drivers/power/supply/cpcap-battery.c ++++ b/drivers/power/supply/cpcap-battery.c +@@ -1071,10 +1071,6 @@ static int cpcap_battery_probe(struct platform_device *pdev) + + platform_set_drvdata(pdev, ddata); + +- error = cpcap_battery_init_interrupts(pdev, ddata); +- if (error) +- return error; +- + error = cpcap_battery_init_iio(ddata); + if (error) + return error; +@@ -1091,6 +1087,10 @@ static int cpcap_battery_probe(struct platform_device *pdev) + return error; + } + ++ error = cpcap_battery_init_interrupts(pdev, ddata); ++ if (error) ++ return error; ++ + atomic_set(&ddata->active, 1); + + error = cpcap_battery_calibrate(ddata); +-- +2.51.0 + diff --git a/queue-5.15/power-supply-goldfish-fix-use-after-free-in-power_su.patch b/queue-5.15/power-supply-goldfish-fix-use-after-free-in-power_su.patch new file mode 100644 index 0000000000..3c91da20ac --- /dev/null +++ b/queue-5.15/power-supply-goldfish-fix-use-after-free-in-power_su.patch @@ -0,0 +1,73 @@ +From 5d973782d63abea102cb748be51264f3da258928 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:36:00 +0100 +Subject: power: supply: goldfish: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit b2ce982e2e0c888dc55c888ad0e20ea04daf2e6b ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: 84d7b7687489 ("power: Add battery driver for goldfish emulator") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/500a606bb6fb6f2bb8d797e19a00cea9dd7b03c1.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/goldfish_battery.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/power/supply/goldfish_battery.c b/drivers/power/supply/goldfish_battery.c +index bf1754355c9fc..c7502fa8efa7b 100644 +--- a/drivers/power/supply/goldfish_battery.c ++++ b/drivers/power/supply/goldfish_battery.c +@@ -226,12 +226,6 @@ static int goldfish_battery_probe(struct platform_device *pdev) + return -ENODEV; + } + +- ret = devm_request_irq(&pdev->dev, data->irq, +- goldfish_battery_interrupt, +- IRQF_SHARED, pdev->name, data); +- if (ret) +- return ret; +- + psy_cfg.drv_data = data; + + data->ac = power_supply_register(&pdev->dev, &ac_desc, &psy_cfg); +@@ -247,6 +241,12 @@ static int goldfish_battery_probe(struct platform_device *pdev) + + platform_set_drvdata(pdev, data); + ++ ret = devm_request_irq(&pdev->dev, data->irq, ++ goldfish_battery_interrupt, ++ IRQF_SHARED, pdev->name, data); ++ if (ret) ++ return ret; ++ + GOLDFISH_BATTERY_WRITE(data, BATTERY_INT_ENABLE, BATTERY_INT_MASK); + return 0; + } +-- +2.51.0 + diff --git a/queue-5.15/power-supply-rt9455-fix-use-after-free-in-power_supp.patch b/queue-5.15/power-supply-rt9455-fix-use-after-free-in-power_supp.patch new file mode 100644 index 0000000000..8f5128bcbd --- /dev/null +++ b/queue-5.15/power-supply-rt9455-fix-use-after-free-in-power_supp.patch @@ -0,0 +1,78 @@ +From 74669540b7ee92f079762cc8498fdfa5bd2f14bb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:36:02 +0100 +Subject: power: supply: rt9455: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit e2febe375e5ea5afed92f4cd9711bde8f24ee6d2 ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: e86d69dd786e ("power_supply: Add support for Richtek RT9455 battery charger") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/1567d831e04c3e2fcb9e18dd36b7bcba4634581a.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/rt9455_charger.c | 17 +++++++++-------- + 1 file changed, 9 insertions(+), 8 deletions(-) + +diff --git a/drivers/power/supply/rt9455_charger.c b/drivers/power/supply/rt9455_charger.c +index a84afccd509f1..89b414fac6c3a 100644 +--- a/drivers/power/supply/rt9455_charger.c ++++ b/drivers/power/supply/rt9455_charger.c +@@ -1665,6 +1665,15 @@ static int rt9455_probe(struct i2c_client *client, + rt9455_charger_config.supplied_to = rt9455_charger_supplied_to; + rt9455_charger_config.num_supplicants = + ARRAY_SIZE(rt9455_charger_supplied_to); ++ ++ info->charger = devm_power_supply_register(dev, &rt9455_charger_desc, ++ &rt9455_charger_config); ++ if (IS_ERR(info->charger)) { ++ dev_err(dev, "Failed to register charger\n"); ++ ret = PTR_ERR(info->charger); ++ goto put_usb_notifier; ++ } ++ + ret = devm_request_threaded_irq(dev, client->irq, NULL, + rt9455_irq_handler_thread, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, +@@ -1680,14 +1689,6 @@ static int rt9455_probe(struct i2c_client *client, + goto put_usb_notifier; + } + +- info->charger = devm_power_supply_register(dev, &rt9455_charger_desc, +- &rt9455_charger_config); +- if (IS_ERR(info->charger)) { +- dev_err(dev, "Failed to register charger\n"); +- ret = PTR_ERR(info->charger); +- goto put_usb_notifier; +- } +- + return 0; + + put_usb_notifier: +-- +2.51.0 + diff --git a/queue-5.15/power-supply-sbs-battery-fix-use-after-free-in-power.patch b/queue-5.15/power-supply-sbs-battery-fix-use-after-free-in-power.patch new file mode 100644 index 0000000000..1d52c2ae46 --- /dev/null +++ b/queue-5.15/power-supply-sbs-battery-fix-use-after-free-in-power.patch @@ -0,0 +1,101 @@ +From 8f95ab93b8e6a04afb0da56c51c06c7639bf51ea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:36:02 +0100 +Subject: power: supply: sbs-battery: Fix use-after-free in + power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 8d59cf3887fbabacef53bfba473e33e8a8d9d07b ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. Keep the old behavior of +just printing a warning in case of any failures during the IRQ request +and finishing the probe successfully. + +Fixes: d2cec82c2880 ("power: sbs-battery: Request threaded irq and fix dev callback cookie") +Signed-off-by: Waqar Hameed +Reviewed-by: Phil Reid +Link: https://patch.msgid.link/0ef896e002495e615157b482d18a437af19ddcd0.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/sbs-battery.c | 36 +++++++++++++++--------------- + 1 file changed, 18 insertions(+), 18 deletions(-) + +diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c +index c4a95b01463ae..a633130a768df 100644 +--- a/drivers/power/supply/sbs-battery.c ++++ b/drivers/power/supply/sbs-battery.c +@@ -1173,24 +1173,6 @@ static int sbs_probe(struct i2c_client *client) + + i2c_set_clientdata(client, chip); + +- if (!chip->gpio_detect) +- goto skip_gpio; +- +- irq = gpiod_to_irq(chip->gpio_detect); +- if (irq <= 0) { +- dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq); +- goto skip_gpio; +- } +- +- rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq, +- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, +- dev_name(&client->dev), chip); +- if (rc) { +- dev_warn(&client->dev, "Failed to request irq: %d\n", rc); +- goto skip_gpio; +- } +- +-skip_gpio: + /* + * Before we register, we might need to make sure we can actually talk + * to the battery. +@@ -1216,6 +1198,24 @@ static int sbs_probe(struct i2c_client *client) + return dev_err_probe(&client->dev, PTR_ERR(chip->power_supply), + "Failed to register power supply\n"); + ++ if (!chip->gpio_detect) ++ goto out; ++ ++ irq = gpiod_to_irq(chip->gpio_detect); ++ if (irq <= 0) { ++ dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq); ++ goto out; ++ } ++ ++ rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq, ++ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, ++ dev_name(&client->dev), chip); ++ if (rc) { ++ dev_warn(&client->dev, "Failed to request irq: %d\n", rc); ++ goto out; ++ } ++ ++out: + dev_info(&client->dev, + "%s: battery gas gauge device registered\n", client->name); + +-- +2.51.0 + diff --git a/queue-5.15/power-supply-wm97xx-fix-null-pointer-dereference-in-.patch b/queue-5.15/power-supply-wm97xx-fix-null-pointer-dereference-in-.patch new file mode 100644 index 0000000000..23c5e349d7 --- /dev/null +++ b/queue-5.15/power-supply-wm97xx-fix-null-pointer-dereference-in-.patch @@ -0,0 +1,98 @@ +From 70389cb3d01fbd17e6b894fdaffc554f0cf618cb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:46:24 +0100 +Subject: power: supply: wm97xx: Fix NULL pointer dereference in + power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 39fe0eac6d755ef215026518985fcf8de9360e9e ] + +In `probe()`, `request_irq()` is called before allocating/registering a +`power_supply` handle. If an interrupt is fired between the call to +`request_irq()` and `power_supply_register()`, the `power_supply` handle +will be used uninitialized in `power_supply_changed()` in +`wm97xx_bat_update()` (triggered from the interrupt handler). This will +lead to a `NULL` pointer dereference since + +Fix this racy `NULL` pointer dereference by making sure the IRQ is +requested _after_ the registration of the `power_supply` handle. Since +the IRQ is the last thing requests in the `probe()` now, remove the +error path for freeing it. Instead add one for unregistering the +`power_supply` handle when IRQ request fails. + +Fixes: 7c87942aef52 ("wm97xx_battery: Use irq to detect charger state") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/97b55f0479a932eea7213844bf66f28a974e27a2.1766270196.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/wm97xx_battery.c | 34 +++++++++++++++------------ + 1 file changed, 19 insertions(+), 15 deletions(-) + +diff --git a/drivers/power/supply/wm97xx_battery.c b/drivers/power/supply/wm97xx_battery.c +index a0e1eaa25d93e..e2a41f9c903c5 100644 +--- a/drivers/power/supply/wm97xx_battery.c ++++ b/drivers/power/supply/wm97xx_battery.c +@@ -178,12 +178,6 @@ static int wm97xx_bat_probe(struct platform_device *dev) + "failed to get charge GPIO\n"); + if (charge_gpiod) { + gpiod_set_consumer_name(charge_gpiod, "BATT CHRG"); +- ret = request_irq(gpiod_to_irq(charge_gpiod), +- wm97xx_chrg_irq, 0, +- "AC Detect", dev); +- if (ret) +- return dev_err_probe(&dev->dev, ret, +- "failed to request GPIO irq\n"); + props++; /* POWER_SUPPLY_PROP_STATUS */ + } + +@@ -199,10 +193,8 @@ static int wm97xx_bat_probe(struct platform_device *dev) + props++; /* POWER_SUPPLY_PROP_VOLTAGE_MIN */ + + prop = kcalloc(props, sizeof(*prop), GFP_KERNEL); +- if (!prop) { +- ret = -ENOMEM; +- goto err3; +- } ++ if (!prop) ++ return -ENOMEM; + + prop[i++] = POWER_SUPPLY_PROP_PRESENT; + if (charge_gpiod) +@@ -236,15 +228,27 @@ static int wm97xx_bat_probe(struct platform_device *dev) + schedule_work(&bat_work); + } else { + ret = PTR_ERR(bat_psy); +- goto err4; ++ goto free; ++ } ++ ++ if (charge_gpiod) { ++ ret = request_irq(gpiod_to_irq(charge_gpiod), wm97xx_chrg_irq, ++ 0, "AC Detect", dev); ++ if (ret) { ++ dev_err_probe(&dev->dev, ret, ++ "failed to request GPIO irq\n"); ++ goto unregister; ++ } + } + + return 0; +-err4: ++ ++unregister: ++ power_supply_unregister(bat_psy); ++ ++free: + kfree(prop); +-err3: +- if (charge_gpiod) +- free_irq(gpiod_to_irq(charge_gpiod), dev); ++ + return ret; + } + +-- +2.51.0 + diff --git a/queue-5.15/powerpc-eeh-fix-recursive-pci_lock_rescan_remove-loc.patch b/queue-5.15/powerpc-eeh-fix-recursive-pci_lock_rescan_remove-loc.patch new file mode 100644 index 0000000000..4e9d7b931e --- /dev/null +++ b/queue-5.15/powerpc-eeh-fix-recursive-pci_lock_rescan_remove-loc.patch @@ -0,0 +1,275 @@ +From 4971772180a9da59550e4cdc5513bf0902271b80 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 10 Dec 2025 08:25:59 -0600 +Subject: powerpc/eeh: fix recursive pci_lock_rescan_remove locking in EEH + event handling +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Narayana Murty N + +[ Upstream commit 815a8d2feb5615ae7f0b5befd206af0b0160614c ] + +The recent commit 1010b4c012b0 ("powerpc/eeh: Make EEH driver device +hotplug safe") restructured the EEH driver to improve synchronization +with the PCI hotplug layer. + +However, it inadvertently moved pci_lock_rescan_remove() outside its +intended scope in eeh_handle_normal_event(), leading to broken PCI +error reporting and improper EEH event triggering. Specifically, +eeh_handle_normal_event() acquired pci_lock_rescan_remove() before +calling eeh_pe_bus_get(), but eeh_pe_bus_get() itself attempts to +acquire the same lock internally, causing nested locking and disrupting +normal EEH event handling paths. + +This patch adds a boolean parameter do_lock to _eeh_pe_bus_get(), +with two public wrappers: + eeh_pe_bus_get() with locking enabled. + eeh_pe_bus_get_nolock() that skips locking. + +Callers that already hold pci_lock_rescan_remove() now use +eeh_pe_bus_get_nolock() to avoid recursive lock acquisition. + +Additionally, pci_lock_rescan_remove() calls are restored to the correct +position—after eeh_pe_bus_get() and immediately before iterating affected +PEs and devices. This ensures EEH-triggered PCI removes occur under proper +bus rescan locking without recursive lock contention. + +The eeh_pe_loc_get() function has been split into two functions: + eeh_pe_loc_get(struct eeh_pe *pe) which retrieves the loc for given PE. + eeh_pe_loc_get_bus(struct pci_bus *bus) which retrieves the location + code for given bus. + +This resolves lockdep warnings such as: + +[ 84.964298] [ T928] ============================================ +[ 84.964304] [ T928] WARNING: possible recursive locking detected +[ 84.964311] [ T928] 6.18.0-rc3 #51 Not tainted +[ 84.964315] [ T928] -------------------------------------------- +[ 84.964320] [ T928] eehd/928 is trying to acquire lock: +[ 84.964324] [ T928] c000000003b29d58 (pci_rescan_remove_lock){+.+.}-{3:3}, at: pci_lock_rescan_remove+0x28/0x40 +[ 84.964342] [ T928] + but task is already holding lock: +[ 84.964347] [ T928] c000000003b29d58 (pci_rescan_remove_lock){+.+.}-{3:3}, at: pci_lock_rescan_remove+0x28/0x40 +[ 84.964357] [ T928] + other info that might help us debug this: +[ 84.964363] [ T928] Possible unsafe locking scenario: + +[ 84.964367] [ T928] CPU0 +[ 84.964370] [ T928] ---- +[ 84.964373] [ T928] lock(pci_rescan_remove_lock); +[ 84.964378] [ T928] lock(pci_rescan_remove_lock); +[ 84.964383] [ T928] + *** DEADLOCK *** + +[ 84.964388] [ T928] May be due to missing lock nesting notation + +[ 84.964393] [ T928] 1 lock held by eehd/928: +[ 84.964397] [ T928] #0: c000000003b29d58 (pci_rescan_remove_lock){+.+.}-{3:3}, at: pci_lock_rescan_remove+0x28/0x40 +[ 84.964408] [ T928] + stack backtrace: +[ 84.964414] [ T928] CPU: 2 UID: 0 PID: 928 Comm: eehd Not tainted 6.18.0-rc3 #51 VOLUNTARY +[ 84.964417] [ T928] Hardware name: IBM,9080-HEX POWER10 (architected) 0x800200 0xf000006 of:IBM,FW1060.00 (NH1060_022) hv:phyp pSeries +[ 84.964419] [ T928] Call Trace: +[ 84.964420] [ T928] [c0000011a7157990] [c000000001705de4] dump_stack_lvl+0xc8/0x130 (unreliable) +[ 84.964424] [ T928] [c0000011a71579d0] [c0000000002f66e0] print_deadlock_bug+0x430/0x440 +[ 84.964428] [ T928] [c0000011a7157a70] [c0000000002fd0c0] __lock_acquire+0x1530/0x2d80 +[ 84.964431] [ T928] [c0000011a7157ba0] [c0000000002fea54] lock_acquire+0x144/0x410 +[ 84.964433] [ T928] [c0000011a7157cb0] [c0000011a7157cb0] __mutex_lock+0xf4/0x1050 +[ 84.964436] [ T928] [c0000011a7157e00] [c000000000de21d8] pci_lock_rescan_remove+0x28/0x40 +[ 84.964439] [ T928] [c0000011a7157e20] [c00000000004ed98] eeh_pe_bus_get+0x48/0xc0 +[ 84.964442] [ T928] [c0000011a7157e50] [c000000000050434] eeh_handle_normal_event+0x64/0xa60 +[ 84.964446] [ T928] [c0000011a7157f30] [c000000000051de8] eeh_event_handler+0xf8/0x190 +[ 84.964450] [ T928] [c0000011a7157f90] [c0000000002747ac] kthread+0x16c/0x180 +[ 84.964453] [ T928] [c0000011a7157fe0] [c00000000000ded8] start_kernel_thread+0x14/0x18 + + +Fixes: 1010b4c012b0 ("powerpc/eeh: Make EEH driver device hotplug safe") +Signed-off-by: Narayana Murty N +Reviewed-by: Sourabh Jain +Reviewed-by: Mahesh Salgaonkar +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/20251210142559.8874-1-nnmlinux@linux.ibm.com +Signed-off-by: Sasha Levin +--- + arch/powerpc/include/asm/eeh.h | 2 + + arch/powerpc/kernel/eeh_driver.c | 11 ++--- + arch/powerpc/kernel/eeh_pe.c | 74 ++++++++++++++++++++++++++++++-- + 3 files changed, 78 insertions(+), 9 deletions(-) + +diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h +index b1a5bba2e0b94..2c9dc733accfd 100644 +--- a/arch/powerpc/include/asm/eeh.h ++++ b/arch/powerpc/include/asm/eeh.h +@@ -289,6 +289,8 @@ void eeh_pe_dev_traverse(struct eeh_pe *root, + void eeh_pe_restore_bars(struct eeh_pe *pe); + const char *eeh_pe_loc_get(struct eeh_pe *pe); + struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe); ++const char *eeh_pe_loc_get_bus(struct pci_bus *bus); ++struct pci_bus *eeh_pe_bus_get_nolock(struct eeh_pe *pe); + + void eeh_show_enabled(void); + int __init eeh_init(struct eeh_ops *ops); +diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c +index 2f13d906e1fcb..20106e490b9c6 100644 +--- a/arch/powerpc/kernel/eeh_driver.c ++++ b/arch/powerpc/kernel/eeh_driver.c +@@ -847,7 +847,7 @@ void eeh_handle_normal_event(struct eeh_pe *pe) + + pci_lock_rescan_remove(); + +- bus = eeh_pe_bus_get(pe); ++ bus = eeh_pe_bus_get_nolock(pe); + if (!bus) { + pr_err("%s: Cannot find PCI bus for PHB#%x-PE#%x\n", + __func__, pe->phb->global_number, pe->addr); +@@ -878,14 +878,15 @@ void eeh_handle_normal_event(struct eeh_pe *pe) + /* Log the event */ + if (pe->type & EEH_PE_PHB) { + pr_err("EEH: Recovering PHB#%x, location: %s\n", +- pe->phb->global_number, eeh_pe_loc_get(pe)); ++ pe->phb->global_number, eeh_pe_loc_get_bus(bus)); + } else { + struct eeh_pe *phb_pe = eeh_phb_pe_get(pe->phb); + + pr_err("EEH: Recovering PHB#%x-PE#%x\n", + pe->phb->global_number, pe->addr); + pr_err("EEH: PE location: %s, PHB location: %s\n", +- eeh_pe_loc_get(pe), eeh_pe_loc_get(phb_pe)); ++ eeh_pe_loc_get_bus(bus), ++ eeh_pe_loc_get_bus(eeh_pe_bus_get_nolock(phb_pe))); + } + + #ifdef CONFIG_STACKTRACE +@@ -1093,7 +1094,7 @@ void eeh_handle_normal_event(struct eeh_pe *pe) + eeh_pe_state_clear(pe, EEH_PE_PRI_BUS, true); + eeh_pe_dev_mode_mark(pe, EEH_DEV_REMOVED); + +- bus = eeh_pe_bus_get(pe); ++ bus = eeh_pe_bus_get_nolock(pe); + if (bus) + pci_hp_remove_devices(bus); + else +@@ -1217,7 +1218,7 @@ void eeh_handle_special_event(void) + (phb_pe->state & EEH_PE_RECOVERING)) + continue; + +- bus = eeh_pe_bus_get(phb_pe); ++ bus = eeh_pe_bus_get_nolock(phb_pe); + if (!bus) { + pr_err("%s: Cannot find PCI bus for " + "PHB#%x-PE#%x\n", +diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c +index fea58e9546f98..6f69242142e0d 100644 +--- a/arch/powerpc/kernel/eeh_pe.c ++++ b/arch/powerpc/kernel/eeh_pe.c +@@ -811,6 +811,24 @@ void eeh_pe_restore_bars(struct eeh_pe *pe) + const char *eeh_pe_loc_get(struct eeh_pe *pe) + { + struct pci_bus *bus = eeh_pe_bus_get(pe); ++ return eeh_pe_loc_get_bus(bus); ++} ++ ++/** ++ * eeh_pe_loc_get_bus - Retrieve location code binding to the given PCI bus ++ * @bus: PCI bus ++ * ++ * Retrieve the location code associated with the given PCI bus. If the bus ++ * is a root bus, the location code is fetched from the PHB device tree node ++ * or root port. Otherwise, the location code is obtained from the device ++ * tree node of the upstream bridge of the bus. The function walks up the ++ * bus hierarchy if necessary, checking each node for the appropriate ++ * location code property ("ibm,io-base-loc-code" for root buses, ++ * "ibm,slot-location-code" for others). If no location code is found, ++ * returns "N/A". ++ */ ++const char *eeh_pe_loc_get_bus(struct pci_bus *bus) ++{ + struct device_node *dn; + const char *loc = NULL; + +@@ -837,8 +855,9 @@ const char *eeh_pe_loc_get(struct eeh_pe *pe) + } + + /** +- * eeh_pe_bus_get - Retrieve PCI bus according to the given PE ++ * _eeh_pe_bus_get - Retrieve PCI bus according to the given PE + * @pe: EEH PE ++ * @do_lock: Is the caller already held the pci_lock_rescan_remove? + * + * Retrieve the PCI bus according to the given PE. Basically, + * there're 3 types of PEs: PHB/Bus/Device. For PHB PE, the +@@ -846,7 +865,7 @@ const char *eeh_pe_loc_get(struct eeh_pe *pe) + * returned for BUS PE. However, we don't have associated PCI + * bus for DEVICE PE. + */ +-struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe) ++static struct pci_bus *_eeh_pe_bus_get(struct eeh_pe *pe, bool do_lock) + { + struct eeh_dev *edev; + struct pci_dev *pdev; +@@ -861,11 +880,58 @@ struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe) + + /* Retrieve the parent PCI bus of first (top) PCI device */ + edev = list_first_entry_or_null(&pe->edevs, struct eeh_dev, entry); +- pci_lock_rescan_remove(); ++ if (do_lock) ++ pci_lock_rescan_remove(); + pdev = eeh_dev_to_pci_dev(edev); + if (pdev) + bus = pdev->bus; +- pci_unlock_rescan_remove(); ++ if (do_lock) ++ pci_unlock_rescan_remove(); + + return bus; + } ++ ++/** ++ * eeh_pe_bus_get - Retrieve PCI bus associated with the given EEH PE, locking ++ * if needed ++ * @pe: Pointer to the EEH PE ++ * ++ * This function is a wrapper around _eeh_pe_bus_get(), which retrieves the PCI ++ * bus associated with the provided EEH PE structure. It acquires the PCI ++ * rescans lock to ensure safe access to shared data during the retrieval ++ * process. This function should be used when the caller requires the PCI bus ++ * while holding the rescan/remove lock, typically during operations that modify ++ * or inspect PCIe device state in a safe manner. ++ * ++ * RETURNS: ++ * A pointer to the PCI bus associated with the EEH PE, or NULL if none found. ++ */ ++ ++struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe) ++{ ++ return _eeh_pe_bus_get(pe, true); ++} ++ ++/** ++ * eeh_pe_bus_get_nolock - Retrieve PCI bus associated with the given EEH PE ++ * without locking ++ * @pe: Pointer to the EEH PE ++ * ++ * This function is a variant of _eeh_pe_bus_get() that retrieves the PCI bus ++ * associated with the specified EEH PE without acquiring the ++ * pci_lock_rescan_remove lock. It should only be used when the caller can ++ * guarantee safe access to PE structures without the need for that lock, ++ * typically in contexts where the lock is already held locking is otherwise ++ * managed. ++ * ++ * RETURNS: ++ * pointer to the PCI bus associated with the EEH PE, or NULL if none is found. ++ * ++ * NOTE: ++ * Use this function carefully to avoid race conditions and data corruption. ++ */ ++ ++struct pci_bus *eeh_pe_bus_get_nolock(struct eeh_pe *pe) ++{ ++ return _eeh_pe_bus_get(pe, false); ++} +-- +2.51.0 + diff --git a/queue-5.15/powerpc-uaccess-move-barrier_nospec-out-of-allow_rea.patch b/queue-5.15/powerpc-uaccess-move-barrier_nospec-out-of-allow_rea.patch new file mode 100644 index 0000000000..f7f17642ae --- /dev/null +++ b/queue-5.15/powerpc-uaccess-move-barrier_nospec-out-of-allow_rea.patch @@ -0,0 +1,98 @@ +From 9686c93b7dc2c60565a9373482c881f86b5379ad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Dec 2025 12:20:49 +0100 +Subject: powerpc/uaccess: Move barrier_nospec() out of + allow_read_{from/write}_user() + +From: Christophe Leroy + +[ Upstream commit 5fbc09eb0b4f4b1a4b33abebacbeee0d29f195e9 ] + +Commit 74e19ef0ff80 ("uaccess: Add speculation barrier to +copy_from_user()") added a redundant barrier_nospec() in +copy_from_user(), because powerpc is already calling +barrier_nospec() in allow_read_from_user() and +allow_read_write_user(). But on other architectures that +call to barrier_nospec() was missing. So change powerpc +instead of reverting the above commit and having to fix +other architectures one by one. This is now possible +because barrier_nospec() has also been added in +copy_from_user_iter(). + +Move barrier_nospec() out of allow_read_from_user() and +allow_read_write_user(). This will also allow reuse of those +functions when implementing masked user access which doesn't +require barrier_nospec(). + +Don't add it back in raw_copy_from_user() as it is already called +by copy_from_user() and copy_from_user_iter(). + +Fixes: 74e19ef0ff80 ("uaccess: Add speculation barrier to copy_from_user()") +Signed-off-by: Christophe Leroy +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/f29612105c5fcbc8ceb7303808ddc1a781f0f6b5.1766574657.git.chleroy@kernel.org +Signed-off-by: Sasha Levin +--- + arch/powerpc/include/asm/kup.h | 2 -- + arch/powerpc/include/asm/uaccess.h | 4 ++++ + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/arch/powerpc/include/asm/kup.h b/arch/powerpc/include/asm/kup.h +index 34ff86e3686ea..eb048b6be6d83 100644 +--- a/arch/powerpc/include/asm/kup.h ++++ b/arch/powerpc/include/asm/kup.h +@@ -81,7 +81,6 @@ static __always_inline void setup_kup(void) + + static __always_inline void allow_read_from_user(const void __user *from, unsigned long size) + { +- barrier_nospec(); + allow_user_access(NULL, from, size, KUAP_READ); + } + +@@ -93,7 +92,6 @@ static __always_inline void allow_write_to_user(void __user *to, unsigned long s + static __always_inline void allow_read_write_user(void __user *to, const void __user *from, + unsigned long size) + { +- barrier_nospec(); + allow_user_access(to, from, size, KUAP_READ_WRITE); + } + +diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h +index 6013a7fc74ba7..7781f6dd51390 100644 +--- a/arch/powerpc/include/asm/uaccess.h ++++ b/arch/powerpc/include/asm/uaccess.h +@@ -276,6 +276,7 @@ do { \ + __typeof__(sizeof(*(ptr))) __gu_size = sizeof(*(ptr)); \ + \ + might_fault(); \ ++ barrier_nospec(); \ + allow_read_from_user(__gu_addr, __gu_size); \ + __get_user_size_allowed(__gu_val, __gu_addr, __gu_size, __gu_err); \ + prevent_read_from_user(__gu_addr, __gu_size); \ +@@ -304,6 +305,7 @@ raw_copy_in_user(void __user *to, const void __user *from, unsigned long n) + { + unsigned long ret; + ++ barrier_nospec(); + allow_read_write_user(to, from, n); + ret = __copy_tofrom_user(to, from, n); + prevent_read_write_user(to, from, n); +@@ -392,6 +394,7 @@ static __must_check inline bool user_access_begin(const void __user *ptr, size_t + + might_fault(); + ++ barrier_nospec(); + allow_read_write_user((void __user *)ptr, ptr, len); + return true; + } +@@ -408,6 +411,7 @@ user_read_access_begin(const void __user *ptr, size_t len) + + might_fault(); + ++ barrier_nospec(); + allow_read_from_user(ptr, len); + return true; + } +-- +2.51.0 + diff --git a/queue-5.15/procfs-fix-missing-rcu-protection-when-reading-real_.patch b/queue-5.15/procfs-fix-missing-rcu-protection-when-reading-real_.patch new file mode 100644 index 0000000000..6add8fb4ac --- /dev/null +++ b/queue-5.15/procfs-fix-missing-rcu-protection-when-reading-real_.patch @@ -0,0 +1,59 @@ +From 9dda12b99a1617e95473646bd7be841039781488 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 16:30:07 +0800 +Subject: procfs: fix missing RCU protection when reading real_parent in + do_task_stat() + +From: Jinliang Zheng + +[ Upstream commit 76149d53502cf17ef3ae454ff384551236fba867 ] + +When reading /proc/[pid]/stat, do_task_stat() accesses task->real_parent +without proper RCU protection, which leads to: + + cpu 0 cpu 1 + ----- ----- + do_task_stat + var = task->real_parent + release_task + call_rcu(delayed_put_task_struct) + task_tgid_nr_ns(var) + rcu_read_lock <--- Too late to protect task->real_parent! + task_pid_ptr <--- UAF! + rcu_read_unlock + +This patch uses task_ppid_nr_ns() instead of task_tgid_nr_ns() to add +proper RCU protection for accessing task->real_parent. + +Link: https://lkml.kernel.org/r/20260128083007.3173016-1-alexjlzheng@tencent.com +Fixes: 06fffb1267c9 ("do_task_stat: don't take rcu_read_lock()") +Signed-off-by: Jinliang Zheng +Acked-by: Oleg Nesterov +Cc: David Hildenbrand +Cc: Ingo Molnar +Cc: Lorenzo Stoakes +Cc: Mateusz Guzik +Cc: ruippan +Cc: Usama Arif +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/proc/array.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/proc/array.c b/fs/proc/array.c +index 2ff568dc58387..6f30b5a316678 100644 +--- a/fs/proc/array.c ++++ b/fs/proc/array.c +@@ -510,7 +510,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, + rsslim = READ_ONCE(sig->rlim[RLIMIT_RSS].rlim_cur); + + sid = task_session_nr_ns(task, ns); +- ppid = task_tgid_nr_ns(task->real_parent, ns); ++ ppid = task_ppid_nr_ns(task, ns); + pgid = task_pgrp_nr_ns(task, ns); + + unlock_task_sighand(task, &flags); +-- +2.51.0 + diff --git a/queue-5.15/pstore-ram-fix-buffer-overflow-in-persistent_ram_sav.patch b/queue-5.15/pstore-ram-fix-buffer-overflow-in-persistent_ram_sav.patch new file mode 100644 index 0000000000..5acdcbf873 --- /dev/null +++ b/queue-5.15/pstore-ram-fix-buffer-overflow-in-persistent_ram_sav.patch @@ -0,0 +1,92 @@ +From f165687e0dacb9a6761995a7646b24b890702e25 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 1 Feb 2026 13:22:40 +0000 +Subject: pstore/ram: fix buffer overflow in persistent_ram_save_old() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Sai Ritvik Tanksalkar + +[ Upstream commit 5669645c052f235726a85f443769b6fc02f66762 ] + +persistent_ram_save_old() can be called multiple times for the same +persistent_ram_zone (e.g., via ramoops_pstore_read -> ramoops_get_next_prz +for PSTORE_TYPE_DMESG records). + +Currently, the function only allocates prz->old_log when it is NULL, +but it unconditionally updates prz->old_log_size to the current buffer +size and then performs memcpy_fromio() using this new size. If the +buffer size has grown since the first allocation (which can happen +across different kernel boot cycles), this leads to: + +1. A heap buffer overflow (OOB write) in the memcpy_fromio() calls +2. A subsequent OOB read when ramoops_pstore_read() accesses the buffer + using the incorrect (larger) old_log_size + +The KASAN splat would look similar to: + BUG: KASAN: slab-out-of-bounds in ramoops_pstore_read+0x... + Read of size N at addr ... by task ... + +The conditions are likely extremely hard to hit: + + 0. Crash with a ramoops write of less-than-record-max-size bytes. + 1. Reboot: ramoops registers, pstore_get_records(0) reads old crash, + allocates old_log with size X + 2. Crash handler registered, timer started (if pstore_update_ms >= 0) + 3. Oops happens (non-fatal, system continues) + 4. pstore_dump() writes oops via ramoops_pstore_write() size Y (>X) + 5. pstore_new_entry = 1, pstore_timer_kick() called + 6. System continues running (not a panic oops) + 7. Timer fires after pstore_update_ms milliseconds + 8. pstore_timefunc() → schedule_work() → pstore_dowork() → pstore_get_records(1) + 9. ramoops_get_next_prz() → persistent_ram_save_old() + 10. buffer_size() returns Y, but old_log is X bytes + 11. Y > X: memcpy_fromio() overflows heap + + Requirements: + - a prior crash record exists that did not fill the record size + (almost impossible since the crash handler writes as much as it + can possibly fit into the record, capped by max record size and + the kmsg buffer almost always exceeds the max record size) + - pstore_update_ms >= 0 (disabled by default) + - Non-fatal oops (system survives) + +Free and reallocate the buffer when the new size differs from the +previously allocated size. This ensures old_log always has sufficient +space for the data being copied. + +Fixes: 201e4aca5aa1 ("pstore/ram: Should update old dmesg buffer before reading") +Signed-off-by: Sai Ritvik Tanksalkar +Link: https://patch.msgid.link/20260201132240.2948732-1-stanksal@purdue.edu +Signed-off-by: Kees Cook +Signed-off-by: Sasha Levin +--- + fs/pstore/ram_core.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c +index ec321722384dc..8eb4bea7295b4 100644 +--- a/fs/pstore/ram_core.c ++++ b/fs/pstore/ram_core.c +@@ -298,6 +298,17 @@ void persistent_ram_save_old(struct persistent_ram_zone *prz) + if (!size) + return; + ++ /* ++ * If the existing buffer is differently sized, free it so a new ++ * one is allocated. This can happen when persistent_ram_save_old() ++ * is called early in boot and later for a timer-triggered ++ * survivable crash when the crash dumps don't match in size ++ * (which would be extremely unlikely given kmsg buffers usually ++ * exceed prz buffer sizes). ++ */ ++ if (prz->old_log && prz->old_log_size != size) ++ persistent_ram_free_old(prz); ++ + if (!prz->old_log) { + persistent_ram_ecc_old(prz); + prz->old_log = kmalloc(size, GFP_KERNEL); +-- +2.51.0 + diff --git a/queue-5.15/rdma-core-add-rdma_rw_max_sge-helper-for-sq-sizing.patch b/queue-5.15/rdma-core-add-rdma_rw_max_sge-helper-for-sq-sizing.patch new file mode 100644 index 0000000000..03d4ab4b47 --- /dev/null +++ b/queue-5.15/rdma-core-add-rdma_rw_max_sge-helper-for-sq-sizing.patch @@ -0,0 +1,159 @@ +From 40468703e4da9ff056d17edb53147571684da01d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 19:53:59 -0500 +Subject: RDMA/core: add rdma_rw_max_sge() helper for SQ sizing + +From: Chuck Lever + +[ Upstream commit afcae7d7b8a278a6c29e064f99e5bafd4ac1fb37 ] + +svc_rdma_accept() computes sc_sq_depth as the sum of rq_depth and the +number of rdma_rw contexts (ctxts). This value is used to allocate the +Send CQ and to initialize the sc_sq_avail credit pool. + +However, when the device uses memory registration for RDMA operations, +rdma_rw_init_qp() inflates the QP's max_send_wr by a factor of three +per context to account for REG and INV work requests. The Send CQ and +credit pool remain sized for only one work request per context, +causing Send Queue exhaustion under heavy NFS WRITE workloads. + +Introduce rdma_rw_max_sge() to compute the actual number of Send Queue +entries required for a given number of rdma_rw contexts. Upper layer +protocols call this helper before creating a Queue Pair so that their +Send CQs and credit accounting match the QP's true capacity. + +Update svc_rdma_accept() to use rdma_rw_max_sge() when computing +sc_sq_depth, ensuring the credit pool reflects the work requests +that rdma_rw_init_qp() will reserve. + +Reviewed-by: Christoph Hellwig +Fixes: 00bd1439f464 ("RDMA/rw: Support threshold for registration vs scattering to local pages") +Signed-off-by: Chuck Lever +Link: https://patch.msgid.link/20260128005400.25147-5-cel@kernel.org +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/rw.c | 53 +++++++++++++++++------- + include/rdma/rw.h | 2 + + net/sunrpc/xprtrdma/svc_rdma_transport.c | 8 +++- + 3 files changed, 46 insertions(+), 17 deletions(-) + +diff --git a/drivers/infiniband/core/rw.c b/drivers/infiniband/core/rw.c +index e35ad03ec7e92..3b6cfa6362e04 100644 +--- a/drivers/infiniband/core/rw.c ++++ b/drivers/infiniband/core/rw.c +@@ -661,34 +661,57 @@ unsigned int rdma_rw_mr_factor(struct ib_device *device, u32 port_num, + } + EXPORT_SYMBOL(rdma_rw_mr_factor); + ++/** ++ * rdma_rw_max_send_wr - compute max Send WRs needed for RDMA R/W contexts ++ * @dev: RDMA device ++ * @port_num: port number ++ * @max_rdma_ctxs: number of rdma_rw_ctx structures ++ * @create_flags: QP create flags (pass IB_QP_CREATE_INTEGRITY_EN if ++ * data integrity will be enabled on the QP) ++ * ++ * Returns the total number of Send Queue entries needed for ++ * @max_rdma_ctxs. The result accounts for memory registration and ++ * invalidation work requests when the device requires them. ++ * ++ * ULPs use this to size Send Queues and Send CQs before creating a ++ * Queue Pair. ++ */ ++unsigned int rdma_rw_max_send_wr(struct ib_device *dev, u32 port_num, ++ unsigned int max_rdma_ctxs, u32 create_flags) ++{ ++ unsigned int factor = 1; ++ unsigned int result; ++ ++ if (create_flags & IB_QP_CREATE_INTEGRITY_EN || ++ rdma_rw_can_use_mr(dev, port_num)) ++ factor += 2; /* reg + inv */ ++ ++ if (check_mul_overflow(factor, max_rdma_ctxs, &result)) ++ return UINT_MAX; ++ return result; ++} ++EXPORT_SYMBOL(rdma_rw_max_send_wr); ++ + void rdma_rw_init_qp(struct ib_device *dev, struct ib_qp_init_attr *attr) + { +- u32 factor; ++ unsigned int factor = 1; + + WARN_ON_ONCE(attr->port_num == 0); + + /* +- * Each context needs at least one RDMA READ or WRITE WR. +- * +- * For some hardware we might need more, eventually we should ask the +- * HCA driver for a multiplier here. +- */ +- factor = 1; +- +- /* +- * If the device needs MRs to perform RDMA READ or WRITE operations, +- * we'll need two additional MRs for the registrations and the +- * invalidation. ++ * If the device uses MRs to perform RDMA READ or WRITE operations, ++ * or if data integrity is enabled, account for registration and ++ * invalidation work requests. + */ + if (attr->create_flags & IB_QP_CREATE_INTEGRITY_EN || + rdma_rw_can_use_mr(dev, attr->port_num)) +- factor += 2; /* inv + reg */ ++ factor += 2; /* reg + inv */ + + attr->cap.max_send_wr += factor * attr->cap.max_rdma_ctxs; + + /* +- * But maybe we were just too high in the sky and the device doesn't +- * even support all we need, and we'll have to live with what we get.. ++ * The device might not support all we need, and we'll have to ++ * live with what we get. + */ + attr->cap.max_send_wr = + min_t(u32, attr->cap.max_send_wr, dev->attrs.max_qp_wr); +diff --git a/include/rdma/rw.h b/include/rdma/rw.h +index d606cac482338..9a8f4b76ce588 100644 +--- a/include/rdma/rw.h ++++ b/include/rdma/rw.h +@@ -66,6 +66,8 @@ int rdma_rw_ctx_post(struct rdma_rw_ctx *ctx, struct ib_qp *qp, u32 port_num, + + unsigned int rdma_rw_mr_factor(struct ib_device *device, u32 port_num, + unsigned int maxpages); ++unsigned int rdma_rw_max_send_wr(struct ib_device *dev, u32 port_num, ++ unsigned int max_rdma_ctxs, u32 create_flags); + void rdma_rw_init_qp(struct ib_device *dev, struct ib_qp_init_attr *attr); + int rdma_rw_init_mrs(struct ib_qp *qp, struct ib_qp_init_attr *attr); + void rdma_rw_cleanup_mrs(struct ib_qp *qp); +diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c +index c5721b75d32a7..45b0fef0b5e26 100644 +--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c ++++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c +@@ -418,7 +418,10 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + newxprt->sc_max_bc_requests = 2; + } + +- /* Arbitrary estimate of the needed number of rdma_rw contexts. ++ /* Estimate the needed number of rdma_rw contexts. The maximum ++ * Read and Write chunks have one segment each. Each request ++ * can involve one Read chunk and either a Write chunk or Reply ++ * chunk; thus a factor of three. + */ + maxpayload = min(xprt->xpt_server->sv_max_payload, + RPCSVC_MAXPAYLOAD_RDMA); +@@ -426,7 +429,8 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + rdma_rw_mr_factor(dev, newxprt->sc_port_num, + maxpayload >> PAGE_SHIFT); + +- newxprt->sc_sq_depth = rq_depth + ctxts; ++ newxprt->sc_sq_depth = rq_depth + ++ rdma_rw_max_send_wr(dev, newxprt->sc_port_num, ctxts, 0); + if (newxprt->sc_sq_depth > dev->attrs.max_qp_wr) + newxprt->sc_sq_depth = dev->attrs.max_qp_wr; + atomic_set(&newxprt->sc_sq_avail, newxprt->sc_sq_depth); +-- +2.51.0 + diff --git a/queue-5.15/rdma-core-fix-a-couple-of-obvious-typos-in-comments.patch b/queue-5.15/rdma-core-fix-a-couple-of-obvious-typos-in-comments.patch new file mode 100644 index 0000000000..22d4e894e9 --- /dev/null +++ b/queue-5.15/rdma-core-fix-a-couple-of-obvious-typos-in-comments.patch @@ -0,0 +1,50 @@ +From 56377aefea4f7746fdeb44576aa2f4cc69c7fb1e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Oct 2023 11:29:41 -0400 +Subject: RDMA/core: Fix a couple of obvious typos in comments + +From: Chuck Lever + +[ Upstream commit 0aa44595d61ca9e61239f321fec799518884feb3 ] + +Fix typos. + +Signed-off-by: Chuck Lever +Link: https://lore.kernel.org/r/169643338101.8035.6826446669479247727.stgit@manet.1015granger.net +Signed-off-by: Leon Romanovsky +Stable-dep-of: afcae7d7b8a2 ("RDMA/core: add rdma_rw_max_sge() helper for SQ sizing") +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/rw.c | 2 +- + include/rdma/ib_verbs.h | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/infiniband/core/rw.c b/drivers/infiniband/core/rw.c +index 5221cce656759..e35ad03ec7e92 100644 +--- a/drivers/infiniband/core/rw.c ++++ b/drivers/infiniband/core/rw.c +@@ -676,7 +676,7 @@ void rdma_rw_init_qp(struct ib_device *dev, struct ib_qp_init_attr *attr) + factor = 1; + + /* +- * If the devices needs MRs to perform RDMA READ or WRITE operations, ++ * If the device needs MRs to perform RDMA READ or WRITE operations, + * we'll need two additional MRs for the registrations and the + * invalidation. + */ +diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h +index f4257c2e96b6d..eada75848eec3 100644 +--- a/include/rdma/ib_verbs.h ++++ b/include/rdma/ib_verbs.h +@@ -1073,7 +1073,7 @@ struct ib_qp_cap { + + /* + * Maximum number of rdma_rw_ctx structures in flight at a time. +- * ib_create_qp() will calculate the right amount of neededed WRs ++ * ib_create_qp() will calculate the right amount of needed WRs + * and MRs based on this. + */ + u32 max_rdma_ctxs; +-- +2.51.0 + diff --git a/queue-5.15/rdma-hns-notify-ulp-of-remaining-soft-wcs-during-res.patch b/queue-5.15/rdma-hns-notify-ulp-of-remaining-soft-wcs-during-res.patch new file mode 100644 index 0000000000..f2f6789cc3 --- /dev/null +++ b/queue-5.15/rdma-hns-notify-ulp-of-remaining-soft-wcs-during-res.patch @@ -0,0 +1,70 @@ +From c75a77aced665ad8f6170f8b3c108a223151b010 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 4 Jan 2026 14:40:57 +0800 +Subject: RDMA/hns: Notify ULP of remaining soft-WCs during reset + +From: Chengchang Tang + +[ Upstream commit 0789f929900d85b80b343c5f04f8b9444e991384 ] + +During a reset, software-generated WCs cannot be reported via +interrupts. This may cause the ULP to miss some WCs. + +To avoid this, add check in the CQ arm process: if a hardware reset +has occurred and there are still unreported soft-WCs, notify the ULP +to handle the remaining WCs, thereby preventing any loss of completions. + +Fixes: 626903e9355b ("RDMA/hns: Add support for reporting wc as software mode") +Signed-off-by: Chengchang Tang +Signed-off-by: Junxian Huang +Link: https://patch.msgid.link/20260104064057.1582216-5-huangjunxian6@hisilicon.com +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 23 ++++++++++++++++++++++ + 1 file changed, 23 insertions(+) + +diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +index 8baf6fb2d1fa5..43b661f971882 100644 +--- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c ++++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +@@ -3376,6 +3376,23 @@ static void hns_roce_v2_write_cqc(struct hns_roce_dev *hr_dev, + HNS_ROCE_V2_CQ_DEFAULT_INTERVAL); + } + ++static bool left_sw_wc(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq) ++{ ++ struct hns_roce_qp *hr_qp; ++ ++ list_for_each_entry(hr_qp, &hr_cq->sq_list, sq_node) { ++ if (hr_qp->sq.head != hr_qp->sq.tail) ++ return true; ++ } ++ ++ list_for_each_entry(hr_qp, &hr_cq->rq_list, rq_node) { ++ if (hr_qp->rq.head != hr_qp->rq.tail) ++ return true; ++ } ++ ++ return false; ++} ++ + static int hns_roce_v2_req_notify_cq(struct ib_cq *ibcq, + enum ib_cq_notify_flags flags) + { +@@ -3384,6 +3401,12 @@ static int hns_roce_v2_req_notify_cq(struct ib_cq *ibcq, + struct hns_roce_v2_db cq_db = {}; + u32 notify_flag; + ++ if (hr_dev->state >= HNS_ROCE_DEVICE_STATE_RST_DOWN) { ++ if ((flags & IB_CQ_REPORT_MISSED_EVENTS) && ++ left_sw_wc(hr_dev, hr_cq)) ++ return 1; ++ return 0; ++ } + /* + * flags = 0, then notify_flag : next + * flags = 1, then notify flag : solocited +-- +2.51.0 + diff --git a/queue-5.15/rdma-rtrs-server-remove-dead-code.patch b/queue-5.15/rdma-rtrs-server-remove-dead-code.patch new file mode 100644 index 0000000000..bc722e3598 --- /dev/null +++ b/queue-5.15/rdma-rtrs-server-remove-dead-code.patch @@ -0,0 +1,57 @@ +From 5c35a12e159d45e0b9e13697ce428d51b9ee88e5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Dec 2025 10:38:19 +0800 +Subject: RDMA/rtrs: server: remove dead code + +From: Honggang LI + +[ Upstream commit a3572bdc3a028ca47f77d7166ac95b719cf77d50 ] + +As rkey had been initialized to zero, the WARN_ON_ONCE should never been +triggered. Remove it. + +Fixes: 9cb837480424 ("RDMA/rtrs: server: main functionality") +Signed-off-by: Honggang LI +Link: https://patch.msgid.link/20251224023819.138846-1-honggangli@163.com +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/ulp/rtrs/rtrs-srv.c | 8 +------- + 1 file changed, 1 insertion(+), 7 deletions(-) + +diff --git a/drivers/infiniband/ulp/rtrs/rtrs-srv.c b/drivers/infiniband/ulp/rtrs/rtrs-srv.c +index ec3ab8df32f7d..0979bb728da24 100644 +--- a/drivers/infiniband/ulp/rtrs/rtrs-srv.c ++++ b/drivers/infiniband/ulp/rtrs/rtrs-srv.c +@@ -212,7 +212,6 @@ static int rdma_write_sg(struct rtrs_srv_op *id) + size_t sg_cnt; + int err, offset; + bool need_inval; +- u32 rkey = 0; + struct ib_reg_wr rwr; + struct ib_sge *plist; + struct ib_sge list; +@@ -244,11 +243,6 @@ static int rdma_write_sg(struct rtrs_srv_op *id) + wr->wr.num_sge = 1; + wr->remote_addr = le64_to_cpu(id->rd_msg->desc[0].addr); + wr->rkey = le32_to_cpu(id->rd_msg->desc[0].key); +- if (rkey == 0) +- rkey = wr->rkey; +- else +- /* Only one key is actually used */ +- WARN_ON_ONCE(rkey != wr->rkey); + + wr->wr.opcode = IB_WR_RDMA_WRITE; + wr->wr.wr_cqe = &io_comp_cqe; +@@ -281,7 +275,7 @@ static int rdma_write_sg(struct rtrs_srv_op *id) + inv_wr.opcode = IB_WR_SEND_WITH_INV; + inv_wr.wr_cqe = &io_comp_cqe; + inv_wr.send_flags = 0; +- inv_wr.ex.invalidate_rkey = rkey; ++ inv_wr.ex.invalidate_rkey = wr->rkey; + } + + imm_wr.wr.next = NULL; +-- +2.51.0 + diff --git a/queue-5.15/rdma-rtrs-srv-correct-the-checking-of-ib_map_mr_sg.patch b/queue-5.15/rdma-rtrs-srv-correct-the-checking-of-ib_map_mr_sg.patch new file mode 100644 index 0000000000..7f800f4d9b --- /dev/null +++ b/queue-5.15/rdma-rtrs-srv-correct-the-checking-of-ib_map_mr_sg.patch @@ -0,0 +1,38 @@ +From 15fe9353257ca9ebc2979bd972c9ea6c7ff25acd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 17 Nov 2022 18:19:40 +0800 +Subject: RDMA/rtrs-srv: Correct the checking of ib_map_mr_sg + +From: Guoqing Jiang + +[ Upstream commit 102d2f70ec0999a5cde181f1ccbe8a81cba45b10 ] + +We should check with nr_sgt, also the only successful case is that +all sg elements are mapped, so make it explicitly. + +Acked-by: Jack Wang +Signed-off-by: Guoqing Jiang +Link: https://lore.kernel.org/r/20221117101945.6317-4-guoqing.jiang@linux.dev +Signed-off-by: Leon Romanovsky +Stable-dep-of: 83835f7c07b5 ("RDMA/rtrs-srv: fix SG mapping") +Signed-off-by: Sasha Levin +--- + drivers/infiniband/ulp/rtrs/rtrs-srv.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/infiniband/ulp/rtrs/rtrs-srv.c b/drivers/infiniband/ulp/rtrs/rtrs-srv.c +index d2ac3a37f46e1..b5f3cbf0fd79c 100644 +--- a/drivers/infiniband/ulp/rtrs/rtrs-srv.c ++++ b/drivers/infiniband/ulp/rtrs/rtrs-srv.c +@@ -627,7 +627,7 @@ static int map_cont_bufs(struct rtrs_srv_path *srv_path) + } + nr = ib_map_mr_sg(mr, sgt->sgl, nr_sgt, + NULL, max_chunk_size); +- if (nr < 0 || nr < sgt->nents) { ++ if (nr != nr_sgt) { + err = nr < 0 ? nr : -EINVAL; + goto dereg_mr; + } +-- +2.51.0 + diff --git a/queue-5.15/rdma-rtrs-srv-fix-sg-mapping.patch b/queue-5.15/rdma-rtrs-srv-fix-sg-mapping.patch new file mode 100644 index 0000000000..e8e5fa158d --- /dev/null +++ b/queue-5.15/rdma-rtrs-srv-fix-sg-mapping.patch @@ -0,0 +1,85 @@ +From 61acd55ea3f61f15290a54bcb07027a04df8a4e4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 17:15:08 +0100 +Subject: RDMA/rtrs-srv: fix SG mapping + +From: Roman Penyaev + +[ Upstream commit 83835f7c07b523c7ca2a5ad0a511670b5810539e ] + +This fixes the following error on the server side: + + RTRS server session allocation failed: -EINVAL + +caused by the caller of the `ib_dma_map_sg()`, which does not expect +less mapped entries, than requested, which is in the order of things +and can be easily reproduced on the machine with enabled IOMMU. + +The fix is to treat any positive number of mapped sg entries as a +successful mapping and cache DMA addresses by traversing modified +SG table. + +Fixes: 9cb837480424 ("RDMA/rtrs: server: main functionality") +Signed-off-by: Roman Penyaev +Signed-off-by: Jack Wang +Signed-off-by: Grzegorz Prajsner +Link: https://patch.msgid.link/20260107161517.56357-2-haris.iqbal@ionos.com +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/ulp/rtrs/rtrs-srv.c | 25 ++++++++++++++++++++----- + 1 file changed, 20 insertions(+), 5 deletions(-) + +diff --git a/drivers/infiniband/ulp/rtrs/rtrs-srv.c b/drivers/infiniband/ulp/rtrs/rtrs-srv.c +index b5f3cbf0fd79c..8ccac2bce5123 100644 +--- a/drivers/infiniband/ulp/rtrs/rtrs-srv.c ++++ b/drivers/infiniband/ulp/rtrs/rtrs-srv.c +@@ -597,7 +597,7 @@ static int map_cont_bufs(struct rtrs_srv_path *srv_path) + srv_path->mrs_num++) { + struct rtrs_srv_mr *srv_mr = &srv_path->mrs[srv_path->mrs_num]; + struct scatterlist *s; +- int nr, nr_sgt, chunks; ++ int nr, nr_sgt, chunks, ind; + + sgt = &srv_mr->sgt; + chunks = chunks_per_mr * srv_path->mrs_num; +@@ -627,7 +627,7 @@ static int map_cont_bufs(struct rtrs_srv_path *srv_path) + } + nr = ib_map_mr_sg(mr, sgt->sgl, nr_sgt, + NULL, max_chunk_size); +- if (nr != nr_sgt) { ++ if (nr < nr_sgt) { + err = nr < 0 ? nr : -EINVAL; + goto dereg_mr; + } +@@ -643,9 +643,24 @@ static int map_cont_bufs(struct rtrs_srv_path *srv_path) + goto dereg_mr; + } + } +- /* Eventually dma addr for each chunk can be cached */ +- for_each_sg(sgt->sgl, s, nr_sgt, i) +- srv_path->dma_addr[chunks + i] = sg_dma_address(s); ++ ++ /* ++ * Cache DMA addresses by traversing sg entries. If ++ * regions were merged, an inner loop is required to ++ * populate the DMA address array by traversing larger ++ * regions. ++ */ ++ ind = chunks; ++ for_each_sg(sgt->sgl, s, nr_sgt, i) { ++ unsigned int dma_len = sg_dma_len(s); ++ u64 dma_addr = sg_dma_address(s); ++ u64 dma_addr_end = dma_addr + dma_len; ++ ++ do { ++ srv_path->dma_addr[ind++] = dma_addr; ++ dma_addr += max_chunk_size; ++ } while (dma_addr < dma_addr_end); ++ } + + ib_update_fast_reg_key(mr, ib_inc_rkey(mr->rkey)); + srv_mr->mr = mr; +-- +2.51.0 + diff --git a/queue-5.15/rdma-rtrs-srv-refactor-the-handling-of-failure-case-.patch b/queue-5.15/rdma-rtrs-srv-refactor-the-handling-of-failure-case-.patch new file mode 100644 index 0000000000..be350714cd --- /dev/null +++ b/queue-5.15/rdma-rtrs-srv-refactor-the-handling-of-failure-case-.patch @@ -0,0 +1,108 @@ +From 92bc154eeb260b432bf4467dff0614834a427158 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 17 Nov 2022 18:19:39 +0800 +Subject: RDMA/rtrs-srv: Refactor the handling of failure case in map_cont_bufs + +From: Guoqing Jiang + +[ Upstream commit 0f597ac618d04beb9de997fda59a29c9d3818fb2 ] + +Let's call unmap_cont_bufs when failure happens, and also only update +mrs_num after everything is settled which means we can remove 'mri'. + +Acked-by: Md Haris Iqbal +Signed-off-by: Guoqing Jiang +Link: https://lore.kernel.org/r/20221117101945.6317-3-guoqing.jiang@linux.dev +Signed-off-by: Leon Romanovsky +Stable-dep-of: 83835f7c07b5 ("RDMA/rtrs-srv: fix SG mapping") +Signed-off-by: Sasha Levin +--- + drivers/infiniband/ulp/rtrs/rtrs-srv.c | 47 +++++++++++--------------- + 1 file changed, 20 insertions(+), 27 deletions(-) + +diff --git a/drivers/infiniband/ulp/rtrs/rtrs-srv.c b/drivers/infiniband/ulp/rtrs/rtrs-srv.c +index 0979bb728da24..d2ac3a37f46e1 100644 +--- a/drivers/infiniband/ulp/rtrs/rtrs-srv.c ++++ b/drivers/infiniband/ulp/rtrs/rtrs-srv.c +@@ -566,9 +566,11 @@ static int map_cont_bufs(struct rtrs_srv_path *srv_path) + { + struct rtrs_srv *srv = srv_path->srv; + struct rtrs_path *ss = &srv_path->s; +- int i, mri, err, mrs_num; ++ int i, err, mrs_num; + unsigned int chunk_bits; + int chunks_per_mr = 1; ++ struct ib_mr *mr; ++ struct sg_table *sgt; + + /* + * Here we map queue_depth chunks to MR. Firstly we have to +@@ -591,16 +593,14 @@ static int map_cont_bufs(struct rtrs_srv_path *srv_path) + if (!srv_path->mrs) + return -ENOMEM; + +- srv_path->mrs_num = mrs_num; +- +- for (mri = 0; mri < mrs_num; mri++) { +- struct rtrs_srv_mr *srv_mr = &srv_path->mrs[mri]; +- struct sg_table *sgt = &srv_mr->sgt; ++ for (srv_path->mrs_num = 0; srv_path->mrs_num < mrs_num; ++ srv_path->mrs_num++) { ++ struct rtrs_srv_mr *srv_mr = &srv_path->mrs[srv_path->mrs_num]; + struct scatterlist *s; +- struct ib_mr *mr; + int nr, nr_sgt, chunks; + +- chunks = chunks_per_mr * mri; ++ sgt = &srv_mr->sgt; ++ chunks = chunks_per_mr * srv_path->mrs_num; + if (!always_invalidate) + chunks_per_mr = min_t(int, chunks_per_mr, + srv->queue_depth - chunks); +@@ -649,31 +649,24 @@ static int map_cont_bufs(struct rtrs_srv_path *srv_path) + + ib_update_fast_reg_key(mr, ib_inc_rkey(mr->rkey)); + srv_mr->mr = mr; +- +- continue; +-err: +- while (mri--) { +- srv_mr = &srv_path->mrs[mri]; +- sgt = &srv_mr->sgt; +- mr = srv_mr->mr; +- rtrs_iu_free(srv_mr->iu, srv_path->s.dev->ib_dev, 1); +-dereg_mr: +- ib_dereg_mr(mr); +-unmap_sg: +- ib_dma_unmap_sg(srv_path->s.dev->ib_dev, sgt->sgl, +- sgt->nents, DMA_BIDIRECTIONAL); +-free_sg: +- sg_free_table(sgt); +- } +- kfree(srv_path->mrs); +- +- return err; + } + + chunk_bits = ilog2(srv->queue_depth - 1) + 1; + srv_path->mem_bits = (MAX_IMM_PAYL_BITS - chunk_bits); + + return 0; ++ ++dereg_mr: ++ ib_dereg_mr(mr); ++unmap_sg: ++ ib_dma_unmap_sg(srv_path->s.dev->ib_dev, sgt->sgl, ++ sgt->nents, DMA_BIDIRECTIONAL); ++free_sg: ++ sg_free_table(sgt); ++err: ++ unmap_cont_bufs(srv_path); ++ ++ return err; + } + + static void rtrs_srv_hb_err_handler(struct rtrs_con *c) +-- +2.51.0 + diff --git a/queue-5.15/rdma-rxe-fix-double-free-in-rxe_srq_from_init.patch b/queue-5.15/rdma-rxe-fix-double-free-in-rxe_srq_from_init.patch new file mode 100644 index 0000000000..307ab723ba --- /dev/null +++ b/queue-5.15/rdma-rxe-fix-double-free-in-rxe_srq_from_init.patch @@ -0,0 +1,57 @@ +From 3c7da586e208e2b4d382daefed85900f4e43672a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 01:54:12 +0000 +Subject: RDMA/rxe: Fix double free in rxe_srq_from_init + +From: Jiasheng Jiang + +[ Upstream commit 0beefd0e15d962f497aad750b2d5e9c3570b66d1 ] + +In rxe_srq_from_init(), the queue pointer 'q' is assigned to +'srq->rq.queue' before copying the SRQ number to user space. +If copy_to_user() fails, the function calls rxe_queue_cleanup() +to free the queue, but leaves the now-invalid pointer in +'srq->rq.queue'. + +The caller of rxe_srq_from_init() (rxe_create_srq) eventually +calls rxe_srq_cleanup() upon receiving the error, which triggers +a second rxe_queue_cleanup() on the same memory, leading to a +double free. + +The call trace looks like this: + kmem_cache_free+0x.../0x... + rxe_queue_cleanup+0x1a/0x30 [rdma_rxe] + rxe_srq_cleanup+0x42/0x60 [rdma_rxe] + rxe_elem_release+0x31/0x70 [rdma_rxe] + rxe_create_srq+0x12b/0x1a0 [rdma_rxe] + ib_create_srq_user+0x9a/0x150 [ib_core] + +Fix this by moving 'srq->rq.queue = q' after copy_to_user. + +Fixes: aae0484e15f0 ("IB/rxe: avoid srq memory leak") +Signed-off-by: Jiasheng Jiang +Link: https://patch.msgid.link/20260112015412.29458-1-jiashengjiangcool@gmail.com +Reviewed-by: Zhu Yanjun +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/sw/rxe/rxe_srq.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/infiniband/sw/rxe/rxe_srq.c b/drivers/infiniband/sw/rxe/rxe_srq.c +index eb1c4c3b3a786..05ae3d183b21d 100644 +--- a/drivers/infiniband/sw/rxe/rxe_srq.c ++++ b/drivers/infiniband/sw/rxe/rxe_srq.c +@@ -118,6 +118,9 @@ int rxe_srq_from_init(struct rxe_dev *rxe, struct rxe_srq *srq, + } + } + ++ srq->rq.queue = q; ++ init->attr.max_wr = srq->rq.max_wr; ++ + return 0; + } + +-- +2.51.0 + diff --git a/queue-5.15/rdma-uverbs-add-__gfp_nowarn-to-ib_uverbs_unmarshall.patch b/queue-5.15/rdma-uverbs-add-__gfp_nowarn-to-ib_uverbs_unmarshall.patch new file mode 100644 index 0000000000..d5331dcb13 --- /dev/null +++ b/queue-5.15/rdma-uverbs-add-__gfp_nowarn-to-ib_uverbs_unmarshall.patch @@ -0,0 +1,39 @@ +From e0dc229bf9585d1f6cfbeb460772303010f2af8c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 17:49:00 +0800 +Subject: RDMA/uverbs: Add __GFP_NOWARN to ib_uverbs_unmarshall_recv() kmalloc + +From: Yi Liu + +[ Upstream commit 58b604dfc7bb753f91bc0ccd3fa705e14e6edfb4 ] + +Since wqe_size in ib_uverbs_unmarshall_recv() is user-provided and already +validated, but can still be large, add __GFP_NOWARN to suppress memory +allocation warnings for large sizes, consistent with the similar fix in +ib_uverbs_post_send(). + +Fixes: 67cdb40ca444 ("[IB] uverbs: Implement more commands") +Signed-off-by: Yi Liu +Link: https://patch.msgid.link/20260129094900.3517706-1-liuy22@mails.tsinghua.edu.cn +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/uverbs_cmd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c +index 754a00e2828bb..9ae14c59777ee 100644 +--- a/drivers/infiniband/core/uverbs_cmd.c ++++ b/drivers/infiniband/core/uverbs_cmd.c +@@ -2224,7 +2224,7 @@ ib_uverbs_unmarshall_recv(struct uverbs_req_iter *iter, u32 wr_count, + if (ret) + return ERR_PTR(ret); + +- user_wr = kmalloc(wqe_size, GFP_KERNEL); ++ user_wr = kmalloc(wqe_size, GFP_KERNEL | __GFP_NOWARN); + if (!user_wr) + return ERR_PTR(-ENOMEM); + +-- +2.51.0 + diff --git a/queue-5.15/rdma-uverbs-validate-wqe_size-before-using-it-in-ib_.patch b/queue-5.15/rdma-uverbs-validate-wqe_size-before-using-it-in-ib_.patch new file mode 100644 index 0000000000..f73ccca437 --- /dev/null +++ b/queue-5.15/rdma-uverbs-validate-wqe_size-before-using-it-in-ib_.patch @@ -0,0 +1,57 @@ +From 1b7b9635ef88d5dfd07cdc93c92a98620e207d89 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 22:29:00 +0800 +Subject: RDMA/uverbs: Validate wqe_size before using it in ib_uverbs_post_send + +From: Yi Liu + +[ Upstream commit 1956f0a74ccf5dc9c3ef717f2985c3ed3400aab0 ] + +ib_uverbs_post_send() uses cmd.wqe_size from userspace without any +validation before passing it to kmalloc() and using the allocated +buffer as struct ib_uverbs_send_wr. + +If a user provides a small wqe_size value (e.g., 1), kmalloc() will +succeed, but subsequent accesses to user_wr->opcode, user_wr->num_sge, +and other fields will read beyond the allocated buffer, resulting in +an out-of-bounds read from kernel heap memory. This could potentially +leak sensitive kernel information to userspace. + +Additionally, providing an excessively large wqe_size can trigger a +WARNING in the memory allocation path, as reported by syzkaller. + +This is inconsistent with ib_uverbs_unmarshall_recv() which properly +validates that wqe_size >= sizeof(struct ib_uverbs_recv_wr) before +proceeding. + +Add the same validation for ib_uverbs_post_send() to ensure wqe_size +is at least sizeof(struct ib_uverbs_send_wr). + +Fixes: c3bea3d2dc53 ("RDMA/uverbs: Use the iterator for ib_uverbs_unmarshall_recv()") +Signed-off-by: Yi Liu +Link: https://patch.msgid.link/20260122142900.2356276-2-liuy22@mails.tsinghua.edu.cn +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/uverbs_cmd.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c +index de631a6abe48d..754a00e2828bb 100644 +--- a/drivers/infiniband/core/uverbs_cmd.c ++++ b/drivers/infiniband/core/uverbs_cmd.c +@@ -2031,7 +2031,10 @@ static int ib_uverbs_post_send(struct uverbs_attr_bundle *attrs) + if (ret) + return ret; + +- user_wr = kmalloc(cmd.wqe_size, GFP_KERNEL); ++ if (cmd.wqe_size < sizeof(struct ib_uverbs_send_wr)) ++ return -EINVAL; ++ ++ user_wr = kmalloc(cmd.wqe_size, GFP_KERNEL | __GFP_NOWARN); + if (!user_wr) + return -ENOMEM; + +-- +2.51.0 + diff --git a/queue-5.15/regulator-core-move-supply-check-earlier-in-set_mach.patch b/queue-5.15/regulator-core-move-supply-check-earlier-in-set_mach.patch new file mode 100644 index 0000000000..a21313151b --- /dev/null +++ b/queue-5.15/regulator-core-move-supply-check-earlier-in-set_mach.patch @@ -0,0 +1,121 @@ +From f854b1b219a97086c387b316b10d5a6a346c2bba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 08:38:39 +0000 +Subject: regulator: core: move supply check earlier in + set_machine_constraints() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: André Draszik + +[ Upstream commit 86a8eeb0e913f4b6a55dabba5122098d4e805e55 ] + +Since commit 98e48cd9283d ("regulator: core: resolve supply for +boot-on/always-on regulators"), set_machine_constraints() can return +-EPROBE_DEFER very late, after it has done a lot of work and +configuration of the regulator. + +This means that configuration will happen multiple times for no +benefit in that case. Furthermore, this can lead to timing-dependent +voltage glitches as mentioned e.g. in commit 8a866d527ac0 ("regulator: +core: Resolve supply name earlier to prevent double-init"). + +We can know that it's going to fail very early, in particular before +going through the complete regulator configuration by moving some code +around a little. + +Do so to avoid re-configuring the regulator multiple times, also +avoiding the voltage glitches if we can. + +Fixes: 98e48cd9283d ("regulator: core: resolve supply for boot-on/always-on regulators") +Signed-off-by: André Draszik +Link: https://patch.msgid.link/20260109-regulators-defer-v2-3-1a25dc968e60@linaro.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/regulator/core.c | 55 ++++++++++++++++++++++------------------ + 1 file changed, 30 insertions(+), 25 deletions(-) + +diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c +index af0218227a8c7..fdb5e1a1f246f 100644 +--- a/drivers/regulator/core.c ++++ b/drivers/regulator/core.c +@@ -1429,6 +1429,33 @@ static int set_machine_constraints(struct regulator_dev *rdev) + int ret = 0; + const struct regulator_ops *ops = rdev->desc->ops; + ++ /* ++ * If there is no mechanism for controlling the regulator then ++ * flag it as always_on so we don't end up duplicating checks ++ * for this so much. Note that we could control the state of ++ * a supply to control the output on a regulator that has no ++ * direct control. ++ */ ++ if (!rdev->ena_pin && !ops->enable) { ++ if (rdev->supply_name && !rdev->supply) ++ return -EPROBE_DEFER; ++ ++ if (rdev->supply) ++ rdev->constraints->always_on = ++ rdev->supply->rdev->constraints->always_on; ++ else ++ rdev->constraints->always_on = true; ++ } ++ ++ /* ++ * If we want to enable this regulator, make sure that we know the ++ * supplying regulator. ++ */ ++ if (rdev->constraints->always_on || rdev->constraints->boot_on) { ++ if (rdev->supply_name && !rdev->supply) ++ return -EPROBE_DEFER; ++ } ++ + ret = machine_constraints_voltage(rdev, rdev->constraints); + if (ret != 0) + return ret; +@@ -1594,37 +1621,15 @@ static int set_machine_constraints(struct regulator_dev *rdev) + } + } + +- /* +- * If there is no mechanism for controlling the regulator then +- * flag it as always_on so we don't end up duplicating checks +- * for this so much. Note that we could control the state of +- * a supply to control the output on a regulator that has no +- * direct control. +- */ +- if (!rdev->ena_pin && !ops->enable) { +- if (rdev->supply_name && !rdev->supply) +- return -EPROBE_DEFER; +- +- if (rdev->supply) +- rdev->constraints->always_on = +- rdev->supply->rdev->constraints->always_on; +- else +- rdev->constraints->always_on = true; +- } +- + /* If the constraints say the regulator should be on at this point + * and we have control then make sure it is enabled. + */ + if (rdev->constraints->always_on || rdev->constraints->boot_on) { + bool supply_enabled = false; + +- /* If we want to enable this regulator, make sure that we know +- * the supplying regulator. +- */ +- if (rdev->supply_name && !rdev->supply) +- return -EPROBE_DEFER; +- +- /* If supplying regulator has already been enabled, ++ /* We have ensured a potential supply has been resolved above. ++ * ++ * If supplying regulator has already been enabled, + * it's not intended to have use_count increment + * when rdev is only boot-on. + */ +-- +2.51.0 + diff --git a/queue-5.15/revert-mmc-rtsx_pci_sdmmc-increase-power-on-settling.patch b/queue-5.15/revert-mmc-rtsx_pci_sdmmc-increase-power-on-settling.patch new file mode 100644 index 0000000000..7210bae155 --- /dev/null +++ b/queue-5.15/revert-mmc-rtsx_pci_sdmmc-increase-power-on-settling.patch @@ -0,0 +1,39 @@ +From ac1bd0c5b488a1c0e765f94e8a3d305d4134ddc5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 15:49:31 +0100 +Subject: Revert "mmc: rtsx_pci_sdmmc: increase power-on settling delay to 5ms" + +From: Greg Kroah-Hartman + +[ Upstream commit ff112f1ecd10b72004eac05bae395e1c65f0c63c ] + +This reverts commit aced969e9bf3701dc75cfca57c78c031b7875b9d. + +It was determined that this was not the correct "fix", so should be +reverted. + +Fixes: aced969e9bf3 ("mmc: rtsx_pci_sdmmc: increase power-on settling delay to 5ms") +Cc: Matthew Schwartz +Cc: Ulf Hansson +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/mmc/host/rtsx_pci_sdmmc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c +index 02da9016245bd..d063d50d69feb 100644 +--- a/drivers/mmc/host/rtsx_pci_sdmmc.c ++++ b/drivers/mmc/host/rtsx_pci_sdmmc.c +@@ -938,7 +938,7 @@ static int sd_power_on(struct realtek_pci_sdmmc *host, unsigned char power_mode) + if (err < 0) + return err; + +- mdelay(5); ++ mdelay(1); + + err = rtsx_pci_write_register(pcr, CARD_OE, SD_OUTPUT_EN, SD_OUTPUT_EN); + if (err < 0) +-- +2.51.0 + diff --git a/queue-5.15/s390-cio-fix-device-lifecycle-handling-in-css_alloc_.patch b/queue-5.15/s390-cio-fix-device-lifecycle-handling-in-css_alloc_.patch new file mode 100644 index 0000000000..89408f1ea5 --- /dev/null +++ b/queue-5.15/s390-cio-fix-device-lifecycle-handling-in-css_alloc_.patch @@ -0,0 +1,49 @@ +From d9c988a5c5aa7d912e33f5f0898aa100d5150cc5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 21:47:59 +0100 +Subject: s390/cio: Fix device lifecycle handling in css_alloc_subchannel() + +From: Salah Triki + +[ Upstream commit f65c75b0b9b5a390bc3beadcde0a6fbc3ad118f7 ] + +`css_alloc_subchannel()` calls `device_initialize()` before setting up +the DMA masks. If `dma_set_coherent_mask()` or `dma_set_mask()` fails, +the error path frees the subchannel structure directly, bypassing +the device model reference counting. + +Once `device_initialize()` has been called, the embedded struct device +must be released via `put_device()`, allowing the release callback to +free the container structure. + +Fix the error path by dropping the initial device reference with +`put_device()` instead of calling `kfree()` directly. + +This ensures correct device lifetime handling and avoids potential +use-after-free or double-free issues. + +Fixes: e5dcf0025d7af ("s390/css: move subchannel lock allocation") +Signed-off-by: Salah Triki +Reviewed-by: Vineeth Vijayan +Signed-off-by: Heiko Carstens +Signed-off-by: Sasha Levin +--- + drivers/s390/cio/css.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c +index 3c499136af657..4c3fde0bd5512 100644 +--- a/drivers/s390/cio/css.c ++++ b/drivers/s390/cio/css.c +@@ -247,7 +247,7 @@ struct subchannel *css_alloc_subchannel(struct subchannel_id schid, + err_lock: + kfree(sch->lock); + err: +- kfree(sch); ++ put_device(&sch->dev); + return ERR_PTR(ret); + } + +-- +2.51.0 + diff --git a/queue-5.15/sched-rt-skip-currently-executing-cpu-in-rto_next_cp.patch b/queue-5.15/sched-rt-skip-currently-executing-cpu-in-rto_next_cp.patch new file mode 100644 index 0000000000..d8d28d82ad --- /dev/null +++ b/queue-5.15/sched-rt-skip-currently-executing-cpu-in-rto_next_cp.patch @@ -0,0 +1,87 @@ +From f2e09602516a8b5bbd8f75b4491cf1b41fc1161d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 01:25:33 +0000 +Subject: sched/rt: Skip currently executing CPU in rto_next_cpu() + +From: Chen Jinghuang + +[ Upstream commit 94894c9c477e53bcea052e075c53f89df3d2a33e ] + +CPU0 becomes overloaded when hosting a CPU-bound RT task, a non-CPU-bound +RT task, and a CFS task stuck in kernel space. When other CPUs switch from +RT to non-RT tasks, RT load balancing (LB) is triggered; with +HAVE_RT_PUSH_IPI enabled, they send IPIs to CPU0 to drive the execution +of rto_push_irq_work_func. During push_rt_task on CPU0, +if next_task->prio < rq->donor->prio, resched_curr() sets NEED_RESCHED +and after the push operation completes, CPU0 calls rto_next_cpu(). +Since only CPU0 is overloaded in this scenario, rto_next_cpu() should +ideally return -1 (no further IPI needed). + +However, multiple CPUs invoking tell_cpu_to_push() during LB increments +rd->rto_loop_next. Even when rd->rto_cpu is set to -1, the mismatch between +rd->rto_loop and rd->rto_loop_next forces rto_next_cpu() to restart its +search from -1. With CPU0 remaining overloaded (satisfying rt_nr_migratory +&& rt_nr_total > 1), it gets reselected, causing CPU0 to queue irq_work to +itself and send self-IPIs repeatedly. As long as CPU0 stays overloaded and +other CPUs run pull_rt_tasks(), it falls into an infinite self-IPI loop, +which triggers a CPU hardlockup due to continuous self-interrupts. + +The trigging scenario is as follows: + + cpu0 cpu1 cpu2 + pull_rt_task + tell_cpu_to_push + <------------irq_work_queue_on +rto_push_irq_work_func + push_rt_task + resched_curr(rq) pull_rt_task + rto_next_cpu tell_cpu_to_push + <-------------------------- atomic_inc(rto_loop_next) +rd->rto_loop != next + rto_next_cpu + irq_work_queue_on +rto_push_irq_work_func + +Fix redundant self-IPI by filtering the initiating CPU in rto_next_cpu(). +This solution has been verified to effectively eliminate spurious self-IPIs +and prevent CPU hardlockup scenarios. + +Fixes: 4bdced5c9a29 ("sched/rt: Simplify the IPI based RT balancing logic") +Suggested-by: Steven Rostedt (Google) +Suggested-by: K Prateek Nayak +Signed-off-by: Chen Jinghuang +Signed-off-by: Peter Zijlstra (Intel) +Reviewed-by: Steven Rostedt (Google) +Reviewed-by: Valentin Schneider +Link: https://patch.msgid.link/20260122012533.673768-1-chenjinghuang2@huawei.com +Signed-off-by: Sasha Levin +--- + kernel/sched/rt.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c +index 9720b3c19ab97..c5122e5f258e4 100644 +--- a/kernel/sched/rt.c ++++ b/kernel/sched/rt.c +@@ -2068,6 +2068,7 @@ static void push_rt_tasks(struct rq *rq) + */ + static int rto_next_cpu(struct root_domain *rd) + { ++ int this_cpu = smp_processor_id(); + int next; + int cpu; + +@@ -2091,6 +2092,10 @@ static int rto_next_cpu(struct root_domain *rd) + + rd->rto_cpu = cpu; + ++ /* Do not send IPI to self */ ++ if (cpu == this_cpu) ++ continue; ++ + if (cpu < nr_cpu_ids) + return cpu; + +-- +2.51.0 + diff --git a/queue-5.15/scsi-csiostor-fix-dereference-of-null-pointer-rn.patch b/queue-5.15/scsi-csiostor-fix-dereference-of-null-pointer-rn.patch new file mode 100644 index 0000000000..a262d11800 --- /dev/null +++ b/queue-5.15/scsi-csiostor-fix-dereference-of-null-pointer-rn.patch @@ -0,0 +1,46 @@ +From 02b5fc8dc757bbb394ded8effb4ea1f44ee05bf2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 15:53:32 +0000 +Subject: scsi: csiostor: Fix dereference of null pointer rn + +From: Colin Ian King + +[ Upstream commit 1982257570b84dc33753d536dd969fd357a014e9 ] + +The error exit path when rn is NULL ends up deferencing the null pointer rn +via the use of the macro CSIO_INC_STATS. Fix this by adding a new error +return path label after the use of the macro to avoid the deference. + +Fixes: a3667aaed569 ("[SCSI] csiostor: Chelsio FCoE offload driver") +Signed-off-by: Colin Ian King +Link: https://patch.msgid.link/20260129155332.196338-1-colin.i.king@gmail.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/csiostor/csio_scsi.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/scsi/csiostor/csio_scsi.c b/drivers/scsi/csiostor/csio_scsi.c +index 3b2eb6ce1fcff..59d7dadfbfb71 100644 +--- a/drivers/scsi/csiostor/csio_scsi.c ++++ b/drivers/scsi/csiostor/csio_scsi.c +@@ -2070,7 +2070,7 @@ csio_eh_lun_reset_handler(struct scsi_cmnd *cmnd) + struct csio_scsi_level_data sld; + + if (!rn) +- goto fail; ++ goto fail_ret; + + csio_dbg(hw, "Request to reset LUN:%llu (ssni:0x%x tgtid:%d)\n", + cmnd->device->lun, rn->flowid, rn->scsi_id); +@@ -2215,6 +2215,7 @@ csio_eh_lun_reset_handler(struct scsi_cmnd *cmnd) + csio_put_scsi_ioreq_lock(hw, scsim, ioreq); + fail: + CSIO_INC_STATS(rn, n_lun_rst_fail); ++fail_ret: + return FAILED; + } + +-- +2.51.0 + diff --git a/queue-5.15/scsi-efct-use-irqf_oneshot-and-default-primary-handl.patch b/queue-5.15/scsi-efct-use-irqf_oneshot-and-default-primary-handl.patch new file mode 100644 index 0000000000..ee723dcbe2 --- /dev/null +++ b/queue-5.15/scsi-efct-use-irqf_oneshot-and-default-primary-handl.patch @@ -0,0 +1,59 @@ +From dffcdd49c656133ed85bec2d46443117da814123 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:55:27 +0100 +Subject: scsi: efct: Use IRQF_ONESHOT and default primary handler + +From: Sebastian Andrzej Siewior + +[ Upstream commit bd81f07e9a27c341cd7e72be95eb0b7cf3910926 ] + +There is no added value in efct_intr_msix() compared to +irq_default_primary_handler(). + +Using a threaded interrupt without a dedicated primary handler mandates +the IRQF_ONESHOT flag to mask the interrupt source while the threaded +handler is active. Otherwise the interrupt can fire again before the +threaded handler had a chance to run. + +Use the default primary interrupt handler by specifying NULL and set +IRQF_ONESHOT so the interrupt source is masked until the secondary +handler is done. + +Fixes: 4df84e8466242 ("scsi: elx: efct: Driver initialization routines") +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260128095540.863589-8-bigeasy@linutronix.de +Signed-off-by: Sasha Levin +--- + drivers/scsi/elx/efct/efct_driver.c | 8 +------- + 1 file changed, 1 insertion(+), 7 deletions(-) + +diff --git a/drivers/scsi/elx/efct/efct_driver.c b/drivers/scsi/elx/efct/efct_driver.c +index 37e1ab96ee5be..658f463744e66 100644 +--- a/drivers/scsi/elx/efct/efct_driver.c ++++ b/drivers/scsi/elx/efct/efct_driver.c +@@ -415,12 +415,6 @@ efct_intr_thread(int irq, void *handle) + return IRQ_HANDLED; + } + +-static irqreturn_t +-efct_intr_msix(int irq, void *handle) +-{ +- return IRQ_WAKE_THREAD; +-} +- + static int + efct_setup_msix(struct efct *efct, u32 num_intrs) + { +@@ -450,7 +444,7 @@ efct_setup_msix(struct efct *efct, u32 num_intrs) + intr_ctx->index = i; + + rc = request_threaded_irq(pci_irq_vector(efct->pci, i), +- efct_intr_msix, efct_intr_thread, 0, ++ NULL, efct_intr_thread, IRQF_ONESHOT, + EFCT_DRIVER_NAME, intr_ctx); + if (rc) { + dev_err(&efct->pci->dev, +-- +2.51.0 + diff --git a/queue-5.15/serial-caif-fix-use-after-free-in-caif_serial-ldisc_.patch b/queue-5.15/serial-caif-fix-use-after-free-in-caif_serial-ldisc_.patch new file mode 100644 index 0000000000..dc6e043a67 --- /dev/null +++ b/queue-5.15/serial-caif-fix-use-after-free-in-caif_serial-ldisc_.patch @@ -0,0 +1,152 @@ +From 3db408987a97f3e23e48b6e1f132b428156a9b2b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 15:44:44 +0800 +Subject: serial: caif: fix use-after-free in caif_serial ldisc_close() + +From: Jiayuan Chen + +[ Upstream commit 308e7e4d0a846359685f40aade023aee7b27284c ] + +There is a use-after-free bug in caif_serial where handle_tx() may +access ser->tty after the tty has been freed. + +The race condition occurs between ldisc_close() and packet transmission: + + CPU 0 (close) CPU 1 (xmit) + ------------- ------------ + ldisc_close() + tty_kref_put(ser->tty) + [tty may be freed here] + <-- race window --> + caif_xmit() + handle_tx() + tty = ser->tty // dangling ptr + tty->ops->write() // UAF! + schedule_work() + ser_release() + unregister_netdevice() + +The root cause is that tty_kref_put() is called in ldisc_close() while +the network device is still active and can receive packets. + +Since ser and tty have a 1:1 binding relationship with consistent +lifecycles (ser is allocated in ldisc_open and freed in ser_release +via unregister_netdevice, and each ser binds exactly one tty), we can +safely defer the tty reference release to ser_release() where the +network device is unregistered. + +Fix this by moving tty_kref_put() from ldisc_close() to ser_release(), +after unregister_netdevice(). This ensures the tty reference is held +as long as the network device exists, preventing the UAF. + +Note: We save ser->tty before unregister_netdevice() because ser is +embedded in netdev's private data and will be freed along with netdev +(needs_free_netdev = true). + +How to reproduce: Add mdelay(500) at the beginning of ldisc_close() +to widen the race window, then run the reproducer program [1]. + +Note: There is a separate deadloop issue in handle_tx() when using +PORT_UNKNOWN serial ports (e.g., /dev/ttyS3 in QEMU without proper +serial backend). This deadloop exists even without this patch, +and is likely caused by inconsistency between uart_write_room() and +uart_write() in serial core. It has been addressed in a separate +patch [2]. + +KASAN report: + +================================================================== +BUG: KASAN: slab-use-after-free in handle_tx+0x5d1/0x620 +Read of size 1 at addr ffff8881131e1490 by task caif_uaf_trigge/9929 + +Call Trace: + + dump_stack_lvl+0x10e/0x1f0 + print_report+0xd0/0x630 + kasan_report+0xe4/0x120 + handle_tx+0x5d1/0x620 + dev_hard_start_xmit+0x9d/0x6c0 + __dev_queue_xmit+0x6e2/0x4410 + packet_xmit+0x243/0x360 + packet_sendmsg+0x26cf/0x5500 + __sys_sendto+0x4a3/0x520 + __x64_sys_sendto+0xe0/0x1c0 + do_syscall_64+0xc9/0xf80 + entry_SYSCALL_64_after_hwframe+0x77/0x7f +RIP: 0033:0x7f615df2c0d7 + +Allocated by task 9930: + +Freed by task 64: + +Last potentially related work creation: + +The buggy address belongs to the object at ffff8881131e1000 + which belongs to the cache kmalloc-cg-2k of size 2048 +The buggy address is located 1168 bytes inside of + freed 2048-byte region [ffff8881131e1000, ffff8881131e1800) + +The buggy address belongs to the physical page: +page_owner tracks the page as allocated +page last free pid 9778 tgid 9778 stack trace: + +Memory state around the buggy address: + ffff8881131e1380: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb + ffff8881131e1400: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb +>ffff8881131e1480: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb + ^ + ffff8881131e1500: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb + ffff8881131e1580: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb +================================================================== +[1]: https://gist.github.com/mrpre/f683f244544f7b11e7fa87df9e6c2eeb +[2]: https://lore.kernel.org/linux-serial/20260204074327.226165-1-jiayuan.chen@linux.dev/T/#u + +Reported-by: syzbot+827272712bd6d12c79a4@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/000000000000a4a7550611e234f5@google.com/T/ +Fixes: 56e0ef527b18 ("drivers/net: caif: fix wrong rtnl_is_locked() usage") +Reviewed-by: Greg Kroah-Hartman +Signed-off-by: Jiayuan Chen +Reviewed-by: Jijie Shao +Link: https://patch.msgid.link/20260206074450.154267-1-jiayuan.chen@linux.dev +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/caif/caif_serial.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c +index 2a7af611d43a5..90b4820486990 100644 +--- a/drivers/net/caif/caif_serial.c ++++ b/drivers/net/caif/caif_serial.c +@@ -298,6 +298,7 @@ static void ser_release(struct work_struct *work) + { + struct list_head list; + struct ser_device *ser, *tmp; ++ struct tty_struct *tty; + + spin_lock(&ser_lock); + list_replace_init(&ser_release_list, &list); +@@ -306,9 +307,11 @@ static void ser_release(struct work_struct *work) + if (!list_empty(&list)) { + rtnl_lock(); + list_for_each_entry_safe(ser, tmp, &list, node) { ++ tty = ser->tty; + dev_close(ser->dev); + unregister_netdevice(ser->dev); + debugfs_deinit(ser); ++ tty_kref_put(tty); + } + rtnl_unlock(); + } +@@ -369,8 +372,6 @@ static void ldisc_close(struct tty_struct *tty) + { + struct ser_device *ser = tty->disc_data; + +- tty_kref_put(ser->tty); +- + spin_lock(&ser_lock); + list_move(&ser->node, &ser_release_list); + spin_unlock(&ser_lock); +-- +2.51.0 + diff --git a/queue-5.15/serial-imx-change-serial_imx_console-to-bool.patch b/queue-5.15/serial-imx-change-serial_imx_console-to-bool.patch new file mode 100644 index 0000000000..d49f883e95 --- /dev/null +++ b/queue-5.15/serial-imx-change-serial_imx_console-to-bool.patch @@ -0,0 +1,50 @@ +From ffea70d9590d91d8cbce3cf1d172857c55378b36 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 10 Jan 2026 15:26:40 -0800 +Subject: serial: imx: change SERIAL_IMX_CONSOLE to bool + +From: Randy Dunlap + +[ Upstream commit 79527d86ba91c2d9354832d19fd12b3baa66bd10 ] + +SERIAL_IMX_CONSOLE is a build option for the imx driver (SERIAL_IMX). +It does not build a separate console driver file, so it can't be built +as a module since it isn't built at all. + +Change the Kconfig symbol from tristate to bool and update the help +text accordingly. + +Fixes: 0db4f9b91c86 ("tty: serial: imx: enable imx serial console port as module") +Signed-off-by: Randy Dunlap +Link: https://patch.msgid.link/20260110232643.3533351-2-rdunlap@infradead.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/Kconfig | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig +index 4fc5c043adf62..824d1a14d981f 100644 +--- a/drivers/tty/serial/Kconfig ++++ b/drivers/tty/serial/Kconfig +@@ -482,14 +482,14 @@ config SERIAL_IMX + can enable its onboard serial port by enabling this option. + + config SERIAL_IMX_CONSOLE +- tristate "Console on IMX serial port" ++ bool "Console on IMX serial port" + depends on SERIAL_IMX + select SERIAL_CORE_CONSOLE + help + If you have enabled the serial port on the Freescale IMX +- CPU you can make it the console by answering Y/M to this option. ++ CPU you can make it the console by answering Y to this option. + +- Even if you say Y/M here, the currently visible virtual console ++ Even if you say Y here, the currently visible virtual console + (/dev/tty0) will still be used as the system console by default, but + you can alter that using a kernel command line option such as + "console=ttymxc0". (Try "man bootparam" or see the documentation of +-- +2.51.0 + diff --git a/queue-5.15/serial-sh_sci-improve-dma-support-prompt.patch b/queue-5.15/serial-sh_sci-improve-dma-support-prompt.patch new file mode 100644 index 0000000000..febbd5a508 --- /dev/null +++ b/queue-5.15/serial-sh_sci-improve-dma-support-prompt.patch @@ -0,0 +1,39 @@ +From d30e1d58f7d5664d41dbb71fa1b448f6a7be7faa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 10 Jan 2026 15:26:43 -0800 +Subject: serial: SH_SCI: improve "DMA support" prompt + +From: Randy Dunlap + +[ Upstream commit 93bb95a11238d66a4c9aa6eabf9774b073a5895c ] + +Having a prompt of "DMA support" suddenly appear during a +"make oldconfig" can be confusing. Add a little helpful text to +the prompt message. + +Fixes: 73a19e4c0301 ("serial: sh-sci: Add DMA support.") +Signed-off-by: Randy Dunlap +Reviewed-by: Geert Uytterhoeven +Link: https://patch.msgid.link/20260110232643.3533351-5-rdunlap@infradead.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig +index 824d1a14d981f..73db1b1306b03 100644 +--- a/drivers/tty/serial/Kconfig ++++ b/drivers/tty/serial/Kconfig +@@ -680,7 +680,7 @@ config SERIAL_SH_SCI_EARLYCON + default ARCH_RENESAS || H8300 + + config SERIAL_SH_SCI_DMA +- bool "DMA support" if EXPERT ++ bool "Support for DMA on SuperH SCI(F)" if EXPERT + depends on SERIAL_SH_SCI && DMA_ENGINE + default ARCH_RENESAS + +-- +2.51.0 + diff --git a/queue-5.15/series b/queue-5.15/series index 0b63edc9fd..784af445a3 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -1,2 +1,152 @@ rdma-siw-fix-potential-null-pointer-dereference-in-header-processing.patch rdma-umad-reject-negative-data_len-in-ib_umad_write.patch +auxdisplay-arm-charlcd-fix-release_mem_region-size.patch +hfsplus-return-error-when-node-already-exists-in-hfs.patch +i3c-remove-i2c-board-info-from-i2c_dev_desc.patch +i3c-move-device-name-assignment-after-i3c_bus_init.patch +fs-add-linux-init_task.h-for-init_fs.patch +gfs2-add-metapath_dibh-helper.patch +gfs2-fix-use-after-free-in-iomap-inline-data-write-p.patch +tpm-tpm_i2c_infineon-fix-locality-leak-on-get_burstc.patch +tpm-st33zp24-fix-missing-cleanup-on-get_burstcount-e.patch +btrfs-qgroup-return-correct-error-when-deleting-qgro.patch +md-raid10-fix-any_working-flag-handling-in-raid10_sy.patch +cpufreq-scmi-correct-scmi-explanation.patch +iomap-fix-submission-side-handling-of-completion-sid.patch +pm-wakeup-handle-empty-list-in-wakeup_sources_walk_s.patch +pm-sleep-wakeirq-harden-dev_pm_clear_wake_irq-agains.patch +s390-cio-fix-device-lifecycle-handling-in-css_alloc_.patch +libbpf-fix-dumping-big-endian-bitfields.patch +libbpf-fix-oob-read-in-btf_dump_get_bitfield_value.patch +arm-vdso-patch-out-__vdso_clock_getres-if-unavailabl.patch +crypto-cavium-fix-dma_free_coherent-size.patch +crypto-octeontx-fix-dma_free_coherent-size.patch +hrtimer-fix-trace-oddity.patch +crypto-hisilicon-trng-modifying-the-order-of-header-.patch +crypto-hisilicon-trng-support-tfms-sharing-the-devic.patch +scsi-efct-use-irqf_oneshot-and-default-primary-handl.patch +edac-altera-remove-irqf_oneshot.patch +mfd-wm8350-core-use-irqf_oneshot.patch +sched-rt-skip-currently-executing-cpu-in-rto_next_cp.patch +pstore-ram-fix-buffer-overflow-in-persistent_ram_sav.patch +edac-i5000-fix-snprintf-size-calculation-in-calculat.patch +edac-i5400-fix-snprintf-limit-calculation-in-calcula.patch +clk-qcom-return-correct-error-code-in-qcom_cc_probe_.patch +arm64-dts-qcom-sdm630-correct-qfprom-byte-offsets.patch +arm64-dts-qcom-sdm630-fix-gpu_speed_bin-size.patch +arm64-dts-qcom-sdm845-oneplus-don-t-mark-ts-supply-b.patch +arm64-dts-qcom-sdm845-oneplus-don-t-keep-panel-regul.patch +arm64-dts-qcom-sdm845-oneplus-mark-l14a-regulator-as.patch +arm-dts-allwinner-sun5i-a13-utoo-p66-delete-power-gp.patch +powerpc-uaccess-move-barrier_nospec-out-of-allow_rea.patch +soc-qcom-cmd-db-use-devm_memremap-to-fix-memory-leak.patch +powerpc-eeh-fix-recursive-pci_lock_rescan_remove-loc.patch +arm-dts-lpc32xx-set-motor-pwm-pwm-cells-property-val.patch +arm-dts-lpc32xx-add-clocks-property-to-motor-control.patch +arm64-dts-amlogic-axg-assign-the-mmc-signal-clocks.patch +arm64-dts-amlogic-gx-assign-the-mmc-signal-clocks.patch +arm64-dts-amlogic-g12-assign-the-mmc-b-and-c-signal-.patch +arm64-dts-amlogic-g12-assign-the-mmc-a-signal-clock.patch +arm64-dts-qcom-sdm845-db845c-specify-power-for-wifi-.patch +smack-smack-doi-must-be-0.patch +smack-smack-doi-accept-previously-used-values.patch +drm-amdgpu-use-explicit-vcn-instance-0-in-sr-iov-ini.patch +regulator-core-move-supply-check-earlier-in-set_mach.patch +hid-playstation-add-missing-check-for-input_ff_creat.patch +media-ccs-accommodate-c-phy-into-the-calculation.patch +media-uvcvideo-fix-allocation-for-small-frame-sizes.patch +platform-chrome-cros_ec_lightbar-fix-response-size-i.patch +spi-tools-add-include-folder-to-.gitignore.patch +pci-mediatek-fix-irq-domain-leak-when-msi-allocation.patch +pci-do-not-attempt-to-set-exttag-for-vfs.patch +pci-portdrv-fix-potential-resource-leak.patch +wifi-cfg80211-stop-nan-and-p2p-in-cfg80211_leave.patch +netfilter-nf_conncount-make-nf_conncount_gc_list-to-.patch +netfilter-nf_conncount-increase-the-connection-clean.patch +netfilter-nf_conncount-fix-tracking-of-connections-f.patch +pci-mark-3ware-9650sa-root-port-extended-tags-as-bro.patch +iommu-vt-d-flush-cache-for-pasid-table-before-using-.patch +nfsd-never-defer-requests-during-idmap-lookup.patch +fat-avoid-parent-link-count-underflow-in-rmdir.patch +tcp-tcp_tx_timestamp-must-look-at-the-rtx-queue.patch +wifi-ath10k-sdio-add-missing-lock-protection-in-ath1.patch +pci-initialize-rcb-from-pci_configure_device.patch +ucount-check-for-cap_sys_resource-using-ns_capable_n.patch +octeontx2-af-fix-pf-driver-crash-with-kexec-kernel-b.patch +bonding-only-set-speed-duplex-to-unknown-if-getting-.patch +timers-replace-in_irq-with-in_hardirq.patch +nfc-hci-shdlc-stop-timers-and-work-before-freeing-co.patch +netfilter-nft_set_hash-fix-get-operation-on-big-endi.patch +netfilter-nft_set_rbtree-check-for-partial-overlaps-.patch +ethtool-add-support-to-set-get-tx-copybreak-buf-size.patch +net-hns3-add-support-to-set-get-tx-copybreak-buf-siz.patch +net-hns3-remove-the-way-to-set-tx-spare-buf-via-modu.patch +net-hns3-fix-ethtool-tx-copybreak-buf-size-indicatin.patch +net-hns3-add-max-order-judgement-for-tx-spare-buffer.patch +net-hns3-fix-double-free-issue-for-tx-spare-buffer.patch +procfs-fix-missing-rcu-protection-when-reading-real_.patch +net-atm-fix-crash-due-to-unvalidated-vcc-pointer-in-.patch +serial-caif-fix-use-after-free-in-caif_serial-ldisc_.patch +ionic-rate-limit-unknown-xcvr-type-messages.patch +octeontx2-pf-unregister-devlink-on-probe-failure.patch +rdma-rtrs-server-remove-dead-code.patch +ib-cache-update-gid-cache-on-client-reregister-event.patch +rdma-hns-notify-ulp-of-remaining-soft-wcs-during-res.patch +power-supply-ab8500_bmdata-use-standard-phandle.patch +power-supply-ab8500-use-core-battery-parser.patch +power-supply-ab8500-fix-use-after-free-in-power_supp.patch +power-supply-act8945a-fix-use-after-free-in-power_su.patch +power-supply-bq256xx-fix-use-after-free-in-power_sup.patch +power-supply-bq25980-fix-use-after-free-in-power_sup.patch +power-supply-cpcap-battery-fix-use-after-free-in-pow.patch +power-supply-goldfish-fix-use-after-free-in-power_su.patch +power-supply-rt9455-fix-use-after-free-in-power_supp.patch +power-supply-sbs-battery-fix-use-after-free-in-power.patch +power-reset-nvmem-reboot-mode-respect-cell-size-for-.patch +power-supply-bq27xxx-fix-wrong-errno-when-bus-ops-ar.patch +power-supply-wm97xx-fix-null-pointer-dereference-in-.patch +rdma-rtrs-srv-refactor-the-handling-of-failure-case-.patch +rdma-rtrs-srv-correct-the-checking-of-ib_map_mr_sg.patch +rdma-rtrs-srv-fix-sg-mapping.patch +rdma-rxe-fix-double-free-in-rxe_srq_from_init.patch +mtd-rawnand-cadence-fix-return-type-of-cdma-send-and.patch +crypto-ccp-add-an-s4-restore-flow.patch +rdma-uverbs-validate-wqe_size-before-using-it-in-ib_.patch +rdma-core-fix-a-couple-of-obvious-typos-in-comments.patch +svcrdma-remove-queue-shortening-warnings.patch +svcrdma-clean-up-comment-in-svc_rdma_accept.patch +svcrdma-increase-the-per-transport-rw_ctx-count.patch +svcrdma-reduce-the-number-of-rdma_rw-contexts-per-qp.patch +rdma-core-add-rdma_rw_max_sge-helper-for-sq-sizing.patch +mtd-parsers-ofpart-fix-of-node-refcount-leak-in-pars.patch +rdma-uverbs-add-__gfp_nowarn-to-ib_uverbs_unmarshall.patch +pnfs-fix-a-missing-wake-up-while-waiting-on-nfs_layo.patch +scsi-csiostor-fix-dereference-of-null-pointer-rn.patch +nvdimm-virtio_pmem-serialize-flush-requests.patch +tracing-remove-duplicate-enable_event_str-and-disabl.patch +fbdev-au1200fb-fix-a-memory-leak-in-au1200fb_drv_pro.patch +clk-qcom-rcg2-compute-2d-using-duty-fraction-directl.patch +clk-meson-gxbb-limit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch +clk-qcom-gcc-msm8953-remove-always_on-flag-from-cpp_.patch +clk-move-clk_-save-restore-_context-to-common_clk-se.patch +clk-qcom-dispcc-sdm845-enable-parents-for-pixel-cloc.patch +dmaengine-mediatek-uart-apdma-fix-above-4g-addressin.patch +dma-dma-axi-dmac-fix-sw-cyclic-transfers.patch +staging-greybus-lights-avoid-null-deref.patch +serial-imx-change-serial_imx_console-to-bool.patch +serial-sh_sci-improve-dma-support-prompt.patch +mmc-rtsx_pci_sdmmc-increase-power-on-settling-delay-.patch +coresight-etm3x-fix-cpulocked-warning-on-cpuhp.patch +revert-mmc-rtsx_pci_sdmmc-increase-power-on-settling.patch +mfd-arizona-fix-regulator-resource-leak-on-wm5102_cl.patch +drivers-iio-mpu3050-use-dev_err_probe-for-regulator-.patch +usb-bdc-fix-sleep-during-atomic.patch +pinctrl-equilibrium-fix-device-node-reference-leak-i.patch +ovl-fix-uninit-value-in-ovl_fill_real.patch +iio-sca3000-fix-a-resource-leak-in-sca3000_probe.patch +pinctrl-qcom-update-macro-name-to-lpi-specific.patch +pinctrl-qcom-update-lpi-pin-group-custiom-functions-.patch +pinctrl-qcom-extract-chip-specific-lpass-lpi-code.patch +pinctrl-qcom-sm8250-lpass-lpi-fix-i2s2_data_groups-d.patch +pinctrl-single-fix-refcount-leak-in-pcs_add_gpio_fun.patch +backlight-qcom-wled-support-ovp-values-for-pmi8994.patch diff --git a/queue-5.15/smack-smack-doi-accept-previously-used-values.patch b/queue-5.15/smack-smack-doi-accept-previously-used-values.patch new file mode 100644 index 0000000000..9d2440b16c --- /dev/null +++ b/queue-5.15/smack-smack-doi-accept-previously-used-values.patch @@ -0,0 +1,233 @@ +From fa6dce1d92233a72f9999baddcaeec84fc60fafd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Sep 2025 15:31:53 +0300 +Subject: smack: /smack/doi: accept previously used values +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Konstantin Andreev + +[ Upstream commit 33d589ed60ae433b483761987b85e0d24e54584e ] + +Writing to /smack/doi a value that has ever been +written there in the past disables networking for +non-ambient labels. +E.g. + + # cat /smack/doi + 3 + # netlabelctl -p cipso list + Configured CIPSO mappings (1) + DOI value : 3 + mapping type : PASS_THROUGH + # netlabelctl -p map list + Configured NetLabel domain mappings (3) + domain: "_" (IPv4) + protocol: UNLABELED + domain: DEFAULT (IPv4) + protocol: CIPSO, DOI = 3 + domain: DEFAULT (IPv6) + protocol: UNLABELED + + # cat /smack/ambient + _ + # cat /proc/$$/attr/smack/current + _ + # ping -c1 10.1.95.12 + 64 bytes from 10.1.95.12: icmp_seq=1 ttl=64 time=0.964 ms + # echo foo >/proc/$$/attr/smack/current + # ping -c1 10.1.95.12 + 64 bytes from 10.1.95.12: icmp_seq=1 ttl=64 time=0.956 ms + unknown option 86 + + # echo 4 >/smack/doi + # echo 3 >/smack/doi +!> [ 214.050395] smk_cipso_doi:691 cipso add rc = -17 + # echo 3 >/smack/doi +!> [ 249.402261] smk_cipso_doi:678 remove rc = -2 +!> [ 249.402261] smk_cipso_doi:691 cipso add rc = -17 + + # ping -c1 10.1.95.12 +!!> ping: 10.1.95.12: Address family for hostname not supported + + # echo _ >/proc/$$/attr/smack/current + # ping -c1 10.1.95.12 + 64 bytes from 10.1.95.12: icmp_seq=1 ttl=64 time=0.617 ms + +This happens because Smack keeps decommissioned DOIs, +fails to re-add them, and consequently refuses to add +the “default” domain map: + + # netlabelctl -p cipso list + Configured CIPSO mappings (2) + DOI value : 3 + mapping type : PASS_THROUGH + DOI value : 4 + mapping type : PASS_THROUGH + # netlabelctl -p map list + Configured NetLabel domain mappings (2) + domain: "_" (IPv4) + protocol: UNLABELED +!> (no ipv4 map for default domain here) + domain: DEFAULT (IPv6) + protocol: UNLABELED + +Fix by clearing decommissioned DOI definitions and +serializing concurrent DOI updates with a new lock. + +Also: +- allow /smack/doi to live unconfigured, since + adding a map (netlbl_cfg_cipsov4_map_add) may fail. + CIPSO_V4_DOI_UNKNOWN(0) indicates the unconfigured DOI +- add new DOI before removing the old default map, + so the old map remains if the add fails + +(2008-02-04, Casey Schaufler) +Fixes: e114e473771c ("Smack: Simplified Mandatory Access Control Kernel") + +Signed-off-by: Konstantin Andreev +Signed-off-by: Casey Schaufler +Signed-off-by: Sasha Levin +--- + security/smack/smackfs.c | 71 +++++++++++++++++++++++++--------------- + 1 file changed, 45 insertions(+), 26 deletions(-) + +diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c +index c0811defd2086..0e05b45052615 100644 +--- a/security/smack/smackfs.c ++++ b/security/smack/smackfs.c +@@ -67,6 +67,7 @@ enum smk_inos { + static DEFINE_MUTEX(smack_cipso_lock); + static DEFINE_MUTEX(smack_ambient_lock); + static DEFINE_MUTEX(smk_net4addr_lock); ++static DEFINE_MUTEX(smk_cipso_doi_lock); + #if IS_ENABLED(CONFIG_IPV6) + static DEFINE_MUTEX(smk_net6addr_lock); + #endif /* CONFIG_IPV6 */ +@@ -138,7 +139,7 @@ struct smack_parsed_rule { + int smk_access2; + }; + +-static u32 smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; ++static u32 smk_cipso_doi_value = CIPSO_V4_DOI_UNKNOWN; + + /* + * Values for parsing cipso rules +@@ -678,43 +679,60 @@ static const struct file_operations smk_load_ops = { + }; + + /** +- * smk_cipso_doi - initialize the CIPSO domain ++ * smk_cipso_doi - set netlabel maps ++ * @ndoi: new value for our CIPSO DOI ++ * @gfp_flags: kmalloc allocation context + */ +-static void smk_cipso_doi(void) ++static int ++smk_cipso_doi(u32 ndoi, gfp_t gfp_flags) + { +- int rc; ++ int rc = 0; + struct cipso_v4_doi *doip; + struct netlbl_audit nai; + +- smk_netlabel_audit_set(&nai); ++ mutex_lock(&smk_cipso_doi_lock); + +- rc = netlbl_cfg_map_del(NULL, PF_INET, NULL, NULL, &nai); +- if (rc != 0) +- printk(KERN_WARNING "%s:%d remove rc = %d\n", +- __func__, __LINE__, rc); ++ if (smk_cipso_doi_value == ndoi) ++ goto clr_doi_lock; ++ ++ smk_netlabel_audit_set(&nai); + +- doip = kmalloc(sizeof(struct cipso_v4_doi), GFP_KERNEL | __GFP_NOFAIL); ++ doip = kmalloc(sizeof(struct cipso_v4_doi), gfp_flags); ++ if (!doip) { ++ rc = -ENOMEM; ++ goto clr_doi_lock; ++ } + doip->map.std = NULL; +- doip->doi = smk_cipso_doi_value; ++ doip->doi = ndoi; + doip->type = CIPSO_V4_MAP_PASS; + doip->tags[0] = CIPSO_V4_TAG_RBITMAP; + for (rc = 1; rc < CIPSO_V4_TAG_MAXCNT; rc++) + doip->tags[rc] = CIPSO_V4_TAG_INVALID; + + rc = netlbl_cfg_cipsov4_add(doip, &nai); +- if (rc != 0) { +- printk(KERN_WARNING "%s:%d cipso add rc = %d\n", +- __func__, __LINE__, rc); ++ if (rc) { + kfree(doip); +- return; ++ goto clr_doi_lock; + } +- rc = netlbl_cfg_cipsov4_map_add(doip->doi, NULL, NULL, NULL, &nai); +- if (rc != 0) { +- printk(KERN_WARNING "%s:%d map add rc = %d\n", +- __func__, __LINE__, rc); +- netlbl_cfg_cipsov4_del(doip->doi, &nai); +- return; ++ ++ if (smk_cipso_doi_value != CIPSO_V4_DOI_UNKNOWN) { ++ rc = netlbl_cfg_map_del(NULL, PF_INET, NULL, NULL, &nai); ++ if (rc && rc != -ENOENT) ++ goto clr_ndoi_def; ++ ++ netlbl_cfg_cipsov4_del(smk_cipso_doi_value, &nai); + } ++ ++ rc = netlbl_cfg_cipsov4_map_add(ndoi, NULL, NULL, NULL, &nai); ++ if (rc) { ++ smk_cipso_doi_value = CIPSO_V4_DOI_UNKNOWN; // no default map ++clr_ndoi_def: netlbl_cfg_cipsov4_del(ndoi, &nai); ++ } else ++ smk_cipso_doi_value = ndoi; ++ ++clr_doi_lock: ++ mutex_unlock(&smk_cipso_doi_lock); ++ return rc; + } + + /** +@@ -1617,11 +1635,8 @@ static ssize_t smk_write_doi(struct file *file, const char __user *buf, + + if (u == CIPSO_V4_DOI_UNKNOWN || u > U32_MAX) + return -EINVAL; +- smk_cipso_doi_value = u; +- +- smk_cipso_doi(); + +- return count; ++ return smk_cipso_doi(u, GFP_KERNEL) ? : count; + } + + static const struct file_operations smk_doi_ops = { +@@ -2998,6 +3013,7 @@ static int __init init_smk_fs(void) + { + int err; + int rc; ++ struct netlbl_audit nai; + + if (smack_enabled == 0) + return 0; +@@ -3016,7 +3032,10 @@ static int __init init_smk_fs(void) + } + } + +- smk_cipso_doi(); ++ smk_netlabel_audit_set(&nai); ++ (void) netlbl_cfg_map_del(NULL, PF_INET, NULL, NULL, &nai); ++ (void) smk_cipso_doi(SMACK_CIPSO_DOI_DEFAULT, ++ GFP_KERNEL | __GFP_NOFAIL); + smk_unlbl_ambient(NULL); + + rc = smack_populate_secattr(&smack_known_floor); +-- +2.51.0 + diff --git a/queue-5.15/smack-smack-doi-must-be-0.patch b/queue-5.15/smack-smack-doi-must-be-0.patch new file mode 100644 index 0000000000..76ada8c3aa --- /dev/null +++ b/queue-5.15/smack-smack-doi-must-be-0.patch @@ -0,0 +1,71 @@ +From 89f0210913d9e2ad6d11300ae1b381becbb839ef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Sep 2025 15:16:02 +0300 +Subject: smack: /smack/doi must be > 0 + +From: Konstantin Andreev + +[ Upstream commit 19c013e1551bf51e1493da1270841d60e4fd3f15 ] + +/smack/doi allows writing and keeping negative doi values. +Correct values are 0 < doi <= (max 32-bit positive integer) + +(2008-02-04, Casey Schaufler) +Fixes: e114e473771c ("Smack: Simplified Mandatory Access Control Kernel") + +Signed-off-by: Konstantin Andreev +Signed-off-by: Casey Schaufler +Signed-off-by: Sasha Levin +--- + security/smack/smackfs.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c +index 0feaa29cc0243..c0811defd2086 100644 +--- a/security/smack/smackfs.c ++++ b/security/smack/smackfs.c +@@ -138,7 +138,7 @@ struct smack_parsed_rule { + int smk_access2; + }; + +-static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; ++static u32 smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; + + /* + * Values for parsing cipso rules +@@ -1580,7 +1580,7 @@ static ssize_t smk_read_doi(struct file *filp, char __user *buf, + if (*ppos != 0) + return 0; + +- sprintf(temp, "%d", smk_cipso_doi_value); ++ sprintf(temp, "%lu", (unsigned long)smk_cipso_doi_value); + rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp)); + + return rc; +@@ -1599,7 +1599,7 @@ static ssize_t smk_write_doi(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) + { + char temp[80]; +- int i; ++ unsigned long u; + + if (!smack_privileged(CAP_MAC_ADMIN)) + return -EPERM; +@@ -1612,10 +1612,12 @@ static ssize_t smk_write_doi(struct file *file, const char __user *buf, + + temp[count] = '\0'; + +- if (sscanf(temp, "%d", &i) != 1) ++ if (kstrtoul(temp, 10, &u)) + return -EINVAL; + +- smk_cipso_doi_value = i; ++ if (u == CIPSO_V4_DOI_UNKNOWN || u > U32_MAX) ++ return -EINVAL; ++ smk_cipso_doi_value = u; + + smk_cipso_doi(); + +-- +2.51.0 + diff --git a/queue-5.15/soc-qcom-cmd-db-use-devm_memremap-to-fix-memory-leak.patch b/queue-5.15/soc-qcom-cmd-db-use-devm_memremap-to-fix-memory-leak.patch new file mode 100644 index 0000000000..0db6c46cbe --- /dev/null +++ b/queue-5.15/soc-qcom-cmd-db-use-devm_memremap-to-fix-memory-leak.patch @@ -0,0 +1,53 @@ +From 0fcc9b3b02ca1f1fe6efcb80f5773502a7c48f81 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Dec 2025 09:39:32 +0800 +Subject: soc: qcom: cmd-db: Use devm_memremap() to fix memory leak in + cmd_db_dev_probe + +From: Haotian Zhang + +[ Upstream commit 0da7824734d8d83e6a844dd0207f071cb0c50cf4 ] + +If cmd_db_magic_matches() fails after memremap() succeeds, the function +returns -EINVAL without unmapping the memory region, causing a +potential resource leak. + +Switch to devm_memremap to automatically manage the map resource. + +Fixes: 312416d9171a ("drivers: qcom: add command DB driver") +Suggested-by: Dmitry Baryshkov +Signed-off-by: Haotian Zhang +Link: https://lore.kernel.org/r/20251216013933.773-1-vulab@iscas.ac.cn +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/cmd-db.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/soc/qcom/cmd-db.c b/drivers/soc/qcom/cmd-db.c +index 6cb5e3956fc52..7854f49611cd7 100644 +--- a/drivers/soc/qcom/cmd-db.c ++++ b/drivers/soc/qcom/cmd-db.c +@@ -350,15 +350,16 @@ static int cmd_db_dev_probe(struct platform_device *pdev) + return -EINVAL; + } + +- cmd_db_header = memremap(rmem->base, rmem->size, MEMREMAP_WC); +- if (!cmd_db_header) { +- ret = -ENOMEM; ++ cmd_db_header = devm_memremap(&pdev->dev, rmem->base, rmem->size, MEMREMAP_WC); ++ if (IS_ERR(cmd_db_header)) { ++ ret = PTR_ERR(cmd_db_header); + cmd_db_header = NULL; + return ret; + } + + if (!cmd_db_magic_matches(cmd_db_header)) { + dev_err(&pdev->dev, "Invalid Command DB Magic\n"); ++ cmd_db_header = NULL; + return -EINVAL; + } + +-- +2.51.0 + diff --git a/queue-5.15/spi-tools-add-include-folder-to-.gitignore.patch b/queue-5.15/spi-tools-add-include-folder-to-.gitignore.patch new file mode 100644 index 0000000000..2706a0b782 --- /dev/null +++ b/queue-5.15/spi-tools-add-include-folder-to-.gitignore.patch @@ -0,0 +1,35 @@ +From 69fef38eb88c69cd9dd76a8ca8a25684903bb545 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 10:50:01 +0100 +Subject: spi: tools: Add include folder to .gitignore + +From: Francesco Lavra + +[ Upstream commit 5af56f30c4fcbade4a92f94dadfea517d1db9703 ] + +The Makefile for the SPI tools creates an include/linux/spi folder and some +symlinks inside it. After running `make -C spi/tools`, this folder shows up +as untracked in the git status. +Add the above folder to the .gitignore file. + +Fixes: f325b73dc4db ("spi: tools: move to tools buildsystem") +Signed-off-by: Francesco Lavra +Link: https://patch.msgid.link/20260209095001.556495-1-flavra@baylibre.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + tools/spi/.gitignore | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/tools/spi/.gitignore b/tools/spi/.gitignore +index 14ddba3d21957..038261b34ed83 100644 +--- a/tools/spi/.gitignore ++++ b/tools/spi/.gitignore +@@ -1,3 +1,4 @@ + # SPDX-License-Identifier: GPL-2.0-only + spidev_fdx + spidev_test ++include/ +-- +2.51.0 + diff --git a/queue-5.15/staging-greybus-lights-avoid-null-deref.patch b/queue-5.15/staging-greybus-lights-avoid-null-deref.patch new file mode 100644 index 0000000000..8ddfb1af4b --- /dev/null +++ b/queue-5.15/staging-greybus-lights-avoid-null-deref.patch @@ -0,0 +1,55 @@ +From 24ba3492db242c013645f0569ee3515c514e769f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 20:42:54 +0530 +Subject: staging: greybus: lights: avoid NULL deref + +From: Chaitanya Mishra + +[ Upstream commit efcffd9a6ad8d190651498d5eda53bfc7cf683a7 ] + +gb_lights_light_config() stores channel_count before allocating the +channels array. If kcalloc() fails, gb_lights_release() iterates the +non-zero count and dereferences light->channels, which is NULL. + +Allocate channels first and only then publish channels_count so the +cleanup path can't walk a NULL pointer. + +Fixes: 2870b52bae4c ("greybus: lights: add lights implementation") +Link: https://lore.kernel.org/all/20260108103700.15384-1-chaitanyamishra.ai@gmail.com/ +Reviewed-by: Rui Miguel Silva +Signed-off-by: Chaitanya Mishra +Link: https://patch.msgid.link/20260108151254.81553-1-chaitanyamishra.ai@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/staging/greybus/light.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/drivers/staging/greybus/light.c b/drivers/staging/greybus/light.c +index 9999f84016992..eb69500e080e0 100644 +--- a/drivers/staging/greybus/light.c ++++ b/drivers/staging/greybus/light.c +@@ -1029,14 +1029,18 @@ static int gb_lights_light_config(struct gb_lights *glights, u8 id) + if (!strlen(conf.name)) + return -EINVAL; + +- light->channels_count = conf.channel_count; + light->name = kstrndup(conf.name, NAMES_MAX, GFP_KERNEL); + if (!light->name) + return -ENOMEM; +- light->channels = kcalloc(light->channels_count, ++ light->channels = kcalloc(conf.channel_count, + sizeof(struct gb_channel), GFP_KERNEL); + if (!light->channels) + return -ENOMEM; ++ /* ++ * Publish channels_count only after channels allocation so cleanup ++ * doesn't walk a NULL channels pointer on allocation failure. ++ */ ++ light->channels_count = conf.channel_count; + + /* First we collect all the configurations for all channels */ + for (i = 0; i < light->channels_count; i++) { +-- +2.51.0 + diff --git a/queue-5.15/svcrdma-clean-up-comment-in-svc_rdma_accept.patch b/queue-5.15/svcrdma-clean-up-comment-in-svc_rdma_accept.patch new file mode 100644 index 0000000000..7c98813c07 --- /dev/null +++ b/queue-5.15/svcrdma-clean-up-comment-in-svc_rdma_accept.patch @@ -0,0 +1,64 @@ +From a9a00034b019f944042e471213302fb73e0c2677 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 Dec 2023 10:24:34 -0500 +Subject: svcrdma: Clean up comment in svc_rdma_accept() + +From: Chuck Lever + +[ Upstream commit fc2e69db82c1ac506cd7f539a3ab66d51d3380dc ] + +The comment that starts "Qualify ..." applies to only some of the +following code paragraph. Re-arrange the lines so the comment makes +more sense. + +Signed-off-by: Chuck Lever +Stable-dep-of: afcae7d7b8a2 ("RDMA/core: add rdma_rw_max_sge() helper for SQ sizing") +Signed-off-by: Sasha Levin +--- + net/sunrpc/xprtrdma/svc_rdma_transport.c | 17 ++++++++++------- + 1 file changed, 10 insertions(+), 7 deletions(-) + +diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c +index 7b7e882c7a508..31e6f4a14bbc0 100644 +--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c ++++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c +@@ -393,18 +393,22 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + dev = newxprt->sc_cm_id->device; + newxprt->sc_port_num = newxprt->sc_cm_id->port_num; + +- /* Qualify the transport resource defaults with the +- * capabilities of this particular device */ ++ newxprt->sc_max_req_size = svcrdma_max_req_size; ++ newxprt->sc_max_requests = svcrdma_max_requests; ++ newxprt->sc_max_bc_requests = svcrdma_max_bc_requests; ++ newxprt->sc_recv_batch = RPCRDMA_MAX_RECV_BATCH; ++ newxprt->sc_fc_credits = cpu_to_be32(newxprt->sc_max_requests); ++ ++ /* Qualify the transport's resource defaults with the ++ * capabilities of this particular device. ++ */ ++ + /* Transport header, head iovec, tail iovec */ + newxprt->sc_max_send_sges = 3; + /* Add one SGE per page list entry */ + newxprt->sc_max_send_sges += (svcrdma_max_req_size / PAGE_SIZE) + 1; + if (newxprt->sc_max_send_sges > dev->attrs.max_send_sge) + newxprt->sc_max_send_sges = dev->attrs.max_send_sge; +- newxprt->sc_max_req_size = svcrdma_max_req_size; +- newxprt->sc_max_requests = svcrdma_max_requests; +- newxprt->sc_max_bc_requests = svcrdma_max_bc_requests; +- newxprt->sc_recv_batch = RPCRDMA_MAX_RECV_BATCH; + rq_depth = newxprt->sc_max_requests + newxprt->sc_max_bc_requests + + newxprt->sc_recv_batch; + if (rq_depth > dev->attrs.max_qp_wr) { +@@ -413,7 +417,6 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + newxprt->sc_max_requests = rq_depth - 2; + newxprt->sc_max_bc_requests = 2; + } +- newxprt->sc_fc_credits = cpu_to_be32(newxprt->sc_max_requests); + ctxts = rdma_rw_mr_factor(dev, newxprt->sc_port_num, RPCSVC_MAXPAGES); + ctxts *= newxprt->sc_max_requests; + newxprt->sc_sq_depth = rq_depth + ctxts; +-- +2.51.0 + diff --git a/queue-5.15/svcrdma-increase-the-per-transport-rw_ctx-count.patch b/queue-5.15/svcrdma-increase-the-per-transport-rw_ctx-count.patch new file mode 100644 index 0000000000..4a384c4459 --- /dev/null +++ b/queue-5.15/svcrdma-increase-the-per-transport-rw_ctx-count.patch @@ -0,0 +1,73 @@ +From 53c0fadac43bfb08f161ec9564b640b278ab8e88 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 4 Feb 2024 18:16:56 -0500 +Subject: svcrdma: Increase the per-transport rw_ctx count + +From: Chuck Lever + +[ Upstream commit 2da0f610e733606e06284ac3c1f188b9dec75d68 ] + +rdma_rw_mr_factor() returns the smallest number of MRs needed to +move a particular number of pages. svcrdma currently asks for the +number of MRs needed to move RPCSVC_MAXPAGES (a little over one +megabyte), as that is the number of pages in the largest r/wsize +the server supports. + +This call assumes that the client's NIC can bundle a full one +megabyte payload in a single rdma_segment. In fact, most NICs cannot +handle a full megabyte with a single rkey / rdma_segment. Clients +will typically split even a single Read chunk into many segments. + +The server needs one MR to read each rdma_segment in a Read chunk, +and thus each one needs an rw_ctx. + +svcrdma has been vastly underestimating the number of rw_ctxs needed +to handle 64 RPC requests with large Read chunks using small +rdma_segments. + +Unfortunately there doesn't seem to be a good way to estimate this +number without knowing the client NIC's capabilities. Even then, +the client RPC/RDMA implementation is still free to split a chunk +into smaller segments (for example, it might be using physical +registration, which needs an rdma_segment per page). + +The best we can do for now is choose a number that will guarantee +forward progress in the worst case (one page per segment). + +At some later point, we could add some mechanisms to make this +much less of a problem: +- Add a core API to add more rw_ctxs to an already-established QP +- svcrdma could treat rw_ctx exhaustion as a temporary error and + try again +- Limit the number of Reads in flight + +Signed-off-by: Chuck Lever +Stable-dep-of: afcae7d7b8a2 ("RDMA/core: add rdma_rw_max_sge() helper for SQ sizing") +Signed-off-by: Sasha Levin +--- + net/sunrpc/xprtrdma/svc_rdma_transport.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c +index 31e6f4a14bbc0..3d3b15f9d6d51 100644 +--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c ++++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c +@@ -417,8 +417,13 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + newxprt->sc_max_requests = rq_depth - 2; + newxprt->sc_max_bc_requests = 2; + } +- ctxts = rdma_rw_mr_factor(dev, newxprt->sc_port_num, RPCSVC_MAXPAGES); +- ctxts *= newxprt->sc_max_requests; ++ ++ /* Arbitrarily estimate the number of rw_ctxs needed for ++ * this transport. This is enough rw_ctxs to make forward ++ * progress even if the client is using one rkey per page ++ * in each Read chunk. ++ */ ++ ctxts = 3 * RPCSVC_MAXPAGES; + newxprt->sc_sq_depth = rq_depth + ctxts; + if (newxprt->sc_sq_depth > dev->attrs.max_qp_wr) + newxprt->sc_sq_depth = dev->attrs.max_qp_wr; +-- +2.51.0 + diff --git a/queue-5.15/svcrdma-reduce-the-number-of-rdma_rw-contexts-per-qp.patch b/queue-5.15/svcrdma-reduce-the-number-of-rdma_rw-contexts-per-qp.patch new file mode 100644 index 0000000000..f9e20f28ec --- /dev/null +++ b/queue-5.15/svcrdma-reduce-the-number-of-rdma_rw-contexts-per-qp.patch @@ -0,0 +1,96 @@ +From 97e694e254cf4a0781423a2ecab08193a11ccfff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 28 Apr 2025 15:36:49 -0400 +Subject: svcrdma: Reduce the number of rdma_rw contexts per-QP + +From: Chuck Lever + +[ Upstream commit 59243315890578a040a2d50ae9e001a2ef2fcb62 ] + +There is an upper bound on the number of rdma_rw contexts that can +be created per QP. + +This invisible upper bound is because rdma_create_qp() adds one or +more additional SQEs for each ctxt that the ULP requests via +qp_attr.cap.max_rdma_ctxs. The QP's actual Send Queue length is on +the order of the sum of qp_attr.cap.max_send_wr and a factor times +qp_attr.cap.max_rdma_ctxs. The factor can be up to three, depending +on whether MR operations are required before RDMA Reads. + +This limit is not visible to RDMA consumers via dev->attrs. When the +limit is surpassed, QP creation fails with -ENOMEM. For example: + +svcrdma's estimate of the number of rdma_rw contexts it needs is +three times the number of pages in RPCSVC_MAXPAGES. When MAXPAGES +is about 260, the internally-computed SQ length should be: + +64 credits + 10 backlog + 3 * (3 * 260) = 2414 + +Which is well below the advertised qp_max_wr of 32768. + +If RPCSVC_MAXPAGES is increased to 4MB, that's 1040 pages: + +64 credits + 10 backlog + 3 * (3 * 1040) = 9434 + +However, QP creation fails. Dynamic printk for mlx5 shows: + +calc_sq_size:618:(pid 1514): send queue size (9326 * 256 / 64 -> 65536) exceeds limits(32768) + +Although 9326 is still far below qp_max_wr, QP creation still +fails. + +Because the total SQ length calculation is opaque to RDMA consumers, +there doesn't seem to be much that can be done about this except for +consumers to try to keep the requested rdma_rw ctxt count low. + +Fixes: 2da0f610e733 ("svcrdma: Increase the per-transport rw_ctx count") +Reviewed-by: NeilBrown +Reviewed-by: Christoph Hellwig +Signed-off-by: Chuck Lever +Stable-dep-of: afcae7d7b8a2 ("RDMA/core: add rdma_rw_max_sge() helper for SQ sizing") +Signed-off-by: Sasha Levin +--- + net/sunrpc/xprtrdma/svc_rdma_transport.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c +index 3d3b15f9d6d51..c5721b75d32a7 100644 +--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c ++++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c +@@ -365,12 +365,12 @@ static struct svc_xprt *svc_rdma_create(struct svc_serv *serv, + */ + static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + { ++ unsigned int ctxts, rq_depth, maxpayload; + struct svcxprt_rdma *listen_rdma; + struct svcxprt_rdma *newxprt = NULL; + struct rdma_conn_param conn_param; + struct rpcrdma_connect_private pmsg; + struct ib_qp_init_attr qp_attr; +- unsigned int ctxts, rq_depth; + struct ib_device *dev; + int ret = 0; + RPC_IFDEBUG(struct sockaddr *sap); +@@ -418,12 +418,14 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + newxprt->sc_max_bc_requests = 2; + } + +- /* Arbitrarily estimate the number of rw_ctxs needed for +- * this transport. This is enough rw_ctxs to make forward +- * progress even if the client is using one rkey per page +- * in each Read chunk. ++ /* Arbitrary estimate of the needed number of rdma_rw contexts. + */ +- ctxts = 3 * RPCSVC_MAXPAGES; ++ maxpayload = min(xprt->xpt_server->sv_max_payload, ++ RPCSVC_MAXPAYLOAD_RDMA); ++ ctxts = newxprt->sc_max_requests * 3 * ++ rdma_rw_mr_factor(dev, newxprt->sc_port_num, ++ maxpayload >> PAGE_SHIFT); ++ + newxprt->sc_sq_depth = rq_depth + ctxts; + if (newxprt->sc_sq_depth > dev->attrs.max_qp_wr) + newxprt->sc_sq_depth = dev->attrs.max_qp_wr; +-- +2.51.0 + diff --git a/queue-5.15/svcrdma-remove-queue-shortening-warnings.patch b/queue-5.15/svcrdma-remove-queue-shortening-warnings.patch new file mode 100644 index 0000000000..8a84487cc3 --- /dev/null +++ b/queue-5.15/svcrdma-remove-queue-shortening-warnings.patch @@ -0,0 +1,52 @@ +From 5932234c0a3d133e5ad6cc187662ed078fe29737 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 Dec 2023 10:24:28 -0500 +Subject: svcrdma: Remove queue-shortening warnings + +From: Chuck Lever + +[ Upstream commit b918bfcf370c92ea3b82fa9bb3d017702b5fa4cb ] + +These won't have much diagnostic value for site administrators. +Since they can't be disabled, they become noise. + +What's more, the subsequent rdma_create_qp() call adjusts the Send +Queue size (possibly downward) without warning, making the size +reported by these pr_warns inaccurate. + +Signed-off-by: Chuck Lever +Stable-dep-of: afcae7d7b8a2 ("RDMA/core: add rdma_rw_max_sge() helper for SQ sizing") +Signed-off-by: Sasha Levin +--- + net/sunrpc/xprtrdma/svc_rdma_transport.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c +index f776f0cb471f0..7b7e882c7a508 100644 +--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c ++++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c +@@ -408,8 +408,6 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + rq_depth = newxprt->sc_max_requests + newxprt->sc_max_bc_requests + + newxprt->sc_recv_batch; + if (rq_depth > dev->attrs.max_qp_wr) { +- pr_warn("svcrdma: reducing receive depth to %d\n", +- dev->attrs.max_qp_wr); + rq_depth = dev->attrs.max_qp_wr; + newxprt->sc_recv_batch = 1; + newxprt->sc_max_requests = rq_depth - 2; +@@ -419,11 +417,8 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + ctxts = rdma_rw_mr_factor(dev, newxprt->sc_port_num, RPCSVC_MAXPAGES); + ctxts *= newxprt->sc_max_requests; + newxprt->sc_sq_depth = rq_depth + ctxts; +- if (newxprt->sc_sq_depth > dev->attrs.max_qp_wr) { +- pr_warn("svcrdma: reducing send depth to %d\n", +- dev->attrs.max_qp_wr); ++ if (newxprt->sc_sq_depth > dev->attrs.max_qp_wr) + newxprt->sc_sq_depth = dev->attrs.max_qp_wr; +- } + atomic_set(&newxprt->sc_sq_avail, newxprt->sc_sq_depth); + + newxprt->sc_pd = ib_alloc_pd(dev, 0); +-- +2.51.0 + diff --git a/queue-5.15/tcp-tcp_tx_timestamp-must-look-at-the-rtx-queue.patch b/queue-5.15/tcp-tcp_tx_timestamp-must-look-at-the-rtx-queue.patch new file mode 100644 index 0000000000..1cee41deeb --- /dev/null +++ b/queue-5.15/tcp-tcp_tx_timestamp-must-look-at-the-rtx-queue.patch @@ -0,0 +1,44 @@ +From 3ecf52ac5fee37cc3aa799b1d806f8ac8ad6dd93 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 12:38:27 +0000 +Subject: tcp: tcp_tx_timestamp() must look at the rtx queue + +From: Eric Dumazet + +[ Upstream commit 838eb9687691d29915797a885b861fd09353386e ] + +tcp_tx_timestamp() is only called at the end of tcp_sendmsg_locked() +before the final tcp_push(). + +By the time it is called, it is possible all the copied data +has been sent already (transmit queue is empty). + +If this is the case, use the last skb in the rtx queue. + +Fixes: 75c119afe14f ("tcp: implement rb-tree based retransmit queue") +Signed-off-by: Eric Dumazet +Reviewed-by: Jason Xing +Link: https://patch.msgid.link/20260127123828.4098577-2-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index b3d373372e841..36981a3e9013f 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -471,6 +471,9 @@ static void tcp_tx_timestamp(struct sock *sk, u16 tsflags) + { + struct sk_buff *skb = tcp_write_queue_tail(sk); + ++ if (unlikely(!skb)) ++ skb = skb_rb_last(&sk->tcp_rtx_queue); ++ + if (tsflags && skb) { + struct skb_shared_info *shinfo = skb_shinfo(skb); + struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); +-- +2.51.0 + diff --git a/queue-5.15/timers-replace-in_irq-with-in_hardirq.patch b/queue-5.15/timers-replace-in_irq-with-in_hardirq.patch new file mode 100644 index 0000000000..abfd1ee199 --- /dev/null +++ b/queue-5.15/timers-replace-in_irq-with-in_hardirq.patch @@ -0,0 +1,38 @@ +From 8b29c1c3deb8e3e090096db923e95b2bdfafb11d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 12 Oct 2022 01:26:29 +0000 +Subject: timers: Replace in_irq() with in_hardirq() + +From: ye xingchen + +[ Upstream commit 8be3f96ceddb911539a53d87a66da84a04502366 ] + +Replace the obsolete and ambiguous macro in_irq() with new +macro in_hardirq(). + +Signed-off-by: ye xingchen +Signed-off-by: Thomas Gleixner +Acked-by: John Stultz +Link: https://lore.kernel.org/r/20221012012629.334966-1-ye.xingchen@zte.com.cn +Stable-dep-of: c9efde1e537b ("nfc: hci: shdlc: Stop timers and work before freeing context") +Signed-off-by: Sasha Levin +--- + kernel/time/timer.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/time/timer.c b/kernel/time/timer.c +index ab4709be7a59a..827d2ec268678 100644 +--- a/kernel/time/timer.c ++++ b/kernel/time/timer.c +@@ -1508,7 +1508,7 @@ static int __timer_delete_sync(struct timer_list *timer, bool shutdown) + * don't use it in hardirq context, because it + * could lead to deadlock. + */ +- WARN_ON(in_irq() && !(timer->flags & TIMER_IRQSAFE)); ++ WARN_ON(in_hardirq() && !(timer->flags & TIMER_IRQSAFE)); + + /* + * Must be able to sleep on PREEMPT_RT because of the slowpath in +-- +2.51.0 + diff --git a/queue-5.15/tpm-st33zp24-fix-missing-cleanup-on-get_burstcount-e.patch b/queue-5.15/tpm-st33zp24-fix-missing-cleanup-on-get_burstcount-e.patch new file mode 100644 index 0000000000..4ef5527bb9 --- /dev/null +++ b/queue-5.15/tpm-st33zp24-fix-missing-cleanup-on-get_burstcount-e.patch @@ -0,0 +1,43 @@ +From 3110306487879c0e3d502a83f3f04a3179bccf24 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Dec 2025 15:09:27 +0300 +Subject: tpm: st33zp24: Fix missing cleanup on get_burstcount() error + +From: Alper Ak + +[ Upstream commit 3e91b44c93ad2871f89fc2a98c5e4fe6ca5db3d9 ] + +get_burstcount() can return -EBUSY on timeout. When this happens, +st33zp24_send() returns directly without releasing the locality +acquired earlier. + +Use goto out_err to ensure proper cleanup when get_burstcount() fails. + +Fixes: bf38b8710892 ("tpm/tpm_i2c_stm_st33: Split tpm_i2c_tpm_st33 in 2 layers (core + phy)") +Signed-off-by: Alper Ak +Signed-off-by: Jarkko Sakkinen +Signed-off-by: Sasha Levin +--- + drivers/char/tpm/st33zp24/st33zp24.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/char/tpm/st33zp24/st33zp24.c b/drivers/char/tpm/st33zp24/st33zp24.c +index 4ec10ab5e5766..33ee4fe693796 100644 +--- a/drivers/char/tpm/st33zp24/st33zp24.c ++++ b/drivers/char/tpm/st33zp24/st33zp24.c +@@ -381,8 +381,10 @@ static int st33zp24_send(struct tpm_chip *chip, unsigned char *buf, + + for (i = 0; i < len - 1;) { + burstcnt = get_burstcount(chip); +- if (burstcnt < 0) +- return burstcnt; ++ if (burstcnt < 0) { ++ ret = burstcnt; ++ goto out_err; ++ } + size = min_t(int, len - i - 1, burstcnt); + ret = tpm_dev->ops->send(tpm_dev->phy_id, TPM_DATA_FIFO, + buf + i, size); +-- +2.51.0 + diff --git a/queue-5.15/tpm-tpm_i2c_infineon-fix-locality-leak-on-get_burstc.patch b/queue-5.15/tpm-tpm_i2c_infineon-fix-locality-leak-on-get_burstc.patch new file mode 100644 index 0000000000..7db210345f --- /dev/null +++ b/queue-5.15/tpm-tpm_i2c_infineon-fix-locality-leak-on-get_burstc.patch @@ -0,0 +1,44 @@ +From 4a269ee4091f90f0fc77229de62abcd5aa3baaf8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Dec 2025 13:23:38 +0300 +Subject: tpm: tpm_i2c_infineon: Fix locality leak on get_burstcount() failure + +From: Alper Ak + +[ Upstream commit bbd6e97c836cbeb9606d7b7e5dcf8a1d89525713 ] + +get_burstcount() can return -EBUSY on timeout. When this happens, the +function returns directly without releasing the locality that was +acquired at the beginning of tpm_tis_i2c_send(). + +Use goto out_err to ensure proper cleanup when get_burstcount() fails. + +Fixes: aad628c1d91a ("char/tpm: Add new driver for Infineon I2C TIS TPM") +Signed-off-by: Alper Ak +Reviewed-by: Jarkko Sakkinen +Signed-off-by: Jarkko Sakkinen +Signed-off-by: Sasha Levin +--- + drivers/char/tpm/tpm_i2c_infineon.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c +index a19d32cb4e942..cabc9e1b49321 100644 +--- a/drivers/char/tpm/tpm_i2c_infineon.c ++++ b/drivers/char/tpm/tpm_i2c_infineon.c +@@ -543,8 +543,10 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len) + burstcnt = get_burstcount(chip); + + /* burstcnt < 0 = TPM is busy */ +- if (burstcnt < 0) +- return burstcnt; ++ if (burstcnt < 0) { ++ rc = burstcnt; ++ goto out_err; ++ } + + if (burstcnt > (len - 1 - count)) + burstcnt = len - 1 - count; +-- +2.51.0 + diff --git a/queue-5.15/tracing-remove-duplicate-enable_event_str-and-disabl.patch b/queue-5.15/tracing-remove-duplicate-enable_event_str-and-disabl.patch new file mode 100644 index 0000000000..feec607358 --- /dev/null +++ b/queue-5.15/tracing-remove-duplicate-enable_event_str-and-disabl.patch @@ -0,0 +1,44 @@ +From a6e35fdc907472589892fcde49926df27db5e425 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 13:00:37 -0500 +Subject: tracing: Remove duplicate ENABLE_EVENT_STR and DISABLE_EVENT_STR + macros + +From: Steven Rostedt + +[ Upstream commit 9df0e49c5b9b8d051529be9994e4f92f2d20be6f ] + +The macros ENABLE_EVENT_STR and DISABLE_EVENT_STR were added to trace.h so +that more than one file can have access to them, but was never removed +from their original location. Remove the duplicates. + +Cc: Masami Hiramatsu +Cc: Mathieu Desnoyers +Cc: Tom Zanussi +Link: https://patch.msgid.link/20260126130037.4ba201f9@gandalf.local.home +Fixes: d0bad49bb0a09 ("tracing: Add enable_hist/disable_hist triggers") +Signed-off-by: Steven Rostedt (Google) +Signed-off-by: Sasha Levin +--- + kernel/trace/trace_events.c | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c +index 4e282deb6f787..1dfdbd365c8c2 100644 +--- a/kernel/trace/trace_events.c ++++ b/kernel/trace/trace_events.c +@@ -3294,11 +3294,6 @@ void trace_put_event_file(struct trace_event_file *file) + EXPORT_SYMBOL_GPL(trace_put_event_file); + + #ifdef CONFIG_DYNAMIC_FTRACE +- +-/* Avoid typos */ +-#define ENABLE_EVENT_STR "enable_event" +-#define DISABLE_EVENT_STR "disable_event" +- + struct event_probe_data { + struct trace_event_file *file; + unsigned long count; +-- +2.51.0 + diff --git a/queue-5.15/ucount-check-for-cap_sys_resource-using-ns_capable_n.patch b/queue-5.15/ucount-check-for-cap_sys_resource-using-ns_capable_n.patch new file mode 100644 index 0000000000..bb1c277fde --- /dev/null +++ b/queue-5.15/ucount-check-for-cap_sys_resource-using-ns_capable_n.patch @@ -0,0 +1,51 @@ +From bc319ae33cbfddc954e3feeab28e36651f60d5b2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 15:07:45 +0100 +Subject: ucount: check for CAP_SYS_RESOURCE using ns_capable_noaudit() + +From: Ondrej Mosnacek + +[ Upstream commit 0895a000e4fff9e950a7894210db45973e485c35 ] + +The user.* sysctls implement the ctl_table_root::permissions hook and they +override the file access mode based on the CAP_SYS_RESOURCE capability (at +most rwx if capable, at most r-- if not). The capability is being checked +unconditionally, so if an LSM denies the capability, an audit record may +be logged even when access is in fact granted. + +Given the logic in the set_permissions() function in kernel/ucount.c and +the unfortunate way the permission checking is implemented, it doesn't +seem viable to avoid false positive denials by deferring the capability +check. Thus, do the same as in net_ctl_permissions() (net/sysctl_net.c) - +switch from ns_capable() to ns_capable_noaudit(), so that the check never +logs an audit record. + +Link: https://lkml.kernel.org/r/20260122140745.239428-1-omosnace@redhat.com +Fixes: dbec28460a89 ("userns: Add per user namespace sysctls.") +Signed-off-by: Ondrej Mosnacek +Reviewed-by: Paul Moore +Acked-by: Serge Hallyn +Cc: Eric Biederman +Cc: Alexey Gladkov +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + kernel/ucount.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/ucount.c b/kernel/ucount.c +index 8c21398f7b4fc..cc8ec071d46d3 100644 +--- a/kernel/ucount.c ++++ b/kernel/ucount.c +@@ -45,7 +45,7 @@ static int set_permissions(struct ctl_table_header *head, + int mode; + + /* Allow users with CAP_SYS_RESOURCE unrestrained access */ +- if (ns_capable(user_ns, CAP_SYS_RESOURCE)) ++ if (ns_capable_noaudit(user_ns, CAP_SYS_RESOURCE)) + mode = (table->mode & S_IRWXU) >> 6; + else + /* Allow all others at most read-only access */ +-- +2.51.0 + diff --git a/queue-5.15/usb-bdc-fix-sleep-during-atomic.patch b/queue-5.15/usb-bdc-fix-sleep-during-atomic.patch new file mode 100644 index 0000000000..631006e044 --- /dev/null +++ b/queue-5.15/usb-bdc-fix-sleep-during-atomic.patch @@ -0,0 +1,41 @@ +From 4ab473423146cf0a7c12098c75e90f5fec9f0fef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 12:07:54 -0800 +Subject: usb: bdc: fix sleep during atomic + +From: Justin Chen + +[ Upstream commit f1195ca3b4bbd001d3f1264dce91f83dec7777f5 ] + +bdc_run() can be ran during atomic context leading to a sleep during +atomic warning. Fix this by replacing read_poll_timeout() with +read_poll_timeout_atomic(). + +Fixes: 75ae051efc9b ("usb: gadget: bdc: use readl_poll_timeout() to simplify code") +Signed-off-by: Justin Chen +Reviewed-by: Florian Fainelli +Link: https://patch.msgid.link/20260120200754.2488765-1-justin.chen@broadcom.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/gadget/udc/bdc/bdc_core.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/usb/gadget/udc/bdc/bdc_core.c b/drivers/usb/gadget/udc/bdc/bdc_core.c +index fa1a3908ec3bb..69d11b703c8d0 100644 +--- a/drivers/usb/gadget/udc/bdc/bdc_core.c ++++ b/drivers/usb/gadget/udc/bdc/bdc_core.c +@@ -35,8 +35,8 @@ static int poll_oip(struct bdc *bdc, u32 usec) + u32 status; + int ret; + +- ret = readl_poll_timeout(bdc->regs + BDC_BDCSC, status, +- (BDC_CSTS(status) != BDC_OIP), 10, usec); ++ ret = readl_poll_timeout_atomic(bdc->regs + BDC_BDCSC, status, ++ (BDC_CSTS(status) != BDC_OIP), 10, usec); + if (ret) + dev_err(bdc->dev, "operation timedout BDCSC: 0x%08x\n", status); + else +-- +2.51.0 + diff --git a/queue-5.15/wifi-ath10k-sdio-add-missing-lock-protection-in-ath1.patch b/queue-5.15/wifi-ath10k-sdio-add-missing-lock-protection-in-ath1.patch new file mode 100644 index 0000000000..6d07fda771 --- /dev/null +++ b/queue-5.15/wifi-ath10k-sdio-add-missing-lock-protection-in-ath1.patch @@ -0,0 +1,62 @@ +From e7fdfa73088e59b05401ba2296a4513880e7511e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 04:58:22 +0000 +Subject: wifi: ath10k: sdio: add missing lock protection in + ath10k_sdio_fw_crashed_dump() + +From: Ziyi Guo + +[ Upstream commit e55ac348089e579fc224569c7bd90340bf2439f9 ] + +ath10k_sdio_fw_crashed_dump() calls ath10k_coredump_new() which requires +ar->dump_mutex to be held, as indicated by lockdep_assert_held() in that +function. However, the SDIO implementation does not acquire this lock, +unlike the PCI and SNOC implementations which properly hold the mutex. + +Additionally, ar->stats.fw_crash_counter is documented as protected by +ar->data_lock in core.h, but the SDIO implementation modifies it without +holding this spinlock. + +Add the missing mutex_lock()/mutex_unlock() around the coredump +operations, and add spin_lock_bh()/spin_unlock_bh() around the +fw_crash_counter increment, following the pattern used in +ath10k_pci_fw_dump_work() and ath10k_snoc_fw_crashed_dump(). + +Fixes: 3c45f21af84e ("ath10k: sdio: add firmware coredump support") +Signed-off-by: Ziyi Guo +Reviewed-by: Baochen Qiang +Link: https://patch.msgid.link/20260123045822.2221549-1-n7l8m4@u.northwestern.edu +Signed-off-by: Jeff Johnson +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/ath/ath10k/sdio.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c +index b2e0abb5b2b53..e092702d25b34 100644 +--- a/drivers/net/wireless/ath/ath10k/sdio.c ++++ b/drivers/net/wireless/ath/ath10k/sdio.c +@@ -2486,7 +2486,11 @@ void ath10k_sdio_fw_crashed_dump(struct ath10k *ar) + if (fast_dump) + ath10k_bmi_start(ar); + ++ mutex_lock(&ar->dump_mutex); ++ ++ spin_lock_bh(&ar->data_lock); + ar->stats.fw_crash_counter++; ++ spin_unlock_bh(&ar->data_lock); + + ath10k_sdio_disable_intrs(ar); + +@@ -2504,6 +2508,8 @@ void ath10k_sdio_fw_crashed_dump(struct ath10k *ar) + + ath10k_sdio_enable_intrs(ar); + ++ mutex_unlock(&ar->dump_mutex); ++ + ath10k_core_start_recovery(ar); + } + +-- +2.51.0 + diff --git a/queue-5.15/wifi-cfg80211-stop-nan-and-p2p-in-cfg80211_leave.patch b/queue-5.15/wifi-cfg80211-stop-nan-and-p2p-in-cfg80211_leave.patch new file mode 100644 index 0000000000..b18a0e0766 --- /dev/null +++ b/queue-5.15/wifi-cfg80211-stop-nan-and-p2p-in-cfg80211_leave.patch @@ -0,0 +1,47 @@ +From 1e2159ecb1115c363cede4301548ac409f85b836 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 14:04:51 +0200 +Subject: wifi: cfg80211: stop NAN and P2P in cfg80211_leave + +From: Miri Korenblit + +[ Upstream commit e1696c8bd0056bc1a5f7766f58ac333adc203e8a ] + +Seems that there is an assumption that this function should be called +only for netdev interfaces, but it can also be called in suspend, or +from nl80211_netlink_notify (indirectly). +Note that the documentation of NL80211_ATTR_SOCKET_OWNER explicitly +says that NAN interfaces would be destroyed as well in the +nl80211_netlink_notify case. + +Fix this by also stopping P2P and NAN. + +Fixes: cb3b7d87652a ("cfg80211: add start / stop NAN commands") +Reviewed-by: Johannes Berg +Signed-off-by: Miri Korenblit +Link: https://patch.msgid.link/20260107140430.dab142cbef0b.I290cc47836d56dd7e35012ce06bec36c6da688cd@changeid +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/wireless/core.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/net/wireless/core.c b/net/wireless/core.c +index 58b91e9647c20..22e6fd12f2016 100644 +--- a/net/wireless/core.c ++++ b/net/wireless/core.c +@@ -1300,8 +1300,10 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev, + __cfg80211_leave_ocb(rdev, dev); + break; + case NL80211_IFTYPE_P2P_DEVICE: ++ cfg80211_stop_p2p_device(rdev, wdev); ++ break; + case NL80211_IFTYPE_NAN: +- /* cannot happen, has no netdev */ ++ cfg80211_stop_nan(rdev, wdev); + break; + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_MONITOR: +-- +2.51.0 + diff --git a/queue-6.1/acpica-fix-null-pointer-dereference-in-acpi_ev_addre.patch b/queue-6.1/acpica-fix-null-pointer-dereference-in-acpi_ev_addre.patch new file mode 100644 index 0000000000..9522e0106d --- /dev/null +++ b/queue-6.1/acpica-fix-null-pointer-dereference-in-acpi_ev_addre.patch @@ -0,0 +1,40 @@ +From 249a85f635f50d5bc467768dc4818ac553e0238b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 13:20:17 +0100 +Subject: ACPICA: Fix NULL pointer dereference in + acpi_ev_address_space_dispatch() + +From: Alexey Simakov + +[ Upstream commit f851e03bce968ff9b3faad1b616062e1244fd38d ] + +Cover a missed execution path with a new check. + +Fixes: 0acf24ad7e10 ("ACPICA: Add support for PCC Opregion special context data") +Link: https://github.com/acpica/acpica/commit/f421dd9dd897 +Signed-off-by: Alexey Simakov +Signed-off-by: Rafael J. Wysocki +Link: https://patch.msgid.link/3030574.e9J7NaK4W3@rafael.j.wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/acpica/evregion.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c +index b96b3a7e78e50..fd6471e764f1a 100644 +--- a/drivers/acpi/acpica/evregion.c ++++ b/drivers/acpi/acpica/evregion.c +@@ -162,7 +162,9 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, + return_ACPI_STATUS(AE_NOT_EXIST); + } + +- if (region_obj->region.space_id == ACPI_ADR_SPACE_PLATFORM_COMM) { ++ if (field_obj ++ && region_obj->region.space_id == ++ ACPI_ADR_SPACE_PLATFORM_COMM) { + struct acpi_pcc_info *ctx = + handler_desc->address_space.context; + +-- +2.51.0 + diff --git a/queue-6.1/arm-dts-allwinner-sun5i-a13-utoo-p66-delete-power-gp.patch b/queue-6.1/arm-dts-allwinner-sun5i-a13-utoo-p66-delete-power-gp.patch new file mode 100644 index 0000000000..861857ebb5 --- /dev/null +++ b/queue-6.1/arm-dts-allwinner-sun5i-a13-utoo-p66-delete-power-gp.patch @@ -0,0 +1,46 @@ +From 5c89192103f2677e31025edfc524851c57867fb1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 25 Dec 2025 18:36:14 +0800 +Subject: ARM: dts: allwinner: sun5i-a13-utoo-p66: delete "power-gpios" + property + +From: Chen-Yu Tsai + +[ Upstream commit 0b2761eb1287bd9f62367cccf6626eb3107cef6f ] + +The P66's device tree includes the reference design dtsi files, which +defines a node and properties for the touchpanel in the common design. +The P66 dts file then overrides all the properties to match its own +design, but as the touchpanel model is different, a different schema +is matched. This other schema uses a different name for the GPIO. + +The original submission added the correct GPIO property, but did not +delete the one inherited from the reference design, causing validation +errors. + +Explicitly delete the incorrect GPIO property. + +Fixes: 2a53aff27236 ("ARM: dts: sun5i: Enable touchscreen on Utoo P66") +Reviewed-by: Jernej Skrabec +Link: https://patch.msgid.link/20251225103616.3203473-4-wens@kernel.org +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Sasha Levin +--- + arch/arm/boot/dts/sun5i-a13-utoo-p66.dts | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/boot/dts/sun5i-a13-utoo-p66.dts b/arch/arm/boot/dts/sun5i-a13-utoo-p66.dts +index be486d28d04fa..428cab5a0e906 100644 +--- a/arch/arm/boot/dts/sun5i-a13-utoo-p66.dts ++++ b/arch/arm/boot/dts/sun5i-a13-utoo-p66.dts +@@ -102,6 +102,7 @@ &touchscreen { + /* The P66 uses a different EINT then the reference design */ + interrupts = <6 9 IRQ_TYPE_EDGE_FALLING>; /* EINT9 (PG9) */ + /* The icn8318 binding expects wake-gpios instead of power-gpios */ ++ /delete-property/ power-gpios; + wake-gpios = <&pio 1 3 GPIO_ACTIVE_HIGH>; /* PB3 */ + touchscreen-size-x = <800>; + touchscreen-size-y = <480>; +-- +2.51.0 + diff --git a/queue-6.1/arm-dts-lpc32xx-add-clocks-property-to-motor-control.patch b/queue-6.1/arm-dts-lpc32xx-add-clocks-property-to-motor-control.patch new file mode 100644 index 0000000000..f0e9d7b3af --- /dev/null +++ b/queue-6.1/arm-dts-lpc32xx-add-clocks-property-to-motor-control.patch @@ -0,0 +1,35 @@ +From 4048b8231006ec3b07e463be7ca85dd880029c0d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Dec 2025 00:49:07 +0200 +Subject: arm: dts: lpc32xx: add clocks property to Motor Control PWM device + tree node + +From: Vladimir Zapolskiy + +[ Upstream commit 71630e581a0e34c03757f5c1706f57c853b92555 ] + +Motor Control PWM depends on its own supply clock, the clock gate control +is present in TIMCLK_CTRL1 register. + +Fixes: b7d41c937ed7 ("ARM: LPC32xx: Add the motor PWM to base dts file") +Signed-off-by: Vladimir Zapolskiy +Signed-off-by: Sasha Levin +--- + arch/arm/boot/dts/lpc32xx.dtsi | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/boot/dts/lpc32xx.dtsi b/arch/arm/boot/dts/lpc32xx.dtsi +index 4fb5d9dae1850..0e856de14e49a 100644 +--- a/arch/arm/boot/dts/lpc32xx.dtsi ++++ b/arch/arm/boot/dts/lpc32xx.dtsi +@@ -301,6 +301,7 @@ i2c2: i2c@400a8000 { + mpwm: mpwm@400e8000 { + compatible = "nxp,lpc3220-motor-pwm"; + reg = <0x400e8000 0x78>; ++ clocks = <&clk LPC32XX_CLK_MCPWM>; + #pwm-cells = <3>; + status = "disabled"; + }; +-- +2.51.0 + diff --git a/queue-6.1/arm-dts-lpc32xx-set-motor-pwm-pwm-cells-property-val.patch b/queue-6.1/arm-dts-lpc32xx-set-motor-pwm-pwm-cells-property-val.patch new file mode 100644 index 0000000000..1fb81564ba --- /dev/null +++ b/queue-6.1/arm-dts-lpc32xx-set-motor-pwm-pwm-cells-property-val.patch @@ -0,0 +1,47 @@ +From 2ddb5d7d445d920da405559964b1b2d455782c0f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Sep 2025 21:46:42 +0300 +Subject: ARM: dts: lpc32xx: Set motor PWM #pwm-cells property value to 3 cells +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Vladimir Zapolskiy + +[ Upstream commit 65ae9ea77e1f2a20ad2866f99596df7ccdbd3b95 ] + +Since commit 4cd2f417a0ac ("dt-bindings: pwm: Convert lpc32xx-pwm.txt +to yaml format") both types of PWM controlles on NXP LPC32xx SoC +fairly gained 3 cells, reflect it in the platform dtsi file. + +The change removes a dt binding checker warning: + + mpwm@400e8000: #pwm-cells:0:0: 3 was expected + +Cc: Uwe Kleine-König +Acked-by: Uwe Kleine-König +Reviewed-by: Frank Li +Signed-off-by: Vladimir Zapolskiy +Stable-dep-of: 71630e581a0e ("arm: dts: lpc32xx: add clocks property to Motor Control PWM device tree node") +Signed-off-by: Sasha Levin +--- + arch/arm/boot/dts/lpc32xx.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/lpc32xx.dtsi b/arch/arm/boot/dts/lpc32xx.dtsi +index c87066d6c9950..4fb5d9dae1850 100644 +--- a/arch/arm/boot/dts/lpc32xx.dtsi ++++ b/arch/arm/boot/dts/lpc32xx.dtsi +@@ -301,8 +301,8 @@ i2c2: i2c@400a8000 { + mpwm: mpwm@400e8000 { + compatible = "nxp,lpc3220-motor-pwm"; + reg = <0x400e8000 0x78>; ++ #pwm-cells = <3>; + status = "disabled"; +- #pwm-cells = <2>; + }; + }; + +-- +2.51.0 + diff --git a/queue-6.1/arm-vdso-patch-out-__vdso_clock_getres-if-unavailabl.patch b/queue-6.1/arm-vdso-patch-out-__vdso_clock_getres-if-unavailabl.patch new file mode 100644 index 0000000000..d593379be0 --- /dev/null +++ b/queue-6.1/arm-vdso-patch-out-__vdso_clock_getres-if-unavailabl.patch @@ -0,0 +1,39 @@ +From 95a8da1f5ce0b62ba7eb2121015d631c7c03edf3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 23 Dec 2025 07:59:17 +0100 +Subject: ARM: VDSO: Patch out __vdso_clock_getres() if unavailable +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh + +[ Upstream commit b9fecf0dddfc55cd7d02b0011494da3c613f7cde ] + +The vDSO code hides symbols which are non-functional. +__vdso_clock_getres() was not added to this list when it got introduced. + +Fixes: 052e76a31b4a ("ARM: 8931/1: Add clock_getres entry point") +Signed-off-by: Thomas Weißschuh +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20251223-vdso-compat-time32-v1-6-97ea7a06a543@linutronix.de +Signed-off-by: Sasha Levin +--- + arch/arm/kernel/vdso.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/kernel/vdso.c b/arch/arm/kernel/vdso.c +index 3408269d19c7d..b38f4a1bc9b8a 100644 +--- a/arch/arm/kernel/vdso.c ++++ b/arch/arm/kernel/vdso.c +@@ -176,6 +176,7 @@ static void __init patch_vdso(void *ehdr) + vdso_nullpatch_one(&einfo, "__vdso_gettimeofday"); + vdso_nullpatch_one(&einfo, "__vdso_clock_gettime"); + vdso_nullpatch_one(&einfo, "__vdso_clock_gettime64"); ++ vdso_nullpatch_one(&einfo, "__vdso_clock_getres"); + } + } + +-- +2.51.0 + diff --git a/queue-6.1/arm64-dts-amlogic-axg-assign-the-mmc-signal-clocks.patch b/queue-6.1/arm64-dts-amlogic-axg-assign-the-mmc-signal-clocks.patch new file mode 100644 index 0000000000..604dbe0c7b --- /dev/null +++ b/queue-6.1/arm64-dts-amlogic-axg-assign-the-mmc-signal-clocks.patch @@ -0,0 +1,52 @@ +From 9b0754dcfbd470da85dc68240eadaeb475e076f5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:08:50 +0100 +Subject: arm64: dts: amlogic: axg: assign the MMC signal clocks + +From: Jerome Brunet + +[ Upstream commit 13d3fe2318ef6e46d6fcfe13bc373827fdf2aeac ] + +The amlogic MMC driver operate with the assumption that MMC clock +is configured to provide 24MHz. It uses this path for low +rates such as 400kHz. + +Assign the clocks to make sure they are properly configured + +Fixes: 221cf34bac54 ("ARM64: dts: meson-axg: enable the eMMC controller") +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Link: https://patch.msgid.link/20260114-amlogic-mmc-clocks-followup-v1-3-a999fafbe0aa@baylibre.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-axg.dtsi | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi +index 6cc685f91fc94..e93f68f705af5 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi +@@ -1892,6 +1892,9 @@ sd_emmc_b: sd@5000 { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_B>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_B_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + sd_emmc_c: mmc@7000 { +@@ -1904,6 +1907,9 @@ sd_emmc_c: mmc@7000 { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_C>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_C_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + usb2_phy1: phy@9020 { +-- +2.51.0 + diff --git a/queue-6.1/arm64-dts-amlogic-g12-assign-the-mmc-a-signal-clock.patch b/queue-6.1/arm64-dts-amlogic-g12-assign-the-mmc-a-signal-clock.patch new file mode 100644 index 0000000000..4b2af9260f --- /dev/null +++ b/queue-6.1/arm64-dts-amlogic-g12-assign-the-mmc-a-signal-clock.patch @@ -0,0 +1,42 @@ +From 9e4d1cde2f8b169e55166746df9cbcc32c58f12f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:08:53 +0100 +Subject: arm64: dts: amlogic: g12: assign the MMC A signal clock + +From: Jerome Brunet + +[ Upstream commit 3c941feaa363f1573a501452391ddf513394c84b ] + +The amlogic MMC driver operate with the assumption that MMC clock +is configured to provide 24MHz. It uses this path for low +rates such as 400kHz. + +Assign the clock to make sure it is properly configured + +Fixes: 8a6b3ca2d361 ("arm64: dts: meson: g12a: add SDIO controller") +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Link: https://patch.msgid.link/20260114-amlogic-mmc-clocks-followup-v1-6-a999fafbe0aa@baylibre.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +index 041f1c1ec49ec..e930c49207dad 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +@@ -2324,6 +2324,9 @@ sd_emmc_a: sd@ffe03000 { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_A>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_A_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + sd_emmc_b: sd@ffe05000 { +-- +2.51.0 + diff --git a/queue-6.1/arm64-dts-amlogic-g12-assign-the-mmc-b-and-c-signal-.patch b/queue-6.1/arm64-dts-amlogic-g12-assign-the-mmc-b-and-c-signal-.patch new file mode 100644 index 0000000000..662692f680 --- /dev/null +++ b/queue-6.1/arm64-dts-amlogic-g12-assign-the-mmc-b-and-c-signal-.patch @@ -0,0 +1,52 @@ +From 1ca3c0391aae3122b7bda73c58c914297da6a7a2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:08:52 +0100 +Subject: arm64: dts: amlogic: g12: assign the MMC B and C signal clocks + +From: Jerome Brunet + +[ Upstream commit be2ff5fdb0e83e32d4ec4e68a69875cec0d14621 ] + +The amlogic MMC driver operate with the assumption that MMC clock +is configured to provide 24MHz. It uses this path for low +rates such as 400kHz. + +Assign the clocks to make sure they are properly configured + +Fixes: 4759fd87b928 ("arm64: dts: meson: g12a: add mmc nodes") +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Link: https://patch.msgid.link/20260114-amlogic-mmc-clocks-followup-v1-5-a999fafbe0aa@baylibre.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +index 88b848c65b0d2..041f1c1ec49ec 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +@@ -2336,6 +2336,9 @@ sd_emmc_b: sd@ffe05000 { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_B>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_B_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + sd_emmc_c: mmc@ffe07000 { +@@ -2348,6 +2351,9 @@ sd_emmc_c: mmc@ffe07000 { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_C>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_C_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + usb: usb@ffe09000 { +-- +2.51.0 + diff --git a/queue-6.1/arm64-dts-amlogic-gx-assign-the-mmc-signal-clocks.patch b/queue-6.1/arm64-dts-amlogic-gx-assign-the-mmc-signal-clocks.patch new file mode 100644 index 0000000000..d0ef248d85 --- /dev/null +++ b/queue-6.1/arm64-dts-amlogic-gx-assign-the-mmc-signal-clocks.patch @@ -0,0 +1,97 @@ +From 94320aa20ad354e11c447737ae53127f5f520542 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:08:51 +0100 +Subject: arm64: dts: amlogic: gx: assign the MMC signal clocks + +From: Jerome Brunet + +[ Upstream commit 406706559046eebc09a31e8ae5e78620bfd746fe ] + +The amlogic MMC driver operate with the assumption that MMC clock +is configured to provide 24MHz. It uses this path for low +rates such as 400kHz. + +Assign the clocks to make sure they are properly configured + +Fixes: 50662499f911 ("ARM64: dts: meson-gx: Use correct mmc clock source 0") +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Link: https://patch.msgid.link/20260114-amlogic-mmc-clocks-followup-v1-4-a999fafbe0aa@baylibre.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 9 +++++++++ + arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 9 +++++++++ + 2 files changed, 18 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi +index 256c46771db78..c57a6f37bc2af 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi +@@ -779,6 +779,9 @@ &sd_emmc_a { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_A>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_A_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &sd_emmc_b { +@@ -787,6 +790,9 @@ &sd_emmc_b { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_B>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_B_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &sd_emmc_c { +@@ -795,6 +801,9 @@ &sd_emmc_c { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_C>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_C_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &simplefb_hdmi { +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi +index a689bd14ece99..fb6e8c466811f 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi +@@ -848,6 +848,9 @@ &sd_emmc_a { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_A>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_A_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &sd_emmc_b { +@@ -856,6 +859,9 @@ &sd_emmc_b { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_B>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_B_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &sd_emmc_c { +@@ -864,6 +870,9 @@ &sd_emmc_c { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_C>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_C_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &simplefb_hdmi { +-- +2.51.0 + diff --git a/queue-6.1/arm64-dts-qcom-sdm630-fix-gpu_speed_bin-size.patch b/queue-6.1/arm64-dts-qcom-sdm630-fix-gpu_speed_bin-size.patch new file mode 100644 index 0000000000..d89b158c8f --- /dev/null +++ b/queue-6.1/arm64-dts-qcom-sdm630-fix-gpu_speed_bin-size.patch @@ -0,0 +1,49 @@ +From dfa25a7911d0f73087988bd287d594b0fdc118be Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 11 Dec 2025 03:27:45 +0200 +Subject: arm64: dts: qcom: sdm630: fix gpu_speed_bin size + +From: Dmitry Baryshkov + +[ Upstream commit e814796dfcae8905682ac3ac2dd57f512a9f6726 ] + +Historically sdm630.dtsi has used 1 byte length for the gpu_speed_bin +cell, although it spans two bytes (offset 5, size 7 bits). It was being +accepted by the kernel because before the commit 7a06ef751077 ("nvmem: +core: fix bit offsets of more than one byte") the kernel didn't have +length check. After this commit nvmem core rejects QFPROM on sdm630 / +sdm660, making GPU and USB unusable on those platforms. + +Set the size of the gpu_speed_bin cell to 2 bytes, fixing the parsing +error. While we are at it, update the length to 8 bits as pointed out by +Alexey Minnekhanov. + +Fixes: b190fb010664 ("arm64: dts: qcom: sdm630: Add sdm630 dts file") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Reviewed-by: Alexey Minnekhanov +Link: https://lore.kernel.org/r/20251211-sdm630-fix-gpu-v2-1-92f0e736dba0@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm630.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/sdm630.dtsi b/arch/arm64/boot/dts/qcom/sdm630.dtsi +index 75ddebebb8fc1..5580a8722045e 100644 +--- a/arch/arm64/boot/dts/qcom/sdm630.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm630.dtsi +@@ -564,8 +564,8 @@ qusb2_hstx_trim: hstx-trim@240 { + }; + + gpu_speed_bin: gpu-speed-bin@41a0 { +- reg = <0x41a2 0x1>; +- bits = <5 7>; ++ reg = <0x41a2 0x2>; ++ bits = <5 8>; + }; + }; + +-- +2.51.0 + diff --git a/queue-6.1/arm64-dts-qcom-sdm845-db845c-drop-cs-from-spio0.patch b/queue-6.1/arm64-dts-qcom-sdm845-db845c-drop-cs-from-spio0.patch new file mode 100644 index 0000000000..3e3e997fc2 --- /dev/null +++ b/queue-6.1/arm64-dts-qcom-sdm845-db845c-drop-cs-from-spio0.patch @@ -0,0 +1,40 @@ +From e90e8230aaa3fcba7348540694d5dd70faa2f960 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Jan 2026 03:01:17 +0200 +Subject: arm64: dts: qcom: sdm845-db845c: drop CS from SPIO0 + +From: Dmitry Baryshkov + +[ Upstream commit 8bfb696ccdc5bcfad7a45b84c2c8a36757070e19 ] + +On SDM845 SPI uses hardware-provided chip select, while specifying +cs-gpio makes the driver request GPIO pin, which on DB845c conflicts +with the normal host controllers pinctrl entry. + +Drop the cs-gpios property to restore SPI functionality. + +Fixes: cb29e7106d4e ("arm64: dts: qcom: db845c: Add support for MCP2517FD") +Reviewed-by: Konrad Dybcio +Signed-off-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260106-wcn3990-pwrctl-v2-7-0386204328be@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm845-db845c.dts | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts +index 5c04c91b0ee2b..feb75ad70d570 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts ++++ b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts +@@ -809,7 +809,6 @@ &spi0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&qup_spi0_default>; +- cs-gpios = <&tlmm 3 GPIO_ACTIVE_LOW>; + + can@0 { + compatible = "microchip,mcp2517fd"; +-- +2.51.0 + diff --git a/queue-6.1/arm64-dts-qcom-sdm845-db845c-specify-power-for-wifi-.patch b/queue-6.1/arm64-dts-qcom-sdm845-db845c-specify-power-for-wifi-.patch new file mode 100644 index 0000000000..d51c01e962 --- /dev/null +++ b/queue-6.1/arm64-dts-qcom-sdm845-db845c-specify-power-for-wifi-.patch @@ -0,0 +1,50 @@ +From 2f69204b0111a2409ee93b6d7d001512ee09fc25 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Jan 2026 03:01:18 +0200 +Subject: arm64: dts: qcom: sdm845-db845c: specify power for WiFi CH1 + +From: Dmitry Baryshkov + +[ Upstream commit c303e89f7f17c29981d09f8beaaf60937ae8b1f2 ] + +Specify power supply for the second chain / antenna output of the +onboard WiFi chip. + +Fixes: 3f72e2d3e682 ("arm64: dts: qcom: Add Dragonboard 845c") +Reviewed-by: Konrad Dybcio +Signed-off-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260106-wcn3990-pwrctl-v2-8-0386204328be@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm845-db845c.dts | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts +index feb75ad70d570..5a5ecae073010 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts ++++ b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts +@@ -365,6 +365,12 @@ vreg_l21a_2p95: ldo21 { + regulator-initial-mode = ; + }; + ++ vreg_l23a_3p3: ldo23 { ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3312000>; ++ regulator-initial-mode = ; ++ }; ++ + vreg_l24a_3p075: ldo24 { + regulator-min-microvolt = <3088000>; + regulator-max-microvolt = <3088000>; +@@ -1124,6 +1130,7 @@ &wifi { + vdd-1.8-xo-supply = <&vreg_l7a_1p8>; + vdd-1.3-rfa-supply = <&vreg_l17a_1p3>; + vdd-3.3-ch0-supply = <&vreg_l25a_3p3>; ++ vdd-3.3-ch1-supply = <&vreg_l23a_3p3>; + + qcom,snoc-host-cap-8bit-quirk; + qcom,ath10k-calibration-variant = "Thundercomm_DB845C"; +-- +2.51.0 + diff --git a/queue-6.1/arm64-dts-qcom-sdm845-oneplus-don-t-keep-panel-regul.patch b/queue-6.1/arm64-dts-qcom-sdm845-oneplus-don-t-keep-panel-regul.patch new file mode 100644 index 0000000000..778708879f --- /dev/null +++ b/queue-6.1/arm64-dts-qcom-sdm845-oneplus-don-t-keep-panel-regul.patch @@ -0,0 +1,39 @@ +From 3d2504552afd15f260bcabf7bbb1b876a1869ecb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 18 Nov 2025 15:52:26 +0100 +Subject: arm64: dts: qcom: sdm845-oneplus: Don't keep panel regulator always + on + +From: Casey Connolly + +[ Upstream commit 45d1f42d3e84b5880cf9fab1eb24a7818320eeb7 ] + +The panel regulator doesn't need to be always on, so remove this +property. + +Fixes: 288ef8a42612 ("arm64: dts: sdm845: add oneplus6/6t devices") +Signed-off-by: Casey Connolly +Signed-off-by: David Heidelberg +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251118-dts-oneplus-regulators-v2-2-3e67cea1e4e7@ixit.cz +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +index 281e1178a2f46..ac3db3d5d2bad 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +@@ -230,7 +230,6 @@ vreg_l14a_1p88: ldo14 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; +- regulator-always-on; + }; + + vreg_l17a_1p3: ldo17 { +-- +2.51.0 + diff --git a/queue-6.1/arm64-dts-qcom-sdm845-oneplus-don-t-mark-ts-supply-b.patch b/queue-6.1/arm64-dts-qcom-sdm845-oneplus-don-t-mark-ts-supply-b.patch new file mode 100644 index 0000000000..aa04a28e84 --- /dev/null +++ b/queue-6.1/arm64-dts-qcom-sdm845-oneplus-don-t-mark-ts-supply-b.patch @@ -0,0 +1,39 @@ +From 29284834fb4d0d5474b650025f8a735f71979ce3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 18 Nov 2025 15:52:25 +0100 +Subject: arm64: dts: qcom: sdm845-oneplus: Don't mark ts supply boot-on + +From: Casey Connolly + +[ Upstream commit c9b98b9dad9749bf2eb7336a6fca31a6af1039d7 ] + +The touchscreen isn't enabled by bootloader and doesn't need to be +enabled at boot, only when the driver probes, thus remove the +regulator-boot-on property. + +Fixes: 288ef8a42612 ("arm64: dts: sdm845: add oneplus6/6t devices") +Signed-off-by: Casey Connolly +Signed-off-by: David Heidelberg +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251118-dts-oneplus-regulators-v2-1-3e67cea1e4e7@ixit.cz +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +index 0713b774a97be..281e1178a2f46 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +@@ -134,7 +134,6 @@ ts_1p8_supply: ts-1p8-regulator { + + gpio = <&tlmm 88 0>; + enable-active-high; +- regulator-boot-on; + }; + }; + +-- +2.51.0 + diff --git a/queue-6.1/arm64-dts-qcom-sdm845-oneplus-mark-l14a-regulator-as.patch b/queue-6.1/arm64-dts-qcom-sdm845-oneplus-mark-l14a-regulator-as.patch new file mode 100644 index 0000000000..8b16854d59 --- /dev/null +++ b/queue-6.1/arm64-dts-qcom-sdm845-oneplus-mark-l14a-regulator-as.patch @@ -0,0 +1,38 @@ +From 1328790cfbb1e902f8094167edd0de23be6b7f5c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 18 Nov 2025 15:52:27 +0100 +Subject: arm64: dts: qcom: sdm845-oneplus: Mark l14a regulator as boot-on + +From: Casey Connolly + +[ Upstream commit ad33ee060be46794a03d033894c9db3a9d6c1a0f ] + +This regulator is used only for the display, which is enabled by the +bootloader and left on for continuous splash. Mark it as such. + +Fixes: 288ef8a42612 ("arm64: dts: sdm845: add oneplus6/6t devices") +Signed-off-by: Casey Connolly +Signed-off-by: David Heidelberg +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251118-dts-oneplus-regulators-v2-3-3e67cea1e4e7@ixit.cz +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +index ac3db3d5d2bad..90bf359d0e2dd 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +@@ -230,6 +230,7 @@ vreg_l14a_1p88: ldo14 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; ++ regulator-boot-on; + }; + + vreg_l17a_1p3: ldo17 { +-- +2.51.0 + diff --git a/queue-6.1/arm64-dts-tqma8mpql-mba8mpxl-fix-hdmi-cec-pad-contro.patch b/queue-6.1/arm64-dts-tqma8mpql-mba8mpxl-fix-hdmi-cec-pad-contro.patch new file mode 100644 index 0000000000..9fd2b980ac --- /dev/null +++ b/queue-6.1/arm64-dts-tqma8mpql-mba8mpxl-fix-hdmi-cec-pad-contro.patch @@ -0,0 +1,36 @@ +From 397a9d23fbfe63dd1a38641906943d73af926c68 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 11:53:09 +0100 +Subject: arm64: dts: tqma8mpql-mba8mpxl: Fix HDMI CEC pad control settings + +From: Alexander Stein + +[ Upstream commit 8401527abb5e3a00c867b6597b8e1b29c80c9824 ] + +As per datasheet of the HDMI protection IC the CEC_IC pin has been +configured as open-drain. + +Fixes: 418d1d840e42 ("arm64: dts: freescale: add initial device tree for TQMa8MPQL with i.MX8MP") +Signed-off-by: Alexander Stein +Signed-off-by: Shawn Guo +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts +index 7bf6f81e87b47..4a75edb73dabe 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts +@@ -628,7 +628,7 @@ pinctrl_hdmi: hdmigrp { + fsl,pins = , + , + , +- ; ++ ; + }; + + pinctrl_hoggpio2: hoggpio2grp { +-- +2.51.0 + diff --git a/queue-6.1/asoc-nau8821-avoid-unnecessary-blocking-in-irq-handl.patch b/queue-6.1/asoc-nau8821-avoid-unnecessary-blocking-in-irq-handl.patch new file mode 100644 index 0000000000..e532da0a48 --- /dev/null +++ b/queue-6.1/asoc-nau8821-avoid-unnecessary-blocking-in-irq-handl.patch @@ -0,0 +1,121 @@ +From 4c8cf689307f10538ceae28f452105751ac9a116 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Oct 2025 21:03:27 +0300 +Subject: ASoC: nau8821: Avoid unnecessary blocking in IRQ handler + +From: Cristian Ciocaltea + +[ Upstream commit ee70bacef1c6050e4836409927294d744dbcfa72 ] + +The interrupt handler offloads the microphone detection logic to +nau8821_jdet_work(), which implies a sleep operation. However, before +being able to process any subsequent hotplug event, the interrupt +handler needs to wait for any prior scheduled work to complete. + +Move the sleep out of jdet_work by converting it to a delayed work. +This eliminates the undesired blocking in the interrupt handler when +attempting to cancel a recently scheduled work item and should help +reducing transient input reports that might confuse user-space. + +Signed-off-by: Cristian Ciocaltea +Link: https://patch.msgid.link/20251003-nau8821-jdet-fixes-v1-5-f7b0e2543f09@collabora.com +Signed-off-by: Mark Brown +Stable-dep-of: 70237853edf0 ("ASoC: nau8821: Fixup nau8821_enable_jack_detect()") +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/nau8821.c | 22 ++++++++++++---------- + sound/soc/codecs/nau8821.h | 2 +- + 2 files changed, 13 insertions(+), 11 deletions(-) + +diff --git a/sound/soc/codecs/nau8821.c b/sound/soc/codecs/nau8821.c +index 625b14b58c335..120dced6ed4ae 100644 +--- a/sound/soc/codecs/nau8821.c ++++ b/sound/soc/codecs/nau8821.c +@@ -985,16 +985,12 @@ static void nau8821_eject_jack(struct nau8821 *nau8821) + static void nau8821_jdet_work(struct work_struct *work) + { + struct nau8821 *nau8821 = +- container_of(work, struct nau8821, jdet_work); ++ container_of(work, struct nau8821, jdet_work.work); + struct snd_soc_dapm_context *dapm = nau8821->dapm; + struct snd_soc_component *component = snd_soc_dapm_to_component(dapm); + struct regmap *regmap = nau8821->regmap; + int jack_status_reg, mic_detected, event = 0, event_mask = 0; + +- snd_soc_component_force_enable_pin(component, "MICBIAS"); +- snd_soc_dapm_sync(dapm); +- msleep(20); +- + regmap_read(regmap, NAU8821_R58_I2C_DEVICE_ID, &jack_status_reg); + mic_detected = !(jack_status_reg & NAU8821_KEYDET); + if (mic_detected) { +@@ -1024,6 +1020,7 @@ static void nau8821_jdet_work(struct work_struct *work) + snd_soc_component_disable_pin(component, "MICBIAS"); + snd_soc_dapm_sync(dapm); + } ++ + event_mask |= SND_JACK_HEADSET; + snd_soc_jack_report(nau8821->jack, event, event_mask); + } +@@ -1072,6 +1069,7 @@ static irqreturn_t nau8821_interrupt(int irq, void *data) + { + struct nau8821 *nau8821 = (struct nau8821 *)data; + struct regmap *regmap = nau8821->regmap; ++ struct snd_soc_component *component; + int active_irq, event = 0, event_mask = 0; + + if (regmap_read(regmap, NAU8821_R10_IRQ_STATUS, &active_irq)) { +@@ -1083,7 +1081,7 @@ static irqreturn_t nau8821_interrupt(int irq, void *data) + + if ((active_irq & NAU8821_JACK_EJECT_IRQ_MASK) == + NAU8821_JACK_EJECT_DETECTED) { +- cancel_work_sync(&nau8821->jdet_work); ++ cancel_delayed_work_sync(&nau8821->jdet_work); + regmap_update_bits(regmap, NAU8821_R71_ANALOG_ADC_1, + NAU8821_MICDET_MASK, NAU8821_MICDET_DIS); + nau8821_eject_jack(nau8821); +@@ -1097,12 +1095,15 @@ static irqreturn_t nau8821_interrupt(int irq, void *data) + nau8821_irq_status_clear(regmap, NAU8821_KEY_RELEASE_IRQ); + } else if ((active_irq & NAU8821_JACK_INSERT_IRQ_MASK) == + NAU8821_JACK_INSERT_DETECTED) { +- cancel_work_sync(&nau8821->jdet_work); ++ cancel_delayed_work_sync(&nau8821->jdet_work); + regmap_update_bits(regmap, NAU8821_R71_ANALOG_ADC_1, + NAU8821_MICDET_MASK, NAU8821_MICDET_EN); + if (nau8821_is_jack_inserted(regmap)) { +- /* detect microphone and jack type */ +- schedule_work(&nau8821->jdet_work); ++ /* Detect microphone and jack type */ ++ component = snd_soc_dapm_to_component(nau8821->dapm); ++ snd_soc_component_force_enable_pin(component, "MICBIAS"); ++ snd_soc_dapm_sync(nau8821->dapm); ++ schedule_delayed_work(&nau8821->jdet_work, msecs_to_jiffies(20)); + /* Turn off insertion interruption at manual mode */ + nau8821_setup_inserted_irq(nau8821); + } else { +@@ -1539,7 +1540,8 @@ int nau8821_enable_jack_detect(struct snd_soc_component *component, + + nau8821->jack = jack; + /* Initiate jack detection work queue */ +- INIT_WORK(&nau8821->jdet_work, nau8821_jdet_work); ++ INIT_DELAYED_WORK(&nau8821->jdet_work, nau8821_jdet_work); ++ + ret = devm_request_threaded_irq(nau8821->dev, nau8821->irq, NULL, + nau8821_interrupt, IRQF_TRIGGER_LOW | IRQF_ONESHOT, + "nau8821", nau8821); +diff --git a/sound/soc/codecs/nau8821.h b/sound/soc/codecs/nau8821.h +index c44251f54d481..7590bbe6fbad0 100644 +--- a/sound/soc/codecs/nau8821.h ++++ b/sound/soc/codecs/nau8821.h +@@ -512,7 +512,7 @@ struct nau8821 { + struct regmap *regmap; + struct snd_soc_dapm_context *dapm; + struct snd_soc_jack *jack; +- struct work_struct jdet_work; ++ struct delayed_work jdet_work; + int irq; + int clk_id; + int micbias_voltage; +-- +2.51.0 + diff --git a/queue-6.1/asoc-nau8821-consistently-clear-interrupts-before-un.patch b/queue-6.1/asoc-nau8821-consistently-clear-interrupts-before-un.patch new file mode 100644 index 0000000000..3b8ea13b00 --- /dev/null +++ b/queue-6.1/asoc-nau8821-consistently-clear-interrupts-before-un.patch @@ -0,0 +1,169 @@ +From dc555e617c378128153fe9613588b42d93fd7166 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Oct 2025 21:03:25 +0300 +Subject: ASoC: nau8821: Consistently clear interrupts before unmasking + +From: Cristian Ciocaltea + +[ Upstream commit a698679fe8b0fec41d1fb9547a53127a85c1be92 ] + +The interrupt handler attempts to perform some IRQ status clear +operations *after* rather than *before* unmasking and enabling +interrupts. This is a rather fragile approach since it may generally +lead to missing IRQ requests or causing spurious interrupts. + +Make use of the nau8821_irq_status_clear() helper instead of +manipulating the related register directly and ensure any interrupt +clearing is performed *after* the target interrupts are disabled/masked +and *before* proceeding with additional interrupt unmasking/enablement +operations. + +This also implicitly drops the redundant clear operation of the ejection +IRQ in the interrupt handler, since nau8821_eject_jack() has been +already responsible for clearing all active interrupts. + +Fixes: aab1ad11d69f ("ASoC: nau8821: new driver") +Fixes: 2551b6e89936 ("ASoC: nau8821: Add headset button detection") +Signed-off-by: Cristian Ciocaltea +Link: https://patch.msgid.link/20251003-nau8821-jdet-fixes-v1-3-f7b0e2543f09@collabora.com +Signed-off-by: Mark Brown +Stable-dep-of: 70237853edf0 ("ASoC: nau8821: Fixup nau8821_enable_jack_detect()") +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/nau8821.c | 58 ++++++++++++++++++++------------------ + 1 file changed, 30 insertions(+), 28 deletions(-) + +diff --git a/sound/soc/codecs/nau8821.c b/sound/soc/codecs/nau8821.c +index 66309eede0dbd..625b14b58c335 100644 +--- a/sound/soc/codecs/nau8821.c ++++ b/sound/soc/codecs/nau8821.c +@@ -939,20 +939,24 @@ static void nau8821_eject_jack(struct nau8821 *nau8821) + snd_soc_component_disable_pin(component, "MICBIAS"); + snd_soc_dapm_sync(dapm); + ++ /* Disable & mask both insertion & ejection IRQs */ ++ regmap_update_bits(regmap, NAU8821_R12_INTERRUPT_DIS_CTRL, ++ NAU8821_IRQ_INSERT_DIS | NAU8821_IRQ_EJECT_DIS, ++ NAU8821_IRQ_INSERT_DIS | NAU8821_IRQ_EJECT_DIS); ++ regmap_update_bits(regmap, NAU8821_R0F_INTERRUPT_MASK, ++ NAU8821_IRQ_INSERT_EN | NAU8821_IRQ_EJECT_EN, ++ NAU8821_IRQ_INSERT_EN | NAU8821_IRQ_EJECT_EN); ++ + /* Clear all interruption status */ + nau8821_irq_status_clear(regmap, 0); + +- /* Enable the insertion interruption, disable the ejection inter- +- * ruption, and then bypass de-bounce circuit. +- */ ++ /* Enable & unmask the insertion IRQ */ + regmap_update_bits(regmap, NAU8821_R12_INTERRUPT_DIS_CTRL, +- NAU8821_IRQ_EJECT_DIS | NAU8821_IRQ_INSERT_DIS, +- NAU8821_IRQ_EJECT_DIS); +- /* Mask unneeded IRQs: 1 - disable, 0 - enable */ ++ NAU8821_IRQ_INSERT_DIS, 0); + regmap_update_bits(regmap, NAU8821_R0F_INTERRUPT_MASK, +- NAU8821_IRQ_EJECT_EN | NAU8821_IRQ_INSERT_EN, +- NAU8821_IRQ_EJECT_EN); ++ NAU8821_IRQ_INSERT_EN, 0); + ++ /* Bypass de-bounce circuit */ + regmap_update_bits(regmap, NAU8821_R0D_JACK_DET_CTRL, + NAU8821_JACK_DET_DB_BYPASS, NAU8821_JACK_DET_DB_BYPASS); + +@@ -976,7 +980,6 @@ static void nau8821_eject_jack(struct nau8821 *nau8821) + NAU8821_IRQ_KEY_RELEASE_DIS | + NAU8821_IRQ_KEY_PRESS_DIS); + } +- + } + + static void nau8821_jdet_work(struct work_struct *work) +@@ -1030,6 +1033,15 @@ static void nau8821_setup_inserted_irq(struct nau8821 *nau8821) + { + struct regmap *regmap = nau8821->regmap; + ++ /* Disable & mask insertion IRQ */ ++ regmap_update_bits(regmap, NAU8821_R12_INTERRUPT_DIS_CTRL, ++ NAU8821_IRQ_INSERT_DIS, NAU8821_IRQ_INSERT_DIS); ++ regmap_update_bits(regmap, NAU8821_R0F_INTERRUPT_MASK, ++ NAU8821_IRQ_INSERT_EN, NAU8821_IRQ_INSERT_EN); ++ ++ /* Clear insert IRQ status */ ++ nau8821_irq_status_clear(regmap, NAU8821_JACK_INSERT_DETECTED); ++ + /* Enable internal VCO needed for interruptions */ + if (nau8821->dapm->bias_level < SND_SOC_BIAS_PREPARE) + nau8821_configure_sysclk(nau8821, NAU8821_CLK_INTERNAL, 0); +@@ -1049,17 +1061,18 @@ static void nau8821_setup_inserted_irq(struct nau8821 *nau8821) + regmap_update_bits(regmap, NAU8821_R0D_JACK_DET_CTRL, + NAU8821_JACK_DET_DB_BYPASS, 0); + ++ /* Unmask & enable the ejection IRQs */ + regmap_update_bits(regmap, NAU8821_R0F_INTERRUPT_MASK, +- NAU8821_IRQ_EJECT_EN, 0); ++ NAU8821_IRQ_EJECT_EN, 0); + regmap_update_bits(regmap, NAU8821_R12_INTERRUPT_DIS_CTRL, +- NAU8821_IRQ_EJECT_DIS, 0); ++ NAU8821_IRQ_EJECT_DIS, 0); + } + + static irqreturn_t nau8821_interrupt(int irq, void *data) + { + struct nau8821 *nau8821 = (struct nau8821 *)data; + struct regmap *regmap = nau8821->regmap; +- int active_irq, clear_irq = 0, event = 0, event_mask = 0; ++ int active_irq, event = 0, event_mask = 0; + + if (regmap_read(regmap, NAU8821_R10_IRQ_STATUS, &active_irq)) { + dev_err(nau8821->dev, "failed to read irq status\n"); +@@ -1075,14 +1088,13 @@ static irqreturn_t nau8821_interrupt(int irq, void *data) + NAU8821_MICDET_MASK, NAU8821_MICDET_DIS); + nau8821_eject_jack(nau8821); + event_mask |= SND_JACK_HEADSET; +- clear_irq = NAU8821_JACK_EJECT_IRQ_MASK; + } else if (active_irq & NAU8821_KEY_SHORT_PRESS_IRQ) { + event |= NAU8821_BUTTON; + event_mask |= NAU8821_BUTTON; +- clear_irq = NAU8821_KEY_SHORT_PRESS_IRQ; ++ nau8821_irq_status_clear(regmap, NAU8821_KEY_SHORT_PRESS_IRQ); + } else if (active_irq & NAU8821_KEY_RELEASE_IRQ) { + event_mask = NAU8821_BUTTON; +- clear_irq = NAU8821_KEY_RELEASE_IRQ; ++ nau8821_irq_status_clear(regmap, NAU8821_KEY_RELEASE_IRQ); + } else if ((active_irq & NAU8821_JACK_INSERT_IRQ_MASK) == + NAU8821_JACK_INSERT_DETECTED) { + cancel_work_sync(&nau8821->jdet_work); +@@ -1092,27 +1104,17 @@ static irqreturn_t nau8821_interrupt(int irq, void *data) + /* detect microphone and jack type */ + schedule_work(&nau8821->jdet_work); + /* Turn off insertion interruption at manual mode */ +- regmap_update_bits(regmap, +- NAU8821_R12_INTERRUPT_DIS_CTRL, +- NAU8821_IRQ_INSERT_DIS, +- NAU8821_IRQ_INSERT_DIS); +- regmap_update_bits(regmap, +- NAU8821_R0F_INTERRUPT_MASK, +- NAU8821_IRQ_INSERT_EN, +- NAU8821_IRQ_INSERT_EN); + nau8821_setup_inserted_irq(nau8821); + } else { + dev_warn(nau8821->dev, + "Inserted IRQ fired but not connected\n"); + nau8821_eject_jack(nau8821); + } ++ } else { ++ /* Clear the rightmost interrupt */ ++ nau8821_irq_status_clear(regmap, active_irq); + } + +- if (!clear_irq) +- clear_irq = active_irq; +- /* clears the rightmost interruption */ +- regmap_write(regmap, NAU8821_R11_INT_CLR_KEY_STATUS, clear_irq); +- + if (event_mask) + snd_soc_jack_report(nau8821->jack, event, event_mask); + +-- +2.51.0 + diff --git a/queue-6.1/asoc-nau8821-fixup-nau8821_enable_jack_detect.patch b/queue-6.1/asoc-nau8821-fixup-nau8821_enable_jack_detect.patch new file mode 100644 index 0000000000..e8f36ae34a --- /dev/null +++ b/queue-6.1/asoc-nau8821-fixup-nau8821_enable_jack_detect.patch @@ -0,0 +1,84 @@ +From e521e66a0daacd4315323aa4620b7860c3dcd6e3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 31 Dec 2025 22:04:15 +0200 +Subject: ASoC: nau8821: Fixup nau8821_enable_jack_detect() + +From: Cristian Ciocaltea + +[ Upstream commit 70237853edf0a69773a7370eb74ea2a44dfe3050 ] + +The nau8821_enable_jack_detect() function was supposed to allow enabling +or disabling jack events reporting. However, once enabled, any +subsequent invocation would fail and the following splat is shown: + +[ 3136.996771] Hardware name: Valve Jupiter/Jupiter, BIOS F7A0131 01/30/2024 +[ 3136.996773] Workqueue: events_unbound deferred_probe_work_func +[ 3136.996780] Call Trace: +[ 3136.996782] +[ 3136.996787] dump_stack_lvl+0x6e/0xa0 +[ 3136.996796] __setup_irq.cold+0x9c/0xce +[ 3136.996803] ? __pfx_irq_default_primary_handler+0x10/0x10 +[ 3136.996812] ? __pfx_nau8821_interrupt+0x10/0x10 [snd_soc_nau8821] +[ 3136.996825] request_threaded_irq+0xd9/0x160 +[ 3136.996853] devm_request_threaded_irq+0x71/0xd0 +[ 3136.996859] ? __pfx_nau8821_interrupt+0x10/0x10 [snd_soc_nau8821] +[ 3136.996882] nau8821_enable_jack_detect+0xa5/0xc0 [snd_soc_nau8821] +[ 3136.996901] acp5x_8821_init+0x8d/0xa0 [snd_soc_acp5x_mach] +[ 3136.996917] snd_soc_link_init+0x25/0x50 [snd_soc_core] +[ 3136.996958] snd_soc_bind_card+0x615/0xd00 [snd_soc_core] +[ 3136.997026] snd_soc_register_card+0x1b2/0x1c0 [snd_soc_core] +[ 3136.997064] devm_snd_soc_register_card+0x47/0x90 [snd_soc_core] +[ 3136.997108] acp5x_probe+0x72/0xb0 [snd_soc_acp5x_mach] +[...] +[ 3136.997508] nau8821 i2c-NVTN2020:00: Cannot request irq 58 (-16) + +Introduce jdet_active flag to driver data structure and use it to +provide one-time initialization of the jack detection work queue and +related interrupt line. + +Note this is also a prerequisite for additional fixes around module +unloading and suspend handling. + +Fixes: aab1ad11d69f ("ASoC: nau8821: new driver") +Signed-off-by: Cristian Ciocaltea +Link: https://patch.msgid.link/20251231-nau8821-cleanup-v1-1-6b0b76cbbb64@collabora.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/nau8821.c | 5 +++++ + sound/soc/codecs/nau8821.h | 1 + + 2 files changed, 6 insertions(+) + +diff --git a/sound/soc/codecs/nau8821.c b/sound/soc/codecs/nau8821.c +index 120dced6ed4ae..f464c70011a15 100644 +--- a/sound/soc/codecs/nau8821.c ++++ b/sound/soc/codecs/nau8821.c +@@ -1539,8 +1539,13 @@ int nau8821_enable_jack_detect(struct snd_soc_component *component, + int ret; + + nau8821->jack = jack; ++ ++ if (nau8821->jdet_active) ++ return 0; ++ + /* Initiate jack detection work queue */ + INIT_DELAYED_WORK(&nau8821->jdet_work, nau8821_jdet_work); ++ nau8821->jdet_active = true; + + ret = devm_request_threaded_irq(nau8821->dev, nau8821->irq, NULL, + nau8821_interrupt, IRQF_TRIGGER_LOW | IRQF_ONESHOT, +diff --git a/sound/soc/codecs/nau8821.h b/sound/soc/codecs/nau8821.h +index 7590bbe6fbad0..2a209317fe21a 100644 +--- a/sound/soc/codecs/nau8821.h ++++ b/sound/soc/codecs/nau8821.h +@@ -513,6 +513,7 @@ struct nau8821 { + struct snd_soc_dapm_context *dapm; + struct snd_soc_jack *jack; + struct delayed_work jdet_work; ++ bool jdet_active; + int irq; + int clk_id; + int micbias_voltage; +-- +2.51.0 + diff --git a/queue-6.1/audit-avoid-missing-prototype-warnings.patch b/queue-6.1/audit-avoid-missing-prototype-warnings.patch new file mode 100644 index 0000000000..09a086e991 --- /dev/null +++ b/queue-6.1/audit-avoid-missing-prototype-warnings.patch @@ -0,0 +1,74 @@ +From 980fc7eabe85a4e352684391d430e5bd3ebb81a4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 17 May 2023 15:10:52 +0200 +Subject: audit: avoid missing-prototype warnings + +From: Arnd Bergmann + +[ Upstream commit e455ca40dbcf2cd50d1e59bf4b2752b300bcdad4 ] + +Building with 'make W=1' reveals two function definitions without +a previous prototype in the audit code: + +lib/compat_audit.c:32:5: error: no previous prototype for 'audit_classify_compat_syscall' [-Werror=missing-prototypes] +kernel/audit.c:1813:14: error: no previous prototype for 'audit_serial' [-Werror=missing-prototypes] + +The first one needs a declaration from linux/audit.h but cannot +include that header without causing conflicting (compat) syscall number +definitions, so move the it into linux/audit_arch.h. + +The second one is declared conditionally based on CONFIG_AUDITSYSCALL +but needed as a local function even when that option is disabled, so +move the declaration out of the #ifdef block. + +Signed-off-by: Arnd Bergmann +Signed-off-by: Paul Moore +Stable-dep-of: 76489955c6d4 ("audit: move the compat_xxx_class[] extern declarations to audit_arch.h") +Signed-off-by: Sasha Levin +--- + include/linux/audit.h | 2 -- + include/linux/audit_arch.h | 2 ++ + kernel/audit.h | 2 +- + 3 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/include/linux/audit.h b/include/linux/audit.h +index 3608992848d3c..6efadd7f60a55 100644 +--- a/include/linux/audit.h ++++ b/include/linux/audit.h +@@ -129,8 +129,6 @@ extern unsigned compat_dir_class[]; + extern unsigned compat_chattr_class[]; + extern unsigned compat_signal_class[]; + +-extern int audit_classify_compat_syscall(int abi, unsigned syscall); +- + /* audit_names->type values */ + #define AUDIT_TYPE_UNKNOWN 0 /* we don't know yet */ + #define AUDIT_TYPE_NORMAL 1 /* a "normal" audit record */ +diff --git a/include/linux/audit_arch.h b/include/linux/audit_arch.h +index 8fdb1afe251a1..0e34d673ef171 100644 +--- a/include/linux/audit_arch.h ++++ b/include/linux/audit_arch.h +@@ -21,4 +21,6 @@ enum auditsc_class_t { + AUDITSC_NVALS /* count */ + }; + ++extern int audit_classify_compat_syscall(int abi, unsigned syscall); ++ + #endif +diff --git a/kernel/audit.h b/kernel/audit.h +index c57b008b9914e..94738bce40b27 100644 +--- a/kernel/audit.h ++++ b/kernel/audit.h +@@ -259,8 +259,8 @@ extern struct tty_struct *audit_get_tty(void); + extern void audit_put_tty(struct tty_struct *tty); + + /* audit watch/mark/tree functions */ +-#ifdef CONFIG_AUDITSYSCALL + extern unsigned int audit_serial(void); ++#ifdef CONFIG_AUDITSYSCALL + extern int auditsc_get_stamp(struct audit_context *ctx, + struct timespec64 *t, unsigned int *serial); + +-- +2.51.0 + diff --git a/queue-6.1/audit-move-the-compat_xxx_class-extern-declarations-.patch b/queue-6.1/audit-move-the-compat_xxx_class-extern-declarations-.patch new file mode 100644 index 0000000000..ddc870e2a4 --- /dev/null +++ b/queue-6.1/audit-move-the-compat_xxx_class-extern-declarations-.patch @@ -0,0 +1,77 @@ +From 685ff99e3ddaa6c100f62a2144f4b49ab8dcc040 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 13:39:38 +0000 +Subject: audit: move the compat_xxx_class[] extern declarations to + audit_arch.h + +From: Ben Dooks + +[ Upstream commit 76489955c6d4a065ca69dc88faf7a50a59b66f35 ] + +The comapt_xxx_class symbols aren't declared in anything that +lib/comapt_audit.c is including (arm64 build) which is causing +the following sparse warnings: + +lib/compat_audit.c:7:10: warning: symbol 'compat_dir_class' + was not declared. Should it be static? +lib/compat_audit.c:12:10: warning: symbol 'compat_read_class' + was not declared. Should it be static? +lib/compat_audit.c:17:10: warning: symbol 'compat_write_class' + was not declared. Should it be static? +lib/compat_audit.c:22:10: warning: symbol 'compat_chattr_class' + was not declared. Should it be static? +lib/compat_audit.c:27:10: warning: symbol 'compat_signal_class' + was not declared. Should it be static? + +Trying to fix this by chaning compat_audit.c to inclde +does not work on arm64 due to compile errors with the extra includes +that changing this header makes. The simpler thing would be just to +move the definitons of these symbols out of into + which is included. + +Fixes: 4b58841149dca ("audit: Add generic compat syscall support") +Signed-off-by: Ben Dooks +[PM: rewrite subject line, fixed line length in description] +Signed-off-by: Paul Moore +Signed-off-by: Sasha Levin +--- + include/linux/audit.h | 6 ------ + include/linux/audit_arch.h | 7 +++++++ + 2 files changed, 7 insertions(+), 6 deletions(-) + +diff --git a/include/linux/audit.h b/include/linux/audit.h +index 6efadd7f60a55..e952868c8d2e9 100644 +--- a/include/linux/audit.h ++++ b/include/linux/audit.h +@@ -122,12 +122,6 @@ enum audit_nfcfgop { + extern int __init audit_register_class(int class, unsigned *list); + extern int audit_classify_syscall(int abi, unsigned syscall); + extern int audit_classify_arch(int arch); +-/* only for compat system calls */ +-extern unsigned compat_write_class[]; +-extern unsigned compat_read_class[]; +-extern unsigned compat_dir_class[]; +-extern unsigned compat_chattr_class[]; +-extern unsigned compat_signal_class[]; + + /* audit_names->type values */ + #define AUDIT_TYPE_UNKNOWN 0 /* we don't know yet */ +diff --git a/include/linux/audit_arch.h b/include/linux/audit_arch.h +index 0e34d673ef171..2b8153791e6a5 100644 +--- a/include/linux/audit_arch.h ++++ b/include/linux/audit_arch.h +@@ -23,4 +23,11 @@ enum auditsc_class_t { + + extern int audit_classify_compat_syscall(int abi, unsigned syscall); + ++/* only for compat system calls */ ++extern unsigned compat_write_class[]; ++extern unsigned compat_read_class[]; ++extern unsigned compat_dir_class[]; ++extern unsigned compat_chattr_class[]; ++extern unsigned compat_signal_class[]; ++ + #endif +-- +2.51.0 + diff --git a/queue-6.1/auxdisplay-arm-charlcd-fix-release_mem_region-size.patch b/queue-6.1/auxdisplay-arm-charlcd-fix-release_mem_region-size.patch new file mode 100644 index 0000000000..a7720eea07 --- /dev/null +++ b/queue-6.1/auxdisplay-arm-charlcd-fix-release_mem_region-size.patch @@ -0,0 +1,39 @@ +From 54594345f2ca547266c159b6fa466113c1495915 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Dec 2025 18:47:13 +0100 +Subject: auxdisplay: arm-charlcd: fix release_mem_region() size + +From: Thomas Fourier + +[ Upstream commit b5c23a4d291d2ac1dfdd574a68a3a68c8da3069e ] + +It seems like, after the request_mem_region(), the corresponding +release_mem_region() must take the same size. This was done +in (now removed due to previous refactoring) charlcd_remove() +but not in the error path in charlcd_probe(). + +Fixes: ce8962455e90 ("ARM: 6214/2: driver for the character LCD found in ARM refdesigns") +Signed-off-by: Thomas Fourier +Reviewed-by: Geert Uytterhoeven +Signed-off-by: Andy Shevchenko +Signed-off-by: Sasha Levin +--- + drivers/auxdisplay/arm-charlcd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/auxdisplay/arm-charlcd.c b/drivers/auxdisplay/arm-charlcd.c +index 0b1c99cca7334..f418b133ee752 100644 +--- a/drivers/auxdisplay/arm-charlcd.c ++++ b/drivers/auxdisplay/arm-charlcd.c +@@ -323,7 +323,7 @@ static int __init charlcd_probe(struct platform_device *pdev) + out_no_irq: + iounmap(lcd->virtbase); + out_no_memregion: +- release_mem_region(lcd->phybase, SZ_4K); ++ release_mem_region(lcd->phybase, lcd->physize); + out_no_resource: + kfree(lcd); + return ret; +-- +2.51.0 + diff --git a/queue-6.1/backlight-qcom-wled-support-ovp-values-for-pmi8994.patch b/queue-6.1/backlight-qcom-wled-support-ovp-values-for-pmi8994.patch new file mode 100644 index 0000000000..2b30f83dd1 --- /dev/null +++ b/queue-6.1/backlight-qcom-wled-support-ovp-values-for-pmi8994.patch @@ -0,0 +1,94 @@ +From cd32b95aa29c7bc8f376be36b194ff2a5fec29b0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 08:07:34 +0100 +Subject: backlight: qcom-wled: Support ovp values for PMI8994 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Czémán + +[ Upstream commit f29f972a6e7e3f187ea4d89b98a76c1981ca4d53 ] + +WLED4 found in PMI8994 supports different ovp values. + +Fixes: 6fc632d3e3e0 ("video: backlight: qcom-wled: Add PMI8994 compatible") +Signed-off-by: Barnabás Czémán +Reviewed-by: Konrad Dybcio +Reviewed-by: Daniel Thompson (RISCstar) +Link: https://patch.msgid.link/20260116-pmi8950-wled-v3-2-e6c93de84079@mainlining.org +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/video/backlight/qcom-wled.c | 41 +++++++++++++++++++++++++++-- + 1 file changed, 39 insertions(+), 2 deletions(-) + +diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c +index 434c6c499fdef..8dfb853c7ab7a 100644 +--- a/drivers/video/backlight/qcom-wled.c ++++ b/drivers/video/backlight/qcom-wled.c +@@ -1244,6 +1244,15 @@ static const struct wled_var_cfg wled4_ovp_cfg = { + .size = ARRAY_SIZE(wled4_ovp_values), + }; + ++static const u32 pmi8994_wled_ovp_values[] = { ++ 31000, 29500, 19400, 17800, ++}; ++ ++static const struct wled_var_cfg pmi8994_wled_ovp_cfg = { ++ .values = pmi8994_wled_ovp_values, ++ .size = ARRAY_SIZE(pmi8994_wled_ovp_values), ++}; ++ + static inline u32 wled5_ovp_values_fn(u32 idx) + { + /* +@@ -1357,6 +1366,29 @@ static int wled_configure(struct wled *wled) + }, + }; + ++ const struct wled_u32_opts pmi8994_wled_opts[] = { ++ { ++ .name = "qcom,current-boost-limit", ++ .val_ptr = &cfg->boost_i_limit, ++ .cfg = &wled4_boost_i_limit_cfg, ++ }, ++ { ++ .name = "qcom,current-limit-microamp", ++ .val_ptr = &cfg->string_i_limit, ++ .cfg = &wled4_string_i_limit_cfg, ++ }, ++ { ++ .name = "qcom,ovp-millivolt", ++ .val_ptr = &cfg->ovp, ++ .cfg = &pmi8994_wled_ovp_cfg, ++ }, ++ { ++ .name = "qcom,switching-freq", ++ .val_ptr = &cfg->switch_freq, ++ .cfg = &wled3_switch_freq_cfg, ++ }, ++ }; ++ + const struct wled_u32_opts wled5_opts[] = { + { + .name = "qcom,current-boost-limit", +@@ -1423,8 +1455,13 @@ static int wled_configure(struct wled *wled) + break; + + case 4: +- u32_opts = wled4_opts; +- size = ARRAY_SIZE(wled4_opts); ++ if (of_device_is_compatible(dev->of_node, "qcom,pmi8994-wled")) { ++ u32_opts = pmi8994_wled_opts; ++ size = ARRAY_SIZE(pmi8994_wled_opts); ++ } else { ++ u32_opts = wled4_opts; ++ size = ARRAY_SIZE(wled4_opts); ++ } + *cfg = wled4_config_defaults; + wled->wled_set_brightness = wled4_set_brightness; + wled->wled_sync_toggle = wled3_sync_toggle; +-- +2.51.0 + diff --git a/queue-6.1/bonding-only-set-speed-duplex-to-unknown-if-getting-.patch b/queue-6.1/bonding-only-set-speed-duplex-to-unknown-if-getting-.patch new file mode 100644 index 0000000000..fd4e71cdd7 --- /dev/null +++ b/queue-6.1/bonding-only-set-speed-duplex-to-unknown-if-getting-.patch @@ -0,0 +1,74 @@ +From bf3a728d72d717f29c97d9d776055c4b598a0d7d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 15:11:52 +0100 +Subject: bonding: only set speed/duplex to unknown, if getting speed failed + +From: Thomas Bogendoerfer + +[ Upstream commit 48dec8d88af96039a4a17b8c2f148f2a4066e195 ] + +bond_update_speed_duplex() first set speed/duplex to unknown and +then asks slave driver for current speed/duplex. Since getting +speed/duplex might take longer there is a race, where this false state +is visible by /proc/net/bonding. With commit 691b2bf14946 ("bonding: + update port speed when getting bond speed") this race gets more visible, +if user space is calling ethtool on a regular base. + +Fix this by only setting speed/duplex to unknown, if link speed is +really unknown/unusable. + +Fixes: 98f41f694f46 ("bonding:update speed/duplex for NETDEV_CHANGE") +Signed-off-by: Thomas Bogendoerfer +Acked-by: Jay Vosburgh +Reviewed-by: Nikolay Aleksandrov +Reviewed-by: Hangbin Liu +Link: https://patch.msgid.link/20260203141153.51581-1-tbogendoerfer@suse.de +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/bonding/bond_main.c | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c +index 71912ddfa7149..113a5504c9ebb 100644 +--- a/drivers/net/bonding/bond_main.c ++++ b/drivers/net/bonding/bond_main.c +@@ -712,26 +712,29 @@ static int bond_update_speed_duplex(struct slave *slave) + struct ethtool_link_ksettings ecmd; + int res; + +- slave->speed = SPEED_UNKNOWN; +- slave->duplex = DUPLEX_UNKNOWN; +- + res = __ethtool_get_link_ksettings(slave_dev, &ecmd); + if (res < 0) +- return 1; ++ goto speed_duplex_unknown; + if (ecmd.base.speed == 0 || ecmd.base.speed == ((__u32)-1)) +- return 1; ++ goto speed_duplex_unknown; + switch (ecmd.base.duplex) { + case DUPLEX_FULL: + case DUPLEX_HALF: + break; + default: +- return 1; ++ goto speed_duplex_unknown; + } + + slave->speed = ecmd.base.speed; + slave->duplex = ecmd.base.duplex; + + return 0; ++ ++speed_duplex_unknown: ++ slave->speed = SPEED_UNKNOWN; ++ slave->duplex = DUPLEX_UNKNOWN; ++ ++ return 1; + } + + const char *bond_slave_link_status(s8 link) +-- +2.51.0 + diff --git a/queue-6.1/bpf-fix-bpf_xdp_store_bytes-proto-for-read-only-arg.patch b/queue-6.1/bpf-fix-bpf_xdp_store_bytes-proto-for-read-only-arg.patch new file mode 100644 index 0000000000..2621b1bae2 --- /dev/null +++ b/queue-6.1/bpf-fix-bpf_xdp_store_bytes-proto-for-read-only-arg.patch @@ -0,0 +1,60 @@ +From 09871c5a4130b25ed995ac84905444bfccbb3051 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Jan 2026 17:08:37 +0100 +Subject: bpf: Fix bpf_xdp_store_bytes proto for read-only arg + +From: Paul Chaignon + +[ Upstream commit 6557f1565d779851c4db9c488c49c05a47a6e72f ] + +While making some maps in Cilium read-only from the BPF side, we noticed +that the bpf_xdp_store_bytes proto is incorrect. In particular, the +verifier was throwing the following error: + + ; ret = ctx_store_bytes(ctx, l3_off + offsetof(struct iphdr, saddr), + &nat->address, 4, 0); + 635: (79) r1 = *(u64 *)(r10 -144) ; R1=ctx() R10=fp0 fp-144=ctx() + 636: (b4) w2 = 26 ; R2=26 + 637: (b4) w4 = 4 ; R4=4 + 638: (b4) w5 = 0 ; R5=0 + 639: (85) call bpf_xdp_store_bytes#190 + write into map forbidden, value_size=6 off=0 size=4 + +nat comes from a BPF_F_RDONLY_PROG map, so R3 is a PTR_TO_MAP_VALUE. +The verifier checks the helper's memory access to R3 in +check_mem_size_reg, as it reaches ARG_CONST_SIZE argument. The third +argument has expected type ARG_PTR_TO_UNINIT_MEM, which includes the +MEM_WRITE flag. The verifier thus checks for a BPF_WRITE access on R3. +Given R3 points to a read-only map, the check fails. + +Conversely, ARG_PTR_TO_UNINIT_MEM can also lead to the helper reading +from uninitialized memory. + +This patch simply fixes the expected argument type to match that of +bpf_skb_store_bytes. + +Fixes: 3f364222d032 ("net: xdp: introduce bpf_xdp_pointer utility routine") +Signed-off-by: Paul Chaignon +Link: https://lore.kernel.org/r/9fa3c9f72d806e82541071c4df88b8cba28ad6a9.1769875479.git.paul.chaignon@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + net/core/filter.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/core/filter.c b/net/core/filter.c +index e19bf63ad9a44..c177e40e70770 100644 +--- a/net/core/filter.c ++++ b/net/core/filter.c +@@ -4069,7 +4069,7 @@ static const struct bpf_func_proto bpf_xdp_store_bytes_proto = { + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_CTX, + .arg2_type = ARG_ANYTHING, +- .arg3_type = ARG_PTR_TO_UNINIT_MEM, ++ .arg3_type = ARG_PTR_TO_MEM | MEM_RDONLY, + .arg4_type = ARG_CONST_SIZE, + }; + +-- +2.51.0 + diff --git a/queue-6.1/bpf-sockmap-fix-incorrect-copied_seq-calculation.patch b/queue-6.1/bpf-sockmap-fix-incorrect-copied_seq-calculation.patch new file mode 100644 index 0000000000..a2161ea558 --- /dev/null +++ b/queue-6.1/bpf-sockmap-fix-incorrect-copied_seq-calculation.patch @@ -0,0 +1,178 @@ +From 5a97b33036d83d663e6b0ec044011ee7ace433ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 24 Jan 2026 19:32:43 +0800 +Subject: bpf, sockmap: Fix incorrect copied_seq calculation + +From: Jiayuan Chen + +[ Upstream commit b40cc5adaa80e1471095a62d78233b611d7a558c ] + +A socket using sockmap has its own independent receive queue: ingress_msg. +This queue may contain data from its own protocol stack or from other +sockets. + +The issue is that when reading from ingress_msg, we update tp->copied_seq +by default. However, if the data is not from its own protocol stack, +tcp->rcv_nxt is not increased. Later, if we convert this socket to a +native socket, reading from this socket may fail because copied_seq might +be significantly larger than rcv_nxt. + +This fix also addresses the syzkaller-reported bug referenced in the +Closes tag. + +This patch marks the skmsg objects in ingress_msg. When reading, we update +copied_seq only if the data is from its own protocol stack. + + FD1:read() + -- FD1->copied_seq++ + | [read data] + | + [enqueue data] v + [sockmap] -> ingress to self -> ingress_msg queue +FD1 native stack ------> ^ +-- FD1->rcv_nxt++ -> redirect to other | [enqueue data] + | | + | ingress to FD1 + v ^ + ... | [sockmap] + FD2 native stack + +Closes: https://syzkaller.appspot.com/bug?extid=06dbd397158ec0ea4983 +Fixes: 04919bed948dc ("tcp: Introduce tcp_read_skb()") +Reviewed-by: Jakub Sitnicki +Reviewed-by: John Fastabend +Signed-off-by: Jiayuan Chen +Link: https://lore.kernel.org/r/20260124113314.113584-2-jiayuan.chen@linux.dev +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + include/linux/skmsg.h | 2 ++ + net/core/skmsg.c | 27 ++++++++++++++++++++++++--- + net/ipv4/tcp_bpf.c | 5 +++-- + 3 files changed, 29 insertions(+), 5 deletions(-) + +diff --git a/include/linux/skmsg.h b/include/linux/skmsg.h +index 32bbebf5b71e3..5c5a2d65184c3 100644 +--- a/include/linux/skmsg.h ++++ b/include/linux/skmsg.h +@@ -132,6 +132,8 @@ int sk_msg_memcopy_from_iter(struct sock *sk, struct iov_iter *from, + struct sk_msg *msg, u32 bytes); + int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, + int len, int flags); ++int __sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, ++ int len, int flags, int *copied_from_self); + bool sk_msg_is_readable(struct sock *sk); + + static inline void sk_msg_check_to_free(struct sk_msg *msg, u32 i, u32 bytes) +diff --git a/net/core/skmsg.c b/net/core/skmsg.c +index 01ca497fe2cd6..444b9b25ade28 100644 +--- a/net/core/skmsg.c ++++ b/net/core/skmsg.c +@@ -407,22 +407,26 @@ int sk_msg_memcopy_from_iter(struct sock *sk, struct iov_iter *from, + } + EXPORT_SYMBOL_GPL(sk_msg_memcopy_from_iter); + +-/* Receive sk_msg from psock->ingress_msg to @msg. */ +-int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, +- int len, int flags) ++int __sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, ++ int len, int flags, int *copied_from_self) + { + struct iov_iter *iter = &msg->msg_iter; + int peek = flags & MSG_PEEK; + struct sk_msg *msg_rx; + int i, copied = 0; ++ bool from_self; + + msg_rx = sk_psock_peek_msg(psock); ++ if (copied_from_self) ++ *copied_from_self = 0; ++ + while (copied != len) { + struct scatterlist *sge; + + if (unlikely(!msg_rx)) + break; + ++ from_self = msg_rx->sk == sk; + i = msg_rx->sg.start; + do { + struct page *page; +@@ -441,6 +445,9 @@ int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, + } + + copied += copy; ++ if (from_self && copied_from_self) ++ *copied_from_self += copy; ++ + if (likely(!peek)) { + sge->offset += copy; + sge->length -= copy; +@@ -485,6 +492,13 @@ int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, + out: + return copied; + } ++ ++/* Receive sk_msg from psock->ingress_msg to @msg. */ ++int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, ++ int len, int flags) ++{ ++ return __sk_msg_recvmsg(sk, psock, msg, len, flags, NULL); ++} + EXPORT_SYMBOL_GPL(sk_msg_recvmsg); + + bool sk_msg_is_readable(struct sock *sk) +@@ -614,6 +628,12 @@ static int sk_psock_skb_ingress_self(struct sk_psock *psock, struct sk_buff *skb + if (unlikely(!msg)) + return -EAGAIN; + skb_set_owner_r(skb, sk); ++ ++ /* This is used in tcp_bpf_recvmsg_parser() to determine whether the ++ * data originates from the socket's own protocol stack. No need to ++ * refcount sk because msg's lifetime is bound to sk via the ingress_msg. ++ */ ++ msg->sk = sk; + err = sk_psock_skb_ingress_enqueue(skb, off, len, psock, sk, msg, take_ref); + if (err < 0) + kfree(msg); +@@ -907,6 +927,7 @@ int sk_psock_msg_verdict(struct sock *sk, struct sk_psock *psock, + sk_msg_compute_data_pointers(msg); + msg->sk = sk; + ret = bpf_prog_run_pin_on_cpu(prog, msg); ++ msg->sk = NULL; + ret = sk_psock_map_verd(ret, msg->sk_redir); + psock->apply_bytes = msg->apply_bytes; + if (ret == __SK_REDIRECT) { +diff --git a/net/ipv4/tcp_bpf.c b/net/ipv4/tcp_bpf.c +index 1727ac094e106..8e6c0737bfe12 100644 +--- a/net/ipv4/tcp_bpf.c ++++ b/net/ipv4/tcp_bpf.c +@@ -221,6 +221,7 @@ static int tcp_bpf_recvmsg_parser(struct sock *sk, + int peek = flags & MSG_PEEK; + struct sk_psock *psock; + struct tcp_sock *tcp; ++ int copied_from_self = 0; + int copied = 0; + u32 seq; + +@@ -257,7 +258,7 @@ static int tcp_bpf_recvmsg_parser(struct sock *sk, + } + + msg_bytes_ready: +- copied = sk_msg_recvmsg(sk, psock, msg, len, flags); ++ copied = __sk_msg_recvmsg(sk, psock, msg, len, flags, &copied_from_self); + /* The typical case for EFAULT is the socket was gracefully + * shutdown with a FIN pkt. So check here the other case is + * some error on copy_page_to_iter which would be unexpected. +@@ -272,7 +273,7 @@ static int tcp_bpf_recvmsg_parser(struct sock *sk, + goto out; + } + } +- seq += copied; ++ seq += copied_from_self; + if (!copied) { + long timeo; + int data; +-- +2.51.0 + diff --git a/queue-6.1/btrfs-fix-block_group_tree-dirty_list-corruption.patch b/queue-6.1/btrfs-fix-block_group_tree-dirty_list-corruption.patch new file mode 100644 index 0000000000..36c5b08b70 --- /dev/null +++ b/queue-6.1/btrfs-fix-block_group_tree-dirty_list-corruption.patch @@ -0,0 +1,150 @@ +From d7070afdd93b9366207c1879e43ce60edf7ca423 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 22 Dec 2025 16:15:44 -0800 +Subject: btrfs: fix block_group_tree dirty_list corruption + +From: Boris Burkov + +[ Upstream commit 3a1f4264daed4b419c325a7fe35e756cada3cf82 ] + +When the incompat flag EXTENT_TREE_V2 is set, we unconditionally add the +block group tree to the switch_commits list before calling +switch_commit_roots, as we do for the tree root and the chunk root. +However, the block group tree uses normal root dirty tracking and in any +transaction that does an allocation and dirties a block group, the block +group root will already be linked to a list by the dirty_list field and +this use of list_add_tail() is invalid and corrupts the prev/next +members of block_group_root->dirty_list. + +This is apparent on a subsequent list_del on the prev if we enable +CONFIG_DEBUG_LIST: + + [32.1571] ------------[ cut here ]------------ + [32.1572] list_del corruption. next->prev should beffff958890202538, but was ffff9588992bd538. (next=ffff958890201538) + [32.1575] WARNING: lib/list_debug.c:65 at 0x0, CPU#3: sync/607 + [32.1583] CPU: 3 UID: 0 PID: 607 Comm: sync Not tainted 6.18.0 #24PREEMPT(none) + [32.1585] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS1.17.0-4.fc41 04/01/2014 + [32.1587] RIP: 0010:__list_del_entry_valid_or_report+0x108/0x120 + [32.1593] RSP: 0018:ffffaa288287fdd0 EFLAGS: 00010202 + [32.1594] RAX: 0000000000000001 RBX: ffff95889326e800 RCX:ffff958890201538 + [32.1596] RDX: ffff9588992bd538 RSI: ffff958890202538 RDI:ffffffff82a41e00 + [32.1597] RBP: ffff958890202538 R08: ffffffff828fc1e8 R09:00000000ffffefff + [32.1599] R10: ffffffff8288c200 R11: ffffffff828e4200 R12:ffff958890201538 + [32.1601] R13: ffff95889326e958 R14: ffff958895c24000 R15:ffff958890202538 + [32.1603] FS: 00007f0c28eb5740(0000) GS:ffff958af2bd2000(0000)knlGS:0000000000000000 + [32.1605] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + [32.1607] CR2: 00007f0c28e8a3cc CR3: 0000000109942005 CR4:0000000000370ef0 + [32.1609] Call Trace: + [32.1610] + [32.1611] switch_commit_roots+0x82/0x1d0 [btrfs] + [32.1615] btrfs_commit_transaction+0x968/0x1550 [btrfs] + [32.1618] ? btrfs_attach_transaction_barrier+0x23/0x60 [btrfs] + [32.1621] __iterate_supers+0xe8/0x190 + [32.1622] ? __pfx_sync_fs_one_sb+0x10/0x10 + [32.1623] ksys_sync+0x63/0xb0 + [32.1624] __do_sys_sync+0xe/0x20 + [32.1625] do_syscall_64+0x73/0x450 + [32.1626] entry_SYSCALL_64_after_hwframe+0x76/0x7e + [32.1627] RIP: 0033:0x7f0c28d05d2b + [32.1632] RSP: 002b:00007ffc9d988048 EFLAGS: 00000246 ORIG_RAX:00000000000000a2 + [32.1634] RAX: ffffffffffffffda RBX: 00007ffc9d988228 RCX:00007f0c28d05d2b + [32.1636] RDX: 00007f0c28e02301 RSI: 00007ffc9d989b21 RDI:00007f0c28dba90d + [32.1637] RBP: 0000000000000001 R08: 0000000000000001 R09:0000000000000000 + [32.1639] R10: 0000000000000000 R11: 0000000000000246 R12:000055b96572cb80 + [32.1641] R13: 000055b96572b19f R14: 00007f0c28dfa434 R15:000055b96572b034 + [32.1643] + [32.1644] irq event stamp: 0 + [32.1644] hardirqs last enabled at (0): [<0000000000000000>] 0x0 + [32.1646] hardirqs last disabled at (0): []copy_process+0xb37/0x2260 + [32.1648] softirqs last enabled at (0): []copy_process+0xb37/0x2260 + [32.1650] softirqs last disabled at (0): [<0000000000000000>] 0x0 + [32.1652] ---[ end trace 0000000000000000 ]--- + +Furthermore, this list corruption eventually (when we happen to add a +new block group) results in getting the switch_commits and +dirty_cowonly_roots lists mixed up and attempting to call update_root +on the tree root which can't be found in the tree root, resulting in a +transaction abort: + + [87.8269] BTRFS critical (device nvme1n1): unable to find root key (1 0 0) in tree 1 + [87.8272] ------------[ cut here ]------------ + [87.8274] BTRFS: Transaction aborted (error -117) + [87.8275] WARNING: fs/btrfs/root-tree.c:153 at 0x0, CPU#4: sync/703 + [87.8285] CPU: 4 UID: 0 PID: 703 Comm: sync Not tainted 6.18.0 #25 PREEMPT(none) + [87.8287] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.17.0-4.fc41 04/01/2014 + [87.8289] RIP: 0010:btrfs_update_root+0x296/0x790 [btrfs] + [87.8295] RSP: 0018:ffffa58d035dfd60 EFLAGS: 00010282 + [87.8297] RAX: ffff9a59126ddb68 RBX: ffff9a59126dc000 RCX: 0000000000000000 + [87.8299] RDX: 0000000000000000 RSI: 00000000ffffff8b RDI: ffffffffc0b28270 + [87.8301] RBP: ffff9a5904aec000 R08: 0000000000000000 R09: 00000000ffffefff + [87.8303] R10: ffffffff9ac8c200 R11: ffffffff9ace4200 R12: 0000000000000001 + [87.8305] R13: ffff9a59041740e8 R14: ffff9a5904aec1f7 R15: ffff9a590fdefaf0 + [87.8307] FS: 00007f54cde6b740(0000) GS:ffff9a5b5a81c000(0000) knlGS:0000000000000000 + [87.8309] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + [87.8310] CR2: 00007f54cde403cc CR3: 0000000112902004 CR4: 0000000000370ef0 + [87.8312] Call Trace: + [87.8313] + [87.8314] ? _raw_spin_unlock+0x23/0x40 + [87.8315] commit_cowonly_roots+0x1ad/0x250 [btrfs] + [87.8317] ? btrfs_commit_transaction+0x79b/0x1560 [btrfs] + [87.8320] btrfs_commit_transaction+0x8aa/0x1560 [btrfs] + [87.8322] ? btrfs_attach_transaction_barrier+0x23/0x60 [btrfs] + [87.8325] __iterate_supers+0xf1/0x170 + [87.8326] ? __pfx_sync_fs_one_sb+0x10/0x10 + [87.8327] ksys_sync+0x63/0xb0 + [87.8328] __do_sys_sync+0xe/0x20 + [87.8329] do_syscall_64+0x73/0x450 + [87.8330] entry_SYSCALL_64_after_hwframe+0x76/0x7e + [87.8331] RIP: 0033:0x7f54cdd05d2b + [87.8336] RSP: 002b:00007fff1b58ff78 EFLAGS: 00000246 ORIG_RAX: 00000000000000a2 + [87.8338] RAX: ffffffffffffffda RBX: 00007fff1b590158 RCX: 00007f54cdd05d2b + [87.8340] RDX: 00007f54cde02301 RSI: 00007fff1b592b66 RDI: 00007f54cddba90d + [87.8342] RBP: 0000000000000001 R08: 0000000000000001 R09: 0000000000000000 + [87.8344] R10: 0000000000000000 R11: 0000000000000246 R12: 000055e07ca96b80 + [87.8346] R13: 000055e07ca9519f R14: 00007f54cddfa434 R15: 000055e07ca95034 + [87.8348] + [87.8348] irq event stamp: 0 + [87.8349] hardirqs last enabled at (0): [<0000000000000000>] 0x0 + [87.8351] hardirqs last disabled at (0): [] copy_process+0xb37/0x21e0 + [87.8353] softirqs last enabled at (0): [] copy_process+0xb37/0x21e0 + [87.8355] softirqs last disabled at (0): [<0000000000000000>] 0x0 + [87.8357] ---[ end trace 0000000000000000 ]--- + [87.8358] BTRFS: error (device nvme1n1 state A) in btrfs_update_root:153: errno=-117 Filesystem corrupted + [87.8360] BTRFS info (device nvme1n1 state EA): forced readonly + [87.8362] BTRFS warning (device nvme1n1 state EA): Skipping commit of aborted transaction. + [87.8364] BTRFS: error (device nvme1n1 state EA) in cleanup_transaction:2037: errno=-117 Filesystem corrupted + +Since the block group tree was pulled out of the extent tree and uses +normal root dirty tracking, remove the offending extra list_add. This +fixes the list corruption and the resulting fs corruption. + +Fixes: 14033b08a029 ("btrfs: don't save block group root into super block") +Reviewed-by: Filipe Manana +Signed-off-by: Boris Burkov +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/transaction.c | 7 ------- + 1 file changed, 7 deletions(-) + +diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c +index b22b8e68672c1..6d1113dc2abf2 100644 +--- a/fs/btrfs/transaction.c ++++ b/fs/btrfs/transaction.c +@@ -2450,13 +2450,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans) + list_add_tail(&fs_info->chunk_root->dirty_list, + &cur_trans->switch_commits); + +- if (btrfs_fs_incompat(fs_info, EXTENT_TREE_V2)) { +- btrfs_set_root_node(&fs_info->block_group_root->root_item, +- fs_info->block_group_root->node); +- list_add_tail(&fs_info->block_group_root->dirty_list, +- &cur_trans->switch_commits); +- } +- + switch_commit_roots(trans); + + ASSERT(list_empty(&cur_trans->dirty_bgs)); +-- +2.51.0 + diff --git a/queue-6.1/btrfs-qgroup-return-correct-error-when-deleting-qgro.patch b/queue-6.1/btrfs-qgroup-return-correct-error-when-deleting-qgro.patch new file mode 100644 index 0000000000..20021e6d1d --- /dev/null +++ b/queue-6.1/btrfs-qgroup-return-correct-error-when-deleting-qgro.patch @@ -0,0 +1,43 @@ +From 2b544a6b5c67004381a2cb14cf0df7993c7c6fd5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 19:35:23 +0000 +Subject: btrfs: qgroup: return correct error when deleting qgroup relation + item + +From: Filipe Manana + +[ Upstream commit 51b1fcf71c88c3c89e7dcf07869c5de837b1f428 ] + +If we fail to delete the second qgroup relation item, we end up returning +success or -ENOENT in case the first item does not exist, instead of +returning the error from the second item deletion. + +Fixes: 73798c465b66 ("btrfs: qgroup: Try our best to delete qgroup relations") +Reviewed-by: Johannes Thumshirn +Signed-off-by: Filipe Manana +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/qgroup.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c +index c95902bf6144d..b175d0a4b3826 100644 +--- a/fs/btrfs/qgroup.c ++++ b/fs/btrfs/qgroup.c +@@ -1575,8 +1575,10 @@ static int __del_qgroup_relation(struct btrfs_trans_handle *trans, u64 src, + if (ret < 0 && ret != -ENOENT) + goto out; + ret2 = del_qgroup_relation_item(trans, dst, src); +- if (ret2 < 0 && ret2 != -ENOENT) ++ if (ret2 < 0 && ret2 != -ENOENT) { ++ ret = ret2; + goto out; ++ } + + /* At least one deletion succeeded, return 0 */ + if (!ret || !ret2) +-- +2.51.0 + diff --git a/queue-6.1/clk-mediatek-fix-error-handling-in-runtime-pm-setup.patch b/queue-6.1/clk-mediatek-fix-error-handling-in-runtime-pm-setup.patch new file mode 100644 index 0000000000..0fbcdecf1c --- /dev/null +++ b/queue-6.1/clk-mediatek-fix-error-handling-in-runtime-pm-setup.patch @@ -0,0 +1,66 @@ +From 6a5d2f3578633c2f5565875e0b6a4dd51429b287 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 23 Nov 2025 23:43:15 +0800 +Subject: clk: mediatek: Fix error handling in runtime PM setup + +From: Haotian Zhang + +[ Upstream commit aa2ad19210a6a444111bce55e8b69579f29318fb ] + +devm_pm_runtime_enable() can fail due to memory allocation. The current +code ignores its return value, and when pm_runtime_resume_and_get() fails, +it returns directly without unmapping the shared_io region. + +Add error handling for devm_pm_runtime_enable(). Reorder cleanup labels +to properly unmap shared_io on pm_runtime_resume_and_get() failure. + +Fixes: 2f7b1d8b5505 ("clk: mediatek: Do a runtime PM get on controllers during probe") +Signed-off-by: Haotian Zhang +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + drivers/clk/mediatek/clk-mtk.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c +index c2ca3d7576c22..589f425a2daf2 100644 +--- a/drivers/clk/mediatek/clk-mtk.c ++++ b/drivers/clk/mediatek/clk-mtk.c +@@ -489,14 +489,16 @@ int mtk_clk_simple_probe(struct platform_device *pdev) + + + if (mcd->need_runtime_pm) { +- devm_pm_runtime_enable(&pdev->dev); ++ r = devm_pm_runtime_enable(&pdev->dev); ++ if (r) ++ goto unmap_io; + /* + * Do a pm_runtime_resume_and_get() to workaround a possible + * deadlock between clk_register() and the genpd framework. + */ + r = pm_runtime_resume_and_get(&pdev->dev); + if (r) +- return r; ++ goto unmap_io; + } + + /* Calculate how many clk_hw_onecell_data entries to allocate */ +@@ -597,11 +599,11 @@ int mtk_clk_simple_probe(struct platform_device *pdev) + free_data: + mtk_free_clk_data(clk_data); + free_base: +- if (mcd->shared_io && base) +- iounmap(base); +- + if (mcd->need_runtime_pm) + pm_runtime_put(&pdev->dev); ++unmap_io: ++ if (mcd->shared_io && base) ++ iounmap(base); + return r; + } + EXPORT_SYMBOL_GPL(mtk_clk_simple_probe); +-- +2.51.0 + diff --git a/queue-6.1/clk-meson-gxbb-limit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch b/queue-6.1/clk-meson-gxbb-limit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch new file mode 100644 index 0000000000..37ab769fd2 --- /dev/null +++ b/queue-6.1/clk-meson-gxbb-limit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch @@ -0,0 +1,87 @@ +From 5d6493dc9b0736c0ee7d625a60197393a6ad240e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Jan 2026 21:47:08 +0100 +Subject: clk: meson: gxbb: Limit the HDMI PLL OD to /4 on GXL/GXM SoCs + +From: Martin Blumenstingl + +[ Upstream commit 5b1a43950fd3162af0ce52b13c14a2d29b179d4f ] + +GXBB has the HDMI PLL OD in the HHI_HDMI_PLL_CNTL2 register while for +GXL/GXM the OD has moved to HHI_HDMI_PLL_CNTL3. At first glance the rest +of the OD setup seems identical. + +However, looking at the downstream kernel sources as well as testing +shows that GXL only supports three OD values: +- register value 0 means: divide by 1 +- register value 1 means: divide by 2 +- register value 2 means: divide by 4 + +Using register value 3 (which on GXBB means: divide by 8) still divides +by 4 as verified using meson-clk-measure. Downstream sources are also +only using OD register values 0, 1 and 2 for GXL (while for GXBB the +downstream kernel sources are also using value 3). + +Add clk_div_table and have it replace the CLK_DIVIDER_POWER_OF_TWO flag +to make the kernel's view of this register match with how the hardware +actually works. + +Fixes: 69d92293274b ("clk: meson: add the gxl hdmi pll") +Signed-off-by: Martin Blumenstingl +Link: https://lore.kernel.org/r/20260105204710.447779-2-martin.blumenstingl@googlemail.com +Signed-off-by: Jerome Brunet +Signed-off-by: Sasha Levin +--- + drivers/clk/meson/gxbb.c | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c +index 35bc13e73c0dd..6f3918f0a7826 100644 +--- a/drivers/clk/meson/gxbb.c ++++ b/drivers/clk/meson/gxbb.c +@@ -316,12 +316,23 @@ static struct clk_regmap gxbb_hdmi_pll = { + }, + }; + ++/* ++ * GXL hdmi OD dividers are POWER_OF_TWO dividers but limited to /4. ++ * A divider value of 3 should map to /8 but instead map /4 so ignore it. ++ */ ++static const struct clk_div_table gxl_hdmi_pll_od_div_table[] = { ++ { .val = 0, .div = 1 }, ++ { .val = 1, .div = 2 }, ++ { .val = 2, .div = 4 }, ++ { /* sentinel */ } ++}; ++ + static struct clk_regmap gxl_hdmi_pll_od = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL + 8, + .shift = 21, + .width = 2, +- .flags = CLK_DIVIDER_POWER_OF_TWO, ++ .table = gxl_hdmi_pll_od_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od", +@@ -339,7 +350,7 @@ static struct clk_regmap gxl_hdmi_pll_od2 = { + .offset = HHI_HDMI_PLL_CNTL + 8, + .shift = 23, + .width = 2, +- .flags = CLK_DIVIDER_POWER_OF_TWO, ++ .table = gxl_hdmi_pll_od_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od2", +@@ -357,7 +368,7 @@ static struct clk_regmap gxl_hdmi_pll = { + .offset = HHI_HDMI_PLL_CNTL + 8, + .shift = 19, + .width = 2, +- .flags = CLK_DIVIDER_POWER_OF_TWO, ++ .table = gxl_hdmi_pll_od_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll", +-- +2.51.0 + diff --git a/queue-6.1/clk-move-clk_-save-restore-_context-to-common_clk-se.patch b/queue-6.1/clk-move-clk_-save-restore-_context-to-common_clk-se.patch new file mode 100644 index 0000000000..d3b881ba20 --- /dev/null +++ b/queue-6.1/clk-move-clk_-save-restore-_context-to-common_clk-se.patch @@ -0,0 +1,117 @@ +From 151f844d3796db42b87c660cc09753357fdc5283 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Dec 2025 10:42:26 +0100 +Subject: clk: Move clk_{save,restore}_context() to COMMON_CLK section + +From: Geert Uytterhoeven + +[ Upstream commit f47c1b77d0a2a9c0d49ec14302e74f933398d1a3 ] + +The clk_save_context() and clk_restore_context() helpers are only +implemented by the Common Clock Framework. They are not available when +using legacy clock frameworks. Dummy implementations are provided, but +only if no clock support is available at all. + +Hence when CONFIG_HAVE_CLK=y, but CONFIG_COMMON_CLK is not enabled: + + m68k-linux-gnu-ld: drivers/net/phy/air_en8811h.o: in function `en8811h_resume': + air_en8811h.c:(.text+0x83e): undefined reference to `clk_restore_context' + m68k-linux-gnu-ld: drivers/net/phy/air_en8811h.o: in function `en8811h_suspend': + air_en8811h.c:(.text+0x856): undefined reference to `clk_save_context' + +Fix this by moving forward declarations and dummy implementions from the +HAVE_CLK to the COMMON_CLK section. + +Fixes: 8b95d1ce3300c411 ("clk: Add functions to save/restore clock context en-masse") +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202511301553.eaEz1nEW-lkp@intel.com/ +Signed-off-by: Geert Uytterhoeven +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + include/linux/clk.h | 48 ++++++++++++++++++++++----------------------- + 1 file changed, 24 insertions(+), 24 deletions(-) + +diff --git a/include/linux/clk.h b/include/linux/clk.h +index 06f1b292f8a00..862ef29ee5f0e 100644 +--- a/include/linux/clk.h ++++ b/include/linux/clk.h +@@ -216,6 +216,23 @@ int clk_rate_exclusive_get(struct clk *clk); + */ + void clk_rate_exclusive_put(struct clk *clk); + ++/** ++ * clk_save_context - save clock context for poweroff ++ * ++ * Saves the context of the clock register for powerstates in which the ++ * contents of the registers will be lost. Occurs deep within the suspend ++ * code so locking is not necessary. ++ */ ++int clk_save_context(void); ++ ++/** ++ * clk_restore_context - restore clock context after poweroff ++ * ++ * This occurs with all clocks enabled. Occurs deep within the resume code ++ * so locking is not necessary. ++ */ ++void clk_restore_context(void); ++ + #else + + static inline int clk_notifier_register(struct clk *clk, +@@ -276,6 +293,13 @@ static inline int clk_rate_exclusive_get(struct clk *clk) + + static inline void clk_rate_exclusive_put(struct clk *clk) {} + ++static inline int clk_save_context(void) ++{ ++ return 0; ++} ++ ++static inline void clk_restore_context(void) {} ++ + #endif + + #ifdef CONFIG_HAVE_CLK_PREPARE +@@ -872,23 +896,6 @@ struct clk *clk_get_parent(struct clk *clk); + */ + struct clk *clk_get_sys(const char *dev_id, const char *con_id); + +-/** +- * clk_save_context - save clock context for poweroff +- * +- * Saves the context of the clock register for powerstates in which the +- * contents of the registers will be lost. Occurs deep within the suspend +- * code so locking is not necessary. +- */ +-int clk_save_context(void); +- +-/** +- * clk_restore_context - restore clock context after poweroff +- * +- * This occurs with all clocks enabled. Occurs deep within the resume code +- * so locking is not necessary. +- */ +-void clk_restore_context(void); +- + #else /* !CONFIG_HAVE_CLK */ + + static inline struct clk *clk_get(struct device *dev, const char *id) +@@ -1055,13 +1062,6 @@ static inline struct clk *clk_get_sys(const char *dev_id, const char *con_id) + return NULL; + } + +-static inline int clk_save_context(void) +-{ +- return 0; +-} +- +-static inline void clk_restore_context(void) {} +- + #endif + + /* clk_prepare_enable helps cases using clk_enable in non-atomic context. */ +-- +2.51.0 + diff --git a/queue-6.1/clk-qcom-dispcc-sdm845-enable-parents-for-pixel-cloc.patch b/queue-6.1/clk-qcom-dispcc-sdm845-enable-parents-for-pixel-cloc.patch new file mode 100644 index 0000000000..c60ef820bc --- /dev/null +++ b/queue-6.1/clk-qcom-dispcc-sdm845-enable-parents-for-pixel-cloc.patch @@ -0,0 +1,49 @@ +From de3552b3dab890c9ab0dcf2991f267341475462c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 12:44:43 +0100 +Subject: clk: qcom: dispcc-sdm845: Enable parents for pixel clocks + +From: Petr Hodina + +[ Upstream commit a1d63493634e98360140027fef49d82b1ff0a267 ] + +Add CLK_OPS_PARENT_ENABLE to MDSS pixel clock sources to ensure parent +clocks are enabled during clock operations, preventing potential +stability issues during display configuration. + +Fixes: 81351776c9fb ("clk: qcom: Add display clock controller driver for SDM845") +Signed-off-by: Petr Hodina +Reviewed-by: Dmitry Baryshkov +Reviewed-by: David Heidelberg +Link: https://lore.kernel.org/r/20260107-stability-discussion-v2-1-ef7717b435ff@protonmail.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sdm845.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/dispcc-sdm845.c b/drivers/clk/qcom/dispcc-sdm845.c +index e792e0b130d33..eae6dcff18da5 100644 +--- a/drivers/clk/qcom/dispcc-sdm845.c ++++ b/drivers/clk/qcom/dispcc-sdm845.c +@@ -280,7 +280,7 @@ static struct clk_rcg2 disp_cc_mdss_pclk0_clk_src = { + .name = "disp_cc_mdss_pclk0_clk_src", + .parent_data = disp_cc_parent_data_4, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_4), +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .ops = &clk_pixel_ops, + }, + }; +@@ -295,7 +295,7 @@ static struct clk_rcg2 disp_cc_mdss_pclk1_clk_src = { + .name = "disp_cc_mdss_pclk1_clk_src", + .parent_data = disp_cc_parent_data_4, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_4), +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .ops = &clk_pixel_ops, + }, + }; +-- +2.51.0 + diff --git a/queue-6.1/clk-qcom-gcc-msm8953-remove-always_on-flag-from-cpp_.patch b/queue-6.1/clk-qcom-gcc-msm8953-remove-always_on-flag-from-cpp_.patch new file mode 100644 index 0000000000..f3918ea304 --- /dev/null +++ b/queue-6.1/clk-qcom-gcc-msm8953-remove-always_on-flag-from-cpp_.patch @@ -0,0 +1,39 @@ +From 0caf5d33d7338d895f88c14cf82013bc13fafce5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 17 Nov 2025 18:58:47 +0100 +Subject: clk: qcom: gcc-msm8953: Remove ALWAYS_ON flag from cpp_gdsc +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Czémán + +[ Upstream commit 5f613e7034187179a9d088ff5fd02b1089d0cf20 ] + +cpp_gdsc should not be always on, ALWAYS_ON flag was set accidentally. + +Fixes: 9bb6cfc3c77e ("clk: qcom: Add Global Clock Controller driver for MSM8953") +Signed-off-by: Barnabás Czémán +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251117-fix-gdsc-cpp-msm8917-msm8953-v1-1-db33adcff28a@mainlining.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-msm8953.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/clk/qcom/gcc-msm8953.c b/drivers/clk/qcom/gcc-msm8953.c +index 3b32830f7466a..954076ff74a39 100644 +--- a/drivers/clk/qcom/gcc-msm8953.c ++++ b/drivers/clk/qcom/gcc-msm8953.c +@@ -3947,7 +3947,6 @@ static struct gdsc cpp_gdsc = { + .pd = { + .name = "cpp_gdsc", + }, +- .flags = ALWAYS_ON, + .pwrsts = PWRSTS_OFF_ON, + }; + +-- +2.51.0 + diff --git a/queue-6.1/clk-qcom-gfx3d-add-parent-to-parent-request-map.patch b/queue-6.1/clk-qcom-gfx3d-add-parent-to-parent-request-map.patch new file mode 100644 index 0000000000..78241cba82 --- /dev/null +++ b/queue-6.1/clk-qcom-gfx3d-add-parent-to-parent-request-map.patch @@ -0,0 +1,67 @@ +From c16da545ae3f5b784fd3180377c99394acdba4f5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 17 Jan 2026 05:54:47 +0200 +Subject: clk: qcom: gfx3d: add parent to parent request map + +From: Dmitry Baryshkov + +[ Upstream commit 2583cb925ca1ce450aa5d74a05a67448db970193 ] + +After commit d228ece36345 ("clk: divider: remove round_rate() in favor +of determine_rate()") determining GFX3D clock rate crashes, because the +passed parent map doesn't provide the expected best_parent_hw clock +(with the roundd_rate path before the offending commit the +best_parent_hw was ignored). + +Set the field in parent_req in addition to setting it in the req, +fixing the crash. + + clk_hw_round_rate (drivers/clk/clk.c:1764) (P) + clk_divider_bestdiv (drivers/clk/clk-divider.c:336) + divider_determine_rate (drivers/clk/clk-divider.c:358) + clk_alpha_pll_postdiv_determine_rate (drivers/clk/qcom/clk-alpha-pll.c:1275) + clk_core_determine_round_nolock (drivers/clk/clk.c:1606) + clk_core_round_rate_nolock (drivers/clk/clk.c:1701) + __clk_determine_rate (drivers/clk/clk.c:1741) + clk_gfx3d_determine_rate (drivers/clk/qcom/clk-rcg2.c:1268) + clk_core_determine_round_nolock (drivers/clk/clk.c:1606) + clk_core_round_rate_nolock (drivers/clk/clk.c:1701) + clk_core_round_rate_nolock (drivers/clk/clk.c:1710) + clk_round_rate (drivers/clk/clk.c:1804) + dev_pm_opp_set_rate (drivers/opp/core.c:1440 (discriminator 1)) + msm_devfreq_target (drivers/gpu/drm/msm/msm_gpu_devfreq.c:51) + devfreq_set_target (drivers/devfreq/devfreq.c:360) + devfreq_update_target (drivers/devfreq/devfreq.c:426) + devfreq_monitor (drivers/devfreq/devfreq.c:458) + process_one_work (arch/arm64/include/asm/jump_label.h:36 include/trace/events/workqueue.h:110 kernel/workqueue.c:3284) + worker_thread (kernel/workqueue.c:3356 (discriminator 2) kernel/workqueue.c:3443 (discriminator 2)) + kthread (kernel/kthread.c:467) + ret_from_fork (arch/arm64/kernel/entry.S:861) + +Fixes: 55213e1acec9 ("clk: qcom: Add gfx3d ping-pong PLL frequency switching") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Abel Vesa +Reviewed-by: Konrad Dybcio +Reviewed-by: Brian Masney +Link: https://lore.kernel.org/r/20260117-db820-fix-gfx3d-v1-1-0f8894d71d63@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/clk-rcg2.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c +index 0e26f4f0bdbae..3dc9356b711d5 100644 +--- a/drivers/clk/qcom/clk-rcg2.c ++++ b/drivers/clk/qcom/clk-rcg2.c +@@ -916,6 +916,7 @@ static int clk_gfx3d_determine_rate(struct clk_hw *hw, + if (req->max_rate < parent_req.max_rate) + parent_req.max_rate = req->max_rate; + ++ parent_req.best_parent_hw = req->best_parent_hw; + ret = __clk_determine_rate(req->best_parent_hw, &parent_req); + if (ret) + return ret; +-- +2.51.0 + diff --git a/queue-6.1/clk-qcom-rcg2-compute-2d-using-duty-fraction-directl.patch b/queue-6.1/clk-qcom-rcg2-compute-2d-using-duty-fraction-directl.patch new file mode 100644 index 0000000000..66ea2914d0 --- /dev/null +++ b/queue-6.1/clk-qcom-rcg2-compute-2d-using-duty-fraction-directl.patch @@ -0,0 +1,71 @@ +From 83b89aa09555c556531f10c1b7abde69ca94d629 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Jan 2026 16:09:50 +0530 +Subject: clk: qcom: rcg2: compute 2d using duty fraction directly +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Taniya Das + +[ Upstream commit d6205a1878dd4cc9664c4b4829b68a29c0426efc ] + +The duty-cycle calculation in clk_rcg2_set_duty_cycle() currently +derives an intermediate percentage `duty_per = (num * 100) / den` and +then computes: + + d = DIV_ROUND_CLOSEST(n * duty_per * 2, 100); + +This introduces integer truncation at the percentage step (division by +`den`) and a redundant scaling by 100, which can reduce precision for +large `den` and skew the final rounding. + +Compute `2d` directly from the duty fraction to preserve precision and +avoid the unnecessary scaling: + + d = DIV_ROUND_CLOSEST(n * duty->num * 2, duty->den); + +This keeps the intended formula `d ≈ n * 2 * (num/den)` while performing +a single, final rounded division, improving accuracy especially for small +duty cycles or large denominators. It also removes the unused `duty_per` +variable, simplifying the code. + +There is no functional changes beyond improved numerical accuracy. + +Fixes: 7f891faf596ed ("clk: qcom: clk-rcg2: Add support for duty-cycle for RCG") +Signed-off-by: Taniya Das +Link: https://lore.kernel.org/r/20260105-duty_cycle_precision-v2-1-d1d466a6330a@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/clk-rcg2.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c +index e46bb60dcda41..0e26f4f0bdbae 100644 +--- a/drivers/clk/qcom/clk-rcg2.c ++++ b/drivers/clk/qcom/clk-rcg2.c +@@ -432,7 +432,7 @@ static int clk_rcg2_get_duty_cycle(struct clk_hw *hw, struct clk_duty *duty) + static int clk_rcg2_set_duty_cycle(struct clk_hw *hw, struct clk_duty *duty) + { + struct clk_rcg2 *rcg = to_clk_rcg2(hw); +- u32 notn_m, n, m, d, not2d, mask, duty_per, cfg; ++ u32 notn_m, n, m, d, not2d, mask, cfg; + int ret; + + /* Duty-cycle cannot be modified for non-MND RCGs */ +@@ -451,10 +451,8 @@ static int clk_rcg2_set_duty_cycle(struct clk_hw *hw, struct clk_duty *duty) + + n = (~(notn_m) + m) & mask; + +- duty_per = (duty->num * 100) / duty->den; +- + /* Calculate 2d value */ +- d = DIV_ROUND_CLOSEST(n * duty_per * 2, 100); ++ d = DIV_ROUND_CLOSEST(n * duty->num * 2, duty->den); + + /* + * Check bit widths of 2d. If D is too big reduce duty cycle. +-- +2.51.0 + diff --git a/queue-6.1/clk-qcom-return-correct-error-code-in-qcom_cc_probe_.patch b/queue-6.1/clk-qcom-return-correct-error-code-in-qcom_cc_probe_.patch new file mode 100644 index 0000000000..7011703261 --- /dev/null +++ b/queue-6.1/clk-qcom-return-correct-error-code-in-qcom_cc_probe_.patch @@ -0,0 +1,42 @@ +From 9464ce7ed7e22120dc1d03eb42c905f8878e4424 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 17 Dec 2025 12:13:38 +0800 +Subject: clk: qcom: Return correct error code in qcom_cc_probe_by_index() + +From: Haotian Zhang + +[ Upstream commit 1e07ebe744fb522983bd52a4a6148601675330c7 ] + +When devm_platform_ioremap_resource() fails, it returns various +error codes. Returning a hardcoded -ENOMEM masks the actual +failure reason. + +Use PTR_ERR() to propagate the actual error code returned by +devm_platform_ioremap_resource() instead of -ENOMEM. + +Fixes: 75e0a1e30191 ("clk: qcom: define probe by index API as common API") +Signed-off-by: Haotian Zhang +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251217041338.2432-1-vulab@iscas.ac.cn +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/common.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c +index 75f09e6e057e1..86a5283381ae7 100644 +--- a/drivers/clk/qcom/common.c ++++ b/drivers/clk/qcom/common.c +@@ -327,7 +327,7 @@ int qcom_cc_probe_by_index(struct platform_device *pdev, int index, + + base = devm_platform_ioremap_resource(pdev, index); + if (IS_ERR(base)) +- return -ENOMEM; ++ return PTR_ERR(base); + + regmap = devm_regmap_init_mmio(&pdev->dev, base, desc->config); + if (IS_ERR(regmap)) +-- +2.51.0 + diff --git a/queue-6.1/coresight-etm3x-fix-cpulocked-warning-on-cpuhp.patch b/queue-6.1/coresight-etm3x-fix-cpulocked-warning-on-cpuhp.patch new file mode 100644 index 0000000000..98c9e43a74 --- /dev/null +++ b/queue-6.1/coresight-etm3x-fix-cpulocked-warning-on-cpuhp.patch @@ -0,0 +1,67 @@ +From 3ac4df24a1fdd1e004d793ac52c6f7bb2d2dc949 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:24:27 +0100 +Subject: coresight: etm3x: Fix cpulocked warning on cpuhp + +From: Antonio Borneo + +[ Upstream commit 1feb0377b9b816f89a04fc381eb19fc6bac9f4a4 ] + +When changes [1] and [2] have been applied to the driver etm4x, the +same modifications have been also collapsed in [3] and applied in +one shot to the driver etm3x. +While doing this, the driver etm3x has not been aligned to etm4x on +the use of non cpuslocked version of cpuhp callback setup APIs. + +The current code triggers two run-time warnings when the kernel is +compiled with CONFIG_PROVE_LOCKING=y. + +Use non cpuslocked version of cpuhp callback setup APIs in driver +etm3x, aligning it to the driver etm4x. + +[1] commit 2d1a8bfb61ec ("coresight: etm4x: Fix etm4_count race by + moving cpuhp callbacks to init") +[2] commit 22a550a306ad ("coresight: etm4x: Allow etm4x to be built + as a module") +[3] commit 97fe626ce64c ("coresight: etm3x: Allow etm3x to be built + as a module") + +Fixes: 97fe626ce64c ("coresight: etm3x: Allow etm3x to be built as a module") +Signed-off-by: Antonio Borneo +Signed-off-by: Suzuki K Poulose +Link: https://lore.kernel.org/r/20260108152427.357379-1-antonio.borneo@foss.st.com +Signed-off-by: Sasha Levin +--- + drivers/hwtracing/coresight/coresight-etm3x-core.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c +index d0ab9933472bc..c0a5fdbbb6595 100644 +--- a/drivers/hwtracing/coresight/coresight-etm3x-core.c ++++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c +@@ -790,16 +790,16 @@ static int __init etm_hp_setup(void) + { + int ret; + +- ret = cpuhp_setup_state_nocalls_cpuslocked(CPUHP_AP_ARM_CORESIGHT_STARTING, +- "arm/coresight:starting", +- etm_starting_cpu, etm_dying_cpu); ++ ret = cpuhp_setup_state_nocalls(CPUHP_AP_ARM_CORESIGHT_STARTING, ++ "arm/coresight:starting", ++ etm_starting_cpu, etm_dying_cpu); + + if (ret) + return ret; + +- ret = cpuhp_setup_state_nocalls_cpuslocked(CPUHP_AP_ONLINE_DYN, +- "arm/coresight:online", +- etm_online_cpu, NULL); ++ ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, ++ "arm/coresight:online", ++ etm_online_cpu, NULL); + + /* HP dyn state ID returned in ret on success */ + if (ret > 0) { +-- +2.51.0 + diff --git a/queue-6.1/cpufreq-scmi-correct-scmi-explanation.patch b/queue-6.1/cpufreq-scmi-correct-scmi-explanation.patch new file mode 100644 index 0000000000..9fccc99056 --- /dev/null +++ b/queue-6.1/cpufreq-scmi-correct-scmi-explanation.patch @@ -0,0 +1,37 @@ +From a6b2f0bb7ed6b4dbf5e9525a562228121f9a8fa2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Jan 2026 22:33:30 +0300 +Subject: cpufreq: scmi: correct SCMI explanation + +From: Sergey Shtylyov + +[ Upstream commit 8c376f337a7e31c42949247e24eaad9a30d6c62c ] + +SCMI stands for System Control and Management Interface, not System Control +and Power Interface -- apparently, Sudeep Holla copied this line from his +SCPI driver and then just forgot to update the acronym explanation... :-) + +Fixes: 99d6bdf33877 ("cpufreq: add support for CPU DVFS based on SCMI message protocol") +Signed-off-by: Sergey Shtylyov +Reviewed-by: Sudeep Holla +Signed-off-by: Viresh Kumar +Signed-off-by: Sasha Levin +--- + drivers/cpufreq/scmi-cpufreq.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c +index 68325ebd56fe3..39d0ef66dd42f 100644 +--- a/drivers/cpufreq/scmi-cpufreq.c ++++ b/drivers/cpufreq/scmi-cpufreq.c +@@ -1,6 +1,6 @@ + // SPDX-License-Identifier: GPL-2.0 + /* +- * System Control and Power Interface (SCMI) based CPUFreq Interface driver ++ * System Control and Management Interface (SCMI) based CPUFreq Interface driver + * + * Copyright (C) 2018-2021 ARM Ltd. + * Sudeep Holla +-- +2.51.0 + diff --git a/queue-6.1/crypto-cavium-fix-dma_free_coherent-size.patch b/queue-6.1/crypto-cavium-fix-dma_free_coherent-size.patch new file mode 100644 index 0000000000..93ba27558c --- /dev/null +++ b/queue-6.1/crypto-cavium-fix-dma_free_coherent-size.patch @@ -0,0 +1,38 @@ +From 0f165203d1a90e706875fc854f209e25932191a1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 10:56:45 +0100 +Subject: crypto: cavium - fix dma_free_coherent() size + +From: Thomas Fourier + +[ Upstream commit 941676c30ba5b40a01bed92448f457ce62fd1f07 ] + +The size of the buffer in alloc_command_queues() is +curr->size + CPT_NEXT_CHUNK_PTR_SIZE, so used that length for +dma_free_coherent(). + +Fixes: c694b233295b ("crypto: cavium - Add the Virtual Function driver for CPT") +Signed-off-by: Thomas Fourier +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/cavium/cpt/cptvf_main.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/crypto/cavium/cpt/cptvf_main.c b/drivers/crypto/cavium/cpt/cptvf_main.c +index c246920e6f540..bccd680c7f7ee 100644 +--- a/drivers/crypto/cavium/cpt/cptvf_main.c ++++ b/drivers/crypto/cavium/cpt/cptvf_main.c +@@ -180,7 +180,8 @@ static void free_command_queues(struct cpt_vf *cptvf, + + hlist_for_each_entry_safe(chunk, node, &cqinfo->queue[i].chead, + nextchunk) { +- dma_free_coherent(&pdev->dev, chunk->size, ++ dma_free_coherent(&pdev->dev, ++ chunk->size + CPT_NEXT_CHUNK_PTR_SIZE, + chunk->head, + chunk->dma_addr); + chunk->head = NULL; +-- +2.51.0 + diff --git a/queue-6.1/crypto-ccp-add-an-s4-restore-flow.patch b/queue-6.1/crypto-ccp-add-an-s4-restore-flow.patch new file mode 100644 index 0000000000..234d1b8214 --- /dev/null +++ b/queue-6.1/crypto-ccp-add-an-s4-restore-flow.patch @@ -0,0 +1,168 @@ +From 9093c9577410f6036c8e85dd3d63ceba5108062f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 22:11:30 -0600 +Subject: crypto: ccp - Add an S4 restore flow +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Mario Limonciello (AMD) + +[ Upstream commit 0ba2035026d0ab6c7c7e65ad8b418dc73d5700d9 ] + +The system will have lost power during S4. The ring used for TEE +communications needs to be initialized before use. + +Fixes: f892a21f51162 ("crypto: ccp - use generic power management") +Reported-by: Lars Francke +Closes: https://lore.kernel.org/platform-driver-x86/CAD-Ua_gfJnQSo8ucS_7ZwzuhoBRJ14zXP7s8b-zX3ZcxcyWePw@mail.gmail.com/ +Tested-by: Yijun Shen +Signed-off-by: Mario Limonciello (AMD) +Reviewed-by: Shyam Sundar S K +Reviewed-by: Tom Lendacky +Link: https://patch.msgid.link/20260116041132.153674-4-superm1@kernel.org +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/crypto/ccp/psp-dev.c | 11 +++++++++++ + drivers/crypto/ccp/sp-dev.c | 12 ++++++++++++ + drivers/crypto/ccp/sp-dev.h | 3 +++ + drivers/crypto/ccp/sp-pci.c | 16 +++++++++++++++- + drivers/crypto/ccp/tee-dev.c | 5 +++++ + drivers/crypto/ccp/tee-dev.h | 1 + + 6 files changed, 47 insertions(+), 1 deletion(-) + +diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c +index 949a3fa0b94a9..4bdf99f9a1094 100644 +--- a/drivers/crypto/ccp/psp-dev.c ++++ b/drivers/crypto/ccp/psp-dev.c +@@ -238,6 +238,17 @@ struct psp_device *psp_get_master_device(void) + return sp ? sp->psp_data : NULL; + } + ++int psp_restore(struct sp_device *sp) ++{ ++ struct psp_device *psp = sp->psp_data; ++ int ret = 0; ++ ++ if (psp->tee_data) ++ ret = tee_restore(psp); ++ ++ return ret; ++} ++ + void psp_pci_init(void) + { + psp_master = psp_get_master_device(); +diff --git a/drivers/crypto/ccp/sp-dev.c b/drivers/crypto/ccp/sp-dev.c +index 7eb3e46682860..ccbe009ad6e58 100644 +--- a/drivers/crypto/ccp/sp-dev.c ++++ b/drivers/crypto/ccp/sp-dev.c +@@ -229,6 +229,18 @@ int sp_resume(struct sp_device *sp) + return 0; + } + ++int sp_restore(struct sp_device *sp) ++{ ++ if (sp->psp_data) { ++ int ret = psp_restore(sp); ++ ++ if (ret) ++ return ret; ++ } ++ ++ return sp_resume(sp); ++} ++ + struct sp_device *sp_get_psp_master_device(void) + { + struct sp_device *i, *ret = NULL; +diff --git a/drivers/crypto/ccp/sp-dev.h b/drivers/crypto/ccp/sp-dev.h +index 20377e67f65df..731e34a65b640 100644 +--- a/drivers/crypto/ccp/sp-dev.h ++++ b/drivers/crypto/ccp/sp-dev.h +@@ -121,6 +121,7 @@ struct sp_device *sp_get_master(void); + + int sp_suspend(struct sp_device *sp); + int sp_resume(struct sp_device *sp); ++int sp_restore(struct sp_device *sp); + int sp_request_ccp_irq(struct sp_device *sp, irq_handler_t handler, + const char *name, void *data); + void sp_free_ccp_irq(struct sp_device *sp, void *data); +@@ -154,6 +155,7 @@ int psp_dev_init(struct sp_device *sp); + void psp_pci_init(void); + void psp_dev_destroy(struct sp_device *sp); + void psp_pci_exit(void); ++int psp_restore(struct sp_device *sp); + + #else /* !CONFIG_CRYPTO_DEV_SP_PSP */ + +@@ -161,6 +163,7 @@ static inline int psp_dev_init(struct sp_device *sp) { return 0; } + static inline void psp_pci_init(void) { } + static inline void psp_dev_destroy(struct sp_device *sp) { } + static inline void psp_pci_exit(void) { } ++static inline int psp_restore(struct sp_device *sp) { return 0; } + + #endif /* CONFIG_CRYPTO_DEV_SP_PSP */ + +diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c +index 32c0b27446540..d3636c2212fe3 100644 +--- a/drivers/crypto/ccp/sp-pci.c ++++ b/drivers/crypto/ccp/sp-pci.c +@@ -343,6 +343,13 @@ static int __maybe_unused sp_pci_resume(struct device *dev) + return sp_resume(sp); + } + ++static int __maybe_unused sp_pci_restore(struct device *dev) ++{ ++ struct sp_device *sp = dev_get_drvdata(dev); ++ ++ return sp_restore(sp); ++} ++ + #ifdef CONFIG_CRYPTO_DEV_SP_PSP + static const struct sev_vdata sevv1 = { + .cmdresp_reg = 0x10580, +@@ -462,7 +469,14 @@ static const struct pci_device_id sp_pci_table[] = { + }; + MODULE_DEVICE_TABLE(pci, sp_pci_table); + +-static SIMPLE_DEV_PM_OPS(sp_pci_pm_ops, sp_pci_suspend, sp_pci_resume); ++static const struct dev_pm_ops sp_pci_pm_ops = { ++ .suspend = pm_sleep_ptr(sp_pci_suspend), ++ .resume = pm_sleep_ptr(sp_pci_resume), ++ .freeze = pm_sleep_ptr(sp_pci_suspend), ++ .thaw = pm_sleep_ptr(sp_pci_resume), ++ .poweroff = pm_sleep_ptr(sp_pci_suspend), ++ .restore_early = pm_sleep_ptr(sp_pci_restore), ++}; + + static struct pci_driver sp_pci_driver = { + .name = "ccp", +diff --git a/drivers/crypto/ccp/tee-dev.c b/drivers/crypto/ccp/tee-dev.c +index 5c9d47f3be375..c0dc462a94288 100644 +--- a/drivers/crypto/ccp/tee-dev.c ++++ b/drivers/crypto/ccp/tee-dev.c +@@ -394,3 +394,8 @@ int psp_check_tee_status(void) + return 0; + } + EXPORT_SYMBOL(psp_check_tee_status); ++ ++int tee_restore(struct psp_device *psp) ++{ ++ return tee_init_ring(psp->tee_data); ++} +diff --git a/drivers/crypto/ccp/tee-dev.h b/drivers/crypto/ccp/tee-dev.h +index 49d26158b71e3..b0bf1de94ea6f 100644 +--- a/drivers/crypto/ccp/tee-dev.h ++++ b/drivers/crypto/ccp/tee-dev.h +@@ -122,5 +122,6 @@ struct tee_ring_cmd { + + int tee_dev_init(struct psp_device *psp); + void tee_dev_destroy(struct psp_device *psp); ++int tee_restore(struct psp_device *psp); + + #endif /* __TEE_DEV_H__ */ +-- +2.51.0 + diff --git a/queue-6.1/crypto-hisilicon-sec-fix-spelling-mistake-ckeck-chec.patch b/queue-6.1/crypto-hisilicon-sec-fix-spelling-mistake-ckeck-chec.patch new file mode 100644 index 0000000000..b5c8c8d3cb --- /dev/null +++ b/queue-6.1/crypto-hisilicon-sec-fix-spelling-mistake-ckeck-chec.patch @@ -0,0 +1,44 @@ +From 27665aeaf4145051fd2db0a19bf962a37f199489 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 12 Nov 2022 08:51:04 +0000 +Subject: crypto: hisilicon/sec - fix spelling mistake 'ckeck' -> 'check' + +From: Kai Ye + +[ Upstream commit 2132d4efaa66388f1f79c79a920908a22464686b ] + +There are a couple of spelling mistakes in sec2. Fix them. + +Signed-off-by: Kai Ye +Signed-off-by: Herbert Xu +Stable-dep-of: e75074396280 ("crypto: hisilicon/sec2 - support skcipher/aead fallback for hardware queue unavailable") +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/sec2/sec_crypto.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.c b/drivers/crypto/hisilicon/sec2/sec_crypto.c +index 292ab0ff2b07c..fe34e17b44424 100644 +--- a/drivers/crypto/hisilicon/sec2/sec_crypto.c ++++ b/drivers/crypto/hisilicon/sec2/sec_crypto.c +@@ -2002,7 +2002,7 @@ static int sec_aead_sha512_ctx_init(struct crypto_aead *tfm) + return sec_aead_ctx_init(tfm, "sha512"); + } + +-static int sec_skcipher_cryptlen_ckeck(struct sec_ctx *ctx, ++static int sec_skcipher_cryptlen_check(struct sec_ctx *ctx, + struct sec_req *sreq) + { + u32 cryptlen = sreq->c_req.sk_req->cryptlen; +@@ -2064,7 +2064,7 @@ static int sec_skcipher_param_check(struct sec_ctx *ctx, struct sec_req *sreq) + } + return 0; + } else if (c_alg == SEC_CALG_AES || c_alg == SEC_CALG_SM4) { +- return sec_skcipher_cryptlen_ckeck(ctx, sreq); ++ return sec_skcipher_cryptlen_check(ctx, sreq); + } + + dev_err(dev, "skcipher algorithm error!\n"); +-- +2.51.0 + diff --git a/queue-6.1/crypto-hisilicon-sec2-fix-for-sec-spec-check.patch b/queue-6.1/crypto-hisilicon-sec2-fix-for-sec-spec-check.patch new file mode 100644 index 0000000000..dc68051922 --- /dev/null +++ b/queue-6.1/crypto-hisilicon-sec2-fix-for-sec-spec-check.patch @@ -0,0 +1,278 @@ +From da369689964d7771873cba29827992be1c469083 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Feb 2025 11:56:28 +0800 +Subject: crypto: hisilicon/sec2 - fix for sec spec check + +From: Wenkai Lin + +[ Upstream commit f4f353cb7ae9bb43e34943edb693532a39118eca ] + +During encryption and decryption, user requests +must be checked first, if the specifications that +are not supported by the hardware are used, the +software computing is used for processing. + +Fixes: 2f072d75d1ab ("crypto: hisilicon - Add aead support on SEC2") +Signed-off-by: Wenkai Lin +Signed-off-by: Chenghai Huang +Signed-off-by: Herbert Xu +Stable-dep-of: e75074396280 ("crypto: hisilicon/sec2 - support skcipher/aead fallback for hardware queue unavailable") +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/sec2/sec.h | 1 - + drivers/crypto/hisilicon/sec2/sec_crypto.c | 101 ++++++++------------- + 2 files changed, 39 insertions(+), 63 deletions(-) + +diff --git a/drivers/crypto/hisilicon/sec2/sec.h b/drivers/crypto/hisilicon/sec2/sec.h +index 30c2b1a64695c..2fc04e210bc4f 100644 +--- a/drivers/crypto/hisilicon/sec2/sec.h ++++ b/drivers/crypto/hisilicon/sec2/sec.h +@@ -37,7 +37,6 @@ struct sec_aead_req { + u8 *a_ivin; + dma_addr_t a_ivin_dma; + struct aead_request *aead_req; +- bool fallback; + }; + + /* SEC request of Crypto */ +diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.c b/drivers/crypto/hisilicon/sec2/sec_crypto.c +index fe34e17b44424..91917a913512a 100644 +--- a/drivers/crypto/hisilicon/sec2/sec_crypto.c ++++ b/drivers/crypto/hisilicon/sec2/sec_crypto.c +@@ -690,14 +690,10 @@ static int sec_skcipher_fbtfm_init(struct crypto_skcipher *tfm) + + c_ctx->fallback = false; + +- /* Currently, only XTS mode need fallback tfm when using 192bit key */ +- if (likely(strncmp(alg, "xts", SEC_XTS_NAME_SZ))) +- return 0; +- + c_ctx->fbtfm = crypto_alloc_sync_skcipher(alg, 0, + CRYPTO_ALG_NEED_FALLBACK); + if (IS_ERR(c_ctx->fbtfm)) { +- pr_err("failed to alloc xts mode fallback tfm!\n"); ++ pr_err("failed to alloc fallback tfm for %s!\n", alg); + return PTR_ERR(c_ctx->fbtfm); + } + +@@ -859,7 +855,7 @@ static int sec_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key, + } + + memcpy(c_ctx->c_key, key, keylen); +- if (c_ctx->fallback && c_ctx->fbtfm) { ++ if (c_ctx->fbtfm) { + ret = crypto_sync_skcipher_setkey(c_ctx->fbtfm, key, keylen); + if (ret) { + dev_err(dev, "failed to set fallback skcipher key!\n"); +@@ -1160,8 +1156,10 @@ static int sec_aead_setkey(struct crypto_aead *tfm, const u8 *key, + } + + ret = crypto_authenc_extractkeys(&keys, key, keylen); +- if (ret) ++ if (ret) { ++ dev_err(dev, "sec extract aead keys err!\n"); + goto bad_key; ++ } + + ret = sec_aead_aes_set_key(c_ctx, &keys); + if (ret) { +@@ -1175,12 +1173,6 @@ static int sec_aead_setkey(struct crypto_aead *tfm, const u8 *key, + goto bad_key; + } + +- if (ctx->a_ctx.a_key_len & WORD_MASK) { +- ret = -EINVAL; +- dev_err(dev, "AUTH key length error!\n"); +- goto bad_key; +- } +- + ret = sec_aead_fallback_setkey(a_ctx, tfm, key, keylen); + if (ret) { + dev_err(dev, "set sec fallback key err!\n"); +@@ -2002,8 +1994,7 @@ static int sec_aead_sha512_ctx_init(struct crypto_aead *tfm) + return sec_aead_ctx_init(tfm, "sha512"); + } + +-static int sec_skcipher_cryptlen_check(struct sec_ctx *ctx, +- struct sec_req *sreq) ++static int sec_skcipher_cryptlen_check(struct sec_ctx *ctx, struct sec_req *sreq) + { + u32 cryptlen = sreq->c_req.sk_req->cryptlen; + struct device *dev = ctx->dev; +@@ -2027,10 +2018,6 @@ static int sec_skcipher_cryptlen_check(struct sec_ctx *ctx, + case SEC_CMODE_CFB: + case SEC_CMODE_OFB: + case SEC_CMODE_CTR: +- if (unlikely(ctx->sec->qm.ver < QM_HW_V3)) { +- dev_err(dev, "skcipher HW version error!\n"); +- ret = -EINVAL; +- } + break; + default: + ret = -EINVAL; +@@ -2039,17 +2026,21 @@ static int sec_skcipher_cryptlen_check(struct sec_ctx *ctx, + return ret; + } + +-static int sec_skcipher_param_check(struct sec_ctx *ctx, struct sec_req *sreq) ++static int sec_skcipher_param_check(struct sec_ctx *ctx, ++ struct sec_req *sreq, bool *need_fallback) + { + struct skcipher_request *sk_req = sreq->c_req.sk_req; + struct device *dev = ctx->dev; + u8 c_alg = ctx->c_ctx.c_alg; + +- if (unlikely(!sk_req->src || !sk_req->dst || +- sk_req->cryptlen > MAX_INPUT_DATA_LEN)) { ++ if (unlikely(!sk_req->src || !sk_req->dst)) { + dev_err(dev, "skcipher input param error!\n"); + return -EINVAL; + } ++ ++ if (sk_req->cryptlen > MAX_INPUT_DATA_LEN) ++ *need_fallback = true; ++ + sreq->c_req.c_len = sk_req->cryptlen; + + if (ctx->pbuf_supported && sk_req->cryptlen <= SEC_PBUF_SZ) +@@ -2107,6 +2098,7 @@ static int sec_skcipher_crypto(struct skcipher_request *sk_req, bool encrypt) + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(sk_req); + struct sec_req *req = skcipher_request_ctx(sk_req); + struct sec_ctx *ctx = crypto_skcipher_ctx(tfm); ++ bool need_fallback = false; + int ret; + + if (!sk_req->cryptlen) { +@@ -2120,11 +2112,11 @@ static int sec_skcipher_crypto(struct skcipher_request *sk_req, bool encrypt) + req->c_req.encrypt = encrypt; + req->ctx = ctx; + +- ret = sec_skcipher_param_check(ctx, req); ++ ret = sec_skcipher_param_check(ctx, req, &need_fallback); + if (unlikely(ret)) + return -EINVAL; + +- if (unlikely(ctx->c_ctx.fallback)) ++ if (unlikely(ctx->c_ctx.fallback || need_fallback)) + return sec_skcipher_soft_crypto(ctx, sk_req, encrypt); + + return ctx->req_op->process(ctx, req); +@@ -2257,52 +2249,35 @@ static int sec_aead_spec_check(struct sec_ctx *ctx, struct sec_req *sreq) + struct crypto_aead *tfm = crypto_aead_reqtfm(req); + size_t sz = crypto_aead_authsize(tfm); + u8 c_mode = ctx->c_ctx.c_mode; +- struct device *dev = ctx->dev; + int ret; + +- /* Hardware does not handle cases where authsize is not 4 bytes aligned */ +- if (c_mode == SEC_CMODE_CBC && (sz & WORD_MASK)) { +- sreq->aead_req.fallback = true; ++ if (unlikely(ctx->sec->qm.ver == QM_HW_V2 && !sreq->c_req.c_len)) + return -EINVAL; +- } + + if (unlikely(req->cryptlen + req->assoclen > MAX_INPUT_DATA_LEN || +- req->assoclen > SEC_MAX_AAD_LEN)) { +- dev_err(dev, "aead input spec error!\n"); ++ req->assoclen > SEC_MAX_AAD_LEN)) + return -EINVAL; +- } + + if (c_mode == SEC_CMODE_CCM) { +- if (unlikely(req->assoclen > SEC_MAX_CCM_AAD_LEN)) { +- dev_err_ratelimited(dev, "CCM input aad parameter is too long!\n"); ++ if (unlikely(req->assoclen > SEC_MAX_CCM_AAD_LEN)) + return -EINVAL; +- } +- ret = aead_iv_demension_check(req); +- if (ret) { +- dev_err(dev, "aead input iv param error!\n"); +- return ret; +- } +- } + +- if (sreq->c_req.encrypt) +- sreq->c_req.c_len = req->cryptlen; +- else +- sreq->c_req.c_len = req->cryptlen - sz; +- if (c_mode == SEC_CMODE_CBC) { +- if (unlikely(sreq->c_req.c_len & (AES_BLOCK_SIZE - 1))) { +- dev_err(dev, "aead crypto length error!\n"); ++ ret = aead_iv_demension_check(req); ++ if (unlikely(ret)) ++ return -EINVAL; ++ } else if (c_mode == SEC_CMODE_CBC) { ++ if (unlikely(sz & WORD_MASK)) ++ return -EINVAL; ++ if (unlikely(ctx->a_ctx.a_key_len & WORD_MASK)) + return -EINVAL; +- } + } + + return 0; + } + +-static int sec_aead_param_check(struct sec_ctx *ctx, struct sec_req *sreq) ++static int sec_aead_param_check(struct sec_ctx *ctx, struct sec_req *sreq, bool *need_fallback) + { + struct aead_request *req = sreq->aead_req.aead_req; +- struct crypto_aead *tfm = crypto_aead_reqtfm(req); +- size_t authsize = crypto_aead_authsize(tfm); + struct device *dev = ctx->dev; + u8 c_alg = ctx->c_ctx.c_alg; + +@@ -2311,12 +2286,10 @@ static int sec_aead_param_check(struct sec_ctx *ctx, struct sec_req *sreq) + return -EINVAL; + } + +- if (ctx->sec->qm.ver == QM_HW_V2) { +- if (unlikely(!req->cryptlen || (!sreq->c_req.encrypt && +- req->cryptlen <= authsize))) { +- sreq->aead_req.fallback = true; +- return -EINVAL; +- } ++ if (unlikely(ctx->c_ctx.c_mode == SEC_CMODE_CBC && ++ sreq->c_req.c_len & (AES_BLOCK_SIZE - 1))) { ++ dev_err(dev, "aead cbc mode input data length error!\n"); ++ return -EINVAL; + } + + /* Support AES or SM4 */ +@@ -2325,8 +2298,10 @@ static int sec_aead_param_check(struct sec_ctx *ctx, struct sec_req *sreq) + return -EINVAL; + } + +- if (unlikely(sec_aead_spec_check(ctx, sreq))) ++ if (unlikely(sec_aead_spec_check(ctx, sreq))) { ++ *need_fallback = true; + return -EINVAL; ++ } + + if (ctx->pbuf_supported && (req->cryptlen + req->assoclen) <= + SEC_PBUF_SZ) +@@ -2370,17 +2345,19 @@ static int sec_aead_crypto(struct aead_request *a_req, bool encrypt) + struct crypto_aead *tfm = crypto_aead_reqtfm(a_req); + struct sec_req *req = aead_request_ctx(a_req); + struct sec_ctx *ctx = crypto_aead_ctx(tfm); ++ size_t sz = crypto_aead_authsize(tfm); ++ bool need_fallback = false; + int ret; + + req->flag = a_req->base.flags; + req->aead_req.aead_req = a_req; + req->c_req.encrypt = encrypt; + req->ctx = ctx; +- req->aead_req.fallback = false; ++ req->c_req.c_len = a_req->cryptlen - (req->c_req.encrypt ? 0 : sz); + +- ret = sec_aead_param_check(ctx, req); ++ ret = sec_aead_param_check(ctx, req, &need_fallback); + if (unlikely(ret)) { +- if (req->aead_req.fallback) ++ if (need_fallback) + return sec_aead_soft_crypto(ctx, a_req, encrypt); + return -EINVAL; + } +-- +2.51.0 + diff --git a/queue-6.1/crypto-hisilicon-sec2-support-skcipher-aead-fallback.patch b/queue-6.1/crypto-hisilicon-sec2-support-skcipher-aead-fallback.patch new file mode 100644 index 0000000000..ecf6d122d4 --- /dev/null +++ b/queue-6.1/crypto-hisilicon-sec2-support-skcipher-aead-fallback.patch @@ -0,0 +1,220 @@ +From bd2cda3b9fb47a17274f9174a9b7707d492ee3ac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 21:44:52 +0800 +Subject: crypto: hisilicon/sec2 - support skcipher/aead fallback for hardware + queue unavailable + +From: Qi Tao + +[ Upstream commit e7507439628052363500d717caffb5c2241854dc ] + +When all hardware queues are busy and no shareable queue, +new processes fail to apply for queues. To avoid affecting +tasks, support fallback mechanism when hardware queues are +unavailable. + +Fixes: c16a70c1f253 ("crypto: hisilicon/sec - add new algorithm mode for AEAD") +Signed-off-by: Qi Tao +Signed-off-by: Chenghai Huang +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/sec2/sec_crypto.c | 62 ++++++++++++++++------ + 1 file changed, 47 insertions(+), 15 deletions(-) + +diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.c b/drivers/crypto/hisilicon/sec2/sec_crypto.c +index 91917a913512a..ae760ce85578b 100644 +--- a/drivers/crypto/hisilicon/sec2/sec_crypto.c ++++ b/drivers/crypto/hisilicon/sec2/sec_crypto.c +@@ -591,10 +591,8 @@ static int sec_ctx_base_init(struct sec_ctx *ctx) + int i, ret; + + ctx->qps = sec_create_qps(); +- if (!ctx->qps) { +- pr_err("Can not create sec qps!\n"); ++ if (!ctx->qps) + return -ENODEV; +- } + + sec = container_of(ctx->qps[0]->qm, struct sec_dev, qm); + ctx->sec = sec; +@@ -633,6 +631,9 @@ static void sec_ctx_base_uninit(struct sec_ctx *ctx) + { + int i; + ++ if (!ctx->qps) ++ return; ++ + for (i = 0; i < ctx->sec->ctx_q_num; i++) + sec_release_qp_ctx(ctx, &ctx->qp_ctx[i]); + +@@ -644,6 +645,9 @@ static int sec_cipher_init(struct sec_ctx *ctx) + { + struct sec_cipher_ctx *c_ctx = &ctx->c_ctx; + ++ if (!ctx->qps) ++ return 0; ++ + c_ctx->c_key = dma_alloc_coherent(ctx->dev, SEC_MAX_KEY_SIZE, + &c_ctx->c_key_dma, GFP_KERNEL); + if (!c_ctx->c_key) +@@ -656,6 +660,9 @@ static void sec_cipher_uninit(struct sec_ctx *ctx) + { + struct sec_cipher_ctx *c_ctx = &ctx->c_ctx; + ++ if (!ctx->qps) ++ return; ++ + memzero_explicit(c_ctx->c_key, SEC_MAX_KEY_SIZE); + dma_free_coherent(ctx->dev, SEC_MAX_KEY_SIZE, + c_ctx->c_key, c_ctx->c_key_dma); +@@ -677,6 +684,9 @@ static void sec_auth_uninit(struct sec_ctx *ctx) + { + struct sec_auth_ctx *a_ctx = &ctx->a_ctx; + ++ if (!ctx->qps) ++ return; ++ + memzero_explicit(a_ctx->a_key, SEC_MAX_AKEY_SIZE); + dma_free_coherent(ctx->dev, SEC_MAX_AKEY_SIZE, + a_ctx->a_key, a_ctx->a_key_dma); +@@ -714,7 +724,7 @@ static int sec_skcipher_init(struct crypto_skcipher *tfm) + } + + ret = sec_ctx_base_init(ctx); +- if (ret) ++ if (ret && ret != -ENODEV) + return ret; + + ret = sec_cipher_init(ctx); +@@ -825,6 +835,9 @@ static int sec_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key, + struct device *dev = ctx->dev; + int ret; + ++ if (!ctx->qps) ++ goto set_soft_key; ++ + if (c_mode == SEC_CMODE_XTS) { + ret = xts_verify_key(tfm, key, keylen); + if (ret) { +@@ -855,13 +868,14 @@ static int sec_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key, + } + + memcpy(c_ctx->c_key, key, keylen); +- if (c_ctx->fbtfm) { +- ret = crypto_sync_skcipher_setkey(c_ctx->fbtfm, key, keylen); +- if (ret) { +- dev_err(dev, "failed to set fallback skcipher key!\n"); +- return ret; +- } ++ ++set_soft_key: ++ ret = crypto_sync_skcipher_setkey(c_ctx->fbtfm, key, keylen); ++ if (ret) { ++ dev_err(dev, "failed to set fallback skcipher key!\n"); ++ return ret; + } ++ + return 0; + } + +@@ -1140,6 +1154,9 @@ static int sec_aead_setkey(struct crypto_aead *tfm, const u8 *key, + struct crypto_authenc_keys keys; + int ret; + ++ if (!ctx->qps) ++ return sec_aead_fallback_setkey(a_ctx, tfm, key, keylen); ++ + ctx->a_ctx.a_alg = a_alg; + ctx->c_ctx.c_alg = c_alg; + c_ctx->c_mode = c_mode; +@@ -1836,6 +1853,9 @@ static int sec_skcipher_ctx_init(struct crypto_skcipher *tfm) + if (ret) + return ret; + ++ if (!ctx->qps) ++ return 0; ++ + if (ctx->sec->qm.ver < QM_HW_V3) { + ctx->type_supported = SEC_BD_TYPE2; + ctx->req_op = &sec_skcipher_req_ops; +@@ -1844,7 +1864,7 @@ static int sec_skcipher_ctx_init(struct crypto_skcipher *tfm) + ctx->req_op = &sec_skcipher_req_ops_v3; + } + +- return ret; ++ return 0; + } + + static void sec_skcipher_ctx_exit(struct crypto_skcipher *tfm) +@@ -1912,7 +1932,7 @@ static int sec_aead_ctx_init(struct crypto_aead *tfm, const char *hash_name) + int ret; + + ret = sec_aead_init(tfm); +- if (ret) { ++ if (ret && ret != -ENODEV) { + pr_err("hisi_sec2: aead init error!\n"); + return ret; + } +@@ -1954,7 +1974,7 @@ static int sec_aead_xcm_ctx_init(struct crypto_aead *tfm) + int ret; + + ret = sec_aead_init(tfm); +- if (ret) { ++ if (ret && ret != -ENODEV) { + dev_err(ctx->dev, "hisi_sec2: aead xcm init error!\n"); + return ret; + } +@@ -2101,6 +2121,9 @@ static int sec_skcipher_crypto(struct skcipher_request *sk_req, bool encrypt) + bool need_fallback = false; + int ret; + ++ if (!ctx->qps) ++ goto soft_crypto; ++ + if (!sk_req->cryptlen) { + if (ctx->c_ctx.c_mode == SEC_CMODE_XTS) + return -EINVAL; +@@ -2117,9 +2140,12 @@ static int sec_skcipher_crypto(struct skcipher_request *sk_req, bool encrypt) + return -EINVAL; + + if (unlikely(ctx->c_ctx.fallback || need_fallback)) +- return sec_skcipher_soft_crypto(ctx, sk_req, encrypt); ++ goto soft_crypto; + + return ctx->req_op->process(ctx, req); ++ ++soft_crypto: ++ return sec_skcipher_soft_crypto(ctx, sk_req, encrypt); + } + + static int sec_skcipher_encrypt(struct skcipher_request *sk_req) +@@ -2349,6 +2375,9 @@ static int sec_aead_crypto(struct aead_request *a_req, bool encrypt) + bool need_fallback = false; + int ret; + ++ if (!ctx->qps) ++ goto soft_crypto; ++ + req->flag = a_req->base.flags; + req->aead_req.aead_req = a_req; + req->c_req.encrypt = encrypt; +@@ -2358,11 +2387,14 @@ static int sec_aead_crypto(struct aead_request *a_req, bool encrypt) + ret = sec_aead_param_check(ctx, req, &need_fallback); + if (unlikely(ret)) { + if (need_fallback) +- return sec_aead_soft_crypto(ctx, a_req, encrypt); ++ goto soft_crypto; + return -EINVAL; + } + + return ctx->req_op->process(ctx, req); ++ ++soft_crypto: ++ return sec_aead_soft_crypto(ctx, a_req, encrypt); + } + + static int sec_aead_encrypt(struct aead_request *a_req) +-- +2.51.0 + diff --git a/queue-6.1/crypto-hisilicon-trng-modifying-the-order-of-header-.patch b/queue-6.1/crypto-hisilicon-trng-modifying-the-order-of-header-.patch new file mode 100644 index 0000000000..a27a251681 --- /dev/null +++ b/queue-6.1/crypto-hisilicon-trng-modifying-the-order-of-header-.patch @@ -0,0 +1,56 @@ +From 2b9ac07cfd8274b3c60fc39632e16dc0690609e2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Aug 2024 17:50:09 +0800 +Subject: crypto: hisilicon/trng - modifying the order of header files + +From: Chenghai Huang + +[ Upstream commit f5dd7c43022799ac5c4e3a0d445f9c293a198413 ] + +Header files is included Order-ref: standard library headers, +OS library headers, and project-specific headers. This patch +modifies the order of header files according to suggestions. + +In addition, use %u to print unsigned int variables to prevent +overflow. + +Signed-off-by: Chenghai Huang +Signed-off-by: Herbert Xu +Stable-dep-of: 3d3135057ff5 ("crypto: hisilicon/trng - support tfms sharing the device") +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/trng/trng.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/crypto/hisilicon/trng/trng.c b/drivers/crypto/hisilicon/trng/trng.c +index 97e500db0a825..ec1eaed32d3bc 100644 +--- a/drivers/crypto/hisilicon/trng/trng.c ++++ b/drivers/crypto/hisilicon/trng/trng.c +@@ -1,6 +1,7 @@ + // SPDX-License-Identifier: GPL-2.0 + /* Copyright (c) 2019 HiSilicon Limited. */ + ++#include + #include + #include + #include +@@ -13,7 +14,6 @@ + #include + #include + #include +-#include + + #define HISI_TRNG_REG 0x00F0 + #define HISI_TRNG_BYTES 4 +@@ -121,7 +121,7 @@ static int hisi_trng_generate(struct crypto_rng *tfm, const u8 *src, + u32 i; + + if (dlen > SW_DRBG_BLOCKS_NUM * SW_DRBG_BYTES || dlen == 0) { +- pr_err("dlen(%d) exceeds limit(%d)!\n", dlen, ++ pr_err("dlen(%u) exceeds limit(%d)!\n", dlen, + SW_DRBG_BLOCKS_NUM * SW_DRBG_BYTES); + return -EINVAL; + } +-- +2.51.0 + diff --git a/queue-6.1/crypto-hisilicon-trng-support-tfms-sharing-the-devic.patch b/queue-6.1/crypto-hisilicon-trng-support-tfms-sharing-the-devic.patch new file mode 100644 index 0000000000..81714cfc5c --- /dev/null +++ b/queue-6.1/crypto-hisilicon-trng-support-tfms-sharing-the-devic.patch @@ -0,0 +1,258 @@ +From 818df3e66b3a35d6004ed1a2a4e812d072f53f27 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 17 Jan 2026 15:18:21 +0800 +Subject: crypto: hisilicon/trng - support tfms sharing the device + +From: Weili Qian + +[ Upstream commit 3d3135057ff567d5c09fff4c9ef6391a684e8042 ] + +Since the number of devices is limited, and the number +of tfms may exceed the number of devices, to ensure that +tfms can be successfully allocated, support tfms +sharing the same device. + +Fixes: e4d9d10ef4be ("crypto: hisilicon/trng - add support for PRNG") +Signed-off-by: Weili Qian +Signed-off-by: Chenghai Huang +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/trng/trng.c | 121 +++++++++++++++++++-------- + 1 file changed, 86 insertions(+), 35 deletions(-) + +diff --git a/drivers/crypto/hisilicon/trng/trng.c b/drivers/crypto/hisilicon/trng/trng.c +index ec1eaed32d3bc..b2d9b5310b784 100644 +--- a/drivers/crypto/hisilicon/trng/trng.c ++++ b/drivers/crypto/hisilicon/trng/trng.c +@@ -40,6 +40,7 @@ + #define SEED_SHIFT_24 24 + #define SEED_SHIFT_16 16 + #define SEED_SHIFT_8 8 ++#define SW_MAX_RANDOM_BYTES 65520 + + struct hisi_trng_list { + struct mutex lock; +@@ -53,8 +54,10 @@ struct hisi_trng { + struct list_head list; + struct hwrng rng; + u32 ver; +- bool is_used; +- struct mutex mutex; ++ u32 ctx_num; ++ /* The bytes of the random number generated since the last seeding. */ ++ u32 random_bytes; ++ struct mutex lock; + }; + + struct hisi_trng_ctx { +@@ -63,10 +66,14 @@ struct hisi_trng_ctx { + + static atomic_t trng_active_devs; + static struct hisi_trng_list trng_devices; ++static int hisi_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait); + +-static void hisi_trng_set_seed(struct hisi_trng *trng, const u8 *seed) ++static int hisi_trng_set_seed(struct hisi_trng *trng, const u8 *seed) + { + u32 val, seed_reg, i; ++ int ret; ++ ++ writel(0x0, trng->base + SW_DRBG_BLOCKS); + + for (i = 0; i < SW_DRBG_SEED_SIZE; + i += SW_DRBG_SEED_SIZE / SW_DRBG_SEED_REGS_NUM) { +@@ -78,6 +85,20 @@ static void hisi_trng_set_seed(struct hisi_trng *trng, const u8 *seed) + seed_reg = (i >> SW_DRBG_NUM_SHIFT) % SW_DRBG_SEED_REGS_NUM; + writel(val, trng->base + SW_DRBG_SEED(seed_reg)); + } ++ ++ writel(SW_DRBG_BLOCKS_NUM | (0x1 << SW_DRBG_ENABLE_SHIFT), ++ trng->base + SW_DRBG_BLOCKS); ++ writel(0x1, trng->base + SW_DRBG_INIT); ++ ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS, ++ val, val & BIT(0), SLEEP_US, TIMEOUT_US); ++ if (ret) { ++ pr_err("failed to init trng(%d)\n", ret); ++ return -EIO; ++ } ++ ++ trng->random_bytes = 0; ++ ++ return 0; + } + + static int hisi_trng_seed(struct crypto_rng *tfm, const u8 *seed, +@@ -85,8 +106,7 @@ static int hisi_trng_seed(struct crypto_rng *tfm, const u8 *seed, + { + struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm); + struct hisi_trng *trng = ctx->trng; +- u32 val = 0; +- int ret = 0; ++ int ret; + + if (slen < SW_DRBG_SEED_SIZE) { + pr_err("slen(%u) is not matched with trng(%d)\n", slen, +@@ -94,43 +114,45 @@ static int hisi_trng_seed(struct crypto_rng *tfm, const u8 *seed, + return -EINVAL; + } + +- writel(0x0, trng->base + SW_DRBG_BLOCKS); +- hisi_trng_set_seed(trng, seed); ++ mutex_lock(&trng->lock); ++ ret = hisi_trng_set_seed(trng, seed); ++ mutex_unlock(&trng->lock); + +- writel(SW_DRBG_BLOCKS_NUM | (0x1 << SW_DRBG_ENABLE_SHIFT), +- trng->base + SW_DRBG_BLOCKS); +- writel(0x1, trng->base + SW_DRBG_INIT); ++ return ret; ++} + +- ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS, +- val, val & BIT(0), SLEEP_US, TIMEOUT_US); +- if (ret) +- pr_err("fail to init trng(%d)\n", ret); ++static int hisi_trng_reseed(struct hisi_trng *trng) ++{ ++ u8 seed[SW_DRBG_SEED_SIZE]; ++ int size; + +- return ret; ++ if (!trng->random_bytes) ++ return 0; ++ ++ size = hisi_trng_read(&trng->rng, seed, SW_DRBG_SEED_SIZE, false); ++ if (size != SW_DRBG_SEED_SIZE) ++ return -EIO; ++ ++ return hisi_trng_set_seed(trng, seed); + } + +-static int hisi_trng_generate(struct crypto_rng *tfm, const u8 *src, +- unsigned int slen, u8 *dstn, unsigned int dlen) ++static int hisi_trng_get_bytes(struct hisi_trng *trng, u8 *dstn, unsigned int dlen) + { +- struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm); +- struct hisi_trng *trng = ctx->trng; + u32 data[SW_DRBG_DATA_NUM]; + u32 currsize = 0; + u32 val = 0; + int ret; + u32 i; + +- if (dlen > SW_DRBG_BLOCKS_NUM * SW_DRBG_BYTES || dlen == 0) { +- pr_err("dlen(%u) exceeds limit(%d)!\n", dlen, +- SW_DRBG_BLOCKS_NUM * SW_DRBG_BYTES); +- return -EINVAL; +- } ++ ret = hisi_trng_reseed(trng); ++ if (ret) ++ return ret; + + do { + ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS, +- val, val & BIT(1), SLEEP_US, TIMEOUT_US); ++ val, val & BIT(1), SLEEP_US, TIMEOUT_US); + if (ret) { +- pr_err("fail to generate random number(%d)!\n", ret); ++ pr_err("failed to generate random number(%d)!\n", ret); + break; + } + +@@ -145,30 +167,57 @@ static int hisi_trng_generate(struct crypto_rng *tfm, const u8 *src, + currsize = dlen; + } + ++ trng->random_bytes += SW_DRBG_BYTES; + writel(0x1, trng->base + SW_DRBG_GEN); + } while (currsize < dlen); + + return ret; + } + ++static int hisi_trng_generate(struct crypto_rng *tfm, const u8 *src, ++ unsigned int slen, u8 *dstn, unsigned int dlen) ++{ ++ struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm); ++ struct hisi_trng *trng = ctx->trng; ++ unsigned int currsize = 0; ++ unsigned int block_size; ++ int ret; ++ ++ if (!dstn || !dlen) { ++ pr_err("output is error, dlen %u!\n", dlen); ++ return -EINVAL; ++ } ++ ++ do { ++ block_size = min_t(unsigned int, dlen - currsize, SW_MAX_RANDOM_BYTES); ++ mutex_lock(&trng->lock); ++ ret = hisi_trng_get_bytes(trng, dstn + currsize, block_size); ++ mutex_unlock(&trng->lock); ++ if (ret) ++ return ret; ++ currsize += block_size; ++ } while (currsize < dlen); ++ ++ return 0; ++} ++ + static int hisi_trng_init(struct crypto_tfm *tfm) + { + struct hisi_trng_ctx *ctx = crypto_tfm_ctx(tfm); + struct hisi_trng *trng; +- int ret = -EBUSY; ++ u32 ctx_num = ~0; + + mutex_lock(&trng_devices.lock); + list_for_each_entry(trng, &trng_devices.list, list) { +- if (!trng->is_used) { +- trng->is_used = true; ++ if (trng->ctx_num < ctx_num) { ++ ctx_num = trng->ctx_num; + ctx->trng = trng; +- ret = 0; +- break; + } + } ++ ctx->trng->ctx_num++; + mutex_unlock(&trng_devices.lock); + +- return ret; ++ return 0; + } + + static void hisi_trng_exit(struct crypto_tfm *tfm) +@@ -176,7 +225,7 @@ static void hisi_trng_exit(struct crypto_tfm *tfm) + struct hisi_trng_ctx *ctx = crypto_tfm_ctx(tfm); + + mutex_lock(&trng_devices.lock); +- ctx->trng->is_used = false; ++ ctx->trng->ctx_num--; + mutex_unlock(&trng_devices.lock); + } + +@@ -238,7 +287,7 @@ static int hisi_trng_del_from_list(struct hisi_trng *trng) + int ret = -EBUSY; + + mutex_lock(&trng_devices.lock); +- if (!trng->is_used) { ++ if (!trng->ctx_num) { + list_del(&trng->list); + ret = 0; + } +@@ -262,7 +311,9 @@ static int hisi_trng_probe(struct platform_device *pdev) + if (IS_ERR(trng->base)) + return PTR_ERR(trng->base); + +- trng->is_used = false; ++ trng->ctx_num = 0; ++ trng->random_bytes = SW_MAX_RANDOM_BYTES; ++ mutex_init(&trng->lock); + trng->ver = readl(trng->base + HISI_TRNG_VERSION); + if (!trng_devices.is_init) { + INIT_LIST_HEAD(&trng_devices.list); +-- +2.51.0 + diff --git a/queue-6.1/crypto-hisilicon-zip-adjust-the-way-to-obtain-the-re.patch b/queue-6.1/crypto-hisilicon-zip-adjust-the-way-to-obtain-the-re.patch new file mode 100644 index 0000000000..1b06e818fc --- /dev/null +++ b/queue-6.1/crypto-hisilicon-zip-adjust-the-way-to-obtain-the-re.patch @@ -0,0 +1,128 @@ +From cc005fa0d6102d5f664775384bac9add188ddab5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 21:44:42 +0800 +Subject: crypto: hisilicon/zip - adjust the way to obtain the req in the + callback function + +From: Chenghai Huang + +[ Upstream commit 19c2475ce1984cf675ebfbbeaa5509b2fb1887d6 ] + +In the shared queue design, multiple tfms use same qp, and one qp +need to corresponds to multiple qp_ctx. So use tag to obtain the +req virtual address. Build a one-to-one relationship between tfm +and qp_ctx. finaly remove the old get_tag operation. + +Fixes: 2bcf36348ce5 ("crypto: hisilicon/zip - initialize operations about 'sqe' in 'acomp_alg.init'") +Signed-off-by: Chenghai Huang +Signed-off-by: Weili Qian +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/zip/zip_crypto.c | 24 +++++++++-------------- + 1 file changed, 9 insertions(+), 15 deletions(-) + +diff --git a/drivers/crypto/hisilicon/zip/zip_crypto.c b/drivers/crypto/hisilicon/zip/zip_crypto.c +index 636ac794ebb75..d21ce4094d7db 100644 +--- a/drivers/crypto/hisilicon/zip/zip_crypto.c ++++ b/drivers/crypto/hisilicon/zip/zip_crypto.c +@@ -36,6 +36,7 @@ enum { + HZIP_CTX_Q_NUM + }; + ++#define GET_REQ_FROM_SQE(sqe) ((u64)(sqe)->dw26 | (u64)(sqe)->dw27 << 32) + #define COMP_NAME_TO_TYPE(alg_name) \ + (!strcmp((alg_name), "deflate") ? HZIP_ALG_TYPE_DEFLATE : 0) + +@@ -45,6 +46,7 @@ struct hisi_zip_req { + struct hisi_acc_hw_sgl *hw_dst; + dma_addr_t dma_src; + dma_addr_t dma_dst; ++ struct hisi_zip_qp_ctx *qp_ctx; + u16 req_id; + }; + +@@ -71,7 +73,6 @@ struct hisi_zip_sqe_ops { + void (*fill_req_type)(struct hisi_zip_sqe *sqe, u8 req_type); + void (*fill_tag)(struct hisi_zip_sqe *sqe, struct hisi_zip_req *req); + void (*fill_sqe_type)(struct hisi_zip_sqe *sqe, u8 sqe_type); +- u32 (*get_tag)(struct hisi_zip_sqe *sqe); + u32 (*get_status)(struct hisi_zip_sqe *sqe); + u32 (*get_dstlen)(struct hisi_zip_sqe *sqe); + }; +@@ -128,6 +129,7 @@ static struct hisi_zip_req *hisi_zip_create_req(struct hisi_zip_qp_ctx *qp_ctx, + req_cache = q + req_id; + req_cache->req_id = req_id; + req_cache->req = req; ++ req_cache->qp_ctx = qp_ctx; + + return req_cache; + } +@@ -178,7 +180,8 @@ static void hisi_zip_fill_req_type(struct hisi_zip_sqe *sqe, u8 req_type) + + static void hisi_zip_fill_tag(struct hisi_zip_sqe *sqe, struct hisi_zip_req *req) + { +- sqe->dw26 = req->req_id; ++ sqe->dw26 = lower_32_bits((u64)req); ++ sqe->dw27 = upper_32_bits((u64)req); + } + + static void hisi_zip_fill_sqe_type(struct hisi_zip_sqe *sqe, u8 sqe_type) +@@ -232,7 +235,7 @@ static int hisi_zip_do_work(struct hisi_zip_qp_ctx *qp_ctx, + &req->dma_dst); + if (IS_ERR(req->hw_dst)) { + ret = PTR_ERR(req->hw_dst); +- dev_err(dev, "failed to map the dst buffer to hw slg (%d)!\n", ++ dev_err(dev, "failed to map the dst buffer to hw sgl (%d)!\n", + ret); + goto err_unmap_input; + } +@@ -258,11 +261,6 @@ static int hisi_zip_do_work(struct hisi_zip_qp_ctx *qp_ctx, + return ret; + } + +-static u32 hisi_zip_get_tag(struct hisi_zip_sqe *sqe) +-{ +- return sqe->dw26; +-} +- + static u32 hisi_zip_get_status(struct hisi_zip_sqe *sqe) + { + return sqe->dw3 & HZIP_BD_STATUS_M; +@@ -275,14 +273,12 @@ static u32 hisi_zip_get_dstlen(struct hisi_zip_sqe *sqe) + + static void hisi_zip_acomp_cb(struct hisi_qp *qp, void *data) + { +- struct hisi_zip_qp_ctx *qp_ctx = qp->qp_ctx; ++ struct hisi_zip_sqe *sqe = data; ++ struct hisi_zip_req *req = (struct hisi_zip_req *)GET_REQ_FROM_SQE(sqe); ++ struct hisi_zip_qp_ctx *qp_ctx = req->qp_ctx; + const struct hisi_zip_sqe_ops *ops = qp_ctx->ctx->ops; + struct hisi_zip_dfx *dfx = &qp_ctx->zip_dev->dfx; +- struct hisi_zip_req_q *req_q = &qp_ctx->req_q; + struct device *dev = &qp->qm->pdev->dev; +- struct hisi_zip_sqe *sqe = data; +- u32 tag = ops->get_tag(sqe); +- struct hisi_zip_req *req = req_q->q + tag; + struct acomp_req *acomp_req = req->req; + int err = 0; + u32 status; +@@ -386,7 +382,6 @@ static const struct hisi_zip_sqe_ops hisi_zip_ops = { + .fill_req_type = hisi_zip_fill_req_type, + .fill_tag = hisi_zip_fill_tag, + .fill_sqe_type = hisi_zip_fill_sqe_type, +- .get_tag = hisi_zip_get_tag, + .get_status = hisi_zip_get_status, + .get_dstlen = hisi_zip_get_dstlen, + }; +@@ -574,7 +569,6 @@ static void hisi_zip_acomp_exit(struct crypto_acomp *tfm) + { + struct hisi_zip_ctx *ctx = crypto_tfm_ctx(&tfm->base); + +- hisi_zip_set_acomp_cb(ctx, NULL); + hisi_zip_release_sgl_pool(ctx); + hisi_zip_release_req_q(ctx); + hisi_zip_ctx_exit(ctx); +-- +2.51.0 + diff --git a/queue-6.1/crypto-hisilicon-zip-remove-zlib-and-gzip.patch b/queue-6.1/crypto-hisilicon-zip-remove-zlib-and-gzip.patch new file mode 100644 index 0000000000..4eb17c9c4b --- /dev/null +++ b/queue-6.1/crypto-hisilicon-zip-remove-zlib-and-gzip.patch @@ -0,0 +1,489 @@ +From d19d67983b2936828a28ee2e96b182d7b5765a28 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 14 Sep 2023 17:09:08 +0800 +Subject: crypto: hisilicon/zip - remove zlib and gzip + +From: Yang Shen + +[ Upstream commit 1a9e6f59caeea35d157f91b452ae75f251d8255b ] + +Remove the support of zlib-deflate and gzip. + +Signed-off-by: Yang Shen +Reviewed-by: Longfang Liu +Signed-off-by: Herbert Xu +Stable-dep-of: 19c2475ce198 ("crypto: hisilicon/zip - adjust the way to obtain the req in the callback function") +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/zip/zip_crypto.c | 308 ++-------------------- + drivers/crypto/hisilicon/zip/zip_main.c | 2 +- + 2 files changed, 22 insertions(+), 288 deletions(-) + +diff --git a/drivers/crypto/hisilicon/zip/zip_crypto.c b/drivers/crypto/hisilicon/zip/zip_crypto.c +index 09f60f7867795..636ac794ebb75 100644 +--- a/drivers/crypto/hisilicon/zip/zip_crypto.c ++++ b/drivers/crypto/hisilicon/zip/zip_crypto.c +@@ -17,38 +17,14 @@ + /* hisi_zip_sqe dw9 */ + #define HZIP_REQ_TYPE_M GENMASK(7, 0) + #define HZIP_ALG_TYPE_DEFLATE 0x01 +-#define HZIP_ALG_TYPE_ZLIB 0x02 +-#define HZIP_ALG_TYPE_GZIP 0x03 + #define HZIP_BUF_TYPE_M GENMASK(11, 8) +-#define HZIP_PBUFFER 0x0 + #define HZIP_SGL 0x1 + +-#define HZIP_ZLIB_HEAD_SIZE 2 +-#define HZIP_GZIP_HEAD_SIZE 10 +- +-#define GZIP_HEAD_FHCRC_BIT BIT(1) +-#define GZIP_HEAD_FEXTRA_BIT BIT(2) +-#define GZIP_HEAD_FNAME_BIT BIT(3) +-#define GZIP_HEAD_FCOMMENT_BIT BIT(4) +- +-#define GZIP_HEAD_FLG_SHIFT 3 +-#define GZIP_HEAD_FEXTRA_SHIFT 10 +-#define GZIP_HEAD_FEXTRA_XLEN 2UL +-#define GZIP_HEAD_FHCRC_SIZE 2 +- +-#define HZIP_GZIP_HEAD_BUF 256 + #define HZIP_ALG_PRIORITY 300 + #define HZIP_SGL_SGE_NR 10 + +-#define HZIP_ALG_ZLIB GENMASK(1, 0) +-#define HZIP_ALG_GZIP GENMASK(3, 2) + #define HZIP_ALG_DEFLATE GENMASK(5, 4) + +-static const u8 zlib_head[HZIP_ZLIB_HEAD_SIZE] = {0x78, 0x9c}; +-static const u8 gzip_head[HZIP_GZIP_HEAD_SIZE] = { +- 0x1f, 0x8b, 0x08, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x03 +-}; +- + enum hisi_zip_alg_type { + HZIP_ALG_TYPE_COMP = 0, + HZIP_ALG_TYPE_DECOMP = 1, +@@ -61,22 +37,10 @@ enum { + }; + + #define COMP_NAME_TO_TYPE(alg_name) \ +- (!strcmp((alg_name), "deflate") ? HZIP_ALG_TYPE_DEFLATE : \ +- (!strcmp((alg_name), "zlib-deflate") ? HZIP_ALG_TYPE_ZLIB : \ +- !strcmp((alg_name), "gzip") ? HZIP_ALG_TYPE_GZIP : 0)) \ +- +-#define TO_HEAD_SIZE(req_type) \ +- (((req_type) == HZIP_ALG_TYPE_ZLIB) ? sizeof(zlib_head) : \ +- ((req_type) == HZIP_ALG_TYPE_GZIP) ? sizeof(gzip_head) : 0) \ +- +-#define TO_HEAD(req_type) \ +- (((req_type) == HZIP_ALG_TYPE_ZLIB) ? zlib_head : \ +- ((req_type) == HZIP_ALG_TYPE_GZIP) ? gzip_head : NULL) \ ++ (!strcmp((alg_name), "deflate") ? HZIP_ALG_TYPE_DEFLATE : 0) + + struct hisi_zip_req { + struct acomp_req *req; +- u32 sskip; +- u32 dskip; + struct hisi_acc_hw_sgl *hw_src; + struct hisi_acc_hw_sgl *hw_dst; + dma_addr_t dma_src; +@@ -141,85 +105,8 @@ static u16 sgl_sge_nr = HZIP_SGL_SGE_NR; + module_param_cb(sgl_sge_nr, &sgl_sge_nr_ops, &sgl_sge_nr, 0444); + MODULE_PARM_DESC(sgl_sge_nr, "Number of sge in sgl(1-255)"); + +-static u32 get_extra_field_size(const u8 *start) +-{ +- return *((u16 *)start) + GZIP_HEAD_FEXTRA_XLEN; +-} +- +-static u32 get_name_field_size(const u8 *start) +-{ +- return strlen(start) + 1; +-} +- +-static u32 get_comment_field_size(const u8 *start) +-{ +- return strlen(start) + 1; +-} +- +-static u32 __get_gzip_head_size(const u8 *src) +-{ +- u8 head_flg = *(src + GZIP_HEAD_FLG_SHIFT); +- u32 size = GZIP_HEAD_FEXTRA_SHIFT; +- +- if (head_flg & GZIP_HEAD_FEXTRA_BIT) +- size += get_extra_field_size(src + size); +- if (head_flg & GZIP_HEAD_FNAME_BIT) +- size += get_name_field_size(src + size); +- if (head_flg & GZIP_HEAD_FCOMMENT_BIT) +- size += get_comment_field_size(src + size); +- if (head_flg & GZIP_HEAD_FHCRC_BIT) +- size += GZIP_HEAD_FHCRC_SIZE; +- +- return size; +-} +- +-static u32 __maybe_unused get_gzip_head_size(struct scatterlist *sgl) +-{ +- char buf[HZIP_GZIP_HEAD_BUF]; +- +- sg_copy_to_buffer(sgl, sg_nents(sgl), buf, sizeof(buf)); +- +- return __get_gzip_head_size(buf); +-} +- +-static int add_comp_head(struct scatterlist *dst, u8 req_type) +-{ +- int head_size = TO_HEAD_SIZE(req_type); +- const u8 *head = TO_HEAD(req_type); +- int ret; +- +- ret = sg_copy_from_buffer(dst, sg_nents(dst), head, head_size); +- if (unlikely(ret != head_size)) { +- pr_err("the head size of buffer is wrong (%d)!\n", ret); +- return -ENOMEM; +- } +- +- return head_size; +-} +- +-static int get_comp_head_size(struct acomp_req *acomp_req, u8 req_type) +-{ +- if (unlikely(!acomp_req->src || !acomp_req->slen)) +- return -EINVAL; +- +- if (unlikely(req_type == HZIP_ALG_TYPE_GZIP && +- acomp_req->slen < GZIP_HEAD_FEXTRA_SHIFT)) +- return -EINVAL; +- +- switch (req_type) { +- case HZIP_ALG_TYPE_ZLIB: +- return TO_HEAD_SIZE(HZIP_ALG_TYPE_ZLIB); +- case HZIP_ALG_TYPE_GZIP: +- return TO_HEAD_SIZE(HZIP_ALG_TYPE_GZIP); +- default: +- pr_err("request type does not support!\n"); +- return -EINVAL; +- } +-} +- +-static struct hisi_zip_req *hisi_zip_create_req(struct acomp_req *req, +- struct hisi_zip_qp_ctx *qp_ctx, +- size_t head_size, bool is_comp) ++static struct hisi_zip_req *hisi_zip_create_req(struct hisi_zip_qp_ctx *qp_ctx, ++ struct acomp_req *req) + { + struct hisi_zip_req_q *req_q = &qp_ctx->req_q; + struct hisi_zip_req *q = req_q->q; +@@ -242,14 +129,6 @@ static struct hisi_zip_req *hisi_zip_create_req(struct acomp_req *req, + req_cache->req_id = req_id; + req_cache->req = req; + +- if (is_comp) { +- req_cache->sskip = 0; +- req_cache->dskip = head_size; +- } else { +- req_cache->sskip = head_size; +- req_cache->dskip = 0; +- } +- + return req_cache; + } + +@@ -275,10 +154,8 @@ static void hisi_zip_fill_buf_size(struct hisi_zip_sqe *sqe, struct hisi_zip_req + { + struct acomp_req *a_req = req->req; + +- sqe->input_data_length = a_req->slen - req->sskip; +- sqe->dest_avail_out = a_req->dlen - req->dskip; +- sqe->dw7 = FIELD_PREP(HZIP_IN_SGE_DATA_OFFSET_M, req->sskip); +- sqe->dw8 = FIELD_PREP(HZIP_OUT_SGE_DATA_OFFSET_M, req->dskip); ++ sqe->input_data_length = a_req->slen; ++ sqe->dest_avail_out = a_req->dlen; + } + + static void hisi_zip_fill_buf_type(struct hisi_zip_sqe *sqe, u8 buf_type) +@@ -299,12 +176,7 @@ static void hisi_zip_fill_req_type(struct hisi_zip_sqe *sqe, u8 req_type) + sqe->dw9 = val; + } + +-static void hisi_zip_fill_tag_v1(struct hisi_zip_sqe *sqe, struct hisi_zip_req *req) +-{ +- sqe->dw13 = req->req_id; +-} +- +-static void hisi_zip_fill_tag_v2(struct hisi_zip_sqe *sqe, struct hisi_zip_req *req) ++static void hisi_zip_fill_tag(struct hisi_zip_sqe *sqe, struct hisi_zip_req *req) + { + sqe->dw26 = req->req_id; + } +@@ -333,8 +205,8 @@ static void hisi_zip_fill_sqe(struct hisi_zip_ctx *ctx, struct hisi_zip_sqe *sqe + ops->fill_sqe_type(sqe, ops->sqe_type); + } + +-static int hisi_zip_do_work(struct hisi_zip_req *req, +- struct hisi_zip_qp_ctx *qp_ctx) ++static int hisi_zip_do_work(struct hisi_zip_qp_ctx *qp_ctx, ++ struct hisi_zip_req *req) + { + struct hisi_acc_sgl_pool *pool = qp_ctx->sgl_pool; + struct hisi_zip_dfx *dfx = &qp_ctx->zip_dev->dfx; +@@ -386,12 +258,7 @@ static int hisi_zip_do_work(struct hisi_zip_req *req, + return ret; + } + +-static u32 hisi_zip_get_tag_v1(struct hisi_zip_sqe *sqe) +-{ +- return sqe->dw13; +-} +- +-static u32 hisi_zip_get_tag_v2(struct hisi_zip_sqe *sqe) ++static u32 hisi_zip_get_tag(struct hisi_zip_sqe *sqe) + { + return sqe->dw26; + } +@@ -417,8 +284,8 @@ static void hisi_zip_acomp_cb(struct hisi_qp *qp, void *data) + u32 tag = ops->get_tag(sqe); + struct hisi_zip_req *req = req_q->q + tag; + struct acomp_req *acomp_req = req->req; +- u32 status, dlen, head_size; + int err = 0; ++ u32 status; + + atomic64_inc(&dfx->recv_cnt); + status = ops->get_status(sqe); +@@ -430,13 +297,10 @@ static void hisi_zip_acomp_cb(struct hisi_qp *qp, void *data) + err = -EIO; + } + +- dlen = ops->get_dstlen(sqe); +- + hisi_acc_sg_buf_unmap(dev, acomp_req->src, req->hw_src); + hisi_acc_sg_buf_unmap(dev, acomp_req->dst, req->hw_dst); + +- head_size = (qp->alg_type == 0) ? TO_HEAD_SIZE(qp->req_type) : 0; +- acomp_req->dlen = dlen + head_size; ++ acomp_req->dlen = ops->get_dstlen(sqe); + + if (acomp_req->base.complete) + acomp_request_complete(acomp_req, err); +@@ -450,24 +314,13 @@ static int hisi_zip_acompress(struct acomp_req *acomp_req) + struct hisi_zip_qp_ctx *qp_ctx = &ctx->qp_ctx[HZIP_QPC_COMP]; + struct device *dev = &qp_ctx->qp->qm->pdev->dev; + struct hisi_zip_req *req; +- int head_size = 0; + int ret; + +- /* let's output compression head now */ +- if (qp_ctx->qp->req_type != HZIP_ALG_TYPE_DEFLATE) { +- head_size = add_comp_head(acomp_req->dst, qp_ctx->qp->req_type); +- if (unlikely(head_size < 0)) { +- dev_err_ratelimited(dev, "failed to add comp head (%d)!\n", +- head_size); +- return head_size; +- } +- } +- +- req = hisi_zip_create_req(acomp_req, qp_ctx, head_size, true); ++ req = hisi_zip_create_req(qp_ctx, acomp_req); + if (IS_ERR(req)) + return PTR_ERR(req); + +- ret = hisi_zip_do_work(req, qp_ctx); ++ ret = hisi_zip_do_work(qp_ctx, req); + if (unlikely(ret != -EINPROGRESS)) { + dev_info_ratelimited(dev, "failed to do compress (%d)!\n", ret); + hisi_zip_remove_req(qp_ctx, req); +@@ -482,22 +335,13 @@ static int hisi_zip_adecompress(struct acomp_req *acomp_req) + struct hisi_zip_qp_ctx *qp_ctx = &ctx->qp_ctx[HZIP_QPC_DECOMP]; + struct device *dev = &qp_ctx->qp->qm->pdev->dev; + struct hisi_zip_req *req; +- int head_size = 0, ret; +- +- if (qp_ctx->qp->req_type != HZIP_ALG_TYPE_DEFLATE) { +- head_size = get_comp_head_size(acomp_req, qp_ctx->qp->req_type); +- if (unlikely(head_size < 0)) { +- dev_err_ratelimited(dev, "failed to get comp head size (%d)!\n", +- head_size); +- return head_size; +- } +- } ++ int ret; + +- req = hisi_zip_create_req(acomp_req, qp_ctx, head_size, false); ++ req = hisi_zip_create_req(qp_ctx, acomp_req); + if (IS_ERR(req)) + return PTR_ERR(req); + +- ret = hisi_zip_do_work(req, qp_ctx); ++ ret = hisi_zip_do_work(qp_ctx, req); + if (unlikely(ret != -EINPROGRESS)) { + dev_info_ratelimited(dev, "failed to do decompress (%d)!\n", + ret); +@@ -534,28 +378,15 @@ static void hisi_zip_release_qp(struct hisi_zip_qp_ctx *qp_ctx) + hisi_qm_free_qps(&qp_ctx->qp, 1); + } + +-static const struct hisi_zip_sqe_ops hisi_zip_ops_v1 = { +- .sqe_type = 0, +- .fill_addr = hisi_zip_fill_addr, +- .fill_buf_size = hisi_zip_fill_buf_size, +- .fill_buf_type = hisi_zip_fill_buf_type, +- .fill_req_type = hisi_zip_fill_req_type, +- .fill_tag = hisi_zip_fill_tag_v1, +- .fill_sqe_type = hisi_zip_fill_sqe_type, +- .get_tag = hisi_zip_get_tag_v1, +- .get_status = hisi_zip_get_status, +- .get_dstlen = hisi_zip_get_dstlen, +-}; +- +-static const struct hisi_zip_sqe_ops hisi_zip_ops_v2 = { ++static const struct hisi_zip_sqe_ops hisi_zip_ops = { + .sqe_type = 0x3, + .fill_addr = hisi_zip_fill_addr, + .fill_buf_size = hisi_zip_fill_buf_size, + .fill_buf_type = hisi_zip_fill_buf_type, + .fill_req_type = hisi_zip_fill_req_type, +- .fill_tag = hisi_zip_fill_tag_v2, ++ .fill_tag = hisi_zip_fill_tag, + .fill_sqe_type = hisi_zip_fill_sqe_type, +- .get_tag = hisi_zip_get_tag_v2, ++ .get_tag = hisi_zip_get_tag, + .get_status = hisi_zip_get_status, + .get_dstlen = hisi_zip_get_dstlen, + }; +@@ -591,10 +422,7 @@ static int hisi_zip_ctx_init(struct hisi_zip_ctx *hisi_zip_ctx, u8 req_type, int + qp_ctx->zip_dev = hisi_zip; + } + +- if (hisi_zip->qm.ver < QM_HW_V3) +- hisi_zip_ctx->ops = &hisi_zip_ops_v1; +- else +- hisi_zip_ctx->ops = &hisi_zip_ops_v2; ++ hisi_zip_ctx->ops = &hisi_zip_ops; + + return 0; + } +@@ -788,106 +616,12 @@ static void hisi_zip_unregister_deflate(struct hisi_qm *qm) + crypto_unregister_acomp(&hisi_zip_acomp_deflate); + } + +-static struct acomp_alg hisi_zip_acomp_zlib = { +- .init = hisi_zip_acomp_init, +- .exit = hisi_zip_acomp_exit, +- .compress = hisi_zip_acompress, +- .decompress = hisi_zip_adecompress, +- .base = { +- .cra_name = "zlib-deflate", +- .cra_driver_name = "hisi-zlib-acomp", +- .cra_module = THIS_MODULE, +- .cra_priority = HZIP_ALG_PRIORITY, +- .cra_ctxsize = sizeof(struct hisi_zip_ctx), +- } +-}; +- +-static int hisi_zip_register_zlib(struct hisi_qm *qm) +-{ +- int ret; +- +- if (!hisi_zip_alg_support(qm, HZIP_ALG_ZLIB)) +- return 0; +- +- ret = crypto_register_acomp(&hisi_zip_acomp_zlib); +- if (ret) +- dev_err(&qm->pdev->dev, "failed to register to zlib (%d)!\n", ret); +- +- return ret; +-} +- +-static void hisi_zip_unregister_zlib(struct hisi_qm *qm) +-{ +- if (!hisi_zip_alg_support(qm, HZIP_ALG_ZLIB)) +- return; +- +- crypto_unregister_acomp(&hisi_zip_acomp_zlib); +-} +- +-static struct acomp_alg hisi_zip_acomp_gzip = { +- .init = hisi_zip_acomp_init, +- .exit = hisi_zip_acomp_exit, +- .compress = hisi_zip_acompress, +- .decompress = hisi_zip_adecompress, +- .base = { +- .cra_name = "gzip", +- .cra_driver_name = "hisi-gzip-acomp", +- .cra_module = THIS_MODULE, +- .cra_priority = HZIP_ALG_PRIORITY, +- .cra_ctxsize = sizeof(struct hisi_zip_ctx), +- } +-}; +- +-static int hisi_zip_register_gzip(struct hisi_qm *qm) +-{ +- int ret; +- +- if (!hisi_zip_alg_support(qm, HZIP_ALG_GZIP)) +- return 0; +- +- ret = crypto_register_acomp(&hisi_zip_acomp_gzip); +- if (ret) +- dev_err(&qm->pdev->dev, "failed to register to gzip (%d)!\n", ret); +- +- return ret; +-} +- +-static void hisi_zip_unregister_gzip(struct hisi_qm *qm) +-{ +- if (!hisi_zip_alg_support(qm, HZIP_ALG_GZIP)) +- return; +- +- crypto_unregister_acomp(&hisi_zip_acomp_gzip); +-} +- + int hisi_zip_register_to_crypto(struct hisi_qm *qm) + { +- int ret = 0; +- +- ret = hisi_zip_register_deflate(qm); +- if (ret) +- return ret; +- +- ret = hisi_zip_register_zlib(qm); +- if (ret) +- goto err_unreg_deflate; +- +- ret = hisi_zip_register_gzip(qm); +- if (ret) +- goto err_unreg_zlib; +- +- return 0; +- +-err_unreg_zlib: +- hisi_zip_unregister_zlib(qm); +-err_unreg_deflate: +- hisi_zip_unregister_deflate(qm); +- return ret; ++ return hisi_zip_register_deflate(qm); + } + + void hisi_zip_unregister_from_crypto(struct hisi_qm *qm) + { + hisi_zip_unregister_deflate(qm); +- hisi_zip_unregister_zlib(qm); +- hisi_zip_unregister_gzip(qm); + } +diff --git a/drivers/crypto/hisilicon/zip/zip_main.c b/drivers/crypto/hisilicon/zip/zip_main.c +index 66dee01007819..9ec76685bcd9a 100644 +--- a/drivers/crypto/hisilicon/zip/zip_main.c ++++ b/drivers/crypto/hisilicon/zip/zip_main.c +@@ -239,7 +239,7 @@ static struct hisi_qm_cap_info zip_basic_cap_info[] = { + {ZIP_CLUSTER_DECOMP_NUM_CAP, 0x313C, 0, GENMASK(7, 0), 0x6, 0x6, 0x3}, + {ZIP_DECOMP_ENABLE_BITMAP, 0x3140, 16, GENMASK(15, 0), 0xFC, 0xFC, 0x1C}, + {ZIP_COMP_ENABLE_BITMAP, 0x3140, 0, GENMASK(15, 0), 0x3, 0x3, 0x3}, +- {ZIP_DRV_ALG_BITMAP, 0x3144, 0, GENMASK(31, 0), 0xF, 0xF, 0x3F}, ++ {ZIP_DRV_ALG_BITMAP, 0x3144, 0, GENMASK(31, 0), 0x0, 0x0, 0x30}, + {ZIP_DEV_ALG_BITMAP, 0x3148, 0, GENMASK(31, 0), 0xF, 0xF, 0x3F}, + {ZIP_CORE1_ALG_BITMAP, 0x314C, 0, GENMASK(31, 0), 0x5, 0x5, 0xD5}, + {ZIP_CORE2_ALG_BITMAP, 0x3150, 0, GENMASK(31, 0), 0x5, 0x5, 0xD5}, +-- +2.51.0 + diff --git a/queue-6.1/crypto-hisilicon-zip-support-deflate-algorithm.patch b/queue-6.1/crypto-hisilicon-zip-support-deflate-algorithm.patch new file mode 100644 index 0000000000..45e8c426ba --- /dev/null +++ b/queue-6.1/crypto-hisilicon-zip-support-deflate-algorithm.patch @@ -0,0 +1,192 @@ +From 0fc55de43b40979dbd37c4c92b0225d358ff0184 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 14 Sep 2023 17:09:07 +0800 +Subject: crypto: hisilicon/zip - support deflate algorithm + +From: Yang Shen + +[ Upstream commit aa3f80500382ca864b7cfcff4e5ca2fa6a0e977d ] + +Add the deflate algorithm support for hisilicon zip hardware. + +Signed-off-by: Yang Shen +Signed-off-by: Herbert Xu +Stable-dep-of: 19c2475ce198 ("crypto: hisilicon/zip - adjust the way to obtain the req in the callback function") +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/zip/zip_crypto.c | 86 ++++++++++++++++++----- + drivers/crypto/hisilicon/zip/zip_main.c | 4 +- + 2 files changed, 72 insertions(+), 18 deletions(-) + +diff --git a/drivers/crypto/hisilicon/zip/zip_crypto.c b/drivers/crypto/hisilicon/zip/zip_crypto.c +index 6608971d10cdc..09f60f7867795 100644 +--- a/drivers/crypto/hisilicon/zip/zip_crypto.c ++++ b/drivers/crypto/hisilicon/zip/zip_crypto.c +@@ -16,6 +16,7 @@ + #define HZIP_OUT_SGE_DATA_OFFSET_M GENMASK(23, 0) + /* hisi_zip_sqe dw9 */ + #define HZIP_REQ_TYPE_M GENMASK(7, 0) ++#define HZIP_ALG_TYPE_DEFLATE 0x01 + #define HZIP_ALG_TYPE_ZLIB 0x02 + #define HZIP_ALG_TYPE_GZIP 0x03 + #define HZIP_BUF_TYPE_M GENMASK(11, 8) +@@ -41,6 +42,7 @@ + + #define HZIP_ALG_ZLIB GENMASK(1, 0) + #define HZIP_ALG_GZIP GENMASK(3, 2) ++#define HZIP_ALG_DEFLATE GENMASK(5, 4) + + static const u8 zlib_head[HZIP_ZLIB_HEAD_SIZE] = {0x78, 0x9c}; + static const u8 gzip_head[HZIP_GZIP_HEAD_SIZE] = { +@@ -59,8 +61,9 @@ enum { + }; + + #define COMP_NAME_TO_TYPE(alg_name) \ ++ (!strcmp((alg_name), "deflate") ? HZIP_ALG_TYPE_DEFLATE : \ + (!strcmp((alg_name), "zlib-deflate") ? HZIP_ALG_TYPE_ZLIB : \ +- !strcmp((alg_name), "gzip") ? HZIP_ALG_TYPE_GZIP : 0) \ ++ !strcmp((alg_name), "gzip") ? HZIP_ALG_TYPE_GZIP : 0)) \ + + #define TO_HEAD_SIZE(req_type) \ + (((req_type) == HZIP_ALG_TYPE_ZLIB) ? sizeof(zlib_head) : \ +@@ -447,15 +450,17 @@ static int hisi_zip_acompress(struct acomp_req *acomp_req) + struct hisi_zip_qp_ctx *qp_ctx = &ctx->qp_ctx[HZIP_QPC_COMP]; + struct device *dev = &qp_ctx->qp->qm->pdev->dev; + struct hisi_zip_req *req; +- int head_size; ++ int head_size = 0; + int ret; + + /* let's output compression head now */ +- head_size = add_comp_head(acomp_req->dst, qp_ctx->qp->req_type); +- if (unlikely(head_size < 0)) { +- dev_err_ratelimited(dev, "failed to add comp head (%d)!\n", +- head_size); +- return head_size; ++ if (qp_ctx->qp->req_type != HZIP_ALG_TYPE_DEFLATE) { ++ head_size = add_comp_head(acomp_req->dst, qp_ctx->qp->req_type); ++ if (unlikely(head_size < 0)) { ++ dev_err_ratelimited(dev, "failed to add comp head (%d)!\n", ++ head_size); ++ return head_size; ++ } + } + + req = hisi_zip_create_req(acomp_req, qp_ctx, head_size, true); +@@ -477,13 +482,15 @@ static int hisi_zip_adecompress(struct acomp_req *acomp_req) + struct hisi_zip_qp_ctx *qp_ctx = &ctx->qp_ctx[HZIP_QPC_DECOMP]; + struct device *dev = &qp_ctx->qp->qm->pdev->dev; + struct hisi_zip_req *req; +- int head_size, ret; +- +- head_size = get_comp_head_size(acomp_req, qp_ctx->qp->req_type); +- if (unlikely(head_size < 0)) { +- dev_err_ratelimited(dev, "failed to get comp head size (%d)!\n", +- head_size); +- return head_size; ++ int head_size = 0, ret; ++ ++ if (qp_ctx->qp->req_type != HZIP_ALG_TYPE_DEFLATE) { ++ head_size = get_comp_head_size(acomp_req, qp_ctx->qp->req_type); ++ if (unlikely(head_size < 0)) { ++ dev_err_ratelimited(dev, "failed to get comp head size (%d)!\n", ++ head_size); ++ return head_size; ++ } + } + + req = hisi_zip_create_req(acomp_req, qp_ctx, head_size, false); +@@ -745,6 +752,42 @@ static void hisi_zip_acomp_exit(struct crypto_acomp *tfm) + hisi_zip_ctx_exit(ctx); + } + ++static struct acomp_alg hisi_zip_acomp_deflate = { ++ .init = hisi_zip_acomp_init, ++ .exit = hisi_zip_acomp_exit, ++ .compress = hisi_zip_acompress, ++ .decompress = hisi_zip_adecompress, ++ .base = { ++ .cra_name = "deflate", ++ .cra_driver_name = "hisi-deflate-acomp", ++ .cra_module = THIS_MODULE, ++ .cra_priority = HZIP_ALG_PRIORITY, ++ .cra_ctxsize = sizeof(struct hisi_zip_ctx), ++ } ++}; ++ ++static int hisi_zip_register_deflate(struct hisi_qm *qm) ++{ ++ int ret; ++ ++ if (!hisi_zip_alg_support(qm, HZIP_ALG_DEFLATE)) ++ return 0; ++ ++ ret = crypto_register_acomp(&hisi_zip_acomp_deflate); ++ if (ret) ++ dev_err(&qm->pdev->dev, "failed to register to deflate (%d)!\n", ret); ++ ++ return ret; ++} ++ ++static void hisi_zip_unregister_deflate(struct hisi_qm *qm) ++{ ++ if (!hisi_zip_alg_support(qm, HZIP_ALG_DEFLATE)) ++ return; ++ ++ crypto_unregister_acomp(&hisi_zip_acomp_deflate); ++} ++ + static struct acomp_alg hisi_zip_acomp_zlib = { + .init = hisi_zip_acomp_init, + .exit = hisi_zip_acomp_exit, +@@ -821,19 +864,30 @@ int hisi_zip_register_to_crypto(struct hisi_qm *qm) + { + int ret = 0; + +- ret = hisi_zip_register_zlib(qm); ++ ret = hisi_zip_register_deflate(qm); + if (ret) + return ret; + ++ ret = hisi_zip_register_zlib(qm); ++ if (ret) ++ goto err_unreg_deflate; ++ + ret = hisi_zip_register_gzip(qm); + if (ret) +- hisi_zip_unregister_zlib(qm); ++ goto err_unreg_zlib; ++ ++ return 0; + ++err_unreg_zlib: ++ hisi_zip_unregister_zlib(qm); ++err_unreg_deflate: ++ hisi_zip_unregister_deflate(qm); + return ret; + } + + void hisi_zip_unregister_from_crypto(struct hisi_qm *qm) + { ++ hisi_zip_unregister_deflate(qm); + hisi_zip_unregister_zlib(qm); + hisi_zip_unregister_gzip(qm); + } +diff --git a/drivers/crypto/hisilicon/zip/zip_main.c b/drivers/crypto/hisilicon/zip/zip_main.c +index 044e7303cb632..66dee01007819 100644 +--- a/drivers/crypto/hisilicon/zip/zip_main.c ++++ b/drivers/crypto/hisilicon/zip/zip_main.c +@@ -239,8 +239,8 @@ static struct hisi_qm_cap_info zip_basic_cap_info[] = { + {ZIP_CLUSTER_DECOMP_NUM_CAP, 0x313C, 0, GENMASK(7, 0), 0x6, 0x6, 0x3}, + {ZIP_DECOMP_ENABLE_BITMAP, 0x3140, 16, GENMASK(15, 0), 0xFC, 0xFC, 0x1C}, + {ZIP_COMP_ENABLE_BITMAP, 0x3140, 0, GENMASK(15, 0), 0x3, 0x3, 0x3}, +- {ZIP_DRV_ALG_BITMAP, 0x3144, 0, GENMASK(31, 0), 0xF, 0xF, 0xF}, +- {ZIP_DEV_ALG_BITMAP, 0x3148, 0, GENMASK(31, 0), 0xF, 0xF, 0xFF}, ++ {ZIP_DRV_ALG_BITMAP, 0x3144, 0, GENMASK(31, 0), 0xF, 0xF, 0x3F}, ++ {ZIP_DEV_ALG_BITMAP, 0x3148, 0, GENMASK(31, 0), 0xF, 0xF, 0x3F}, + {ZIP_CORE1_ALG_BITMAP, 0x314C, 0, GENMASK(31, 0), 0x5, 0x5, 0xD5}, + {ZIP_CORE2_ALG_BITMAP, 0x3150, 0, GENMASK(31, 0), 0x5, 0x5, 0xD5}, + {ZIP_CORE3_ALG_BITMAP, 0x3154, 0, GENMASK(31, 0), 0xA, 0xA, 0x2A}, +-- +2.51.0 + diff --git a/queue-6.1/crypto-octeontx-fix-dma_free_coherent-size.patch b/queue-6.1/crypto-octeontx-fix-dma_free_coherent-size.patch new file mode 100644 index 0000000000..6e0852cad0 --- /dev/null +++ b/queue-6.1/crypto-octeontx-fix-dma_free_coherent-size.patch @@ -0,0 +1,38 @@ +From d21501df8f239471c007720cf1ff01956078a66e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 11:12:57 +0100 +Subject: crypto: octeontx - fix dma_free_coherent() size + +From: Thomas Fourier + +[ Upstream commit 624a6760bf8464965c17c8df10b40b557eaa3002 ] + +The size of the buffer in alloc_command_queues() is +curr->size + OTX_CPT_NEXT_CHUNK_PTR_SIZE, so used that length for +dma_free_coherent(). + +Fixes: 10b4f09491bf ("crypto: marvell - add the Virtual Function driver for CPT") +Signed-off-by: Thomas Fourier +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/marvell/octeontx/otx_cptvf_main.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/crypto/marvell/octeontx/otx_cptvf_main.c b/drivers/crypto/marvell/octeontx/otx_cptvf_main.c +index 88a41d1ca5f64..6c0bfb3ea1c9f 100644 +--- a/drivers/crypto/marvell/octeontx/otx_cptvf_main.c ++++ b/drivers/crypto/marvell/octeontx/otx_cptvf_main.c +@@ -168,7 +168,8 @@ static void free_command_queues(struct otx_cptvf *cptvf, + chunk = list_first_entry(&cqinfo->queue[i].chead, + struct otx_cpt_cmd_chunk, nextchunk); + +- dma_free_coherent(&pdev->dev, chunk->size, ++ dma_free_coherent(&pdev->dev, ++ chunk->size + OTX_CPT_NEXT_CHUNK_PTR_SIZE, + chunk->head, + chunk->dma_addr); + chunk->head = NULL; +-- +2.51.0 + diff --git a/queue-6.1/crypto-qat-fix-warning-on-adf_pfvf_pf_proto.c.patch b/queue-6.1/crypto-qat-fix-warning-on-adf_pfvf_pf_proto.c.patch new file mode 100644 index 0000000000..a40831b4f7 --- /dev/null +++ b/queue-6.1/crypto-qat-fix-warning-on-adf_pfvf_pf_proto.c.patch @@ -0,0 +1,63 @@ +From d8131a8cea7f4fa05e2373d70ebdb7b6d53a9c9a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 20 Nov 2025 16:30:46 +0000 +Subject: crypto: qat - fix warning on adf_pfvf_pf_proto.c +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Giovanni Cabiddu + +[ Upstream commit 994689b8f91b02fdb5f64cba2412cde5ef3084b5 ] + +Building the QAT driver with -Wmaybe-uninitialized triggers warnings in +qat_common/adf_pfvf_pf_proto.c. Specifically, the variables blk_type, +blk_byte, and byte_max may be used uninitialized in handle_blkmsg_req(): + + make M=drivers/crypto/intel/qat W=1 C=2 "KCFLAGS=-Werror" \ + KBUILD_CFLAGS_KERNEL=-Wmaybe-uninitialized \ + CFLAGS_MODULE=-Wmaybe-uninitialized + + ... + warning: ‘byte_max’ may be used uninitialized [-Wmaybe-uninitialized] + warning: ‘blk_type’ may be used uninitialized [-Wmaybe-uninitialized] + warning: ‘blk_byte’ may be used uninitialized [-Wmaybe-uninitialized] + +Although the caller of handle_blkmsg_req() always provides a req.type +that is handled by the switch, the compiler cannot guarantee this. + +Add a default case to the switch statement to handle an invalid req.type. + +Fixes: 673184a2a58f ("crypto: qat - introduce support for PFVF block messages") +Signed-off-by: Giovanni Cabiddu +Reviewed-by: Ahsan Atta +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/qat/qat_common/adf_pfvf_pf_proto.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/crypto/qat/qat_common/adf_pfvf_pf_proto.c b/drivers/crypto/qat/qat_common/adf_pfvf_pf_proto.c +index 388e58bcbcaf2..4a1ea3e720329 100644 +--- a/drivers/crypto/qat/qat_common/adf_pfvf_pf_proto.c ++++ b/drivers/crypto/qat/qat_common/adf_pfvf_pf_proto.c +@@ -148,6 +148,16 @@ static struct pfvf_message handle_blkmsg_req(struct adf_accel_vf_info *vf_info, + blk_byte = FIELD_GET(ADF_VF2PF_SMALL_BLOCK_BYTE_MASK, req.data); + byte_max = ADF_VF2PF_SMALL_BLOCK_BYTE_MAX; + break; ++ default: ++ dev_err(&GET_DEV(vf_info->accel_dev), ++ "Invalid BlockMsg type 0x%.4x received from VF%u\n", ++ req.type, vf_info->vf_nr); ++ resp.type = ADF_PF2VF_MSGTYPE_BLKMSG_RESP; ++ resp.data = FIELD_PREP(ADF_PF2VF_BLKMSG_RESP_TYPE_MASK, ++ ADF_PF2VF_BLKMSG_RESP_TYPE_ERROR) | ++ FIELD_PREP(ADF_PF2VF_BLKMSG_RESP_DATA_MASK, ++ ADF_PF2VF_UNSPECIFIED_ERROR); ++ return resp; + } + + /* Is this a request for CRC or data? */ +-- +2.51.0 + diff --git a/queue-6.1/cxl-fix-premature-commit_end-increment-on-decoder-co.patch b/queue-6.1/cxl-fix-premature-commit_end-increment-on-decoder-co.patch new file mode 100644 index 0000000000..6a5d3c763a --- /dev/null +++ b/queue-6.1/cxl-fix-premature-commit_end-increment-on-decoder-co.patch @@ -0,0 +1,63 @@ +From d4255122a19d9cea57f87b18ac7184e4d503be11 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 14:45:52 +0800 +Subject: cxl: Fix premature commit_end increment on decoder commit failure + +From: Yuxiong Wang + +[ Upstream commit 7b6f9d9b1ea05c9c22570126547c780e8c6c3f62 ] + +In cxl_decoder_commit(), commit_end is incremented before verifying +whether the commit succeeded, and the CXL_DECODER_F_ENABLE bit in +cxld->flags is only set after a successful commit. As a result, if the +commit fails, commit_end has been incremented and cxld->reset() has no +effect since the flag is not set, so commit_end remains incorrectly +incremented. The inconsistency between commit_end and CXL_DECODER_F_ENABLE +causes failure during subsequent either commit or reset operations. + +Fix this by incrementing commit_end only after confirming the commit +succeeded. Also, remove the ineffective cxld->reset() call. According to +CXL Spec r4.0 8.2.4.20.12 Committing Decoder Programming, since +cxld_await_commit() has cleared the decoder commit bit on failure, no +additional reset is required. + +[dj: Fixed commit log 80 char wrapping. ] +[dj: Fix "Fixes" tag to correct hash length. ] +[dj: Change spec to r4.0. ] + +Fixes: 176baefb2eb5 ("cxl/hdm: Commit decoder state to hardware") +Signed-off-by: Yuxiong Wang +Acked-by: Huang Ying +Reviewed-by: Dave Jiang +Reviewed-by: Alison Schofield +Link: https://patch.msgid.link/20260129064552.31180-1-yuxiong.wang@linux.alibaba.com +Signed-off-by: Dave Jiang +Signed-off-by: Sasha Levin +--- + drivers/cxl/core/hdm.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c +index 8c1db4e1b816d..7d48f5a575ceb 100644 +--- a/drivers/cxl/core/hdm.c ++++ b/drivers/cxl/core/hdm.c +@@ -628,15 +628,14 @@ static int cxl_decoder_commit(struct cxl_decoder *cxld) + writel(ctrl, hdm + CXL_HDM_DECODER0_CTRL_OFFSET(id)); + up_read(&cxl_dpa_rwsem); + +- port->commit_end++; + rc = cxld_await_commit(hdm, cxld->id); + err: + if (rc) { + dev_dbg(&port->dev, "%s: error %d committing decoder\n", + dev_name(&cxld->dev), rc); +- cxld->reset(cxld); + return rc; + } ++ port->commit_end++; + cxld->flags |= CXL_DECODER_F_ENABLE; + + return 0; +-- +2.51.0 + diff --git a/queue-6.1/dm-use-bio_clone_blkg_association.patch b/queue-6.1/dm-use-bio_clone_blkg_association.patch new file mode 100644 index 0000000000..dd740c1dd0 --- /dev/null +++ b/queue-6.1/dm-use-bio_clone_blkg_association.patch @@ -0,0 +1,44 @@ +From cc588a7f10abc4c6a395130eb41b0f4a2f2f3d61 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 15:36:22 +0100 +Subject: dm: use bio_clone_blkg_association + +From: Mikulas Patocka + +[ Upstream commit 2df8b310bcfe76827fd71092f58a2493ee6590b0 ] + +The origin bio carries blk-cgroup information which could be set from +foreground(task_css(css) - wbc->wb->blkcg_css), so the blkcg won't +control buffer io since commit ca522482e3eaf ("dm: pass NULL bdev to +bio_alloc_clone"). The synchronous io is still under control by blkcg, +because 'bio->bi_blkg' is set by io submitting task which has been added +into 'cgroup.procs'. + +Fix it by using bio_clone_blkg_association when submitting a cloned bio. + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=220985 +Fixes: ca522482e3eaf ("dm: pass NULL bdev to bio_alloc_clone") +Reported-by: Zhihao Cheng +Signed-off-by: Mikulas Patocka +Tested-by: Zhihao Cheng +Signed-off-by: Sasha Levin +--- + drivers/md/dm.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/md/dm.c b/drivers/md/dm.c +index f745b9cf462aa..13225b7f11491 100644 +--- a/drivers/md/dm.c ++++ b/drivers/md/dm.c +@@ -1351,6 +1351,8 @@ void dm_submit_bio_remap(struct bio *clone, struct bio *tgt_clone) + if (!tgt_clone) + tgt_clone = clone; + ++ bio_clone_blkg_association(tgt_clone, io->orig_bio); ++ + /* + * Account io->origin_bio to DM dev on behalf of target + * that took ownership of IO with DM_MAPIO_SUBMITTED. +-- +2.51.0 + diff --git a/queue-6.1/dma-dma-axi-dmac-fix-sw-cyclic-transfers.patch b/queue-6.1/dma-dma-axi-dmac-fix-sw-cyclic-transfers.patch new file mode 100644 index 0000000000..9b6b6ccaa2 --- /dev/null +++ b/queue-6.1/dma-dma-axi-dmac-fix-sw-cyclic-transfers.patch @@ -0,0 +1,57 @@ +From f56e15cdac40a3253c3c411f70239ab7124e5af5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Nov 2025 16:22:25 +0000 +Subject: dma: dma-axi-dmac: fix SW cyclic transfers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Nuno Sá + +[ Upstream commit 9bd257181fd5c996d922e9991500ad27987cfbf4 ] + +If 'hw_cyclic' is false we should still be able to do cyclic transfers in +"software". That was not working for the case where 'desc->num_sgs' is 1 +because 'chan->next_desc' is never set with the current desc which means +that the cyclic transfer only runs once and in the next SOT interrupt we +do nothing since vchan_next_desc() will return NULL. + +Fix it by setting 'chan->next_desc' as soon as we get a new desc via +vchan_next_desc(). + +Fixes: 0e3b67b348b8 ("dmaengine: Add support for the Analog Devices AXI-DMAC DMA controller") +Signed-off-by: Nuno Sá +base-commit: 398035178503bf662281bbffb4bebce1460a4bc5 +change-id: 20251104-axi-dmac-fixes-and-improvs-e3ad512a329c +Acked-by: Michael Hennerich +Link: https://patch.msgid.link/20251104-axi-dmac-fixes-and-improvs-v1-1-3e6fd9328f72@analog.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/dma/dma-axi-dmac.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c +index 176cf3665a185..ac73c3b59d268 100644 +--- a/drivers/dma/dma-axi-dmac.c ++++ b/drivers/dma/dma-axi-dmac.c +@@ -225,6 +225,7 @@ static void axi_dmac_start_transfer(struct axi_dmac_chan *chan) + return; + list_move_tail(&vdesc->node, &chan->active_descs); + desc = to_axi_dmac_desc(vdesc); ++ chan->next_desc = desc; + } + sg = &desc->sg[desc->num_submitted]; + +@@ -242,8 +243,6 @@ static void axi_dmac_start_transfer(struct axi_dmac_chan *chan) + else + chan->next_desc = NULL; + flags |= AXI_DMAC_FLAG_LAST; +- } else { +- chan->next_desc = desc; + } + + sg->id = axi_dmac_read(dmac, AXI_DMAC_REG_TRANSFER_ID); +-- +2.51.0 + diff --git a/queue-6.1/dmaengine-mediatek-uart-apdma-fix-above-4g-addressin.patch b/queue-6.1/dmaengine-mediatek-uart-apdma-fix-above-4g-addressin.patch new file mode 100644 index 0000000000..c9779177f1 --- /dev/null +++ b/queue-6.1/dmaengine-mediatek-uart-apdma-fix-above-4g-addressin.patch @@ -0,0 +1,83 @@ +From 1598eaae16303db2183c2c3b0d8e4515db595120 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 13 Nov 2025 13:22:26 +0100 +Subject: dmaengine: mediatek: uart-apdma: Fix above 4G addressing TX/RX + +From: AngeloGioacchino Del Regno + +[ Upstream commit 58ab9d7b6651d21e1cff1777529f2d3dd0b4e851 ] + +The VFF_4G_SUPPORT register is named differently in datasheets, +and its name is "VFF_ADDR2"; was this named correctly from the +beginning it would've been clearer that there was a mistake in +the programming sequence. + +This register is supposed to hold the high bits to support the +DMA addressing above 4G (so, more than 32 bits) and not a bit +to "enable" the support for VFF 4G. + +Fix the name of this register, and also fix its usage by writing +the upper 32 bits of the dma_addr_t on it when the SoC supports +such feature. + +Fixes: 9135408c3ace ("dmaengine: mediatek: Add MediaTek UART APDMA support") +Signed-off-by: AngeloGioacchino Del Regno +Link: https://patch.msgid.link/20251113122229.23998-6-angelogioacchino.delregno@collabora.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/dma/mediatek/mtk-uart-apdma.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/dma/mediatek/mtk-uart-apdma.c b/drivers/dma/mediatek/mtk-uart-apdma.c +index 0acf6a92a4ad3..c1e132a110ffb 100644 +--- a/drivers/dma/mediatek/mtk-uart-apdma.c ++++ b/drivers/dma/mediatek/mtk-uart-apdma.c +@@ -42,7 +42,7 @@ + #define VFF_STOP_CLR_B 0 + #define VFF_EN_CLR_B 0 + #define VFF_INT_EN_CLR_B 0 +-#define VFF_4G_SUPPORT_CLR_B 0 ++#define VFF_ADDR2_CLR_B 0 + + /* + * interrupt trigger level for tx +@@ -73,7 +73,7 @@ + /* TX: the buffer size SW can write. RX: the buffer size HW can write. */ + #define VFF_LEFT_SIZE 0x40 + #define VFF_DEBUG_STATUS 0x50 +-#define VFF_4G_SUPPORT 0x54 ++#define VFF_ADDR2 0x54 + + struct mtk_uart_apdmadev { + struct dma_device ddev; +@@ -150,7 +150,7 @@ static void mtk_uart_apdma_start_tx(struct mtk_chan *c) + mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_TX_INT_CLR_B); + + if (mtkd->support_33bits) +- mtk_uart_apdma_write(c, VFF_4G_SUPPORT, VFF_4G_EN_B); ++ mtk_uart_apdma_write(c, VFF_ADDR2, upper_32_bits(d->addr)); + } + + mtk_uart_apdma_write(c, VFF_EN, VFF_EN_B); +@@ -193,7 +193,7 @@ static void mtk_uart_apdma_start_rx(struct mtk_chan *c) + mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_RX_INT_CLR_B); + + if (mtkd->support_33bits) +- mtk_uart_apdma_write(c, VFF_4G_SUPPORT, VFF_4G_EN_B); ++ mtk_uart_apdma_write(c, VFF_ADDR2, upper_32_bits(d->addr)); + } + + mtk_uart_apdma_write(c, VFF_INT_EN, VFF_RX_INT_EN_B); +@@ -299,7 +299,7 @@ static int mtk_uart_apdma_alloc_chan_resources(struct dma_chan *chan) + } + + if (mtkd->support_33bits) +- mtk_uart_apdma_write(c, VFF_4G_SUPPORT, VFF_4G_SUPPORT_CLR_B); ++ mtk_uart_apdma_write(c, VFF_ADDR2, VFF_ADDR2_CLR_B); + + err_pm: + pm_runtime_put_noidle(mtkd->ddev.dev); +-- +2.51.0 + diff --git a/queue-6.1/documentation-pci-endpoint-fix-ntb-vntb-copy-paste-e.patch b/queue-6.1/documentation-pci-endpoint-fix-ntb-vntb-copy-paste-e.patch new file mode 100644 index 0000000000..7c99be1882 --- /dev/null +++ b/queue-6.1/documentation-pci-endpoint-fix-ntb-vntb-copy-paste-e.patch @@ -0,0 +1,82 @@ +From fa1519159ea536c87dc4c5b8682ccf89db18078e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 3 Nov 2025 09:28:30 +0200 +Subject: Documentation: PCI: endpoint: Fix ntb/vntb copy & paste errors + +From: Baruch Siach + +[ Upstream commit ad0c6da5be901f5c181490f683d22b416059bccb ] + +Fix copy & paste errors by changing the references from 'ntb' to 'vntb'. + +Fixes: 4ac8c8e52cd9 ("Documentation: PCI: Add specification for the PCI vNTB function device") +Signed-off-by: Baruch Siach +[mani: squashed the patches and fixed more errors] +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Reviewed-by: Frank Li +Link: https://patch.msgid.link/b51c2a69ffdbfa2c359f5cf33f3ad2acc3db87e4.1762154911.git.baruch@tkos.co.il +Signed-off-by: Sasha Levin +--- + Documentation/PCI/endpoint/pci-vntb-howto.rst | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/Documentation/PCI/endpoint/pci-vntb-howto.rst b/Documentation/PCI/endpoint/pci-vntb-howto.rst +index 70d3bc90893f3..949c0d35694c2 100644 +--- a/Documentation/PCI/endpoint/pci-vntb-howto.rst ++++ b/Documentation/PCI/endpoint/pci-vntb-howto.rst +@@ -52,14 +52,14 @@ pci-epf-vntb device, the following commands can be used:: + # cd /sys/kernel/config/pci_ep/ + # mkdir functions/pci_epf_vntb/func1 + +-The "mkdir func1" above creates the pci-epf-ntb function device that will ++The "mkdir func1" above creates the pci-epf-vntb function device that will + be probed by pci_epf_vntb driver. + + The PCI endpoint framework populates the directory with the following + configurable fields:: + +- # ls functions/pci_epf_ntb/func1 +- baseclass_code deviceid msi_interrupts pci-epf-ntb.0 ++ # ls functions/pci_epf_vntb/func1 ++ baseclass_code deviceid msi_interrupts pci-epf-vntb.0 + progif_code secondary subsys_id vendorid + cache_line_size interrupt_pin msix_interrupts primary + revid subclass_code subsys_vendor_id +@@ -106,13 +106,13 @@ A sample configuration for virtual NTB driver for virtual PCI bus:: + # echo 0x080A > functions/pci_epf_vntb/func1/pci_epf_vntb.0/vntb_pid + # echo 0x10 > functions/pci_epf_vntb/func1/pci_epf_vntb.0/vbus_number + +-Binding pci-epf-ntb Device to EP Controller ++Binding pci-epf-vntb Device to EP Controller + -------------------------------------------- + + NTB function device should be attached to PCI endpoint controllers + connected to the host. + +- # ln -s controllers/5f010000.pcie_ep functions/pci-epf-ntb/func1/primary ++ # ln -s controllers/5f010000.pcie_ep functions/pci_epf_vntb/func1/primary + + Once the above step is completed, the PCI endpoint controllers are ready to + establish a link with the host. +@@ -134,7 +134,7 @@ lspci Output at Host side + ------------------------- + + Note that the devices listed here correspond to the values populated in +-"Creating pci-epf-ntb Device" section above:: ++"Creating pci-epf-vntb Device" section above:: + + # lspci + 00:00.0 PCI bridge: Freescale Semiconductor Inc Device 0000 (rev 01) +@@ -147,7 +147,7 @@ lspci Output at EP Side / Virtual PCI bus + ----------------------------------------- + + Note that the devices listed here correspond to the values populated in +-"Creating pci-epf-ntb Device" section above:: ++"Creating pci-epf-vntb Device" section above:: + + # lspci + 10:00.0 Unassigned class [ffff]: Dawicontrol Computersysteme GmbH Device 1234 (rev ff) +-- +2.51.0 + diff --git a/queue-6.1/drivers-iio-mpu3050-use-dev_err_probe-for-regulator-.patch b/queue-6.1/drivers-iio-mpu3050-use-dev_err_probe-for-regulator-.patch new file mode 100644 index 0000000000..4979dfdeac --- /dev/null +++ b/queue-6.1/drivers-iio-mpu3050-use-dev_err_probe-for-regulator-.patch @@ -0,0 +1,42 @@ +From fd680312c4bab7e7d0ffc1f248ac22878213df6d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 17:34:25 +0200 +Subject: drivers: iio: mpu3050: use dev_err_probe for regulator request + +From: Svyatoslav Ryhel + +[ Upstream commit b010880b9936da14f8035585ab57577aa05be23a ] + +Regulator requesting may result in deferred probing error which will +abort driver probing. To avoid this just use dev_err_probe which handles +deferred probing. + +Fixes: 3904b28efb2c ("iio: gyro: Add driver for the MPU-3050 gyroscope") +Signed-off-by: Svyatoslav Ryhel +Reviewed-by: Andy Shevchenko +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/gyro/mpu3050-core.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/iio/gyro/mpu3050-core.c b/drivers/iio/gyro/mpu3050-core.c +index 6a6d84a3deda6..b830ca6bea078 100644 +--- a/drivers/iio/gyro/mpu3050-core.c ++++ b/drivers/iio/gyro/mpu3050-core.c +@@ -1172,10 +1172,8 @@ int mpu3050_common_probe(struct device *dev, + mpu3050->regs[1].supply = mpu3050_reg_vlogic; + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(mpu3050->regs), + mpu3050->regs); +- if (ret) { +- dev_err(dev, "Cannot get regulators\n"); +- return ret; +- } ++ if (ret) ++ return dev_err_probe(dev, ret, "Cannot get regulators\n"); + + ret = mpu3050_power_up(mpu3050); + if (ret) +-- +2.51.0 + diff --git a/queue-6.1/drm-amdgpu-use-explicit-vcn-instance-0-in-sr-iov-ini.patch b/queue-6.1/drm-amdgpu-use-explicit-vcn-instance-0-in-sr-iov-ini.patch new file mode 100644 index 0000000000..885338fcc5 --- /dev/null +++ b/queue-6.1/drm-amdgpu-use-explicit-vcn-instance-0-in-sr-iov-ini.patch @@ -0,0 +1,179 @@ +From 988a6d5a6e9cffabc2c803c56849303537c33bea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 15:25:25 +0530 +Subject: drm/amdgpu: Use explicit VCN instance 0 in SR-IOV init +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Srinivasan Shanmugam + +[ Upstream commit af26fa751c2eef66916acbf0d3c3e9159da56186 ] + +vcn_v2_0_start_sriov() declares a local variable "i" initialized to zero +and uses it only as the instance index in SOC15_REG_OFFSET(UVD, i, ...). +The value is never changed and all other fields are taken from +adev->vcn.inst[0], so this path only ever programs VCN instance 0. + +This triggered a Smatch: +warn: iterator 'i' not incremented + +Replace the dummy iterator with an explicit instance index of 0 in +SOC15_REG_OFFSET() calls. + +Fixes: dd26858a9cd8 ("drm/amdgpu: implement initialization part on VCN2.0 for SRIOV") +Reported by: Dan Carpenter +Cc: darlington Opara +Cc: Jinage Zhao +Cc: Monk Liu +Cc: Emily Deng +Cc: Christian König +Cc: Alex Deucher +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Emily Deng +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c | 45 ++++++++++++++------------- + 1 file changed, 23 insertions(+), 22 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c +index 08871bad9994a..08bdacf8690bc 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c +@@ -1861,7 +1861,8 @@ static int vcn_v2_0_start_sriov(struct amdgpu_device *adev) + struct mmsch_v2_0_cmd_end end = { {0} }; + struct mmsch_v2_0_init_header *header; + uint32_t *init_table = adev->virt.mm_table.cpu_addr; +- uint8_t i = 0; ++ ++ /* This path only programs VCN instance 0. */ + + header = (struct mmsch_v2_0_init_header *)init_table; + direct_wt.cmd_header.command_type = MMSCH_COMMAND__DIRECT_REG_WRITE; +@@ -1880,93 +1881,93 @@ static int vcn_v2_0_start_sriov(struct amdgpu_device *adev) + size = AMDGPU_GPU_PAGE_ALIGN(adev->vcn.fw->size + 4); + + MMSCH_V2_0_INSERT_DIRECT_RD_MOD_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_STATUS), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_STATUS), + 0xFFFFFFFF, 0x00000004); + + /* mc resume*/ + if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW), + adev->firmware.ucode[AMDGPU_UCODE_ID_VCN].tmr_mc_addr_lo); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE_64BIT_BAR_HIGH), + adev->firmware.ucode[AMDGPU_UCODE_ID_VCN].tmr_mc_addr_hi); + offset = 0; + } else { + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW), + lower_32_bits(adev->vcn.inst->gpu_addr)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE_64BIT_BAR_HIGH), + upper_32_bits(adev->vcn.inst->gpu_addr)); + offset = size; + } + + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_OFFSET0), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_OFFSET0), + 0); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_SIZE0), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_SIZE0), + size); + + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE1_64BIT_BAR_LOW), + lower_32_bits(adev->vcn.inst->gpu_addr + offset)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE1_64BIT_BAR_HIGH), + upper_32_bits(adev->vcn.inst->gpu_addr + offset)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_OFFSET1), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_OFFSET1), + 0); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_SIZE1), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_SIZE1), + AMDGPU_VCN_STACK_SIZE); + + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE2_64BIT_BAR_LOW), + lower_32_bits(adev->vcn.inst->gpu_addr + offset + + AMDGPU_VCN_STACK_SIZE)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE2_64BIT_BAR_HIGH), + upper_32_bits(adev->vcn.inst->gpu_addr + offset + + AMDGPU_VCN_STACK_SIZE)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_OFFSET2), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_OFFSET2), + 0); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_SIZE2), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_SIZE2), + AMDGPU_VCN_CONTEXT_SIZE); + + for (r = 0; r < adev->vcn.num_enc_rings; ++r) { + ring = &adev->vcn.inst->ring_enc[r]; + ring->wptr = 0; + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_RB_BASE_LO), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_RB_BASE_LO), + lower_32_bits(ring->gpu_addr)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_RB_BASE_HI), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_RB_BASE_HI), + upper_32_bits(ring->gpu_addr)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_RB_SIZE), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_RB_SIZE), + ring->ring_size / 4); + } + + ring = &adev->vcn.inst->ring_dec; + ring->wptr = 0; + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_RBC_RB_64BIT_BAR_LOW), + lower_32_bits(ring->gpu_addr)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH), + upper_32_bits(ring->gpu_addr)); + /* force RBC into idle state */ +@@ -1977,7 +1978,7 @@ static int vcn_v2_0_start_sriov(struct amdgpu_device *adev) + tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1); + tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_RBC_RB_CNTL), tmp); ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_RBC_RB_CNTL), tmp); + + /* add end packet */ + tmp = sizeof(struct mmsch_v2_0_cmd_end); +-- +2.51.0 + diff --git a/queue-6.1/drm-msm-dpu-fix-cmd-panels-on-dpu-1.x-3.x.patch b/queue-6.1/drm-msm-dpu-fix-cmd-panels-on-dpu-1.x-3.x.patch new file mode 100644 index 0000000000..05ef718a24 --- /dev/null +++ b/queue-6.1/drm-msm-dpu-fix-cmd-panels-on-dpu-1.x-3.x.patch @@ -0,0 +1,48 @@ +From f13168f890bd9262dcef2bced3de84053cbc5ade Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 28 Dec 2025 06:02:28 +0200 +Subject: drm/msm/dpu: fix CMD panels on DPU 1.x - 3.x + +From: Dmitry Baryshkov + +[ Upstream commit 59ca3d11f5311d9167015fe4f431701614ae0048 ] + +DPU units before 4.x don't have a separate CTL_START IRQ to mark the +begin of the data transfer. In such a case, wait for the frame transfer +to complete rather than trying to wait for the CTL_START interrupt (and +obviously hitting the timeout). + +Fixes: 050770cbbd26 ("drm/msm/dpu: Fix timeout issues on command mode panels") +Reported-by: Alexey Minnekhanov +Closes: https://lore.kernel.org/r/8e1d33ff-d902-4ae9-9162-e00d17a5e6d1@postmarketos.org +Patchwork: https://patchwork.freedesktop.org/patch/696490/ +Link: https://lore.kernel.org/r/20251228-mdp5-drop-dpu3-v4-2-7497c3d39179@oss.qualcomm.com +Tested-by: Alexey Minnekhanov +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c +index e05c3ccf07f8e..7581e418418f1 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c +@@ -685,10 +685,11 @@ static int dpu_encoder_phys_cmd_wait_for_commit_done( + if (!dpu_encoder_phys_cmd_is_master(phys_enc)) + return 0; + +- if (phys_enc->hw_ctl->ops.is_started(phys_enc->hw_ctl)) +- return dpu_encoder_phys_cmd_wait_for_tx_complete(phys_enc); ++ if (phys_enc->irq[INTR_IDX_CTL_START] && ++ !phys_enc->hw_ctl->ops.is_started(phys_enc->hw_ctl)) ++ return _dpu_encoder_phys_cmd_wait_for_ctl_start(phys_enc); + +- return _dpu_encoder_phys_cmd_wait_for_ctl_start(phys_enc); ++ return dpu_encoder_phys_cmd_wait_for_tx_complete(phys_enc); + } + + static int dpu_encoder_phys_cmd_wait_for_vblank( +-- +2.51.0 + diff --git a/queue-6.1/edac-altera-remove-irqf_oneshot.patch b/queue-6.1/edac-altera-remove-irqf_oneshot.patch new file mode 100644 index 0000000000..a77829594f --- /dev/null +++ b/queue-6.1/edac-altera-remove-irqf_oneshot.patch @@ -0,0 +1,74 @@ +From 216821cb3238d83673ef9896fb49b93f22cd97a6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:55:30 +0100 +Subject: EDAC/altera: Remove IRQF_ONESHOT + +From: Sebastian Andrzej Siewior + +[ Upstream commit 5c858d6c66304b4c7579582ec5235f02d43578ea ] + +Passing IRQF_ONESHOT ensures that the interrupt source is masked until +the secondary (threaded) handler is done. If only a primary handler is +used then the flag makes no sense because the interrupt can not fire +(again) while its handler is running. + +The flag also prevents force-threading of the primary handler and the +irq-core will warn about this. + +Remove IRQF_ONESHOT from irqflags. + +Fixes: a29d64a45eed1 ("EDAC, altera: Add IRQ Flags to disable IRQ while handling") +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260128095540.863589-11-bigeasy@linutronix.de +Signed-off-by: Sasha Levin +--- + drivers/edac/altera_edac.c | 11 ++++------- + 1 file changed, 4 insertions(+), 7 deletions(-) + +diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c +index 368ede6a4f596..09b6871151676 100644 +--- a/drivers/edac/altera_edac.c ++++ b/drivers/edac/altera_edac.c +@@ -1573,8 +1573,7 @@ static int altr_portb_setup(struct altr_edac_device_dev *device) + goto err_release_group_1; + } + rc = devm_request_irq(&altdev->ddev, altdev->sb_irq, +- prv->ecc_irq_handler, +- IRQF_ONESHOT | IRQF_TRIGGER_HIGH, ++ prv->ecc_irq_handler, IRQF_TRIGGER_HIGH, + ecc_name, altdev); + if (rc) { + edac_printk(KERN_ERR, EDAC_DEVICE, "PortB SBERR IRQ error\n"); +@@ -1597,8 +1596,7 @@ static int altr_portb_setup(struct altr_edac_device_dev *device) + goto err_release_group_1; + } + rc = devm_request_irq(&altdev->ddev, altdev->db_irq, +- prv->ecc_irq_handler, +- IRQF_ONESHOT | IRQF_TRIGGER_HIGH, ++ prv->ecc_irq_handler, IRQF_TRIGGER_HIGH, + ecc_name, altdev); + if (rc) { + edac_printk(KERN_ERR, EDAC_DEVICE, "PortB DBERR IRQ error\n"); +@@ -1981,8 +1979,7 @@ static int altr_edac_a10_device_add(struct altr_arria10_edac *edac, + goto err_release_group1; + } + rc = devm_request_irq(edac->dev, altdev->sb_irq, prv->ecc_irq_handler, +- IRQF_ONESHOT | IRQF_TRIGGER_HIGH, +- ecc_name, altdev); ++ IRQF_TRIGGER_HIGH, ecc_name, altdev); + if (rc) { + edac_printk(KERN_ERR, EDAC_DEVICE, "No SBERR IRQ resource\n"); + goto err_release_group1; +@@ -2004,7 +2001,7 @@ static int altr_edac_a10_device_add(struct altr_arria10_edac *edac, + goto err_release_group1; + } + rc = devm_request_irq(edac->dev, altdev->db_irq, prv->ecc_irq_handler, +- IRQF_ONESHOT | IRQF_TRIGGER_HIGH, ++ IRQF_TRIGGER_HIGH, + ecc_name, altdev); + if (rc) { + edac_printk(KERN_ERR, EDAC_DEVICE, "No DBERR IRQ resource\n"); +-- +2.51.0 + diff --git a/queue-6.1/edac-i5000-fix-snprintf-size-calculation-in-calculat.patch b/queue-6.1/edac-i5000-fix-snprintf-size-calculation-in-calculat.patch new file mode 100644 index 0000000000..92867cfeb7 --- /dev/null +++ b/queue-6.1/edac-i5000-fix-snprintf-size-calculation-in-calculat.patch @@ -0,0 +1,40 @@ +From 815df864a7c5787213c0f0b3aef480f9567f992a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 17:36:59 +0300 +Subject: EDAC/i5000: Fix snprintf() size calculation in calculate_dimm_size() + +From: Dan Carpenter + +[ Upstream commit 7b5c7e83ac405ff9ecbdd92b37a477f4288f8814 ] + +The snprintf() can't really overflow because we're writing a max of 42 +bytes to a PAGE_SIZE buffer. But the limit calculation doesn't take +the first 11 bytes that we wrote into consideration so the limit is +not correct. Just fix it for correctness even though it doesn't +affect runtime. + +Fixes: 64e1fdaf55d6 ("i5000_edac: Fix the logic that retrieves memory information") +Signed-off-by: Dan Carpenter +Signed-off-by: Tony Luck +Reviewed-by: Qiuxu Zhuo +Link: https://patch.msgid.link/07cd652c51e77aad5a8350e1a7cd9407e5bbe373.1765290801.git.dan.carpenter@linaro.org +Signed-off-by: Sasha Levin +--- + drivers/edac/i5000_edac.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c +index ba46057d42207..3d82ab8eb2c71 100644 +--- a/drivers/edac/i5000_edac.c ++++ b/drivers/edac/i5000_edac.c +@@ -1111,6 +1111,7 @@ static void calculate_dimm_size(struct i5000_pvt *pvt) + + n = snprintf(p, space, " "); + p += n; ++ space -= n; + for (branch = 0; branch < MAX_BRANCHES; branch++) { + n = snprintf(p, space, " branch %d | ", branch); + p += n; +-- +2.51.0 + diff --git a/queue-6.1/edac-i5400-fix-snprintf-limit-calculation-in-calcula.patch b/queue-6.1/edac-i5400-fix-snprintf-limit-calculation-in-calcula.patch new file mode 100644 index 0000000000..c58742f250 --- /dev/null +++ b/queue-6.1/edac-i5400-fix-snprintf-limit-calculation-in-calcula.patch @@ -0,0 +1,49 @@ +From 4ddaceb4af7d8e505a2e6769eab8f35f168bcbef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 17:37:04 +0300 +Subject: EDAC/i5400: Fix snprintf() limit calculation in calculate_dimm_size() + +From: Dan Carpenter + +[ Upstream commit 72f12683611344853ab030fe7d19b23970ed2bd8 ] + +The snprintf() can't really overflow because we're writing a max of 42 +bytes to a PAGE_SIZE buffer. But my static checker complains because +the limit calculation doesn't take the first 11 space characters that +we wrote into the buffer into consideration. Fix this for the sake of +correctness even though it doesn't affect runtime. + +Also delete an earlier "space -= n;" which was not used. + +Fixes: 68d086f89b80 ("i5400_edac: improve debug messages to better represent the filled memory") +Signed-off-by: Dan Carpenter +Signed-off-by: Tony Luck +Reviewed-by: Qiuxu Zhuo +Link: https://patch.msgid.link/ccd06b91748e7ed8e33eeb2ff1e7b98700879304.1765290801.git.dan.carpenter@linaro.org +Signed-off-by: Sasha Levin +--- + drivers/edac/i5400_edac.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/edac/i5400_edac.c b/drivers/edac/i5400_edac.c +index f76624ee82ef7..5b1188f1b5705 100644 +--- a/drivers/edac/i5400_edac.c ++++ b/drivers/edac/i5400_edac.c +@@ -1024,13 +1024,13 @@ static void calculate_dimm_size(struct i5400_pvt *pvt) + space -= n; + } + +- space -= n; + edac_dbg(2, "%s\n", mem_buffer); + p = mem_buffer; + space = PAGE_SIZE; + + n = snprintf(p, space, " "); + p += n; ++ space -= n; + for (branch = 0; branch < MAX_BRANCHES; branch++) { + n = snprintf(p, space, " branch %d | ", branch); + p += n; +-- +2.51.0 + diff --git a/queue-6.1/fat-avoid-parent-link-count-underflow-in-rmdir.patch b/queue-6.1/fat-avoid-parent-link-count-underflow-in-rmdir.patch new file mode 100644 index 0000000000..5d2c0970c2 --- /dev/null +++ b/queue-6.1/fat-avoid-parent-link-count-underflow-in-rmdir.patch @@ -0,0 +1,74 @@ +From 88875564c6fe0b10884c8e21dcba62d57b9bfbc4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 1 Jan 2026 19:11:48 +0800 +Subject: fat: avoid parent link count underflow in rmdir + +From: Zhiyu Zhang + +[ Upstream commit 8cafcb881364af5ef3a8b9fed4db254054033d8a ] + +Corrupted FAT images can leave a directory inode with an incorrect +i_nlink (e.g. 2 even though subdirectories exist). rmdir then +unconditionally calls drop_nlink(dir) and can drive i_nlink to 0, +triggering the WARN_ON in drop_nlink(). + +Add a sanity check in vfat_rmdir() and msdos_rmdir(): only drop the +parent link count when it is at least 3, otherwise report a filesystem +error. + +Link: https://lkml.kernel.org/r/20260101111148.1437-1-zhiyuzhang999@gmail.com +Fixes: 9a53c3a783c2 ("[PATCH] r/o bind mounts: unlink: monitor i_nlink") +Signed-off-by: Zhiyu Zhang +Reported-by: Zhiyu Zhang +Closes: https://lore.kernel.org/linux-fsdevel/aVN06OKsKxZe6-Kv@casper.infradead.org/T/#t +Tested-by: Zhiyu Zhang +Acked-by: OGAWA Hirofumi +Cc: Al Viro +Cc: Christian Brauner +Cc: Jan Kara +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/fat/namei_msdos.c | 7 ++++++- + fs/fat/namei_vfat.c | 7 ++++++- + 2 files changed, 12 insertions(+), 2 deletions(-) + +diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c +index efba301d68aec..fba3a07d39478 100644 +--- a/fs/fat/namei_msdos.c ++++ b/fs/fat/namei_msdos.c +@@ -325,7 +325,12 @@ static int msdos_rmdir(struct inode *dir, struct dentry *dentry) + err = fat_remove_entries(dir, &sinfo); /* and releases bh */ + if (err) + goto out; +- drop_nlink(dir); ++ if (dir->i_nlink >= 3) ++ drop_nlink(dir); ++ else { ++ fat_fs_error(sb, "parent dir link count too low (%u)", ++ dir->i_nlink); ++ } + + clear_nlink(inode); + fat_truncate_time(inode, NULL, S_CTIME); +diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c +index 93fa8ddcf4145..3a9a849bc7885 100644 +--- a/fs/fat/namei_vfat.c ++++ b/fs/fat/namei_vfat.c +@@ -806,7 +806,12 @@ static int vfat_rmdir(struct inode *dir, struct dentry *dentry) + err = fat_remove_entries(dir, &sinfo); /* and releases bh */ + if (err) + goto out; +- drop_nlink(dir); ++ if (dir->i_nlink >= 3) ++ drop_nlink(dir); ++ else { ++ fat_fs_error(sb, "parent dir link count too low (%u)", ++ dir->i_nlink); ++ } + + clear_nlink(inode); + fat_truncate_time(inode, NULL, S_ATIME|S_MTIME); +-- +2.51.0 + diff --git a/queue-6.1/fbdev-au1200fb-fix-a-memory-leak-in-au1200fb_drv_pro.patch b/queue-6.1/fbdev-au1200fb-fix-a-memory-leak-in-au1200fb_drv_pro.patch new file mode 100644 index 0000000000..db9387f652 --- /dev/null +++ b/queue-6.1/fbdev-au1200fb-fix-a-memory-leak-in-au1200fb_drv_pro.patch @@ -0,0 +1,43 @@ +From 218a6a6408902758b30a3e5a1c80e85540f9ef68 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 20:14:58 +0800 +Subject: fbdev: au1200fb: Fix a memory leak in au1200fb_drv_probe() + +From: Felix Gu + +[ Upstream commit ce4e25198a6aaaaf36248edf8daf3d744ec8e309 ] + +In au1200fb_drv_probe(), when platform_get_irq fails(), it directly +returns from the function with an error code, which causes a memory +leak. + +Replace it with a goto label to ensure proper cleanup. + +Fixes: 4e88761f5f8c ("fbdev: au1200fb: Fix missing IRQ check in au1200fb_drv_probe") +Signed-off-by: Felix Gu +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/au1200fb.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/video/fbdev/au1200fb.c b/drivers/video/fbdev/au1200fb.c +index fd3ff398d234a..f55f3380f17e5 100644 +--- a/drivers/video/fbdev/au1200fb.c ++++ b/drivers/video/fbdev/au1200fb.c +@@ -1732,8 +1732,10 @@ static int au1200fb_drv_probe(struct platform_device *dev) + + /* Now hook interrupt too */ + irq = platform_get_irq(dev, 0); +- if (irq < 0) +- return irq; ++ if (irq < 0) { ++ ret = irq; ++ goto failed; ++ } + + ret = request_irq(irq, au1200fb_handle_irq, + IRQF_SHARED, "lcd", (void *)dev); +-- +2.51.0 + diff --git a/queue-6.1/fbdev-of_display_timing-fix-device-node-reference-le.patch b/queue-6.1/fbdev-of_display_timing-fix-device-node-reference-le.patch new file mode 100644 index 0000000000..95f0dba183 --- /dev/null +++ b/queue-6.1/fbdev-of_display_timing-fix-device-node-reference-le.patch @@ -0,0 +1,56 @@ +From 9d7d9d4aaac187f5e607e10813f6eebe16af4699 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Jan 2026 20:48:33 +0800 +Subject: fbdev: of_display_timing: Fix device node reference leak in + of_get_display_timings() + +From: Felix Gu + +[ Upstream commit c39ee2d264f98efa14aa46c9942114cb03c7baa6 ] + +Use for_each_child_of_node_scoped instead of for_each_child_of_node +to ensure automatic of_node_put on early exit paths, preventing +device node reference leak. + +Fixes: cc3f414cf2e4 ("video: add of helper for display timings/videomode") +Signed-off-by: Felix Gu +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/of_display_timing.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/video/of_display_timing.c b/drivers/video/of_display_timing.c +index bebd371c6b93e..a4cd446ac5a59 100644 +--- a/drivers/video/of_display_timing.c ++++ b/drivers/video/of_display_timing.c +@@ -195,7 +195,7 @@ struct display_timings *of_get_display_timings(const struct device_node *np) + disp->num_timings = 0; + disp->native_mode = 0; + +- for_each_child_of_node(timings_np, entry) { ++ for_each_child_of_node_scoped(timings_np, child) { + struct display_timing *dt; + int r; + +@@ -206,7 +206,7 @@ struct display_timings *of_get_display_timings(const struct device_node *np) + goto timingfail; + } + +- r = of_parse_display_timing(entry, dt); ++ r = of_parse_display_timing(child, dt); + if (r) { + /* + * to not encourage wrong devicetrees, fail in case of +@@ -218,7 +218,7 @@ struct display_timings *of_get_display_timings(const struct device_node *np) + goto timingfail; + } + +- if (native_mode == entry) ++ if (native_mode == child) + disp->native_mode = disp->num_timings; + + disp->timings[disp->num_timings] = dt; +-- +2.51.0 + diff --git a/queue-6.1/fs-add-linux-init_task.h-for-init_fs.patch b/queue-6.1/fs-add-linux-init_task.h-for-init_fs.patch new file mode 100644 index 0000000000..24ceb5bfc5 --- /dev/null +++ b/queue-6.1/fs-add-linux-init_task.h-for-init_fs.patch @@ -0,0 +1,40 @@ +From 190af29a1dcab143f2da3204830f7333fb25cd91 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 11:58:56 +0000 +Subject: fs: add for 'init_fs' + +From: Ben Dooks + +[ Upstream commit 589cff4975afe1a4eaaa1d961652f50b1628d78d ] + +The init_fs symbol is defined in but was +not included in fs/fs_struct.c so fix by adding the include. + +Fixes the following sparse warning: +fs/fs_struct.c:150:18: warning: symbol 'init_fs' was not declared. Should it be static? + +Fixes: 3e93cd671813e ("Take fs_struct handling to new file") +Signed-off-by: Ben Dooks +Link: https://patch.msgid.link/20260108115856.238027-1-ben.dooks@codethink.co.uk +Reviewed-by: Jan Kara +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/fs_struct.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/fs_struct.c b/fs/fs_struct.c +index 04b3f5b9c6295..0b0f88259cc60 100644 +--- a/fs/fs_struct.c ++++ b/fs/fs_struct.c +@@ -6,6 +6,7 @@ + #include + #include + #include ++#include + #include "internal.h" + + /* +-- +2.51.0 + diff --git a/queue-6.1/fs-nfs-fix-readdir-slow-start-regression.patch b/queue-6.1/fs-nfs-fix-readdir-slow-start-regression.patch new file mode 100644 index 0000000000..fde58fbced --- /dev/null +++ b/queue-6.1/fs-nfs-fix-readdir-slow-start-regression.patch @@ -0,0 +1,54 @@ +From 6705e66422e62bacb13840df991e3dbfbd091fef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 27 Dec 2025 12:46:29 +0200 +Subject: fs/nfs: Fix readdir slow-start regression + +From: Sagi Grimberg + +[ Upstream commit 42e7c876b182da65723700f6bc507a8aecb10d3b ] + +Commit 580f236737d1 ("NFS: Adjust the amount of readahead +performed by NFS readdir") reduces the amount of readahead names +caching done by the client. + +The downside of this approach is READDIR now may suffer from +a slow-start issue, where initially it will fetch names that fit +in a single page, then in 2, 4, 8 until the maximum supported +transfer size (usually 1M). + +This patch tries to take a balanced approach between mitigating +the slow-start issue still maintaining some efficiency gains. + +Fixes: 580f236737d1 ("NFS: Adjust the amount of readahead performed by NFS readdir") +Signed-off-by: Sagi Grimberg +Signed-off-by: Anna Schumaker +Signed-off-by: Sasha Levin +--- + fs/nfs/dir.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c +index a89c0528c858e..024b1848c7971 100644 +--- a/fs/nfs/dir.c ++++ b/fs/nfs/dir.c +@@ -70,7 +70,7 @@ const struct address_space_operations nfs_dir_aops = { + .free_folio = nfs_readdir_free_folio, + }; + +-#define NFS_INIT_DTSIZE PAGE_SIZE ++#define NFS_INIT_DTSIZE SZ_64K + + static struct nfs_open_dir_context * + alloc_nfs_open_dir_context(struct inode *dir) +@@ -81,7 +81,7 @@ alloc_nfs_open_dir_context(struct inode *dir) + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL_ACCOUNT); + if (ctx != NULL) { + ctx->attr_gencount = nfsi->attr_gencount; +- ctx->dtsize = NFS_INIT_DTSIZE; ++ ctx->dtsize = min(NFS_SERVER(dir)->dtsize, NFS_INIT_DTSIZE); + spin_lock(&dir->i_lock); + if (list_empty(&nfsi->open_files) && + (nfsi->cache_validity & NFS_INO_DATA_INVAL_DEFER)) +-- +2.51.0 + diff --git a/queue-6.1/gfs2-add-metapath_dibh-helper.patch b/queue-6.1/gfs2-add-metapath_dibh-helper.patch new file mode 100644 index 0000000000..cc85e7845f --- /dev/null +++ b/queue-6.1/gfs2-add-metapath_dibh-helper.patch @@ -0,0 +1,48 @@ +From d706e4b69070a9c7d2cb022a366909e1056a587d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Oct 2023 01:32:15 +0200 +Subject: gfs2: Add metapath_dibh helper + +From: Andreas Gruenbacher + +[ Upstream commit 92099f0c92270c8c7a79e6bc6e0312ad248ea331 ] + +Add a metapath_dibh() helper for extracting the inode's buffer head from +a metapath. + +Signed-off-by: Andreas Gruenbacher +Stable-dep-of: faddeb848305 ("gfs2: Fix use-after-free in iomap inline data write path") +Signed-off-by: Sasha Levin +--- + fs/gfs2/bmap.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c +index 9ad11e5bf14c3..9f0dec17fa431 100644 +--- a/fs/gfs2/bmap.c ++++ b/fs/gfs2/bmap.c +@@ -317,6 +317,12 @@ static void gfs2_metapath_ra(struct gfs2_glock *gl, __be64 *start, __be64 *end) + } + } + ++static inline struct buffer_head * ++metapath_dibh(struct metapath *mp) ++{ ++ return mp->mp_bh[0]; ++} ++ + static int __fillup_metapath(struct gfs2_inode *ip, struct metapath *mp, + unsigned int x, unsigned int h) + { +@@ -660,7 +666,7 @@ static int __gfs2_iomap_alloc(struct inode *inode, struct iomap *iomap, + { + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); +- struct buffer_head *dibh = mp->mp_bh[0]; ++ struct buffer_head *dibh = metapath_dibh(mp); + u64 bn; + unsigned n, i, blks, alloced = 0, iblks = 0, branch_start = 0; + size_t dblks = iomap->length >> inode->i_blkbits; +-- +2.51.0 + diff --git a/queue-6.1/gfs2-fix-use-after-free-in-iomap-inline-data-write-p.patch b/queue-6.1/gfs2-fix-use-after-free-in-iomap-inline-data-write-p.patch new file mode 100644 index 0000000000..3366e8fcb2 --- /dev/null +++ b/queue-6.1/gfs2-fix-use-after-free-in-iomap-inline-data-write-p.patch @@ -0,0 +1,84 @@ +From 1998acd4eb2548000a7b74eecb4a272e8dbc1ce7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 14:51:34 +0530 +Subject: gfs2: Fix use-after-free in iomap inline data write path + +From: Deepanshu Kartikey + +[ Upstream commit faddeb848305e79db89ee0479bb0e33380656321 ] + +The inline data buffer head (dibh) is being released prematurely in +gfs2_iomap_begin() via release_metapath() while iomap->inline_data +still points to dibh->b_data. This causes a use-after-free when +iomap_write_end_inline() later attempts to write to the inline data +area. + +The bug sequence: +1. gfs2_iomap_begin() calls gfs2_meta_inode_buffer() to read inode + metadata into dibh +2. Sets iomap->inline_data = dibh->b_data + sizeof(struct gfs2_dinode) +3. Calls release_metapath() which calls brelse(dibh), dropping refcount + to 0 +4. kswapd reclaims the page (~39ms later in the syzbot report) +5. iomap_write_end_inline() tries to memcpy() to iomap->inline_data +6. KASAN detects use-after-free write to freed memory + +Fix by storing dibh in iomap->private and incrementing its refcount +with get_bh() in gfs2_iomap_begin(). The buffer is then properly +released in gfs2_iomap_end() after the inline write completes, +ensuring the page stays alive for the entire iomap operation. + +Note: A C reproducer is not available for this issue. The fix is based +on analysis of the KASAN report and code review showing the buffer head +is freed before use. + +[agruenba: Take buffer head reference in gfs2_iomap_begin() to avoid +leaks in gfs2_iomap_get() and gfs2_iomap_alloc().] + +Reported-by: syzbot+ea1cd4aa4d1e98458a55@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=ea1cd4aa4d1e98458a55 +Fixes: d0a22a4b03b8 ("gfs2: Fix iomap write page reclaim deadlock") +Signed-off-by: Deepanshu Kartikey +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Sasha Levin +--- + fs/gfs2/bmap.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c +index 9f0dec17fa431..8a17c3bad4ca0 100644 +--- a/fs/gfs2/bmap.c ++++ b/fs/gfs2/bmap.c +@@ -1112,10 +1112,18 @@ static int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length, + goto out_unlock; + break; + default: +- goto out_unlock; ++ goto out; + } + + ret = gfs2_iomap_begin_write(inode, pos, length, flags, iomap, &mp); ++ if (ret) ++ goto out_unlock; ++ ++out: ++ if (iomap->type == IOMAP_INLINE) { ++ iomap->private = metapath_dibh(&mp); ++ get_bh(iomap->private); ++ } + + out_unlock: + release_metapath(&mp); +@@ -1129,6 +1137,9 @@ static int gfs2_iomap_end(struct inode *inode, loff_t pos, loff_t length, + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); + ++ if (iomap->private) ++ brelse(iomap->private); ++ + switch (flags & (IOMAP_WRITE | IOMAP_ZERO)) { + case IOMAP_WRITE: + if (flags & IOMAP_DIRECT) +-- +2.51.0 + diff --git a/queue-6.1/hfsplus-return-error-when-node-already-exists-in-hfs.patch b/queue-6.1/hfsplus-return-error-when-node-already-exists-in-hfs.patch new file mode 100644 index 0000000000..bd36878815 --- /dev/null +++ b/queue-6.1/hfsplus-return-error-when-node-already-exists-in-hfs.patch @@ -0,0 +1,58 @@ +From f4deb1d2e54f8aea747f10538c0c92ed9c1267e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Dec 2025 02:19:38 +0530 +Subject: hfsplus: return error when node already exists in hfs_bnode_create + +From: Shardul Bankar + +[ Upstream commit d8a73cc46c8462a969a7516131feb3096f4c49d3 ] + +When hfs_bnode_create() finds that a node is already hashed (which should +not happen in normal operation), it currently returns the existing node +without incrementing its reference count. This causes a reference count +inconsistency that leads to a kernel panic when the node is later freed +in hfs_bnode_put(): + + kernel BUG at fs/hfsplus/bnode.c:676! + BUG_ON(!atomic_read(&node->refcnt)) + +This scenario can occur when hfs_bmap_alloc() attempts to allocate a node +that is already in use (e.g., when node 0's bitmap bit is incorrectly +unset), or due to filesystem corruption. + +Returning an existing node from a create path is not normal operation. + +Fix this by returning ERR_PTR(-EEXIST) instead of the node when it's +already hashed. This properly signals the error condition to callers, +which already check for IS_ERR() return values. + +Reported-by: syzbot+1c8ff72d0cd8a50dfeaa@syzkaller.appspotmail.com +Link: https://syzkaller.appspot.com/bug?extid=1c8ff72d0cd8a50dfeaa +Link: https://lore.kernel.org/all/784415834694f39902088fa8946850fc1779a318.camel@ibm.com/ +Fixes: 634725a92938 ("[PATCH] hfs: cleanup HFS+ prints") +Signed-off-by: Shardul Bankar +Reviewed-by: Viacheslav Dubeyko +Signed-off-by: Viacheslav Dubeyko +Link: https://lore.kernel.org/r/20251229204938.1907089-1-shardul.b@mpiricsoftware.com +Signed-off-by: Viacheslav Dubeyko +Signed-off-by: Sasha Levin +--- + fs/hfsplus/bnode.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/hfsplus/bnode.c b/fs/hfsplus/bnode.c +index c0089849be50e..fb437598e2625 100644 +--- a/fs/hfsplus/bnode.c ++++ b/fs/hfsplus/bnode.c +@@ -629,7 +629,7 @@ struct hfs_bnode *hfs_bnode_create(struct hfs_btree *tree, u32 num) + if (node) { + pr_crit("new node %u already hashed?\n", num); + WARN_ON(1); +- return node; ++ return ERR_PTR(-EEXIST); + } + node = __hfs_bnode_create(tree, num); + if (!node) +-- +2.51.0 + diff --git a/queue-6.1/hid-playstation-add-missing-check-for-input_ff_creat.patch b/queue-6.1/hid-playstation-add-missing-check-for-input_ff_creat.patch new file mode 100644 index 0000000000..b00e88995b --- /dev/null +++ b/queue-6.1/hid-playstation-add-missing-check-for-input_ff_creat.patch @@ -0,0 +1,41 @@ +From 1de3aa18f92b8ce5319cee508d2e8cac487f609a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 17 Nov 2025 16:28:08 +0800 +Subject: HID: playstation: Add missing check for input_ff_create_memless + +From: Haotian Zhang + +[ Upstream commit e6807641ac94e832988655a1c0e60ccc806b76dc ] + +The ps_gamepad_create() function calls input_ff_create_memless() +without verifying its return value, which can lead to incorrect +behavior or potential crashes when FF effects are triggered. + +Add a check for the return value of input_ff_create_memless(). + +Fixes: 51151098d7ab ("HID: playstation: add DualSense classic rumble support.") +Signed-off-by: Haotian Zhang +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-playstation.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c +index 38d5171dd25b2..d6d86406f42fd 100644 +--- a/drivers/hid/hid-playstation.c ++++ b/drivers/hid/hid-playstation.c +@@ -508,7 +508,9 @@ static struct input_dev *ps_gamepad_create(struct hid_device *hdev, + #if IS_ENABLED(CONFIG_PLAYSTATION_FF) + if (play_effect) { + input_set_capability(gamepad, EV_FF, FF_RUMBLE); +- input_ff_create_memless(gamepad, NULL, play_effect); ++ ret = input_ff_create_memless(gamepad, NULL, play_effect); ++ if (ret) ++ return ERR_PTR(ret); + } + #endif + +-- +2.51.0 + diff --git a/queue-6.1/hrtimer-fix-trace-oddity.patch b/queue-6.1/hrtimer-fix-trace-oddity.patch new file mode 100644 index 0000000000..54eab05a45 --- /dev/null +++ b/queue-6.1/hrtimer-fix-trace-oddity.patch @@ -0,0 +1,43 @@ +From 67ff727ff1f93cfbe31fcc1cebf602e924569e81 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 11:38:34 +0100 +Subject: hrtimer: Fix trace oddity + +From: Thomas Gleixner + +[ Upstream commit 5d6446f409da00e5a389125ddb5ce09f5bc404c9 ] + +It turns out that __run_hrtimer() will trace like: + + -0 [032] d.h2. 20705.474563: hrtimer_cancel: hrtimer=0xff2db8f77f8226e8 + -0 [032] d.h1. 20705.474563: hrtimer_expire_entry: hrtimer=0xff2db8f77f8226e8 now=20699452001850 function=tick_nohz_handler/0x0 + +Which is a bit nonsensical, the timer doesn't get canceled on +expiration. The cause is the use of the incorrect debug helper. + +Fixes: c6a2a1770245 ("hrtimer: Add tracepoint for hrtimers") +Reported-by: Peter Zijlstra (Intel) +Signed-off-by: Thomas Gleixner +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260121143208.219595606@infradead.org +Signed-off-by: Sasha Levin +--- + kernel/time/hrtimer.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c +index 049dd5b37274b..002b29e566cb3 100644 +--- a/kernel/time/hrtimer.c ++++ b/kernel/time/hrtimer.c +@@ -1712,7 +1712,7 @@ static void __run_hrtimer(struct hrtimer_cpu_base *cpu_base, + + lockdep_assert_held(&cpu_base->lock); + +- debug_deactivate(timer); ++ debug_hrtimer_deactivate(timer); + base->running = timer; + + /* +-- +2.51.0 + diff --git a/queue-6.1/i3c-master-update-hot-join-flag-only-on-success.patch b/queue-6.1/i3c-master-update-hot-join-flag-only-on-success.patch new file mode 100644 index 0000000000..56fb387fb7 --- /dev/null +++ b/queue-6.1/i3c-master-update-hot-join-flag-only-on-success.patch @@ -0,0 +1,39 @@ +From 05eb93398c7d7cf3fea9703321a20421dda37c47 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Jan 2026 09:26:44 +0200 +Subject: i3c: master: Update hot-join flag only on success + +From: Adrian Hunter + +[ Upstream commit f0775157b9f9a28ae3eabc8d05b0bc52e8056c80 ] + +To prevent inconsistent state when an error occurs, ensure the hot-join +flag is updated only when enabling or disabling hot-join succeeds. + +Fixes: 317bacf960a48 ("i3c: master: add enable(disable) hot join in sys entry") +Signed-off-by: Adrian Hunter +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260113072702.16268-4-adrian.hunter@intel.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c +index fea1f852358c2..74138c499642e 100644 +--- a/drivers/i3c/master.c ++++ b/drivers/i3c/master.c +@@ -586,7 +586,8 @@ static int i3c_set_hotjoin(struct i3c_master_controller *master, bool enable) + else + ret = master->ops->disable_hotjoin(master); + +- master->hotjoin = enable; ++ if (!ret) ++ master->hotjoin = enable; + + i3c_bus_normaluse_unlock(&master->bus); + +-- +2.51.0 + diff --git a/queue-6.1/i3c-move-device-name-assignment-after-i3c_bus_init.patch b/queue-6.1/i3c-move-device-name-assignment-after-i3c_bus_init.patch new file mode 100644 index 0000000000..66de3ef825 --- /dev/null +++ b/queue-6.1/i3c-move-device-name-assignment-after-i3c_bus_init.patch @@ -0,0 +1,46 @@ +From a12f5c4606fca5d28670efacf401e78f69d4dfd7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 14:07:22 +0800 +Subject: i3c: Move device name assignment after i3c_bus_init + +From: Billy Tsai + +[ Upstream commit 3502cea99c7ceb331458cbd34ef6792c83144687 ] + +Move device name initialization to occur after i3c_bus_init() +so that i3cbus->id is guaranteed to be assigned before it is used. + +Fixes: 9d4f219807d5 ("i3c: fix refcount inconsistency in i3c_master_register") +Signed-off-by: Billy Tsai +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260112-upstream_i3c_fix-v1-1-cbbf2cb71809@aspeedtech.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c +index 44574474bda35..fea1f852358c2 100644 +--- a/drivers/i3c/master.c ++++ b/drivers/i3c/master.c +@@ -2764,7 +2764,6 @@ int i3c_master_register(struct i3c_master_controller *master, + INIT_LIST_HEAD(&master->boardinfo.i3c); + + device_initialize(&master->dev); +- dev_set_name(&master->dev, "i3c-%d", i3cbus->id); + + master->dev.dma_mask = parent->dma_mask; + master->dev.coherent_dma_mask = parent->coherent_dma_mask; +@@ -2774,6 +2773,8 @@ int i3c_master_register(struct i3c_master_controller *master, + if (ret) + goto err_put_dev; + ++ dev_set_name(&master->dev, "i3c-%d", i3cbus->id); ++ + ret = of_populate_i3c_bus(master); + if (ret) + goto err_put_dev; +-- +2.51.0 + diff --git a/queue-6.1/ib-cache-update-gid-cache-on-client-reregister-event.patch b/queue-6.1/ib-cache-update-gid-cache-on-client-reregister-event.patch new file mode 100644 index 0000000000..01c13f4407 --- /dev/null +++ b/queue-6.1/ib-cache-update-gid-cache-on-client-reregister-event.patch @@ -0,0 +1,54 @@ +From d23a17c874c1dae9d413599992bc640d6acd1db4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 31 Dec 2025 14:07:45 +0100 +Subject: IB/cache: update gid cache on client reregister event +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Etienne AUJAMES + +[ Upstream commit ddd6c8c873e912cb1ead79def54de5e24ff71c80 ] + +Some HCAs (e.g: ConnectX4) do not trigger a IB_EVENT_GID_CHANGE on +subnet prefix update from SM (PortInfo). + +Since the commit d58c23c92548 ("IB/core: Only update PKEY and GID caches +on respective events"), the GID cache is updated exclusively on +IB_EVENT_GID_CHANGE. If this event is not emitted, the subnet prefix in the +IPoIB interface’s hardware address remains set to its default value +(0xfe80000000000000). + +Then rdma_bind_addr() failed because it relies on hardware address to +find the port GID (subnet_prefix + port GUID). + +This patch fixes this issue by updating the GID cache on +IB_EVENT_CLIENT_REREGISTER event (emitted on PortInfo::ClientReregister=1). + +Fixes: d58c23c92548 ("IB/core: Only update PKEY and GID caches on respective events") +Signed-off-by: Etienne AUJAMES +Link: https://patch.msgid.link/aVUfsO58QIDn5bGX@eaujamesFR0130 +Reviewed-by: Parav Pandit +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/cache.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c +index 0023aad0e7e43..6d980ac2488a9 100644 +--- a/drivers/infiniband/core/cache.c ++++ b/drivers/infiniband/core/cache.c +@@ -1555,7 +1555,8 @@ static void ib_cache_event_task(struct work_struct *_work) + * the cache. + */ + ret = ib_cache_update(work->event.device, work->event.element.port_num, +- work->event.event == IB_EVENT_GID_CHANGE, ++ work->event.event == IB_EVENT_GID_CHANGE || ++ work->event.event == IB_EVENT_CLIENT_REREGISTER, + work->event.event == IB_EVENT_PKEY_CHANGE, + work->enforce_security); + +-- +2.51.0 + diff --git a/queue-6.1/iio-sca3000-fix-a-resource-leak-in-sca3000_probe.patch b/queue-6.1/iio-sca3000-fix-a-resource-leak-in-sca3000_probe.patch new file mode 100644 index 0000000000..9290de935c --- /dev/null +++ b/queue-6.1/iio-sca3000-fix-a-resource-leak-in-sca3000_probe.patch @@ -0,0 +1,42 @@ +From e9e0c42e1a7b8f18752bde3855dcddb1f6a7091c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 22:49:49 -0800 +Subject: iio: sca3000: Fix a resource leak in sca3000_probe() + +From: Harshit Mogalapalli + +[ Upstream commit 62b44ebc1f2c71db3ca2d4737c52e433f6f03038 ] + +spi->irq from request_threaded_irq() not released when +iio_device_register() fails. Add an return value check and jump to a +common error handler when iio_device_register() fails. + +Fixes: 9a4936dc89a3 ("staging:iio:accel:sca3000 Tidy up probe order to avoid a race.") +Signed-off-by: Harshit Mogalapalli +Reviewed-by: Andy Shevchenko +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/accel/sca3000.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/iio/accel/sca3000.c b/drivers/iio/accel/sca3000.c +index 87c54e41f6ccd..2b87f7f5508bb 100644 +--- a/drivers/iio/accel/sca3000.c ++++ b/drivers/iio/accel/sca3000.c +@@ -1496,7 +1496,11 @@ static int sca3000_probe(struct spi_device *spi) + if (ret) + goto error_free_irq; + +- return iio_device_register(indio_dev); ++ ret = iio_device_register(indio_dev); ++ if (ret) ++ goto error_free_irq; ++ ++ return 0; + + error_free_irq: + if (spi->irq) +-- +2.51.0 + diff --git a/queue-6.1/io_uring-cancel-abstract-out-request-match-helper.patch b/queue-6.1/io_uring-cancel-abstract-out-request-match-helper.patch new file mode 100644 index 0000000000..9efe0e8f95 --- /dev/null +++ b/queue-6.1/io_uring-cancel-abstract-out-request-match-helper.patch @@ -0,0 +1,72 @@ +From 085bb14a950baa4a2dc77e675ab4122f0cd085e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jun 2023 09:00:24 -0600 +Subject: io_uring/cancel: abstract out request match helper + +From: Jens Axboe + +[ Upstream commit aa5cd116f3c25c05e4724d7b5e24dc9ed9020a12 ] + +We have different match code in a variety of spots. Start the cleanup of +this by abstracting out a helper that can be used to check if a given +request matches the cancelation criteria outlined in io_cancel_data. + +Signed-off-by: Jens Axboe +Stable-dep-of: 22dbb0987bd1 ("io_uring/cancel: de-unionize file and user_data in struct io_cancel_data") +Signed-off-by: Sasha Levin +--- + io_uring/cancel.c | 17 +++++++++++++---- + io_uring/cancel.h | 1 + + 2 files changed, 14 insertions(+), 4 deletions(-) + +diff --git a/io_uring/cancel.c b/io_uring/cancel.c +index b4f5dfacc0c31..88586911b516b 100644 +--- a/io_uring/cancel.c ++++ b/io_uring/cancel.c +@@ -27,11 +27,11 @@ struct io_cancel { + #define CANCEL_FLAGS (IORING_ASYNC_CANCEL_ALL | IORING_ASYNC_CANCEL_FD | \ + IORING_ASYNC_CANCEL_ANY | IORING_ASYNC_CANCEL_FD_FIXED) + +-static bool io_cancel_cb(struct io_wq_work *work, void *data) ++/* ++ * Returns true if the request matches the criteria outlined by 'cd'. ++ */ ++bool io_cancel_req_match(struct io_kiocb *req, struct io_cancel_data *cd) + { +- struct io_kiocb *req = container_of(work, struct io_kiocb, work); +- struct io_cancel_data *cd = data; +- + if (req->ctx != cd->ctx) + return false; + if (cd->flags & IORING_ASYNC_CANCEL_ANY) { +@@ -48,9 +48,18 @@ static bool io_cancel_cb(struct io_wq_work *work, void *data) + return false; + req->work.cancel_seq = cd->seq; + } ++ + return true; + } + ++static bool io_cancel_cb(struct io_wq_work *work, void *data) ++{ ++ struct io_kiocb *req = container_of(work, struct io_kiocb, work); ++ struct io_cancel_data *cd = data; ++ ++ return io_cancel_req_match(req, cd); ++} ++ + static int io_async_cancel_one(struct io_uring_task *tctx, + struct io_cancel_data *cd) + { +diff --git a/io_uring/cancel.h b/io_uring/cancel.h +index 6a59ee484d0cc..496ce4dac78ed 100644 +--- a/io_uring/cancel.h ++++ b/io_uring/cancel.h +@@ -21,3 +21,4 @@ int io_try_cancel(struct io_uring_task *tctx, struct io_cancel_data *cd, + void init_hash_table(struct io_hash_table *table, unsigned size); + + int io_sync_cancel(struct io_ring_ctx *ctx, void __user *arg); ++bool io_cancel_req_match(struct io_kiocb *req, struct io_cancel_data *cd); +-- +2.51.0 + diff --git a/queue-6.1/io_uring-cancel-add-ioring_async_cancel_userdata.patch b/queue-6.1/io_uring-cancel-add-ioring_async_cancel_userdata.patch new file mode 100644 index 0000000000..b3bc50f2a5 --- /dev/null +++ b/queue-6.1/io_uring-cancel-add-ioring_async_cancel_userdata.patch @@ -0,0 +1,84 @@ +From 769f66e4d502f04bbce0f246e6a9e216cc246c16 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jun 2023 10:33:11 -0600 +Subject: io_uring/cancel: add IORING_ASYNC_CANCEL_USERDATA + +From: Jens Axboe + +[ Upstream commit 8165b566049b14152873011ea540eb22eae5111d ] + +Add a flag to explicitly match on user_data in the request for +cancelation purposes. This is the default behavior if none of the +other match flags are set, but if we ALSO want to match on user_data, +then this flag can be set. + +Signed-off-by: Jens Axboe +Stable-dep-of: 22dbb0987bd1 ("io_uring/cancel: de-unionize file and user_data in struct io_cancel_data") +Signed-off-by: Sasha Levin +--- + include/uapi/linux/io_uring.h | 2 ++ + io_uring/cancel.c | 18 ++++++++++++------ + 2 files changed, 14 insertions(+), 6 deletions(-) + +diff --git a/include/uapi/linux/io_uring.h b/include/uapi/linux/io_uring.h +index a8579ec1a8683..7adc7c4e9894b 100644 +--- a/include/uapi/linux/io_uring.h ++++ b/include/uapi/linux/io_uring.h +@@ -276,11 +276,13 @@ enum io_uring_op { + * request 'user_data' + * IORING_ASYNC_CANCEL_ANY Match any request + * IORING_ASYNC_CANCEL_FD_FIXED 'fd' passed in is a fixed descriptor ++ * IORING_ASYNC_CANCEL_USERDATA Match on user_data, default for no other key + */ + #define IORING_ASYNC_CANCEL_ALL (1U << 0) + #define IORING_ASYNC_CANCEL_FD (1U << 1) + #define IORING_ASYNC_CANCEL_ANY (1U << 2) + #define IORING_ASYNC_CANCEL_FD_FIXED (1U << 3) ++#define IORING_ASYNC_CANCEL_USERDATA (1U << 4) + + /* + * send/sendmsg and recv/recvmsg flags (sqe->ioprio) +diff --git a/io_uring/cancel.c b/io_uring/cancel.c +index c27e10e3dd8c3..577d2f85b3e5b 100644 +--- a/io_uring/cancel.c ++++ b/io_uring/cancel.c +@@ -25,24 +25,30 @@ struct io_cancel { + }; + + #define CANCEL_FLAGS (IORING_ASYNC_CANCEL_ALL | IORING_ASYNC_CANCEL_FD | \ +- IORING_ASYNC_CANCEL_ANY | IORING_ASYNC_CANCEL_FD_FIXED) ++ IORING_ASYNC_CANCEL_ANY | IORING_ASYNC_CANCEL_FD_FIXED | \ ++ IORING_ASYNC_CANCEL_USERDATA) + + /* + * Returns true if the request matches the criteria outlined by 'cd'. + */ + bool io_cancel_req_match(struct io_kiocb *req, struct io_cancel_data *cd) + { ++ bool match_user_data = cd->flags & IORING_ASYNC_CANCEL_USERDATA; ++ + if (req->ctx != cd->ctx) + return false; +- if (cd->flags & IORING_ASYNC_CANCEL_ANY) { ++ ++ if (!(cd->flags & (IORING_ASYNC_CANCEL_FD))) ++ match_user_data = true; ++ ++ if (cd->flags & IORING_ASYNC_CANCEL_ANY) + goto check_seq; +- } else if (cd->flags & IORING_ASYNC_CANCEL_FD) { ++ if (cd->flags & IORING_ASYNC_CANCEL_FD) { + if (req->file != cd->file) + return false; +- } else { +- if (req->cqe.user_data != cd->data) +- return false; + } ++ if (match_user_data && req->cqe.user_data != cd->data) ++ return false; + if (cd->flags & IORING_ASYNC_CANCEL_ALL) { + check_seq: + if (cd->seq == req->work.cancel_seq) +-- +2.51.0 + diff --git a/queue-6.1/io_uring-cancel-de-unionize-file-and-user_data-in-st.patch b/queue-6.1/io_uring-cancel-de-unionize-file-and-user_data-in-st.patch new file mode 100644 index 0000000000..1be91d3ee9 --- /dev/null +++ b/queue-6.1/io_uring-cancel-de-unionize-file-and-user_data-in-st.patch @@ -0,0 +1,45 @@ +From f4dcdc0c5d51b0072e055a0bd5a34faf5173fbfc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 14:16:27 -0700 +Subject: io_uring/cancel: de-unionize file and user_data in struct + io_cancel_data + +From: Jens Axboe + +[ Upstream commit 22dbb0987bd1e0ec3b1e4ad20756a98f99aa4a08 ] + +By having them share the same space in struct io_cancel_data, it ends up +disallowing IORING_ASYNC_CANCEL_FD|IORING_ASYNC_CANCEL_USERDATA from +working. Eg you cannot match on both a file and user_data for +cancelation purposes. This obviously isn't a common use case as nobody +has reported this, but it does result in -ENOENT potentially being +returned when trying to match on both, rather than actually doing what +the API says it would. + +Fixes: 4bf94615b888 ("io_uring: allow IORING_OP_ASYNC_CANCEL with 'fd' key") +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + io_uring/cancel.h | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/io_uring/cancel.h b/io_uring/cancel.h +index fc98622e6166e..7e6d0fca7db28 100644 +--- a/io_uring/cancel.h ++++ b/io_uring/cancel.h +@@ -4,10 +4,8 @@ + + struct io_cancel_data { + struct io_ring_ctx *ctx; +- union { +- u64 data; +- struct file *file; +- }; ++ u64 data; ++ struct file *file; + u8 opcode; + u32 flags; + int seq; +-- +2.51.0 + diff --git a/queue-6.1/io_uring-cancel-fix-sequence-matching-for-ioring_asy.patch b/queue-6.1/io_uring-cancel-fix-sequence-matching-for-ioring_asy.patch new file mode 100644 index 0000000000..d86d01d61e --- /dev/null +++ b/queue-6.1/io_uring-cancel-fix-sequence-matching-for-ioring_asy.patch @@ -0,0 +1,47 @@ +From 0dbcdb0bcee0180f41ea85df68cf855a8d309785 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jun 2023 09:38:26 -0600 +Subject: io_uring/cancel: fix sequence matching for IORING_ASYNC_CANCEL_ANY + +From: Jens Axboe + +[ Upstream commit 3a372b66923e4af966af2900da588e3b3de6fcd2 ] + +We always need to check/update the cancel sequence if +IORING_ASYNC_CANCEL_ALL is set. Also kill the redundant check for +IORING_ASYNC_CANCEL_ANY at the end, if we get here we know it's +not set as we would've matched it higher up. + +Signed-off-by: Jens Axboe +Stable-dep-of: 22dbb0987bd1 ("io_uring/cancel: de-unionize file and user_data in struct io_cancel_data") +Signed-off-by: Sasha Levin +--- + io_uring/cancel.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/io_uring/cancel.c b/io_uring/cancel.c +index 88586911b516b..c27e10e3dd8c3 100644 +--- a/io_uring/cancel.c ++++ b/io_uring/cancel.c +@@ -35,7 +35,7 @@ bool io_cancel_req_match(struct io_kiocb *req, struct io_cancel_data *cd) + if (req->ctx != cd->ctx) + return false; + if (cd->flags & IORING_ASYNC_CANCEL_ANY) { +- ; ++ goto check_seq; + } else if (cd->flags & IORING_ASYNC_CANCEL_FD) { + if (req->file != cd->file) + return false; +@@ -43,7 +43,8 @@ bool io_cancel_req_match(struct io_kiocb *req, struct io_cancel_data *cd) + if (req->cqe.user_data != cd->data) + return false; + } +- if (cd->flags & (IORING_ASYNC_CANCEL_ALL|IORING_ASYNC_CANCEL_ANY)) { ++ if (cd->flags & IORING_ASYNC_CANCEL_ALL) { ++check_seq: + if (cd->seq == req->work.cancel_seq) + return false; + req->work.cancel_seq = cd->seq; +-- +2.51.0 + diff --git a/queue-6.1/io_uring-cancel-support-opcode-based-lookup-and-canc.patch b/queue-6.1/io_uring-cancel-support-opcode-based-lookup-and-canc.patch new file mode 100644 index 0000000000..e36a8f25f0 --- /dev/null +++ b/queue-6.1/io_uring-cancel-support-opcode-based-lookup-and-canc.patch @@ -0,0 +1,143 @@ +From 6757fd33f172fd9aa2b8706020d0f86fde88d306 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jun 2023 10:36:43 -0600 +Subject: io_uring/cancel: support opcode based lookup and cancelation + +From: Jens Axboe + +[ Upstream commit d7b8b079a8f6bc007d06d9ee468659dae6053e13 ] + +Add IORING_ASYNC_CANCEL_OP flag for cancelation, which allows the +application to target cancelation based on the opcode of the original +request. + +Signed-off-by: Jens Axboe +Stable-dep-of: 22dbb0987bd1 ("io_uring/cancel: de-unionize file and user_data in struct io_cancel_data") +Signed-off-by: Sasha Levin +--- + include/uapi/linux/io_uring.h | 2 ++ + io_uring/cancel.c | 17 ++++++++++++++--- + io_uring/cancel.h | 2 +- + io_uring/poll.c | 3 ++- + 4 files changed, 19 insertions(+), 5 deletions(-) + +diff --git a/include/uapi/linux/io_uring.h b/include/uapi/linux/io_uring.h +index 7adc7c4e9894b..aeed98cb5c1c8 100644 +--- a/include/uapi/linux/io_uring.h ++++ b/include/uapi/linux/io_uring.h +@@ -277,12 +277,14 @@ enum io_uring_op { + * IORING_ASYNC_CANCEL_ANY Match any request + * IORING_ASYNC_CANCEL_FD_FIXED 'fd' passed in is a fixed descriptor + * IORING_ASYNC_CANCEL_USERDATA Match on user_data, default for no other key ++ * IORING_ASYNC_CANCEL_OP Match request based on opcode + */ + #define IORING_ASYNC_CANCEL_ALL (1U << 0) + #define IORING_ASYNC_CANCEL_FD (1U << 1) + #define IORING_ASYNC_CANCEL_ANY (1U << 2) + #define IORING_ASYNC_CANCEL_FD_FIXED (1U << 3) + #define IORING_ASYNC_CANCEL_USERDATA (1U << 4) ++#define IORING_ASYNC_CANCEL_OP (1U << 5) + + /* + * send/sendmsg and recv/recvmsg flags (sqe->ioprio) +diff --git a/io_uring/cancel.c b/io_uring/cancel.c +index 577d2f85b3e5b..bfaf8f9f1defc 100644 +--- a/io_uring/cancel.c ++++ b/io_uring/cancel.c +@@ -22,11 +22,12 @@ struct io_cancel { + u64 addr; + u32 flags; + s32 fd; ++ u8 opcode; + }; + + #define CANCEL_FLAGS (IORING_ASYNC_CANCEL_ALL | IORING_ASYNC_CANCEL_FD | \ + IORING_ASYNC_CANCEL_ANY | IORING_ASYNC_CANCEL_FD_FIXED | \ +- IORING_ASYNC_CANCEL_USERDATA) ++ IORING_ASYNC_CANCEL_USERDATA | IORING_ASYNC_CANCEL_OP) + + /* + * Returns true if the request matches the criteria outlined by 'cd'. +@@ -38,7 +39,7 @@ bool io_cancel_req_match(struct io_kiocb *req, struct io_cancel_data *cd) + if (req->ctx != cd->ctx) + return false; + +- if (!(cd->flags & (IORING_ASYNC_CANCEL_FD))) ++ if (!(cd->flags & (IORING_ASYNC_CANCEL_FD | IORING_ASYNC_CANCEL_OP))) + match_user_data = true; + + if (cd->flags & IORING_ASYNC_CANCEL_ANY) +@@ -47,6 +48,10 @@ bool io_cancel_req_match(struct io_kiocb *req, struct io_cancel_data *cd) + if (req->file != cd->file) + return false; + } ++ if (cd->flags & IORING_ASYNC_CANCEL_OP) { ++ if (req->opcode != cd->opcode) ++ return false; ++ } + if (match_user_data && req->cqe.user_data != cd->data) + return false; + if (cd->flags & IORING_ASYNC_CANCEL_ALL) { +@@ -127,7 +132,7 @@ int io_async_cancel_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) + + if (unlikely(req->flags & REQ_F_BUFFER_SELECT)) + return -EINVAL; +- if (sqe->off || sqe->len || sqe->splice_fd_in) ++ if (sqe->off || sqe->splice_fd_in) + return -EINVAL; + + cancel->addr = READ_ONCE(sqe->addr); +@@ -139,6 +144,11 @@ int io_async_cancel_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) + return -EINVAL; + cancel->fd = READ_ONCE(sqe->fd); + } ++ if (cancel->flags & IORING_ASYNC_CANCEL_OP) { ++ if (cancel->flags & IORING_ASYNC_CANCEL_ANY) ++ return -EINVAL; ++ cancel->opcode = READ_ONCE(sqe->len); ++ } + + return 0; + } +@@ -185,6 +195,7 @@ int io_async_cancel(struct io_kiocb *req, unsigned int issue_flags) + .ctx = req->ctx, + .data = cancel->addr, + .flags = cancel->flags, ++ .opcode = cancel->opcode, + .seq = atomic_inc_return(&req->ctx->cancel_seq), + }; + struct io_uring_task *tctx = req->task->io_uring; +diff --git a/io_uring/cancel.h b/io_uring/cancel.h +index 496ce4dac78ed..fc98622e6166e 100644 +--- a/io_uring/cancel.h ++++ b/io_uring/cancel.h +@@ -8,11 +8,11 @@ struct io_cancel_data { + u64 data; + struct file *file; + }; ++ u8 opcode; + u32 flags; + int seq; + }; + +- + int io_async_cancel_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe); + int io_async_cancel(struct io_kiocb *req, unsigned int issue_flags); + +diff --git a/io_uring/poll.c b/io_uring/poll.c +index d4d107931f629..bac9e77d44b09 100644 +--- a/io_uring/poll.c ++++ b/io_uring/poll.c +@@ -873,7 +873,8 @@ static int __io_poll_cancel(struct io_ring_ctx *ctx, struct io_cancel_data *cd, + struct io_hash_bucket *bucket; + struct io_kiocb *req; + +- if (cd->flags & (IORING_ASYNC_CANCEL_FD|IORING_ASYNC_CANCEL_ANY)) ++ if (cd->flags & (IORING_ASYNC_CANCEL_FD | IORING_ASYNC_CANCEL_OP | ++ IORING_ASYNC_CANCEL_ANY)) + req = io_poll_file_find(ctx, cd, table, &bucket); + else + req = io_poll_find(ctx, false, cd, table, &bucket); +-- +2.51.0 + diff --git a/queue-6.1/io_uring-sync-validate-passed-in-offset.patch b/queue-6.1/io_uring-sync-validate-passed-in-offset.patch new file mode 100644 index 0000000000..351812ecda --- /dev/null +++ b/queue-6.1/io_uring-sync-validate-passed-in-offset.patch @@ -0,0 +1,36 @@ +From 8bc23d8f1228db06a36c0660728d80cb3f06f0ba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 11:48:56 -0700 +Subject: io_uring/sync: validate passed in offset + +From: Jens Axboe + +[ Upstream commit 649dd18f559891bdafc5532d737c7dfb56060a6d ] + +Check if the passed in offset is negative once cast to sync->off. This +ensures that -EINVAL is returned for that case, like it would be for +sync_file_range(2). + +Fixes: c992fe2925d7 ("io_uring: add fsync support") +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + io_uring/sync.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/io_uring/sync.c b/io_uring/sync.c +index 64e87ea2b8fbb..59f951a4b5241 100644 +--- a/io_uring/sync.c ++++ b/io_uring/sync.c +@@ -61,6 +61,8 @@ int io_fsync_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) + return -EINVAL; + + sync->off = READ_ONCE(sqe->off); ++ if (sync->off < 0) ++ return -EINVAL; + sync->len = READ_ONCE(sqe->len); + return 0; + } +-- +2.51.0 + diff --git a/queue-6.1/iomap-fix-submission-side-handling-of-completion-sid.patch b/queue-6.1/iomap-fix-submission-side-handling-of-completion-sid.patch new file mode 100644 index 0000000000..35b830d511 --- /dev/null +++ b/queue-6.1/iomap-fix-submission-side-handling-of-completion-sid.patch @@ -0,0 +1,49 @@ +From f65f09e2754560907d4786cea6459e2140a7c565 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 06:53:38 +0100 +Subject: iomap: fix submission side handling of completion side errors + +From: Christoph Hellwig + +[ Upstream commit 4ad357e39b2ecd5da7bcc7e840ee24d179593cd5 ] + +The "if (dio->error)" in iomap_dio_bio_iter exists to stop submitting +more bios when a completion already return an error. Commit cfe057f7db1f +("iomap_dio_actor(): fix iov_iter bugs") made it revert the iov by +"copied", which is very wrong given that we've already consumed that +range and submitted a bio for it. + +Fixes: cfe057f7db1f ("iomap_dio_actor(): fix iov_iter bugs") +Signed-off-by: Christoph Hellwig +Reviewed-by: Damien Le Moal +Reviewed-by: Darrick J. Wong +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + fs/iomap/direct-io.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/fs/iomap/direct-io.c b/fs/iomap/direct-io.c +index 9acfc9e847cdc..69347b08116fd 100644 +--- a/fs/iomap/direct-io.c ++++ b/fs/iomap/direct-io.c +@@ -306,9 +306,13 @@ static loff_t iomap_dio_bio_iter(const struct iomap_iter *iter, + nr_pages = bio_iov_vecs_to_alloc(dio->submit.iter, BIO_MAX_VECS); + do { + size_t n; +- if (dio->error) { +- iov_iter_revert(dio->submit.iter, copied); +- copied = ret = 0; ++ ++ /* ++ * If completions already occurred and reported errors, give up now and ++ * don't bother submitting more bios. ++ */ ++ if (unlikely(data_race(dio->error))) { ++ ret = 0; + goto out; + } + +-- +2.51.0 + diff --git a/queue-6.1/iommu-vt-d-flush-cache-for-pasid-table-before-using-.patch b/queue-6.1/iommu-vt-d-flush-cache-for-pasid-table-before-using-.patch new file mode 100644 index 0000000000..7e77532461 --- /dev/null +++ b/queue-6.1/iommu-vt-d-flush-cache-for-pasid-table-before-using-.patch @@ -0,0 +1,55 @@ +From a900ca4e7377d862a508556fef87cb0cb8e428f9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 09:48:52 +0800 +Subject: iommu/vt-d: Flush cache for PASID table before using it + +From: Dmytro Maluka + +[ Upstream commit 22d169bdd2849fe6bd18c2643742e1c02be6451c ] + +When writing the address of a freshly allocated zero-initialized PASID +table to a PASID directory entry, do that after the CPU cache flush for +this PASID table, not before it, to avoid the time window when this +PASID table may be already used by non-coherent IOMMU hardware while +its contents in RAM is still some random old data, not zero-initialized. + +Fixes: 194b3348bdbb ("iommu/vt-d: Fix PASID directory pointer coherency") +Signed-off-by: Dmytro Maluka +Reviewed-by: Kevin Tian +Link: https://lore.kernel.org/r/20251221123508.37495-1-dmaluka@chromium.org +Signed-off-by: Lu Baolu +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/intel/pasid.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c +index 32432d82d7744..9b82676dfd99f 100644 +--- a/drivers/iommu/intel/pasid.c ++++ b/drivers/iommu/intel/pasid.c +@@ -205,6 +205,9 @@ static struct pasid_entry *intel_pasid_get_entry(struct device *dev, u32 pasid) + if (!entries) + return NULL; + ++ if (!ecap_coherent(info->iommu->ecap)) ++ clflush_cache_range(entries, VTD_PAGE_SIZE); ++ + /* + * The pasid directory table entry won't be freed after + * allocation. No worry about the race with free and +@@ -216,10 +219,8 @@ static struct pasid_entry *intel_pasid_get_entry(struct device *dev, u32 pasid) + free_pgtable_page(entries); + goto retry; + } +- if (!ecap_coherent(info->iommu->ecap)) { +- clflush_cache_range(entries, VTD_PAGE_SIZE); ++ if (!ecap_coherent(info->iommu->ecap)) + clflush_cache_range(&dir[dir_index].val, sizeof(*dir)); +- } + } + + return &entries[index]; +-- +2.51.0 + diff --git a/queue-6.1/ionic-rate-limit-unknown-xcvr-type-messages.patch b/queue-6.1/ionic-rate-limit-unknown-xcvr-type-messages.patch new file mode 100644 index 0000000000..5b2c37d1f4 --- /dev/null +++ b/queue-6.1/ionic-rate-limit-unknown-xcvr-type-messages.patch @@ -0,0 +1,51 @@ +From 9d66be8d65758d4d219b283b240a76126a77e189 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 14:46:51 -0800 +Subject: ionic: Rate limit unknown xcvr type messages + +From: Eric Joyner + +[ Upstream commit cdb1634de3bf197c0d86487d1fb84c128a79cc7c ] + +Running ethtool repeatedly with a transceiver unknown to the driver or +firmware will cause the driver to spam the kernel logs with "unknown +xcvr type" messages which can distract from real issues; and this isn't +interesting information outside of debugging. Fix this by rate limiting +the output so that there are still notifications but not so many that +they flood the log. + +Using dev_dbg_once() would reduce the number of messages further, but +this would miss the case where a different unknown transceiver type is +plugged in, and its status is requested. + +Fixes: 4d03e00a2140 ("ionic: Add initial ethtool support") +Signed-off-by: Eric Joyner +Reviewed-by: Brett Creeley +Link: https://patch.msgid.link/20260206224651.1491-1-eric.joyner@amd.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/pensando/ionic/ionic_ethtool.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c +index 928ef29339907..2e8744815af66 100644 +--- a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c ++++ b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c +@@ -208,9 +208,10 @@ static int ionic_get_link_ksettings(struct net_device *netdev, + /* This means there's no module plugged in */ + break; + default: +- dev_info(lif->ionic->dev, "unknown xcvr type pid=%d / 0x%x\n", +- idev->port_info->status.xcvr.pid, +- idev->port_info->status.xcvr.pid); ++ dev_dbg_ratelimited(lif->ionic->dev, ++ "unknown xcvr type pid=%d / 0x%x\n", ++ idev->port_info->status.xcvr.pid, ++ idev->port_info->status.xcvr.pid); + break; + } + +-- +2.51.0 + diff --git a/queue-6.1/ipc-don-t-audit-capability-check-in-ipc_permissions.patch b/queue-6.1/ipc-don-t-audit-capability-check-in-ipc_permissions.patch new file mode 100644 index 0000000000..77bdb12228 --- /dev/null +++ b/queue-6.1/ipc-don-t-audit-capability-check-in-ipc_permissions.patch @@ -0,0 +1,66 @@ +From 7498a1e44d32ae1db57c45eef2996ec5096405ce Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 15:13:03 +0100 +Subject: ipc: don't audit capability check in ipc_permissions() + +From: Ondrej Mosnacek + +[ Upstream commit 071588136007482d70fd2667b827036bc60b1f8f ] + +The IPC sysctls implement the ctl_table_root::permissions hook and +they override the file access mode based on the CAP_CHECKPOINT_RESTORE +capability, which is being checked regardless of whether any access is +actually denied or not, so if an LSM denies the capability, an audit +record may be logged even when access is in fact granted. + +It wouldn't be viable to restructure the sysctl permission logic to only +check the capability when the access would be actually denied if it's +not granted. Thus, do the same as in net_ctl_permissions() +(net/sysctl_net.c) - switch from ns_capable() to ns_capable_noaudit(), +so that the check never emits an audit record. + +Fixes: 0889f44e2810 ("ipc: Check permissions for checkpoint_restart sysctls at open time") +Signed-off-by: Ondrej Mosnacek +Acked-by: Alexey Gladkov +Acked-by: Serge Hallyn +Signed-off-by: Serge Hallyn +Stable-dep-of: 8924336531e2 ("ipc: don't audit capability check in ipc_permissions()") +Signed-off-by: Sasha Levin +--- + include/linux/capability.h | 6 ++++++ + ipc/ipc_sysctl.c | 2 +- + 2 files changed, 7 insertions(+), 1 deletion(-) + +diff --git a/include/linux/capability.h b/include/linux/capability.h +index 65efb74c3585d..d5973c2898b83 100644 +--- a/include/linux/capability.h ++++ b/include/linux/capability.h +@@ -270,6 +270,12 @@ static inline bool checkpoint_restore_ns_capable(struct user_namespace *ns) + ns_capable(ns, CAP_SYS_ADMIN); + } + ++static inline bool checkpoint_restore_ns_capable_noaudit(struct user_namespace *ns) ++{ ++ return ns_capable_noaudit(ns, CAP_CHECKPOINT_RESTORE) || ++ ns_capable_noaudit(ns, CAP_SYS_ADMIN); ++} ++ + /* audit system wants to get cap info from files as well */ + int get_vfs_caps_from_disk(struct user_namespace *mnt_userns, + const struct dentry *dentry, +diff --git a/ipc/ipc_sysctl.c b/ipc/ipc_sysctl.c +index d7ca2bdae9e82..9ca2f9f4f16ca 100644 +--- a/ipc/ipc_sysctl.c ++++ b/ipc/ipc_sysctl.c +@@ -215,7 +215,7 @@ static int ipc_permissions(struct ctl_table_header *head, struct ctl_table *tabl + if (((table->data == &ns->ids[IPC_SEM_IDS].next_id) || + (table->data == &ns->ids[IPC_MSG_IDS].next_id) || + (table->data == &ns->ids[IPC_SHM_IDS].next_id)) && +- checkpoint_restore_ns_capable(ns->user_ns)) ++ checkpoint_restore_ns_capable_noaudit(ns->user_ns)) + mode = 0666; + else + #endif +-- +2.51.0 + diff --git a/queue-6.1/kallsyms-ftrace-set-module-buildid-in-ftrace_mod_add.patch b/queue-6.1/kallsyms-ftrace-set-module-buildid-in-ftrace_mod_add.patch new file mode 100644 index 0000000000..f123d32aa6 --- /dev/null +++ b/queue-6.1/kallsyms-ftrace-set-module-buildid-in-ftrace_mod_add.patch @@ -0,0 +1,100 @@ +From 81490cea1990e11b041c91413b8f61225da1a6b6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 14:59:19 +0100 +Subject: kallsyms/ftrace: set module buildid in ftrace_mod_address_lookup() + +From: Petr Mladek + +[ Upstream commit e8a1e7eaa19d0b757b06a2f913e3eeb4b1c002c6 ] + +__sprint_symbol() might access an invalid pointer when +kallsyms_lookup_buildid() returns a symbol found by +ftrace_mod_address_lookup(). + +The ftrace lookup function must set both @modname and @modbuildid the same +way as module_address_lookup(). + +Link: https://lkml.kernel.org/r/20251128135920.217303-7-pmladek@suse.com +Fixes: 9294523e3768 ("module: add printk formats to add module build ID to stacktraces") +Signed-off-by: Petr Mladek +Reviewed-by: Aaron Tomlin +Acked-by: Steven Rostedt (Google) +Cc: Alexei Starovoitov +Cc: Daniel Borkman +Cc: Daniel Gomez +Cc: John Fastabend +Cc: Kees Cook +Cc: Luis Chamberalin +Cc: Marc Rutland +Cc: "Masami Hiramatsu (Google)" +Cc: Petr Pavlu +Cc: Sami Tolvanen +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + include/linux/ftrace.h | 6 ++++-- + kernel/kallsyms.c | 4 ++-- + kernel/trace/ftrace.c | 5 ++++- + 3 files changed, 10 insertions(+), 5 deletions(-) + +diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h +index 8128059db5ed7..d29b74e4e7c3d 100644 +--- a/include/linux/ftrace.h ++++ b/include/linux/ftrace.h +@@ -75,11 +75,13 @@ struct ftrace_direct_func; + defined(CONFIG_DYNAMIC_FTRACE) + const char * + ftrace_mod_address_lookup(unsigned long addr, unsigned long *size, +- unsigned long *off, char **modname, char *sym); ++ unsigned long *off, char **modname, ++ const unsigned char **modbuildid, char *sym); + #else + static inline const char * + ftrace_mod_address_lookup(unsigned long addr, unsigned long *size, +- unsigned long *off, char **modname, char *sym) ++ unsigned long *off, char **modname, ++ const unsigned char **modbuildid, char *sym) + { + return NULL; + } +diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c +index 5e98cd80eed89..5a3ae3365049b 100644 +--- a/kernel/kallsyms.c ++++ b/kernel/kallsyms.c +@@ -434,8 +434,8 @@ static const char *kallsyms_lookup_buildid(unsigned long addr, + offset, modname, namebuf); + + if (!ret) +- ret = ftrace_mod_address_lookup(addr, symbolsize, +- offset, modname, namebuf); ++ ret = ftrace_mod_address_lookup(addr, symbolsize, offset, ++ modname, modbuildid, namebuf); + + found: + cleanup_symbol_name(namebuf); +diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c +index e24906e7fcc5d..7217b872ff4ff 100644 +--- a/kernel/trace/ftrace.c ++++ b/kernel/trace/ftrace.c +@@ -7230,7 +7230,8 @@ ftrace_func_address_lookup(struct ftrace_mod_map *mod_map, + + const char * + ftrace_mod_address_lookup(unsigned long addr, unsigned long *size, +- unsigned long *off, char **modname, char *sym) ++ unsigned long *off, char **modname, ++ const unsigned char **modbuildid, char *sym) + { + struct ftrace_mod_map *mod_map; + const char *ret = NULL; +@@ -7242,6 +7243,8 @@ ftrace_mod_address_lookup(unsigned long addr, unsigned long *size, + if (ret) { + if (modname) + *modname = mod_map->mod->name; ++ if (modbuildid) ++ *modbuildid = module_buildid(mod_map->mod); + break; + } + } +-- +2.51.0 + diff --git a/queue-6.1/leds-qcom-lpg-check-the-return-value-of-regmap_bulk_.patch b/queue-6.1/leds-qcom-lpg-check-the-return-value-of-regmap_bulk_.patch new file mode 100644 index 0000000000..449d700faf --- /dev/null +++ b/queue-6.1/leds-qcom-lpg-check-the-return-value-of-regmap_bulk_.patch @@ -0,0 +1,55 @@ +From ba78dc0af0f48bc3b3eac2ca5e931031721fd47c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 01:51:33 +0800 +Subject: leds: qcom-lpg: Check the return value of regmap_bulk_write() + +From: Haotian Zhang + +[ Upstream commit f42033b5ce8c79c5db645916c9a72ee3e10cecfa ] + +The lpg_lut_store() function currently ignores the return value of +regmap_bulk_write() and always returns 0. This can cause hardware write +failures to go undetected, leading the caller to believe LUT programming +succeeded when it may have failed. + +Check the return value of regmap_bulk_write() in lpg_lut_store and return +the error to the caller on failure. + +Fixes: 24e2d05d1b68 ("leds: Add driver for Qualcomm LPG") +Signed-off-by: Haotian Zhang +Link: https://patch.msgid.link/20260108175133.638-1-vulab@iscas.ac.cn +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/leds/rgb/leds-qcom-lpg.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/leds/rgb/leds-qcom-lpg.c b/drivers/leds/rgb/leds-qcom-lpg.c +index f85a5d65d1314..d03699bb98742 100644 +--- a/drivers/leds/rgb/leds-qcom-lpg.c ++++ b/drivers/leds/rgb/leds-qcom-lpg.c +@@ -214,7 +214,7 @@ static int lpg_lut_store(struct lpg *lpg, struct led_pattern *pattern, + { + unsigned int idx; + u16 val; +- int i; ++ int i, ret; + + idx = bitmap_find_next_zero_area(lpg->lut_bitmap, lpg->lut_size, + 0, len, 0); +@@ -224,8 +224,10 @@ static int lpg_lut_store(struct lpg *lpg, struct led_pattern *pattern, + for (i = 0; i < len; i++) { + val = pattern[i].brightness; + +- regmap_bulk_write(lpg->map, lpg->lut_base + LPG_LUT_REG(idx + i), +- &val, sizeof(val)); ++ ret = regmap_bulk_write(lpg->map, lpg->lut_base + LPG_LUT_REG(idx + i), ++ &val, sizeof(val)); ++ if (ret) ++ return ret; + } + + bitmap_set(lpg->lut_bitmap, idx, len); +-- +2.51.0 + diff --git a/queue-6.1/libbpf-fix-oob-read-in-btf_dump_get_bitfield_value.patch b/queue-6.1/libbpf-fix-oob-read-in-btf_dump_get_bitfield_value.patch new file mode 100644 index 0000000000..9630e6f058 --- /dev/null +++ b/queue-6.1/libbpf-fix-oob-read-in-btf_dump_get_bitfield_value.patch @@ -0,0 +1,59 @@ +From 7c1a6d8ed200c0580a15165a55cba056e4471a83 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 05:05:27 +0530 +Subject: libbpf: Fix OOB read in btf_dump_get_bitfield_value + +From: Varun R Mallya + +[ Upstream commit 5714ca8cba5ed736f3733663c446cbee63a10a64 ] + +When dumping bitfield data, btf_dump_get_bitfield_value() reads data +based on the underlying type's size (t->size). However, it does not +verify that the provided data buffer (data_sz) is large enough to +contain these bytes. + +If btf_dump__dump_type_data() is called with a buffer smaller than +the type's size, this leads to an out-of-bounds read. This was +confirmed by AddressSanitizer in the linked issue. + +Fix this by ensuring we do not read past the provided data_sz limit. + +Fixes: a1d3cc3c5eca ("libbpf: Avoid use of __int128 in typed dump display") +Reported-by: Harrison Green +Suggested-by: Alan Maguire +Signed-off-by: Varun R Mallya +Signed-off-by: Andrii Nakryiko +Link: https://lore.kernel.org/bpf/20260106233527.163487-1-varunrmallya@gmail.com + +Closes: https://github.com/libbpf/libbpf/issues/928 +Signed-off-by: Sasha Levin +--- + tools/lib/bpf/btf_dump.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/tools/lib/bpf/btf_dump.c b/tools/lib/bpf/btf_dump.c +index 72334cc14d737..cce69301c5e3a 100644 +--- a/tools/lib/bpf/btf_dump.c ++++ b/tools/lib/bpf/btf_dump.c +@@ -1721,9 +1721,18 @@ static int btf_dump_get_bitfield_value(struct btf_dump *d, + __u16 left_shift_bits, right_shift_bits; + const __u8 *bytes = data; + __u8 nr_copy_bits; ++ __u8 start_bit, nr_bytes; + __u64 num = 0; + int i; + ++ /* Calculate how many bytes cover the bitfield */ ++ start_bit = bits_offset % 8; ++ nr_bytes = (start_bit + bit_sz + 7) / 8; ++ ++ /* Bound check */ ++ if (data + nr_bytes > d->typed_dump->data_end) ++ return -E2BIG; ++ + /* Maximum supported bitfield size is 64 bits */ + if (t->size > 8) { + pr_warn("unexpected bitfield size %d\n", t->size); +-- +2.51.0 + diff --git a/queue-6.1/mctp-i2c-initialise-event-handler-read-bytes.patch b/queue-6.1/mctp-i2c-initialise-event-handler-read-bytes.patch new file mode 100644 index 0000000000..3ede033260 --- /dev/null +++ b/queue-6.1/mctp-i2c-initialise-event-handler-read-bytes.patch @@ -0,0 +1,43 @@ +From a3bff1c5872c8796b3ed62c811d6e718a574a2d4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Jan 2026 17:01:16 +0800 +Subject: mctp i2c: initialise event handler read bytes + +From: Matt Johnston + +[ Upstream commit 2a14e91b6d76639dac70ea170f4384c1ee3cb48d ] + +Set a 0xff value for i2c reads of an mctp-i2c device. Otherwise reads +will return "val" from the i2c bus driver. For i2c-aspeed and +i2c-npcm7xx that is a stack uninitialised u8. + +Tested with "i2ctransfer -y 1 r10@0x34" where 0x34 is a mctp-i2c +instance, now it returns all 0xff. + +Fixes: f5b8abf9fc3d ("mctp i2c: MCTP I2C binding driver") +Signed-off-by: Matt Johnston +Link: https://patch.msgid.link/20260113-mctp-read-fix-v1-1-70c4b59c741c@codeconstruct.com.au +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/mctp/mctp-i2c.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/mctp/mctp-i2c.c b/drivers/net/mctp/mctp-i2c.c +index 1d0c516842793..f77389c7006f8 100644 +--- a/drivers/net/mctp/mctp-i2c.c ++++ b/drivers/net/mctp/mctp-i2c.c +@@ -244,7 +244,10 @@ static int mctp_i2c_slave_cb(struct i2c_client *client, + + switch (event) { + case I2C_SLAVE_READ_REQUESTED: ++ case I2C_SLAVE_READ_PROCESSED: ++ /* MCTP I2C transport only uses writes */ + midev->rx_pos = 0; ++ *val = 0xff; + break; + case I2C_SLAVE_WRITE_RECEIVED: + if (midev->rx_pos < MCTP_I2C_BUFSZ) { +-- +2.51.0 + diff --git a/queue-6.1/md-raid10-fix-any_working-flag-handling-in-raid10_sy.patch b/queue-6.1/md-raid10-fix-any_working-flag-handling-in-raid10_sy.patch new file mode 100644 index 0000000000..4055ab6cc3 --- /dev/null +++ b/queue-6.1/md-raid10-fix-any_working-flag-handling-in-raid10_sy.patch @@ -0,0 +1,47 @@ +From f1158c87f79474c8101c746cad49b6ba6e7eb74c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Jan 2026 19:02:58 +0800 +Subject: md/raid10: fix any_working flag handling in raid10_sync_request + +From: Li Nan + +[ Upstream commit 99582edb3f62e8ee6c34512021368f53f9b091f2 ] + +In raid10_sync_request(), 'any_working' indicates if any IO will +be submitted. When there's only one In_sync disk with badblocks, +'any_working' might be set to 1 but no IO is submitted. Fix it by +setting 'any_working' after badblock checks. + +Link: https://lore.kernel.org/linux-raid/20260105110300.1442509-11-linan666@huaweicloud.com +Fixes: e875ecea266a ("md/raid10 record bad blocks as needed during recovery.") +Signed-off-by: Li Nan +Reviewed-by: Yu Kuai +Signed-off-by: Yu Kuai +Signed-off-by: Sasha Levin +--- + drivers/md/raid10.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c +index 2ae68b7b79598..99ebcb4475024 100644 +--- a/drivers/md/raid10.c ++++ b/drivers/md/raid10.c +@@ -3535,7 +3535,6 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr, + !test_bit(In_sync, &rdev->flags)) + continue; + /* This is where we read from */ +- any_working = 1; + sector = r10_bio->devs[j].addr; + + if (is_badblock(rdev, sector, max_sync, +@@ -3550,6 +3549,7 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr, + continue; + } + } ++ any_working = 1; + bio = r10_bio->devs[0].bio; + bio->bi_next = biolist; + biolist = bio; +-- +2.51.0 + diff --git a/queue-6.1/media-ccs-accommodate-c-phy-into-the-calculation.patch b/queue-6.1/media-ccs-accommodate-c-phy-into-the-calculation.patch new file mode 100644 index 0000000000..acde828545 --- /dev/null +++ b/queue-6.1/media-ccs-accommodate-c-phy-into-the-calculation.patch @@ -0,0 +1,53 @@ +From 2e653241ac71c060274b00f737a59acd9910c0e7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 18:57:07 +0100 +Subject: media: ccs: Accommodate C-PHY into the calculation + +From: David Heidelberg + +[ Upstream commit 3085977e734dab74adebb1dda195befce25addff ] + +We need to set correct mode for PLL to calculate correct frequency. +Signalling mode is known at this point, so use it for that. + +Fixes: 47b6eaf36eba ("media: ccs-pll: Differentiate between CSI-2 D-PHY and C-PHY") +Reviewed-by: Mehdi Djait +Signed-off-by: David Heidelberg +[Sakari Ailus: Drop extra newline.] +Signed-off-by: Sakari Ailus +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/i2c/ccs/ccs-core.c | 16 +++++++++++++++- + 1 file changed, 15 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c +index 0579fae3d014f..ed753e4e86bdf 100644 +--- a/drivers/media/i2c/ccs/ccs-core.c ++++ b/drivers/media/i2c/ccs/ccs-core.c +@@ -3521,7 +3521,21 @@ static int ccs_probe(struct i2c_client *client) + sensor->scale_m = CCS_LIM(sensor, SCALER_N_MIN); + + /* prepare PLL configuration input values */ +- sensor->pll.bus_type = CCS_PLL_BUS_TYPE_CSI2_DPHY; ++ switch (sensor->hwcfg.csi_signalling_mode) { ++ case CCS_CSI_SIGNALING_MODE_CSI_2_CPHY: ++ sensor->pll.bus_type = CCS_PLL_BUS_TYPE_CSI2_CPHY; ++ break; ++ case CCS_CSI_SIGNALING_MODE_CSI_2_DPHY: ++ case SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK: ++ case SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_STROBE: ++ sensor->pll.bus_type = CCS_PLL_BUS_TYPE_CSI2_DPHY; ++ break; ++ default: ++ dev_err(&client->dev, "unsupported signalling mode %u\n", ++ sensor->hwcfg.csi_signalling_mode); ++ rval = -EINVAL; ++ goto out_cleanup; ++ } + sensor->pll.csi2.lanes = sensor->hwcfg.lanes; + if (CCS_LIM(sensor, CLOCK_CALCULATION) & + CCS_CLOCK_CALCULATION_LANE_SPEED) { +-- +2.51.0 + diff --git a/queue-6.1/media-uvcvideo-fix-allocation-for-small-frame-sizes.patch b/queue-6.1/media-uvcvideo-fix-allocation-for-small-frame-sizes.patch new file mode 100644 index 0000000000..9f2b0199cf --- /dev/null +++ b/queue-6.1/media-uvcvideo-fix-allocation-for-small-frame-sizes.patch @@ -0,0 +1,57 @@ +From aef9c668ed8712ac80699c336dd6cda667f6481b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 10:32:13 +0000 +Subject: media: uvcvideo: Fix allocation for small frame sizes + +From: Ricardo Ribalda + +[ Upstream commit 40d3ac25c11310bfaa50ed7614846ef75cb69a1e ] + +If a frame has size of less or equal than one packet size +uvc_alloc_urb_buffers() is unable to allocate memory for it due to a +off-by-one error. + +Fix the off-by-one-error and now that we are at it, make sure that +stream->urb_size has always a valid value when we return from the +function, even when an error happens. + +Fixes: efdc8a9585ce ("V4L/DVB (10295): uvcvideo: Retry URB buffers allocation when the system is low on memory.") +Reported-by: Itay Chamiel +Closes: https://lore.kernel.org/linux-media/CANiDSCsSoZf2LsCCoWAUbCg6tJT-ypXR1B85aa6rAdMVYr2iBQ@mail.gmail.com/T/#t +Co-developed-by: Itay Chamiel +Signed-off-by: Itay Chamiel +Signed-off-by: Ricardo Ribalda +Reviewed-by: Laurent Pinchart +Tested-by: Itay Chamiel +Link: https://patch.msgid.link/20260114-uvc-alloc-urb-v1-1-cedf3fb66711@chromium.org +Signed-off-by: Laurent Pinchart +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/usb/uvc/uvc_video.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c +index da693e3905dd9..87262bf0232c4 100644 +--- a/drivers/media/usb/uvc/uvc_video.c ++++ b/drivers/media/usb/uvc/uvc_video.c +@@ -1758,7 +1758,7 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream, + npackets = UVC_MAX_PACKETS; + + /* Retry allocations until one succeed. */ +- for (; npackets > 1; npackets /= 2) { ++ for (; npackets > 0; npackets /= 2) { + stream->urb_size = psize * npackets; + + for (i = 0; i < UVC_URBS; ++i) { +@@ -1783,6 +1783,7 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream, + uvc_dbg(stream->dev, VIDEO, + "Failed to allocate URB buffers (%u bytes per packet)\n", + psize); ++ stream->urb_size = 0; + return 0; + } + +-- +2.51.0 + diff --git a/queue-6.1/mfd-arizona-fix-regulator-resource-leak-on-wm5102_cl.patch b/queue-6.1/mfd-arizona-fix-regulator-resource-leak-on-wm5102_cl.patch new file mode 100644 index 0000000000..e0732a5a5d --- /dev/null +++ b/queue-6.1/mfd-arizona-fix-regulator-resource-leak-on-wm5102_cl.patch @@ -0,0 +1,43 @@ +From 37dca47e9ae1be9a10dd5095a9699fd5c6f9e83f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 14 Dec 2025 22:58:03 +0800 +Subject: mfd: arizona: Fix regulator resource leak on + wm5102_clear_write_sequencer() failure + +From: Haotian Zhang + +[ Upstream commit 4feb753ba6e5e5bbaba868b841a2db41c21e56fa ] + +The wm5102_clear_write_sequencer() helper may return an error +and just return, bypassing the cleanup sequence and causing +regulators to remain enabled, leading to a resource leak. + +Change the direct return to jump to the err_reset label to +properly free the resources. + +Fixes: 1c1c6bba57f5 ("mfd: wm5102: Ensure we always boot the device fully") +Signed-off-by: Haotian Zhang +Reviewed-by: Charles Keepax +Link: https://patch.msgid.link/20251214145804.2037-1-vulab@iscas.ac.cn +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/mfd/arizona-core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c +index b1c53e0407710..9ac671ec26684 100644 +--- a/drivers/mfd/arizona-core.c ++++ b/drivers/mfd/arizona-core.c +@@ -1106,7 +1106,7 @@ int arizona_dev_init(struct arizona *arizona) + } else if (val & 0x01) { + ret = wm5102_clear_write_sequencer(arizona); + if (ret) +- return ret; ++ goto err_reset; + } + break; + default: +-- +2.51.0 + diff --git a/queue-6.1/mfd-wm8350-core-use-irqf_oneshot.patch b/queue-6.1/mfd-wm8350-core-use-irqf_oneshot.patch new file mode 100644 index 0000000000..28dac82af1 --- /dev/null +++ b/queue-6.1/mfd-wm8350-core-use-irqf_oneshot.patch @@ -0,0 +1,48 @@ +From 8a5e9ba0d3f7d8e0c95a2a2448440fb39e7ceb60 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:55:35 +0100 +Subject: mfd: wm8350-core: Use IRQF_ONESHOT + +From: Sebastian Andrzej Siewior + +[ Upstream commit 553b4999cbe231b5011cb8db05a3092dec168aca ] + +Using a threaded interrupt without a dedicated primary handler mandates +the IRQF_ONESHOT flag to mask the interrupt source while the threaded +handler is active. Otherwise the interrupt can fire again before the +threaded handler had a chance to run. + +Mark explained that this should not happen with this hardware since it +is a slow irqchip which is behind an I2C/ SPI bus but the IRQ-core will +refuse to accept such a handler. + +Set IRQF_ONESHOT so the interrupt source is masked until the secondary +handler is done. + +Fixes: 1c6c69525b40e ("genirq: Reject bogus threaded irq requests") +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Reviewed-by: Charles Keepax +Reviewed-by: Andy Shevchenko +Link: https://patch.msgid.link/20260128095540.863589-16-bigeasy@linutronix.de +Signed-off-by: Sasha Levin +--- + include/linux/mfd/wm8350/core.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/linux/mfd/wm8350/core.h b/include/linux/mfd/wm8350/core.h +index a3241e4d75486..4816d4f472101 100644 +--- a/include/linux/mfd/wm8350/core.h ++++ b/include/linux/mfd/wm8350/core.h +@@ -663,7 +663,7 @@ static inline int wm8350_register_irq(struct wm8350 *wm8350, int irq, + return -ENODEV; + + return request_threaded_irq(irq + wm8350->irq_base, NULL, +- handler, flags, name, data); ++ handler, flags | IRQF_ONESHOT, name, data); + } + + static inline void wm8350_free_irq(struct wm8350 *wm8350, int irq, void *data) +-- +2.51.0 + diff --git a/queue-6.1/mmc-rtsx_pci_sdmmc-increase-power-on-settling-delay-.patch b/queue-6.1/mmc-rtsx_pci_sdmmc-increase-power-on-settling-delay-.patch new file mode 100644 index 0000000000..14f8c5025b --- /dev/null +++ b/queue-6.1/mmc-rtsx_pci_sdmmc-increase-power-on-settling-delay-.patch @@ -0,0 +1,40 @@ +From 7af62f01ddb4643fa228b553a69fed03a8c4b788 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 4 Jan 2026 22:02:36 -0800 +Subject: mmc: rtsx_pci_sdmmc: increase power-on settling delay to 5ms + +From: Matthew Schwartz + +[ Upstream commit aced969e9bf3701dc75cfca57c78c031b7875b9d ] + +The existing 1ms delay in sd_power_on is insufficient and causes resume +errors around 4% of the time. + +Increasing the delay to 5ms resolves this issue after testing 300 +s2idle cycles. + +Fixes: 1f311c94aabd ("mmc: rtsx: add 74 Clocks in power on flow") +Signed-off-by: Matthew Schwartz +Link: https://patch.msgid.link/20260105060236.400366-3-matthew.schwartz@linux.dev +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/mmc/host/rtsx_pci_sdmmc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c +index d063d50d69feb..02da9016245bd 100644 +--- a/drivers/mmc/host/rtsx_pci_sdmmc.c ++++ b/drivers/mmc/host/rtsx_pci_sdmmc.c +@@ -938,7 +938,7 @@ static int sd_power_on(struct realtek_pci_sdmmc *host, unsigned char power_mode) + if (err < 0) + return err; + +- mdelay(1); ++ mdelay(5); + + err = rtsx_pci_write_register(pcr, CARD_OE, SD_OUTPUT_EN, SD_OUTPUT_EN); + if (err < 0) +-- +2.51.0 + diff --git a/queue-6.1/module-add-helper-function-for-reading-module_buildi.patch b/queue-6.1/module-add-helper-function-for-reading-module_buildi.patch new file mode 100644 index 0000000000..965c03c481 --- /dev/null +++ b/queue-6.1/module-add-helper-function-for-reading-module_buildi.patch @@ -0,0 +1,80 @@ +From 7cde3a06140b05376295208719c0a5592e41f240 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 14:59:16 +0100 +Subject: module: add helper function for reading module_buildid() + +From: Petr Mladek + +[ Upstream commit acfdbb4ab2910ff6f03becb569c23ac7b2223913 ] + +Add a helper function for reading the optional "build_id" member of struct +module. It is going to be used also in ftrace_mod_address_lookup(). + +Use "#ifdef" instead of "#if IS_ENABLED()" to match the declaration of the +optional field in struct module. + +Link: https://lkml.kernel.org/r/20251128135920.217303-4-pmladek@suse.com +Signed-off-by: Petr Mladek +Reviewed-by: Daniel Gomez +Reviewed-by: Petr Pavlu +Cc: Aaron Tomlin +Cc: Alexei Starovoitov +Cc: Daniel Borkman +Cc: John Fastabend +Cc: Kees Cook +Cc: Luis Chamberalin +Cc: Marc Rutland +Cc: "Masami Hiramatsu (Google)" +Cc: Sami Tolvanen +Cc: Steven Rostedt (Google) +Signed-off-by: Andrew Morton +Stable-dep-of: e8a1e7eaa19d ("kallsyms/ftrace: set module buildid in ftrace_mod_address_lookup()") +Signed-off-by: Sasha Levin +--- + include/linux/module.h | 9 +++++++++ + kernel/module/kallsyms.c | 9 ++------- + 2 files changed, 11 insertions(+), 7 deletions(-) + +diff --git a/include/linux/module.h b/include/linux/module.h +index 41c4c472ed175..a119d2d6c0cba 100644 +--- a/include/linux/module.h ++++ b/include/linux/module.h +@@ -656,6 +656,15 @@ static inline void __module_get(struct module *module) + __mod ? __mod->name : "kernel"; \ + }) + ++static inline const unsigned char *module_buildid(struct module *mod) ++{ ++#ifdef CONFIG_STACKTRACE_BUILD_ID ++ return mod->build_id; ++#else ++ return NULL; ++#endif ++} ++ + /* Dereference module function descriptor */ + void *dereference_module_function_descriptor(struct module *mod, void *ptr); + +diff --git a/kernel/module/kallsyms.c b/kernel/module/kallsyms.c +index 4523f99b03589..824265d6dd166 100644 +--- a/kernel/module/kallsyms.c ++++ b/kernel/module/kallsyms.c +@@ -339,13 +339,8 @@ const char *module_address_lookup(unsigned long addr, + if (mod) { + if (modname) + *modname = mod->name; +- if (modbuildid) { +-#if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID) +- *modbuildid = mod->build_id; +-#else +- *modbuildid = NULL; +-#endif +- } ++ if (modbuildid) ++ *modbuildid = module_buildid(mod); + + ret = find_kallsyms_symbol(mod, addr, size, offset); + } +-- +2.51.0 + diff --git a/queue-6.1/mtd-parsers-ofpart-fix-of-node-refcount-leak-in-pars.patch b/queue-6.1/mtd-parsers-ofpart-fix-of-node-refcount-leak-in-pars.patch new file mode 100644 index 0000000000..d9118c4e0f --- /dev/null +++ b/queue-6.1/mtd-parsers-ofpart-fix-of-node-refcount-leak-in-pars.patch @@ -0,0 +1,84 @@ +From 364835ad968b7fa6028fcd95dc748352112ea20a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 05:26:08 +0000 +Subject: mtd: parsers: ofpart: fix OF node refcount leak in + parse_fixed_partitions() + +From: Weigang He + +[ Upstream commit 7cce81df7d26d44123bd7620715c8349d96793d7 ] + +of_get_child_by_name() returns a node pointer with refcount incremented, +which must be released with of_node_put() when done. However, in +parse_fixed_partitions(), when dedicated is true (i.e., a "partitions" +subnode was found), the ofpart_node obtained from of_get_child_by_name() +is never released on any code path. + +Add of_node_put(ofpart_node) calls on all exit paths when dedicated is +true to fix the reference count leak. + +This bug was detected by our static analysis tool. + +Fixes: 562b4e91d3b2 ("mtd: parsers: ofpart: fix parsing subpartitions") +Signed-off-by: Weigang He +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/parsers/ofpart_core.c | 16 ++++++++++++++-- + 1 file changed, 14 insertions(+), 2 deletions(-) + +diff --git a/drivers/mtd/parsers/ofpart_core.c b/drivers/mtd/parsers/ofpart_core.c +index e7b8e9d0a9103..3cf75b56d5a2e 100644 +--- a/drivers/mtd/parsers/ofpart_core.c ++++ b/drivers/mtd/parsers/ofpart_core.c +@@ -77,6 +77,7 @@ static int parse_fixed_partitions(struct mtd_info *master, + of_id = of_match_node(parse_ofpart_match_table, ofpart_node); + if (dedicated && !of_id) { + /* The 'partitions' subnode might be used by another parser */ ++ of_node_put(ofpart_node); + return 0; + } + +@@ -91,12 +92,18 @@ static int parse_fixed_partitions(struct mtd_info *master, + nr_parts++; + } + +- if (nr_parts == 0) ++ if (nr_parts == 0) { ++ if (dedicated) ++ of_node_put(ofpart_node); + return 0; ++ } + + parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL); +- if (!parts) ++ if (!parts) { ++ if (dedicated) ++ of_node_put(ofpart_node); + return -ENOMEM; ++ } + + i = 0; + for_each_child_of_node(ofpart_node, pp) { +@@ -175,6 +182,9 @@ static int parse_fixed_partitions(struct mtd_info *master, + if (quirks && quirks->post_parse) + quirks->post_parse(master, parts, nr_parts); + ++ if (dedicated) ++ of_node_put(ofpart_node); ++ + *pparts = parts; + return nr_parts; + +@@ -183,6 +193,8 @@ static int parse_fixed_partitions(struct mtd_info *master, + master->name, pp, mtd_node); + ret = -EINVAL; + ofpart_none: ++ if (dedicated) ++ of_node_put(ofpart_node); + of_node_put(pp); + kfree(parts); + return ret; +-- +2.51.0 + diff --git a/queue-6.1/mtd-rawnand-cadence-fix-return-type-of-cdma-send-and.patch b/queue-6.1/mtd-rawnand-cadence-fix-return-type-of-cdma-send-and.patch new file mode 100644 index 0000000000..50ab9a6e66 --- /dev/null +++ b/queue-6.1/mtd-rawnand-cadence-fix-return-type-of-cdma-send-and.patch @@ -0,0 +1,40 @@ +From bb16ceb363105044eb6bb536969f632a6160daff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 19 Dec 2025 03:09:30 -0800 +Subject: mtd: rawnand: cadence: Fix return type of CDMA send-and-wait helper + +From: Alok Tiwari + +[ Upstream commit 6d8226cbbf124bb5613b532216b74c886a4361b7 ] + +cadence_nand_cdma_send_and_wait() propagates negative errno values +from cadence_nand_cdma_send(), returns -ETIMEDOUT on failure and -EIO +when the CDMA engine reports a command failure. + +However, it is declared as u32, causing error codes to wrap. +Change the return type to int to correctly propagate errors. + +Fixes: ec4ba01e894d ("mtd: rawnand: Add new Cadence NAND driver to MTD subsystem") +Signed-off-by: Alok Tiwari +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/nand/raw/cadence-nand-controller.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/nand/raw/cadence-nand-controller.c b/drivers/mtd/nand/raw/cadence-nand-controller.c +index 5623bf5c34618..3a28ac5254289 100644 +--- a/drivers/mtd/nand/raw/cadence-nand-controller.c ++++ b/drivers/mtd/nand/raw/cadence-nand-controller.c +@@ -1018,7 +1018,7 @@ static int cadence_nand_cdma_send(struct cdns_nand_ctrl *cdns_ctrl, + } + + /* Send SDMA command and wait for finish. */ +-static u32 ++static int + cadence_nand_cdma_send_and_wait(struct cdns_nand_ctrl *cdns_ctrl, + u8 thread) + { +-- +2.51.0 + diff --git a/queue-6.1/net-add-skb_dstref_steal-and-skb_dstref_restore.patch b/queue-6.1/net-add-skb_dstref_steal-and-skb_dstref_restore.patch new file mode 100644 index 0000000000..d966de1ad3 --- /dev/null +++ b/queue-6.1/net-add-skb_dstref_steal-and-skb_dstref_restore.patch @@ -0,0 +1,73 @@ +From 2a3919c6ce7d7dcaa6e06d38e7a44bb3656a1bda Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 18 Aug 2025 08:40:26 -0700 +Subject: net: Add skb_dstref_steal and skb_dstref_restore + +From: Stanislav Fomichev + +[ Upstream commit c3f0c02997c7f8489fec259e28e0e04e9811edac ] + +Going forward skb_dst_set will assert that skb dst_entry +is empty during skb_dst_set to prevent potential leaks. There +are few places that still manually manage dst_entry not using +the helpers. Convert them to the following new helpers: +- skb_dstref_steal that resets dst_entry and returns previous dst_entry + value +- skb_dstref_restore that restores dst_entry previously reset via + skb_dstref_steal + +Signed-off-by: Stanislav Fomichev +Link: https://patch.msgid.link/20250818154032.3173645-2-sdf@fomichev.me +Signed-off-by: Jakub Kicinski +Stable-dep-of: 81b84de32bb2 ("xfrm: fix ip_rt_bug race in icmp_route_lookup reverse path") +Signed-off-by: Sasha Levin +--- + include/linux/skbuff.h | 32 ++++++++++++++++++++++++++++++++ + 1 file changed, 32 insertions(+) + +diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h +index 9a04a188b9f8e..af868e03b7dc8 100644 +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -1119,6 +1119,38 @@ static inline struct dst_entry *skb_dst(const struct sk_buff *skb) + return (struct dst_entry *)(skb->_skb_refdst & SKB_DST_PTRMASK); + } + ++/** ++ * skb_dstref_steal() - return current dst_entry value and clear it ++ * @skb: buffer ++ * ++ * Resets skb dst_entry without adjusting its reference count. Useful in ++ * cases where dst_entry needs to be temporarily reset and restored. ++ * Note that the returned value cannot be used directly because it ++ * might contain SKB_DST_NOREF bit. ++ * ++ * When in doubt, prefer skb_dst_drop() over skb_dstref_steal() to correctly ++ * handle dst_entry reference counting. ++ * ++ * Returns: original skb dst_entry. ++ */ ++static inline unsigned long skb_dstref_steal(struct sk_buff *skb) ++{ ++ unsigned long refdst = skb->_skb_refdst; ++ ++ skb->_skb_refdst = 0; ++ return refdst; ++} ++ ++/** ++ * skb_dstref_restore() - restore skb dst_entry removed via skb_dstref_steal() ++ * @skb: buffer ++ * @refdst: dst entry from a call to skb_dstref_steal() ++ */ ++static inline void skb_dstref_restore(struct sk_buff *skb, unsigned long refdst) ++{ ++ skb->_skb_refdst = refdst; ++} ++ + /** + * skb_dst_set - sets skb dst + * @skb: buffer +-- +2.51.0 + diff --git a/queue-6.1/net-atm-fix-crash-due-to-unvalidated-vcc-pointer-in-.patch b/queue-6.1/net-atm-fix-crash-due-to-unvalidated-vcc-pointer-in-.patch new file mode 100644 index 0000000000..03340f6948 --- /dev/null +++ b/queue-6.1/net-atm-fix-crash-due-to-unvalidated-vcc-pointer-in-.patch @@ -0,0 +1,154 @@ +From 7c3f942d08aa65d53be35ee70401902ad0534b28 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 17:54:51 +0800 +Subject: net: atm: fix crash due to unvalidated vcc pointer in sigd_send() + +From: Jiayuan Chen + +[ Upstream commit ae88a5d2f29b69819dc7b04086734439d074a643 ] + +Reproducer available at [1]. + +The ATM send path (sendmsg -> vcc_sendmsg -> sigd_send) reads the vcc +pointer from msg->vcc and uses it directly without any validation. This +pointer comes from userspace via sendmsg() and can be arbitrarily forged: + + int fd = socket(AF_ATMSVC, SOCK_DGRAM, 0); + ioctl(fd, ATMSIGD_CTRL); // become ATM signaling daemon + struct msghdr msg = { .msg_iov = &iov, ... }; + *(unsigned long *)(buf + 4) = 0xdeadbeef; // fake vcc pointer + sendmsg(fd, &msg, 0); // kernel dereferences 0xdeadbeef + +In normal operation, the kernel sends the vcc pointer to the signaling +daemon via sigd_enq() when processing operations like connect(), bind(), +or listen(). The daemon is expected to return the same pointer when +responding. However, a malicious daemon can send arbitrary pointer values. + +Fix this by introducing find_get_vcc() which validates the pointer by +searching through vcc_hash (similar to how sigd_close() iterates over +all VCCs), and acquires a reference via sock_hold() if found. + +Since struct atm_vcc embeds struct sock as its first member, they share +the same lifetime. Therefore using sock_hold/sock_put is sufficient to +keep the vcc alive while it is being used. + +Note that there may be a race with sigd_close() which could mark the vcc +with various flags (e.g., ATM_VF_RELEASED) after find_get_vcc() returns. +However, sock_hold() guarantees the memory remains valid, so this race +only affects the logical state, not memory safety. + +[1]: https://gist.github.com/mrpre/1ba5949c45529c511152e2f4c755b0f3 +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: syzbot+1f22cb1769f249df9fa0@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/69039850.a70a0220.5b2ed.005d.GAE@google.com/T/ +Signed-off-by: Jiayuan Chen +Link: https://patch.msgid.link/20260205095501.131890-1-jiayuan.chen@linux.dev +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/atm/signaling.c | 56 +++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 54 insertions(+), 2 deletions(-) + +diff --git a/net/atm/signaling.c b/net/atm/signaling.c +index 5de06ab8ed752..5a5d8b1fa8be8 100644 +--- a/net/atm/signaling.c ++++ b/net/atm/signaling.c +@@ -22,6 +22,36 @@ + + struct atm_vcc *sigd = NULL; + ++/* ++ * find_get_vcc - validate and get a reference to a vcc pointer ++ * @vcc: the vcc pointer to validate ++ * ++ * This function validates that @vcc points to a registered VCC in vcc_hash. ++ * If found, it increments the socket reference count and returns the vcc. ++ * The caller must call sock_put(sk_atm(vcc)) when done. ++ * ++ * Returns the vcc pointer if valid, NULL otherwise. ++ */ ++static struct atm_vcc *find_get_vcc(struct atm_vcc *vcc) ++{ ++ int i; ++ ++ read_lock(&vcc_sklist_lock); ++ for (i = 0; i < VCC_HTABLE_SIZE; i++) { ++ struct sock *s; ++ ++ sk_for_each(s, &vcc_hash[i]) { ++ if (atm_sk(s) == vcc) { ++ sock_hold(s); ++ read_unlock(&vcc_sklist_lock); ++ return vcc; ++ } ++ } ++ } ++ read_unlock(&vcc_sklist_lock); ++ return NULL; ++} ++ + static void sigd_put_skb(struct sk_buff *skb) + { + if (!sigd) { +@@ -69,7 +99,14 @@ static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb) + + msg = (struct atmsvc_msg *) skb->data; + WARN_ON(refcount_sub_and_test(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc)); +- vcc = *(struct atm_vcc **) &msg->vcc; ++ ++ vcc = find_get_vcc(*(struct atm_vcc **)&msg->vcc); ++ if (!vcc) { ++ pr_debug("invalid vcc pointer in msg\n"); ++ dev_kfree_skb(skb); ++ return -EINVAL; ++ } ++ + pr_debug("%d (0x%lx)\n", (int)msg->type, (unsigned long)vcc); + sk = sk_atm(vcc); + +@@ -100,7 +137,16 @@ static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb) + clear_bit(ATM_VF_WAITING, &vcc->flags); + break; + case as_indicate: +- vcc = *(struct atm_vcc **)&msg->listen_vcc; ++ /* Release the reference from msg->vcc, we'll use msg->listen_vcc instead */ ++ sock_put(sk); ++ ++ vcc = find_get_vcc(*(struct atm_vcc **)&msg->listen_vcc); ++ if (!vcc) { ++ pr_debug("invalid listen_vcc pointer in msg\n"); ++ dev_kfree_skb(skb); ++ return -EINVAL; ++ } ++ + sk = sk_atm(vcc); + pr_debug("as_indicate!!!\n"); + lock_sock(sk); +@@ -115,6 +161,8 @@ static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb) + sk->sk_state_change(sk); + as_indicate_complete: + release_sock(sk); ++ /* Paired with find_get_vcc(msg->listen_vcc) above */ ++ sock_put(sk); + return 0; + case as_close: + set_bit(ATM_VF_RELEASED, &vcc->flags); +@@ -131,11 +179,15 @@ static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb) + break; + default: + pr_alert("bad message type %d\n", (int)msg->type); ++ /* Paired with find_get_vcc(msg->vcc) above */ ++ sock_put(sk); + return -EINVAL; + } + sk->sk_state_change(sk); + out: + dev_kfree_skb(skb); ++ /* Paired with find_get_vcc(msg->vcc) above */ ++ sock_put(sk); + return 0; + } + +-- +2.51.0 + diff --git a/queue-6.1/net-hns3-fix-double-free-issue-for-tx-spare-buffer.patch b/queue-6.1/net-hns3-fix-double-free-issue-for-tx-spare-buffer.patch new file mode 100644 index 0000000000..8161bf4663 --- /dev/null +++ b/queue-6.1/net-hns3-fix-double-free-issue-for-tx-spare-buffer.patch @@ -0,0 +1,74 @@ +From 6dc7df25318d1f37bc1486dc3e2f112bf8062fe5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 20:17:19 +0800 +Subject: net: hns3: fix double free issue for tx spare buffer + +From: Jian Shen + +[ Upstream commit 6d2f142b1e4b203387a92519d9d2e34752a79dbb ] + +In hns3_set_ringparam(), a temporary copy (tmp_rings) of the ring structure +is created for rollback. However, the tx_spare pointer in the original +ring handle is incorrectly left pointing to the old backup memory. + +Later, if memory allocation fails in hns3_init_all_ring() during the setup, +the error path attempts to free all newly allocated rings. Since tx_spare +contains a stale (non-NULL) pointer from the backup, it is mistaken for +a newly allocated buffer and is erroneously freed, leading to a double-free +of the backup memory. + +The root cause is that the tx_spare field was not cleared after its value +was saved in tmp_rings, leaving a dangling pointer. + +Fix this by setting tx_spare to NULL in the original ring structure +when the creation of the new `tx_spare` fails. This ensures the +error cleanup path only frees genuinely newly allocated buffers. + +Fixes: 907676b130711 ("net: hns3: use tx bounce buffer for small packets") +Signed-off-by: Jian Shen +Signed-off-by: Jijie Shao +Reviewed-by: Jacob Keller +Link: https://patch.msgid.link/20260205121719.3285730-1-shaojijie@huawei.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +index 9bcd03e1994f6..646cfce10d804 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +@@ -1044,13 +1044,13 @@ static void hns3_init_tx_spare_buffer(struct hns3_enet_ring *ring) + int order; + + if (!alloc_size) +- return; ++ goto not_init; + + order = get_order(alloc_size); + if (order >= MAX_ORDER) { + if (net_ratelimit()) + dev_warn(ring_to_dev(ring), "failed to allocate tx spare buffer, exceed to max order\n"); +- return; ++ goto not_init; + } + + tx_spare = devm_kzalloc(ring_to_dev(ring), sizeof(*tx_spare), +@@ -1087,6 +1087,13 @@ static void hns3_init_tx_spare_buffer(struct hns3_enet_ring *ring) + devm_kfree(ring_to_dev(ring), tx_spare); + devm_kzalloc_error: + ring->tqp->handle->kinfo.tx_spare_buf_size = 0; ++not_init: ++ /* When driver init or reset_init, the ring->tx_spare is always NULL; ++ * but when called from hns3_set_ringparam, it's usually not NULL, and ++ * will be restored if hns3_init_all_ring() failed. So it's safe to set ++ * ring->tx_spare to NULL here. ++ */ ++ ring->tx_spare = NULL; + } + + /* Use hns3_tx_spare_space() to make sure there is enough buffer +-- +2.51.0 + diff --git a/queue-6.1/net-mctp-i2c-fix-duplicate-reception-of-old-data.patch b/queue-6.1/net-mctp-i2c-fix-duplicate-reception-of-old-data.patch new file mode 100644 index 0000000000..b4c9eae64e --- /dev/null +++ b/queue-6.1/net-mctp-i2c-fix-duplicate-reception-of-old-data.patch @@ -0,0 +1,49 @@ +From c627769ef499f1071afb873031cf3e53888a6f22 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 18:18:29 +0800 +Subject: net: mctp-i2c: fix duplicate reception of old data + +From: Jian Zhang + +[ Upstream commit ae4744e173fadd092c43eda4ca92dcb74645225a ] + +The MCTP I2C slave callback did not handle I2C_SLAVE_READ_REQUESTED +events. As a result, i2c read event will trigger repeated reception of +old data, reset rx_pos when a read request is received. + +Signed-off-by: Jian Zhang +Link: https://patch.msgid.link/20260108101829.1140448-1-zhangjian.3032@bytedance.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 2a14e91b6d76 ("mctp i2c: initialise event handler read bytes") +Signed-off-by: Sasha Levin +--- + drivers/net/mctp/mctp-i2c.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/mctp/mctp-i2c.c b/drivers/net/mctp/mctp-i2c.c +index 17619d011689f..1d0c516842793 100644 +--- a/drivers/net/mctp/mctp-i2c.c ++++ b/drivers/net/mctp/mctp-i2c.c +@@ -243,6 +243,9 @@ static int mctp_i2c_slave_cb(struct i2c_client *client, + return 0; + + switch (event) { ++ case I2C_SLAVE_READ_REQUESTED: ++ midev->rx_pos = 0; ++ break; + case I2C_SLAVE_WRITE_RECEIVED: + if (midev->rx_pos < MCTP_I2C_BUFSZ) { + midev->rx_buffer[midev->rx_pos] = *val; +@@ -280,6 +283,9 @@ static int mctp_i2c_recv(struct mctp_i2c_dev *midev) + size_t recvlen; + int status; + ++ if (midev->rx_pos == 0) ++ return 0; ++ + /* + 1 for the PEC */ + if (midev->rx_pos < MCTP_I2C_MINLEN + 1) { + ndev->stats.rx_length_errors++; +-- +2.51.0 + diff --git a/queue-6.1/net-switch-to-skb_dstref_steal-skb_dstref_restore-fo.patch b/queue-6.1/net-switch-to-skb_dstref_steal-skb_dstref_restore-fo.patch new file mode 100644 index 0000000000..e7e7b3bb38 --- /dev/null +++ b/queue-6.1/net-switch-to-skb_dstref_steal-skb_dstref_restore-fo.patch @@ -0,0 +1,75 @@ +From 629a05c0636b0f06701efaf4a811f68445e15009 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 18 Aug 2025 08:40:29 -0700 +Subject: net: Switch to skb_dstref_steal/skb_dstref_restore for ip_route_input + callers + +From: Stanislav Fomichev + +[ Upstream commit e97e6a1830ddb5885ba312e56b6fa3aa39b5f47e ] + +Going forward skb_dst_set will assert that skb dst_entry +is empty during skb_dst_set. skb_dstref_steal is added to reset +existing entry without doing refcnt. skb_dstref_restore should +be used to restore the previous entry. Convert icmp_route_lookup +and ip_options_rcv_srr to these helpers. Add extra call to +skb_dstref_reset to icmp_route_lookup to clear the ip_route_input +entry. + +Signed-off-by: Stanislav Fomichev +Link: https://patch.msgid.link/20250818154032.3173645-5-sdf@fomichev.me +Signed-off-by: Jakub Kicinski +Stable-dep-of: 81b84de32bb2 ("xfrm: fix ip_rt_bug race in icmp_route_lookup reverse path") +Signed-off-by: Sasha Levin +--- + net/ipv4/icmp.c | 7 ++++--- + net/ipv4/ip_options.c | 5 ++--- + 2 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c +index b17549c4e5de8..9e1a574384aa6 100644 +--- a/net/ipv4/icmp.c ++++ b/net/ipv4/icmp.c +@@ -546,14 +546,15 @@ static struct rtable *icmp_route_lookup(struct net *net, struct flowi4 *fl4, + goto relookup_failed; + } + /* Ugh! */ +- orefdst = skb_in->_skb_refdst; /* save old refdst */ +- skb_dst_set(skb_in, NULL); ++ orefdst = skb_dstref_steal(skb_in); + err = ip_route_input(skb_in, fl4_dec.daddr, fl4_dec.saddr, + dscp, rt2->dst.dev); + + dst_release(&rt2->dst); + rt2 = skb_rtable(skb_in); +- skb_in->_skb_refdst = orefdst; /* restore old refdst */ ++ /* steal dst entry from skb_in, don't drop refcnt */ ++ skb_dstref_steal(skb_in); ++ skb_dstref_restore(skb_in, orefdst); + } + + if (err) +diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c +index b4c59708fc095..d898e1523a453 100644 +--- a/net/ipv4/ip_options.c ++++ b/net/ipv4/ip_options.c +@@ -615,14 +615,13 @@ int ip_options_rcv_srr(struct sk_buff *skb, struct net_device *dev) + } + memcpy(&nexthop, &optptr[srrptr-1], 4); + +- orefdst = skb->_skb_refdst; +- skb_dst_set(skb, NULL); ++ orefdst = skb_dstref_steal(skb); + err = ip_route_input(skb, nexthop, iph->saddr, ip4h_dscp(iph), + dev); + rt2 = skb_rtable(skb); + if (err || (rt2->rt_type != RTN_UNICAST && rt2->rt_type != RTN_LOCAL)) { + skb_dst_drop(skb); +- skb->_skb_refdst = orefdst; ++ skb_dstref_restore(skb, orefdst); + return -EINVAL; + } + refdst_drop(orefdst); +-- +2.51.0 + diff --git a/queue-6.1/netfilter-nf_conncount-fix-tracking-of-connections-f.patch b/queue-6.1/netfilter-nf_conncount-fix-tracking-of-connections-f.patch new file mode 100644 index 0000000000..f772af09ed --- /dev/null +++ b/queue-6.1/netfilter-nf_conncount-fix-tracking-of-connections-f.patch @@ -0,0 +1,69 @@ +From 07da215971c5075c7585d044c10391d550b469a7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 21:35:46 +0100 +Subject: netfilter: nf_conncount: fix tracking of connections from localhost + +From: Fernando Fernandez Mancera + +[ Upstream commit de8a70cefcb26cdceaafdc5ac144712681419c29 ] + +Since commit be102eb6a0e7 ("netfilter: nf_conncount: rework API to use +sk_buff directly"), we skip the adding and trigger a GC when the ct is +confirmed. For connections originated from local to local it doesn't +work because the connection is confirmed on POSTROUTING, therefore +tracking on the INPUT hook is always skipped. + +In order to fix this, we check whether skb input ifindex is set to +loopback ifindex. If it is then we fallback on a GC plus track operation +skipping the optimization. This fallback is necessary to avoid +duplicated tracking of a packet train e.g 10 UDP datagrams sent on a +burst when initiating the connection. + +Tested with xt_connlimit/nft_connlimit and OVS limit and with a HTTP +server and iperf3 on UDP mode. + +Fixes: be102eb6a0e7 ("netfilter: nf_conncount: rework API to use sk_buff directly") +Reported-by: Michal Slabihoudek +Closes: https://lore.kernel.org/netfilter/6989BD9F-8C24-4397-9AD7-4613B28BF0DB@gooddata.com/ +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_conncount.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +diff --git a/net/netfilter/nf_conncount.c b/net/netfilter/nf_conncount.c +index 47bdd8d121bb5..ae9ad439449fa 100644 +--- a/net/netfilter/nf_conncount.c ++++ b/net/netfilter/nf_conncount.c +@@ -179,14 +179,25 @@ static int __nf_conncount_add(struct net *net, + return -ENOENT; + + if (ct && nf_ct_is_confirmed(ct)) { +- err = -EEXIST; +- goto out_put; ++ /* local connections are confirmed in postrouting so confirmation ++ * might have happened before hitting connlimit ++ */ ++ if (skb->skb_iif != LOOPBACK_IFINDEX) { ++ err = -EEXIST; ++ goto out_put; ++ } ++ ++ /* this is likely a local connection, skip optimization to avoid ++ * adding duplicates from a 'packet train' ++ */ ++ goto check_connections; + } + + if ((u32)jiffies == list->last_gc && + (list->count - list->last_gc_count) < CONNCOUNT_GC_MAX_COLLECT) + goto add_new_node; + ++check_connections: + /* check the saved connections */ + list_for_each_entry_safe(conn, conn_n, &list->head, node) { + if (collect > CONNCOUNT_GC_MAX_COLLECT) +-- +2.51.0 + diff --git a/queue-6.1/netfilter-nf_conncount-increase-the-connection-clean.patch b/queue-6.1/netfilter-nf_conncount-increase-the-connection-clean.patch new file mode 100644 index 0000000000..9aa27d20c0 --- /dev/null +++ b/queue-6.1/netfilter-nf_conncount-increase-the-connection-clean.patch @@ -0,0 +1,123 @@ +From f219d79e363a48f253f79e6c0a3b96080a11f6cc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 17 Dec 2025 15:46:41 +0100 +Subject: netfilter: nf_conncount: increase the connection clean up limit to 64 + +From: Fernando Fernandez Mancera + +[ Upstream commit 21d033e472735ecec677f1ae46d6740b5e47a4f3 ] + +After the optimization to only perform one GC per jiffy, a new problem +was introduced. If more than 8 new connections are tracked per jiffy the +list won't be cleaned up fast enough possibly reaching the limit +wrongly. + +In order to prevent this issue, only skip the GC if it was already +triggered during the same jiffy and the increment is lower than the +clean up limit. In addition, increase the clean up limit to 64 +connections to avoid triggering GC too often and do more effective GCs. + +This has been tested using a HTTP server and several +performance tools while having nft_connlimit/xt_connlimit or OVS limit +configured. + +Output of slowhttptest + OVS limit at 52000 connections: + + slow HTTP test status on 340th second: + initializing: 0 + pending: 432 + connected: 51998 + error: 0 + closed: 0 + service available: YES + +Fixes: d265929930e2 ("netfilter: nf_conncount: reduce unnecessary GC") +Reported-by: Aleksandra Rukomoinikova +Closes: https://lore.kernel.org/netfilter/b2064e7b-0776-4e14-adb6-c68080987471@k2.cloud/ +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + include/net/netfilter/nf_conntrack_count.h | 1 + + net/netfilter/nf_conncount.c | 15 ++++++++++----- + 2 files changed, 11 insertions(+), 5 deletions(-) + +diff --git a/include/net/netfilter/nf_conntrack_count.h b/include/net/netfilter/nf_conntrack_count.h +index 115bb7e572f7d..bf22661925b81 100644 +--- a/include/net/netfilter/nf_conntrack_count.h ++++ b/include/net/netfilter/nf_conntrack_count.h +@@ -13,6 +13,7 @@ struct nf_conncount_list { + u32 last_gc; /* jiffies at most recent gc */ + struct list_head head; /* connections with the same filtering key */ + unsigned int count; /* length of list */ ++ unsigned int last_gc_count; /* length of list at most recent gc */ + }; + + struct nf_conncount_data *nf_conncount_init(struct net *net, unsigned int family, +diff --git a/net/netfilter/nf_conncount.c b/net/netfilter/nf_conncount.c +index 70e9662fe1777..47bdd8d121bb5 100644 +--- a/net/netfilter/nf_conncount.c ++++ b/net/netfilter/nf_conncount.c +@@ -34,8 +34,9 @@ + + #define CONNCOUNT_SLOTS 256U + +-#define CONNCOUNT_GC_MAX_NODES 8 +-#define MAX_KEYLEN 5 ++#define CONNCOUNT_GC_MAX_NODES 8 ++#define CONNCOUNT_GC_MAX_COLLECT 64 ++#define MAX_KEYLEN 5 + + /* we will save the tuples of all connections we care about */ + struct nf_conncount_tuple { +@@ -182,12 +183,13 @@ static int __nf_conncount_add(struct net *net, + goto out_put; + } + +- if ((u32)jiffies == list->last_gc) ++ if ((u32)jiffies == list->last_gc && ++ (list->count - list->last_gc_count) < CONNCOUNT_GC_MAX_COLLECT) + goto add_new_node; + + /* check the saved connections */ + list_for_each_entry_safe(conn, conn_n, &list->head, node) { +- if (collect > CONNCOUNT_GC_MAX_NODES) ++ if (collect > CONNCOUNT_GC_MAX_COLLECT) + break; + + found = find_or_evict(net, list, conn); +@@ -230,6 +232,7 @@ static int __nf_conncount_add(struct net *net, + nf_ct_put(found_ct); + } + list->last_gc = (u32)jiffies; ++ list->last_gc_count = list->count; + + add_new_node: + if (WARN_ON_ONCE(list->count > INT_MAX)) { +@@ -277,6 +280,7 @@ void nf_conncount_list_init(struct nf_conncount_list *list) + spin_lock_init(&list->list_lock); + INIT_LIST_HEAD(&list->head); + list->count = 0; ++ list->last_gc_count = 0; + list->last_gc = (u32)jiffies; + } + EXPORT_SYMBOL_GPL(nf_conncount_list_init); +@@ -316,13 +320,14 @@ static bool __nf_conncount_gc_list(struct net *net, + } + + nf_ct_put(found_ct); +- if (collected > CONNCOUNT_GC_MAX_NODES) ++ if (collected > CONNCOUNT_GC_MAX_COLLECT) + break; + } + + if (!list->count) + ret = true; + list->last_gc = (u32)jiffies; ++ list->last_gc_count = list->count; + + return ret; + } +-- +2.51.0 + diff --git a/queue-6.1/netfilter-nf_conncount-make-nf_conncount_gc_list-to-.patch b/queue-6.1/netfilter-nf_conncount-make-nf_conncount_gc_list-to-.patch new file mode 100644 index 0000000000..ec56b9e4ab --- /dev/null +++ b/queue-6.1/netfilter-nf_conncount-make-nf_conncount_gc_list-to-.patch @@ -0,0 +1,93 @@ +From 635e4ae07e044503327f98b04a1ea486f6091e61 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 21 Nov 2025 01:14:31 +0100 +Subject: netfilter: nf_conncount: make nf_conncount_gc_list() to disable BH + +From: Fernando Fernandez Mancera + +[ Upstream commit c0362b5748282e22fa1592a8d3474f726ad964c2 ] + +For convenience when performing GC over the connection list, make +nf_conncount_gc_list() to disable BH. This unifies the behavior with +nf_conncount_add() and nf_conncount_count(). + +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: 21d033e47273 ("netfilter: nf_conncount: increase the connection clean up limit to 64") +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_conncount.c | 24 +++++++++++++++++------- + net/netfilter/nft_connlimit.c | 7 +------ + 2 files changed, 18 insertions(+), 13 deletions(-) + +diff --git a/net/netfilter/nf_conncount.c b/net/netfilter/nf_conncount.c +index a2c5a7ba0c6fc..70e9662fe1777 100644 +--- a/net/netfilter/nf_conncount.c ++++ b/net/netfilter/nf_conncount.c +@@ -282,8 +282,8 @@ void nf_conncount_list_init(struct nf_conncount_list *list) + EXPORT_SYMBOL_GPL(nf_conncount_list_init); + + /* Return true if the list is empty. Must be called with BH disabled. */ +-bool nf_conncount_gc_list(struct net *net, +- struct nf_conncount_list *list) ++static bool __nf_conncount_gc_list(struct net *net, ++ struct nf_conncount_list *list) + { + const struct nf_conntrack_tuple_hash *found; + struct nf_conncount_tuple *conn, *conn_n; +@@ -295,10 +295,6 @@ bool nf_conncount_gc_list(struct net *net, + if ((u32)jiffies == READ_ONCE(list->last_gc)) + return false; + +- /* don't bother if other cpu is already doing GC */ +- if (!spin_trylock(&list->list_lock)) +- return false; +- + list_for_each_entry_safe(conn, conn_n, &list->head, node) { + found = find_or_evict(net, list, conn); + if (IS_ERR(found)) { +@@ -327,7 +323,21 @@ bool nf_conncount_gc_list(struct net *net, + if (!list->count) + ret = true; + list->last_gc = (u32)jiffies; +- spin_unlock(&list->list_lock); ++ ++ return ret; ++} ++ ++bool nf_conncount_gc_list(struct net *net, ++ struct nf_conncount_list *list) ++{ ++ bool ret; ++ ++ /* don't bother if other cpu is already doing GC */ ++ if (!spin_trylock_bh(&list->list_lock)) ++ return false; ++ ++ ret = __nf_conncount_gc_list(net, list); ++ spin_unlock_bh(&list->list_lock); + + return ret; + } +diff --git a/net/netfilter/nft_connlimit.c b/net/netfilter/nft_connlimit.c +index f47a4932dc734..b3411dec16fd2 100644 +--- a/net/netfilter/nft_connlimit.c ++++ b/net/netfilter/nft_connlimit.c +@@ -231,13 +231,8 @@ static void nft_connlimit_destroy_clone(const struct nft_ctx *ctx, + static bool nft_connlimit_gc(struct net *net, const struct nft_expr *expr) + { + struct nft_connlimit *priv = nft_expr_priv(expr); +- bool ret; + +- local_bh_disable(); +- ret = nf_conncount_gc_list(net, priv->list); +- local_bh_enable(); +- +- return ret; ++ return nf_conncount_gc_list(net, priv->list); + } + + static struct nft_expr_type nft_connlimit_type; +-- +2.51.0 + diff --git a/queue-6.1/netfilter-nft_compat-add-more-restrictions-on-netlin.patch b/queue-6.1/netfilter-nft_compat-add-more-restrictions-on-netlin.patch new file mode 100644 index 0000000000..7ab24d0645 --- /dev/null +++ b/queue-6.1/netfilter-nft_compat-add-more-restrictions-on-netlin.patch @@ -0,0 +1,71 @@ +From 4b2460176f8d55dce7f643fc7013c16024442683 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 19 Aug 2022 16:16:07 +0200 +Subject: netfilter: nft_compat: add more restrictions on netlink attributes + +From: Florian Westphal + +[ Upstream commit cda26c645946b08f070f20c166d4736767e4a805 ] + +As far as I can see nothing bad can happen when NFTA_TARGET/MATCH_NAME +are too large because this calls x_tables helpers which check for the +length, but it seems better to already reject it during netlink parsing. + +Rest of the changes avoid silent u8/u16 truncations. + +For _TYPE, its expected to be only 1 or 0. In x_tables world, this +variable is set by kernel, for IPT_SO_GET_REVISION_TARGET its 1, for +all others its set to 0. + +As older versions of nf_tables permitted any value except 1 to mean 'match', +keep this as-is but sanitize the value for consistency. + +Fixes: 0ca743a55991 ("netfilter: nf_tables: add compatibility layer for x_tables") +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_compat.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/net/netfilter/nft_compat.c b/net/netfilter/nft_compat.c +index e4b8c02c5e6ae..4f674a472bb69 100644 +--- a/net/netfilter/nft_compat.c ++++ b/net/netfilter/nft_compat.c +@@ -134,7 +134,8 @@ static void nft_target_eval_bridge(const struct nft_expr *expr, + } + + static const struct nla_policy nft_target_policy[NFTA_TARGET_MAX + 1] = { +- [NFTA_TARGET_NAME] = { .type = NLA_NUL_STRING }, ++ [NFTA_TARGET_NAME] = { .type = NLA_NUL_STRING, ++ .len = XT_EXTENSION_MAXNAMELEN, }, + [NFTA_TARGET_REV] = NLA_POLICY_MAX(NLA_BE32, 255), + [NFTA_TARGET_INFO] = { .type = NLA_BINARY }, + }; +@@ -434,7 +435,8 @@ static void nft_match_eval(const struct nft_expr *expr, + } + + static const struct nla_policy nft_match_policy[NFTA_MATCH_MAX + 1] = { +- [NFTA_MATCH_NAME] = { .type = NLA_NUL_STRING }, ++ [NFTA_MATCH_NAME] = { .type = NLA_NUL_STRING, ++ .len = XT_EXTENSION_MAXNAMELEN }, + [NFTA_MATCH_REV] = NLA_POLICY_MAX(NLA_BE32, 255), + [NFTA_MATCH_INFO] = { .type = NLA_BINARY }, + }; +@@ -692,7 +694,12 @@ static int nfnl_compat_get_rcu(struct sk_buff *skb, + + name = nla_data(tb[NFTA_COMPAT_NAME]); + rev = ntohl(nla_get_be32(tb[NFTA_COMPAT_REV])); +- target = ntohl(nla_get_be32(tb[NFTA_COMPAT_TYPE])); ++ /* x_tables api checks for 'target == 1' to mean target, ++ * everything else means 'match'. ++ * In x_tables world, the number is set by kernel, not ++ * userspace. ++ */ ++ target = nla_get_be32(tb[NFTA_COMPAT_TYPE]) == htonl(1); + + switch(family) { + case AF_INET: +-- +2.51.0 + diff --git a/queue-6.1/netfilter-nft_counter-fix-reset-of-counters-on-32bit.patch b/queue-6.1/netfilter-nft_counter-fix-reset-of-counters-on-32bit.patch new file mode 100644 index 0000000000..f6b2c0fa08 --- /dev/null +++ b/queue-6.1/netfilter-nft_counter-fix-reset-of-counters-on-32bit.patch @@ -0,0 +1,75 @@ +From 6564fed8775e1d11cd9da6672183632b8b4e5df2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 14:48:30 +0100 +Subject: netfilter: nft_counter: fix reset of counters on 32bit archs + +From: Anders Grahn + +[ Upstream commit 1e13f27e0675552161ab1778be9a23a636dde8a7 ] + +nft_counter_reset() calls u64_stats_add() with a negative value to reset +the counter. This will work on 64bit archs, hence the negative value +added will wrap as a 64bit value which then can wrap the stat counter as +well. + +On 32bit archs, the added negative value will wrap as a 32bit value and +_not_ wrapping the stat counter properly. In most cases, this would just +lead to a very large 32bit value being added to the stat counter. + +Fix by introducing u64_stats_sub(). + +Fixes: 4a1d3acd6ea8 ("netfilter: nft_counter: Use u64_stats_t for statistic.") +Signed-off-by: Anders Grahn +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + include/linux/u64_stats_sync.h | 10 ++++++++++ + net/netfilter/nft_counter.c | 4 ++-- + 2 files changed, 12 insertions(+), 2 deletions(-) + +diff --git a/include/linux/u64_stats_sync.h b/include/linux/u64_stats_sync.h +index 79c3bbaa7e13e..0a3f9416f8464 100644 +--- a/include/linux/u64_stats_sync.h ++++ b/include/linux/u64_stats_sync.h +@@ -89,6 +89,11 @@ static inline void u64_stats_add(u64_stats_t *p, unsigned long val) + local64_add(val, &p->v); + } + ++static inline void u64_stats_sub(u64_stats_t *p, s64 val) ++{ ++ local64_sub(val, &p->v); ++} ++ + static inline void u64_stats_inc(u64_stats_t *p) + { + local64_inc(&p->v); +@@ -130,6 +135,11 @@ static inline void u64_stats_add(u64_stats_t *p, unsigned long val) + p->v += val; + } + ++static inline void u64_stats_sub(u64_stats_t *p, s64 val) ++{ ++ p->v -= val; ++} ++ + static inline void u64_stats_inc(u64_stats_t *p) + { + p->v++; +diff --git a/net/netfilter/nft_counter.c b/net/netfilter/nft_counter.c +index 8d19bd0012770..7411bba75d4cb 100644 +--- a/net/netfilter/nft_counter.c ++++ b/net/netfilter/nft_counter.c +@@ -117,8 +117,8 @@ static void nft_counter_reset(struct nft_counter_percpu_priv *priv, + nft_sync = this_cpu_ptr(&nft_counter_sync); + + u64_stats_update_begin(nft_sync); +- u64_stats_add(&this_cpu->packets, -total->packets); +- u64_stats_add(&this_cpu->bytes, -total->bytes); ++ u64_stats_sub(&this_cpu->packets, total->packets); ++ u64_stats_sub(&this_cpu->bytes, total->bytes); + u64_stats_update_end(nft_sync); + + local_bh_enable(); +-- +2.51.0 + diff --git a/queue-6.1/netfilter-nft_set_hash-fix-get-operation-on-big-endi.patch b/queue-6.1/netfilter-nft_set_hash-fix-get-operation-on-big-endi.patch new file mode 100644 index 0000000000..9dd46e62c3 --- /dev/null +++ b/queue-6.1/netfilter-nft_set_hash-fix-get-operation-on-big-endi.patch @@ -0,0 +1,57 @@ +From 07ceb232a606654c49661949e58cb0f2d3cd2eb2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 20:13:45 +0100 +Subject: netfilter: nft_set_hash: fix get operation on big endian + +From: Florian Westphal + +[ Upstream commit 2f635adbe2642d398a0be3ab245accd2987be0c3 ] + +tests/shell/testcases/packetpath/set_match_nomatch_hash_fast +fails on big endian with: + +Error: Could not process rule: No such file or directory +reset element ip test s { 244.147.90.126 } +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Fatal: Cannot fetch element "244.147.90.126" + +... because the wrong bucket is searched, jhash() and jhash1_word are +not interchangeable on big endian. + +Fixes: 3b02b0adc242 ("netfilter: nft_set_hash: fix lookups with fixed size hash on big endian") +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_set_hash.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/net/netfilter/nft_set_hash.c b/net/netfilter/nft_set_hash.c +index a592cca7a61f9..9ea4a09903186 100644 +--- a/net/netfilter/nft_set_hash.c ++++ b/net/netfilter/nft_set_hash.c +@@ -527,15 +527,20 @@ bool nft_hash_lookup(const struct net *net, const struct nft_set *set, + static void *nft_hash_get(const struct net *net, const struct nft_set *set, + const struct nft_set_elem *elem, unsigned int flags) + { ++ const u32 *key = (const u32 *)&elem->key.val; + struct nft_hash *priv = nft_set_priv(set); + u8 genmask = nft_genmask_cur(net); + struct nft_hash_elem *he; + u32 hash; + +- hash = jhash(elem->key.val.data, set->klen, priv->seed); ++ if (set->klen == 4) ++ hash = jhash_1word(*key, priv->seed); ++ else ++ hash = jhash(key, set->klen, priv->seed); ++ + hash = reciprocal_scale(hash, priv->buckets); + hlist_for_each_entry_rcu(he, &priv->table[hash], node) { +- if (!memcmp(nft_set_ext_key(&he->ext), elem->key.val.data, set->klen) && ++ if (!memcmp(nft_set_ext_key(&he->ext), key, set->klen) && + nft_set_elem_active(&he->ext, genmask)) + return he; + } +-- +2.51.0 + diff --git a/queue-6.1/netfilter-nft_set_rbtree-check-for-partial-overlaps-.patch b/queue-6.1/netfilter-nft_set_rbtree-check-for-partial-overlaps-.patch new file mode 100644 index 0000000000..aabdfbe35e --- /dev/null +++ b/queue-6.1/netfilter-nft_set_rbtree-check-for-partial-overlaps-.patch @@ -0,0 +1,90 @@ +From 81344a093918f7867787363e7483712dfcb6bc51 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 13:33:44 +0100 +Subject: netfilter: nft_set_rbtree: check for partial overlaps in anonymous + sets + +From: Pablo Neira Ayuso + +[ Upstream commit 4780ec142cbb24b794129d3080eee5cac2943ffc ] + +Userspace provides an optimized representation in case intervals are +adjacent, where the end element is omitted. + +The existing partial overlap detection logic skips anonymous set checks +on start elements for this reason. + +However, it is possible to add intervals that overlap to this anonymous +where two start elements with the same, eg. A-B, A-C where C < B. + + start end + A B + start end + A C + +Restore the check on overlapping start elements to report an overlap. + +Fixes: c9e6978e2725 ("netfilter: nft_set_rbtree: Switch to node list walk for overlap detection") +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_set_rbtree.c | 30 +++++++++++++++++++++++++----- + 1 file changed, 25 insertions(+), 5 deletions(-) + +diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c +index 021d9e76129a5..426becaad1b94 100644 +--- a/net/netfilter/nft_set_rbtree.c ++++ b/net/netfilter/nft_set_rbtree.c +@@ -305,11 +305,23 @@ static bool nft_rbtree_update_first(const struct nft_set *set, + return false; + } + ++/* Only for anonymous sets which do not allow updates, all element are active. */ ++static struct nft_rbtree_elem *nft_rbtree_prev_active(struct nft_rbtree_elem *rbe) ++{ ++ struct rb_node *node; ++ ++ node = rb_prev(&rbe->node); ++ if (!node) ++ return NULL; ++ ++ return rb_entry(node, struct nft_rbtree_elem, node); ++} ++ + static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set, + struct nft_rbtree_elem *new, + struct nft_set_ext **ext) + { +- struct nft_rbtree_elem *rbe, *rbe_le = NULL, *rbe_ge = NULL; ++ struct nft_rbtree_elem *rbe, *rbe_le = NULL, *rbe_ge = NULL, *rbe_prev; + struct rb_node *node, *next, *parent, **p, *first = NULL; + struct nft_rbtree *priv = nft_set_priv(set); + u8 cur_genmask = nft_genmask_cur(net); +@@ -441,11 +453,19 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set, + /* - new start element with existing closest, less or equal key value + * being a start element: partial overlap, reported as -ENOTEMPTY. + * Anonymous sets allow for two consecutive start element since they +- * are constant, skip them to avoid bogus overlap reports. ++ * are constant, but validate that this new start element does not ++ * sit in between an existing start and end elements: partial overlap, ++ * reported as -ENOTEMPTY. + */ +- if (!nft_set_is_anonymous(set) && rbe_le && +- nft_rbtree_interval_start(rbe_le) && nft_rbtree_interval_start(new)) +- return -ENOTEMPTY; ++ if (rbe_le && ++ nft_rbtree_interval_start(rbe_le) && nft_rbtree_interval_start(new)) { ++ if (!nft_set_is_anonymous(set)) ++ return -ENOTEMPTY; ++ ++ rbe_prev = nft_rbtree_prev_active(rbe_le); ++ if (rbe_prev && nft_rbtree_interval_end(rbe_prev)) ++ return -ENOTEMPTY; ++ } + + /* - new end element with existing closest, less or equal key value + * being a end element: partial overlap, reported as -ENOTEMPTY. +-- +2.51.0 + diff --git a/queue-6.1/nfc-hci-shdlc-stop-timers-and-work-before-freeing-co.patch b/queue-6.1/nfc-hci-shdlc-stop-timers-and-work-before-freeing-co.patch new file mode 100644 index 0000000000..0399b61d1a --- /dev/null +++ b/queue-6.1/nfc-hci-shdlc-stop-timers-and-work-before-freeing-co.patch @@ -0,0 +1,52 @@ +From 321665932a77ae665a538f5d810823627e1623fb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 14:31:57 +0300 +Subject: nfc: hci: shdlc: Stop timers and work before freeing context + +From: Votokina Victoria + +[ Upstream commit c9efde1e537baed7648a94022b43836a348a074f ] + +llc_shdlc_deinit() purges SHDLC skb queues and frees the llc_shdlc +structure while its timers and state machine work may still be active. + +Timer callbacks can schedule sm_work, and sm_work accesses SHDLC state +and the skb queues. If teardown happens in parallel with a queued/running +work item, it can lead to UAF and other shutdown races. + +Stop all SHDLC timers and cancel sm_work synchronously before purging the +queues and freeing the context. + +Found by Linux Verification Center (linuxtesting.org) with SVACE. + +Fixes: 4a61cd6687fc ("NFC: Add an shdlc llc module to llc core") +Signed-off-by: Votokina Victoria +Link: https://patch.msgid.link/20260203113158.2008723-1-Victoria.Votokina@kaspersky.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/nfc/hci/llc_shdlc.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/net/nfc/hci/llc_shdlc.c b/net/nfc/hci/llc_shdlc.c +index e90f70385813a..a106f4352356d 100644 +--- a/net/nfc/hci/llc_shdlc.c ++++ b/net/nfc/hci/llc_shdlc.c +@@ -762,6 +762,14 @@ static void llc_shdlc_deinit(struct nfc_llc *llc) + { + struct llc_shdlc *shdlc = nfc_llc_get_data(llc); + ++ timer_shutdown_sync(&shdlc->connect_timer); ++ timer_shutdown_sync(&shdlc->t1_timer); ++ timer_shutdown_sync(&shdlc->t2_timer); ++ shdlc->t1_active = false; ++ shdlc->t2_active = false; ++ ++ cancel_work_sync(&shdlc->sm_work); ++ + skb_queue_purge(&shdlc->rcv_q); + skb_queue_purge(&shdlc->send_q); + skb_queue_purge(&shdlc->ack_pending_q); +-- +2.51.0 + diff --git a/queue-6.1/nfsd-never-defer-requests-during-idmap-lookup.patch b/queue-6.1/nfsd-never-defer-requests-during-idmap-lookup.patch new file mode 100644 index 0000000000..15c94c2bed --- /dev/null +++ b/queue-6.1/nfsd-never-defer-requests-during-idmap-lookup.patch @@ -0,0 +1,152 @@ +From bad854f63c4069ca2e7284dccc922ab7c68ea457 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 22 Dec 2025 14:30:04 -0500 +Subject: nfsd: never defer requests during idmap lookup + +From: Anthony Iliopoulos + +[ Upstream commit f9c206cdc4266caad6a9a7f46341420a10f03ccb ] + +During v4 request compound arg decoding, some ops (e.g. SETATTR) +can trigger idmap lookup upcalls. When those upcall responses get +delayed beyond the allowed time limit, cache_check() will mark the +request for deferral and cause it to be dropped. + +This prevents nfs4svc_encode_compoundres from being executed, and +thus the session slot flag NFSD4_SLOT_INUSE never gets cleared. +Subsequent client requests will fail with NFSERR_JUKEBOX, given +that the slot will be marked as in-use, making the SEQUENCE op +fail. + +Fix this by making sure that the RQ_USEDEFERRAL flag is always +clear during nfs4svc_decode_compoundargs(), since no v4 request +should ever be deferred. + +Fixes: 2f425878b6a7 ("nfsd: don't use the deferral service, return NFS4ERR_DELAY") +Signed-off-by: Anthony Iliopoulos +Reviewed-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4idmap.c | 48 +++++++++++++++++++++++++++++++++++++++------ + fs/nfsd/nfs4proc.c | 2 -- + fs/nfsd/nfs4xdr.c | 16 +++++++++++++++ + 3 files changed, 58 insertions(+), 8 deletions(-) + +diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c +index 717e400b16b86..21e5b4c990ef3 100644 +--- a/fs/nfsd/nfs4idmap.c ++++ b/fs/nfsd/nfs4idmap.c +@@ -643,13 +643,31 @@ static __be32 encode_name_from_id(struct xdr_stream *xdr, + return idmap_id_to_name(xdr, rqstp, type, id); + } + +-__be32 +-nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen, +- kuid_t *uid) ++/** ++ * nfsd_map_name_to_uid - Map user@domain to local UID ++ * @rqstp: RPC execution context ++ * @name: user@domain name to be mapped ++ * @namelen: length of name, in bytes ++ * @uid: OUT: mapped local UID value ++ * ++ * Returns nfs_ok on success or an NFSv4 status code on failure. ++ */ ++__be32 nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, ++ size_t namelen, kuid_t *uid) + { + __be32 status; + u32 id = -1; + ++ /* ++ * The idmap lookup below triggers an upcall that invokes ++ * cache_check(). RQ_USEDEFERRAL must be clear to prevent ++ * cache_check() from setting RQ_DROPME via svc_defer(). ++ * NFSv4 servers are not permitted to drop requests. Also ++ * RQ_DROPME will force NFSv4.1 session slot processing to ++ * be skipped. ++ */ ++ WARN_ON_ONCE(test_bit(RQ_USEDEFERRAL, &rqstp->rq_flags)); ++ + if (name == NULL || namelen == 0) + return nfserr_inval; + +@@ -660,13 +678,31 @@ nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen, + return status; + } + +-__be32 +-nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, size_t namelen, +- kgid_t *gid) ++/** ++ * nfsd_map_name_to_gid - Map user@domain to local GID ++ * @rqstp: RPC execution context ++ * @name: user@domain name to be mapped ++ * @namelen: length of name, in bytes ++ * @gid: OUT: mapped local GID value ++ * ++ * Returns nfs_ok on success or an NFSv4 status code on failure. ++ */ ++__be32 nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, ++ size_t namelen, kgid_t *gid) + { + __be32 status; + u32 id = -1; + ++ /* ++ * The idmap lookup below triggers an upcall that invokes ++ * cache_check(). RQ_USEDEFERRAL must be clear to prevent ++ * cache_check() from setting RQ_DROPME via svc_defer(). ++ * NFSv4 servers are not permitted to drop requests. Also ++ * RQ_DROPME will force NFSv4.1 session slot processing to ++ * be skipped. ++ */ ++ WARN_ON_ONCE(test_bit(RQ_USEDEFERRAL, &rqstp->rq_flags)); ++ + if (name == NULL || namelen == 0) + return nfserr_inval; + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 714e4c471e863..d29a37f696a44 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -2716,8 +2716,6 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) + BUG_ON(cstate->replay_owner); + out: + cstate->status = status; +- /* Reset deferral mechanism for RPC deferrals */ +- set_bit(RQ_USEDEFERRAL, &rqstp->rq_flags); + return rpc_success; + } + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 8ef533b2dc351..d37c90691b953 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -5499,6 +5499,22 @@ nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + args->ops = args->iops; + args->rqstp = rqstp; + ++ /* ++ * NFSv4 operation decoders can invoke svc cache lookups ++ * that trigger svc_defer() when RQ_USEDEFERRAL is set, ++ * setting RQ_DROPME. This creates two problems: ++ * ++ * 1. Non-idempotency: Compounds make it too hard to avoid ++ * problems if a request is deferred and replayed. ++ * ++ * 2. Session slot leakage (NFSv4.1+): If RQ_DROPME is set ++ * during decode but SEQUENCE executes successfully, the ++ * session slot will be marked INUSE. The request is then ++ * dropped before encoding, so the slot is never released, ++ * rendering it permanently unusable by the client. ++ */ ++ clear_bit(RQ_USEDEFERRAL, &rqstp->rq_flags); ++ + return nfsd4_decode_compound(args); + } + +-- +2.51.0 + diff --git a/queue-6.1/nvdimm-virtio_pmem-serialize-flush-requests.patch b/queue-6.1/nvdimm-virtio_pmem-serialize-flush-requests.patch new file mode 100644 index 0000000000..c2f17f0583 --- /dev/null +++ b/queue-6.1/nvdimm-virtio_pmem-serialize-flush-requests.patch @@ -0,0 +1,98 @@ +From a2320fba820da5a43e1d5c1c17394e794f3851af Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 10:13:51 +0800 +Subject: nvdimm: virtio_pmem: serialize flush requests + +From: Li Chen + +[ Upstream commit a9ba6733c7f1096c4506bf4e34a546e07242df74 ] + +Under heavy concurrent flush traffic, virtio-pmem can overflow its request +virtqueue (req_vq): virtqueue_add_sgs() starts returning -ENOSPC and the +driver logs "no free slots in the virtqueue". Shortly after that the +device enters VIRTIO_CONFIG_S_NEEDS_RESET and flush requests fail with +"virtio pmem device needs a reset". + +Serialize virtio_pmem_flush() with a per-device mutex so only one flush +request is in-flight at a time. This prevents req_vq descriptor overflow +under high concurrency. + +Reproducer (guest with virtio-pmem): + - mkfs.ext4 -F /dev/pmem0 + - mount -t ext4 -o dax,noatime /dev/pmem0 /mnt/bench + - fio: ioengine=io_uring rw=randwrite bs=4k iodepth=64 numjobs=64 + direct=1 fsync=1 runtime=30s time_based=1 + - dmesg: "no free slots in the virtqueue" + "virtio pmem device needs a reset" + +Fixes: 6e84200c0a29 ("virtio-pmem: Add virtio pmem driver") +Signed-off-by: Li Chen +Acked-by: Pankaj Gupta +Acked-by: Michael S. Tsirkin +Link: https://patch.msgid.link/20260203021353.121091-1-me@linux.beauty +Signed-off-by: Ira Weiny +Signed-off-by: Sasha Levin +--- + drivers/nvdimm/nd_virtio.c | 3 ++- + drivers/nvdimm/virtio_pmem.c | 1 + + drivers/nvdimm/virtio_pmem.h | 4 ++++ + 3 files changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/nvdimm/nd_virtio.c b/drivers/nvdimm/nd_virtio.c +index a78e17a43a9d2..90b0fdb72024a 100644 +--- a/drivers/nvdimm/nd_virtio.c ++++ b/drivers/nvdimm/nd_virtio.c +@@ -44,6 +44,8 @@ static int virtio_pmem_flush(struct nd_region *nd_region) + unsigned long flags; + int err, err1; + ++ guard(mutex)(&vpmem->flush_lock); ++ + /* + * Don't bother to submit the request to the device if the device is + * not activated. +@@ -53,7 +55,6 @@ static int virtio_pmem_flush(struct nd_region *nd_region) + return -EIO; + } + +- might_sleep(); + req_data = kmalloc(sizeof(*req_data), GFP_KERNEL); + if (!req_data) + return -ENOMEM; +diff --git a/drivers/nvdimm/virtio_pmem.c b/drivers/nvdimm/virtio_pmem.c +index 20da455d2ef63..ed5376128bbd8 100644 +--- a/drivers/nvdimm/virtio_pmem.c ++++ b/drivers/nvdimm/virtio_pmem.c +@@ -50,6 +50,7 @@ static int virtio_pmem_probe(struct virtio_device *vdev) + goto out_err; + } + ++ mutex_init(&vpmem->flush_lock); + vpmem->vdev = vdev; + vdev->priv = vpmem; + err = init_vq(vpmem); +diff --git a/drivers/nvdimm/virtio_pmem.h b/drivers/nvdimm/virtio_pmem.h +index 0dddefe594c46..f72cf17f9518f 100644 +--- a/drivers/nvdimm/virtio_pmem.h ++++ b/drivers/nvdimm/virtio_pmem.h +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + #include + + struct virtio_pmem_request { +@@ -35,6 +36,9 @@ struct virtio_pmem { + /* Virtio pmem request queue */ + struct virtqueue *req_vq; + ++ /* Serialize flush requests to the device. */ ++ struct mutex flush_lock; ++ + /* nvdimm bus registers virtio pmem device */ + struct nvdimm_bus *nvdimm_bus; + struct nvdimm_bus_descriptor nd_desc; +-- +2.51.0 + diff --git a/queue-6.1/octeontx2-af-fix-pf-driver-crash-with-kexec-kernel-b.patch b/queue-6.1/octeontx2-af-fix-pf-driver-crash-with-kexec-kernel-b.patch new file mode 100644 index 0000000000..be63e015cc --- /dev/null +++ b/queue-6.1/octeontx2-af-fix-pf-driver-crash-with-kexec-kernel-b.patch @@ -0,0 +1,62 @@ +From d2d6fb506be7bfdca3e98cc36af761fccc34eb6b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 10:37:01 +0530 +Subject: octeontx2-af: Fix PF driver crash with kexec kernel booting + +From: Anshumali Gaur + +[ Upstream commit 2d2d574309e3ae84ee794869a5da8b4c38753a94 ] + +During a kexec reboot the hardware is not power-cycled, so AF state from +the old kernel can persist into the new kernel. When AF and PF drivers +are built as modules, the PF driver may probe before AF reinitializes +the hardware. + +The PF driver treats the RVUM block revision as an indication that AF +initialization is complete. If this value is left uncleared at shutdown, +PF may incorrectly assume AF is ready and access stale hardware state, +leading to a crash. + +Clear the RVUM block revision during AF shutdown to avoid PF +mis-detecting AF readiness after kexec. + +Fixes: 54494aa5d1e6 ("octeontx2-af: Add Marvell OcteonTX2 RVU AF driver") +Signed-off-by: Anshumali Gaur +Reviewed-by: Jacob Keller +Link: https://patch.msgid.link/20260203050701.2616685-1-agaur@marvell.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/octeontx2/af/rvu.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +index 7034a977102ea..1e3661524040a 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +@@ -3442,11 +3442,22 @@ static void rvu_remove(struct pci_dev *pdev) + devm_kfree(&pdev->dev, rvu); + } + ++static void rvu_shutdown(struct pci_dev *pdev) ++{ ++ struct rvu *rvu = pci_get_drvdata(pdev); ++ ++ if (!rvu) ++ return; ++ ++ rvu_clear_rvum_blk_revid(rvu); ++} ++ + static struct pci_driver rvu_driver = { + .name = DRV_NAME, + .id_table = rvu_id_table, + .probe = rvu_probe, + .remove = rvu_remove, ++ .shutdown = rvu_shutdown, + }; + + static int __init rvu_init_module(void) +-- +2.51.0 + diff --git a/queue-6.1/octeontx2-pf-unregister-devlink-on-probe-failure.patch b/queue-6.1/octeontx2-pf-unregister-devlink-on-probe-failure.patch new file mode 100644 index 0000000000..b5e7d75ef0 --- /dev/null +++ b/queue-6.1/octeontx2-pf-unregister-devlink-on-probe-failure.patch @@ -0,0 +1,36 @@ +From 41147d827d67a7562eeb80d2974c3a24b0ad9e3b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 23:56:45 +0530 +Subject: octeontx2-pf: Unregister devlink on probe failure + +From: Hariprasad Kelam + +[ Upstream commit 943f3b8bfbf297cf74392b50a7108ce1fe4cbd8c ] + +When probe fails after devlink registration, the missing devlink unregister +call causing a memory leak. + +Fixes: 2da489432747 ("octeontx2-pf: devlink params support to set mcam entry count") +Signed-off-by: Hariprasad Kelam +Link: https://patch.msgid.link/20260206182645.4032737-1-hkelam@marvell.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +index c29cb56caf083..6f1da4296ad5e 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c ++++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +@@ -3027,6 +3027,7 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id) + return 0; + + err_pf_sriov_init: ++ otx2_unregister_dl(pf); + otx2_shutdown_tc(pf); + err_mcam_flow_del: + otx2_mcam_flow_del(pf); +-- +2.51.0 + diff --git a/queue-6.1/ovl-fix-uninit-value-in-ovl_fill_real.patch b/queue-6.1/ovl-fix-uninit-value-in-ovl_fill_real.patch new file mode 100644 index 0000000000..ad4ec20afb --- /dev/null +++ b/queue-6.1/ovl-fix-uninit-value-in-ovl_fill_real.patch @@ -0,0 +1,58 @@ +From 5aa45688bf1c72d99ca12e24031bd0842bf1b6da Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 14:24:04 +0100 +Subject: ovl: Fix uninit-value in ovl_fill_real + +From: Qing Wang + +[ Upstream commit 1992330d90dd766fcf1730fd7bf2d6af65370ac4 ] + +Syzbot reported a KMSAN uninit-value issue in ovl_fill_real. + +This iusse's call chain is: +__do_sys_getdents64() + -> iterate_dir() + ... + -> ext4_readdir() + -> fscrypt_fname_alloc_buffer() // alloc + -> fscrypt_fname_disk_to_usr // write without tail '\0' + -> dir_emit() + -> ovl_fill_real() // read by strcmp() + +The string is used to store the decrypted directory entry name for an +encrypted inode. As shown in the call chain, fscrypt_fname_disk_to_usr() +write it without null-terminate. However, ovl_fill_real() uses strcmp() to +compare the name against "..", which assumes a null-terminated string and +may trigger a KMSAN uninit-value warning when the buffer tail contains +uninit data. + +Reported-by: syzbot+d130f98b2c265fae5297@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=d130f98b2c265fae5297 +Fixes: 4edb83bb1041 ("ovl: constant d_ino for non-merge dirs") +Signed-off-by: Qing Wang +Signed-off-by: Amir Goldstein +Link: https://patch.msgid.link/20260128132406.23768-2-amir73il@gmail.com +Acked-by: Miklos Szeredi +Reviewed-by: Eric Biggers +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/overlayfs/readdir.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c +index 2b210640036c4..6e74bcb63b0ba 100644 +--- a/fs/overlayfs/readdir.c ++++ b/fs/overlayfs/readdir.c +@@ -656,7 +656,7 @@ static bool ovl_fill_real(struct dir_context *ctx, const char *name, + container_of(ctx, struct ovl_readdir_translate, ctx); + struct dir_context *orig_ctx = rdt->orig_ctx; + +- if (rdt->parent_ino && strcmp(name, "..") == 0) { ++ if (rdt->parent_ino && namelen == 2 && !strncmp(name, "..", 2)) { + ino = rdt->parent_ino; + } else if (rdt->cache) { + struct ovl_cache_entry *p; +-- +2.51.0 + diff --git a/queue-6.1/pci-add-acs-quirk-for-pericom-pi7c9x2g404-switches-1.patch b/queue-6.1/pci-add-acs-quirk-for-pericom-pi7c9x2g404-switches-1.patch new file mode 100644 index 0000000000..4e32204716 --- /dev/null +++ b/queue-6.1/pci-add-acs-quirk-for-pericom-pi7c9x2g404-switches-1.patch @@ -0,0 +1,46 @@ +From 314e2814163edceb682623dde64ad6a4125b0b03 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 17:08:33 +0100 +Subject: PCI: Add ACS quirk for Pericom PI7C9X2G404 switches [12d8:b404] + +From: Nicolas Cavallari + +[ Upstream commit 5907a90551e9f7968781f3a6ab8684458959beb3 ] + +12d8:b404 is apparently another PCI ID for Pericom PI7C9X2G404 (as +identified by the chip silkscreen and lspci). + +It is also affected by the PI7C9X2G errata (e.g. a network card attached +to it fails under load when P2P Redirect Request is enabled), so apply +the same quirk to this PCI ID too. + +PCI bridge [0604]: Pericom Semiconductor PI7C9X2G404 EV/SV PCIe2 4-Port/4-Lane Packet Switch [12d8:b404] (rev 01) + +Fixes: acd61ffb2f16 ("PCI: Add ACS quirk for Pericom PI7C9X2G switches") +Closes: https://lore.kernel.org/all/a1d926f0-4cb5-4877-a4df-617902648d80@green-communications.fr/ +Signed-off-by: Nicolas Cavallari +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260119160915.26456-1-nicolas.cavallari@green-communications.fr +Signed-off-by: Sasha Levin +--- + drivers/pci/quirks.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index fc793635a3d81..9a2076ddfe4e1 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -6073,6 +6073,10 @@ DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_PERICOM, 0x2303, + pci_fixup_pericom_acs_store_forward); + DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_PERICOM, 0x2303, + pci_fixup_pericom_acs_store_forward); ++DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_PERICOM, 0xb404, ++ pci_fixup_pericom_acs_store_forward); ++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_PERICOM, 0xb404, ++ pci_fixup_pericom_acs_store_forward); + + static void nvidia_ion_ahci_fixup(struct pci_dev *pdev) + { +-- +2.51.0 + diff --git a/queue-6.1/pci-do-not-attempt-to-set-exttag-for-vfs.patch b/queue-6.1/pci-do-not-attempt-to-set-exttag-for-vfs.patch new file mode 100644 index 0000000000..bca5c583f8 --- /dev/null +++ b/queue-6.1/pci-do-not-attempt-to-set-exttag-for-vfs.patch @@ -0,0 +1,49 @@ +From 5d1659f3def62adb1303cf76e3ecfdd6cb03b58a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 12 Nov 2025 10:54:40 +0100 +Subject: PCI: Do not attempt to set ExtTag for VFs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: HÃ¥kon Bugge + +[ Upstream commit 73711730a1128d91ebca1a6994ceeb18f36cb0cd ] + +The bit for enabling extended tags is Reserved and Preserved (RsvdP) for +VFs, according to PCIe r7.0 section 7.5.3.4 table 7.21. Hence, bail out +early from pci_configure_extended_tags() if the device is a VF. + +Otherwise, we may see incorrect log messages such as: + + kernel: pci 0000:af:00.2: enabling Extended Tags + +(af:00.2 is a VF) + +Fixes: 60db3a4d8cc9 ("PCI: Enable PCIe Extended Tags if supported") +Signed-off-by: HÃ¥kon Bugge +Signed-off-by: Bjorn Helgaas +Reviewed-by: Zhu Yanjun +Link: https://patch.msgid.link/20251112095442.1913258-1-haakon.bugge@oracle.com +Signed-off-by: Sasha Levin +--- + drivers/pci/probe.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c +index c37ff0ee53f82..4a72a0163a862 100644 +--- a/drivers/pci/probe.c ++++ b/drivers/pci/probe.c +@@ -2097,7 +2097,8 @@ int pci_configure_extended_tags(struct pci_dev *dev, void *ign) + u16 ctl; + int ret; + +- if (!pci_is_pcie(dev)) ++ /* PCI_EXP_DEVCTL_EXT_TAG is RsvdP in VFs */ ++ if (!pci_is_pcie(dev) || dev->is_virtfn) + return 0; + + ret = pcie_capability_read_dword(dev, PCI_EXP_DEVCAP, &cap); +-- +2.51.0 + diff --git a/queue-6.1/pci-initialize-rcb-from-pci_configure_device.patch b/queue-6.1/pci-initialize-rcb-from-pci_configure_device.patch new file mode 100644 index 0000000000..dc1cb4fde4 --- /dev/null +++ b/queue-6.1/pci-initialize-rcb-from-pci_configure_device.patch @@ -0,0 +1,90 @@ +From db6086b215d63a00c13af4aae3f16f8b4b58b98b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 18:52:32 +0100 +Subject: PCI: Initialize RCB from pci_configure_device() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: HÃ¥kon Bugge + +[ Upstream commit 1a6845aaa6de81f95959b380b45de8f10d6a8502 ] + +Commit e42010d8207f ("PCI: Set Read Completion Boundary to 128 iff Root +Port supports it (_HPX)") worked around a bogus _HPX type 2 record, which +caused program_hpx_type2() to set the RCB in an endpoint even though the +Root Port did not have the RCB bit set. + +e42010d8207f fixed that by setting the RCB in the endpoint only when it was +set in the Root Port. + +In retrospect, program_hpx_type2() is intended for AER-related settings, +and the RCB should be configured elsewhere so it doesn't depend on the +presence or contents of an _HPX record. + +Explicitly program the RCB from pci_configure_device() so it matches the +Root Port's RCB. The Root Port may not be visible to virtualized guests; +in that case, leave RCB alone. + +Fixes: e42010d8207f ("PCI: Set Read Completion Boundary to 128 iff Root Port supports it (_HPX)") +Signed-off-by: HÃ¥kon Bugge +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260129175237.727059-2-haakon.bugge@oracle.com +Signed-off-by: Sasha Levin +--- + drivers/pci/probe.c | 32 ++++++++++++++++++++++++++++++++ + 1 file changed, 32 insertions(+) + +diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c +index 4a72a0163a862..ea7db1bd21143 100644 +--- a/drivers/pci/probe.c ++++ b/drivers/pci/probe.c +@@ -2284,6 +2284,37 @@ static void pci_configure_serr(struct pci_dev *dev) + } + } + ++static void pci_configure_rcb(struct pci_dev *dev) ++{ ++ struct pci_dev *rp; ++ u16 rp_lnkctl; ++ ++ /* ++ * Per PCIe r7.0, sec 7.5.3.7, RCB is only meaningful in Root Ports ++ * (where it is read-only), Endpoints, and Bridges. It may only be ++ * set for Endpoints and Bridges if it is set in the Root Port. For ++ * Endpoints, it is 'RsvdP' for Virtual Functions. ++ */ ++ if (!pci_is_pcie(dev) || ++ pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT || ++ pci_pcie_type(dev) == PCI_EXP_TYPE_UPSTREAM || ++ pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM || ++ pci_pcie_type(dev) == PCI_EXP_TYPE_RC_EC || ++ dev->is_virtfn) ++ return; ++ ++ /* Root Port often not visible to virtualized guests */ ++ rp = pcie_find_root_port(dev); ++ if (!rp) ++ return; ++ ++ pcie_capability_read_word(rp, PCI_EXP_LNKCTL, &rp_lnkctl); ++ pcie_capability_clear_and_set_word(dev, PCI_EXP_LNKCTL, ++ PCI_EXP_LNKCTL_RCB, ++ (rp_lnkctl & PCI_EXP_LNKCTL_RCB) ? ++ PCI_EXP_LNKCTL_RCB : 0); ++} ++ + static void pci_configure_device(struct pci_dev *dev) + { + pci_configure_mps(dev); +@@ -2292,6 +2323,7 @@ static void pci_configure_device(struct pci_dev *dev) + pci_configure_ltr(dev); + pci_configure_eetlp_prefix(dev); + pci_configure_serr(dev); ++ pci_configure_rcb(dev); + + pci_acpi_program_hp_params(dev); + } +-- +2.51.0 + diff --git a/queue-6.1/pci-mark-3ware-9650sa-root-port-extended-tags-as-bro.patch b/queue-6.1/pci-mark-3ware-9650sa-root-port-extended-tags-as-bro.patch new file mode 100644 index 0000000000..2f287acf2b --- /dev/null +++ b/queue-6.1/pci-mark-3ware-9650sa-root-port-extended-tags-as-bro.patch @@ -0,0 +1,56 @@ +From 726e83736b9ca1467d0c422b1979f29e51f784b9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 15:31:10 +0100 +Subject: PCI: Mark 3ware-9650SA Root Port Extended Tags as broken +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jörg Wedekind + +[ Upstream commit 959ac08a2c2811305be8c2779779e8b0932e5a99 ] + +Per PCIe r7.0, sec 2.2.6.2.1 and 7.5.3.4, a Requester may not use 8-bit Tags +unless its Extended Tag Field Enable is set, but all Receivers/Completers +must handle 8-bit Tags correctly regardless of their Extended Tag Field +Enable. + +Some devices do not handle 8-bit Tags as Completers, so add a quirk for +them. If we find such a device, we disable Extended Tags for the entire +hierarchy to make peer-to-peer DMA possible. + +The 3ware 9650SA seems to have issues with handling 8-bit tags. Mark it as +broken. + +This fixes PCI Parity Errors like : + + 3w-9xxx: scsi0: ERROR: (0x06:0x000C): PCI Parity Error: clearing. + 3w-9xxx: scsi0: ERROR: (0x06:0x000D): PCI Abort: clearing. + 3w-9xxx: scsi0: ERROR: (0x06:0x000E): Controller Queue Error: clearing. + 3w-9xxx: scsi0: ERROR: (0x06:0x0010): Microcontroller Error: clearing. + +Fixes: 60db3a4d8cc9 ("PCI: Enable PCIe Extended Tags if supported") +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=202425 +Signed-off-by: Jörg Wedekind +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260119143114.21948-1-joerg@wedekind.de +Signed-off-by: Sasha Levin +--- + drivers/pci/quirks.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index e8cfae79a47a9..fc793635a3d81 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -5465,6 +5465,7 @@ static void quirk_no_ext_tags(struct pci_dev *pdev) + pci_walk_bus(bridge->bus, pci_configure_extended_tags, NULL); + } + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_3WARE, 0x1004, quirk_no_ext_tags); ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_3WARE, 0x1005, quirk_no_ext_tags); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0132, quirk_no_ext_tags); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0140, quirk_no_ext_tags); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0141, quirk_no_ext_tags); +-- +2.51.0 + diff --git a/queue-6.1/pci-mediatek-fix-irq-domain-leak-when-msi-allocation.patch b/queue-6.1/pci-mediatek-fix-irq-domain-leak-when-msi-allocation.patch new file mode 100644 index 0000000000..8c78f75d77 --- /dev/null +++ b/queue-6.1/pci-mediatek-fix-irq-domain-leak-when-msi-allocation.patch @@ -0,0 +1,45 @@ +From 14e4e555c2ecdfbd061e254b2dcedd6e1933c8f0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 19 Nov 2025 10:33:08 +0800 +Subject: PCI: mediatek: Fix IRQ domain leak when MSI allocation fails + +From: Haotian Zhang + +[ Upstream commit 7f0cdcddf8bef1c8c18f9be6708073fd3790a20f ] + +In mtk_pcie_init_irq_domain(), if mtk_pcie_allocate_msi_domains() +fails after port->irq_domain has been successfully created via +irq_domain_create_linear(), the function returns directly without +cleaning up the allocated IRQ domain, resulting in a resource leak. + +Add irq_domain_remove() call in the error path to properly release the +INTx IRQ domain before returning the error. + +Fixes: 43e6409db64d ("PCI: mediatek: Add MSI support for MT2712 and MT7622") +Signed-off-by: Haotian Zhang +Signed-off-by: Manivannan Sadhasivam +Link: https://patch.msgid.link/20251119023308.476-1-vulab@iscas.ac.cn +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/pcie-mediatek.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c +index 11bdef206d120..03ac5df9bb129 100644 +--- a/drivers/pci/controller/pcie-mediatek.c ++++ b/drivers/pci/controller/pcie-mediatek.c +@@ -587,8 +587,10 @@ static int mtk_pcie_init_irq_domain(struct mtk_pcie_port *port, + + if (IS_ENABLED(CONFIG_PCI_MSI)) { + ret = mtk_pcie_allocate_msi_domains(port); +- if (ret) ++ if (ret) { ++ irq_domain_remove(port->irq_domain); + return ret; ++ } + } + + return 0; +-- +2.51.0 + diff --git a/queue-6.1/pci-pm-avoid-redundant-delays-on-d3hot-d3cold.patch b/queue-6.1/pci-pm-avoid-redundant-delays-on-d3hot-d3cold.patch new file mode 100644 index 0000000000..cd23169941 --- /dev/null +++ b/queue-6.1/pci-pm-avoid-redundant-delays-on-d3hot-d3cold.patch @@ -0,0 +1,56 @@ +From 84ca06e4a9a1cb226ac39a68741c3d3b24ef4971 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Oct 2025 15:40:09 -0700 +Subject: PCI/PM: Avoid redundant delays on D3hot->D3cold + +From: Brian Norris + +[ Upstream commit 4d982084507d663df160546c4c48066a8887ed89 ] + +When transitioning to D3cold, __pci_set_power_state() first transitions to +D3hot. If the device was already in D3hot, this adds excess work: + + (a) read/modify/write PMCSR; and + (b) excess delay (pci_dev_d3_sleep()). + +For (b), we already performed the necessary delay on the previous D3hot +entry; this was extra noticeable when evaluating runtime PM transition +latency. + +Check whether we're already in the target state before continuing. + +Note that __pci_set_power_state() already does this same check for other +state transitions, but D3cold is special because __pci_set_power_state() +converts it to D3hot for the purposes of PMCSR. + +This seems to be an oversight in commit 0aacdc957401 ("PCI/PM: Clean up +pci_set_low_power_state()"). + +Fixes: 0aacdc957401 ("PCI/PM: Clean up pci_set_low_power_state()") +Signed-off-by: Brian Norris +Signed-off-by: Brian Norris +[bhelgaas: reverse test to match other "dev->current_state == state" cases] +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20251003154008.1.I7a21c240b30062c66471329567a96dceb6274358@changeid +Signed-off-by: Sasha Levin +--- + drivers/pci/pci.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c +index b4692c3f98d3b..bafa695bd7ec7 100644 +--- a/drivers/pci/pci.c ++++ b/drivers/pci/pci.c +@@ -1397,6 +1397,9 @@ static int pci_set_low_power_state(struct pci_dev *dev, pci_power_t state, bool + || (state == PCI_D2 && !dev->d2_support)) + return -EIO; + ++ if (dev->current_state == state) ++ return 0; ++ + pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr); + if (PCI_POSSIBLE_ERROR(pmcsr)) { + pci_err(dev, "Unable to change power state from %s to %s, device inaccessible\n", +-- +2.51.0 + diff --git a/queue-6.1/pci-portdrv-fix-potential-resource-leak.patch b/queue-6.1/pci-portdrv-fix-potential-resource-leak.patch new file mode 100644 index 0000000000..e6e2ee77ab --- /dev/null +++ b/queue-6.1/pci-portdrv-fix-potential-resource-leak.patch @@ -0,0 +1,48 @@ +From 3e49c9aaeaa4e11af1fd0d03cff31f16f8e48da4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Dec 2025 16:13:49 +0100 +Subject: PCI/portdrv: Fix potential resource leak +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Uwe Kleine-König + +[ Upstream commit 01464a3fdf91c041a381d93a1b6fefbdb819a46f ] + +pcie_port_probe_service() unconditionally calls get_device() (unless it +fails). So drop that reference also unconditionally as it's fine for a +PCIe driver to not have a remove callback. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Uwe Kleine-König +Signed-off-by: Bjorn Helgaas +Reviewed-by: Ilpo Järvinen +Reviewed-by: Jonathan Cameron +Link: https://patch.msgid.link/e1c68c3b3f1af8427e98ca5e2c79f8bf0ebe2ce4.1764688034.git.u.kleine-koenig@baylibre.com +Signed-off-by: Sasha Levin +--- + drivers/pci/pcie/portdrv_core.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c +index 332315183cd45..8b7aadc716ae8 100644 +--- a/drivers/pci/pcie/portdrv_core.c ++++ b/drivers/pci/pcie/portdrv_core.c +@@ -540,10 +540,10 @@ static int pcie_port_remove_service(struct device *dev) + + pciedev = to_pcie_device(dev); + driver = to_service_driver(dev->driver); +- if (driver && driver->remove) { ++ if (driver && driver->remove) + driver->remove(pciedev); +- put_device(dev); +- } ++ ++ put_device(dev); + return 0; + } + +-- +2.51.0 + diff --git a/queue-6.1/pinctrl-equilibrium-fix-device-node-reference-leak-i.patch b/queue-6.1/pinctrl-equilibrium-fix-device-node-reference-leak-i.patch new file mode 100644 index 0000000000..2b96c1a0e7 --- /dev/null +++ b/queue-6.1/pinctrl-equilibrium-fix-device-node-reference-leak-i.patch @@ -0,0 +1,44 @@ +From fbbe552171f0984a0bd95df77ec5e565a709da35 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 01:30:07 +0800 +Subject: pinctrl: equilibrium: Fix device node reference leak in + pinbank_init() + +From: Felix Gu + +[ Upstream commit c0b4a4feeb43305a754893d8d9c6b2b5a52d45ac ] + +When calling of_parse_phandle_with_fixed_args(), the caller is +responsible to call of_node_put() to release the reference of device +node. + +In pinbank_init(), the reference of the node obtained from the +"gpio-ranges" property is never released, resulting in a reference +count leak. + +Add the missing of_node_put() call to fix the leak. + +Fixes: 1948d5c51dba ("pinctrl: Add pinmux & GPIO controller driver for a new SoC") +Signed-off-by: Felix Gu +Acked-by: Andy Shevchenko +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-equilibrium.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/pinctrl/pinctrl-equilibrium.c b/drivers/pinctrl/pinctrl-equilibrium.c +index 99cf24eb67ae6..9d140ec58b3b9 100644 +--- a/drivers/pinctrl/pinctrl-equilibrium.c ++++ b/drivers/pinctrl/pinctrl-equilibrium.c +@@ -844,6 +844,7 @@ static int pinbank_init(struct device_node *np, + + bank->pin_base = spec.args[1]; + bank->nr_pins = spec.args[2]; ++ of_node_put(spec.np); + + bank->aval_pinmap = readl(bank->membase + REG_AVAIL); + bank->id = id; +-- +2.51.0 + diff --git a/queue-6.1/pinctrl-qcom-sm8250-lpass-lpi-fix-i2s2_data_groups-d.patch b/queue-6.1/pinctrl-qcom-sm8250-lpass-lpi-fix-i2s2_data_groups-d.patch new file mode 100644 index 0000000000..b87c27785c --- /dev/null +++ b/queue-6.1/pinctrl-qcom-sm8250-lpass-lpi-fix-i2s2_data_groups-d.patch @@ -0,0 +1,38 @@ +From d66b3c0352a3832921b129ae6323272a96ea2543 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 12:22:28 +0100 +Subject: pinctrl: qcom: sm8250-lpass-lpi: Fix i2s2_data_groups definition + +From: Luca Weiss + +[ Upstream commit eabf273c8466af3f033473c2d2267a6ea7946d57 ] + +The i2s2_data function is available on both gpio12 and gpio13. Fix the +groups definition. + +Fixes: 6e261d1090d6 ("pinctrl: qcom: Add sm8250 lpass lpi pinctrl driver") +Signed-off-by: Luca Weiss +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c +index ddbc6317f2a74..422ef44b86423 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c ++++ b/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c +@@ -88,7 +88,7 @@ static const char * const i2s1_ws_groups[] = { "gpio7" }; + static const char * const i2s1_data_groups[] = { "gpio8", "gpio9" }; + static const char * const wsa_swr_clk_groups[] = { "gpio10" }; + static const char * const wsa_swr_data_groups[] = { "gpio11" }; +-static const char * const i2s2_data_groups[] = { "gpio12", "gpio12" }; ++static const char * const i2s2_data_groups[] = { "gpio12", "gpio13" }; + + static const struct lpi_pingroup sm8250_groups[] = { + LPI_PINGROUP(0, 0, swr_tx_clk, qua_mi2s_sclk, _, _), +-- +2.51.0 + diff --git a/queue-6.1/pinctrl-single-fix-refcount-leak-in-pcs_add_gpio_fun.patch b/queue-6.1/pinctrl-single-fix-refcount-leak-in-pcs_add_gpio_fun.patch new file mode 100644 index 0000000000..46ebbd827a --- /dev/null +++ b/queue-6.1/pinctrl-single-fix-refcount-leak-in-pcs_add_gpio_fun.patch @@ -0,0 +1,50 @@ +From 1eda90684ec9f14dc8538db7399719a692452703 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 08:07:35 +0000 +Subject: pinctrl: single: fix refcount leak in pcs_add_gpio_func() + +From: Wei Li + +[ Upstream commit 353353309b0f7afa407df29e455f9d15b5acc296 ] + +of_parse_phandle_with_args() returns a device_node pointer with refcount +incremented in gpiospec.np. The loop iterates through all phandles but +never releases the reference, causing a refcount leak on each iteration. + +Add of_node_put() calls to release the reference after extracting the +needed arguments and on the error path when devm_kzalloc() fails. + +This bug was detected by our static analysis tool and verified by my +code review. + +Fixes: a1a277eb76b3 ("pinctrl: single: create new gpio function range") +Signed-off-by: Wei Li +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-single.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c +index 0659cd3aa3a5a..2c5b5ce60248e 100644 +--- a/drivers/pinctrl/pinctrl-single.c ++++ b/drivers/pinctrl/pinctrl-single.c +@@ -1364,6 +1364,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) + } + range = devm_kzalloc(pcs->dev, sizeof(*range), GFP_KERNEL); + if (!range) { ++ of_node_put(gpiospec.np); + ret = -ENOMEM; + break; + } +@@ -1373,6 +1374,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) + mutex_lock(&pcs->mutex); + list_add_tail(&range->node, &pcs->gpiofuncs); + mutex_unlock(&pcs->mutex); ++ of_node_put(gpiospec.np); + } + return ret; + } +-- +2.51.0 + diff --git a/queue-6.1/platform-chrome-cros_ec_lightbar-fix-response-size-i.patch b/queue-6.1/platform-chrome-cros_ec_lightbar-fix-response-size-i.patch new file mode 100644 index 0000000000..5a2ef5cdce --- /dev/null +++ b/queue-6.1/platform-chrome-cros_ec_lightbar-fix-response-size-i.patch @@ -0,0 +1,43 @@ +From c2bf9981d9843c22c267776620e71f9a104588cb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 04:03:35 +0000 +Subject: platform/chrome: cros_ec_lightbar: Fix response size initialization + +From: Tzung-Bi Shih + +[ Upstream commit ec0dd36dbf8b0b209e63d0cd795451fa2203c736 ] + +Commit 1e7913ff5f9f ("platform/chrome: cros_ec_lightbar: Reduce +ligthbar get version command") meant to set smaller values for both +request and response sizes. + +However, it incorrectly assigned the response size to the `result` field +instead of `insize`. Fix it. + +Reported-by: Gwendal Grignou +Closes: https://lore.kernel.org/chrome-platform/CAMHSBOVrrYaB=1nEqZk09VkczCrj=6B-P8Fe29TpPdSDgT2CCQ@mail.gmail.com +Fixes: 1e7913ff5f9f ("platform/chrome: cros_ec_lightbar: Reduce ligthbar get version command") +Link: https://lore.kernel.org/r/20260130040335.361997-1-tzungbi@kernel.org +Reviewed-by: Gwendal Grignou +Signed-off-by: Tzung-Bi Shih +Signed-off-by: Sasha Levin +--- + drivers/platform/chrome/cros_ec_lightbar.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/platform/chrome/cros_ec_lightbar.c b/drivers/platform/chrome/cros_ec_lightbar.c +index 469dfc7a4a030..e2365788d4590 100644 +--- a/drivers/platform/chrome/cros_ec_lightbar.c ++++ b/drivers/platform/chrome/cros_ec_lightbar.c +@@ -117,7 +117,7 @@ static int get_lightbar_version(struct cros_ec_dev *ec, + param = (struct ec_params_lightbar *)msg->data; + param->cmd = LIGHTBAR_CMD_VERSION; + msg->outsize = sizeof(param->cmd); +- msg->result = sizeof(resp->version); ++ msg->insize = sizeof(resp->version); + ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg); + if (ret < 0 && ret != -EINVAL) { + ret = 0; +-- +2.51.0 + diff --git a/queue-6.1/platform-chrome-cros_typec_switch-don-t-touch-struct.patch b/queue-6.1/platform-chrome-cros_typec_switch-don-t-touch-struct.patch new file mode 100644 index 0000000000..0bec024d42 --- /dev/null +++ b/queue-6.1/platform-chrome-cros_typec_switch-don-t-touch-struct.patch @@ -0,0 +1,54 @@ +From a60a5ba0ee0017418d0d0715db9dd6e0c764c6c1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 14:12:30 +0100 +Subject: platform/chrome: cros_typec_switch: Don't touch struct + fwnode_handle::dev + +From: Andy Shevchenko + +[ Upstream commit e1adf48853bc715f4deea074932aa1c44eb7abea ] + +The 'dev' field in struct fwnode is special and related to device links, +There no driver should use it for printing messages. Fix incorrect use +of private field. + +Fixes: affc804c44c8 ("platform/chrome: cros_typec_switch: Add switch driver") +Signed-off-by: Andy Shevchenko +Link: https://lore.kernel.org/r/20260120131413.1697891-2-andriy.shevchenko@linux.intel.com +Signed-off-by: Tzung-Bi Shih +Signed-off-by: Sasha Levin +--- + drivers/platform/chrome/cros_typec_switch.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/platform/chrome/cros_typec_switch.c b/drivers/platform/chrome/cros_typec_switch.c +index 26af51952f7f1..2b37e1b30aca0 100644 +--- a/drivers/platform/chrome/cros_typec_switch.c ++++ b/drivers/platform/chrome/cros_typec_switch.c +@@ -225,20 +225,20 @@ static int cros_typec_register_switches(struct cros_typec_switch_data *sdata) + + adev = to_acpi_device_node(fwnode); + if (!adev) { +- dev_err(fwnode->dev, "Couldn't get ACPI device handle\n"); ++ dev_err(dev, "Couldn't get ACPI device handle for %pfwP\n", fwnode); + ret = -ENODEV; + goto err_switch; + } + + ret = acpi_evaluate_integer(adev->handle, "_ADR", NULL, &index); + if (ACPI_FAILURE(ret)) { +- dev_err(fwnode->dev, "_ADR wasn't evaluated\n"); ++ dev_err(dev, "_ADR wasn't evaluated for %pfwP\n", fwnode); + ret = -ENODATA; + goto err_switch; + } + + if (index >= EC_USB_PD_MAX_PORTS) { +- dev_err(fwnode->dev, "Invalid port index number: %llu\n", index); ++ dev_err(dev, "%pfwP: Invalid port index number: %llu\n", fwnode, index); + ret = -EINVAL; + goto err_switch; + } +-- +2.51.0 + diff --git a/queue-6.1/pm-sleep-wakeirq-harden-dev_pm_clear_wake_irq-agains.patch b/queue-6.1/pm-sleep-wakeirq-harden-dev_pm_clear_wake_irq-agains.patch new file mode 100644 index 0000000000..7e09885531 --- /dev/null +++ b/queue-6.1/pm-sleep-wakeirq-harden-dev_pm_clear_wake_irq-agains.patch @@ -0,0 +1,65 @@ +From 1d8ee9e787081a352005cd06b28ef0667e0759e6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 11:19:43 +0800 +Subject: PM: sleep: wakeirq: harden dev_pm_clear_wake_irq() against races + +From: Gui-Dong Han + +[ Upstream commit 5c9ecd8e6437cd55a38ea4f1e1d19cee8e226cb8 ] + +dev_pm_clear_wake_irq() currently uses a dangerous pattern where +dev->power.wakeirq is read and checked for NULL outside the lock. +If two callers invoke this function concurrently, both might see +a valid pointer and proceed. This could result in a double-free +when the second caller acquires the lock and tries to release the +same object. + +Address this by removing the lockless check of dev->power.wakeirq. +Instead, acquire dev->power.lock immediately to ensure the check and +the subsequent operations are atomic. If dev->power.wakeirq is NULL +under the lock, simply unlock and return. This guarantees that +concurrent calls cannot race to free the same object. + +Based on a quick scan of current users, I did not find an actual bug as +drivers seem to rely on their own synchronization. However, since +asynchronous usage patterns exist (e.g., in +drivers/net/wireless/ti/wlcore), I believe a race is theoretically +possible if the API is used less carefully in the future. This change +hardens the API to be robust against such cases. + +Fixes: 4990d4fe327b ("PM / Wakeirq: Add automated device wake IRQ handling") +Signed-off-by: Gui-Dong Han +Link: https://patch.msgid.link/20260203031943.1924-1-hanguidong02@gmail.com +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/base/power/wakeirq.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/drivers/base/power/wakeirq.c b/drivers/base/power/wakeirq.c +index ca0c092ba47fb..09a677c8007a7 100644 +--- a/drivers/base/power/wakeirq.c ++++ b/drivers/base/power/wakeirq.c +@@ -83,13 +83,16 @@ EXPORT_SYMBOL_GPL(dev_pm_set_wake_irq); + */ + void dev_pm_clear_wake_irq(struct device *dev) + { +- struct wake_irq *wirq = dev->power.wakeirq; ++ struct wake_irq *wirq; + unsigned long flags; + +- if (!wirq) ++ spin_lock_irqsave(&dev->power.lock, flags); ++ wirq = dev->power.wakeirq; ++ if (!wirq) { ++ spin_unlock_irqrestore(&dev->power.lock, flags); + return; ++ } + +- spin_lock_irqsave(&dev->power.lock, flags); + device_wakeup_detach_irq(dev); + dev->power.wakeirq = NULL; + spin_unlock_irqrestore(&dev->power.lock, flags); +-- +2.51.0 + diff --git a/queue-6.1/pm-wakeup-handle-empty-list-in-wakeup_sources_walk_s.patch b/queue-6.1/pm-wakeup-handle-empty-list-in-wakeup_sources_walk_s.patch new file mode 100644 index 0000000000..a9873fa366 --- /dev/null +++ b/queue-6.1/pm-wakeup-handle-empty-list-in-wakeup_sources_walk_s.patch @@ -0,0 +1,44 @@ +From b4664329e3f8b91ce6abace23a1995fbbb5a8d09 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 17:21:29 -0800 +Subject: PM: wakeup: Handle empty list in wakeup_sources_walk_start() + +From: Samuel Wu + +[ Upstream commit 75ce02f4bc9a8b8350b6b1b01872467b0cc960cc ] + +In the case of an empty wakeup_sources list, wakeup_sources_walk_start() +will return an invalid but non-NULL address. This also affects wrappers +of the aforementioned function, like for_each_wakeup_source(). + +Update wakeup_sources_walk_start() to return NULL in case of an empty +list. + +Fixes: b4941adb24c0 ("PM: wakeup: Add routine to help fetch wakeup source object.") +Signed-off-by: Samuel Wu +[ rjw: Subject and changelog edits ] +Link: https://patch.msgid.link/20260124012133.2451708-2-wusamuel@google.com +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/base/power/wakeup.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c +index a917219feea62..eae81def0902a 100644 +--- a/drivers/base/power/wakeup.c ++++ b/drivers/base/power/wakeup.c +@@ -280,9 +280,7 @@ EXPORT_SYMBOL_GPL(wakeup_sources_read_unlock); + */ + struct wakeup_source *wakeup_sources_walk_start(void) + { +- struct list_head *ws_head = &wakeup_sources; +- +- return list_entry_rcu(ws_head->next, struct wakeup_source, entry); ++ return list_first_or_null_rcu(&wakeup_sources, struct wakeup_source, entry); + } + EXPORT_SYMBOL_GPL(wakeup_sources_walk_start); + +-- +2.51.0 + diff --git a/queue-6.1/pnfs-fix-a-missing-wake-up-while-waiting-on-nfs_layo.patch b/queue-6.1/pnfs-fix-a-missing-wake-up-while-waiting-on-nfs_layo.patch new file mode 100644 index 0000000000..a0de442937 --- /dev/null +++ b/queue-6.1/pnfs-fix-a-missing-wake-up-while-waiting-on-nfs_layo.patch @@ -0,0 +1,61 @@ +From adaa256c2e680796d67e5996a90c903d75bd04b0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 14:15:39 -0500 +Subject: pNFS: fix a missing wake up while waiting on NFS_LAYOUT_DRAIN + +From: Olga Kornievskaia + +[ Upstream commit 5248d8474e594d156bee1ed10339cc16e207a28b ] + +It is possible to have a task get stuck on waiting on the +NFS_LAYOUT_DRAIN in the following scenario + +1. cpu a: waiter test NFS_LAYOUT_DRAIN (1) and plh_outstanding (1) +2. cpu b: atomic_dec_and_test() -> clear bit -> wake up +3. cpu c: sets NFS_LAYOUT_DRAIN again +4. cpu a: calls wait_on_bit() sleeps forever. + +To expand on this we have say 2 outstanding pnfs write IO that get +ESTALE which causes both to call pnfs_destroy_layout() and set the +NFS_LAYOUT_DRAIN bit but the 1st one doesn't call the +pnfs_put_layout_hdr() yet (as that would prevent the 2nd ESTALE write +from trying to call pnfs_destroy_layout()). If the 1st ESTALE write +is the one that initially sets the NFS_LAYOUT_DRAIN so that new IO +on this file initiates new LAYOUTGET. Another new write would find +NFS_LAYOUT_DRAIN set and phl_outstanding>0 (step 1) and would +wait_on_bit(). LAYOUTGET completes doing step 2. Now, the 2nd of +ESTALE writes is calling pnfs_destory_layout() and set the +NFS_LAYOUT_DRAIN bit (step 3). Finally, the waiting write wakes up +to check the bit and goes back to sleep. + +The problem revolves around the fact that if NFS_LAYOUT_INVALID_STID +was already set, it should not do the work of +pnfs_mark_layout_stateid_invalid(), thus NFS_LAYOUT_DRAIN will not +be set more than once for an invalid layout. + +Suggested-by: Trond Myklebust +Fixes: 880265c77ac4 ("pNFS: Avoid a live lock condition in pnfs_update_layout()") +Signed-off-by: Olga Kornievskaia +Signed-off-by: Anna Schumaker +Signed-off-by: Sasha Levin +--- + fs/nfs/pnfs.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c +index 43cd2d6a0836a..34cd66c98021a 100644 +--- a/fs/nfs/pnfs.c ++++ b/fs/nfs/pnfs.c +@@ -464,7 +464,8 @@ pnfs_mark_layout_stateid_invalid(struct pnfs_layout_hdr *lo, + }; + struct pnfs_layout_segment *lseg, *next; + +- set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags); ++ if (test_and_set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags)) ++ return !list_empty(&lo->plh_segs); + clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(lo->plh_inode)->flags); + list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list) + pnfs_clear_lseg_state(lseg, lseg_list); +-- +2.51.0 + diff --git a/queue-6.1/power-reset-nvmem-reboot-mode-respect-cell-size-for-.patch b/queue-6.1/power-reset-nvmem-reboot-mode-respect-cell-size-for-.patch new file mode 100644 index 0000000000..b3036b6cca --- /dev/null +++ b/queue-6.1/power-reset-nvmem-reboot-mode-respect-cell-size-for-.patch @@ -0,0 +1,64 @@ +From 46b958cc8ad2670c106697c4061e14dfcd381f6f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 14 Dec 2025 19:16:18 +0000 +Subject: power: reset: nvmem-reboot-mode: respect cell size for + nvmem_cell_write + +From: Alexander Koskovich + +[ Upstream commit 36b05629226413836cfbb3fbe6689cd188bca156 ] + +Some platforms expose reboot mode cells that are smaller than an +unsigned int, in which cases lead to write failures. Read the cell +first to determine actual size and only write the number of bytes the +cell can hold. + +Fixes: 7a78a7f7695b ("power: reset: nvmem-reboot-mode: use NVMEM as reboot mode write interface") +Signed-off-by: Alexander Koskovich +Link: https://patch.msgid.link/20251214191529.2470580-1-akoskovich@pm.me +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/reset/nvmem-reboot-mode.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +diff --git a/drivers/power/reset/nvmem-reboot-mode.c b/drivers/power/reset/nvmem-reboot-mode.c +index e229308d43e25..819f11bae788b 100644 +--- a/drivers/power/reset/nvmem-reboot-mode.c ++++ b/drivers/power/reset/nvmem-reboot-mode.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + + struct nvmem_reboot_mode { + struct reboot_mode_driver reboot; +@@ -19,12 +20,22 @@ struct nvmem_reboot_mode { + static int nvmem_reboot_mode_write(struct reboot_mode_driver *reboot, + unsigned int magic) + { +- int ret; + struct nvmem_reboot_mode *nvmem_rbm; ++ size_t buf_len; ++ void *buf; ++ int ret; + + nvmem_rbm = container_of(reboot, struct nvmem_reboot_mode, reboot); + +- ret = nvmem_cell_write(nvmem_rbm->cell, &magic, sizeof(magic)); ++ buf = nvmem_cell_read(nvmem_rbm->cell, &buf_len); ++ if (IS_ERR(buf)) ++ return PTR_ERR(buf); ++ kfree(buf); ++ ++ if (buf_len > sizeof(magic)) ++ return -EINVAL; ++ ++ ret = nvmem_cell_write(nvmem_rbm->cell, &magic, buf_len); + if (ret < 0) + dev_err(reboot->dev, "update reboot mode bits failed\n"); + +-- +2.51.0 + diff --git a/queue-6.1/power-supply-ab8500-fix-use-after-free-in-power_supp.patch b/queue-6.1/power-supply-ab8500-fix-use-after-free-in-power_supp.patch new file mode 100644 index 0000000000..e0b820da1b --- /dev/null +++ b/queue-6.1/power-supply-ab8500-fix-use-after-free-in-power_supp.patch @@ -0,0 +1,104 @@ +From afbdb501f79689fb0d400fbe8928133b918764a3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:35:58 +0100 +Subject: power: supply: ab8500: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit c4af8a98bb52825a5331ae1d0604c0ea6956ba4b ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Commit 1c1f13a006ed ("power: supply: ab8500: Move to componentized +binding") introduced this issue during a refactorization. Fix this racy +use-after-free by making sure the IRQ is requested _after_ the +registration of the `power_supply` handle. + +Fixes: 1c1f13a006ed ("power: supply: ab8500: Move to componentized binding") +Signed-off-by: Waqar Hameed +Reviewed-by: Linus Walleij +Link: https://patch.msgid.link/ccf83a09942cb8dda3dff70b2682f2c2e9cb97f2.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/ab8500_charger.c | 40 +++++++++++++-------------- + 1 file changed, 20 insertions(+), 20 deletions(-) + +diff --git a/drivers/power/supply/ab8500_charger.c b/drivers/power/supply/ab8500_charger.c +index 58757a5799f8b..b497c4c370faa 100644 +--- a/drivers/power/supply/ab8500_charger.c ++++ b/drivers/power/supply/ab8500_charger.c +@@ -3456,26 +3456,6 @@ static int ab8500_charger_probe(struct platform_device *pdev) + return ret; + } + +- /* Request interrupts */ +- for (i = 0; i < ARRAY_SIZE(ab8500_charger_irq); i++) { +- irq = platform_get_irq_byname(pdev, ab8500_charger_irq[i].name); +- if (irq < 0) +- return irq; +- +- ret = devm_request_threaded_irq(dev, +- irq, NULL, ab8500_charger_irq[i].isr, +- IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT, +- ab8500_charger_irq[i].name, di); +- +- if (ret != 0) { +- dev_err(dev, "failed to request %s IRQ %d: %d\n" +- , ab8500_charger_irq[i].name, irq, ret); +- return ret; +- } +- dev_dbg(dev, "Requested %s IRQ %d: %d\n", +- ab8500_charger_irq[i].name, irq, ret); +- } +- + /* initialize lock */ + spin_lock_init(&di->usb_state.usb_lock); + mutex_init(&di->usb_ipt_crnt_lock); +@@ -3604,6 +3584,26 @@ static int ab8500_charger_probe(struct platform_device *pdev) + return PTR_ERR(di->usb_chg.psy); + } + ++ /* Request interrupts */ ++ for (i = 0; i < ARRAY_SIZE(ab8500_charger_irq); i++) { ++ irq = platform_get_irq_byname(pdev, ab8500_charger_irq[i].name); ++ if (irq < 0) ++ return irq; ++ ++ ret = devm_request_threaded_irq(dev, ++ irq, NULL, ab8500_charger_irq[i].isr, ++ IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT, ++ ab8500_charger_irq[i].name, di); ++ ++ if (ret != 0) { ++ dev_err(dev, "failed to request %s IRQ %d: %d\n" ++ , ab8500_charger_irq[i].name, irq, ret); ++ return ret; ++ } ++ dev_dbg(dev, "Requested %s IRQ %d: %d\n", ++ ab8500_charger_irq[i].name, irq, ret); ++ } ++ + /* + * Check what battery we have, since we always have the USB + * psy, use that as a handle. +-- +2.51.0 + diff --git a/queue-6.1/power-supply-act8945a-fix-use-after-free-in-power_su.patch b/queue-6.1/power-supply-act8945a-fix-use-after-free-in-power_su.patch new file mode 100644 index 0000000000..8c324c6316 --- /dev/null +++ b/queue-6.1/power-supply-act8945a-fix-use-after-free-in-power_su.patch @@ -0,0 +1,77 @@ +From 6ebcd4ef90a8f5f6d89730e0d01b2f8ffba942a3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:35:59 +0100 +Subject: power: supply: act8945a: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 3291c51d4684d048dd2eb91b5b65fcfdaf72141f ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: a09209acd6a8 ("power: supply: act8945a_charger: Add status change update support") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/bcf3a23b5187df0bba54a8c8fe09f8b8a0031dee.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/act8945a_charger.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/drivers/power/supply/act8945a_charger.c b/drivers/power/supply/act8945a_charger.c +index e9b5f42837729..e9cb06daecea9 100644 +--- a/drivers/power/supply/act8945a_charger.c ++++ b/drivers/power/supply/act8945a_charger.c +@@ -597,14 +597,6 @@ static int act8945a_charger_probe(struct platform_device *pdev) + return irq ?: -ENXIO; + } + +- ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, +- IRQF_TRIGGER_FALLING, "act8945a_interrupt", +- charger); +- if (ret) { +- dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); +- return ret; +- } +- + charger->desc.name = "act8945a-charger"; + charger->desc.get_property = act8945a_charger_get_property; + charger->desc.properties = act8945a_charger_props; +@@ -625,6 +617,14 @@ static int act8945a_charger_probe(struct platform_device *pdev) + return PTR_ERR(charger->psy); + } + ++ ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, ++ IRQF_TRIGGER_FALLING, "act8945a_interrupt", ++ charger); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); ++ return ret; ++ } ++ + platform_set_drvdata(pdev, charger); + + INIT_WORK(&charger->work, act8945a_work); +-- +2.51.0 + diff --git a/queue-6.1/power-supply-bq256xx-fix-use-after-free-in-power_sup.patch b/queue-6.1/power-supply-bq256xx-fix-use-after-free-in-power_sup.patch new file mode 100644 index 0000000000..888498d89e --- /dev/null +++ b/queue-6.1/power-supply-bq256xx-fix-use-after-free-in-power_sup.patch @@ -0,0 +1,73 @@ +From 37dc62ac0bbc780ceddfa7da83c12180c666752c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:35:59 +0100 +Subject: power: supply: bq256xx: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 8005843369723d9c8975b7c4202d1b85d6125302 ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: 32e4978bb920 ("power: supply: bq256xx: Introduce the BQ256XX charger driver") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/39da6da8cc060fa0382ca859f65071e791cb6119.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/bq256xx_charger.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/power/supply/bq256xx_charger.c b/drivers/power/supply/bq256xx_charger.c +index 686eb8d86e221..e75283006d29c 100644 +--- a/drivers/power/supply/bq256xx_charger.c ++++ b/drivers/power/supply/bq256xx_charger.c +@@ -1678,6 +1678,12 @@ static int bq256xx_probe(struct i2c_client *client, + usb_register_notifier(bq->usb3_phy, &bq->usb_nb); + } + ++ ret = bq256xx_power_supply_init(bq, &psy_cfg, dev); ++ if (ret) { ++ dev_err(dev, "Failed to register power supply\n"); ++ return ret; ++ } ++ + if (client->irq) { + ret = devm_request_threaded_irq(dev, client->irq, NULL, + bq256xx_irq_handler_thread, +@@ -1690,12 +1696,6 @@ static int bq256xx_probe(struct i2c_client *client, + } + } + +- ret = bq256xx_power_supply_init(bq, &psy_cfg, dev); +- if (ret) { +- dev_err(dev, "Failed to register power supply\n"); +- return ret; +- } +- + ret = bq256xx_hw_init(bq); + if (ret) { + dev_err(dev, "Cannot initialize the chip.\n"); +-- +2.51.0 + diff --git a/queue-6.1/power-supply-bq25980-fix-use-after-free-in-power_sup.patch b/queue-6.1/power-supply-bq25980-fix-use-after-free-in-power_sup.patch new file mode 100644 index 0000000000..8c128033ba --- /dev/null +++ b/queue-6.1/power-supply-bq25980-fix-use-after-free-in-power_sup.patch @@ -0,0 +1,73 @@ +From ccaddb0136ddb0dbd73209f8d770b1a474452ff4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:35:59 +0100 +Subject: power: supply: bq25980: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 5f0b1cb41906e86b64bf69f5ededb83b0d757c27 ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: 5069185fc18e ("power: supply: bq25980: Add support for the BQ259xx family") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/8763035cadb959e14787b3837f2d3db61f6e1c34.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/bq25980_charger.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/power/supply/bq25980_charger.c b/drivers/power/supply/bq25980_charger.c +index 9339f56492827..54f444776f174 100644 +--- a/drivers/power/supply/bq25980_charger.c ++++ b/drivers/power/supply/bq25980_charger.c +@@ -1241,6 +1241,12 @@ static int bq25980_probe(struct i2c_client *client, + return ret; + } + ++ ret = bq25980_power_supply_init(bq, dev); ++ if (ret) { ++ dev_err(dev, "Failed to register power supply\n"); ++ return ret; ++ } ++ + if (client->irq) { + ret = devm_request_threaded_irq(dev, client->irq, NULL, + bq25980_irq_handler_thread, +@@ -1251,12 +1257,6 @@ static int bq25980_probe(struct i2c_client *client, + return ret; + } + +- ret = bq25980_power_supply_init(bq, dev); +- if (ret) { +- dev_err(dev, "Failed to register power supply\n"); +- return ret; +- } +- + ret = bq25980_hw_init(bq); + if (ret) { + dev_err(dev, "Cannot initialize the chip.\n"); +-- +2.51.0 + diff --git a/queue-6.1/power-supply-bq27xxx-fix-wrong-errno-when-bus-ops-ar.patch b/queue-6.1/power-supply-bq27xxx-fix-wrong-errno-when-bus-ops-ar.patch new file mode 100644 index 0000000000..92836f13fc --- /dev/null +++ b/queue-6.1/power-supply-bq27xxx-fix-wrong-errno-when-bus-ops-ar.patch @@ -0,0 +1,61 @@ +From f1383bf7f4b2b6862a19ed28353deb78f8964e60 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Dec 2025 16:34:36 +0800 +Subject: power: supply: bq27xxx: fix wrong errno when bus ops are unsupported + +From: Haotian Zhang + +[ Upstream commit 688364a11647dc09ba1e4429313e0008066ec790 ] + +bq27xxx_write(), bq27xxx_read_block(), and bq27xxx_write_block() +return -EPERM when the bus callback pointer is NULL. A NULL callback +indicates the operation is not supported by the bus/driver, +not that permission is denied. + +Return -EOPNOTSUPP instead of -EPERM when di->bus.write/ +read_bulk/write_bulk is NULL. + +Fixes: 14073f6614f6 ("power: supply: bq27xxx: Add bulk transfer bus methods") +Signed-off-by: Haotian Zhang +Reviewed-by: Matt Ranostay +Link: https://patch.msgid.link/20251204083436.1367-1-vulab@iscas.ac.cn +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/bq27xxx_battery.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c +index 5a11424ae774e..f973b25c7bf3d 100644 +--- a/drivers/power/supply/bq27xxx_battery.c ++++ b/drivers/power/supply/bq27xxx_battery.c +@@ -1162,7 +1162,7 @@ static inline int bq27xxx_write(struct bq27xxx_device_info *di, int reg_index, + return -EINVAL; + + if (!di->bus.write) +- return -EPERM; ++ return -EOPNOTSUPP; + + ret = di->bus.write(di, di->regs[reg_index], value, single); + if (ret < 0) +@@ -1181,7 +1181,7 @@ static inline int bq27xxx_read_block(struct bq27xxx_device_info *di, int reg_ind + return -EINVAL; + + if (!di->bus.read_bulk) +- return -EPERM; ++ return -EOPNOTSUPP; + + ret = di->bus.read_bulk(di, di->regs[reg_index], data, len); + if (ret < 0) +@@ -1200,7 +1200,7 @@ static inline int bq27xxx_write_block(struct bq27xxx_device_info *di, int reg_in + return -EINVAL; + + if (!di->bus.write_bulk) +- return -EPERM; ++ return -EOPNOTSUPP; + + ret = di->bus.write_bulk(di, di->regs[reg_index], data, len); + if (ret < 0) +-- +2.51.0 + diff --git a/queue-6.1/power-supply-cpcap-battery-fix-use-after-free-in-pow.patch b/queue-6.1/power-supply-cpcap-battery-fix-use-after-free-in-pow.patch new file mode 100644 index 0000000000..e86939ec1a --- /dev/null +++ b/queue-6.1/power-supply-cpcap-battery-fix-use-after-free-in-pow.patch @@ -0,0 +1,70 @@ +From 3e5a45cec2bd710b72e6f2775779b75f8cfa81c1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:36:00 +0100 +Subject: power: supply: cpcap-battery: Fix use-after-free in + power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 642f33e34b969eedec334738fd5df95d2dc42742 ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: 874b2adbed12 ("power: supply: cpcap-battery: Add a battery driver") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/81db58d610c9a51a68184f856cd431a934cccee2.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/cpcap-battery.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/power/supply/cpcap-battery.c b/drivers/power/supply/cpcap-battery.c +index d98d9244e3948..1dbd1c67d00a9 100644 +--- a/drivers/power/supply/cpcap-battery.c ++++ b/drivers/power/supply/cpcap-battery.c +@@ -1122,10 +1122,6 @@ static int cpcap_battery_probe(struct platform_device *pdev) + + platform_set_drvdata(pdev, ddata); + +- error = cpcap_battery_init_interrupts(pdev, ddata); +- if (error) +- return error; +- + error = cpcap_battery_init_iio(ddata); + if (error) + return error; +@@ -1142,6 +1138,10 @@ static int cpcap_battery_probe(struct platform_device *pdev) + return error; + } + ++ error = cpcap_battery_init_interrupts(pdev, ddata); ++ if (error) ++ return error; ++ + atomic_set(&ddata->active, 1); + + error = cpcap_battery_calibrate(ddata); +-- +2.51.0 + diff --git a/queue-6.1/power-supply-goldfish-fix-use-after-free-in-power_su.patch b/queue-6.1/power-supply-goldfish-fix-use-after-free-in-power_su.patch new file mode 100644 index 0000000000..3a8f092c7b --- /dev/null +++ b/queue-6.1/power-supply-goldfish-fix-use-after-free-in-power_su.patch @@ -0,0 +1,73 @@ +From abe86e801e01e539acbf04d1feaac179ab82d79d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:36:00 +0100 +Subject: power: supply: goldfish: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit b2ce982e2e0c888dc55c888ad0e20ea04daf2e6b ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: 84d7b7687489 ("power: Add battery driver for goldfish emulator") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/500a606bb6fb6f2bb8d797e19a00cea9dd7b03c1.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/goldfish_battery.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/power/supply/goldfish_battery.c b/drivers/power/supply/goldfish_battery.c +index a58d713d75ce8..4d204f0e18532 100644 +--- a/drivers/power/supply/goldfish_battery.c ++++ b/drivers/power/supply/goldfish_battery.c +@@ -224,12 +224,6 @@ static int goldfish_battery_probe(struct platform_device *pdev) + if (data->irq < 0) + return -ENODEV; + +- ret = devm_request_irq(&pdev->dev, data->irq, +- goldfish_battery_interrupt, +- IRQF_SHARED, pdev->name, data); +- if (ret) +- return ret; +- + psy_cfg.drv_data = data; + + data->ac = power_supply_register(&pdev->dev, &ac_desc, &psy_cfg); +@@ -245,6 +239,12 @@ static int goldfish_battery_probe(struct platform_device *pdev) + + platform_set_drvdata(pdev, data); + ++ ret = devm_request_irq(&pdev->dev, data->irq, ++ goldfish_battery_interrupt, ++ IRQF_SHARED, pdev->name, data); ++ if (ret) ++ return ret; ++ + GOLDFISH_BATTERY_WRITE(data, BATTERY_INT_ENABLE, BATTERY_INT_MASK); + return 0; + } +-- +2.51.0 + diff --git a/queue-6.1/power-supply-rt9455-fix-use-after-free-in-power_supp.patch b/queue-6.1/power-supply-rt9455-fix-use-after-free-in-power_supp.patch new file mode 100644 index 0000000000..5ffbcedd3d --- /dev/null +++ b/queue-6.1/power-supply-rt9455-fix-use-after-free-in-power_supp.patch @@ -0,0 +1,78 @@ +From 8f2bb7485e33b1eb63c3a8fb037c887989e0c1e2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:36:02 +0100 +Subject: power: supply: rt9455: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit e2febe375e5ea5afed92f4cd9711bde8f24ee6d2 ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: e86d69dd786e ("power_supply: Add support for Richtek RT9455 battery charger") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/1567d831e04c3e2fcb9e18dd36b7bcba4634581a.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/rt9455_charger.c | 17 +++++++++-------- + 1 file changed, 9 insertions(+), 8 deletions(-) + +diff --git a/drivers/power/supply/rt9455_charger.c b/drivers/power/supply/rt9455_charger.c +index c5597967a0699..566243a423c8f 100644 +--- a/drivers/power/supply/rt9455_charger.c ++++ b/drivers/power/supply/rt9455_charger.c +@@ -1665,6 +1665,15 @@ static int rt9455_probe(struct i2c_client *client, + rt9455_charger_config.supplied_to = rt9455_charger_supplied_to; + rt9455_charger_config.num_supplicants = + ARRAY_SIZE(rt9455_charger_supplied_to); ++ ++ info->charger = devm_power_supply_register(dev, &rt9455_charger_desc, ++ &rt9455_charger_config); ++ if (IS_ERR(info->charger)) { ++ dev_err(dev, "Failed to register charger\n"); ++ ret = PTR_ERR(info->charger); ++ goto put_usb_notifier; ++ } ++ + ret = devm_request_threaded_irq(dev, client->irq, NULL, + rt9455_irq_handler_thread, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, +@@ -1680,14 +1689,6 @@ static int rt9455_probe(struct i2c_client *client, + goto put_usb_notifier; + } + +- info->charger = devm_power_supply_register(dev, &rt9455_charger_desc, +- &rt9455_charger_config); +- if (IS_ERR(info->charger)) { +- dev_err(dev, "Failed to register charger\n"); +- ret = PTR_ERR(info->charger); +- goto put_usb_notifier; +- } +- + return 0; + + put_usb_notifier: +-- +2.51.0 + diff --git a/queue-6.1/power-supply-sbs-battery-fix-use-after-free-in-power.patch b/queue-6.1/power-supply-sbs-battery-fix-use-after-free-in-power.patch new file mode 100644 index 0000000000..c6f2f33fb1 --- /dev/null +++ b/queue-6.1/power-supply-sbs-battery-fix-use-after-free-in-power.patch @@ -0,0 +1,101 @@ +From df1beae008ea5faab465682d3149c88cff76edda Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:36:02 +0100 +Subject: power: supply: sbs-battery: Fix use-after-free in + power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 8d59cf3887fbabacef53bfba473e33e8a8d9d07b ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. Keep the old behavior of +just printing a warning in case of any failures during the IRQ request +and finishing the probe successfully. + +Fixes: d2cec82c2880 ("power: sbs-battery: Request threaded irq and fix dev callback cookie") +Signed-off-by: Waqar Hameed +Reviewed-by: Phil Reid +Link: https://patch.msgid.link/0ef896e002495e615157b482d18a437af19ddcd0.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/sbs-battery.c | 36 +++++++++++++++--------------- + 1 file changed, 18 insertions(+), 18 deletions(-) + +diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c +index c4a95b01463ae..a633130a768df 100644 +--- a/drivers/power/supply/sbs-battery.c ++++ b/drivers/power/supply/sbs-battery.c +@@ -1173,24 +1173,6 @@ static int sbs_probe(struct i2c_client *client) + + i2c_set_clientdata(client, chip); + +- if (!chip->gpio_detect) +- goto skip_gpio; +- +- irq = gpiod_to_irq(chip->gpio_detect); +- if (irq <= 0) { +- dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq); +- goto skip_gpio; +- } +- +- rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq, +- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, +- dev_name(&client->dev), chip); +- if (rc) { +- dev_warn(&client->dev, "Failed to request irq: %d\n", rc); +- goto skip_gpio; +- } +- +-skip_gpio: + /* + * Before we register, we might need to make sure we can actually talk + * to the battery. +@@ -1216,6 +1198,24 @@ static int sbs_probe(struct i2c_client *client) + return dev_err_probe(&client->dev, PTR_ERR(chip->power_supply), + "Failed to register power supply\n"); + ++ if (!chip->gpio_detect) ++ goto out; ++ ++ irq = gpiod_to_irq(chip->gpio_detect); ++ if (irq <= 0) { ++ dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq); ++ goto out; ++ } ++ ++ rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq, ++ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, ++ dev_name(&client->dev), chip); ++ if (rc) { ++ dev_warn(&client->dev, "Failed to request irq: %d\n", rc); ++ goto out; ++ } ++ ++out: + dev_info(&client->dev, + "%s: battery gas gauge device registered\n", client->name); + +-- +2.51.0 + diff --git a/queue-6.1/power-supply-wm97xx-fix-null-pointer-dereference-in-.patch b/queue-6.1/power-supply-wm97xx-fix-null-pointer-dereference-in-.patch new file mode 100644 index 0000000000..4f8332ee28 --- /dev/null +++ b/queue-6.1/power-supply-wm97xx-fix-null-pointer-dereference-in-.patch @@ -0,0 +1,98 @@ +From 11645be04e87cbcbeb239a9dfa0f3135d00aabf5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:46:24 +0100 +Subject: power: supply: wm97xx: Fix NULL pointer dereference in + power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 39fe0eac6d755ef215026518985fcf8de9360e9e ] + +In `probe()`, `request_irq()` is called before allocating/registering a +`power_supply` handle. If an interrupt is fired between the call to +`request_irq()` and `power_supply_register()`, the `power_supply` handle +will be used uninitialized in `power_supply_changed()` in +`wm97xx_bat_update()` (triggered from the interrupt handler). This will +lead to a `NULL` pointer dereference since + +Fix this racy `NULL` pointer dereference by making sure the IRQ is +requested _after_ the registration of the `power_supply` handle. Since +the IRQ is the last thing requests in the `probe()` now, remove the +error path for freeing it. Instead add one for unregistering the +`power_supply` handle when IRQ request fails. + +Fixes: 7c87942aef52 ("wm97xx_battery: Use irq to detect charger state") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/97b55f0479a932eea7213844bf66f28a974e27a2.1766270196.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/wm97xx_battery.c | 34 +++++++++++++++------------ + 1 file changed, 19 insertions(+), 15 deletions(-) + +diff --git a/drivers/power/supply/wm97xx_battery.c b/drivers/power/supply/wm97xx_battery.c +index a0e1eaa25d93e..e2a41f9c903c5 100644 +--- a/drivers/power/supply/wm97xx_battery.c ++++ b/drivers/power/supply/wm97xx_battery.c +@@ -178,12 +178,6 @@ static int wm97xx_bat_probe(struct platform_device *dev) + "failed to get charge GPIO\n"); + if (charge_gpiod) { + gpiod_set_consumer_name(charge_gpiod, "BATT CHRG"); +- ret = request_irq(gpiod_to_irq(charge_gpiod), +- wm97xx_chrg_irq, 0, +- "AC Detect", dev); +- if (ret) +- return dev_err_probe(&dev->dev, ret, +- "failed to request GPIO irq\n"); + props++; /* POWER_SUPPLY_PROP_STATUS */ + } + +@@ -199,10 +193,8 @@ static int wm97xx_bat_probe(struct platform_device *dev) + props++; /* POWER_SUPPLY_PROP_VOLTAGE_MIN */ + + prop = kcalloc(props, sizeof(*prop), GFP_KERNEL); +- if (!prop) { +- ret = -ENOMEM; +- goto err3; +- } ++ if (!prop) ++ return -ENOMEM; + + prop[i++] = POWER_SUPPLY_PROP_PRESENT; + if (charge_gpiod) +@@ -236,15 +228,27 @@ static int wm97xx_bat_probe(struct platform_device *dev) + schedule_work(&bat_work); + } else { + ret = PTR_ERR(bat_psy); +- goto err4; ++ goto free; ++ } ++ ++ if (charge_gpiod) { ++ ret = request_irq(gpiod_to_irq(charge_gpiod), wm97xx_chrg_irq, ++ 0, "AC Detect", dev); ++ if (ret) { ++ dev_err_probe(&dev->dev, ret, ++ "failed to request GPIO irq\n"); ++ goto unregister; ++ } + } + + return 0; +-err4: ++ ++unregister: ++ power_supply_unregister(bat_psy); ++ ++free: + kfree(prop); +-err3: +- if (charge_gpiod) +- free_irq(gpiod_to_irq(charge_gpiod), dev); ++ + return ret; + } + +-- +2.51.0 + diff --git a/queue-6.1/powerpc-eeh-fix-recursive-pci_lock_rescan_remove-loc.patch b/queue-6.1/powerpc-eeh-fix-recursive-pci_lock_rescan_remove-loc.patch new file mode 100644 index 0000000000..f3766001c0 --- /dev/null +++ b/queue-6.1/powerpc-eeh-fix-recursive-pci_lock_rescan_remove-loc.patch @@ -0,0 +1,275 @@ +From b4bb07829a86afcffdd723b1edca87df49b99882 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 10 Dec 2025 08:25:59 -0600 +Subject: powerpc/eeh: fix recursive pci_lock_rescan_remove locking in EEH + event handling +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Narayana Murty N + +[ Upstream commit 815a8d2feb5615ae7f0b5befd206af0b0160614c ] + +The recent commit 1010b4c012b0 ("powerpc/eeh: Make EEH driver device +hotplug safe") restructured the EEH driver to improve synchronization +with the PCI hotplug layer. + +However, it inadvertently moved pci_lock_rescan_remove() outside its +intended scope in eeh_handle_normal_event(), leading to broken PCI +error reporting and improper EEH event triggering. Specifically, +eeh_handle_normal_event() acquired pci_lock_rescan_remove() before +calling eeh_pe_bus_get(), but eeh_pe_bus_get() itself attempts to +acquire the same lock internally, causing nested locking and disrupting +normal EEH event handling paths. + +This patch adds a boolean parameter do_lock to _eeh_pe_bus_get(), +with two public wrappers: + eeh_pe_bus_get() with locking enabled. + eeh_pe_bus_get_nolock() that skips locking. + +Callers that already hold pci_lock_rescan_remove() now use +eeh_pe_bus_get_nolock() to avoid recursive lock acquisition. + +Additionally, pci_lock_rescan_remove() calls are restored to the correct +position—after eeh_pe_bus_get() and immediately before iterating affected +PEs and devices. This ensures EEH-triggered PCI removes occur under proper +bus rescan locking without recursive lock contention. + +The eeh_pe_loc_get() function has been split into two functions: + eeh_pe_loc_get(struct eeh_pe *pe) which retrieves the loc for given PE. + eeh_pe_loc_get_bus(struct pci_bus *bus) which retrieves the location + code for given bus. + +This resolves lockdep warnings such as: + +[ 84.964298] [ T928] ============================================ +[ 84.964304] [ T928] WARNING: possible recursive locking detected +[ 84.964311] [ T928] 6.18.0-rc3 #51 Not tainted +[ 84.964315] [ T928] -------------------------------------------- +[ 84.964320] [ T928] eehd/928 is trying to acquire lock: +[ 84.964324] [ T928] c000000003b29d58 (pci_rescan_remove_lock){+.+.}-{3:3}, at: pci_lock_rescan_remove+0x28/0x40 +[ 84.964342] [ T928] + but task is already holding lock: +[ 84.964347] [ T928] c000000003b29d58 (pci_rescan_remove_lock){+.+.}-{3:3}, at: pci_lock_rescan_remove+0x28/0x40 +[ 84.964357] [ T928] + other info that might help us debug this: +[ 84.964363] [ T928] Possible unsafe locking scenario: + +[ 84.964367] [ T928] CPU0 +[ 84.964370] [ T928] ---- +[ 84.964373] [ T928] lock(pci_rescan_remove_lock); +[ 84.964378] [ T928] lock(pci_rescan_remove_lock); +[ 84.964383] [ T928] + *** DEADLOCK *** + +[ 84.964388] [ T928] May be due to missing lock nesting notation + +[ 84.964393] [ T928] 1 lock held by eehd/928: +[ 84.964397] [ T928] #0: c000000003b29d58 (pci_rescan_remove_lock){+.+.}-{3:3}, at: pci_lock_rescan_remove+0x28/0x40 +[ 84.964408] [ T928] + stack backtrace: +[ 84.964414] [ T928] CPU: 2 UID: 0 PID: 928 Comm: eehd Not tainted 6.18.0-rc3 #51 VOLUNTARY +[ 84.964417] [ T928] Hardware name: IBM,9080-HEX POWER10 (architected) 0x800200 0xf000006 of:IBM,FW1060.00 (NH1060_022) hv:phyp pSeries +[ 84.964419] [ T928] Call Trace: +[ 84.964420] [ T928] [c0000011a7157990] [c000000001705de4] dump_stack_lvl+0xc8/0x130 (unreliable) +[ 84.964424] [ T928] [c0000011a71579d0] [c0000000002f66e0] print_deadlock_bug+0x430/0x440 +[ 84.964428] [ T928] [c0000011a7157a70] [c0000000002fd0c0] __lock_acquire+0x1530/0x2d80 +[ 84.964431] [ T928] [c0000011a7157ba0] [c0000000002fea54] lock_acquire+0x144/0x410 +[ 84.964433] [ T928] [c0000011a7157cb0] [c0000011a7157cb0] __mutex_lock+0xf4/0x1050 +[ 84.964436] [ T928] [c0000011a7157e00] [c000000000de21d8] pci_lock_rescan_remove+0x28/0x40 +[ 84.964439] [ T928] [c0000011a7157e20] [c00000000004ed98] eeh_pe_bus_get+0x48/0xc0 +[ 84.964442] [ T928] [c0000011a7157e50] [c000000000050434] eeh_handle_normal_event+0x64/0xa60 +[ 84.964446] [ T928] [c0000011a7157f30] [c000000000051de8] eeh_event_handler+0xf8/0x190 +[ 84.964450] [ T928] [c0000011a7157f90] [c0000000002747ac] kthread+0x16c/0x180 +[ 84.964453] [ T928] [c0000011a7157fe0] [c00000000000ded8] start_kernel_thread+0x14/0x18 + + +Fixes: 1010b4c012b0 ("powerpc/eeh: Make EEH driver device hotplug safe") +Signed-off-by: Narayana Murty N +Reviewed-by: Sourabh Jain +Reviewed-by: Mahesh Salgaonkar +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/20251210142559.8874-1-nnmlinux@linux.ibm.com +Signed-off-by: Sasha Levin +--- + arch/powerpc/include/asm/eeh.h | 2 + + arch/powerpc/kernel/eeh_driver.c | 11 ++--- + arch/powerpc/kernel/eeh_pe.c | 74 ++++++++++++++++++++++++++++++-- + 3 files changed, 78 insertions(+), 9 deletions(-) + +diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h +index 514dd056c2c84..b5709b9aed238 100644 +--- a/arch/powerpc/include/asm/eeh.h ++++ b/arch/powerpc/include/asm/eeh.h +@@ -289,6 +289,8 @@ void eeh_pe_dev_traverse(struct eeh_pe *root, + void eeh_pe_restore_bars(struct eeh_pe *pe); + const char *eeh_pe_loc_get(struct eeh_pe *pe); + struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe); ++const char *eeh_pe_loc_get_bus(struct pci_bus *bus); ++struct pci_bus *eeh_pe_bus_get_nolock(struct eeh_pe *pe); + + void eeh_show_enabled(void); + int __init eeh_init(struct eeh_ops *ops); +diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c +index 9a761f46c7b23..70251c8c365ef 100644 +--- a/arch/powerpc/kernel/eeh_driver.c ++++ b/arch/powerpc/kernel/eeh_driver.c +@@ -846,7 +846,7 @@ void eeh_handle_normal_event(struct eeh_pe *pe) + + pci_lock_rescan_remove(); + +- bus = eeh_pe_bus_get(pe); ++ bus = eeh_pe_bus_get_nolock(pe); + if (!bus) { + pr_err("%s: Cannot find PCI bus for PHB#%x-PE#%x\n", + __func__, pe->phb->global_number, pe->addr); +@@ -877,14 +877,15 @@ void eeh_handle_normal_event(struct eeh_pe *pe) + /* Log the event */ + if (pe->type & EEH_PE_PHB) { + pr_err("EEH: Recovering PHB#%x, location: %s\n", +- pe->phb->global_number, eeh_pe_loc_get(pe)); ++ pe->phb->global_number, eeh_pe_loc_get_bus(bus)); + } else { + struct eeh_pe *phb_pe = eeh_phb_pe_get(pe->phb); + + pr_err("EEH: Recovering PHB#%x-PE#%x\n", + pe->phb->global_number, pe->addr); + pr_err("EEH: PE location: %s, PHB location: %s\n", +- eeh_pe_loc_get(pe), eeh_pe_loc_get(phb_pe)); ++ eeh_pe_loc_get_bus(bus), ++ eeh_pe_loc_get_bus(eeh_pe_bus_get_nolock(phb_pe))); + } + + #ifdef CONFIG_STACKTRACE +@@ -1089,7 +1090,7 @@ void eeh_handle_normal_event(struct eeh_pe *pe) + eeh_pe_state_clear(pe, EEH_PE_PRI_BUS, true); + eeh_pe_dev_mode_mark(pe, EEH_DEV_REMOVED); + +- bus = eeh_pe_bus_get(pe); ++ bus = eeh_pe_bus_get_nolock(pe); + if (bus) + pci_hp_remove_devices(bus); + else +@@ -1213,7 +1214,7 @@ void eeh_handle_special_event(void) + (phb_pe->state & EEH_PE_RECOVERING)) + continue; + +- bus = eeh_pe_bus_get(phb_pe); ++ bus = eeh_pe_bus_get_nolock(phb_pe); + if (!bus) { + pr_err("%s: Cannot find PCI bus for " + "PHB#%x-PE#%x\n", +diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c +index 08095aeba5c98..b10fcca520400 100644 +--- a/arch/powerpc/kernel/eeh_pe.c ++++ b/arch/powerpc/kernel/eeh_pe.c +@@ -812,6 +812,24 @@ void eeh_pe_restore_bars(struct eeh_pe *pe) + const char *eeh_pe_loc_get(struct eeh_pe *pe) + { + struct pci_bus *bus = eeh_pe_bus_get(pe); ++ return eeh_pe_loc_get_bus(bus); ++} ++ ++/** ++ * eeh_pe_loc_get_bus - Retrieve location code binding to the given PCI bus ++ * @bus: PCI bus ++ * ++ * Retrieve the location code associated with the given PCI bus. If the bus ++ * is a root bus, the location code is fetched from the PHB device tree node ++ * or root port. Otherwise, the location code is obtained from the device ++ * tree node of the upstream bridge of the bus. The function walks up the ++ * bus hierarchy if necessary, checking each node for the appropriate ++ * location code property ("ibm,io-base-loc-code" for root buses, ++ * "ibm,slot-location-code" for others). If no location code is found, ++ * returns "N/A". ++ */ ++const char *eeh_pe_loc_get_bus(struct pci_bus *bus) ++{ + struct device_node *dn; + const char *loc = NULL; + +@@ -838,8 +856,9 @@ const char *eeh_pe_loc_get(struct eeh_pe *pe) + } + + /** +- * eeh_pe_bus_get - Retrieve PCI bus according to the given PE ++ * _eeh_pe_bus_get - Retrieve PCI bus according to the given PE + * @pe: EEH PE ++ * @do_lock: Is the caller already held the pci_lock_rescan_remove? + * + * Retrieve the PCI bus according to the given PE. Basically, + * there're 3 types of PEs: PHB/Bus/Device. For PHB PE, the +@@ -847,7 +866,7 @@ const char *eeh_pe_loc_get(struct eeh_pe *pe) + * returned for BUS PE. However, we don't have associated PCI + * bus for DEVICE PE. + */ +-struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe) ++static struct pci_bus *_eeh_pe_bus_get(struct eeh_pe *pe, bool do_lock) + { + struct eeh_dev *edev; + struct pci_dev *pdev; +@@ -862,11 +881,58 @@ struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe) + + /* Retrieve the parent PCI bus of first (top) PCI device */ + edev = list_first_entry_or_null(&pe->edevs, struct eeh_dev, entry); +- pci_lock_rescan_remove(); ++ if (do_lock) ++ pci_lock_rescan_remove(); + pdev = eeh_dev_to_pci_dev(edev); + if (pdev) + bus = pdev->bus; +- pci_unlock_rescan_remove(); ++ if (do_lock) ++ pci_unlock_rescan_remove(); + + return bus; + } ++ ++/** ++ * eeh_pe_bus_get - Retrieve PCI bus associated with the given EEH PE, locking ++ * if needed ++ * @pe: Pointer to the EEH PE ++ * ++ * This function is a wrapper around _eeh_pe_bus_get(), which retrieves the PCI ++ * bus associated with the provided EEH PE structure. It acquires the PCI ++ * rescans lock to ensure safe access to shared data during the retrieval ++ * process. This function should be used when the caller requires the PCI bus ++ * while holding the rescan/remove lock, typically during operations that modify ++ * or inspect PCIe device state in a safe manner. ++ * ++ * RETURNS: ++ * A pointer to the PCI bus associated with the EEH PE, or NULL if none found. ++ */ ++ ++struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe) ++{ ++ return _eeh_pe_bus_get(pe, true); ++} ++ ++/** ++ * eeh_pe_bus_get_nolock - Retrieve PCI bus associated with the given EEH PE ++ * without locking ++ * @pe: Pointer to the EEH PE ++ * ++ * This function is a variant of _eeh_pe_bus_get() that retrieves the PCI bus ++ * associated with the specified EEH PE without acquiring the ++ * pci_lock_rescan_remove lock. It should only be used when the caller can ++ * guarantee safe access to PE structures without the need for that lock, ++ * typically in contexts where the lock is already held locking is otherwise ++ * managed. ++ * ++ * RETURNS: ++ * pointer to the PCI bus associated with the EEH PE, or NULL if none is found. ++ * ++ * NOTE: ++ * Use this function carefully to avoid race conditions and data corruption. ++ */ ++ ++struct pci_bus *eeh_pe_bus_get_nolock(struct eeh_pe *pe) ++{ ++ return _eeh_pe_bus_get(pe, false); ++} +-- +2.51.0 + diff --git a/queue-6.1/powerpc-uaccess-move-barrier_nospec-out-of-allow_rea.patch b/queue-6.1/powerpc-uaccess-move-barrier_nospec-out-of-allow_rea.patch new file mode 100644 index 0000000000..67994b3e2a --- /dev/null +++ b/queue-6.1/powerpc-uaccess-move-barrier_nospec-out-of-allow_rea.patch @@ -0,0 +1,98 @@ +From e08bfa2162c1968b1e15b5c645bf435ea1f6cf92 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Dec 2025 12:20:49 +0100 +Subject: powerpc/uaccess: Move barrier_nospec() out of + allow_read_{from/write}_user() + +From: Christophe Leroy + +[ Upstream commit 5fbc09eb0b4f4b1a4b33abebacbeee0d29f195e9 ] + +Commit 74e19ef0ff80 ("uaccess: Add speculation barrier to +copy_from_user()") added a redundant barrier_nospec() in +copy_from_user(), because powerpc is already calling +barrier_nospec() in allow_read_from_user() and +allow_read_write_user(). But on other architectures that +call to barrier_nospec() was missing. So change powerpc +instead of reverting the above commit and having to fix +other architectures one by one. This is now possible +because barrier_nospec() has also been added in +copy_from_user_iter(). + +Move barrier_nospec() out of allow_read_from_user() and +allow_read_write_user(). This will also allow reuse of those +functions when implementing masked user access which doesn't +require barrier_nospec(). + +Don't add it back in raw_copy_from_user() as it is already called +by copy_from_user() and copy_from_user_iter(). + +Fixes: 74e19ef0ff80 ("uaccess: Add speculation barrier to copy_from_user()") +Signed-off-by: Christophe Leroy +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/f29612105c5fcbc8ceb7303808ddc1a781f0f6b5.1766574657.git.chleroy@kernel.org +Signed-off-by: Sasha Levin +--- + arch/powerpc/include/asm/kup.h | 2 -- + arch/powerpc/include/asm/uaccess.h | 4 ++++ + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/arch/powerpc/include/asm/kup.h b/arch/powerpc/include/asm/kup.h +index d751ddd081108..6ee6601f5d4e9 100644 +--- a/arch/powerpc/include/asm/kup.h ++++ b/arch/powerpc/include/asm/kup.h +@@ -163,7 +163,6 @@ static __always_inline void restore_user_access(unsigned long flags) + + static __always_inline void allow_read_from_user(const void __user *from, unsigned long size) + { +- barrier_nospec(); + allow_user_access(NULL, from, size, KUAP_READ); + } + +@@ -175,7 +174,6 @@ static __always_inline void allow_write_to_user(void __user *to, unsigned long s + static __always_inline void allow_read_write_user(void __user *to, const void __user *from, + unsigned long size) + { +- barrier_nospec(); + allow_user_access(to, from, size, KUAP_READ_WRITE); + } + +diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h +index 63e7c3107cc88..0d874e343b9f6 100644 +--- a/arch/powerpc/include/asm/uaccess.h ++++ b/arch/powerpc/include/asm/uaccess.h +@@ -285,6 +285,7 @@ do { \ + __typeof__(sizeof(*(ptr))) __gu_size = sizeof(*(ptr)); \ + \ + might_fault(); \ ++ barrier_nospec(); \ + allow_read_from_user(__gu_addr, __gu_size); \ + __get_user_size_allowed(__gu_val, __gu_addr, __gu_size, __gu_err); \ + prevent_read_from_user(__gu_addr, __gu_size); \ +@@ -313,6 +314,7 @@ raw_copy_in_user(void __user *to, const void __user *from, unsigned long n) + { + unsigned long ret; + ++ barrier_nospec(); + allow_read_write_user(to, from, n); + ret = __copy_tofrom_user(to, from, n); + prevent_read_write_user(to, from, n); +@@ -401,6 +403,7 @@ static __must_check inline bool user_access_begin(const void __user *ptr, size_t + + might_fault(); + ++ barrier_nospec(); + allow_read_write_user((void __user *)ptr, ptr, len); + return true; + } +@@ -417,6 +420,7 @@ user_read_access_begin(const void __user *ptr, size_t len) + + might_fault(); + ++ barrier_nospec(); + allow_read_from_user(ptr, len); + return true; + } +-- +2.51.0 + diff --git a/queue-6.1/procfs-fix-missing-rcu-protection-when-reading-real_.patch b/queue-6.1/procfs-fix-missing-rcu-protection-when-reading-real_.patch new file mode 100644 index 0000000000..56485443d7 --- /dev/null +++ b/queue-6.1/procfs-fix-missing-rcu-protection-when-reading-real_.patch @@ -0,0 +1,59 @@ +From 8085dbc6843f4a9f46d0cbbf7bf0cba0e16bab6a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 16:30:07 +0800 +Subject: procfs: fix missing RCU protection when reading real_parent in + do_task_stat() + +From: Jinliang Zheng + +[ Upstream commit 76149d53502cf17ef3ae454ff384551236fba867 ] + +When reading /proc/[pid]/stat, do_task_stat() accesses task->real_parent +without proper RCU protection, which leads to: + + cpu 0 cpu 1 + ----- ----- + do_task_stat + var = task->real_parent + release_task + call_rcu(delayed_put_task_struct) + task_tgid_nr_ns(var) + rcu_read_lock <--- Too late to protect task->real_parent! + task_pid_ptr <--- UAF! + rcu_read_unlock + +This patch uses task_ppid_nr_ns() instead of task_tgid_nr_ns() to add +proper RCU protection for accessing task->real_parent. + +Link: https://lkml.kernel.org/r/20260128083007.3173016-1-alexjlzheng@tencent.com +Fixes: 06fffb1267c9 ("do_task_stat: don't take rcu_read_lock()") +Signed-off-by: Jinliang Zheng +Acked-by: Oleg Nesterov +Cc: David Hildenbrand +Cc: Ingo Molnar +Cc: Lorenzo Stoakes +Cc: Mateusz Guzik +Cc: ruippan +Cc: Usama Arif +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/proc/array.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/proc/array.c b/fs/proc/array.c +index 86fde69ec11a2..a3212f11a1b43 100644 +--- a/fs/proc/array.c ++++ b/fs/proc/array.c +@@ -521,7 +521,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, + } + + sid = task_session_nr_ns(task, ns); +- ppid = task_tgid_nr_ns(task->real_parent, ns); ++ ppid = task_ppid_nr_ns(task, ns); + pgid = task_pgrp_nr_ns(task, ns); + + unlock_task_sighand(task, &flags); +-- +2.51.0 + diff --git a/queue-6.1/pstore-ram-fix-buffer-overflow-in-persistent_ram_sav.patch b/queue-6.1/pstore-ram-fix-buffer-overflow-in-persistent_ram_sav.patch new file mode 100644 index 0000000000..4b55d3c7dc --- /dev/null +++ b/queue-6.1/pstore-ram-fix-buffer-overflow-in-persistent_ram_sav.patch @@ -0,0 +1,92 @@ +From e92e88a4fd623d2f5dd186cdcaafa6a15311e7e6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 1 Feb 2026 13:22:40 +0000 +Subject: pstore/ram: fix buffer overflow in persistent_ram_save_old() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Sai Ritvik Tanksalkar + +[ Upstream commit 5669645c052f235726a85f443769b6fc02f66762 ] + +persistent_ram_save_old() can be called multiple times for the same +persistent_ram_zone (e.g., via ramoops_pstore_read -> ramoops_get_next_prz +for PSTORE_TYPE_DMESG records). + +Currently, the function only allocates prz->old_log when it is NULL, +but it unconditionally updates prz->old_log_size to the current buffer +size and then performs memcpy_fromio() using this new size. If the +buffer size has grown since the first allocation (which can happen +across different kernel boot cycles), this leads to: + +1. A heap buffer overflow (OOB write) in the memcpy_fromio() calls +2. A subsequent OOB read when ramoops_pstore_read() accesses the buffer + using the incorrect (larger) old_log_size + +The KASAN splat would look similar to: + BUG: KASAN: slab-out-of-bounds in ramoops_pstore_read+0x... + Read of size N at addr ... by task ... + +The conditions are likely extremely hard to hit: + + 0. Crash with a ramoops write of less-than-record-max-size bytes. + 1. Reboot: ramoops registers, pstore_get_records(0) reads old crash, + allocates old_log with size X + 2. Crash handler registered, timer started (if pstore_update_ms >= 0) + 3. Oops happens (non-fatal, system continues) + 4. pstore_dump() writes oops via ramoops_pstore_write() size Y (>X) + 5. pstore_new_entry = 1, pstore_timer_kick() called + 6. System continues running (not a panic oops) + 7. Timer fires after pstore_update_ms milliseconds + 8. pstore_timefunc() → schedule_work() → pstore_dowork() → pstore_get_records(1) + 9. ramoops_get_next_prz() → persistent_ram_save_old() + 10. buffer_size() returns Y, but old_log is X bytes + 11. Y > X: memcpy_fromio() overflows heap + + Requirements: + - a prior crash record exists that did not fill the record size + (almost impossible since the crash handler writes as much as it + can possibly fit into the record, capped by max record size and + the kmsg buffer almost always exceeds the max record size) + - pstore_update_ms >= 0 (disabled by default) + - Non-fatal oops (system survives) + +Free and reallocate the buffer when the new size differs from the +previously allocated size. This ensures old_log always has sufficient +space for the data being copied. + +Fixes: 201e4aca5aa1 ("pstore/ram: Should update old dmesg buffer before reading") +Signed-off-by: Sai Ritvik Tanksalkar +Link: https://patch.msgid.link/20260201132240.2948732-1-stanksal@purdue.edu +Signed-off-by: Kees Cook +Signed-off-by: Sasha Levin +--- + fs/pstore/ram_core.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c +index f479e0755a247..03d586f1ebc8c 100644 +--- a/fs/pstore/ram_core.c ++++ b/fs/pstore/ram_core.c +@@ -298,6 +298,17 @@ void persistent_ram_save_old(struct persistent_ram_zone *prz) + if (!size) + return; + ++ /* ++ * If the existing buffer is differently sized, free it so a new ++ * one is allocated. This can happen when persistent_ram_save_old() ++ * is called early in boot and later for a timer-triggered ++ * survivable crash when the crash dumps don't match in size ++ * (which would be extremely unlikely given kmsg buffers usually ++ * exceed prz buffer sizes). ++ */ ++ if (prz->old_log && prz->old_log_size != size) ++ persistent_ram_free_old(prz); ++ + if (!prz->old_log) { + persistent_ram_ecc_old(prz); + prz->old_log = kmalloc(size, GFP_KERNEL); +-- +2.51.0 + diff --git a/queue-6.1/rdma-core-add-rdma_rw_max_sge-helper-for-sq-sizing.patch b/queue-6.1/rdma-core-add-rdma_rw_max_sge-helper-for-sq-sizing.patch new file mode 100644 index 0000000000..4f4149b708 --- /dev/null +++ b/queue-6.1/rdma-core-add-rdma_rw_max_sge-helper-for-sq-sizing.patch @@ -0,0 +1,159 @@ +From 5c828067c89e12370293fe8ab94590f1da5b0781 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 19:53:59 -0500 +Subject: RDMA/core: add rdma_rw_max_sge() helper for SQ sizing + +From: Chuck Lever + +[ Upstream commit afcae7d7b8a278a6c29e064f99e5bafd4ac1fb37 ] + +svc_rdma_accept() computes sc_sq_depth as the sum of rq_depth and the +number of rdma_rw contexts (ctxts). This value is used to allocate the +Send CQ and to initialize the sc_sq_avail credit pool. + +However, when the device uses memory registration for RDMA operations, +rdma_rw_init_qp() inflates the QP's max_send_wr by a factor of three +per context to account for REG and INV work requests. The Send CQ and +credit pool remain sized for only one work request per context, +causing Send Queue exhaustion under heavy NFS WRITE workloads. + +Introduce rdma_rw_max_sge() to compute the actual number of Send Queue +entries required for a given number of rdma_rw contexts. Upper layer +protocols call this helper before creating a Queue Pair so that their +Send CQs and credit accounting match the QP's true capacity. + +Update svc_rdma_accept() to use rdma_rw_max_sge() when computing +sc_sq_depth, ensuring the credit pool reflects the work requests +that rdma_rw_init_qp() will reserve. + +Reviewed-by: Christoph Hellwig +Fixes: 00bd1439f464 ("RDMA/rw: Support threshold for registration vs scattering to local pages") +Signed-off-by: Chuck Lever +Link: https://patch.msgid.link/20260128005400.25147-5-cel@kernel.org +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/rw.c | 53 +++++++++++++++++------- + include/rdma/rw.h | 2 + + net/sunrpc/xprtrdma/svc_rdma_transport.c | 8 +++- + 3 files changed, 46 insertions(+), 17 deletions(-) + +diff --git a/drivers/infiniband/core/rw.c b/drivers/infiniband/core/rw.c +index 6354ddf2a274c..2522ff1cc462c 100644 +--- a/drivers/infiniband/core/rw.c ++++ b/drivers/infiniband/core/rw.c +@@ -651,34 +651,57 @@ unsigned int rdma_rw_mr_factor(struct ib_device *device, u32 port_num, + } + EXPORT_SYMBOL(rdma_rw_mr_factor); + ++/** ++ * rdma_rw_max_send_wr - compute max Send WRs needed for RDMA R/W contexts ++ * @dev: RDMA device ++ * @port_num: port number ++ * @max_rdma_ctxs: number of rdma_rw_ctx structures ++ * @create_flags: QP create flags (pass IB_QP_CREATE_INTEGRITY_EN if ++ * data integrity will be enabled on the QP) ++ * ++ * Returns the total number of Send Queue entries needed for ++ * @max_rdma_ctxs. The result accounts for memory registration and ++ * invalidation work requests when the device requires them. ++ * ++ * ULPs use this to size Send Queues and Send CQs before creating a ++ * Queue Pair. ++ */ ++unsigned int rdma_rw_max_send_wr(struct ib_device *dev, u32 port_num, ++ unsigned int max_rdma_ctxs, u32 create_flags) ++{ ++ unsigned int factor = 1; ++ unsigned int result; ++ ++ if (create_flags & IB_QP_CREATE_INTEGRITY_EN || ++ rdma_rw_can_use_mr(dev, port_num)) ++ factor += 2; /* reg + inv */ ++ ++ if (check_mul_overflow(factor, max_rdma_ctxs, &result)) ++ return UINT_MAX; ++ return result; ++} ++EXPORT_SYMBOL(rdma_rw_max_send_wr); ++ + void rdma_rw_init_qp(struct ib_device *dev, struct ib_qp_init_attr *attr) + { +- u32 factor; ++ unsigned int factor = 1; + + WARN_ON_ONCE(attr->port_num == 0); + + /* +- * Each context needs at least one RDMA READ or WRITE WR. +- * +- * For some hardware we might need more, eventually we should ask the +- * HCA driver for a multiplier here. +- */ +- factor = 1; +- +- /* +- * If the device needs MRs to perform RDMA READ or WRITE operations, +- * we'll need two additional MRs for the registrations and the +- * invalidation. ++ * If the device uses MRs to perform RDMA READ or WRITE operations, ++ * or if data integrity is enabled, account for registration and ++ * invalidation work requests. + */ + if (attr->create_flags & IB_QP_CREATE_INTEGRITY_EN || + rdma_rw_can_use_mr(dev, attr->port_num)) +- factor += 2; /* inv + reg */ ++ factor += 2; /* reg + inv */ + + attr->cap.max_send_wr += factor * attr->cap.max_rdma_ctxs; + + /* +- * But maybe we were just too high in the sky and the device doesn't +- * even support all we need, and we'll have to live with what we get.. ++ * The device might not support all we need, and we'll have to ++ * live with what we get. + */ + attr->cap.max_send_wr = + min_t(u32, attr->cap.max_send_wr, dev->attrs.max_qp_wr); +diff --git a/include/rdma/rw.h b/include/rdma/rw.h +index d606cac482338..9a8f4b76ce588 100644 +--- a/include/rdma/rw.h ++++ b/include/rdma/rw.h +@@ -66,6 +66,8 @@ int rdma_rw_ctx_post(struct rdma_rw_ctx *ctx, struct ib_qp *qp, u32 port_num, + + unsigned int rdma_rw_mr_factor(struct ib_device *device, u32 port_num, + unsigned int maxpages); ++unsigned int rdma_rw_max_send_wr(struct ib_device *dev, u32 port_num, ++ unsigned int max_rdma_ctxs, u32 create_flags); + void rdma_rw_init_qp(struct ib_device *dev, struct ib_qp_init_attr *attr); + int rdma_rw_init_mrs(struct ib_qp *qp, struct ib_qp_init_attr *attr); + void rdma_rw_cleanup_mrs(struct ib_qp *qp); +diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c +index c5721b75d32a7..45b0fef0b5e26 100644 +--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c ++++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c +@@ -418,7 +418,10 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + newxprt->sc_max_bc_requests = 2; + } + +- /* Arbitrary estimate of the needed number of rdma_rw contexts. ++ /* Estimate the needed number of rdma_rw contexts. The maximum ++ * Read and Write chunks have one segment each. Each request ++ * can involve one Read chunk and either a Write chunk or Reply ++ * chunk; thus a factor of three. + */ + maxpayload = min(xprt->xpt_server->sv_max_payload, + RPCSVC_MAXPAYLOAD_RDMA); +@@ -426,7 +429,8 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + rdma_rw_mr_factor(dev, newxprt->sc_port_num, + maxpayload >> PAGE_SHIFT); + +- newxprt->sc_sq_depth = rq_depth + ctxts; ++ newxprt->sc_sq_depth = rq_depth + ++ rdma_rw_max_send_wr(dev, newxprt->sc_port_num, ctxts, 0); + if (newxprt->sc_sq_depth > dev->attrs.max_qp_wr) + newxprt->sc_sq_depth = dev->attrs.max_qp_wr; + atomic_set(&newxprt->sc_sq_avail, newxprt->sc_sq_depth); +-- +2.51.0 + diff --git a/queue-6.1/rdma-core-fix-a-couple-of-obvious-typos-in-comments.patch b/queue-6.1/rdma-core-fix-a-couple-of-obvious-typos-in-comments.patch new file mode 100644 index 0000000000..588287cad6 --- /dev/null +++ b/queue-6.1/rdma-core-fix-a-couple-of-obvious-typos-in-comments.patch @@ -0,0 +1,50 @@ +From f9222bac11ee813d78648a4b60b956178375053a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Oct 2023 11:29:41 -0400 +Subject: RDMA/core: Fix a couple of obvious typos in comments + +From: Chuck Lever + +[ Upstream commit 0aa44595d61ca9e61239f321fec799518884feb3 ] + +Fix typos. + +Signed-off-by: Chuck Lever +Link: https://lore.kernel.org/r/169643338101.8035.6826446669479247727.stgit@manet.1015granger.net +Signed-off-by: Leon Romanovsky +Stable-dep-of: afcae7d7b8a2 ("RDMA/core: add rdma_rw_max_sge() helper for SQ sizing") +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/rw.c | 2 +- + include/rdma/ib_verbs.h | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/infiniband/core/rw.c b/drivers/infiniband/core/rw.c +index 8367974b7998b..6354ddf2a274c 100644 +--- a/drivers/infiniband/core/rw.c ++++ b/drivers/infiniband/core/rw.c +@@ -666,7 +666,7 @@ void rdma_rw_init_qp(struct ib_device *dev, struct ib_qp_init_attr *attr) + factor = 1; + + /* +- * If the devices needs MRs to perform RDMA READ or WRITE operations, ++ * If the device needs MRs to perform RDMA READ or WRITE operations, + * we'll need two additional MRs for the registrations and the + * invalidation. + */ +diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h +index 41eb2a7c9695d..4d00fce739672 100644 +--- a/include/rdma/ib_verbs.h ++++ b/include/rdma/ib_verbs.h +@@ -1088,7 +1088,7 @@ struct ib_qp_cap { + + /* + * Maximum number of rdma_rw_ctx structures in flight at a time. +- * ib_create_qp() will calculate the right amount of neededed WRs ++ * ib_create_qp() will calculate the right amount of needed WRs + * and MRs based on this. + */ + u32 max_rdma_ctxs; +-- +2.51.0 + diff --git a/queue-6.1/rdma-hns-fix-wq_mem_reclaim-warning.patch b/queue-6.1/rdma-hns-fix-wq_mem_reclaim-warning.patch new file mode 100644 index 0000000000..1ac8916ca2 --- /dev/null +++ b/queue-6.1/rdma-hns-fix-wq_mem_reclaim-warning.patch @@ -0,0 +1,62 @@ +From 9e175d7db29dfae5c47d1e47af996329840ada2d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 4 Jan 2026 14:40:54 +0800 +Subject: RDMA/hns: Fix WQ_MEM_RECLAIM warning + +From: Chengchang Tang + +[ Upstream commit c0a26bbd3f99b7b03f072e3409aff4e6ec8af6f6 ] + +When sunrpc is used, if a reset triggered, our wq may lead the +following trace: + +workqueue: WQ_MEM_RECLAIM xprtiod:xprt_rdma_connect_worker [rpcrdma] +is flushing !WQ_MEM_RECLAIM hns_roce_irq_workq:flush_work_handle +[hns_roce_hw_v2] +WARNING: CPU: 0 PID: 8250 at kernel/workqueue.c:2644 check_flush_dependency+0xe0/0x144 +Call trace: + check_flush_dependency+0xe0/0x144 + start_flush_work.constprop.0+0x1d0/0x2f0 + __flush_work.isra.0+0x40/0xb0 + flush_work+0x14/0x30 + hns_roce_v2_destroy_qp+0xac/0x1e0 [hns_roce_hw_v2] + ib_destroy_qp_user+0x9c/0x2b4 + rdma_destroy_qp+0x34/0xb0 + rpcrdma_ep_destroy+0x28/0xcc [rpcrdma] + rpcrdma_ep_put+0x74/0xb4 [rpcrdma] + rpcrdma_xprt_disconnect+0x1d8/0x260 [rpcrdma] + xprt_rdma_connect_worker+0xc0/0x120 [rpcrdma] + process_one_work+0x1cc/0x4d0 + worker_thread+0x154/0x414 + kthread+0x104/0x144 + ret_from_fork+0x10/0x18 + +Since QP destruction frees memory, this wq should have the WQ_MEM_RECLAIM. + +Fixes: ffd541d45726 ("RDMA/hns: Add the workqueue framework for flush cqe handler") +Signed-off-by: Chengchang Tang +Signed-off-by: Junxian Huang +Link: https://patch.msgid.link/20260104064057.1582216-2-huangjunxian6@hisilicon.com +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +index 5fdab366fb32d..c9aa4c8e05371 100644 +--- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c ++++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +@@ -6743,7 +6743,8 @@ static int hns_roce_v2_init_eq_table(struct hns_roce_dev *hr_dev) + + INIT_WORK(&hr_dev->ecc_work, fmea_ram_ecc_work); + +- hr_dev->irq_workq = alloc_ordered_workqueue("hns_roce_irq_workq", 0); ++ hr_dev->irq_workq = alloc_ordered_workqueue("hns_roce_irq_workq", ++ WQ_MEM_RECLAIM); + if (!hr_dev->irq_workq) { + dev_err(dev, "failed to create irq workqueue.\n"); + ret = -ENOMEM; +-- +2.51.0 + diff --git a/queue-6.1/rdma-hns-notify-ulp-of-remaining-soft-wcs-during-res.patch b/queue-6.1/rdma-hns-notify-ulp-of-remaining-soft-wcs-during-res.patch new file mode 100644 index 0000000000..d3ab05772d --- /dev/null +++ b/queue-6.1/rdma-hns-notify-ulp-of-remaining-soft-wcs-during-res.patch @@ -0,0 +1,70 @@ +From c86dbc9529cda816074842b45d5c618fd92a12fa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 4 Jan 2026 14:40:57 +0800 +Subject: RDMA/hns: Notify ULP of remaining soft-WCs during reset + +From: Chengchang Tang + +[ Upstream commit 0789f929900d85b80b343c5f04f8b9444e991384 ] + +During a reset, software-generated WCs cannot be reported via +interrupts. This may cause the ULP to miss some WCs. + +To avoid this, add check in the CQ arm process: if a hardware reset +has occurred and there are still unreported soft-WCs, notify the ULP +to handle the remaining WCs, thereby preventing any loss of completions. + +Fixes: 626903e9355b ("RDMA/hns: Add support for reporting wc as software mode") +Signed-off-by: Chengchang Tang +Signed-off-by: Junxian Huang +Link: https://patch.msgid.link/20260104064057.1582216-5-huangjunxian6@hisilicon.com +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 23 ++++++++++++++++++++++ + 1 file changed, 23 insertions(+) + +diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +index c9aa4c8e05371..1c180a6b1c078 100644 +--- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c ++++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +@@ -3696,6 +3696,23 @@ static void hns_roce_v2_write_cqc(struct hns_roce_dev *hr_dev, + HNS_ROCE_V2_CQ_DEFAULT_INTERVAL); + } + ++static bool left_sw_wc(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq) ++{ ++ struct hns_roce_qp *hr_qp; ++ ++ list_for_each_entry(hr_qp, &hr_cq->sq_list, sq_node) { ++ if (hr_qp->sq.head != hr_qp->sq.tail) ++ return true; ++ } ++ ++ list_for_each_entry(hr_qp, &hr_cq->rq_list, rq_node) { ++ if (hr_qp->rq.head != hr_qp->rq.tail) ++ return true; ++ } ++ ++ return false; ++} ++ + static int hns_roce_v2_req_notify_cq(struct ib_cq *ibcq, + enum ib_cq_notify_flags flags) + { +@@ -3704,6 +3721,12 @@ static int hns_roce_v2_req_notify_cq(struct ib_cq *ibcq, + struct hns_roce_v2_db cq_db = {}; + u32 notify_flag; + ++ if (hr_dev->state >= HNS_ROCE_DEVICE_STATE_RST_DOWN) { ++ if ((flags & IB_CQ_REPORT_MISSED_EVENTS) && ++ left_sw_wc(hr_dev, hr_cq)) ++ return 1; ++ return 0; ++ } + /* + * flags = 0, then notify_flag : next + * flags = 1, then notify flag : solocited +-- +2.51.0 + diff --git a/queue-6.1/rdma-rtrs-server-remove-dead-code.patch b/queue-6.1/rdma-rtrs-server-remove-dead-code.patch new file mode 100644 index 0000000000..ffc2611417 --- /dev/null +++ b/queue-6.1/rdma-rtrs-server-remove-dead-code.patch @@ -0,0 +1,57 @@ +From 9abc5fecf864a73bef6193e90bb3e80f63dcc14f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Dec 2025 10:38:19 +0800 +Subject: RDMA/rtrs: server: remove dead code + +From: Honggang LI + +[ Upstream commit a3572bdc3a028ca47f77d7166ac95b719cf77d50 ] + +As rkey had been initialized to zero, the WARN_ON_ONCE should never been +triggered. Remove it. + +Fixes: 9cb837480424 ("RDMA/rtrs: server: main functionality") +Signed-off-by: Honggang LI +Link: https://patch.msgid.link/20251224023819.138846-1-honggangli@163.com +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/ulp/rtrs/rtrs-srv.c | 8 +------- + 1 file changed, 1 insertion(+), 7 deletions(-) + +diff --git a/drivers/infiniband/ulp/rtrs/rtrs-srv.c b/drivers/infiniband/ulp/rtrs/rtrs-srv.c +index 51ec4620ca821..b69d6c5c9442b 100644 +--- a/drivers/infiniband/ulp/rtrs/rtrs-srv.c ++++ b/drivers/infiniband/ulp/rtrs/rtrs-srv.c +@@ -203,7 +203,6 @@ static int rdma_write_sg(struct rtrs_srv_op *id) + size_t sg_cnt; + int err, offset; + bool need_inval; +- u32 rkey = 0; + struct ib_reg_wr rwr; + struct ib_sge *plist; + struct ib_sge list; +@@ -235,11 +234,6 @@ static int rdma_write_sg(struct rtrs_srv_op *id) + wr->wr.num_sge = 1; + wr->remote_addr = le64_to_cpu(id->rd_msg->desc[0].addr); + wr->rkey = le32_to_cpu(id->rd_msg->desc[0].key); +- if (rkey == 0) +- rkey = wr->rkey; +- else +- /* Only one key is actually used */ +- WARN_ON_ONCE(rkey != wr->rkey); + + wr->wr.opcode = IB_WR_RDMA_WRITE; + wr->wr.wr_cqe = &io_comp_cqe; +@@ -272,7 +266,7 @@ static int rdma_write_sg(struct rtrs_srv_op *id) + inv_wr.opcode = IB_WR_SEND_WITH_INV; + inv_wr.wr_cqe = &io_comp_cqe; + inv_wr.send_flags = 0; +- inv_wr.ex.invalidate_rkey = rkey; ++ inv_wr.ex.invalidate_rkey = wr->rkey; + } + + imm_wr.wr.next = NULL; +-- +2.51.0 + diff --git a/queue-6.1/rdma-rtrs-srv-correct-the-checking-of-ib_map_mr_sg.patch b/queue-6.1/rdma-rtrs-srv-correct-the-checking-of-ib_map_mr_sg.patch new file mode 100644 index 0000000000..1b4775d7c2 --- /dev/null +++ b/queue-6.1/rdma-rtrs-srv-correct-the-checking-of-ib_map_mr_sg.patch @@ -0,0 +1,38 @@ +From ef6bcf5943ae6cb856166e9e8196b511ddbf315c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 17 Nov 2022 18:19:40 +0800 +Subject: RDMA/rtrs-srv: Correct the checking of ib_map_mr_sg + +From: Guoqing Jiang + +[ Upstream commit 102d2f70ec0999a5cde181f1ccbe8a81cba45b10 ] + +We should check with nr_sgt, also the only successful case is that +all sg elements are mapped, so make it explicitly. + +Acked-by: Jack Wang +Signed-off-by: Guoqing Jiang +Link: https://lore.kernel.org/r/20221117101945.6317-4-guoqing.jiang@linux.dev +Signed-off-by: Leon Romanovsky +Stable-dep-of: 83835f7c07b5 ("RDMA/rtrs-srv: fix SG mapping") +Signed-off-by: Sasha Levin +--- + drivers/infiniband/ulp/rtrs/rtrs-srv.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/infiniband/ulp/rtrs/rtrs-srv.c b/drivers/infiniband/ulp/rtrs/rtrs-srv.c +index c7f4dc7f2f7da..b0d5ee6d15224 100644 +--- a/drivers/infiniband/ulp/rtrs/rtrs-srv.c ++++ b/drivers/infiniband/ulp/rtrs/rtrs-srv.c +@@ -620,7 +620,7 @@ static int map_cont_bufs(struct rtrs_srv_path *srv_path) + } + nr = ib_map_mr_sg(mr, sgt->sgl, nr_sgt, + NULL, max_chunk_size); +- if (nr < 0 || nr < sgt->nents) { ++ if (nr != nr_sgt) { + err = nr < 0 ? nr : -EINVAL; + goto dereg_mr; + } +-- +2.51.0 + diff --git a/queue-6.1/rdma-rtrs-srv-fix-sg-mapping.patch b/queue-6.1/rdma-rtrs-srv-fix-sg-mapping.patch new file mode 100644 index 0000000000..9b5c475ed0 --- /dev/null +++ b/queue-6.1/rdma-rtrs-srv-fix-sg-mapping.patch @@ -0,0 +1,85 @@ +From f8e6bec0ba69f0185cb69f491446ba1ba124910f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 17:15:08 +0100 +Subject: RDMA/rtrs-srv: fix SG mapping + +From: Roman Penyaev + +[ Upstream commit 83835f7c07b523c7ca2a5ad0a511670b5810539e ] + +This fixes the following error on the server side: + + RTRS server session allocation failed: -EINVAL + +caused by the caller of the `ib_dma_map_sg()`, which does not expect +less mapped entries, than requested, which is in the order of things +and can be easily reproduced on the machine with enabled IOMMU. + +The fix is to treat any positive number of mapped sg entries as a +successful mapping and cache DMA addresses by traversing modified +SG table. + +Fixes: 9cb837480424 ("RDMA/rtrs: server: main functionality") +Signed-off-by: Roman Penyaev +Signed-off-by: Jack Wang +Signed-off-by: Grzegorz Prajsner +Link: https://patch.msgid.link/20260107161517.56357-2-haris.iqbal@ionos.com +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/ulp/rtrs/rtrs-srv.c | 25 ++++++++++++++++++++----- + 1 file changed, 20 insertions(+), 5 deletions(-) + +diff --git a/drivers/infiniband/ulp/rtrs/rtrs-srv.c b/drivers/infiniband/ulp/rtrs/rtrs-srv.c +index b0d5ee6d15224..f65a5eeec65f8 100644 +--- a/drivers/infiniband/ulp/rtrs/rtrs-srv.c ++++ b/drivers/infiniband/ulp/rtrs/rtrs-srv.c +@@ -590,7 +590,7 @@ static int map_cont_bufs(struct rtrs_srv_path *srv_path) + srv_path->mrs_num++) { + struct rtrs_srv_mr *srv_mr = &srv_path->mrs[srv_path->mrs_num]; + struct scatterlist *s; +- int nr, nr_sgt, chunks; ++ int nr, nr_sgt, chunks, ind; + + sgt = &srv_mr->sgt; + chunks = chunks_per_mr * srv_path->mrs_num; +@@ -620,7 +620,7 @@ static int map_cont_bufs(struct rtrs_srv_path *srv_path) + } + nr = ib_map_mr_sg(mr, sgt->sgl, nr_sgt, + NULL, max_chunk_size); +- if (nr != nr_sgt) { ++ if (nr < nr_sgt) { + err = nr < 0 ? nr : -EINVAL; + goto dereg_mr; + } +@@ -636,9 +636,24 @@ static int map_cont_bufs(struct rtrs_srv_path *srv_path) + goto dereg_mr; + } + } +- /* Eventually dma addr for each chunk can be cached */ +- for_each_sg(sgt->sgl, s, nr_sgt, i) +- srv_path->dma_addr[chunks + i] = sg_dma_address(s); ++ ++ /* ++ * Cache DMA addresses by traversing sg entries. If ++ * regions were merged, an inner loop is required to ++ * populate the DMA address array by traversing larger ++ * regions. ++ */ ++ ind = chunks; ++ for_each_sg(sgt->sgl, s, nr_sgt, i) { ++ unsigned int dma_len = sg_dma_len(s); ++ u64 dma_addr = sg_dma_address(s); ++ u64 dma_addr_end = dma_addr + dma_len; ++ ++ do { ++ srv_path->dma_addr[ind++] = dma_addr; ++ dma_addr += max_chunk_size; ++ } while (dma_addr < dma_addr_end); ++ } + + ib_update_fast_reg_key(mr, ib_inc_rkey(mr->rkey)); + srv_mr->mr = mr; +-- +2.51.0 + diff --git a/queue-6.1/rdma-rtrs-srv-refactor-the-handling-of-failure-case-.patch b/queue-6.1/rdma-rtrs-srv-refactor-the-handling-of-failure-case-.patch new file mode 100644 index 0000000000..c45c504968 --- /dev/null +++ b/queue-6.1/rdma-rtrs-srv-refactor-the-handling-of-failure-case-.patch @@ -0,0 +1,108 @@ +From 2851815b95becc3551bb7d7b28228a1847122266 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 17 Nov 2022 18:19:39 +0800 +Subject: RDMA/rtrs-srv: Refactor the handling of failure case in map_cont_bufs + +From: Guoqing Jiang + +[ Upstream commit 0f597ac618d04beb9de997fda59a29c9d3818fb2 ] + +Let's call unmap_cont_bufs when failure happens, and also only update +mrs_num after everything is settled which means we can remove 'mri'. + +Acked-by: Md Haris Iqbal +Signed-off-by: Guoqing Jiang +Link: https://lore.kernel.org/r/20221117101945.6317-3-guoqing.jiang@linux.dev +Signed-off-by: Leon Romanovsky +Stable-dep-of: 83835f7c07b5 ("RDMA/rtrs-srv: fix SG mapping") +Signed-off-by: Sasha Levin +--- + drivers/infiniband/ulp/rtrs/rtrs-srv.c | 47 +++++++++++--------------- + 1 file changed, 20 insertions(+), 27 deletions(-) + +diff --git a/drivers/infiniband/ulp/rtrs/rtrs-srv.c b/drivers/infiniband/ulp/rtrs/rtrs-srv.c +index b69d6c5c9442b..c7f4dc7f2f7da 100644 +--- a/drivers/infiniband/ulp/rtrs/rtrs-srv.c ++++ b/drivers/infiniband/ulp/rtrs/rtrs-srv.c +@@ -559,9 +559,11 @@ static int map_cont_bufs(struct rtrs_srv_path *srv_path) + { + struct rtrs_srv_sess *srv = srv_path->srv; + struct rtrs_path *ss = &srv_path->s; +- int i, mri, err, mrs_num; ++ int i, err, mrs_num; + unsigned int chunk_bits; + int chunks_per_mr = 1; ++ struct ib_mr *mr; ++ struct sg_table *sgt; + + /* + * Here we map queue_depth chunks to MR. Firstly we have to +@@ -584,16 +586,14 @@ static int map_cont_bufs(struct rtrs_srv_path *srv_path) + if (!srv_path->mrs) + return -ENOMEM; + +- srv_path->mrs_num = mrs_num; +- +- for (mri = 0; mri < mrs_num; mri++) { +- struct rtrs_srv_mr *srv_mr = &srv_path->mrs[mri]; +- struct sg_table *sgt = &srv_mr->sgt; ++ for (srv_path->mrs_num = 0; srv_path->mrs_num < mrs_num; ++ srv_path->mrs_num++) { ++ struct rtrs_srv_mr *srv_mr = &srv_path->mrs[srv_path->mrs_num]; + struct scatterlist *s; +- struct ib_mr *mr; + int nr, nr_sgt, chunks; + +- chunks = chunks_per_mr * mri; ++ sgt = &srv_mr->sgt; ++ chunks = chunks_per_mr * srv_path->mrs_num; + if (!always_invalidate) + chunks_per_mr = min_t(int, chunks_per_mr, + srv->queue_depth - chunks); +@@ -642,31 +642,24 @@ static int map_cont_bufs(struct rtrs_srv_path *srv_path) + + ib_update_fast_reg_key(mr, ib_inc_rkey(mr->rkey)); + srv_mr->mr = mr; +- +- continue; +-err: +- while (mri--) { +- srv_mr = &srv_path->mrs[mri]; +- sgt = &srv_mr->sgt; +- mr = srv_mr->mr; +- rtrs_iu_free(srv_mr->iu, srv_path->s.dev->ib_dev, 1); +-dereg_mr: +- ib_dereg_mr(mr); +-unmap_sg: +- ib_dma_unmap_sg(srv_path->s.dev->ib_dev, sgt->sgl, +- sgt->nents, DMA_BIDIRECTIONAL); +-free_sg: +- sg_free_table(sgt); +- } +- kfree(srv_path->mrs); +- +- return err; + } + + chunk_bits = ilog2(srv->queue_depth - 1) + 1; + srv_path->mem_bits = (MAX_IMM_PAYL_BITS - chunk_bits); + + return 0; ++ ++dereg_mr: ++ ib_dereg_mr(mr); ++unmap_sg: ++ ib_dma_unmap_sg(srv_path->s.dev->ib_dev, sgt->sgl, ++ sgt->nents, DMA_BIDIRECTIONAL); ++free_sg: ++ sg_free_table(sgt); ++err: ++ unmap_cont_bufs(srv_path); ++ ++ return err; + } + + static void rtrs_srv_hb_err_handler(struct rtrs_con *c) +-- +2.51.0 + diff --git a/queue-6.1/rdma-rxe-fix-double-free-in-rxe_srq_from_init.patch b/queue-6.1/rdma-rxe-fix-double-free-in-rxe_srq_from_init.patch new file mode 100644 index 0000000000..dea7130999 --- /dev/null +++ b/queue-6.1/rdma-rxe-fix-double-free-in-rxe_srq_from_init.patch @@ -0,0 +1,57 @@ +From 964c1eead33a4d9c5637057cb114dafa7a6d4bbe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 01:54:12 +0000 +Subject: RDMA/rxe: Fix double free in rxe_srq_from_init + +From: Jiasheng Jiang + +[ Upstream commit 0beefd0e15d962f497aad750b2d5e9c3570b66d1 ] + +In rxe_srq_from_init(), the queue pointer 'q' is assigned to +'srq->rq.queue' before copying the SRQ number to user space. +If copy_to_user() fails, the function calls rxe_queue_cleanup() +to free the queue, but leaves the now-invalid pointer in +'srq->rq.queue'. + +The caller of rxe_srq_from_init() (rxe_create_srq) eventually +calls rxe_srq_cleanup() upon receiving the error, which triggers +a second rxe_queue_cleanup() on the same memory, leading to a +double free. + +The call trace looks like this: + kmem_cache_free+0x.../0x... + rxe_queue_cleanup+0x1a/0x30 [rdma_rxe] + rxe_srq_cleanup+0x42/0x60 [rdma_rxe] + rxe_elem_release+0x31/0x70 [rdma_rxe] + rxe_create_srq+0x12b/0x1a0 [rdma_rxe] + ib_create_srq_user+0x9a/0x150 [ib_core] + +Fix this by moving 'srq->rq.queue = q' after copy_to_user. + +Fixes: aae0484e15f0 ("IB/rxe: avoid srq memory leak") +Signed-off-by: Jiasheng Jiang +Link: https://patch.msgid.link/20260112015412.29458-1-jiashengjiangcool@gmail.com +Reviewed-by: Zhu Yanjun +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/sw/rxe/rxe_srq.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/infiniband/sw/rxe/rxe_srq.c b/drivers/infiniband/sw/rxe/rxe_srq.c +index 02b39498c370d..115ff5428f6cf 100644 +--- a/drivers/infiniband/sw/rxe/rxe_srq.c ++++ b/drivers/infiniband/sw/rxe/rxe_srq.c +@@ -87,6 +87,9 @@ int rxe_srq_from_init(struct rxe_dev *rxe, struct rxe_srq *srq, + } + } + ++ srq->rq.queue = q; ++ init->attr.max_wr = srq->rq.max_wr; ++ + return 0; + } + +-- +2.51.0 + diff --git a/queue-6.1/rdma-uverbs-add-__gfp_nowarn-to-ib_uverbs_unmarshall.patch b/queue-6.1/rdma-uverbs-add-__gfp_nowarn-to-ib_uverbs_unmarshall.patch new file mode 100644 index 0000000000..9172e6714d --- /dev/null +++ b/queue-6.1/rdma-uverbs-add-__gfp_nowarn-to-ib_uverbs_unmarshall.patch @@ -0,0 +1,39 @@ +From 505119e014ea200857c3f26c5885695f7608186f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 17:49:00 +0800 +Subject: RDMA/uverbs: Add __GFP_NOWARN to ib_uverbs_unmarshall_recv() kmalloc + +From: Yi Liu + +[ Upstream commit 58b604dfc7bb753f91bc0ccd3fa705e14e6edfb4 ] + +Since wqe_size in ib_uverbs_unmarshall_recv() is user-provided and already +validated, but can still be large, add __GFP_NOWARN to suppress memory +allocation warnings for large sizes, consistent with the similar fix in +ib_uverbs_post_send(). + +Fixes: 67cdb40ca444 ("[IB] uverbs: Implement more commands") +Signed-off-by: Yi Liu +Link: https://patch.msgid.link/20260129094900.3517706-1-liuy22@mails.tsinghua.edu.cn +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/uverbs_cmd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c +index 2ed51a7df60fd..2e4265ba35b7f 100644 +--- a/drivers/infiniband/core/uverbs_cmd.c ++++ b/drivers/infiniband/core/uverbs_cmd.c +@@ -2223,7 +2223,7 @@ ib_uverbs_unmarshall_recv(struct uverbs_req_iter *iter, u32 wr_count, + if (ret) + return ERR_PTR(ret); + +- user_wr = kmalloc(wqe_size, GFP_KERNEL); ++ user_wr = kmalloc(wqe_size, GFP_KERNEL | __GFP_NOWARN); + if (!user_wr) + return ERR_PTR(-ENOMEM); + +-- +2.51.0 + diff --git a/queue-6.1/rdma-uverbs-validate-wqe_size-before-using-it-in-ib_.patch b/queue-6.1/rdma-uverbs-validate-wqe_size-before-using-it-in-ib_.patch new file mode 100644 index 0000000000..f53e3ce765 --- /dev/null +++ b/queue-6.1/rdma-uverbs-validate-wqe_size-before-using-it-in-ib_.patch @@ -0,0 +1,57 @@ +From 7c709e1495ba82be0efd90bb1903a4dc84289245 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 22:29:00 +0800 +Subject: RDMA/uverbs: Validate wqe_size before using it in ib_uverbs_post_send + +From: Yi Liu + +[ Upstream commit 1956f0a74ccf5dc9c3ef717f2985c3ed3400aab0 ] + +ib_uverbs_post_send() uses cmd.wqe_size from userspace without any +validation before passing it to kmalloc() and using the allocated +buffer as struct ib_uverbs_send_wr. + +If a user provides a small wqe_size value (e.g., 1), kmalloc() will +succeed, but subsequent accesses to user_wr->opcode, user_wr->num_sge, +and other fields will read beyond the allocated buffer, resulting in +an out-of-bounds read from kernel heap memory. This could potentially +leak sensitive kernel information to userspace. + +Additionally, providing an excessively large wqe_size can trigger a +WARNING in the memory allocation path, as reported by syzkaller. + +This is inconsistent with ib_uverbs_unmarshall_recv() which properly +validates that wqe_size >= sizeof(struct ib_uverbs_recv_wr) before +proceeding. + +Add the same validation for ib_uverbs_post_send() to ensure wqe_size +is at least sizeof(struct ib_uverbs_send_wr). + +Fixes: c3bea3d2dc53 ("RDMA/uverbs: Use the iterator for ib_uverbs_unmarshall_recv()") +Signed-off-by: Yi Liu +Link: https://patch.msgid.link/20260122142900.2356276-2-liuy22@mails.tsinghua.edu.cn +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/uverbs_cmd.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c +index 33e2fe0facd52..2ed51a7df60fd 100644 +--- a/drivers/infiniband/core/uverbs_cmd.c ++++ b/drivers/infiniband/core/uverbs_cmd.c +@@ -2030,7 +2030,10 @@ static int ib_uverbs_post_send(struct uverbs_attr_bundle *attrs) + if (ret) + return ret; + +- user_wr = kmalloc(cmd.wqe_size, GFP_KERNEL); ++ if (cmd.wqe_size < sizeof(struct ib_uverbs_send_wr)) ++ return -EINVAL; ++ ++ user_wr = kmalloc(cmd.wqe_size, GFP_KERNEL | __GFP_NOWARN); + if (!user_wr) + return -ENOMEM; + +-- +2.51.0 + diff --git a/queue-6.1/regulator-core-move-supply-check-earlier-in-set_mach.patch b/queue-6.1/regulator-core-move-supply-check-earlier-in-set_mach.patch new file mode 100644 index 0000000000..379fcd4c3c --- /dev/null +++ b/queue-6.1/regulator-core-move-supply-check-earlier-in-set_mach.patch @@ -0,0 +1,121 @@ +From 933b4c4740fbd2fb9a2b8215651a0f5bde1ca693 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 08:38:39 +0000 +Subject: regulator: core: move supply check earlier in + set_machine_constraints() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: André Draszik + +[ Upstream commit 86a8eeb0e913f4b6a55dabba5122098d4e805e55 ] + +Since commit 98e48cd9283d ("regulator: core: resolve supply for +boot-on/always-on regulators"), set_machine_constraints() can return +-EPROBE_DEFER very late, after it has done a lot of work and +configuration of the regulator. + +This means that configuration will happen multiple times for no +benefit in that case. Furthermore, this can lead to timing-dependent +voltage glitches as mentioned e.g. in commit 8a866d527ac0 ("regulator: +core: Resolve supply name earlier to prevent double-init"). + +We can know that it's going to fail very early, in particular before +going through the complete regulator configuration by moving some code +around a little. + +Do so to avoid re-configuring the regulator multiple times, also +avoiding the voltage glitches if we can. + +Fixes: 98e48cd9283d ("regulator: core: resolve supply for boot-on/always-on regulators") +Signed-off-by: André Draszik +Link: https://patch.msgid.link/20260109-regulators-defer-v2-3-1a25dc968e60@linaro.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/regulator/core.c | 55 ++++++++++++++++++++++------------------ + 1 file changed, 30 insertions(+), 25 deletions(-) + +diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c +index 7b1d60628a001..454e19d87e35a 100644 +--- a/drivers/regulator/core.c ++++ b/drivers/regulator/core.c +@@ -1473,6 +1473,33 @@ static int set_machine_constraints(struct regulator_dev *rdev) + int ret = 0; + const struct regulator_ops *ops = rdev->desc->ops; + ++ /* ++ * If there is no mechanism for controlling the regulator then ++ * flag it as always_on so we don't end up duplicating checks ++ * for this so much. Note that we could control the state of ++ * a supply to control the output on a regulator that has no ++ * direct control. ++ */ ++ if (!rdev->ena_pin && !ops->enable) { ++ if (rdev->supply_name && !rdev->supply) ++ return -EPROBE_DEFER; ++ ++ if (rdev->supply) ++ rdev->constraints->always_on = ++ rdev->supply->rdev->constraints->always_on; ++ else ++ rdev->constraints->always_on = true; ++ } ++ ++ /* ++ * If we want to enable this regulator, make sure that we know the ++ * supplying regulator. ++ */ ++ if (rdev->constraints->always_on || rdev->constraints->boot_on) { ++ if (rdev->supply_name && !rdev->supply) ++ return -EPROBE_DEFER; ++ } ++ + ret = machine_constraints_voltage(rdev, rdev->constraints); + if (ret != 0) + return ret; +@@ -1638,37 +1665,15 @@ static int set_machine_constraints(struct regulator_dev *rdev) + } + } + +- /* +- * If there is no mechanism for controlling the regulator then +- * flag it as always_on so we don't end up duplicating checks +- * for this so much. Note that we could control the state of +- * a supply to control the output on a regulator that has no +- * direct control. +- */ +- if (!rdev->ena_pin && !ops->enable) { +- if (rdev->supply_name && !rdev->supply) +- return -EPROBE_DEFER; +- +- if (rdev->supply) +- rdev->constraints->always_on = +- rdev->supply->rdev->constraints->always_on; +- else +- rdev->constraints->always_on = true; +- } +- + /* If the constraints say the regulator should be on at this point + * and we have control then make sure it is enabled. + */ + if (rdev->constraints->always_on || rdev->constraints->boot_on) { + bool supply_enabled = false; + +- /* If we want to enable this regulator, make sure that we know +- * the supplying regulator. +- */ +- if (rdev->supply_name && !rdev->supply) +- return -EPROBE_DEFER; +- +- /* If supplying regulator has already been enabled, ++ /* We have ensured a potential supply has been resolved above. ++ * ++ * If supplying regulator has already been enabled, + * it's not intended to have use_count increment + * when rdev is only boot-on. + */ +-- +2.51.0 + diff --git a/queue-6.1/revert-hwmon-ibmpex-fix-use-after-free-in-high-low-s.patch b/queue-6.1/revert-hwmon-ibmpex-fix-use-after-free-in-high-low-s.patch new file mode 100644 index 0000000000..5349fe1c9a --- /dev/null +++ b/queue-6.1/revert-hwmon-ibmpex-fix-use-after-free-in-high-low-s.patch @@ -0,0 +1,89 @@ +From 3b992585fa73433d5437ae42fa6dceb6c5bd29be Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Feb 2026 08:12:25 -0800 +Subject: Revert "hwmon: (ibmpex) fix use-after-free in high/low store" + +From: Guenter Roeck + +[ Upstream commit 8bde3e395a85017f12af2b0ba5c3684f5af9c006 ] + +This reverts commit 6946c726c3f4c36f0f049e6f97e88c510b15f65d. + +Jean Delvare points out that the patch does not completely +fix the reported problem, that it in fact introduces a +(new) race condition, and that it may actually not be needed in +the first place. + +Various AI reviews agree. Specific and relevant AI feedback: + +" +This reordering sets the driver data to NULL before removing the sensor +attributes in the loop below. + +ibmpex_show_sensor() retrieves this driver data via dev_get_drvdata() but +does not check if it is NULL before dereferencing it to access +data->sensors[]. + +If a userspace process reads a sensor file (like temp1_input) while this +delete function is running, could it race with the dev_set_drvdata(..., +NULL) call here and crash in ibmpex_show_sensor()? + +Would it be safer to keep the original order where device_remove_file() is +called before clearing the driver data? device_remove_file() should wait +for any active sysfs callbacks to complete, which might already prevent the +use-after-free this patch intends to fix. +" + +Revert the offending patch. If it can be shown that the originally reported +alleged race condition does indeed exist, it can always be re-introduced +with a complete fix. + +Reported-by: Jean Delvare +Closes: https://lore.kernel.org/linux-hwmon/20260121095342.73e723cb@endymion/ +Cc: Jean Delvare +Cc: Junrui Luo +Fixes: 6946c726c3f4 ("hwmon: (ibmpex) fix use-after-free in high/low store") +Reviewed-by: Jean Delvare +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + drivers/hwmon/ibmpex.c | 9 ++------- + 1 file changed, 2 insertions(+), 7 deletions(-) + +diff --git a/drivers/hwmon/ibmpex.c b/drivers/hwmon/ibmpex.c +index 9c7e2fa395dbf..1837cccd993c8 100644 +--- a/drivers/hwmon/ibmpex.c ++++ b/drivers/hwmon/ibmpex.c +@@ -282,9 +282,6 @@ static ssize_t ibmpex_high_low_store(struct device *dev, + { + struct ibmpex_bmc_data *data = dev_get_drvdata(dev); + +- if (!data) +- return -ENODEV; +- + ibmpex_reset_high_low_data(data); + + return count; +@@ -517,9 +514,6 @@ static void ibmpex_bmc_delete(struct ibmpex_bmc_data *data) + { + int i, j; + +- hwmon_device_unregister(data->hwmon_dev); +- dev_set_drvdata(data->bmc_device, NULL); +- + device_remove_file(data->bmc_device, + &sensor_dev_attr_reset_high_low.dev_attr); + device_remove_file(data->bmc_device, &sensor_dev_attr_name.dev_attr); +@@ -533,7 +527,8 @@ static void ibmpex_bmc_delete(struct ibmpex_bmc_data *data) + } + + list_del(&data->list); +- ++ dev_set_drvdata(data->bmc_device, NULL); ++ hwmon_device_unregister(data->hwmon_dev); + ipmi_destroy_user(data->user); + kfree(data->sensors); + kfree(data); +-- +2.51.0 + diff --git a/queue-6.1/revert-mmc-rtsx_pci_sdmmc-increase-power-on-settling.patch b/queue-6.1/revert-mmc-rtsx_pci_sdmmc-increase-power-on-settling.patch new file mode 100644 index 0000000000..717c811b58 --- /dev/null +++ b/queue-6.1/revert-mmc-rtsx_pci_sdmmc-increase-power-on-settling.patch @@ -0,0 +1,39 @@ +From b1dcfc99b777bed57c27466f08ea3b4041997a4d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 15:49:31 +0100 +Subject: Revert "mmc: rtsx_pci_sdmmc: increase power-on settling delay to 5ms" + +From: Greg Kroah-Hartman + +[ Upstream commit ff112f1ecd10b72004eac05bae395e1c65f0c63c ] + +This reverts commit aced969e9bf3701dc75cfca57c78c031b7875b9d. + +It was determined that this was not the correct "fix", so should be +reverted. + +Fixes: aced969e9bf3 ("mmc: rtsx_pci_sdmmc: increase power-on settling delay to 5ms") +Cc: Matthew Schwartz +Cc: Ulf Hansson +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/mmc/host/rtsx_pci_sdmmc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c +index 02da9016245bd..d063d50d69feb 100644 +--- a/drivers/mmc/host/rtsx_pci_sdmmc.c ++++ b/drivers/mmc/host/rtsx_pci_sdmmc.c +@@ -938,7 +938,7 @@ static int sd_power_on(struct realtek_pci_sdmmc *host, unsigned char power_mode) + if (err < 0) + return err; + +- mdelay(5); ++ mdelay(1); + + err = rtsx_pci_write_register(pcr, CARD_OE, SD_OUTPUT_EN, SD_OUTPUT_EN); + if (err < 0) +-- +2.51.0 + diff --git a/queue-6.1/s390-cio-fix-device-lifecycle-handling-in-css_alloc_.patch b/queue-6.1/s390-cio-fix-device-lifecycle-handling-in-css_alloc_.patch new file mode 100644 index 0000000000..af1b89b42d --- /dev/null +++ b/queue-6.1/s390-cio-fix-device-lifecycle-handling-in-css_alloc_.patch @@ -0,0 +1,49 @@ +From adb46d455b6ca5bde34582cd350559e3f6d7f890 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 21:47:59 +0100 +Subject: s390/cio: Fix device lifecycle handling in css_alloc_subchannel() + +From: Salah Triki + +[ Upstream commit f65c75b0b9b5a390bc3beadcde0a6fbc3ad118f7 ] + +`css_alloc_subchannel()` calls `device_initialize()` before setting up +the DMA masks. If `dma_set_coherent_mask()` or `dma_set_mask()` fails, +the error path frees the subchannel structure directly, bypassing +the device model reference counting. + +Once `device_initialize()` has been called, the embedded struct device +must be released via `put_device()`, allowing the release callback to +free the container structure. + +Fix the error path by dropping the initial device reference with +`put_device()` instead of calling `kfree()` directly. + +This ensures correct device lifetime handling and avoids potential +use-after-free or double-free issues. + +Fixes: e5dcf0025d7af ("s390/css: move subchannel lock allocation") +Signed-off-by: Salah Triki +Reviewed-by: Vineeth Vijayan +Signed-off-by: Heiko Carstens +Signed-off-by: Sasha Levin +--- + drivers/s390/cio/css.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c +index 98a14c1f3d672..85c1734ebfe88 100644 +--- a/drivers/s390/cio/css.c ++++ b/drivers/s390/cio/css.c +@@ -247,7 +247,7 @@ struct subchannel *css_alloc_subchannel(struct subchannel_id schid, + err_lock: + kfree(sch->lock); + err: +- kfree(sch); ++ put_device(&sch->dev); + return ERR_PTR(ret); + } + +-- +2.51.0 + diff --git a/queue-6.1/sched-rt-skip-currently-executing-cpu-in-rto_next_cp.patch b/queue-6.1/sched-rt-skip-currently-executing-cpu-in-rto_next_cp.patch new file mode 100644 index 0000000000..a7d67c96d0 --- /dev/null +++ b/queue-6.1/sched-rt-skip-currently-executing-cpu-in-rto_next_cp.patch @@ -0,0 +1,87 @@ +From 55d26c9d20866afc5b9d9205f80a72299f1b8943 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 01:25:33 +0000 +Subject: sched/rt: Skip currently executing CPU in rto_next_cpu() + +From: Chen Jinghuang + +[ Upstream commit 94894c9c477e53bcea052e075c53f89df3d2a33e ] + +CPU0 becomes overloaded when hosting a CPU-bound RT task, a non-CPU-bound +RT task, and a CFS task stuck in kernel space. When other CPUs switch from +RT to non-RT tasks, RT load balancing (LB) is triggered; with +HAVE_RT_PUSH_IPI enabled, they send IPIs to CPU0 to drive the execution +of rto_push_irq_work_func. During push_rt_task on CPU0, +if next_task->prio < rq->donor->prio, resched_curr() sets NEED_RESCHED +and after the push operation completes, CPU0 calls rto_next_cpu(). +Since only CPU0 is overloaded in this scenario, rto_next_cpu() should +ideally return -1 (no further IPI needed). + +However, multiple CPUs invoking tell_cpu_to_push() during LB increments +rd->rto_loop_next. Even when rd->rto_cpu is set to -1, the mismatch between +rd->rto_loop and rd->rto_loop_next forces rto_next_cpu() to restart its +search from -1. With CPU0 remaining overloaded (satisfying rt_nr_migratory +&& rt_nr_total > 1), it gets reselected, causing CPU0 to queue irq_work to +itself and send self-IPIs repeatedly. As long as CPU0 stays overloaded and +other CPUs run pull_rt_tasks(), it falls into an infinite self-IPI loop, +which triggers a CPU hardlockup due to continuous self-interrupts. + +The trigging scenario is as follows: + + cpu0 cpu1 cpu2 + pull_rt_task + tell_cpu_to_push + <------------irq_work_queue_on +rto_push_irq_work_func + push_rt_task + resched_curr(rq) pull_rt_task + rto_next_cpu tell_cpu_to_push + <-------------------------- atomic_inc(rto_loop_next) +rd->rto_loop != next + rto_next_cpu + irq_work_queue_on +rto_push_irq_work_func + +Fix redundant self-IPI by filtering the initiating CPU in rto_next_cpu(). +This solution has been verified to effectively eliminate spurious self-IPIs +and prevent CPU hardlockup scenarios. + +Fixes: 4bdced5c9a29 ("sched/rt: Simplify the IPI based RT balancing logic") +Suggested-by: Steven Rostedt (Google) +Suggested-by: K Prateek Nayak +Signed-off-by: Chen Jinghuang +Signed-off-by: Peter Zijlstra (Intel) +Reviewed-by: Steven Rostedt (Google) +Reviewed-by: Valentin Schneider +Link: https://patch.msgid.link/20260122012533.673768-1-chenjinghuang2@huawei.com +Signed-off-by: Sasha Levin +--- + kernel/sched/rt.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c +index 3a2335bc1d58b..99e5d37b3f6eb 100644 +--- a/kernel/sched/rt.c ++++ b/kernel/sched/rt.c +@@ -2230,6 +2230,7 @@ static void push_rt_tasks(struct rq *rq) + */ + static int rto_next_cpu(struct root_domain *rd) + { ++ int this_cpu = smp_processor_id(); + int next; + int cpu; + +@@ -2253,6 +2254,10 @@ static int rto_next_cpu(struct root_domain *rd) + + rd->rto_cpu = cpu; + ++ /* Do not send IPI to self */ ++ if (cpu == this_cpu) ++ continue; ++ + if (cpu < nr_cpu_ids) + return cpu; + +-- +2.51.0 + diff --git a/queue-6.1/scsi-csiostor-fix-dereference-of-null-pointer-rn.patch b/queue-6.1/scsi-csiostor-fix-dereference-of-null-pointer-rn.patch new file mode 100644 index 0000000000..99dfc56a81 --- /dev/null +++ b/queue-6.1/scsi-csiostor-fix-dereference-of-null-pointer-rn.patch @@ -0,0 +1,46 @@ +From 4c77c916a3462e269bb50243d8876ed2b9cc2cc4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 15:53:32 +0000 +Subject: scsi: csiostor: Fix dereference of null pointer rn + +From: Colin Ian King + +[ Upstream commit 1982257570b84dc33753d536dd969fd357a014e9 ] + +The error exit path when rn is NULL ends up deferencing the null pointer rn +via the use of the macro CSIO_INC_STATS. Fix this by adding a new error +return path label after the use of the macro to avoid the deference. + +Fixes: a3667aaed569 ("[SCSI] csiostor: Chelsio FCoE offload driver") +Signed-off-by: Colin Ian King +Link: https://patch.msgid.link/20260129155332.196338-1-colin.i.king@gmail.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/csiostor/csio_scsi.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/scsi/csiostor/csio_scsi.c b/drivers/scsi/csiostor/csio_scsi.c +index 05e1a63e00c3a..ed40ae6b9800c 100644 +--- a/drivers/scsi/csiostor/csio_scsi.c ++++ b/drivers/scsi/csiostor/csio_scsi.c +@@ -2074,7 +2074,7 @@ csio_eh_lun_reset_handler(struct scsi_cmnd *cmnd) + struct csio_scsi_level_data sld; + + if (!rn) +- goto fail; ++ goto fail_ret; + + csio_dbg(hw, "Request to reset LUN:%llu (ssni:0x%x tgtid:%d)\n", + cmnd->device->lun, rn->flowid, rn->scsi_id); +@@ -2220,6 +2220,7 @@ csio_eh_lun_reset_handler(struct scsi_cmnd *cmnd) + csio_put_scsi_ioreq_lock(hw, scsim, ioreq); + fail: + CSIO_INC_STATS(rn, n_lun_rst_fail); ++fail_ret: + return FAILED; + } + +-- +2.51.0 + diff --git a/queue-6.1/scsi-efct-use-irqf_oneshot-and-default-primary-handl.patch b/queue-6.1/scsi-efct-use-irqf_oneshot-and-default-primary-handl.patch new file mode 100644 index 0000000000..d7e14cdee5 --- /dev/null +++ b/queue-6.1/scsi-efct-use-irqf_oneshot-and-default-primary-handl.patch @@ -0,0 +1,59 @@ +From 6f36eba9b694c9a1e0b72d418ce1224c4829755e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:55:27 +0100 +Subject: scsi: efct: Use IRQF_ONESHOT and default primary handler + +From: Sebastian Andrzej Siewior + +[ Upstream commit bd81f07e9a27c341cd7e72be95eb0b7cf3910926 ] + +There is no added value in efct_intr_msix() compared to +irq_default_primary_handler(). + +Using a threaded interrupt without a dedicated primary handler mandates +the IRQF_ONESHOT flag to mask the interrupt source while the threaded +handler is active. Otherwise the interrupt can fire again before the +threaded handler had a chance to run. + +Use the default primary interrupt handler by specifying NULL and set +IRQF_ONESHOT so the interrupt source is masked until the secondary +handler is done. + +Fixes: 4df84e8466242 ("scsi: elx: efct: Driver initialization routines") +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260128095540.863589-8-bigeasy@linutronix.de +Signed-off-by: Sasha Levin +--- + drivers/scsi/elx/efct/efct_driver.c | 8 +------- + 1 file changed, 1 insertion(+), 7 deletions(-) + +diff --git a/drivers/scsi/elx/efct/efct_driver.c b/drivers/scsi/elx/efct/efct_driver.c +index 49fd2cfed70c7..37aba56e07217 100644 +--- a/drivers/scsi/elx/efct/efct_driver.c ++++ b/drivers/scsi/elx/efct/efct_driver.c +@@ -415,12 +415,6 @@ efct_intr_thread(int irq, void *handle) + return IRQ_HANDLED; + } + +-static irqreturn_t +-efct_intr_msix(int irq, void *handle) +-{ +- return IRQ_WAKE_THREAD; +-} +- + static int + efct_setup_msix(struct efct *efct, u32 num_intrs) + { +@@ -450,7 +444,7 @@ efct_setup_msix(struct efct *efct, u32 num_intrs) + intr_ctx->index = i; + + rc = request_threaded_irq(pci_irq_vector(efct->pci, i), +- efct_intr_msix, efct_intr_thread, 0, ++ NULL, efct_intr_thread, IRQF_ONESHOT, + EFCT_DRIVER_NAME, intr_ctx); + if (rc) { + dev_err(&efct->pci->dev, +-- +2.51.0 + diff --git a/queue-6.1/scsi-smartpqi-fix-memory-leak-in-pqi_report_phys_lun.patch b/queue-6.1/scsi-smartpqi-fix-memory-leak-in-pqi_report_phys_lun.patch new file mode 100644 index 0000000000..2692f7cf59 --- /dev/null +++ b/queue-6.1/scsi-smartpqi-fix-memory-leak-in-pqi_report_phys_lun.patch @@ -0,0 +1,72 @@ +From f5e6f1ae6aa2029abdd0f277bcf5cf1668057322 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Jan 2026 09:36:41 +0000 +Subject: scsi: smartpqi: Fix memory leak in pqi_report_phys_luns() + +From: Zilin Guan + +[ Upstream commit 41b37312bd9722af77ec7817ccf22d7a4880c289 ] + +pqi_report_phys_luns() fails to release the rpl_list buffer when +encountering an unsupported data format or when the allocation for +rpl_16byte_wwid_list fails. These early returns bypass the cleanup logic, +leading to memory leaks. + +Consolidate the error handling by adding an out_free_rpl_list label and use +goto statements to ensure rpl_list is consistently freed on failure. + +Compile tested only. Issue found using a prototype static analysis tool and +code review. + +Fixes: 28ca6d876c5a ("scsi: smartpqi: Add extended report physical LUNs") +Signed-off-by: Zilin Guan +Tested-by: Don Brace +Acked-by: Don Brace +Link: https://patch.msgid.link/20260131093641.1008117-1-zilin@seu.edu.cn +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/smartpqi/smartpqi_init.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c +index 5c0f23dd808c4..5dd116554ef62 100644 +--- a/drivers/scsi/smartpqi/smartpqi_init.c ++++ b/drivers/scsi/smartpqi/smartpqi_init.c +@@ -1213,7 +1213,8 @@ static inline int pqi_report_phys_luns(struct pqi_ctrl_info *ctrl_info, void **b + dev_err(&ctrl_info->pci_dev->dev, + "RPL returned unsupported data format %u\n", + rpl_response_format); +- return -EINVAL; ++ rc = -EINVAL; ++ goto out_free_rpl_list; + } else { + dev_warn(&ctrl_info->pci_dev->dev, + "RPL returned extended format 2 instead of 4\n"); +@@ -1225,8 +1226,10 @@ static inline int pqi_report_phys_luns(struct pqi_ctrl_info *ctrl_info, void **b + + rpl_16byte_wwid_list = kmalloc(struct_size(rpl_16byte_wwid_list, lun_entries, + num_physicals), GFP_KERNEL); +- if (!rpl_16byte_wwid_list) +- return -ENOMEM; ++ if (!rpl_16byte_wwid_list) { ++ rc = -ENOMEM; ++ goto out_free_rpl_list; ++ } + + put_unaligned_be32(num_physicals * sizeof(struct report_phys_lun_16byte_wwid), + &rpl_16byte_wwid_list->header.list_length); +@@ -1247,6 +1250,10 @@ static inline int pqi_report_phys_luns(struct pqi_ctrl_info *ctrl_info, void **b + *buffer = rpl_16byte_wwid_list; + + return 0; ++ ++out_free_rpl_list: ++ kfree(rpl_list); ++ return rc; + } + + static inline int pqi_report_logical_luns(struct pqi_ctrl_info *ctrl_info, void **buffer) +-- +2.51.0 + diff --git a/queue-6.1/scsi-smartpqi-replace-one-element-arrays-with-flexib.patch b/queue-6.1/scsi-smartpqi-replace-one-element-arrays-with-flexib.patch new file mode 100644 index 0000000000..0b9a5103d4 --- /dev/null +++ b/queue-6.1/scsi-smartpqi-replace-one-element-arrays-with-flexib.patch @@ -0,0 +1,79 @@ +From c9040d35deb6c455682b9b3ece803b483c47a7ed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jun 2023 14:27:20 -0600 +Subject: scsi: smartpqi: Replace one-element arrays with flexible-array + members + +From: Gustavo A. R. Silva + +[ Upstream commit 6f0a92fd7db1507b203111ee53632eeeba2daca5 ] + +One-element arrays are deprecated, and we are replacing them with flexible +array members instead. So, replace one-element arrays with flexible-array +members in a couple of structures, and refactor the rest of the code, +accordingly. + +This helps with the ongoing efforts to tighten the FORTIFY_SOURCE routines +on memcpy(). + +This results in no differences in binary output. + +Link: https://github.com/KSPP/linux/issues/79 +Link: https://github.com/KSPP/linux/issues/204 +Signed-off-by: Gustavo A. R. Silva +Link: https://lore.kernel.org/r/ZJNdKDkuRbFZpASS@work +Reviewed-by: Kees Cook +Signed-off-by: Martin K. Petersen +Stable-dep-of: 41b37312bd97 ("scsi: smartpqi: Fix memory leak in pqi_report_phys_luns()") +Signed-off-by: Sasha Levin +--- + drivers/scsi/smartpqi/smartpqi.h | 4 ++-- + drivers/scsi/smartpqi/smartpqi_init.c | 5 ++--- + 2 files changed, 4 insertions(+), 5 deletions(-) + +diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h +index 5b40e7ad5e02d..7a5c51cf58005 100644 +--- a/drivers/scsi/smartpqi/smartpqi.h ++++ b/drivers/scsi/smartpqi/smartpqi.h +@@ -982,12 +982,12 @@ struct report_phys_lun_16byte_wwid { + + struct report_phys_lun_8byte_wwid_list { + struct report_lun_header header; +- struct report_phys_lun_8byte_wwid lun_entries[1]; ++ struct report_phys_lun_8byte_wwid lun_entries[]; + }; + + struct report_phys_lun_16byte_wwid_list { + struct report_lun_header header; +- struct report_phys_lun_16byte_wwid lun_entries[1]; ++ struct report_phys_lun_16byte_wwid lun_entries[]; + }; + + struct raid_map_disk_data { +diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c +index a9f504959dd56..5c0f23dd808c4 100644 +--- a/drivers/scsi/smartpqi/smartpqi_init.c ++++ b/drivers/scsi/smartpqi/smartpqi_init.c +@@ -1194,7 +1194,6 @@ static inline int pqi_report_phys_luns(struct pqi_ctrl_info *ctrl_info, void **b + unsigned int i; + u8 rpl_response_format; + u32 num_physicals; +- size_t rpl_16byte_wwid_list_length; + void *rpl_list; + struct report_lun_header *rpl_header; + struct report_phys_lun_8byte_wwid_list *rpl_8byte_wwid_list; +@@ -1223,9 +1222,9 @@ static inline int pqi_report_phys_luns(struct pqi_ctrl_info *ctrl_info, void **b + + rpl_8byte_wwid_list = rpl_list; + num_physicals = get_unaligned_be32(&rpl_8byte_wwid_list->header.list_length) / sizeof(rpl_8byte_wwid_list->lun_entries[0]); +- rpl_16byte_wwid_list_length = sizeof(struct report_lun_header) + (num_physicals * sizeof(struct report_phys_lun_16byte_wwid)); + +- rpl_16byte_wwid_list = kmalloc(rpl_16byte_wwid_list_length, GFP_KERNEL); ++ rpl_16byte_wwid_list = kmalloc(struct_size(rpl_16byte_wwid_list, lun_entries, ++ num_physicals), GFP_KERNEL); + if (!rpl_16byte_wwid_list) + return -ENOMEM; + +-- +2.51.0 + diff --git a/queue-6.1/selftests-bpf-veristat-fix-printing-order-in-output_.patch b/queue-6.1/selftests-bpf-veristat-fix-printing-order-in-output_.patch new file mode 100644 index 0000000000..76bafb83e7 --- /dev/null +++ b/queue-6.1/selftests-bpf-veristat-fix-printing-order-in-output_.patch @@ -0,0 +1,46 @@ +From 3ed05fdb2e0d2c295ca84fece18c91e37107decd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 31 Dec 2025 14:10:50 -0800 +Subject: selftests/bpf: veristat: fix printing order in output_stats() + +From: Puranjay Mohan + +[ Upstream commit c286e7e9d1f1f3d90ad11c37e896f582b02d19c4 ] + +The order of the variables in the printf() doesn't match the text and +therefore veristat prints something like this: + +Done. Processed 24 files, 0 programs. Skipped 62 files, 0 programs. + +When it should print: + +Done. Processed 24 files, 62 programs. Skipped 0 files, 0 programs. + +Fix the order of variables in the printf() call. + +Fixes: 518fee8bfaf2 ("selftests/bpf: make veristat skip non-BPF and failing-to-open BPF objects") +Tested-by: Eduard Zingerman +Signed-off-by: Puranjay Mohan +Link: https://lore.kernel.org/r/20251231221052.759396-1-puranjay@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/bpf/veristat.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/testing/selftests/bpf/veristat.c b/tools/testing/selftests/bpf/veristat.c +index b0d83a28e3486..726a968ae8aa0 100644 +--- a/tools/testing/selftests/bpf/veristat.c ++++ b/tools/testing/selftests/bpf/veristat.c +@@ -812,7 +812,7 @@ static void output_stats(const struct verif_stats *s, enum resfmt fmt, bool last + if (last && fmt == RESFMT_TABLE) { + output_header_underlines(); + printf("Done. Processed %d files, %d programs. Skipped %d files, %d programs.\n", +- env.files_processed, env.files_skipped, env.progs_processed, env.progs_skipped); ++ env.files_processed, env.progs_processed, env.files_skipped, env.progs_skipped); + } + } + +-- +2.51.0 + diff --git a/queue-6.1/serial-caif-fix-use-after-free-in-caif_serial-ldisc_.patch b/queue-6.1/serial-caif-fix-use-after-free-in-caif_serial-ldisc_.patch new file mode 100644 index 0000000000..627091aabc --- /dev/null +++ b/queue-6.1/serial-caif-fix-use-after-free-in-caif_serial-ldisc_.patch @@ -0,0 +1,152 @@ +From e81813c7fe81998dd6656b637135905e5278324b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 15:44:44 +0800 +Subject: serial: caif: fix use-after-free in caif_serial ldisc_close() + +From: Jiayuan Chen + +[ Upstream commit 308e7e4d0a846359685f40aade023aee7b27284c ] + +There is a use-after-free bug in caif_serial where handle_tx() may +access ser->tty after the tty has been freed. + +The race condition occurs between ldisc_close() and packet transmission: + + CPU 0 (close) CPU 1 (xmit) + ------------- ------------ + ldisc_close() + tty_kref_put(ser->tty) + [tty may be freed here] + <-- race window --> + caif_xmit() + handle_tx() + tty = ser->tty // dangling ptr + tty->ops->write() // UAF! + schedule_work() + ser_release() + unregister_netdevice() + +The root cause is that tty_kref_put() is called in ldisc_close() while +the network device is still active and can receive packets. + +Since ser and tty have a 1:1 binding relationship with consistent +lifecycles (ser is allocated in ldisc_open and freed in ser_release +via unregister_netdevice, and each ser binds exactly one tty), we can +safely defer the tty reference release to ser_release() where the +network device is unregistered. + +Fix this by moving tty_kref_put() from ldisc_close() to ser_release(), +after unregister_netdevice(). This ensures the tty reference is held +as long as the network device exists, preventing the UAF. + +Note: We save ser->tty before unregister_netdevice() because ser is +embedded in netdev's private data and will be freed along with netdev +(needs_free_netdev = true). + +How to reproduce: Add mdelay(500) at the beginning of ldisc_close() +to widen the race window, then run the reproducer program [1]. + +Note: There is a separate deadloop issue in handle_tx() when using +PORT_UNKNOWN serial ports (e.g., /dev/ttyS3 in QEMU without proper +serial backend). This deadloop exists even without this patch, +and is likely caused by inconsistency between uart_write_room() and +uart_write() in serial core. It has been addressed in a separate +patch [2]. + +KASAN report: + +================================================================== +BUG: KASAN: slab-use-after-free in handle_tx+0x5d1/0x620 +Read of size 1 at addr ffff8881131e1490 by task caif_uaf_trigge/9929 + +Call Trace: + + dump_stack_lvl+0x10e/0x1f0 + print_report+0xd0/0x630 + kasan_report+0xe4/0x120 + handle_tx+0x5d1/0x620 + dev_hard_start_xmit+0x9d/0x6c0 + __dev_queue_xmit+0x6e2/0x4410 + packet_xmit+0x243/0x360 + packet_sendmsg+0x26cf/0x5500 + __sys_sendto+0x4a3/0x520 + __x64_sys_sendto+0xe0/0x1c0 + do_syscall_64+0xc9/0xf80 + entry_SYSCALL_64_after_hwframe+0x77/0x7f +RIP: 0033:0x7f615df2c0d7 + +Allocated by task 9930: + +Freed by task 64: + +Last potentially related work creation: + +The buggy address belongs to the object at ffff8881131e1000 + which belongs to the cache kmalloc-cg-2k of size 2048 +The buggy address is located 1168 bytes inside of + freed 2048-byte region [ffff8881131e1000, ffff8881131e1800) + +The buggy address belongs to the physical page: +page_owner tracks the page as allocated +page last free pid 9778 tgid 9778 stack trace: + +Memory state around the buggy address: + ffff8881131e1380: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb + ffff8881131e1400: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb +>ffff8881131e1480: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb + ^ + ffff8881131e1500: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb + ffff8881131e1580: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb +================================================================== +[1]: https://gist.github.com/mrpre/f683f244544f7b11e7fa87df9e6c2eeb +[2]: https://lore.kernel.org/linux-serial/20260204074327.226165-1-jiayuan.chen@linux.dev/T/#u + +Reported-by: syzbot+827272712bd6d12c79a4@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/000000000000a4a7550611e234f5@google.com/T/ +Fixes: 56e0ef527b18 ("drivers/net: caif: fix wrong rtnl_is_locked() usage") +Reviewed-by: Greg Kroah-Hartman +Signed-off-by: Jiayuan Chen +Reviewed-by: Jijie Shao +Link: https://patch.msgid.link/20260206074450.154267-1-jiayuan.chen@linux.dev +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/caif/caif_serial.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c +index 688075859ae47..737faeaf847fe 100644 +--- a/drivers/net/caif/caif_serial.c ++++ b/drivers/net/caif/caif_serial.c +@@ -298,6 +298,7 @@ static void ser_release(struct work_struct *work) + { + struct list_head list; + struct ser_device *ser, *tmp; ++ struct tty_struct *tty; + + spin_lock(&ser_lock); + list_replace_init(&ser_release_list, &list); +@@ -306,9 +307,11 @@ static void ser_release(struct work_struct *work) + if (!list_empty(&list)) { + rtnl_lock(); + list_for_each_entry_safe(ser, tmp, &list, node) { ++ tty = ser->tty; + dev_close(ser->dev); + unregister_netdevice(ser->dev); + debugfs_deinit(ser); ++ tty_kref_put(tty); + } + rtnl_unlock(); + } +@@ -369,8 +372,6 @@ static void ldisc_close(struct tty_struct *tty) + { + struct ser_device *ser = tty->disc_data; + +- tty_kref_put(ser->tty); +- + spin_lock(&ser_lock); + list_move(&ser->node, &ser_release_list); + spin_unlock(&ser_lock); +-- +2.51.0 + diff --git a/queue-6.1/serial-imx-change-serial_imx_console-to-bool.patch b/queue-6.1/serial-imx-change-serial_imx_console-to-bool.patch new file mode 100644 index 0000000000..9b6af482fa --- /dev/null +++ b/queue-6.1/serial-imx-change-serial_imx_console-to-bool.patch @@ -0,0 +1,50 @@ +From bec4e87fd1eb7809b4c808753d78b9a50b68aaa0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 10 Jan 2026 15:26:40 -0800 +Subject: serial: imx: change SERIAL_IMX_CONSOLE to bool + +From: Randy Dunlap + +[ Upstream commit 79527d86ba91c2d9354832d19fd12b3baa66bd10 ] + +SERIAL_IMX_CONSOLE is a build option for the imx driver (SERIAL_IMX). +It does not build a separate console driver file, so it can't be built +as a module since it isn't built at all. + +Change the Kconfig symbol from tristate to bool and update the help +text accordingly. + +Fixes: 0db4f9b91c86 ("tty: serial: imx: enable imx serial console port as module") +Signed-off-by: Randy Dunlap +Link: https://patch.msgid.link/20260110232643.3533351-2-rdunlap@infradead.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/Kconfig | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig +index 71951b543d4c2..3c45956a1d454 100644 +--- a/drivers/tty/serial/Kconfig ++++ b/drivers/tty/serial/Kconfig +@@ -486,14 +486,14 @@ config SERIAL_IMX + can enable its onboard serial port by enabling this option. + + config SERIAL_IMX_CONSOLE +- tristate "Console on IMX serial port" ++ bool "Console on IMX serial port" + depends on SERIAL_IMX + select SERIAL_CORE_CONSOLE + help + If you have enabled the serial port on the Freescale IMX +- CPU you can make it the console by answering Y/M to this option. ++ CPU you can make it the console by answering Y to this option. + +- Even if you say Y/M here, the currently visible virtual console ++ Even if you say Y here, the currently visible virtual console + (/dev/tty0) will still be used as the system console by default, but + you can alter that using a kernel command line option such as + "console=ttymxc0". (Try "man bootparam" or see the documentation of +-- +2.51.0 + diff --git a/queue-6.1/serial-sh_sci-improve-dma-support-prompt.patch b/queue-6.1/serial-sh_sci-improve-dma-support-prompt.patch new file mode 100644 index 0000000000..ef45ea53e2 --- /dev/null +++ b/queue-6.1/serial-sh_sci-improve-dma-support-prompt.patch @@ -0,0 +1,39 @@ +From 891ae1b076a10d41cc0a0d2df441d64f03fa1c4b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 10 Jan 2026 15:26:43 -0800 +Subject: serial: SH_SCI: improve "DMA support" prompt + +From: Randy Dunlap + +[ Upstream commit 93bb95a11238d66a4c9aa6eabf9774b073a5895c ] + +Having a prompt of "DMA support" suddenly appear during a +"make oldconfig" can be confusing. Add a little helpful text to +the prompt message. + +Fixes: 73a19e4c0301 ("serial: sh-sci: Add DMA support.") +Signed-off-by: Randy Dunlap +Reviewed-by: Geert Uytterhoeven +Link: https://patch.msgid.link/20260110232643.3533351-5-rdunlap@infradead.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig +index 3c45956a1d454..32b4db13fa963 100644 +--- a/drivers/tty/serial/Kconfig ++++ b/drivers/tty/serial/Kconfig +@@ -668,7 +668,7 @@ config SERIAL_SH_SCI_EARLYCON + default ARCH_RENESAS + + config SERIAL_SH_SCI_DMA +- bool "DMA support" if EXPERT ++ bool "Support for DMA on SuperH SCI(F)" if EXPERT + depends on SERIAL_SH_SCI && DMA_ENGINE + default ARCH_RENESAS + +-- +2.51.0 + diff --git a/queue-6.1/series b/queue-6.1/series index 0b63edc9fd..6437e62eff 100644 --- a/queue-6.1/series +++ b/queue-6.1/series @@ -1,2 +1,201 @@ rdma-siw-fix-potential-null-pointer-dereference-in-header-processing.patch rdma-umad-reject-negative-data_len-in-ib_umad_write.patch +auxdisplay-arm-charlcd-fix-release_mem_region-size.patch +hfsplus-return-error-when-node-already-exists-in-hfs.patch +audit-avoid-missing-prototype-warnings.patch +audit-move-the-compat_xxx_class-extern-declarations-.patch +i3c-move-device-name-assignment-after-i3c_bus_init.patch +fs-add-linux-init_task.h-for-init_fs.patch +i3c-master-update-hot-join-flag-only-on-success.patch +gfs2-add-metapath_dibh-helper.patch +gfs2-fix-use-after-free-in-iomap-inline-data-write-p.patch +tpm-tpm_i2c_infineon-fix-locality-leak-on-get_burstc.patch +tpm-st33zp24-fix-missing-cleanup-on-get_burstcount-e.patch +btrfs-qgroup-return-correct-error-when-deleting-qgro.patch +btrfs-fix-block_group_tree-dirty_list-corruption.patch +smb-client-fix-potential-uaf-and-double-free-in-smb2.patch +xen-virtio-optimize-the-setup-of-xen-grant-dma-devic.patch +xen-virtio-handle-pci-devices-which-host-controller-.patch +xen-virtio-don-t-use-grant-dma-ops-when-running-as-d.patch +acpica-fix-null-pointer-dereference-in-acpi_ev_addre.patch +io_uring-sync-validate-passed-in-offset.patch +md-raid10-fix-any_working-flag-handling-in-raid10_sy.patch +cpufreq-scmi-correct-scmi-explanation.patch +iomap-fix-submission-side-handling-of-completion-sid.patch +ublk-validate-sqe128-flag-before-accessing-the-cmd.patch +pm-wakeup-handle-empty-list-in-wakeup_sources_walk_s.patch +pm-sleep-wakeirq-harden-dev_pm_clear_wake_irq-agains.patch +s390-cio-fix-device-lifecycle-handling-in-css_alloc_.patch +crypto-qat-fix-warning-on-adf_pfvf_pf_proto.c.patch +selftests-bpf-veristat-fix-printing-order-in-output_.patch +libbpf-fix-oob-read-in-btf_dump_get_bitfield_value.patch +arm-vdso-patch-out-__vdso_clock_getres-if-unavailabl.patch +crypto-cavium-fix-dma_free_coherent-size.patch +crypto-octeontx-fix-dma_free_coherent-size.patch +crypto-hisilicon-zip-support-deflate-algorithm.patch +crypto-hisilicon-zip-remove-zlib-and-gzip.patch +crypto-hisilicon-zip-adjust-the-way-to-obtain-the-re.patch +crypto-hisilicon-sec-fix-spelling-mistake-ckeck-chec.patch +crypto-hisilicon-sec2-fix-for-sec-spec-check.patch +crypto-hisilicon-sec2-support-skcipher-aead-fallback.patch +hrtimer-fix-trace-oddity.patch +bpf-sockmap-fix-incorrect-copied_seq-calculation.patch +crypto-hisilicon-trng-modifying-the-order-of-header-.patch +crypto-hisilicon-trng-support-tfms-sharing-the-devic.patch +bpf-fix-bpf_xdp_store_bytes-proto-for-read-only-arg.patch +scsi-efct-use-irqf_oneshot-and-default-primary-handl.patch +edac-altera-remove-irqf_oneshot.patch +mfd-wm8350-core-use-irqf_oneshot.patch +sched-rt-skip-currently-executing-cpu-in-rto_next_cp.patch +pstore-ram-fix-buffer-overflow-in-persistent_ram_sav.patch +soc-qcom-smem-handle-enomem-error-during-probe.patch +edac-i5000-fix-snprintf-size-calculation-in-calculat.patch +edac-i5400-fix-snprintf-limit-calculation-in-calcula.patch +arm64-dts-tqma8mpql-mba8mpxl-fix-hdmi-cec-pad-contro.patch +clk-qcom-return-correct-error-code-in-qcom_cc_probe_.patch +arm64-dts-qcom-sdm630-fix-gpu_speed_bin-size.patch +arm64-dts-qcom-sdm845-oneplus-don-t-mark-ts-supply-b.patch +arm64-dts-qcom-sdm845-oneplus-don-t-keep-panel-regul.patch +arm64-dts-qcom-sdm845-oneplus-mark-l14a-regulator-as.patch +arm-dts-allwinner-sun5i-a13-utoo-p66-delete-power-gp.patch +powerpc-uaccess-move-barrier_nospec-out-of-allow_rea.patch +soc-qcom-cmd-db-use-devm_memremap-to-fix-memory-leak.patch +soc-mediatek-mtk-svs-add-explicit-include-for-cpu.h.patch +soc-mediatek-svs-fix-memory-leak-in-svs_enable_debug.patch +powerpc-eeh-fix-recursive-pci_lock_rescan_remove-loc.patch +arm-dts-lpc32xx-set-motor-pwm-pwm-cells-property-val.patch +arm-dts-lpc32xx-add-clocks-property-to-motor-control.patch +arm64-dts-amlogic-axg-assign-the-mmc-signal-clocks.patch +arm64-dts-amlogic-gx-assign-the-mmc-signal-clocks.patch +arm64-dts-amlogic-g12-assign-the-mmc-b-and-c-signal-.patch +arm64-dts-amlogic-g12-assign-the-mmc-a-signal-clock.patch +arm64-dts-qcom-sdm845-db845c-drop-cs-from-spio0.patch +arm64-dts-qcom-sdm845-db845c-specify-power-for-wifi-.patch +smack-smack-doi-must-be-0.patch +smack-smack-doi-accept-previously-used-values.patch +asoc-nau8821-consistently-clear-interrupts-before-un.patch +asoc-nau8821-avoid-unnecessary-blocking-in-irq-handl.patch +asoc-nau8821-fixup-nau8821_enable_jack_detect.patch +drm-amdgpu-use-explicit-vcn-instance-0-in-sr-iov-ini.patch +regulator-core-move-supply-check-earlier-in-set_mach.patch +hid-playstation-add-missing-check-for-input_ff_creat.patch +drm-msm-dpu-fix-cmd-panels-on-dpu-1.x-3.x.patch +media-ccs-accommodate-c-phy-into-the-calculation.patch +platform-chrome-cros_typec_switch-don-t-touch-struct.patch +media-uvcvideo-fix-allocation-for-small-frame-sizes.patch +platform-chrome-cros_ec_lightbar-fix-response-size-i.patch +spi-tools-add-include-folder-to-.gitignore.patch +revert-hwmon-ibmpex-fix-use-after-free-in-high-low-s.patch +pci-mediatek-fix-irq-domain-leak-when-msi-allocation.patch +documentation-pci-endpoint-fix-ntb-vntb-copy-paste-e.patch +pci-pm-avoid-redundant-delays-on-d3hot-d3cold.patch +pci-do-not-attempt-to-set-exttag-for-vfs.patch +pci-portdrv-fix-potential-resource-leak.patch +net-mctp-i2c-fix-duplicate-reception-of-old-data.patch +mctp-i2c-initialise-event-handler-read-bytes.patch +wifi-cfg80211-stop-nan-and-p2p-in-cfg80211_leave.patch +netfilter-nf_conncount-make-nf_conncount_gc_list-to-.patch +netfilter-nf_conncount-increase-the-connection-clean.patch +netfilter-nft_compat-add-more-restrictions-on-netlin.patch +netfilter-nf_conncount-fix-tracking-of-connections-f.patch +module-add-helper-function-for-reading-module_buildi.patch +kallsyms-ftrace-set-module-buildid-in-ftrace_mod_add.patch +pci-mark-3ware-9650sa-root-port-extended-tags-as-bro.patch +iommu-vt-d-flush-cache-for-pasid-table-before-using-.patch +dm-use-bio_clone_blkg_association.patch +nfsd-never-defer-requests-during-idmap-lookup.patch +fat-avoid-parent-link-count-underflow-in-rmdir.patch +tcp-tcp_tx_timestamp-must-look-at-the-rtx-queue.patch +wifi-ath10k-sdio-add-missing-lock-protection-in-ath1.patch +pci-initialize-rcb-from-pci_configure_device.patch +ipc-don-t-audit-capability-check-in-ipc_permissions.patch +ucount-check-for-cap_sys_resource-using-ns_capable_n.patch +octeontx2-af-fix-pf-driver-crash-with-kexec-kernel-b.patch +bonding-only-set-speed-duplex-to-unknown-if-getting-.patch +timers-replace-in_irq-with-in_hardirq.patch +nfc-hci-shdlc-stop-timers-and-work-before-freeing-co.patch +netfilter-nft_set_hash-fix-get-operation-on-big-endi.patch +netfilter-nft_counter-fix-reset-of-counters-on-32bit.patch +netfilter-nft_set_rbtree-check-for-partial-overlaps-.patch +pci-add-acs-quirk-for-pericom-pi7c9x2g404-switches-1.patch +net-hns3-fix-double-free-issue-for-tx-spare-buffer.patch +procfs-fix-missing-rcu-protection-when-reading-real_.patch +smb-client-correct-value-for-smbd_max_fragmented_rec.patch +net-atm-fix-crash-due-to-unvalidated-vcc-pointer-in-.patch +net-add-skb_dstref_steal-and-skb_dstref_restore.patch +net-switch-to-skb_dstref_steal-skb_dstref_restore-fo.patch +xfrm-fix-ip_rt_bug-race-in-icmp_route_lookup-reverse.patch +serial-caif-fix-use-after-free-in-caif_serial-ldisc_.patch +ionic-rate-limit-unknown-xcvr-type-messages.patch +octeontx2-pf-unregister-devlink-on-probe-failure.patch +rdma-rtrs-server-remove-dead-code.patch +ib-cache-update-gid-cache-on-client-reregister-event.patch +rdma-hns-fix-wq_mem_reclaim-warning.patch +rdma-hns-notify-ulp-of-remaining-soft-wcs-during-res.patch +power-supply-ab8500-fix-use-after-free-in-power_supp.patch +power-supply-act8945a-fix-use-after-free-in-power_su.patch +power-supply-bq256xx-fix-use-after-free-in-power_sup.patch +power-supply-bq25980-fix-use-after-free-in-power_sup.patch +power-supply-cpcap-battery-fix-use-after-free-in-pow.patch +power-supply-goldfish-fix-use-after-free-in-power_su.patch +power-supply-rt9455-fix-use-after-free-in-power_supp.patch +power-supply-sbs-battery-fix-use-after-free-in-power.patch +power-reset-nvmem-reboot-mode-respect-cell-size-for-.patch +power-supply-bq27xxx-fix-wrong-errno-when-bus-ops-ar.patch +power-supply-wm97xx-fix-null-pointer-dereference-in-.patch +rdma-rtrs-srv-refactor-the-handling-of-failure-case-.patch +rdma-rtrs-srv-correct-the-checking-of-ib_map_mr_sg.patch +rdma-rtrs-srv-fix-sg-mapping.patch +rdma-rxe-fix-double-free-in-rxe_srq_from_init.patch +mtd-rawnand-cadence-fix-return-type-of-cdma-send-and.patch +crypto-ccp-add-an-s4-restore-flow.patch +rdma-uverbs-validate-wqe_size-before-using-it-in-ib_.patch +rdma-core-fix-a-couple-of-obvious-typos-in-comments.patch +svcrdma-remove-queue-shortening-warnings.patch +svcrdma-clean-up-comment-in-svc_rdma_accept.patch +svcrdma-increase-the-per-transport-rw_ctx-count.patch +svcrdma-reduce-the-number-of-rdma_rw-contexts-per-qp.patch +rdma-core-add-rdma_rw_max_sge-helper-for-sq-sizing.patch +cxl-fix-premature-commit_end-increment-on-decoder-co.patch +mtd-parsers-ofpart-fix-of-node-refcount-leak-in-pars.patch +rdma-uverbs-add-__gfp_nowarn-to-ib_uverbs_unmarshall.patch +pnfs-fix-a-missing-wake-up-while-waiting-on-nfs_layo.patch +scsi-smartpqi-replace-one-element-arrays-with-flexib.patch +scsi-smartpqi-fix-memory-leak-in-pqi_report_phys_lun.patch +scsi-csiostor-fix-dereference-of-null-pointer-rn.patch +nvdimm-virtio_pmem-serialize-flush-requests.patch +fs-nfs-fix-readdir-slow-start-regression.patch +tracing-properly-process-error-handling-in-event_his.patch +tracing-remove-duplicate-enable_event_str-and-disabl.patch +fbdev-of_display_timing-fix-device-node-reference-le.patch +fbdev-au1200fb-fix-a-memory-leak-in-au1200fb_drv_pro.patch +clk-qcom-rcg2-compute-2d-using-duty-fraction-directl.patch +clk-meson-gxbb-limit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch +clk-qcom-gcc-msm8953-remove-always_on-flag-from-cpp_.patch +clk-move-clk_-save-restore-_context-to-common_clk-se.patch +clk-qcom-dispcc-sdm845-enable-parents-for-pixel-cloc.patch +clk-qcom-gfx3d-add-parent-to-parent-request-map.patch +clk-mediatek-fix-error-handling-in-runtime-pm-setup.patch +dmaengine-mediatek-uart-apdma-fix-above-4g-addressin.patch +dma-dma-axi-dmac-fix-sw-cyclic-transfers.patch +staging-greybus-lights-avoid-null-deref.patch +serial-imx-change-serial_imx_console-to-bool.patch +serial-sh_sci-improve-dma-support-prompt.patch +mmc-rtsx_pci_sdmmc-increase-power-on-settling-delay-.patch +coresight-etm3x-fix-cpulocked-warning-on-cpuhp.patch +revert-mmc-rtsx_pci_sdmmc-increase-power-on-settling.patch +mfd-arizona-fix-regulator-resource-leak-on-wm5102_cl.patch +drivers-iio-mpu3050-use-dev_err_probe-for-regulator-.patch +usb-bdc-fix-sleep-during-atomic.patch +pinctrl-equilibrium-fix-device-node-reference-leak-i.patch +ovl-fix-uninit-value-in-ovl_fill_real.patch +iio-sca3000-fix-a-resource-leak-in-sca3000_probe.patch +pinctrl-qcom-sm8250-lpass-lpi-fix-i2s2_data_groups-d.patch +pinctrl-single-fix-refcount-leak-in-pcs_add_gpio_fun.patch +leds-qcom-lpg-check-the-return-value-of-regmap_bulk_.patch +backlight-qcom-wled-support-ovp-values-for-pmi8994.patch +io_uring-cancel-abstract-out-request-match-helper.patch +io_uring-cancel-fix-sequence-matching-for-ioring_asy.patch +io_uring-cancel-add-ioring_async_cancel_userdata.patch +io_uring-cancel-support-opcode-based-lookup-and-canc.patch +io_uring-cancel-de-unionize-file-and-user_data-in-st.patch diff --git a/queue-6.1/smack-smack-doi-accept-previously-used-values.patch b/queue-6.1/smack-smack-doi-accept-previously-used-values.patch new file mode 100644 index 0000000000..2387d4e3a1 --- /dev/null +++ b/queue-6.1/smack-smack-doi-accept-previously-used-values.patch @@ -0,0 +1,233 @@ +From 1654401034953786f59946eaeabf5e908266c9db Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Sep 2025 15:31:53 +0300 +Subject: smack: /smack/doi: accept previously used values +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Konstantin Andreev + +[ Upstream commit 33d589ed60ae433b483761987b85e0d24e54584e ] + +Writing to /smack/doi a value that has ever been +written there in the past disables networking for +non-ambient labels. +E.g. + + # cat /smack/doi + 3 + # netlabelctl -p cipso list + Configured CIPSO mappings (1) + DOI value : 3 + mapping type : PASS_THROUGH + # netlabelctl -p map list + Configured NetLabel domain mappings (3) + domain: "_" (IPv4) + protocol: UNLABELED + domain: DEFAULT (IPv4) + protocol: CIPSO, DOI = 3 + domain: DEFAULT (IPv6) + protocol: UNLABELED + + # cat /smack/ambient + _ + # cat /proc/$$/attr/smack/current + _ + # ping -c1 10.1.95.12 + 64 bytes from 10.1.95.12: icmp_seq=1 ttl=64 time=0.964 ms + # echo foo >/proc/$$/attr/smack/current + # ping -c1 10.1.95.12 + 64 bytes from 10.1.95.12: icmp_seq=1 ttl=64 time=0.956 ms + unknown option 86 + + # echo 4 >/smack/doi + # echo 3 >/smack/doi +!> [ 214.050395] smk_cipso_doi:691 cipso add rc = -17 + # echo 3 >/smack/doi +!> [ 249.402261] smk_cipso_doi:678 remove rc = -2 +!> [ 249.402261] smk_cipso_doi:691 cipso add rc = -17 + + # ping -c1 10.1.95.12 +!!> ping: 10.1.95.12: Address family for hostname not supported + + # echo _ >/proc/$$/attr/smack/current + # ping -c1 10.1.95.12 + 64 bytes from 10.1.95.12: icmp_seq=1 ttl=64 time=0.617 ms + +This happens because Smack keeps decommissioned DOIs, +fails to re-add them, and consequently refuses to add +the “default” domain map: + + # netlabelctl -p cipso list + Configured CIPSO mappings (2) + DOI value : 3 + mapping type : PASS_THROUGH + DOI value : 4 + mapping type : PASS_THROUGH + # netlabelctl -p map list + Configured NetLabel domain mappings (2) + domain: "_" (IPv4) + protocol: UNLABELED +!> (no ipv4 map for default domain here) + domain: DEFAULT (IPv6) + protocol: UNLABELED + +Fix by clearing decommissioned DOI definitions and +serializing concurrent DOI updates with a new lock. + +Also: +- allow /smack/doi to live unconfigured, since + adding a map (netlbl_cfg_cipsov4_map_add) may fail. + CIPSO_V4_DOI_UNKNOWN(0) indicates the unconfigured DOI +- add new DOI before removing the old default map, + so the old map remains if the add fails + +(2008-02-04, Casey Schaufler) +Fixes: e114e473771c ("Smack: Simplified Mandatory Access Control Kernel") + +Signed-off-by: Konstantin Andreev +Signed-off-by: Casey Schaufler +Signed-off-by: Sasha Levin +--- + security/smack/smackfs.c | 71 +++++++++++++++++++++++++--------------- + 1 file changed, 45 insertions(+), 26 deletions(-) + +diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c +index 136d89efdc0c2..6a4d175527bd6 100644 +--- a/security/smack/smackfs.c ++++ b/security/smack/smackfs.c +@@ -68,6 +68,7 @@ enum smk_inos { + static DEFINE_MUTEX(smack_cipso_lock); + static DEFINE_MUTEX(smack_ambient_lock); + static DEFINE_MUTEX(smk_net4addr_lock); ++static DEFINE_MUTEX(smk_cipso_doi_lock); + #if IS_ENABLED(CONFIG_IPV6) + static DEFINE_MUTEX(smk_net6addr_lock); + #endif /* CONFIG_IPV6 */ +@@ -139,7 +140,7 @@ struct smack_parsed_rule { + int smk_access2; + }; + +-static u32 smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; ++static u32 smk_cipso_doi_value = CIPSO_V4_DOI_UNKNOWN; + + /* + * Values for parsing cipso rules +@@ -679,43 +680,60 @@ static const struct file_operations smk_load_ops = { + }; + + /** +- * smk_cipso_doi - initialize the CIPSO domain ++ * smk_cipso_doi - set netlabel maps ++ * @ndoi: new value for our CIPSO DOI ++ * @gfp_flags: kmalloc allocation context + */ +-static void smk_cipso_doi(void) ++static int ++smk_cipso_doi(u32 ndoi, gfp_t gfp_flags) + { +- int rc; ++ int rc = 0; + struct cipso_v4_doi *doip; + struct netlbl_audit nai; + +- smk_netlabel_audit_set(&nai); ++ mutex_lock(&smk_cipso_doi_lock); + +- rc = netlbl_cfg_map_del(NULL, PF_INET, NULL, NULL, &nai); +- if (rc != 0) +- printk(KERN_WARNING "%s:%d remove rc = %d\n", +- __func__, __LINE__, rc); ++ if (smk_cipso_doi_value == ndoi) ++ goto clr_doi_lock; ++ ++ smk_netlabel_audit_set(&nai); + +- doip = kmalloc(sizeof(struct cipso_v4_doi), GFP_KERNEL | __GFP_NOFAIL); ++ doip = kmalloc(sizeof(struct cipso_v4_doi), gfp_flags); ++ if (!doip) { ++ rc = -ENOMEM; ++ goto clr_doi_lock; ++ } + doip->map.std = NULL; +- doip->doi = smk_cipso_doi_value; ++ doip->doi = ndoi; + doip->type = CIPSO_V4_MAP_PASS; + doip->tags[0] = CIPSO_V4_TAG_RBITMAP; + for (rc = 1; rc < CIPSO_V4_TAG_MAXCNT; rc++) + doip->tags[rc] = CIPSO_V4_TAG_INVALID; + + rc = netlbl_cfg_cipsov4_add(doip, &nai); +- if (rc != 0) { +- printk(KERN_WARNING "%s:%d cipso add rc = %d\n", +- __func__, __LINE__, rc); ++ if (rc) { + kfree(doip); +- return; ++ goto clr_doi_lock; + } +- rc = netlbl_cfg_cipsov4_map_add(doip->doi, NULL, NULL, NULL, &nai); +- if (rc != 0) { +- printk(KERN_WARNING "%s:%d map add rc = %d\n", +- __func__, __LINE__, rc); +- netlbl_cfg_cipsov4_del(doip->doi, &nai); +- return; ++ ++ if (smk_cipso_doi_value != CIPSO_V4_DOI_UNKNOWN) { ++ rc = netlbl_cfg_map_del(NULL, PF_INET, NULL, NULL, &nai); ++ if (rc && rc != -ENOENT) ++ goto clr_ndoi_def; ++ ++ netlbl_cfg_cipsov4_del(smk_cipso_doi_value, &nai); + } ++ ++ rc = netlbl_cfg_cipsov4_map_add(ndoi, NULL, NULL, NULL, &nai); ++ if (rc) { ++ smk_cipso_doi_value = CIPSO_V4_DOI_UNKNOWN; // no default map ++clr_ndoi_def: netlbl_cfg_cipsov4_del(ndoi, &nai); ++ } else ++ smk_cipso_doi_value = ndoi; ++ ++clr_doi_lock: ++ mutex_unlock(&smk_cipso_doi_lock); ++ return rc; + } + + /** +@@ -1617,11 +1635,8 @@ static ssize_t smk_write_doi(struct file *file, const char __user *buf, + + if (u == CIPSO_V4_DOI_UNKNOWN || u > U32_MAX) + return -EINVAL; +- smk_cipso_doi_value = u; +- +- smk_cipso_doi(); + +- return count; ++ return smk_cipso_doi(u, GFP_KERNEL) ? : count; + } + + static const struct file_operations smk_doi_ops = { +@@ -2998,6 +3013,7 @@ static int __init init_smk_fs(void) + { + int err; + int rc; ++ struct netlbl_audit nai; + + if (smack_enabled == 0) + return 0; +@@ -3016,7 +3032,10 @@ static int __init init_smk_fs(void) + } + } + +- smk_cipso_doi(); ++ smk_netlabel_audit_set(&nai); ++ (void) netlbl_cfg_map_del(NULL, PF_INET, NULL, NULL, &nai); ++ (void) smk_cipso_doi(SMACK_CIPSO_DOI_DEFAULT, ++ GFP_KERNEL | __GFP_NOFAIL); + smk_unlbl_ambient(NULL); + + rc = smack_populate_secattr(&smack_known_floor); +-- +2.51.0 + diff --git a/queue-6.1/smack-smack-doi-must-be-0.patch b/queue-6.1/smack-smack-doi-must-be-0.patch new file mode 100644 index 0000000000..d1273a20fe --- /dev/null +++ b/queue-6.1/smack-smack-doi-must-be-0.patch @@ -0,0 +1,71 @@ +From 7a32bc728a3b8429d9b73ae5f4c8f637c4e33222 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Sep 2025 15:16:02 +0300 +Subject: smack: /smack/doi must be > 0 + +From: Konstantin Andreev + +[ Upstream commit 19c013e1551bf51e1493da1270841d60e4fd3f15 ] + +/smack/doi allows writing and keeping negative doi values. +Correct values are 0 < doi <= (max 32-bit positive integer) + +(2008-02-04, Casey Schaufler) +Fixes: e114e473771c ("Smack: Simplified Mandatory Access Control Kernel") + +Signed-off-by: Konstantin Andreev +Signed-off-by: Casey Schaufler +Signed-off-by: Sasha Levin +--- + security/smack/smackfs.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c +index 9dca3672d82b4..136d89efdc0c2 100644 +--- a/security/smack/smackfs.c ++++ b/security/smack/smackfs.c +@@ -139,7 +139,7 @@ struct smack_parsed_rule { + int smk_access2; + }; + +-static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; ++static u32 smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; + + /* + * Values for parsing cipso rules +@@ -1580,7 +1580,7 @@ static ssize_t smk_read_doi(struct file *filp, char __user *buf, + if (*ppos != 0) + return 0; + +- sprintf(temp, "%d", smk_cipso_doi_value); ++ sprintf(temp, "%lu", (unsigned long)smk_cipso_doi_value); + rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp)); + + return rc; +@@ -1599,7 +1599,7 @@ static ssize_t smk_write_doi(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) + { + char temp[80]; +- int i; ++ unsigned long u; + + if (!smack_privileged(CAP_MAC_ADMIN)) + return -EPERM; +@@ -1612,10 +1612,12 @@ static ssize_t smk_write_doi(struct file *file, const char __user *buf, + + temp[count] = '\0'; + +- if (sscanf(temp, "%d", &i) != 1) ++ if (kstrtoul(temp, 10, &u)) + return -EINVAL; + +- smk_cipso_doi_value = i; ++ if (u == CIPSO_V4_DOI_UNKNOWN || u > U32_MAX) ++ return -EINVAL; ++ smk_cipso_doi_value = u; + + smk_cipso_doi(); + +-- +2.51.0 + diff --git a/queue-6.1/smb-client-correct-value-for-smbd_max_fragmented_rec.patch b/queue-6.1/smb-client-correct-value-for-smbd_max_fragmented_rec.patch new file mode 100644 index 0000000000..07eb14c1c4 --- /dev/null +++ b/queue-6.1/smb-client-correct-value-for-smbd_max_fragmented_rec.patch @@ -0,0 +1,78 @@ +From be7ab679bb7cc8bbc6b27d1e942f75e57c2054c3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 17:14:14 +0100 +Subject: smb: client: correct value for smbd_max_fragmented_recv_size + +From: Stefan Metzmacher + +[ Upstream commit 4a93d1ee2d0206970b6eb13fbffe07938cd95948 ] + +When we download a file without rdma offload or get +a large directly enumeration from the server, +the server might want to send up to smbd_max_fragmented_recv_size +bytes, but if it is too large all our recv buffers +might already be moved to the recv_io.reassembly.list +and we're no longer able to grant recv credits. + +The maximum fragmented upper-layer payload receive size supported + +Assume max_payload_per_credit is +smbd_max_receive_size - 24 = 1340 + +The maximum number would be +smbd_receive_credit_max * max_payload_per_credit + + 1340 * 255 = 341700 (0x536C4) + +The minimum value from the spec is 131072 (0x20000) + +For now we use the logic we used in ksmbd before: + (1364 * 255) / 2 = 173910 (0x2A756) + +Fixes: 03bee01d6215 ("CIFS: SMBD: Add SMB Direct protocol initial values and constants") +Cc: Steve French +Cc: Tom Talpey +Cc: Long Li +Cc: Namjae Jeon +Cc: linux-cifs@vger.kernel.org +Cc: samba-technical@lists.samba.org +Signed-off-by: Stefan Metzmacher +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/client/smbdirect.c | 19 +++++++++++++++++-- + 1 file changed, 17 insertions(+), 2 deletions(-) + +diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c +index b648bb30401d5..9b16840952c09 100644 +--- a/fs/smb/client/smbdirect.c ++++ b/fs/smb/client/smbdirect.c +@@ -86,8 +86,23 @@ int smbd_send_credit_target = 255; + /* The maximum single message size can be sent to remote peer */ + int smbd_max_send_size = 1364; + +-/* The maximum fragmented upper-layer payload receive size supported */ +-int smbd_max_fragmented_recv_size = 1024 * 1024; ++/* ++ * The maximum fragmented upper-layer payload receive size supported ++ * ++ * Assume max_payload_per_credit is ++ * smbd_max_receive_size - 24 = 1340 ++ * ++ * The maximum number would be ++ * smbd_receive_credit_max * max_payload_per_credit ++ * ++ * 1340 * 255 = 341700 (0x536C4) ++ * ++ * The minimum value from the spec is 131072 (0x20000) ++ * ++ * For now we use the logic we used in ksmbd before: ++ * (1364 * 255) / 2 = 173910 (0x2A756) ++ */ ++int smbd_max_fragmented_recv_size = (1364 * 255) / 2; + + /* The maximum single-message size which can be received */ + int smbd_max_receive_size = 1364; +-- +2.51.0 + diff --git a/queue-6.1/smb-client-fix-potential-uaf-and-double-free-in-smb2.patch b/queue-6.1/smb-client-fix-potential-uaf-and-double-free-in-smb2.patch new file mode 100644 index 0000000000..3d67c58d27 --- /dev/null +++ b/queue-6.1/smb-client-fix-potential-uaf-and-double-free-in-smb2.patch @@ -0,0 +1,41 @@ +From bda7e4e6210da85d1ffb1dc97e14e5d924b08bf9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 13:19:52 -0300 +Subject: smb: client: fix potential UAF and double free in smb2_open_file() + +From: Paulo Alcantara + +[ Upstream commit ebbbc4bfad4cb355d17c671223d0814ee3ef4eda ] + +Zero out @err_iov and @err_buftype before retrying SMB2_open() to +prevent an UAF bug if @data != NULL, otherwise a double free. + +Fixes: e3a43633023e ("smb/client: fix memory leak in smb2_open_file()") +Reported-by: David Howells +Closes: https://lore.kernel.org/r/2892312.1770306653@warthog.procyon.org.uk +Signed-off-by: Paulo Alcantara (Red Hat) +Reviewed-by: David Howells +Reviewed-by: ChenXiaoSong +Cc: linux-cifs@vger.kernel.org +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/client/smb2file.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/fs/smb/client/smb2file.c b/fs/smb/client/smb2file.c +index 7fc7fcabce80c..fe016144f3405 100644 +--- a/fs/smb/client/smb2file.c ++++ b/fs/smb/client/smb2file.c +@@ -124,6 +124,8 @@ int smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, __u32 + &err_buftype); + if (rc == -EACCES && retry_without_read_attributes) { + free_rsp_buf(err_buftype, err_iov.iov_base); ++ memset(&err_iov, 0, sizeof(err_iov)); ++ err_buftype = CIFS_NO_BUFFER; + oparms->desired_access &= ~FILE_READ_ATTRIBUTES; + rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, smb2_data, NULL, &err_iov, + &err_buftype); +-- +2.51.0 + diff --git a/queue-6.1/soc-mediatek-mtk-svs-add-explicit-include-for-cpu.h.patch b/queue-6.1/soc-mediatek-mtk-svs-add-explicit-include-for-cpu.h.patch new file mode 100644 index 0000000000..663b7ce62a --- /dev/null +++ b/queue-6.1/soc-mediatek-mtk-svs-add-explicit-include-for-cpu.h.patch @@ -0,0 +1,39 @@ +From 9ec834fb57fba241e24f33aa3fd031f1d408f499 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Mar 2023 10:52:10 -0500 +Subject: soc: mediatek: mtk-svs: Add explicit include for cpu.h + +From: Rob Herring + +[ Upstream commit 26c682676471777c8464645695d3590b9134a5e7 ] + +Removing the include of cpu.h from of_device.h (included by +of_platform.h) causes an error: + +drivers/soc/mediatek/mtk-svs.c:2134:41: error: implicit declaration of function 'get_cpu_device'; did you mean 'get_swap_device'? [-Werror=implicit-function-declaration] + +of_platform.h is still needed for of_find_device_by_node(). + +Link: https://lore.kernel.org/r/20230329-dt-cpu-header-cleanups-v1-13-581e2605fe47@kernel.org +Signed-off-by: Rob Herring +Stable-dep-of: 6259094ee806 ("soc: mediatek: svs: Fix memory leak in svs_enable_debug_write()") +Signed-off-by: Sasha Levin +--- + drivers/soc/mediatek/mtk-svs.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/soc/mediatek/mtk-svs.c b/drivers/soc/mediatek/mtk-svs.c +index f00cd5c723499..1ec6e631a7796 100644 +--- a/drivers/soc/mediatek/mtk-svs.c ++++ b/drivers/soc/mediatek/mtk-svs.c +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + #include + #include + #include +-- +2.51.0 + diff --git a/queue-6.1/soc-mediatek-svs-fix-memory-leak-in-svs_enable_debug.patch b/queue-6.1/soc-mediatek-svs-fix-memory-leak-in-svs_enable_debug.patch new file mode 100644 index 0000000000..49079ef711 --- /dev/null +++ b/queue-6.1/soc-mediatek-svs-fix-memory-leak-in-svs_enable_debug.patch @@ -0,0 +1,59 @@ +From 532d8a5ab1f868ca3e2267fbf2f27c77765973e9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 28 Dec 2025 16:26:36 +0000 +Subject: soc: mediatek: svs: Fix memory leak in svs_enable_debug_write() + +From: Zilin Guan + +[ Upstream commit 6259094ee806fb813ca95894c65fb80e2ec98bf1 ] + +In svs_enable_debug_write(), the buf allocated by memdup_user_nul() +is leaked if kstrtoint() fails. + +Fix this by using __free(kfree) to automatically free buf, eliminating +the need for explicit kfree() calls and preventing leaks. + +Fixes: 13f1bbcfb582 ("soc: mediatek: SVS: add debug commands") +Co-developed-by: Jianhao Xu +Signed-off-by: Jianhao Xu +Signed-off-by: Zilin Guan +[Angelo: Added missing cleanup.h inclusion] +Signed-off-by: AngeloGioacchino Del Regno +Signed-off-by: Sasha Levin +--- + drivers/soc/mediatek/mtk-svs.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/soc/mediatek/mtk-svs.c b/drivers/soc/mediatek/mtk-svs.c +index 1ec6e631a7796..9897905a65baf 100644 +--- a/drivers/soc/mediatek/mtk-svs.c ++++ b/drivers/soc/mediatek/mtk-svs.c +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -709,7 +710,7 @@ static ssize_t svs_enable_debug_write(struct file *filp, + struct svs_platform *svsp = dev_get_drvdata(svsb->dev); + unsigned long flags; + int enabled, ret; +- char *buf = NULL; ++ char *buf __free(kfree) = NULL; + + if (count >= PAGE_SIZE) + return -EINVAL; +@@ -735,8 +736,6 @@ static ssize_t svs_enable_debug_write(struct file *filp, + svs_adjust_pm_opp_volts(svsb); + } + +- kfree(buf); +- + return count; + } + +-- +2.51.0 + diff --git a/queue-6.1/soc-qcom-cmd-db-use-devm_memremap-to-fix-memory-leak.patch b/queue-6.1/soc-qcom-cmd-db-use-devm_memremap-to-fix-memory-leak.patch new file mode 100644 index 0000000000..d5bcc1c3ba --- /dev/null +++ b/queue-6.1/soc-qcom-cmd-db-use-devm_memremap-to-fix-memory-leak.patch @@ -0,0 +1,53 @@ +From af3629e0e812724f01c22ff2b76e8dc0d95024d4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Dec 2025 09:39:32 +0800 +Subject: soc: qcom: cmd-db: Use devm_memremap() to fix memory leak in + cmd_db_dev_probe + +From: Haotian Zhang + +[ Upstream commit 0da7824734d8d83e6a844dd0207f071cb0c50cf4 ] + +If cmd_db_magic_matches() fails after memremap() succeeds, the function +returns -EINVAL without unmapping the memory region, causing a +potential resource leak. + +Switch to devm_memremap to automatically manage the map resource. + +Fixes: 312416d9171a ("drivers: qcom: add command DB driver") +Suggested-by: Dmitry Baryshkov +Signed-off-by: Haotian Zhang +Link: https://lore.kernel.org/r/20251216013933.773-1-vulab@iscas.ac.cn +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/cmd-db.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/soc/qcom/cmd-db.c b/drivers/soc/qcom/cmd-db.c +index 81ddbcd253d92..0b0766a79b19c 100644 +--- a/drivers/soc/qcom/cmd-db.c ++++ b/drivers/soc/qcom/cmd-db.c +@@ -354,15 +354,16 @@ static int cmd_db_dev_probe(struct platform_device *pdev) + return -EINVAL; + } + +- cmd_db_header = memremap(rmem->base, rmem->size, MEMREMAP_WC); +- if (!cmd_db_header) { +- ret = -ENOMEM; ++ cmd_db_header = devm_memremap(&pdev->dev, rmem->base, rmem->size, MEMREMAP_WC); ++ if (IS_ERR(cmd_db_header)) { ++ ret = PTR_ERR(cmd_db_header); + cmd_db_header = NULL; + return ret; + } + + if (!cmd_db_magic_matches(cmd_db_header)) { + dev_err(&pdev->dev, "Invalid Command DB Magic\n"); ++ cmd_db_header = NULL; + return -EINVAL; + } + +-- +2.51.0 + diff --git a/queue-6.1/soc-qcom-smem-handle-enomem-error-during-probe.patch b/queue-6.1/soc-qcom-smem-handle-enomem-error-during-probe.patch new file mode 100644 index 0000000000..2feb0e9ca1 --- /dev/null +++ b/queue-6.1/soc-qcom-smem-handle-enomem-error-during-probe.patch @@ -0,0 +1,39 @@ +From a0191913dcb77b2de0828f890a39c7f9364b7ee6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 08:45:37 +0100 +Subject: soc: qcom: smem: handle ENOMEM error during probe + +From: Jorge Ramirez-Ortiz + +[ Upstream commit 0fe01a7955f4fef97e7cc6d14bfc5931c660402b ] + +Fail the driver probe if the region can't be mapped + +Signed-off-by: Jorge Ramirez-Ortiz +Fixes: 20bb6c9de1b7 ("soc: qcom: smem: map only partitions used by local HOST") +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20251209074610.3751781-1-jorge.ramirez@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/smem.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c +index 06958de43f8ca..ab5c839511e88 100644 +--- a/drivers/soc/qcom/smem.c ++++ b/drivers/soc/qcom/smem.c +@@ -1130,7 +1130,9 @@ static int qcom_smem_probe(struct platform_device *pdev) + smem->item_count = qcom_smem_get_item_count(smem); + break; + case SMEM_GLOBAL_HEAP_VERSION: +- qcom_smem_map_global(smem, size); ++ ret = qcom_smem_map_global(smem, size); ++ if (ret < 0) ++ return ret; + smem->item_count = SMEM_ITEM_COUNT; + break; + default: +-- +2.51.0 + diff --git a/queue-6.1/spi-tools-add-include-folder-to-.gitignore.patch b/queue-6.1/spi-tools-add-include-folder-to-.gitignore.patch new file mode 100644 index 0000000000..2aa647db21 --- /dev/null +++ b/queue-6.1/spi-tools-add-include-folder-to-.gitignore.patch @@ -0,0 +1,35 @@ +From 208751605676cea3dbae9bc59318d4040b22806a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 10:50:01 +0100 +Subject: spi: tools: Add include folder to .gitignore + +From: Francesco Lavra + +[ Upstream commit 5af56f30c4fcbade4a92f94dadfea517d1db9703 ] + +The Makefile for the SPI tools creates an include/linux/spi folder and some +symlinks inside it. After running `make -C spi/tools`, this folder shows up +as untracked in the git status. +Add the above folder to the .gitignore file. + +Fixes: f325b73dc4db ("spi: tools: move to tools buildsystem") +Signed-off-by: Francesco Lavra +Link: https://patch.msgid.link/20260209095001.556495-1-flavra@baylibre.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + tools/spi/.gitignore | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/tools/spi/.gitignore b/tools/spi/.gitignore +index 14ddba3d21957..038261b34ed83 100644 +--- a/tools/spi/.gitignore ++++ b/tools/spi/.gitignore +@@ -1,3 +1,4 @@ + # SPDX-License-Identifier: GPL-2.0-only + spidev_fdx + spidev_test ++include/ +-- +2.51.0 + diff --git a/queue-6.1/staging-greybus-lights-avoid-null-deref.patch b/queue-6.1/staging-greybus-lights-avoid-null-deref.patch new file mode 100644 index 0000000000..da83ae9765 --- /dev/null +++ b/queue-6.1/staging-greybus-lights-avoid-null-deref.patch @@ -0,0 +1,55 @@ +From b170c016219fd4605b064086d0053bc16181d890 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 20:42:54 +0530 +Subject: staging: greybus: lights: avoid NULL deref + +From: Chaitanya Mishra + +[ Upstream commit efcffd9a6ad8d190651498d5eda53bfc7cf683a7 ] + +gb_lights_light_config() stores channel_count before allocating the +channels array. If kcalloc() fails, gb_lights_release() iterates the +non-zero count and dereferences light->channels, which is NULL. + +Allocate channels first and only then publish channels_count so the +cleanup path can't walk a NULL pointer. + +Fixes: 2870b52bae4c ("greybus: lights: add lights implementation") +Link: https://lore.kernel.org/all/20260108103700.15384-1-chaitanyamishra.ai@gmail.com/ +Reviewed-by: Rui Miguel Silva +Signed-off-by: Chaitanya Mishra +Link: https://patch.msgid.link/20260108151254.81553-1-chaitanyamishra.ai@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/staging/greybus/light.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/drivers/staging/greybus/light.c b/drivers/staging/greybus/light.c +index 9999f84016992..eb69500e080e0 100644 +--- a/drivers/staging/greybus/light.c ++++ b/drivers/staging/greybus/light.c +@@ -1029,14 +1029,18 @@ static int gb_lights_light_config(struct gb_lights *glights, u8 id) + if (!strlen(conf.name)) + return -EINVAL; + +- light->channels_count = conf.channel_count; + light->name = kstrndup(conf.name, NAMES_MAX, GFP_KERNEL); + if (!light->name) + return -ENOMEM; +- light->channels = kcalloc(light->channels_count, ++ light->channels = kcalloc(conf.channel_count, + sizeof(struct gb_channel), GFP_KERNEL); + if (!light->channels) + return -ENOMEM; ++ /* ++ * Publish channels_count only after channels allocation so cleanup ++ * doesn't walk a NULL channels pointer on allocation failure. ++ */ ++ light->channels_count = conf.channel_count; + + /* First we collect all the configurations for all channels */ + for (i = 0; i < light->channels_count; i++) { +-- +2.51.0 + diff --git a/queue-6.1/svcrdma-clean-up-comment-in-svc_rdma_accept.patch b/queue-6.1/svcrdma-clean-up-comment-in-svc_rdma_accept.patch new file mode 100644 index 0000000000..e3fa0ce9b5 --- /dev/null +++ b/queue-6.1/svcrdma-clean-up-comment-in-svc_rdma_accept.patch @@ -0,0 +1,64 @@ +From 43930c5fca328611dab3dbf8f80f92ea50a141b7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 Dec 2023 10:24:34 -0500 +Subject: svcrdma: Clean up comment in svc_rdma_accept() + +From: Chuck Lever + +[ Upstream commit fc2e69db82c1ac506cd7f539a3ab66d51d3380dc ] + +The comment that starts "Qualify ..." applies to only some of the +following code paragraph. Re-arrange the lines so the comment makes +more sense. + +Signed-off-by: Chuck Lever +Stable-dep-of: afcae7d7b8a2 ("RDMA/core: add rdma_rw_max_sge() helper for SQ sizing") +Signed-off-by: Sasha Levin +--- + net/sunrpc/xprtrdma/svc_rdma_transport.c | 17 ++++++++++------- + 1 file changed, 10 insertions(+), 7 deletions(-) + +diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c +index 7b7e882c7a508..31e6f4a14bbc0 100644 +--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c ++++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c +@@ -393,18 +393,22 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + dev = newxprt->sc_cm_id->device; + newxprt->sc_port_num = newxprt->sc_cm_id->port_num; + +- /* Qualify the transport resource defaults with the +- * capabilities of this particular device */ ++ newxprt->sc_max_req_size = svcrdma_max_req_size; ++ newxprt->sc_max_requests = svcrdma_max_requests; ++ newxprt->sc_max_bc_requests = svcrdma_max_bc_requests; ++ newxprt->sc_recv_batch = RPCRDMA_MAX_RECV_BATCH; ++ newxprt->sc_fc_credits = cpu_to_be32(newxprt->sc_max_requests); ++ ++ /* Qualify the transport's resource defaults with the ++ * capabilities of this particular device. ++ */ ++ + /* Transport header, head iovec, tail iovec */ + newxprt->sc_max_send_sges = 3; + /* Add one SGE per page list entry */ + newxprt->sc_max_send_sges += (svcrdma_max_req_size / PAGE_SIZE) + 1; + if (newxprt->sc_max_send_sges > dev->attrs.max_send_sge) + newxprt->sc_max_send_sges = dev->attrs.max_send_sge; +- newxprt->sc_max_req_size = svcrdma_max_req_size; +- newxprt->sc_max_requests = svcrdma_max_requests; +- newxprt->sc_max_bc_requests = svcrdma_max_bc_requests; +- newxprt->sc_recv_batch = RPCRDMA_MAX_RECV_BATCH; + rq_depth = newxprt->sc_max_requests + newxprt->sc_max_bc_requests + + newxprt->sc_recv_batch; + if (rq_depth > dev->attrs.max_qp_wr) { +@@ -413,7 +417,6 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + newxprt->sc_max_requests = rq_depth - 2; + newxprt->sc_max_bc_requests = 2; + } +- newxprt->sc_fc_credits = cpu_to_be32(newxprt->sc_max_requests); + ctxts = rdma_rw_mr_factor(dev, newxprt->sc_port_num, RPCSVC_MAXPAGES); + ctxts *= newxprt->sc_max_requests; + newxprt->sc_sq_depth = rq_depth + ctxts; +-- +2.51.0 + diff --git a/queue-6.1/svcrdma-increase-the-per-transport-rw_ctx-count.patch b/queue-6.1/svcrdma-increase-the-per-transport-rw_ctx-count.patch new file mode 100644 index 0000000000..2ae5226a03 --- /dev/null +++ b/queue-6.1/svcrdma-increase-the-per-transport-rw_ctx-count.patch @@ -0,0 +1,73 @@ +From 59091c56f3cbd00d8b353827559198767db1abb3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 4 Feb 2024 18:16:56 -0500 +Subject: svcrdma: Increase the per-transport rw_ctx count + +From: Chuck Lever + +[ Upstream commit 2da0f610e733606e06284ac3c1f188b9dec75d68 ] + +rdma_rw_mr_factor() returns the smallest number of MRs needed to +move a particular number of pages. svcrdma currently asks for the +number of MRs needed to move RPCSVC_MAXPAGES (a little over one +megabyte), as that is the number of pages in the largest r/wsize +the server supports. + +This call assumes that the client's NIC can bundle a full one +megabyte payload in a single rdma_segment. In fact, most NICs cannot +handle a full megabyte with a single rkey / rdma_segment. Clients +will typically split even a single Read chunk into many segments. + +The server needs one MR to read each rdma_segment in a Read chunk, +and thus each one needs an rw_ctx. + +svcrdma has been vastly underestimating the number of rw_ctxs needed +to handle 64 RPC requests with large Read chunks using small +rdma_segments. + +Unfortunately there doesn't seem to be a good way to estimate this +number without knowing the client NIC's capabilities. Even then, +the client RPC/RDMA implementation is still free to split a chunk +into smaller segments (for example, it might be using physical +registration, which needs an rdma_segment per page). + +The best we can do for now is choose a number that will guarantee +forward progress in the worst case (one page per segment). + +At some later point, we could add some mechanisms to make this +much less of a problem: +- Add a core API to add more rw_ctxs to an already-established QP +- svcrdma could treat rw_ctx exhaustion as a temporary error and + try again +- Limit the number of Reads in flight + +Signed-off-by: Chuck Lever +Stable-dep-of: afcae7d7b8a2 ("RDMA/core: add rdma_rw_max_sge() helper for SQ sizing") +Signed-off-by: Sasha Levin +--- + net/sunrpc/xprtrdma/svc_rdma_transport.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c +index 31e6f4a14bbc0..3d3b15f9d6d51 100644 +--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c ++++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c +@@ -417,8 +417,13 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + newxprt->sc_max_requests = rq_depth - 2; + newxprt->sc_max_bc_requests = 2; + } +- ctxts = rdma_rw_mr_factor(dev, newxprt->sc_port_num, RPCSVC_MAXPAGES); +- ctxts *= newxprt->sc_max_requests; ++ ++ /* Arbitrarily estimate the number of rw_ctxs needed for ++ * this transport. This is enough rw_ctxs to make forward ++ * progress even if the client is using one rkey per page ++ * in each Read chunk. ++ */ ++ ctxts = 3 * RPCSVC_MAXPAGES; + newxprt->sc_sq_depth = rq_depth + ctxts; + if (newxprt->sc_sq_depth > dev->attrs.max_qp_wr) + newxprt->sc_sq_depth = dev->attrs.max_qp_wr; +-- +2.51.0 + diff --git a/queue-6.1/svcrdma-reduce-the-number-of-rdma_rw-contexts-per-qp.patch b/queue-6.1/svcrdma-reduce-the-number-of-rdma_rw-contexts-per-qp.patch new file mode 100644 index 0000000000..38205b7fd5 --- /dev/null +++ b/queue-6.1/svcrdma-reduce-the-number-of-rdma_rw-contexts-per-qp.patch @@ -0,0 +1,96 @@ +From d56eadee607ff459a1b6e891c23f379c9314451c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 28 Apr 2025 15:36:49 -0400 +Subject: svcrdma: Reduce the number of rdma_rw contexts per-QP + +From: Chuck Lever + +[ Upstream commit 59243315890578a040a2d50ae9e001a2ef2fcb62 ] + +There is an upper bound on the number of rdma_rw contexts that can +be created per QP. + +This invisible upper bound is because rdma_create_qp() adds one or +more additional SQEs for each ctxt that the ULP requests via +qp_attr.cap.max_rdma_ctxs. The QP's actual Send Queue length is on +the order of the sum of qp_attr.cap.max_send_wr and a factor times +qp_attr.cap.max_rdma_ctxs. The factor can be up to three, depending +on whether MR operations are required before RDMA Reads. + +This limit is not visible to RDMA consumers via dev->attrs. When the +limit is surpassed, QP creation fails with -ENOMEM. For example: + +svcrdma's estimate of the number of rdma_rw contexts it needs is +three times the number of pages in RPCSVC_MAXPAGES. When MAXPAGES +is about 260, the internally-computed SQ length should be: + +64 credits + 10 backlog + 3 * (3 * 260) = 2414 + +Which is well below the advertised qp_max_wr of 32768. + +If RPCSVC_MAXPAGES is increased to 4MB, that's 1040 pages: + +64 credits + 10 backlog + 3 * (3 * 1040) = 9434 + +However, QP creation fails. Dynamic printk for mlx5 shows: + +calc_sq_size:618:(pid 1514): send queue size (9326 * 256 / 64 -> 65536) exceeds limits(32768) + +Although 9326 is still far below qp_max_wr, QP creation still +fails. + +Because the total SQ length calculation is opaque to RDMA consumers, +there doesn't seem to be much that can be done about this except for +consumers to try to keep the requested rdma_rw ctxt count low. + +Fixes: 2da0f610e733 ("svcrdma: Increase the per-transport rw_ctx count") +Reviewed-by: NeilBrown +Reviewed-by: Christoph Hellwig +Signed-off-by: Chuck Lever +Stable-dep-of: afcae7d7b8a2 ("RDMA/core: add rdma_rw_max_sge() helper for SQ sizing") +Signed-off-by: Sasha Levin +--- + net/sunrpc/xprtrdma/svc_rdma_transport.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c +index 3d3b15f9d6d51..c5721b75d32a7 100644 +--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c ++++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c +@@ -365,12 +365,12 @@ static struct svc_xprt *svc_rdma_create(struct svc_serv *serv, + */ + static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + { ++ unsigned int ctxts, rq_depth, maxpayload; + struct svcxprt_rdma *listen_rdma; + struct svcxprt_rdma *newxprt = NULL; + struct rdma_conn_param conn_param; + struct rpcrdma_connect_private pmsg; + struct ib_qp_init_attr qp_attr; +- unsigned int ctxts, rq_depth; + struct ib_device *dev; + int ret = 0; + RPC_IFDEBUG(struct sockaddr *sap); +@@ -418,12 +418,14 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + newxprt->sc_max_bc_requests = 2; + } + +- /* Arbitrarily estimate the number of rw_ctxs needed for +- * this transport. This is enough rw_ctxs to make forward +- * progress even if the client is using one rkey per page +- * in each Read chunk. ++ /* Arbitrary estimate of the needed number of rdma_rw contexts. + */ +- ctxts = 3 * RPCSVC_MAXPAGES; ++ maxpayload = min(xprt->xpt_server->sv_max_payload, ++ RPCSVC_MAXPAYLOAD_RDMA); ++ ctxts = newxprt->sc_max_requests * 3 * ++ rdma_rw_mr_factor(dev, newxprt->sc_port_num, ++ maxpayload >> PAGE_SHIFT); ++ + newxprt->sc_sq_depth = rq_depth + ctxts; + if (newxprt->sc_sq_depth > dev->attrs.max_qp_wr) + newxprt->sc_sq_depth = dev->attrs.max_qp_wr; +-- +2.51.0 + diff --git a/queue-6.1/svcrdma-remove-queue-shortening-warnings.patch b/queue-6.1/svcrdma-remove-queue-shortening-warnings.patch new file mode 100644 index 0000000000..f9509620fb --- /dev/null +++ b/queue-6.1/svcrdma-remove-queue-shortening-warnings.patch @@ -0,0 +1,52 @@ +From c2b0b8023bdb150d2d6bd39c6dd963f0a561440c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 Dec 2023 10:24:28 -0500 +Subject: svcrdma: Remove queue-shortening warnings + +From: Chuck Lever + +[ Upstream commit b918bfcf370c92ea3b82fa9bb3d017702b5fa4cb ] + +These won't have much diagnostic value for site administrators. +Since they can't be disabled, they become noise. + +What's more, the subsequent rdma_create_qp() call adjusts the Send +Queue size (possibly downward) without warning, making the size +reported by these pr_warns inaccurate. + +Signed-off-by: Chuck Lever +Stable-dep-of: afcae7d7b8a2 ("RDMA/core: add rdma_rw_max_sge() helper for SQ sizing") +Signed-off-by: Sasha Levin +--- + net/sunrpc/xprtrdma/svc_rdma_transport.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c +index f776f0cb471f0..7b7e882c7a508 100644 +--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c ++++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c +@@ -408,8 +408,6 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + rq_depth = newxprt->sc_max_requests + newxprt->sc_max_bc_requests + + newxprt->sc_recv_batch; + if (rq_depth > dev->attrs.max_qp_wr) { +- pr_warn("svcrdma: reducing receive depth to %d\n", +- dev->attrs.max_qp_wr); + rq_depth = dev->attrs.max_qp_wr; + newxprt->sc_recv_batch = 1; + newxprt->sc_max_requests = rq_depth - 2; +@@ -419,11 +417,8 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + ctxts = rdma_rw_mr_factor(dev, newxprt->sc_port_num, RPCSVC_MAXPAGES); + ctxts *= newxprt->sc_max_requests; + newxprt->sc_sq_depth = rq_depth + ctxts; +- if (newxprt->sc_sq_depth > dev->attrs.max_qp_wr) { +- pr_warn("svcrdma: reducing send depth to %d\n", +- dev->attrs.max_qp_wr); ++ if (newxprt->sc_sq_depth > dev->attrs.max_qp_wr) + newxprt->sc_sq_depth = dev->attrs.max_qp_wr; +- } + atomic_set(&newxprt->sc_sq_avail, newxprt->sc_sq_depth); + + newxprt->sc_pd = ib_alloc_pd(dev, 0); +-- +2.51.0 + diff --git a/queue-6.1/tcp-tcp_tx_timestamp-must-look-at-the-rtx-queue.patch b/queue-6.1/tcp-tcp_tx_timestamp-must-look-at-the-rtx-queue.patch new file mode 100644 index 0000000000..ce809f45e1 --- /dev/null +++ b/queue-6.1/tcp-tcp_tx_timestamp-must-look-at-the-rtx-queue.patch @@ -0,0 +1,44 @@ +From 01ca0988b555eb8814a7edcd7e2eb7fc97bbf2ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 12:38:27 +0000 +Subject: tcp: tcp_tx_timestamp() must look at the rtx queue + +From: Eric Dumazet + +[ Upstream commit 838eb9687691d29915797a885b861fd09353386e ] + +tcp_tx_timestamp() is only called at the end of tcp_sendmsg_locked() +before the final tcp_push(). + +By the time it is called, it is possible all the copied data +has been sent already (transmit queue is empty). + +If this is the case, use the last skb in the rtx queue. + +Fixes: 75c119afe14f ("tcp: implement rb-tree based retransmit queue") +Signed-off-by: Eric Dumazet +Reviewed-by: Jason Xing +Link: https://patch.msgid.link/20260127123828.4098577-2-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index c195f85149519..6bef8514e29ad 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -467,6 +467,9 @@ static void tcp_tx_timestamp(struct sock *sk, u16 tsflags) + { + struct sk_buff *skb = tcp_write_queue_tail(sk); + ++ if (unlikely(!skb)) ++ skb = skb_rb_last(&sk->tcp_rtx_queue); ++ + if (tsflags && skb) { + struct skb_shared_info *shinfo = skb_shinfo(skb); + struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); +-- +2.51.0 + diff --git a/queue-6.1/timers-replace-in_irq-with-in_hardirq.patch b/queue-6.1/timers-replace-in_irq-with-in_hardirq.patch new file mode 100644 index 0000000000..cc5381a082 --- /dev/null +++ b/queue-6.1/timers-replace-in_irq-with-in_hardirq.patch @@ -0,0 +1,38 @@ +From 33deaa7690e5a0bf8fa1b94faade4487ddb4efe6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 12 Oct 2022 01:26:29 +0000 +Subject: timers: Replace in_irq() with in_hardirq() + +From: ye xingchen + +[ Upstream commit 8be3f96ceddb911539a53d87a66da84a04502366 ] + +Replace the obsolete and ambiguous macro in_irq() with new +macro in_hardirq(). + +Signed-off-by: ye xingchen +Signed-off-by: Thomas Gleixner +Acked-by: John Stultz +Link: https://lore.kernel.org/r/20221012012629.334966-1-ye.xingchen@zte.com.cn +Stable-dep-of: c9efde1e537b ("nfc: hci: shdlc: Stop timers and work before freeing context") +Signed-off-by: Sasha Levin +--- + kernel/time/timer.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/time/timer.c b/kernel/time/timer.c +index d7462b19b2f7e..4a2aeaa85af31 100644 +--- a/kernel/time/timer.c ++++ b/kernel/time/timer.c +@@ -1561,7 +1561,7 @@ static int __timer_delete_sync(struct timer_list *timer, bool shutdown) + * don't use it in hardirq context, because it + * could lead to deadlock. + */ +- WARN_ON(in_irq() && !(timer->flags & TIMER_IRQSAFE)); ++ WARN_ON(in_hardirq() && !(timer->flags & TIMER_IRQSAFE)); + + /* + * Must be able to sleep on PREEMPT_RT because of the slowpath in +-- +2.51.0 + diff --git a/queue-6.1/tpm-st33zp24-fix-missing-cleanup-on-get_burstcount-e.patch b/queue-6.1/tpm-st33zp24-fix-missing-cleanup-on-get_burstcount-e.patch new file mode 100644 index 0000000000..992e442083 --- /dev/null +++ b/queue-6.1/tpm-st33zp24-fix-missing-cleanup-on-get_burstcount-e.patch @@ -0,0 +1,43 @@ +From ab64a04d406b52c8cb8d00d6856693f407aa8565 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Dec 2025 15:09:27 +0300 +Subject: tpm: st33zp24: Fix missing cleanup on get_burstcount() error + +From: Alper Ak + +[ Upstream commit 3e91b44c93ad2871f89fc2a98c5e4fe6ca5db3d9 ] + +get_burstcount() can return -EBUSY on timeout. When this happens, +st33zp24_send() returns directly without releasing the locality +acquired earlier. + +Use goto out_err to ensure proper cleanup when get_burstcount() fails. + +Fixes: bf38b8710892 ("tpm/tpm_i2c_stm_st33: Split tpm_i2c_tpm_st33 in 2 layers (core + phy)") +Signed-off-by: Alper Ak +Signed-off-by: Jarkko Sakkinen +Signed-off-by: Sasha Levin +--- + drivers/char/tpm/st33zp24/st33zp24.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/char/tpm/st33zp24/st33zp24.c b/drivers/char/tpm/st33zp24/st33zp24.c +index 15b393e92c8ec..71cc97f394b51 100644 +--- a/drivers/char/tpm/st33zp24/st33zp24.c ++++ b/drivers/char/tpm/st33zp24/st33zp24.c +@@ -327,8 +327,10 @@ static int st33zp24_send(struct tpm_chip *chip, unsigned char *buf, + + for (i = 0; i < len - 1;) { + burstcnt = get_burstcount(chip); +- if (burstcnt < 0) +- return burstcnt; ++ if (burstcnt < 0) { ++ ret = burstcnt; ++ goto out_err; ++ } + size = min_t(int, len - i - 1, burstcnt); + ret = tpm_dev->ops->send(tpm_dev->phy_id, TPM_DATA_FIFO, + buf + i, size); +-- +2.51.0 + diff --git a/queue-6.1/tpm-tpm_i2c_infineon-fix-locality-leak-on-get_burstc.patch b/queue-6.1/tpm-tpm_i2c_infineon-fix-locality-leak-on-get_burstc.patch new file mode 100644 index 0000000000..50ad47b310 --- /dev/null +++ b/queue-6.1/tpm-tpm_i2c_infineon-fix-locality-leak-on-get_burstc.patch @@ -0,0 +1,44 @@ +From e93ad69e8236396e9c5a87d003f550566e966824 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Dec 2025 13:23:38 +0300 +Subject: tpm: tpm_i2c_infineon: Fix locality leak on get_burstcount() failure + +From: Alper Ak + +[ Upstream commit bbd6e97c836cbeb9606d7b7e5dcf8a1d89525713 ] + +get_burstcount() can return -EBUSY on timeout. When this happens, the +function returns directly without releasing the locality that was +acquired at the beginning of tpm_tis_i2c_send(). + +Use goto out_err to ensure proper cleanup when get_burstcount() fails. + +Fixes: aad628c1d91a ("char/tpm: Add new driver for Infineon I2C TIS TPM") +Signed-off-by: Alper Ak +Reviewed-by: Jarkko Sakkinen +Signed-off-by: Jarkko Sakkinen +Signed-off-by: Sasha Levin +--- + drivers/char/tpm/tpm_i2c_infineon.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c +index fd3c3661e6466..b1cfd2da5eb3e 100644 +--- a/drivers/char/tpm/tpm_i2c_infineon.c ++++ b/drivers/char/tpm/tpm_i2c_infineon.c +@@ -543,8 +543,10 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len) + burstcnt = get_burstcount(chip); + + /* burstcnt < 0 = TPM is busy */ +- if (burstcnt < 0) +- return burstcnt; ++ if (burstcnt < 0) { ++ rc = burstcnt; ++ goto out_err; ++ } + + if (burstcnt > (len - 1 - count)) + burstcnt = len - 1 - count; +-- +2.51.0 + diff --git a/queue-6.1/tracing-properly-process-error-handling-in-event_his.patch b/queue-6.1/tracing-properly-process-error-handling-in-event_his.patch new file mode 100644 index 0000000000..a8e5ecc740 --- /dev/null +++ b/queue-6.1/tracing-properly-process-error-handling-in-event_his.patch @@ -0,0 +1,51 @@ +From 71c6146a62f4d2b2005ef48c010c641d049c4ba1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 11 Dec 2025 14:00:58 +0400 +Subject: tracing: Properly process error handling in + event_hist_trigger_parse() + +From: Miaoqian Lin + +[ Upstream commit 0550069cc25f513ce1f109c88f7c1f01d63297db ] + +Memory allocated with trigger_data_alloc() requires trigger_data_free() +for proper cleanup. + +Replace kfree() with trigger_data_free() to fix this. + +Found via static analysis and code review. + +This isn't a real bug due to the current code basically being an open +coded version of trigger_data_free() without the synchronization. The +synchronization isn't needed as this is the error path of creation and +there's nothing to synchronize against yet. Replace the kfree() to be +consistent with the allocation. + +Cc: Masami Hiramatsu +Cc: Mathieu Desnoyers +Cc: Tom Zanussi +Link: https://patch.msgid.link/20251211100058.2381268-1-linmq006@gmail.com +Fixes: e1f187d09e11 ("tracing: Have existing event_command.parse() implementations use helpers") +Signed-off-by: Miaoqian Lin +Signed-off-by: Steven Rostedt (Google) +Signed-off-by: Sasha Levin +--- + kernel/trace/trace_events_hist.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c +index 31d60758053d1..356360e75f9a7 100644 +--- a/kernel/trace/trace_events_hist.c ++++ b/kernel/trace/trace_events_hist.c +@@ -6594,7 +6594,7 @@ static int event_hist_trigger_parse(struct event_command *cmd_ops, + + remove_hist_vars(hist_data); + +- kfree(trigger_data); ++ trigger_data_free(trigger_data); + + destroy_hist_data(hist_data); + goto out; +-- +2.51.0 + diff --git a/queue-6.1/tracing-remove-duplicate-enable_event_str-and-disabl.patch b/queue-6.1/tracing-remove-duplicate-enable_event_str-and-disabl.patch new file mode 100644 index 0000000000..e70941c6fc --- /dev/null +++ b/queue-6.1/tracing-remove-duplicate-enable_event_str-and-disabl.patch @@ -0,0 +1,44 @@ +From 369e2d4245dd3703a1fe1b7ab89c02bf3cb02e8b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 13:00:37 -0500 +Subject: tracing: Remove duplicate ENABLE_EVENT_STR and DISABLE_EVENT_STR + macros + +From: Steven Rostedt + +[ Upstream commit 9df0e49c5b9b8d051529be9994e4f92f2d20be6f ] + +The macros ENABLE_EVENT_STR and DISABLE_EVENT_STR were added to trace.h so +that more than one file can have access to them, but was never removed +from their original location. Remove the duplicates. + +Cc: Masami Hiramatsu +Cc: Mathieu Desnoyers +Cc: Tom Zanussi +Link: https://patch.msgid.link/20260126130037.4ba201f9@gandalf.local.home +Fixes: d0bad49bb0a09 ("tracing: Add enable_hist/disable_hist triggers") +Signed-off-by: Steven Rostedt (Google) +Signed-off-by: Sasha Levin +--- + kernel/trace/trace_events.c | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c +index 6a146dfbbd7e5..55623a9bb64ac 100644 +--- a/kernel/trace/trace_events.c ++++ b/kernel/trace/trace_events.c +@@ -3327,11 +3327,6 @@ void trace_put_event_file(struct trace_event_file *file) + EXPORT_SYMBOL_GPL(trace_put_event_file); + + #ifdef CONFIG_DYNAMIC_FTRACE +- +-/* Avoid typos */ +-#define ENABLE_EVENT_STR "enable_event" +-#define DISABLE_EVENT_STR "disable_event" +- + struct event_probe_data { + struct trace_event_file *file; + unsigned long count; +-- +2.51.0 + diff --git a/queue-6.1/ublk-validate-sqe128-flag-before-accessing-the-cmd.patch b/queue-6.1/ublk-validate-sqe128-flag-before-accessing-the-cmd.patch new file mode 100644 index 0000000000..5c80bbbd7b --- /dev/null +++ b/queue-6.1/ublk-validate-sqe128-flag-before-accessing-the-cmd.patch @@ -0,0 +1,47 @@ +From 1ff4dbbc292c4fa7e2a46aac313728197966814c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 10:14:12 -0700 +Subject: ublk: Validate SQE128 flag before accessing the cmd + +From: Govindarajulu Varadarajan + +[ Upstream commit da7e4b75e50c087d2031a92f6646eb90f7045a67 ] + +ublk_ctrl_cmd_dump() accesses (header *)sqe->cmd before +IO_URING_F_SQE128 flag check. This could cause out of boundary memory +access. + +Move the SQE128 flag check earlier in ublk_ctrl_uring_cmd() to return +-EINVAL immediately if the flag is not set. + +Fixes: 71f28f3136af ("ublk_drv: add io_uring based userspace block driver") +Signed-off-by: Govindarajulu Varadarajan +Reviewed-by: Caleb Sander Mateos +Reviewed-by: Ming Lei +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/block/ublk_drv.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c +index 3a7c42f76d894..121b62f8bb0a2 100644 +--- a/drivers/block/ublk_drv.c ++++ b/drivers/block/ublk_drv.c +@@ -2010,10 +2010,10 @@ static int ublk_ctrl_uring_cmd(struct io_uring_cmd *cmd, + if (issue_flags & IO_URING_F_NONBLOCK) + return -EAGAIN; + +- ublk_ctrl_cmd_dump(cmd); +- + if (!(issue_flags & IO_URING_F_SQE128)) +- goto out; ++ return -EINVAL; ++ ++ ublk_ctrl_cmd_dump(cmd); + + ret = -EPERM; + if (!capable(CAP_SYS_ADMIN)) +-- +2.51.0 + diff --git a/queue-6.1/ucount-check-for-cap_sys_resource-using-ns_capable_n.patch b/queue-6.1/ucount-check-for-cap_sys_resource-using-ns_capable_n.patch new file mode 100644 index 0000000000..1a5b287772 --- /dev/null +++ b/queue-6.1/ucount-check-for-cap_sys_resource-using-ns_capable_n.patch @@ -0,0 +1,51 @@ +From bb0f74641aa76b0bff66b435d1565a4f0e50834f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 15:07:45 +0100 +Subject: ucount: check for CAP_SYS_RESOURCE using ns_capable_noaudit() + +From: Ondrej Mosnacek + +[ Upstream commit 0895a000e4fff9e950a7894210db45973e485c35 ] + +The user.* sysctls implement the ctl_table_root::permissions hook and they +override the file access mode based on the CAP_SYS_RESOURCE capability (at +most rwx if capable, at most r-- if not). The capability is being checked +unconditionally, so if an LSM denies the capability, an audit record may +be logged even when access is in fact granted. + +Given the logic in the set_permissions() function in kernel/ucount.c and +the unfortunate way the permission checking is implemented, it doesn't +seem viable to avoid false positive denials by deferring the capability +check. Thus, do the same as in net_ctl_permissions() (net/sysctl_net.c) - +switch from ns_capable() to ns_capable_noaudit(), so that the check never +logs an audit record. + +Link: https://lkml.kernel.org/r/20260122140745.239428-1-omosnace@redhat.com +Fixes: dbec28460a89 ("userns: Add per user namespace sysctls.") +Signed-off-by: Ondrej Mosnacek +Reviewed-by: Paul Moore +Acked-by: Serge Hallyn +Cc: Eric Biederman +Cc: Alexey Gladkov +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + kernel/ucount.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/ucount.c b/kernel/ucount.c +index 8afa2878422d5..7f29cc9728189 100644 +--- a/kernel/ucount.c ++++ b/kernel/ucount.c +@@ -45,7 +45,7 @@ static int set_permissions(struct ctl_table_header *head, + int mode; + + /* Allow users with CAP_SYS_RESOURCE unrestrained access */ +- if (ns_capable(user_ns, CAP_SYS_RESOURCE)) ++ if (ns_capable_noaudit(user_ns, CAP_SYS_RESOURCE)) + mode = (table->mode & S_IRWXU) >> 6; + else + /* Allow all others at most read-only access */ +-- +2.51.0 + diff --git a/queue-6.1/usb-bdc-fix-sleep-during-atomic.patch b/queue-6.1/usb-bdc-fix-sleep-during-atomic.patch new file mode 100644 index 0000000000..cc53d9bf1c --- /dev/null +++ b/queue-6.1/usb-bdc-fix-sleep-during-atomic.patch @@ -0,0 +1,41 @@ +From f9edd1361c9b909380b6b726c18007e92e909f3b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 12:07:54 -0800 +Subject: usb: bdc: fix sleep during atomic + +From: Justin Chen + +[ Upstream commit f1195ca3b4bbd001d3f1264dce91f83dec7777f5 ] + +bdc_run() can be ran during atomic context leading to a sleep during +atomic warning. Fix this by replacing read_poll_timeout() with +read_poll_timeout_atomic(). + +Fixes: 75ae051efc9b ("usb: gadget: bdc: use readl_poll_timeout() to simplify code") +Signed-off-by: Justin Chen +Reviewed-by: Florian Fainelli +Link: https://patch.msgid.link/20260120200754.2488765-1-justin.chen@broadcom.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/gadget/udc/bdc/bdc_core.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/usb/gadget/udc/bdc/bdc_core.c b/drivers/usb/gadget/udc/bdc/bdc_core.c +index 9849e0c86e23e..9460ef0a7f892 100644 +--- a/drivers/usb/gadget/udc/bdc/bdc_core.c ++++ b/drivers/usb/gadget/udc/bdc/bdc_core.c +@@ -35,8 +35,8 @@ static int poll_oip(struct bdc *bdc, u32 usec) + u32 status; + int ret; + +- ret = readl_poll_timeout(bdc->regs + BDC_BDCSC, status, +- (BDC_CSTS(status) != BDC_OIP), 10, usec); ++ ret = readl_poll_timeout_atomic(bdc->regs + BDC_BDCSC, status, ++ (BDC_CSTS(status) != BDC_OIP), 10, usec); + if (ret) + dev_err(bdc->dev, "operation timedout BDCSC: 0x%08x\n", status); + else +-- +2.51.0 + diff --git a/queue-6.1/wifi-ath10k-sdio-add-missing-lock-protection-in-ath1.patch b/queue-6.1/wifi-ath10k-sdio-add-missing-lock-protection-in-ath1.patch new file mode 100644 index 0000000000..6d8bacaecb --- /dev/null +++ b/queue-6.1/wifi-ath10k-sdio-add-missing-lock-protection-in-ath1.patch @@ -0,0 +1,62 @@ +From ddb36b68243286520035cad62ce7ce72e19ba3ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 04:58:22 +0000 +Subject: wifi: ath10k: sdio: add missing lock protection in + ath10k_sdio_fw_crashed_dump() + +From: Ziyi Guo + +[ Upstream commit e55ac348089e579fc224569c7bd90340bf2439f9 ] + +ath10k_sdio_fw_crashed_dump() calls ath10k_coredump_new() which requires +ar->dump_mutex to be held, as indicated by lockdep_assert_held() in that +function. However, the SDIO implementation does not acquire this lock, +unlike the PCI and SNOC implementations which properly hold the mutex. + +Additionally, ar->stats.fw_crash_counter is documented as protected by +ar->data_lock in core.h, but the SDIO implementation modifies it without +holding this spinlock. + +Add the missing mutex_lock()/mutex_unlock() around the coredump +operations, and add spin_lock_bh()/spin_unlock_bh() around the +fw_crash_counter increment, following the pattern used in +ath10k_pci_fw_dump_work() and ath10k_snoc_fw_crashed_dump(). + +Fixes: 3c45f21af84e ("ath10k: sdio: add firmware coredump support") +Signed-off-by: Ziyi Guo +Reviewed-by: Baochen Qiang +Link: https://patch.msgid.link/20260123045822.2221549-1-n7l8m4@u.northwestern.edu +Signed-off-by: Jeff Johnson +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/ath/ath10k/sdio.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c +index d0705f2f46560..b49eeaaadde79 100644 +--- a/drivers/net/wireless/ath/ath10k/sdio.c ++++ b/drivers/net/wireless/ath/ath10k/sdio.c +@@ -2485,7 +2485,11 @@ void ath10k_sdio_fw_crashed_dump(struct ath10k *ar) + if (fast_dump) + ath10k_bmi_start(ar); + ++ mutex_lock(&ar->dump_mutex); ++ ++ spin_lock_bh(&ar->data_lock); + ar->stats.fw_crash_counter++; ++ spin_unlock_bh(&ar->data_lock); + + ath10k_sdio_disable_intrs(ar); + +@@ -2503,6 +2507,8 @@ void ath10k_sdio_fw_crashed_dump(struct ath10k *ar) + + ath10k_sdio_enable_intrs(ar); + ++ mutex_unlock(&ar->dump_mutex); ++ + ath10k_core_start_recovery(ar); + } + +-- +2.51.0 + diff --git a/queue-6.1/wifi-cfg80211-stop-nan-and-p2p-in-cfg80211_leave.patch b/queue-6.1/wifi-cfg80211-stop-nan-and-p2p-in-cfg80211_leave.patch new file mode 100644 index 0000000000..d3a4439480 --- /dev/null +++ b/queue-6.1/wifi-cfg80211-stop-nan-and-p2p-in-cfg80211_leave.patch @@ -0,0 +1,47 @@ +From fee73fbe307d19743bb9700bb88e3ad525466a17 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 14:04:51 +0200 +Subject: wifi: cfg80211: stop NAN and P2P in cfg80211_leave + +From: Miri Korenblit + +[ Upstream commit e1696c8bd0056bc1a5f7766f58ac333adc203e8a ] + +Seems that there is an assumption that this function should be called +only for netdev interfaces, but it can also be called in suspend, or +from nl80211_netlink_notify (indirectly). +Note that the documentation of NL80211_ATTR_SOCKET_OWNER explicitly +says that NAN interfaces would be destroyed as well in the +nl80211_netlink_notify case. + +Fix this by also stopping P2P and NAN. + +Fixes: cb3b7d87652a ("cfg80211: add start / stop NAN commands") +Reviewed-by: Johannes Berg +Signed-off-by: Miri Korenblit +Link: https://patch.msgid.link/20260107140430.dab142cbef0b.I290cc47836d56dd7e35012ce06bec36c6da688cd@changeid +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/wireless/core.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/net/wireless/core.c b/net/wireless/core.c +index 1788431c82207..2b6bdb7eaf18d 100644 +--- a/net/wireless/core.c ++++ b/net/wireless/core.c +@@ -1328,8 +1328,10 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev, + __cfg80211_leave_ocb(rdev, dev); + break; + case NL80211_IFTYPE_P2P_DEVICE: ++ cfg80211_stop_p2p_device(rdev, wdev); ++ break; + case NL80211_IFTYPE_NAN: +- /* cannot happen, has no netdev */ ++ cfg80211_stop_nan(rdev, wdev); + break; + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_MONITOR: +-- +2.51.0 + diff --git a/queue-6.1/xen-virtio-don-t-use-grant-dma-ops-when-running-as-d.patch b/queue-6.1/xen-virtio-don-t-use-grant-dma-ops-when-running-as-d.patch new file mode 100644 index 0000000000..a0abc23b7d --- /dev/null +++ b/queue-6.1/xen-virtio-don-t-use-grant-dma-ops-when-running-as-d.patch @@ -0,0 +1,45 @@ +From 2ae0c83777e84907c6f31da9b41b8efb723cc821 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Jan 2026 17:36:50 +0000 +Subject: xen/virtio: Don't use grant-dma-ops when running as Dom0 + +From: Teddy Astie + +[ Upstream commit dc8ea8714311e549ee93a2b0bdd5487d20bfadbf ] + +Dom0 inherit devices from the machine and is usually in PV mode. +If we are running in a virtual that has virtio devices, these devices +would be considered as using grants with Dom0 as backend, while being +the said Dom0 itself, while we want to use these devices like regular +PCI devices. + +Fix this by preventing grant-dma-ops from being used when running as Dom0 +(initial domain). We still keep the device-tree logic as-is. + +Signed-off-by: Teddy Astie +Fixes: 61367688f1fb0 ("xen/virtio: enable grant based virtio on x86") +Reviewed-by: Juergen Gross +Signed-off-by: Juergen Gross +Message-ID: <6698564dd2270a9f7377b78ebfb20cb425cabbe8.1767720955.git.teddy.astie@vates.tech> +Signed-off-by: Sasha Levin +--- + drivers/xen/grant-dma-ops.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/xen/grant-dma-ops.c b/drivers/xen/grant-dma-ops.c +index 9784a77fa3c99..46cc47bd1dd0f 100644 +--- a/drivers/xen/grant-dma-ops.c ++++ b/drivers/xen/grant-dma-ops.c +@@ -360,7 +360,8 @@ static int xen_grant_init_backend_domid(struct device *dev, + if (np) { + ret = xen_dt_grant_init_backend_domid(dev, np, backend_domid); + of_node_put(np); +- } else if (IS_ENABLED(CONFIG_XEN_VIRTIO_FORCE_GRANT) || xen_pv_domain()) { ++ } else if (!xen_initial_domain() && ++ (IS_ENABLED(CONFIG_XEN_VIRTIO_FORCE_GRANT) || xen_pv_domain())) { + dev_info(dev, "Using dom0 as backend\n"); + *backend_domid = 0; + ret = 0; +-- +2.51.0 + diff --git a/queue-6.1/xen-virtio-handle-pci-devices-which-host-controller-.patch b/queue-6.1/xen-virtio-handle-pci-devices-which-host-controller-.patch new file mode 100644 index 0000000000..e8ac192e59 --- /dev/null +++ b/queue-6.1/xen-virtio-handle-pci-devices-which-host-controller-.patch @@ -0,0 +1,126 @@ +From d515cbb4c22f9e534aff5afb107d3d856f7174aa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 25 Oct 2022 19:20:04 +0300 +Subject: xen/virtio: Handle PCI devices which Host controller is described in + DT + +From: Oleksandr Tyshchenko + +[ Upstream commit ef8ae384b4c9ccefecf4754f34644bd9fb0105b7 ] + +Use the same "xen-grant-dma" device concept for the PCI devices +behind device-tree based PCI Host controller, but with one modification. +Unlike for platform devices, we cannot use generic IOMMU bindings +(iommus property), as we need to support more flexible configuration. +The problem is that PCI devices under the single PCI Host controller +may have the backends running in different Xen domains and thus have +different endpoints ID (backend domains ID). + +Add ability to deal with generic PCI-IOMMU bindings (iommu-map/ +iommu-map-mask properties) which allows us to describe relationship +between PCI devices and backend domains ID properly. + +To avoid having to look up for the PCI Host bridge twice and reduce +the amount of checks pass an extra struct device_node *np to +xen_dt_grant_init_backend_domid(). + +So with current patch the code expects iommus property for the platform +devices and iommu-map/iommu-map-mask properties for PCI devices. + +The example of generated by the toolstack iommu-map property +for two PCI devices 0000:00:01.0 and 0000:00:02.0 whose +backends are running in different Xen domains with IDs 1 and 2 +respectively: +iommu-map = <0x08 0xfde9 0x01 0x08 0x10 0xfde9 0x02 0x08>; + +Signed-off-by: Oleksandr Tyshchenko +Reviewed-by: Xenia Ragiadakou +Reviewed-by: Stefano Stabellini +Link: https://lore.kernel.org/r/20221025162004.8501-3-olekstysh@gmail.com +Signed-off-by: Juergen Gross +Stable-dep-of: dc8ea8714311 ("xen/virtio: Don't use grant-dma-ops when running as Dom0") +Signed-off-by: Sasha Levin +--- + drivers/xen/grant-dma-ops.c | 46 +++++++++++++++++++++++++++++++------ + 1 file changed, 39 insertions(+), 7 deletions(-) + +diff --git a/drivers/xen/grant-dma-ops.c b/drivers/xen/grant-dma-ops.c +index 1e797a043980a..9784a77fa3c99 100644 +--- a/drivers/xen/grant-dma-ops.c ++++ b/drivers/xen/grant-dma-ops.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -292,15 +293,43 @@ static const struct dma_map_ops xen_grant_dma_ops = { + .dma_supported = xen_grant_dma_supported, + }; + ++static struct device_node *xen_dt_get_node(struct device *dev) ++{ ++ if (dev_is_pci(dev)) { ++ struct pci_dev *pdev = to_pci_dev(dev); ++ struct pci_bus *bus = pdev->bus; ++ ++ /* Walk up to the root bus to look for PCI Host controller */ ++ while (!pci_is_root_bus(bus)) ++ bus = bus->parent; ++ ++ return of_node_get(bus->bridge->parent->of_node); ++ } ++ ++ return of_node_get(dev->of_node); ++} ++ + static int xen_dt_grant_init_backend_domid(struct device *dev, ++ struct device_node *np, + domid_t *backend_domid) + { +- struct of_phandle_args iommu_spec; ++ struct of_phandle_args iommu_spec = { .args_count = 1 }; + +- if (of_parse_phandle_with_args(dev->of_node, "iommus", "#iommu-cells", +- 0, &iommu_spec)) { +- dev_dbg(dev, "Cannot parse iommus property\n"); +- return -ESRCH; ++ if (dev_is_pci(dev)) { ++ struct pci_dev *pdev = to_pci_dev(dev); ++ u32 rid = PCI_DEVID(pdev->bus->number, pdev->devfn); ++ ++ if (of_map_id(np, rid, "iommu-map", "iommu-map-mask", &iommu_spec.np, ++ iommu_spec.args)) { ++ dev_dbg(dev, "Cannot translate ID\n"); ++ return -ESRCH; ++ } ++ } else { ++ if (of_parse_phandle_with_args(np, "iommus", "#iommu-cells", ++ 0, &iommu_spec)) { ++ dev_dbg(dev, "Cannot parse iommus property\n"); ++ return -ESRCH; ++ } + } + + if (!of_device_is_compatible(iommu_spec.np, "xen,grant-dma") || +@@ -324,10 +353,13 @@ static int xen_dt_grant_init_backend_domid(struct device *dev, + static int xen_grant_init_backend_domid(struct device *dev, + domid_t *backend_domid) + { ++ struct device_node *np; + int ret = -ENODEV; + +- if (dev->of_node) { +- ret = xen_dt_grant_init_backend_domid(dev, backend_domid); ++ np = xen_dt_get_node(dev); ++ if (np) { ++ ret = xen_dt_grant_init_backend_domid(dev, np, backend_domid); ++ of_node_put(np); + } else if (IS_ENABLED(CONFIG_XEN_VIRTIO_FORCE_GRANT) || xen_pv_domain()) { + dev_info(dev, "Using dom0 as backend\n"); + *backend_domid = 0; +-- +2.51.0 + diff --git a/queue-6.1/xen-virtio-optimize-the-setup-of-xen-grant-dma-devic.patch b/queue-6.1/xen-virtio-optimize-the-setup-of-xen-grant-dma-devic.patch new file mode 100644 index 0000000000..6f27d545b5 --- /dev/null +++ b/queue-6.1/xen-virtio-optimize-the-setup-of-xen-grant-dma-devic.patch @@ -0,0 +1,232 @@ +From c56bfedfd47dca75367454d6308d7d902a286dc0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 25 Oct 2022 19:20:03 +0300 +Subject: xen/virtio: Optimize the setup of "xen-grant-dma" devices + +From: Oleksandr Tyshchenko + +[ Upstream commit 035e3a4321f73c352b6408ec2153fa5bc3feb459 ] + +This is needed to avoid having to parse the same device-tree +several times for a given device. + +For this to work we need to install the xen_virtio_restricted_mem_acc +callback in Arm's xen_guest_init() which is same callback as x86's +PV and HVM modes already use and remove the manual assignment in +xen_setup_dma_ops(). Also we need to split the code to initialize +backend_domid into a separate function. + +Prior to current patch we parsed the device-tree three times: +1. xen_setup_dma_ops()->...->xen_is_dt_grant_dma_device() +2. xen_setup_dma_ops()->...->xen_dt_grant_init_backend_domid() +3. xen_virtio_mem_acc()->...->xen_is_dt_grant_dma_device() + +With current patch we parse the device-tree only once in +xen_virtio_restricted_mem_acc()->...->xen_dt_grant_init_backend_domid() + +Other benefits are: +- Not diverge from x86 when setting up Xen grant DMA ops +- Drop several global functions + +Signed-off-by: Oleksandr Tyshchenko +Reviewed-by: Xenia Ragiadakou +Reviewed-by: Stefano Stabellini +Link: https://lore.kernel.org/r/20221025162004.8501-2-olekstysh@gmail.com +Signed-off-by: Juergen Gross +Stable-dep-of: dc8ea8714311 ("xen/virtio: Don't use grant-dma-ops when running as Dom0") +Signed-off-by: Sasha Levin +--- + arch/arm/xen/enlighten.c | 2 +- + drivers/xen/grant-dma-ops.c | 77 ++++++++++++++----------------------- + include/xen/arm/xen-ops.h | 4 +- + include/xen/xen-ops.h | 16 -------- + 4 files changed, 30 insertions(+), 69 deletions(-) + +diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c +index eace3607fef41..a395b6c0aae2a 100644 +--- a/arch/arm/xen/enlighten.c ++++ b/arch/arm/xen/enlighten.c +@@ -442,7 +442,7 @@ static int __init xen_guest_init(void) + return 0; + + if (IS_ENABLED(CONFIG_XEN_VIRTIO)) +- virtio_set_mem_acc_cb(xen_virtio_mem_acc); ++ virtio_set_mem_acc_cb(xen_virtio_restricted_mem_acc); + + if (!acpi_disabled) + xen_acpi_guest_init(); +diff --git a/drivers/xen/grant-dma-ops.c b/drivers/xen/grant-dma-ops.c +index daa525df7bdc5..1e797a043980a 100644 +--- a/drivers/xen/grant-dma-ops.c ++++ b/drivers/xen/grant-dma-ops.c +@@ -292,50 +292,20 @@ static const struct dma_map_ops xen_grant_dma_ops = { + .dma_supported = xen_grant_dma_supported, + }; + +-static bool xen_is_dt_grant_dma_device(struct device *dev) +-{ +- struct device_node *iommu_np; +- bool has_iommu; +- +- iommu_np = of_parse_phandle(dev->of_node, "iommus", 0); +- has_iommu = iommu_np && +- of_device_is_compatible(iommu_np, "xen,grant-dma"); +- of_node_put(iommu_np); +- +- return has_iommu; +-} +- +-bool xen_is_grant_dma_device(struct device *dev) +-{ +- /* XXX Handle only DT devices for now */ +- if (dev->of_node) +- return xen_is_dt_grant_dma_device(dev); +- +- return false; +-} +- +-bool xen_virtio_mem_acc(struct virtio_device *dev) +-{ +- if (IS_ENABLED(CONFIG_XEN_VIRTIO_FORCE_GRANT) || xen_pv_domain()) +- return true; +- +- return xen_is_grant_dma_device(dev->dev.parent); +-} +- + static int xen_dt_grant_init_backend_domid(struct device *dev, +- struct xen_grant_dma_data *data) ++ domid_t *backend_domid) + { + struct of_phandle_args iommu_spec; + + if (of_parse_phandle_with_args(dev->of_node, "iommus", "#iommu-cells", + 0, &iommu_spec)) { +- dev_err(dev, "Cannot parse iommus property\n"); ++ dev_dbg(dev, "Cannot parse iommus property\n"); + return -ESRCH; + } + + if (!of_device_is_compatible(iommu_spec.np, "xen,grant-dma") || + iommu_spec.args_count != 1) { +- dev_err(dev, "Incompatible IOMMU node\n"); ++ dev_dbg(dev, "Incompatible IOMMU node\n"); + of_node_put(iommu_spec.np); + return -ESRCH; + } +@@ -346,12 +316,28 @@ static int xen_dt_grant_init_backend_domid(struct device *dev, + * The endpoint ID here means the ID of the domain where the + * corresponding backend is running + */ +- data->backend_domid = iommu_spec.args[0]; ++ *backend_domid = iommu_spec.args[0]; + + return 0; + } + +-void xen_grant_setup_dma_ops(struct device *dev) ++static int xen_grant_init_backend_domid(struct device *dev, ++ domid_t *backend_domid) ++{ ++ int ret = -ENODEV; ++ ++ if (dev->of_node) { ++ ret = xen_dt_grant_init_backend_domid(dev, backend_domid); ++ } else if (IS_ENABLED(CONFIG_XEN_VIRTIO_FORCE_GRANT) || xen_pv_domain()) { ++ dev_info(dev, "Using dom0 as backend\n"); ++ *backend_domid = 0; ++ ret = 0; ++ } ++ ++ return ret; ++} ++ ++static void xen_grant_setup_dma_ops(struct device *dev, domid_t backend_domid) + { + struct xen_grant_dma_data *data; + +@@ -365,16 +351,7 @@ void xen_grant_setup_dma_ops(struct device *dev) + if (!data) + goto err; + +- if (dev->of_node) { +- if (xen_dt_grant_init_backend_domid(dev, data)) +- goto err; +- } else if (IS_ENABLED(CONFIG_XEN_VIRTIO_FORCE_GRANT)) { +- dev_info(dev, "Using dom0 as backend\n"); +- data->backend_domid = 0; +- } else { +- /* XXX ACPI device unsupported for now */ +- goto err; +- } ++ data->backend_domid = backend_domid; + + if (store_xen_grant_dma_data(dev, data)) { + dev_err(dev, "Cannot store Xen grant DMA data\n"); +@@ -392,12 +369,14 @@ void xen_grant_setup_dma_ops(struct device *dev) + + bool xen_virtio_restricted_mem_acc(struct virtio_device *dev) + { +- bool ret = xen_virtio_mem_acc(dev); ++ domid_t backend_domid; + +- if (ret) +- xen_grant_setup_dma_ops(dev->dev.parent); ++ if (!xen_grant_init_backend_domid(dev->dev.parent, &backend_domid)) { ++ xen_grant_setup_dma_ops(dev->dev.parent, backend_domid); ++ return true; ++ } + +- return ret; ++ return false; + } + + MODULE_DESCRIPTION("Xen grant DMA-mapping layer"); +diff --git a/include/xen/arm/xen-ops.h b/include/xen/arm/xen-ops.h +index b0766a660338f..70073f5a2b545 100644 +--- a/include/xen/arm/xen-ops.h ++++ b/include/xen/arm/xen-ops.h +@@ -8,9 +8,7 @@ + static inline void xen_setup_dma_ops(struct device *dev) + { + #ifdef CONFIG_XEN +- if (xen_is_grant_dma_device(dev)) +- xen_grant_setup_dma_ops(dev); +- else if (xen_swiotlb_detect()) ++ if (xen_swiotlb_detect()) + dev->dma_ops = &xen_swiotlb_dma_ops; + #endif + } +diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h +index a34f4271a2e9f..47f11bec5e90c 100644 +--- a/include/xen/xen-ops.h ++++ b/include/xen/xen-ops.h +@@ -216,26 +216,10 @@ static inline void xen_preemptible_hcall_end(void) { } + #endif /* CONFIG_XEN_PV && !CONFIG_PREEMPTION */ + + #ifdef CONFIG_XEN_GRANT_DMA_OPS +-void xen_grant_setup_dma_ops(struct device *dev); +-bool xen_is_grant_dma_device(struct device *dev); +-bool xen_virtio_mem_acc(struct virtio_device *dev); + bool xen_virtio_restricted_mem_acc(struct virtio_device *dev); + #else +-static inline void xen_grant_setup_dma_ops(struct device *dev) +-{ +-} +-static inline bool xen_is_grant_dma_device(struct device *dev) +-{ +- return false; +-} +- + struct virtio_device; + +-static inline bool xen_virtio_mem_acc(struct virtio_device *dev) +-{ +- return false; +-} +- + static inline bool xen_virtio_restricted_mem_acc(struct virtio_device *dev) + { + return false; +-- +2.51.0 + diff --git a/queue-6.1/xfrm-fix-ip_rt_bug-race-in-icmp_route_lookup-reverse.patch b/queue-6.1/xfrm-fix-ip_rt_bug-race-in-icmp_route_lookup-reverse.patch new file mode 100644 index 0000000000..dec1960e29 --- /dev/null +++ b/queue-6.1/xfrm-fix-ip_rt_bug-race-in-icmp_route_lookup-reverse.patch @@ -0,0 +1,100 @@ +From a1dc865afe6902f239eb026659bc76c39e931371 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 13:02:19 +0800 +Subject: xfrm: fix ip_rt_bug race in icmp_route_lookup reverse path + +From: Jiayuan Chen + +[ Upstream commit 81b84de32bb27ae1ae2eb9acf0420e9d0d14bf00 ] + +icmp_route_lookup() performs multiple route lookups to find a suitable +route for sending ICMP error messages, with special handling for XFRM +(IPsec) policies. + +The lookup sequence is: +1. First, lookup output route for ICMP reply (dst = original src) +2. Pass through xfrm_lookup() for policy check +3. If blocked (-EPERM) or dst is not local, enter "reverse path" +4. In reverse path, call xfrm_decode_session_reverse() to get fl4_dec + which reverses the original packet's flow (saddr<->daddr swapped) +5. If fl4_dec.saddr is local (we are the original destination), use + __ip_route_output_key() for output route lookup +6. If fl4_dec.saddr is NOT local (we are a forwarding node), use + ip_route_input() to simulate the reverse packet's input path +7. Finally, pass rt2 through xfrm_lookup() with XFRM_LOOKUP_ICMP flag + +The bug occurs in step 6: ip_route_input() is called with fl4_dec.daddr +(original packet's source) as destination. If this address becomes local +between the initial check and ip_route_input() call (e.g., due to +concurrent "ip addr add"), ip_route_input() returns a LOCAL route with +dst.output set to ip_rt_bug. + +This route is then used for ICMP output, causing dst_output() to call +ip_rt_bug(), triggering a WARN_ON: + + ------------[ cut here ]------------ + WARNING: net/ipv4/route.c:1275 at ip_rt_bug+0x21/0x30, CPU#1 + Call Trace: + + ip_push_pending_frames+0x202/0x240 + icmp_push_reply+0x30d/0x430 + __icmp_send+0x1149/0x24f0 + ip_options_compile+0xa2/0xd0 + ip_rcv_finish_core+0x829/0x1950 + ip_rcv+0x2d7/0x420 + __netif_receive_skb_one_core+0x185/0x1f0 + netif_receive_skb+0x90/0x450 + tun_get_user+0x3413/0x3fb0 + tun_chr_write_iter+0xe4/0x220 + ... + +Fix this by checking rt2->rt_type after ip_route_input(). If it's +RTN_LOCAL, the route cannot be used for output, so treat it as an error. + +The reproducer requires kernel modification to widen the race window, +making it unsuitable as a selftest. It is available at: + + https://gist.github.com/mrpre/eae853b72ac6a750f5d45d64ddac1e81 + +Reported-by: syzbot+e738404dcd14b620923c@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/000000000000b1060905eada8881@google.com/T/ +Closes: https://lore.kernel.org/r/20260128090523.356953-1-jiayuan.chen@linux.dev +Fixes: 8b7817f3a959 ("[IPSEC]: Add ICMP host relookup support") +Signed-off-by: Jiayuan Chen +Signed-off-by: Jiayuan Chen +Link: https://patch.msgid.link/20260206050220.59642-1-jiayuan.chen@linux.dev +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/ipv4/icmp.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c +index 9e1a574384aa6..56b240e7f083c 100644 +--- a/net/ipv4/icmp.c ++++ b/net/ipv4/icmp.c +@@ -555,6 +555,21 @@ static struct rtable *icmp_route_lookup(struct net *net, struct flowi4 *fl4, + /* steal dst entry from skb_in, don't drop refcnt */ + skb_dstref_steal(skb_in); + skb_dstref_restore(skb_in, orefdst); ++ ++ /* ++ * At this point, fl4_dec.daddr should NOT be local (we ++ * checked fl4_dec.saddr above). However, a race condition ++ * may occur if the address is added to the interface ++ * concurrently. In that case, ip_route_input() returns a ++ * LOCAL route with dst.output=ip_rt_bug, which must not ++ * be used for output. ++ */ ++ if (!err && rt2 && rt2->rt_type == RTN_LOCAL) { ++ net_warn_ratelimited("detected local route for %pI4 during ICMP sending, src %pI4\n", ++ &fl4_dec.daddr, &fl4_dec.saddr); ++ dst_release(&rt2->dst); ++ err = -EINVAL; ++ } + } + + if (err) +-- +2.51.0 + diff --git a/queue-6.12/acpica-fix-null-pointer-dereference-in-acpi_ev_addre.patch b/queue-6.12/acpica-fix-null-pointer-dereference-in-acpi_ev_addre.patch new file mode 100644 index 0000000000..9a2310511d --- /dev/null +++ b/queue-6.12/acpica-fix-null-pointer-dereference-in-acpi_ev_addre.patch @@ -0,0 +1,40 @@ +From f6a86221cf406d0c62c071ee91ae089b0ec23f58 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 13:20:17 +0100 +Subject: ACPICA: Fix NULL pointer dereference in + acpi_ev_address_space_dispatch() + +From: Alexey Simakov + +[ Upstream commit f851e03bce968ff9b3faad1b616062e1244fd38d ] + +Cover a missed execution path with a new check. + +Fixes: 0acf24ad7e10 ("ACPICA: Add support for PCC Opregion special context data") +Link: https://github.com/acpica/acpica/commit/f421dd9dd897 +Signed-off-by: Alexey Simakov +Signed-off-by: Rafael J. Wysocki +Link: https://patch.msgid.link/3030574.e9J7NaK4W3@rafael.j.wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/acpica/evregion.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c +index cf53b9535f18e..7788c27ccf461 100644 +--- a/drivers/acpi/acpica/evregion.c ++++ b/drivers/acpi/acpica/evregion.c +@@ -163,7 +163,9 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, + return_ACPI_STATUS(AE_NOT_EXIST); + } + +- if (region_obj->region.space_id == ACPI_ADR_SPACE_PLATFORM_COMM) { ++ if (field_obj ++ && region_obj->region.space_id == ++ ACPI_ADR_SPACE_PLATFORM_COMM) { + struct acpi_pcc_info *ctx = + handler_desc->address_space.context; + +-- +2.51.0 + diff --git a/queue-6.12/alsa-pcm-relax-__free-variable-declarations.patch b/queue-6.12/alsa-pcm-relax-__free-variable-declarations.patch new file mode 100644 index 0000000000..52b332f0ee --- /dev/null +++ b/queue-6.12/alsa-pcm-relax-__free-variable-declarations.patch @@ -0,0 +1,268 @@ +From e84bd81aca04466a65c1e209c5faed7f3ba16de7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Dec 2025 15:06:25 +0100 +Subject: ALSA: pcm: Relax __free() variable declarations + +From: Takashi Iwai + +[ Upstream commit f3d233daf011abbad2f6ebd0e545b42d2f378a4f ] + +We used to have a variable declaration with __free() initialized with +NULL. This was to keep the old coding style rule, but recently it's +relaxed and rather recommends to follow the new rule to declare in +place of use for __free() -- which avoids potential deadlocks or UAFs +with nested cleanups. + +Although the current code has no bug, per se, let's follow the new +standard and move the declaration to the place of assignment (or +directly assign the allocated result) instead of NULL initializations. + +Fixes: ae9213984864 ("ALSA: pcm: Use automatic cleanup of kfree()") +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20251216140634.171890-4-tiwai@suse.de +Signed-off-by: Sasha Levin +--- + sound/core/pcm.c | 4 ++-- + sound/core/pcm_compat.c | 9 ++++---- + sound/core/pcm_native.c | 50 +++++++++++++++++++++-------------------- + 3 files changed, 33 insertions(+), 30 deletions(-) + +diff --git a/sound/core/pcm.c b/sound/core/pcm.c +index 290690fc2abcb..ff1e9f8c1ecae 100644 +--- a/sound/core/pcm.c ++++ b/sound/core/pcm.c +@@ -328,13 +328,13 @@ static const char *snd_pcm_oss_format_name(int format) + static void snd_pcm_proc_info_read(struct snd_pcm_substream *substream, + struct snd_info_buffer *buffer) + { +- struct snd_pcm_info *info __free(kfree) = NULL; + int err; + + if (! substream) + return; + +- info = kmalloc(sizeof(*info), GFP_KERNEL); ++ struct snd_pcm_info *info __free(kfree) = ++ kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return; + +diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c +index a42ec7f5a1daf..c1c64da2eabd0 100644 +--- a/sound/core/pcm_compat.c ++++ b/sound/core/pcm_compat.c +@@ -235,7 +235,6 @@ static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream, + int refine, + struct snd_pcm_hw_params32 __user *data32) + { +- struct snd_pcm_hw_params *data __free(kfree) = NULL; + struct snd_pcm_runtime *runtime; + int err; + +@@ -243,7 +242,8 @@ static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream, + if (!runtime) + return -ENOTTY; + +- data = kmalloc(sizeof(*data), GFP_KERNEL); ++ struct snd_pcm_hw_params *data __free(kfree) = ++ kmalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + +@@ -332,7 +332,6 @@ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream, + compat_caddr_t buf; + compat_caddr_t __user *bufptr; + u32 frames; +- void __user **bufs __free(kfree) = NULL; + int err, ch, i; + + if (! substream->runtime) +@@ -349,7 +348,9 @@ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream, + get_user(frames, &data32->frames)) + return -EFAULT; + bufptr = compat_ptr(buf); +- bufs = kmalloc_array(ch, sizeof(void __user *), GFP_KERNEL); ++ ++ void __user **bufs __free(kfree) = ++ kmalloc_array(ch, sizeof(void __user *), GFP_KERNEL); + if (bufs == NULL) + return -ENOMEM; + for (i = 0; i < ch; i++) { +diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c +index f5a4541fbda00..fc400fa816ec6 100644 +--- a/sound/core/pcm_native.c ++++ b/sound/core/pcm_native.c +@@ -242,10 +242,10 @@ int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info) + int snd_pcm_info_user(struct snd_pcm_substream *substream, + struct snd_pcm_info __user * _info) + { +- struct snd_pcm_info *info __free(kfree) = NULL; + int err; ++ struct snd_pcm_info *info __free(kfree) = ++ kmalloc(sizeof(*info), GFP_KERNEL); + +- info = kmalloc(sizeof(*info), GFP_KERNEL); + if (! info) + return -ENOMEM; + err = snd_pcm_info(substream, info); +@@ -364,7 +364,6 @@ static int constrain_params_by_rules(struct snd_pcm_substream *substream, + struct snd_pcm_hw_constraints *constrs = + &substream->runtime->hw_constraints; + unsigned int k; +- unsigned int *rstamps __free(kfree) = NULL; + unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1]; + unsigned int stamp; + struct snd_pcm_hw_rule *r; +@@ -380,7 +379,8 @@ static int constrain_params_by_rules(struct snd_pcm_substream *substream, + * Each member of 'rstamps' array represents the sequence number of + * recent application of corresponding rule. + */ +- rstamps = kcalloc(constrs->rules_num, sizeof(unsigned int), GFP_KERNEL); ++ unsigned int *rstamps __free(kfree) = ++ kcalloc(constrs->rules_num, sizeof(unsigned int), GFP_KERNEL); + if (!rstamps) + return -ENOMEM; + +@@ -583,10 +583,10 @@ EXPORT_SYMBOL(snd_pcm_hw_refine); + static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params __user * _params) + { +- struct snd_pcm_hw_params *params __free(kfree) = NULL; + int err; ++ struct snd_pcm_hw_params *params __free(kfree) = ++ memdup_user(_params, sizeof(*params)); + +- params = memdup_user(_params, sizeof(*params)); + if (IS_ERR(params)) + return PTR_ERR(params); + +@@ -889,10 +889,10 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, + static int snd_pcm_hw_params_user(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params __user * _params) + { +- struct snd_pcm_hw_params *params __free(kfree) = NULL; + int err; ++ struct snd_pcm_hw_params *params __free(kfree) = ++ memdup_user(_params, sizeof(*params)); + +- params = memdup_user(_params, sizeof(*params)); + if (IS_ERR(params)) + return PTR_ERR(params); + +@@ -2267,7 +2267,6 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) + { + struct snd_pcm_file *pcm_file; + struct snd_pcm_substream *substream1; +- struct snd_pcm_group *group __free(kfree) = NULL; + struct snd_pcm_group *target_group; + bool nonatomic = substream->pcm->nonatomic; + CLASS(fd, f)(fd); +@@ -2283,7 +2282,8 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) + if (substream == substream1) + return -EINVAL; + +- group = kzalloc(sizeof(*group), GFP_KERNEL); ++ struct snd_pcm_group *group __free(kfree) = ++ kzalloc(sizeof(*group), GFP_KERNEL); + if (!group) + return -ENOMEM; + snd_pcm_group_init(group); +@@ -3265,7 +3265,6 @@ static int snd_pcm_xfern_frames_ioctl(struct snd_pcm_substream *substream, + { + struct snd_xfern xfern; + struct snd_pcm_runtime *runtime = substream->runtime; +- void *bufs __free(kfree) = NULL; + snd_pcm_sframes_t result; + + if (runtime->state == SNDRV_PCM_STATE_OPEN) +@@ -3277,7 +3276,8 @@ static int snd_pcm_xfern_frames_ioctl(struct snd_pcm_substream *substream, + if (copy_from_user(&xfern, _xfern, sizeof(xfern))) + return -EFAULT; + +- bufs = memdup_array_user(xfern.bufs, runtime->channels, sizeof(void *)); ++ void *bufs __free(kfree) = ++ memdup_array_user(xfern.bufs, runtime->channels, sizeof(void *)); + if (IS_ERR(bufs)) + return PTR_ERR(bufs); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) +@@ -3551,7 +3551,6 @@ static ssize_t snd_pcm_readv(struct kiocb *iocb, struct iov_iter *to) + struct snd_pcm_runtime *runtime; + snd_pcm_sframes_t result; + unsigned long i; +- void __user **bufs __free(kfree) = NULL; + snd_pcm_uframes_t frames; + const struct iovec *iov = iter_iov(to); + +@@ -3570,7 +3569,9 @@ static ssize_t snd_pcm_readv(struct kiocb *iocb, struct iov_iter *to) + if (!frame_aligned(runtime, iov->iov_len)) + return -EINVAL; + frames = bytes_to_samples(runtime, iov->iov_len); +- bufs = kmalloc_array(to->nr_segs, sizeof(void *), GFP_KERNEL); ++ ++ void __user **bufs __free(kfree) = ++ kmalloc_array(to->nr_segs, sizeof(void *), GFP_KERNEL); + if (bufs == NULL) + return -ENOMEM; + for (i = 0; i < to->nr_segs; ++i) { +@@ -3590,7 +3591,6 @@ static ssize_t snd_pcm_writev(struct kiocb *iocb, struct iov_iter *from) + struct snd_pcm_runtime *runtime; + snd_pcm_sframes_t result; + unsigned long i; +- void __user **bufs __free(kfree) = NULL; + snd_pcm_uframes_t frames; + const struct iovec *iov = iter_iov(from); + +@@ -3608,7 +3608,9 @@ static ssize_t snd_pcm_writev(struct kiocb *iocb, struct iov_iter *from) + !frame_aligned(runtime, iov->iov_len)) + return -EINVAL; + frames = bytes_to_samples(runtime, iov->iov_len); +- bufs = kmalloc_array(from->nr_segs, sizeof(void *), GFP_KERNEL); ++ ++ void __user **bufs __free(kfree) = ++ kmalloc_array(from->nr_segs, sizeof(void *), GFP_KERNEL); + if (bufs == NULL) + return -ENOMEM; + for (i = 0; i < from->nr_segs; ++i) { +@@ -4060,15 +4062,15 @@ static void snd_pcm_hw_convert_to_old_params(struct snd_pcm_hw_params_old *opara + static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params_old __user * _oparams) + { +- struct snd_pcm_hw_params *params __free(kfree) = NULL; +- struct snd_pcm_hw_params_old *oparams __free(kfree) = NULL; + int err; + +- params = kmalloc(sizeof(*params), GFP_KERNEL); ++ struct snd_pcm_hw_params *params __free(kfree) = ++ kmalloc(sizeof(*params), GFP_KERNEL); + if (!params) + return -ENOMEM; + +- oparams = memdup_user(_oparams, sizeof(*oparams)); ++ struct snd_pcm_hw_params_old *oparams __free(kfree) = ++ memdup_user(_oparams, sizeof(*oparams)); + if (IS_ERR(oparams)) + return PTR_ERR(oparams); + snd_pcm_hw_convert_from_old_params(params, oparams); +@@ -4089,15 +4091,15 @@ static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream, + static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params_old __user * _oparams) + { +- struct snd_pcm_hw_params *params __free(kfree) = NULL; +- struct snd_pcm_hw_params_old *oparams __free(kfree) = NULL; + int err; + +- params = kmalloc(sizeof(*params), GFP_KERNEL); ++ struct snd_pcm_hw_params *params __free(kfree) = ++ kmalloc(sizeof(*params), GFP_KERNEL); + if (!params) + return -ENOMEM; + +- oparams = memdup_user(_oparams, sizeof(*oparams)); ++ struct snd_pcm_hw_params_old *oparams __free(kfree) = ++ memdup_user(_oparams, sizeof(*oparams)); + if (IS_ERR(oparams)) + return PTR_ERR(oparams); + +-- +2.51.0 + diff --git a/queue-6.12/alsa-pcm-use-new-array-copying-wrapper.patch b/queue-6.12/alsa-pcm-use-new-array-copying-wrapper.patch new file mode 100644 index 0000000000..78af3f30fa --- /dev/null +++ b/queue-6.12/alsa-pcm-use-new-array-copying-wrapper.patch @@ -0,0 +1,44 @@ +From 6ee64cd7a64c84676fb786a55a85dd481b49a003 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jan 2025 10:06:55 -0600 +Subject: ALSA: pcm: use new array-copying-wrapper + +From: Chenyuan Yang + +[ Upstream commit 519b2b14bef70922bd64117a978ea7f2a683b75b ] + +This is found by our static analysis tool. + +pcm_native.c utilizes memdup_user() to copy an array from userspace. + +There is a new wrapper, specifically designed for copying arrays. Use +this one instead. + +This is similar to the +commit 3e91a38de1dc ("fbdev: viafb: use new array-copying-wrapper"). + +Signed-off-by: Chenyuan Yang +Link: https://patch.msgid.link/20250127160655.3119470-1-cy1yang@outlook.com +Signed-off-by: Takashi Iwai +Stable-dep-of: f3d233daf011 ("ALSA: pcm: Relax __free() variable declarations") +Signed-off-by: Sasha Levin +--- + sound/core/pcm_native.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c +index 6417178ca0978..f5a4541fbda00 100644 +--- a/sound/core/pcm_native.c ++++ b/sound/core/pcm_native.c +@@ -3277,7 +3277,7 @@ static int snd_pcm_xfern_frames_ioctl(struct snd_pcm_substream *substream, + if (copy_from_user(&xfern, _xfern, sizeof(xfern))) + return -EFAULT; + +- bufs = memdup_user(xfern.bufs, sizeof(void *) * runtime->channels); ++ bufs = memdup_array_user(xfern.bufs, runtime->channels, sizeof(void *)); + if (IS_ERR(bufs)) + return PTR_ERR(bufs); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) +-- +2.51.0 + diff --git a/queue-6.12/alsa-vmaster-relax-__free-variable-declarations.patch b/queue-6.12/alsa-vmaster-relax-__free-variable-declarations.patch new file mode 100644 index 0000000000..9d740f9a76 --- /dev/null +++ b/queue-6.12/alsa-vmaster-relax-__free-variable-declarations.patch @@ -0,0 +1,77 @@ +From eb32fe0e6beb36399c60f730ab59948d5a20ed31 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Dec 2025 15:06:30 +0100 +Subject: ALSA: vmaster: Relax __free() variable declarations + +From: Takashi Iwai + +[ Upstream commit 3b7c7bda39e1e48f926fb3d280a5f5d20a939857 ] + +We used to have a variable declaration with __free() initialized with +NULL. This was to keep the old coding style rule, but recently it's +relaxed and rather recommends to follow the new rule to declare in +place of use for __free() -- which avoids potential deadlocks or UAFs +with nested cleanups. + +Although the current code has no bug, per se, let's follow the new +standard and move the declaration to the place of assignment (or +directly assign the allocated result) instead of NULL initializations. + +Fixes: fb9e197f3f27 ("ALSA: vmaster: Use automatic cleanup of kfree()") +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20251216140634.171890-9-tiwai@suse.de +Signed-off-by: Sasha Levin +--- + sound/core/vmaster.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/sound/core/vmaster.c b/sound/core/vmaster.c +index c657659b236c4..76cc64245f5df 100644 +--- a/sound/core/vmaster.c ++++ b/sound/core/vmaster.c +@@ -56,10 +56,10 @@ struct link_follower { + + static int follower_update(struct link_follower *follower) + { +- struct snd_ctl_elem_value *uctl __free(kfree) = NULL; + int err, ch; ++ struct snd_ctl_elem_value *uctl __free(kfree) = ++ kzalloc(sizeof(*uctl), GFP_KERNEL); + +- uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); + if (!uctl) + return -ENOMEM; + uctl->id = follower->follower.id; +@@ -74,7 +74,6 @@ static int follower_update(struct link_follower *follower) + /* get the follower ctl info and save the initial values */ + static int follower_init(struct link_follower *follower) + { +- struct snd_ctl_elem_info *uinfo __free(kfree) = NULL; + int err; + + if (follower->info.count) { +@@ -84,7 +83,8 @@ static int follower_init(struct link_follower *follower) + return 0; + } + +- uinfo = kmalloc(sizeof(*uinfo), GFP_KERNEL); ++ struct snd_ctl_elem_info *uinfo __free(kfree) = ++ kmalloc(sizeof(*uinfo), GFP_KERNEL); + if (!uinfo) + return -ENOMEM; + uinfo->id = follower->follower.id; +@@ -341,9 +341,9 @@ static int master_get(struct snd_kcontrol *kcontrol, + static int sync_followers(struct link_master *master, int old_val, int new_val) + { + struct link_follower *follower; +- struct snd_ctl_elem_value *uval __free(kfree) = NULL; ++ struct snd_ctl_elem_value *uval __free(kfree) = ++ kmalloc(sizeof(*uval), GFP_KERNEL); + +- uval = kmalloc(sizeof(*uval), GFP_KERNEL); + if (!uval) + return -ENOMEM; + list_for_each_entry(follower, &master->followers, list) { +-- +2.51.0 + diff --git a/queue-6.12/arm-dts-allwinner-sun5i-a13-utoo-p66-delete-power-gp.patch b/queue-6.12/arm-dts-allwinner-sun5i-a13-utoo-p66-delete-power-gp.patch new file mode 100644 index 0000000000..528a7db264 --- /dev/null +++ b/queue-6.12/arm-dts-allwinner-sun5i-a13-utoo-p66-delete-power-gp.patch @@ -0,0 +1,46 @@ +From 983bf2e4bb93324c20b30fbeb25a710c306f8510 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 25 Dec 2025 18:36:14 +0800 +Subject: ARM: dts: allwinner: sun5i-a13-utoo-p66: delete "power-gpios" + property + +From: Chen-Yu Tsai + +[ Upstream commit 0b2761eb1287bd9f62367cccf6626eb3107cef6f ] + +The P66's device tree includes the reference design dtsi files, which +defines a node and properties for the touchpanel in the common design. +The P66 dts file then overrides all the properties to match its own +design, but as the touchpanel model is different, a different schema +is matched. This other schema uses a different name for the GPIO. + +The original submission added the correct GPIO property, but did not +delete the one inherited from the reference design, causing validation +errors. + +Explicitly delete the incorrect GPIO property. + +Fixes: 2a53aff27236 ("ARM: dts: sun5i: Enable touchscreen on Utoo P66") +Reviewed-by: Jernej Skrabec +Link: https://patch.msgid.link/20251225103616.3203473-4-wens@kernel.org +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Sasha Levin +--- + arch/arm/boot/dts/allwinner/sun5i-a13-utoo-p66.dts | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/boot/dts/allwinner/sun5i-a13-utoo-p66.dts b/arch/arm/boot/dts/allwinner/sun5i-a13-utoo-p66.dts +index be486d28d04fa..428cab5a0e906 100644 +--- a/arch/arm/boot/dts/allwinner/sun5i-a13-utoo-p66.dts ++++ b/arch/arm/boot/dts/allwinner/sun5i-a13-utoo-p66.dts +@@ -102,6 +102,7 @@ &touchscreen { + /* The P66 uses a different EINT then the reference design */ + interrupts = <6 9 IRQ_TYPE_EDGE_FALLING>; /* EINT9 (PG9) */ + /* The icn8318 binding expects wake-gpios instead of power-gpios */ ++ /delete-property/ power-gpios; + wake-gpios = <&pio 1 3 GPIO_ACTIVE_HIGH>; /* PB3 */ + touchscreen-size-x = <800>; + touchscreen-size-y = <480>; +-- +2.51.0 + diff --git a/queue-6.12/arm-dts-lpc32xx-add-clocks-property-to-motor-control.patch b/queue-6.12/arm-dts-lpc32xx-add-clocks-property-to-motor-control.patch new file mode 100644 index 0000000000..b72dbd719f --- /dev/null +++ b/queue-6.12/arm-dts-lpc32xx-add-clocks-property-to-motor-control.patch @@ -0,0 +1,35 @@ +From f7369c2f9202bf7e73a62de3cbf21196655e2e06 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Dec 2025 00:49:07 +0200 +Subject: arm: dts: lpc32xx: add clocks property to Motor Control PWM device + tree node + +From: Vladimir Zapolskiy + +[ Upstream commit 71630e581a0e34c03757f5c1706f57c853b92555 ] + +Motor Control PWM depends on its own supply clock, the clock gate control +is present in TIMCLK_CTRL1 register. + +Fixes: b7d41c937ed7 ("ARM: LPC32xx: Add the motor PWM to base dts file") +Signed-off-by: Vladimir Zapolskiy +Signed-off-by: Sasha Levin +--- + arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi +index 770e85b8268f3..7503074d2877c 100644 +--- a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi ++++ b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi +@@ -301,6 +301,7 @@ i2c2: i2c@400a8000 { + mpwm: mpwm@400e8000 { + compatible = "nxp,lpc3220-motor-pwm"; + reg = <0x400e8000 0x78>; ++ clocks = <&clk LPC32XX_CLK_MCPWM>; + #pwm-cells = <3>; + status = "disabled"; + }; +-- +2.51.0 + diff --git a/queue-6.12/arm-dts-lpc32xx-set-motor-pwm-pwm-cells-property-val.patch b/queue-6.12/arm-dts-lpc32xx-set-motor-pwm-pwm-cells-property-val.patch new file mode 100644 index 0000000000..491669cccb --- /dev/null +++ b/queue-6.12/arm-dts-lpc32xx-set-motor-pwm-pwm-cells-property-val.patch @@ -0,0 +1,47 @@ +From a781821bbf78e64e68f714d1751f7150960dd88d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Sep 2025 21:46:42 +0300 +Subject: ARM: dts: lpc32xx: Set motor PWM #pwm-cells property value to 3 cells +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Vladimir Zapolskiy + +[ Upstream commit 65ae9ea77e1f2a20ad2866f99596df7ccdbd3b95 ] + +Since commit 4cd2f417a0ac ("dt-bindings: pwm: Convert lpc32xx-pwm.txt +to yaml format") both types of PWM controlles on NXP LPC32xx SoC +fairly gained 3 cells, reflect it in the platform dtsi file. + +The change removes a dt binding checker warning: + + mpwm@400e8000: #pwm-cells:0:0: 3 was expected + +Cc: Uwe Kleine-König +Acked-by: Uwe Kleine-König +Reviewed-by: Frank Li +Signed-off-by: Vladimir Zapolskiy +Stable-dep-of: 71630e581a0e ("arm: dts: lpc32xx: add clocks property to Motor Control PWM device tree node") +Signed-off-by: Sasha Levin +--- + arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi +index 974410918f35b..770e85b8268f3 100644 +--- a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi ++++ b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi +@@ -301,8 +301,8 @@ i2c2: i2c@400a8000 { + mpwm: mpwm@400e8000 { + compatible = "nxp,lpc3220-motor-pwm"; + reg = <0x400e8000 0x78>; ++ #pwm-cells = <3>; + status = "disabled"; +- #pwm-cells = <2>; + }; + }; + +-- +2.51.0 + diff --git a/queue-6.12/arm-vdso-patch-out-__vdso_clock_getres-if-unavailabl.patch b/queue-6.12/arm-vdso-patch-out-__vdso_clock_getres-if-unavailabl.patch new file mode 100644 index 0000000000..475f1270e8 --- /dev/null +++ b/queue-6.12/arm-vdso-patch-out-__vdso_clock_getres-if-unavailabl.patch @@ -0,0 +1,39 @@ +From 0ec8d03a42d73982b27b8a8d03f6159c1de54b97 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 23 Dec 2025 07:59:17 +0100 +Subject: ARM: VDSO: Patch out __vdso_clock_getres() if unavailable +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh + +[ Upstream commit b9fecf0dddfc55cd7d02b0011494da3c613f7cde ] + +The vDSO code hides symbols which are non-functional. +__vdso_clock_getres() was not added to this list when it got introduced. + +Fixes: 052e76a31b4a ("ARM: 8931/1: Add clock_getres entry point") +Signed-off-by: Thomas Weißschuh +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20251223-vdso-compat-time32-v1-6-97ea7a06a543@linutronix.de +Signed-off-by: Sasha Levin +--- + arch/arm/kernel/vdso.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/kernel/vdso.c b/arch/arm/kernel/vdso.c +index d499ad461b004..6e5494bf5a24d 100644 +--- a/arch/arm/kernel/vdso.c ++++ b/arch/arm/kernel/vdso.c +@@ -172,6 +172,7 @@ static void __init patch_vdso(void *ehdr) + vdso_nullpatch_one(&einfo, "__vdso_gettimeofday"); + vdso_nullpatch_one(&einfo, "__vdso_clock_gettime"); + vdso_nullpatch_one(&einfo, "__vdso_clock_gettime64"); ++ vdso_nullpatch_one(&einfo, "__vdso_clock_getres"); + } + } + +-- +2.51.0 + diff --git a/queue-6.12/arm64-dts-amlogic-axg-assign-the-mmc-signal-clocks.patch b/queue-6.12/arm64-dts-amlogic-axg-assign-the-mmc-signal-clocks.patch new file mode 100644 index 0000000000..8c9d26d21e --- /dev/null +++ b/queue-6.12/arm64-dts-amlogic-axg-assign-the-mmc-signal-clocks.patch @@ -0,0 +1,52 @@ +From a4d5df006632ece85fcb00cce3b6288616272aed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:08:50 +0100 +Subject: arm64: dts: amlogic: axg: assign the MMC signal clocks + +From: Jerome Brunet + +[ Upstream commit 13d3fe2318ef6e46d6fcfe13bc373827fdf2aeac ] + +The amlogic MMC driver operate with the assumption that MMC clock +is configured to provide 24MHz. It uses this path for low +rates such as 400kHz. + +Assign the clocks to make sure they are properly configured + +Fixes: 221cf34bac54 ("ARM64: dts: meson-axg: enable the eMMC controller") +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Link: https://patch.msgid.link/20260114-amlogic-mmc-clocks-followup-v1-3-a999fafbe0aa@baylibre.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-axg.dtsi | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi +index e9b22868983db..4717c9666f2a5 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi +@@ -1923,6 +1923,9 @@ sd_emmc_b: mmc@5000 { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_B>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_B_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + sd_emmc_c: mmc@7000 { +@@ -1935,6 +1938,9 @@ sd_emmc_c: mmc@7000 { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_C>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_C_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + nfc: nand-controller@7800 { +-- +2.51.0 + diff --git a/queue-6.12/arm64-dts-amlogic-c3-assign-the-mmc-signal-clocks.patch b/queue-6.12/arm64-dts-amlogic-c3-assign-the-mmc-signal-clocks.patch new file mode 100644 index 0000000000..3db3c264e6 --- /dev/null +++ b/queue-6.12/arm64-dts-amlogic-c3-assign-the-mmc-signal-clocks.patch @@ -0,0 +1,53 @@ +From 082e86b611407bdd6a91df0287ee398ccfce5bba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:08:48 +0100 +Subject: arm64: dts: amlogic: c3: assign the MMC signal clocks + +From: Jerome Brunet + +[ Upstream commit 69330fd2368371c4eb47d60ace6bca09763d24a0 ] + +The amlogic MMC driver operate with the assumption that MMC clock +is configured to provide 24MHz. It uses this path for low +rates such as 400kHz. + +Assign the clocks to make sure they are properly configured + +Fixes: 520b792e8317 ("arm64: dts: amlogic: add some device nodes for C3") +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Link: https://patch.msgid.link/20260114-amlogic-mmc-clocks-followup-v1-1-a999fafbe0aa@baylibre.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi b/arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi +index d0cda759c25d0..edd92500ebc96 100644 +--- a/arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi ++++ b/arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi +@@ -570,6 +570,10 @@ sdio: mmc@88000 { + no-sd; + resets = <&reset RESET_SD_EMMC_A>; + status = "disabled"; ++ ++ assigned-clocks = <&clkc_periphs CLKID_SD_EMMC_A>; ++ assigned-clock-rates = <24000000>; ++ + }; + + sd: mmc@8a000 { +@@ -585,6 +589,9 @@ sd: mmc@8a000 { + no-sdio; + resets = <&reset RESET_SD_EMMC_B>; + status = "disabled"; ++ ++ assigned-clocks = <&clkc_periphs CLKID_SD_EMMC_B>; ++ assigned-clock-rates = <24000000>; + }; + + nand: nand-controller@8d000 { +-- +2.51.0 + diff --git a/queue-6.12/arm64-dts-amlogic-g12-assign-the-mmc-a-signal-clock.patch b/queue-6.12/arm64-dts-amlogic-g12-assign-the-mmc-a-signal-clock.patch new file mode 100644 index 0000000000..c30a2b9d02 --- /dev/null +++ b/queue-6.12/arm64-dts-amlogic-g12-assign-the-mmc-a-signal-clock.patch @@ -0,0 +1,42 @@ +From 028fd316ff518c8031b4c35263c02fbbaea910ca Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:08:53 +0100 +Subject: arm64: dts: amlogic: g12: assign the MMC A signal clock + +From: Jerome Brunet + +[ Upstream commit 3c941feaa363f1573a501452391ddf513394c84b ] + +The amlogic MMC driver operate with the assumption that MMC clock +is configured to provide 24MHz. It uses this path for low +rates such as 400kHz. + +Assign the clock to make sure it is properly configured + +Fixes: 8a6b3ca2d361 ("arm64: dts: meson: g12a: add SDIO controller") +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Link: https://patch.msgid.link/20260114-amlogic-mmc-clocks-followup-v1-6-a999fafbe0aa@baylibre.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +index c3a718de85c6d..e0ddb28a34c29 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +@@ -2408,6 +2408,9 @@ sd_emmc_a: mmc@ffe03000 { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_A>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_A_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + sd_emmc_b: mmc@ffe05000 { +-- +2.51.0 + diff --git a/queue-6.12/arm64-dts-amlogic-g12-assign-the-mmc-b-and-c-signal-.patch b/queue-6.12/arm64-dts-amlogic-g12-assign-the-mmc-b-and-c-signal-.patch new file mode 100644 index 0000000000..eeeac5d3e4 --- /dev/null +++ b/queue-6.12/arm64-dts-amlogic-g12-assign-the-mmc-b-and-c-signal-.patch @@ -0,0 +1,52 @@ +From f60ad9e5356734e85415c33ee2bc453e50b58b84 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:08:52 +0100 +Subject: arm64: dts: amlogic: g12: assign the MMC B and C signal clocks + +From: Jerome Brunet + +[ Upstream commit be2ff5fdb0e83e32d4ec4e68a69875cec0d14621 ] + +The amlogic MMC driver operate with the assumption that MMC clock +is configured to provide 24MHz. It uses this path for low +rates such as 400kHz. + +Assign the clocks to make sure they are properly configured + +Fixes: 4759fd87b928 ("arm64: dts: meson: g12a: add mmc nodes") +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Link: https://patch.msgid.link/20260114-amlogic-mmc-clocks-followup-v1-5-a999fafbe0aa@baylibre.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +index d08c97797010d..c3a718de85c6d 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +@@ -2420,6 +2420,9 @@ sd_emmc_b: mmc@ffe05000 { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_B>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_B_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + sd_emmc_c: mmc@ffe07000 { +@@ -2432,6 +2435,9 @@ sd_emmc_c: mmc@ffe07000 { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_C>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_C_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + usb: usb@ffe09000 { +-- +2.51.0 + diff --git a/queue-6.12/arm64-dts-amlogic-gx-assign-the-mmc-signal-clocks.patch b/queue-6.12/arm64-dts-amlogic-gx-assign-the-mmc-signal-clocks.patch new file mode 100644 index 0000000000..700522165a --- /dev/null +++ b/queue-6.12/arm64-dts-amlogic-gx-assign-the-mmc-signal-clocks.patch @@ -0,0 +1,97 @@ +From f635cdf0f2425880dd19945e937a7f8773fa4831 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:08:51 +0100 +Subject: arm64: dts: amlogic: gx: assign the MMC signal clocks + +From: Jerome Brunet + +[ Upstream commit 406706559046eebc09a31e8ae5e78620bfd746fe ] + +The amlogic MMC driver operate with the assumption that MMC clock +is configured to provide 24MHz. It uses this path for low +rates such as 400kHz. + +Assign the clocks to make sure they are properly configured + +Fixes: 50662499f911 ("ARM64: dts: meson-gx: Use correct mmc clock source 0") +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Link: https://patch.msgid.link/20260114-amlogic-mmc-clocks-followup-v1-4-a999fafbe0aa@baylibre.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 9 +++++++++ + arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 9 +++++++++ + 2 files changed, 18 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi +index ed00e67e6923a..851ae89dd17fa 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi +@@ -799,6 +799,9 @@ &sd_emmc_a { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_A>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_A_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &sd_emmc_b { +@@ -807,6 +810,9 @@ &sd_emmc_b { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_B>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_B_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &sd_emmc_c { +@@ -815,6 +821,9 @@ &sd_emmc_c { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_C>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_C_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &simplefb_hdmi { +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi +index f58d1790de1cb..f7fafebafd809 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi +@@ -869,6 +869,9 @@ &sd_emmc_a { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_A>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_A_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &sd_emmc_b { +@@ -877,6 +880,9 @@ &sd_emmc_b { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_B>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_B_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &sd_emmc_c { +@@ -885,6 +891,9 @@ &sd_emmc_c { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_C>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_C_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &simplefb_hdmi { +-- +2.51.0 + diff --git a/queue-6.12/arm64-dts-amlogic-s4-assign-mmc-b-clock-to-24mhz.patch b/queue-6.12/arm64-dts-amlogic-s4-assign-mmc-b-clock-to-24mhz.patch new file mode 100644 index 0000000000..7485c22818 --- /dev/null +++ b/queue-6.12/arm64-dts-amlogic-s4-assign-mmc-b-clock-to-24mhz.patch @@ -0,0 +1,51 @@ +From 78a558eec4d70b056283caf77e0c94bcc2808402 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 11:43:11 +0100 +Subject: arm64: dts: amlogic: s4: assign mmc b clock to 24MHz + +From: Jerome Brunet + +[ Upstream commit 86124a8becb43eed3103f2459399daee8af2c99d ] + +The amlogic MMC driver operate with the assumption that MMC clock +is configured to provide 24MHz. It uses this path for low +rates such as 400kHz. + +This assumption did hold true until but it now, but it is apparently +not the case with s4. The clock has been reported to provide 1GHz +instead. This is most likely due to how the bootloader is using the MMC +clock on this platform. + +Regardless of why the MMC clock rate is 1GHz, if the MMC driver expects +24MHz, the clock should be properly assigned, so assign it. + +Reported-by: Nick Xie +Closes: https://lore.kernel.org/linux-amlogic/20260113011931.40424-1-nick@khadas.com/ +Fixes: 3ab9d54b5d84 ("arm64: dts: amlogic: enable some device nodes for S4") +Tested-by: Nick Xie +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Link: https://patch.msgid.link/20260114-amlogic-s4-mmc-fixup-v3-1-a4d3e136b3f2@baylibre.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-s4.dtsi | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-s4.dtsi b/arch/arm64/boot/dts/amlogic/meson-s4.dtsi +index 957577d986c06..4c45fd98381e8 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-s4.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-s4.dtsi +@@ -833,6 +833,9 @@ sd: mmc@fe08a000 { + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_B>; + status = "disabled"; ++ ++ assigned-clocks = <&clkc_periphs CLKID_SD_EMMC_B>; ++ assigned-clock-rates = <24000000>; + }; + + emmc: mmc@fe08c000 { +-- +2.51.0 + diff --git a/queue-6.12/arm64-dts-amlogic-s4-fix-mmc-clock-assignment.patch b/queue-6.12/arm64-dts-amlogic-s4-fix-mmc-clock-assignment.patch new file mode 100644 index 0000000000..df5d3bc42c --- /dev/null +++ b/queue-6.12/arm64-dts-amlogic-s4-fix-mmc-clock-assignment.patch @@ -0,0 +1,70 @@ +From d9a00a69b46d0b6d717bdfa92b770962ae7f9be5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 11:43:12 +0100 +Subject: arm64: dts: amlogic: s4: fix mmc clock assignment + +From: Jerome Brunet + +[ Upstream commit 3a115d42922cffc91b303992eadf220111d66c31 ] + +MMC A and C are mis-represented as having their "clkin0" input connected to +xtal while it is actually connected to the MMC clock, probably in an +attempt to provide 24MHz to the device on this input. + +Fix this and assign the clock to 24MHz to actually provide the required +rate. + +Fixes: 3ab9d54b5d84 ("arm64: dts: amlogic: enable some device nodes for S4") +Tested-by: Nick Xie +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Link: https://patch.msgid.link/20260114-amlogic-s4-mmc-fixup-v3-2-a4d3e136b3f2@baylibre.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-s4.dtsi | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-s4.dtsi b/arch/arm64/boot/dts/amlogic/meson-s4.dtsi +index 4c45fd98381e8..7326aaa8d0ed7 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-s4.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-s4.dtsi +@@ -814,13 +814,16 @@ sdio: mmc@fe088000 { + reg = <0x0 0xfe088000 0x0 0x800>; + interrupts = ; + clocks = <&clkc_periphs CLKID_SDEMMC_A>, +- <&xtal>, ++ <&clkc_periphs CLKID_SD_EMMC_A>, + <&clkc_pll CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_A>; + cap-sdio-irq; + keep-power-in-suspend; + status = "disabled"; ++ ++ assigned-clocks = <&clkc_periphs CLKID_SD_EMMC_A>; ++ assigned-clock-rates = <24000000>; + }; + + sd: mmc@fe08a000 { +@@ -843,13 +846,16 @@ emmc: mmc@fe08c000 { + reg = <0x0 0xfe08c000 0x0 0x800>; + interrupts = ; + clocks = <&clkc_periphs CLKID_NAND>, +- <&xtal>, ++ <&clkc_periphs CLKID_SD_EMMC_C>, + <&clkc_pll CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_NAND_EMMC>; + no-sdio; + no-sd; + status = "disabled"; ++ ++ assigned-clocks = <&clkc_periphs CLKID_SD_EMMC_C>; ++ assigned-clock-rates = <24000000>; + }; + }; + }; +-- +2.51.0 + diff --git a/queue-6.12/arm64-dts-mediatek-mt8183-jacuzzi-pico6-fix-typo-in-.patch b/queue-6.12/arm64-dts-mediatek-mt8183-jacuzzi-pico6-fix-typo-in-.patch new file mode 100644 index 0000000000..ecdcb9ef5d --- /dev/null +++ b/queue-6.12/arm64-dts-mediatek-mt8183-jacuzzi-pico6-fix-typo-in-.patch @@ -0,0 +1,36 @@ +From 3da4a144a35aa29aa03e17c6026a780dfa56d854 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 12:47:41 +0100 +Subject: arm64: dts: mediatek: mt8183-jacuzzi-pico6: Fix typo in pinmux node + +From: AngeloGioacchino Del Regno + +[ Upstream commit b1fc81a986c9b8089db31e21a372cc8b6514e900 ] + +Rename "piins-bt-wakeup" to "pins-bt-wakeup" to fix a dtbs_check +warning happening due to this typo. + +Fixes: 055ef10ccdd4 ("arm64: dts: mt8183: Add jacuzzi pico/pico6 board") +Reviewed-by: Chen-Yu Tsai +Signed-off-by: AngeloGioacchino Del Regno +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-pico6.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-pico6.dts b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-pico6.dts +index cce326aec1aa5..40af5656d6f15 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-pico6.dts ++++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-pico6.dts +@@ -91,7 +91,7 @@ bluetooth@2 { + + &pio { + bt_pins_wakeup: bt-pins-wakeup { +- piins-bt-wakeup { ++ pins-bt-wakeup { + pinmux = ; + input-enable; + }; +-- +2.51.0 + diff --git a/queue-6.12/arm64-dts-qcom-agatti-add-cx_mem-dbgc-gpu-regions.patch b/queue-6.12/arm64-dts-qcom-agatti-add-cx_mem-dbgc-gpu-regions.patch new file mode 100644 index 0000000000..6df7d29ceb --- /dev/null +++ b/queue-6.12/arm64-dts-qcom-agatti-add-cx_mem-dbgc-gpu-regions.patch @@ -0,0 +1,49 @@ +From d5b724ba3889ddd8d73f995bb1af4067194279e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Dec 2025 21:47:40 +0100 +Subject: arm64: dts: qcom: agatti: Add CX_MEM/DBGC GPU regions + +From: Konrad Dybcio + +[ Upstream commit 0fdcc948929a6d673bd0f90631dd6e42090c3dbd ] + +Describe the GPU register regions, with the former existing but not +being used much if at all on this silicon, and the latter containing +various debugging levers generally related to dumping the state of +the IP upon a crash. + +Fixes: 4faeef52c8e6 ("arm64: dts: qcom: qcm2290: Add GPU nodes") +Reported-by: Krzysztof Kozlowski +Closes: https://lore.kernel.org/linux-arm-msm/8a64f70b-8034-45e7-86a3-0015cf357132@oss.qualcomm.com/T/#m404f1425c36b61467760f058b696b8910340a063 +Signed-off-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Akhil P Oommen +Link: https://lore.kernel.org/r/20251229-topic-6115_2290_gpu_dbgc-v1-2-4a24d196389c@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/qcm2290.dtsi | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/qcm2290.dtsi b/arch/arm64/boot/dts/qcom/qcm2290.dtsi +index e75e6354b2d52..dbc78b2d5095a 100644 +--- a/arch/arm64/boot/dts/qcom/qcm2290.dtsi ++++ b/arch/arm64/boot/dts/qcom/qcm2290.dtsi +@@ -1434,8 +1434,12 @@ usb_dwc3_ss: endpoint { + + gpu: gpu@5900000 { + compatible = "qcom,adreno-07000200", "qcom,adreno"; +- reg = <0x0 0x05900000 0x0 0x40000>; +- reg-names = "kgsl_3d0_reg_memory"; ++ reg = <0x0 0x05900000 0x0 0x40000>, ++ <0x0 0x0599e000 0x0 0x1000>, ++ <0x0 0x05961000 0x0 0x800>; ++ reg-names = "kgsl_3d0_reg_memory", ++ "cx_mem", ++ "cx_dbgc"; + + interrupts = ; + +-- +2.51.0 + diff --git a/queue-6.12/arm64-dts-qcom-msm8994-octagon-fix-analog-devices-ve.patch b/queue-6.12/arm64-dts-qcom-msm8994-octagon-fix-analog-devices-ve.patch new file mode 100644 index 0000000000..84f7a8f794 --- /dev/null +++ b/queue-6.12/arm64-dts-qcom-msm8994-octagon-fix-analog-devices-ve.patch @@ -0,0 +1,43 @@ +From e91520cab6687c9721bfb07fdc35b3f2cda77d96 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Dec 2025 02:39:23 +0200 +Subject: arm64: dts: qcom: msm8994-octagon: Fix Analog Devices vendor prefix + of AD7147 + +From: Vladimir Zapolskiy + +[ Upstream commit 7db5fbe508deedec6c183d5056cf3c504c027f40 ] + +Trivial change, Analog Devices vendor prefix is "adi", but there is +a valid "ad" vendor prefix of another company, this may explain why +the issue hasn't been discovered by the automatic tests. + +A problem of not described compatible value is out of this change scope. + +Fixes: c636eeb751f6 ("arm64: dts: qcom: msm8994-octagon: Add AD7147 and APDS9930 sensors") +Signed-off-by: Vladimir Zapolskiy +Reviewed-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20251226003923.3341904-1-vladimir.zapolskiy@linaro.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/msm8994-msft-lumia-octagon.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/msm8994-msft-lumia-octagon.dtsi b/arch/arm64/boot/dts/qcom/msm8994-msft-lumia-octagon.dtsi +index 10cd244dea4f7..ef8dfce8d9b2d 100644 +--- a/arch/arm64/boot/dts/qcom/msm8994-msft-lumia-octagon.dtsi ++++ b/arch/arm64/boot/dts/qcom/msm8994-msft-lumia-octagon.dtsi +@@ -378,7 +378,7 @@ &blsp2_i2c1 { + status = "okay"; + + sideinteraction: touch@2c { +- compatible = "ad,ad7147_captouch"; ++ compatible = "adi,ad7147_captouch"; + reg = <0x2c>; + + pinctrl-names = "default", "sleep"; +-- +2.51.0 + diff --git a/queue-6.12/arm64-dts-qcom-qrb4210-rb2-fix-uart3-wakeup-irq-stor.patch b/queue-6.12/arm64-dts-qcom-qrb4210-rb2-fix-uart3-wakeup-irq-stor.patch new file mode 100644 index 0000000000..8a843c94f5 --- /dev/null +++ b/queue-6.12/arm64-dts-qcom-qrb4210-rb2-fix-uart3-wakeup-irq-stor.patch @@ -0,0 +1,43 @@ +From 716d222a56b905d984465227d1d11dc646f52b10 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Jan 2026 03:01:16 +0200 +Subject: arm64: dts: qcom: qrb4210-rb2: Fix UART3 wakeup IRQ storm + +From: Dmitry Baryshkov + +[ Upstream commit c5dc4812f6bf397b82290c540085e9ec98b47b30 ] + +Follow commit 9c92d36b0b1e ("arm64: dts: qcom: qrb2210-rb1: Fix UART3 +wakeup IRQ storm") and apply the similar fix to the RB2 platform. + +Having RX / TX pins as pull up and wakup interrupt as high-level +triggered generates an interrupt storm when trying to suspend the +device. Avoid the storm by using the falling edge trigger (as all other +platforms do). + +Fixes: cab60b166575 ("arm64: dts: qcom: qrb4210-rb2: Enable bluetooth") +Reviewed-by: Konrad Dybcio +Signed-off-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260106-wcn3990-pwrctl-v2-6-0386204328be@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/qrb4210-rb2.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts b/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts +index f99fb9159e0b6..547c6d4204601 100644 +--- a/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts ++++ b/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts +@@ -636,7 +636,7 @@ sdc2_card_det_n: sd-card-det-n-state { + + &uart3 { + interrupts-extended = <&intc GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH>, +- <&tlmm 11 IRQ_TYPE_LEVEL_HIGH>; ++ <&tlmm 11 IRQ_TYPE_EDGE_FALLING>; + pinctrl-0 = <&uart3_default>; + pinctrl-1 = <&uart3_sleep>; + pinctrl-names = "default", "sleep"; +-- +2.51.0 + diff --git a/queue-6.12/arm64-dts-qcom-sdm630-fix-gpu_speed_bin-size.patch b/queue-6.12/arm64-dts-qcom-sdm630-fix-gpu_speed_bin-size.patch new file mode 100644 index 0000000000..e6d9828c63 --- /dev/null +++ b/queue-6.12/arm64-dts-qcom-sdm630-fix-gpu_speed_bin-size.patch @@ -0,0 +1,49 @@ +From abfe28790efce1716d3b3417a7a206c77100ba00 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 11 Dec 2025 03:27:45 +0200 +Subject: arm64: dts: qcom: sdm630: fix gpu_speed_bin size + +From: Dmitry Baryshkov + +[ Upstream commit e814796dfcae8905682ac3ac2dd57f512a9f6726 ] + +Historically sdm630.dtsi has used 1 byte length for the gpu_speed_bin +cell, although it spans two bytes (offset 5, size 7 bits). It was being +accepted by the kernel because before the commit 7a06ef751077 ("nvmem: +core: fix bit offsets of more than one byte") the kernel didn't have +length check. After this commit nvmem core rejects QFPROM on sdm630 / +sdm660, making GPU and USB unusable on those platforms. + +Set the size of the gpu_speed_bin cell to 2 bytes, fixing the parsing +error. While we are at it, update the length to 8 bits as pointed out by +Alexey Minnekhanov. + +Fixes: b190fb010664 ("arm64: dts: qcom: sdm630: Add sdm630 dts file") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Reviewed-by: Alexey Minnekhanov +Link: https://lore.kernel.org/r/20251211-sdm630-fix-gpu-v2-1-92f0e736dba0@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm630.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/sdm630.dtsi b/arch/arm64/boot/dts/qcom/sdm630.dtsi +index c8da5cb8d04e9..37692d438d230 100644 +--- a/arch/arm64/boot/dts/qcom/sdm630.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm630.dtsi +@@ -591,8 +591,8 @@ qusb2_hstx_trim: hstx-trim@240 { + }; + + gpu_speed_bin: gpu-speed-bin@41a0 { +- reg = <0x41a2 0x1>; +- bits = <5 7>; ++ reg = <0x41a2 0x2>; ++ bits = <5 8>; + }; + }; + +-- +2.51.0 + diff --git a/queue-6.12/arm64-dts-qcom-sdm845-db845c-drop-cs-from-spio0.patch b/queue-6.12/arm64-dts-qcom-sdm845-db845c-drop-cs-from-spio0.patch new file mode 100644 index 0000000000..8e7cec9ba8 --- /dev/null +++ b/queue-6.12/arm64-dts-qcom-sdm845-db845c-drop-cs-from-spio0.patch @@ -0,0 +1,40 @@ +From 485b51ea031dc77b0477de292e43f003d578c926 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Jan 2026 03:01:17 +0200 +Subject: arm64: dts: qcom: sdm845-db845c: drop CS from SPIO0 + +From: Dmitry Baryshkov + +[ Upstream commit 8bfb696ccdc5bcfad7a45b84c2c8a36757070e19 ] + +On SDM845 SPI uses hardware-provided chip select, while specifying +cs-gpio makes the driver request GPIO pin, which on DB845c conflicts +with the normal host controllers pinctrl entry. + +Drop the cs-gpios property to restore SPI functionality. + +Fixes: cb29e7106d4e ("arm64: dts: qcom: db845c: Add support for MCP2517FD") +Reviewed-by: Konrad Dybcio +Signed-off-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260106-wcn3990-pwrctl-v2-7-0386204328be@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm845-db845c.dts | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts +index 9a6d3d0c0ee43..276df1b078118 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts ++++ b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts +@@ -858,7 +858,6 @@ &spi0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&qup_spi0_default>; +- cs-gpios = <&tlmm 3 GPIO_ACTIVE_LOW>; + + can@0 { + compatible = "microchip,mcp2517fd"; +-- +2.51.0 + diff --git a/queue-6.12/arm64-dts-qcom-sdm845-db845c-specify-power-for-wifi-.patch b/queue-6.12/arm64-dts-qcom-sdm845-db845c-specify-power-for-wifi-.patch new file mode 100644 index 0000000000..14ae5a6f56 --- /dev/null +++ b/queue-6.12/arm64-dts-qcom-sdm845-db845c-specify-power-for-wifi-.patch @@ -0,0 +1,50 @@ +From f5ab8f90347018724d4820daf4f533c930e38116 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Jan 2026 03:01:18 +0200 +Subject: arm64: dts: qcom: sdm845-db845c: specify power for WiFi CH1 + +From: Dmitry Baryshkov + +[ Upstream commit c303e89f7f17c29981d09f8beaaf60937ae8b1f2 ] + +Specify power supply for the second chain / antenna output of the +onboard WiFi chip. + +Fixes: 3f72e2d3e682 ("arm64: dts: qcom: Add Dragonboard 845c") +Reviewed-by: Konrad Dybcio +Signed-off-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260106-wcn3990-pwrctl-v2-8-0386204328be@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm845-db845c.dts | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts +index 276df1b078118..8f3b31a30e247 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts ++++ b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts +@@ -378,6 +378,12 @@ vreg_l21a_2p95: ldo21 { + regulator-initial-mode = ; + }; + ++ vreg_l23a_3p3: ldo23 { ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3312000>; ++ regulator-initial-mode = ; ++ }; ++ + vreg_l24a_3p075: ldo24 { + regulator-min-microvolt = <3088000>; + regulator-max-microvolt = <3088000>; +@@ -1163,6 +1169,7 @@ &wifi { + vdd-1.8-xo-supply = <&vreg_l7a_1p8>; + vdd-1.3-rfa-supply = <&vreg_l17a_1p3>; + vdd-3.3-ch0-supply = <&vreg_l25a_3p3>; ++ vdd-3.3-ch1-supply = <&vreg_l23a_3p3>; + + qcom,snoc-host-cap-8bit-quirk; + qcom,ath10k-calibration-variant = "Thundercomm_DB845C"; +-- +2.51.0 + diff --git a/queue-6.12/arm64-dts-qcom-sdm845-oneplus-don-t-keep-panel-regul.patch b/queue-6.12/arm64-dts-qcom-sdm845-oneplus-don-t-keep-panel-regul.patch new file mode 100644 index 0000000000..80b9c698f8 --- /dev/null +++ b/queue-6.12/arm64-dts-qcom-sdm845-oneplus-don-t-keep-panel-regul.patch @@ -0,0 +1,39 @@ +From 61e29a34792f40960e7399679790f835b6ae9415 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 18 Nov 2025 15:52:26 +0100 +Subject: arm64: dts: qcom: sdm845-oneplus: Don't keep panel regulator always + on + +From: Casey Connolly + +[ Upstream commit 45d1f42d3e84b5880cf9fab1eb24a7818320eeb7 ] + +The panel regulator doesn't need to be always on, so remove this +property. + +Fixes: 288ef8a42612 ("arm64: dts: sdm845: add oneplus6/6t devices") +Signed-off-by: Casey Connolly +Signed-off-by: David Heidelberg +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251118-dts-oneplus-regulators-v2-2-3e67cea1e4e7@ixit.cz +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +index 56840b6ed6449..3b47baa011c23 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +@@ -252,7 +252,6 @@ vreg_l14a_1p88: ldo14 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; +- regulator-always-on; + }; + + vreg_l17a_1p3: ldo17 { +-- +2.51.0 + diff --git a/queue-6.12/arm64-dts-qcom-sdm845-oneplus-don-t-mark-ts-supply-b.patch b/queue-6.12/arm64-dts-qcom-sdm845-oneplus-don-t-mark-ts-supply-b.patch new file mode 100644 index 0000000000..e587ef24f1 --- /dev/null +++ b/queue-6.12/arm64-dts-qcom-sdm845-oneplus-don-t-mark-ts-supply-b.patch @@ -0,0 +1,39 @@ +From 37d7d02b9453904d3487a3b309647115e33bf190 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 18 Nov 2025 15:52:25 +0100 +Subject: arm64: dts: qcom: sdm845-oneplus: Don't mark ts supply boot-on + +From: Casey Connolly + +[ Upstream commit c9b98b9dad9749bf2eb7336a6fca31a6af1039d7 ] + +The touchscreen isn't enabled by bootloader and doesn't need to be +enabled at boot, only when the driver probes, thus remove the +regulator-boot-on property. + +Fixes: 288ef8a42612 ("arm64: dts: sdm845: add oneplus6/6t devices") +Signed-off-by: Casey Connolly +Signed-off-by: David Heidelberg +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251118-dts-oneplus-regulators-v2-1-3e67cea1e4e7@ixit.cz +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +index d0cbf9106a792..56840b6ed6449 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +@@ -156,7 +156,6 @@ ts_1p8_supply: ts-1p8-regulator { + + gpio = <&tlmm 88 0>; + enable-active-high; +- regulator-boot-on; + }; + }; + +-- +2.51.0 + diff --git a/queue-6.12/arm64-dts-qcom-sdm845-oneplus-mark-l14a-regulator-as.patch b/queue-6.12/arm64-dts-qcom-sdm845-oneplus-mark-l14a-regulator-as.patch new file mode 100644 index 0000000000..4a6588b887 --- /dev/null +++ b/queue-6.12/arm64-dts-qcom-sdm845-oneplus-mark-l14a-regulator-as.patch @@ -0,0 +1,38 @@ +From 7b84c1c759cc766289885baa22b63e2ebd06eae8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 18 Nov 2025 15:52:27 +0100 +Subject: arm64: dts: qcom: sdm845-oneplus: Mark l14a regulator as boot-on + +From: Casey Connolly + +[ Upstream commit ad33ee060be46794a03d033894c9db3a9d6c1a0f ] + +This regulator is used only for the display, which is enabled by the +bootloader and left on for continuous splash. Mark it as such. + +Fixes: 288ef8a42612 ("arm64: dts: sdm845: add oneplus6/6t devices") +Signed-off-by: Casey Connolly +Signed-off-by: David Heidelberg +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251118-dts-oneplus-regulators-v2-3-3e67cea1e4e7@ixit.cz +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +index 3b47baa011c23..9d71623faa40a 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +@@ -252,6 +252,7 @@ vreg_l14a_1p88: ldo14 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; ++ regulator-boot-on; + }; + + vreg_l17a_1p3: ldo17 { +-- +2.51.0 + diff --git a/queue-6.12/arm64-dts-qcom-sm6115-add-cx_mem-dbgc-gpu-regions.patch b/queue-6.12/arm64-dts-qcom-sm6115-add-cx_mem-dbgc-gpu-regions.patch new file mode 100644 index 0000000000..60ea5dceb3 --- /dev/null +++ b/queue-6.12/arm64-dts-qcom-sm6115-add-cx_mem-dbgc-gpu-regions.patch @@ -0,0 +1,49 @@ +From 5d3c2f5b07aef7210921c7d86195eebb38784c6d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Dec 2025 21:47:41 +0100 +Subject: arm64: dts: qcom: sm6115: Add CX_MEM/DBGC GPU regions + +From: Konrad Dybcio + +[ Upstream commit 78c13dac18cf0e6f6cbc6ea85d4f967e6cca9562 ] + +Describe the GPU register regions, with the former existing but not +being used much if at all on this silicon, and the latter containing +various debugging levers generally related to dumping the state of +the IP upon a crash. + +Fixes: 11750af256f8 ("arm64: dts: qcom: sm6115: Add GPU nodes") +Reported-by: Krzysztof Kozlowski +Closes: https://lore.kernel.org/linux-arm-msm/8a64f70b-8034-45e7-86a3-0015cf357132@oss.qualcomm.com/T/#m404f1425c36b61467760f058b696b8910340a063 +Signed-off-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Akhil P Oommen +Link: https://lore.kernel.org/r/20251229-topic-6115_2290_gpu_dbgc-v1-3-4a24d196389c@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm6115.dtsi | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm6115.dtsi b/arch/arm64/boot/dts/qcom/sm6115.dtsi +index 4adadfd1e51ae..e33da2975240f 100644 +--- a/arch/arm64/boot/dts/qcom/sm6115.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm6115.dtsi +@@ -1688,8 +1688,12 @@ usb_dwc3_ss: endpoint { + + gpu: gpu@5900000 { + compatible = "qcom,adreno-610.0", "qcom,adreno"; +- reg = <0x0 0x05900000 0x0 0x40000>; +- reg-names = "kgsl_3d0_reg_memory"; ++ reg = <0x0 0x05900000 0x0 0x40000>, ++ <0x0 0x0599e000 0x0 0x1000>, ++ <0x0 0x05961000 0x0 0x800>; ++ reg-names = "kgsl_3d0_reg_memory", ++ "cx_mem", ++ "cx_dbgc"; + + /* There's no (real) GMU, so we have to handle quite a bunch of clocks! */ + clocks = <&gpucc GPU_CC_GX_GFX3D_CLK>, +-- +2.51.0 + diff --git a/queue-6.12/arm64-dts-qcom-x1e-bus-is-40-bits-fix-64gb-models.patch b/queue-6.12/arm64-dts-qcom-x1e-bus-is-40-bits-fix-64gb-models.patch new file mode 100644 index 0000000000..2a60d6799f --- /dev/null +++ b/queue-6.12/arm64-dts-qcom-x1e-bus-is-40-bits-fix-64gb-models.patch @@ -0,0 +1,42 @@ +From 3c31f9f85dfc5a4dd2a95ba3d350f2018cd80b0b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Nov 2025 16:29:42 -0500 +Subject: arm64: dts: qcom: x1e: bus is 40-bits (fix 64GB models) + +From: Jonathan Marek + +[ Upstream commit b38dd256e11a4c8bd5a893e11fc42d493939c907 ] + +Unlike the phone SoCs this was copied from, x1e has a 40-bit physical bus. +The upper address space is used to support more than 32GB of memory. + +This fixes issues when DMA buffers are allocated outside the 36-bit range. + +Fixes: af16b00578a7 ("arm64: dts: qcom: Add base X1E80100 dtsi and the QCP dts") +Signed-off-by: Jonathan Marek +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251127212943.24480-1-jonathan@marek.ca +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/x1e80100.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/x1e80100.dtsi b/arch/arm64/boot/dts/qcom/x1e80100.dtsi +index a19b217b6f8ee..6f47f4d5ff2a6 100644 +--- a/arch/arm64/boot/dts/qcom/x1e80100.dtsi ++++ b/arch/arm64/boot/dts/qcom/x1e80100.dtsi +@@ -736,8 +736,8 @@ soc: soc@0 { + + #address-cells = <2>; + #size-cells = <2>; +- dma-ranges = <0 0 0 0 0x10 0>; +- ranges = <0 0 0 0 0x10 0>; ++ dma-ranges = <0 0 0 0 0x100 0>; ++ ranges = <0 0 0 0 0x100 0>; + + gcc: clock-controller@100000 { + compatible = "qcom,x1e80100-gcc"; +-- +2.51.0 + diff --git a/queue-6.12/arm64-dts-qcom-x1e80100-fix-usb-combo-phys-ss1-and-s.patch b/queue-6.12/arm64-dts-qcom-x1e80100-fix-usb-combo-phys-ss1-and-s.patch new file mode 100644 index 0000000000..f04af4819d --- /dev/null +++ b/queue-6.12/arm64-dts-qcom-x1e80100-fix-usb-combo-phys-ss1-and-s.patch @@ -0,0 +1,61 @@ +From 0fafbd72e92ac8bad7ca6b97c6db29670e87af09 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 3 Nov 2025 18:51:40 +0200 +Subject: arm64: dts: qcom: x1e80100: Fix USB combo PHYs SS1 and SS2 ref clocks + +From: Abel Vesa + +[ Upstream commit 3af51501e2b8c87564b5cda43b0e5c316cf54717 ] + +It seems the USB combo SS1 and SS2 ref clocks have another gate, unlike +the SS0. These gates are part of the TCSR clock controller. + +At least on Dell XPS 13 (9345), if the ref clock provided by the TCSR +clock controller for SS1 PHY is disabled on the clk_disable_unused late +initcall, the PHY fails to initialize. It doesn't happen on the SS0 PHY +and the SS2 is not used on this device. + +This doesn't seem to be a problem on CRD though. It might be that the +RPMh has a vote for it from some other consumer and does not actually +disable it when ther kernel drops its vote. + +Either way, these TCSR provided clocks seem to be the correct ones for +the SS1 and SS2, so use them instead. + +Fixes: 4af46b7bd66f ("arm64: dts: qcom: x1e80100: Add USB nodes") +Signed-off-by: Abel Vesa +Reviewed-by: Neil Armstrong +Reviewed-by: Taniya Das +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251103-dts-qcom-x1e80100-fix-combo-ref-clks-v1-1-f395ec3cb7e8@linaro.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/x1e80100.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/x1e80100.dtsi b/arch/arm64/boot/dts/qcom/x1e80100.dtsi +index 8536403e6ac99..a19b217b6f8ee 100644 +--- a/arch/arm64/boot/dts/qcom/x1e80100.dtsi ++++ b/arch/arm64/boot/dts/qcom/x1e80100.dtsi +@@ -2679,7 +2679,7 @@ usb_1_ss1_qmpphy: phy@fda000 { + reg = <0 0x00fda000 0 0x4000>; + + clocks = <&gcc GCC_USB3_SEC_PHY_AUX_CLK>, +- <&rpmhcc RPMH_CXO_CLK>, ++ <&tcsr TCSR_USB4_1_CLKREF_EN>, + <&gcc GCC_USB3_SEC_PHY_COM_AUX_CLK>, + <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>; + clock-names = "aux", +@@ -2749,7 +2749,7 @@ usb_1_ss2_qmpphy: phy@fdf000 { + reg = <0 0x00fdf000 0 0x4000>; + + clocks = <&gcc GCC_USB3_TERT_PHY_AUX_CLK>, +- <&rpmhcc RPMH_CXO_CLK>, ++ <&tcsr TCSR_USB4_2_CLKREF_EN>, + <&gcc GCC_USB3_TERT_PHY_COM_AUX_CLK>, + <&gcc GCC_USB3_TERT_PHY_PIPE_CLK>; + clock-names = "aux", +-- +2.51.0 + diff --git a/queue-6.12/arm64-dts-ti-k3-j784s4-j742s2-main-common.dtsi-refac.patch b/queue-6.12/arm64-dts-ti-k3-j784s4-j742s2-main-common.dtsi-refac.patch new file mode 100644 index 0000000000..2c81a12e5e --- /dev/null +++ b/queue-6.12/arm64-dts-ti-k3-j784s4-j742s2-main-common.dtsi-refac.patch @@ -0,0 +1,125 @@ +From b5011283da62ba70dc612ed0c5291a22b9c142fa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 14:21:13 +0530 +Subject: arm64: dts: ti: k3-j784s4-j742s2-main-common.dtsi: Refactor watchdog + instances for j784s4 + +From: Abhash Kumar Jha + +[ Upstream commit 61acc4428a7f52e0a13e226ba76f2ce2ca66c065 ] + +Each A72 core has one watchdog instance associated with it. Since j742s2 +has 4 A72 cores, the common file should not define 8 watchdog instances. + +Refactor the last 4 extra watchdogs from the common file to j784s4 +specific file, as j784s4 has 8 A72 cores and thus hardware description +requires 8 watchdog instances. + +Fixes: 9cc161a4509c ("arm64: dts: ti: Refactor J784s4 SoC files to a common file") +Signed-off-by: Abhash Kumar Jha +Reviewed-by: Udit Kumar +Link: https://patch.msgid.link/20260112085113.3476193-3-a-kumar2@ti.com +Signed-off-by: Nishanth Menon +Signed-off-by: Sasha Levin +--- + .../dts/ti/k3-j784s4-j742s2-main-common.dtsi | 36 ------------------- + arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi | 36 +++++++++++++++++++ + 2 files changed, 36 insertions(+), 36 deletions(-) + +diff --git a/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-main-common.dtsi b/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-main-common.dtsi +index 013c0d25d3481..079ccefeabe91 100644 +--- a/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-main-common.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-main-common.dtsi +@@ -2350,42 +2350,6 @@ watchdog3: watchdog@2230000 { + assigned-clock-parents = <&k3_clks 351 4>; + }; + +- watchdog4: watchdog@2240000 { +- compatible = "ti,j7-rti-wdt"; +- reg = <0x00 0x2240000 0x00 0x100>; +- clocks = <&k3_clks 352 0>; +- power-domains = <&k3_pds 352 TI_SCI_PD_EXCLUSIVE>; +- assigned-clocks = <&k3_clks 352 0>; +- assigned-clock-parents = <&k3_clks 352 4>; +- }; +- +- watchdog5: watchdog@2250000 { +- compatible = "ti,j7-rti-wdt"; +- reg = <0x00 0x2250000 0x00 0x100>; +- clocks = <&k3_clks 353 0>; +- power-domains = <&k3_pds 353 TI_SCI_PD_EXCLUSIVE>; +- assigned-clocks = <&k3_clks 353 0>; +- assigned-clock-parents = <&k3_clks 353 4>; +- }; +- +- watchdog6: watchdog@2260000 { +- compatible = "ti,j7-rti-wdt"; +- reg = <0x00 0x2260000 0x00 0x100>; +- clocks = <&k3_clks 354 0>; +- power-domains = <&k3_pds 354 TI_SCI_PD_EXCLUSIVE>; +- assigned-clocks = <&k3_clks 354 0>; +- assigned-clock-parents = <&k3_clks 354 4>; +- }; +- +- watchdog7: watchdog@2270000 { +- compatible = "ti,j7-rti-wdt"; +- reg = <0x00 0x2270000 0x00 0x100>; +- clocks = <&k3_clks 355 0>; +- power-domains = <&k3_pds 355 TI_SCI_PD_EXCLUSIVE>; +- assigned-clocks = <&k3_clks 355 0>; +- assigned-clock-parents = <&k3_clks 355 4>; +- }; +- + /* + * The following RTI instances are coupled with MCU R5Fs, c7x and + * GPU so keeping them reserved as these will be used by their +diff --git a/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi b/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi +index 5b7830a3c0975..78fcd0c40abcf 100644 +--- a/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi +@@ -6,6 +6,42 @@ + */ + + &cbass_main { ++ watchdog4: watchdog@2240000 { ++ compatible = "ti,j7-rti-wdt"; ++ reg = <0x00 0x2240000 0x00 0x100>; ++ clocks = <&k3_clks 352 0>; ++ power-domains = <&k3_pds 352 TI_SCI_PD_EXCLUSIVE>; ++ assigned-clocks = <&k3_clks 352 0>; ++ assigned-clock-parents = <&k3_clks 352 4>; ++ }; ++ ++ watchdog5: watchdog@2250000 { ++ compatible = "ti,j7-rti-wdt"; ++ reg = <0x00 0x2250000 0x00 0x100>; ++ clocks = <&k3_clks 353 0>; ++ power-domains = <&k3_pds 353 TI_SCI_PD_EXCLUSIVE>; ++ assigned-clocks = <&k3_clks 353 0>; ++ assigned-clock-parents = <&k3_clks 353 4>; ++ }; ++ ++ watchdog6: watchdog@2260000 { ++ compatible = "ti,j7-rti-wdt"; ++ reg = <0x00 0x2260000 0x00 0x100>; ++ clocks = <&k3_clks 354 0>; ++ power-domains = <&k3_pds 354 TI_SCI_PD_EXCLUSIVE>; ++ assigned-clocks = <&k3_clks 354 0>; ++ assigned-clock-parents = <&k3_clks 354 4>; ++ }; ++ ++ watchdog7: watchdog@2270000 { ++ compatible = "ti,j7-rti-wdt"; ++ reg = <0x00 0x2270000 0x00 0x100>; ++ clocks = <&k3_clks 355 0>; ++ power-domains = <&k3_pds 355 TI_SCI_PD_EXCLUSIVE>; ++ assigned-clocks = <&k3_clks 355 0>; ++ assigned-clock-parents = <&k3_clks 355 4>; ++ }; ++ + pcie2_rc: pcie@2920000 { + compatible = "ti,j784s4-pcie-host"; + reg = <0x00 0x02920000 0x00 0x1000>, +-- +2.51.0 + diff --git a/queue-6.12/arm64-dts-ti-k3-j784s4-main.dtsi-move-c71_3-node-to-.patch b/queue-6.12/arm64-dts-ti-k3-j784s4-main.dtsi-move-c71_3-node-to-.patch new file mode 100644 index 0000000000..3a616325b5 --- /dev/null +++ b/queue-6.12/arm64-dts-ti-k3-j784s4-main.dtsi-move-c71_3-node-to-.patch @@ -0,0 +1,73 @@ +From 472b34bd8e04160a6184a6ec2173f317b4729c9d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 14:21:12 +0530 +Subject: arm64: dts: ti: k3-j784s4-main.dtsi: Move c71_3 node to appropriate + order + +From: Abhash Kumar Jha + +[ Upstream commit 24c9d5fb8bbf5e8c9e6fc2beffeb80ac2da83de4 ] + +The device tree nodes should be ordered by unit addresses in ascending +order. + +Correct the order by moving the c71_3 DSP node at the end as it has a +higher unit address. + +Signed-off-by: Abhash Kumar Jha +Reviewed-by: Udit Kumar +Link: https://patch.msgid.link/20260112085113.3476193-2-a-kumar2@ti.com +Signed-off-by: Nishanth Menon +Stable-dep-of: 61acc4428a7f ("arm64: dts: ti: k3-j784s4-j742s2-main-common.dtsi: Refactor watchdog instances for j784s4") +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi | 26 +++++++++++----------- + 1 file changed, 13 insertions(+), 13 deletions(-) + +diff --git a/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi b/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi +index 0160fe0da9838..5b7830a3c0975 100644 +--- a/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi +@@ -6,19 +6,6 @@ + */ + + &cbass_main { +- c71_3: dsp@67800000 { +- compatible = "ti,j721s2-c71-dsp"; +- reg = <0x00 0x67800000 0x00 0x00080000>, +- <0x00 0x67e00000 0x00 0x0000c000>; +- reg-names = "l2sram", "l1dram"; +- resets = <&k3_reset 40 1>; +- firmware-name = "j784s4-c71_3-fw"; +- ti,sci = <&sms>; +- ti,sci-dev-id = <40>; +- ti,sci-proc-ids = <0x33 0xff>; +- status = "disabled"; +- }; +- + pcie2_rc: pcie@2920000 { + compatible = "ti,j784s4-pcie-host"; + reg = <0x00 0x02920000 0x00 0x1000>, +@@ -113,6 +100,19 @@ serdes2: serdes@5020000 { + status = "disabled"; + }; + }; ++ ++ c71_3: dsp@67800000 { ++ compatible = "ti,j721s2-c71-dsp"; ++ reg = <0x00 0x67800000 0x00 0x00080000>, ++ <0x00 0x67e00000 0x00 0x0000c000>; ++ reg-names = "l2sram", "l1dram"; ++ resets = <&k3_reset 40 1>; ++ firmware-name = "j784s4-c71_3-fw"; ++ ti,sci = <&sms>; ++ ti,sci-dev-id = <40>; ++ ti,sci-proc-ids = <0x33 0xff>; ++ status = "disabled"; ++ }; + }; + + &scm_conf { +-- +2.51.0 + diff --git a/queue-6.12/arm64-dts-tqma8mpql-mba8mp-ras314-fix-hdmi-cec-pad-c.patch b/queue-6.12/arm64-dts-tqma8mpql-mba8mp-ras314-fix-hdmi-cec-pad-c.patch new file mode 100644 index 0000000000..ab44c67a5b --- /dev/null +++ b/queue-6.12/arm64-dts-tqma8mpql-mba8mp-ras314-fix-hdmi-cec-pad-c.patch @@ -0,0 +1,37 @@ +From 038c5c1938e8e97503dc84770b5a3c0f3cb93258 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 11:53:13 +0100 +Subject: arm64: dts: tqma8mpql-mba8mp-ras314: Fix HDMI CEC pad control + settings + +From: Alexander Stein + +[ Upstream commit 53a5c1d98d1155ece4c9446c0fea55e17d08774a ] + +As per datasheet of the HDMI protection IC the CEC_IC pin has been +configured as open-drain. + +Fixes: ddabb3ce3f90 ("arm64: dts: freescale: add TQMa8MPQL on MBa8MP-RAS314") +Signed-off-by: Alexander Stein +Signed-off-by: Shawn Guo +Signed-off-by: Sasha Levin +--- + .../arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts +index f7346b3d35fe5..a122f2ed5f531 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts +@@ -704,7 +704,7 @@ pinctrl_hdmi: hdmigrp { + fsl,pins = , + , + , +- ; ++ ; + }; + + pinctrl_gpt1: gpt1grp { +-- +2.51.0 + diff --git a/queue-6.12/arm64-dts-tqma8mpql-mba8mpxl-fix-hdmi-cec-pad-contro.patch b/queue-6.12/arm64-dts-tqma8mpql-mba8mpxl-fix-hdmi-cec-pad-contro.patch new file mode 100644 index 0000000000..501f1e8f92 --- /dev/null +++ b/queue-6.12/arm64-dts-tqma8mpql-mba8mpxl-fix-hdmi-cec-pad-contro.patch @@ -0,0 +1,36 @@ +From e18ffedf506ba942528df775021f44b5b58f7827 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 11:53:09 +0100 +Subject: arm64: dts: tqma8mpql-mba8mpxl: Fix HDMI CEC pad control settings + +From: Alexander Stein + +[ Upstream commit 8401527abb5e3a00c867b6597b8e1b29c80c9824 ] + +As per datasheet of the HDMI protection IC the CEC_IC pin has been +configured as open-drain. + +Fixes: 418d1d840e42 ("arm64: dts: freescale: add initial device tree for TQMa8MPQL with i.MX8MP") +Signed-off-by: Alexander Stein +Signed-off-by: Shawn Guo +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts +index e7c16a7ee6c26..773282002e6c6 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts +@@ -859,7 +859,7 @@ pinctrl_hdmi: hdmigrp { + fsl,pins = , + , + , +- ; ++ ; + }; + + pinctrl_hoggpio2: hoggpio2grp { +-- +2.51.0 + diff --git a/queue-6.12/asoc-nau8821-avoid-unnecessary-blocking-in-irq-handl.patch b/queue-6.12/asoc-nau8821-avoid-unnecessary-blocking-in-irq-handl.patch new file mode 100644 index 0000000000..e0b9fdaaec --- /dev/null +++ b/queue-6.12/asoc-nau8821-avoid-unnecessary-blocking-in-irq-handl.patch @@ -0,0 +1,121 @@ +From 675b67908abff2e729d4743434379c7518e2de56 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Oct 2025 21:03:27 +0300 +Subject: ASoC: nau8821: Avoid unnecessary blocking in IRQ handler + +From: Cristian Ciocaltea + +[ Upstream commit ee70bacef1c6050e4836409927294d744dbcfa72 ] + +The interrupt handler offloads the microphone detection logic to +nau8821_jdet_work(), which implies a sleep operation. However, before +being able to process any subsequent hotplug event, the interrupt +handler needs to wait for any prior scheduled work to complete. + +Move the sleep out of jdet_work by converting it to a delayed work. +This eliminates the undesired blocking in the interrupt handler when +attempting to cancel a recently scheduled work item and should help +reducing transient input reports that might confuse user-space. + +Signed-off-by: Cristian Ciocaltea +Link: https://patch.msgid.link/20251003-nau8821-jdet-fixes-v1-5-f7b0e2543f09@collabora.com +Signed-off-by: Mark Brown +Stable-dep-of: 70237853edf0 ("ASoC: nau8821: Fixup nau8821_enable_jack_detect()") +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/nau8821.c | 22 ++++++++++++---------- + sound/soc/codecs/nau8821.h | 2 +- + 2 files changed, 13 insertions(+), 11 deletions(-) + +diff --git a/sound/soc/codecs/nau8821.c b/sound/soc/codecs/nau8821.c +index beeca33a0b7ee..9d006c4b6f284 100644 +--- a/sound/soc/codecs/nau8821.c ++++ b/sound/soc/codecs/nau8821.c +@@ -1105,16 +1105,12 @@ static void nau8821_eject_jack(struct nau8821 *nau8821) + static void nau8821_jdet_work(struct work_struct *work) + { + struct nau8821 *nau8821 = +- container_of(work, struct nau8821, jdet_work); ++ container_of(work, struct nau8821, jdet_work.work); + struct snd_soc_dapm_context *dapm = nau8821->dapm; + struct snd_soc_component *component = snd_soc_dapm_to_component(dapm); + struct regmap *regmap = nau8821->regmap; + int jack_status_reg, mic_detected, event = 0, event_mask = 0; + +- snd_soc_component_force_enable_pin(component, "MICBIAS"); +- snd_soc_dapm_sync(dapm); +- msleep(20); +- + regmap_read(regmap, NAU8821_R58_I2C_DEVICE_ID, &jack_status_reg); + mic_detected = !(jack_status_reg & NAU8821_KEYDET); + if (mic_detected) { +@@ -1147,6 +1143,7 @@ static void nau8821_jdet_work(struct work_struct *work) + snd_soc_component_disable_pin(component, "MICBIAS"); + snd_soc_dapm_sync(dapm); + } ++ + event_mask |= SND_JACK_HEADSET; + snd_soc_jack_report(nau8821->jack, event, event_mask); + } +@@ -1195,6 +1192,7 @@ static irqreturn_t nau8821_interrupt(int irq, void *data) + { + struct nau8821 *nau8821 = (struct nau8821 *)data; + struct regmap *regmap = nau8821->regmap; ++ struct snd_soc_component *component; + int active_irq, event = 0, event_mask = 0; + + if (regmap_read(regmap, NAU8821_R10_IRQ_STATUS, &active_irq)) { +@@ -1206,7 +1204,7 @@ static irqreturn_t nau8821_interrupt(int irq, void *data) + + if ((active_irq & NAU8821_JACK_EJECT_IRQ_MASK) == + NAU8821_JACK_EJECT_DETECTED) { +- cancel_work_sync(&nau8821->jdet_work); ++ cancel_delayed_work_sync(&nau8821->jdet_work); + regmap_update_bits(regmap, NAU8821_R71_ANALOG_ADC_1, + NAU8821_MICDET_MASK, NAU8821_MICDET_DIS); + nau8821_eject_jack(nau8821); +@@ -1220,12 +1218,15 @@ static irqreturn_t nau8821_interrupt(int irq, void *data) + nau8821_irq_status_clear(regmap, NAU8821_KEY_RELEASE_IRQ); + } else if ((active_irq & NAU8821_JACK_INSERT_IRQ_MASK) == + NAU8821_JACK_INSERT_DETECTED) { +- cancel_work_sync(&nau8821->jdet_work); ++ cancel_delayed_work_sync(&nau8821->jdet_work); + regmap_update_bits(regmap, NAU8821_R71_ANALOG_ADC_1, + NAU8821_MICDET_MASK, NAU8821_MICDET_EN); + if (nau8821_is_jack_inserted(regmap)) { +- /* detect microphone and jack type */ +- schedule_work(&nau8821->jdet_work); ++ /* Detect microphone and jack type */ ++ component = snd_soc_dapm_to_component(nau8821->dapm); ++ snd_soc_component_force_enable_pin(component, "MICBIAS"); ++ snd_soc_dapm_sync(nau8821->dapm); ++ schedule_delayed_work(&nau8821->jdet_work, msecs_to_jiffies(20)); + /* Turn off insertion interruption at manual mode */ + nau8821_setup_inserted_irq(nau8821); + } else { +@@ -1662,7 +1663,8 @@ int nau8821_enable_jack_detect(struct snd_soc_component *component, + + nau8821->jack = jack; + /* Initiate jack detection work queue */ +- INIT_WORK(&nau8821->jdet_work, nau8821_jdet_work); ++ INIT_DELAYED_WORK(&nau8821->jdet_work, nau8821_jdet_work); ++ + ret = devm_request_threaded_irq(nau8821->dev, nau8821->irq, NULL, + nau8821_interrupt, IRQF_TRIGGER_LOW | IRQF_ONESHOT, + "nau8821", nau8821); +diff --git a/sound/soc/codecs/nau8821.h b/sound/soc/codecs/nau8821.h +index f0935ffafcbec..88602923780d8 100644 +--- a/sound/soc/codecs/nau8821.h ++++ b/sound/soc/codecs/nau8821.h +@@ -561,7 +561,7 @@ struct nau8821 { + struct regmap *regmap; + struct snd_soc_dapm_context *dapm; + struct snd_soc_jack *jack; +- struct work_struct jdet_work; ++ struct delayed_work jdet_work; + int irq; + int clk_id; + int micbias_voltage; +-- +2.51.0 + diff --git a/queue-6.12/asoc-nau8821-consistently-clear-interrupts-before-un.patch b/queue-6.12/asoc-nau8821-consistently-clear-interrupts-before-un.patch new file mode 100644 index 0000000000..90bf396f98 --- /dev/null +++ b/queue-6.12/asoc-nau8821-consistently-clear-interrupts-before-un.patch @@ -0,0 +1,169 @@ +From 9481476eddd30cab3834478deb1593fe06280030 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Oct 2025 21:03:25 +0300 +Subject: ASoC: nau8821: Consistently clear interrupts before unmasking + +From: Cristian Ciocaltea + +[ Upstream commit a698679fe8b0fec41d1fb9547a53127a85c1be92 ] + +The interrupt handler attempts to perform some IRQ status clear +operations *after* rather than *before* unmasking and enabling +interrupts. This is a rather fragile approach since it may generally +lead to missing IRQ requests or causing spurious interrupts. + +Make use of the nau8821_irq_status_clear() helper instead of +manipulating the related register directly and ensure any interrupt +clearing is performed *after* the target interrupts are disabled/masked +and *before* proceeding with additional interrupt unmasking/enablement +operations. + +This also implicitly drops the redundant clear operation of the ejection +IRQ in the interrupt handler, since nau8821_eject_jack() has been +already responsible for clearing all active interrupts. + +Fixes: aab1ad11d69f ("ASoC: nau8821: new driver") +Fixes: 2551b6e89936 ("ASoC: nau8821: Add headset button detection") +Signed-off-by: Cristian Ciocaltea +Link: https://patch.msgid.link/20251003-nau8821-jdet-fixes-v1-3-f7b0e2543f09@collabora.com +Signed-off-by: Mark Brown +Stable-dep-of: 70237853edf0 ("ASoC: nau8821: Fixup nau8821_enable_jack_detect()") +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/nau8821.c | 58 ++++++++++++++++++++------------------ + 1 file changed, 30 insertions(+), 28 deletions(-) + +diff --git a/sound/soc/codecs/nau8821.c b/sound/soc/codecs/nau8821.c +index bfb719ca4c2cf..beeca33a0b7ee 100644 +--- a/sound/soc/codecs/nau8821.c ++++ b/sound/soc/codecs/nau8821.c +@@ -1059,20 +1059,24 @@ static void nau8821_eject_jack(struct nau8821 *nau8821) + snd_soc_component_disable_pin(component, "MICBIAS"); + snd_soc_dapm_sync(dapm); + ++ /* Disable & mask both insertion & ejection IRQs */ ++ regmap_update_bits(regmap, NAU8821_R12_INTERRUPT_DIS_CTRL, ++ NAU8821_IRQ_INSERT_DIS | NAU8821_IRQ_EJECT_DIS, ++ NAU8821_IRQ_INSERT_DIS | NAU8821_IRQ_EJECT_DIS); ++ regmap_update_bits(regmap, NAU8821_R0F_INTERRUPT_MASK, ++ NAU8821_IRQ_INSERT_EN | NAU8821_IRQ_EJECT_EN, ++ NAU8821_IRQ_INSERT_EN | NAU8821_IRQ_EJECT_EN); ++ + /* Clear all interruption status */ + nau8821_irq_status_clear(regmap, 0); + +- /* Enable the insertion interruption, disable the ejection inter- +- * ruption, and then bypass de-bounce circuit. +- */ ++ /* Enable & unmask the insertion IRQ */ + regmap_update_bits(regmap, NAU8821_R12_INTERRUPT_DIS_CTRL, +- NAU8821_IRQ_EJECT_DIS | NAU8821_IRQ_INSERT_DIS, +- NAU8821_IRQ_EJECT_DIS); +- /* Mask unneeded IRQs: 1 - disable, 0 - enable */ ++ NAU8821_IRQ_INSERT_DIS, 0); + regmap_update_bits(regmap, NAU8821_R0F_INTERRUPT_MASK, +- NAU8821_IRQ_EJECT_EN | NAU8821_IRQ_INSERT_EN, +- NAU8821_IRQ_EJECT_EN); ++ NAU8821_IRQ_INSERT_EN, 0); + ++ /* Bypass de-bounce circuit */ + regmap_update_bits(regmap, NAU8821_R0D_JACK_DET_CTRL, + NAU8821_JACK_DET_DB_BYPASS, NAU8821_JACK_DET_DB_BYPASS); + +@@ -1096,7 +1100,6 @@ static void nau8821_eject_jack(struct nau8821 *nau8821) + NAU8821_IRQ_KEY_RELEASE_DIS | + NAU8821_IRQ_KEY_PRESS_DIS); + } +- + } + + static void nau8821_jdet_work(struct work_struct *work) +@@ -1153,6 +1156,15 @@ static void nau8821_setup_inserted_irq(struct nau8821 *nau8821) + { + struct regmap *regmap = nau8821->regmap; + ++ /* Disable & mask insertion IRQ */ ++ regmap_update_bits(regmap, NAU8821_R12_INTERRUPT_DIS_CTRL, ++ NAU8821_IRQ_INSERT_DIS, NAU8821_IRQ_INSERT_DIS); ++ regmap_update_bits(regmap, NAU8821_R0F_INTERRUPT_MASK, ++ NAU8821_IRQ_INSERT_EN, NAU8821_IRQ_INSERT_EN); ++ ++ /* Clear insert IRQ status */ ++ nau8821_irq_status_clear(regmap, NAU8821_JACK_INSERT_DETECTED); ++ + /* Enable internal VCO needed for interruptions */ + if (nau8821->dapm->bias_level < SND_SOC_BIAS_PREPARE) + nau8821_configure_sysclk(nau8821, NAU8821_CLK_INTERNAL, 0); +@@ -1172,17 +1184,18 @@ static void nau8821_setup_inserted_irq(struct nau8821 *nau8821) + regmap_update_bits(regmap, NAU8821_R0D_JACK_DET_CTRL, + NAU8821_JACK_DET_DB_BYPASS, 0); + ++ /* Unmask & enable the ejection IRQs */ + regmap_update_bits(regmap, NAU8821_R0F_INTERRUPT_MASK, +- NAU8821_IRQ_EJECT_EN, 0); ++ NAU8821_IRQ_EJECT_EN, 0); + regmap_update_bits(regmap, NAU8821_R12_INTERRUPT_DIS_CTRL, +- NAU8821_IRQ_EJECT_DIS, 0); ++ NAU8821_IRQ_EJECT_DIS, 0); + } + + static irqreturn_t nau8821_interrupt(int irq, void *data) + { + struct nau8821 *nau8821 = (struct nau8821 *)data; + struct regmap *regmap = nau8821->regmap; +- int active_irq, clear_irq = 0, event = 0, event_mask = 0; ++ int active_irq, event = 0, event_mask = 0; + + if (regmap_read(regmap, NAU8821_R10_IRQ_STATUS, &active_irq)) { + dev_err(nau8821->dev, "failed to read irq status\n"); +@@ -1198,14 +1211,13 @@ static irqreturn_t nau8821_interrupt(int irq, void *data) + NAU8821_MICDET_MASK, NAU8821_MICDET_DIS); + nau8821_eject_jack(nau8821); + event_mask |= SND_JACK_HEADSET; +- clear_irq = NAU8821_JACK_EJECT_IRQ_MASK; + } else if (active_irq & NAU8821_KEY_SHORT_PRESS_IRQ) { + event |= NAU8821_BUTTON; + event_mask |= NAU8821_BUTTON; +- clear_irq = NAU8821_KEY_SHORT_PRESS_IRQ; ++ nau8821_irq_status_clear(regmap, NAU8821_KEY_SHORT_PRESS_IRQ); + } else if (active_irq & NAU8821_KEY_RELEASE_IRQ) { + event_mask = NAU8821_BUTTON; +- clear_irq = NAU8821_KEY_RELEASE_IRQ; ++ nau8821_irq_status_clear(regmap, NAU8821_KEY_RELEASE_IRQ); + } else if ((active_irq & NAU8821_JACK_INSERT_IRQ_MASK) == + NAU8821_JACK_INSERT_DETECTED) { + cancel_work_sync(&nau8821->jdet_work); +@@ -1215,27 +1227,17 @@ static irqreturn_t nau8821_interrupt(int irq, void *data) + /* detect microphone and jack type */ + schedule_work(&nau8821->jdet_work); + /* Turn off insertion interruption at manual mode */ +- regmap_update_bits(regmap, +- NAU8821_R12_INTERRUPT_DIS_CTRL, +- NAU8821_IRQ_INSERT_DIS, +- NAU8821_IRQ_INSERT_DIS); +- regmap_update_bits(regmap, +- NAU8821_R0F_INTERRUPT_MASK, +- NAU8821_IRQ_INSERT_EN, +- NAU8821_IRQ_INSERT_EN); + nau8821_setup_inserted_irq(nau8821); + } else { + dev_warn(nau8821->dev, + "Inserted IRQ fired but not connected\n"); + nau8821_eject_jack(nau8821); + } ++ } else { ++ /* Clear the rightmost interrupt */ ++ nau8821_irq_status_clear(regmap, active_irq); + } + +- if (!clear_irq) +- clear_irq = active_irq; +- /* clears the rightmost interruption */ +- regmap_write(regmap, NAU8821_R11_INT_CLR_KEY_STATUS, clear_irq); +- + if (event_mask) + snd_soc_jack_report(nau8821->jack, event, event_mask); + +-- +2.51.0 + diff --git a/queue-6.12/asoc-nau8821-fixup-nau8821_enable_jack_detect.patch b/queue-6.12/asoc-nau8821-fixup-nau8821_enable_jack_detect.patch new file mode 100644 index 0000000000..0d6760859a --- /dev/null +++ b/queue-6.12/asoc-nau8821-fixup-nau8821_enable_jack_detect.patch @@ -0,0 +1,84 @@ +From 881c275b9f21c1a4f8baf7f3e7ba62b94c2388c4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 31 Dec 2025 22:04:15 +0200 +Subject: ASoC: nau8821: Fixup nau8821_enable_jack_detect() + +From: Cristian Ciocaltea + +[ Upstream commit 70237853edf0a69773a7370eb74ea2a44dfe3050 ] + +The nau8821_enable_jack_detect() function was supposed to allow enabling +or disabling jack events reporting. However, once enabled, any +subsequent invocation would fail and the following splat is shown: + +[ 3136.996771] Hardware name: Valve Jupiter/Jupiter, BIOS F7A0131 01/30/2024 +[ 3136.996773] Workqueue: events_unbound deferred_probe_work_func +[ 3136.996780] Call Trace: +[ 3136.996782] +[ 3136.996787] dump_stack_lvl+0x6e/0xa0 +[ 3136.996796] __setup_irq.cold+0x9c/0xce +[ 3136.996803] ? __pfx_irq_default_primary_handler+0x10/0x10 +[ 3136.996812] ? __pfx_nau8821_interrupt+0x10/0x10 [snd_soc_nau8821] +[ 3136.996825] request_threaded_irq+0xd9/0x160 +[ 3136.996853] devm_request_threaded_irq+0x71/0xd0 +[ 3136.996859] ? __pfx_nau8821_interrupt+0x10/0x10 [snd_soc_nau8821] +[ 3136.996882] nau8821_enable_jack_detect+0xa5/0xc0 [snd_soc_nau8821] +[ 3136.996901] acp5x_8821_init+0x8d/0xa0 [snd_soc_acp5x_mach] +[ 3136.996917] snd_soc_link_init+0x25/0x50 [snd_soc_core] +[ 3136.996958] snd_soc_bind_card+0x615/0xd00 [snd_soc_core] +[ 3136.997026] snd_soc_register_card+0x1b2/0x1c0 [snd_soc_core] +[ 3136.997064] devm_snd_soc_register_card+0x47/0x90 [snd_soc_core] +[ 3136.997108] acp5x_probe+0x72/0xb0 [snd_soc_acp5x_mach] +[...] +[ 3136.997508] nau8821 i2c-NVTN2020:00: Cannot request irq 58 (-16) + +Introduce jdet_active flag to driver data structure and use it to +provide one-time initialization of the jack detection work queue and +related interrupt line. + +Note this is also a prerequisite for additional fixes around module +unloading and suspend handling. + +Fixes: aab1ad11d69f ("ASoC: nau8821: new driver") +Signed-off-by: Cristian Ciocaltea +Link: https://patch.msgid.link/20251231-nau8821-cleanup-v1-1-6b0b76cbbb64@collabora.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/nau8821.c | 5 +++++ + sound/soc/codecs/nau8821.h | 1 + + 2 files changed, 6 insertions(+) + +diff --git a/sound/soc/codecs/nau8821.c b/sound/soc/codecs/nau8821.c +index 9d006c4b6f284..2d040722ab881 100644 +--- a/sound/soc/codecs/nau8821.c ++++ b/sound/soc/codecs/nau8821.c +@@ -1662,8 +1662,13 @@ int nau8821_enable_jack_detect(struct snd_soc_component *component, + int ret; + + nau8821->jack = jack; ++ ++ if (nau8821->jdet_active) ++ return 0; ++ + /* Initiate jack detection work queue */ + INIT_DELAYED_WORK(&nau8821->jdet_work, nau8821_jdet_work); ++ nau8821->jdet_active = true; + + ret = devm_request_threaded_irq(nau8821->dev, nau8821->irq, NULL, + nau8821_interrupt, IRQF_TRIGGER_LOW | IRQF_ONESHOT, +diff --git a/sound/soc/codecs/nau8821.h b/sound/soc/codecs/nau8821.h +index 88602923780d8..f9d7cd8cbd211 100644 +--- a/sound/soc/codecs/nau8821.h ++++ b/sound/soc/codecs/nau8821.h +@@ -562,6 +562,7 @@ struct nau8821 { + struct snd_soc_dapm_context *dapm; + struct snd_soc_jack *jack; + struct delayed_work jdet_work; ++ bool jdet_active; + int irq; + int clk_id; + int micbias_voltage; +-- +2.51.0 + diff --git a/queue-6.12/audit-move-the-compat_xxx_class-extern-declarations-.patch b/queue-6.12/audit-move-the-compat_xxx_class-extern-declarations-.patch new file mode 100644 index 0000000000..2cc2bb84ef --- /dev/null +++ b/queue-6.12/audit-move-the-compat_xxx_class-extern-declarations-.patch @@ -0,0 +1,77 @@ +From 043c1f3bdff09392d392a77292f7ccb2a76f0bb4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 13:39:38 +0000 +Subject: audit: move the compat_xxx_class[] extern declarations to + audit_arch.h + +From: Ben Dooks + +[ Upstream commit 76489955c6d4a065ca69dc88faf7a50a59b66f35 ] + +The comapt_xxx_class symbols aren't declared in anything that +lib/comapt_audit.c is including (arm64 build) which is causing +the following sparse warnings: + +lib/compat_audit.c:7:10: warning: symbol 'compat_dir_class' + was not declared. Should it be static? +lib/compat_audit.c:12:10: warning: symbol 'compat_read_class' + was not declared. Should it be static? +lib/compat_audit.c:17:10: warning: symbol 'compat_write_class' + was not declared. Should it be static? +lib/compat_audit.c:22:10: warning: symbol 'compat_chattr_class' + was not declared. Should it be static? +lib/compat_audit.c:27:10: warning: symbol 'compat_signal_class' + was not declared. Should it be static? + +Trying to fix this by chaning compat_audit.c to inclde +does not work on arm64 due to compile errors with the extra includes +that changing this header makes. The simpler thing would be just to +move the definitons of these symbols out of into + which is included. + +Fixes: 4b58841149dca ("audit: Add generic compat syscall support") +Signed-off-by: Ben Dooks +[PM: rewrite subject line, fixed line length in description] +Signed-off-by: Paul Moore +Signed-off-by: Sasha Levin +--- + include/linux/audit.h | 6 ------ + include/linux/audit_arch.h | 7 +++++++ + 2 files changed, 7 insertions(+), 6 deletions(-) + +diff --git a/include/linux/audit.h b/include/linux/audit.h +index e3f06eba9c6e6..73fb8a4bcf2ae 100644 +--- a/include/linux/audit.h ++++ b/include/linux/audit.h +@@ -126,12 +126,6 @@ enum audit_nfcfgop { + extern int __init audit_register_class(int class, unsigned *list); + extern int audit_classify_syscall(int abi, unsigned syscall); + extern int audit_classify_arch(int arch); +-/* only for compat system calls */ +-extern unsigned compat_write_class[]; +-extern unsigned compat_read_class[]; +-extern unsigned compat_dir_class[]; +-extern unsigned compat_chattr_class[]; +-extern unsigned compat_signal_class[]; + + /* audit_names->type values */ + #define AUDIT_TYPE_UNKNOWN 0 /* we don't know yet */ +diff --git a/include/linux/audit_arch.h b/include/linux/audit_arch.h +index 0e34d673ef171..2b8153791e6a5 100644 +--- a/include/linux/audit_arch.h ++++ b/include/linux/audit_arch.h +@@ -23,4 +23,11 @@ enum auditsc_class_t { + + extern int audit_classify_compat_syscall(int abi, unsigned syscall); + ++/* only for compat system calls */ ++extern unsigned compat_write_class[]; ++extern unsigned compat_read_class[]; ++extern unsigned compat_dir_class[]; ++extern unsigned compat_chattr_class[]; ++extern unsigned compat_signal_class[]; ++ + #endif +-- +2.51.0 + diff --git a/queue-6.12/auxdisplay-arm-charlcd-fix-release_mem_region-size.patch b/queue-6.12/auxdisplay-arm-charlcd-fix-release_mem_region-size.patch new file mode 100644 index 0000000000..f87dff7f11 --- /dev/null +++ b/queue-6.12/auxdisplay-arm-charlcd-fix-release_mem_region-size.patch @@ -0,0 +1,39 @@ +From f09e1d460a5f83a220d9b7b5e4d1466edfcf9ab1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Dec 2025 18:47:13 +0100 +Subject: auxdisplay: arm-charlcd: fix release_mem_region() size + +From: Thomas Fourier + +[ Upstream commit b5c23a4d291d2ac1dfdd574a68a3a68c8da3069e ] + +It seems like, after the request_mem_region(), the corresponding +release_mem_region() must take the same size. This was done +in (now removed due to previous refactoring) charlcd_remove() +but not in the error path in charlcd_probe(). + +Fixes: ce8962455e90 ("ARM: 6214/2: driver for the character LCD found in ARM refdesigns") +Signed-off-by: Thomas Fourier +Reviewed-by: Geert Uytterhoeven +Signed-off-by: Andy Shevchenko +Signed-off-by: Sasha Levin +--- + drivers/auxdisplay/arm-charlcd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/auxdisplay/arm-charlcd.c b/drivers/auxdisplay/arm-charlcd.c +index a7eae99a48f77..4e22882f57c9c 100644 +--- a/drivers/auxdisplay/arm-charlcd.c ++++ b/drivers/auxdisplay/arm-charlcd.c +@@ -323,7 +323,7 @@ static int __init charlcd_probe(struct platform_device *pdev) + out_no_irq: + iounmap(lcd->virtbase); + out_no_memregion: +- release_mem_region(lcd->phybase, SZ_4K); ++ release_mem_region(lcd->phybase, lcd->physize); + out_no_resource: + kfree(lcd); + return ret; +-- +2.51.0 + diff --git a/queue-6.12/backlight-qcom-wled-change-pm8950-wled-configuration.patch b/queue-6.12/backlight-qcom-wled-change-pm8950-wled-configuration.patch new file mode 100644 index 0000000000..a84126cec4 --- /dev/null +++ b/queue-6.12/backlight-qcom-wled-change-pm8950-wled-configuration.patch @@ -0,0 +1,42 @@ +From 34abf343625cc9c823aa2987d100069d4cce3075 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 08:07:36 +0100 +Subject: backlight: qcom-wled: Change PM8950 WLED configurations +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Czémán + +[ Upstream commit 83333aa97441ba7ce32b91e8a007c72d316a1c67 ] + +PMI8950 WLED needs same configurations as PMI8994 WLED. + +Fixes: 10258bf4534b ("backlight: qcom-wled: Add PMI8950 compatible") +Signed-off-by: Barnabás Czémán +Reviewed-by: Konrad Dybcio +Reviewed-by: Daniel Thompson (RISCstar) +Link: https://patch.msgid.link/20260116-pmi8950-wled-v3-4-e6c93de84079@mainlining.org +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/video/backlight/qcom-wled.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c +index 79337e84069fb..0d55818f554ec 100644 +--- a/drivers/video/backlight/qcom-wled.c ++++ b/drivers/video/backlight/qcom-wled.c +@@ -1455,7 +1455,8 @@ static int wled_configure(struct wled *wled) + break; + + case 4: +- if (of_device_is_compatible(dev->of_node, "qcom,pmi8994-wled")) { ++ if (of_device_is_compatible(dev->of_node, "qcom,pmi8950-wled") || ++ of_device_is_compatible(dev->of_node, "qcom,pmi8994-wled")) { + u32_opts = pmi8994_wled_opts; + size = ARRAY_SIZE(pmi8994_wled_opts); + } else { +-- +2.51.0 + diff --git a/queue-6.12/backlight-qcom-wled-support-ovp-values-for-pmi8994.patch b/queue-6.12/backlight-qcom-wled-support-ovp-values-for-pmi8994.patch new file mode 100644 index 0000000000..897fd0a88e --- /dev/null +++ b/queue-6.12/backlight-qcom-wled-support-ovp-values-for-pmi8994.patch @@ -0,0 +1,94 @@ +From 880da58652cc81d2b4d26870d2fea372f00693ac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 08:07:34 +0100 +Subject: backlight: qcom-wled: Support ovp values for PMI8994 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Czémán + +[ Upstream commit f29f972a6e7e3f187ea4d89b98a76c1981ca4d53 ] + +WLED4 found in PMI8994 supports different ovp values. + +Fixes: 6fc632d3e3e0 ("video: backlight: qcom-wled: Add PMI8994 compatible") +Signed-off-by: Barnabás Czémán +Reviewed-by: Konrad Dybcio +Reviewed-by: Daniel Thompson (RISCstar) +Link: https://patch.msgid.link/20260116-pmi8950-wled-v3-2-e6c93de84079@mainlining.org +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/video/backlight/qcom-wled.c | 41 +++++++++++++++++++++++++++-- + 1 file changed, 39 insertions(+), 2 deletions(-) + +diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c +index b19e5f73de8bb..79337e84069fb 100644 +--- a/drivers/video/backlight/qcom-wled.c ++++ b/drivers/video/backlight/qcom-wled.c +@@ -1244,6 +1244,15 @@ static const struct wled_var_cfg wled4_ovp_cfg = { + .size = ARRAY_SIZE(wled4_ovp_values), + }; + ++static const u32 pmi8994_wled_ovp_values[] = { ++ 31000, 29500, 19400, 17800, ++}; ++ ++static const struct wled_var_cfg pmi8994_wled_ovp_cfg = { ++ .values = pmi8994_wled_ovp_values, ++ .size = ARRAY_SIZE(pmi8994_wled_ovp_values), ++}; ++ + static inline u32 wled5_ovp_values_fn(u32 idx) + { + /* +@@ -1357,6 +1366,29 @@ static int wled_configure(struct wled *wled) + }, + }; + ++ const struct wled_u32_opts pmi8994_wled_opts[] = { ++ { ++ .name = "qcom,current-boost-limit", ++ .val_ptr = &cfg->boost_i_limit, ++ .cfg = &wled4_boost_i_limit_cfg, ++ }, ++ { ++ .name = "qcom,current-limit-microamp", ++ .val_ptr = &cfg->string_i_limit, ++ .cfg = &wled4_string_i_limit_cfg, ++ }, ++ { ++ .name = "qcom,ovp-millivolt", ++ .val_ptr = &cfg->ovp, ++ .cfg = &pmi8994_wled_ovp_cfg, ++ }, ++ { ++ .name = "qcom,switching-freq", ++ .val_ptr = &cfg->switch_freq, ++ .cfg = &wled3_switch_freq_cfg, ++ }, ++ }; ++ + const struct wled_u32_opts wled5_opts[] = { + { + .name = "qcom,current-boost-limit", +@@ -1423,8 +1455,13 @@ static int wled_configure(struct wled *wled) + break; + + case 4: +- u32_opts = wled4_opts; +- size = ARRAY_SIZE(wled4_opts); ++ if (of_device_is_compatible(dev->of_node, "qcom,pmi8994-wled")) { ++ u32_opts = pmi8994_wled_opts; ++ size = ARRAY_SIZE(pmi8994_wled_opts); ++ } else { ++ u32_opts = wled4_opts; ++ size = ARRAY_SIZE(wled4_opts); ++ } + *cfg = wled4_config_defaults; + wled->wled_set_brightness = wled4_set_brightness; + wled->wled_sync_toggle = wled3_sync_toggle; +-- +2.51.0 + diff --git a/queue-6.12/block-add-a-bio_add_virt_nofail-helper.patch b/queue-6.12/block-add-a-bio_add_virt_nofail-helper.patch new file mode 100644 index 0000000000..f4bc0711f9 --- /dev/null +++ b/queue-6.12/block-add-a-bio_add_virt_nofail-helper.patch @@ -0,0 +1,71 @@ +From 93377cbb386791198e173b7268c7e767c115c786 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 May 2025 14:04:25 +0200 +Subject: block: add a bio_add_virt_nofail helper + +From: Christoph Hellwig + +[ Upstream commit 850e210d5ad21b94b55b97d4d82b4cdeb0bb05df ] + +Add a helper to add a directly mapped kernel virtual address to a +bio so that callers don't have to convert to pages or folios. + +For now only the _nofail variant is provided as that is what all the +obvious callers want. + +Signed-off-by: Christoph Hellwig +Reviewed-by: Damien Le Moal +Reviewed-by: Hannes Reinecke +Reviewed-by: Johannes Thumshirn +Link: https://lore.kernel.org/r/20250507120451.4000627-2-hch@lst.de +Signed-off-by: Jens Axboe +Stable-dep-of: 4ac9690d4b94 ("rnbd-srv: Fix server side setting of bi_size for special IOs") +Signed-off-by: Sasha Levin +--- + block/bio.c | 16 ++++++++++++++++ + include/linux/bio.h | 2 ++ + 2 files changed, 18 insertions(+) + +diff --git a/block/bio.c b/block/bio.c +index 094a5adf79d23..b919f3fa2f2d4 100644 +--- a/block/bio.c ++++ b/block/bio.c +@@ -1119,6 +1119,22 @@ void __bio_add_page(struct bio *bio, struct page *page, + } + EXPORT_SYMBOL_GPL(__bio_add_page); + ++/** ++ * bio_add_virt_nofail - add data in the direct kernel mapping to a bio ++ * @bio: destination bio ++ * @vaddr: data to add ++ * @len: length of the data to add, may cross pages ++ * ++ * Add the data at @vaddr to @bio. The caller must have ensure a segment ++ * is available for the added data. No merging into an existing segment ++ * will be performed. ++ */ ++void bio_add_virt_nofail(struct bio *bio, void *vaddr, unsigned len) ++{ ++ __bio_add_page(bio, virt_to_page(vaddr), len, offset_in_page(vaddr)); ++} ++EXPORT_SYMBOL_GPL(bio_add_virt_nofail); ++ + /** + * bio_add_page - attempt to add page(s) to bio + * @bio: destination bio +diff --git a/include/linux/bio.h b/include/linux/bio.h +index 1289b8e487801..80ca2fb879504 100644 +--- a/include/linux/bio.h ++++ b/include/linux/bio.h +@@ -425,6 +425,8 @@ void __bio_add_page(struct bio *bio, struct page *page, + unsigned int len, unsigned int off); + void bio_add_folio_nofail(struct bio *bio, struct folio *folio, size_t len, + size_t off); ++void bio_add_virt_nofail(struct bio *bio, void *vaddr, unsigned len); ++ + int bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter); + void bio_iov_bvec_set(struct bio *bio, struct iov_iter *iter); + void __bio_release_pages(struct bio *bio, bool mark_dirty); +-- +2.51.0 + diff --git a/queue-6.12/bluetooth-btintel_pcie-use-irqf_oneshot-and-default-.patch b/queue-6.12/bluetooth-btintel_pcie-use-irqf_oneshot-and-default-.patch new file mode 100644 index 0000000000..4b63f3d454 --- /dev/null +++ b/queue-6.12/bluetooth-btintel_pcie-use-irqf_oneshot-and-default-.patch @@ -0,0 +1,61 @@ +From 1070b4636f5337683cd131a763b07edcdfb8ab50 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:55:26 +0100 +Subject: Bluetooth: btintel_pcie: Use IRQF_ONESHOT and default primary handler + +From: Sebastian Andrzej Siewior + +[ Upstream commit 28abed6569c87eab9071ab56c64433c2f0d9ce51 ] + +There is no added value in btintel_pcie_msix_isr() compared to +irq_default_primary_handler(). + +Using a threaded interrupt without a dedicated primary handler mandates +the IRQF_ONESHOT flag to mask the interrupt source while the threaded +handler is active. Otherwise the interrupt can fire again before the +threaded handler had a chance to run. + +Use the default primary interrupt handler by specifying NULL and set +IRQF_ONESHOT so the interrupt source is masked until the secondary +handler is done. + +Fixes: c2b636b3f788d ("Bluetooth: btintel_pcie: Add support for PCIe transport") +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260128095540.863589-7-bigeasy@linutronix.de +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/btintel_pcie.c | 9 ++------- + 1 file changed, 2 insertions(+), 7 deletions(-) + +diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c +index 34812bf7587d6..d430645657e3d 100644 +--- a/drivers/bluetooth/btintel_pcie.c ++++ b/drivers/bluetooth/btintel_pcie.c +@@ -798,11 +798,6 @@ static void btintel_pcie_msix_rx_handle(struct btintel_pcie_data *data) + } + } + +-static irqreturn_t btintel_pcie_msix_isr(int irq, void *data) +-{ +- return IRQ_WAKE_THREAD; +-} +- + static inline bool btintel_pcie_is_rxq_empty(struct btintel_pcie_data *data) + { + return data->ia.cr_hia[BTINTEL_PCIE_RXQ_NUM] == data->ia.cr_tia[BTINTEL_PCIE_RXQ_NUM]; +@@ -896,9 +891,9 @@ static int btintel_pcie_setup_irq(struct btintel_pcie_data *data) + + err = devm_request_threaded_irq(&data->pdev->dev, + msix_entry->vector, +- btintel_pcie_msix_isr, ++ NULL, + btintel_pcie_irq_msix_handler, +- IRQF_SHARED, ++ IRQF_ONESHOT | IRQF_SHARED, + KBUILD_MODNAME, + msix_entry); + if (err) { +-- +2.51.0 + diff --git a/queue-6.12/bonding-only-set-speed-duplex-to-unknown-if-getting-.patch b/queue-6.12/bonding-only-set-speed-duplex-to-unknown-if-getting-.patch new file mode 100644 index 0000000000..0a42015666 --- /dev/null +++ b/queue-6.12/bonding-only-set-speed-duplex-to-unknown-if-getting-.patch @@ -0,0 +1,74 @@ +From 9c3128a426628ae20c82801927dc4430410d7259 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 15:11:52 +0100 +Subject: bonding: only set speed/duplex to unknown, if getting speed failed + +From: Thomas Bogendoerfer + +[ Upstream commit 48dec8d88af96039a4a17b8c2f148f2a4066e195 ] + +bond_update_speed_duplex() first set speed/duplex to unknown and +then asks slave driver for current speed/duplex. Since getting +speed/duplex might take longer there is a race, where this false state +is visible by /proc/net/bonding. With commit 691b2bf14946 ("bonding: + update port speed when getting bond speed") this race gets more visible, +if user space is calling ethtool on a regular base. + +Fix this by only setting speed/duplex to unknown, if link speed is +really unknown/unusable. + +Fixes: 98f41f694f46 ("bonding:update speed/duplex for NETDEV_CHANGE") +Signed-off-by: Thomas Bogendoerfer +Acked-by: Jay Vosburgh +Reviewed-by: Nikolay Aleksandrov +Reviewed-by: Hangbin Liu +Link: https://patch.msgid.link/20260203141153.51581-1-tbogendoerfer@suse.de +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/bonding/bond_main.c | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c +index 209cab75ac0a5..95456a753b184 100644 +--- a/drivers/net/bonding/bond_main.c ++++ b/drivers/net/bonding/bond_main.c +@@ -803,26 +803,29 @@ static int bond_update_speed_duplex(struct slave *slave) + struct ethtool_link_ksettings ecmd; + int res; + +- slave->speed = SPEED_UNKNOWN; +- slave->duplex = DUPLEX_UNKNOWN; +- + res = __ethtool_get_link_ksettings(slave_dev, &ecmd); + if (res < 0) +- return 1; ++ goto speed_duplex_unknown; + if (ecmd.base.speed == 0 || ecmd.base.speed == ((__u32)-1)) +- return 1; ++ goto speed_duplex_unknown; + switch (ecmd.base.duplex) { + case DUPLEX_FULL: + case DUPLEX_HALF: + break; + default: +- return 1; ++ goto speed_duplex_unknown; + } + + slave->speed = ecmd.base.speed; + slave->duplex = ecmd.base.duplex; + + return 0; ++ ++speed_duplex_unknown: ++ slave->speed = SPEED_UNKNOWN; ++ slave->duplex = DUPLEX_UNKNOWN; ++ ++ return 1; + } + + const char *bond_slave_link_status(s8 link) +-- +2.51.0 + diff --git a/queue-6.12/bpf-fix-bpf_xdp_store_bytes-proto-for-read-only-arg.patch b/queue-6.12/bpf-fix-bpf_xdp_store_bytes-proto-for-read-only-arg.patch new file mode 100644 index 0000000000..e018e80fb9 --- /dev/null +++ b/queue-6.12/bpf-fix-bpf_xdp_store_bytes-proto-for-read-only-arg.patch @@ -0,0 +1,60 @@ +From a0f5098c5a4b6c040f7d57d38d00d47098954d81 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Jan 2026 17:08:37 +0100 +Subject: bpf: Fix bpf_xdp_store_bytes proto for read-only arg + +From: Paul Chaignon + +[ Upstream commit 6557f1565d779851c4db9c488c49c05a47a6e72f ] + +While making some maps in Cilium read-only from the BPF side, we noticed +that the bpf_xdp_store_bytes proto is incorrect. In particular, the +verifier was throwing the following error: + + ; ret = ctx_store_bytes(ctx, l3_off + offsetof(struct iphdr, saddr), + &nat->address, 4, 0); + 635: (79) r1 = *(u64 *)(r10 -144) ; R1=ctx() R10=fp0 fp-144=ctx() + 636: (b4) w2 = 26 ; R2=26 + 637: (b4) w4 = 4 ; R4=4 + 638: (b4) w5 = 0 ; R5=0 + 639: (85) call bpf_xdp_store_bytes#190 + write into map forbidden, value_size=6 off=0 size=4 + +nat comes from a BPF_F_RDONLY_PROG map, so R3 is a PTR_TO_MAP_VALUE. +The verifier checks the helper's memory access to R3 in +check_mem_size_reg, as it reaches ARG_CONST_SIZE argument. The third +argument has expected type ARG_PTR_TO_UNINIT_MEM, which includes the +MEM_WRITE flag. The verifier thus checks for a BPF_WRITE access on R3. +Given R3 points to a read-only map, the check fails. + +Conversely, ARG_PTR_TO_UNINIT_MEM can also lead to the helper reading +from uninitialized memory. + +This patch simply fixes the expected argument type to match that of +bpf_skb_store_bytes. + +Fixes: 3f364222d032 ("net: xdp: introduce bpf_xdp_pointer utility routine") +Signed-off-by: Paul Chaignon +Link: https://lore.kernel.org/r/9fa3c9f72d806e82541071c4df88b8cba28ad6a9.1769875479.git.paul.chaignon@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + net/core/filter.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/core/filter.c b/net/core/filter.c +index 06e179865a21b..182a7388e84f5 100644 +--- a/net/core/filter.c ++++ b/net/core/filter.c +@@ -4140,7 +4140,7 @@ static const struct bpf_func_proto bpf_xdp_store_bytes_proto = { + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_CTX, + .arg2_type = ARG_ANYTHING, +- .arg3_type = ARG_PTR_TO_UNINIT_MEM, ++ .arg3_type = ARG_PTR_TO_MEM | MEM_RDONLY, + .arg4_type = ARG_CONST_SIZE, + }; + +-- +2.51.0 + diff --git a/queue-6.12/bpf-preserve-id-of-register-in-sync_linked_regs.patch b/queue-6.12/bpf-preserve-id-of-register-in-sync_linked_regs.patch new file mode 100644 index 0000000000..5ff18aebab --- /dev/null +++ b/queue-6.12/bpf-preserve-id-of-register-in-sync_linked_regs.patch @@ -0,0 +1,95 @@ +From d653fa70477c0f9e090dab86eb3eb2fa38191b02 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 07:11:40 -0800 +Subject: bpf: Preserve id of register in sync_linked_regs() + +From: Puranjay Mohan + +[ Upstream commit af9e89d8dd39530c8bd14c33ddf6b502df1071b6 ] + +sync_linked_regs() copies the id of known_reg to reg when propagating +bounds of known_reg to reg using the off of known_reg, but when +known_reg was linked to reg like: + +known_reg = reg ; both known_reg and reg get same id +known_reg += 4 ; known_reg gets off = 4, and its id gets BPF_ADD_CONST + +now when a call to sync_linked_regs() happens, let's say with the following: + +if known_reg >= 10 goto pc+2 + +known_reg's new bounds are propagated to reg but now reg gets +BPF_ADD_CONST from the copy. + +This means if another link to reg is created like: + +another_reg = reg ; another_reg should get the id of reg but + assign_scalar_id_before_mov() sees + BPF_ADD_CONST on reg and assigns a new id to it. + +As reg has a new id now, known_reg's link to reg is broken. If we find +new bounds for known_reg, they will not be propagated to reg. + +This can be seen in the selftest added in the next commit: + +0: (85) call bpf_get_prandom_u32#7 ; R0=scalar() +1: (57) r0 &= 255 ; R0=scalar(smin=smin32=0,smax=umax=smax32=umax32=255,var_off=(0x0; 0xff)) +2: (bf) r1 = r0 ; R0=scalar(id=1,smin=smin32=0,smax=umax=smax32=umax32=255,var_off=(0x0; 0xff)) R1=scalar(id=1,smin=smin32=0,smax=umax=smax32=umax32=255,var_off=(0x0; 0xff)) +3: (07) r1 += 4 ; R1=scalar(id=1+4,smin=umin=smin32=umin32=4,smax=umax=smax32=umax32=259,var_off=(0x0; 0x1ff)) +4: (a5) if r1 < 0xa goto pc+4 ; R1=scalar(id=1+4,smin=umin=smin32=umin32=10,smax=umax=smax32=umax32=259,var_off=(0x0; 0x1ff)) +5: (bf) r2 = r0 ; R0=scalar(id=2,smin=umin=smin32=umin32=6,smax=umax=smax32=umax32=255) R2=scalar(id=2,smin=umin=smin32=umin32=6,smax=umax=smax32=umax32=255) +6: (a5) if r1 < 0xe goto pc+2 ; R1=scalar(id=1+4,smin=umin=smin32=umin32=14,smax=umax=smax32=umax32=259,var_off=(0x0; 0x1ff)) +7: (35) if r0 >= 0xa goto pc+1 ; R0=scalar(id=2,smin=umin=smin32=umin32=6,smax=umax=smax32=umax32=9,var_off=(0x0; 0xf)) +8: (37) r0 /= 0 +div by zero + +When 4 is verified, r1's bounds are propagated to r0 but r0 also gets +BPF_ADD_CONST (bug). +When 5 is verified, r0 gets a new id (2) and its link with r1 is broken. + +After 6 we know r1 has bounds [14, 259] and therefore r0 should have +bounds [10, 255], therefore the branch at 7 is always taken. But because +r0's id was changed to 2, r1's new bounds are not propagated to r0. +The verifier still thinks r0 has bounds [6, 255] before 7 and execution +can reach div by zero. + +Fix this by preserving id in sync_linked_regs() like off and subreg_def. + +Fixes: 98d7ca374ba4 ("bpf: Track delta between "linked" registers.") +Signed-off-by: Puranjay Mohan +Acked-by: Eduard Zingerman +Link: https://lore.kernel.org/r/20260115151143.1344724-2-puranjay@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/verifier.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index 7b75a2dd8cb8f..08cdf6ace02ac 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -15478,6 +15478,7 @@ static void sync_linked_regs(struct bpf_verifier_state *vstate, struct bpf_reg_s + } else { + s32 saved_subreg_def = reg->subreg_def; + s32 saved_off = reg->off; ++ u32 saved_id = reg->id; + + fake_reg.type = SCALAR_VALUE; + __mark_reg_known(&fake_reg, (s32)reg->off - (s32)known_reg->off); +@@ -15485,10 +15486,11 @@ static void sync_linked_regs(struct bpf_verifier_state *vstate, struct bpf_reg_s + /* reg = known_reg; reg += delta */ + copy_register_state(reg, known_reg); + /* +- * Must preserve off, id and add_const flag, ++ * Must preserve off, id and subreg_def flag, + * otherwise another sync_linked_regs() will be incorrect. + */ + reg->off = saved_off; ++ reg->id = saved_id; + reg->subreg_def = saved_subreg_def; + + scalar32_min_max_add(reg, &fake_reg); +-- +2.51.0 + diff --git a/queue-6.12/bpf-sockmap-fix-fionread-for-sockmap.patch b/queue-6.12/bpf-sockmap-fix-fionread-for-sockmap.patch new file mode 100644 index 0000000000..14bb2bf8c8 --- /dev/null +++ b/queue-6.12/bpf-sockmap-fix-fionread-for-sockmap.patch @@ -0,0 +1,293 @@ +From e33180fcb439b3f8b17ea1e40ba35ce85e98bb16 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 24 Jan 2026 19:32:44 +0800 +Subject: bpf, sockmap: Fix FIONREAD for sockmap + +From: Jiayuan Chen + +[ Upstream commit 929e30f9312514902133c45e51c79088421ab084 ] + +A socket using sockmap has its own independent receive queue: ingress_msg. +This queue may contain data from its own protocol stack or from other +sockets. + +Therefore, for sockmap, relying solely on copied_seq and rcv_nxt to +calculate FIONREAD is not enough. + +This patch adds a new msg_tot_len field in the psock structure to record +the data length in ingress_msg. Additionally, we implement new ioctl +interfaces for TCP and UDP to intercept FIONREAD operations. + +Note that we intentionally do not include sk_receive_queue data in the +FIONREAD result. Data in sk_receive_queue has not yet been processed by +the BPF verdict program, and may be redirected to other sockets or +dropped. Including it would create semantic ambiguity since this data +may never be readable by the user. + +Unix and VSOCK sockets have similar issues, but fixing them is outside +the scope of this patch as it would require more intrusive changes. + +Previous work by John Fastabend made some efforts towards FIONREAD support: +commit e5c6de5fa025 ("bpf, sockmap: Incorrectly handling copied_seq") +Although the current patch is based on the previous work by John Fastabend, +it is acceptable for our Fixes tag to point to the same commit. + + FD1:read() + -- FD1->copied_seq++ + | [read data] + | + [enqueue data] v + [sockmap] -> ingress to self -> ingress_msg queue +FD1 native stack ------> ^ +-- FD1->rcv_nxt++ -> redirect to other | [enqueue data] + | | + | ingress to FD1 + v ^ + ... | [sockmap] + FD2 native stack + +Fixes: 04919bed948dc ("tcp: Introduce tcp_read_skb()") +Signed-off-by: Jiayuan Chen +Reviewed-by: Jakub Sitnicki +Link: https://lore.kernel.org/r/20260124113314.113584-3-jiayuan.chen@linux.dev +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + include/linux/skmsg.h | 68 +++++++++++++++++++++++++++++++++++++++++-- + net/core/skmsg.c | 3 ++ + net/ipv4/tcp_bpf.c | 20 +++++++++++++ + net/ipv4/udp_bpf.c | 23 ++++++++++++--- + 4 files changed, 108 insertions(+), 6 deletions(-) + +diff --git a/include/linux/skmsg.h b/include/linux/skmsg.h +index da1e6274c5586..5581e7263c504 100644 +--- a/include/linux/skmsg.h ++++ b/include/linux/skmsg.h +@@ -97,6 +97,8 @@ struct sk_psock { + struct sk_buff_head ingress_skb; + struct list_head ingress_msg; + spinlock_t ingress_lock; ++ /** @msg_tot_len: Total bytes queued in ingress_msg list. */ ++ u32 msg_tot_len; + unsigned long state; + struct list_head link; + spinlock_t link_lock; +@@ -321,6 +323,27 @@ static inline void sock_drop(struct sock *sk, struct sk_buff *skb) + kfree_skb(skb); + } + ++static inline u32 sk_psock_get_msg_len_nolock(struct sk_psock *psock) ++{ ++ /* Used by ioctl to read msg_tot_len only; lock-free for performance */ ++ return READ_ONCE(psock->msg_tot_len); ++} ++ ++static inline void sk_psock_msg_len_add_locked(struct sk_psock *psock, int diff) ++{ ++ /* Use WRITE_ONCE to ensure correct read in sk_psock_get_msg_len_nolock(). ++ * ingress_lock should be held to prevent concurrent updates to msg_tot_len ++ */ ++ WRITE_ONCE(psock->msg_tot_len, psock->msg_tot_len + diff); ++} ++ ++static inline void sk_psock_msg_len_add(struct sk_psock *psock, int diff) ++{ ++ spin_lock_bh(&psock->ingress_lock); ++ sk_psock_msg_len_add_locked(psock, diff); ++ spin_unlock_bh(&psock->ingress_lock); ++} ++ + static inline bool sk_psock_queue_msg(struct sk_psock *psock, + struct sk_msg *msg) + { +@@ -329,6 +352,7 @@ static inline bool sk_psock_queue_msg(struct sk_psock *psock, + spin_lock_bh(&psock->ingress_lock); + if (sk_psock_test_state(psock, SK_PSOCK_TX_ENABLED)) { + list_add_tail(&msg->list, &psock->ingress_msg); ++ sk_psock_msg_len_add_locked(psock, msg->sg.size); + ret = true; + } else { + sk_msg_free(psock->sk, msg); +@@ -345,18 +369,25 @@ static inline struct sk_msg *sk_psock_dequeue_msg(struct sk_psock *psock) + + spin_lock_bh(&psock->ingress_lock); + msg = list_first_entry_or_null(&psock->ingress_msg, struct sk_msg, list); +- if (msg) ++ if (msg) { + list_del(&msg->list); ++ sk_psock_msg_len_add_locked(psock, -msg->sg.size); ++ } + spin_unlock_bh(&psock->ingress_lock); + return msg; + } + ++static inline struct sk_msg *sk_psock_peek_msg_locked(struct sk_psock *psock) ++{ ++ return list_first_entry_or_null(&psock->ingress_msg, struct sk_msg, list); ++} ++ + static inline struct sk_msg *sk_psock_peek_msg(struct sk_psock *psock) + { + struct sk_msg *msg; + + spin_lock_bh(&psock->ingress_lock); +- msg = list_first_entry_or_null(&psock->ingress_msg, struct sk_msg, list); ++ msg = sk_psock_peek_msg_locked(psock); + spin_unlock_bh(&psock->ingress_lock); + return msg; + } +@@ -523,6 +554,39 @@ static inline bool sk_psock_strp_enabled(struct sk_psock *psock) + return !!psock->saved_data_ready; + } + ++/* for tcp only, sk is locked */ ++static inline ssize_t sk_psock_msg_inq(struct sock *sk) ++{ ++ struct sk_psock *psock; ++ ssize_t inq = 0; ++ ++ psock = sk_psock_get(sk); ++ if (likely(psock)) { ++ inq = sk_psock_get_msg_len_nolock(psock); ++ sk_psock_put(sk, psock); ++ } ++ return inq; ++} ++ ++/* for udp only, sk is not locked */ ++static inline ssize_t sk_msg_first_len(struct sock *sk) ++{ ++ struct sk_psock *psock; ++ struct sk_msg *msg; ++ ssize_t inq = 0; ++ ++ psock = sk_psock_get(sk); ++ if (likely(psock)) { ++ spin_lock_bh(&psock->ingress_lock); ++ msg = sk_psock_peek_msg_locked(psock); ++ if (msg) ++ inq = msg->sg.size; ++ spin_unlock_bh(&psock->ingress_lock); ++ sk_psock_put(sk, psock); ++ } ++ return inq; ++} ++ + #if IS_ENABLED(CONFIG_NET_SOCK_MSG) + + #define BPF_F_STRPARSER (1UL << 1) +diff --git a/net/core/skmsg.c b/net/core/skmsg.c +index 4a274caf75fc6..6ece4eaecd489 100644 +--- a/net/core/skmsg.c ++++ b/net/core/skmsg.c +@@ -457,6 +457,7 @@ int __sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg + atomic_sub(copy, &sk->sk_rmem_alloc); + } + msg_rx->sg.size -= copy; ++ sk_psock_msg_len_add(psock, -copy); + + if (!sge->length) { + sk_msg_iter_var_next(i); +@@ -820,9 +821,11 @@ static void __sk_psock_purge_ingress_msg(struct sk_psock *psock) + list_del(&msg->list); + if (!msg->skb) + atomic_sub(msg->sg.size, &psock->sk->sk_rmem_alloc); ++ sk_psock_msg_len_add(psock, -msg->sg.size); + sk_msg_free(psock->sk, msg); + kfree(msg); + } ++ WARN_ON_ONCE(psock->msg_tot_len); + } + + static void __sk_psock_zap_ingress(struct sk_psock *psock) +diff --git a/net/ipv4/tcp_bpf.c b/net/ipv4/tcp_bpf.c +index 8bd3d8b8dddab..f5817438f1734 100644 +--- a/net/ipv4/tcp_bpf.c ++++ b/net/ipv4/tcp_bpf.c +@@ -10,6 +10,7 @@ + + #include + #include ++#include + + void tcp_eat_skb(struct sock *sk, struct sk_buff *skb) + { +@@ -332,6 +333,24 @@ static int tcp_bpf_recvmsg_parser(struct sock *sk, + return copied; + } + ++static int tcp_bpf_ioctl(struct sock *sk, int cmd, int *karg) ++{ ++ bool slow; ++ ++ if (cmd != SIOCINQ) ++ return tcp_ioctl(sk, cmd, karg); ++ ++ /* works similar as tcp_ioctl */ ++ if (sk->sk_state == TCP_LISTEN) ++ return -EINVAL; ++ ++ slow = lock_sock_fast(sk); ++ *karg = sk_psock_msg_inq(sk); ++ unlock_sock_fast(sk, slow); ++ ++ return 0; ++} ++ + static int tcp_bpf_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, + int flags, int *addr_len) + { +@@ -610,6 +629,7 @@ static void tcp_bpf_rebuild_protos(struct proto prot[TCP_BPF_NUM_CFGS], + prot[TCP_BPF_BASE].close = sock_map_close; + prot[TCP_BPF_BASE].recvmsg = tcp_bpf_recvmsg; + prot[TCP_BPF_BASE].sock_is_readable = sk_msg_is_readable; ++ prot[TCP_BPF_BASE].ioctl = tcp_bpf_ioctl; + + prot[TCP_BPF_TX] = prot[TCP_BPF_BASE]; + prot[TCP_BPF_TX].sendmsg = tcp_bpf_sendmsg; +diff --git a/net/ipv4/udp_bpf.c b/net/ipv4/udp_bpf.c +index 0735d820e413f..91233e37cd97a 100644 +--- a/net/ipv4/udp_bpf.c ++++ b/net/ipv4/udp_bpf.c +@@ -5,6 +5,7 @@ + #include + #include + #include ++#include + + #include "udp_impl.h" + +@@ -111,12 +112,26 @@ enum { + static DEFINE_SPINLOCK(udpv6_prot_lock); + static struct proto udp_bpf_prots[UDP_BPF_NUM_PROTS]; + ++static int udp_bpf_ioctl(struct sock *sk, int cmd, int *karg) ++{ ++ if (cmd != SIOCINQ) ++ return udp_ioctl(sk, cmd, karg); ++ ++ /* Since we don't hold a lock, sk_receive_queue may contain data. ++ * BPF might only be processing this data at the moment. We only ++ * care about the data in the ingress_msg here. ++ */ ++ *karg = sk_msg_first_len(sk); ++ return 0; ++} ++ + static void udp_bpf_rebuild_protos(struct proto *prot, const struct proto *base) + { +- *prot = *base; +- prot->close = sock_map_close; +- prot->recvmsg = udp_bpf_recvmsg; +- prot->sock_is_readable = sk_msg_is_readable; ++ *prot = *base; ++ prot->close = sock_map_close; ++ prot->recvmsg = udp_bpf_recvmsg; ++ prot->sock_is_readable = sk_msg_is_readable; ++ prot->ioctl = udp_bpf_ioctl; + } + + static void udp_bpf_check_v6_needs_rebuild(struct proto *ops) +-- +2.51.0 + diff --git a/queue-6.12/bpf-sockmap-fix-incorrect-copied_seq-calculation.patch b/queue-6.12/bpf-sockmap-fix-incorrect-copied_seq-calculation.patch new file mode 100644 index 0000000000..5c93beb310 --- /dev/null +++ b/queue-6.12/bpf-sockmap-fix-incorrect-copied_seq-calculation.patch @@ -0,0 +1,178 @@ +From ceba595fcd2bceed1e0f2413fa7ab06da9449f8f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 24 Jan 2026 19:32:43 +0800 +Subject: bpf, sockmap: Fix incorrect copied_seq calculation + +From: Jiayuan Chen + +[ Upstream commit b40cc5adaa80e1471095a62d78233b611d7a558c ] + +A socket using sockmap has its own independent receive queue: ingress_msg. +This queue may contain data from its own protocol stack or from other +sockets. + +The issue is that when reading from ingress_msg, we update tp->copied_seq +by default. However, if the data is not from its own protocol stack, +tcp->rcv_nxt is not increased. Later, if we convert this socket to a +native socket, reading from this socket may fail because copied_seq might +be significantly larger than rcv_nxt. + +This fix also addresses the syzkaller-reported bug referenced in the +Closes tag. + +This patch marks the skmsg objects in ingress_msg. When reading, we update +copied_seq only if the data is from its own protocol stack. + + FD1:read() + -- FD1->copied_seq++ + | [read data] + | + [enqueue data] v + [sockmap] -> ingress to self -> ingress_msg queue +FD1 native stack ------> ^ +-- FD1->rcv_nxt++ -> redirect to other | [enqueue data] + | | + | ingress to FD1 + v ^ + ... | [sockmap] + FD2 native stack + +Closes: https://syzkaller.appspot.com/bug?extid=06dbd397158ec0ea4983 +Fixes: 04919bed948dc ("tcp: Introduce tcp_read_skb()") +Reviewed-by: Jakub Sitnicki +Reviewed-by: John Fastabend +Signed-off-by: Jiayuan Chen +Link: https://lore.kernel.org/r/20260124113314.113584-2-jiayuan.chen@linux.dev +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + include/linux/skmsg.h | 2 ++ + net/core/skmsg.c | 27 ++++++++++++++++++++++++--- + net/ipv4/tcp_bpf.c | 5 +++-- + 3 files changed, 29 insertions(+), 5 deletions(-) + +diff --git a/include/linux/skmsg.h b/include/linux/skmsg.h +index 0b9095a281b89..da1e6274c5586 100644 +--- a/include/linux/skmsg.h ++++ b/include/linux/skmsg.h +@@ -141,6 +141,8 @@ int sk_msg_memcopy_from_iter(struct sock *sk, struct iov_iter *from, + struct sk_msg *msg, u32 bytes); + int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, + int len, int flags); ++int __sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, ++ int len, int flags, int *copied_from_self); + bool sk_msg_is_readable(struct sock *sk); + + static inline void sk_msg_check_to_free(struct sk_msg *msg, u32 i, u32 bytes) +diff --git a/net/core/skmsg.c b/net/core/skmsg.c +index adb3166ede972..4a274caf75fc6 100644 +--- a/net/core/skmsg.c ++++ b/net/core/skmsg.c +@@ -408,22 +408,26 @@ int sk_msg_memcopy_from_iter(struct sock *sk, struct iov_iter *from, + } + EXPORT_SYMBOL_GPL(sk_msg_memcopy_from_iter); + +-/* Receive sk_msg from psock->ingress_msg to @msg. */ +-int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, +- int len, int flags) ++int __sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, ++ int len, int flags, int *copied_from_self) + { + struct iov_iter *iter = &msg->msg_iter; + int peek = flags & MSG_PEEK; + struct sk_msg *msg_rx; + int i, copied = 0; ++ bool from_self; + + msg_rx = sk_psock_peek_msg(psock); ++ if (copied_from_self) ++ *copied_from_self = 0; ++ + while (copied != len) { + struct scatterlist *sge; + + if (unlikely(!msg_rx)) + break; + ++ from_self = msg_rx->sk == sk; + i = msg_rx->sg.start; + do { + struct page *page; +@@ -442,6 +446,9 @@ int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, + } + + copied += copy; ++ if (from_self && copied_from_self) ++ *copied_from_self += copy; ++ + if (likely(!peek)) { + sge->offset += copy; + sge->length -= copy; +@@ -486,6 +493,13 @@ int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, + out: + return copied; + } ++ ++/* Receive sk_msg from psock->ingress_msg to @msg. */ ++int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, ++ int len, int flags) ++{ ++ return __sk_msg_recvmsg(sk, psock, msg, len, flags, NULL); ++} + EXPORT_SYMBOL_GPL(sk_msg_recvmsg); + + bool sk_msg_is_readable(struct sock *sk) +@@ -615,6 +629,12 @@ static int sk_psock_skb_ingress_self(struct sk_psock *psock, struct sk_buff *skb + if (unlikely(!msg)) + return -EAGAIN; + skb_set_owner_r(skb, sk); ++ ++ /* This is used in tcp_bpf_recvmsg_parser() to determine whether the ++ * data originates from the socket's own protocol stack. No need to ++ * refcount sk because msg's lifetime is bound to sk via the ingress_msg. ++ */ ++ msg->sk = sk; + err = sk_psock_skb_ingress_enqueue(skb, off, len, psock, sk, msg, take_ref); + if (err < 0) + kfree(msg); +@@ -908,6 +928,7 @@ int sk_psock_msg_verdict(struct sock *sk, struct sk_psock *psock, + sk_msg_compute_data_pointers(msg); + msg->sk = sk; + ret = bpf_prog_run_pin_on_cpu(prog, msg); ++ msg->sk = NULL; + ret = sk_psock_map_verd(ret, msg->sk_redir); + psock->apply_bytes = msg->apply_bytes; + if (ret == __SK_REDIRECT) { +diff --git a/net/ipv4/tcp_bpf.c b/net/ipv4/tcp_bpf.c +index 8372ca512a755..8bd3d8b8dddab 100644 +--- a/net/ipv4/tcp_bpf.c ++++ b/net/ipv4/tcp_bpf.c +@@ -226,6 +226,7 @@ static int tcp_bpf_recvmsg_parser(struct sock *sk, + int peek = flags & MSG_PEEK; + struct sk_psock *psock; + struct tcp_sock *tcp; ++ int copied_from_self = 0; + int copied = 0; + u32 seq; + +@@ -262,7 +263,7 @@ static int tcp_bpf_recvmsg_parser(struct sock *sk, + } + + msg_bytes_ready: +- copied = sk_msg_recvmsg(sk, psock, msg, len, flags); ++ copied = __sk_msg_recvmsg(sk, psock, msg, len, flags, &copied_from_self); + /* The typical case for EFAULT is the socket was gracefully + * shutdown with a FIN pkt. So check here the other case is + * some error on copy_page_to_iter which would be unexpected. +@@ -277,7 +278,7 @@ static int tcp_bpf_recvmsg_parser(struct sock *sk, + goto out; + } + } +- seq += copied; ++ seq += copied_from_self; + if (!copied) { + long timeo; + int data; +-- +2.51.0 + diff --git a/queue-6.12/btrfs-fix-block_group_tree-dirty_list-corruption.patch b/queue-6.12/btrfs-fix-block_group_tree-dirty_list-corruption.patch new file mode 100644 index 0000000000..dd46a75579 --- /dev/null +++ b/queue-6.12/btrfs-fix-block_group_tree-dirty_list-corruption.patch @@ -0,0 +1,150 @@ +From e69a2590d2b7ec560a5c90fde81b4ea08c5e7b37 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 22 Dec 2025 16:15:44 -0800 +Subject: btrfs: fix block_group_tree dirty_list corruption + +From: Boris Burkov + +[ Upstream commit 3a1f4264daed4b419c325a7fe35e756cada3cf82 ] + +When the incompat flag EXTENT_TREE_V2 is set, we unconditionally add the +block group tree to the switch_commits list before calling +switch_commit_roots, as we do for the tree root and the chunk root. +However, the block group tree uses normal root dirty tracking and in any +transaction that does an allocation and dirties a block group, the block +group root will already be linked to a list by the dirty_list field and +this use of list_add_tail() is invalid and corrupts the prev/next +members of block_group_root->dirty_list. + +This is apparent on a subsequent list_del on the prev if we enable +CONFIG_DEBUG_LIST: + + [32.1571] ------------[ cut here ]------------ + [32.1572] list_del corruption. next->prev should beffff958890202538, but was ffff9588992bd538. (next=ffff958890201538) + [32.1575] WARNING: lib/list_debug.c:65 at 0x0, CPU#3: sync/607 + [32.1583] CPU: 3 UID: 0 PID: 607 Comm: sync Not tainted 6.18.0 #24PREEMPT(none) + [32.1585] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS1.17.0-4.fc41 04/01/2014 + [32.1587] RIP: 0010:__list_del_entry_valid_or_report+0x108/0x120 + [32.1593] RSP: 0018:ffffaa288287fdd0 EFLAGS: 00010202 + [32.1594] RAX: 0000000000000001 RBX: ffff95889326e800 RCX:ffff958890201538 + [32.1596] RDX: ffff9588992bd538 RSI: ffff958890202538 RDI:ffffffff82a41e00 + [32.1597] RBP: ffff958890202538 R08: ffffffff828fc1e8 R09:00000000ffffefff + [32.1599] R10: ffffffff8288c200 R11: ffffffff828e4200 R12:ffff958890201538 + [32.1601] R13: ffff95889326e958 R14: ffff958895c24000 R15:ffff958890202538 + [32.1603] FS: 00007f0c28eb5740(0000) GS:ffff958af2bd2000(0000)knlGS:0000000000000000 + [32.1605] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + [32.1607] CR2: 00007f0c28e8a3cc CR3: 0000000109942005 CR4:0000000000370ef0 + [32.1609] Call Trace: + [32.1610] + [32.1611] switch_commit_roots+0x82/0x1d0 [btrfs] + [32.1615] btrfs_commit_transaction+0x968/0x1550 [btrfs] + [32.1618] ? btrfs_attach_transaction_barrier+0x23/0x60 [btrfs] + [32.1621] __iterate_supers+0xe8/0x190 + [32.1622] ? __pfx_sync_fs_one_sb+0x10/0x10 + [32.1623] ksys_sync+0x63/0xb0 + [32.1624] __do_sys_sync+0xe/0x20 + [32.1625] do_syscall_64+0x73/0x450 + [32.1626] entry_SYSCALL_64_after_hwframe+0x76/0x7e + [32.1627] RIP: 0033:0x7f0c28d05d2b + [32.1632] RSP: 002b:00007ffc9d988048 EFLAGS: 00000246 ORIG_RAX:00000000000000a2 + [32.1634] RAX: ffffffffffffffda RBX: 00007ffc9d988228 RCX:00007f0c28d05d2b + [32.1636] RDX: 00007f0c28e02301 RSI: 00007ffc9d989b21 RDI:00007f0c28dba90d + [32.1637] RBP: 0000000000000001 R08: 0000000000000001 R09:0000000000000000 + [32.1639] R10: 0000000000000000 R11: 0000000000000246 R12:000055b96572cb80 + [32.1641] R13: 000055b96572b19f R14: 00007f0c28dfa434 R15:000055b96572b034 + [32.1643] + [32.1644] irq event stamp: 0 + [32.1644] hardirqs last enabled at (0): [<0000000000000000>] 0x0 + [32.1646] hardirqs last disabled at (0): []copy_process+0xb37/0x2260 + [32.1648] softirqs last enabled at (0): []copy_process+0xb37/0x2260 + [32.1650] softirqs last disabled at (0): [<0000000000000000>] 0x0 + [32.1652] ---[ end trace 0000000000000000 ]--- + +Furthermore, this list corruption eventually (when we happen to add a +new block group) results in getting the switch_commits and +dirty_cowonly_roots lists mixed up and attempting to call update_root +on the tree root which can't be found in the tree root, resulting in a +transaction abort: + + [87.8269] BTRFS critical (device nvme1n1): unable to find root key (1 0 0) in tree 1 + [87.8272] ------------[ cut here ]------------ + [87.8274] BTRFS: Transaction aborted (error -117) + [87.8275] WARNING: fs/btrfs/root-tree.c:153 at 0x0, CPU#4: sync/703 + [87.8285] CPU: 4 UID: 0 PID: 703 Comm: sync Not tainted 6.18.0 #25 PREEMPT(none) + [87.8287] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.17.0-4.fc41 04/01/2014 + [87.8289] RIP: 0010:btrfs_update_root+0x296/0x790 [btrfs] + [87.8295] RSP: 0018:ffffa58d035dfd60 EFLAGS: 00010282 + [87.8297] RAX: ffff9a59126ddb68 RBX: ffff9a59126dc000 RCX: 0000000000000000 + [87.8299] RDX: 0000000000000000 RSI: 00000000ffffff8b RDI: ffffffffc0b28270 + [87.8301] RBP: ffff9a5904aec000 R08: 0000000000000000 R09: 00000000ffffefff + [87.8303] R10: ffffffff9ac8c200 R11: ffffffff9ace4200 R12: 0000000000000001 + [87.8305] R13: ffff9a59041740e8 R14: ffff9a5904aec1f7 R15: ffff9a590fdefaf0 + [87.8307] FS: 00007f54cde6b740(0000) GS:ffff9a5b5a81c000(0000) knlGS:0000000000000000 + [87.8309] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + [87.8310] CR2: 00007f54cde403cc CR3: 0000000112902004 CR4: 0000000000370ef0 + [87.8312] Call Trace: + [87.8313] + [87.8314] ? _raw_spin_unlock+0x23/0x40 + [87.8315] commit_cowonly_roots+0x1ad/0x250 [btrfs] + [87.8317] ? btrfs_commit_transaction+0x79b/0x1560 [btrfs] + [87.8320] btrfs_commit_transaction+0x8aa/0x1560 [btrfs] + [87.8322] ? btrfs_attach_transaction_barrier+0x23/0x60 [btrfs] + [87.8325] __iterate_supers+0xf1/0x170 + [87.8326] ? __pfx_sync_fs_one_sb+0x10/0x10 + [87.8327] ksys_sync+0x63/0xb0 + [87.8328] __do_sys_sync+0xe/0x20 + [87.8329] do_syscall_64+0x73/0x450 + [87.8330] entry_SYSCALL_64_after_hwframe+0x76/0x7e + [87.8331] RIP: 0033:0x7f54cdd05d2b + [87.8336] RSP: 002b:00007fff1b58ff78 EFLAGS: 00000246 ORIG_RAX: 00000000000000a2 + [87.8338] RAX: ffffffffffffffda RBX: 00007fff1b590158 RCX: 00007f54cdd05d2b + [87.8340] RDX: 00007f54cde02301 RSI: 00007fff1b592b66 RDI: 00007f54cddba90d + [87.8342] RBP: 0000000000000001 R08: 0000000000000001 R09: 0000000000000000 + [87.8344] R10: 0000000000000000 R11: 0000000000000246 R12: 000055e07ca96b80 + [87.8346] R13: 000055e07ca9519f R14: 00007f54cddfa434 R15: 000055e07ca95034 + [87.8348] + [87.8348] irq event stamp: 0 + [87.8349] hardirqs last enabled at (0): [<0000000000000000>] 0x0 + [87.8351] hardirqs last disabled at (0): [] copy_process+0xb37/0x21e0 + [87.8353] softirqs last enabled at (0): [] copy_process+0xb37/0x21e0 + [87.8355] softirqs last disabled at (0): [<0000000000000000>] 0x0 + [87.8357] ---[ end trace 0000000000000000 ]--- + [87.8358] BTRFS: error (device nvme1n1 state A) in btrfs_update_root:153: errno=-117 Filesystem corrupted + [87.8360] BTRFS info (device nvme1n1 state EA): forced readonly + [87.8362] BTRFS warning (device nvme1n1 state EA): Skipping commit of aborted transaction. + [87.8364] BTRFS: error (device nvme1n1 state EA) in cleanup_transaction:2037: errno=-117 Filesystem corrupted + +Since the block group tree was pulled out of the extent tree and uses +normal root dirty tracking, remove the offending extra list_add. This +fixes the list corruption and the resulting fs corruption. + +Fixes: 14033b08a029 ("btrfs: don't save block group root into super block") +Reviewed-by: Filipe Manana +Signed-off-by: Boris Burkov +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/transaction.c | 7 ------- + 1 file changed, 7 deletions(-) + +diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c +index 7371a3c0bdede..b7679f3399407 100644 +--- a/fs/btrfs/transaction.c ++++ b/fs/btrfs/transaction.c +@@ -2487,13 +2487,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans) + list_add_tail(&fs_info->chunk_root->dirty_list, + &cur_trans->switch_commits); + +- if (btrfs_fs_incompat(fs_info, EXTENT_TREE_V2)) { +- btrfs_set_root_node(&fs_info->block_group_root->root_item, +- fs_info->block_group_root->node); +- list_add_tail(&fs_info->block_group_root->dirty_list, +- &cur_trans->switch_commits); +- } +- + switch_commit_roots(trans); + + ASSERT(list_empty(&cur_trans->dirty_bgs)); +-- +2.51.0 + diff --git a/queue-6.12/btrfs-qgroup-return-correct-error-when-deleting-qgro.patch b/queue-6.12/btrfs-qgroup-return-correct-error-when-deleting-qgro.patch new file mode 100644 index 0000000000..489d210e7d --- /dev/null +++ b/queue-6.12/btrfs-qgroup-return-correct-error-when-deleting-qgro.patch @@ -0,0 +1,43 @@ +From 8d0caa018c9a0f71134fb9a1c40138442a849b9f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 19:35:23 +0000 +Subject: btrfs: qgroup: return correct error when deleting qgroup relation + item + +From: Filipe Manana + +[ Upstream commit 51b1fcf71c88c3c89e7dcf07869c5de837b1f428 ] + +If we fail to delete the second qgroup relation item, we end up returning +success or -ENOENT in case the first item does not exist, instead of +returning the error from the second item deletion. + +Fixes: 73798c465b66 ("btrfs: qgroup: Try our best to delete qgroup relations") +Reviewed-by: Johannes Thumshirn +Signed-off-by: Filipe Manana +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/qgroup.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c +index 029017afaf344..4df0ba100f9de 100644 +--- a/fs/btrfs/qgroup.c ++++ b/fs/btrfs/qgroup.c +@@ -1673,8 +1673,10 @@ static int __del_qgroup_relation(struct btrfs_trans_handle *trans, u64 src, + if (ret < 0 && ret != -ENOENT) + goto out; + ret2 = del_qgroup_relation_item(trans, dst, src); +- if (ret2 < 0 && ret2 != -ENOENT) ++ if (ret2 < 0 && ret2 != -ENOENT) { ++ ret = ret2; + goto out; ++ } + + /* At least one deletion succeeded, return 0 */ + if (!ret || !ret2) +-- +2.51.0 + diff --git a/queue-6.12/clk-mediatek-fix-error-handling-in-runtime-pm-setup.patch b/queue-6.12/clk-mediatek-fix-error-handling-in-runtime-pm-setup.patch new file mode 100644 index 0000000000..2b13830ae5 --- /dev/null +++ b/queue-6.12/clk-mediatek-fix-error-handling-in-runtime-pm-setup.patch @@ -0,0 +1,66 @@ +From 859b21b0f86559b180199f893b1b8eabba8e983b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 23 Nov 2025 23:43:15 +0800 +Subject: clk: mediatek: Fix error handling in runtime PM setup + +From: Haotian Zhang + +[ Upstream commit aa2ad19210a6a444111bce55e8b69579f29318fb ] + +devm_pm_runtime_enable() can fail due to memory allocation. The current +code ignores its return value, and when pm_runtime_resume_and_get() fails, +it returns directly without unmapping the shared_io region. + +Add error handling for devm_pm_runtime_enable(). Reorder cleanup labels +to properly unmap shared_io on pm_runtime_resume_and_get() failure. + +Fixes: 2f7b1d8b5505 ("clk: mediatek: Do a runtime PM get on controllers during probe") +Signed-off-by: Haotian Zhang +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + drivers/clk/mediatek/clk-mtk.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c +index ba1d1c495bc2b..644e5a854f2b6 100644 +--- a/drivers/clk/mediatek/clk-mtk.c ++++ b/drivers/clk/mediatek/clk-mtk.c +@@ -497,14 +497,16 @@ static int __mtk_clk_simple_probe(struct platform_device *pdev, + + + if (mcd->need_runtime_pm) { +- devm_pm_runtime_enable(&pdev->dev); ++ r = devm_pm_runtime_enable(&pdev->dev); ++ if (r) ++ goto unmap_io; + /* + * Do a pm_runtime_resume_and_get() to workaround a possible + * deadlock between clk_register() and the genpd framework. + */ + r = pm_runtime_resume_and_get(&pdev->dev); + if (r) +- return r; ++ goto unmap_io; + } + + /* Calculate how many clk_hw_onecell_data entries to allocate */ +@@ -618,11 +620,11 @@ static int __mtk_clk_simple_probe(struct platform_device *pdev, + free_data: + mtk_free_clk_data(clk_data); + free_base: +- if (mcd->shared_io && base) +- iounmap(base); +- + if (mcd->need_runtime_pm) + pm_runtime_put(&pdev->dev); ++unmap_io: ++ if (mcd->shared_io && base) ++ iounmap(base); + return r; + } + +-- +2.51.0 + diff --git a/queue-6.12/clk-meson-gxbb-limit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch b/queue-6.12/clk-meson-gxbb-limit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch new file mode 100644 index 0000000000..5c339f5132 --- /dev/null +++ b/queue-6.12/clk-meson-gxbb-limit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch @@ -0,0 +1,87 @@ +From eb9a62f371d468860e3074da4989c7cd2dc9a182 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Jan 2026 21:47:08 +0100 +Subject: clk: meson: gxbb: Limit the HDMI PLL OD to /4 on GXL/GXM SoCs + +From: Martin Blumenstingl + +[ Upstream commit 5b1a43950fd3162af0ce52b13c14a2d29b179d4f ] + +GXBB has the HDMI PLL OD in the HHI_HDMI_PLL_CNTL2 register while for +GXL/GXM the OD has moved to HHI_HDMI_PLL_CNTL3. At first glance the rest +of the OD setup seems identical. + +However, looking at the downstream kernel sources as well as testing +shows that GXL only supports three OD values: +- register value 0 means: divide by 1 +- register value 1 means: divide by 2 +- register value 2 means: divide by 4 + +Using register value 3 (which on GXBB means: divide by 8) still divides +by 4 as verified using meson-clk-measure. Downstream sources are also +only using OD register values 0, 1 and 2 for GXL (while for GXBB the +downstream kernel sources are also using value 3). + +Add clk_div_table and have it replace the CLK_DIVIDER_POWER_OF_TWO flag +to make the kernel's view of this register match with how the hardware +actually works. + +Fixes: 69d92293274b ("clk: meson: add the gxl hdmi pll") +Signed-off-by: Martin Blumenstingl +Link: https://lore.kernel.org/r/20260105204710.447779-2-martin.blumenstingl@googlemail.com +Signed-off-by: Jerome Brunet +Signed-off-by: Sasha Levin +--- + drivers/clk/meson/gxbb.c | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c +index d9529de200ae4..2bfb0ab9c93cc 100644 +--- a/drivers/clk/meson/gxbb.c ++++ b/drivers/clk/meson/gxbb.c +@@ -318,12 +318,23 @@ static struct clk_regmap gxbb_hdmi_pll = { + }, + }; + ++/* ++ * GXL hdmi OD dividers are POWER_OF_TWO dividers but limited to /4. ++ * A divider value of 3 should map to /8 but instead map /4 so ignore it. ++ */ ++static const struct clk_div_table gxl_hdmi_pll_od_div_table[] = { ++ { .val = 0, .div = 1 }, ++ { .val = 1, .div = 2 }, ++ { .val = 2, .div = 4 }, ++ { /* sentinel */ } ++}; ++ + static struct clk_regmap gxl_hdmi_pll_od = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL + 8, + .shift = 21, + .width = 2, +- .flags = CLK_DIVIDER_POWER_OF_TWO, ++ .table = gxl_hdmi_pll_od_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od", +@@ -341,7 +352,7 @@ static struct clk_regmap gxl_hdmi_pll_od2 = { + .offset = HHI_HDMI_PLL_CNTL + 8, + .shift = 23, + .width = 2, +- .flags = CLK_DIVIDER_POWER_OF_TWO, ++ .table = gxl_hdmi_pll_od_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od2", +@@ -359,7 +370,7 @@ static struct clk_regmap gxl_hdmi_pll = { + .offset = HHI_HDMI_PLL_CNTL + 8, + .shift = 19, + .width = 2, +- .flags = CLK_DIVIDER_POWER_OF_TWO, ++ .table = gxl_hdmi_pll_od_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll", +-- +2.51.0 + diff --git a/queue-6.12/clk-move-clk_-save-restore-_context-to-common_clk-se.patch b/queue-6.12/clk-move-clk_-save-restore-_context-to-common_clk-se.patch new file mode 100644 index 0000000000..a081870f79 --- /dev/null +++ b/queue-6.12/clk-move-clk_-save-restore-_context-to-common_clk-se.patch @@ -0,0 +1,117 @@ +From c5072ea54594472a6629efd83e0a886daef58f53 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Dec 2025 10:42:26 +0100 +Subject: clk: Move clk_{save,restore}_context() to COMMON_CLK section + +From: Geert Uytterhoeven + +[ Upstream commit f47c1b77d0a2a9c0d49ec14302e74f933398d1a3 ] + +The clk_save_context() and clk_restore_context() helpers are only +implemented by the Common Clock Framework. They are not available when +using legacy clock frameworks. Dummy implementations are provided, but +only if no clock support is available at all. + +Hence when CONFIG_HAVE_CLK=y, but CONFIG_COMMON_CLK is not enabled: + + m68k-linux-gnu-ld: drivers/net/phy/air_en8811h.o: in function `en8811h_resume': + air_en8811h.c:(.text+0x83e): undefined reference to `clk_restore_context' + m68k-linux-gnu-ld: drivers/net/phy/air_en8811h.o: in function `en8811h_suspend': + air_en8811h.c:(.text+0x856): undefined reference to `clk_save_context' + +Fix this by moving forward declarations and dummy implementions from the +HAVE_CLK to the COMMON_CLK section. + +Fixes: 8b95d1ce3300c411 ("clk: Add functions to save/restore clock context en-masse") +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202511301553.eaEz1nEW-lkp@intel.com/ +Signed-off-by: Geert Uytterhoeven +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + include/linux/clk.h | 48 ++++++++++++++++++++++----------------------- + 1 file changed, 24 insertions(+), 24 deletions(-) + +diff --git a/include/linux/clk.h b/include/linux/clk.h +index 851a0f2cf42c8..9488c58d8e6af 100644 +--- a/include/linux/clk.h ++++ b/include/linux/clk.h +@@ -228,6 +228,23 @@ int devm_clk_rate_exclusive_get(struct device *dev, struct clk *clk); + */ + void clk_rate_exclusive_put(struct clk *clk); + ++/** ++ * clk_save_context - save clock context for poweroff ++ * ++ * Saves the context of the clock register for powerstates in which the ++ * contents of the registers will be lost. Occurs deep within the suspend ++ * code so locking is not necessary. ++ */ ++int clk_save_context(void); ++ ++/** ++ * clk_restore_context - restore clock context after poweroff ++ * ++ * This occurs with all clocks enabled. Occurs deep within the resume code ++ * so locking is not necessary. ++ */ ++void clk_restore_context(void); ++ + #else + + static inline int clk_notifier_register(struct clk *clk, +@@ -293,6 +310,13 @@ static inline int devm_clk_rate_exclusive_get(struct device *dev, struct clk *cl + + static inline void clk_rate_exclusive_put(struct clk *clk) {} + ++static inline int clk_save_context(void) ++{ ++ return 0; ++} ++ ++static inline void clk_restore_context(void) {} ++ + #endif + + #ifdef CONFIG_HAVE_CLK_PREPARE +@@ -931,23 +955,6 @@ struct clk *clk_get_parent(struct clk *clk); + */ + struct clk *clk_get_sys(const char *dev_id, const char *con_id); + +-/** +- * clk_save_context - save clock context for poweroff +- * +- * Saves the context of the clock register for powerstates in which the +- * contents of the registers will be lost. Occurs deep within the suspend +- * code so locking is not necessary. +- */ +-int clk_save_context(void); +- +-/** +- * clk_restore_context - restore clock context after poweroff +- * +- * This occurs with all clocks enabled. Occurs deep within the resume code +- * so locking is not necessary. +- */ +-void clk_restore_context(void); +- + #else /* !CONFIG_HAVE_CLK */ + + static inline struct clk *clk_get(struct device *dev, const char *id) +@@ -1127,13 +1134,6 @@ static inline struct clk *clk_get_sys(const char *dev_id, const char *con_id) + return NULL; + } + +-static inline int clk_save_context(void) +-{ +- return 0; +-} +- +-static inline void clk_restore_context(void) {} +- + #endif + + /* clk_prepare_enable helps cases using clk_enable in non-atomic context. */ +-- +2.51.0 + diff --git a/queue-6.12/clk-qcom-dispcc-sdm845-enable-parents-for-pixel-cloc.patch b/queue-6.12/clk-qcom-dispcc-sdm845-enable-parents-for-pixel-cloc.patch new file mode 100644 index 0000000000..64254482d4 --- /dev/null +++ b/queue-6.12/clk-qcom-dispcc-sdm845-enable-parents-for-pixel-cloc.patch @@ -0,0 +1,49 @@ +From 4affa84bb025c099ff016e376924618e5c521fa4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 12:44:43 +0100 +Subject: clk: qcom: dispcc-sdm845: Enable parents for pixel clocks + +From: Petr Hodina + +[ Upstream commit a1d63493634e98360140027fef49d82b1ff0a267 ] + +Add CLK_OPS_PARENT_ENABLE to MDSS pixel clock sources to ensure parent +clocks are enabled during clock operations, preventing potential +stability issues during display configuration. + +Fixes: 81351776c9fb ("clk: qcom: Add display clock controller driver for SDM845") +Signed-off-by: Petr Hodina +Reviewed-by: Dmitry Baryshkov +Reviewed-by: David Heidelberg +Link: https://lore.kernel.org/r/20260107-stability-discussion-v2-1-ef7717b435ff@protonmail.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sdm845.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/dispcc-sdm845.c b/drivers/clk/qcom/dispcc-sdm845.c +index e6139e8f74dc0..1859c093a241b 100644 +--- a/drivers/clk/qcom/dispcc-sdm845.c ++++ b/drivers/clk/qcom/dispcc-sdm845.c +@@ -280,7 +280,7 @@ static struct clk_rcg2 disp_cc_mdss_pclk0_clk_src = { + .name = "disp_cc_mdss_pclk0_clk_src", + .parent_data = disp_cc_parent_data_4, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_4), +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .ops = &clk_pixel_ops, + }, + }; +@@ -295,7 +295,7 @@ static struct clk_rcg2 disp_cc_mdss_pclk1_clk_src = { + .name = "disp_cc_mdss_pclk1_clk_src", + .parent_data = disp_cc_parent_data_4, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_4), +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .ops = &clk_pixel_ops, + }, + }; +-- +2.51.0 + diff --git a/queue-6.12/clk-qcom-dispcc-sm7150-fix-dispcc_mdss_pclk1_clk_src.patch b/queue-6.12/clk-qcom-dispcc-sm7150-fix-dispcc_mdss_pclk1_clk_src.patch new file mode 100644 index 0000000000..08b28a68dc --- /dev/null +++ b/queue-6.12/clk-qcom-dispcc-sm7150-fix-dispcc_mdss_pclk1_clk_src.patch @@ -0,0 +1,37 @@ +From 2977f9cc501ff60834ff599a76fd0ae4f99cea3b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 17 Jan 2026 19:18:28 +0100 +Subject: clk: qcom: dispcc-sm7150: Fix dispcc_mdss_pclk1_clk_src + +From: David Heidelberg + +[ Upstream commit fab13d738c9bd645965464b881335f580d38a54e ] + +Set CLK_OPS_PARENT_ENABLE to ensure the parent gets prepared and enabled +when switching to it. + +Fixes: e3c13e0caa8c ("clk: qcom: dispcc-sm7150: Fix dispcc_mdss_pclk0_clk_src") +Signed-off-by: David Heidelberg +Link: https://lore.kernel.org/r/20260117-sm7150-dispcc-fix-v1-1-2f39966bcad2@ixit.cz +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sm7150.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/qcom/dispcc-sm7150.c b/drivers/clk/qcom/dispcc-sm7150.c +index 1e2a98a63511d..3cd2af842143c 100644 +--- a/drivers/clk/qcom/dispcc-sm7150.c ++++ b/drivers/clk/qcom/dispcc-sm7150.c +@@ -371,7 +371,7 @@ static struct clk_rcg2 dispcc_mdss_pclk1_clk_src = { + .name = "dispcc_mdss_pclk1_clk_src", + .parent_data = dispcc_parent_data_4, + .num_parents = ARRAY_SIZE(dispcc_parent_data_4), +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .ops = &clk_pixel_ops, + }, + }; +-- +2.51.0 + diff --git a/queue-6.12/clk-qcom-gcc-ipq5018-flag-sleep-clock-as-critical.patch b/queue-6.12/clk-qcom-gcc-ipq5018-flag-sleep-clock-as-critical.patch new file mode 100644 index 0000000000..eb663cb50a --- /dev/null +++ b/queue-6.12/clk-qcom-gcc-ipq5018-flag-sleep-clock-as-critical.patch @@ -0,0 +1,37 @@ +From 503f7fe45b61ea837c21b73ea4b92b07b4d3ade5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 15:03:19 +0400 +Subject: clk: qcom: gcc-ipq5018: flag sleep clock as critical + +From: George Moussalem + +[ Upstream commit 04c4dc1f541135708d90a9b4632af51136f93ac3 ] + +The sleep clock never be disabled. To avoid the kernel trying to disable +it and keep it always on, flag it as critical. + +Fixes: e3fdbef1bab8 ("clk: qcom: Add Global Clock controller (GCC) driver for IPQ5018") +Signed-off-by: George Moussalem +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251128-ipq5018-sleep-clk-fix-v1-1-6f4b75ec336c@outlook.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-ipq5018.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/clk/qcom/gcc-ipq5018.c b/drivers/clk/qcom/gcc-ipq5018.c +index 24eb4c40da634..ee45ba9f13e06 100644 +--- a/drivers/clk/qcom/gcc-ipq5018.c ++++ b/drivers/clk/qcom/gcc-ipq5018.c +@@ -1340,6 +1340,7 @@ static struct clk_branch gcc_sleep_clk_src = { + .name = "gcc_sleep_clk_src", + .parent_data = gcc_sleep_clk_data, + .num_parents = ARRAY_SIZE(gcc_sleep_clk_data), ++ .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +-- +2.51.0 + diff --git a/queue-6.12/clk-qcom-gcc-msm8917-remove-always_on-flag-from-cpp_.patch b/queue-6.12/clk-qcom-gcc-msm8917-remove-always_on-flag-from-cpp_.patch new file mode 100644 index 0000000000..656baee8b1 --- /dev/null +++ b/queue-6.12/clk-qcom-gcc-msm8917-remove-always_on-flag-from-cpp_.patch @@ -0,0 +1,39 @@ +From e5da436d933374f06a47f27e325644d5e07b9106 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 17 Nov 2025 18:58:48 +0100 +Subject: clk: qcom: gcc-msm8917: Remove ALWAYS_ON flag from cpp_gdsc +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Czémán + +[ Upstream commit e4eb42f290aecac0ba355b1f8d7243be6de11f32 ] + +cpp_gdsc should not be always on, ALWAYS_ON flag was set accidentally. + +Fixes: 33cc27a47d3a ("clk: qcom: Add global clock controller driver for MSM8917") +Signed-off-by: Barnabás Czémán +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251117-fix-gdsc-cpp-msm8917-msm8953-v1-2-db33adcff28a@mainlining.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-msm8917.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/clk/qcom/gcc-msm8917.c b/drivers/clk/qcom/gcc-msm8917.c +index 3e2a2ae2ee6e9..cb5e18b084296 100644 +--- a/drivers/clk/qcom/gcc-msm8917.c ++++ b/drivers/clk/qcom/gcc-msm8917.c +@@ -3034,7 +3034,6 @@ static struct gdsc cpp_gdsc = { + .pd = { + .name = "cpp_gdsc", + }, +- .flags = ALWAYS_ON, + .pwrsts = PWRSTS_OFF_ON, + }; + +-- +2.51.0 + diff --git a/queue-6.12/clk-qcom-gcc-msm8953-remove-always_on-flag-from-cpp_.patch b/queue-6.12/clk-qcom-gcc-msm8953-remove-always_on-flag-from-cpp_.patch new file mode 100644 index 0000000000..dd2911516f --- /dev/null +++ b/queue-6.12/clk-qcom-gcc-msm8953-remove-always_on-flag-from-cpp_.patch @@ -0,0 +1,39 @@ +From 569647e9b0d808dc25317acb76b14ea0cbcecf09 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 17 Nov 2025 18:58:47 +0100 +Subject: clk: qcom: gcc-msm8953: Remove ALWAYS_ON flag from cpp_gdsc +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Czémán + +[ Upstream commit 5f613e7034187179a9d088ff5fd02b1089d0cf20 ] + +cpp_gdsc should not be always on, ALWAYS_ON flag was set accidentally. + +Fixes: 9bb6cfc3c77e ("clk: qcom: Add Global Clock Controller driver for MSM8953") +Signed-off-by: Barnabás Czémán +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251117-fix-gdsc-cpp-msm8917-msm8953-v1-1-db33adcff28a@mainlining.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-msm8953.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/clk/qcom/gcc-msm8953.c b/drivers/clk/qcom/gcc-msm8953.c +index 8f29ecc74c50b..8fe1d3e421440 100644 +--- a/drivers/clk/qcom/gcc-msm8953.c ++++ b/drivers/clk/qcom/gcc-msm8953.c +@@ -3946,7 +3946,6 @@ static struct gdsc cpp_gdsc = { + .pd = { + .name = "cpp_gdsc", + }, +- .flags = ALWAYS_ON, + .pwrsts = PWRSTS_OFF_ON, + }; + +-- +2.51.0 + diff --git a/queue-6.12/clk-qcom-gcc-qdu1000-update-the-sdcc-rcgs-to-use-sha.patch b/queue-6.12/clk-qcom-gcc-qdu1000-update-the-sdcc-rcgs-to-use-sha.patch new file mode 100644 index 0000000000..e193b30c65 --- /dev/null +++ b/queue-6.12/clk-qcom-gcc-qdu1000-update-the-sdcc-rcgs-to-use-sha.patch @@ -0,0 +1,51 @@ +From 65efb5ca36d7890c4d0424fbdb56d9a6f493c145 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Nov 2025 23:27:42 +0530 +Subject: clk: qcom: gcc-qdu1000: Update the SDCC RCGs to use shared_floor_ops + +From: Jagadeesh Kona + +[ Upstream commit 947c4b326c1f4dc64aed42170b39c2cf551ba8ca ] + +Use shared_floor_ops for the SDCC RCGs so the RCG is safely parked +during disable and the new parent configuration is programmed in +hardware only when the new parent is enabled, avoiding cases where +the RCG configuration fails to update. + +Fixes: baa316580013 ("clk: qcom: gcc-qdu1000: Update the SDCC clock RCG ops") +Signed-off-by: Jagadeesh Kona +Reviewed-by: Imran Shaik +Reviewed-by: Taniya Das +Reviewed-by: Vladimir Zapolskiy +Link: https://lore.kernel.org/r/20251127-sdcc_shared_floor_ops-v2-7-473afc86589c@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-qdu1000.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-qdu1000.c b/drivers/clk/qcom/gcc-qdu1000.c +index dbe9e9437939a..915bb9b4ff813 100644 +--- a/drivers/clk/qcom/gcc-qdu1000.c ++++ b/drivers/clk/qcom/gcc-qdu1000.c +@@ -904,7 +904,7 @@ static struct clk_rcg2 gcc_sdcc5_apps_clk_src = { + .name = "gcc_sdcc5_apps_clk_src", + .parent_data = gcc_parent_data_8, + .num_parents = ARRAY_SIZE(gcc_parent_data_8), +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +@@ -923,7 +923,7 @@ static struct clk_rcg2 gcc_sdcc5_ice_core_clk_src = { + .name = "gcc_sdcc5_ice_core_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = ARRAY_SIZE(gcc_parent_data_2), +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +-- +2.51.0 + diff --git a/queue-6.12/clk-qcom-gcc-sdx75-update-the-sdcc-rcgs-to-use-share.patch b/queue-6.12/clk-qcom-gcc-sdx75-update-the-sdcc-rcgs-to-use-share.patch new file mode 100644 index 0000000000..0f31582385 --- /dev/null +++ b/queue-6.12/clk-qcom-gcc-sdx75-update-the-sdcc-rcgs-to-use-share.patch @@ -0,0 +1,52 @@ +From 09ac71b11e3a3b1463c8004f85dfb8c52d920936 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Nov 2025 23:27:39 +0530 +Subject: clk: qcom: gcc-sdx75: Update the SDCC RCGs to use shared_floor_ops + +From: Jagadeesh Kona + +[ Upstream commit 4b057462bb61a6571608ba393e6e018c9da9c9c3 ] + +Use shared_floor_ops for the SDCC RCGs so the RCG is safely parked +during disable and the new parent configuration is programmed in +hardware only when the new parent is enabled, avoiding cases where +the RCG configuration fails to update. + +Fixes: 108cdc09b2de ("clk: qcom: Add GCC driver support for SDX75") +Reviewed-by: Taniya Das +Reviewed-by: Imran Shaik +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Vladimir Zapolskiy +Signed-off-by: Jagadeesh Kona +Link: https://lore.kernel.org/r/20251127-sdcc_shared_floor_ops-v2-4-473afc86589c@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-sdx75.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-sdx75.c b/drivers/clk/qcom/gcc-sdx75.c +index 453a6bf8e8786..1f3cd58483a2d 100644 +--- a/drivers/clk/qcom/gcc-sdx75.c ++++ b/drivers/clk/qcom/gcc-sdx75.c +@@ -1033,7 +1033,7 @@ static struct clk_rcg2 gcc_sdcc1_apps_clk_src = { + .name = "gcc_sdcc1_apps_clk_src", + .parent_data = gcc_parent_data_17, + .num_parents = ARRAY_SIZE(gcc_parent_data_17), +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +@@ -1057,7 +1057,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .name = "gcc_sdcc2_apps_clk_src", + .parent_data = gcc_parent_data_18, + .num_parents = ARRAY_SIZE(gcc_parent_data_18), +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +-- +2.51.0 + diff --git a/queue-6.12/clk-qcom-gcc-sm4450-update-the-sdcc-rcgs-to-use-shar.patch b/queue-6.12/clk-qcom-gcc-sm4450-update-the-sdcc-rcgs-to-use-shar.patch new file mode 100644 index 0000000000..2e2b6f7996 --- /dev/null +++ b/queue-6.12/clk-qcom-gcc-sm4450-update-the-sdcc-rcgs-to-use-shar.patch @@ -0,0 +1,61 @@ +From 41f647deda4aa33ea7934f2bd7e68c1abe28a8e6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Nov 2025 23:27:38 +0530 +Subject: clk: qcom: gcc-sm4450: Update the SDCC RCGs to use shared_floor_ops + +From: Jagadeesh Kona + +[ Upstream commit 458e8a082186335380a9ab83003a385aec9bb254 ] + +Use shared_floor_ops for the SDCC RCGs so the RCG is safely parked +during disable and the new parent configuration is programmed in +hardware only when the new parent is enabled, avoiding cases where +the RCG configuration fails to update. + +Fixes: c32c4ef98bac ("clk: qcom: Add GCC driver support for SM4450") +Reviewed-by: Taniya Das +Reviewed-by: Imran Shaik +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Vladimir Zapolskiy +Signed-off-by: Jagadeesh Kona +Link: https://lore.kernel.org/r/20251127-sdcc_shared_floor_ops-v2-3-473afc86589c@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-sm4450.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-sm4450.c b/drivers/clk/qcom/gcc-sm4450.c +index e2d9e4691c5b7..023d840e9f4ef 100644 +--- a/drivers/clk/qcom/gcc-sm4450.c ++++ b/drivers/clk/qcom/gcc-sm4450.c +@@ -769,7 +769,7 @@ static struct clk_rcg2 gcc_sdcc1_apps_clk_src = { + .parent_data = gcc_parent_data_4, + .num_parents = ARRAY_SIZE(gcc_parent_data_4), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +@@ -791,7 +791,7 @@ static struct clk_rcg2 gcc_sdcc1_ice_core_clk_src = { + .parent_data = gcc_parent_data_4, + .num_parents = ARRAY_SIZE(gcc_parent_data_4), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +@@ -815,7 +815,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .parent_data = gcc_parent_data_6, + .num_parents = ARRAY_SIZE(gcc_parent_data_6), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +-- +2.51.0 + diff --git a/queue-6.12/clk-qcom-gcc-sm8450-update-the-sdcc-rcgs-to-use-shar.patch b/queue-6.12/clk-qcom-gcc-sm8450-update-the-sdcc-rcgs-to-use-shar.patch new file mode 100644 index 0000000000..1d0715acbb --- /dev/null +++ b/queue-6.12/clk-qcom-gcc-sm8450-update-the-sdcc-rcgs-to-use-shar.patch @@ -0,0 +1,52 @@ +From 932a40f0cf02199f5a6cee37b62e734e9fcbe9c0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Nov 2025 23:27:36 +0530 +Subject: clk: qcom: gcc-sm8450: Update the SDCC RCGs to use shared_floor_ops + +From: Jagadeesh Kona + +[ Upstream commit 89428516f99572a9c37ebbb7859595881e7025a0 ] + +Use shared_floor_ops for the SDCC RCGs so the RCG is safely parked +during disable and the new parent configuration is programmed in +hardware only when the new parent is enabled, avoiding cases where +the RCG configuration fails to update. + +Fixes: a27ac3806b0a ("clk: qcom: gcc-sm8450: Use floor ops for SDCC RCGs") +Reviewed-by: Taniya Das +Reviewed-by: Imran Shaik +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Vladimir Zapolskiy +Signed-off-by: Jagadeesh Kona +Link: https://lore.kernel.org/r/20251127-sdcc_shared_floor_ops-v2-1-473afc86589c@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-sm8450.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-sm8450.c b/drivers/clk/qcom/gcc-sm8450.c +index c445c271678a5..ff62381ecdd97 100644 +--- a/drivers/clk/qcom/gcc-sm8450.c ++++ b/drivers/clk/qcom/gcc-sm8450.c +@@ -936,7 +936,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .parent_data = gcc_parent_data_7, + .num_parents = ARRAY_SIZE(gcc_parent_data_7), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +@@ -959,7 +959,7 @@ static struct clk_rcg2 gcc_sdcc4_apps_clk_src = { + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +-- +2.51.0 + diff --git a/queue-6.12/clk-qcom-gcc-sm8550-use-floor-ops-for-sdcc-rcgs.patch b/queue-6.12/clk-qcom-gcc-sm8550-use-floor-ops-for-sdcc-rcgs.patch new file mode 100644 index 0000000000..05d8922934 --- /dev/null +++ b/queue-6.12/clk-qcom-gcc-sm8550-use-floor-ops-for-sdcc-rcgs.patch @@ -0,0 +1,55 @@ +From c8be2f01411a8539d493714c03332737d5619634 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 24 Nov 2025 23:20:11 +0200 +Subject: clk: qcom: gcc-sm8550: Use floor ops for SDCC RCGs + +From: Vladimir Zapolskiy + +[ Upstream commit 1c06e3956054fb5a0930f07b02726b1774b6c700 ] + +In line with commit a27ac3806b0a ("clk: qcom: gcc-sm8450: Use floor ops +for SDCC RCGs") done to fix issues with overclocked SD cards on SM8450 +powered boards set floor clock operations for SDCC RCGs on SM8550. + +This change fixes initialization of some SD cards, where the problem +is manifested by the SDHC driver: + + mmc0: Card appears overclocked; req 50000000 Hz, actual 100000000 Hz + mmc0: error -110 whilst initialising SD card + +Fixes: 955f2ea3b9e9 ("clk: qcom: Add GCC driver for SM8550") +Signed-off-by: Vladimir Zapolskiy +Reviewed-by: Neil Armstrong +Reviewed-by: Taniya Das +Link: https://lore.kernel.org/r/20251124212012.3660189-2-vladimir.zapolskiy@linaro.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-sm8550.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-sm8550.c b/drivers/clk/qcom/gcc-sm8550.c +index 862a9bf73bcb5..36a5b7de5b55d 100644 +--- a/drivers/clk/qcom/gcc-sm8550.c ++++ b/drivers/clk/qcom/gcc-sm8550.c +@@ -1025,7 +1025,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .parent_data = gcc_parent_data_9, + .num_parents = ARRAY_SIZE(gcc_parent_data_9), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_shared_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +@@ -1048,7 +1048,7 @@ static struct clk_rcg2 gcc_sdcc4_apps_clk_src = { + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_shared_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +-- +2.51.0 + diff --git a/queue-6.12/clk-qcom-gcc-sm8650-use-floor-ops-for-sdcc-rcgs.patch b/queue-6.12/clk-qcom-gcc-sm8650-use-floor-ops-for-sdcc-rcgs.patch new file mode 100644 index 0000000000..9a06768eed --- /dev/null +++ b/queue-6.12/clk-qcom-gcc-sm8650-use-floor-ops-for-sdcc-rcgs.patch @@ -0,0 +1,55 @@ +From ba8346e59e4893f9f759327e16c26ccb8e14f76d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 24 Nov 2025 23:20:12 +0200 +Subject: clk: qcom: gcc-sm8650: Use floor ops for SDCC RCGs + +From: Vladimir Zapolskiy + +[ Upstream commit 8c4415fd17cd5979c31a4bf303acc702e9726033 ] + +In line with commit a27ac3806b0a ("clk: qcom: gcc-sm8450: Use floor ops +for SDCC RCGs") done to fix issues with overclocked SD cards on SM8450 +powered boards set floor clock operations for SDCC RCGs on SM8650. + +This change fixes initialization of some SD cards, where the problem +is manifested by the SDHC driver: + + mmc0: Card appears overclocked; req 50000000 Hz, actual 100000000 Hz + mmc0: error -110 whilst initialising SD card + +Fixes: c58225b7e3d7 ("clk: qcom: add the SM8650 Global Clock Controller driver, part 1") +Signed-off-by: Vladimir Zapolskiy +Reviewed-by: Neil Armstrong +Reviewed-by: Taniya Das +Link: https://lore.kernel.org/r/20251124212012.3660189-3-vladimir.zapolskiy@linaro.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-sm8650.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-sm8650.c b/drivers/clk/qcom/gcc-sm8650.c +index fa1672c4e7d81..8c4b86494183c 100644 +--- a/drivers/clk/qcom/gcc-sm8650.c ++++ b/drivers/clk/qcom/gcc-sm8650.c +@@ -1257,7 +1257,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .parent_data = gcc_parent_data_11, + .num_parents = ARRAY_SIZE(gcc_parent_data_11), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_shared_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +@@ -1279,7 +1279,7 @@ static struct clk_rcg2 gcc_sdcc4_apps_clk_src = { + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_shared_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +-- +2.51.0 + diff --git a/queue-6.12/clk-qcom-gcc-x1e80100-update-the-sdcc-rcgs-to-use-sh.patch b/queue-6.12/clk-qcom-gcc-x1e80100-update-the-sdcc-rcgs-to-use-sh.patch new file mode 100644 index 0000000000..e187e533fe --- /dev/null +++ b/queue-6.12/clk-qcom-gcc-x1e80100-update-the-sdcc-rcgs-to-use-sh.patch @@ -0,0 +1,50 @@ +From 4284fe34a274e99dd3f50c422b87fdd69d8896a8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Nov 2025 23:27:41 +0530 +Subject: clk: qcom: gcc-x1e80100: Update the SDCC RCGs to use shared_floor_ops + +From: Jagadeesh Kona + +[ Upstream commit a468047c4e1c56783204a3ac551b843b4277c8fc ] + +Use shared_floor_ops for the SDCC RCGs so the RCG is safely parked +during disable and the new parent configuration is programmed in +hardware only when the new parent is enabled, avoiding cases where +the RCG configuration fails to update. + +Fixes: 161b7c401f4b ("clk: qcom: Add Global Clock controller (GCC) driver for X1E80100") +Signed-off-by: Jagadeesh Kona +Reviewed-by: Imran Shaik +Reviewed-by: Vladimir Zapolskiy +Link: https://lore.kernel.org/r/20251127-sdcc_shared_floor_ops-v2-6-473afc86589c@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-x1e80100.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-x1e80100.c b/drivers/clk/qcom/gcc-x1e80100.c +index 86cc8ecf16a48..0c49f0461ae32 100644 +--- a/drivers/clk/qcom/gcc-x1e80100.c ++++ b/drivers/clk/qcom/gcc-x1e80100.c +@@ -1516,7 +1516,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .parent_data = gcc_parent_data_9, + .num_parents = ARRAY_SIZE(gcc_parent_data_9), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +@@ -1538,7 +1538,7 @@ static struct clk_rcg2 gcc_sdcc4_apps_clk_src = { + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +-- +2.51.0 + diff --git a/queue-6.12/clk-qcom-gfx3d-add-parent-to-parent-request-map.patch b/queue-6.12/clk-qcom-gfx3d-add-parent-to-parent-request-map.patch new file mode 100644 index 0000000000..0753199a1e --- /dev/null +++ b/queue-6.12/clk-qcom-gfx3d-add-parent-to-parent-request-map.patch @@ -0,0 +1,67 @@ +From e805ff4b3bf25c5620aebca0e6ca596f9cb9c538 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 17 Jan 2026 05:54:47 +0200 +Subject: clk: qcom: gfx3d: add parent to parent request map + +From: Dmitry Baryshkov + +[ Upstream commit 2583cb925ca1ce450aa5d74a05a67448db970193 ] + +After commit d228ece36345 ("clk: divider: remove round_rate() in favor +of determine_rate()") determining GFX3D clock rate crashes, because the +passed parent map doesn't provide the expected best_parent_hw clock +(with the roundd_rate path before the offending commit the +best_parent_hw was ignored). + +Set the field in parent_req in addition to setting it in the req, +fixing the crash. + + clk_hw_round_rate (drivers/clk/clk.c:1764) (P) + clk_divider_bestdiv (drivers/clk/clk-divider.c:336) + divider_determine_rate (drivers/clk/clk-divider.c:358) + clk_alpha_pll_postdiv_determine_rate (drivers/clk/qcom/clk-alpha-pll.c:1275) + clk_core_determine_round_nolock (drivers/clk/clk.c:1606) + clk_core_round_rate_nolock (drivers/clk/clk.c:1701) + __clk_determine_rate (drivers/clk/clk.c:1741) + clk_gfx3d_determine_rate (drivers/clk/qcom/clk-rcg2.c:1268) + clk_core_determine_round_nolock (drivers/clk/clk.c:1606) + clk_core_round_rate_nolock (drivers/clk/clk.c:1701) + clk_core_round_rate_nolock (drivers/clk/clk.c:1710) + clk_round_rate (drivers/clk/clk.c:1804) + dev_pm_opp_set_rate (drivers/opp/core.c:1440 (discriminator 1)) + msm_devfreq_target (drivers/gpu/drm/msm/msm_gpu_devfreq.c:51) + devfreq_set_target (drivers/devfreq/devfreq.c:360) + devfreq_update_target (drivers/devfreq/devfreq.c:426) + devfreq_monitor (drivers/devfreq/devfreq.c:458) + process_one_work (arch/arm64/include/asm/jump_label.h:36 include/trace/events/workqueue.h:110 kernel/workqueue.c:3284) + worker_thread (kernel/workqueue.c:3356 (discriminator 2) kernel/workqueue.c:3443 (discriminator 2)) + kthread (kernel/kthread.c:467) + ret_from_fork (arch/arm64/kernel/entry.S:861) + +Fixes: 55213e1acec9 ("clk: qcom: Add gfx3d ping-pong PLL frequency switching") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Abel Vesa +Reviewed-by: Konrad Dybcio +Reviewed-by: Brian Masney +Link: https://lore.kernel.org/r/20260117-db820-fix-gfx3d-v1-1-0f8894d71d63@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/clk-rcg2.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c +index 005c1da75dafc..6aa9dcdabffde 100644 +--- a/drivers/clk/qcom/clk-rcg2.c ++++ b/drivers/clk/qcom/clk-rcg2.c +@@ -1084,6 +1084,7 @@ static int clk_gfx3d_determine_rate(struct clk_hw *hw, + if (req->max_rate < parent_req.max_rate) + parent_req.max_rate = req->max_rate; + ++ parent_req.best_parent_hw = req->best_parent_hw; + ret = __clk_determine_rate(req->best_parent_hw, &parent_req); + if (ret) + return ret; +-- +2.51.0 + diff --git a/queue-6.12/clk-qcom-rcg2-compute-2d-using-duty-fraction-directl.patch b/queue-6.12/clk-qcom-rcg2-compute-2d-using-duty-fraction-directl.patch new file mode 100644 index 0000000000..9711cee827 --- /dev/null +++ b/queue-6.12/clk-qcom-rcg2-compute-2d-using-duty-fraction-directl.patch @@ -0,0 +1,71 @@ +From bf683f17c750f315a8f3f7b22a3211aa793e6b01 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Jan 2026 16:09:50 +0530 +Subject: clk: qcom: rcg2: compute 2d using duty fraction directly +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Taniya Das + +[ Upstream commit d6205a1878dd4cc9664c4b4829b68a29c0426efc ] + +The duty-cycle calculation in clk_rcg2_set_duty_cycle() currently +derives an intermediate percentage `duty_per = (num * 100) / den` and +then computes: + + d = DIV_ROUND_CLOSEST(n * duty_per * 2, 100); + +This introduces integer truncation at the percentage step (division by +`den`) and a redundant scaling by 100, which can reduce precision for +large `den` and skew the final rounding. + +Compute `2d` directly from the duty fraction to preserve precision and +avoid the unnecessary scaling: + + d = DIV_ROUND_CLOSEST(n * duty->num * 2, duty->den); + +This keeps the intended formula `d ≈ n * 2 * (num/den)` while performing +a single, final rounded division, improving accuracy especially for small +duty cycles or large denominators. It also removes the unused `duty_per` +variable, simplifying the code. + +There is no functional changes beyond improved numerical accuracy. + +Fixes: 7f891faf596ed ("clk: qcom: clk-rcg2: Add support for duty-cycle for RCG") +Signed-off-by: Taniya Das +Link: https://lore.kernel.org/r/20260105-duty_cycle_precision-v2-1-d1d466a6330a@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/clk-rcg2.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c +index bf6406f5279a4..005c1da75dafc 100644 +--- a/drivers/clk/qcom/clk-rcg2.c ++++ b/drivers/clk/qcom/clk-rcg2.c +@@ -587,7 +587,7 @@ static int clk_rcg2_get_duty_cycle(struct clk_hw *hw, struct clk_duty *duty) + static int clk_rcg2_set_duty_cycle(struct clk_hw *hw, struct clk_duty *duty) + { + struct clk_rcg2 *rcg = to_clk_rcg2(hw); +- u32 notn_m, n, m, d, not2d, mask, duty_per, cfg; ++ u32 notn_m, n, m, d, not2d, mask, cfg; + int ret; + + /* Duty-cycle cannot be modified for non-MND RCGs */ +@@ -606,10 +606,8 @@ static int clk_rcg2_set_duty_cycle(struct clk_hw *hw, struct clk_duty *duty) + + n = (~(notn_m) + m) & mask; + +- duty_per = (duty->num * 100) / duty->den; +- + /* Calculate 2d value */ +- d = DIV_ROUND_CLOSEST(n * duty_per * 2, 100); ++ d = DIV_ROUND_CLOSEST(n * duty->num * 2, duty->den); + + /* + * Check bit widths of 2d. If D is too big reduce duty cycle. +-- +2.51.0 + diff --git a/queue-6.12/clk-qcom-return-correct-error-code-in-qcom_cc_probe_.patch b/queue-6.12/clk-qcom-return-correct-error-code-in-qcom_cc_probe_.patch new file mode 100644 index 0000000000..d8aeadfddf --- /dev/null +++ b/queue-6.12/clk-qcom-return-correct-error-code-in-qcom_cc_probe_.patch @@ -0,0 +1,42 @@ +From 2664b75c0e96ad3de315926c4b363d193f9c979e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 17 Dec 2025 12:13:38 +0800 +Subject: clk: qcom: Return correct error code in qcom_cc_probe_by_index() + +From: Haotian Zhang + +[ Upstream commit 1e07ebe744fb522983bd52a4a6148601675330c7 ] + +When devm_platform_ioremap_resource() fails, it returns various +error codes. Returning a hardcoded -ENOMEM masks the actual +failure reason. + +Use PTR_ERR() to propagate the actual error code returned by +devm_platform_ioremap_resource() instead of -ENOMEM. + +Fixes: 75e0a1e30191 ("clk: qcom: define probe by index API as common API") +Signed-off-by: Haotian Zhang +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251217041338.2432-1-vulab@iscas.ac.cn +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/common.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c +index cab2dbb7a8d49..e1a83ec481509 100644 +--- a/drivers/clk/qcom/common.c ++++ b/drivers/clk/qcom/common.c +@@ -375,7 +375,7 @@ int qcom_cc_probe_by_index(struct platform_device *pdev, int index, + + base = devm_platform_ioremap_resource(pdev, index); + if (IS_ERR(base)) +- return -ENOMEM; ++ return PTR_ERR(base); + + regmap = devm_regmap_init_mmio(&pdev->dev, base, desc->config); + if (IS_ERR(regmap)) +-- +2.51.0 + diff --git a/queue-6.12/coresight-etm3x-fix-cpulocked-warning-on-cpuhp.patch b/queue-6.12/coresight-etm3x-fix-cpulocked-warning-on-cpuhp.patch new file mode 100644 index 0000000000..2b63f7dec1 --- /dev/null +++ b/queue-6.12/coresight-etm3x-fix-cpulocked-warning-on-cpuhp.patch @@ -0,0 +1,67 @@ +From c555e95ad30093962e4f0de4065c34a821c760fe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:24:27 +0100 +Subject: coresight: etm3x: Fix cpulocked warning on cpuhp + +From: Antonio Borneo + +[ Upstream commit 1feb0377b9b816f89a04fc381eb19fc6bac9f4a4 ] + +When changes [1] and [2] have been applied to the driver etm4x, the +same modifications have been also collapsed in [3] and applied in +one shot to the driver etm3x. +While doing this, the driver etm3x has not been aligned to etm4x on +the use of non cpuslocked version of cpuhp callback setup APIs. + +The current code triggers two run-time warnings when the kernel is +compiled with CONFIG_PROVE_LOCKING=y. + +Use non cpuslocked version of cpuhp callback setup APIs in driver +etm3x, aligning it to the driver etm4x. + +[1] commit 2d1a8bfb61ec ("coresight: etm4x: Fix etm4_count race by + moving cpuhp callbacks to init") +[2] commit 22a550a306ad ("coresight: etm4x: Allow etm4x to be built + as a module") +[3] commit 97fe626ce64c ("coresight: etm3x: Allow etm3x to be built + as a module") + +Fixes: 97fe626ce64c ("coresight: etm3x: Allow etm3x to be built as a module") +Signed-off-by: Antonio Borneo +Signed-off-by: Suzuki K Poulose +Link: https://lore.kernel.org/r/20260108152427.357379-1-antonio.borneo@foss.st.com +Signed-off-by: Sasha Levin +--- + drivers/hwtracing/coresight/coresight-etm3x-core.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c +index c103f4c70f5d0..994ae1e08af8b 100644 +--- a/drivers/hwtracing/coresight/coresight-etm3x-core.c ++++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c +@@ -812,16 +812,16 @@ static int __init etm_hp_setup(void) + { + int ret; + +- ret = cpuhp_setup_state_nocalls_cpuslocked(CPUHP_AP_ARM_CORESIGHT_STARTING, +- "arm/coresight:starting", +- etm_starting_cpu, etm_dying_cpu); ++ ret = cpuhp_setup_state_nocalls(CPUHP_AP_ARM_CORESIGHT_STARTING, ++ "arm/coresight:starting", ++ etm_starting_cpu, etm_dying_cpu); + + if (ret) + return ret; + +- ret = cpuhp_setup_state_nocalls_cpuslocked(CPUHP_AP_ONLINE_DYN, +- "arm/coresight:online", +- etm_online_cpu, NULL); ++ ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, ++ "arm/coresight:online", ++ etm_online_cpu, NULL); + + /* HP dyn state ID returned in ret on success */ + if (ret > 0) { +-- +2.51.0 + diff --git a/queue-6.12/cpufreq-intel_pstate-enable-asym-capacity-only-when-.patch b/queue-6.12/cpufreq-intel_pstate-enable-asym-capacity-only-when-.patch new file mode 100644 index 0000000000..eae2dff174 --- /dev/null +++ b/queue-6.12/cpufreq-intel_pstate-enable-asym-capacity-only-when-.patch @@ -0,0 +1,51 @@ +From f0f41afba7857cb77b1fe3727e7b36b1839c928c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 10:48:52 +0800 +Subject: cpufreq: intel_pstate: Enable asym capacity only when CPU SMT is not + possible + +From: Yaxiong Tian + +[ Upstream commit 1fedbb589448bee9f20bb2ed9c850d1d2cf9963c ] + +According to the description in the intel_pstate.rst documentation, +Capacity-Aware Scheduling and Energy-Aware Scheduling are only +supported on a hybrid processor without SMT. Previously, the system +used sched_smt_active() for judgment, which is not a strict condition +because users can switch it on or off via /sys at any time. + +This could lead to incorrect driver settings in certain scenarios. +For example, on a CPU that supports SMT, a user can disable SMT +via the nosmt parameter to enable asym capacity, and then re-enable +SMT via /sys. In such cases, some settings in the driver would no +longer be correct. + +To address this issue, replace sched_smt_active() with cpu_smt_possible(), +and only enable asym capacity when CPU SMT is not possible. + +Fixes: 929ebc93ccaa ("cpufreq: intel_pstate: Set asymmetric CPU capacity on hybrid systems") +Signed-off-by: Yaxiong Tian +[ rjw: Subject and changelog edits ] +Link: https://patch.msgid.link/20260203024852.301066-1-tianyaxiong@kylinos.cn +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/cpufreq/intel_pstate.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c +index 9d8cb44c26c70..f8f9ff2b73ea0 100644 +--- a/drivers/cpufreq/intel_pstate.c ++++ b/drivers/cpufreq/intel_pstate.c +@@ -1058,7 +1058,7 @@ static void hybrid_init_cpu_capacity_scaling(bool refresh) + * the capacity of SMT threads is not deterministic even approximately, + * do not do that when SMT is in use. + */ +- if (hwp_is_hybrid && !sched_smt_active() && arch_enable_hybrid_capacity_scale()) { ++ if (hwp_is_hybrid && !cpu_smt_possible() && arch_enable_hybrid_capacity_scale()) { + hybrid_refresh_cpu_capacity_scaling(); + /* + * Disabling ITMT causes sched domains to be rebuilt to disable asym +-- +2.51.0 + diff --git a/queue-6.12/cpufreq-scmi-correct-scmi-explanation.patch b/queue-6.12/cpufreq-scmi-correct-scmi-explanation.patch new file mode 100644 index 0000000000..4a4040bdb1 --- /dev/null +++ b/queue-6.12/cpufreq-scmi-correct-scmi-explanation.patch @@ -0,0 +1,37 @@ +From ceeccd1137192851f8819e242290d0942c252d86 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Jan 2026 22:33:30 +0300 +Subject: cpufreq: scmi: correct SCMI explanation + +From: Sergey Shtylyov + +[ Upstream commit 8c376f337a7e31c42949247e24eaad9a30d6c62c ] + +SCMI stands for System Control and Management Interface, not System Control +and Power Interface -- apparently, Sudeep Holla copied this line from his +SCPI driver and then just forgot to update the acronym explanation... :-) + +Fixes: 99d6bdf33877 ("cpufreq: add support for CPU DVFS based on SCMI message protocol") +Signed-off-by: Sergey Shtylyov +Reviewed-by: Sudeep Holla +Signed-off-by: Viresh Kumar +Signed-off-by: Sasha Levin +--- + drivers/cpufreq/scmi-cpufreq.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c +index bb265541671a5..729262799ea98 100644 +--- a/drivers/cpufreq/scmi-cpufreq.c ++++ b/drivers/cpufreq/scmi-cpufreq.c +@@ -1,6 +1,6 @@ + // SPDX-License-Identifier: GPL-2.0 + /* +- * System Control and Power Interface (SCMI) based CPUFreq Interface driver ++ * System Control and Management Interface (SCMI) based CPUFreq Interface driver + * + * Copyright (C) 2018-2021 ARM Ltd. + * Sudeep Holla +-- +2.51.0 + diff --git a/queue-6.12/cpufreq-scmi-fix-device_node-reference-leak-in-scmi_.patch b/queue-6.12/cpufreq-scmi-fix-device_node-reference-leak-in-scmi_.patch new file mode 100644 index 0000000000..21ff00c98d --- /dev/null +++ b/queue-6.12/cpufreq-scmi-fix-device_node-reference-leak-in-scmi_.patch @@ -0,0 +1,36 @@ +From 95cbaab02a23f5932282135e2580fbaa01769679 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 23:32:06 +0800 +Subject: cpufreq: scmi: Fix device_node reference leak in scmi_cpu_domain_id() + +From: Felix Gu + +[ Upstream commit 0b7fbf9333fa4699a53145bad8ce74ea986caa13 ] + +When calling of_parse_phandle_with_args(), the caller is responsible +to call of_node_put() to release the reference of device node. +In scmi_cpu_domain_id(), it does not release the reference. + +Fixes: e336baa4193e ("cpufreq: scmi: Prepare to move OF parsing of domain-id to cpufreq") +Signed-off-by: Felix Gu +Signed-off-by: Viresh Kumar +Signed-off-by: Sasha Levin +--- + drivers/cpufreq/scmi-cpufreq.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c +index 729262799ea98..dfdc32c6b375a 100644 +--- a/drivers/cpufreq/scmi-cpufreq.c ++++ b/drivers/cpufreq/scmi-cpufreq.c +@@ -98,6 +98,7 @@ static int scmi_cpu_domain_id(struct device *cpu_dev) + return -EINVAL; + } + ++ of_node_put(domain_id.np); + return domain_id.args[0]; + } + +-- +2.51.0 + diff --git a/queue-6.12/cpuidle-governors-menu-always-check-timers-with-tick.patch b/queue-6.12/cpuidle-governors-menu-always-check-timers-with-tick.patch new file mode 100644 index 0000000000..8d5404cae7 --- /dev/null +++ b/queue-6.12/cpuidle-governors-menu-always-check-timers-with-tick.patch @@ -0,0 +1,88 @@ +From d0965835748664f590552cf97674177b4abc09da Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 16:26:14 +0100 +Subject: cpuidle: governors: menu: Always check timers with tick stopped + +From: Rafael J. Wysocki + +[ Upstream commit 80606f4eb8d7484ab7f7d6f0fd30d71e6fbcf328 ] + +After commit 5484e31bbbff ("cpuidle: menu: Skip tick_nohz_get_sleep_length() +call in some cases"), if the return value of get_typical_interval() +multiplied by NSEC_PER_USEC is not greater than RESIDENCY_THRESHOLD_NS, +the menu governor will skip computing the time till the closest timer. +If that happens when the tick has been stopped already, the selected +idle state may be too deep due to the subsequent check comparing +predicted_ns with TICK_NSEC and causing its value to be replaced with +the expected time till the closest timer, which is KTIME_MAX in that +case. That will cause the deepest enabled idle state to be selected, +but the time till the closest timer very well may be shorter than the +target residency of that state, in which case a shallower state should +be used. + +Address this by making menu_select() always compute the time till the +closest timer when the tick has been stopped. + +Also move the predicted_ns check mentioned above into the branch in +which the time till the closest timer is determined because it only +needs to be done in that case. + +Fixes: 5484e31bbbff ("cpuidle: menu: Skip tick_nohz_get_sleep_length() call in some cases") +Signed-off-by: Rafael J. Wysocki +Reviewed-by: Christian Loehle +Link: https://patch.msgid.link/5959091.DvuYhMxLoT@rafael.j.wysocki +Signed-off-by: Sasha Levin +--- + drivers/cpuidle/governors/menu.c | 22 +++++++++++----------- + 1 file changed, 11 insertions(+), 11 deletions(-) + +diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c +index 3be761961f1be..0ce7323450011 100644 +--- a/drivers/cpuidle/governors/menu.c ++++ b/drivers/cpuidle/governors/menu.c +@@ -245,7 +245,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, + + /* Find the shortest expected idle interval. */ + predicted_ns = get_typical_interval(data) * NSEC_PER_USEC; +- if (predicted_ns > RESIDENCY_THRESHOLD_NS) { ++ if (predicted_ns > RESIDENCY_THRESHOLD_NS || tick_nohz_tick_stopped()) { + unsigned int timer_us; + + /* Determine the time till the closest timer. */ +@@ -265,6 +265,16 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, + RESOLUTION * DECAY * NSEC_PER_USEC); + /* Use the lowest expected idle interval to pick the idle state. */ + predicted_ns = min((u64)timer_us * NSEC_PER_USEC, predicted_ns); ++ /* ++ * If the tick is already stopped, the cost of possible short ++ * idle duration misprediction is much higher, because the CPU ++ * may be stuck in a shallow idle state for a long time as a ++ * result of it. In that case, say we might mispredict and use ++ * the known time till the closest timer event for the idle ++ * state selection. ++ */ ++ if (tick_nohz_tick_stopped() && predicted_ns < TICK_NSEC) ++ predicted_ns = data->next_timer_ns; + } else { + /* + * Because the next timer event is not going to be determined +@@ -290,16 +300,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, + return 0; + } + +- /* +- * If the tick is already stopped, the cost of possible short idle +- * duration misprediction is much higher, because the CPU may be stuck +- * in a shallow idle state for a long time as a result of it. In that +- * case, say we might mispredict and use the known time till the closest +- * timer event for the idle state selection. +- */ +- if (tick_nohz_tick_stopped() && predicted_ns < TICK_NSEC) +- predicted_ns = data->next_timer_ns; +- + /* + * Find the idle state with the lowest power while satisfying + * our constraints. +-- +2.51.0 + diff --git a/queue-6.12/crypto-caam-fix-netdev-memory-leak-in-dpaa2_caam_pro.patch b/queue-6.12/crypto-caam-fix-netdev-memory-leak-in-dpaa2_caam_pro.patch new file mode 100644 index 0000000000..d0f19ec2bf --- /dev/null +++ b/queue-6.12/crypto-caam-fix-netdev-memory-leak-in-dpaa2_caam_pro.patch @@ -0,0 +1,145 @@ +From 67ff881712fffb048580f3ad2cafbdbceefb8e38 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 09:55:24 +0800 +Subject: crypto: caam - fix netdev memory leak in dpaa2_caam_probe + +From: Jianpeng Chang + +[ Upstream commit 7d43252b3060b0ba4a192dce5dba85a3f39ffe39 ] + +When commit 0e1a4d427f58 ("crypto: caam: Unembed net_dev structure in +dpaa2") converted embedded net_device to dynamically allocated pointers, +it added cleanup in dpaa2_dpseci_disable() but missed adding cleanup in +dpaa2_dpseci_free() for error paths. + +This causes memory leaks when dpaa2_dpseci_dpio_setup() fails during probe +due to DPIO devices not being ready yet. The kernel's deferred probe +mechanism handles the retry successfully, but the netdevs allocated during +the failed probe attempt are never freed, resulting in kmemleak reports +showing multiple leaked netdev-related allocations all traced back to +dpaa2_caam_probe(). + +Fix this by preserving the CPU mask of allocated netdevs during setup and +using it for cleanup in dpaa2_dpseci_free(). This approach ensures that +only the CPUs that actually had netdevs allocated will be cleaned up, +avoiding potential issues with CPU hotplug scenarios. + +Fixes: 0e1a4d427f58 ("crypto: caam: Unembed net_dev structure in dpaa2") +Signed-off-by: Jianpeng Chang +Reviewed-by: Breno Leitao +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/caam/caamalg_qi2.c | 27 +++++++++++++++------------ + drivers/crypto/caam/caamalg_qi2.h | 2 ++ + 2 files changed, 17 insertions(+), 12 deletions(-) + +diff --git a/drivers/crypto/caam/caamalg_qi2.c b/drivers/crypto/caam/caamalg_qi2.c +index e809d030ab113..ece9f1e5a689f 100644 +--- a/drivers/crypto/caam/caamalg_qi2.c ++++ b/drivers/crypto/caam/caamalg_qi2.c +@@ -4813,7 +4813,8 @@ static void dpaa2_dpseci_free(struct dpaa2_caam_priv *priv) + { + struct device *dev = priv->dev; + struct fsl_mc_device *ls_dev = to_fsl_mc_device(dev); +- int err; ++ struct dpaa2_caam_priv_per_cpu *ppriv; ++ int i, err; + + if (DPSECI_VER(priv->major_ver, priv->minor_ver) > DPSECI_VER(5, 3)) { + err = dpseci_reset(priv->mc_io, 0, ls_dev->mc_handle); +@@ -4821,6 +4822,12 @@ static void dpaa2_dpseci_free(struct dpaa2_caam_priv *priv) + dev_err(dev, "dpseci_reset() failed\n"); + } + ++ for_each_cpu(i, priv->clean_mask) { ++ ppriv = per_cpu_ptr(priv->ppriv, i); ++ free_netdev(ppriv->net_dev); ++ } ++ free_cpumask_var(priv->clean_mask); ++ + dpaa2_dpseci_congestion_free(priv); + dpseci_close(priv->mc_io, 0, ls_dev->mc_handle); + } +@@ -5006,16 +5013,15 @@ static int __cold dpaa2_dpseci_setup(struct fsl_mc_device *ls_dev) + struct device *dev = &ls_dev->dev; + struct dpaa2_caam_priv *priv; + struct dpaa2_caam_priv_per_cpu *ppriv; +- cpumask_var_t clean_mask; + int err, cpu; + u8 i; + + err = -ENOMEM; +- if (!zalloc_cpumask_var(&clean_mask, GFP_KERNEL)) +- goto err_cpumask; +- + priv = dev_get_drvdata(dev); + ++ if (!zalloc_cpumask_var(&priv->clean_mask, GFP_KERNEL)) ++ goto err_cpumask; ++ + priv->dev = dev; + priv->dpsec_id = ls_dev->obj_desc.id; + +@@ -5117,7 +5123,7 @@ static int __cold dpaa2_dpseci_setup(struct fsl_mc_device *ls_dev) + err = -ENOMEM; + goto err_alloc_netdev; + } +- cpumask_set_cpu(cpu, clean_mask); ++ cpumask_set_cpu(cpu, priv->clean_mask); + ppriv->net_dev->dev = *dev; + + netif_napi_add_tx_weight(ppriv->net_dev, &ppriv->napi, +@@ -5125,18 +5131,16 @@ static int __cold dpaa2_dpseci_setup(struct fsl_mc_device *ls_dev) + DPAA2_CAAM_NAPI_WEIGHT); + } + +- err = 0; +- goto free_cpumask; ++ return 0; + + err_alloc_netdev: +- free_dpaa2_pcpu_netdev(priv, clean_mask); ++ free_dpaa2_pcpu_netdev(priv, priv->clean_mask); + err_get_rx_queue: + dpaa2_dpseci_congestion_free(priv); + err_get_vers: + dpseci_close(priv->mc_io, 0, ls_dev->mc_handle); + err_open: +-free_cpumask: +- free_cpumask_var(clean_mask); ++ free_cpumask_var(priv->clean_mask); + err_cpumask: + return err; + } +@@ -5181,7 +5185,6 @@ static int __cold dpaa2_dpseci_disable(struct dpaa2_caam_priv *priv) + ppriv = per_cpu_ptr(priv->ppriv, i); + napi_disable(&ppriv->napi); + netif_napi_del(&ppriv->napi); +- free_netdev(ppriv->net_dev); + } + + return 0; +diff --git a/drivers/crypto/caam/caamalg_qi2.h b/drivers/crypto/caam/caamalg_qi2.h +index 61d1219a202fc..8e65b4b28c7ba 100644 +--- a/drivers/crypto/caam/caamalg_qi2.h ++++ b/drivers/crypto/caam/caamalg_qi2.h +@@ -42,6 +42,7 @@ + * @mc_io: pointer to MC portal's I/O object + * @domain: IOMMU domain + * @ppriv: per CPU pointers to privata data ++ * @clean_mask: CPU mask of CPUs that have allocated netdevs + */ + struct dpaa2_caam_priv { + int dpsec_id; +@@ -65,6 +66,7 @@ struct dpaa2_caam_priv { + + struct dpaa2_caam_priv_per_cpu __percpu *ppriv; + struct dentry *dfs_root; ++ cpumask_var_t clean_mask; + }; + + /** +-- +2.51.0 + diff --git a/queue-6.12/crypto-cavium-fix-dma_free_coherent-size.patch b/queue-6.12/crypto-cavium-fix-dma_free_coherent-size.patch new file mode 100644 index 0000000000..ae2cda4ae7 --- /dev/null +++ b/queue-6.12/crypto-cavium-fix-dma_free_coherent-size.patch @@ -0,0 +1,38 @@ +From d68a6de8dcc9efde11759904b94e9d6ee5206617 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 10:56:45 +0100 +Subject: crypto: cavium - fix dma_free_coherent() size + +From: Thomas Fourier + +[ Upstream commit 941676c30ba5b40a01bed92448f457ce62fd1f07 ] + +The size of the buffer in alloc_command_queues() is +curr->size + CPT_NEXT_CHUNK_PTR_SIZE, so used that length for +dma_free_coherent(). + +Fixes: c694b233295b ("crypto: cavium - Add the Virtual Function driver for CPT") +Signed-off-by: Thomas Fourier +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/cavium/cpt/cptvf_main.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/crypto/cavium/cpt/cptvf_main.c b/drivers/crypto/cavium/cpt/cptvf_main.c +index c246920e6f540..bccd680c7f7ee 100644 +--- a/drivers/crypto/cavium/cpt/cptvf_main.c ++++ b/drivers/crypto/cavium/cpt/cptvf_main.c +@@ -180,7 +180,8 @@ static void free_command_queues(struct cpt_vf *cptvf, + + hlist_for_each_entry_safe(chunk, node, &cqinfo->queue[i].chead, + nextchunk) { +- dma_free_coherent(&pdev->dev, chunk->size, ++ dma_free_coherent(&pdev->dev, ++ chunk->size + CPT_NEXT_CHUNK_PTR_SIZE, + chunk->head, + chunk->dma_addr); + chunk->head = NULL; +-- +2.51.0 + diff --git a/queue-6.12/crypto-ccp-add-an-s4-restore-flow.patch b/queue-6.12/crypto-ccp-add-an-s4-restore-flow.patch new file mode 100644 index 0000000000..ec06e1bdc0 --- /dev/null +++ b/queue-6.12/crypto-ccp-add-an-s4-restore-flow.patch @@ -0,0 +1,168 @@ +From 265136ec11367e8362770d843daac4707f7f3b6f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 22:11:30 -0600 +Subject: crypto: ccp - Add an S4 restore flow +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Mario Limonciello (AMD) + +[ Upstream commit 0ba2035026d0ab6c7c7e65ad8b418dc73d5700d9 ] + +The system will have lost power during S4. The ring used for TEE +communications needs to be initialized before use. + +Fixes: f892a21f51162 ("crypto: ccp - use generic power management") +Reported-by: Lars Francke +Closes: https://lore.kernel.org/platform-driver-x86/CAD-Ua_gfJnQSo8ucS_7ZwzuhoBRJ14zXP7s8b-zX3ZcxcyWePw@mail.gmail.com/ +Tested-by: Yijun Shen +Signed-off-by: Mario Limonciello (AMD) +Reviewed-by: Shyam Sundar S K +Reviewed-by: Tom Lendacky +Link: https://patch.msgid.link/20260116041132.153674-4-superm1@kernel.org +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/crypto/ccp/psp-dev.c | 11 +++++++++++ + drivers/crypto/ccp/sp-dev.c | 12 ++++++++++++ + drivers/crypto/ccp/sp-dev.h | 3 +++ + drivers/crypto/ccp/sp-pci.c | 16 +++++++++++++++- + drivers/crypto/ccp/tee-dev.c | 5 +++++ + drivers/crypto/ccp/tee-dev.h | 1 + + 6 files changed, 47 insertions(+), 1 deletion(-) + +diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c +index 1c5a7189631ec..fa43da7824207 100644 +--- a/drivers/crypto/ccp/psp-dev.c ++++ b/drivers/crypto/ccp/psp-dev.c +@@ -331,6 +331,17 @@ struct psp_device *psp_get_master_device(void) + return sp ? sp->psp_data : NULL; + } + ++int psp_restore(struct sp_device *sp) ++{ ++ struct psp_device *psp = sp->psp_data; ++ int ret = 0; ++ ++ if (psp->tee_data) ++ ret = tee_restore(psp); ++ ++ return ret; ++} ++ + void psp_pci_init(void) + { + psp_master = psp_get_master_device(); +diff --git a/drivers/crypto/ccp/sp-dev.c b/drivers/crypto/ccp/sp-dev.c +index 7eb3e46682860..ccbe009ad6e58 100644 +--- a/drivers/crypto/ccp/sp-dev.c ++++ b/drivers/crypto/ccp/sp-dev.c +@@ -229,6 +229,18 @@ int sp_resume(struct sp_device *sp) + return 0; + } + ++int sp_restore(struct sp_device *sp) ++{ ++ if (sp->psp_data) { ++ int ret = psp_restore(sp); ++ ++ if (ret) ++ return ret; ++ } ++ ++ return sp_resume(sp); ++} ++ + struct sp_device *sp_get_psp_master_device(void) + { + struct sp_device *i, *ret = NULL; +diff --git a/drivers/crypto/ccp/sp-dev.h b/drivers/crypto/ccp/sp-dev.h +index 6f9d7063257d7..c8a611ef275b5 100644 +--- a/drivers/crypto/ccp/sp-dev.h ++++ b/drivers/crypto/ccp/sp-dev.h +@@ -141,6 +141,7 @@ void sp_destroy(struct sp_device *sp); + + int sp_suspend(struct sp_device *sp); + int sp_resume(struct sp_device *sp); ++int sp_restore(struct sp_device *sp); + int sp_request_ccp_irq(struct sp_device *sp, irq_handler_t handler, + const char *name, void *data); + void sp_free_ccp_irq(struct sp_device *sp, void *data); +@@ -174,6 +175,7 @@ int psp_dev_init(struct sp_device *sp); + void psp_pci_init(void); + void psp_dev_destroy(struct sp_device *sp); + void psp_pci_exit(void); ++int psp_restore(struct sp_device *sp); + + #else /* !CONFIG_CRYPTO_DEV_SP_PSP */ + +@@ -181,6 +183,7 @@ static inline int psp_dev_init(struct sp_device *sp) { return 0; } + static inline void psp_pci_init(void) { } + static inline void psp_dev_destroy(struct sp_device *sp) { } + static inline void psp_pci_exit(void) { } ++static inline int psp_restore(struct sp_device *sp) { return 0; } + + #endif /* CONFIG_CRYPTO_DEV_SP_PSP */ + +diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c +index 224edaaa737b6..e8f7fcf66cc72 100644 +--- a/drivers/crypto/ccp/sp-pci.c ++++ b/drivers/crypto/ccp/sp-pci.c +@@ -353,6 +353,13 @@ static int __maybe_unused sp_pci_resume(struct device *dev) + return sp_resume(sp); + } + ++static int __maybe_unused sp_pci_restore(struct device *dev) ++{ ++ struct sp_device *sp = dev_get_drvdata(dev); ++ ++ return sp_restore(sp); ++} ++ + #ifdef CONFIG_CRYPTO_DEV_SP_PSP + static const struct sev_vdata sevv1 = { + .cmdresp_reg = 0x10580, /* C2PMSG_32 */ +@@ -541,7 +548,14 @@ static const struct pci_device_id sp_pci_table[] = { + }; + MODULE_DEVICE_TABLE(pci, sp_pci_table); + +-static SIMPLE_DEV_PM_OPS(sp_pci_pm_ops, sp_pci_suspend, sp_pci_resume); ++static const struct dev_pm_ops sp_pci_pm_ops = { ++ .suspend = pm_sleep_ptr(sp_pci_suspend), ++ .resume = pm_sleep_ptr(sp_pci_resume), ++ .freeze = pm_sleep_ptr(sp_pci_suspend), ++ .thaw = pm_sleep_ptr(sp_pci_resume), ++ .poweroff = pm_sleep_ptr(sp_pci_suspend), ++ .restore_early = pm_sleep_ptr(sp_pci_restore), ++}; + + static struct pci_driver sp_pci_driver = { + .name = "ccp", +diff --git a/drivers/crypto/ccp/tee-dev.c b/drivers/crypto/ccp/tee-dev.c +index af881daa5855b..11c4b05e2f3a2 100644 +--- a/drivers/crypto/ccp/tee-dev.c ++++ b/drivers/crypto/ccp/tee-dev.c +@@ -366,3 +366,8 @@ int psp_check_tee_status(void) + return 0; + } + EXPORT_SYMBOL(psp_check_tee_status); ++ ++int tee_restore(struct psp_device *psp) ++{ ++ return tee_init_ring(psp->tee_data); ++} +diff --git a/drivers/crypto/ccp/tee-dev.h b/drivers/crypto/ccp/tee-dev.h +index ea9a2b7c05f57..c23416cb7bb37 100644 +--- a/drivers/crypto/ccp/tee-dev.h ++++ b/drivers/crypto/ccp/tee-dev.h +@@ -111,5 +111,6 @@ struct tee_ring_cmd { + + int tee_dev_init(struct psp_device *psp); + void tee_dev_destroy(struct psp_device *psp); ++int tee_restore(struct psp_device *psp); + + #endif /* __TEE_DEV_H__ */ +-- +2.51.0 + diff --git a/queue-6.12/crypto-ccp-declare-psp-dead-if-psp_cmd_tee_ring_init.patch b/queue-6.12/crypto-ccp-declare-psp-dead-if-psp_cmd_tee_ring_init.patch new file mode 100644 index 0000000000..ab43472a9d --- /dev/null +++ b/queue-6.12/crypto-ccp-declare-psp-dead-if-psp_cmd_tee_ring_init.patch @@ -0,0 +1,43 @@ +From 725828723f409770a9288b08f88a5b56a88a299f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 22:11:29 -0600 +Subject: crypto: ccp - Declare PSP dead if PSP_CMD_TEE_RING_INIT fails +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Mario Limonciello (AMD) + +[ Upstream commit 5e599d7871bf852e94e8aa08b99724635f2cbf96 ] + +tee_init_ring() only declares PSP dead if the command times out. +If there is any other failure it is still considered fatal though. +Set psp_dead for other failures as well. + +Fixes: 949a0c8dd3c2 ("crypto: ccp - Move direct access to some PSP registers out of TEE") +Tested-by: Yijun Shen +Signed-off-by: Mario Limonciello (AMD) +Acked-by: Tom Lendacky +Reviewed-by: Shyam Sundar S K +Link: https://patch.msgid.link/20260116041132.153674-3-superm1@kernel.org +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/crypto/ccp/tee-dev.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/crypto/ccp/tee-dev.c b/drivers/crypto/ccp/tee-dev.c +index 5e1d80724678d..af881daa5855b 100644 +--- a/drivers/crypto/ccp/tee-dev.c ++++ b/drivers/crypto/ccp/tee-dev.c +@@ -125,6 +125,7 @@ static int tee_init_ring(struct psp_tee_device *tee) + dev_err(tee->dev, "tee: ring init command failed (%#010lx)\n", + FIELD_GET(PSP_CMDRESP_STS, reg)); + tee_free_ring(tee); ++ psp_dead = true; + ret = -EIO; + } + +-- +2.51.0 + diff --git a/queue-6.12/crypto-ccp-ensure-implicit-sev-snp-init-and-shutdown.patch b/queue-6.12/crypto-ccp-ensure-implicit-sev-snp-init-and-shutdown.patch new file mode 100644 index 0000000000..1efc7302a0 --- /dev/null +++ b/queue-6.12/crypto-ccp-ensure-implicit-sev-snp-init-and-shutdown.patch @@ -0,0 +1,361 @@ +From 5beabf48ec8ed54aeb320723763748a900c3444d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 24 Mar 2025 21:14:32 +0000 +Subject: crypto: ccp - Ensure implicit SEV/SNP init and shutdown in ioctls + +From: Ashish Kalra + +[ Upstream commit ceac7fb89e8da465aec3ac3c20477f912f5c3a6c ] + +Modify the behavior of implicit SEV initialization in some of the +SEV ioctls to do both SEV initialization and shutdown and add +implicit SNP initialization and shutdown to some of the SNP ioctls +so that the change of SEV/SNP platform initialization not being +done during PSP driver probe time does not break userspace tools +such as sevtool, etc. + +Prior to this patch, SEV has always been initialized before these +ioctls as SEV initialization is done as part of PSP module probe, +but now with SEV initialization being moved to KVM module load instead +of PSP driver probe, the implied SEV INIT actually makes sense and gets +used and additionally to maintain SEV platform state consistency +before and after the ioctl SEV shutdown needs to be done after the +firmware call. + +It is important to do SEV Shutdown here with the SEV/SNP initialization +moving to KVM, an implicit SEV INIT here as part of the SEV ioctls not +followed with SEV Shutdown will cause SEV to remain in INIT state and +then a future SNP INIT in KVM module load will fail. + +Also ensure that for these SEV ioctls both implicit SNP and SEV INIT is +done followed by both SEV and SNP shutdown as RMP table must be +initialized before calling SEV INIT if SNP host support is enabled. + +Similarly, prior to this patch, SNP has always been initialized before +these ioctls as SNP initialization is done as part of PSP module probe, +therefore, to keep a consistent behavior, SNP init needs to be done +here implicitly as part of these ioctls followed with SNP shutdown +before returning from the ioctl to maintain the consistent platform +state before and after the ioctl. + +Suggested-by: Tom Lendacky +Reviewed-by: Tom Lendacky +Signed-off-by: Ashish Kalra +Signed-off-by: Herbert Xu +Stable-dep-of: dc8ccab15081 ("crypto: ccp - narrow scope of snp_range_list") +Signed-off-by: Sasha Levin +--- + drivers/crypto/ccp/sev-dev.c | 142 +++++++++++++++++++++++++++++------ + 1 file changed, 119 insertions(+), 23 deletions(-) + +diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c +index bc0ecdb5c79e5..3e08df45a8bdb 100644 +--- a/drivers/crypto/ccp/sev-dev.c ++++ b/drivers/crypto/ccp/sev-dev.c +@@ -110,6 +110,8 @@ static void *sev_init_ex_buffer; + */ + static struct sev_data_range_list *snp_range_list; + ++static void __sev_firmware_shutdown(struct sev_device *sev, bool panic); ++ + static inline bool sev_version_greater_or_equal(u8 maj, u8 min) + { + struct sev_device *sev = psp_master->sev_data; +@@ -1399,6 +1401,37 @@ static int sev_get_platform_state(int *state, int *error) + return rc; + } + ++static int sev_move_to_init_state(struct sev_issue_cmd *argp, bool *shutdown_required) ++{ ++ struct sev_platform_init_args init_args = {0}; ++ int rc; ++ ++ rc = _sev_platform_init_locked(&init_args); ++ if (rc) { ++ argp->error = SEV_RET_INVALID_PLATFORM_STATE; ++ return rc; ++ } ++ ++ *shutdown_required = true; ++ ++ return 0; ++} ++ ++static int snp_move_to_init_state(struct sev_issue_cmd *argp, bool *shutdown_required) ++{ ++ int error, rc; ++ ++ rc = __sev_snp_init_locked(&error); ++ if (rc) { ++ argp->error = SEV_RET_INVALID_PLATFORM_STATE; ++ return rc; ++ } ++ ++ *shutdown_required = true; ++ ++ return 0; ++} ++ + static int sev_ioctl_do_reset(struct sev_issue_cmd *argp, bool writable) + { + int state, rc; +@@ -1451,24 +1484,31 @@ static int sev_ioctl_do_platform_status(struct sev_issue_cmd *argp) + static int sev_ioctl_do_pek_pdh_gen(int cmd, struct sev_issue_cmd *argp, bool writable) + { + struct sev_device *sev = psp_master->sev_data; ++ bool shutdown_required = false; + int rc; + + if (!writable) + return -EPERM; + + if (sev->state == SEV_STATE_UNINIT) { +- rc = __sev_platform_init_locked(&argp->error); ++ rc = sev_move_to_init_state(argp, &shutdown_required); + if (rc) + return rc; + } + +- return __sev_do_cmd_locked(cmd, NULL, &argp->error); ++ rc = __sev_do_cmd_locked(cmd, NULL, &argp->error); ++ ++ if (shutdown_required) ++ __sev_firmware_shutdown(sev, false); ++ ++ return rc; + } + + static int sev_ioctl_do_pek_csr(struct sev_issue_cmd *argp, bool writable) + { + struct sev_device *sev = psp_master->sev_data; + struct sev_user_data_pek_csr input; ++ bool shutdown_required = false; + struct sev_data_pek_csr data; + void __user *input_address; + void *blob = NULL; +@@ -1500,7 +1540,7 @@ static int sev_ioctl_do_pek_csr(struct sev_issue_cmd *argp, bool writable) + + cmd: + if (sev->state == SEV_STATE_UNINIT) { +- ret = __sev_platform_init_locked(&argp->error); ++ ret = sev_move_to_init_state(argp, &shutdown_required); + if (ret) + goto e_free_blob; + } +@@ -1521,6 +1561,9 @@ static int sev_ioctl_do_pek_csr(struct sev_issue_cmd *argp, bool writable) + } + + e_free_blob: ++ if (shutdown_required) ++ __sev_firmware_shutdown(sev, false); ++ + kfree(blob); + return ret; + } +@@ -1736,6 +1779,7 @@ static int sev_ioctl_do_pek_import(struct sev_issue_cmd *argp, bool writable) + struct sev_device *sev = psp_master->sev_data; + struct sev_user_data_pek_cert_import input; + struct sev_data_pek_cert_import data; ++ bool shutdown_required = false; + void *pek_blob, *oca_blob; + int ret; + +@@ -1766,7 +1810,7 @@ static int sev_ioctl_do_pek_import(struct sev_issue_cmd *argp, bool writable) + + /* If platform is not in INIT state then transition it to INIT */ + if (sev->state != SEV_STATE_INIT) { +- ret = __sev_platform_init_locked(&argp->error); ++ ret = sev_move_to_init_state(argp, &shutdown_required); + if (ret) + goto e_free_oca; + } +@@ -1774,6 +1818,9 @@ static int sev_ioctl_do_pek_import(struct sev_issue_cmd *argp, bool writable) + ret = __sev_do_cmd_locked(SEV_CMD_PEK_CERT_IMPORT, &data, &argp->error); + + e_free_oca: ++ if (shutdown_required) ++ __sev_firmware_shutdown(sev, false); ++ + kfree(oca_blob); + e_free_pek: + kfree(pek_blob); +@@ -1890,18 +1937,9 @@ static int sev_ioctl_do_pdh_export(struct sev_issue_cmd *argp, bool writable) + struct sev_data_pdh_cert_export data; + void __user *input_cert_chain_address; + void __user *input_pdh_cert_address; ++ bool shutdown_required = false; + int ret; + +- /* If platform is not in INIT state then transition it to INIT. */ +- if (sev->state != SEV_STATE_INIT) { +- if (!writable) +- return -EPERM; +- +- ret = __sev_platform_init_locked(&argp->error); +- if (ret) +- return ret; +- } +- + if (copy_from_user(&input, (void __user *)argp->data, sizeof(input))) + return -EFAULT; + +@@ -1941,6 +1979,17 @@ static int sev_ioctl_do_pdh_export(struct sev_issue_cmd *argp, bool writable) + data.cert_chain_len = input.cert_chain_len; + + cmd: ++ /* If platform is not in INIT state then transition it to INIT. */ ++ if (sev->state != SEV_STATE_INIT) { ++ if (!writable) { ++ ret = -EPERM; ++ goto e_free_cert; ++ } ++ ret = sev_move_to_init_state(argp, &shutdown_required); ++ if (ret) ++ goto e_free_cert; ++ } ++ + ret = __sev_do_cmd_locked(SEV_CMD_PDH_CERT_EXPORT, &data, &argp->error); + + /* If we query the length, FW responded with expected data. */ +@@ -1967,6 +2016,9 @@ static int sev_ioctl_do_pdh_export(struct sev_issue_cmd *argp, bool writable) + } + + e_free_cert: ++ if (shutdown_required) ++ __sev_firmware_shutdown(sev, false); ++ + kfree(cert_blob); + e_free_pdh: + kfree(pdh_blob); +@@ -1976,12 +2028,13 @@ static int sev_ioctl_do_pdh_export(struct sev_issue_cmd *argp, bool writable) + static int sev_ioctl_do_snp_platform_status(struct sev_issue_cmd *argp) + { + struct sev_device *sev = psp_master->sev_data; ++ bool shutdown_required = false; + struct sev_data_snp_addr buf; + struct page *status_page; ++ int ret, error; + void *data; +- int ret; + +- if (!sev->snp_initialized || !argp->data) ++ if (!argp->data) + return -EINVAL; + + status_page = alloc_page(GFP_KERNEL_ACCOUNT); +@@ -1990,6 +2043,12 @@ static int sev_ioctl_do_snp_platform_status(struct sev_issue_cmd *argp) + + data = page_address(status_page); + ++ if (!sev->snp_initialized) { ++ ret = snp_move_to_init_state(argp, &shutdown_required); ++ if (ret) ++ goto cleanup; ++ } ++ + /* + * Firmware expects status page to be in firmware-owned state, otherwise + * it will report firmware error code INVALID_PAGE_STATE (0x1A). +@@ -2018,6 +2077,9 @@ static int sev_ioctl_do_snp_platform_status(struct sev_issue_cmd *argp) + ret = -EFAULT; + + cleanup: ++ if (shutdown_required) ++ __sev_snp_shutdown_locked(&error, false); ++ + __free_pages(status_page, 0); + return ret; + } +@@ -2026,21 +2088,33 @@ static int sev_ioctl_do_snp_commit(struct sev_issue_cmd *argp) + { + struct sev_device *sev = psp_master->sev_data; + struct sev_data_snp_commit buf; ++ bool shutdown_required = false; ++ int ret, error; + +- if (!sev->snp_initialized) +- return -EINVAL; ++ if (!sev->snp_initialized) { ++ ret = snp_move_to_init_state(argp, &shutdown_required); ++ if (ret) ++ return ret; ++ } + + buf.len = sizeof(buf); + +- return __sev_do_cmd_locked(SEV_CMD_SNP_COMMIT, &buf, &argp->error); ++ ret = __sev_do_cmd_locked(SEV_CMD_SNP_COMMIT, &buf, &argp->error); ++ ++ if (shutdown_required) ++ __sev_snp_shutdown_locked(&error, false); ++ ++ return ret; + } + + static int sev_ioctl_do_snp_set_config(struct sev_issue_cmd *argp, bool writable) + { + struct sev_device *sev = psp_master->sev_data; + struct sev_user_data_snp_config config; ++ bool shutdown_required = false; ++ int ret, error; + +- if (!sev->snp_initialized || !argp->data) ++ if (!argp->data) + return -EINVAL; + + if (!writable) +@@ -2049,17 +2123,29 @@ static int sev_ioctl_do_snp_set_config(struct sev_issue_cmd *argp, bool writable + if (copy_from_user(&config, (void __user *)argp->data, sizeof(config))) + return -EFAULT; + +- return __sev_do_cmd_locked(SEV_CMD_SNP_CONFIG, &config, &argp->error); ++ if (!sev->snp_initialized) { ++ ret = snp_move_to_init_state(argp, &shutdown_required); ++ if (ret) ++ return ret; ++ } ++ ++ ret = __sev_do_cmd_locked(SEV_CMD_SNP_CONFIG, &config, &argp->error); ++ ++ if (shutdown_required) ++ __sev_snp_shutdown_locked(&error, false); ++ ++ return ret; + } + + static int sev_ioctl_do_snp_vlek_load(struct sev_issue_cmd *argp, bool writable) + { + struct sev_device *sev = psp_master->sev_data; + struct sev_user_data_snp_vlek_load input; ++ bool shutdown_required = false; ++ int ret, error; + void *blob; +- int ret; + +- if (!sev->snp_initialized || !argp->data) ++ if (!argp->data) + return -EINVAL; + + if (!writable) +@@ -2078,8 +2164,18 @@ static int sev_ioctl_do_snp_vlek_load(struct sev_issue_cmd *argp, bool writable) + + input.vlek_wrapped_address = __psp_pa(blob); + ++ if (!sev->snp_initialized) { ++ ret = snp_move_to_init_state(argp, &shutdown_required); ++ if (ret) ++ goto cleanup; ++ } ++ + ret = __sev_do_cmd_locked(SEV_CMD_SNP_VLEK_LOAD, &input, &argp->error); + ++ if (shutdown_required) ++ __sev_snp_shutdown_locked(&error, false); ++ ++cleanup: + kfree(blob); + + return ret; +-- +2.51.0 + diff --git a/queue-6.12/crypto-ccp-factor-out-ring-destroy-handling-to-a-hel.patch b/queue-6.12/crypto-ccp-factor-out-ring-destroy-handling-to-a-hel.patch new file mode 100644 index 0000000000..088881ef3c --- /dev/null +++ b/queue-6.12/crypto-ccp-factor-out-ring-destroy-handling-to-a-hel.patch @@ -0,0 +1,90 @@ +From 2c69f973b4457ae12b6798fd446922237345c70a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 22:11:31 -0600 +Subject: crypto: ccp - Factor out ring destroy handling to a helper +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Mario Limonciello (AMD) + +[ Upstream commit d95f87a65bce5f2f2a02ca6094ca4841d4073df3 ] + +The ring destroy command needs to be used in multiple places. Split +out the code to a helper. + +Tested-by: Yijun Shen +Signed-off-by: Mario Limonciello (AMD) +Acked-by: Tom Lendacky +Reviewed-by: Shyam Sundar S K +Link: https://patch.msgid.link/20260116041132.153674-5-superm1@kernel.org +Signed-off-by: Ilpo Järvinen +Stable-dep-of: 7b85137caf11 ("crypto: ccp - Send PSP_CMD_TEE_RING_DESTROY when PSP_CMD_TEE_RING_INIT fails") +Signed-off-by: Sasha Levin +--- + drivers/crypto/ccp/tee-dev.c | 36 ++++++++++++++++++++++++------------ + 1 file changed, 24 insertions(+), 12 deletions(-) + +diff --git a/drivers/crypto/ccp/tee-dev.c b/drivers/crypto/ccp/tee-dev.c +index 11c4b05e2f3a2..ef1430f86ad62 100644 +--- a/drivers/crypto/ccp/tee-dev.c ++++ b/drivers/crypto/ccp/tee-dev.c +@@ -86,6 +86,29 @@ static inline void tee_free_cmd_buffer(struct tee_init_ring_cmd *cmd) + kfree(cmd); + } + ++static bool tee_send_destroy_cmd(struct psp_tee_device *tee) ++{ ++ unsigned int reg; ++ int ret; ++ ++ ret = psp_mailbox_command(tee->psp, PSP_CMD_TEE_RING_DESTROY, NULL, ++ TEE_DEFAULT_CMD_TIMEOUT, ®); ++ if (ret) { ++ dev_err(tee->dev, "tee: ring destroy command timed out, disabling TEE support\n"); ++ psp_dead = true; ++ return false; ++ } ++ ++ if (FIELD_GET(PSP_CMDRESP_STS, reg)) { ++ dev_err(tee->dev, "tee: ring destroy command failed (%#010lx)\n", ++ FIELD_GET(PSP_CMDRESP_STS, reg)); ++ psp_dead = true; ++ return false; ++ } ++ ++ return true; ++} ++ + static int tee_init_ring(struct psp_tee_device *tee) + { + int ring_size = MAX_RING_BUFFER_ENTRIES * sizeof(struct tee_ring_cmd); +@@ -137,24 +160,13 @@ static int tee_init_ring(struct psp_tee_device *tee) + + static void tee_destroy_ring(struct psp_tee_device *tee) + { +- unsigned int reg; +- int ret; +- + if (!tee->rb_mgr.ring_start) + return; + + if (psp_dead) + goto free_ring; + +- ret = psp_mailbox_command(tee->psp, PSP_CMD_TEE_RING_DESTROY, NULL, +- TEE_DEFAULT_CMD_TIMEOUT, ®); +- if (ret) { +- dev_err(tee->dev, "tee: ring destroy command timed out, disabling TEE support\n"); +- psp_dead = true; +- } else if (FIELD_GET(PSP_CMDRESP_STS, reg)) { +- dev_err(tee->dev, "tee: ring destroy command failed (%#010lx)\n", +- FIELD_GET(PSP_CMDRESP_STS, reg)); +- } ++ tee_send_destroy_cmd(tee); + + free_ring: + tee_free_ring(tee); +-- +2.51.0 + diff --git a/queue-6.12/crypto-ccp-narrow-scope-of-snp_range_list.patch b/queue-6.12/crypto-ccp-narrow-scope-of-snp_range_list.patch new file mode 100644 index 0000000000..5f4ce5da05 --- /dev/null +++ b/queue-6.12/crypto-ccp-narrow-scope-of-snp_range_list.patch @@ -0,0 +1,64 @@ +From 65323cacdb9d8f3234be78c63808d4ba776c4ea3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Jan 2026 10:22:18 -0700 +Subject: crypto: ccp - narrow scope of snp_range_list + +From: Tycho Andersen (AMD) + +[ Upstream commit dc8ccab15081efc4f2c5a9fc7b209cd641d29177 ] + +snp_range_list is only used in __sev_snp_init_locked() in the SNP_INIT_EX +case, move the declaration there and add a __free() cleanup helper for it +instead of waiting until shutdown. + +Fixes: 1ca5614b84ee ("crypto: ccp: Add support to initialize the AMD-SP for SEV-SNP") +Reviewed-by: Alexey Kardashevskiy +Signed-off-by: Tycho Andersen (AMD) +Reviewed-by: Tom Lendacky +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/ccp/sev-dev.c | 13 +------------ + 1 file changed, 1 insertion(+), 12 deletions(-) + +diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c +index 3e08df45a8bdb..3016d1369ac51 100644 +--- a/drivers/crypto/ccp/sev-dev.c ++++ b/drivers/crypto/ccp/sev-dev.c +@@ -103,13 +103,6 @@ static size_t sev_es_tmr_size = SEV_TMR_SIZE; + #define NV_LENGTH (32 * 1024) + static void *sev_init_ex_buffer; + +-/* +- * SEV_DATA_RANGE_LIST: +- * Array containing range of pages that firmware transitions to HV-fixed +- * page state. +- */ +-static struct sev_data_range_list *snp_range_list; +- + static void __sev_firmware_shutdown(struct sev_device *sev, bool panic); + + static inline bool sev_version_greater_or_equal(u8 maj, u8 min) +@@ -1098,6 +1091,7 @@ static int snp_filter_reserved_mem_regions(struct resource *rs, void *arg) + + static int __sev_snp_init_locked(int *error) + { ++ struct sev_data_range_list *snp_range_list __free(kfree) = NULL; + struct psp_device *psp = psp_master; + struct sev_data_snp_init_ex data; + struct sev_device *sev; +@@ -2430,11 +2424,6 @@ static void __sev_firmware_shutdown(struct sev_device *sev, bool panic) + sev_init_ex_buffer = NULL; + } + +- if (snp_range_list) { +- kfree(snp_range_list); +- snp_range_list = NULL; +- } +- + __sev_snp_shutdown_locked(&error, panic); + } + +-- +2.51.0 + diff --git a/queue-6.12/crypto-ccp-send-psp_cmd_tee_ring_destroy-when-psp_cm.patch b/queue-6.12/crypto-ccp-send-psp_cmd_tee_ring_destroy-when-psp_cm.patch new file mode 100644 index 0000000000..61a18968c8 --- /dev/null +++ b/queue-6.12/crypto-ccp-send-psp_cmd_tee_ring_destroy-when-psp_cm.patch @@ -0,0 +1,113 @@ +From 0d9dde06a642be9497890030a63d0e676c979984 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 22:11:32 -0600 +Subject: crypto: ccp - Send PSP_CMD_TEE_RING_DESTROY when + PSP_CMD_TEE_RING_INIT fails +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Mario Limonciello (AMD) + +[ Upstream commit 7b85137caf110a09a4a18f00f730de4709f9afc8 ] + +The hibernate resume sequence involves loading a resume kernel that is just +used for loading the hibernate image before shifting back to the existing +kernel. + +During that hibernate resume sequence the resume kernel may have loaded +the ccp driver. If this happens the resume kernel will also have called +PSP_CMD_TEE_RING_INIT but it will never have called +PSP_CMD_TEE_RING_DESTROY. + +This is problematic because the existing kernel needs to re-initialize the +ring. One could argue that the existing kernel should call destroy +as part of restore() but there is no guarantee that the resume kernel did +or didn't load the ccp driver. There is also no callback opportunity for +the resume kernel to destroy before handing back control to the existing +kernel. + +Similar problems could potentially exist with the use of kdump and +crash handling. I actually reproduced this issue like this: + +1) rmmod ccp +2) hibernate the system +3) resume the system +4) modprobe ccp + +The resume kernel will have loaded ccp but never destroyed and then when +I try to modprobe it fails. + +Because of these possible cases add a flow that checks the error code from +the PSP_CMD_TEE_RING_INIT call and tries to call PSP_CMD_TEE_RING_DESTROY +if it failed. If this succeeds then call PSP_CMD_TEE_RING_INIT again. + +Fixes: f892a21f51162 ("crypto: ccp - use generic power management") +Reported-by: Lars Francke +Closes: https://lore.kernel.org/platform-driver-x86/CAD-Ua_gfJnQSo8ucS_7ZwzuhoBRJ14zXP7s8b-zX3ZcxcyWePw@mail.gmail.com/ +Tested-by: Yijun Shen +Signed-off-by: Mario Limonciello (AMD) +Reviewed-by: Shyam Sundar S K +Acked-by: Tom Lendacky +Link: https://patch.msgid.link/20260116041132.153674-6-superm1@kernel.org +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/crypto/ccp/tee-dev.c | 14 ++++++++++++++ + include/linux/psp.h | 1 + + 2 files changed, 15 insertions(+) + +diff --git a/drivers/crypto/ccp/tee-dev.c b/drivers/crypto/ccp/tee-dev.c +index ef1430f86ad62..92ffa412622a2 100644 +--- a/drivers/crypto/ccp/tee-dev.c ++++ b/drivers/crypto/ccp/tee-dev.c +@@ -113,6 +113,7 @@ static int tee_init_ring(struct psp_tee_device *tee) + { + int ring_size = MAX_RING_BUFFER_ENTRIES * sizeof(struct tee_ring_cmd); + struct tee_init_ring_cmd *cmd; ++ bool retry = false; + unsigned int reg; + int ret; + +@@ -135,6 +136,7 @@ static int tee_init_ring(struct psp_tee_device *tee) + /* Send command buffer details to Trusted OS by writing to + * CPU-PSP message registers + */ ++retry_init: + ret = psp_mailbox_command(tee->psp, PSP_CMD_TEE_RING_INIT, cmd, + TEE_DEFAULT_CMD_TIMEOUT, ®); + if (ret) { +@@ -145,6 +147,18 @@ static int tee_init_ring(struct psp_tee_device *tee) + } + + if (FIELD_GET(PSP_CMDRESP_STS, reg)) { ++ /* ++ * During the hibernate resume sequence driver may have gotten loaded ++ * but the ring not properly destroyed. If the ring doesn't work, try ++ * to destroy and re-init once. ++ */ ++ if (!retry && FIELD_GET(PSP_CMDRESP_STS, reg) == PSP_TEE_STS_RING_BUSY) { ++ dev_info(tee->dev, "tee: ring init command failed with busy status, retrying\n"); ++ if (tee_send_destroy_cmd(tee)) { ++ retry = true; ++ goto retry_init; ++ } ++ } + dev_err(tee->dev, "tee: ring init command failed (%#010lx)\n", + FIELD_GET(PSP_CMDRESP_STS, reg)); + tee_free_ring(tee); +diff --git a/include/linux/psp.h b/include/linux/psp.h +index 92e60aeef21e1..b337dcce1e991 100644 +--- a/include/linux/psp.h ++++ b/include/linux/psp.h +@@ -18,6 +18,7 @@ + * and should include an appropriate local definition in their source file. + */ + #define PSP_CMDRESP_STS GENMASK(15, 0) ++#define PSP_TEE_STS_RING_BUSY 0x0000000d /* Ring already initialized */ + #define PSP_CMDRESP_CMD GENMASK(23, 16) + #define PSP_CMDRESP_RESERVED GENMASK(29, 24) + #define PSP_CMDRESP_RECOVERY BIT(30) +-- +2.51.0 + diff --git a/queue-6.12/crypto-hisilicon-hpre-extend-tag-field-to-64-bits-fo.patch b/queue-6.12/crypto-hisilicon-hpre-extend-tag-field-to-64-bits-fo.patch new file mode 100644 index 0000000000..eaa87a62f1 --- /dev/null +++ b/queue-6.12/crypto-hisilicon-hpre-extend-tag-field-to-64-bits-fo.patch @@ -0,0 +1,340 @@ +From 5f161bb28865b5a83826c8c08c689292968d7a09 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 21:44:44 +0800 +Subject: crypto: hisilicon/hpre: extend tag field to 64 bits for better + performance + +From: lizhi + +[ Upstream commit 3a1984758197f7fd4c557dd98090e8e0cf9f498e ] + +This commit expands the tag field in hpre_sqe structure from 16-bit +to 64-bit. The change enables storing request addresses directly +in the tag field, allowing callback functions to access request messages +without the previous indirection mechanism. + +By eliminating the need for lookup tables, this modification reduces lock +contention and associated overhead, leading to improved efficiency and +simplified code. + +Fixes: c8b4b477079d ("crypto: hisilicon - add HiSilicon HPRE accelerator") +Signed-off-by: lizhi +Signed-off-by: Weili Qian +Signed-off-by: Chenghai Huang +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/hpre/hpre.h | 5 +- + drivers/crypto/hisilicon/hpre/hpre_crypto.c | 142 ++++---------------- + 2 files changed, 25 insertions(+), 122 deletions(-) + +diff --git a/drivers/crypto/hisilicon/hpre/hpre.h b/drivers/crypto/hisilicon/hpre/hpre.h +index 9f0b94c8e03dd..feed77429c8f6 100644 +--- a/drivers/crypto/hisilicon/hpre/hpre.h ++++ b/drivers/crypto/hisilicon/hpre/hpre.h +@@ -94,9 +94,8 @@ struct hpre_sqe { + __le64 key; + __le64 in; + __le64 out; +- __le16 tag; +- __le16 resv2; +-#define _HPRE_SQE_ALIGN_EXT 7 ++ __le64 tag; ++#define _HPRE_SQE_ALIGN_EXT 6 + __le32 rsvd1[_HPRE_SQE_ALIGN_EXT]; + }; + +diff --git a/drivers/crypto/hisilicon/hpre/hpre_crypto.c b/drivers/crypto/hisilicon/hpre/hpre_crypto.c +index e71f1e4597640..ee89282aec571 100644 +--- a/drivers/crypto/hisilicon/hpre/hpre_crypto.c ++++ b/drivers/crypto/hisilicon/hpre/hpre_crypto.c +@@ -117,12 +117,10 @@ struct hpre_curve25519_ctx { + struct hpre_ctx { + struct hisi_qp *qp; + struct device *dev; +- struct hpre_asym_request **req_list; + struct hpre *hpre; + spinlock_t req_lock; + unsigned int key_sz; + bool crt_g2_mode; +- struct idr req_idr; + union { + struct hpre_rsa_ctx rsa; + struct hpre_dh_ctx dh; +@@ -145,7 +143,6 @@ struct hpre_asym_request { + struct kpp_request *curve25519; + } areq; + int err; +- int req_id; + hpre_cb cb; + struct timespec64 req_time; + }; +@@ -160,58 +157,13 @@ static inline unsigned int hpre_align_pd(void) + return (hpre_align_sz() - 1) & ~(crypto_tfm_ctx_alignment() - 1); + } + +-static int hpre_alloc_req_id(struct hpre_ctx *ctx) +-{ +- unsigned long flags; +- int id; +- +- spin_lock_irqsave(&ctx->req_lock, flags); +- id = idr_alloc(&ctx->req_idr, NULL, 0, ctx->qp->sq_depth, GFP_ATOMIC); +- spin_unlock_irqrestore(&ctx->req_lock, flags); +- +- return id; +-} +- +-static void hpre_free_req_id(struct hpre_ctx *ctx, int req_id) +-{ +- unsigned long flags; +- +- spin_lock_irqsave(&ctx->req_lock, flags); +- idr_remove(&ctx->req_idr, req_id); +- spin_unlock_irqrestore(&ctx->req_lock, flags); +-} +- +-static int hpre_add_req_to_ctx(struct hpre_asym_request *hpre_req) ++static void hpre_dfx_add_req_time(struct hpre_asym_request *hpre_req) + { +- struct hpre_ctx *ctx; +- struct hpre_dfx *dfx; +- int id; +- +- ctx = hpre_req->ctx; +- id = hpre_alloc_req_id(ctx); +- if (unlikely(id < 0)) +- return -EINVAL; +- +- ctx->req_list[id] = hpre_req; +- hpre_req->req_id = id; ++ struct hpre_ctx *ctx = hpre_req->ctx; ++ struct hpre_dfx *dfx = ctx->hpre->debug.dfx; + +- dfx = ctx->hpre->debug.dfx; + if (atomic64_read(&dfx[HPRE_OVERTIME_THRHLD].value)) + ktime_get_ts64(&hpre_req->req_time); +- +- return id; +-} +- +-static void hpre_rm_req_from_ctx(struct hpre_asym_request *hpre_req) +-{ +- struct hpre_ctx *ctx = hpre_req->ctx; +- int id = hpre_req->req_id; +- +- if (hpre_req->req_id >= 0) { +- hpre_req->req_id = HPRE_INVLD_REQ_ID; +- ctx->req_list[id] = NULL; +- hpre_free_req_id(ctx, id); +- } + } + + static struct hisi_qp *hpre_get_qp_and_start(u8 type) +@@ -349,26 +301,19 @@ static void hpre_hw_data_clr_all(struct hpre_ctx *ctx, + static int hpre_alg_res_post_hf(struct hpre_ctx *ctx, struct hpre_sqe *sqe, + void **kreq) + { +- struct hpre_asym_request *req; + unsigned int err, done, alg; +- int id; + + #define HPRE_NO_HW_ERR 0 + #define HPRE_HW_TASK_DONE 3 + #define HREE_HW_ERR_MASK GENMASK(10, 0) + #define HREE_SQE_DONE_MASK GENMASK(1, 0) + #define HREE_ALG_TYPE_MASK GENMASK(4, 0) +- id = (int)le16_to_cpu(sqe->tag); +- req = ctx->req_list[id]; +- hpre_rm_req_from_ctx(req); +- *kreq = req; ++ *kreq = (void *)le64_to_cpu(sqe->tag); + + err = (le32_to_cpu(sqe->dw0) >> HPRE_SQE_ALG_BITS) & + HREE_HW_ERR_MASK; +- + done = (le32_to_cpu(sqe->dw0) >> HPRE_SQE_DONE_SHIFT) & + HREE_SQE_DONE_MASK; +- + if (likely(err == HPRE_NO_HW_ERR && done == HPRE_HW_TASK_DONE)) + return 0; + +@@ -379,34 +324,9 @@ static int hpre_alg_res_post_hf(struct hpre_ctx *ctx, struct hpre_sqe *sqe, + return -EINVAL; + } + +-static int hpre_ctx_set(struct hpre_ctx *ctx, struct hisi_qp *qp, int qlen) +-{ +- struct hpre *hpre; +- +- if (!ctx || !qp || qlen < 0) +- return -EINVAL; +- +- spin_lock_init(&ctx->req_lock); +- ctx->qp = qp; +- ctx->dev = &qp->qm->pdev->dev; +- +- hpre = container_of(ctx->qp->qm, struct hpre, qm); +- ctx->hpre = hpre; +- ctx->req_list = kcalloc(qlen, sizeof(void *), GFP_KERNEL); +- if (!ctx->req_list) +- return -ENOMEM; +- ctx->key_sz = 0; +- ctx->crt_g2_mode = false; +- idr_init(&ctx->req_idr); +- +- return 0; +-} +- + static void hpre_ctx_clear(struct hpre_ctx *ctx, bool is_clear_all) + { + if (is_clear_all) { +- idr_destroy(&ctx->req_idr); +- kfree(ctx->req_list); + hisi_qm_free_qps(&ctx->qp, 1); + } + +@@ -476,29 +396,22 @@ static void hpre_rsa_cb(struct hpre_ctx *ctx, void *resp) + + static void hpre_alg_cb(struct hisi_qp *qp, void *resp) + { +- struct hpre_ctx *ctx = qp->qp_ctx; +- struct hpre_dfx *dfx = ctx->hpre->debug.dfx; ++ struct hpre_asym_request *h_req; + struct hpre_sqe *sqe = resp; +- struct hpre_asym_request *req = ctx->req_list[le16_to_cpu(sqe->tag)]; + +- if (unlikely(!req)) { +- atomic64_inc(&dfx[HPRE_INVALID_REQ_CNT].value); ++ h_req = (struct hpre_asym_request *)le64_to_cpu(sqe->tag); ++ if (unlikely(!h_req)) { ++ pr_err("Failed to get request, and qp_id is %u\n", qp->qp_id); + return; + } + +- req->cb(ctx, resp); +-} +- +-static void hpre_stop_qp_and_put(struct hisi_qp *qp) +-{ +- hisi_qm_stop_qp(qp); +- hisi_qm_free_qps(&qp, 1); ++ h_req->cb(h_req->ctx, resp); + } + + static int hpre_ctx_init(struct hpre_ctx *ctx, u8 type) + { + struct hisi_qp *qp; +- int ret; ++ struct hpre *hpre; + + qp = hpre_get_qp_and_start(type); + if (IS_ERR(qp)) +@@ -506,19 +419,21 @@ static int hpre_ctx_init(struct hpre_ctx *ctx, u8 type) + + qp->qp_ctx = ctx; + qp->req_cb = hpre_alg_cb; ++ spin_lock_init(&ctx->req_lock); ++ ctx->qp = qp; ++ ctx->dev = &qp->qm->pdev->dev; ++ hpre = container_of(ctx->qp->qm, struct hpre, qm); ++ ctx->hpre = hpre; ++ ctx->key_sz = 0; ++ ctx->crt_g2_mode = false; + +- ret = hpre_ctx_set(ctx, qp, qp->sq_depth); +- if (ret) +- hpre_stop_qp_and_put(qp); +- +- return ret; ++ return 0; + } + + static int hpre_msg_request_set(struct hpre_ctx *ctx, void *req, bool is_rsa) + { + struct hpre_asym_request *h_req; + struct hpre_sqe *msg; +- int req_id; + void *tmp; + + if (is_rsa) { +@@ -558,11 +473,8 @@ static int hpre_msg_request_set(struct hpre_ctx *ctx, void *req, bool is_rsa) + msg->task_len1 = (ctx->key_sz >> HPRE_BITS_2_BYTES_SHIFT) - 1; + h_req->ctx = ctx; + +- req_id = hpre_add_req_to_ctx(h_req); +- if (req_id < 0) +- return -EBUSY; +- +- msg->tag = cpu_to_le16((u16)req_id); ++ hpre_dfx_add_req_time(h_req); ++ msg->tag = cpu_to_le64((uintptr_t)h_req); + + return 0; + } +@@ -628,7 +540,6 @@ static int hpre_dh_compute_value(struct kpp_request *req) + return -EINPROGRESS; + + clear_all: +- hpre_rm_req_from_ctx(hpre_req); + hpre_hw_data_clr_all(ctx, hpre_req, req->dst, req->src); + + return ret; +@@ -837,7 +748,6 @@ static int hpre_rsa_enc(struct akcipher_request *req) + return -EINPROGRESS; + + clear_all: +- hpre_rm_req_from_ctx(hpre_req); + hpre_hw_data_clr_all(ctx, hpre_req, req->dst, req->src); + + return ret; +@@ -892,7 +802,6 @@ static int hpre_rsa_dec(struct akcipher_request *req) + return -EINPROGRESS; + + clear_all: +- hpre_rm_req_from_ctx(hpre_req); + hpre_hw_data_clr_all(ctx, hpre_req, req->dst, req->src); + + return ret; +@@ -1362,7 +1271,7 @@ static int hpre_ecdh_set_param(struct hpre_ctx *ctx, struct ecdh *params) + return 0; + } + +-static bool hpre_key_is_zero(char *key, unsigned short key_sz) ++static bool hpre_key_is_zero(const char *key, unsigned short key_sz) + { + int i; + +@@ -1504,7 +1413,6 @@ static int hpre_ecdh_msg_request_set(struct hpre_ctx *ctx, + { + struct hpre_asym_request *h_req; + struct hpre_sqe *msg; +- int req_id; + void *tmp; + + if (req->dst_len < ctx->key_sz << 1) { +@@ -1526,11 +1434,8 @@ static int hpre_ecdh_msg_request_set(struct hpre_ctx *ctx, + msg->task_len1 = (ctx->key_sz >> HPRE_BITS_2_BYTES_SHIFT) - 1; + h_req->ctx = ctx; + +- req_id = hpre_add_req_to_ctx(h_req); +- if (req_id < 0) +- return -EBUSY; +- +- msg->tag = cpu_to_le16((u16)req_id); ++ hpre_dfx_add_req_time(h_req); ++ msg->tag = cpu_to_le64((uintptr_t)h_req); + return 0; + } + +@@ -1626,7 +1531,6 @@ static int hpre_ecdh_compute_value(struct kpp_request *req) + return -EINPROGRESS; + + clear_all: +- hpre_rm_req_from_ctx(hpre_req); + hpre_ecdh_hw_data_clr_all(ctx, hpre_req, req->dst, req->src); + return ret; + } +-- +2.51.0 + diff --git a/queue-6.12/crypto-hisilicon-sec2-support-skcipher-aead-fallback.patch b/queue-6.12/crypto-hisilicon-sec2-support-skcipher-aead-fallback.patch new file mode 100644 index 0000000000..fd4b361a85 --- /dev/null +++ b/queue-6.12/crypto-hisilicon-sec2-support-skcipher-aead-fallback.patch @@ -0,0 +1,220 @@ +From 3052792f1400ffd5f5d721e26b55e27c0cf6f37c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 21:44:52 +0800 +Subject: crypto: hisilicon/sec2 - support skcipher/aead fallback for hardware + queue unavailable + +From: Qi Tao + +[ Upstream commit e7507439628052363500d717caffb5c2241854dc ] + +When all hardware queues are busy and no shareable queue, +new processes fail to apply for queues. To avoid affecting +tasks, support fallback mechanism when hardware queues are +unavailable. + +Fixes: c16a70c1f253 ("crypto: hisilicon/sec - add new algorithm mode for AEAD") +Signed-off-by: Qi Tao +Signed-off-by: Chenghai Huang +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/sec2/sec_crypto.c | 62 ++++++++++++++++------ + 1 file changed, 47 insertions(+), 15 deletions(-) + +diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.c b/drivers/crypto/hisilicon/sec2/sec_crypto.c +index 8605cb3cae92c..cdd485fcbc5bb 100644 +--- a/drivers/crypto/hisilicon/sec2/sec_crypto.c ++++ b/drivers/crypto/hisilicon/sec2/sec_crypto.c +@@ -591,10 +591,8 @@ static int sec_ctx_base_init(struct sec_ctx *ctx) + int i, ret; + + ctx->qps = sec_create_qps(); +- if (!ctx->qps) { +- pr_err("Can not create sec qps!\n"); ++ if (!ctx->qps) + return -ENODEV; +- } + + sec = container_of(ctx->qps[0]->qm, struct sec_dev, qm); + ctx->sec = sec; +@@ -633,6 +631,9 @@ static void sec_ctx_base_uninit(struct sec_ctx *ctx) + { + int i; + ++ if (!ctx->qps) ++ return; ++ + for (i = 0; i < ctx->sec->ctx_q_num; i++) + sec_release_qp_ctx(ctx, &ctx->qp_ctx[i]); + +@@ -644,6 +645,9 @@ static int sec_cipher_init(struct sec_ctx *ctx) + { + struct sec_cipher_ctx *c_ctx = &ctx->c_ctx; + ++ if (!ctx->qps) ++ return 0; ++ + c_ctx->c_key = dma_alloc_coherent(ctx->dev, SEC_MAX_KEY_SIZE, + &c_ctx->c_key_dma, GFP_KERNEL); + if (!c_ctx->c_key) +@@ -656,6 +660,9 @@ static void sec_cipher_uninit(struct sec_ctx *ctx) + { + struct sec_cipher_ctx *c_ctx = &ctx->c_ctx; + ++ if (!ctx->qps) ++ return; ++ + memzero_explicit(c_ctx->c_key, SEC_MAX_KEY_SIZE); + dma_free_coherent(ctx->dev, SEC_MAX_KEY_SIZE, + c_ctx->c_key, c_ctx->c_key_dma); +@@ -677,6 +684,9 @@ static void sec_auth_uninit(struct sec_ctx *ctx) + { + struct sec_auth_ctx *a_ctx = &ctx->a_ctx; + ++ if (!ctx->qps) ++ return; ++ + memzero_explicit(a_ctx->a_key, SEC_MAX_AKEY_SIZE); + dma_free_coherent(ctx->dev, SEC_MAX_AKEY_SIZE, + a_ctx->a_key, a_ctx->a_key_dma); +@@ -714,7 +724,7 @@ static int sec_skcipher_init(struct crypto_skcipher *tfm) + } + + ret = sec_ctx_base_init(ctx); +- if (ret) ++ if (ret && ret != -ENODEV) + return ret; + + ret = sec_cipher_init(ctx); +@@ -823,6 +833,9 @@ static int sec_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key, + struct device *dev = ctx->dev; + int ret; + ++ if (!ctx->qps) ++ goto set_soft_key; ++ + if (c_mode == SEC_CMODE_XTS) { + ret = xts_verify_key(tfm, key, keylen); + if (ret) { +@@ -853,13 +866,14 @@ static int sec_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key, + } + + memcpy(c_ctx->c_key, key, keylen); +- if (c_ctx->fbtfm) { +- ret = crypto_sync_skcipher_setkey(c_ctx->fbtfm, key, keylen); +- if (ret) { +- dev_err(dev, "failed to set fallback skcipher key!\n"); +- return ret; +- } ++ ++set_soft_key: ++ ret = crypto_sync_skcipher_setkey(c_ctx->fbtfm, key, keylen); ++ if (ret) { ++ dev_err(dev, "failed to set fallback skcipher key!\n"); ++ return ret; + } ++ + return 0; + } + +@@ -1135,6 +1149,9 @@ static int sec_aead_setkey(struct crypto_aead *tfm, const u8 *key, + struct crypto_authenc_keys keys; + int ret; + ++ if (!ctx->qps) ++ return sec_aead_fallback_setkey(a_ctx, tfm, key, keylen); ++ + ctx->a_ctx.a_alg = a_alg; + ctx->c_ctx.c_alg = c_alg; + c_ctx->c_mode = c_mode; +@@ -1829,6 +1846,9 @@ static int sec_skcipher_ctx_init(struct crypto_skcipher *tfm) + if (ret) + return ret; + ++ if (!ctx->qps) ++ return 0; ++ + if (ctx->sec->qm.ver < QM_HW_V3) { + ctx->type_supported = SEC_BD_TYPE2; + ctx->req_op = &sec_skcipher_req_ops; +@@ -1837,7 +1857,7 @@ static int sec_skcipher_ctx_init(struct crypto_skcipher *tfm) + ctx->req_op = &sec_skcipher_req_ops_v3; + } + +- return ret; ++ return 0; + } + + static void sec_skcipher_ctx_exit(struct crypto_skcipher *tfm) +@@ -1905,7 +1925,7 @@ static int sec_aead_ctx_init(struct crypto_aead *tfm, const char *hash_name) + int ret; + + ret = sec_aead_init(tfm); +- if (ret) { ++ if (ret && ret != -ENODEV) { + pr_err("hisi_sec2: aead init error!\n"); + return ret; + } +@@ -1947,7 +1967,7 @@ static int sec_aead_xcm_ctx_init(struct crypto_aead *tfm) + int ret; + + ret = sec_aead_init(tfm); +- if (ret) { ++ if (ret && ret != -ENODEV) { + dev_err(ctx->dev, "hisi_sec2: aead xcm init error!\n"); + return ret; + } +@@ -2092,6 +2112,9 @@ static int sec_skcipher_crypto(struct skcipher_request *sk_req, bool encrypt) + bool need_fallback = false; + int ret; + ++ if (!ctx->qps) ++ goto soft_crypto; ++ + if (!sk_req->cryptlen) { + if (ctx->c_ctx.c_mode == SEC_CMODE_XTS) + return -EINVAL; +@@ -2108,9 +2131,12 @@ static int sec_skcipher_crypto(struct skcipher_request *sk_req, bool encrypt) + return -EINVAL; + + if (unlikely(ctx->c_ctx.fallback || need_fallback)) +- return sec_skcipher_soft_crypto(ctx, sk_req, encrypt); ++ goto soft_crypto; + + return ctx->req_op->process(ctx, req); ++ ++soft_crypto: ++ return sec_skcipher_soft_crypto(ctx, sk_req, encrypt); + } + + static int sec_skcipher_encrypt(struct skcipher_request *sk_req) +@@ -2315,6 +2341,9 @@ static int sec_aead_crypto(struct aead_request *a_req, bool encrypt) + bool need_fallback = false; + int ret; + ++ if (!ctx->qps) ++ goto soft_crypto; ++ + req->flag = a_req->base.flags; + req->aead_req.aead_req = a_req; + req->c_req.encrypt = encrypt; +@@ -2324,11 +2353,14 @@ static int sec_aead_crypto(struct aead_request *a_req, bool encrypt) + ret = sec_aead_param_check(ctx, req, &need_fallback); + if (unlikely(ret)) { + if (need_fallback) +- return sec_aead_soft_crypto(ctx, a_req, encrypt); ++ goto soft_crypto; + return -EINVAL; + } + + return ctx->req_op->process(ctx, req); ++ ++soft_crypto: ++ return sec_aead_soft_crypto(ctx, a_req, encrypt); + } + + static int sec_aead_encrypt(struct aead_request *a_req) +-- +2.51.0 + diff --git a/queue-6.12/crypto-hisilicon-trng-support-tfms-sharing-the-devic.patch b/queue-6.12/crypto-hisilicon-trng-support-tfms-sharing-the-devic.patch new file mode 100644 index 0000000000..08b446116f --- /dev/null +++ b/queue-6.12/crypto-hisilicon-trng-support-tfms-sharing-the-devic.patch @@ -0,0 +1,258 @@ +From 59991429f860daa03a0a427f7c971e59ab1f1996 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 17 Jan 2026 15:18:21 +0800 +Subject: crypto: hisilicon/trng - support tfms sharing the device + +From: Weili Qian + +[ Upstream commit 3d3135057ff567d5c09fff4c9ef6391a684e8042 ] + +Since the number of devices is limited, and the number +of tfms may exceed the number of devices, to ensure that +tfms can be successfully allocated, support tfms +sharing the same device. + +Fixes: e4d9d10ef4be ("crypto: hisilicon/trng - add support for PRNG") +Signed-off-by: Weili Qian +Signed-off-by: Chenghai Huang +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/trng/trng.c | 121 +++++++++++++++++++-------- + 1 file changed, 86 insertions(+), 35 deletions(-) + +diff --git a/drivers/crypto/hisilicon/trng/trng.c b/drivers/crypto/hisilicon/trng/trng.c +index 66c551ecdee80..85a4b99f9055a 100644 +--- a/drivers/crypto/hisilicon/trng/trng.c ++++ b/drivers/crypto/hisilicon/trng/trng.c +@@ -40,6 +40,7 @@ + #define SEED_SHIFT_24 24 + #define SEED_SHIFT_16 16 + #define SEED_SHIFT_8 8 ++#define SW_MAX_RANDOM_BYTES 65520 + + struct hisi_trng_list { + struct mutex lock; +@@ -53,8 +54,10 @@ struct hisi_trng { + struct list_head list; + struct hwrng rng; + u32 ver; +- bool is_used; +- struct mutex mutex; ++ u32 ctx_num; ++ /* The bytes of the random number generated since the last seeding. */ ++ u32 random_bytes; ++ struct mutex lock; + }; + + struct hisi_trng_ctx { +@@ -63,10 +66,14 @@ struct hisi_trng_ctx { + + static atomic_t trng_active_devs; + static struct hisi_trng_list trng_devices; ++static int hisi_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait); + +-static void hisi_trng_set_seed(struct hisi_trng *trng, const u8 *seed) ++static int hisi_trng_set_seed(struct hisi_trng *trng, const u8 *seed) + { + u32 val, seed_reg, i; ++ int ret; ++ ++ writel(0x0, trng->base + SW_DRBG_BLOCKS); + + for (i = 0; i < SW_DRBG_SEED_SIZE; + i += SW_DRBG_SEED_SIZE / SW_DRBG_SEED_REGS_NUM) { +@@ -78,6 +85,20 @@ static void hisi_trng_set_seed(struct hisi_trng *trng, const u8 *seed) + seed_reg = (i >> SW_DRBG_NUM_SHIFT) % SW_DRBG_SEED_REGS_NUM; + writel(val, trng->base + SW_DRBG_SEED(seed_reg)); + } ++ ++ writel(SW_DRBG_BLOCKS_NUM | (0x1 << SW_DRBG_ENABLE_SHIFT), ++ trng->base + SW_DRBG_BLOCKS); ++ writel(0x1, trng->base + SW_DRBG_INIT); ++ ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS, ++ val, val & BIT(0), SLEEP_US, TIMEOUT_US); ++ if (ret) { ++ pr_err("failed to init trng(%d)\n", ret); ++ return -EIO; ++ } ++ ++ trng->random_bytes = 0; ++ ++ return 0; + } + + static int hisi_trng_seed(struct crypto_rng *tfm, const u8 *seed, +@@ -85,8 +106,7 @@ static int hisi_trng_seed(struct crypto_rng *tfm, const u8 *seed, + { + struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm); + struct hisi_trng *trng = ctx->trng; +- u32 val = 0; +- int ret = 0; ++ int ret; + + if (slen < SW_DRBG_SEED_SIZE) { + pr_err("slen(%u) is not matched with trng(%d)\n", slen, +@@ -94,43 +114,45 @@ static int hisi_trng_seed(struct crypto_rng *tfm, const u8 *seed, + return -EINVAL; + } + +- writel(0x0, trng->base + SW_DRBG_BLOCKS); +- hisi_trng_set_seed(trng, seed); ++ mutex_lock(&trng->lock); ++ ret = hisi_trng_set_seed(trng, seed); ++ mutex_unlock(&trng->lock); + +- writel(SW_DRBG_BLOCKS_NUM | (0x1 << SW_DRBG_ENABLE_SHIFT), +- trng->base + SW_DRBG_BLOCKS); +- writel(0x1, trng->base + SW_DRBG_INIT); ++ return ret; ++} + +- ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS, +- val, val & BIT(0), SLEEP_US, TIMEOUT_US); +- if (ret) +- pr_err("fail to init trng(%d)\n", ret); ++static int hisi_trng_reseed(struct hisi_trng *trng) ++{ ++ u8 seed[SW_DRBG_SEED_SIZE]; ++ int size; + +- return ret; ++ if (!trng->random_bytes) ++ return 0; ++ ++ size = hisi_trng_read(&trng->rng, seed, SW_DRBG_SEED_SIZE, false); ++ if (size != SW_DRBG_SEED_SIZE) ++ return -EIO; ++ ++ return hisi_trng_set_seed(trng, seed); + } + +-static int hisi_trng_generate(struct crypto_rng *tfm, const u8 *src, +- unsigned int slen, u8 *dstn, unsigned int dlen) ++static int hisi_trng_get_bytes(struct hisi_trng *trng, u8 *dstn, unsigned int dlen) + { +- struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm); +- struct hisi_trng *trng = ctx->trng; + u32 data[SW_DRBG_DATA_NUM]; + u32 currsize = 0; + u32 val = 0; + int ret; + u32 i; + +- if (dlen > SW_DRBG_BLOCKS_NUM * SW_DRBG_BYTES || dlen == 0) { +- pr_err("dlen(%u) exceeds limit(%d)!\n", dlen, +- SW_DRBG_BLOCKS_NUM * SW_DRBG_BYTES); +- return -EINVAL; +- } ++ ret = hisi_trng_reseed(trng); ++ if (ret) ++ return ret; + + do { + ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS, +- val, val & BIT(1), SLEEP_US, TIMEOUT_US); ++ val, val & BIT(1), SLEEP_US, TIMEOUT_US); + if (ret) { +- pr_err("fail to generate random number(%d)!\n", ret); ++ pr_err("failed to generate random number(%d)!\n", ret); + break; + } + +@@ -145,30 +167,57 @@ static int hisi_trng_generate(struct crypto_rng *tfm, const u8 *src, + currsize = dlen; + } + ++ trng->random_bytes += SW_DRBG_BYTES; + writel(0x1, trng->base + SW_DRBG_GEN); + } while (currsize < dlen); + + return ret; + } + ++static int hisi_trng_generate(struct crypto_rng *tfm, const u8 *src, ++ unsigned int slen, u8 *dstn, unsigned int dlen) ++{ ++ struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm); ++ struct hisi_trng *trng = ctx->trng; ++ unsigned int currsize = 0; ++ unsigned int block_size; ++ int ret; ++ ++ if (!dstn || !dlen) { ++ pr_err("output is error, dlen %u!\n", dlen); ++ return -EINVAL; ++ } ++ ++ do { ++ block_size = min_t(unsigned int, dlen - currsize, SW_MAX_RANDOM_BYTES); ++ mutex_lock(&trng->lock); ++ ret = hisi_trng_get_bytes(trng, dstn + currsize, block_size); ++ mutex_unlock(&trng->lock); ++ if (ret) ++ return ret; ++ currsize += block_size; ++ } while (currsize < dlen); ++ ++ return 0; ++} ++ + static int hisi_trng_init(struct crypto_tfm *tfm) + { + struct hisi_trng_ctx *ctx = crypto_tfm_ctx(tfm); + struct hisi_trng *trng; +- int ret = -EBUSY; ++ u32 ctx_num = ~0; + + mutex_lock(&trng_devices.lock); + list_for_each_entry(trng, &trng_devices.list, list) { +- if (!trng->is_used) { +- trng->is_used = true; ++ if (trng->ctx_num < ctx_num) { ++ ctx_num = trng->ctx_num; + ctx->trng = trng; +- ret = 0; +- break; + } + } ++ ctx->trng->ctx_num++; + mutex_unlock(&trng_devices.lock); + +- return ret; ++ return 0; + } + + static void hisi_trng_exit(struct crypto_tfm *tfm) +@@ -176,7 +225,7 @@ static void hisi_trng_exit(struct crypto_tfm *tfm) + struct hisi_trng_ctx *ctx = crypto_tfm_ctx(tfm); + + mutex_lock(&trng_devices.lock); +- ctx->trng->is_used = false; ++ ctx->trng->ctx_num--; + mutex_unlock(&trng_devices.lock); + } + +@@ -238,7 +287,7 @@ static int hisi_trng_del_from_list(struct hisi_trng *trng) + int ret = -EBUSY; + + mutex_lock(&trng_devices.lock); +- if (!trng->is_used) { ++ if (!trng->ctx_num) { + list_del(&trng->list); + ret = 0; + } +@@ -262,7 +311,9 @@ static int hisi_trng_probe(struct platform_device *pdev) + if (IS_ERR(trng->base)) + return PTR_ERR(trng->base); + +- trng->is_used = false; ++ trng->ctx_num = 0; ++ trng->random_bytes = SW_MAX_RANDOM_BYTES; ++ mutex_init(&trng->lock); + trng->ver = readl(trng->base + HISI_TRNG_VERSION); + if (!trng_devices.is_init) { + INIT_LIST_HEAD(&trng_devices.list); +-- +2.51.0 + diff --git a/queue-6.12/crypto-hisilicon-zip-adjust-the-way-to-obtain-the-re.patch b/queue-6.12/crypto-hisilicon-zip-adjust-the-way-to-obtain-the-re.patch new file mode 100644 index 0000000000..5d55fba8b9 --- /dev/null +++ b/queue-6.12/crypto-hisilicon-zip-adjust-the-way-to-obtain-the-re.patch @@ -0,0 +1,128 @@ +From 2e09e7e563191537dac12a05c47b5f684b898337 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 21:44:42 +0800 +Subject: crypto: hisilicon/zip - adjust the way to obtain the req in the + callback function + +From: Chenghai Huang + +[ Upstream commit 19c2475ce1984cf675ebfbbeaa5509b2fb1887d6 ] + +In the shared queue design, multiple tfms use same qp, and one qp +need to corresponds to multiple qp_ctx. So use tag to obtain the +req virtual address. Build a one-to-one relationship between tfm +and qp_ctx. finaly remove the old get_tag operation. + +Fixes: 2bcf36348ce5 ("crypto: hisilicon/zip - initialize operations about 'sqe' in 'acomp_alg.init'") +Signed-off-by: Chenghai Huang +Signed-off-by: Weili Qian +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/zip/zip_crypto.c | 24 +++++++++-------------- + 1 file changed, 9 insertions(+), 15 deletions(-) + +diff --git a/drivers/crypto/hisilicon/zip/zip_crypto.c b/drivers/crypto/hisilicon/zip/zip_crypto.c +index 7327f8f29b013..42ac275be36fc 100644 +--- a/drivers/crypto/hisilicon/zip/zip_crypto.c ++++ b/drivers/crypto/hisilicon/zip/zip_crypto.c +@@ -39,6 +39,7 @@ enum { + HZIP_CTX_Q_NUM + }; + ++#define GET_REQ_FROM_SQE(sqe) ((u64)(sqe)->dw26 | (u64)(sqe)->dw27 << 32) + #define COMP_NAME_TO_TYPE(alg_name) \ + (!strcmp((alg_name), "deflate") ? HZIP_ALG_TYPE_DEFLATE : 0) + +@@ -48,6 +49,7 @@ struct hisi_zip_req { + struct hisi_acc_hw_sgl *hw_dst; + dma_addr_t dma_src; + dma_addr_t dma_dst; ++ struct hisi_zip_qp_ctx *qp_ctx; + u16 req_id; + }; + +@@ -74,7 +76,6 @@ struct hisi_zip_sqe_ops { + void (*fill_req_type)(struct hisi_zip_sqe *sqe, u8 req_type); + void (*fill_tag)(struct hisi_zip_sqe *sqe, struct hisi_zip_req *req); + void (*fill_sqe_type)(struct hisi_zip_sqe *sqe, u8 sqe_type); +- u32 (*get_tag)(struct hisi_zip_sqe *sqe); + u32 (*get_status)(struct hisi_zip_sqe *sqe); + u32 (*get_dstlen)(struct hisi_zip_sqe *sqe); + }; +@@ -131,6 +132,7 @@ static struct hisi_zip_req *hisi_zip_create_req(struct hisi_zip_qp_ctx *qp_ctx, + req_cache = q + req_id; + req_cache->req_id = req_id; + req_cache->req = req; ++ req_cache->qp_ctx = qp_ctx; + + return req_cache; + } +@@ -181,7 +183,8 @@ static void hisi_zip_fill_req_type(struct hisi_zip_sqe *sqe, u8 req_type) + + static void hisi_zip_fill_tag(struct hisi_zip_sqe *sqe, struct hisi_zip_req *req) + { +- sqe->dw26 = req->req_id; ++ sqe->dw26 = lower_32_bits((u64)req); ++ sqe->dw27 = upper_32_bits((u64)req); + } + + static void hisi_zip_fill_sqe_type(struct hisi_zip_sqe *sqe, u8 sqe_type) +@@ -236,7 +239,7 @@ static int hisi_zip_do_work(struct hisi_zip_qp_ctx *qp_ctx, + &req->dma_dst); + if (IS_ERR(req->hw_dst)) { + ret = PTR_ERR(req->hw_dst); +- dev_err(dev, "failed to map the dst buffer to hw slg (%d)!\n", ++ dev_err(dev, "failed to map the dst buffer to hw sgl (%d)!\n", + ret); + goto err_unmap_input; + } +@@ -264,11 +267,6 @@ static int hisi_zip_do_work(struct hisi_zip_qp_ctx *qp_ctx, + return ret; + } + +-static u32 hisi_zip_get_tag(struct hisi_zip_sqe *sqe) +-{ +- return sqe->dw26; +-} +- + static u32 hisi_zip_get_status(struct hisi_zip_sqe *sqe) + { + return sqe->dw3 & HZIP_BD_STATUS_M; +@@ -281,14 +279,12 @@ static u32 hisi_zip_get_dstlen(struct hisi_zip_sqe *sqe) + + static void hisi_zip_acomp_cb(struct hisi_qp *qp, void *data) + { +- struct hisi_zip_qp_ctx *qp_ctx = qp->qp_ctx; ++ struct hisi_zip_sqe *sqe = data; ++ struct hisi_zip_req *req = (struct hisi_zip_req *)GET_REQ_FROM_SQE(sqe); ++ struct hisi_zip_qp_ctx *qp_ctx = req->qp_ctx; + const struct hisi_zip_sqe_ops *ops = qp_ctx->ctx->ops; + struct hisi_zip_dfx *dfx = &qp_ctx->zip_dev->dfx; +- struct hisi_zip_req_q *req_q = &qp_ctx->req_q; + struct device *dev = &qp->qm->pdev->dev; +- struct hisi_zip_sqe *sqe = data; +- u32 tag = ops->get_tag(sqe); +- struct hisi_zip_req *req = req_q->q + tag; + struct acomp_req *acomp_req = req->req; + int err = 0; + u32 status; +@@ -392,7 +388,6 @@ static const struct hisi_zip_sqe_ops hisi_zip_ops = { + .fill_req_type = hisi_zip_fill_req_type, + .fill_tag = hisi_zip_fill_tag, + .fill_sqe_type = hisi_zip_fill_sqe_type, +- .get_tag = hisi_zip_get_tag, + .get_status = hisi_zip_get_status, + .get_dstlen = hisi_zip_get_dstlen, + }; +@@ -580,7 +575,6 @@ static void hisi_zip_acomp_exit(struct crypto_acomp *tfm) + { + struct hisi_zip_ctx *ctx = crypto_tfm_ctx(&tfm->base); + +- hisi_zip_set_acomp_cb(ctx, NULL); + hisi_zip_release_sgl_pool(ctx); + hisi_zip_release_req_q(ctx); + hisi_zip_ctx_exit(ctx); +-- +2.51.0 + diff --git a/queue-6.12/crypto-octeontx-fix-dma_free_coherent-size.patch b/queue-6.12/crypto-octeontx-fix-dma_free_coherent-size.patch new file mode 100644 index 0000000000..57865654a3 --- /dev/null +++ b/queue-6.12/crypto-octeontx-fix-dma_free_coherent-size.patch @@ -0,0 +1,38 @@ +From 5efc10dfae9b98ecd51fe6ac75633a74c0b57897 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 11:12:57 +0100 +Subject: crypto: octeontx - fix dma_free_coherent() size + +From: Thomas Fourier + +[ Upstream commit 624a6760bf8464965c17c8df10b40b557eaa3002 ] + +The size of the buffer in alloc_command_queues() is +curr->size + OTX_CPT_NEXT_CHUNK_PTR_SIZE, so used that length for +dma_free_coherent(). + +Fixes: 10b4f09491bf ("crypto: marvell - add the Virtual Function driver for CPT") +Signed-off-by: Thomas Fourier +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/marvell/octeontx/otx_cptvf_main.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/crypto/marvell/octeontx/otx_cptvf_main.c b/drivers/crypto/marvell/octeontx/otx_cptvf_main.c +index 88a41d1ca5f64..6c0bfb3ea1c9f 100644 +--- a/drivers/crypto/marvell/octeontx/otx_cptvf_main.c ++++ b/drivers/crypto/marvell/octeontx/otx_cptvf_main.c +@@ -168,7 +168,8 @@ static void free_command_queues(struct otx_cptvf *cptvf, + chunk = list_first_entry(&cqinfo->queue[i].chead, + struct otx_cpt_cmd_chunk, nextchunk); + +- dma_free_coherent(&pdev->dev, chunk->size, ++ dma_free_coherent(&pdev->dev, ++ chunk->size + OTX_CPT_NEXT_CHUNK_PTR_SIZE, + chunk->head, + chunk->dma_addr); + chunk->head = NULL; +-- +2.51.0 + diff --git a/queue-6.12/crypto-qat-fix-warning-on-adf_pfvf_pf_proto.c.patch b/queue-6.12/crypto-qat-fix-warning-on-adf_pfvf_pf_proto.c.patch new file mode 100644 index 0000000000..98325c6308 --- /dev/null +++ b/queue-6.12/crypto-qat-fix-warning-on-adf_pfvf_pf_proto.c.patch @@ -0,0 +1,63 @@ +From f903590b3b79f8179ab113c4d72fd7f5119cc5cc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 20 Nov 2025 16:30:46 +0000 +Subject: crypto: qat - fix warning on adf_pfvf_pf_proto.c +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Giovanni Cabiddu + +[ Upstream commit 994689b8f91b02fdb5f64cba2412cde5ef3084b5 ] + +Building the QAT driver with -Wmaybe-uninitialized triggers warnings in +qat_common/adf_pfvf_pf_proto.c. Specifically, the variables blk_type, +blk_byte, and byte_max may be used uninitialized in handle_blkmsg_req(): + + make M=drivers/crypto/intel/qat W=1 C=2 "KCFLAGS=-Werror" \ + KBUILD_CFLAGS_KERNEL=-Wmaybe-uninitialized \ + CFLAGS_MODULE=-Wmaybe-uninitialized + + ... + warning: ‘byte_max’ may be used uninitialized [-Wmaybe-uninitialized] + warning: ‘blk_type’ may be used uninitialized [-Wmaybe-uninitialized] + warning: ‘blk_byte’ may be used uninitialized [-Wmaybe-uninitialized] + +Although the caller of handle_blkmsg_req() always provides a req.type +that is handled by the switch, the compiler cannot guarantee this. + +Add a default case to the switch statement to handle an invalid req.type. + +Fixes: 673184a2a58f ("crypto: qat - introduce support for PFVF block messages") +Signed-off-by: Giovanni Cabiddu +Reviewed-by: Ahsan Atta +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + .../crypto/intel/qat/qat_common/adf_pfvf_pf_proto.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/crypto/intel/qat/qat_common/adf_pfvf_pf_proto.c b/drivers/crypto/intel/qat/qat_common/adf_pfvf_pf_proto.c +index b9b5e744a3f16..af8dbc7517cf8 100644 +--- a/drivers/crypto/intel/qat/qat_common/adf_pfvf_pf_proto.c ++++ b/drivers/crypto/intel/qat/qat_common/adf_pfvf_pf_proto.c +@@ -148,6 +148,16 @@ static struct pfvf_message handle_blkmsg_req(struct adf_accel_vf_info *vf_info, + blk_byte = FIELD_GET(ADF_VF2PF_SMALL_BLOCK_BYTE_MASK, req.data); + byte_max = ADF_VF2PF_SMALL_BLOCK_BYTE_MAX; + break; ++ default: ++ dev_err(&GET_DEV(vf_info->accel_dev), ++ "Invalid BlockMsg type 0x%.4x received from VF%u\n", ++ req.type, vf_info->vf_nr); ++ resp.type = ADF_PF2VF_MSGTYPE_BLKMSG_RESP; ++ resp.data = FIELD_PREP(ADF_PF2VF_BLKMSG_RESP_TYPE_MASK, ++ ADF_PF2VF_BLKMSG_RESP_TYPE_ERROR) | ++ FIELD_PREP(ADF_PF2VF_BLKMSG_RESP_DATA_MASK, ++ ADF_PF2VF_UNSPECIFIED_ERROR); ++ return resp; + } + + /* Is this a request for CRC or data? */ +-- +2.51.0 + diff --git a/queue-6.12/crypto-starfive-fix-memory-leak-in-starfive_aes_aead.patch b/queue-6.12/crypto-starfive-fix-memory-leak-in-starfive_aes_aead.patch new file mode 100644 index 0000000000..53f15b8916 --- /dev/null +++ b/queue-6.12/crypto-starfive-fix-memory-leak-in-starfive_aes_aead.patch @@ -0,0 +1,60 @@ +From 6994cf2c33aeb4f809cba83ae9ed06024b8724f8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 15:10:16 +0000 +Subject: crypto: starfive - Fix memory leak in starfive_aes_aead_do_one_req() + +From: Zilin Guan + +[ Upstream commit ccb679fdae2e62ed92fd9acb25ed809c0226fcc6 ] + +The starfive_aes_aead_do_one_req() function allocates rctx->adata with +kzalloc() but fails to free it if sg_copy_to_buffer() or +starfive_aes_hw_init() fails, which lead to memory leaks. + +Since rctx->adata is unconditionally freed after the write_adata +operations, ensure consistent cleanup by freeing the allocation in these +earlier error paths as well. + +Compile tested only. Issue found using a prototype static analysis tool +and code review. + +Fixes: 7467147ef9bf ("crypto: starfive - Use dma for aes requests") +Signed-off-by: Zilin Guan +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/starfive/jh7110-aes.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/drivers/crypto/starfive/jh7110-aes.c b/drivers/crypto/starfive/jh7110-aes.c +index 86a1a1fa9f8f9..04f2f97ce238a 100644 +--- a/drivers/crypto/starfive/jh7110-aes.c ++++ b/drivers/crypto/starfive/jh7110-aes.c +@@ -673,8 +673,10 @@ static int starfive_aes_aead_do_one_req(struct crypto_engine *engine, void *areq + "Failed to alloc memory for adata"); + + if (sg_copy_to_buffer(req->src, sg_nents_for_len(req->src, cryp->assoclen), +- rctx->adata, cryp->assoclen) != cryp->assoclen) ++ rctx->adata, cryp->assoclen) != cryp->assoclen) { ++ kfree(rctx->adata); + return -EINVAL; ++ } + } + + if (cryp->total_in) +@@ -685,8 +687,11 @@ static int starfive_aes_aead_do_one_req(struct crypto_engine *engine, void *areq + ctx->rctx = rctx; + + ret = starfive_aes_hw_init(ctx); +- if (ret) ++ if (ret) { ++ if (cryp->assoclen) ++ kfree(rctx->adata); + return ret; ++ } + + if (!cryp->assoclen) + goto write_text; +-- +2.51.0 + diff --git a/queue-6.12/cxl-fix-premature-commit_end-increment-on-decoder-co.patch b/queue-6.12/cxl-fix-premature-commit_end-increment-on-decoder-co.patch new file mode 100644 index 0000000000..9d2a5ae453 --- /dev/null +++ b/queue-6.12/cxl-fix-premature-commit_end-increment-on-decoder-co.patch @@ -0,0 +1,62 @@ +From b52669ccf2d19f6f14148a3e5b686ce863699a20 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 14:45:52 +0800 +Subject: cxl: Fix premature commit_end increment on decoder commit failure + +From: Yuxiong Wang + +[ Upstream commit 7b6f9d9b1ea05c9c22570126547c780e8c6c3f62 ] + +In cxl_decoder_commit(), commit_end is incremented before verifying +whether the commit succeeded, and the CXL_DECODER_F_ENABLE bit in +cxld->flags is only set after a successful commit. As a result, if the +commit fails, commit_end has been incremented and cxld->reset() has no +effect since the flag is not set, so commit_end remains incorrectly +incremented. The inconsistency between commit_end and CXL_DECODER_F_ENABLE +causes failure during subsequent either commit or reset operations. + +Fix this by incrementing commit_end only after confirming the commit +succeeded. Also, remove the ineffective cxld->reset() call. According to +CXL Spec r4.0 8.2.4.20.12 Committing Decoder Programming, since +cxld_await_commit() has cleared the decoder commit bit on failure, no +additional reset is required. + +[dj: Fixed commit log 80 char wrapping. ] +[dj: Fix "Fixes" tag to correct hash length. ] +[dj: Change spec to r4.0. ] + +Fixes: 176baefb2eb5 ("cxl/hdm: Commit decoder state to hardware") +Signed-off-by: Yuxiong Wang +Acked-by: Huang Ying +Reviewed-by: Dave Jiang +Reviewed-by: Alison Schofield +Link: https://patch.msgid.link/20260129064552.31180-1-yuxiong.wang@linux.alibaba.com +Signed-off-by: Dave Jiang +Signed-off-by: Sasha Levin +--- + drivers/cxl/core/hdm.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c +index 223c273c0cd17..fde609f37e562 100644 +--- a/drivers/cxl/core/hdm.c ++++ b/drivers/cxl/core/hdm.c +@@ -699,14 +699,13 @@ static int cxl_decoder_commit(struct cxl_decoder *cxld) + writel(ctrl, hdm + CXL_HDM_DECODER0_CTRL_OFFSET(id)); + up_read(&cxl_dpa_rwsem); + +- port->commit_end++; + rc = cxld_await_commit(hdm, cxld->id); + if (rc) { + dev_dbg(&port->dev, "%s: error %d committing decoder\n", + dev_name(&cxld->dev), rc); +- cxld->reset(cxld); + return rc; + } ++ port->commit_end++; + cxld->flags |= CXL_DECODER_F_ENABLE; + + return 0; +-- +2.51.0 + diff --git a/queue-6.12/dm-fix-unlocked-test-for-dm_suspended_md.patch b/queue-6.12/dm-fix-unlocked-test-for-dm_suspended_md.patch new file mode 100644 index 0000000000..64dac2eb51 --- /dev/null +++ b/queue-6.12/dm-fix-unlocked-test-for-dm_suspended_md.patch @@ -0,0 +1,56 @@ +From 118233bc70b09d31fafe8b6360999da3bd59553e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 20:55:08 +0100 +Subject: dm: fix unlocked test for dm_suspended_md + +From: Mikulas Patocka + +[ Upstream commit 24c405fdbe215c45e57bba672cc42859038491ee ] + +The function dm_blk_report_zones tests if the device is suspended with +the "dm_suspended_md" call. However, this function is called without +holding any locks, so the device may be suspended just after it. + +Move the call to dm_suspended_md after dm_get_live_table, so that the +device can't be suspended after the suspended state was tested. + +Signed-off-by: Mikulas Patocka +Fixes: 37f53a2c60d0 ("dm: fix dm_blk_report_zones") +Reviewed-by: Benjamin Marzinski +Signed-off-by: Sasha Levin +--- + drivers/md/dm-zone.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/drivers/md/dm-zone.c b/drivers/md/dm-zone.c +index 04cc36a9d5ca4..d7b1c89fcd87b 100644 +--- a/drivers/md/dm-zone.c ++++ b/drivers/md/dm-zone.c +@@ -66,11 +66,13 @@ int dm_blk_report_zones(struct gendisk *disk, sector_t sector, + * Zone revalidation during __bind() is in progress, but this + * call is from a different process + */ +- if (dm_suspended_md(md)) +- return -EAGAIN; +- + map = dm_get_live_table(md, &srcu_idx); + put_table = true; ++ ++ if (dm_suspended_md(md)) { ++ ret = -EAGAIN; ++ goto do_put_table; ++ } + } else { + /* Zone revalidation during __bind() */ + map = zone_revalidate_map; +@@ -80,6 +82,7 @@ int dm_blk_report_zones(struct gendisk *disk, sector_t sector, + ret = dm_blk_do_report_zones(md, map, sector, nr_zones, cb, + data); + ++do_put_table: + if (put_table) + dm_put_live_table(md, srcu_idx); + +-- +2.51.0 + diff --git a/queue-6.12/dm-use-bio_clone_blkg_association.patch b/queue-6.12/dm-use-bio_clone_blkg_association.patch new file mode 100644 index 0000000000..128c7d292b --- /dev/null +++ b/queue-6.12/dm-use-bio_clone_blkg_association.patch @@ -0,0 +1,44 @@ +From 49af9748efd7fdfa98ac6d07b04b8d49d5ba5bb4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 15:36:22 +0100 +Subject: dm: use bio_clone_blkg_association + +From: Mikulas Patocka + +[ Upstream commit 2df8b310bcfe76827fd71092f58a2493ee6590b0 ] + +The origin bio carries blk-cgroup information which could be set from +foreground(task_css(css) - wbc->wb->blkcg_css), so the blkcg won't +control buffer io since commit ca522482e3eaf ("dm: pass NULL bdev to +bio_alloc_clone"). The synchronous io is still under control by blkcg, +because 'bio->bi_blkg' is set by io submitting task which has been added +into 'cgroup.procs'. + +Fix it by using bio_clone_blkg_association when submitting a cloned bio. + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=220985 +Fixes: ca522482e3eaf ("dm: pass NULL bdev to bio_alloc_clone") +Reported-by: Zhihao Cheng +Signed-off-by: Mikulas Patocka +Tested-by: Zhihao Cheng +Signed-off-by: Sasha Levin +--- + drivers/md/dm.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/md/dm.c b/drivers/md/dm.c +index fd84a126f63fb..ec48fcdb19ed8 100644 +--- a/drivers/md/dm.c ++++ b/drivers/md/dm.c +@@ -1386,6 +1386,8 @@ void dm_submit_bio_remap(struct bio *clone, struct bio *tgt_clone) + if (!tgt_clone) + tgt_clone = clone; + ++ bio_clone_blkg_association(tgt_clone, io->orig_bio); ++ + /* + * Account io->origin_bio to DM dev on behalf of target + * that took ownership of IO with DM_MAPIO_SUBMITTED. +-- +2.51.0 + diff --git a/queue-6.12/dm-use-read_once-in-dm_blk_report_zones.patch b/queue-6.12/dm-use-read_once-in-dm_blk_report_zones.patch new file mode 100644 index 0000000000..76b815fee7 --- /dev/null +++ b/queue-6.12/dm-use-read_once-in-dm_blk_report_zones.patch @@ -0,0 +1,36 @@ +From c1a031fb8e1ed552a17d66282db3b6d28900981a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 20:56:20 +0100 +Subject: dm: use READ_ONCE in dm_blk_report_zones + +From: Mikulas Patocka + +[ Upstream commit e9f5a55b70ae6187ab64ef2d1232ae2738e31d1f ] + +The functon dm_blk_report_zones reads md->zone_revalidate_map, however it +may change while the function is running. Use READ_ONCE. + +Signed-off-by: Mikulas Patocka +Fixes: 37f53a2c60d0 ("dm: fix dm_blk_report_zones") +Reviewed-by: Benjamin Marzinski +Signed-off-by: Sasha Levin +--- + drivers/md/dm-zone.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/md/dm-zone.c b/drivers/md/dm-zone.c +index d7b1c89fcd87b..912b9fe1f5648 100644 +--- a/drivers/md/dm-zone.c ++++ b/drivers/md/dm-zone.c +@@ -56,7 +56,7 @@ int dm_blk_report_zones(struct gendisk *disk, sector_t sector, + { + struct mapped_device *md = disk->private_data; + struct dm_table *map; +- struct dm_table *zone_revalidate_map = md->zone_revalidate_map; ++ struct dm_table *zone_revalidate_map = READ_ONCE(md->zone_revalidate_map); + int srcu_idx, ret = -EIO; + bool put_table = false; + +-- +2.51.0 + diff --git a/queue-6.12/dma-dma-axi-dmac-fix-hw-scatter-gather-not-looking-a.patch b/queue-6.12/dma-dma-axi-dmac-fix-hw-scatter-gather-not-looking-a.patch new file mode 100644 index 0000000000..005a450834 --- /dev/null +++ b/queue-6.12/dma-dma-axi-dmac-fix-hw-scatter-gather-not-looking-a.patch @@ -0,0 +1,51 @@ +From 0611de2b5211fb24d076c2210468c8b699a41c68 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Nov 2025 16:22:26 +0000 +Subject: dma: dma-axi-dmac: fix HW scatter-gather not looking at the queue +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Nuno Sá + +[ Upstream commit bbcbafb99df41a1d81403eb4f5bb443b38228b57 ] + +For HW scatter gather transfers we still need to look for the queue. The +HW is capable of queueing 3 concurrent transfers and if we try more than +that we'll get the submit queue full and should return. Otherwise, if we +go ahead and program the new transfer, we end up discarding it. + +Fixes: e97dc7435972 ("dmaengine: axi-dmac: Add support for scatter-gather transfers") +Signed-off-by: Nuno Sá +base-commit: 398035178503bf662281bbffb4bebce1460a4bc5 +change-id: 20251104-axi-dmac-fixes-and-improvs-e3ad512a329c +Acked-by: Michael Hennerich +Link: https://patch.msgid.link/20251104-axi-dmac-fixes-and-improvs-v1-2-3e6fd9328f72@analog.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/dma/dma-axi-dmac.c | 8 +++----- + 1 file changed, 3 insertions(+), 5 deletions(-) + +diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c +index 2aa06f66624ba..47d95d2d743b1 100644 +--- a/drivers/dma/dma-axi-dmac.c ++++ b/drivers/dma/dma-axi-dmac.c +@@ -233,11 +233,9 @@ static void axi_dmac_start_transfer(struct axi_dmac_chan *chan) + unsigned int flags = 0; + unsigned int val; + +- if (!chan->hw_sg) { +- val = axi_dmac_read(dmac, AXI_DMAC_REG_START_TRANSFER); +- if (val) /* Queue is full, wait for the next SOT IRQ */ +- return; +- } ++ val = axi_dmac_read(dmac, AXI_DMAC_REG_START_TRANSFER); ++ if (val) /* Queue is full, wait for the next SOT IRQ */ ++ return; + + desc = chan->next_desc; + +-- +2.51.0 + diff --git a/queue-6.12/dma-dma-axi-dmac-fix-sw-cyclic-transfers.patch b/queue-6.12/dma-dma-axi-dmac-fix-sw-cyclic-transfers.patch new file mode 100644 index 0000000000..2fa87f0dd3 --- /dev/null +++ b/queue-6.12/dma-dma-axi-dmac-fix-sw-cyclic-transfers.patch @@ -0,0 +1,57 @@ +From ebeb30b72efb8387e2a1b1be0a3e15288d02b732 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Nov 2025 16:22:25 +0000 +Subject: dma: dma-axi-dmac: fix SW cyclic transfers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Nuno Sá + +[ Upstream commit 9bd257181fd5c996d922e9991500ad27987cfbf4 ] + +If 'hw_cyclic' is false we should still be able to do cyclic transfers in +"software". That was not working for the case where 'desc->num_sgs' is 1 +because 'chan->next_desc' is never set with the current desc which means +that the cyclic transfer only runs once and in the next SOT interrupt we +do nothing since vchan_next_desc() will return NULL. + +Fix it by setting 'chan->next_desc' as soon as we get a new desc via +vchan_next_desc(). + +Fixes: 0e3b67b348b8 ("dmaengine: Add support for the Analog Devices AXI-DMAC DMA controller") +Signed-off-by: Nuno Sá +base-commit: 398035178503bf662281bbffb4bebce1460a4bc5 +change-id: 20251104-axi-dmac-fixes-and-improvs-e3ad512a329c +Acked-by: Michael Hennerich +Link: https://patch.msgid.link/20251104-axi-dmac-fixes-and-improvs-v1-1-3e6fd9328f72@analog.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/dma/dma-axi-dmac.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c +index 36943b0c6d603..2aa06f66624ba 100644 +--- a/drivers/dma/dma-axi-dmac.c ++++ b/drivers/dma/dma-axi-dmac.c +@@ -247,6 +247,7 @@ static void axi_dmac_start_transfer(struct axi_dmac_chan *chan) + return; + list_move_tail(&vdesc->node, &chan->active_descs); + desc = to_axi_dmac_desc(vdesc); ++ chan->next_desc = desc; + } + sg = &desc->sg[desc->num_submitted]; + +@@ -265,8 +266,6 @@ static void axi_dmac_start_transfer(struct axi_dmac_chan *chan) + else + chan->next_desc = NULL; + flags |= AXI_DMAC_FLAG_LAST; +- } else { +- chan->next_desc = desc; + } + + sg->hw->id = axi_dmac_read(dmac, AXI_DMAC_REG_TRANSFER_ID); +-- +2.51.0 + diff --git a/queue-6.12/dmaengine-fsl-edma-don-t-explicitly-disable-clocks-i.patch b/queue-6.12/dmaengine-fsl-edma-don-t-explicitly-disable-clocks-i.patch new file mode 100644 index 0000000000..0a023f84eb --- /dev/null +++ b/queue-6.12/dmaengine-fsl-edma-don-t-explicitly-disable-clocks-i.patch @@ -0,0 +1,61 @@ +From 9c4d759429e8528ddec6b1bbc5ef8e13df6a2f73 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Jan 2026 11:46:50 -0800 +Subject: dmaengine: fsl-edma: don't explicitly disable clocks in .remove() + +From: Jared Kangas + +[ Upstream commit 666c53e94c1d0bf0bdf14c49505ece9ddbe725bc ] + +The clocks in fsl_edma_engine::muxclk are allocated and enabled with +devm_clk_get_enabled(), which automatically cleans these resources up, +but these clocks are also manually disabled in fsl_edma_remove(). This +causes warnings on driver removal for each clock: + + edma_module already disabled + WARNING: CPU: 0 PID: 418 at drivers/clk/clk.c:1200 clk_core_disable+0x198/0x1c8 + [...] + Call trace: + clk_core_disable+0x198/0x1c8 (P) + clk_disable+0x34/0x58 + fsl_edma_remove+0x74/0xe8 [fsl_edma] + [...] + ---[ end trace 0000000000000000 ]--- + edma_module already unprepared + WARNING: CPU: 0 PID: 418 at drivers/clk/clk.c:1059 clk_core_unprepare+0x1f8/0x220 + [...] + Call trace: + clk_core_unprepare+0x1f8/0x220 (P) + clk_unprepare+0x34/0x58 + fsl_edma_remove+0x7c/0xe8 [fsl_edma] + [...] + ---[ end trace 0000000000000000 ]--- + +Fix these warnings by removing the unnecessary fsl_disable_clocks() call +in fsl_edma_remove(). + +Fixes: a9903de3aa16 ("dmaengine: fsl-edma: refactor using devm_clk_get_enabled") +Signed-off-by: Jared Kangas +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260113-fsl-edma-clock-removal-v1-1-2025b49e7bcc@redhat.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/dma/fsl-edma-main.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/dma/fsl-edma-main.c b/drivers/dma/fsl-edma-main.c +index 4794d58dab556..540b47c520dce 100644 +--- a/drivers/dma/fsl-edma-main.c ++++ b/drivers/dma/fsl-edma-main.c +@@ -708,7 +708,6 @@ static void fsl_edma_remove(struct platform_device *pdev) + of_dma_controller_free(np); + dma_async_device_unregister(&fsl_edma->dma_dev); + fsl_edma_cleanup_vchan(&fsl_edma->dma_dev); +- fsl_disable_clocks(fsl_edma, fsl_edma->drvdata->dmamuxs); + } + + static int fsl_edma_suspend_late(struct device *dev) +-- +2.51.0 + diff --git a/queue-6.12/dmaengine-mediatek-uart-apdma-fix-above-4g-addressin.patch b/queue-6.12/dmaengine-mediatek-uart-apdma-fix-above-4g-addressin.patch new file mode 100644 index 0000000000..0831eb0ac9 --- /dev/null +++ b/queue-6.12/dmaengine-mediatek-uart-apdma-fix-above-4g-addressin.patch @@ -0,0 +1,83 @@ +From 95681f179709507c5c81f2a9408432bf8043df1e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 13 Nov 2025 13:22:26 +0100 +Subject: dmaengine: mediatek: uart-apdma: Fix above 4G addressing TX/RX + +From: AngeloGioacchino Del Regno + +[ Upstream commit 58ab9d7b6651d21e1cff1777529f2d3dd0b4e851 ] + +The VFF_4G_SUPPORT register is named differently in datasheets, +and its name is "VFF_ADDR2"; was this named correctly from the +beginning it would've been clearer that there was a mistake in +the programming sequence. + +This register is supposed to hold the high bits to support the +DMA addressing above 4G (so, more than 32 bits) and not a bit +to "enable" the support for VFF 4G. + +Fix the name of this register, and also fix its usage by writing +the upper 32 bits of the dma_addr_t on it when the SoC supports +such feature. + +Fixes: 9135408c3ace ("dmaengine: mediatek: Add MediaTek UART APDMA support") +Signed-off-by: AngeloGioacchino Del Regno +Link: https://patch.msgid.link/20251113122229.23998-6-angelogioacchino.delregno@collabora.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/dma/mediatek/mtk-uart-apdma.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/dma/mediatek/mtk-uart-apdma.c b/drivers/dma/mediatek/mtk-uart-apdma.c +index 1bdc1500be40f..3e7f8acf41dd0 100644 +--- a/drivers/dma/mediatek/mtk-uart-apdma.c ++++ b/drivers/dma/mediatek/mtk-uart-apdma.c +@@ -41,7 +41,7 @@ + #define VFF_STOP_CLR_B 0 + #define VFF_EN_CLR_B 0 + #define VFF_INT_EN_CLR_B 0 +-#define VFF_4G_SUPPORT_CLR_B 0 ++#define VFF_ADDR2_CLR_B 0 + + /* + * interrupt trigger level for tx +@@ -72,7 +72,7 @@ + /* TX: the buffer size SW can write. RX: the buffer size HW can write. */ + #define VFF_LEFT_SIZE 0x40 + #define VFF_DEBUG_STATUS 0x50 +-#define VFF_4G_SUPPORT 0x54 ++#define VFF_ADDR2 0x54 + + struct mtk_uart_apdmadev { + struct dma_device ddev; +@@ -149,7 +149,7 @@ static void mtk_uart_apdma_start_tx(struct mtk_chan *c) + mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_TX_INT_CLR_B); + + if (mtkd->support_33bits) +- mtk_uart_apdma_write(c, VFF_4G_SUPPORT, VFF_4G_EN_B); ++ mtk_uart_apdma_write(c, VFF_ADDR2, upper_32_bits(d->addr)); + } + + mtk_uart_apdma_write(c, VFF_EN, VFF_EN_B); +@@ -192,7 +192,7 @@ static void mtk_uart_apdma_start_rx(struct mtk_chan *c) + mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_RX_INT_CLR_B); + + if (mtkd->support_33bits) +- mtk_uart_apdma_write(c, VFF_4G_SUPPORT, VFF_4G_EN_B); ++ mtk_uart_apdma_write(c, VFF_ADDR2, upper_32_bits(d->addr)); + } + + mtk_uart_apdma_write(c, VFF_INT_EN, VFF_RX_INT_EN_B); +@@ -298,7 +298,7 @@ static int mtk_uart_apdma_alloc_chan_resources(struct dma_chan *chan) + } + + if (mtkd->support_33bits) +- mtk_uart_apdma_write(c, VFF_4G_SUPPORT, VFF_4G_SUPPORT_CLR_B); ++ mtk_uart_apdma_write(c, VFF_ADDR2, VFF_ADDR2_CLR_B); + + err_pm: + pm_runtime_put_noidle(mtkd->ddev.dev); +-- +2.51.0 + diff --git a/queue-6.12/docs-fix-warning-document-not-included-in-any-toctre.patch b/queue-6.12/docs-fix-warning-document-not-included-in-any-toctre.patch new file mode 100644 index 0000000000..41a522b7fd --- /dev/null +++ b/queue-6.12/docs-fix-warning-document-not-included-in-any-toctre.patch @@ -0,0 +1,36 @@ +From 5ae313174ba786572bf555e027ec3e9f04d4b518 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 3 Oct 2024 01:28:17 +0530 +Subject: docs: fix WARNING document not included in any toctree + +From: SurajSonawane2415 + +[ Upstream commit 998bece1d22bf2cbc819cb3a492148932d4e12a8 ] + +Add debugging.rst to the relevant toctree to fix warning +about missing documentation inclusion in toctree. + +Signed-off-by: SurajSonawane2415 +Signed-off-by: Jonathan Corbet +Link: https://lore.kernel.org/r/20241002195817.22972-1-surajsonawane0215@gmail.com +Stable-dep-of: 8236fc613d44 ("Documentation: tracing: Add PCI tracepoint documentation") +Signed-off-by: Sasha Levin +--- + Documentation/trace/index.rst | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/Documentation/trace/index.rst b/Documentation/trace/index.rst +index 0b300901fd750..2c991dc96ace6 100644 +--- a/Documentation/trace/index.rst ++++ b/Documentation/trace/index.rst +@@ -24,6 +24,7 @@ Linux Tracing Technologies + histogram + histogram-design + boottime-trace ++ debugging + hwlat_detector + osnoise-tracer + timerlat-tracer +-- +2.51.0 + diff --git a/queue-6.12/documentation-pci-endpoint-fix-ntb-vntb-copy-paste-e.patch b/queue-6.12/documentation-pci-endpoint-fix-ntb-vntb-copy-paste-e.patch new file mode 100644 index 0000000000..a06d4e909b --- /dev/null +++ b/queue-6.12/documentation-pci-endpoint-fix-ntb-vntb-copy-paste-e.patch @@ -0,0 +1,82 @@ +From 50877f041e76eea16aa761b98fc64166af8354cd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 3 Nov 2025 09:28:30 +0200 +Subject: Documentation: PCI: endpoint: Fix ntb/vntb copy & paste errors + +From: Baruch Siach + +[ Upstream commit ad0c6da5be901f5c181490f683d22b416059bccb ] + +Fix copy & paste errors by changing the references from 'ntb' to 'vntb'. + +Fixes: 4ac8c8e52cd9 ("Documentation: PCI: Add specification for the PCI vNTB function device") +Signed-off-by: Baruch Siach +[mani: squashed the patches and fixed more errors] +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Reviewed-by: Frank Li +Link: https://patch.msgid.link/b51c2a69ffdbfa2c359f5cf33f3ad2acc3db87e4.1762154911.git.baruch@tkos.co.il +Signed-off-by: Sasha Levin +--- + Documentation/PCI/endpoint/pci-vntb-howto.rst | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/Documentation/PCI/endpoint/pci-vntb-howto.rst b/Documentation/PCI/endpoint/pci-vntb-howto.rst +index 70d3bc90893f3..949c0d35694c2 100644 +--- a/Documentation/PCI/endpoint/pci-vntb-howto.rst ++++ b/Documentation/PCI/endpoint/pci-vntb-howto.rst +@@ -52,14 +52,14 @@ pci-epf-vntb device, the following commands can be used:: + # cd /sys/kernel/config/pci_ep/ + # mkdir functions/pci_epf_vntb/func1 + +-The "mkdir func1" above creates the pci-epf-ntb function device that will ++The "mkdir func1" above creates the pci-epf-vntb function device that will + be probed by pci_epf_vntb driver. + + The PCI endpoint framework populates the directory with the following + configurable fields:: + +- # ls functions/pci_epf_ntb/func1 +- baseclass_code deviceid msi_interrupts pci-epf-ntb.0 ++ # ls functions/pci_epf_vntb/func1 ++ baseclass_code deviceid msi_interrupts pci-epf-vntb.0 + progif_code secondary subsys_id vendorid + cache_line_size interrupt_pin msix_interrupts primary + revid subclass_code subsys_vendor_id +@@ -106,13 +106,13 @@ A sample configuration for virtual NTB driver for virtual PCI bus:: + # echo 0x080A > functions/pci_epf_vntb/func1/pci_epf_vntb.0/vntb_pid + # echo 0x10 > functions/pci_epf_vntb/func1/pci_epf_vntb.0/vbus_number + +-Binding pci-epf-ntb Device to EP Controller ++Binding pci-epf-vntb Device to EP Controller + -------------------------------------------- + + NTB function device should be attached to PCI endpoint controllers + connected to the host. + +- # ln -s controllers/5f010000.pcie_ep functions/pci-epf-ntb/func1/primary ++ # ln -s controllers/5f010000.pcie_ep functions/pci_epf_vntb/func1/primary + + Once the above step is completed, the PCI endpoint controllers are ready to + establish a link with the host. +@@ -134,7 +134,7 @@ lspci Output at Host side + ------------------------- + + Note that the devices listed here correspond to the values populated in +-"Creating pci-epf-ntb Device" section above:: ++"Creating pci-epf-vntb Device" section above:: + + # lspci + 00:00.0 PCI bridge: Freescale Semiconductor Inc Device 0000 (rev 01) +@@ -147,7 +147,7 @@ lspci Output at EP Side / Virtual PCI bus + ----------------------------------------- + + Note that the devices listed here correspond to the values populated in +-"Creating pci-epf-ntb Device" section above:: ++"Creating pci-epf-vntb Device" section above:: + + # lspci + 10:00.0 Unassigned class [ffff]: Dawicontrol Computersysteme GmbH Device 1234 (rev ff) +-- +2.51.0 + diff --git a/queue-6.12/documentation-trace-refactor-toctree.patch b/queue-6.12/documentation-trace-refactor-toctree.patch new file mode 100644 index 0000000000..31ba9ac35e --- /dev/null +++ b/queue-6.12/documentation-trace-refactor-toctree.patch @@ -0,0 +1,156 @@ +From c5a01b5bc65750f24477ad8b105585237cf6a569 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 16 Apr 2025 09:40:50 +0700 +Subject: Documentation: trace: Refactor toctree + +From: Purva Yeshi + +[ Upstream commit f0ba72e65516d1d86f40c79a49c4ba01c9555592 ] + +Refactor table of contents of kernel tracing subsystem docs to improve +clarity, structure, and organization: + +- Reformat sections and add appropriate headings +- Improve section grouping and refine descriptions for each group +- Add docs intro paragraph + +Signed-off-by: Purva Yeshi +Link: https://lore.kernel.org/r/20250318113230.24950-2-purvayeshi550@gmail.com +[Bagas: massage commit message and address reviews] +Co-developed-by: Bagas Sanjaya +Signed-off-by: Bagas Sanjaya +Acked-by: Steven Rostedt (Google) +Signed-off-by: Jonathan Corbet +Stable-dep-of: 8236fc613d44 ("Documentation: tracing: Add PCI tracepoint documentation") +Signed-off-by: Sasha Levin +--- + Documentation/trace/index.rst | 96 +++++++++++++++++++++++++++++------ + 1 file changed, 80 insertions(+), 16 deletions(-) + +diff --git a/Documentation/trace/index.rst b/Documentation/trace/index.rst +index 2c991dc96ace6..770d3bece22c3 100644 +--- a/Documentation/trace/index.rst ++++ b/Documentation/trace/index.rst +@@ -1,39 +1,103 @@ +-========================== +-Linux Tracing Technologies +-========================== ++================================ ++Linux Tracing Technologies Guide ++================================ ++ ++Tracing in the Linux kernel is a powerful mechanism that allows ++developers and system administrators to analyze and debug system ++behavior. This guide provides documentation on various tracing ++frameworks and tools available in the Linux kernel. ++ ++Introduction to Tracing ++----------------------- ++ ++This section provides an overview of Linux tracing mechanisms ++and debugging approaches. + + .. toctree:: + :maxdepth: 2 + +- ftrace-design ++ debugging ++ tracepoints + tracepoint-analysis ++ ring-buffer-map ++ ++Core Tracing Frameworks ++----------------------- ++ ++The following are the primary tracing frameworks integrated into ++the Linux kernel. ++ ++.. toctree:: ++ :maxdepth: 1 ++ + ftrace ++ ftrace-design + ftrace-uses +- fprobe + kprobes + kprobetrace +- uprobetracer + fprobetrace +- tracepoints ++ fprobe ++ ring-buffer-design ++ ++Event Tracing and Analysis ++-------------------------- ++ ++A detailed explanation of event tracing mechanisms and their ++applications. ++ ++.. toctree:: ++ :maxdepth: 1 ++ + events + events-kmem + events-power + events-nmi + events-msr +- mmiotrace ++ boottime-trace + histogram + histogram-design +- boottime-trace +- debugging +- hwlat_detector +- osnoise-tracer +- timerlat-tracer ++ ++Hardware and Performance Tracing ++-------------------------------- ++ ++This section covers tracing features that monitor hardware ++interactions and system performance. ++ ++.. toctree:: ++ :maxdepth: 1 ++ + intel_th +- ring-buffer-design +- ring-buffer-map + stm + sys-t + coresight/index +- user_events + rv/index + hisi-ptt ++ mmiotrace ++ hwlat_detector ++ osnoise-tracer ++ timerlat-tracer ++ ++User-Space Tracing ++------------------ ++ ++These tools allow tracing user-space applications and ++interactions. ++ ++.. toctree:: ++ :maxdepth: 1 ++ ++ user_events ++ uprobetracer ++ ++Additional Resources ++-------------------- ++ ++For more details, refer to the respective documentation of each ++tracing tool and framework. ++ ++.. only:: subproject and html ++ ++ Indices ++ ======= ++ ++ * :ref:`genindex` +-- +2.51.0 + diff --git a/queue-6.12/documentation-tracing-add-pci-tracepoint-documentati.patch b/queue-6.12/documentation-tracing-add-pci-tracepoint-documentati.patch new file mode 100644 index 0000000000..7fdcf9f6a0 --- /dev/null +++ b/queue-6.12/documentation-tracing-add-pci-tracepoint-documentati.patch @@ -0,0 +1,125 @@ +From 811be2d4500cba8aef94ab8447a97b8d5b22abed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 10 Dec 2025 21:29:07 +0800 +Subject: Documentation: tracing: Add PCI tracepoint documentation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Shuai Xue + +[ Upstream commit 8236fc613d44e59f6736d6c3e9efffaf26ab7f00 ] + +The PCI tracing system provides tracepoints to monitor critical hardware +events that can impact system performance and reliability. Add +documentation about it. + +Signed-off-by: Shuai Xue +[bhelgaas: squash fixes: +https://lore.kernel.org/r/20260108013956.14351-2-bagasdotme@gmail.com +https://lore.kernel.org/r/20260108013956.14351-3-bagasdotme@gmail.com] +Signed-off-by: Bjorn Helgaas +Reviewed-by: Ilpo Järvinen +Link: https://patch.msgid.link/20251210132907.58799-4-xueshuai@linux.alibaba.com +Signed-off-by: Sasha Levin +--- + Documentation/trace/events-pci.rst | 74 ++++++++++++++++++++++++++++++ + Documentation/trace/index.rst | 1 + + 2 files changed, 75 insertions(+) + create mode 100644 Documentation/trace/events-pci.rst + +diff --git a/Documentation/trace/events-pci.rst b/Documentation/trace/events-pci.rst +new file mode 100644 +index 0000000000000..03ff4ad30ddfa +--- /dev/null ++++ b/Documentation/trace/events-pci.rst +@@ -0,0 +1,74 @@ ++.. SPDX-License-Identifier: GPL-2.0 ++ ++=========================== ++Subsystem Trace Points: PCI ++=========================== ++ ++Overview ++======== ++The PCI tracing system provides tracepoints to monitor critical hardware events ++that can impact system performance and reliability. These events normally show ++up here: ++ ++ /sys/kernel/tracing/events/pci ++ ++Cf. include/trace/events/pci.h for the events definitions. ++ ++Available Tracepoints ++===================== ++ ++pci_hp_event ++------------ ++ ++Monitors PCI hotplug events including card insertion/removal and link ++state changes. ++:: ++ ++ pci_hp_event "%s slot:%s, event:%s\n" ++ ++**Event Types**: ++ ++* ``LINK_UP`` - PCIe link established ++* ``LINK_DOWN`` - PCIe link lost ++* ``CARD_PRESENT`` - Card detected in slot ++* ``CARD_NOT_PRESENT`` - Card removed from slot ++ ++**Example Usage**:: ++ ++ # Enable the tracepoint ++ echo 1 > /sys/kernel/debug/tracing/events/pci/pci_hp_event/enable ++ ++ # Monitor events (the following output is generated when a device is hotplugged) ++ cat /sys/kernel/debug/tracing/trace_pipe ++ irq/51-pciehp-88 [001] ..... 1311.177459: pci_hp_event: 0000:00:02.0 slot:10, event:CARD_PRESENT ++ ++ irq/51-pciehp-88 [001] ..... 1311.177566: pci_hp_event: 0000:00:02.0 slot:10, event:LINK_UP ++ ++pcie_link_event ++--------------- ++ ++Monitors PCIe link speed changes and provides detailed link status information. ++:: ++ ++ pcie_link_event "%s type:%d, reason:%d, cur_bus_speed:%d, max_bus_speed:%d, width:%u, flit_mode:%u, status:%s\n" ++ ++**Parameters**: ++ ++* ``type`` - PCIe device type (4=Root Port, etc.) ++* ``reason`` - Reason for link change: ++ ++ - ``0`` - Link retrain ++ - ``1`` - Bus enumeration ++ - ``2`` - Bandwidth notification enable ++ - ``3`` - Bandwidth notification IRQ ++ - ``4`` - Hotplug event ++ ++ ++**Example Usage**:: ++ ++ # Enable the tracepoint ++ echo 1 > /sys/kernel/debug/tracing/events/pci/pcie_link_event/enable ++ ++ # Monitor events (the following output is generated when a device is hotplugged) ++ cat /sys/kernel/debug/tracing/trace_pipe ++ irq/51-pciehp-88 [001] ..... 381.545386: pcie_link_event: 0000:00:02.0 type:4, reason:4, cur_bus_speed:20, max_bus_speed:23, width:1, flit_mode:0, status:DLLLA +diff --git a/Documentation/trace/index.rst b/Documentation/trace/index.rst +index 770d3bece22c3..e9bcb9d9f7f3b 100644 +--- a/Documentation/trace/index.rst ++++ b/Documentation/trace/index.rst +@@ -53,6 +53,7 @@ applications. + events-power + events-nmi + events-msr ++ events-pci + boottime-trace + histogram + histogram-design +-- +2.51.0 + diff --git a/queue-6.12/drbd-always-set-blk_feat_stable_writes.patch b/queue-6.12/drbd-always-set-blk_feat_stable_writes.patch new file mode 100644 index 0000000000..235c8fc70d --- /dev/null +++ b/queue-6.12/drbd-always-set-blk_feat_stable_writes.patch @@ -0,0 +1,94 @@ +From a6db666cc00ae8d80406da540c6d834a97a111b0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 18:39:29 +0100 +Subject: drbd: always set BLK_FEAT_STABLE_WRITES +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Christoph Böhmwalder + +[ Upstream commit 2ebc8d600fb907fa6b1e7095c0b6d84fc47e91ea ] + +DRBD requires stable pages because it may read the same bio data +multiple times for local disk I/O and network transmission, and in +some cases for calculating checksums. + +The BLK_FEAT_STABLE_WRITES flag is set when the device is first +created, but blk_set_stacking_limits() clears it whenever a +backing device is attached. In some cases the flag may be +inherited from the backing device, but we want it to be enabled +at all times. + +Unconditionally re-enable BLK_FEAT_STABLE_WRITES in +drbd_reconsider_queue_parameters() after the queue parameter +negotiations. + +Also, document why we want this flag enabled in the first place. + +Fixes: 1a02f3a73f8c ("block: move the stable_writes flag to queue_limits") +Signed-off-by: Christoph Böhmwalder +Reviewed-by: Christoph Hellwig +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/block/drbd/drbd_main.c | 3 --- + drivers/block/drbd/drbd_nl.c | 20 +++++++++++++++++++- + 2 files changed, 19 insertions(+), 4 deletions(-) + +diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c +index 5bbd312c3e14d..8c5a7bcfa82b2 100644 +--- a/drivers/block/drbd/drbd_main.c ++++ b/drivers/block/drbd/drbd_main.c +@@ -2683,9 +2683,6 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig + * connect. + */ + .max_hw_sectors = DRBD_MAX_BIO_SIZE_SAFE >> 8, +- .features = BLK_FEAT_WRITE_CACHE | BLK_FEAT_FUA | +- BLK_FEAT_ROTATIONAL | +- BLK_FEAT_STABLE_WRITES, + }; + + device = minor_to_device(minor); +diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c +index 720fc30e2ecc9..8c12bf1b2a0d2 100644 +--- a/drivers/block/drbd/drbd_nl.c ++++ b/drivers/block/drbd/drbd_nl.c +@@ -1296,6 +1296,8 @@ void drbd_reconsider_queue_parameters(struct drbd_device *device, + lim.max_segments = drbd_backing_dev_max_segments(device); + } else { + lim.max_segments = BLK_MAX_SEGMENTS; ++ lim.features = BLK_FEAT_WRITE_CACHE | BLK_FEAT_FUA | ++ BLK_FEAT_ROTATIONAL | BLK_FEAT_STABLE_WRITES; + } + + lim.max_hw_sectors = new >> SECTOR_SHIFT; +@@ -1318,8 +1320,24 @@ void drbd_reconsider_queue_parameters(struct drbd_device *device, + lim.max_hw_discard_sectors = 0; + } + +- if (bdev) ++ if (bdev) { + blk_stack_limits(&lim, &b->limits, 0); ++ /* ++ * blk_set_stacking_limits() cleared the features, and ++ * blk_stack_limits() may or may not have inherited ++ * BLK_FEAT_STABLE_WRITES from the backing device. ++ * ++ * DRBD always requires stable writes because: ++ * 1. The same bio data is read for both local disk I/O and ++ * network transmission. If the page changes mid-flight, ++ * the local and remote copies could diverge. ++ * 2. When data integrity is enabled, DRBD calculates a ++ * checksum before sending the data. If the page changes ++ * between checksum calculation and transmission, the ++ * receiver will detect a checksum mismatch. ++ */ ++ lim.features |= BLK_FEAT_STABLE_WRITES; ++ } + + /* + * If we can handle "zeroes" efficiently on the protocol, we want to do +-- +2.51.0 + diff --git a/queue-6.12/drivers-iio-mpu3050-use-dev_err_probe-for-regulator-.patch b/queue-6.12/drivers-iio-mpu3050-use-dev_err_probe-for-regulator-.patch new file mode 100644 index 0000000000..18adbb5aaa --- /dev/null +++ b/queue-6.12/drivers-iio-mpu3050-use-dev_err_probe-for-regulator-.patch @@ -0,0 +1,42 @@ +From e7cf64a257a175356534e5109dced7c0b5665911 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 17:34:25 +0200 +Subject: drivers: iio: mpu3050: use dev_err_probe for regulator request + +From: Svyatoslav Ryhel + +[ Upstream commit b010880b9936da14f8035585ab57577aa05be23a ] + +Regulator requesting may result in deferred probing error which will +abort driver probing. To avoid this just use dev_err_probe which handles +deferred probing. + +Fixes: 3904b28efb2c ("iio: gyro: Add driver for the MPU-3050 gyroscope") +Signed-off-by: Svyatoslav Ryhel +Reviewed-by: Andy Shevchenko +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/gyro/mpu3050-core.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/iio/gyro/mpu3050-core.c b/drivers/iio/gyro/mpu3050-core.c +index 35af68b41408f..4dcd0cc545518 100644 +--- a/drivers/iio/gyro/mpu3050-core.c ++++ b/drivers/iio/gyro/mpu3050-core.c +@@ -1165,10 +1165,8 @@ int mpu3050_common_probe(struct device *dev, + mpu3050->regs[1].supply = mpu3050_reg_vlogic; + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(mpu3050->regs), + mpu3050->regs); +- if (ret) { +- dev_err(dev, "Cannot get regulators\n"); +- return ret; +- } ++ if (ret) ++ return dev_err_probe(dev, ret, "Cannot get regulators\n"); + + ret = mpu3050_power_up(mpu3050); + if (ret) +-- +2.51.0 + diff --git a/queue-6.12/drm-amd-drop-amdgpu-kernel-modesetting-enabled-messa.patch b/queue-6.12/drm-amd-drop-amdgpu-kernel-modesetting-enabled-messa.patch new file mode 100644 index 0000000000..65a40e4305 --- /dev/null +++ b/queue-6.12/drm-amd-drop-amdgpu-kernel-modesetting-enabled-messa.patch @@ -0,0 +1,40 @@ +From 33c24a31372a1f77f96cbbe8fb7a1d62ac28306f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 14 Dec 2025 19:12:19 -0600 +Subject: drm/amd: Drop "amdgpu kernel modesetting enabled" message + +From: Mario Limonciello (AMD) + +[ Upstream commit 8644084a74a4573278d6f454c6638ccd5965f4e2 ] + +The behavior for amdgpu was changed with commit e00e5c223878 +("drm/amdgpu: adjust drm_firmware_drivers_only() handling") to +potentially allow loading even if nomodeset was set, so the +message is no longer accurate. + +Just drop it to avoid confusion. + +Fixes: e00e5c223878 ("drm/amdgpu: adjust drm_firmware_drivers_only() handling") +Signed-off-by: Mario Limonciello (AMD) +Reviewed-by: Aurabindo Pillai +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +index 48de2f088a3b9..bf706ee2e0ed3 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +@@ -3081,7 +3081,6 @@ static int __init amdgpu_init(void) + if (r) + goto error_fence; + +- DRM_INFO("amdgpu kernel modesetting enabled.\n"); + amdgpu_register_atpx_handler(); + amdgpu_acpi_detect(); + +-- +2.51.0 + diff --git a/queue-6.12/drm-amdgpu-use-explicit-vcn-instance-0-in-sr-iov-ini.patch b/queue-6.12/drm-amdgpu-use-explicit-vcn-instance-0-in-sr-iov-ini.patch new file mode 100644 index 0000000000..4e55684e61 --- /dev/null +++ b/queue-6.12/drm-amdgpu-use-explicit-vcn-instance-0-in-sr-iov-ini.patch @@ -0,0 +1,179 @@ +From a963abdaf871efe74f8c591baafef434ba3a9f70 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 15:25:25 +0530 +Subject: drm/amdgpu: Use explicit VCN instance 0 in SR-IOV init +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Srinivasan Shanmugam + +[ Upstream commit af26fa751c2eef66916acbf0d3c3e9159da56186 ] + +vcn_v2_0_start_sriov() declares a local variable "i" initialized to zero +and uses it only as the instance index in SOC15_REG_OFFSET(UVD, i, ...). +The value is never changed and all other fields are taken from +adev->vcn.inst[0], so this path only ever programs VCN instance 0. + +This triggered a Smatch: +warn: iterator 'i' not incremented + +Replace the dummy iterator with an explicit instance index of 0 in +SOC15_REG_OFFSET() calls. + +Fixes: dd26858a9cd8 ("drm/amdgpu: implement initialization part on VCN2.0 for SRIOV") +Reported by: Dan Carpenter +Cc: darlington Opara +Cc: Jinage Zhao +Cc: Monk Liu +Cc: Emily Deng +Cc: Christian König +Cc: Alex Deucher +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Emily Deng +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c | 45 ++++++++++++++------------- + 1 file changed, 23 insertions(+), 22 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c +index f085fdaafae00..9479bf9ea30fe 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c +@@ -1913,7 +1913,8 @@ static int vcn_v2_0_start_sriov(struct amdgpu_device *adev) + struct mmsch_v2_0_cmd_end end = { {0} }; + struct mmsch_v2_0_init_header *header; + uint32_t *init_table = adev->virt.mm_table.cpu_addr; +- uint8_t i = 0; ++ ++ /* This path only programs VCN instance 0. */ + + header = (struct mmsch_v2_0_init_header *)init_table; + direct_wt.cmd_header.command_type = MMSCH_COMMAND__DIRECT_REG_WRITE; +@@ -1932,93 +1933,93 @@ static int vcn_v2_0_start_sriov(struct amdgpu_device *adev) + size = AMDGPU_GPU_PAGE_ALIGN(adev->vcn.fw[0]->size + 4); + + MMSCH_V2_0_INSERT_DIRECT_RD_MOD_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_STATUS), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_STATUS), + 0xFFFFFFFF, 0x00000004); + + /* mc resume*/ + if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW), + adev->firmware.ucode[AMDGPU_UCODE_ID_VCN].tmr_mc_addr_lo); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE_64BIT_BAR_HIGH), + adev->firmware.ucode[AMDGPU_UCODE_ID_VCN].tmr_mc_addr_hi); + offset = 0; + } else { + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW), + lower_32_bits(adev->vcn.inst->gpu_addr)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE_64BIT_BAR_HIGH), + upper_32_bits(adev->vcn.inst->gpu_addr)); + offset = size; + } + + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_OFFSET0), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_OFFSET0), + 0); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_SIZE0), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_SIZE0), + size); + + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE1_64BIT_BAR_LOW), + lower_32_bits(adev->vcn.inst->gpu_addr + offset)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE1_64BIT_BAR_HIGH), + upper_32_bits(adev->vcn.inst->gpu_addr + offset)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_OFFSET1), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_OFFSET1), + 0); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_SIZE1), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_SIZE1), + AMDGPU_VCN_STACK_SIZE); + + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE2_64BIT_BAR_LOW), + lower_32_bits(adev->vcn.inst->gpu_addr + offset + + AMDGPU_VCN_STACK_SIZE)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE2_64BIT_BAR_HIGH), + upper_32_bits(adev->vcn.inst->gpu_addr + offset + + AMDGPU_VCN_STACK_SIZE)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_OFFSET2), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_OFFSET2), + 0); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_SIZE2), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_SIZE2), + AMDGPU_VCN_CONTEXT_SIZE); + + for (r = 0; r < adev->vcn.num_enc_rings; ++r) { + ring = &adev->vcn.inst->ring_enc[r]; + ring->wptr = 0; + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_RB_BASE_LO), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_RB_BASE_LO), + lower_32_bits(ring->gpu_addr)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_RB_BASE_HI), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_RB_BASE_HI), + upper_32_bits(ring->gpu_addr)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_RB_SIZE), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_RB_SIZE), + ring->ring_size / 4); + } + + ring = &adev->vcn.inst->ring_dec; + ring->wptr = 0; + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_RBC_RB_64BIT_BAR_LOW), + lower_32_bits(ring->gpu_addr)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH), + upper_32_bits(ring->gpu_addr)); + /* force RBC into idle state */ +@@ -2029,7 +2030,7 @@ static int vcn_v2_0_start_sriov(struct amdgpu_device *adev) + tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1); + tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_RBC_RB_CNTL), tmp); ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_RBC_RB_CNTL), tmp); + + /* add end packet */ + tmp = sizeof(struct mmsch_v2_0_cmd_end); +-- +2.51.0 + diff --git a/queue-6.12/drm-amdkfd-fix-signal_eviction_fence-bool-return-val.patch b/queue-6.12/drm-amdkfd-fix-signal_eviction_fence-bool-return-val.patch new file mode 100644 index 0000000000..171b6ee0ec --- /dev/null +++ b/queue-6.12/drm-amdkfd-fix-signal_eviction_fence-bool-return-val.patch @@ -0,0 +1,79 @@ +From 5157dcf0b440c6b4b8248581d2092df4910c73bb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 17 Dec 2025 15:21:57 +0530 +Subject: drm/amdkfd: Fix signal_eviction_fence() bool return value +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Srinivasan Shanmugam + +[ Upstream commit 31dc58adda9874420ab8fa5a2f9c43377745753a ] + +signal_eviction_fence() is declared to return bool, but returns -EINVAL +when no eviction fence is present. This makes the "no fence" or "the +NULL-fence" path evaluate to true and triggers a Smatch warning. + +v2: Return true instead to explicitly indicate that there is no eviction +fence to signal and that eviction is already complete. This matches the +existing caller logic where a NULL fence means "nothing to do" and +allows restore handling to proceed normally. (Christian) + +Fixes the below: +drivers/gpu/drm/amd/amdgpu/../amdkfd/kfd_process.c:2099 signal_eviction_fence() +warn: '(-22)' is not bool + +drivers/gpu/drm/amd/amdgpu/../amdkfd/kfd_process.c + 2090 static bool signal_eviction_fence(struct kfd_process *p) + ^^^^ + + 2091 { + 2092 struct dma_fence *ef; + 2093 bool ret; + 2094 + 2095 rcu_read_lock(); + 2096 ef = dma_fence_get_rcu_safe(&p->ef); + 2097 rcu_read_unlock(); + 2098 if (!ef) +--> 2099 return -EINVAL; + + This should be either true or false. + Probably true because presumably + it has been tested? + + 2100 + 2101 ret = dma_fence_check_and_signal(ef); + 2102 dma_fence_put(ef); + 2103 + 2104 return ret; + 2105 } + +Fixes: 37865e02e6cc ("drm/amdkfd: Fix eviction fence handling") +Reported by: Dan Carpenter +Cc: Philip Yang +Cc: Gang BA +Cc: Felix Kuehling +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Christian König +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdkfd/kfd_process.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c +index 45923da7709fd..64f3a0687f8a2 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c +@@ -1970,7 +1970,7 @@ static int signal_eviction_fence(struct kfd_process *p) + ef = dma_fence_get_rcu_safe(&p->ef); + rcu_read_unlock(); + if (!ef) +- return -EINVAL; ++ return true; + + ret = dma_fence_signal(ef); + dma_fence_put(ef); +-- +2.51.0 + diff --git a/queue-6.12/drm-buddy-release-free_trees-array-on-buddy-mm-teard.patch b/queue-6.12/drm-buddy-release-free_trees-array-on-buddy-mm-teard.patch new file mode 100644 index 0000000000..f8dc750c97 --- /dev/null +++ b/queue-6.12/drm-buddy-release-free_trees-array-on-buddy-mm-teard.patch @@ -0,0 +1,63 @@ +From 0d5911eef9ecdcaf22b72ffdd3a4736b7f22d196 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Dec 2025 11:27:14 +0100 +Subject: drm/buddy: release free_trees array on buddy mm teardown +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Michał Grzelak + +[ Upstream commit 7d0507772406e129329983b8b807e5b499bd74fd ] + +During initialization of DRM buddy memory manager at drm_buddy_init, +mm->free_trees array is allocated for both clear and dirty RB trees. +During cleanup happening at drm_buddy_fini it is never freed, leading to +following memory leaks observed on xe module load & unload cycles: + + kmemleak_alloc+0x4a/0x90 + __kmalloc_cache_noprof+0x488/0x800 + drm_buddy_init+0xc2/0x330 [drm_buddy] + __xe_ttm_vram_mgr_init+0xc3/0x190 [xe] + xe_ttm_stolen_mgr_init+0xf5/0x9d0 [xe] + xe_device_probe+0x326/0x9e0 [xe] + xe_pci_probe+0x39a/0x610 [xe] + local_pci_probe+0x47/0xb0 + pci_device_probe+0xf3/0x260 + really_probe+0xf1/0x3c0 + __driver_probe_device+0x8c/0x180 + driver_probe_device+0x24/0xd0 + __driver_attach+0x10f/0x220 + bus_for_each_dev+0x7f/0xe0 + driver_attach+0x1e/0x30 + bus_add_driver+0x151/0x290 + +Deallocate array for free trees when cleaning up buddy memory manager +in the same way as if going through out_free_tree label. + +Fixes: d4cd665c98c1 ("drm/buddy: Separate clear and dirty free block trees") +Signed-off-by: Michał Grzelak +Reviewed-by: Lucas De Marchi +Reviewed-by: Matthew Auld +Signed-off-by: Arunpravin Paneer Selvam +Link: https://patch.msgid.link/20251208102714.4008260-2-michal.grzelak@intel.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/drm_buddy.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/drm_buddy.c b/drivers/gpu/drm/drm_buddy.c +index 7debf079c943f..39a1d589df3a4 100644 +--- a/drivers/gpu/drm/drm_buddy.c ++++ b/drivers/gpu/drm/drm_buddy.c +@@ -414,6 +414,7 @@ void drm_buddy_fini(struct drm_buddy *mm) + + for_each_free_tree(i) + kfree(mm->free_trees[i]); ++ kfree(mm->free_trees); + kfree(mm->roots); + } + EXPORT_SYMBOL(drm_buddy_fini); +-- +2.51.0 + diff --git a/queue-6.12/drm-msm-a2xx-fix-pixel-shader-start-on-a225.patch b/queue-6.12/drm-msm-a2xx-fix-pixel-shader-start-on-a225.patch new file mode 100644 index 0000000000..a24f897508 --- /dev/null +++ b/queue-6.12/drm-msm-a2xx-fix-pixel-shader-start-on-a225.patch @@ -0,0 +1,42 @@ +From 6f4829ec541fe568a3c86b7d9adf0f4be98ee967 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 21 Nov 2025 18:13:03 +0200 +Subject: drm/msm/a2xx: fix pixel shader start on A225 + +From: Dmitry Baryshkov + +[ Upstream commit 6a7b0a670ba4d283285d76d45233cbecc5af5e40 ] + +A225 has a different PixelShader start address, write correct address +while initializing GPU. + +Fixes: 21af872cd8c6 ("drm/msm/adreno: add a2xx") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Patchwork: https://patchwork.freedesktop.org/patch/689906/ +Message-ID: <20251121-a225-v1-1-a1bab651d186@oss.qualcomm.com> +Signed-off-by: Rob Clark +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/adreno/a2xx_gpu.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/msm/adreno/a2xx_gpu.c b/drivers/gpu/drm/msm/adreno/a2xx_gpu.c +index 2e25af3462ab6..a0ca41f4818a3 100644 +--- a/drivers/gpu/drm/msm/adreno/a2xx_gpu.c ++++ b/drivers/gpu/drm/msm/adreno/a2xx_gpu.c +@@ -77,7 +77,10 @@ static bool a2xx_me_init(struct msm_gpu *gpu) + + /* Vertex and Pixel Shader Start Addresses in instructions + * (3 DWORDS per instruction) */ +- OUT_RING(ring, 0x80000180); ++ if (adreno_is_a225(adreno_gpu)) ++ OUT_RING(ring, 0x80000300); ++ else ++ OUT_RING(ring, 0x80000180); + /* Maximum Contexts */ + OUT_RING(ring, 0x00000001); + /* Write Confirm Interval and The CP will wait the +-- +2.51.0 + diff --git a/queue-6.12/drm-msm-disp-dpu-add-merge3d-support-for-sc7280.patch b/queue-6.12/drm-msm-disp-dpu-add-merge3d-support-for-sc7280.patch new file mode 100644 index 0000000000..c9bdddbf22 --- /dev/null +++ b/queue-6.12/drm-msm-disp-dpu-add-merge3d-support-for-sc7280.patch @@ -0,0 +1,84 @@ +From 652cc5063f19c8e3a21d6bdf43eceec7e12ebba2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 1 Jan 2026 10:34:38 +0530 +Subject: drm/msm/disp/dpu: add merge3d support for sc7280 + +From: Mahadevan P + +[ Upstream commit 2892de3f4f985fa779c330468e2f341fdb762ccd ] + +On SC7280 targets, display modes with a width greater than the +max_mixer_width (2400) are rejected during mode validation when +merge3d is disabled. This limitation exists because, without a +3D merge block, two layer mixers cannot be combined(non-DSC interface), +preventing large layers from being split across mixers. As a result, +higher resolution modes cannot be supported. + +Enable merge3d support on SC7280 to allow combining streams from +two layer mixers into a single non-DSC interface. This capability +removes the width restriction and enables buffer sizes beyond the +2400-pixel limit. + +Fixes: 591e34a091d1 ("drm/msm/disp/dpu1: add support for display for SC7280 target") +Signed-off-by: Mahadevan P +Reviewed-by: Dmitry Baryshkov +Patchwork: https://patchwork.freedesktop.org/patch/696713/ +Link: https://lore.kernel.org/r/20260101-4k-v2-1-712ae3c1f816@oss.qualcomm.com +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + .../gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h +index 2f153e0b5c6a9..d53ab3d886262 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h +@@ -13,6 +13,7 @@ static const struct dpu_caps sc7280_dpu_caps = { + .has_dim_layer = true, + .has_idle_pc = true, + .max_linewidth = 2400, ++ .has_3d_merge = true, + .pixel_ram_size = DEFAULT_PIXEL_RAM_SIZE, + }; + +@@ -142,18 +143,25 @@ static const struct dpu_pingpong_cfg sc7280_pp[] = { + .base = 0x6b000, .len = 0, + .features = BIT(DPU_PINGPONG_DITHER), + .sblk = &sc7280_pp_sblk, +- .merge_3d = 0, ++ .merge_3d = MERGE_3D_1, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 10), + }, { + .name = "pingpong_3", .id = PINGPONG_3, + .base = 0x6c000, .len = 0, + .features = BIT(DPU_PINGPONG_DITHER), + .sblk = &sc7280_pp_sblk, +- .merge_3d = 0, ++ .merge_3d = MERGE_3D_1, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 11), + }, + }; + ++static const struct dpu_merge_3d_cfg sc7280_merge_3d[] = { ++ { ++ .name = "merge_3d_1", .id = MERGE_3D_1, ++ .base = 0x4f000, .len = 0x8, ++ }, ++}; ++ + /* NOTE: sc7280 only has one DSC hard slice encoder */ + static const struct dpu_dsc_cfg sc7280_dsc[] = { + { +@@ -259,6 +267,8 @@ const struct dpu_mdss_cfg dpu_sc7280_cfg = { + .mixer = sc7280_lm, + .pingpong_count = ARRAY_SIZE(sc7280_pp), + .pingpong = sc7280_pp, ++ .merge_3d_count = ARRAY_SIZE(sc7280_merge_3d), ++ .merge_3d = sc7280_merge_3d, + .dsc_count = ARRAY_SIZE(sc7280_dsc), + .dsc = sc7280_dsc, + .wb_count = ARRAY_SIZE(sc7280_wb), +-- +2.51.0 + diff --git a/queue-6.12/drm-msm-disp-set-num_planes-to-1-for-interleaved-yuv.patch b/queue-6.12/drm-msm-disp-set-num_planes-to-1-for-interleaved-yuv.patch new file mode 100644 index 0000000000..28e7e7c767 --- /dev/null +++ b/queue-6.12/drm-msm-disp-set-num_planes-to-1-for-interleaved-yuv.patch @@ -0,0 +1,61 @@ +From 680bbb567b05b8446be0bd9895b3e10ece52d3bd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 Nov 2025 05:43:28 +0200 +Subject: drm/msm/disp: set num_planes to 1 for interleaved YUV formats + +From: Dmitry Baryshkov + +[ Upstream commit 6421e1c5075b7e1536a8fcbe6b4086db07103048 ] + +Interleaved YUV formats use only one plane for all pixel data. Specify +num_planes = 1 for those formats. This was left unnoticed since +_dpu_format_populate_plane_sizes_linear() overrides layout->num_planes. + +Fixes: 25fdd5933e4c ("drm/msm: Add SDM845 DPU support") +Reviewed-by: Jessica Zhang +Patchwork: https://patchwork.freedesktop.org/patch/688162/ +Link: https://lore.kernel.org/r/20251114-dpu-formats-v3-1-cae312379d49@oss.qualcomm.com +Tested-by: Luca Weiss # qcm6490-fairphone-fp5 +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/disp/mdp_format.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/msm/disp/mdp_format.c b/drivers/gpu/drm/msm/disp/mdp_format.c +index 426782d50cb49..eebedb1a2636e 100644 +--- a/drivers/gpu/drm/msm/disp/mdp_format.c ++++ b/drivers/gpu/drm/msm/disp/mdp_format.c +@@ -479,25 +479,25 @@ static const struct msm_format mdp_formats[] = { + 0, BPC8, BPC8, BPC8, + C2_R_Cr, C0_G_Y, C1_B_Cb, C0_G_Y, + false, CHROMA_H2V1, 4, 2, MSM_FORMAT_FLAG_YUV, +- MDP_FETCH_LINEAR, 2), ++ MDP_FETCH_LINEAR, 1), + + INTERLEAVED_YUV_FMT(UYVY, + 0, BPC8, BPC8, BPC8, + C1_B_Cb, C0_G_Y, C2_R_Cr, C0_G_Y, + false, CHROMA_H2V1, 4, 2, MSM_FORMAT_FLAG_YUV, +- MDP_FETCH_LINEAR, 2), ++ MDP_FETCH_LINEAR, 1), + + INTERLEAVED_YUV_FMT(YUYV, + 0, BPC8, BPC8, BPC8, + C0_G_Y, C1_B_Cb, C0_G_Y, C2_R_Cr, + false, CHROMA_H2V1, 4, 2, MSM_FORMAT_FLAG_YUV, +- MDP_FETCH_LINEAR, 2), ++ MDP_FETCH_LINEAR, 1), + + INTERLEAVED_YUV_FMT(YVYU, + 0, BPC8, BPC8, BPC8, + C0_G_Y, C2_R_Cr, C0_G_Y, C1_B_Cb, + false, CHROMA_H2V1, 4, 2, MSM_FORMAT_FLAG_YUV, +- MDP_FETCH_LINEAR, 2), ++ MDP_FETCH_LINEAR, 1), + + /* 3 plane YUV */ + PLANAR_YUV_FMT(YUV420, +-- +2.51.0 + diff --git a/queue-6.12/drm-msm-dpu-fix-cmd-panels-on-dpu-1.x-3.x.patch b/queue-6.12/drm-msm-dpu-fix-cmd-panels-on-dpu-1.x-3.x.patch new file mode 100644 index 0000000000..b0a3c94545 --- /dev/null +++ b/queue-6.12/drm-msm-dpu-fix-cmd-panels-on-dpu-1.x-3.x.patch @@ -0,0 +1,48 @@ +From dbf0f47b41b89fef4c0ebb527bd324ccf380d358 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 28 Dec 2025 06:02:28 +0200 +Subject: drm/msm/dpu: fix CMD panels on DPU 1.x - 3.x + +From: Dmitry Baryshkov + +[ Upstream commit 59ca3d11f5311d9167015fe4f431701614ae0048 ] + +DPU units before 4.x don't have a separate CTL_START IRQ to mark the +begin of the data transfer. In such a case, wait for the frame transfer +to complete rather than trying to wait for the CTL_START interrupt (and +obviously hitting the timeout). + +Fixes: 050770cbbd26 ("drm/msm/dpu: Fix timeout issues on command mode panels") +Reported-by: Alexey Minnekhanov +Closes: https://lore.kernel.org/r/8e1d33ff-d902-4ae9-9162-e00d17a5e6d1@postmarketos.org +Patchwork: https://patchwork.freedesktop.org/patch/696490/ +Link: https://lore.kernel.org/r/20251228-mdp5-drop-dpu3-v4-2-7497c3d39179@oss.qualcomm.com +Tested-by: Alexey Minnekhanov +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c +index 6fc31d47cd1dc..65dad86edb46e 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c +@@ -677,10 +677,11 @@ static int dpu_encoder_phys_cmd_wait_for_commit_done( + if (!dpu_encoder_phys_cmd_is_master(phys_enc)) + return 0; + +- if (phys_enc->hw_ctl->ops.is_started(phys_enc->hw_ctl)) +- return dpu_encoder_phys_cmd_wait_for_tx_complete(phys_enc); ++ if (phys_enc->irq[INTR_IDX_CTL_START] && ++ !phys_enc->hw_ctl->ops.is_started(phys_enc->hw_ctl)) ++ return _dpu_encoder_phys_cmd_wait_for_ctl_start(phys_enc); + +- return _dpu_encoder_phys_cmd_wait_for_ctl_start(phys_enc); ++ return dpu_encoder_phys_cmd_wait_for_tx_complete(phys_enc); + } + + static void dpu_encoder_phys_cmd_handle_post_kickoff( +-- +2.51.0 + diff --git a/queue-6.12/drm-msm-dpu-fix-wd-timer-handling-on-dpu-8.x.patch b/queue-6.12/drm-msm-dpu-fix-wd-timer-handling-on-dpu-8.x.patch new file mode 100644 index 0000000000..e6b9303840 --- /dev/null +++ b/queue-6.12/drm-msm-dpu-fix-wd-timer-handling-on-dpu-8.x.patch @@ -0,0 +1,198 @@ +From e5b77474e9eda52ed5cfbdeff1f0e4592e5a0643 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Dec 2025 09:17:57 +0200 +Subject: drm/msm/dpu: fix WD timer handling on DPU 8.x + +From: Dmitry Baryshkov + +[ Upstream commit 794b0e68caba49b950b42ec32e364028c2facf57 ] + +Since DPU 8.x Watchdog timer settings were moved from the TOP to the +INTF block. Support programming the timer in the INTF block. Fixes tag +points to the commit which removed register access to those registers on +DPU 8.x+ (and which also should have added proper support for WD timer +on those devices). + +Fixes: 43e3293fc614 ("drm/msm/dpu: add support for MDP_TOP blackhole") +Reviewed-by: Marijn Suijten +Signed-off-by: Dmitry Baryshkov +Patchwork: https://patchwork.freedesktop.org/patch/696586/ +Link: https://lore.kernel.org/r/20251230-intf-fix-wd-v6-2-98203d150611@oss.qualcomm.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 4 +- + drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c | 49 +++++++++++++++++++-- + drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h | 3 +- + drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c | 7 --- + drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h | 7 +++ + 5 files changed, 57 insertions(+), 13 deletions(-) + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +index 19c84426e6693..170d60bb7602d 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +@@ -769,13 +769,13 @@ static void _dpu_encoder_update_vsync_source(struct dpu_encoder_virt *dpu_enc, + } + + vsync_cfg.vsync_source = disp_info->vsync_source; ++ vsync_cfg.frame_rate = drm_mode_vrefresh(&dpu_enc->base.crtc->state->adjusted_mode); + + if (hw_mdptop->ops.setup_vsync_source) { + for (i = 0; i < dpu_enc->num_phys_encs; i++) + vsync_cfg.ppnumber[i] = dpu_enc->hw_pp[i]->idx; + + vsync_cfg.pp_count = dpu_enc->num_phys_encs; +- vsync_cfg.frame_rate = drm_mode_vrefresh(&dpu_enc->base.crtc->state->adjusted_mode); + + hw_mdptop->ops.setup_vsync_source(hw_mdptop, &vsync_cfg); + } +@@ -785,7 +785,7 @@ static void _dpu_encoder_update_vsync_source(struct dpu_encoder_virt *dpu_enc, + + if (phys_enc->has_intf_te && phys_enc->hw_intf->ops.vsync_sel) + phys_enc->hw_intf->ops.vsync_sel(phys_enc->hw_intf, +- vsync_cfg.vsync_source); ++ &vsync_cfg); + } + } + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c +index 29cb854f831a3..17c0f40385f1e 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c +@@ -67,6 +67,10 @@ + #define INTF_MISR_CTRL 0x180 + #define INTF_MISR_SIGNATURE 0x184 + ++#define INTF_WD_TIMER_0_CTL 0x230 ++#define INTF_WD_TIMER_0_CTL2 0x234 ++#define INTF_WD_TIMER_0_LOAD_VALUE 0x238 ++ + #define INTF_MUX 0x25C + #define INTF_STATUS 0x26C + #define INTF_AVR_CONTROL 0x270 +@@ -477,7 +481,20 @@ static int dpu_hw_intf_get_vsync_info(struct dpu_hw_intf *intf, + } + + static void dpu_hw_intf_vsync_sel(struct dpu_hw_intf *intf, +- enum dpu_vsync_source vsync_source) ++ struct dpu_vsync_source_cfg *cfg) ++{ ++ struct dpu_hw_blk_reg_map *c; ++ ++ if (!intf) ++ return; ++ ++ c = &intf->hw; ++ ++ DPU_REG_WRITE(c, INTF_TEAR_MDP_VSYNC_SEL, (cfg->vsync_source & 0xf)); ++} ++ ++static void dpu_hw_intf_vsync_sel_v8(struct dpu_hw_intf *intf, ++ struct dpu_vsync_source_cfg *cfg) + { + struct dpu_hw_blk_reg_map *c; + +@@ -486,7 +503,30 @@ static void dpu_hw_intf_vsync_sel(struct dpu_hw_intf *intf, + + c = &intf->hw; + +- DPU_REG_WRITE(c, INTF_TEAR_MDP_VSYNC_SEL, (vsync_source & 0xf)); ++ if (cfg->vsync_source >= DPU_VSYNC_SOURCE_WD_TIMER_4 && ++ cfg->vsync_source <= DPU_VSYNC_SOURCE_WD_TIMER_1) { ++ pr_warn_once("DPU 8.x supports only GPIOs and timer0 as TE sources\n"); ++ return; ++ } ++ ++ if (cfg->vsync_source == DPU_VSYNC_SOURCE_WD_TIMER_0) { ++ u32 reg; ++ ++ DPU_REG_WRITE(c, INTF_WD_TIMER_0_LOAD_VALUE, ++ CALCULATE_WD_LOAD_VALUE(cfg->frame_rate)); ++ ++ DPU_REG_WRITE(c, INTF_WD_TIMER_0_CTL, BIT(0)); /* clear timer */ ++ ++ reg = BIT(8); /* enable heartbeat timer */ ++ reg |= BIT(0); /* enable WD timer */ ++ reg |= BIT(1); /* select default 16 clock ticks */ ++ DPU_REG_WRITE(c, INTF_WD_TIMER_0_CTL2, reg); ++ ++ /* make sure that timers are enabled/disabled for vsync state */ ++ wmb(); ++ } ++ ++ dpu_hw_intf_vsync_sel(intf, cfg); + } + + static void dpu_hw_intf_disable_autorefresh(struct dpu_hw_intf *intf, +@@ -590,7 +630,10 @@ struct dpu_hw_intf *dpu_hw_intf_init(struct drm_device *dev, + c->ops.enable_tearcheck = dpu_hw_intf_enable_te; + c->ops.disable_tearcheck = dpu_hw_intf_disable_te; + c->ops.connect_external_te = dpu_hw_intf_connect_external_te; +- c->ops.vsync_sel = dpu_hw_intf_vsync_sel; ++ if (mdss_rev->core_major_ver >= 8) ++ c->ops.vsync_sel = dpu_hw_intf_vsync_sel_v8; ++ else ++ c->ops.vsync_sel = dpu_hw_intf_vsync_sel; + c->ops.disable_autorefresh = dpu_hw_intf_disable_autorefresh; + } + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h +index fc23650dfbf05..4039f11068764 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h +@@ -12,6 +12,7 @@ + #include "dpu_hw_util.h" + + struct dpu_hw_intf; ++struct dpu_vsync_source_cfg; + + /* intf timing settings */ + struct dpu_hw_intf_timing_params { +@@ -108,7 +109,7 @@ struct dpu_hw_intf_ops { + + int (*connect_external_te)(struct dpu_hw_intf *intf, bool enable_external_te); + +- void (*vsync_sel)(struct dpu_hw_intf *intf, enum dpu_vsync_source vsync_source); ++ void (*vsync_sel)(struct dpu_hw_intf *intf, struct dpu_vsync_source_cfg *cfg); + + /** + * Disable autorefresh if enabled +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c +index 2040bee8d512f..2c312439cf184 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c +@@ -22,13 +22,6 @@ + #define TRAFFIC_SHAPER_WR_CLIENT(num) (0x060 + (num * 4)) + #define TRAFFIC_SHAPER_FIXPOINT_FACTOR 4 + +-#define MDP_TICK_COUNT 16 +-#define XO_CLK_RATE 19200 +-#define MS_TICKS_IN_SEC 1000 +- +-#define CALCULATE_WD_LOAD_VALUE(fps) \ +- ((uint32_t)((MS_TICKS_IN_SEC * XO_CLK_RATE)/(MDP_TICK_COUNT * fps))) +- + static void dpu_hw_setup_split_pipe(struct dpu_hw_mdp *mdp, + struct split_pipe_cfg *cfg) + { +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h +index 67b08e99335dc..6fe65bc3bff4e 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h +@@ -21,6 +21,13 @@ + + #define TO_S15D16(_x_)((_x_) << 7) + ++#define MDP_TICK_COUNT 16 ++#define XO_CLK_RATE 19200 ++#define MS_TICKS_IN_SEC 1000 ++ ++#define CALCULATE_WD_LOAD_VALUE(fps) \ ++ ((uint32_t)((MS_TICKS_IN_SEC * XO_CLK_RATE)/(MDP_TICK_COUNT * fps))) ++ + extern const struct dpu_csc_cfg dpu_csc_YUV2RGB_601L; + extern const struct dpu_csc_cfg dpu_csc10_YUV2RGB_601L; + extern const struct dpu_csc_cfg dpu_csc10_rgb2yuv_601l; +-- +2.51.0 + diff --git a/queue-6.12/drm-msm-dpu-set-vsync-source-irrespective-of-mdp-top.patch b/queue-6.12/drm-msm-dpu-set-vsync-source-irrespective-of-mdp-top.patch new file mode 100644 index 0000000000..9afbd4b9ae --- /dev/null +++ b/queue-6.12/drm-msm-dpu-set-vsync-source-irrespective-of-mdp-top.patch @@ -0,0 +1,68 @@ +From c4c9ea562e91439b0077062267831cfd35dd8b37 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Dec 2025 09:17:56 +0200 +Subject: drm/msm/dpu: Set vsync source irrespective of mdp top support + +From: Teguh Sobirin + +[ Upstream commit 1ad9880f059c9b0943e53714f9a59924cb035bbb ] + +Since DPU 5.x the vsync source TE setup is split between MDP TOP and +INTF blocks. Currently all code to setup vsync_source is only executed +if MDP TOP implements the setup_vsync_source() callback. However on +DPU >= 8.x this callback is not implemented, making DPU driver skip all +vsync setup. Move the INTF part out of this condition, letting DPU +driver to setup TE vsync selection on all new DPU devices. + +Signed-off-by: Teguh Sobirin +Fixes: 2f69e5458447 ("drm/msm/dpu: skip watchdog timer programming through TOP on >= SM8450") +[DB: restored top->ops.setup_vsync_source call] +Reviewed-by: Marijn Suijten +Signed-off-by: Dmitry Baryshkov +Patchwork: https://patchwork.freedesktop.org/patch/696584/ +Link: https://lore.kernel.org/r/20251230-intf-fix-wd-v6-1-98203d150611@oss.qualcomm.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +index 47b514c89ce66..19c84426e6693 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +@@ -768,6 +768,8 @@ static void _dpu_encoder_update_vsync_source(struct dpu_encoder_virt *dpu_enc, + return; + } + ++ vsync_cfg.vsync_source = disp_info->vsync_source; ++ + if (hw_mdptop->ops.setup_vsync_source) { + for (i = 0; i < dpu_enc->num_phys_encs; i++) + vsync_cfg.ppnumber[i] = dpu_enc->hw_pp[i]->idx; +@@ -775,17 +777,15 @@ static void _dpu_encoder_update_vsync_source(struct dpu_encoder_virt *dpu_enc, + vsync_cfg.pp_count = dpu_enc->num_phys_encs; + vsync_cfg.frame_rate = drm_mode_vrefresh(&dpu_enc->base.crtc->state->adjusted_mode); + +- vsync_cfg.vsync_source = disp_info->vsync_source; +- + hw_mdptop->ops.setup_vsync_source(hw_mdptop, &vsync_cfg); ++ } + +- for (i = 0; i < dpu_enc->num_phys_encs; i++) { +- phys_enc = dpu_enc->phys_encs[i]; ++ for (i = 0; i < dpu_enc->num_phys_encs; i++) { ++ phys_enc = dpu_enc->phys_encs[i]; + +- if (phys_enc->has_intf_te && phys_enc->hw_intf->ops.vsync_sel) +- phys_enc->hw_intf->ops.vsync_sel(phys_enc->hw_intf, +- vsync_cfg.vsync_source); +- } ++ if (phys_enc->has_intf_te && phys_enc->hw_intf->ops.vsync_sel) ++ phys_enc->hw_intf->ops.vsync_sel(phys_enc->hw_intf, ++ vsync_cfg.vsync_source); + } + } + +-- +2.51.0 + diff --git a/queue-6.12/drm-panel-sw43408-remove-manual-invocation-of-unprep.patch b/queue-6.12/drm-panel-sw43408-remove-manual-invocation-of-unprep.patch new file mode 100644 index 0000000000..435e47f9f1 --- /dev/null +++ b/queue-6.12/drm-panel-sw43408-remove-manual-invocation-of-unprep.patch @@ -0,0 +1,40 @@ +From ba0e132602c8e48473eb3af9df5ce03c81669235 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 14 Dec 2025 15:51:21 +0100 +Subject: drm/panel: sw43408: Remove manual invocation of unprepare at remove + +From: David Heidelberg + +[ Upstream commit cbc1e99a9e0a6c8b22ddcbb40ca37457066f9493 ] + +The drm_panel_remove should take care of disable/unprepare. Remove the +manual call from the sw43408_remove function. + +Fixes: 069a6c0e94f9 ("drm: panel: Add LG sw43408 panel driver") +Reviewed-by: Dmitry Baryshkov +Signed-off-by: David Heidelberg +Signed-off-by: Neil Armstrong +Link: https://patch.msgid.link/20251214-pixel-3-v7-5-b1c0cf6f224d@ixit.cz +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panel/panel-lg-sw43408.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/drivers/gpu/drm/panel/panel-lg-sw43408.c b/drivers/gpu/drm/panel/panel-lg-sw43408.c +index f3dcc39670eae..8109ded2fe563 100644 +--- a/drivers/gpu/drm/panel/panel-lg-sw43408.c ++++ b/drivers/gpu/drm/panel/panel-lg-sw43408.c +@@ -294,10 +294,6 @@ static void sw43408_remove(struct mipi_dsi_device *dsi) + struct sw43408_panel *ctx = mipi_dsi_get_drvdata(dsi); + int ret; + +- ret = sw43408_unprepare(&ctx->base); +- if (ret < 0) +- dev_err(&dsi->dev, "failed to unprepare panel: %d\n", ret); +- + ret = mipi_dsi_detach(dsi); + if (ret < 0) + dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret); +-- +2.51.0 + diff --git a/queue-6.12/drm-panthor-evict-groups-before-vm-termination.patch b/queue-6.12/drm-panthor-evict-groups-before-vm-termination.patch new file mode 100644 index 0000000000..64acd4a4b5 --- /dev/null +++ b/queue-6.12/drm-panthor-evict-groups-before-vm-termination.patch @@ -0,0 +1,90 @@ +From 4535a375497e28734ff372bdb5c6617ae649d10a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 19 Dec 2025 10:35:44 +0100 +Subject: drm/panthor: Evict groups before VM termination + +From: Ketil Johnsen + +[ Upstream commit 565ed40b5fc1242f7538a016fce5a85f802d4fb5 ] + +Ensure all related groups are evicted and suspended before VM +destruction takes place. + +This fixes an issue where panthor_vm_destroy() destroys and unmaps the +heap context while there are still on slot groups using this. +The FW will do a write out to the heap context when a CSG (group) is +suspended, so a premature unmap of the heap context will cause a +GPU page fault. +This page fault is quite harmless, and do not affect the continued +operation of the GPU. + +Fixes: 647810ec2476 ("drm/panthor: Add the MMU/VM logical block") +Reviewed-by: Boris Brezillon +Signed-off-by: Ketil Johnsen +Reviewed-by: Liviu Dudau +Reviewed-by: Steven Price +Link: https://patch.msgid.link/20251219093546.1227697-1-ketil.johnsen@arm.com +Co-developed-by: Boris Brezillon +Signed-off-by: Boris Brezillon +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panthor/panthor_mmu.c | 4 ++++ + drivers/gpu/drm/panthor/panthor_sched.c | 14 ++++++++++++++ + drivers/gpu/drm/panthor/panthor_sched.h | 1 + + 3 files changed, 19 insertions(+) + +diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c +index ed769749ec354..e221708cf1aa3 100644 +--- a/drivers/gpu/drm/panthor/panthor_mmu.c ++++ b/drivers/gpu/drm/panthor/panthor_mmu.c +@@ -1554,6 +1554,10 @@ static void panthor_vm_destroy(struct panthor_vm *vm) + + vm->destroyed = true; + ++ /* Tell scheduler to stop all GPU work related to this VM */ ++ if (refcount_read(&vm->as.active_cnt) > 0) ++ panthor_sched_prepare_for_vm_destruction(vm->ptdev); ++ + mutex_lock(&vm->heaps.lock); + panthor_heap_pool_destroy(vm->heaps.pool); + vm->heaps.pool = NULL; +diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c +index 9124df017a1a4..2d4dacece655f 100644 +--- a/drivers/gpu/drm/panthor/panthor_sched.c ++++ b/drivers/gpu/drm/panthor/panthor_sched.c +@@ -2658,6 +2658,20 @@ void panthor_sched_report_mmu_fault(struct panthor_device *ptdev) + panthor_sched_immediate_tick(ptdev); + } + ++void panthor_sched_prepare_for_vm_destruction(struct panthor_device *ptdev) ++{ ++ /* FW can write out internal state, like the heap context, during CSG ++ * suspend. It is therefore important that the scheduler has fully ++ * evicted any pending and related groups before VM destruction can ++ * safely continue. Failure to do so can lead to GPU page faults. ++ * A controlled termination of a Panthor instance involves destroying ++ * the group(s) before the VM. This means any relevant group eviction ++ * has already been initiated by this point, and we just need to ++ * ensure that any pending tick_work() has been completed. ++ */ ++ flush_work(&ptdev->scheduler->tick_work.work); ++} ++ + void panthor_sched_resume(struct panthor_device *ptdev) + { + /* Force a tick to re-evaluate after a resume. */ +diff --git a/drivers/gpu/drm/panthor/panthor_sched.h b/drivers/gpu/drm/panthor/panthor_sched.h +index 3a30d2328b308..666d1655ee18e 100644 +--- a/drivers/gpu/drm/panthor/panthor_sched.h ++++ b/drivers/gpu/drm/panthor/panthor_sched.h +@@ -45,6 +45,7 @@ void panthor_sched_suspend(struct panthor_device *ptdev); + void panthor_sched_resume(struct panthor_device *ptdev); + + void panthor_sched_report_mmu_fault(struct panthor_device *ptdev); ++void panthor_sched_prepare_for_vm_destruction(struct panthor_device *ptdev); + void panthor_sched_report_fw_events(struct panthor_device *ptdev, u32 events); + + #endif +-- +2.51.0 + diff --git a/queue-6.12/drm-panthor-fix-immediate-ticking-on-a-disabled-tick.patch b/queue-6.12/drm-panthor-fix-immediate-ticking-on-a-disabled-tick.patch new file mode 100644 index 0000000000..55dc88f77c --- /dev/null +++ b/queue-6.12/drm-panthor-fix-immediate-ticking-on-a-disabled-tick.patch @@ -0,0 +1,61 @@ +From 143330765839cdb2193c8e2ace276c8c40795282 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 10:48:36 +0100 +Subject: drm/panthor: Fix immediate ticking on a disabled tick + +From: Boris Brezillon + +[ Upstream commit 4356d21994f4ff5c87305b874939b359f16f6677 ] + +We have a few paths where we schedule the tick work immediately without +changing the resched_target. If the tick was stopped, this would lead +to a remaining_jiffies that's always > 0, and it wouldn't force a full +tick in that case. Add extra checks to cover that case properly. + +v2: +- Fix typo +- Simplify the code as suggested by Steve + +v3: +- Collect R-b + +Fixes: de8548813824 ("drm/panthor: Add the scheduler logical block") +Reviewed-by: Steven Price +Reviewed-by: Chia-I Wu +Link: https://patch.msgid.link/20251128094839.3856402-6-boris.brezillon@collabora.com +Signed-off-by: Boris Brezillon +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panthor/panthor_sched.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c +index d2386e54a4bc4..04236fd41518d 100644 +--- a/drivers/gpu/drm/panthor/panthor_sched.c ++++ b/drivers/gpu/drm/panthor/panthor_sched.c +@@ -2325,6 +2325,7 @@ static void tick_work(struct work_struct *work) + tick_work.work); + struct panthor_device *ptdev = sched->ptdev; + struct panthor_sched_tick_ctx ctx; ++ u64 resched_target = sched->resched_target; + u64 remaining_jiffies = 0, resched_delay; + u64 now = get_jiffies_64(); + int prio, ret, cookie; +@@ -2337,8 +2338,12 @@ static void tick_work(struct work_struct *work) + if (drm_WARN_ON(&ptdev->base, ret)) + goto out_dev_exit; + +- if (time_before64(now, sched->resched_target)) +- remaining_jiffies = sched->resched_target - now; ++ /* If the tick is stopped, calculate when the next tick would be */ ++ if (resched_target == U64_MAX) ++ resched_target = sched->last_tick + sched->tick_period; ++ ++ if (time_before64(now, resched_target)) ++ remaining_jiffies = resched_target - now; + + full_tick = remaining_jiffies == 0; + +-- +2.51.0 + diff --git a/queue-6.12/drm-panthor-fix-the-full_tick-check.patch b/queue-6.12/drm-panthor-fix-the-full_tick-check.patch new file mode 100644 index 0000000000..1352f73f4c --- /dev/null +++ b/queue-6.12/drm-panthor-fix-the-full_tick-check.patch @@ -0,0 +1,64 @@ +From 9a62e4936b43571b8927943befc2ab121f5d22fe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 10:48:34 +0100 +Subject: drm/panthor: Fix the full_tick check + +From: Boris Brezillon + +[ Upstream commit a3c2d0b40b108bd45d44f6c1dfa33c39d577adcd ] + +We have a full tick when the remaining time to the next tick is zero, +not the other way around. Declare a full_tick variable so we don't get +that test wrong in other places. + +v2: +- Add R-b + +v3: +- Collect R-b + +Fixes: de8548813824 ("drm/panthor: Add the scheduler logical block") +Reviewed-by: Steven Price +Reviewed-by: Chia-I Wu +Link: https://patch.msgid.link/20251128094839.3856402-4-boris.brezillon@collabora.com +Signed-off-by: Boris Brezillon +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panthor/panthor_sched.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c +index 1d95decddc273..6cfd44a414802 100644 +--- a/drivers/gpu/drm/panthor/panthor_sched.c ++++ b/drivers/gpu/drm/panthor/panthor_sched.c +@@ -2338,6 +2338,7 @@ static void tick_work(struct work_struct *work) + u64 remaining_jiffies = 0, resched_delay; + u64 now = get_jiffies_64(); + int prio, ret, cookie; ++ bool full_tick; + + if (!drm_dev_enter(&ptdev->base, &cookie)) + return; +@@ -2349,15 +2350,17 @@ static void tick_work(struct work_struct *work) + if (time_before64(now, sched->resched_target)) + remaining_jiffies = sched->resched_target - now; + ++ full_tick = remaining_jiffies == 0; ++ + mutex_lock(&sched->lock); + if (panthor_device_reset_is_pending(sched->ptdev)) + goto out_unlock; + +- tick_ctx_init(sched, &ctx, remaining_jiffies != 0); ++ tick_ctx_init(sched, &ctx, full_tick); + if (ctx.csg_upd_failed_mask) + goto out_cleanup_ctx; + +- if (remaining_jiffies) { ++ if (!full_tick) { + /* Scheduling forced in the middle of a tick. Only RT groups + * can preempt non-RT ones. Currently running RT groups can't be + * preempted. +-- +2.51.0 + diff --git a/queue-6.12/drm-panthor-fix-the-group-priority-rotation-logic.patch b/queue-6.12/drm-panthor-fix-the-group-priority-rotation-logic.patch new file mode 100644 index 0000000000..159a7cf88f --- /dev/null +++ b/queue-6.12/drm-panthor-fix-the-group-priority-rotation-logic.patch @@ -0,0 +1,140 @@ +From 530ddd8ddb3b4948851282a9555956bcc3f30b30 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 10:48:35 +0100 +Subject: drm/panthor: Fix the group priority rotation logic + +From: Boris Brezillon + +[ Upstream commit 55429c51d5db3db24c2ad561944c6a0ca922d476 ] + +When rotating group priorities, we want the group with the +highest priority to go back to the end of the queue, and all +other active groups to get their priority bumped, otherwise +some groups will never get a chance to run with the highest +priority. This implies moving the rotation itself to +tick_work(), and only dealing with old group ordering in +tick_ctx_insert_old_group(). + +v2: +- Add R-b +- Fix the commit message + +v3: +- Drop the full_tick argument in tick_ctx_init() +- Collect R-b + +Fixes: de8548813824 ("drm/panthor: Add the scheduler logical block") +Reviewed-by: Steven Price +Reviewed-by: Chia-I Wu +Link: https://patch.msgid.link/20251128094839.3856402-5-boris.brezillon@collabora.com +Signed-off-by: Boris Brezillon +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panthor/panthor_sched.c | 52 +++++++++++++++---------- + 1 file changed, 31 insertions(+), 21 deletions(-) + +diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c +index 6cfd44a414802..d2386e54a4bc4 100644 +--- a/drivers/gpu/drm/panthor/panthor_sched.c ++++ b/drivers/gpu/drm/panthor/panthor_sched.c +@@ -1940,31 +1940,22 @@ tick_ctx_pick_groups_from_list(const struct panthor_scheduler *sched, + static void + tick_ctx_insert_old_group(struct panthor_scheduler *sched, + struct panthor_sched_tick_ctx *ctx, +- struct panthor_group *group, +- bool full_tick) ++ struct panthor_group *group) + { + struct panthor_csg_slot *csg_slot = &sched->csg_slots[group->csg_id]; + struct panthor_group *other_group; + +- if (!full_tick) { +- list_add_tail(&group->run_node, &ctx->old_groups[group->priority]); +- return; +- } +- +- /* Rotate to make sure groups with lower CSG slot +- * priorities have a chance to get a higher CSG slot +- * priority next time they get picked. This priority +- * has an impact on resource request ordering, so it's +- * important to make sure we don't let one group starve +- * all other groups with the same group priority. +- */ ++ /* Class groups in descending priority order so we can easily rotate. */ + list_for_each_entry(other_group, + &ctx->old_groups[csg_slot->group->priority], + run_node) { + struct panthor_csg_slot *other_csg_slot = &sched->csg_slots[other_group->csg_id]; + +- if (other_csg_slot->priority > csg_slot->priority) { +- list_add_tail(&csg_slot->group->run_node, &other_group->run_node); ++ /* Our group has a higher prio than the one we're testing against, ++ * place it just before. ++ */ ++ if (csg_slot->priority > other_csg_slot->priority) { ++ list_add_tail(&group->run_node, &other_group->run_node); + return; + } + } +@@ -1974,8 +1965,7 @@ tick_ctx_insert_old_group(struct panthor_scheduler *sched, + + static void + tick_ctx_init(struct panthor_scheduler *sched, +- struct panthor_sched_tick_ctx *ctx, +- bool full_tick) ++ struct panthor_sched_tick_ctx *ctx) + { + struct panthor_device *ptdev = sched->ptdev; + struct panthor_csg_slots_upd_ctx upd_ctx; +@@ -2013,7 +2003,7 @@ tick_ctx_init(struct panthor_scheduler *sched, + group->fatal_queues |= GENMASK(group->queue_count - 1, 0); + } + +- tick_ctx_insert_old_group(sched, ctx, group, full_tick); ++ tick_ctx_insert_old_group(sched, ctx, group); + csgs_upd_ctx_queue_reqs(ptdev, &upd_ctx, i, + csg_iface->output->ack ^ CSG_STATUS_UPDATE, + CSG_STATUS_UPDATE); +@@ -2356,7 +2346,7 @@ static void tick_work(struct work_struct *work) + if (panthor_device_reset_is_pending(sched->ptdev)) + goto out_unlock; + +- tick_ctx_init(sched, &ctx, full_tick); ++ tick_ctx_init(sched, &ctx); + if (ctx.csg_upd_failed_mask) + goto out_cleanup_ctx; + +@@ -2382,9 +2372,29 @@ static void tick_work(struct work_struct *work) + for (prio = PANTHOR_CSG_PRIORITY_COUNT - 1; + prio >= 0 && !tick_ctx_is_full(sched, &ctx); + prio--) { ++ struct panthor_group *old_highest_prio_group = ++ list_first_entry_or_null(&ctx.old_groups[prio], ++ struct panthor_group, run_node); ++ ++ /* Pull out the group with the highest prio for rotation. */ ++ if (old_highest_prio_group) ++ list_del(&old_highest_prio_group->run_node); ++ ++ /* Re-insert old active groups so they get a chance to run with higher prio. */ ++ tick_ctx_pick_groups_from_list(sched, &ctx, &ctx.old_groups[prio], true, true); ++ ++ /* Fill the remaining slots with runnable groups. */ + tick_ctx_pick_groups_from_list(sched, &ctx, &sched->groups.runnable[prio], + true, false); +- tick_ctx_pick_groups_from_list(sched, &ctx, &ctx.old_groups[prio], true, true); ++ ++ /* Re-insert the old group with the highest prio, and give it a chance to be ++ * scheduled again (but with a lower prio) if there's room left. ++ */ ++ if (old_highest_prio_group) { ++ list_add_tail(&old_highest_prio_group->run_node, &ctx.old_groups[prio]); ++ tick_ctx_pick_groups_from_list(sched, &ctx, &ctx.old_groups[prio], ++ true, true); ++ } + } + + /* If we have free CSG slots left, pick idle groups */ +-- +2.51.0 + diff --git a/queue-6.12/drm-panthor-fix-the-logic-that-decides-when-to-stop-.patch b/queue-6.12/drm-panthor-fix-the-logic-that-decides-when-to-stop-.patch new file mode 100644 index 0000000000..4f752497aa --- /dev/null +++ b/queue-6.12/drm-panthor-fix-the-logic-that-decides-when-to-stop-.patch @@ -0,0 +1,130 @@ +From 7c6d041959da590b3be9eb2ab640905ac43ce5db Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 10:48:37 +0100 +Subject: drm/panthor: Fix the logic that decides when to stop ticking + +From: Boris Brezillon + +[ Upstream commit 61d9a43d70dc3e1709ecd14a34f6d5f01e21dfc9 ] + +When we have multiple active groups with the same priority, we need to +keep ticking for the priority rotation to take place. If we don't do +that, we might starve slots with lower priorities. + +It's annoying to deal with that in tick_ctx_update_resched_target(), +so let's add a ::stop_tick field to the tick context which is +initialized to true, and downgraded to false as soon as we detect +something that requires to tick to happen. This way we can complement +the current logic with extra conditions if needed. + +v2: +- Add R-b + +v3: +- Drop panthor_sched_tick_ctx::min_priority (no longer relevant) +- Collect R-b + +Fixes: de8548813824 ("drm/panthor: Add the scheduler logical block") +Reviewed-by: Steven Price +Reviewed-by: Chia-I Wu +Link: https://patch.msgid.link/20251128094839.3856402-7-boris.brezillon@collabora.com +Signed-off-by: Boris Brezillon +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panthor/panthor_sched.c | 44 ++++++++++--------------- + 1 file changed, 17 insertions(+), 27 deletions(-) + +diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c +index 04236fd41518d..6be977e69b192 100644 +--- a/drivers/gpu/drm/panthor/panthor_sched.c ++++ b/drivers/gpu/drm/panthor/panthor_sched.c +@@ -1853,10 +1853,10 @@ struct panthor_sched_tick_ctx { + struct list_head groups[PANTHOR_CSG_PRIORITY_COUNT]; + u32 idle_group_count; + u32 group_count; +- enum panthor_csg_priority min_priority; + struct panthor_vm *vms[MAX_CS_PER_CSG]; + u32 as_count; + bool immediate_tick; ++ bool stop_tick; + u32 csg_upd_failed_mask; + }; + +@@ -1921,17 +1921,21 @@ tick_ctx_pick_groups_from_list(const struct panthor_scheduler *sched, + if (!owned_by_tick_ctx) + group_get(group); + +- list_move_tail(&group->run_node, &ctx->groups[group->priority]); + ctx->group_count++; ++ ++ /* If we have more than one active group with the same priority, ++ * we need to keep ticking to rotate the CSG priority. ++ */ + if (group_is_idle(group)) + ctx->idle_group_count++; ++ else if (!list_empty(&ctx->groups[group->priority])) ++ ctx->stop_tick = false; ++ ++ list_move_tail(&group->run_node, &ctx->groups[group->priority]); + + if (i == ctx->as_count) + ctx->vms[ctx->as_count++] = group->vm; + +- if (ctx->min_priority > group->priority) +- ctx->min_priority = group->priority; +- + if (tick_ctx_is_full(sched, ctx)) + return; + } +@@ -1975,7 +1979,7 @@ tick_ctx_init(struct panthor_scheduler *sched, + memset(ctx, 0, sizeof(*ctx)); + csgs_upd_ctx_init(&upd_ctx); + +- ctx->min_priority = PANTHOR_CSG_PRIORITY_COUNT; ++ ctx->stop_tick = true; + for (i = 0; i < ARRAY_SIZE(ctx->groups); i++) { + INIT_LIST_HEAD(&ctx->groups[i]); + INIT_LIST_HEAD(&ctx->old_groups[i]); +@@ -2287,32 +2291,18 @@ static u64 + tick_ctx_update_resched_target(struct panthor_scheduler *sched, + const struct panthor_sched_tick_ctx *ctx) + { +- /* We had space left, no need to reschedule until some external event happens. */ +- if (!tick_ctx_is_full(sched, ctx)) +- goto no_tick; +- +- /* If idle groups were scheduled, no need to wake up until some external +- * event happens (group unblocked, new job submitted, ...). +- */ +- if (ctx->idle_group_count) +- goto no_tick; ++ u64 resched_target; + +- if (drm_WARN_ON(&sched->ptdev->base, ctx->min_priority >= PANTHOR_CSG_PRIORITY_COUNT)) ++ if (ctx->stop_tick) + goto no_tick; + +- /* If there are groups of the same priority waiting, we need to +- * keep the scheduler ticking, otherwise, we'll just wait for +- * new groups with higher priority to be queued. +- */ +- if (!list_empty(&sched->groups.runnable[ctx->min_priority])) { +- u64 resched_target = sched->last_tick + sched->tick_period; ++ resched_target = sched->last_tick + sched->tick_period; + +- if (time_before64(sched->resched_target, sched->last_tick) || +- time_before64(resched_target, sched->resched_target)) +- sched->resched_target = resched_target; ++ if (time_before64(sched->resched_target, sched->last_tick) || ++ time_before64(resched_target, sched->resched_target)) ++ sched->resched_target = resched_target; + +- return sched->resched_target - sched->last_tick; +- } ++ return sched->resched_target - sched->last_tick; + + no_tick: + sched->resched_target = U64_MAX; +-- +2.51.0 + diff --git a/queue-6.12/drm-panthor-make-sure-we-resume-the-tick-when-new-jo.patch b/queue-6.12/drm-panthor-make-sure-we-resume-the-tick-when-new-jo.patch new file mode 100644 index 0000000000..afa6ade715 --- /dev/null +++ b/queue-6.12/drm-panthor-make-sure-we-resume-the-tick-when-new-jo.patch @@ -0,0 +1,109 @@ +From 2d94983cff75b93edf1c53f5c80e15b9c450c5f9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 10:48:38 +0100 +Subject: drm/panthor: Make sure we resume the tick when new jobs are submitted + +From: Boris Brezillon + +[ Upstream commit 99820b4b7e50d9651f01d2d55b6b9ba92dcc5b99 ] + +If the group is already assigned a slot but was idle before this job +submission, we need to make sure the priority rotation happens in the +future. Extract the existing logic living in group_schedule_locked() +and call this new sched_resume_tick() helper from the "group is +assigned a slot" path. + +v2: +- Add R-b + +v3: +- Re-use queue_mask to clear the bit +- Collect R-b + +Fixes: de8548813824 ("drm/panthor: Add the scheduler logical block") +Reviewed-by: Steven Price +Reviewed-by: Chia-I Wu +Link: https://patch.msgid.link/20251128094839.3856402-8-boris.brezillon@collabora.com +Signed-off-by: Boris Brezillon +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panthor/panthor_sched.c | 43 +++++++++++++++++++------ + 1 file changed, 34 insertions(+), 9 deletions(-) + +diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c +index 6be977e69b192..9124df017a1a4 100644 +--- a/drivers/gpu/drm/panthor/panthor_sched.c ++++ b/drivers/gpu/drm/panthor/panthor_sched.c +@@ -2514,14 +2514,33 @@ static void sync_upd_work(struct work_struct *work) + sched_queue_delayed_work(sched, tick, 0); + } + ++static void sched_resume_tick(struct panthor_device *ptdev) ++{ ++ struct panthor_scheduler *sched = ptdev->scheduler; ++ u64 delay_jiffies, now; ++ ++ drm_WARN_ON(&ptdev->base, sched->resched_target != U64_MAX); ++ ++ /* Scheduler tick was off, recalculate the resched_target based on the ++ * last tick event, and queue the scheduler work. ++ */ ++ now = get_jiffies_64(); ++ sched->resched_target = sched->last_tick + sched->tick_period; ++ if (sched->used_csg_slot_count == sched->csg_slot_count && ++ time_before64(now, sched->resched_target)) ++ delay_jiffies = min_t(unsigned long, sched->resched_target - now, ULONG_MAX); ++ else ++ delay_jiffies = 0; ++ ++ sched_queue_delayed_work(sched, tick, delay_jiffies); ++} ++ + static void group_schedule_locked(struct panthor_group *group, u32 queue_mask) + { + struct panthor_device *ptdev = group->ptdev; + struct panthor_scheduler *sched = ptdev->scheduler; + struct list_head *queue = &sched->groups.runnable[group->priority]; +- u64 delay_jiffies = 0; + bool was_idle; +- u64 now; + + if (!group_can_run(group)) + return; +@@ -2566,13 +2585,7 @@ static void group_schedule_locked(struct panthor_group *group, u32 queue_mask) + /* Scheduler tick was off, recalculate the resched_target based on the + * last tick event, and queue the scheduler work. + */ +- now = get_jiffies_64(); +- sched->resched_target = sched->last_tick + sched->tick_period; +- if (sched->used_csg_slot_count == sched->csg_slot_count && +- time_before64(now, sched->resched_target)) +- delay_jiffies = min_t(unsigned long, sched->resched_target - now, ULONG_MAX); +- +- sched_queue_delayed_work(sched, tick, delay_jiffies); ++ sched_resume_tick(ptdev); + } + + static void queue_stop(struct panthor_queue *queue, +@@ -3129,6 +3142,18 @@ queue_run_job(struct drm_sched_job *sched_job) + + group_schedule_locked(group, BIT(job->queue_idx)); + } else { ++ u32 queue_mask = BIT(job->queue_idx); ++ bool resume_tick = group_is_idle(group) && ++ (group->idle_queues & queue_mask) && ++ !(group->blocked_queues & queue_mask) && ++ sched->resched_target == U64_MAX; ++ ++ /* We just added something to the queue, so it's no longer idle. */ ++ group->idle_queues &= ~queue_mask; ++ ++ if (resume_tick) ++ sched_resume_tick(ptdev); ++ + gpu_write(ptdev, CSF_DOORBELL(queue->doorbell_id), 1); + if (!sched->pm.has_ref && + !(group->blocked_queues & BIT(job->queue_idx))) { +-- +2.51.0 + diff --git a/queue-6.12/drm-panthor-recover-from-panthor_gpu_flush_caches-fa.patch b/queue-6.12/drm-panthor-recover-from-panthor_gpu_flush_caches-fa.patch new file mode 100644 index 0000000000..e69129450e --- /dev/null +++ b/queue-6.12/drm-panthor-recover-from-panthor_gpu_flush_caches-fa.patch @@ -0,0 +1,108 @@ +From 041e6b6e5fa8f219f7d36ca0ec303305c2dadc65 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 09:48:37 +0100 +Subject: drm/panthor: Recover from panthor_gpu_flush_caches() failures + +From: Boris Brezillon + +[ Upstream commit 3c0a60195b37af83bbbaf223cd3a78945bace49e ] + +We have seen a few cases where the whole memory subsystem is blocked +and flush operations never complete. When that happens, we want to: + +- schedule a reset, so we can recover from this situation +- in the reset path, we need to reset the pending_reqs so we can send + new commands after the reset +- if more panthor_gpu_flush_caches() operations are queued after + the timeout, we skip them and return -EIO directly to avoid needless + waits (the memory block won't miraculously work again) + +Note that we drop the WARN_ON()s because these hangs can be triggered +with buggy GPU jobs created by the UMD, and there's no way we can +prevent it. We do keep the error messages though. + +v2: +- New patch + +v3: +- Collect R-b +- Explicitly mention the fact we dropped the WARN_ON()s in the commit + message + +v4: +- No changes + +Fixes: 5cd894e258c4 ("drm/panthor: Add the GPU logical block") +Reviewed-by: Steven Price +Link: https://patch.msgid.link/20251128084841.3804658-4-boris.brezillon@collabora.com +Signed-off-by: Boris Brezillon +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panthor/panthor_gpu.c | 19 ++++++++++++------- + 1 file changed, 12 insertions(+), 7 deletions(-) + +diff --git a/drivers/gpu/drm/panthor/panthor_gpu.c b/drivers/gpu/drm/panthor/panthor_gpu.c +index 1ca2924e6d552..15e4371d98945 100644 +--- a/drivers/gpu/drm/panthor/panthor_gpu.c ++++ b/drivers/gpu/drm/panthor/panthor_gpu.c +@@ -384,38 +384,42 @@ int panthor_gpu_l2_power_on(struct panthor_device *ptdev) + int panthor_gpu_flush_caches(struct panthor_device *ptdev, + u32 l2, u32 lsc, u32 other) + { +- bool timedout = false; + unsigned long flags; ++ int ret = 0; + + /* Serialize cache flush operations. */ + guard(mutex)(&ptdev->gpu->cache_flush_lock); + + spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags); +- if (!drm_WARN_ON(&ptdev->base, +- ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED)) { ++ if (!(ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED)) { + ptdev->gpu->pending_reqs |= GPU_IRQ_CLEAN_CACHES_COMPLETED; + gpu_write(ptdev, GPU_CMD, GPU_FLUSH_CACHES(l2, lsc, other)); ++ } else { ++ ret = -EIO; + } + spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags); + ++ if (ret) ++ return ret; ++ + if (!wait_event_timeout(ptdev->gpu->reqs_acked, + !(ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED), + msecs_to_jiffies(100))) { + spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags); + if ((ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED) != 0 && + !(gpu_read(ptdev, GPU_INT_RAWSTAT) & GPU_IRQ_CLEAN_CACHES_COMPLETED)) +- timedout = true; ++ ret = -ETIMEDOUT; + else + ptdev->gpu->pending_reqs &= ~GPU_IRQ_CLEAN_CACHES_COMPLETED; + spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags); + } + +- if (timedout) { ++ if (ret) { ++ panthor_device_schedule_reset(ptdev); + drm_err(&ptdev->base, "Flush caches timeout"); +- return -ETIMEDOUT; + } + +- return 0; ++ return ret; + } + + /** +@@ -455,6 +459,7 @@ int panthor_gpu_soft_reset(struct panthor_device *ptdev) + return -ETIMEDOUT; + } + ++ ptdev->gpu->pending_reqs = 0; + return 0; + } + +-- +2.51.0 + diff --git a/queue-6.12/drm-xe-unregister-drm-device-on-probe-error.patch b/queue-6.12/drm-xe-unregister-drm-device-on-probe-error.patch new file mode 100644 index 0000000000..2f58d8db98 --- /dev/null +++ b/queue-6.12/drm-xe-unregister-drm-device-on-probe-error.patch @@ -0,0 +1,91 @@ +From b6a98dadf9dabf1cd7e4c642e495c3f2d2caa9be Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 21:10:42 +0000 +Subject: drm/xe: Unregister drm device on probe error + +From: Shuicheng Lin + +[ Upstream commit 96c2c72b817d70e8d110e78b0162e044a0c41f9f ] + +Call drm_dev_unregister() when xe_device_probe() fails after successful +drm_dev_register(). This ensures the DRM device is promptly unregistered +before returning an error, avoiding leaving it registered on the failure +path. +Otherwise, there is warn message if xe_device_probe() is called again: +" +[ 207.322365] [drm:drm_minor_register] +[ 207.322381] debugfs: '128' already exists in 'dri' +[ 207.322432] sysfs: cannot create duplicate filename '/devices/pci0000:00/0000:00:01.0/0000:01:00.0/0000:02:01.0/0000:03:00.0/drm/renderD128' +[ 207.322435] CPU: 5 UID: 0 PID: 10261 Comm: modprobe Tainted: G B W 6.19.0-rc2-lgci-xe-kernel+ #223 PREEMPT(voluntary) +[ 207.322439] Tainted: [B]=BAD_PAGE, [W]=WARN +[ 207.322440] Hardware name: ASUS System Product Name/PRIME Z790-P WIFI, BIOS 0812 02/24/2023 +[ 207.322441] Call Trace: +[ 207.322442] +[ 207.322443] dump_stack_lvl+0xa0/0xc0 +[ 207.322446] dump_stack+0x10/0x20 +[ 207.322448] sysfs_warn_dup+0xd5/0x110 +[ 207.322451] sysfs_create_dir_ns+0x1f6/0x280 +[ 207.322453] ? __pfx_sysfs_create_dir_ns+0x10/0x10 +[ 207.322455] ? lock_acquire+0x1a4/0x2e0 +[ 207.322458] ? __kasan_check_read+0x11/0x20 +[ 207.322461] kobject_add_internal+0x28d/0x8e0 +[ 207.322464] kobject_add+0x11f/0x1f0 +[ 207.322465] ? lock_acquire+0x1a4/0x2e0 +[ 207.322467] ? __pfx_kobject_add+0x10/0x10 +[ 207.322469] ? __kasan_check_write+0x14/0x20 +[ 207.322471] ? kobject_put+0x62/0x4a0 +[ 207.322473] ? get_device_parent.isra.0+0x1bb/0x4c0 +[ 207.322475] ? kobject_put+0x62/0x4a0 +[ 207.322477] device_add+0x2d7/0x1500 +[ 207.322479] ? __pfx_device_add+0x10/0x10 +[ 207.322481] ? drm_debugfs_add_file+0xfa/0x170 +[ 207.322483] ? drm_debugfs_add_files+0x82/0xd0 +[ 207.322485] ? drm_debugfs_add_files+0x82/0xd0 +[ 207.322487] drm_minor_register+0x10a/0x2d0 +[ 207.322489] drm_dev_register+0x143/0x860 +[ 207.322491] ? xe_configfs_get_psmi_enabled+0x12/0x90 [xe] +[ 207.322667] xe_device_probe+0x185b/0x2c40 [xe] +[ 207.322812] ? __pfx___drm_dev_dbg+0x10/0x10 +[ 207.322815] ? add_dr+0x180/0x220 +[ 207.322818] ? __pfx___drmm_mutex_release+0x10/0x10 +[ 207.322821] ? __pfx_xe_device_probe+0x10/0x10 [xe] +[ 207.322966] ? xe_pm_init_early+0x33a/0x410 [xe] +[ 207.323136] xe_pci_probe+0x936/0x1250 [xe] +[ 207.323298] ? lock_acquire+0x1a4/0x2e0 +[ 207.323302] ? __pfx_xe_pci_probe+0x10/0x10 [xe] +[ 207.323464] local_pci_probe+0xe6/0x1a0 +[ 207.323468] pci_device_probe+0x523/0x840 +[ 207.323470] ? __pfx_pci_device_probe+0x10/0x10 +[ 207.323473] ? sysfs_do_create_link_sd.isra.0+0x8c/0x110 +[ 207.323476] ? sysfs_create_link+0x48/0xc0 +[ 207.323479] really_probe+0x1fd/0x8a0 +... +" + +Fixes: dd08ebf6c352 ("drm/xe: Introduce a new DRM driver for Intel GPUs") +Signed-off-by: Shuicheng Lin +Reviewed-by: Jonathan Cavitt +Link: https://patch.msgid.link/20260109211041.2446012-2-shuicheng.lin@intel.com +Signed-off-by: Matt Roper +(cherry picked from commit 60bfb8baf8f0d5b0d521744dfd01c880ce1a23f3) +Signed-off-by: Rodrigo Vivi +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/xe/xe_device.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c +index 161c73e676640..3ce5bf902f700 100644 +--- a/drivers/gpu/drm/xe/xe_device.c ++++ b/drivers/gpu/drm/xe/xe_device.c +@@ -783,6 +783,7 @@ int xe_device_probe(struct xe_device *xe) + static void xe_device_remove_display(struct xe_device *xe) + { + xe_display_unregister(xe); ++ drm_dev_unregister(&xe->drm); + + drm_dev_unplug(&xe->drm); + xe_display_driver_remove(xe); +-- +2.51.0 + diff --git a/queue-6.12/edac-altera-remove-irqf_oneshot.patch b/queue-6.12/edac-altera-remove-irqf_oneshot.patch new file mode 100644 index 0000000000..c8e83754af --- /dev/null +++ b/queue-6.12/edac-altera-remove-irqf_oneshot.patch @@ -0,0 +1,74 @@ +From 7731b62c1d899af358af9dd8a8cd7b7b7ebf3f1a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:55:30 +0100 +Subject: EDAC/altera: Remove IRQF_ONESHOT + +From: Sebastian Andrzej Siewior + +[ Upstream commit 5c858d6c66304b4c7579582ec5235f02d43578ea ] + +Passing IRQF_ONESHOT ensures that the interrupt source is masked until +the secondary (threaded) handler is done. If only a primary handler is +used then the flag makes no sense because the interrupt can not fire +(again) while its handler is running. + +The flag also prevents force-threading of the primary handler and the +irq-core will warn about this. + +Remove IRQF_ONESHOT from irqflags. + +Fixes: a29d64a45eed1 ("EDAC, altera: Add IRQ Flags to disable IRQ while handling") +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260128095540.863589-11-bigeasy@linutronix.de +Signed-off-by: Sasha Levin +--- + drivers/edac/altera_edac.c | 11 ++++------- + 1 file changed, 4 insertions(+), 7 deletions(-) + +diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c +index 3bb851e1e608a..6c5fb06976415 100644 +--- a/drivers/edac/altera_edac.c ++++ b/drivers/edac/altera_edac.c +@@ -1563,8 +1563,7 @@ static int altr_portb_setup(struct altr_edac_device_dev *device) + goto err_release_group_1; + } + rc = devm_request_irq(&altdev->ddev, altdev->sb_irq, +- prv->ecc_irq_handler, +- IRQF_ONESHOT | IRQF_TRIGGER_HIGH, ++ prv->ecc_irq_handler, IRQF_TRIGGER_HIGH, + ecc_name, altdev); + if (rc) { + edac_printk(KERN_ERR, EDAC_DEVICE, "PortB SBERR IRQ error\n"); +@@ -1587,8 +1586,7 @@ static int altr_portb_setup(struct altr_edac_device_dev *device) + goto err_release_group_1; + } + rc = devm_request_irq(&altdev->ddev, altdev->db_irq, +- prv->ecc_irq_handler, +- IRQF_ONESHOT | IRQF_TRIGGER_HIGH, ++ prv->ecc_irq_handler, IRQF_TRIGGER_HIGH, + ecc_name, altdev); + if (rc) { + edac_printk(KERN_ERR, EDAC_DEVICE, "PortB DBERR IRQ error\n"); +@@ -1970,8 +1968,7 @@ static int altr_edac_a10_device_add(struct altr_arria10_edac *edac, + goto err_release_group1; + } + rc = devm_request_irq(edac->dev, altdev->sb_irq, prv->ecc_irq_handler, +- IRQF_ONESHOT | IRQF_TRIGGER_HIGH, +- ecc_name, altdev); ++ IRQF_TRIGGER_HIGH, ecc_name, altdev); + if (rc) { + edac_printk(KERN_ERR, EDAC_DEVICE, "No SBERR IRQ resource\n"); + goto err_release_group1; +@@ -1993,7 +1990,7 @@ static int altr_edac_a10_device_add(struct altr_arria10_edac *edac, + goto err_release_group1; + } + rc = devm_request_irq(edac->dev, altdev->db_irq, prv->ecc_irq_handler, +- IRQF_ONESHOT | IRQF_TRIGGER_HIGH, ++ IRQF_TRIGGER_HIGH, + ecc_name, altdev); + if (rc) { + edac_printk(KERN_ERR, EDAC_DEVICE, "No DBERR IRQ resource\n"); +-- +2.51.0 + diff --git a/queue-6.12/edac-i5000-fix-snprintf-size-calculation-in-calculat.patch b/queue-6.12/edac-i5000-fix-snprintf-size-calculation-in-calculat.patch new file mode 100644 index 0000000000..c798765f01 --- /dev/null +++ b/queue-6.12/edac-i5000-fix-snprintf-size-calculation-in-calculat.patch @@ -0,0 +1,40 @@ +From c9a865ac6e549bed23d40a050b691a9f7bc07690 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 17:36:59 +0300 +Subject: EDAC/i5000: Fix snprintf() size calculation in calculate_dimm_size() + +From: Dan Carpenter + +[ Upstream commit 7b5c7e83ac405ff9ecbdd92b37a477f4288f8814 ] + +The snprintf() can't really overflow because we're writing a max of 42 +bytes to a PAGE_SIZE buffer. But the limit calculation doesn't take +the first 11 bytes that we wrote into consideration so the limit is +not correct. Just fix it for correctness even though it doesn't +affect runtime. + +Fixes: 64e1fdaf55d6 ("i5000_edac: Fix the logic that retrieves memory information") +Signed-off-by: Dan Carpenter +Signed-off-by: Tony Luck +Reviewed-by: Qiuxu Zhuo +Link: https://patch.msgid.link/07cd652c51e77aad5a8350e1a7cd9407e5bbe373.1765290801.git.dan.carpenter@linaro.org +Signed-off-by: Sasha Levin +--- + drivers/edac/i5000_edac.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c +index 4b5a71f8739d9..8c6a291e01f6a 100644 +--- a/drivers/edac/i5000_edac.c ++++ b/drivers/edac/i5000_edac.c +@@ -1111,6 +1111,7 @@ static void calculate_dimm_size(struct i5000_pvt *pvt) + + n = snprintf(p, space, " "); + p += n; ++ space -= n; + for (branch = 0; branch < MAX_BRANCHES; branch++) { + n = snprintf(p, space, " branch %d | ", branch); + p += n; +-- +2.51.0 + diff --git a/queue-6.12/edac-i5400-fix-snprintf-limit-calculation-in-calcula.patch b/queue-6.12/edac-i5400-fix-snprintf-limit-calculation-in-calcula.patch new file mode 100644 index 0000000000..7622f9765a --- /dev/null +++ b/queue-6.12/edac-i5400-fix-snprintf-limit-calculation-in-calcula.patch @@ -0,0 +1,49 @@ +From 175efd96bd513c653f3725c0d7bcd2dac1ff7a44 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 17:37:04 +0300 +Subject: EDAC/i5400: Fix snprintf() limit calculation in calculate_dimm_size() + +From: Dan Carpenter + +[ Upstream commit 72f12683611344853ab030fe7d19b23970ed2bd8 ] + +The snprintf() can't really overflow because we're writing a max of 42 +bytes to a PAGE_SIZE buffer. But my static checker complains because +the limit calculation doesn't take the first 11 space characters that +we wrote into the buffer into consideration. Fix this for the sake of +correctness even though it doesn't affect runtime. + +Also delete an earlier "space -= n;" which was not used. + +Fixes: 68d086f89b80 ("i5400_edac: improve debug messages to better represent the filled memory") +Signed-off-by: Dan Carpenter +Signed-off-by: Tony Luck +Reviewed-by: Qiuxu Zhuo +Link: https://patch.msgid.link/ccd06b91748e7ed8e33eeb2ff1e7b98700879304.1765290801.git.dan.carpenter@linaro.org +Signed-off-by: Sasha Levin +--- + drivers/edac/i5400_edac.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/edac/i5400_edac.c b/drivers/edac/i5400_edac.c +index 49b4499269fb7..68afb3bb8e290 100644 +--- a/drivers/edac/i5400_edac.c ++++ b/drivers/edac/i5400_edac.c +@@ -1025,13 +1025,13 @@ static void calculate_dimm_size(struct i5400_pvt *pvt) + space -= n; + } + +- space -= n; + edac_dbg(2, "%s\n", mem_buffer); + p = mem_buffer; + space = PAGE_SIZE; + + n = snprintf(p, space, " "); + p += n; ++ space -= n; + for (branch = 0; branch < MAX_BRANCHES; branch++) { + n = snprintf(p, space, " branch %d | ", branch); + p += n; +-- +2.51.0 + diff --git a/queue-6.12/erofs-get-rid-of-raw-bi_end_io-usage.patch b/queue-6.12/erofs-get-rid-of-raw-bi_end_io-usage.patch new file mode 100644 index 0000000000..b176755aba --- /dev/null +++ b/queue-6.12/erofs-get-rid-of-raw-bi_end_io-usage.patch @@ -0,0 +1,71 @@ +From f7785aca00deef376422d4ed852f3f022de61c0a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Nov 2025 16:07:56 +0800 +Subject: erofs: get rid of raw bi_end_io() usage + +From: Gao Xiang + +[ Upstream commit 80d0c27a0a4af8e0678d7412781482e6f73c22c7 ] + +These BIOs are actually harmless in practice, as they are all pseudo +BIOs and do not use advanced features like chaining. Using the BIO +interface is a more friendly and unified approach for both bdev and +and file-backed I/Os (compared to awkward bvec interfaces). + +Let's use bio_endio() instead. + +Reviewed-by: Christoph Hellwig +Reviewed-by: Ming Lei +Reviewed-by: Chao Yu +Signed-off-by: Gao Xiang +Stable-dep-of: bc804a8d7e86 ("erofs: handle end of filesystem properly for file-backed mounts") +Signed-off-by: Sasha Levin +--- + fs/erofs/fileio.c | 2 +- + fs/erofs/fscache.c | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/fs/erofs/fileio.c b/fs/erofs/fileio.c +index 990defcf93043..bc2c9fb44236e 100644 +--- a/fs/erofs/fileio.c ++++ b/fs/erofs/fileio.c +@@ -35,13 +35,13 @@ static void erofs_fileio_ki_complete(struct kiocb *iocb, long ret) + if (rq->bio.bi_end_io) { + if (ret < 0 && !rq->bio.bi_status) + rq->bio.bi_status = errno_to_blk_status(ret); +- rq->bio.bi_end_io(&rq->bio); + } else { + bio_for_each_folio_all(fi, &rq->bio) { + DBG_BUGON(folio_test_uptodate(fi.folio)); + erofs_onlinefolio_end(fi.folio, ret, false); + } + } ++ bio_endio(&rq->bio); + bio_uninit(&rq->bio); + if (refcount_dec_and_test(&rq->ref)) + kfree(rq); +diff --git a/fs/erofs/fscache.c b/fs/erofs/fscache.c +index ce3d8737df85d..20e2cb18ed1d4 100644 +--- a/fs/erofs/fscache.c ++++ b/fs/erofs/fscache.c +@@ -187,7 +187,7 @@ static void erofs_fscache_bio_endio(void *priv, + + if (IS_ERR_VALUE(transferred_or_error)) + io->bio.bi_status = errno_to_blk_status(transferred_or_error); +- io->bio.bi_end_io(&io->bio); ++ bio_endio(&io->bio); + BUILD_BUG_ON(offsetof(struct erofs_fscache_bio, io) != 0); + erofs_fscache_io_put(&io->io); + } +@@ -218,7 +218,7 @@ void erofs_fscache_submit_bio(struct bio *bio) + if (!ret) + return; + bio->bi_status = errno_to_blk_status(ret); +- bio->bi_end_io(bio); ++ bio_endio(bio); + } + + static int erofs_fscache_meta_read_folio(struct file *data, struct folio *folio) +-- +2.51.0 + diff --git a/queue-6.12/erofs-handle-end-of-filesystem-properly-for-file-bac.patch b/queue-6.12/erofs-handle-end-of-filesystem-properly-for-file-bac.patch new file mode 100644 index 0000000000..d5df365a2b --- /dev/null +++ b/queue-6.12/erofs-handle-end-of-filesystem-properly-for-file-bac.patch @@ -0,0 +1,64 @@ +From d2339c661e8c7f4f1e43add610a548fd7f340cde Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 15:54:22 +0800 +Subject: erofs: handle end of filesystem properly for file-backed mounts + +From: Gao Xiang + +[ Upstream commit bc804a8d7e865ef47fb7edcaf5e77d18bf444ebc ] + +I/O requests beyond the end of the filesystem should be zeroed out, +similar to loopback devices and that is what we expect. + +Fixes: ce63cb62d794 ("erofs: support unencoded inodes for fileio") +Signed-off-by: Gao Xiang +Signed-off-by: Sasha Levin +--- + fs/erofs/fileio.c | 20 ++++++++------------ + 1 file changed, 8 insertions(+), 12 deletions(-) + +diff --git a/fs/erofs/fileio.c b/fs/erofs/fileio.c +index bc2c9fb44236e..2c7f066daacdd 100644 +--- a/fs/erofs/fileio.c ++++ b/fs/erofs/fileio.c +@@ -25,21 +25,17 @@ static void erofs_fileio_ki_complete(struct kiocb *iocb, long ret) + container_of(iocb, struct erofs_fileio_rq, iocb); + struct folio_iter fi; + +- if (ret > 0) { +- if (ret != rq->bio.bi_iter.bi_size) { +- bio_advance(&rq->bio, ret); +- zero_fill_bio(&rq->bio); +- } +- ret = 0; ++ if (ret >= 0 && ret != rq->bio.bi_iter.bi_size) { ++ bio_advance(&rq->bio, ret); ++ zero_fill_bio(&rq->bio); + } +- if (rq->bio.bi_end_io) { +- if (ret < 0 && !rq->bio.bi_status) +- rq->bio.bi_status = errno_to_blk_status(ret); +- } else { ++ if (!rq->bio.bi_end_io) { + bio_for_each_folio_all(fi, &rq->bio) { + DBG_BUGON(folio_test_uptodate(fi.folio)); +- erofs_onlinefolio_end(fi.folio, ret, false); ++ erofs_onlinefolio_end(fi.folio, ret < 0, false); + } ++ } else if (ret < 0 && !rq->bio.bi_status) { ++ rq->bio.bi_status = errno_to_blk_status(ret); + } + bio_endio(&rq->bio); + bio_uninit(&rq->bio); +@@ -50,7 +46,7 @@ static void erofs_fileio_ki_complete(struct kiocb *iocb, long ret) + static void erofs_fileio_rq_submit(struct erofs_fileio_rq *rq) + { + struct iov_iter iter; +- int ret; ++ ssize_t ret; + + if (!rq) + return; +-- +2.51.0 + diff --git a/queue-6.12/evm-use-ordered-xattrs-list-to-calculate-hmac-in-evm.patch b/queue-6.12/evm-use-ordered-xattrs-list-to-calculate-hmac-in-evm.patch new file mode 100644 index 0000000000..c7e0b16772 --- /dev/null +++ b/queue-6.12/evm-use-ordered-xattrs-list-to-calculate-hmac-in-evm.patch @@ -0,0 +1,70 @@ +From cd7021c193f323fb09e5406dd05023d67f90c8dd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 15:53:41 +0100 +Subject: evm: Use ordered xattrs list to calculate HMAC in evm_init_hmac() + +From: Roberto Sassu + +[ Upstream commit 0496fc9cdc384f67be4413b1c6156eb64fccd5c4 ] + +Commit 8e5d9f916a96 ("smack: deduplicate xattr setting in +smack_inode_init_security()") introduced xattr_dupval() to simplify setting +the xattrs to be provided by the SMACK LSM on inode creation, in the +smack_inode_init_security(). + +Unfortunately, moving lsm_get_xattr_slot() caused the SMACK64TRANSMUTE +xattr be added in the array of new xattrs before SMACK64. This causes the +HMAC of xattrs calculated by evm_init_hmac() for new files to diverge from +the one calculated by both evm_calc_hmac_or_hash() and evmctl. + +evm_init_hmac() calculates the HMAC of the xattrs of new files based on the +order LSMs provide them, while evm_calc_hmac_or_hash() and evmctl calculate +the HMAC based on an ordered xattrs list. + +Fix the issue by making evm_init_hmac() calculate the HMAC of new files +based on the ordered xattrs list too. + +Fixes: 8e5d9f916a96 ("smack: deduplicate xattr setting in smack_inode_init_security()") +Signed-off-by: Roberto Sassu +Signed-off-by: Mimi Zohar +Signed-off-by: Sasha Levin +--- + security/integrity/evm/evm_crypto.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c +index 7c06ffd633d24..c588af7cc5f87 100644 +--- a/security/integrity/evm/evm_crypto.c ++++ b/security/integrity/evm/evm_crypto.c +@@ -401,6 +401,7 @@ int evm_init_hmac(struct inode *inode, const struct xattr *xattrs, + { + struct shash_desc *desc; + const struct xattr *xattr; ++ struct xattr_list *xattr_entry; + + desc = init_desc(EVM_XATTR_HMAC, HASH_ALGO_SHA1); + if (IS_ERR(desc)) { +@@ -408,11 +409,16 @@ int evm_init_hmac(struct inode *inode, const struct xattr *xattrs, + return PTR_ERR(desc); + } + +- for (xattr = xattrs; xattr->name; xattr++) { +- if (!evm_protected_xattr(xattr->name)) +- continue; ++ list_for_each_entry_lockless(xattr_entry, &evm_config_xattrnames, ++ list) { ++ for (xattr = xattrs; xattr->name; xattr++) { ++ if (strcmp(xattr_entry->name + ++ XATTR_SECURITY_PREFIX_LEN, xattr->name) != 0) ++ continue; + +- crypto_shash_update(desc, xattr->value, xattr->value_len); ++ crypto_shash_update(desc, xattr->value, ++ xattr->value_len); ++ } + } + + hmac_add_misc(desc, inode, EVM_XATTR_HMAC, hmac_val); +-- +2.51.0 + diff --git a/queue-6.12/fat-avoid-parent-link-count-underflow-in-rmdir.patch b/queue-6.12/fat-avoid-parent-link-count-underflow-in-rmdir.patch new file mode 100644 index 0000000000..f39889a5c2 --- /dev/null +++ b/queue-6.12/fat-avoid-parent-link-count-underflow-in-rmdir.patch @@ -0,0 +1,74 @@ +From 006cbe47745582fd16ff7e7ad4caf0127ce9a3fb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 1 Jan 2026 19:11:48 +0800 +Subject: fat: avoid parent link count underflow in rmdir + +From: Zhiyu Zhang + +[ Upstream commit 8cafcb881364af5ef3a8b9fed4db254054033d8a ] + +Corrupted FAT images can leave a directory inode with an incorrect +i_nlink (e.g. 2 even though subdirectories exist). rmdir then +unconditionally calls drop_nlink(dir) and can drive i_nlink to 0, +triggering the WARN_ON in drop_nlink(). + +Add a sanity check in vfat_rmdir() and msdos_rmdir(): only drop the +parent link count when it is at least 3, otherwise report a filesystem +error. + +Link: https://lkml.kernel.org/r/20260101111148.1437-1-zhiyuzhang999@gmail.com +Fixes: 9a53c3a783c2 ("[PATCH] r/o bind mounts: unlink: monitor i_nlink") +Signed-off-by: Zhiyu Zhang +Reported-by: Zhiyu Zhang +Closes: https://lore.kernel.org/linux-fsdevel/aVN06OKsKxZe6-Kv@casper.infradead.org/T/#t +Tested-by: Zhiyu Zhang +Acked-by: OGAWA Hirofumi +Cc: Al Viro +Cc: Christian Brauner +Cc: Jan Kara +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/fat/namei_msdos.c | 7 ++++++- + fs/fat/namei_vfat.c | 7 ++++++- + 2 files changed, 12 insertions(+), 2 deletions(-) + +diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c +index f06f6ba643cc8..c75e3791514a2 100644 +--- a/fs/fat/namei_msdos.c ++++ b/fs/fat/namei_msdos.c +@@ -325,7 +325,12 @@ static int msdos_rmdir(struct inode *dir, struct dentry *dentry) + err = fat_remove_entries(dir, &sinfo); /* and releases bh */ + if (err) + goto out; +- drop_nlink(dir); ++ if (dir->i_nlink >= 3) ++ drop_nlink(dir); ++ else { ++ fat_fs_error(sb, "parent dir link count too low (%u)", ++ dir->i_nlink); ++ } + + clear_nlink(inode); + fat_truncate_time(inode, NULL, S_CTIME); +diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c +index 15bf32c21ac0d..31d37e2b4f679 100644 +--- a/fs/fat/namei_vfat.c ++++ b/fs/fat/namei_vfat.c +@@ -806,7 +806,12 @@ static int vfat_rmdir(struct inode *dir, struct dentry *dentry) + err = fat_remove_entries(dir, &sinfo); /* and releases bh */ + if (err) + goto out; +- drop_nlink(dir); ++ if (dir->i_nlink >= 3) ++ drop_nlink(dir); ++ else { ++ fat_fs_error(sb, "parent dir link count too low (%u)", ++ dir->i_nlink); ++ } + + clear_nlink(inode); + fat_truncate_time(inode, NULL, S_ATIME|S_MTIME); +-- +2.51.0 + diff --git a/queue-6.12/fbcon-fbcon_cursor_noblink-fbcon_cursor_blink.patch b/queue-6.12/fbcon-fbcon_cursor_noblink-fbcon_cursor_blink.patch new file mode 100644 index 0000000000..13c8b839cf --- /dev/null +++ b/queue-6.12/fbcon-fbcon_cursor_noblink-fbcon_cursor_blink.patch @@ -0,0 +1,63 @@ +From a47bd9ea62a9f78a8a6f9cc3b5bc00b8443eda74 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Sep 2024 23:48:53 +0300 +Subject: fbcon: fbcon_cursor_noblink -> fbcon_cursor_blink +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ville Syrjälä + +[ Upstream commit 91a256467eed9e4449969163e3c93bc4bd990145 ] + +Invert fbcon_cursor_noblink into fbcon_cursor_blink so that: +- it matches the sysfs attribute exactly +- avoids having to do these NOT operations all over the place +- use bool instead of int + +Signed-off-by: Ville Syrjälä +Signed-off-by: Helge Deller +Stable-dep-of: 8e9bf8b9e8c0 ("printk, vt, fbcon: Remove console_conditional_schedule()") +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/core/fbcon.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c +index e681066736dea..f8ea11b988090 100644 +--- a/drivers/video/fbdev/core/fbcon.c ++++ b/drivers/video/fbdev/core/fbcon.c +@@ -174,7 +174,7 @@ static const struct consw fb_con; + + #define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row) + +-static int fbcon_cursor_noblink; ++static bool fbcon_cursor_blink = true; + + #define divides(a, b) ((!(a) || (b)%(a)) ? 0 : 1) + +@@ -409,7 +409,7 @@ static void fbcon_add_cursor_work(struct fb_info *info) + { + struct fbcon_ops *ops = info->fbcon_par; + +- if (!fbcon_cursor_noblink) ++ if (fbcon_cursor_blink) + queue_delayed_work(system_power_efficient_wq, &ops->cursor_work, + ops->cur_blink_jiffies); + } +@@ -3310,10 +3310,10 @@ static ssize_t store_cursor_blink(struct device *device, + blink = simple_strtoul(buf, last, 0); + + if (blink) { +- fbcon_cursor_noblink = 0; ++ fbcon_cursor_blink = true; + fbcon_add_cursor_work(info); + } else { +- fbcon_cursor_noblink = 1; ++ fbcon_cursor_blink = false; + fbcon_del_cursor_work(info); + } + +-- +2.51.0 + diff --git a/queue-6.12/fbcon-fbcon_is_inactive-fbcon_is_active.patch b/queue-6.12/fbcon-fbcon_is_inactive-fbcon_is_active.patch new file mode 100644 index 0000000000..9755edb0ca --- /dev/null +++ b/queue-6.12/fbcon-fbcon_is_inactive-fbcon_is_active.patch @@ -0,0 +1,157 @@ +From 56bec22b9e384402ccf77349a0041fcb1bf92a48 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Sep 2024 18:57:47 +0300 +Subject: fbcon: fbcon_is_inactive() -> fbcon_is_active() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ville Syrjälä + +[ Upstream commit ffc825a27f5503136196cb38f41641b58bf2df31 ] + +Invert fbcon_is_inactive() into fbcon_is_active(). Much easier +on the poor brain when you don't have to do dobule negations +all over the place. + +Signed-off-by: Ville Syrjälä +Acked-by: Helge Deller +Reviewed-by: Thomas Zimmermann +Signed-off-by: Helge Deller +Stable-dep-of: 8e9bf8b9e8c0 ("printk, vt, fbcon: Remove console_conditional_schedule()") +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/core/fbcon.c | 30 +++++++++++++++--------------- + 1 file changed, 15 insertions(+), 15 deletions(-) + +diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c +index f8ea11b988090..800c9e1724f16 100644 +--- a/drivers/video/fbdev/core/fbcon.c ++++ b/drivers/video/fbdev/core/fbcon.c +@@ -291,12 +291,12 @@ static bool fbcon_skip_panic(struct fb_info *info) + #endif + } + +-static inline int fbcon_is_inactive(struct vc_data *vc, struct fb_info *info) ++static inline int fbcon_is_active(struct vc_data *vc, struct fb_info *info) + { + struct fbcon_ops *ops = info->fbcon_par; + +- return (info->state != FBINFO_STATE_RUNNING || +- vc->vc_mode != KD_TEXT || ops->graphics || fbcon_skip_panic(info)); ++ return info->state == FBINFO_STATE_RUNNING && ++ vc->vc_mode == KD_TEXT && !ops->graphics && !fbcon_skip_panic(info); + } + + static int get_color(struct vc_data *vc, struct fb_info *info, +@@ -1270,7 +1270,7 @@ static void __fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx, + struct fbcon_display *p = &fb_display[vc->vc_num]; + u_int y_break; + +- if (fbcon_is_inactive(vc, info)) ++ if (!fbcon_is_active(vc, info)) + return; + + if (!height || !width) +@@ -1314,7 +1314,7 @@ static void fbcon_putcs(struct vc_data *vc, const u16 *s, unsigned int count, + struct fbcon_display *p = &fb_display[vc->vc_num]; + struct fbcon_ops *ops = info->fbcon_par; + +- if (!fbcon_is_inactive(vc, info)) ++ if (fbcon_is_active(vc, info)) + ops->putcs(vc, info, s, count, real_y(p, ypos), xpos, + get_color(vc, info, scr_readw(s), 1), + get_color(vc, info, scr_readw(s), 0)); +@@ -1325,7 +1325,7 @@ static void fbcon_clear_margins(struct vc_data *vc, int bottom_only) + struct fb_info *info = fbcon_info_from_console(vc->vc_num); + struct fbcon_ops *ops = info->fbcon_par; + +- if (!fbcon_is_inactive(vc, info)) ++ if (fbcon_is_active(vc, info)) + ops->clear_margins(vc, info, margin_color, bottom_only); + } + +@@ -1337,7 +1337,7 @@ static void fbcon_cursor(struct vc_data *vc, bool enable) + + ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms); + +- if (fbcon_is_inactive(vc, info) || vc->vc_deccm != 1) ++ if (!fbcon_is_active(vc, info) || vc->vc_deccm != 1) + return; + + if (vc->vc_cursor_type & CUR_SW) +@@ -1743,7 +1743,7 @@ static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx, + struct fb_info *info = fbcon_info_from_console(vc->vc_num); + struct fbcon_display *p = &fb_display[vc->vc_num]; + +- if (fbcon_is_inactive(vc, info)) ++ if (!fbcon_is_active(vc, info)) + return; + + if (!width || !height) +@@ -1767,7 +1767,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b, + struct fbcon_display *p = &fb_display[vc->vc_num]; + int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK; + +- if (fbcon_is_inactive(vc, info)) ++ if (!fbcon_is_active(vc, info)) + return true; + + fbcon_cursor(vc, false); +@@ -2151,7 +2151,7 @@ static bool fbcon_switch(struct vc_data *vc) + fbcon_del_cursor_work(old_info); + } + +- if (fbcon_is_inactive(vc, info) || ++ if (!fbcon_is_active(vc, info) || + ops->blank_state != FB_BLANK_UNBLANK) + fbcon_del_cursor_work(info); + else +@@ -2191,7 +2191,7 @@ static bool fbcon_switch(struct vc_data *vc) + scrollback_max = 0; + scrollback_current = 0; + +- if (!fbcon_is_inactive(vc, info)) { ++ if (fbcon_is_active(vc, info)) { + ops->var.xoffset = ops->var.yoffset = p->yscroll = 0; + ops->update_start(info); + } +@@ -2247,7 +2247,7 @@ static bool fbcon_blank(struct vc_data *vc, enum vesa_blank_mode blank, + } + } + +- if (!fbcon_is_inactive(vc, info)) { ++ if (fbcon_is_active(vc, info)) { + if (ops->blank_state != blank) { + ops->blank_state = blank; + fbcon_cursor(vc, !blank); +@@ -2261,7 +2261,7 @@ static bool fbcon_blank(struct vc_data *vc, enum vesa_blank_mode blank, + update_screen(vc); + } + +- if (mode_switch || fbcon_is_inactive(vc, info) || ++ if (mode_switch || !fbcon_is_active(vc, info) || + ops->blank_state != FB_BLANK_UNBLANK) + fbcon_del_cursor_work(info); + else +@@ -2598,7 +2598,7 @@ static void fbcon_set_palette(struct vc_data *vc, const unsigned char *table) + int i, j, k, depth; + u8 val; + +- if (fbcon_is_inactive(vc, info)) ++ if (!fbcon_is_active(vc, info)) + return; + + if (!con_is_visible(vc)) +@@ -2698,7 +2698,7 @@ static void fbcon_modechanged(struct fb_info *info) + scrollback_max = 0; + scrollback_current = 0; + +- if (!fbcon_is_inactive(vc, info)) { ++ if (fbcon_is_active(vc, info)) { + ops->var.xoffset = ops->var.yoffset = p->yscroll = 0; + ops->update_start(info); + } +-- +2.51.0 + diff --git a/queue-6.12/fbcon-introduce-get_-fg-bg-_color.patch b/queue-6.12/fbcon-introduce-get_-fg-bg-_color.patch new file mode 100644 index 0000000000..5318a714fd --- /dev/null +++ b/queue-6.12/fbcon-introduce-get_-fg-bg-_color.patch @@ -0,0 +1,85 @@ +From 5b78f9e637bdacf8b66b09cd4b230be8fa24aa7f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Sep 2024 18:57:48 +0300 +Subject: fbcon: Introduce get_{fg,bg}_color() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ville Syrjälä + +[ Upstream commit 311b07842fb0bb69b5b266b3dfd6037260a3ec2a ] + +Make the code more legible by adding get_{fg,bg}_color() +which hide the obscure 'is_fg' parameter of get_color() +from the caller. + +Signed-off-by: Ville Syrjälä +Acked-by: Helge Deller +Reviewed-by: Thomas Zimmermann +Signed-off-by: Helge Deller +Stable-dep-of: 8e9bf8b9e8c0 ("printk, vt, fbcon: Remove console_conditional_schedule()") +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/core/fbcon.c | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c +index 800c9e1724f16..890c6f79f24f6 100644 +--- a/drivers/video/fbdev/core/fbcon.c ++++ b/drivers/video/fbdev/core/fbcon.c +@@ -366,6 +366,16 @@ static int get_color(struct vc_data *vc, struct fb_info *info, + return color; + } + ++static int get_fg_color(struct vc_data *vc, struct fb_info *info, u16 c) ++{ ++ return get_color(vc, info, c, 1); ++} ++ ++static int get_bg_color(struct vc_data *vc, struct fb_info *info, u16 c) ++{ ++ return get_color(vc, info, c, 0); ++} ++ + static void fb_flashcursor(struct work_struct *work) + { + struct fbcon_ops *ops = container_of(work, struct fbcon_ops, cursor_work.work); +@@ -397,8 +407,9 @@ static void fb_flashcursor(struct work_struct *work) + + c = scr_readw((u16 *) vc->vc_pos); + enable = ops->cursor_flash && !ops->cursor_state.enable; +- ops->cursor(vc, info, enable, get_color(vc, info, c, 1), +- get_color(vc, info, c, 0)); ++ ops->cursor(vc, info, enable, ++ get_fg_color(vc, info, c), ++ get_bg_color(vc, info, c)); + console_unlock(); + + queue_delayed_work(system_power_efficient_wq, &ops->cursor_work, +@@ -1316,8 +1327,8 @@ static void fbcon_putcs(struct vc_data *vc, const u16 *s, unsigned int count, + + if (fbcon_is_active(vc, info)) + ops->putcs(vc, info, s, count, real_y(p, ypos), xpos, +- get_color(vc, info, scr_readw(s), 1), +- get_color(vc, info, scr_readw(s), 0)); ++ get_fg_color(vc, info, scr_readw(s)), ++ get_bg_color(vc, info, scr_readw(s))); + } + + static void fbcon_clear_margins(struct vc_data *vc, int bottom_only) +@@ -1350,8 +1361,9 @@ static void fbcon_cursor(struct vc_data *vc, bool enable) + if (!ops->cursor) + return; + +- ops->cursor(vc, info, enable, get_color(vc, info, c, 1), +- get_color(vc, info, c, 0)); ++ ops->cursor(vc, info, enable, ++ get_fg_color(vc, info, c), ++ get_bg_color(vc, info, c)); + } + + static int scrollback_phys_max = 0; +-- +2.51.0 + diff --git a/queue-6.12/fbcon-move-fbcon-callbacks-into-struct-fbcon_bitops.patch b/queue-6.12/fbcon-move-fbcon-callbacks-into-struct-fbcon_bitops.patch new file mode 100644 index 0000000000..f747e5a87b --- /dev/null +++ b/queue-6.12/fbcon-move-fbcon-callbacks-into-struct-fbcon_bitops.patch @@ -0,0 +1,432 @@ +From fbf85f230d07d459c01a529a1cd5ce7fc4cdb10b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Sep 2025 14:44:44 +0200 +Subject: fbcon: Move fbcon callbacks into struct fbcon_bitops + +From: Thomas Zimmermann + +[ Upstream commit 217cb07be424d127293dc0b32dbd077ad37c24f6 ] + +Depending on rotation settings, fbcon sets different callback +functions in struct fbcon_par from within fbcon_set_bitops(). Declare +the callback functions in the new type struct fbcon_bitops. Then +only replace the single bitops pointer in struct fbcon_par. + +Keeping callbacks in constant instances of struct fbcon_bitops +makes it harder to exploit the callbacks. Also makes the code slightly +easier to maintain. + +For tile-based consoles, there's a separate instance of the bitops +structure. + +Signed-off-by: Thomas Zimmermann +Reviewed-by: Sam Ravnborg +Link: https://lore.kernel.org/r/20250909124616.143365-5-tzimmermann@suse.de +Stable-dep-of: 8e9bf8b9e8c0 ("printk, vt, fbcon: Remove console_conditional_schedule()") +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/core/bitblit.c | 17 ++++--- + drivers/video/fbdev/core/fbcon.c | 67 +++++++++++++++------------- + drivers/video/fbdev/core/fbcon.h | 7 ++- + drivers/video/fbdev/core/fbcon_ccw.c | 18 +++++--- + drivers/video/fbdev/core/fbcon_cw.c | 18 +++++--- + drivers/video/fbdev/core/fbcon_ud.c | 18 +++++--- + drivers/video/fbdev/core/tileblit.c | 16 ++++--- + 7 files changed, 94 insertions(+), 67 deletions(-) + +diff --git a/drivers/video/fbdev/core/bitblit.c b/drivers/video/fbdev/core/bitblit.c +index bed8ba18222b9..8b5819877469e 100644 +--- a/drivers/video/fbdev/core/bitblit.c ++++ b/drivers/video/fbdev/core/bitblit.c +@@ -409,15 +409,18 @@ static int bit_update_start(struct fb_info *info) + return err; + } + ++static const struct fbcon_bitops bit_fbcon_bitops = { ++ .bmove = bit_bmove, ++ .clear = bit_clear, ++ .putcs = bit_putcs, ++ .clear_margins = bit_clear_margins, ++ .cursor = bit_cursor, ++ .update_start = bit_update_start, ++}; ++ + void fbcon_set_bitops(struct fbcon_par *par) + { +- par->bmove = bit_bmove; +- par->clear = bit_clear; +- par->putcs = bit_putcs; +- par->clear_margins = bit_clear_margins; +- par->cursor = bit_cursor; +- par->update_start = bit_update_start; +- par->rotate_font = NULL; ++ par->bitops = &bit_fbcon_bitops; + + if (par->rotate) + fbcon_set_rotate(par); +diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c +index 665c400a2d3a9..3cc68324f297b 100644 +--- a/drivers/video/fbdev/core/fbcon.c ++++ b/drivers/video/fbdev/core/fbcon.c +@@ -407,9 +407,9 @@ static void fb_flashcursor(struct work_struct *work) + + c = scr_readw((u16 *) vc->vc_pos); + enable = par->cursor_flash && !par->cursor_state.enable; +- par->cursor(vc, info, enable, +- get_fg_color(vc, info, c), +- get_bg_color(vc, info, c)); ++ par->bitops->cursor(vc, info, enable, ++ get_fg_color(vc, info, c), ++ get_bg_color(vc, info, c)); + console_unlock(); + + queue_delayed_work(system_power_efficient_wq, &par->cursor_work, +@@ -1164,7 +1164,7 @@ static void fbcon_init(struct vc_data *vc, bool init) + if (logo) + fbcon_prepare_logo(vc, info, cols, rows, new_cols, new_rows); + +- if (par->rotate_font && par->rotate_font(info, vc)) { ++ if (par->bitops->rotate_font && par->bitops->rotate_font(info, vc)) { + par->rotate = FB_ROTATE_UR; + set_blitting_type(vc, info); + } +@@ -1305,10 +1305,11 @@ static void __fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx, + y_break = p->vrows - p->yscroll; + if (sy < y_break && sy + height - 1 >= y_break) { + u_int b = y_break - sy; +- par->clear(vc, info, real_y(p, sy), sx, b, width, fg, bg); +- par->clear(vc, info, real_y(p, sy + b), sx, height - b, width, fg, bg); ++ par->bitops->clear(vc, info, real_y(p, sy), sx, b, width, fg, bg); ++ par->bitops->clear(vc, info, real_y(p, sy + b), sx, height - b, ++ width, fg, bg); + } else +- par->clear(vc, info, real_y(p, sy), sx, height, width, fg, bg); ++ par->bitops->clear(vc, info, real_y(p, sy), sx, height, width, fg, bg); + } + + static void fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx, +@@ -1325,9 +1326,9 @@ static void fbcon_putcs(struct vc_data *vc, const u16 *s, unsigned int count, + struct fbcon_par *par = info->fbcon_par; + + if (fbcon_is_active(vc, info)) +- par->putcs(vc, info, s, count, real_y(p, ypos), xpos, +- get_fg_color(vc, info, scr_readw(s)), +- get_bg_color(vc, info, scr_readw(s))); ++ par->bitops->putcs(vc, info, s, count, real_y(p, ypos), xpos, ++ get_fg_color(vc, info, scr_readw(s)), ++ get_bg_color(vc, info, scr_readw(s))); + } + + static void fbcon_clear_margins(struct vc_data *vc, int bottom_only) +@@ -1336,7 +1337,7 @@ static void fbcon_clear_margins(struct vc_data *vc, int bottom_only) + struct fbcon_par *par = info->fbcon_par; + + if (fbcon_is_active(vc, info)) +- par->clear_margins(vc, info, margin_color, bottom_only); ++ par->bitops->clear_margins(vc, info, margin_color, bottom_only); + } + + static void fbcon_cursor(struct vc_data *vc, bool enable) +@@ -1357,12 +1358,12 @@ static void fbcon_cursor(struct vc_data *vc, bool enable) + + par->cursor_flash = enable; + +- if (!par->cursor) ++ if (!par->bitops->cursor) + return; + +- par->cursor(vc, info, enable, +- get_fg_color(vc, info, c), +- get_bg_color(vc, info, c)); ++ par->bitops->cursor(vc, info, enable, ++ get_fg_color(vc, info, c), ++ get_bg_color(vc, info, c)); + } + + static int scrollback_phys_max = 0; +@@ -1446,7 +1447,7 @@ static __inline__ void ywrap_up(struct vc_data *vc, int count) + par->var.xoffset = 0; + par->var.yoffset = p->yscroll * vc->vc_font.height; + par->var.vmode |= FB_VMODE_YWRAP; +- par->update_start(info); ++ par->bitops->update_start(info); + scrollback_max += count; + if (scrollback_max > scrollback_phys_max) + scrollback_max = scrollback_phys_max; +@@ -1465,7 +1466,7 @@ static __inline__ void ywrap_down(struct vc_data *vc, int count) + par->var.xoffset = 0; + par->var.yoffset = p->yscroll * vc->vc_font.height; + par->var.vmode |= FB_VMODE_YWRAP; +- par->update_start(info); ++ par->bitops->update_start(info); + scrollback_max -= count; + if (scrollback_max < 0) + scrollback_max = 0; +@@ -1480,15 +1481,15 @@ static __inline__ void ypan_up(struct vc_data *vc, int count) + + p->yscroll += count; + if (p->yscroll > p->vrows - vc->vc_rows) { +- par->bmove(vc, info, p->vrows - vc->vc_rows, +- 0, 0, 0, vc->vc_rows, vc->vc_cols); ++ par->bitops->bmove(vc, info, p->vrows - vc->vc_rows, ++ 0, 0, 0, vc->vc_rows, vc->vc_cols); + p->yscroll -= p->vrows - vc->vc_rows; + } + + par->var.xoffset = 0; + par->var.yoffset = p->yscroll * vc->vc_font.height; + par->var.vmode &= ~FB_VMODE_YWRAP; +- par->update_start(info); ++ par->bitops->update_start(info); + fbcon_clear_margins(vc, 1); + scrollback_max += count; + if (scrollback_max > scrollback_phys_max) +@@ -1512,7 +1513,7 @@ static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count) + par->var.xoffset = 0; + par->var.yoffset = p->yscroll * vc->vc_font.height; + par->var.vmode &= ~FB_VMODE_YWRAP; +- par->update_start(info); ++ par->bitops->update_start(info); + fbcon_clear_margins(vc, 1); + scrollback_max += count; + if (scrollback_max > scrollback_phys_max) +@@ -1528,15 +1529,15 @@ static __inline__ void ypan_down(struct vc_data *vc, int count) + + p->yscroll -= count; + if (p->yscroll < 0) { +- par->bmove(vc, info, 0, 0, p->vrows - vc->vc_rows, +- 0, vc->vc_rows, vc->vc_cols); ++ par->bitops->bmove(vc, info, 0, 0, p->vrows - vc->vc_rows, ++ 0, vc->vc_rows, vc->vc_cols); + p->yscroll += p->vrows - vc->vc_rows; + } + + par->var.xoffset = 0; + par->var.yoffset = p->yscroll * vc->vc_font.height; + par->var.vmode &= ~FB_VMODE_YWRAP; +- par->update_start(info); ++ par->bitops->update_start(info); + fbcon_clear_margins(vc, 1); + scrollback_max -= count; + if (scrollback_max < 0) +@@ -1560,7 +1561,7 @@ static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count) + par->var.xoffset = 0; + par->var.yoffset = p->yscroll * vc->vc_font.height; + par->var.vmode &= ~FB_VMODE_YWRAP; +- par->update_start(info); ++ par->bitops->update_start(info); + fbcon_clear_margins(vc, 1); + scrollback_max -= count; + if (scrollback_max < 0) +@@ -1622,8 +1623,8 @@ static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info, + + if (c == scr_readw(d)) { + if (s > start) { +- par->bmove(vc, info, line + ycount, x, +- line, x, 1, s - start); ++ par->bitops->bmove(vc, info, line + ycount, x, ++ line, x, 1, s - start); + x += s - start + 1; + start = s + 1; + } else { +@@ -1638,7 +1639,8 @@ static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info, + d++; + } while (s < le); + if (s > start) +- par->bmove(vc, info, line + ycount, x, line, x, 1, s - start); ++ par->bitops->bmove(vc, info, line + ycount, x, line, x, 1, ++ s - start); + console_conditional_schedule(); + if (ycount > 0) + line++; +@@ -1743,7 +1745,8 @@ static void fbcon_bmove_rec(struct vc_data *vc, struct fbcon_display *p, int sy, + } + return; + } +- par->bmove(vc, info, real_y(p, sy), sx, real_y(p, dy), dx, height, width); ++ par->bitops->bmove(vc, info, real_y(p, sy), sx, real_y(p, dy), dx, ++ height, width); + } + + static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx, +@@ -2163,7 +2166,7 @@ static bool fbcon_switch(struct vc_data *vc) + set_blitting_type(vc, info); + par->cursor_reset = 1; + +- if (par->rotate_font && par->rotate_font(info, vc)) { ++ if (par->bitops->rotate_font && par->bitops->rotate_font(info, vc)) { + par->rotate = FB_ROTATE_UR; + set_blitting_type(vc, info); + } +@@ -2196,7 +2199,7 @@ static bool fbcon_switch(struct vc_data *vc) + + if (fbcon_is_active(vc, info)) { + par->var.xoffset = par->var.yoffset = p->yscroll = 0; +- par->update_start(info); ++ par->bitops->update_start(info); + } + + fbcon_set_palette(vc, color_table); +@@ -2702,7 +2705,7 @@ static void fbcon_modechanged(struct fb_info *info) + + if (fbcon_is_active(vc, info)) { + par->var.xoffset = par->var.yoffset = p->yscroll = 0; +- par->update_start(info); ++ par->bitops->update_start(info); + } + + fbcon_set_palette(vc, color_table); +diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h +index 31ee2d5912219..69ae6b965a103 100644 +--- a/drivers/video/fbdev/core/fbcon.h ++++ b/drivers/video/fbdev/core/fbcon.h +@@ -51,7 +51,7 @@ struct fbcon_display { + const struct fb_videomode *mode; + }; + +-struct fbcon_par { ++struct fbcon_bitops { + void (*bmove)(struct vc_data *vc, struct fb_info *info, int sy, + int sx, int dy, int dx, int height, int width); + void (*clear)(struct vc_data *vc, struct fb_info *info, int sy, +@@ -65,6 +65,9 @@ struct fbcon_par { + bool enable, int fg, int bg); + int (*update_start)(struct fb_info *info); + int (*rotate_font)(struct fb_info *info, struct vc_data *vc); ++}; ++ ++struct fbcon_par { + struct fb_var_screeninfo var; /* copy of the current fb_var_screeninfo */ + struct delayed_work cursor_work; /* Cursor timer */ + struct fb_cursor cursor_state; +@@ -86,6 +89,8 @@ struct fbcon_par { + u8 *cursor_src; + u32 cursor_size; + u32 fd_size; ++ ++ const struct fbcon_bitops *bitops; + }; + /* + * Attribute Decoding +diff --git a/drivers/video/fbdev/core/fbcon_ccw.c b/drivers/video/fbdev/core/fbcon_ccw.c +index ba744b67a4fd9..4721f4b5e29a5 100644 +--- a/drivers/video/fbdev/core/fbcon_ccw.c ++++ b/drivers/video/fbdev/core/fbcon_ccw.c +@@ -390,13 +390,17 @@ static int ccw_update_start(struct fb_info *info) + return err; + } + ++static const struct fbcon_bitops ccw_fbcon_bitops = { ++ .bmove = ccw_bmove, ++ .clear = ccw_clear, ++ .putcs = ccw_putcs, ++ .clear_margins = ccw_clear_margins, ++ .cursor = ccw_cursor, ++ .update_start = ccw_update_start, ++ .rotate_font = fbcon_rotate_font, ++}; ++ + void fbcon_rotate_ccw(struct fbcon_par *par) + { +- par->bmove = ccw_bmove; +- par->clear = ccw_clear; +- par->putcs = ccw_putcs; +- par->clear_margins = ccw_clear_margins; +- par->cursor = ccw_cursor; +- par->update_start = ccw_update_start; +- par->rotate_font = fbcon_rotate_font; ++ par->bitops = &ccw_fbcon_bitops; + } +diff --git a/drivers/video/fbdev/core/fbcon_cw.c b/drivers/video/fbdev/core/fbcon_cw.c +index 974bd9d9b7702..2771924d0fb72 100644 +--- a/drivers/video/fbdev/core/fbcon_cw.c ++++ b/drivers/video/fbdev/core/fbcon_cw.c +@@ -373,13 +373,17 @@ static int cw_update_start(struct fb_info *info) + return err; + } + ++static const struct fbcon_bitops cw_fbcon_bitops = { ++ .bmove = cw_bmove, ++ .clear = cw_clear, ++ .putcs = cw_putcs, ++ .clear_margins = cw_clear_margins, ++ .cursor = cw_cursor, ++ .update_start = cw_update_start, ++ .rotate_font = fbcon_rotate_font, ++}; ++ + void fbcon_rotate_cw(struct fbcon_par *par) + { +- par->bmove = cw_bmove; +- par->clear = cw_clear; +- par->putcs = cw_putcs; +- par->clear_margins = cw_clear_margins; +- par->cursor = cw_cursor; +- par->update_start = cw_update_start; +- par->rotate_font = fbcon_rotate_font; ++ par->bitops = &cw_fbcon_bitops; + } +diff --git a/drivers/video/fbdev/core/fbcon_ud.c b/drivers/video/fbdev/core/fbcon_ud.c +index 1a214a4d538fb..148ca9b539d19 100644 +--- a/drivers/video/fbdev/core/fbcon_ud.c ++++ b/drivers/video/fbdev/core/fbcon_ud.c +@@ -417,13 +417,17 @@ static int ud_update_start(struct fb_info *info) + return err; + } + ++static const struct fbcon_bitops ud_fbcon_bitops = { ++ .bmove = ud_bmove, ++ .clear = ud_clear, ++ .putcs = ud_putcs, ++ .clear_margins = ud_clear_margins, ++ .cursor = ud_cursor, ++ .update_start = ud_update_start, ++ .rotate_font = fbcon_rotate_font, ++}; ++ + void fbcon_rotate_ud(struct fbcon_par *par) + { +- par->bmove = ud_bmove; +- par->clear = ud_clear; +- par->putcs = ud_putcs; +- par->clear_margins = ud_clear_margins; +- par->cursor = ud_cursor; +- par->update_start = ud_update_start; +- par->rotate_font = fbcon_rotate_font; ++ par->bitops = &ud_fbcon_bitops; + } +diff --git a/drivers/video/fbdev/core/tileblit.c b/drivers/video/fbdev/core/tileblit.c +index 4428f2bcd3f8c..a9db668caf727 100644 +--- a/drivers/video/fbdev/core/tileblit.c ++++ b/drivers/video/fbdev/core/tileblit.c +@@ -161,17 +161,21 @@ static int tile_update_start(struct fb_info *info) + return err; + } + ++static const struct fbcon_bitops tile_fbcon_bitops = { ++ .bmove = tile_bmove, ++ .clear = tile_clear, ++ .putcs = tile_putcs, ++ .clear_margins = tile_clear_margins, ++ .cursor = tile_cursor, ++ .update_start = tile_update_start, ++}; ++ + void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info) + { + struct fb_tilemap map; + struct fbcon_par *par = info->fbcon_par; + +- par->bmove = tile_bmove; +- par->clear = tile_clear; +- par->putcs = tile_putcs; +- par->clear_margins = tile_clear_margins; +- par->cursor = tile_cursor; +- par->update_start = tile_update_start; ++ par->bitops = &tile_fbcon_bitops; + + if (par->p) { + map.width = vc->vc_font.width; +-- +2.51.0 + diff --git a/queue-6.12/fbcon-rename-struct-fbcon_ops-to-struct-fbcon_par.patch b/queue-6.12/fbcon-rename-struct-fbcon_ops-to-struct-fbcon_par.patch new file mode 100644 index 0000000000..474c9573d8 --- /dev/null +++ b/queue-6.12/fbcon-rename-struct-fbcon_ops-to-struct-fbcon_par.patch @@ -0,0 +1,2478 @@ +From fd6811ebe8165d0d74eabf975e3744b6a308634b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Sep 2025 14:44:42 +0200 +Subject: fbcon: Rename struct fbcon_ops to struct fbcon_par + +From: Thomas Zimmermann + +[ Upstream commit a6adbbc4c32a016146e117b1e9e5242724a75e10 ] + +The type struct fbcon_ops contains fbcon state and callbacks. As the +callbacks will be removed from struct fbcon_ops, rename the data type +to struct fbcon_par. Also rename the variables from ops to par. + +The _par postfix ("private access registers") is used throughout the +fbdev subsystem for per-driver state. The fbcon pointer within struct +fb_info is also named fbcon_par. Hence, the new naming fits existing +practice. + +v2: +- rename struct fbcon_ops to struct fbcon_par +- fix build for CONFIG_FB_TILEBITTING=n (kernel test robot) +- fix indention + +Signed-off-by: Thomas Zimmermann +Reviewed-by: Sam Ravnborg +Link: https://lore.kernel.org/r/20250909124616.143365-3-tzimmermann@suse.de +Stable-dep-of: 8e9bf8b9e8c0 ("printk, vt, fbcon: Remove console_conditional_schedule()") +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/core/bitblit.c | 122 +++---- + drivers/video/fbdev/core/fbcon.c | 419 ++++++++++++------------ + drivers/video/fbdev/core/fbcon.h | 6 +- + drivers/video/fbdev/core/fbcon_ccw.c | 146 ++++----- + drivers/video/fbdev/core/fbcon_cw.c | 146 ++++----- + drivers/video/fbdev/core/fbcon_rotate.c | 40 +-- + drivers/video/fbdev/core/fbcon_rotate.h | 6 +- + drivers/video/fbdev/core/fbcon_ud.c | 162 ++++----- + drivers/video/fbdev/core/softcursor.c | 18 +- + drivers/video/fbdev/core/tileblit.c | 28 +- + 10 files changed, 541 insertions(+), 552 deletions(-) + +diff --git a/drivers/video/fbdev/core/bitblit.c b/drivers/video/fbdev/core/bitblit.c +index dc5ad3fcc7be4..bed8ba18222b9 100644 +--- a/drivers/video/fbdev/core/bitblit.c ++++ b/drivers/video/fbdev/core/bitblit.c +@@ -261,10 +261,10 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + int fg, int bg) + { + struct fb_cursor cursor; +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; + int w = DIV_ROUND_UP(vc->vc_font.width, 8), c; +- int y = real_y(ops->p, vc->state.y); ++ int y = real_y(par->p, vc->state.y); + int attribute, use_sw = vc->vc_cursor_type & CUR_SW; + int err = 1; + char *src; +@@ -278,10 +278,10 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + attribute = get_attribute(info, c); + src = vc->vc_font.data + ((c & charmask) * (w * vc->vc_font.height)); + +- if (ops->cursor_state.image.data != src || +- ops->cursor_reset) { +- ops->cursor_state.image.data = src; +- cursor.set |= FB_CUR_SETIMAGE; ++ if (par->cursor_state.image.data != src || ++ par->cursor_reset) { ++ par->cursor_state.image.data = src; ++ cursor.set |= FB_CUR_SETIMAGE; + } + + if (attribute) { +@@ -290,46 +290,46 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + dst = kmalloc_array(w, vc->vc_font.height, GFP_ATOMIC); + if (!dst) + return; +- kfree(ops->cursor_data); +- ops->cursor_data = dst; ++ kfree(par->cursor_data); ++ par->cursor_data = dst; + update_attr(dst, src, attribute, vc); + src = dst; + } + +- if (ops->cursor_state.image.fg_color != fg || +- ops->cursor_state.image.bg_color != bg || +- ops->cursor_reset) { +- ops->cursor_state.image.fg_color = fg; +- ops->cursor_state.image.bg_color = bg; ++ if (par->cursor_state.image.fg_color != fg || ++ par->cursor_state.image.bg_color != bg || ++ par->cursor_reset) { ++ par->cursor_state.image.fg_color = fg; ++ par->cursor_state.image.bg_color = bg; + cursor.set |= FB_CUR_SETCMAP; + } + +- if ((ops->cursor_state.image.dx != (vc->vc_font.width * vc->state.x)) || +- (ops->cursor_state.image.dy != (vc->vc_font.height * y)) || +- ops->cursor_reset) { +- ops->cursor_state.image.dx = vc->vc_font.width * vc->state.x; +- ops->cursor_state.image.dy = vc->vc_font.height * y; ++ if ((par->cursor_state.image.dx != (vc->vc_font.width * vc->state.x)) || ++ (par->cursor_state.image.dy != (vc->vc_font.height * y)) || ++ par->cursor_reset) { ++ par->cursor_state.image.dx = vc->vc_font.width * vc->state.x; ++ par->cursor_state.image.dy = vc->vc_font.height * y; + cursor.set |= FB_CUR_SETPOS; + } + +- if (ops->cursor_state.image.height != vc->vc_font.height || +- ops->cursor_state.image.width != vc->vc_font.width || +- ops->cursor_reset) { +- ops->cursor_state.image.height = vc->vc_font.height; +- ops->cursor_state.image.width = vc->vc_font.width; ++ if (par->cursor_state.image.height != vc->vc_font.height || ++ par->cursor_state.image.width != vc->vc_font.width || ++ par->cursor_reset) { ++ par->cursor_state.image.height = vc->vc_font.height; ++ par->cursor_state.image.width = vc->vc_font.width; + cursor.set |= FB_CUR_SETSIZE; + } + +- if (ops->cursor_state.hot.x || ops->cursor_state.hot.y || +- ops->cursor_reset) { +- ops->cursor_state.hot.x = cursor.hot.y = 0; ++ if (par->cursor_state.hot.x || par->cursor_state.hot.y || ++ par->cursor_reset) { ++ par->cursor_state.hot.x = cursor.hot.y = 0; + cursor.set |= FB_CUR_SETHOT; + } + + if (cursor.set & FB_CUR_SETSIZE || +- vc->vc_cursor_type != ops->p->cursor_shape || +- ops->cursor_state.mask == NULL || +- ops->cursor_reset) { ++ vc->vc_cursor_type != par->p->cursor_shape || ++ par->cursor_state.mask == NULL || ++ par->cursor_reset) { + char *mask = kmalloc_array(w, vc->vc_font.height, GFP_ATOMIC); + int cur_height, size, i = 0; + u8 msk = 0xff; +@@ -337,13 +337,13 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + if (!mask) + return; + +- kfree(ops->cursor_state.mask); +- ops->cursor_state.mask = mask; ++ kfree(par->cursor_state.mask); ++ par->cursor_state.mask = mask; + +- ops->p->cursor_shape = vc->vc_cursor_type; ++ par->p->cursor_shape = vc->vc_cursor_type; + cursor.set |= FB_CUR_SETSHAPE; + +- switch (CUR_SIZE(ops->p->cursor_shape)) { ++ switch (CUR_SIZE(par->p->cursor_shape)) { + case CUR_NONE: + cur_height = 0; + break; +@@ -372,19 +372,19 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + mask[i++] = msk; + } + +- ops->cursor_state.enable = enable && !use_sw; ++ par->cursor_state.enable = enable && !use_sw; + + cursor.image.data = src; +- cursor.image.fg_color = ops->cursor_state.image.fg_color; +- cursor.image.bg_color = ops->cursor_state.image.bg_color; +- cursor.image.dx = ops->cursor_state.image.dx; +- cursor.image.dy = ops->cursor_state.image.dy; +- cursor.image.height = ops->cursor_state.image.height; +- cursor.image.width = ops->cursor_state.image.width; +- cursor.hot.x = ops->cursor_state.hot.x; +- cursor.hot.y = ops->cursor_state.hot.y; +- cursor.mask = ops->cursor_state.mask; +- cursor.enable = ops->cursor_state.enable; ++ cursor.image.fg_color = par->cursor_state.image.fg_color; ++ cursor.image.bg_color = par->cursor_state.image.bg_color; ++ cursor.image.dx = par->cursor_state.image.dx; ++ cursor.image.dy = par->cursor_state.image.dy; ++ cursor.image.height = par->cursor_state.image.height; ++ cursor.image.width = par->cursor_state.image.width; ++ cursor.hot.x = par->cursor_state.hot.x; ++ cursor.hot.y = par->cursor_state.hot.y; ++ cursor.mask = par->cursor_state.mask; ++ cursor.enable = par->cursor_state.enable; + cursor.image.depth = 1; + cursor.rop = ROP_XOR; + +@@ -394,31 +394,31 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + if (err) + soft_cursor(info, &cursor); + +- ops->cursor_reset = 0; ++ par->cursor_reset = 0; + } + + static int bit_update_start(struct fb_info *info) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + int err; + +- err = fb_pan_display(info, &ops->var); +- ops->var.xoffset = info->var.xoffset; +- ops->var.yoffset = info->var.yoffset; +- ops->var.vmode = info->var.vmode; ++ err = fb_pan_display(info, &par->var); ++ par->var.xoffset = info->var.xoffset; ++ par->var.yoffset = info->var.yoffset; ++ par->var.vmode = info->var.vmode; + return err; + } + +-void fbcon_set_bitops(struct fbcon_ops *ops) ++void fbcon_set_bitops(struct fbcon_par *par) + { +- ops->bmove = bit_bmove; +- ops->clear = bit_clear; +- ops->putcs = bit_putcs; +- ops->clear_margins = bit_clear_margins; +- ops->cursor = bit_cursor; +- ops->update_start = bit_update_start; +- ops->rotate_font = NULL; +- +- if (ops->rotate) +- fbcon_set_rotate(ops); ++ par->bmove = bit_bmove; ++ par->clear = bit_clear; ++ par->putcs = bit_putcs; ++ par->clear_margins = bit_clear_margins; ++ par->cursor = bit_cursor; ++ par->update_start = bit_update_start; ++ par->rotate_font = NULL; ++ ++ if (par->rotate) ++ fbcon_set_rotate(par); + } +diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c +index 890c6f79f24f6..665c400a2d3a9 100644 +--- a/drivers/video/fbdev/core/fbcon.c ++++ b/drivers/video/fbdev/core/fbcon.c +@@ -200,27 +200,27 @@ static struct device *fbcon_device; + #ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION + static inline void fbcon_set_rotation(struct fb_info *info) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + + if (!(info->flags & FBINFO_MISC_TILEBLITTING) && +- ops->p->con_rotate < 4) +- ops->rotate = ops->p->con_rotate; ++ par->p->con_rotate < 4) ++ par->rotate = par->p->con_rotate; + else +- ops->rotate = 0; ++ par->rotate = 0; + } + + static void fbcon_rotate(struct fb_info *info, u32 rotate) + { +- struct fbcon_ops *ops= info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + struct fb_info *fb_info; + +- if (!ops || ops->currcon == -1) ++ if (!par || par->currcon == -1) + return; + +- fb_info = fbcon_info_from_console(ops->currcon); ++ fb_info = fbcon_info_from_console(par->currcon); + + if (info == fb_info) { +- struct fbcon_display *p = &fb_display[ops->currcon]; ++ struct fbcon_display *p = &fb_display[par->currcon]; + + if (rotate < 4) + p->con_rotate = rotate; +@@ -233,12 +233,12 @@ static void fbcon_rotate(struct fb_info *info, u32 rotate) + + static void fbcon_rotate_all(struct fb_info *info, u32 rotate) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + struct vc_data *vc; + struct fbcon_display *p; + int i; + +- if (!ops || ops->currcon < 0 || rotate > 3) ++ if (!par || par->currcon < 0 || rotate > 3) + return; + + for (i = first_fb_vc; i <= last_fb_vc; i++) { +@@ -256,9 +256,9 @@ static void fbcon_rotate_all(struct fb_info *info, u32 rotate) + #else + static inline void fbcon_set_rotation(struct fb_info *info) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + +- ops->rotate = FB_ROTATE_UR; ++ par->rotate = FB_ROTATE_UR; + } + + static void fbcon_rotate(struct fb_info *info, u32 rotate) +@@ -274,9 +274,9 @@ static void fbcon_rotate_all(struct fb_info *info, u32 rotate) + + static int fbcon_get_rotate(struct fb_info *info) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + +- return (ops) ? ops->rotate : 0; ++ return (par) ? par->rotate : 0; + } + + static bool fbcon_skip_panic(struct fb_info *info) +@@ -293,10 +293,10 @@ static bool fbcon_skip_panic(struct fb_info *info) + + static inline int fbcon_is_active(struct vc_data *vc, struct fb_info *info) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + + return info->state == FBINFO_STATE_RUNNING && +- vc->vc_mode == KD_TEXT && !ops->graphics && !fbcon_skip_panic(info); ++ vc->vc_mode == KD_TEXT && !par->graphics && !fbcon_skip_panic(info); + } + + static int get_color(struct vc_data *vc, struct fb_info *info, +@@ -378,7 +378,7 @@ static int get_bg_color(struct vc_data *vc, struct fb_info *info, u16 c) + + static void fb_flashcursor(struct work_struct *work) + { +- struct fbcon_ops *ops = container_of(work, struct fbcon_ops, cursor_work.work); ++ struct fbcon_par *par = container_of(work, struct fbcon_par, cursor_work.work); + struct fb_info *info; + struct vc_data *vc = NULL; + int c; +@@ -393,10 +393,10 @@ static void fb_flashcursor(struct work_struct *work) + return; + + /* protected by console_lock */ +- info = ops->info; ++ info = par->info; + +- if (ops->currcon != -1) +- vc = vc_cons[ops->currcon].d; ++ if (par->currcon != -1) ++ vc = vc_cons[par->currcon].d; + + if (!vc || !con_is_visible(vc) || + fbcon_info_from_console(vc->vc_num) != info || +@@ -406,30 +406,30 @@ static void fb_flashcursor(struct work_struct *work) + } + + c = scr_readw((u16 *) vc->vc_pos); +- enable = ops->cursor_flash && !ops->cursor_state.enable; +- ops->cursor(vc, info, enable, ++ enable = par->cursor_flash && !par->cursor_state.enable; ++ par->cursor(vc, info, enable, + get_fg_color(vc, info, c), + get_bg_color(vc, info, c)); + console_unlock(); + +- queue_delayed_work(system_power_efficient_wq, &ops->cursor_work, +- ops->cur_blink_jiffies); ++ queue_delayed_work(system_power_efficient_wq, &par->cursor_work, ++ par->cur_blink_jiffies); + } + + static void fbcon_add_cursor_work(struct fb_info *info) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + + if (fbcon_cursor_blink) +- queue_delayed_work(system_power_efficient_wq, &ops->cursor_work, +- ops->cur_blink_jiffies); ++ queue_delayed_work(system_power_efficient_wq, &par->cursor_work, ++ par->cur_blink_jiffies); + } + + static void fbcon_del_cursor_work(struct fb_info *info) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + +- cancel_delayed_work_sync(&ops->cursor_work); ++ cancel_delayed_work_sync(&par->cursor_work); + } + + #ifndef MODULE +@@ -589,7 +589,7 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info, + int cols, int rows, int new_cols, int new_rows) + { + /* Need to make room for the logo */ +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + int cnt, erase = vc->vc_video_erase_char, step; + unsigned short *save = NULL, *r, *q; + int logo_height; +@@ -605,7 +605,7 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info, + */ + if (fb_get_color_depth(&info->var, &info->fix) == 1) + erase &= ~0x400; +- logo_height = fb_prepare_logo(info, ops->rotate); ++ logo_height = fb_prepare_logo(info, par->rotate); + logo_lines = DIV_ROUND_UP(logo_height, vc->vc_font.height); + q = (unsigned short *) (vc->vc_origin + + vc->vc_size_row * rows); +@@ -677,15 +677,15 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info, + #ifdef CONFIG_FB_TILEBLITTING + static void set_blitting_type(struct vc_data *vc, struct fb_info *info) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + +- ops->p = &fb_display[vc->vc_num]; ++ par->p = &fb_display[vc->vc_num]; + + if ((info->flags & FBINFO_MISC_TILEBLITTING)) + fbcon_set_tileops(vc, info); + else { + fbcon_set_rotation(info); +- fbcon_set_bitops(ops); ++ fbcon_set_bitops(par); + } + } + +@@ -702,12 +702,12 @@ static int fbcon_invalid_charcount(struct fb_info *info, unsigned charcount) + #else + static void set_blitting_type(struct vc_data *vc, struct fb_info *info) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + + info->flags &= ~FBINFO_MISC_TILEBLITTING; +- ops->p = &fb_display[vc->vc_num]; ++ par->p = &fb_display[vc->vc_num]; + fbcon_set_rotation(info); +- fbcon_set_bitops(ops); ++ fbcon_set_bitops(par); + } + + static int fbcon_invalid_charcount(struct fb_info *info, unsigned charcount) +@@ -727,13 +727,13 @@ static void fbcon_release(struct fb_info *info) + module_put(info->fbops->owner); + + if (info->fbcon_par) { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + + fbcon_del_cursor_work(info); +- kfree(ops->cursor_state.mask); +- kfree(ops->cursor_data); +- kfree(ops->cursor_src); +- kfree(ops->fontbuffer); ++ kfree(par->cursor_state.mask); ++ kfree(par->cursor_data); ++ kfree(par->cursor_src); ++ kfree(par->fontbuffer); + kfree(info->fbcon_par); + info->fbcon_par = NULL; + } +@@ -741,7 +741,7 @@ static void fbcon_release(struct fb_info *info) + + static int fbcon_open(struct fb_info *info) + { +- struct fbcon_ops *ops; ++ struct fbcon_par *par; + + if (!try_module_get(info->fbops->owner)) + return -ENODEV; +@@ -755,16 +755,16 @@ static int fbcon_open(struct fb_info *info) + } + unlock_fb_info(info); + +- ops = kzalloc(sizeof(struct fbcon_ops), GFP_KERNEL); +- if (!ops) { ++ par = kzalloc(sizeof(*par), GFP_KERNEL); ++ if (!par) { + fbcon_release(info); + return -ENOMEM; + } + +- INIT_DELAYED_WORK(&ops->cursor_work, fb_flashcursor); +- ops->info = info; +- info->fbcon_par = ops; +- ops->cur_blink_jiffies = HZ / 5; ++ INIT_DELAYED_WORK(&par->cursor_work, fb_flashcursor); ++ par->info = info; ++ info->fbcon_par = par; ++ par->cur_blink_jiffies = HZ / 5; + + return 0; + } +@@ -811,12 +811,12 @@ static void con2fb_release_oldinfo(struct vc_data *vc, struct fb_info *oldinfo, + static void con2fb_init_display(struct vc_data *vc, struct fb_info *info, + int unit, int show_logo) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + int ret; + +- ops->currcon = fg_console; ++ par->currcon = fg_console; + +- if (info->fbops->fb_set_par && !ops->initialized) { ++ if (info->fbops->fb_set_par && !par->initialized) { + ret = info->fbops->fb_set_par(info); + + if (ret) +@@ -825,8 +825,8 @@ static void con2fb_init_display(struct vc_data *vc, struct fb_info *info, + "error code %d\n", ret); + } + +- ops->initialized = true; +- ops->graphics = 0; ++ par->initialized = true; ++ par->graphics = 0; + fbcon_set_disp(info, &info->var, unit); + + if (show_logo) { +@@ -963,7 +963,7 @@ static const char *fbcon_startup(void) + struct vc_data *vc = vc_cons[fg_console].d; + const struct font_desc *font = NULL; + struct fb_info *info = NULL; +- struct fbcon_ops *ops; ++ struct fbcon_par *par; + int rows, cols; + + /* +@@ -983,10 +983,10 @@ static const char *fbcon_startup(void) + if (fbcon_open(info)) + return NULL; + +- ops = info->fbcon_par; +- ops->currcon = -1; +- ops->graphics = 1; +- ops->cur_rotate = -1; ++ par = info->fbcon_par; ++ par->currcon = -1; ++ par->graphics = 1; ++ par->cur_rotate = -1; + + p->con_rotate = initial_rotation; + if (p->con_rotate == -1) +@@ -1009,8 +1009,8 @@ static const char *fbcon_startup(void) + vc->vc_font.charcount = font->charcount; + } + +- cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); +- rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); ++ cols = FBCON_SWAP(par->rotate, info->var.xres, info->var.yres); ++ rows = FBCON_SWAP(par->rotate, info->var.yres, info->var.xres); + cols /= vc->vc_font.width; + rows /= vc->vc_font.height; + vc_resize(vc, cols, rows); +@@ -1028,7 +1028,7 @@ static const char *fbcon_startup(void) + static void fbcon_init(struct vc_data *vc, bool init) + { + struct fb_info *info; +- struct fbcon_ops *ops; ++ struct fbcon_par *par; + struct vc_data **default_mode = vc->vc_display_fg; + struct vc_data *svc = *default_mode; + struct fbcon_display *t, *p = &fb_display[vc->vc_num]; +@@ -1102,8 +1102,8 @@ static void fbcon_init(struct vc_data *vc, bool init) + if (!*vc->uni_pagedict_loc) + con_copy_unimap(vc, svc); + +- ops = info->fbcon_par; +- ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms); ++ par = info->fbcon_par; ++ par->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms); + + p->con_rotate = initial_rotation; + if (p->con_rotate == -1) +@@ -1115,8 +1115,8 @@ static void fbcon_init(struct vc_data *vc, bool init) + + cols = vc->vc_cols; + rows = vc->vc_rows; +- new_cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); +- new_rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); ++ new_cols = FBCON_SWAP(par->rotate, info->var.xres, info->var.yres); ++ new_rows = FBCON_SWAP(par->rotate, info->var.yres, info->var.xres); + new_cols /= vc->vc_font.width; + new_rows /= vc->vc_font.height; + +@@ -1128,7 +1128,7 @@ static void fbcon_init(struct vc_data *vc, bool init) + * We need to do it in fbcon_init() to prevent screen corruption. + */ + if (con_is_visible(vc) && vc->vc_mode == KD_TEXT) { +- if (info->fbops->fb_set_par && !ops->initialized) { ++ if (info->fbops->fb_set_par && !par->initialized) { + ret = info->fbops->fb_set_par(info); + + if (ret) +@@ -1137,10 +1137,10 @@ static void fbcon_init(struct vc_data *vc, bool init) + "error code %d\n", ret); + } + +- ops->initialized = true; ++ par->initialized = true; + } + +- ops->graphics = 0; ++ par->graphics = 0; + + #ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION + if ((info->flags & FBINFO_HWACCEL_COPYAREA) && +@@ -1164,12 +1164,12 @@ static void fbcon_init(struct vc_data *vc, bool init) + if (logo) + fbcon_prepare_logo(vc, info, cols, rows, new_cols, new_rows); + +- if (ops->rotate_font && ops->rotate_font(info, vc)) { +- ops->rotate = FB_ROTATE_UR; ++ if (par->rotate_font && par->rotate_font(info, vc)) { ++ par->rotate = FB_ROTATE_UR; + set_blitting_type(vc, info); + } + +- ops->p = &fb_display[fg_console]; ++ par->p = &fb_display[fg_console]; + } + + static void fbcon_free_font(struct fbcon_display *p) +@@ -1207,7 +1207,7 @@ static void fbcon_deinit(struct vc_data *vc) + { + struct fbcon_display *p = &fb_display[vc->vc_num]; + struct fb_info *info; +- struct fbcon_ops *ops; ++ struct fbcon_par *par; + int idx; + + fbcon_free_font(p); +@@ -1221,15 +1221,15 @@ static void fbcon_deinit(struct vc_data *vc) + if (!info) + goto finished; + +- ops = info->fbcon_par; ++ par = info->fbcon_par; + +- if (!ops) ++ if (!par) + goto finished; + + if (con_is_visible(vc)) + fbcon_del_cursor_work(info); + +- ops->initialized = false; ++ par->initialized = false; + finished: + + fbcon_free_font(p); +@@ -1276,7 +1276,7 @@ static void __fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx, + unsigned int height, unsigned int width) + { + struct fb_info *info = fbcon_info_from_console(vc->vc_num); +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + int fg, bg; + struct fbcon_display *p = &fb_display[vc->vc_num]; + u_int y_break; +@@ -1291,7 +1291,7 @@ static void __fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx, + vc->vc_top = 0; + /* + * If the font dimensions are not an integral of the display +- * dimensions then the ops->clear below won't end up clearing ++ * dimensions then the par->clear below won't end up clearing + * the margins. Call clear_margins here in case the logo + * bitmap stretched into the margin area. + */ +@@ -1305,11 +1305,10 @@ static void __fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx, + y_break = p->vrows - p->yscroll; + if (sy < y_break && sy + height - 1 >= y_break) { + u_int b = y_break - sy; +- ops->clear(vc, info, real_y(p, sy), sx, b, width, fg, bg); +- ops->clear(vc, info, real_y(p, sy + b), sx, height - b, +- width, fg, bg); ++ par->clear(vc, info, real_y(p, sy), sx, b, width, fg, bg); ++ par->clear(vc, info, real_y(p, sy + b), sx, height - b, width, fg, bg); + } else +- ops->clear(vc, info, real_y(p, sy), sx, height, width, fg, bg); ++ par->clear(vc, info, real_y(p, sy), sx, height, width, fg, bg); + } + + static void fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx, +@@ -1323,10 +1322,10 @@ static void fbcon_putcs(struct vc_data *vc, const u16 *s, unsigned int count, + { + struct fb_info *info = fbcon_info_from_console(vc->vc_num); + struct fbcon_display *p = &fb_display[vc->vc_num]; +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + + if (fbcon_is_active(vc, info)) +- ops->putcs(vc, info, s, count, real_y(p, ypos), xpos, ++ par->putcs(vc, info, s, count, real_y(p, ypos), xpos, + get_fg_color(vc, info, scr_readw(s)), + get_bg_color(vc, info, scr_readw(s))); + } +@@ -1334,19 +1333,19 @@ static void fbcon_putcs(struct vc_data *vc, const u16 *s, unsigned int count, + static void fbcon_clear_margins(struct vc_data *vc, int bottom_only) + { + struct fb_info *info = fbcon_info_from_console(vc->vc_num); +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + + if (fbcon_is_active(vc, info)) +- ops->clear_margins(vc, info, margin_color, bottom_only); ++ par->clear_margins(vc, info, margin_color, bottom_only); + } + + static void fbcon_cursor(struct vc_data *vc, bool enable) + { + struct fb_info *info = fbcon_info_from_console(vc->vc_num); +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + int c = scr_readw((u16 *) vc->vc_pos); + +- ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms); ++ par->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms); + + if (!fbcon_is_active(vc, info) || vc->vc_deccm != 1) + return; +@@ -1356,12 +1355,12 @@ static void fbcon_cursor(struct vc_data *vc, bool enable) + else + fbcon_add_cursor_work(info); + +- ops->cursor_flash = enable; ++ par->cursor_flash = enable; + +- if (!ops->cursor) ++ if (!par->cursor) + return; + +- ops->cursor(vc, info, enable, ++ par->cursor(vc, info, enable, + get_fg_color(vc, info, c), + get_bg_color(vc, info, c)); + } +@@ -1376,7 +1375,7 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, + struct fbcon_display *p, *t; + struct vc_data **default_mode, *vc; + struct vc_data *svc; +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + int rows, cols; + unsigned long ret = 0; + +@@ -1409,7 +1408,7 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, + var->yoffset = info->var.yoffset; + var->xoffset = info->var.xoffset; + fb_set_var(info, var); +- ops->var = info->var; ++ par->var = info->var; + vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1); + vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; + if (vc->vc_font.charcount == 256) { +@@ -1425,8 +1424,8 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, + if (!*vc->uni_pagedict_loc) + con_copy_unimap(vc, svc); + +- cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); +- rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); ++ cols = FBCON_SWAP(par->rotate, info->var.xres, info->var.yres); ++ rows = FBCON_SWAP(par->rotate, info->var.yres, info->var.xres); + cols /= vc->vc_font.width; + rows /= vc->vc_font.height; + ret = vc_resize(vc, cols, rows); +@@ -1438,16 +1437,16 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, + static __inline__ void ywrap_up(struct vc_data *vc, int count) + { + struct fb_info *info = fbcon_info_from_console(vc->vc_num); +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + struct fbcon_display *p = &fb_display[vc->vc_num]; + + p->yscroll += count; + if (p->yscroll >= p->vrows) /* Deal with wrap */ + p->yscroll -= p->vrows; +- ops->var.xoffset = 0; +- ops->var.yoffset = p->yscroll * vc->vc_font.height; +- ops->var.vmode |= FB_VMODE_YWRAP; +- ops->update_start(info); ++ par->var.xoffset = 0; ++ par->var.yoffset = p->yscroll * vc->vc_font.height; ++ par->var.vmode |= FB_VMODE_YWRAP; ++ par->update_start(info); + scrollback_max += count; + if (scrollback_max > scrollback_phys_max) + scrollback_max = scrollback_phys_max; +@@ -1457,16 +1456,16 @@ static __inline__ void ywrap_up(struct vc_data *vc, int count) + static __inline__ void ywrap_down(struct vc_data *vc, int count) + { + struct fb_info *info = fbcon_info_from_console(vc->vc_num); +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + struct fbcon_display *p = &fb_display[vc->vc_num]; + + p->yscroll -= count; + if (p->yscroll < 0) /* Deal with wrap */ + p->yscroll += p->vrows; +- ops->var.xoffset = 0; +- ops->var.yoffset = p->yscroll * vc->vc_font.height; +- ops->var.vmode |= FB_VMODE_YWRAP; +- ops->update_start(info); ++ par->var.xoffset = 0; ++ par->var.yoffset = p->yscroll * vc->vc_font.height; ++ par->var.vmode |= FB_VMODE_YWRAP; ++ par->update_start(info); + scrollback_max -= count; + if (scrollback_max < 0) + scrollback_max = 0; +@@ -1477,19 +1476,19 @@ static __inline__ void ypan_up(struct vc_data *vc, int count) + { + struct fb_info *info = fbcon_info_from_console(vc->vc_num); + struct fbcon_display *p = &fb_display[vc->vc_num]; +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + + p->yscroll += count; + if (p->yscroll > p->vrows - vc->vc_rows) { +- ops->bmove(vc, info, p->vrows - vc->vc_rows, ++ par->bmove(vc, info, p->vrows - vc->vc_rows, + 0, 0, 0, vc->vc_rows, vc->vc_cols); + p->yscroll -= p->vrows - vc->vc_rows; + } + +- ops->var.xoffset = 0; +- ops->var.yoffset = p->yscroll * vc->vc_font.height; +- ops->var.vmode &= ~FB_VMODE_YWRAP; +- ops->update_start(info); ++ par->var.xoffset = 0; ++ par->var.yoffset = p->yscroll * vc->vc_font.height; ++ par->var.vmode &= ~FB_VMODE_YWRAP; ++ par->update_start(info); + fbcon_clear_margins(vc, 1); + scrollback_max += count; + if (scrollback_max > scrollback_phys_max) +@@ -1500,7 +1499,7 @@ static __inline__ void ypan_up(struct vc_data *vc, int count) + static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count) + { + struct fb_info *info = fbcon_info_from_console(vc->vc_num); +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + struct fbcon_display *p = &fb_display[vc->vc_num]; + + p->yscroll += count; +@@ -1510,10 +1509,10 @@ static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count) + fbcon_redraw_move(vc, p, t + count, vc->vc_rows - count, t); + } + +- ops->var.xoffset = 0; +- ops->var.yoffset = p->yscroll * vc->vc_font.height; +- ops->var.vmode &= ~FB_VMODE_YWRAP; +- ops->update_start(info); ++ par->var.xoffset = 0; ++ par->var.yoffset = p->yscroll * vc->vc_font.height; ++ par->var.vmode &= ~FB_VMODE_YWRAP; ++ par->update_start(info); + fbcon_clear_margins(vc, 1); + scrollback_max += count; + if (scrollback_max > scrollback_phys_max) +@@ -1525,19 +1524,19 @@ static __inline__ void ypan_down(struct vc_data *vc, int count) + { + struct fb_info *info = fbcon_info_from_console(vc->vc_num); + struct fbcon_display *p = &fb_display[vc->vc_num]; +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + + p->yscroll -= count; + if (p->yscroll < 0) { +- ops->bmove(vc, info, 0, 0, p->vrows - vc->vc_rows, ++ par->bmove(vc, info, 0, 0, p->vrows - vc->vc_rows, + 0, vc->vc_rows, vc->vc_cols); + p->yscroll += p->vrows - vc->vc_rows; + } + +- ops->var.xoffset = 0; +- ops->var.yoffset = p->yscroll * vc->vc_font.height; +- ops->var.vmode &= ~FB_VMODE_YWRAP; +- ops->update_start(info); ++ par->var.xoffset = 0; ++ par->var.yoffset = p->yscroll * vc->vc_font.height; ++ par->var.vmode &= ~FB_VMODE_YWRAP; ++ par->update_start(info); + fbcon_clear_margins(vc, 1); + scrollback_max -= count; + if (scrollback_max < 0) +@@ -1548,7 +1547,7 @@ static __inline__ void ypan_down(struct vc_data *vc, int count) + static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count) + { + struct fb_info *info = fbcon_info_from_console(vc->vc_num); +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + struct fbcon_display *p = &fb_display[vc->vc_num]; + + p->yscroll -= count; +@@ -1558,10 +1557,10 @@ static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count) + fbcon_redraw_move(vc, p, t, vc->vc_rows - count, t + count); + } + +- ops->var.xoffset = 0; +- ops->var.yoffset = p->yscroll * vc->vc_font.height; +- ops->var.vmode &= ~FB_VMODE_YWRAP; +- ops->update_start(info); ++ par->var.xoffset = 0; ++ par->var.yoffset = p->yscroll * vc->vc_font.height; ++ par->var.vmode &= ~FB_VMODE_YWRAP; ++ par->update_start(info); + fbcon_clear_margins(vc, 1); + scrollback_max -= count; + if (scrollback_max < 0) +@@ -1610,7 +1609,7 @@ static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info, + unsigned short *d = (unsigned short *) + (vc->vc_origin + vc->vc_size_row * line); + unsigned short *s = d + offset; +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + + while (count--) { + unsigned short *start = s; +@@ -1623,8 +1622,8 @@ static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info, + + if (c == scr_readw(d)) { + if (s > start) { +- ops->bmove(vc, info, line + ycount, x, +- line, x, 1, s-start); ++ par->bmove(vc, info, line + ycount, x, ++ line, x, 1, s - start); + x += s - start + 1; + start = s + 1; + } else { +@@ -1639,8 +1638,7 @@ static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info, + d++; + } while (s < le); + if (s > start) +- ops->bmove(vc, info, line + ycount, x, line, x, 1, +- s-start); ++ par->bmove(vc, info, line + ycount, x, line, x, 1, s - start); + console_conditional_schedule(); + if (ycount > 0) + line++; +@@ -1711,7 +1709,7 @@ static void fbcon_bmove_rec(struct vc_data *vc, struct fbcon_display *p, int sy, + int dy, int dx, int height, int width, u_int y_break) + { + struct fb_info *info = fbcon_info_from_console(vc->vc_num); +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + u_int b; + + if (sy < y_break && sy + height > y_break) { +@@ -1745,8 +1743,7 @@ static void fbcon_bmove_rec(struct vc_data *vc, struct fbcon_display *p, int sy, + } + return; + } +- ops->bmove(vc, info, real_y(p, sy), sx, real_y(p, dy), dx, +- height, width); ++ par->bmove(vc, info, real_y(p, sy), sx, real_y(p, dy), dx, height, width); + } + + static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx, +@@ -1973,15 +1970,13 @@ static void updatescrollmode_accel(struct fbcon_display *p, + struct vc_data *vc) + { + #ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + int cap = info->flags; + u16 t = 0; +- int ypan = FBCON_SWAP(ops->rotate, info->fix.ypanstep, +- info->fix.xpanstep); +- int ywrap = FBCON_SWAP(ops->rotate, info->fix.ywrapstep, t); +- int yres = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); +- int vyres = FBCON_SWAP(ops->rotate, info->var.yres_virtual, +- info->var.xres_virtual); ++ int ypan = FBCON_SWAP(par->rotate, info->fix.ypanstep, info->fix.xpanstep); ++ int ywrap = FBCON_SWAP(par->rotate, info->fix.ywrapstep, t); ++ int yres = FBCON_SWAP(par->rotate, info->var.yres, info->var.xres); ++ int vyres = FBCON_SWAP(par->rotate, info->var.yres_virtual, info->var.xres_virtual); + int good_pan = (cap & FBINFO_HWACCEL_YPAN) && + divides(ypan, vc->vc_font.height) && vyres > yres; + int good_wrap = (cap & FBINFO_HWACCEL_YWRAP) && +@@ -2014,11 +2009,10 @@ static void updatescrollmode(struct fbcon_display *p, + struct fb_info *info, + struct vc_data *vc) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + int fh = vc->vc_font.height; +- int yres = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); +- int vyres = FBCON_SWAP(ops->rotate, info->var.yres_virtual, +- info->var.xres_virtual); ++ int yres = FBCON_SWAP(par->rotate, info->var.yres, info->var.xres); ++ int vyres = FBCON_SWAP(par->rotate, info->var.yres_virtual, info->var.xres_virtual); + + p->vrows = vyres/fh; + if (yres > (fh * (vc->vc_rows + 1))) +@@ -2037,7 +2031,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width, + unsigned int height, bool from_user) + { + struct fb_info *info = fbcon_info_from_console(vc->vc_num); +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + struct fbcon_display *p = &fb_display[vc->vc_num]; + struct fb_var_screeninfo var = info->var; + int x_diff, y_diff, virt_w, virt_h, virt_fw, virt_fh; +@@ -2060,12 +2054,10 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width, + return -EINVAL; + } + +- virt_w = FBCON_SWAP(ops->rotate, width, height); +- virt_h = FBCON_SWAP(ops->rotate, height, width); +- virt_fw = FBCON_SWAP(ops->rotate, vc->vc_font.width, +- vc->vc_font.height); +- virt_fh = FBCON_SWAP(ops->rotate, vc->vc_font.height, +- vc->vc_font.width); ++ virt_w = FBCON_SWAP(par->rotate, width, height); ++ virt_h = FBCON_SWAP(par->rotate, height, width); ++ virt_fw = FBCON_SWAP(par->rotate, vc->vc_font.width, vc->vc_font.height); ++ virt_fh = FBCON_SWAP(par->rotate, vc->vc_font.height, vc->vc_font.width); + var.xres = virt_w * virt_fw; + var.yres = virt_h * virt_fh; + x_diff = info->var.xres - var.xres; +@@ -2091,7 +2083,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width, + fb_set_var(info, &var); + } + var_to_display(p, &info->var, info); +- ops->var = info->var; ++ par->var = info->var; + } + updatescrollmode(p, info, vc); + return 0; +@@ -2100,13 +2092,13 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width, + static bool fbcon_switch(struct vc_data *vc) + { + struct fb_info *info, *old_info = NULL; +- struct fbcon_ops *ops; ++ struct fbcon_par *par; + struct fbcon_display *p = &fb_display[vc->vc_num]; + struct fb_var_screeninfo var; + int i, ret, prev_console; + + info = fbcon_info_from_console(vc->vc_num); +- ops = info->fbcon_par; ++ par = info->fbcon_par; + + if (logo_shown >= 0) { + struct vc_data *conp2 = vc_cons[logo_shown].d; +@@ -2117,7 +2109,7 @@ static bool fbcon_switch(struct vc_data *vc) + logo_shown = FBCON_LOGO_CANSHOW; + } + +- prev_console = ops->currcon; ++ prev_console = par->currcon; + if (prev_console != -1) + old_info = fbcon_info_from_console(prev_console); + /* +@@ -2130,9 +2122,9 @@ static bool fbcon_switch(struct vc_data *vc) + */ + fbcon_for_each_registered_fb(i) { + if (fbcon_registered_fb[i]->fbcon_par) { +- struct fbcon_ops *o = fbcon_registered_fb[i]->fbcon_par; ++ struct fbcon_par *par = fbcon_registered_fb[i]->fbcon_par; + +- o->currcon = vc->vc_num; ++ par->currcon = vc->vc_num; + } + } + memset(&var, 0, sizeof(struct fb_var_screeninfo)); +@@ -2146,7 +2138,7 @@ static bool fbcon_switch(struct vc_data *vc) + info->var.activate = var.activate; + var.vmode |= info->var.vmode & ~FB_VMODE_MASK; + fb_set_var(info, &var); +- ops->var = info->var; ++ par->var = info->var; + + if (old_info != NULL && (old_info != info || + info->flags & FBINFO_MISC_ALWAYS_SETPAR)) { +@@ -2163,17 +2155,16 @@ static bool fbcon_switch(struct vc_data *vc) + fbcon_del_cursor_work(old_info); + } + +- if (!fbcon_is_active(vc, info) || +- ops->blank_state != FB_BLANK_UNBLANK) ++ if (!fbcon_is_active(vc, info) || par->blank_state != FB_BLANK_UNBLANK) + fbcon_del_cursor_work(info); + else + fbcon_add_cursor_work(info); + + set_blitting_type(vc, info); +- ops->cursor_reset = 1; ++ par->cursor_reset = 1; + +- if (ops->rotate_font && ops->rotate_font(info, vc)) { +- ops->rotate = FB_ROTATE_UR; ++ if (par->rotate_font && par->rotate_font(info, vc)) { ++ par->rotate = FB_ROTATE_UR; + set_blitting_type(vc, info); + } + +@@ -2204,8 +2195,8 @@ static bool fbcon_switch(struct vc_data *vc) + scrollback_current = 0; + + if (fbcon_is_active(vc, info)) { +- ops->var.xoffset = ops->var.yoffset = p->yscroll = 0; +- ops->update_start(info); ++ par->var.xoffset = par->var.yoffset = p->yscroll = 0; ++ par->update_start(info); + } + + fbcon_set_palette(vc, color_table); +@@ -2214,7 +2205,7 @@ static bool fbcon_switch(struct vc_data *vc) + if (logo_shown == FBCON_LOGO_DRAW) { + + logo_shown = fg_console; +- fb_show_logo(info, ops->rotate); ++ fb_show_logo(info, par->rotate); + update_region(vc, + vc->vc_origin + vc->vc_size_row * vc->vc_top, + vc->vc_size_row * (vc->vc_bottom - +@@ -2243,27 +2234,27 @@ static bool fbcon_blank(struct vc_data *vc, enum vesa_blank_mode blank, + bool mode_switch) + { + struct fb_info *info = fbcon_info_from_console(vc->vc_num); +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + + if (mode_switch) { + struct fb_var_screeninfo var = info->var; + +- ops->graphics = 1; ++ par->graphics = 1; + + if (!blank) { + var.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE | + FB_ACTIVATE_KD_TEXT; + fb_set_var(info, &var); +- ops->graphics = 0; +- ops->var = info->var; ++ par->graphics = 0; ++ par->var = info->var; + } + } + + if (fbcon_is_active(vc, info)) { +- if (ops->blank_state != blank) { +- ops->blank_state = blank; ++ if (par->blank_state != blank) { ++ par->blank_state = blank; + fbcon_cursor(vc, !blank); +- ops->cursor_flash = (!blank); ++ par->cursor_flash = (!blank); + + if (fb_blank(info, blank)) + fbcon_generic_blank(vc, info, blank); +@@ -2273,8 +2264,7 @@ static bool fbcon_blank(struct vc_data *vc, enum vesa_blank_mode blank, + update_screen(vc); + } + +- if (mode_switch || !fbcon_is_active(vc, info) || +- ops->blank_state != FB_BLANK_UNBLANK) ++ if (mode_switch || !fbcon_is_active(vc, info) || par->blank_state != FB_BLANK_UNBLANK) + fbcon_del_cursor_work(info); + else + fbcon_add_cursor_work(info); +@@ -2285,10 +2275,10 @@ static bool fbcon_blank(struct vc_data *vc, enum vesa_blank_mode blank, + static void fbcon_debug_enter(struct vc_data *vc) + { + struct fb_info *info = fbcon_info_from_console(vc->vc_num); +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + +- ops->save_graphics = ops->graphics; +- ops->graphics = 0; ++ par->save_graphics = par->graphics; ++ par->graphics = 0; + if (info->fbops->fb_debug_enter) + info->fbops->fb_debug_enter(info); + fbcon_set_palette(vc, color_table); +@@ -2297,9 +2287,9 @@ static void fbcon_debug_enter(struct vc_data *vc) + static void fbcon_debug_leave(struct vc_data *vc) + { + struct fb_info *info = fbcon_info_from_console(vc->vc_num); +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + +- ops->graphics = ops->save_graphics; ++ par->graphics = par->save_graphics; + if (info->fbops->fb_debug_leave) + info->fbops->fb_debug_leave(info); + } +@@ -2434,7 +2424,7 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount, + const u8 * data, int userfont) + { + struct fb_info *info = fbcon_info_from_console(vc->vc_num); +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + struct fbcon_display *p = &fb_display[vc->vc_num]; + int resize, ret, old_userfont, old_width, old_height, old_charcount; + u8 *old_data = vc->vc_font.data; +@@ -2460,8 +2450,8 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount, + if (resize) { + int cols, rows; + +- cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); +- rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); ++ cols = FBCON_SWAP(par->rotate, info->var.xres, info->var.yres); ++ rows = FBCON_SWAP(par->rotate, info->var.yres, info->var.xres); + cols /= w; + rows /= h; + ret = vc_resize(vc, cols, rows); +@@ -2660,11 +2650,11 @@ static void fbcon_invert_region(struct vc_data *vc, u16 * p, int cnt) + void fbcon_suspended(struct fb_info *info) + { + struct vc_data *vc = NULL; +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + +- if (!ops || ops->currcon < 0) ++ if (!par || par->currcon < 0) + return; +- vc = vc_cons[ops->currcon].d; ++ vc = vc_cons[par->currcon].d; + + /* Clear cursor, restore saved data */ + fbcon_cursor(vc, false); +@@ -2673,27 +2663,27 @@ void fbcon_suspended(struct fb_info *info) + void fbcon_resumed(struct fb_info *info) + { + struct vc_data *vc; +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + +- if (!ops || ops->currcon < 0) ++ if (!par || par->currcon < 0) + return; +- vc = vc_cons[ops->currcon].d; ++ vc = vc_cons[par->currcon].d; + + update_screen(vc); + } + + static void fbcon_modechanged(struct fb_info *info) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + struct vc_data *vc; + struct fbcon_display *p; + int rows, cols; + +- if (!ops || ops->currcon < 0) ++ if (!par || par->currcon < 0) + return; +- vc = vc_cons[ops->currcon].d; ++ vc = vc_cons[par->currcon].d; + if (vc->vc_mode != KD_TEXT || +- fbcon_info_from_console(ops->currcon) != info) ++ fbcon_info_from_console(par->currcon) != info) + return; + + p = &fb_display[vc->vc_num]; +@@ -2701,8 +2691,8 @@ static void fbcon_modechanged(struct fb_info *info) + + if (con_is_visible(vc)) { + var_to_display(p, &info->var, info); +- cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); +- rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); ++ cols = FBCON_SWAP(par->rotate, info->var.xres, info->var.yres); ++ rows = FBCON_SWAP(par->rotate, info->var.yres, info->var.xres); + cols /= vc->vc_font.width; + rows /= vc->vc_font.height; + vc_resize(vc, cols, rows); +@@ -2711,8 +2701,8 @@ static void fbcon_modechanged(struct fb_info *info) + scrollback_current = 0; + + if (fbcon_is_active(vc, info)) { +- ops->var.xoffset = ops->var.yoffset = p->yscroll = 0; +- ops->update_start(info); ++ par->var.xoffset = par->var.yoffset = p->yscroll = 0; ++ par->update_start(info); + } + + fbcon_set_palette(vc, color_table); +@@ -2722,12 +2712,12 @@ static void fbcon_modechanged(struct fb_info *info) + + static void fbcon_set_all_vcs(struct fb_info *info) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + struct vc_data *vc; + struct fbcon_display *p; + int i, rows, cols, fg = -1; + +- if (!ops || ops->currcon < 0) ++ if (!par || par->currcon < 0) + return; + + for (i = first_fb_vc; i <= last_fb_vc; i++) { +@@ -2744,8 +2734,8 @@ static void fbcon_set_all_vcs(struct fb_info *info) + p = &fb_display[vc->vc_num]; + set_blitting_type(vc, info); + var_to_display(p, &info->var, info); +- cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); +- rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); ++ cols = FBCON_SWAP(par->rotate, info->var.xres, info->var.yres); ++ rows = FBCON_SWAP(par->rotate, info->var.yres, info->var.xres); + cols /= vc->vc_font.width; + rows /= vc->vc_font.height; + vc_resize(vc, cols, rows); +@@ -2768,13 +2758,13 @@ EXPORT_SYMBOL(fbcon_update_vcs); + /* let fbcon check if it supports a new screen resolution */ + int fbcon_modechange_possible(struct fb_info *info, struct fb_var_screeninfo *var) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + struct vc_data *vc; + unsigned int i; + + WARN_CONSOLE_UNLOCKED(); + +- if (!ops) ++ if (!par) + return 0; + + /* prevent setting a screen size which is smaller than font size */ +@@ -3072,15 +3062,14 @@ int fbcon_fb_registered(struct fb_info *info) + + void fbcon_fb_blanked(struct fb_info *info, int blank) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + struct vc_data *vc; + +- if (!ops || ops->currcon < 0) ++ if (!par || par->currcon < 0) + return; + +- vc = vc_cons[ops->currcon].d; +- if (vc->vc_mode != KD_TEXT || +- fbcon_info_from_console(ops->currcon) != info) ++ vc = vc_cons[par->currcon].d; ++ if (vc->vc_mode != KD_TEXT || fbcon_info_from_console(par->currcon) != info) + return; + + if (con_is_visible(vc)) { +@@ -3089,7 +3078,7 @@ void fbcon_fb_blanked(struct fb_info *info, int blank) + else + do_unblank_screen(0); + } +- ops->blank_state = blank; ++ par->blank_state = blank; + } + + void fbcon_new_modelist(struct fb_info *info) +@@ -3279,7 +3268,7 @@ static ssize_t show_cursor_blink(struct device *device, + struct device_attribute *attr, char *buf) + { + struct fb_info *info; +- struct fbcon_ops *ops; ++ struct fbcon_par *par; + int idx, blink = -1; + + console_lock(); +@@ -3289,12 +3278,12 @@ static ssize_t show_cursor_blink(struct device *device, + goto err; + + info = fbcon_registered_fb[idx]; +- ops = info->fbcon_par; ++ par = info->fbcon_par; + +- if (!ops) ++ if (!par) + goto err; + +- blink = delayed_work_pending(&ops->cursor_work); ++ blink = delayed_work_pending(&par->cursor_work); + err: + console_unlock(); + return sysfs_emit(buf, "%d\n", blink); +diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h +index 4d97e6d8a16a2..31ee2d5912219 100644 +--- a/drivers/video/fbdev/core/fbcon.h ++++ b/drivers/video/fbdev/core/fbcon.h +@@ -51,7 +51,7 @@ struct fbcon_display { + const struct fb_videomode *mode; + }; + +-struct fbcon_ops { ++struct fbcon_par { + void (*bmove)(struct vc_data *vc, struct fb_info *info, int sy, + int sx, int dy, int dx, int height, int width); + void (*clear)(struct vc_data *vc, struct fb_info *info, int sy, +@@ -186,7 +186,7 @@ static inline u_short fb_scrollmode(struct fbcon_display *fb) + #ifdef CONFIG_FB_TILEBLITTING + extern void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info); + #endif +-extern void fbcon_set_bitops(struct fbcon_ops *ops); ++extern void fbcon_set_bitops(struct fbcon_par *par); + extern int soft_cursor(struct fb_info *info, struct fb_cursor *cursor); + + #define FBCON_ATTRIBUTE_UNDERLINE 1 +@@ -225,7 +225,7 @@ static inline int get_attribute(struct fb_info *info, u16 c) + (i == FB_ROTATE_UR || i == FB_ROTATE_UD) ? _r : _v; }) + + #ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION +-extern void fbcon_set_rotate(struct fbcon_ops *ops); ++extern void fbcon_set_rotate(struct fbcon_par *par); + #else + #define fbcon_set_rotate(x) do {} while(0) + #endif /* CONFIG_FRAMEBUFFER_CONSOLE_ROTATION */ +diff --git a/drivers/video/fbdev/core/fbcon_ccw.c b/drivers/video/fbdev/core/fbcon_ccw.c +index 89ef4ba7e8672..2ba8ec4c3e2bc 100644 +--- a/drivers/video/fbdev/core/fbcon_ccw.c ++++ b/drivers/video/fbdev/core/fbcon_ccw.c +@@ -63,9 +63,9 @@ static void ccw_update_attr(u8 *dst, u8 *src, int attribute, + static void ccw_bmove(struct vc_data *vc, struct fb_info *info, int sy, + int sx, int dy, int dx, int height, int width) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + struct fb_copyarea area; +- u32 vyres = GETVYRES(ops->p, info); ++ u32 vyres = GETVYRES(par->p, info); + + area.sx = sy * vc->vc_font.height; + area.sy = vyres - ((sx + width) * vc->vc_font.width); +@@ -80,9 +80,9 @@ static void ccw_bmove(struct vc_data *vc, struct fb_info *info, int sy, + static void ccw_clear(struct vc_data *vc, struct fb_info *info, int sy, + int sx, int height, int width, int fg, int bg) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + struct fb_fillrect region; +- u32 vyres = GETVYRES(ops->p, info); ++ u32 vyres = GETVYRES(par->p, info); + + region.color = bg; + region.dx = sy * vc->vc_font.height; +@@ -99,13 +99,13 @@ static inline void ccw_putcs_aligned(struct vc_data *vc, struct fb_info *info, + u32 d_pitch, u32 s_pitch, u32 cellsize, + struct fb_image *image, u8 *buf, u8 *dst) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; + u32 idx = (vc->vc_font.height + 7) >> 3; + u8 *src; + + while (cnt--) { +- src = ops->fontbuffer + (scr_readw(s--) & charmask)*cellsize; ++ src = par->fontbuffer + (scr_readw(s--) & charmask) * cellsize; + + if (attr) { + ccw_update_attr(buf, src, attr, vc); +@@ -130,7 +130,7 @@ static void ccw_putcs(struct vc_data *vc, struct fb_info *info, + int fg, int bg) + { + struct fb_image image; +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + u32 width = (vc->vc_font.height + 7)/8; + u32 cellsize = width * vc->vc_font.width; + u32 maxcnt = info->pixmap.size/cellsize; +@@ -139,9 +139,9 @@ static void ccw_putcs(struct vc_data *vc, struct fb_info *info, + u32 cnt, pitch, size; + u32 attribute = get_attribute(info, scr_readw(s)); + u8 *dst, *buf = NULL; +- u32 vyres = GETVYRES(ops->p, info); ++ u32 vyres = GETVYRES(par->p, info); + +- if (!ops->fontbuffer) ++ if (!par->fontbuffer) + return; + + image.fg_color = fg; +@@ -221,28 +221,28 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + int fg, int bg) + { + struct fb_cursor cursor; +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; + int w = (vc->vc_font.height + 7) >> 3, c; +- int y = real_y(ops->p, vc->state.y); ++ int y = real_y(par->p, vc->state.y); + int attribute, use_sw = vc->vc_cursor_type & CUR_SW; + int err = 1, dx, dy; + char *src; +- u32 vyres = GETVYRES(ops->p, info); ++ u32 vyres = GETVYRES(par->p, info); + +- if (!ops->fontbuffer) ++ if (!par->fontbuffer) + return; + + cursor.set = 0; + + c = scr_readw((u16 *) vc->vc_pos); + attribute = get_attribute(info, c); +- src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.width)); ++ src = par->fontbuffer + ((c & charmask) * (w * vc->vc_font.width)); + +- if (ops->cursor_state.image.data != src || +- ops->cursor_reset) { +- ops->cursor_state.image.data = src; +- cursor.set |= FB_CUR_SETIMAGE; ++ if (par->cursor_state.image.data != src || ++ par->cursor_reset) { ++ par->cursor_state.image.data = src; ++ cursor.set |= FB_CUR_SETIMAGE; + } + + if (attribute) { +@@ -251,49 +251,49 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + dst = kmalloc_array(w, vc->vc_font.width, GFP_ATOMIC); + if (!dst) + return; +- kfree(ops->cursor_data); +- ops->cursor_data = dst; ++ kfree(par->cursor_data); ++ par->cursor_data = dst; + ccw_update_attr(dst, src, attribute, vc); + src = dst; + } + +- if (ops->cursor_state.image.fg_color != fg || +- ops->cursor_state.image.bg_color != bg || +- ops->cursor_reset) { +- ops->cursor_state.image.fg_color = fg; +- ops->cursor_state.image.bg_color = bg; ++ if (par->cursor_state.image.fg_color != fg || ++ par->cursor_state.image.bg_color != bg || ++ par->cursor_reset) { ++ par->cursor_state.image.fg_color = fg; ++ par->cursor_state.image.bg_color = bg; + cursor.set |= FB_CUR_SETCMAP; + } + +- if (ops->cursor_state.image.height != vc->vc_font.width || +- ops->cursor_state.image.width != vc->vc_font.height || +- ops->cursor_reset) { +- ops->cursor_state.image.height = vc->vc_font.width; +- ops->cursor_state.image.width = vc->vc_font.height; ++ if (par->cursor_state.image.height != vc->vc_font.width || ++ par->cursor_state.image.width != vc->vc_font.height || ++ par->cursor_reset) { ++ par->cursor_state.image.height = vc->vc_font.width; ++ par->cursor_state.image.width = vc->vc_font.height; + cursor.set |= FB_CUR_SETSIZE; + } + + dx = y * vc->vc_font.height; + dy = vyres - ((vc->state.x + 1) * vc->vc_font.width); + +- if (ops->cursor_state.image.dx != dx || +- ops->cursor_state.image.dy != dy || +- ops->cursor_reset) { +- ops->cursor_state.image.dx = dx; +- ops->cursor_state.image.dy = dy; ++ if (par->cursor_state.image.dx != dx || ++ par->cursor_state.image.dy != dy || ++ par->cursor_reset) { ++ par->cursor_state.image.dx = dx; ++ par->cursor_state.image.dy = dy; + cursor.set |= FB_CUR_SETPOS; + } + +- if (ops->cursor_state.hot.x || ops->cursor_state.hot.y || +- ops->cursor_reset) { +- ops->cursor_state.hot.x = cursor.hot.y = 0; ++ if (par->cursor_state.hot.x || par->cursor_state.hot.y || ++ par->cursor_reset) { ++ par->cursor_state.hot.x = cursor.hot.y = 0; + cursor.set |= FB_CUR_SETHOT; + } + + if (cursor.set & FB_CUR_SETSIZE || +- vc->vc_cursor_type != ops->p->cursor_shape || +- ops->cursor_state.mask == NULL || +- ops->cursor_reset) { ++ vc->vc_cursor_type != par->p->cursor_shape || ++ par->cursor_state.mask == NULL || ++ par->cursor_reset) { + char *tmp, *mask = kmalloc_array(w, vc->vc_font.width, + GFP_ATOMIC); + int cur_height, size, i = 0; +@@ -309,13 +309,13 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + return; + } + +- kfree(ops->cursor_state.mask); +- ops->cursor_state.mask = mask; ++ kfree(par->cursor_state.mask); ++ par->cursor_state.mask = mask; + +- ops->p->cursor_shape = vc->vc_cursor_type; ++ par->p->cursor_shape = vc->vc_cursor_type; + cursor.set |= FB_CUR_SETSHAPE; + +- switch (CUR_SIZE(ops->p->cursor_shape)) { ++ switch (CUR_SIZE(par->p->cursor_shape)) { + case CUR_NONE: + cur_height = 0; + break; +@@ -348,19 +348,19 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + kfree(tmp); + } + +- ops->cursor_state.enable = enable && !use_sw; ++ par->cursor_state.enable = enable && !use_sw; + + cursor.image.data = src; +- cursor.image.fg_color = ops->cursor_state.image.fg_color; +- cursor.image.bg_color = ops->cursor_state.image.bg_color; +- cursor.image.dx = ops->cursor_state.image.dx; +- cursor.image.dy = ops->cursor_state.image.dy; +- cursor.image.height = ops->cursor_state.image.height; +- cursor.image.width = ops->cursor_state.image.width; +- cursor.hot.x = ops->cursor_state.hot.x; +- cursor.hot.y = ops->cursor_state.hot.y; +- cursor.mask = ops->cursor_state.mask; +- cursor.enable = ops->cursor_state.enable; ++ cursor.image.fg_color = par->cursor_state.image.fg_color; ++ cursor.image.bg_color = par->cursor_state.image.bg_color; ++ cursor.image.dx = par->cursor_state.image.dx; ++ cursor.image.dy = par->cursor_state.image.dy; ++ cursor.image.height = par->cursor_state.image.height; ++ cursor.image.width = par->cursor_state.image.width; ++ cursor.hot.x = par->cursor_state.hot.x; ++ cursor.hot.y = par->cursor_state.hot.y; ++ cursor.mask = par->cursor_state.mask; ++ cursor.enable = par->cursor_state.enable; + cursor.image.depth = 1; + cursor.rop = ROP_XOR; + +@@ -370,32 +370,32 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + if (err) + soft_cursor(info, &cursor); + +- ops->cursor_reset = 0; ++ par->cursor_reset = 0; + } + + static int ccw_update_start(struct fb_info *info) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + u32 yoffset; +- u32 vyres = GETVYRES(ops->p, info); ++ u32 vyres = GETVYRES(par->p, info); + int err; + +- yoffset = (vyres - info->var.yres) - ops->var.xoffset; +- ops->var.xoffset = ops->var.yoffset; +- ops->var.yoffset = yoffset; +- err = fb_pan_display(info, &ops->var); +- ops->var.xoffset = info->var.xoffset; +- ops->var.yoffset = info->var.yoffset; +- ops->var.vmode = info->var.vmode; ++ yoffset = (vyres - info->var.yres) - par->var.xoffset; ++ par->var.xoffset = par->var.yoffset; ++ par->var.yoffset = yoffset; ++ err = fb_pan_display(info, &par->var); ++ par->var.xoffset = info->var.xoffset; ++ par->var.yoffset = info->var.yoffset; ++ par->var.vmode = info->var.vmode; + return err; + } + +-void fbcon_rotate_ccw(struct fbcon_ops *ops) ++void fbcon_rotate_ccw(struct fbcon_par *par) + { +- ops->bmove = ccw_bmove; +- ops->clear = ccw_clear; +- ops->putcs = ccw_putcs; +- ops->clear_margins = ccw_clear_margins; +- ops->cursor = ccw_cursor; +- ops->update_start = ccw_update_start; ++ par->bmove = ccw_bmove; ++ par->clear = ccw_clear; ++ par->putcs = ccw_putcs; ++ par->clear_margins = ccw_clear_margins; ++ par->cursor = ccw_cursor; ++ par->update_start = ccw_update_start; + } +diff --git a/drivers/video/fbdev/core/fbcon_cw.c b/drivers/video/fbdev/core/fbcon_cw.c +index b9dac7940fb77..4bd22d5ee5f41 100644 +--- a/drivers/video/fbdev/core/fbcon_cw.c ++++ b/drivers/video/fbdev/core/fbcon_cw.c +@@ -48,9 +48,9 @@ static void cw_update_attr(u8 *dst, u8 *src, int attribute, + static void cw_bmove(struct vc_data *vc, struct fb_info *info, int sy, + int sx, int dy, int dx, int height, int width) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + struct fb_copyarea area; +- u32 vxres = GETVXRES(ops->p, info); ++ u32 vxres = GETVXRES(par->p, info); + + area.sx = vxres - ((sy + height) * vc->vc_font.height); + area.sy = sx * vc->vc_font.width; +@@ -65,9 +65,9 @@ static void cw_bmove(struct vc_data *vc, struct fb_info *info, int sy, + static void cw_clear(struct vc_data *vc, struct fb_info *info, int sy, + int sx, int height, int width, int fg, int bg) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + struct fb_fillrect region; +- u32 vxres = GETVXRES(ops->p, info); ++ u32 vxres = GETVXRES(par->p, info); + + region.color = bg; + region.dx = vxres - ((sy + height) * vc->vc_font.height); +@@ -84,13 +84,13 @@ static inline void cw_putcs_aligned(struct vc_data *vc, struct fb_info *info, + u32 d_pitch, u32 s_pitch, u32 cellsize, + struct fb_image *image, u8 *buf, u8 *dst) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; + u32 idx = (vc->vc_font.height + 7) >> 3; + u8 *src; + + while (cnt--) { +- src = ops->fontbuffer + (scr_readw(s++) & charmask)*cellsize; ++ src = par->fontbuffer + (scr_readw(s++) & charmask) * cellsize; + + if (attr) { + cw_update_attr(buf, src, attr, vc); +@@ -115,7 +115,7 @@ static void cw_putcs(struct vc_data *vc, struct fb_info *info, + int fg, int bg) + { + struct fb_image image; +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + u32 width = (vc->vc_font.height + 7)/8; + u32 cellsize = width * vc->vc_font.width; + u32 maxcnt = info->pixmap.size/cellsize; +@@ -124,9 +124,9 @@ static void cw_putcs(struct vc_data *vc, struct fb_info *info, + u32 cnt, pitch, size; + u32 attribute = get_attribute(info, scr_readw(s)); + u8 *dst, *buf = NULL; +- u32 vxres = GETVXRES(ops->p, info); ++ u32 vxres = GETVXRES(par->p, info); + +- if (!ops->fontbuffer) ++ if (!par->fontbuffer) + return; + + image.fg_color = fg; +@@ -204,28 +204,28 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + int fg, int bg) + { + struct fb_cursor cursor; +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; + int w = (vc->vc_font.height + 7) >> 3, c; +- int y = real_y(ops->p, vc->state.y); ++ int y = real_y(par->p, vc->state.y); + int attribute, use_sw = vc->vc_cursor_type & CUR_SW; + int err = 1, dx, dy; + char *src; +- u32 vxres = GETVXRES(ops->p, info); ++ u32 vxres = GETVXRES(par->p, info); + +- if (!ops->fontbuffer) ++ if (!par->fontbuffer) + return; + + cursor.set = 0; + + c = scr_readw((u16 *) vc->vc_pos); + attribute = get_attribute(info, c); +- src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.width)); ++ src = par->fontbuffer + ((c & charmask) * (w * vc->vc_font.width)); + +- if (ops->cursor_state.image.data != src || +- ops->cursor_reset) { +- ops->cursor_state.image.data = src; +- cursor.set |= FB_CUR_SETIMAGE; ++ if (par->cursor_state.image.data != src || ++ par->cursor_reset) { ++ par->cursor_state.image.data = src; ++ cursor.set |= FB_CUR_SETIMAGE; + } + + if (attribute) { +@@ -234,49 +234,49 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + dst = kmalloc_array(w, vc->vc_font.width, GFP_ATOMIC); + if (!dst) + return; +- kfree(ops->cursor_data); +- ops->cursor_data = dst; ++ kfree(par->cursor_data); ++ par->cursor_data = dst; + cw_update_attr(dst, src, attribute, vc); + src = dst; + } + +- if (ops->cursor_state.image.fg_color != fg || +- ops->cursor_state.image.bg_color != bg || +- ops->cursor_reset) { +- ops->cursor_state.image.fg_color = fg; +- ops->cursor_state.image.bg_color = bg; ++ if (par->cursor_state.image.fg_color != fg || ++ par->cursor_state.image.bg_color != bg || ++ par->cursor_reset) { ++ par->cursor_state.image.fg_color = fg; ++ par->cursor_state.image.bg_color = bg; + cursor.set |= FB_CUR_SETCMAP; + } + +- if (ops->cursor_state.image.height != vc->vc_font.width || +- ops->cursor_state.image.width != vc->vc_font.height || +- ops->cursor_reset) { +- ops->cursor_state.image.height = vc->vc_font.width; +- ops->cursor_state.image.width = vc->vc_font.height; ++ if (par->cursor_state.image.height != vc->vc_font.width || ++ par->cursor_state.image.width != vc->vc_font.height || ++ par->cursor_reset) { ++ par->cursor_state.image.height = vc->vc_font.width; ++ par->cursor_state.image.width = vc->vc_font.height; + cursor.set |= FB_CUR_SETSIZE; + } + + dx = vxres - ((y * vc->vc_font.height) + vc->vc_font.height); + dy = vc->state.x * vc->vc_font.width; + +- if (ops->cursor_state.image.dx != dx || +- ops->cursor_state.image.dy != dy || +- ops->cursor_reset) { +- ops->cursor_state.image.dx = dx; +- ops->cursor_state.image.dy = dy; ++ if (par->cursor_state.image.dx != dx || ++ par->cursor_state.image.dy != dy || ++ par->cursor_reset) { ++ par->cursor_state.image.dx = dx; ++ par->cursor_state.image.dy = dy; + cursor.set |= FB_CUR_SETPOS; + } + +- if (ops->cursor_state.hot.x || ops->cursor_state.hot.y || +- ops->cursor_reset) { +- ops->cursor_state.hot.x = cursor.hot.y = 0; ++ if (par->cursor_state.hot.x || par->cursor_state.hot.y || ++ par->cursor_reset) { ++ par->cursor_state.hot.x = cursor.hot.y = 0; + cursor.set |= FB_CUR_SETHOT; + } + + if (cursor.set & FB_CUR_SETSIZE || +- vc->vc_cursor_type != ops->p->cursor_shape || +- ops->cursor_state.mask == NULL || +- ops->cursor_reset) { ++ vc->vc_cursor_type != par->p->cursor_shape || ++ par->cursor_state.mask == NULL || ++ par->cursor_reset) { + char *tmp, *mask = kmalloc_array(w, vc->vc_font.width, + GFP_ATOMIC); + int cur_height, size, i = 0; +@@ -292,13 +292,13 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + return; + } + +- kfree(ops->cursor_state.mask); +- ops->cursor_state.mask = mask; ++ kfree(par->cursor_state.mask); ++ par->cursor_state.mask = mask; + +- ops->p->cursor_shape = vc->vc_cursor_type; ++ par->p->cursor_shape = vc->vc_cursor_type; + cursor.set |= FB_CUR_SETSHAPE; + +- switch (CUR_SIZE(ops->p->cursor_shape)) { ++ switch (CUR_SIZE(par->p->cursor_shape)) { + case CUR_NONE: + cur_height = 0; + break; +@@ -331,19 +331,19 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + kfree(tmp); + } + +- ops->cursor_state.enable = enable && !use_sw; ++ par->cursor_state.enable = enable && !use_sw; + + cursor.image.data = src; +- cursor.image.fg_color = ops->cursor_state.image.fg_color; +- cursor.image.bg_color = ops->cursor_state.image.bg_color; +- cursor.image.dx = ops->cursor_state.image.dx; +- cursor.image.dy = ops->cursor_state.image.dy; +- cursor.image.height = ops->cursor_state.image.height; +- cursor.image.width = ops->cursor_state.image.width; +- cursor.hot.x = ops->cursor_state.hot.x; +- cursor.hot.y = ops->cursor_state.hot.y; +- cursor.mask = ops->cursor_state.mask; +- cursor.enable = ops->cursor_state.enable; ++ cursor.image.fg_color = par->cursor_state.image.fg_color; ++ cursor.image.bg_color = par->cursor_state.image.bg_color; ++ cursor.image.dx = par->cursor_state.image.dx; ++ cursor.image.dy = par->cursor_state.image.dy; ++ cursor.image.height = par->cursor_state.image.height; ++ cursor.image.width = par->cursor_state.image.width; ++ cursor.hot.x = par->cursor_state.hot.x; ++ cursor.hot.y = par->cursor_state.hot.y; ++ cursor.mask = par->cursor_state.mask; ++ cursor.enable = par->cursor_state.enable; + cursor.image.depth = 1; + cursor.rop = ROP_XOR; + +@@ -353,32 +353,32 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + if (err) + soft_cursor(info, &cursor); + +- ops->cursor_reset = 0; ++ par->cursor_reset = 0; + } + + static int cw_update_start(struct fb_info *info) + { +- struct fbcon_ops *ops = info->fbcon_par; +- u32 vxres = GETVXRES(ops->p, info); ++ struct fbcon_par *par = info->fbcon_par; ++ u32 vxres = GETVXRES(par->p, info); + u32 xoffset; + int err; + +- xoffset = vxres - (info->var.xres + ops->var.yoffset); +- ops->var.yoffset = ops->var.xoffset; +- ops->var.xoffset = xoffset; +- err = fb_pan_display(info, &ops->var); +- ops->var.xoffset = info->var.xoffset; +- ops->var.yoffset = info->var.yoffset; +- ops->var.vmode = info->var.vmode; ++ xoffset = vxres - (info->var.xres + par->var.yoffset); ++ par->var.yoffset = par->var.xoffset; ++ par->var.xoffset = xoffset; ++ err = fb_pan_display(info, &par->var); ++ par->var.xoffset = info->var.xoffset; ++ par->var.yoffset = info->var.yoffset; ++ par->var.vmode = info->var.vmode; + return err; + } + +-void fbcon_rotate_cw(struct fbcon_ops *ops) ++void fbcon_rotate_cw(struct fbcon_par *par) + { +- ops->bmove = cw_bmove; +- ops->clear = cw_clear; +- ops->putcs = cw_putcs; +- ops->clear_margins = cw_clear_margins; +- ops->cursor = cw_cursor; +- ops->update_start = cw_update_start; ++ par->bmove = cw_bmove; ++ par->clear = cw_clear; ++ par->putcs = cw_putcs; ++ par->clear_margins = cw_clear_margins; ++ par->cursor = cw_cursor; ++ par->update_start = cw_update_start; + } +diff --git a/drivers/video/fbdev/core/fbcon_rotate.c b/drivers/video/fbdev/core/fbcon_rotate.c +index ec3c883400f7b..380b2746451a1 100644 +--- a/drivers/video/fbdev/core/fbcon_rotate.c ++++ b/drivers/video/fbdev/core/fbcon_rotate.c +@@ -20,32 +20,32 @@ + + static int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + int len, err = 0; + int s_cellsize, d_cellsize, i; + const u8 *src; + u8 *dst; + +- if (vc->vc_font.data == ops->fontdata && +- ops->p->con_rotate == ops->cur_rotate) ++ if (vc->vc_font.data == par->fontdata && ++ par->p->con_rotate == par->cur_rotate) + goto finished; + +- src = ops->fontdata = vc->vc_font.data; +- ops->cur_rotate = ops->p->con_rotate; ++ src = par->fontdata = vc->vc_font.data; ++ par->cur_rotate = par->p->con_rotate; + len = vc->vc_font.charcount; + s_cellsize = ((vc->vc_font.width + 7)/8) * + vc->vc_font.height; + d_cellsize = s_cellsize; + +- if (ops->rotate == FB_ROTATE_CW || +- ops->rotate == FB_ROTATE_CCW) ++ if (par->rotate == FB_ROTATE_CW || ++ par->rotate == FB_ROTATE_CCW) + d_cellsize = ((vc->vc_font.height + 7)/8) * + vc->vc_font.width; + + if (info->fbops->fb_sync) + info->fbops->fb_sync(info); + +- if (ops->fd_size < d_cellsize * len) { ++ if (par->fd_size < d_cellsize * len) { + dst = kmalloc_array(len, d_cellsize, GFP_KERNEL); + + if (dst == NULL) { +@@ -53,15 +53,15 @@ static int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc) + goto finished; + } + +- ops->fd_size = d_cellsize * len; +- kfree(ops->fontbuffer); +- ops->fontbuffer = dst; ++ par->fd_size = d_cellsize * len; ++ kfree(par->fontbuffer); ++ par->fontbuffer = dst; + } + +- dst = ops->fontbuffer; +- memset(dst, 0, ops->fd_size); ++ dst = par->fontbuffer; ++ memset(dst, 0, par->fd_size); + +- switch (ops->rotate) { ++ switch (par->rotate) { + case FB_ROTATE_UD: + for (i = len; i--; ) { + rotate_ud(src, dst, vc->vc_font.width, +@@ -93,19 +93,19 @@ static int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc) + return err; + } + +-void fbcon_set_rotate(struct fbcon_ops *ops) ++void fbcon_set_rotate(struct fbcon_par *par) + { +- ops->rotate_font = fbcon_rotate_font; ++ par->rotate_font = fbcon_rotate_font; + +- switch(ops->rotate) { ++ switch (par->rotate) { + case FB_ROTATE_CW: +- fbcon_rotate_cw(ops); ++ fbcon_rotate_cw(par); + break; + case FB_ROTATE_UD: +- fbcon_rotate_ud(ops); ++ fbcon_rotate_ud(par); + break; + case FB_ROTATE_CCW: +- fbcon_rotate_ccw(ops); ++ fbcon_rotate_ccw(par); + break; + } + } +diff --git a/drivers/video/fbdev/core/fbcon_rotate.h b/drivers/video/fbdev/core/fbcon_rotate.h +index 01cbe303b8a29..48305e1a07631 100644 +--- a/drivers/video/fbdev/core/fbcon_rotate.h ++++ b/drivers/video/fbdev/core/fbcon_rotate.h +@@ -90,7 +90,7 @@ static inline void rotate_ccw(const char *in, char *out, u32 width, u32 height) + } + } + +-extern void fbcon_rotate_cw(struct fbcon_ops *ops); +-extern void fbcon_rotate_ud(struct fbcon_ops *ops); +-extern void fbcon_rotate_ccw(struct fbcon_ops *ops); ++extern void fbcon_rotate_cw(struct fbcon_par *par); ++extern void fbcon_rotate_ud(struct fbcon_par *par); ++extern void fbcon_rotate_ccw(struct fbcon_par *par); + #endif +diff --git a/drivers/video/fbdev/core/fbcon_ud.c b/drivers/video/fbdev/core/fbcon_ud.c +index 0af7913a2abdc..14b40e2bf323f 100644 +--- a/drivers/video/fbdev/core/fbcon_ud.c ++++ b/drivers/video/fbdev/core/fbcon_ud.c +@@ -48,10 +48,10 @@ static void ud_update_attr(u8 *dst, u8 *src, int attribute, + static void ud_bmove(struct vc_data *vc, struct fb_info *info, int sy, + int sx, int dy, int dx, int height, int width) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + struct fb_copyarea area; +- u32 vyres = GETVYRES(ops->p, info); +- u32 vxres = GETVXRES(ops->p, info); ++ u32 vyres = GETVYRES(par->p, info); ++ u32 vxres = GETVXRES(par->p, info); + + area.sy = vyres - ((sy + height) * vc->vc_font.height); + area.sx = vxres - ((sx + width) * vc->vc_font.width); +@@ -66,10 +66,10 @@ static void ud_bmove(struct vc_data *vc, struct fb_info *info, int sy, + static void ud_clear(struct vc_data *vc, struct fb_info *info, int sy, + int sx, int height, int width, int fg, int bg) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + struct fb_fillrect region; +- u32 vyres = GETVYRES(ops->p, info); +- u32 vxres = GETVXRES(ops->p, info); ++ u32 vyres = GETVYRES(par->p, info); ++ u32 vxres = GETVXRES(par->p, info); + + region.color = bg; + region.dy = vyres - ((sy + height) * vc->vc_font.height); +@@ -86,13 +86,13 @@ static inline void ud_putcs_aligned(struct vc_data *vc, struct fb_info *info, + u32 d_pitch, u32 s_pitch, u32 cellsize, + struct fb_image *image, u8 *buf, u8 *dst) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; + u32 idx = vc->vc_font.width >> 3; + u8 *src; + + while (cnt--) { +- src = ops->fontbuffer + (scr_readw(s--) & charmask)*cellsize; ++ src = par->fontbuffer + (scr_readw(s--) & charmask) * cellsize; + + if (attr) { + ud_update_attr(buf, src, attr, vc); +@@ -119,7 +119,7 @@ static inline void ud_putcs_unaligned(struct vc_data *vc, + struct fb_image *image, u8 *buf, + u8 *dst) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; + u32 shift_low = 0, mod = vc->vc_font.width % 8; + u32 shift_high = 8; +@@ -127,7 +127,7 @@ static inline void ud_putcs_unaligned(struct vc_data *vc, + u8 *src; + + while (cnt--) { +- src = ops->fontbuffer + (scr_readw(s--) & charmask)*cellsize; ++ src = par->fontbuffer + (scr_readw(s--) & charmask) * cellsize; + + if (attr) { + ud_update_attr(buf, src, attr, vc); +@@ -152,7 +152,7 @@ static void ud_putcs(struct vc_data *vc, struct fb_info *info, + int fg, int bg) + { + struct fb_image image; +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + u32 width = (vc->vc_font.width + 7)/8; + u32 cellsize = width * vc->vc_font.height; + u32 maxcnt = info->pixmap.size/cellsize; +@@ -161,10 +161,10 @@ static void ud_putcs(struct vc_data *vc, struct fb_info *info, + u32 mod = vc->vc_font.width % 8, cnt, pitch, size; + u32 attribute = get_attribute(info, scr_readw(s)); + u8 *dst, *buf = NULL; +- u32 vyres = GETVYRES(ops->p, info); +- u32 vxres = GETVXRES(ops->p, info); ++ u32 vyres = GETVYRES(par->p, info); ++ u32 vxres = GETVXRES(par->p, info); + +- if (!ops->fontbuffer) ++ if (!par->fontbuffer) + return; + + image.fg_color = fg; +@@ -251,29 +251,29 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + int fg, int bg) + { + struct fb_cursor cursor; +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; + int w = (vc->vc_font.width + 7) >> 3, c; +- int y = real_y(ops->p, vc->state.y); ++ int y = real_y(par->p, vc->state.y); + int attribute, use_sw = vc->vc_cursor_type & CUR_SW; + int err = 1, dx, dy; + char *src; +- u32 vyres = GETVYRES(ops->p, info); +- u32 vxres = GETVXRES(ops->p, info); ++ u32 vyres = GETVYRES(par->p, info); ++ u32 vxres = GETVXRES(par->p, info); + +- if (!ops->fontbuffer) ++ if (!par->fontbuffer) + return; + + cursor.set = 0; + + c = scr_readw((u16 *) vc->vc_pos); + attribute = get_attribute(info, c); +- src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.height)); ++ src = par->fontbuffer + ((c & charmask) * (w * vc->vc_font.height)); + +- if (ops->cursor_state.image.data != src || +- ops->cursor_reset) { +- ops->cursor_state.image.data = src; +- cursor.set |= FB_CUR_SETIMAGE; ++ if (par->cursor_state.image.data != src || ++ par->cursor_reset) { ++ par->cursor_state.image.data = src; ++ cursor.set |= FB_CUR_SETIMAGE; + } + + if (attribute) { +@@ -282,49 +282,49 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + dst = kmalloc_array(w, vc->vc_font.height, GFP_ATOMIC); + if (!dst) + return; +- kfree(ops->cursor_data); +- ops->cursor_data = dst; ++ kfree(par->cursor_data); ++ par->cursor_data = dst; + ud_update_attr(dst, src, attribute, vc); + src = dst; + } + +- if (ops->cursor_state.image.fg_color != fg || +- ops->cursor_state.image.bg_color != bg || +- ops->cursor_reset) { +- ops->cursor_state.image.fg_color = fg; +- ops->cursor_state.image.bg_color = bg; ++ if (par->cursor_state.image.fg_color != fg || ++ par->cursor_state.image.bg_color != bg || ++ par->cursor_reset) { ++ par->cursor_state.image.fg_color = fg; ++ par->cursor_state.image.bg_color = bg; + cursor.set |= FB_CUR_SETCMAP; + } + +- if (ops->cursor_state.image.height != vc->vc_font.height || +- ops->cursor_state.image.width != vc->vc_font.width || +- ops->cursor_reset) { +- ops->cursor_state.image.height = vc->vc_font.height; +- ops->cursor_state.image.width = vc->vc_font.width; ++ if (par->cursor_state.image.height != vc->vc_font.height || ++ par->cursor_state.image.width != vc->vc_font.width || ++ par->cursor_reset) { ++ par->cursor_state.image.height = vc->vc_font.height; ++ par->cursor_state.image.width = vc->vc_font.width; + cursor.set |= FB_CUR_SETSIZE; + } + + dy = vyres - ((y * vc->vc_font.height) + vc->vc_font.height); + dx = vxres - ((vc->state.x * vc->vc_font.width) + vc->vc_font.width); + +- if (ops->cursor_state.image.dx != dx || +- ops->cursor_state.image.dy != dy || +- ops->cursor_reset) { +- ops->cursor_state.image.dx = dx; +- ops->cursor_state.image.dy = dy; ++ if (par->cursor_state.image.dx != dx || ++ par->cursor_state.image.dy != dy || ++ par->cursor_reset) { ++ par->cursor_state.image.dx = dx; ++ par->cursor_state.image.dy = dy; + cursor.set |= FB_CUR_SETPOS; + } + +- if (ops->cursor_state.hot.x || ops->cursor_state.hot.y || +- ops->cursor_reset) { +- ops->cursor_state.hot.x = cursor.hot.y = 0; ++ if (par->cursor_state.hot.x || par->cursor_state.hot.y || ++ par->cursor_reset) { ++ par->cursor_state.hot.x = cursor.hot.y = 0; + cursor.set |= FB_CUR_SETHOT; + } + + if (cursor.set & FB_CUR_SETSIZE || +- vc->vc_cursor_type != ops->p->cursor_shape || +- ops->cursor_state.mask == NULL || +- ops->cursor_reset) { ++ vc->vc_cursor_type != par->p->cursor_shape || ++ par->cursor_state.mask == NULL || ++ par->cursor_reset) { + char *mask = kmalloc_array(w, vc->vc_font.height, GFP_ATOMIC); + int cur_height, size, i = 0; + u8 msk = 0xff; +@@ -332,13 +332,13 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + if (!mask) + return; + +- kfree(ops->cursor_state.mask); +- ops->cursor_state.mask = mask; ++ kfree(par->cursor_state.mask); ++ par->cursor_state.mask = mask; + +- ops->p->cursor_shape = vc->vc_cursor_type; ++ par->p->cursor_shape = vc->vc_cursor_type; + cursor.set |= FB_CUR_SETSHAPE; + +- switch (CUR_SIZE(ops->p->cursor_shape)) { ++ switch (CUR_SIZE(par->p->cursor_shape)) { + case CUR_NONE: + cur_height = 0; + break; +@@ -371,19 +371,19 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + mask[i++] = ~msk; + } + +- ops->cursor_state.enable = enable && !use_sw; ++ par->cursor_state.enable = enable && !use_sw; + + cursor.image.data = src; +- cursor.image.fg_color = ops->cursor_state.image.fg_color; +- cursor.image.bg_color = ops->cursor_state.image.bg_color; +- cursor.image.dx = ops->cursor_state.image.dx; +- cursor.image.dy = ops->cursor_state.image.dy; +- cursor.image.height = ops->cursor_state.image.height; +- cursor.image.width = ops->cursor_state.image.width; +- cursor.hot.x = ops->cursor_state.hot.x; +- cursor.hot.y = ops->cursor_state.hot.y; +- cursor.mask = ops->cursor_state.mask; +- cursor.enable = ops->cursor_state.enable; ++ cursor.image.fg_color = par->cursor_state.image.fg_color; ++ cursor.image.bg_color = par->cursor_state.image.bg_color; ++ cursor.image.dx = par->cursor_state.image.dx; ++ cursor.image.dy = par->cursor_state.image.dy; ++ cursor.image.height = par->cursor_state.image.height; ++ cursor.image.width = par->cursor_state.image.width; ++ cursor.hot.x = par->cursor_state.hot.x; ++ cursor.hot.y = par->cursor_state.hot.y; ++ cursor.mask = par->cursor_state.mask; ++ cursor.enable = par->cursor_state.enable; + cursor.image.depth = 1; + cursor.rop = ROP_XOR; + +@@ -393,36 +393,36 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + if (err) + soft_cursor(info, &cursor); + +- ops->cursor_reset = 0; ++ par->cursor_reset = 0; + } + + static int ud_update_start(struct fb_info *info) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + int xoffset, yoffset; +- u32 vyres = GETVYRES(ops->p, info); +- u32 vxres = GETVXRES(ops->p, info); ++ u32 vyres = GETVYRES(par->p, info); ++ u32 vxres = GETVXRES(par->p, info); + int err; + +- xoffset = vxres - info->var.xres - ops->var.xoffset; +- yoffset = vyres - info->var.yres - ops->var.yoffset; ++ xoffset = vxres - info->var.xres - par->var.xoffset; ++ yoffset = vyres - info->var.yres - par->var.yoffset; + if (yoffset < 0) + yoffset += vyres; +- ops->var.xoffset = xoffset; +- ops->var.yoffset = yoffset; +- err = fb_pan_display(info, &ops->var); +- ops->var.xoffset = info->var.xoffset; +- ops->var.yoffset = info->var.yoffset; +- ops->var.vmode = info->var.vmode; ++ par->var.xoffset = xoffset; ++ par->var.yoffset = yoffset; ++ err = fb_pan_display(info, &par->var); ++ par->var.xoffset = info->var.xoffset; ++ par->var.yoffset = info->var.yoffset; ++ par->var.vmode = info->var.vmode; + return err; + } + +-void fbcon_rotate_ud(struct fbcon_ops *ops) ++void fbcon_rotate_ud(struct fbcon_par *par) + { +- ops->bmove = ud_bmove; +- ops->clear = ud_clear; +- ops->putcs = ud_putcs; +- ops->clear_margins = ud_clear_margins; +- ops->cursor = ud_cursor; +- ops->update_start = ud_update_start; ++ par->bmove = ud_bmove; ++ par->clear = ud_clear; ++ par->putcs = ud_putcs; ++ par->clear_margins = ud_clear_margins; ++ par->cursor = ud_cursor; ++ par->update_start = ud_update_start; + } +diff --git a/drivers/video/fbdev/core/softcursor.c b/drivers/video/fbdev/core/softcursor.c +index 29e5b21cf373e..900788c059153 100644 +--- a/drivers/video/fbdev/core/softcursor.c ++++ b/drivers/video/fbdev/core/softcursor.c +@@ -21,7 +21,7 @@ + + int soft_cursor(struct fb_info *info, struct fb_cursor *cursor) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + unsigned int scan_align = info->pixmap.scan_align - 1; + unsigned int buf_align = info->pixmap.buf_align - 1; + unsigned int i, size, dsize, s_pitch, d_pitch; +@@ -34,19 +34,19 @@ int soft_cursor(struct fb_info *info, struct fb_cursor *cursor) + s_pitch = (cursor->image.width + 7) >> 3; + dsize = s_pitch * cursor->image.height; + +- if (dsize + sizeof(struct fb_image) != ops->cursor_size) { +- kfree(ops->cursor_src); +- ops->cursor_size = dsize + sizeof(struct fb_image); ++ if (dsize + sizeof(struct fb_image) != par->cursor_size) { ++ kfree(par->cursor_src); ++ par->cursor_size = dsize + sizeof(struct fb_image); + +- ops->cursor_src = kmalloc(ops->cursor_size, GFP_ATOMIC); +- if (!ops->cursor_src) { +- ops->cursor_size = 0; ++ par->cursor_src = kmalloc(par->cursor_size, GFP_ATOMIC); ++ if (!par->cursor_src) { ++ par->cursor_size = 0; + return -ENOMEM; + } + } + +- src = ops->cursor_src + sizeof(struct fb_image); +- image = (struct fb_image *)ops->cursor_src; ++ src = par->cursor_src + sizeof(struct fb_image); ++ image = (struct fb_image *)par->cursor_src; + *image = cursor->image; + d_pitch = (s_pitch + scan_align) & ~scan_align; + +diff --git a/drivers/video/fbdev/core/tileblit.c b/drivers/video/fbdev/core/tileblit.c +index d342b90c42b7f..4428f2bcd3f8c 100644 +--- a/drivers/video/fbdev/core/tileblit.c ++++ b/drivers/video/fbdev/core/tileblit.c +@@ -151,34 +151,34 @@ static void tile_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + + static int tile_update_start(struct fb_info *info) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + int err; + +- err = fb_pan_display(info, &ops->var); +- ops->var.xoffset = info->var.xoffset; +- ops->var.yoffset = info->var.yoffset; +- ops->var.vmode = info->var.vmode; ++ err = fb_pan_display(info, &par->var); ++ par->var.xoffset = info->var.xoffset; ++ par->var.yoffset = info->var.yoffset; ++ par->var.vmode = info->var.vmode; + return err; + } + + void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info) + { + struct fb_tilemap map; +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + +- ops->bmove = tile_bmove; +- ops->clear = tile_clear; +- ops->putcs = tile_putcs; +- ops->clear_margins = tile_clear_margins; +- ops->cursor = tile_cursor; +- ops->update_start = tile_update_start; ++ par->bmove = tile_bmove; ++ par->clear = tile_clear; ++ par->putcs = tile_putcs; ++ par->clear_margins = tile_clear_margins; ++ par->cursor = tile_cursor; ++ par->update_start = tile_update_start; + +- if (ops->p) { ++ if (par->p) { + map.width = vc->vc_font.width; + map.height = vc->vc_font.height; + map.depth = 1; + map.length = vc->vc_font.charcount; +- map.data = ops->p->fontdata; ++ map.data = par->p->fontdata; + info->tileops->fb_settile(info, &map); + } + } +-- +2.51.0 + diff --git a/queue-6.12/fbcon-set-rotate_font-callback-with-related-callback.patch b/queue-6.12/fbcon-set-rotate_font-callback-with-related-callback.patch new file mode 100644 index 0000000000..147698910c --- /dev/null +++ b/queue-6.12/fbcon-set-rotate_font-callback-with-related-callback.patch @@ -0,0 +1,99 @@ +From 2fe21df6ac0e5f7e1b1c9238912478c1f262c32c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Sep 2025 14:44:43 +0200 +Subject: fbcon: Set rotate_font callback with related callbacks + +From: Thomas Zimmermann + +[ Upstream commit 9cfd09402eb45f1b14b60668fd7c628445efdd8d ] + +The field struct fbcon_par.rotate_font points to fbcon_rotate_font() if +the console is rotated. Set the callback in the same place as the other +callbacks. Prepares for declaring all fbcon callbacks in a dedicated +struct type. + +If not rotated, fbcon_set_bitops() still clears the callback to NULL. + +Signed-off-by: Thomas Zimmermann +Reviewed-by: Sam Ravnborg +Link: https://lore.kernel.org/r/20250909124616.143365-4-tzimmermann@suse.de +Stable-dep-of: 8e9bf8b9e8c0 ("printk, vt, fbcon: Remove console_conditional_schedule()") +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/core/fbcon_ccw.c | 1 + + drivers/video/fbdev/core/fbcon_cw.c | 1 + + drivers/video/fbdev/core/fbcon_rotate.c | 4 +--- + drivers/video/fbdev/core/fbcon_rotate.h | 3 +++ + drivers/video/fbdev/core/fbcon_ud.c | 1 + + 5 files changed, 7 insertions(+), 3 deletions(-) + +diff --git a/drivers/video/fbdev/core/fbcon_ccw.c b/drivers/video/fbdev/core/fbcon_ccw.c +index 2ba8ec4c3e2bc..ba744b67a4fd9 100644 +--- a/drivers/video/fbdev/core/fbcon_ccw.c ++++ b/drivers/video/fbdev/core/fbcon_ccw.c +@@ -398,4 +398,5 @@ void fbcon_rotate_ccw(struct fbcon_par *par) + par->clear_margins = ccw_clear_margins; + par->cursor = ccw_cursor; + par->update_start = ccw_update_start; ++ par->rotate_font = fbcon_rotate_font; + } +diff --git a/drivers/video/fbdev/core/fbcon_cw.c b/drivers/video/fbdev/core/fbcon_cw.c +index 4bd22d5ee5f41..974bd9d9b7702 100644 +--- a/drivers/video/fbdev/core/fbcon_cw.c ++++ b/drivers/video/fbdev/core/fbcon_cw.c +@@ -381,4 +381,5 @@ void fbcon_rotate_cw(struct fbcon_par *par) + par->clear_margins = cw_clear_margins; + par->cursor = cw_cursor; + par->update_start = cw_update_start; ++ par->rotate_font = fbcon_rotate_font; + } +diff --git a/drivers/video/fbdev/core/fbcon_rotate.c b/drivers/video/fbdev/core/fbcon_rotate.c +index 380b2746451a1..0c7cac71a9c21 100644 +--- a/drivers/video/fbdev/core/fbcon_rotate.c ++++ b/drivers/video/fbdev/core/fbcon_rotate.c +@@ -18,7 +18,7 @@ + #include "fbcon.h" + #include "fbcon_rotate.h" + +-static int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc) ++int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc) + { + struct fbcon_par *par = info->fbcon_par; + int len, err = 0; +@@ -95,8 +95,6 @@ static int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc) + + void fbcon_set_rotate(struct fbcon_par *par) + { +- par->rotate_font = fbcon_rotate_font; +- + switch (par->rotate) { + case FB_ROTATE_CW: + fbcon_rotate_cw(par); +diff --git a/drivers/video/fbdev/core/fbcon_rotate.h b/drivers/video/fbdev/core/fbcon_rotate.h +index 48305e1a07631..784f3231a958f 100644 +--- a/drivers/video/fbdev/core/fbcon_rotate.h ++++ b/drivers/video/fbdev/core/fbcon_rotate.h +@@ -90,7 +90,10 @@ static inline void rotate_ccw(const char *in, char *out, u32 width, u32 height) + } + } + ++int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc); ++ + extern void fbcon_rotate_cw(struct fbcon_par *par); + extern void fbcon_rotate_ud(struct fbcon_par *par); + extern void fbcon_rotate_ccw(struct fbcon_par *par); ++ + #endif +diff --git a/drivers/video/fbdev/core/fbcon_ud.c b/drivers/video/fbdev/core/fbcon_ud.c +index 14b40e2bf323f..1a214a4d538fb 100644 +--- a/drivers/video/fbdev/core/fbcon_ud.c ++++ b/drivers/video/fbdev/core/fbcon_ud.c +@@ -425,4 +425,5 @@ void fbcon_rotate_ud(struct fbcon_par *par) + par->clear_margins = ud_clear_margins; + par->cursor = ud_cursor; + par->update_start = ud_update_start; ++ par->rotate_font = fbcon_rotate_font; + } +-- +2.51.0 + diff --git a/queue-6.12/fbdev-au1200fb-fix-a-memory-leak-in-au1200fb_drv_pro.patch b/queue-6.12/fbdev-au1200fb-fix-a-memory-leak-in-au1200fb_drv_pro.patch new file mode 100644 index 0000000000..1828545238 --- /dev/null +++ b/queue-6.12/fbdev-au1200fb-fix-a-memory-leak-in-au1200fb_drv_pro.patch @@ -0,0 +1,43 @@ +From 809b99706f3e2ce6b56c5c8ee841d09cc5e4780b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 20:14:58 +0800 +Subject: fbdev: au1200fb: Fix a memory leak in au1200fb_drv_probe() + +From: Felix Gu + +[ Upstream commit ce4e25198a6aaaaf36248edf8daf3d744ec8e309 ] + +In au1200fb_drv_probe(), when platform_get_irq fails(), it directly +returns from the function with an error code, which causes a memory +leak. + +Replace it with a goto label to ensure proper cleanup. + +Fixes: 4e88761f5f8c ("fbdev: au1200fb: Fix missing IRQ check in au1200fb_drv_probe") +Signed-off-by: Felix Gu +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/au1200fb.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/video/fbdev/au1200fb.c b/drivers/video/fbdev/au1200fb.c +index ed770222660b5..685e629e7e164 100644 +--- a/drivers/video/fbdev/au1200fb.c ++++ b/drivers/video/fbdev/au1200fb.c +@@ -1724,8 +1724,10 @@ static int au1200fb_drv_probe(struct platform_device *dev) + + /* Now hook interrupt too */ + irq = platform_get_irq(dev, 0); +- if (irq < 0) +- return irq; ++ if (irq < 0) { ++ ret = irq; ++ goto failed; ++ } + + ret = request_irq(irq, au1200fb_handle_irq, + IRQF_SHARED, "lcd", (void *)dev); +-- +2.51.0 + diff --git a/queue-6.12/fbdev-of_display_timing-fix-device-node-reference-le.patch b/queue-6.12/fbdev-of_display_timing-fix-device-node-reference-le.patch new file mode 100644 index 0000000000..e6d956f871 --- /dev/null +++ b/queue-6.12/fbdev-of_display_timing-fix-device-node-reference-le.patch @@ -0,0 +1,56 @@ +From 069028047edbb095717e08abf3f23b5c23480936 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Jan 2026 20:48:33 +0800 +Subject: fbdev: of_display_timing: Fix device node reference leak in + of_get_display_timings() + +From: Felix Gu + +[ Upstream commit c39ee2d264f98efa14aa46c9942114cb03c7baa6 ] + +Use for_each_child_of_node_scoped instead of for_each_child_of_node +to ensure automatic of_node_put on early exit paths, preventing +device node reference leak. + +Fixes: cc3f414cf2e4 ("video: add of helper for display timings/videomode") +Signed-off-by: Felix Gu +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/of_display_timing.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/video/of_display_timing.c b/drivers/video/of_display_timing.c +index bebd371c6b93e..a4cd446ac5a59 100644 +--- a/drivers/video/of_display_timing.c ++++ b/drivers/video/of_display_timing.c +@@ -195,7 +195,7 @@ struct display_timings *of_get_display_timings(const struct device_node *np) + disp->num_timings = 0; + disp->native_mode = 0; + +- for_each_child_of_node(timings_np, entry) { ++ for_each_child_of_node_scoped(timings_np, child) { + struct display_timing *dt; + int r; + +@@ -206,7 +206,7 @@ struct display_timings *of_get_display_timings(const struct device_node *np) + goto timingfail; + } + +- r = of_parse_display_timing(entry, dt); ++ r = of_parse_display_timing(child, dt); + if (r) { + /* + * to not encourage wrong devicetrees, fail in case of +@@ -218,7 +218,7 @@ struct display_timings *of_get_display_timings(const struct device_node *np) + goto timingfail; + } + +- if (native_mode == entry) ++ if (native_mode == child) + disp->native_mode = disp->num_timings; + + disp->timings[disp->num_timings] = dt; +-- +2.51.0 + diff --git a/queue-6.12/fgraph-replace-fgraph_ret_regs-with-ftrace_regs.patch b/queue-6.12/fgraph-replace-fgraph_ret_regs-with-ftrace_regs.patch new file mode 100644 index 0000000000..355377d27f --- /dev/null +++ b/queue-6.12/fgraph-replace-fgraph_ret_regs-with-ftrace_regs.patch @@ -0,0 +1,766 @@ +From 616eb0de2458e3b86817bbff07d115e978c38b7e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Dec 2024 14:11:55 +0900 +Subject: fgraph: Replace fgraph_ret_regs with ftrace_regs + +From: Masami Hiramatsu (Google) + +[ Upstream commit a3ed4157b7d89800a0008de0c9e46a438a5c3745 ] + +Use ftrace_regs instead of fgraph_ret_regs for tracing return value +on function_graph tracer because of simplifying the callback interface. + +The CONFIG_HAVE_FUNCTION_GRAPH_RETVAL is also replaced by +CONFIG_HAVE_FUNCTION_GRAPH_FREGS. + +Signed-off-by: Masami Hiramatsu (Google) +Acked-by: Heiko Carstens +Acked-by: Will Deacon +Cc: Catalin Marinas +Cc: Alexei Starovoitov +Cc: Florent Revest +Cc: Martin KaFai Lau +Cc: bpf +Cc: Alexei Starovoitov +Cc: Jiri Olsa +Cc: Alan Maguire +Cc: Mark Rutland +Cc: Huacai Chen +Cc: WANG Xuerui +Cc: Paul Walmsley +Cc: Palmer Dabbelt +Cc: Albert Ou +Cc: Vasily Gorbik +Cc: Alexander Gordeev +Cc: Heiko Carstens +Cc: Christian Borntraeger +Cc: Sven Schnelle +Cc: Thomas Gleixner +Cc: Ingo Molnar +Cc: Borislav Petkov +Cc: Dave Hansen +Cc: x86@kernel.org +Cc: "H. Peter Anvin" +Cc: Mathieu Desnoyers +Link: https://lore.kernel.org/173518991508.391279.16635322774382197642.stgit@devnote2 +Signed-off-by: Steven Rostedt (Google) +Stable-dep-of: aea251799998 ("x86/fgraph,bpf: Switch kprobe_multi program stack unwind to hw_regs path") +Signed-off-by: Sasha Levin +--- + arch/arm64/Kconfig | 1 + + arch/arm64/include/asm/ftrace.h | 23 ++++++--------------- + arch/arm64/kernel/asm-offsets.c | 12 ----------- + arch/arm64/kernel/entry-ftrace.S | 32 ++++++++++++++++------------- + arch/loongarch/Kconfig | 2 +- + arch/loongarch/include/asm/ftrace.h | 26 ++++------------------- + arch/loongarch/kernel/asm-offsets.c | 12 ----------- + arch/loongarch/kernel/mcount.S | 17 ++++++++------- + arch/loongarch/kernel/mcount_dyn.S | 14 ++++++------- + arch/riscv/Kconfig | 2 +- + arch/riscv/include/asm/ftrace.h | 26 +++++------------------ + arch/riscv/kernel/mcount.S | 24 ++++++++++++---------- + arch/s390/Kconfig | 2 +- + arch/s390/include/asm/ftrace.h | 24 +++++++--------------- + arch/s390/kernel/asm-offsets.c | 6 ------ + arch/s390/kernel/mcount.S | 12 +++++------ + arch/x86/Kconfig | 2 +- + arch/x86/include/asm/ftrace.h | 20 ------------------ + arch/x86/kernel/ftrace_32.S | 13 ++++++------ + arch/x86/kernel/ftrace_64.S | 17 +++++++-------- + include/linux/ftrace.h | 12 ++++++++--- + include/linux/ftrace_regs.h | 2 ++ + kernel/trace/Kconfig | 4 ++-- + kernel/trace/fgraph.c | 21 ++++++++----------- + 24 files changed, 119 insertions(+), 207 deletions(-) + +diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig +index 40ae4dd961b15..0e2902f38e70e 100644 +--- a/arch/arm64/Kconfig ++++ b/arch/arm64/Kconfig +@@ -216,6 +216,7 @@ config ARM64 + select HAVE_FTRACE_MCOUNT_RECORD + select HAVE_FUNCTION_TRACER + select HAVE_FUNCTION_ERROR_INJECTION ++ select HAVE_FUNCTION_GRAPH_FREGS + select HAVE_FUNCTION_GRAPH_TRACER + select HAVE_FUNCTION_GRAPH_RETVAL + select HAVE_GCC_PLUGINS +diff --git a/arch/arm64/include/asm/ftrace.h b/arch/arm64/include/asm/ftrace.h +index 5ccff4de7f091..b5fa57b61378e 100644 +--- a/arch/arm64/include/asm/ftrace.h ++++ b/arch/arm64/include/asm/ftrace.h +@@ -129,6 +129,12 @@ ftrace_override_function_with_return(struct ftrace_regs *fregs) + arch_ftrace_regs(fregs)->pc = arch_ftrace_regs(fregs)->lr; + } + ++static __always_inline unsigned long ++ftrace_regs_get_frame_pointer(const struct ftrace_regs *fregs) ++{ ++ return arch_ftrace_regs(fregs)->fp; ++} ++ + int ftrace_regs_query_register_offset(const char *name); + + int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec); +@@ -186,23 +192,6 @@ static inline bool arch_syscall_match_sym_name(const char *sym, + + #ifndef __ASSEMBLY__ + #ifdef CONFIG_FUNCTION_GRAPH_TRACER +-struct fgraph_ret_regs { +- /* x0 - x7 */ +- unsigned long regs[8]; +- +- unsigned long fp; +- unsigned long __unused; +-}; +- +-static inline unsigned long fgraph_ret_regs_return_value(struct fgraph_ret_regs *ret_regs) +-{ +- return ret_regs->regs[0]; +-} +- +-static inline unsigned long fgraph_ret_regs_frame_pointer(struct fgraph_ret_regs *ret_regs) +-{ +- return ret_regs->fp; +-} + + void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent, + unsigned long frame_pointer); +diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c +index 1a1feca26515e..eccbe4d725f3b 100644 +--- a/arch/arm64/kernel/asm-offsets.c ++++ b/arch/arm64/kernel/asm-offsets.c +@@ -203,18 +203,6 @@ int main(void) + DEFINE(FTRACE_OPS_FUNC, offsetof(struct ftrace_ops, func)); + #endif + BLANK(); +-#ifdef CONFIG_FUNCTION_GRAPH_TRACER +- DEFINE(FGRET_REGS_X0, offsetof(struct fgraph_ret_regs, regs[0])); +- DEFINE(FGRET_REGS_X1, offsetof(struct fgraph_ret_regs, regs[1])); +- DEFINE(FGRET_REGS_X2, offsetof(struct fgraph_ret_regs, regs[2])); +- DEFINE(FGRET_REGS_X3, offsetof(struct fgraph_ret_regs, regs[3])); +- DEFINE(FGRET_REGS_X4, offsetof(struct fgraph_ret_regs, regs[4])); +- DEFINE(FGRET_REGS_X5, offsetof(struct fgraph_ret_regs, regs[5])); +- DEFINE(FGRET_REGS_X6, offsetof(struct fgraph_ret_regs, regs[6])); +- DEFINE(FGRET_REGS_X7, offsetof(struct fgraph_ret_regs, regs[7])); +- DEFINE(FGRET_REGS_FP, offsetof(struct fgraph_ret_regs, fp)); +- DEFINE(FGRET_REGS_SIZE, sizeof(struct fgraph_ret_regs)); +-#endif + #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS + DEFINE(FTRACE_OPS_DIRECT_CALL, offsetof(struct ftrace_ops, direct_call)); + #endif +diff --git a/arch/arm64/kernel/entry-ftrace.S b/arch/arm64/kernel/entry-ftrace.S +index f0c16640ef215..169ccf600066b 100644 +--- a/arch/arm64/kernel/entry-ftrace.S ++++ b/arch/arm64/kernel/entry-ftrace.S +@@ -329,24 +329,28 @@ SYM_FUNC_END(ftrace_stub_graph) + * @fp is checked against the value passed by ftrace_graph_caller(). + */ + SYM_CODE_START(return_to_handler) +- /* save return value regs */ +- sub sp, sp, #FGRET_REGS_SIZE +- stp x0, x1, [sp, #FGRET_REGS_X0] +- stp x2, x3, [sp, #FGRET_REGS_X2] +- stp x4, x5, [sp, #FGRET_REGS_X4] +- stp x6, x7, [sp, #FGRET_REGS_X6] +- str x29, [sp, #FGRET_REGS_FP] // parent's fp ++ /* Make room for ftrace_regs */ ++ sub sp, sp, #FREGS_SIZE ++ ++ /* Save return value regs */ ++ stp x0, x1, [sp, #FREGS_X0] ++ stp x2, x3, [sp, #FREGS_X2] ++ stp x4, x5, [sp, #FREGS_X4] ++ stp x6, x7, [sp, #FREGS_X6] ++ ++ /* Save the callsite's FP */ ++ str x29, [sp, #FREGS_FP] + + mov x0, sp +- bl ftrace_return_to_handler // addr = ftrace_return_to_hander(regs); ++ bl ftrace_return_to_handler // addr = ftrace_return_to_hander(fregs); + mov x30, x0 // restore the original return address + +- /* restore return value regs */ +- ldp x0, x1, [sp, #FGRET_REGS_X0] +- ldp x2, x3, [sp, #FGRET_REGS_X2] +- ldp x4, x5, [sp, #FGRET_REGS_X4] +- ldp x6, x7, [sp, #FGRET_REGS_X6] +- add sp, sp, #FGRET_REGS_SIZE ++ /* Restore return value regs */ ++ ldp x0, x1, [sp, #FREGS_X0] ++ ldp x2, x3, [sp, #FREGS_X2] ++ ldp x4, x5, [sp, #FREGS_X4] ++ ldp x6, x7, [sp, #FREGS_X6] ++ add sp, sp, #FREGS_SIZE + + ret + SYM_CODE_END(return_to_handler) +diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig +index 5f35a8bd8996e..d402fcdf08610 100644 +--- a/arch/loongarch/Kconfig ++++ b/arch/loongarch/Kconfig +@@ -136,7 +136,7 @@ config LOONGARCH + select HAVE_FTRACE_MCOUNT_RECORD + select HAVE_FUNCTION_ARG_ACCESS_API + select HAVE_FUNCTION_ERROR_INJECTION +- select HAVE_FUNCTION_GRAPH_RETVAL if HAVE_FUNCTION_GRAPH_TRACER ++ select HAVE_FUNCTION_GRAPH_FREGS + select HAVE_FUNCTION_GRAPH_TRACER + select HAVE_FUNCTION_TRACER + select HAVE_GCC_PLUGINS +diff --git a/arch/loongarch/include/asm/ftrace.h b/arch/loongarch/include/asm/ftrace.h +index 8f13eaeaa3251..ceb3e3d9c0d3d 100644 +--- a/arch/loongarch/include/asm/ftrace.h ++++ b/arch/loongarch/include/asm/ftrace.h +@@ -57,6 +57,10 @@ ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs, unsigned long ip) + instruction_pointer_set(&arch_ftrace_regs(fregs)->regs, ip); + } + ++#undef ftrace_regs_get_frame_pointer ++#define ftrace_regs_get_frame_pointer(fregs) \ ++ (arch_ftrace_regs(fregs)->regs.regs[22]) ++ + #define ftrace_graph_func ftrace_graph_func + void ftrace_graph_func(unsigned long ip, unsigned long parent_ip, + struct ftrace_ops *op, struct ftrace_regs *fregs); +@@ -78,26 +82,4 @@ __arch_ftrace_set_direct_caller(struct pt_regs *regs, unsigned long addr) + + #endif /* CONFIG_FUNCTION_TRACER */ + +-#ifndef __ASSEMBLY__ +-#ifdef CONFIG_FUNCTION_GRAPH_TRACER +-struct fgraph_ret_regs { +- /* a0 - a1 */ +- unsigned long regs[2]; +- +- unsigned long fp; +- unsigned long __unused; +-}; +- +-static inline unsigned long fgraph_ret_regs_return_value(struct fgraph_ret_regs *ret_regs) +-{ +- return ret_regs->regs[0]; +-} +- +-static inline unsigned long fgraph_ret_regs_frame_pointer(struct fgraph_ret_regs *ret_regs) +-{ +- return ret_regs->fp; +-} +-#endif /* ifdef CONFIG_FUNCTION_GRAPH_TRACER */ +-#endif +- + #endif /* _ASM_LOONGARCH_FTRACE_H */ +diff --git a/arch/loongarch/kernel/asm-offsets.c b/arch/loongarch/kernel/asm-offsets.c +index d20d71d4bcae6..73954aa226646 100644 +--- a/arch/loongarch/kernel/asm-offsets.c ++++ b/arch/loongarch/kernel/asm-offsets.c +@@ -281,18 +281,6 @@ static void __used output_pbe_defines(void) + } + #endif + +-#ifdef CONFIG_FUNCTION_GRAPH_TRACER +-static void __used output_fgraph_ret_regs_defines(void) +-{ +- COMMENT("LoongArch fgraph_ret_regs offsets."); +- OFFSET(FGRET_REGS_A0, fgraph_ret_regs, regs[0]); +- OFFSET(FGRET_REGS_A1, fgraph_ret_regs, regs[1]); +- OFFSET(FGRET_REGS_FP, fgraph_ret_regs, fp); +- DEFINE(FGRET_REGS_SIZE, sizeof(struct fgraph_ret_regs)); +- BLANK(); +-} +-#endif +- + static void __used output_kvm_defines(void) + { + COMMENT("KVM/LoongArch Specific offsets."); +diff --git a/arch/loongarch/kernel/mcount.S b/arch/loongarch/kernel/mcount.S +index 3015896016a0b..b6850503e061b 100644 +--- a/arch/loongarch/kernel/mcount.S ++++ b/arch/loongarch/kernel/mcount.S +@@ -79,10 +79,11 @@ SYM_FUNC_START(ftrace_graph_caller) + SYM_FUNC_END(ftrace_graph_caller) + + SYM_FUNC_START(return_to_handler) +- PTR_ADDI sp, sp, -FGRET_REGS_SIZE +- PTR_S a0, sp, FGRET_REGS_A0 +- PTR_S a1, sp, FGRET_REGS_A1 +- PTR_S zero, sp, FGRET_REGS_FP ++ /* Save return value regs */ ++ PTR_ADDI sp, sp, -PT_SIZE ++ PTR_S a0, sp, PT_R4 ++ PTR_S a1, sp, PT_R5 ++ PTR_S zero, sp, PT_R22 + + move a0, sp + bl ftrace_return_to_handler +@@ -90,9 +91,11 @@ SYM_FUNC_START(return_to_handler) + /* Restore the real parent address: a0 -> ra */ + move ra, a0 + +- PTR_L a0, sp, FGRET_REGS_A0 +- PTR_L a1, sp, FGRET_REGS_A1 +- PTR_ADDI sp, sp, FGRET_REGS_SIZE ++ /* Restore return value regs */ ++ PTR_L a0, sp, PT_R4 ++ PTR_L a1, sp, PT_R5 ++ PTR_ADDI sp, sp, PT_SIZE ++ + jr ra + SYM_FUNC_END(return_to_handler) + #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ +diff --git a/arch/loongarch/kernel/mcount_dyn.S b/arch/loongarch/kernel/mcount_dyn.S +index 4e05adb405043..5729c20e5b8b0 100644 +--- a/arch/loongarch/kernel/mcount_dyn.S ++++ b/arch/loongarch/kernel/mcount_dyn.S +@@ -144,19 +144,19 @@ SYM_CODE_END(ftrace_graph_caller) + SYM_CODE_START(return_to_handler) + UNWIND_HINT_UNDEFINED + /* Save return value regs */ +- PTR_ADDI sp, sp, -FGRET_REGS_SIZE +- PTR_S a0, sp, FGRET_REGS_A0 +- PTR_S a1, sp, FGRET_REGS_A1 +- PTR_S zero, sp, FGRET_REGS_FP ++ PTR_ADDI sp, sp, -PT_SIZE ++ PTR_S a0, sp, PT_R4 ++ PTR_S a1, sp, PT_R5 ++ PTR_S zero, sp, PT_R22 + + move a0, sp + bl ftrace_return_to_handler + move ra, a0 + + /* Restore return value regs */ +- PTR_L a0, sp, FGRET_REGS_A0 +- PTR_L a1, sp, FGRET_REGS_A1 +- PTR_ADDI sp, sp, FGRET_REGS_SIZE ++ PTR_L a0, sp, PT_R4 ++ PTR_L a1, sp, PT_R5 ++ PTR_ADDI sp, sp, PT_SIZE + + jr ra + SYM_CODE_END(return_to_handler) +diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig +index d160c3b830266..9e8667a523d55 100644 +--- a/arch/riscv/Kconfig ++++ b/arch/riscv/Kconfig +@@ -144,7 +144,7 @@ config RISCV + select HAVE_DYNAMIC_FTRACE_WITH_ARGS if HAVE_DYNAMIC_FTRACE + select HAVE_FTRACE_MCOUNT_RECORD if !XIP_KERNEL + select HAVE_FUNCTION_GRAPH_TRACER +- select HAVE_FUNCTION_GRAPH_RETVAL if HAVE_FUNCTION_GRAPH_TRACER ++ select HAVE_FUNCTION_GRAPH_FREGS + select HAVE_FUNCTION_TRACER if !XIP_KERNEL && !PREEMPTION + select HAVE_EBPF_JIT if MMU + select HAVE_GUP_FAST if MMU +diff --git a/arch/riscv/include/asm/ftrace.h b/arch/riscv/include/asm/ftrace.h +index af174ea0c9451..d9b80a42fa4df 100644 +--- a/arch/riscv/include/asm/ftrace.h ++++ b/arch/riscv/include/asm/ftrace.h +@@ -168,6 +168,11 @@ static __always_inline unsigned long ftrace_regs_get_stack_pointer(const struct + return arch_ftrace_regs(fregs)->sp; + } + ++static __always_inline unsigned long ftrace_regs_get_frame_pointer(const struct ftrace_regs *fregs) ++{ ++ return arch_ftrace_regs(fregs)->s0; ++} ++ + static __always_inline unsigned long ftrace_regs_get_argument(struct ftrace_regs *fregs, + unsigned int n) + { +@@ -208,25 +213,4 @@ static inline void arch_ftrace_set_direct_caller(struct ftrace_regs *fregs, unsi + + #endif /* CONFIG_DYNAMIC_FTRACE */ + +-#ifndef __ASSEMBLY__ +-#ifdef CONFIG_FUNCTION_GRAPH_TRACER +-struct fgraph_ret_regs { +- unsigned long a1; +- unsigned long a0; +- unsigned long s0; +- unsigned long ra; +-}; +- +-static inline unsigned long fgraph_ret_regs_return_value(struct fgraph_ret_regs *ret_regs) +-{ +- return ret_regs->a0; +-} +- +-static inline unsigned long fgraph_ret_regs_frame_pointer(struct fgraph_ret_regs *ret_regs) +-{ +- return ret_regs->s0; +-} +-#endif /* ifdef CONFIG_FUNCTION_GRAPH_TRACER */ +-#endif +- + #endif /* _ASM_RISCV_FTRACE_H */ +diff --git a/arch/riscv/kernel/mcount.S b/arch/riscv/kernel/mcount.S +index 3a42f6287909d..068168046e0ef 100644 +--- a/arch/riscv/kernel/mcount.S ++++ b/arch/riscv/kernel/mcount.S +@@ -12,6 +12,8 @@ + #include + #include + ++#define ABI_SIZE_ON_STACK 80 ++ + .text + + .macro SAVE_ABI_STATE +@@ -26,12 +28,12 @@ + * register if a0 was not saved. + */ + .macro SAVE_RET_ABI_STATE +- addi sp, sp, -4*SZREG +- REG_S s0, 2*SZREG(sp) +- REG_S ra, 3*SZREG(sp) +- REG_S a0, 1*SZREG(sp) +- REG_S a1, 0*SZREG(sp) +- addi s0, sp, 4*SZREG ++ addi sp, sp, -ABI_SIZE_ON_STACK ++ REG_S ra, 1*SZREG(sp) ++ REG_S s0, 8*SZREG(sp) ++ REG_S a0, 10*SZREG(sp) ++ REG_S a1, 11*SZREG(sp) ++ addi s0, sp, ABI_SIZE_ON_STACK + .endm + + .macro RESTORE_ABI_STATE +@@ -41,11 +43,11 @@ + .endm + + .macro RESTORE_RET_ABI_STATE +- REG_L ra, 3*SZREG(sp) +- REG_L s0, 2*SZREG(sp) +- REG_L a0, 1*SZREG(sp) +- REG_L a1, 0*SZREG(sp) +- addi sp, sp, 4*SZREG ++ REG_L ra, 1*SZREG(sp) ++ REG_L s0, 8*SZREG(sp) ++ REG_L a0, 10*SZREG(sp) ++ REG_L a1, 11*SZREG(sp) ++ addi sp, sp, ABI_SIZE_ON_STACK + .endm + + SYM_TYPED_FUNC_START(ftrace_stub) +diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig +index 5c9349df71ccf..1786b30307942 100644 +--- a/arch/s390/Kconfig ++++ b/arch/s390/Kconfig +@@ -184,7 +184,7 @@ config S390 + select HAVE_FTRACE_MCOUNT_RECORD + select HAVE_FUNCTION_ARG_ACCESS_API + select HAVE_FUNCTION_ERROR_INJECTION +- select HAVE_FUNCTION_GRAPH_RETVAL ++ select HAVE_FUNCTION_GRAPH_FREGS + select HAVE_FUNCTION_GRAPH_TRACER + select HAVE_FUNCTION_TRACER + select HAVE_GCC_PLUGINS +diff --git a/arch/s390/include/asm/ftrace.h b/arch/s390/include/asm/ftrace.h +index fc97d75dc752c..5c94c1fc1bc1c 100644 +--- a/arch/s390/include/asm/ftrace.h ++++ b/arch/s390/include/asm/ftrace.h +@@ -62,23 +62,6 @@ static __always_inline struct pt_regs *arch_ftrace_get_regs(struct ftrace_regs * + return NULL; + } + +-#ifdef CONFIG_FUNCTION_GRAPH_TRACER +-struct fgraph_ret_regs { +- unsigned long gpr2; +- unsigned long fp; +-}; +- +-static __always_inline unsigned long fgraph_ret_regs_return_value(struct fgraph_ret_regs *ret_regs) +-{ +- return ret_regs->gpr2; +-} +- +-static __always_inline unsigned long fgraph_ret_regs_frame_pointer(struct fgraph_ret_regs *ret_regs) +-{ +- return ret_regs->fp; +-} +-#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ +- + static __always_inline void + ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs, + unsigned long ip) +@@ -86,6 +69,13 @@ ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs, + arch_ftrace_regs(fregs)->regs.psw.addr = ip; + } + ++#undef ftrace_regs_get_frame_pointer ++static __always_inline unsigned long ++ftrace_regs_get_frame_pointer(struct ftrace_regs *fregs) ++{ ++ return ftrace_regs_get_stack_pointer(fregs); ++} ++ + #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS + /* + * When an ftrace registered caller is tracing a function that is +diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c +index 0bab4a9cdc768..8fd98a0f999f8 100644 +--- a/arch/s390/kernel/asm-offsets.c ++++ b/arch/s390/kernel/asm-offsets.c +@@ -179,12 +179,6 @@ int main(void) + DEFINE(OLDMEM_SIZE, PARMAREA + offsetof(struct parmarea, oldmem_size)); + DEFINE(COMMAND_LINE, PARMAREA + offsetof(struct parmarea, command_line)); + DEFINE(MAX_COMMAND_LINE_SIZE, PARMAREA + offsetof(struct parmarea, max_command_line_size)); +-#ifdef CONFIG_FUNCTION_GRAPH_TRACER +- /* function graph return value tracing */ +- OFFSET(__FGRAPH_RET_GPR2, fgraph_ret_regs, gpr2); +- OFFSET(__FGRAPH_RET_FP, fgraph_ret_regs, fp); +- DEFINE(__FGRAPH_RET_SIZE, sizeof(struct fgraph_ret_regs)); +-#endif + OFFSET(__FTRACE_REGS_PT_REGS, __arch_ftrace_regs, regs); + DEFINE(__FTRACE_REGS_SIZE, sizeof(struct __arch_ftrace_regs)); + +diff --git a/arch/s390/kernel/mcount.S b/arch/s390/kernel/mcount.S +index 7e267ef63a7fe..2b628aa3d8095 100644 +--- a/arch/s390/kernel/mcount.S ++++ b/arch/s390/kernel/mcount.S +@@ -134,14 +134,14 @@ SYM_CODE_END(ftrace_common) + SYM_FUNC_START(return_to_handler) + stmg %r2,%r5,32(%r15) + lgr %r1,%r15 +- aghi %r15,-(STACK_FRAME_OVERHEAD+__FGRAPH_RET_SIZE) ++ # allocate ftrace_regs and stack frame for ftrace_return_to_handler ++ aghi %r15,-STACK_FRAME_SIZE_FREGS + stg %r1,__SF_BACKCHAIN(%r15) +- la %r3,STACK_FRAME_OVERHEAD(%r15) +- stg %r1,__FGRAPH_RET_FP(%r3) +- stg %r2,__FGRAPH_RET_GPR2(%r3) +- lgr %r2,%r3 ++ stg %r2,(STACK_FREGS_PTREGS_GPRS+2*8)(%r15) ++ stg %r1,(STACK_FREGS_PTREGS_GPRS+15*8)(%r15) ++ la %r2,STACK_FRAME_OVERHEAD(%r15) + brasl %r14,ftrace_return_to_handler +- aghi %r15,STACK_FRAME_OVERHEAD+__FGRAPH_RET_SIZE ++ aghi %r15,STACK_FRAME_SIZE_FREGS + lgr %r14,%r2 + lmg %r2,%r5,32(%r15) + BR_EX %r14 +diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig +index df14d0e67ea0c..d1c73d5ed32f7 100644 +--- a/arch/x86/Kconfig ++++ b/arch/x86/Kconfig +@@ -231,7 +231,7 @@ config X86 + select HAVE_GUP_FAST + select HAVE_FENTRY if X86_64 || DYNAMIC_FTRACE + select HAVE_FTRACE_MCOUNT_RECORD +- select HAVE_FUNCTION_GRAPH_RETVAL if HAVE_FUNCTION_GRAPH_TRACER ++ select HAVE_FUNCTION_GRAPH_FREGS if HAVE_FUNCTION_GRAPH_TRACER + select HAVE_FUNCTION_GRAPH_TRACER if X86_32 || (X86_64 && DYNAMIC_FTRACE) + select HAVE_FUNCTION_TRACER + select HAVE_GCC_PLUGINS +diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h +index 6e8cf0fa48fc6..d61407c680c28 100644 +--- a/arch/x86/include/asm/ftrace.h ++++ b/arch/x86/include/asm/ftrace.h +@@ -134,24 +134,4 @@ static inline bool arch_trace_is_compat_syscall(struct pt_regs *regs) + #endif /* !COMPILE_OFFSETS */ + #endif /* !__ASSEMBLY__ */ + +-#ifndef __ASSEMBLY__ +-#ifdef CONFIG_FUNCTION_GRAPH_TRACER +-struct fgraph_ret_regs { +- unsigned long ax; +- unsigned long dx; +- unsigned long bp; +-}; +- +-static inline unsigned long fgraph_ret_regs_return_value(struct fgraph_ret_regs *ret_regs) +-{ +- return ret_regs->ax; +-} +- +-static inline unsigned long fgraph_ret_regs_frame_pointer(struct fgraph_ret_regs *ret_regs) +-{ +- return ret_regs->bp; +-} +-#endif /* ifdef CONFIG_FUNCTION_GRAPH_TRACER */ +-#endif +- + #endif /* _ASM_X86_FTRACE_H */ +diff --git a/arch/x86/kernel/ftrace_32.S b/arch/x86/kernel/ftrace_32.S +index 58d9ed50fe617..f4e0c33612342 100644 +--- a/arch/x86/kernel/ftrace_32.S ++++ b/arch/x86/kernel/ftrace_32.S +@@ -187,14 +187,15 @@ SYM_CODE_END(ftrace_graph_caller) + + .globl return_to_handler + return_to_handler: +- pushl $0 +- pushl %edx +- pushl %eax ++ subl $(PTREGS_SIZE), %esp ++ movl $0, PT_EBP(%esp) ++ movl %edx, PT_EDX(%esp) ++ movl %eax, PT_EAX(%esp) + movl %esp, %eax + call ftrace_return_to_handler + movl %eax, %ecx +- popl %eax +- popl %edx +- addl $4, %esp # skip ebp ++ movl PT_EAX(%esp), %eax ++ movl PT_EDX(%esp), %edx ++ addl $(PTREGS_SIZE), %esp + JMP_NOSPEC ecx + #endif +diff --git a/arch/x86/kernel/ftrace_64.S b/arch/x86/kernel/ftrace_64.S +index 214f30e9f0c01..d516472285967 100644 +--- a/arch/x86/kernel/ftrace_64.S ++++ b/arch/x86/kernel/ftrace_64.S +@@ -348,21 +348,22 @@ STACK_FRAME_NON_STANDARD_FP(__fentry__) + SYM_CODE_START(return_to_handler) + UNWIND_HINT_UNDEFINED + ANNOTATE_NOENDBR +- subq $24, %rsp + +- /* Save the return values */ +- movq %rax, (%rsp) +- movq %rdx, 8(%rsp) +- movq %rbp, 16(%rsp) ++ /* Save ftrace_regs for function exit context */ ++ subq $(FRAME_SIZE), %rsp ++ ++ movq %rax, RAX(%rsp) ++ movq %rdx, RDX(%rsp) ++ movq %rbp, RBP(%rsp) + movq %rsp, %rdi + + call ftrace_return_to_handler + + movq %rax, %rdi +- movq 8(%rsp), %rdx +- movq (%rsp), %rax ++ movq RDX(%rsp), %rdx ++ movq RAX(%rsp), %rax + +- addq $24, %rsp ++ addq $(FRAME_SIZE), %rsp + /* + * Jump back to the old return address. This cannot be JMP_NOSPEC rdi + * since IBT would demand that contain ENDBR, which simply isn't so for +diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h +index 7930a3374bb52..b71ad5c04f482 100644 +--- a/include/linux/ftrace.h ++++ b/include/linux/ftrace.h +@@ -43,9 +43,8 @@ struct dyn_ftrace; + + char *arch_ftrace_match_adjust(char *str, const char *search); + +-#ifdef CONFIG_HAVE_FUNCTION_GRAPH_RETVAL +-struct fgraph_ret_regs; +-unsigned long ftrace_return_to_handler(struct fgraph_ret_regs *ret_regs); ++#ifdef CONFIG_HAVE_FUNCTION_GRAPH_FREGS ++unsigned long ftrace_return_to_handler(struct ftrace_regs *fregs); + #else + unsigned long ftrace_return_to_handler(unsigned long frame_pointer); + #endif +@@ -134,6 +133,13 @@ extern int ftrace_enabled; + * Also, architecture dependent fields can be used for internal process. + * (e.g. orig_ax on x86_64) + * ++ * Basically, ftrace_regs stores the registers related to the context. ++ * On function entry, registers for function parameters and hooking the ++ * function call are stored, and on function exit, registers for function ++ * return value and frame pointers are stored. ++ * ++ * And also, it dpends on the context that which registers are restored ++ * from the ftrace_regs. + * On the function entry, those registers will be restored except for + * the stack pointer, so that user can change the function parameters + * and instruction pointer (e.g. live patching.) +diff --git a/include/linux/ftrace_regs.h b/include/linux/ftrace_regs.h +index be1ed0c891d07..bbc1873ca6b8e 100644 +--- a/include/linux/ftrace_regs.h ++++ b/include/linux/ftrace_regs.h +@@ -30,6 +30,8 @@ struct ftrace_regs; + override_function_with_return(&arch_ftrace_regs(fregs)->regs) + #define ftrace_regs_query_register_offset(name) \ + regs_query_register_offset(name) ++#define ftrace_regs_get_frame_pointer(fregs) \ ++ frame_pointer(&arch_ftrace_regs(fregs)->regs) + + #endif /* HAVE_ARCH_FTRACE_REGS */ + +diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig +index 721c3b221048a..ab277eff80dc2 100644 +--- a/kernel/trace/Kconfig ++++ b/kernel/trace/Kconfig +@@ -31,7 +31,7 @@ config HAVE_FUNCTION_GRAPH_TRACER + help + See Documentation/trace/ftrace-design.rst + +-config HAVE_FUNCTION_GRAPH_RETVAL ++config HAVE_FUNCTION_GRAPH_FREGS + bool + + config HAVE_DYNAMIC_FTRACE +@@ -232,7 +232,7 @@ config FUNCTION_GRAPH_TRACER + + config FUNCTION_GRAPH_RETVAL + bool "Kernel Function Graph Return Value" +- depends on HAVE_FUNCTION_GRAPH_RETVAL ++ depends on HAVE_FUNCTION_GRAPH_FREGS + depends on FUNCTION_GRAPH_TRACER + default n + help +diff --git a/kernel/trace/fgraph.c b/kernel/trace/fgraph.c +index 910da0e4531ae..352f0d4ce2e35 100644 +--- a/kernel/trace/fgraph.c ++++ b/kernel/trace/fgraph.c +@@ -761,15 +761,12 @@ static struct notifier_block ftrace_suspend_notifier = { + .notifier_call = ftrace_suspend_notifier_call, + }; + +-/* fgraph_ret_regs is not defined without CONFIG_FUNCTION_GRAPH_RETVAL */ +-struct fgraph_ret_regs; +- + /* + * Send the trace to the ring-buffer. + * @return the original return address. + */ +-static unsigned long __ftrace_return_to_handler(struct fgraph_ret_regs *ret_regs, +- unsigned long frame_pointer) ++static inline unsigned long ++__ftrace_return_to_handler(struct ftrace_regs *fregs, unsigned long frame_pointer) + { + struct ftrace_ret_stack *ret_stack; + struct ftrace_graph_ret trace; +@@ -789,7 +786,7 @@ static unsigned long __ftrace_return_to_handler(struct fgraph_ret_regs *ret_regs + + trace.rettime = trace_clock_local(); + #ifdef CONFIG_FUNCTION_GRAPH_RETVAL +- trace.retval = fgraph_ret_regs_return_value(ret_regs); ++ trace.retval = ftrace_regs_get_return_value(fregs); + #endif + + bitmap = get_bitmap_bits(current, offset); +@@ -824,14 +821,14 @@ static unsigned long __ftrace_return_to_handler(struct fgraph_ret_regs *ret_regs + } + + /* +- * After all architecures have selected HAVE_FUNCTION_GRAPH_RETVAL, we can +- * leave only ftrace_return_to_handler(ret_regs). ++ * After all architecures have selected HAVE_FUNCTION_GRAPH_FREGS, we can ++ * leave only ftrace_return_to_handler(fregs). + */ +-#ifdef CONFIG_HAVE_FUNCTION_GRAPH_RETVAL +-unsigned long ftrace_return_to_handler(struct fgraph_ret_regs *ret_regs) ++#ifdef CONFIG_HAVE_FUNCTION_GRAPH_FREGS ++unsigned long ftrace_return_to_handler(struct ftrace_regs *fregs) + { +- return __ftrace_return_to_handler(ret_regs, +- fgraph_ret_regs_frame_pointer(ret_regs)); ++ return __ftrace_return_to_handler(fregs, ++ ftrace_regs_get_frame_pointer(fregs)); + } + #else + unsigned long ftrace_return_to_handler(unsigned long frame_pointer) +-- +2.51.0 + diff --git a/queue-6.12/firmware-arm_ffa-correct-32-bit-response-handling-in.patch b/queue-6.12/firmware-arm_ffa-correct-32-bit-response-handling-in.patch new file mode 100644 index 0000000000..d85162240a --- /dev/null +++ b/queue-6.12/firmware-arm_ffa-correct-32-bit-response-handling-in.patch @@ -0,0 +1,119 @@ +From cbcf11ac5ad990981761fdb29def70b9e3331a23 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 14:20:01 +0000 +Subject: firmware: arm_ffa: Correct 32-bit response handling in + NOTIFICATION_INFO_GET + +From: Sudeep Holla + +[ Upstream commit be4d4543f78074fbebd530ba5109d39a2a34e668 ] + +The FF-A specification allows NOTIFICATION_INFO_GET to return either a +64-bit (FFA_FN64_SUCCESS) or a 32-bit (FFA_SUCCESS) response, depending on +whether the firmware chooses the SMC64 or SMC32 calling convention. + +The driver previously detected the response format by checking ret.a0, but +still interpreted the returned ID lists (x3..x17 or w3..w7) as if they always +followed the 64-bit SMC64 layout. In the SMC32 case, the upper 32 bits of +each argument register are undefined by the calling convention, meaning the +driver could read stale or garbage values when parsing notification IDs. + +This resulted in incorrectly decoded partition/VCPU IDs whenever the FF-A +firmware used an SMC32 return path. + +Fix the issue by: + +- Introducing logic to map list indices to the correct u16 offsets, + depending on whether the response width matches the kernel word size + or is a 32-bit response on a 64-bit kernel. +- Ensuring that the packed ID list is parsed using the proper layout, + avoiding reads from undefined upper halves in the SMC32 case. + +With this change, NOTIFICATION_INFO_GET now correctly interprets ID list +entries regardless of the response width, aligning the driver with the FF-A +specification. + +Fixes: 3522be48d82b ("firmware: arm_ffa: Implement the NOTIFICATION_INFO_GET interface") +Reported-by: Sourav Mohapatra +Message-Id: <20251218142001.2457111-1-sudeep.holla@arm.com> +Signed-off-by: Sudeep Holla +Signed-off-by: Sasha Levin +--- + drivers/firmware/arm_ffa/driver.c | 33 +++++++++++++++++++++++++++---- + 1 file changed, 29 insertions(+), 4 deletions(-) + +diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c +index 9fdfccbc6479a..7e486e49d1eed 100644 +--- a/drivers/firmware/arm_ffa/driver.c ++++ b/drivers/firmware/arm_ffa/driver.c +@@ -895,10 +895,27 @@ static void __do_sched_recv_cb(u16 part_id, u16 vcpu, bool is_per_vcpu) + callback(vcpu, is_per_vcpu, cb_data); + } + ++/* ++ * Map logical ID index to the u16 index within the packed ID list. ++ * ++ * For native responses (FF-A width == kernel word size), IDs are ++ * tightly packed: idx -> idx. ++ * ++ * For 32-bit responses on a 64-bit kernel, each 64-bit register ++ * contributes 4 x u16 values but only the lower 2 are defined; the ++ * upper 2 are garbage. This mapping skips those upper halves: ++ * 0,1,2,3,4,5,... -> 0,1,4,5,8,9,... ++ */ ++static int list_idx_to_u16_idx(int idx, bool is_native_resp) ++{ ++ return is_native_resp ? idx : idx + 2 * (idx >> 1); ++} ++ + static void ffa_notification_info_get(void) + { +- int idx, list, max_ids, lists_cnt, ids_processed, ids_count[MAX_IDS_64]; +- bool is_64b_resp; ++ int ids_processed, ids_count[MAX_IDS_64]; ++ int idx, list, max_ids, lists_cnt; ++ bool is_64b_resp, is_native_resp; + ffa_value_t ret; + u64 id_list; + +@@ -915,6 +932,7 @@ static void ffa_notification_info_get(void) + } + + is_64b_resp = (ret.a0 == FFA_FN64_SUCCESS); ++ is_native_resp = (ret.a0 == FFA_FN_NATIVE(SUCCESS)); + + ids_processed = 0; + lists_cnt = FIELD_GET(NOTIFICATION_INFO_GET_ID_COUNT, ret.a2); +@@ -931,12 +949,16 @@ static void ffa_notification_info_get(void) + + /* Process IDs */ + for (list = 0; list < lists_cnt; list++) { ++ int u16_idx; + u16 vcpu_id, part_id, *packed_id_list = (u16 *)&ret.a3; + + if (ids_processed >= max_ids - 1) + break; + +- part_id = packed_id_list[ids_processed++]; ++ u16_idx = list_idx_to_u16_idx(ids_processed, ++ is_native_resp); ++ part_id = packed_id_list[u16_idx]; ++ ids_processed++; + + if (ids_count[list] == 1) { /* Global Notification */ + __do_sched_recv_cb(part_id, 0, false); +@@ -948,7 +970,10 @@ static void ffa_notification_info_get(void) + if (ids_processed >= max_ids - 1) + break; + +- vcpu_id = packed_id_list[ids_processed++]; ++ u16_idx = list_idx_to_u16_idx(ids_processed, ++ is_native_resp); ++ vcpu_id = packed_id_list[u16_idx]; ++ ids_processed++; + + __do_sched_recv_cb(part_id, vcpu_id, true); + } +-- +2.51.0 + diff --git a/queue-6.12/fs-add-linux-init_task.h-for-init_fs.patch b/queue-6.12/fs-add-linux-init_task.h-for-init_fs.patch new file mode 100644 index 0000000000..ca652dcc44 --- /dev/null +++ b/queue-6.12/fs-add-linux-init_task.h-for-init_fs.patch @@ -0,0 +1,40 @@ +From 484c561ebeaeb76eb6b3af351d991f259f0bb034 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 11:58:56 +0000 +Subject: fs: add for 'init_fs' + +From: Ben Dooks + +[ Upstream commit 589cff4975afe1a4eaaa1d961652f50b1628d78d ] + +The init_fs symbol is defined in but was +not included in fs/fs_struct.c so fix by adding the include. + +Fixes the following sparse warning: +fs/fs_struct.c:150:18: warning: symbol 'init_fs' was not declared. Should it be static? + +Fixes: 3e93cd671813e ("Take fs_struct handling to new file") +Signed-off-by: Ben Dooks +Link: https://patch.msgid.link/20260108115856.238027-1-ben.dooks@codethink.co.uk +Reviewed-by: Jan Kara +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/fs_struct.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/fs_struct.c b/fs/fs_struct.c +index 64c2d0814ed68..100bd3474476b 100644 +--- a/fs/fs_struct.c ++++ b/fs/fs_struct.c +@@ -6,6 +6,7 @@ + #include + #include + #include ++#include + #include "internal.h" + + /* +-- +2.51.0 + diff --git a/queue-6.12/fs-nfs-fix-readdir-slow-start-regression.patch b/queue-6.12/fs-nfs-fix-readdir-slow-start-regression.patch new file mode 100644 index 0000000000..217be28f50 --- /dev/null +++ b/queue-6.12/fs-nfs-fix-readdir-slow-start-regression.patch @@ -0,0 +1,54 @@ +From 77f3db922e8c8a251c448d1030cc6d25657775f5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 27 Dec 2025 12:46:29 +0200 +Subject: fs/nfs: Fix readdir slow-start regression + +From: Sagi Grimberg + +[ Upstream commit 42e7c876b182da65723700f6bc507a8aecb10d3b ] + +Commit 580f236737d1 ("NFS: Adjust the amount of readahead +performed by NFS readdir") reduces the amount of readahead names +caching done by the client. + +The downside of this approach is READDIR now may suffer from +a slow-start issue, where initially it will fetch names that fit +in a single page, then in 2, 4, 8 until the maximum supported +transfer size (usually 1M). + +This patch tries to take a balanced approach between mitigating +the slow-start issue still maintaining some efficiency gains. + +Fixes: 580f236737d1 ("NFS: Adjust the amount of readahead performed by NFS readdir") +Signed-off-by: Sagi Grimberg +Signed-off-by: Anna Schumaker +Signed-off-by: Sasha Levin +--- + fs/nfs/dir.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c +index 1cf1b2ddbf549..5b90f8727e683 100644 +--- a/fs/nfs/dir.c ++++ b/fs/nfs/dir.c +@@ -72,7 +72,7 @@ const struct address_space_operations nfs_dir_aops = { + .free_folio = nfs_readdir_clear_array, + }; + +-#define NFS_INIT_DTSIZE PAGE_SIZE ++#define NFS_INIT_DTSIZE SZ_64K + + static struct nfs_open_dir_context * + alloc_nfs_open_dir_context(struct inode *dir) +@@ -83,7 +83,7 @@ alloc_nfs_open_dir_context(struct inode *dir) + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL_ACCOUNT); + if (ctx != NULL) { + ctx->attr_gencount = nfsi->attr_gencount; +- ctx->dtsize = NFS_INIT_DTSIZE; ++ ctx->dtsize = min(NFS_SERVER(dir)->dtsize, NFS_INIT_DTSIZE); + spin_lock(&dir->i_lock); + if (list_empty(&nfsi->open_files) && + (nfsi->cache_validity & NFS_INO_DATA_INVAL_DEFER)) +-- +2.51.0 + diff --git a/queue-6.12/fs-tests-exec-drop-duplicate-bprm_stack_limits-test-.patch b/queue-6.12/fs-tests-exec-drop-duplicate-bprm_stack_limits-test-.patch new file mode 100644 index 0000000000..fd45e00f7e --- /dev/null +++ b/queue-6.12/fs-tests-exec-drop-duplicate-bprm_stack_limits-test-.patch @@ -0,0 +1,48 @@ +From d3b87f228bdccfe760e3874574805ae64535085a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 18:59:50 +0100 +Subject: fs/tests: exec: drop duplicate bprm_stack_limits test vectors + +From: Titouan Ameline de Cadeville + +[ Upstream commit 46a03ea50b5f380bdb99178b8f90b39c6ba1f528 ] + +Remove duplicate entries from the bprm_stack_limits KUnit test vector +table. The duplicates do not add coverage and only increase test size. + +Signed-off-by: Titouan Ameline de Cadeville +Fixes: 60371f43e56b ("exec: Add KUnit test for bprm_stack_limits()") +Link: https://patch.msgid.link/20260203175950.43710-1-titouan.ameline@gmail.com +Signed-off-by: Kees Cook +Signed-off-by: Sasha Levin +--- + fs/tests/exec_kunit.c | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/fs/tests/exec_kunit.c b/fs/tests/exec_kunit.c +index 7c77d039680bb..f412d1a0f6bba 100644 +--- a/fs/tests/exec_kunit.c ++++ b/fs/tests/exec_kunit.c +@@ -87,9 +87,6 @@ static const struct bprm_stack_limits_result bprm_stack_limits_results[] = { + .argc = 0, .envc = ARG_MAX / sizeof(void *) - 1 }, + .expected_argmin = ULONG_MAX - sizeof(void *) }, + /* Raising rlim_stack / 4 to _STK_LIM / 4 * 3 will see more space. */ +- { { .p = ULONG_MAX, .rlim_stack.rlim_cur = 4 * (_STK_LIM / 4 * 3), +- .argc = 0, .envc = 0 }, +- .expected_argmin = ULONG_MAX - (_STK_LIM / 4 * 3) + sizeof(void *) }, + { { .p = ULONG_MAX, .rlim_stack.rlim_cur = 4 * (_STK_LIM / 4 * 3), + .argc = 0, .envc = 0 }, + .expected_argmin = ULONG_MAX - (_STK_LIM / 4 * 3) + sizeof(void *) }, +@@ -103,9 +100,6 @@ static const struct bprm_stack_limits_result bprm_stack_limits_results[] = { + { { .p = ULONG_MAX, .rlim_stack.rlim_cur = 4 * _STK_LIM, + .argc = 0, .envc = 0 }, + .expected_argmin = ULONG_MAX - (_STK_LIM / 4 * 3) + sizeof(void *) }, +- { { .p = ULONG_MAX, .rlim_stack.rlim_cur = 4 * _STK_LIM, +- .argc = 0, .envc = 0 }, +- .expected_argmin = ULONG_MAX - (_STK_LIM / 4 * 3) + sizeof(void *) }, + }; + + static void exec_test_bprm_stack_limits(struct kunit *test) +-- +2.51.0 + diff --git a/queue-6.12/ftrace-consolidate-ftrace_regs-accessor-functions-fo.patch b/queue-6.12/ftrace-consolidate-ftrace_regs-accessor-functions-fo.patch new file mode 100644 index 0000000000..aaf7cf38ea --- /dev/null +++ b/queue-6.12/ftrace-consolidate-ftrace_regs-accessor-functions-fo.patch @@ -0,0 +1,376 @@ +From e239a5bf2e5c43703f75b2e2ba2e69b5c8befc39 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 10 Oct 2024 20:21:14 -0400 +Subject: ftrace: Consolidate ftrace_regs accessor functions for archs using + pt_regs + +From: Steven Rostedt + +[ Upstream commit e4cf33ca48128d580e25ebe779b7ba7b4b4cf733 ] + +Most architectures use pt_regs within ftrace_regs making a lot of the +accessor functions just calls to the pt_regs internally. Instead of +duplication this effort, use a HAVE_ARCH_FTRACE_REGS for architectures +that have their own ftrace_regs that is not based on pt_regs and will +define all the accessor functions, and for the architectures that just use +pt_regs, it will leave it undefined, and the default accessor functions +will be used. + +Note, this will also make it easier to add new accessor functions to +ftrace_regs as it will mean having to touch less architectures. + +Cc: +Cc: "x86@kernel.org" +Cc: Mathieu Desnoyers +Cc: Mark Rutland +Cc: Will Deacon +Cc: Huacai Chen +Cc: WANG Xuerui +Cc: Michael Ellerman +Cc: Nicholas Piggin +Cc: Christophe Leroy +Cc: Naveen N Rao +Cc: Madhavan Srinivasan +Cc: Paul Walmsley +Cc: Palmer Dabbelt +Cc: Albert Ou +Cc: Heiko Carstens +Cc: Vasily Gorbik +Cc: Alexander Gordeev +Cc: Christian Borntraeger +Cc: Sven Schnelle +Cc: Thomas Gleixner +Cc: Ingo Molnar +Cc: Borislav Petkov +Cc: Dave Hansen +Link: https://lore.kernel.org/20241010202114.2289f6fd@gandalf.local.home +Acked-by: Masami Hiramatsu (Google) +Acked-by: Heiko Carstens # s390 +Acked-by: Catalin Marinas +Acked-by: Michael Ellerman # powerpc +Suggested-by: Masami Hiramatsu (Google) +Signed-off-by: Steven Rostedt (Google) +Stable-dep-of: aea251799998 ("x86/fgraph,bpf: Switch kprobe_multi program stack unwind to hw_regs path") +Signed-off-by: Sasha Levin +--- + arch/arm64/include/asm/ftrace.h | 1 + + arch/loongarch/include/asm/ftrace.h | 25 +------------------- + arch/powerpc/include/asm/ftrace.h | 26 +-------------------- + arch/riscv/include/asm/ftrace.h | 1 + + arch/s390/include/asm/ftrace.h | 26 +-------------------- + arch/x86/include/asm/ftrace.h | 21 +---------------- + include/linux/ftrace.h | 32 ++++++------------------- + include/linux/ftrace_regs.h | 36 +++++++++++++++++++++++++++++ + 8 files changed, 49 insertions(+), 119 deletions(-) + create mode 100644 include/linux/ftrace_regs.h + +diff --git a/arch/arm64/include/asm/ftrace.h b/arch/arm64/include/asm/ftrace.h +index bbb69c7751b99..5ccff4de7f091 100644 +--- a/arch/arm64/include/asm/ftrace.h ++++ b/arch/arm64/include/asm/ftrace.h +@@ -54,6 +54,7 @@ extern void return_to_handler(void); + unsigned long ftrace_call_adjust(unsigned long addr); + + #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS ++#define HAVE_ARCH_FTRACE_REGS + struct dyn_ftrace; + struct ftrace_ops; + struct ftrace_regs; +diff --git a/arch/loongarch/include/asm/ftrace.h b/arch/loongarch/include/asm/ftrace.h +index 0e15d36ce2512..8f13eaeaa3251 100644 +--- a/arch/loongarch/include/asm/ftrace.h ++++ b/arch/loongarch/include/asm/ftrace.h +@@ -43,43 +43,20 @@ void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent); + + #ifdef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS + struct ftrace_ops; +-struct ftrace_regs; +-#define arch_ftrace_regs(fregs) ((struct __arch_ftrace_regs *)(fregs)) + +-struct __arch_ftrace_regs { +- struct pt_regs regs; +-}; ++#include + + static __always_inline struct pt_regs *arch_ftrace_get_regs(struct ftrace_regs *fregs) + { + return &arch_ftrace_regs(fregs)->regs; + } + +-static __always_inline unsigned long +-ftrace_regs_get_instruction_pointer(struct ftrace_regs *fregs) +-{ +- return instruction_pointer(&arch_ftrace_regs(fregs)->regs); +-} +- + static __always_inline void + ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs, unsigned long ip) + { + instruction_pointer_set(&arch_ftrace_regs(fregs)->regs, ip); + } + +-#define ftrace_regs_get_argument(fregs, n) \ +- regs_get_kernel_argument(&arch_ftrace_regs(fregs)->regs, n) +-#define ftrace_regs_get_stack_pointer(fregs) \ +- kernel_stack_pointer(&arch_ftrace_regs(fregs)->regs) +-#define ftrace_regs_return_value(fregs) \ +- regs_return_value(&arch_ftrace_regs(fregs)->regs) +-#define ftrace_regs_set_return_value(fregs, ret) \ +- regs_set_return_value(&arch_ftrace_regs(fregs)->regs, ret) +-#define ftrace_override_function_with_return(fregs) \ +- override_function_with_return(&arch_ftrace_regs(fregs)->regs) +-#define ftrace_regs_query_register_offset(name) \ +- regs_query_register_offset(name) +- + #define ftrace_graph_func ftrace_graph_func + void ftrace_graph_func(unsigned long ip, unsigned long parent_ip, + struct ftrace_ops *op, struct ftrace_regs *fregs); +diff --git a/arch/powerpc/include/asm/ftrace.h b/arch/powerpc/include/asm/ftrace.h +index e299fd47d2014..0edfb874eb02b 100644 +--- a/arch/powerpc/include/asm/ftrace.h ++++ b/arch/powerpc/include/asm/ftrace.h +@@ -32,12 +32,7 @@ struct dyn_arch_ftrace { + int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec); + #define ftrace_init_nop ftrace_init_nop + +-struct ftrace_regs; +-#define arch_ftrace_regs(fregs) ((struct __arch_ftrace_regs *)(fregs)) +- +-struct __arch_ftrace_regs { +- struct pt_regs regs; +-}; ++#include + + static __always_inline struct pt_regs *arch_ftrace_get_regs(struct ftrace_regs *fregs) + { +@@ -52,25 +47,6 @@ ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs, + regs_set_return_ip(&arch_ftrace_regs(fregs)->regs, ip); + } + +-static __always_inline unsigned long +-ftrace_regs_get_instruction_pointer(struct ftrace_regs *fregs) +-{ +- return instruction_pointer(&arch_ftrace_regs(fregs)->regs); +-} +- +-#define ftrace_regs_get_argument(fregs, n) \ +- regs_get_kernel_argument(&arch_ftrace_regs(fregs)->regs, n) +-#define ftrace_regs_get_stack_pointer(fregs) \ +- kernel_stack_pointer(&arch_ftrace_regs(fregs)->regs) +-#define ftrace_regs_return_value(fregs) \ +- regs_return_value(&arch_ftrace_regs(fregs)->regs) +-#define ftrace_regs_set_return_value(fregs, ret) \ +- regs_set_return_value(&arch_ftrace_regs(fregs)->regs, ret) +-#define ftrace_override_function_with_return(fregs) \ +- override_function_with_return(&arch_ftrace_regs(fregs)->regs) +-#define ftrace_regs_query_register_offset(name) \ +- regs_query_register_offset(name) +- + struct ftrace_ops; + + #define ftrace_graph_func ftrace_graph_func +diff --git a/arch/riscv/include/asm/ftrace.h b/arch/riscv/include/asm/ftrace.h +index 8a97ce5077e73..af174ea0c9451 100644 +--- a/arch/riscv/include/asm/ftrace.h ++++ b/arch/riscv/include/asm/ftrace.h +@@ -125,6 +125,7 @@ int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec); + + #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS + #define arch_ftrace_get_regs(regs) NULL ++#define HAVE_ARCH_FTRACE_REGS + struct ftrace_ops; + struct ftrace_regs; + #define arch_ftrace_regs(fregs) ((struct __arch_ftrace_regs *)(fregs)) +diff --git a/arch/s390/include/asm/ftrace.h b/arch/s390/include/asm/ftrace.h +index 1498d0a9c7625..fc97d75dc752c 100644 +--- a/arch/s390/include/asm/ftrace.h ++++ b/arch/s390/include/asm/ftrace.h +@@ -51,12 +51,7 @@ static inline unsigned long ftrace_call_adjust(unsigned long addr) + return addr; + } + +-struct ftrace_regs; +-#define arch_ftrace_regs(fregs) ((struct __arch_ftrace_regs *)(fregs)) +- +-struct __arch_ftrace_regs { +- struct pt_regs regs; +-}; ++#include + + static __always_inline struct pt_regs *arch_ftrace_get_regs(struct ftrace_regs *fregs) + { +@@ -84,12 +79,6 @@ static __always_inline unsigned long fgraph_ret_regs_frame_pointer(struct fgraph + } + #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ + +-static __always_inline unsigned long +-ftrace_regs_get_instruction_pointer(const struct ftrace_regs *fregs) +-{ +- return arch_ftrace_regs(fregs)->regs.psw.addr; +-} +- + static __always_inline void + ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs, + unsigned long ip) +@@ -97,19 +86,6 @@ ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs, + arch_ftrace_regs(fregs)->regs.psw.addr = ip; + } + +-#define ftrace_regs_get_argument(fregs, n) \ +- regs_get_kernel_argument(&arch_ftrace_regs(fregs)->regs, n) +-#define ftrace_regs_get_stack_pointer(fregs) \ +- kernel_stack_pointer(&arch_ftrace_regs(fregs)->regs) +-#define ftrace_regs_return_value(fregs) \ +- regs_return_value(&arch_ftrace_regs(fregs)->regs) +-#define ftrace_regs_set_return_value(fregs, ret) \ +- regs_set_return_value(&arch_ftrace_regs(fregs)->regs, ret) +-#define ftrace_override_function_with_return(fregs) \ +- override_function_with_return(&arch_ftrace_regs(fregs)->regs) +-#define ftrace_regs_query_register_offset(name) \ +- regs_query_register_offset(name) +- + #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS + /* + * When an ftrace registered caller is tracing a function that is +diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h +index 62fed5547c2e1..6e8cf0fa48fc6 100644 +--- a/arch/x86/include/asm/ftrace.h ++++ b/arch/x86/include/asm/ftrace.h +@@ -35,12 +35,8 @@ static inline unsigned long ftrace_call_adjust(unsigned long addr) + } + + #ifdef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS +-struct ftrace_regs; +-#define arch_ftrace_regs(fregs) ((struct __arch_ftrace_regs *)(fregs)) + +-struct __arch_ftrace_regs { +- struct pt_regs regs; +-}; ++#include + + static __always_inline struct pt_regs * + arch_ftrace_get_regs(struct ftrace_regs *fregs) +@@ -54,21 +50,6 @@ arch_ftrace_get_regs(struct ftrace_regs *fregs) + #define ftrace_regs_set_instruction_pointer(fregs, _ip) \ + do { arch_ftrace_regs(fregs)->regs.ip = (_ip); } while (0) + +-#define ftrace_regs_get_instruction_pointer(fregs) \ +- arch_ftrace_regs(fregs)->regs.ip) +- +-#define ftrace_regs_get_argument(fregs, n) \ +- regs_get_kernel_argument(&arch_ftrace_regs(fregs)->regs, n) +-#define ftrace_regs_get_stack_pointer(fregs) \ +- kernel_stack_pointer(&arch_ftrace_regs(fregs)->regs) +-#define ftrace_regs_return_value(fregs) \ +- regs_return_value(&arch_ftrace_regs(fregs)->regs) +-#define ftrace_regs_set_return_value(fregs, ret) \ +- regs_set_return_value(&arch_ftrace_regs(fregs)->regs, ret) +-#define ftrace_override_function_with_return(fregs) \ +- override_function_with_return(&arch_ftrace_regs(fregs)->regs) +-#define ftrace_regs_query_register_offset(name) \ +- regs_query_register_offset(name) + + struct ftrace_ops; + #define ftrace_graph_func ftrace_graph_func +diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h +index fc76ce4bf0b7e..7930a3374bb52 100644 +--- a/include/linux/ftrace.h ++++ b/include/linux/ftrace.h +@@ -113,6 +113,8 @@ static inline int ftrace_mod_get_kallsym(unsigned int symnum, unsigned long *val + + #ifdef CONFIG_FUNCTION_TRACER + ++#include ++ + extern int ftrace_enabled; + + /** +@@ -150,14 +152,11 @@ struct ftrace_regs { + #define ftrace_regs_size() sizeof(struct __arch_ftrace_regs) + + #ifndef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS +- +-struct __arch_ftrace_regs { +- struct pt_regs regs; +-}; +- +-struct ftrace_regs; +-#define arch_ftrace_regs(fregs) ((struct __arch_ftrace_regs *)(fregs)) +- ++/* ++ * Architectures that define HAVE_DYNAMIC_FTRACE_WITH_ARGS must define their own ++ * arch_ftrace_get_regs() where it only returns pt_regs *if* it is fully ++ * populated. It should return NULL otherwise. ++ */ + static inline struct pt_regs *arch_ftrace_get_regs(struct ftrace_regs *fregs) + { + return &arch_ftrace_regs(fregs)->regs; +@@ -191,23 +190,6 @@ static __always_inline bool ftrace_regs_has_args(struct ftrace_regs *fregs) + return ftrace_get_regs(fregs) != NULL; + } + +-#ifndef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS +-#define ftrace_regs_get_instruction_pointer(fregs) \ +- instruction_pointer(ftrace_get_regs(fregs)) +-#define ftrace_regs_get_argument(fregs, n) \ +- regs_get_kernel_argument(ftrace_get_regs(fregs), n) +-#define ftrace_regs_get_stack_pointer(fregs) \ +- kernel_stack_pointer(ftrace_get_regs(fregs)) +-#define ftrace_regs_return_value(fregs) \ +- regs_return_value(ftrace_get_regs(fregs)) +-#define ftrace_regs_set_return_value(fregs, ret) \ +- regs_set_return_value(ftrace_get_regs(fregs), ret) +-#define ftrace_override_function_with_return(fregs) \ +- override_function_with_return(ftrace_get_regs(fregs)) +-#define ftrace_regs_query_register_offset(name) \ +- regs_query_register_offset(name) +-#endif +- + typedef void (*ftrace_func_t)(unsigned long ip, unsigned long parent_ip, + struct ftrace_ops *op, struct ftrace_regs *fregs); + +diff --git a/include/linux/ftrace_regs.h b/include/linux/ftrace_regs.h +new file mode 100644 +index 0000000000000..dea6a0851b749 +--- /dev/null ++++ b/include/linux/ftrace_regs.h +@@ -0,0 +1,36 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef _LINUX_FTRACE_REGS_H ++#define _LINUX_FTRACE_REGS_H ++ ++/* ++ * For archs that just copy pt_regs in ftrace regs, it can use this default. ++ * If an architecture does not use pt_regs, it must define all the below ++ * accessor functions. ++ */ ++#ifndef HAVE_ARCH_FTRACE_REGS ++struct __arch_ftrace_regs { ++ struct pt_regs regs; ++}; ++ ++#define arch_ftrace_regs(fregs) ((struct __arch_ftrace_regs *)(fregs)) ++ ++struct ftrace_regs; ++ ++#define ftrace_regs_get_instruction_pointer(fregs) \ ++ instruction_pointer(arch_ftrace_get_regs(fregs)) ++#define ftrace_regs_get_argument(fregs, n) \ ++ regs_get_kernel_argument(arch_ftrace_get_regs(fregs), n) ++#define ftrace_regs_get_stack_pointer(fregs) \ ++ kernel_stack_pointer(arch_ftrace_get_regs(fregs)) ++#define ftrace_regs_return_value(fregs) \ ++ regs_return_value(arch_ftrace_get_regs(fregs)) ++#define ftrace_regs_set_return_value(fregs, ret) \ ++ regs_set_return_value(arch_ftrace_get_regs(fregs), ret) ++#define ftrace_override_function_with_return(fregs) \ ++ override_function_with_return(arch_ftrace_get_regs(fregs)) ++#define ftrace_regs_query_register_offset(name) \ ++ regs_query_register_offset(name) ++ ++#endif /* HAVE_ARCH_FTRACE_REGS */ ++ ++#endif /* _LINUX_FTRACE_REGS_H */ +-- +2.51.0 + diff --git a/queue-6.12/ftrace-make-ftrace_regs-abstract-from-direct-use.patch b/queue-6.12/ftrace-make-ftrace_regs-abstract-from-direct-use.patch new file mode 100644 index 0000000000..df0bbfb3a1 --- /dev/null +++ b/queue-6.12/ftrace-make-ftrace_regs-abstract-from-direct-use.patch @@ -0,0 +1,762 @@ +From 6e8cdf4c52ffad03118067b597d83ed43eb1d092 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 8 Oct 2024 19:05:28 -0400 +Subject: ftrace: Make ftrace_regs abstract from direct use + +From: Steven Rostedt + +[ Upstream commit 7888af4166d4ab07ba51234be6ba332b7807e901 ] + +ftrace_regs was created to hold registers that store information to save +function parameters, return value and stack. Since it is a subset of +pt_regs, it should only be used by its accessor functions. But because +pt_regs can easily be taken from ftrace_regs (on most archs), it is +tempting to use it directly. But when running on other architectures, it +may fail to build or worse, build but crash the kernel! + +Instead, make struct ftrace_regs an empty structure and have the +architectures define __arch_ftrace_regs and all the accessor functions +will typecast to it to get to the actual fields. This will help avoid +usage of ftrace_regs directly. + +Link: https://lore.kernel.org/all/20241007171027.629bdafd@gandalf.local.home/ + +Cc: "linux-arch@vger.kernel.org" +Cc: "x86@kernel.org" +Cc: Mathieu Desnoyers +Cc: Mark Rutland +Cc: Will Deacon +Cc: Huacai Chen +Cc: WANG Xuerui +Cc: Michael Ellerman +Cc: Nicholas Piggin +Cc: Christophe Leroy +Cc: Naveen N Rao +Cc: Madhavan Srinivasan +Cc: Paul Walmsley +Cc: Palmer Dabbelt +Cc: Albert Ou +Cc: Heiko Carstens +Cc: Vasily Gorbik +Cc: Alexander Gordeev +Cc: Christian Borntraeger +Cc: Sven Schnelle +Cc: Thomas Gleixner +Cc: Ingo Molnar +Cc: Borislav Petkov +Cc: Dave Hansen +Link: https://lore.kernel.org/20241008230628.958778821@goodmis.org +Acked-by: Catalin Marinas +Signed-off-by: Steven Rostedt (Google) +Acked-by: Masami Hiramatsu (Google) +Acked-by: Heiko Carstens # s390 +Signed-off-by: Steven Rostedt (Google) +Stable-dep-of: aea251799998 ("x86/fgraph,bpf: Switch kprobe_multi program stack unwind to hw_regs path") +Signed-off-by: Sasha Levin +--- + arch/arm64/include/asm/ftrace.h | 20 +++++++++-------- + arch/arm64/kernel/asm-offsets.c | 22 +++++++++---------- + arch/arm64/kernel/ftrace.c | 10 ++++----- + arch/loongarch/include/asm/ftrace.h | 22 ++++++++++--------- + arch/loongarch/kernel/ftrace_dyn.c | 2 +- + arch/powerpc/include/asm/ftrace.h | 21 ++++++++++-------- + arch/powerpc/kernel/trace/ftrace.c | 4 ++-- + arch/powerpc/kernel/trace/ftrace_64_pg.c | 2 +- + arch/riscv/include/asm/ftrace.h | 21 ++++++++++-------- + arch/riscv/kernel/asm-offsets.c | 28 ++++++++++++------------ + arch/riscv/kernel/ftrace.c | 2 +- + arch/s390/include/asm/ftrace.h | 23 ++++++++++--------- + arch/s390/kernel/asm-offsets.c | 4 ++-- + arch/s390/kernel/ftrace.c | 2 +- + arch/s390/lib/test_unwind.c | 4 ++-- + arch/x86/include/asm/ftrace.h | 25 +++++++++++---------- + arch/x86/kernel/ftrace.c | 2 +- + include/linux/ftrace.h | 21 +++++++++++++++--- + kernel/trace/ftrace.c | 2 +- + 19 files changed, 134 insertions(+), 103 deletions(-) + +diff --git a/arch/arm64/include/asm/ftrace.h b/arch/arm64/include/asm/ftrace.h +index dc9cf0bd2a4cb..bbb69c7751b99 100644 +--- a/arch/arm64/include/asm/ftrace.h ++++ b/arch/arm64/include/asm/ftrace.h +@@ -56,6 +56,8 @@ unsigned long ftrace_call_adjust(unsigned long addr); + #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS + struct dyn_ftrace; + struct ftrace_ops; ++struct ftrace_regs; ++#define arch_ftrace_regs(fregs) ((struct __arch_ftrace_regs *)(fregs)) + + #define arch_ftrace_get_regs(regs) NULL + +@@ -63,7 +65,7 @@ struct ftrace_ops; + * Note: sizeof(struct ftrace_regs) must be a multiple of 16 to ensure correct + * stack alignment + */ +-struct ftrace_regs { ++struct __arch_ftrace_regs { + /* x0 - x8 */ + unsigned long regs[9]; + +@@ -83,47 +85,47 @@ struct ftrace_regs { + static __always_inline unsigned long + ftrace_regs_get_instruction_pointer(const struct ftrace_regs *fregs) + { +- return fregs->pc; ++ return arch_ftrace_regs(fregs)->pc; + } + + static __always_inline void + ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs, + unsigned long pc) + { +- fregs->pc = pc; ++ arch_ftrace_regs(fregs)->pc = pc; + } + + static __always_inline unsigned long + ftrace_regs_get_stack_pointer(const struct ftrace_regs *fregs) + { +- return fregs->sp; ++ return arch_ftrace_regs(fregs)->sp; + } + + static __always_inline unsigned long + ftrace_regs_get_argument(struct ftrace_regs *fregs, unsigned int n) + { + if (n < 8) +- return fregs->regs[n]; ++ return arch_ftrace_regs(fregs)->regs[n]; + return 0; + } + + static __always_inline unsigned long + ftrace_regs_get_return_value(const struct ftrace_regs *fregs) + { +- return fregs->regs[0]; ++ return arch_ftrace_regs(fregs)->regs[0]; + } + + static __always_inline void + ftrace_regs_set_return_value(struct ftrace_regs *fregs, + unsigned long ret) + { +- fregs->regs[0] = ret; ++ arch_ftrace_regs(fregs)->regs[0] = ret; + } + + static __always_inline void + ftrace_override_function_with_return(struct ftrace_regs *fregs) + { +- fregs->pc = fregs->lr; ++ arch_ftrace_regs(fregs)->pc = arch_ftrace_regs(fregs)->lr; + } + + int ftrace_regs_query_register_offset(const char *name); +@@ -143,7 +145,7 @@ static inline void arch_ftrace_set_direct_caller(struct ftrace_regs *fregs, + * The ftrace trampoline will return to this address instead of the + * instrumented function. + */ +- fregs->direct_tramp = addr; ++ arch_ftrace_regs(fregs)->direct_tramp = addr; + } + #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */ + +diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c +index 020e01181a0f1..1a1feca26515e 100644 +--- a/arch/arm64/kernel/asm-offsets.c ++++ b/arch/arm64/kernel/asm-offsets.c +@@ -85,19 +85,19 @@ int main(void) + DEFINE(PT_REGS_SIZE, sizeof(struct pt_regs)); + BLANK(); + #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS +- DEFINE(FREGS_X0, offsetof(struct ftrace_regs, regs[0])); +- DEFINE(FREGS_X2, offsetof(struct ftrace_regs, regs[2])); +- DEFINE(FREGS_X4, offsetof(struct ftrace_regs, regs[4])); +- DEFINE(FREGS_X6, offsetof(struct ftrace_regs, regs[6])); +- DEFINE(FREGS_X8, offsetof(struct ftrace_regs, regs[8])); +- DEFINE(FREGS_FP, offsetof(struct ftrace_regs, fp)); +- DEFINE(FREGS_LR, offsetof(struct ftrace_regs, lr)); +- DEFINE(FREGS_SP, offsetof(struct ftrace_regs, sp)); +- DEFINE(FREGS_PC, offsetof(struct ftrace_regs, pc)); ++ DEFINE(FREGS_X0, offsetof(struct __arch_ftrace_regs, regs[0])); ++ DEFINE(FREGS_X2, offsetof(struct __arch_ftrace_regs, regs[2])); ++ DEFINE(FREGS_X4, offsetof(struct __arch_ftrace_regs, regs[4])); ++ DEFINE(FREGS_X6, offsetof(struct __arch_ftrace_regs, regs[6])); ++ DEFINE(FREGS_X8, offsetof(struct __arch_ftrace_regs, regs[8])); ++ DEFINE(FREGS_FP, offsetof(struct __arch_ftrace_regs, fp)); ++ DEFINE(FREGS_LR, offsetof(struct __arch_ftrace_regs, lr)); ++ DEFINE(FREGS_SP, offsetof(struct __arch_ftrace_regs, sp)); ++ DEFINE(FREGS_PC, offsetof(struct __arch_ftrace_regs, pc)); + #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS +- DEFINE(FREGS_DIRECT_TRAMP, offsetof(struct ftrace_regs, direct_tramp)); ++ DEFINE(FREGS_DIRECT_TRAMP, offsetof(struct __arch_ftrace_regs, direct_tramp)); + #endif +- DEFINE(FREGS_SIZE, sizeof(struct ftrace_regs)); ++ DEFINE(FREGS_SIZE, sizeof(struct __arch_ftrace_regs)); + BLANK(); + #endif + #ifdef CONFIG_COMPAT +diff --git a/arch/arm64/kernel/ftrace.c b/arch/arm64/kernel/ftrace.c +index b657f058bf4d5..06017bc1a555f 100644 +--- a/arch/arm64/kernel/ftrace.c ++++ b/arch/arm64/kernel/ftrace.c +@@ -23,10 +23,10 @@ struct fregs_offset { + int offset; + }; + +-#define FREGS_OFFSET(n, field) \ +-{ \ +- .name = n, \ +- .offset = offsetof(struct ftrace_regs, field), \ ++#define FREGS_OFFSET(n, field) \ ++{ \ ++ .name = n, \ ++ .offset = offsetof(struct __arch_ftrace_regs, field), \ + } + + static const struct fregs_offset fregs_offsets[] = { +@@ -488,7 +488,7 @@ void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent, + void ftrace_graph_func(unsigned long ip, unsigned long parent_ip, + struct ftrace_ops *op, struct ftrace_regs *fregs) + { +- prepare_ftrace_return(ip, &fregs->lr, fregs->fp); ++ prepare_ftrace_return(ip, &arch_ftrace_regs(fregs)->lr, arch_ftrace_regs(fregs)->fp); + } + #else + /* +diff --git a/arch/loongarch/include/asm/ftrace.h b/arch/loongarch/include/asm/ftrace.h +index c0a682808e070..0e15d36ce2512 100644 +--- a/arch/loongarch/include/asm/ftrace.h ++++ b/arch/loongarch/include/asm/ftrace.h +@@ -43,38 +43,40 @@ void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent); + + #ifdef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS + struct ftrace_ops; ++struct ftrace_regs; ++#define arch_ftrace_regs(fregs) ((struct __arch_ftrace_regs *)(fregs)) + +-struct ftrace_regs { ++struct __arch_ftrace_regs { + struct pt_regs regs; + }; + + static __always_inline struct pt_regs *arch_ftrace_get_regs(struct ftrace_regs *fregs) + { +- return &fregs->regs; ++ return &arch_ftrace_regs(fregs)->regs; + } + + static __always_inline unsigned long + ftrace_regs_get_instruction_pointer(struct ftrace_regs *fregs) + { +- return instruction_pointer(&fregs->regs); ++ return instruction_pointer(&arch_ftrace_regs(fregs)->regs); + } + + static __always_inline void + ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs, unsigned long ip) + { +- instruction_pointer_set(&fregs->regs, ip); ++ instruction_pointer_set(&arch_ftrace_regs(fregs)->regs, ip); + } + + #define ftrace_regs_get_argument(fregs, n) \ +- regs_get_kernel_argument(&(fregs)->regs, n) ++ regs_get_kernel_argument(&arch_ftrace_regs(fregs)->regs, n) + #define ftrace_regs_get_stack_pointer(fregs) \ +- kernel_stack_pointer(&(fregs)->regs) ++ kernel_stack_pointer(&arch_ftrace_regs(fregs)->regs) + #define ftrace_regs_return_value(fregs) \ +- regs_return_value(&(fregs)->regs) ++ regs_return_value(&arch_ftrace_regs(fregs)->regs) + #define ftrace_regs_set_return_value(fregs, ret) \ +- regs_set_return_value(&(fregs)->regs, ret) ++ regs_set_return_value(&arch_ftrace_regs(fregs)->regs, ret) + #define ftrace_override_function_with_return(fregs) \ +- override_function_with_return(&(fregs)->regs) ++ override_function_with_return(&arch_ftrace_regs(fregs)->regs) + #define ftrace_regs_query_register_offset(name) \ + regs_query_register_offset(name) + +@@ -90,7 +92,7 @@ __arch_ftrace_set_direct_caller(struct pt_regs *regs, unsigned long addr) + } + + #define arch_ftrace_set_direct_caller(fregs, addr) \ +- __arch_ftrace_set_direct_caller(&(fregs)->regs, addr) ++ __arch_ftrace_set_direct_caller(&arch_ftrace_regs(fregs)->regs, addr) + #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */ + + #endif +diff --git a/arch/loongarch/kernel/ftrace_dyn.c b/arch/loongarch/kernel/ftrace_dyn.c +index bff058317062e..18056229e22e4 100644 +--- a/arch/loongarch/kernel/ftrace_dyn.c ++++ b/arch/loongarch/kernel/ftrace_dyn.c +@@ -241,7 +241,7 @@ void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent) + void ftrace_graph_func(unsigned long ip, unsigned long parent_ip, + struct ftrace_ops *op, struct ftrace_regs *fregs) + { +- struct pt_regs *regs = &fregs->regs; ++ struct pt_regs *regs = &arch_ftrace_regs(fregs)->regs; + unsigned long *parent = (unsigned long *)®s->regs[1]; + + prepare_ftrace_return(ip, (unsigned long *)parent); +diff --git a/arch/powerpc/include/asm/ftrace.h b/arch/powerpc/include/asm/ftrace.h +index 559560286e6d0..e299fd47d2014 100644 +--- a/arch/powerpc/include/asm/ftrace.h ++++ b/arch/powerpc/include/asm/ftrace.h +@@ -32,39 +32,42 @@ struct dyn_arch_ftrace { + int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec); + #define ftrace_init_nop ftrace_init_nop + +-struct ftrace_regs { ++struct ftrace_regs; ++#define arch_ftrace_regs(fregs) ((struct __arch_ftrace_regs *)(fregs)) ++ ++struct __arch_ftrace_regs { + struct pt_regs regs; + }; + + static __always_inline struct pt_regs *arch_ftrace_get_regs(struct ftrace_regs *fregs) + { + /* We clear regs.msr in ftrace_call */ +- return fregs->regs.msr ? &fregs->regs : NULL; ++ return arch_ftrace_regs(fregs)->regs.msr ? &arch_ftrace_regs(fregs)->regs : NULL; + } + + static __always_inline void + ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs, + unsigned long ip) + { +- regs_set_return_ip(&fregs->regs, ip); ++ regs_set_return_ip(&arch_ftrace_regs(fregs)->regs, ip); + } + + static __always_inline unsigned long + ftrace_regs_get_instruction_pointer(struct ftrace_regs *fregs) + { +- return instruction_pointer(&fregs->regs); ++ return instruction_pointer(&arch_ftrace_regs(fregs)->regs); + } + + #define ftrace_regs_get_argument(fregs, n) \ +- regs_get_kernel_argument(&(fregs)->regs, n) ++ regs_get_kernel_argument(&arch_ftrace_regs(fregs)->regs, n) + #define ftrace_regs_get_stack_pointer(fregs) \ +- kernel_stack_pointer(&(fregs)->regs) ++ kernel_stack_pointer(&arch_ftrace_regs(fregs)->regs) + #define ftrace_regs_return_value(fregs) \ +- regs_return_value(&(fregs)->regs) ++ regs_return_value(&arch_ftrace_regs(fregs)->regs) + #define ftrace_regs_set_return_value(fregs, ret) \ +- regs_set_return_value(&(fregs)->regs, ret) ++ regs_set_return_value(&arch_ftrace_regs(fregs)->regs, ret) + #define ftrace_override_function_with_return(fregs) \ +- override_function_with_return(&(fregs)->regs) ++ override_function_with_return(&arch_ftrace_regs(fregs)->regs) + #define ftrace_regs_query_register_offset(name) \ + regs_query_register_offset(name) + +diff --git a/arch/powerpc/kernel/trace/ftrace.c b/arch/powerpc/kernel/trace/ftrace.c +index d8d6b4fd9a14c..df41f4a7c738b 100644 +--- a/arch/powerpc/kernel/trace/ftrace.c ++++ b/arch/powerpc/kernel/trace/ftrace.c +@@ -421,7 +421,7 @@ int __init ftrace_dyn_arch_init(void) + void ftrace_graph_func(unsigned long ip, unsigned long parent_ip, + struct ftrace_ops *op, struct ftrace_regs *fregs) + { +- unsigned long sp = fregs->regs.gpr[1]; ++ unsigned long sp = arch_ftrace_regs(fregs)->regs.gpr[1]; + int bit; + + if (unlikely(ftrace_graph_is_dead())) +@@ -439,6 +439,6 @@ void ftrace_graph_func(unsigned long ip, unsigned long parent_ip, + + ftrace_test_recursion_unlock(bit); + out: +- fregs->regs.link = parent_ip; ++ arch_ftrace_regs(fregs)->regs.link = parent_ip; + } + #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ +diff --git a/arch/powerpc/kernel/trace/ftrace_64_pg.c b/arch/powerpc/kernel/trace/ftrace_64_pg.c +index 12fab1803bcf4..d3c5552e4984d 100644 +--- a/arch/powerpc/kernel/trace/ftrace_64_pg.c ++++ b/arch/powerpc/kernel/trace/ftrace_64_pg.c +@@ -829,7 +829,7 @@ __prepare_ftrace_return(unsigned long parent, unsigned long ip, unsigned long sp + void ftrace_graph_func(unsigned long ip, unsigned long parent_ip, + struct ftrace_ops *op, struct ftrace_regs *fregs) + { +- fregs->regs.link = __prepare_ftrace_return(parent_ip, ip, fregs->regs.gpr[1]); ++ arch_ftrace_regs(fregs)->regs.link = __prepare_ftrace_return(parent_ip, ip, arch_ftrace_regs(fregs)->regs.gpr[1]); + } + #else + unsigned long prepare_ftrace_return(unsigned long parent, unsigned long ip, +diff --git a/arch/riscv/include/asm/ftrace.h b/arch/riscv/include/asm/ftrace.h +index f253c8dae878e..8a97ce5077e73 100644 +--- a/arch/riscv/include/asm/ftrace.h ++++ b/arch/riscv/include/asm/ftrace.h +@@ -126,7 +126,10 @@ int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec); + #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS + #define arch_ftrace_get_regs(regs) NULL + struct ftrace_ops; +-struct ftrace_regs { ++struct ftrace_regs; ++#define arch_ftrace_regs(fregs) ((struct __arch_ftrace_regs *)(fregs)) ++ ++struct __arch_ftrace_regs { + unsigned long epc; + unsigned long ra; + unsigned long sp; +@@ -150,42 +153,42 @@ struct ftrace_regs { + static __always_inline unsigned long ftrace_regs_get_instruction_pointer(const struct ftrace_regs + *fregs) + { +- return fregs->epc; ++ return arch_ftrace_regs(fregs)->epc; + } + + static __always_inline void ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs, + unsigned long pc) + { +- fregs->epc = pc; ++ arch_ftrace_regs(fregs)->epc = pc; + } + + static __always_inline unsigned long ftrace_regs_get_stack_pointer(const struct ftrace_regs *fregs) + { +- return fregs->sp; ++ return arch_ftrace_regs(fregs)->sp; + } + + static __always_inline unsigned long ftrace_regs_get_argument(struct ftrace_regs *fregs, + unsigned int n) + { + if (n < 8) +- return fregs->args[n]; ++ return arch_ftrace_regs(fregs)->args[n]; + return 0; + } + + static __always_inline unsigned long ftrace_regs_get_return_value(const struct ftrace_regs *fregs) + { +- return fregs->a0; ++ return arch_ftrace_regs(fregs)->a0; + } + + static __always_inline void ftrace_regs_set_return_value(struct ftrace_regs *fregs, + unsigned long ret) + { +- fregs->a0 = ret; ++ arch_ftrace_regs(fregs)->a0 = ret; + } + + static __always_inline void ftrace_override_function_with_return(struct ftrace_regs *fregs) + { +- fregs->epc = fregs->ra; ++ arch_ftrace_regs(fregs)->epc = arch_ftrace_regs(fregs)->ra; + } + + int ftrace_regs_query_register_offset(const char *name); +@@ -196,7 +199,7 @@ void ftrace_graph_func(unsigned long ip, unsigned long parent_ip, + + static inline void arch_ftrace_set_direct_caller(struct ftrace_regs *fregs, unsigned long addr) + { +- fregs->t1 = addr; ++ arch_ftrace_regs(fregs)->t1 = addr; + } + #endif /* CONFIG_DYNAMIC_FTRACE_WITH_ARGS */ + +diff --git a/arch/riscv/kernel/asm-offsets.c b/arch/riscv/kernel/asm-offsets.c +index 05c6152a65310..dfed9986b45ed 100644 +--- a/arch/riscv/kernel/asm-offsets.c ++++ b/arch/riscv/kernel/asm-offsets.c +@@ -497,19 +497,19 @@ void asm_offsets(void) + OFFSET(STACKFRAME_RA, stackframe, ra); + + #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS +- DEFINE(FREGS_SIZE_ON_STACK, ALIGN(sizeof(struct ftrace_regs), STACK_ALIGN)); +- DEFINE(FREGS_EPC, offsetof(struct ftrace_regs, epc)); +- DEFINE(FREGS_RA, offsetof(struct ftrace_regs, ra)); +- DEFINE(FREGS_SP, offsetof(struct ftrace_regs, sp)); +- DEFINE(FREGS_S0, offsetof(struct ftrace_regs, s0)); +- DEFINE(FREGS_T1, offsetof(struct ftrace_regs, t1)); +- DEFINE(FREGS_A0, offsetof(struct ftrace_regs, a0)); +- DEFINE(FREGS_A1, offsetof(struct ftrace_regs, a1)); +- DEFINE(FREGS_A2, offsetof(struct ftrace_regs, a2)); +- DEFINE(FREGS_A3, offsetof(struct ftrace_regs, a3)); +- DEFINE(FREGS_A4, offsetof(struct ftrace_regs, a4)); +- DEFINE(FREGS_A5, offsetof(struct ftrace_regs, a5)); +- DEFINE(FREGS_A6, offsetof(struct ftrace_regs, a6)); +- DEFINE(FREGS_A7, offsetof(struct ftrace_regs, a7)); ++ DEFINE(FREGS_SIZE_ON_STACK, ALIGN(sizeof(struct __arch_ftrace_regs), STACK_ALIGN)); ++ DEFINE(FREGS_EPC, offsetof(struct __arch_ftrace_regs, epc)); ++ DEFINE(FREGS_RA, offsetof(struct __arch_ftrace_regs, ra)); ++ DEFINE(FREGS_SP, offsetof(struct __arch_ftrace_regs, sp)); ++ DEFINE(FREGS_S0, offsetof(struct __arch_ftrace_regs, s0)); ++ DEFINE(FREGS_T1, offsetof(struct __arch_ftrace_regs, t1)); ++ DEFINE(FREGS_A0, offsetof(struct __arch_ftrace_regs, a0)); ++ DEFINE(FREGS_A1, offsetof(struct __arch_ftrace_regs, a1)); ++ DEFINE(FREGS_A2, offsetof(struct __arch_ftrace_regs, a2)); ++ DEFINE(FREGS_A3, offsetof(struct __arch_ftrace_regs, a3)); ++ DEFINE(FREGS_A4, offsetof(struct __arch_ftrace_regs, a4)); ++ DEFINE(FREGS_A5, offsetof(struct __arch_ftrace_regs, a5)); ++ DEFINE(FREGS_A6, offsetof(struct __arch_ftrace_regs, a6)); ++ DEFINE(FREGS_A7, offsetof(struct __arch_ftrace_regs, a7)); + #endif + } +diff --git a/arch/riscv/kernel/ftrace.c b/arch/riscv/kernel/ftrace.c +index 4b95c574fd045..5081ad886841f 100644 +--- a/arch/riscv/kernel/ftrace.c ++++ b/arch/riscv/kernel/ftrace.c +@@ -214,7 +214,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, + void ftrace_graph_func(unsigned long ip, unsigned long parent_ip, + struct ftrace_ops *op, struct ftrace_regs *fregs) + { +- prepare_ftrace_return(&fregs->ra, ip, fregs->s0); ++ prepare_ftrace_return(&arch_ftrace_regs(fregs)->ra, ip, arch_ftrace_regs(fregs)->s0); + } + #else /* CONFIG_DYNAMIC_FTRACE_WITH_ARGS */ + extern void ftrace_graph_call(void); +diff --git a/arch/s390/include/asm/ftrace.h b/arch/s390/include/asm/ftrace.h +index 406746666eb78..1498d0a9c7625 100644 +--- a/arch/s390/include/asm/ftrace.h ++++ b/arch/s390/include/asm/ftrace.h +@@ -51,13 +51,16 @@ static inline unsigned long ftrace_call_adjust(unsigned long addr) + return addr; + } + +-struct ftrace_regs { ++struct ftrace_regs; ++#define arch_ftrace_regs(fregs) ((struct __arch_ftrace_regs *)(fregs)) ++ ++struct __arch_ftrace_regs { + struct pt_regs regs; + }; + + static __always_inline struct pt_regs *arch_ftrace_get_regs(struct ftrace_regs *fregs) + { +- struct pt_regs *regs = &fregs->regs; ++ struct pt_regs *regs = &arch_ftrace_regs(fregs)->regs; + + if (test_pt_regs_flag(regs, PIF_FTRACE_FULL_REGS)) + return regs; +@@ -84,26 +87,26 @@ static __always_inline unsigned long fgraph_ret_regs_frame_pointer(struct fgraph + static __always_inline unsigned long + ftrace_regs_get_instruction_pointer(const struct ftrace_regs *fregs) + { +- return fregs->regs.psw.addr; ++ return arch_ftrace_regs(fregs)->regs.psw.addr; + } + + static __always_inline void + ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs, + unsigned long ip) + { +- fregs->regs.psw.addr = ip; ++ arch_ftrace_regs(fregs)->regs.psw.addr = ip; + } + + #define ftrace_regs_get_argument(fregs, n) \ +- regs_get_kernel_argument(&(fregs)->regs, n) ++ regs_get_kernel_argument(&arch_ftrace_regs(fregs)->regs, n) + #define ftrace_regs_get_stack_pointer(fregs) \ +- kernel_stack_pointer(&(fregs)->regs) ++ kernel_stack_pointer(&arch_ftrace_regs(fregs)->regs) + #define ftrace_regs_return_value(fregs) \ +- regs_return_value(&(fregs)->regs) ++ regs_return_value(&arch_ftrace_regs(fregs)->regs) + #define ftrace_regs_set_return_value(fregs, ret) \ +- regs_set_return_value(&(fregs)->regs, ret) ++ regs_set_return_value(&arch_ftrace_regs(fregs)->regs, ret) + #define ftrace_override_function_with_return(fregs) \ +- override_function_with_return(&(fregs)->regs) ++ override_function_with_return(&arch_ftrace_regs(fregs)->regs) + #define ftrace_regs_query_register_offset(name) \ + regs_query_register_offset(name) + +@@ -117,7 +120,7 @@ ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs, + */ + static inline void arch_ftrace_set_direct_caller(struct ftrace_regs *fregs, unsigned long addr) + { +- struct pt_regs *regs = &fregs->regs; ++ struct pt_regs *regs = &arch_ftrace_regs(fregs)->regs; + regs->orig_gpr2 = addr; + } + #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */ +diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c +index 3cfc4939033c9..0bab4a9cdc768 100644 +--- a/arch/s390/kernel/asm-offsets.c ++++ b/arch/s390/kernel/asm-offsets.c +@@ -185,8 +185,8 @@ int main(void) + OFFSET(__FGRAPH_RET_FP, fgraph_ret_regs, fp); + DEFINE(__FGRAPH_RET_SIZE, sizeof(struct fgraph_ret_regs)); + #endif +- OFFSET(__FTRACE_REGS_PT_REGS, ftrace_regs, regs); +- DEFINE(__FTRACE_REGS_SIZE, sizeof(struct ftrace_regs)); ++ OFFSET(__FTRACE_REGS_PT_REGS, __arch_ftrace_regs, regs); ++ DEFINE(__FTRACE_REGS_SIZE, sizeof(struct __arch_ftrace_regs)); + + OFFSET(__PCPU_FLAGS, pcpu, flags); + return 0; +diff --git a/arch/s390/kernel/ftrace.c b/arch/s390/kernel/ftrace.c +index 0b6e62d1d8b87..51439a71e392c 100644 +--- a/arch/s390/kernel/ftrace.c ++++ b/arch/s390/kernel/ftrace.c +@@ -318,7 +318,7 @@ void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip, + if (bit < 0) + return; + +- kmsan_unpoison_memory(fregs, sizeof(*fregs)); ++ kmsan_unpoison_memory(fregs, ftrace_regs_size()); + regs = ftrace_get_regs(fregs); + p = get_kprobe((kprobe_opcode_t *)ip); + if (!regs || unlikely(!p) || kprobe_disabled(p)) +diff --git a/arch/s390/lib/test_unwind.c b/arch/s390/lib/test_unwind.c +index 8b7f981e6f347..6e42100875e75 100644 +--- a/arch/s390/lib/test_unwind.c ++++ b/arch/s390/lib/test_unwind.c +@@ -270,9 +270,9 @@ static void notrace __used test_unwind_ftrace_handler(unsigned long ip, + struct ftrace_ops *fops, + struct ftrace_regs *fregs) + { +- struct unwindme *u = (struct unwindme *)fregs->regs.gprs[2]; ++ struct unwindme *u = (struct unwindme *)arch_ftrace_regs(fregs)->regs.gprs[2]; + +- u->ret = test_unwind(NULL, (u->flags & UWM_REGS) ? &fregs->regs : NULL, ++ u->ret = test_unwind(NULL, (u->flags & UWM_REGS) ? &arch_ftrace_regs(fregs)->regs : NULL, + (u->flags & UWM_SP) ? u->sp : 0); + } + +diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h +index b4d719de2c845..62fed5547c2e1 100644 +--- a/arch/x86/include/asm/ftrace.h ++++ b/arch/x86/include/asm/ftrace.h +@@ -35,7 +35,10 @@ static inline unsigned long ftrace_call_adjust(unsigned long addr) + } + + #ifdef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS +-struct ftrace_regs { ++struct ftrace_regs; ++#define arch_ftrace_regs(fregs) ((struct __arch_ftrace_regs *)(fregs)) ++ ++struct __arch_ftrace_regs { + struct pt_regs regs; + }; + +@@ -43,27 +46,27 @@ static __always_inline struct pt_regs * + arch_ftrace_get_regs(struct ftrace_regs *fregs) + { + /* Only when FL_SAVE_REGS is set, cs will be non zero */ +- if (!fregs->regs.cs) ++ if (!arch_ftrace_regs(fregs)->regs.cs) + return NULL; +- return &fregs->regs; ++ return &arch_ftrace_regs(fregs)->regs; + } + + #define ftrace_regs_set_instruction_pointer(fregs, _ip) \ +- do { (fregs)->regs.ip = (_ip); } while (0) ++ do { arch_ftrace_regs(fregs)->regs.ip = (_ip); } while (0) + + #define ftrace_regs_get_instruction_pointer(fregs) \ +- ((fregs)->regs.ip) ++ arch_ftrace_regs(fregs)->regs.ip) + + #define ftrace_regs_get_argument(fregs, n) \ +- regs_get_kernel_argument(&(fregs)->regs, n) ++ regs_get_kernel_argument(&arch_ftrace_regs(fregs)->regs, n) + #define ftrace_regs_get_stack_pointer(fregs) \ +- kernel_stack_pointer(&(fregs)->regs) ++ kernel_stack_pointer(&arch_ftrace_regs(fregs)->regs) + #define ftrace_regs_return_value(fregs) \ +- regs_return_value(&(fregs)->regs) ++ regs_return_value(&arch_ftrace_regs(fregs)->regs) + #define ftrace_regs_set_return_value(fregs, ret) \ +- regs_set_return_value(&(fregs)->regs, ret) ++ regs_set_return_value(&arch_ftrace_regs(fregs)->regs, ret) + #define ftrace_override_function_with_return(fregs) \ +- override_function_with_return(&(fregs)->regs) ++ override_function_with_return(&arch_ftrace_regs(fregs)->regs) + #define ftrace_regs_query_register_offset(name) \ + regs_query_register_offset(name) + +@@ -90,7 +93,7 @@ __arch_ftrace_set_direct_caller(struct pt_regs *regs, unsigned long addr) + regs->orig_ax = addr; + } + #define arch_ftrace_set_direct_caller(fregs, addr) \ +- __arch_ftrace_set_direct_caller(&(fregs)->regs, addr) ++ __arch_ftrace_set_direct_caller(&arch_ftrace_regs(fregs)->regs, addr) + #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */ + + #ifdef CONFIG_DYNAMIC_FTRACE +diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c +index bfab966ea56e8..d3b14a9ad2edb 100644 +--- a/arch/x86/kernel/ftrace.c ++++ b/arch/x86/kernel/ftrace.c +@@ -647,7 +647,7 @@ void prepare_ftrace_return(unsigned long ip, unsigned long *parent, + void ftrace_graph_func(unsigned long ip, unsigned long parent_ip, + struct ftrace_ops *op, struct ftrace_regs *fregs) + { +- struct pt_regs *regs = &fregs->regs; ++ struct pt_regs *regs = &arch_ftrace_regs(fregs)->regs; + unsigned long *stack = (unsigned long *)kernel_stack_pointer(regs); + + prepare_ftrace_return(ip, (unsigned long *)stack, 0); +diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h +index 42106b3de3961..fc76ce4bf0b7e 100644 +--- a/include/linux/ftrace.h ++++ b/include/linux/ftrace.h +@@ -115,8 +115,6 @@ static inline int ftrace_mod_get_kallsym(unsigned int symnum, unsigned long *val + + extern int ftrace_enabled; + +-#ifndef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS +- + /** + * ftrace_regs - ftrace partial/optimal register set + * +@@ -142,11 +140,28 @@ extern int ftrace_enabled; + * + * NOTE: user *must not* access regs directly, only do it via APIs, because + * the member can be changed according to the architecture. ++ * This is why the structure is empty here, so that nothing accesses ++ * the ftrace_regs directly. + */ + struct ftrace_regs { ++ /* Nothing to see here, use the accessor functions! */ ++}; ++ ++#define ftrace_regs_size() sizeof(struct __arch_ftrace_regs) ++ ++#ifndef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS ++ ++struct __arch_ftrace_regs { + struct pt_regs regs; + }; +-#define arch_ftrace_get_regs(fregs) (&(fregs)->regs) ++ ++struct ftrace_regs; ++#define arch_ftrace_regs(fregs) ((struct __arch_ftrace_regs *)(fregs)) ++ ++static inline struct pt_regs *arch_ftrace_get_regs(struct ftrace_regs *fregs) ++{ ++ return &arch_ftrace_regs(fregs)->regs; ++} + + /* + * ftrace_regs_set_instruction_pointer() is to be defined by the architecture +diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c +index b2442aabccfd0..27718845f86d8 100644 +--- a/kernel/trace/ftrace.c ++++ b/kernel/trace/ftrace.c +@@ -7973,7 +7973,7 @@ __ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip, + void arch_ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip, + struct ftrace_ops *op, struct ftrace_regs *fregs) + { +- kmsan_unpoison_memory(fregs, sizeof(*fregs)); ++ kmsan_unpoison_memory(fregs, ftrace_regs_size()); + __ftrace_ops_list_func(ip, parent_ip, NULL, fregs); + } + #else +-- +2.51.0 + diff --git a/queue-6.12/ftrace-rename-ftrace_regs_return_value-to-ftrace_reg.patch b/queue-6.12/ftrace-rename-ftrace_regs_return_value-to-ftrace_reg.patch new file mode 100644 index 0000000000..0d463cf966 --- /dev/null +++ b/queue-6.12/ftrace-rename-ftrace_regs_return_value-to-ftrace_reg.patch @@ -0,0 +1,47 @@ +From 1898d6c511666f230aaee7623e3c108d10d5442a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 15 Oct 2024 10:28:53 +0900 +Subject: ftrace: Rename ftrace_regs_return_value to + ftrace_regs_get_return_value + +From: Masami Hiramatsu (Google) + +[ Upstream commit 2d17932da44fdc1ba835ad05110ab996d2912dbf ] + +Rename ftrace_regs_return_value to ftrace_regs_get_return_value as same as +other ftrace_regs_get/set_* APIs. arm64 and riscv are already using this +new name. + +Cc: Alexei Starovoitov +Cc: Florent Revest +Cc: Martin KaFai Lau +Cc: bpf +Cc: Alexei Starovoitov +Cc: Jiri Olsa +Cc: Alan Maguire +Link: https://lore.kernel.org/172895573350.107311.7564634260652361511.stgit@devnote2 +Acked-by: Mark Rutland +Signed-off-by: Masami Hiramatsu (Google) +Signed-off-by: Steven Rostedt (Google) +Stable-dep-of: aea251799998 ("x86/fgraph,bpf: Switch kprobe_multi program stack unwind to hw_regs path") +Signed-off-by: Sasha Levin +--- + include/linux/ftrace_regs.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/linux/ftrace_regs.h b/include/linux/ftrace_regs.h +index b78a0a60515b2..be1ed0c891d07 100644 +--- a/include/linux/ftrace_regs.h ++++ b/include/linux/ftrace_regs.h +@@ -22,7 +22,7 @@ struct ftrace_regs; + regs_get_kernel_argument(&arch_ftrace_regs(fregs)->regs, n) + #define ftrace_regs_get_stack_pointer(fregs) \ + kernel_stack_pointer(&arch_ftrace_regs(fregs)->regs) +-#define ftrace_regs_return_value(fregs) \ ++#define ftrace_regs_get_return_value(fregs) \ + regs_return_value(&arch_ftrace_regs(fregs)->regs) + #define ftrace_regs_set_return_value(fregs, ret) \ + regs_set_return_value(&arch_ftrace_regs(fregs)->regs, ret) +-- +2.51.0 + diff --git a/queue-6.12/ftrace-use-arch_ftrace_regs-for-ftrace_regs_-macros.patch b/queue-6.12/ftrace-use-arch_ftrace_regs-for-ftrace_regs_-macros.patch new file mode 100644 index 0000000000..f74545de06 --- /dev/null +++ b/queue-6.12/ftrace-use-arch_ftrace_regs-for-ftrace_regs_-macros.patch @@ -0,0 +1,63 @@ +From 68766746e58b4b745712525c6e2413e498804463 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 15 Oct 2024 10:28:43 +0900 +Subject: ftrace: Use arch_ftrace_regs() for ftrace_regs_*() macros + +From: Masami Hiramatsu (Google) + +[ Upstream commit 0b582611a8f4270fa357a22a546909b2dd5fc5fe ] + +Since the arch_ftrace_get_regs(fregs) is only valid when the +FL_SAVE_REGS is set, we need to use `&arch_ftrace_regs()->regs` for +ftrace_regs_*() APIs because those APIs are for ftrace_regs, not +complete pt_regs. + +Cc: Alexei Starovoitov +Cc: Florent Revest +Cc: Martin KaFai Lau +Cc: bpf +Cc: Alexei Starovoitov +Cc: Jiri Olsa +Cc: Alan Maguire +Cc: Mark Rutland +Link: https://lore.kernel.org/172895572290.107311.16057631001860177198.stgit@devnote2 +Fixes: e4cf33ca4812 ("ftrace: Consolidate ftrace_regs accessor functions for archs using pt_regs") +Signed-off-by: Masami Hiramatsu (Google) +Signed-off-by: Steven Rostedt (Google) +Stable-dep-of: aea251799998 ("x86/fgraph,bpf: Switch kprobe_multi program stack unwind to hw_regs path") +Signed-off-by: Sasha Levin +--- + include/linux/ftrace_regs.h | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/include/linux/ftrace_regs.h b/include/linux/ftrace_regs.h +index dea6a0851b749..b78a0a60515b2 100644 +--- a/include/linux/ftrace_regs.h ++++ b/include/linux/ftrace_regs.h +@@ -17,17 +17,17 @@ struct __arch_ftrace_regs { + struct ftrace_regs; + + #define ftrace_regs_get_instruction_pointer(fregs) \ +- instruction_pointer(arch_ftrace_get_regs(fregs)) ++ instruction_pointer(&arch_ftrace_regs(fregs)->regs) + #define ftrace_regs_get_argument(fregs, n) \ +- regs_get_kernel_argument(arch_ftrace_get_regs(fregs), n) ++ regs_get_kernel_argument(&arch_ftrace_regs(fregs)->regs, n) + #define ftrace_regs_get_stack_pointer(fregs) \ +- kernel_stack_pointer(arch_ftrace_get_regs(fregs)) ++ kernel_stack_pointer(&arch_ftrace_regs(fregs)->regs) + #define ftrace_regs_return_value(fregs) \ +- regs_return_value(arch_ftrace_get_regs(fregs)) ++ regs_return_value(&arch_ftrace_regs(fregs)->regs) + #define ftrace_regs_set_return_value(fregs, ret) \ +- regs_set_return_value(arch_ftrace_get_regs(fregs), ret) ++ regs_set_return_value(&arch_ftrace_regs(fregs)->regs, ret) + #define ftrace_override_function_with_return(fregs) \ +- override_function_with_return(arch_ftrace_get_regs(fregs)) ++ override_function_with_return(&arch_ftrace_regs(fregs)->regs) + #define ftrace_regs_query_register_offset(name) \ + regs_query_register_offset(name) + +-- +2.51.0 + diff --git a/queue-6.12/genirq-set-irqf_cond_oneshot-in-devm_request_irq.patch b/queue-6.12/genirq-set-irqf_cond_oneshot-in-devm_request_irq.patch new file mode 100644 index 0000000000..3d8f227d12 --- /dev/null +++ b/queue-6.12/genirq-set-irqf_cond_oneshot-in-devm_request_irq.patch @@ -0,0 +1,43 @@ +From 481380fbe66946fd3ad0afe368bbaeb7031aedf5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:55:21 +0100 +Subject: genirq: Set IRQF_COND_ONESHOT in devm_request_irq(). + +From: Sebastian Andrzej Siewior + +[ Upstream commit 943b052ded21feb84f293d40b06af3181cd0d0d7 ] + +The flag IRQF_COND_ONESHOT was already force-added to request_irq() because +the ACPI SCI interrupt handler is using the IRQF_ONESHOT flag which breaks +all shared handlers. + +devm_request_irq() needs the same change since some users, such as +int0002_vgpio, are using this function instead. + +Add IRQF_COND_ONESHOT to the flags passed to devm_request_irq(). + +Fixes: c37927a203fa2 ("genirq: Set IRQF_COND_ONESHOT in request_irq()") +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260128095540.863589-2-bigeasy@linutronix.de +Signed-off-by: Sasha Levin +--- + include/linux/interrupt.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h +index b378fbf885ce3..2125d4d9b44f2 100644 +--- a/include/linux/interrupt.h ++++ b/include/linux/interrupt.h +@@ -215,7 +215,7 @@ static inline int __must_check + devm_request_irq(struct device *dev, unsigned int irq, irq_handler_t handler, + unsigned long irqflags, const char *devname, void *dev_id) + { +- return devm_request_threaded_irq(dev, irq, handler, NULL, irqflags, ++ return devm_request_threaded_irq(dev, irq, handler, NULL, irqflags | IRQF_COND_ONESHOT, + devname, dev_id); + } + +-- +2.51.0 + diff --git a/queue-6.12/gfs2-fix-slab-use-after-free-in-qd_put.patch b/queue-6.12/gfs2-fix-slab-use-after-free-in-qd_put.patch new file mode 100644 index 0000000000..bce5499519 --- /dev/null +++ b/queue-6.12/gfs2-fix-slab-use-after-free-in-qd_put.patch @@ -0,0 +1,45 @@ +From 48f2595d2d539ea0e64969c44f2c331b8f183df0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 14 Dec 2025 16:47:34 +0000 +Subject: gfs2: Fix slab-use-after-free in qd_put + +From: Andreas Gruenbacher + +[ Upstream commit 22150a7d401d9e9169b9b68e05bed95f7f49bf69 ] + +Commit a475c5dd16e5 ("gfs2: Free quota data objects synchronously") +started freeing quota data objects during filesystem shutdown instead of +putting them back onto the LRU list, but it failed to remove these +objects from the LRU list, causing LRU list corruption. This caused +use-after-free when the shrinker (gfs2_qd_shrink_scan) tried to access +already-freed objects on the LRU list. + +Fix this by removing qd objects from the LRU list before freeing them in +qd_put(). + +Initial fix from Deepanshu Kartikey . + +Fixes: a475c5dd16e5 ("gfs2: Free quota data objects synchronously") +Reported-by: syzbot+046b605f01802054bff0@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=046b605f01802054bff0 +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Sasha Levin +--- + fs/gfs2/quota.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c +index 642584265a6f4..95b20e6a3fbc6 100644 +--- a/fs/gfs2/quota.c ++++ b/fs/gfs2/quota.c +@@ -336,6 +336,7 @@ static void qd_put(struct gfs2_quota_data *qd) + lockref_mark_dead(&qd->qd_lockref); + spin_unlock(&qd->qd_lockref.lock); + ++ list_lru_del_obj(&gfs2_qd_lru, &qd->qd_lru); + gfs2_qd_dispose(qd); + return; + } +-- +2.51.0 + diff --git a/queue-6.12/gfs2-fix-use-after-free-in-iomap-inline-data-write-p.patch b/queue-6.12/gfs2-fix-use-after-free-in-iomap-inline-data-write-p.patch new file mode 100644 index 0000000000..c6985c1ac5 --- /dev/null +++ b/queue-6.12/gfs2-fix-use-after-free-in-iomap-inline-data-write-p.patch @@ -0,0 +1,84 @@ +From de82891ebedcdd6d743cb210a51e1c67d22e9e30 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 14:51:34 +0530 +Subject: gfs2: Fix use-after-free in iomap inline data write path + +From: Deepanshu Kartikey + +[ Upstream commit faddeb848305e79db89ee0479bb0e33380656321 ] + +The inline data buffer head (dibh) is being released prematurely in +gfs2_iomap_begin() via release_metapath() while iomap->inline_data +still points to dibh->b_data. This causes a use-after-free when +iomap_write_end_inline() later attempts to write to the inline data +area. + +The bug sequence: +1. gfs2_iomap_begin() calls gfs2_meta_inode_buffer() to read inode + metadata into dibh +2. Sets iomap->inline_data = dibh->b_data + sizeof(struct gfs2_dinode) +3. Calls release_metapath() which calls brelse(dibh), dropping refcount + to 0 +4. kswapd reclaims the page (~39ms later in the syzbot report) +5. iomap_write_end_inline() tries to memcpy() to iomap->inline_data +6. KASAN detects use-after-free write to freed memory + +Fix by storing dibh in iomap->private and incrementing its refcount +with get_bh() in gfs2_iomap_begin(). The buffer is then properly +released in gfs2_iomap_end() after the inline write completes, +ensuring the page stays alive for the entire iomap operation. + +Note: A C reproducer is not available for this issue. The fix is based +on analysis of the KASAN report and code review showing the buffer head +is freed before use. + +[agruenba: Take buffer head reference in gfs2_iomap_begin() to avoid +leaks in gfs2_iomap_get() and gfs2_iomap_alloc().] + +Reported-by: syzbot+ea1cd4aa4d1e98458a55@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=ea1cd4aa4d1e98458a55 +Fixes: d0a22a4b03b8 ("gfs2: Fix iomap write page reclaim deadlock") +Signed-off-by: Deepanshu Kartikey +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Sasha Levin +--- + fs/gfs2/bmap.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c +index 28ad07b003484..776090fbc9aa5 100644 +--- a/fs/gfs2/bmap.c ++++ b/fs/gfs2/bmap.c +@@ -1124,10 +1124,18 @@ static int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length, + goto out_unlock; + break; + default: +- goto out_unlock; ++ goto out; + } + + ret = gfs2_iomap_begin_write(inode, pos, length, flags, iomap, &mp); ++ if (ret) ++ goto out_unlock; ++ ++out: ++ if (iomap->type == IOMAP_INLINE) { ++ iomap->private = metapath_dibh(&mp); ++ get_bh(iomap->private); ++ } + + out_unlock: + release_metapath(&mp); +@@ -1141,6 +1149,9 @@ static int gfs2_iomap_end(struct inode *inode, loff_t pos, loff_t length, + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); + ++ if (iomap->private) ++ brelse(iomap->private); ++ + switch (flags & (IOMAP_WRITE | IOMAP_ZERO)) { + case IOMAP_WRITE: + if (flags & IOMAP_DIRECT) +-- +2.51.0 + diff --git a/queue-6.12/gfs2-retries-missing-in-gfs2_-rename-exchange.patch b/queue-6.12/gfs2-retries-missing-in-gfs2_-rename-exchange.patch new file mode 100644 index 0000000000..da76fee072 --- /dev/null +++ b/queue-6.12/gfs2-retries-missing-in-gfs2_-rename-exchange.patch @@ -0,0 +1,178 @@ +From b2df36e2347b6ee1e626d98c9b68aa398632d8c5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 22:59:12 +0000 +Subject: gfs2: Retries missing in gfs2_{rename,exchange} + +From: Andreas Gruenbacher + +[ Upstream commit 11d763f0b0afc2cf5f92f4adae5dbbbbef712f8f ] + +Fix a bug in gfs2's asynchronous glock handling for rename and exchange +operations. The original async implementation from commit ad26967b9afa +("gfs2: Use async glocks for rename") mentioned that retries were needed +but never implemented them, causing operations to fail with -ESTALE +instead of retrying on timeout. + +Also makes the waiting interruptible. + +In addition, the timeouts used were too high for situations in which +timing out is a rare but expected scenario. Switch to shorter timeouts +with randomization and exponentional backoff. + +Fixes: ad26967b9afa ("gfs2: Use async glocks for rename") +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Sasha Levin +--- + fs/gfs2/glock.c | 36 +++++++++++++++++++++++++++--------- + fs/gfs2/glock.h | 3 ++- + fs/gfs2/inode.c | 18 ++++++++++++++---- + 3 files changed, 43 insertions(+), 14 deletions(-) + +diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c +index 54d0eee24e10b..1a1cd631b5880 100644 +--- a/fs/gfs2/glock.c ++++ b/fs/gfs2/glock.c +@@ -1393,31 +1393,45 @@ static int glocks_pending(unsigned int num_gh, struct gfs2_holder *ghs) + * gfs2_glock_async_wait - wait on multiple asynchronous glock acquisitions + * @num_gh: the number of holders in the array + * @ghs: the glock holder array ++ * @retries: number of retries attempted so far + * + * Returns: 0 on success, meaning all glocks have been granted and are held. + * -ESTALE if the request timed out, meaning all glocks were released, + * and the caller should retry the operation. + */ + +-int gfs2_glock_async_wait(unsigned int num_gh, struct gfs2_holder *ghs) ++int gfs2_glock_async_wait(unsigned int num_gh, struct gfs2_holder *ghs, ++ unsigned int retries) + { + struct gfs2_sbd *sdp = ghs[0].gh_gl->gl_name.ln_sbd; +- int i, ret = 0, timeout = 0; + unsigned long start_time = jiffies; ++ int i, ret = 0; ++ long timeout; + + might_sleep(); +- /* +- * Total up the (minimum hold time * 2) of all glocks and use that to +- * determine the max amount of time we should wait. +- */ +- for (i = 0; i < num_gh; i++) +- timeout += ghs[i].gh_gl->gl_hold_time << 1; + +- if (!wait_event_timeout(sdp->sd_async_glock_wait, ++ timeout = GL_GLOCK_MIN_HOLD; ++ if (retries) { ++ unsigned int max_shift; ++ long incr; ++ ++ /* Add a random delay and increase the timeout exponentially. */ ++ max_shift = BITS_PER_LONG - 2 - __fls(GL_GLOCK_HOLD_INCR); ++ incr = min(GL_GLOCK_HOLD_INCR << min(retries - 1, max_shift), ++ 10 * HZ - GL_GLOCK_MIN_HOLD); ++ schedule_timeout_interruptible(get_random_long() % (incr / 3)); ++ if (signal_pending(current)) ++ goto interrupted; ++ timeout += (incr / 3) + get_random_long() % (incr / 3); ++ } ++ ++ if (!wait_event_interruptible_timeout(sdp->sd_async_glock_wait, + !glocks_pending(num_gh, ghs), timeout)) { + ret = -ESTALE; /* request timed out. */ + goto out; + } ++ if (signal_pending(current)) ++ goto interrupted; + + for (i = 0; i < num_gh; i++) { + struct gfs2_holder *gh = &ghs[i]; +@@ -1441,6 +1455,10 @@ int gfs2_glock_async_wait(unsigned int num_gh, struct gfs2_holder *ghs) + } + } + return ret; ++ ++interrupted: ++ ret = -EINTR; ++ goto out; + } + + /** +diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h +index 63e101d448e96..b54cc21cac7e6 100644 +--- a/fs/gfs2/glock.h ++++ b/fs/gfs2/glock.h +@@ -190,7 +190,8 @@ int gfs2_glock_poll(struct gfs2_holder *gh); + int gfs2_instantiate(struct gfs2_holder *gh); + int gfs2_glock_holder_ready(struct gfs2_holder *gh); + int gfs2_glock_wait(struct gfs2_holder *gh); +-int gfs2_glock_async_wait(unsigned int num_gh, struct gfs2_holder *ghs); ++int gfs2_glock_async_wait(unsigned int num_gh, struct gfs2_holder *ghs, ++ unsigned int retries); + void gfs2_glock_dq(struct gfs2_holder *gh); + void gfs2_glock_dq_wait(struct gfs2_holder *gh); + void gfs2_glock_dq_uninit(struct gfs2_holder *gh); +diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c +index 90c7a795112d6..c8a59bc1714bf 100644 +--- a/fs/gfs2/inode.c ++++ b/fs/gfs2/inode.c +@@ -1504,7 +1504,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, + unsigned int num_gh; + int dir_rename = 0; + struct gfs2_diradd da = { .nr_blocks = 0, .save_loc = 0, }; +- unsigned int x; ++ unsigned int retries = 0, x; + int error; + + gfs2_holder_mark_uninitialized(&r_gh); +@@ -1554,12 +1554,17 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, + num_gh++; + } + ++again: + for (x = 0; x < num_gh; x++) { + error = gfs2_glock_nq(ghs + x); + if (error) + goto out_gunlock; + } +- error = gfs2_glock_async_wait(num_gh, ghs); ++ error = gfs2_glock_async_wait(num_gh, ghs, retries); ++ if (error == -ESTALE) { ++ retries++; ++ goto again; ++ } + if (error) + goto out_gunlock; + +@@ -1748,7 +1753,7 @@ static int gfs2_exchange(struct inode *odir, struct dentry *odentry, + struct gfs2_sbd *sdp = GFS2_SB(odir); + struct gfs2_holder ghs[4], r_gh; + unsigned int num_gh; +- unsigned int x; ++ unsigned int retries = 0, x; + umode_t old_mode = oip->i_inode.i_mode; + umode_t new_mode = nip->i_inode.i_mode; + int error; +@@ -1792,13 +1797,18 @@ static int gfs2_exchange(struct inode *odir, struct dentry *odentry, + gfs2_holder_init(nip->i_gl, LM_ST_EXCLUSIVE, GL_ASYNC, ghs + num_gh); + num_gh++; + ++again: + for (x = 0; x < num_gh; x++) { + error = gfs2_glock_nq(ghs + x); + if (error) + goto out_gunlock; + } + +- error = gfs2_glock_async_wait(num_gh, ghs); ++ error = gfs2_glock_async_wait(num_gh, ghs, retries); ++ if (error == -ESTALE) { ++ retries++; ++ goto again; ++ } + if (error) + goto out_gunlock; + +-- +2.51.0 + diff --git a/queue-6.12/hfsplus-return-error-when-node-already-exists-in-hfs.patch b/queue-6.12/hfsplus-return-error-when-node-already-exists-in-hfs.patch new file mode 100644 index 0000000000..f1c23b123e --- /dev/null +++ b/queue-6.12/hfsplus-return-error-when-node-already-exists-in-hfs.patch @@ -0,0 +1,58 @@ +From 4b68280d275981157d81c3449834fb493e9fca92 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Dec 2025 02:19:38 +0530 +Subject: hfsplus: return error when node already exists in hfs_bnode_create + +From: Shardul Bankar + +[ Upstream commit d8a73cc46c8462a969a7516131feb3096f4c49d3 ] + +When hfs_bnode_create() finds that a node is already hashed (which should +not happen in normal operation), it currently returns the existing node +without incrementing its reference count. This causes a reference count +inconsistency that leads to a kernel panic when the node is later freed +in hfs_bnode_put(): + + kernel BUG at fs/hfsplus/bnode.c:676! + BUG_ON(!atomic_read(&node->refcnt)) + +This scenario can occur when hfs_bmap_alloc() attempts to allocate a node +that is already in use (e.g., when node 0's bitmap bit is incorrectly +unset), or due to filesystem corruption. + +Returning an existing node from a create path is not normal operation. + +Fix this by returning ERR_PTR(-EEXIST) instead of the node when it's +already hashed. This properly signals the error condition to callers, +which already check for IS_ERR() return values. + +Reported-by: syzbot+1c8ff72d0cd8a50dfeaa@syzkaller.appspotmail.com +Link: https://syzkaller.appspot.com/bug?extid=1c8ff72d0cd8a50dfeaa +Link: https://lore.kernel.org/all/784415834694f39902088fa8946850fc1779a318.camel@ibm.com/ +Fixes: 634725a92938 ("[PATCH] hfs: cleanup HFS+ prints") +Signed-off-by: Shardul Bankar +Reviewed-by: Viacheslav Dubeyko +Signed-off-by: Viacheslav Dubeyko +Link: https://lore.kernel.org/r/20251229204938.1907089-1-shardul.b@mpiricsoftware.com +Signed-off-by: Viacheslav Dubeyko +Signed-off-by: Sasha Levin +--- + fs/hfsplus/bnode.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/hfsplus/bnode.c b/fs/hfsplus/bnode.c +index c0089849be50e..fb437598e2625 100644 +--- a/fs/hfsplus/bnode.c ++++ b/fs/hfsplus/bnode.c +@@ -629,7 +629,7 @@ struct hfs_bnode *hfs_bnode_create(struct hfs_btree *tree, u32 num) + if (node) { + pr_crit("new node %u already hashed?\n", num); + WARN_ON(1); +- return node; ++ return ERR_PTR(-EEXIST); + } + node = __hfs_bnode_create(tree, num); + if (!node) +-- +2.51.0 + diff --git a/queue-6.12/hid-intel-ish-hid-fix-null-ptr-deref-in-ishtp_bus_re.patch b/queue-6.12/hid-intel-ish-hid-fix-null-ptr-deref-in-ishtp_bus_re.patch new file mode 100644 index 0000000000..4969b972dc --- /dev/null +++ b/queue-6.12/hid-intel-ish-hid-fix-null-ptr-deref-in-ishtp_bus_re.patch @@ -0,0 +1,50 @@ +From 44ab4402019efd3de75ac6b568d698b8f49cb1b5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 13:34:56 +0800 +Subject: HID: intel-ish-hid: fix NULL-ptr-deref in + ishtp_bus_remove_all_clients + +From: Ryan Lin + +[ Upstream commit 56f7db581ee73af53cd512e00a6261a025bf1d58 ] + +During a warm reset flow, the cl->device pointer may be NULL if the +reset occurs while clients are still being enumerated. Accessing +cl->device->reference_count without a NULL check leads to a kernel panic. + +This issue was identified during multi-unit warm reboot stress clycles. +Add a defensive NULL check for cl->device to ensure stability under +such intensive testing conditions. + +KASAN: null-ptr-deref in range [0000000000000000-0000000000000007] +Workqueue: ish_fw_update_wq fw_reset_work_fn + +Call Trace: + ishtp_bus_remove_all_clients+0xbe/0x130 [intel_ishtp] + ishtp_reset_handler+0x85/0x1a0 [intel_ishtp] + fw_reset_work_fn+0x8a/0xc0 [intel_ish_ipc] + +Fixes: 3703f53b99e4a ("HID: intel_ish-hid: ISH Transport layer") +Signed-off-by: Ryan Lin +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/intel-ish-hid/ishtp/bus.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/hid/intel-ish-hid/ishtp/bus.c b/drivers/hid/intel-ish-hid/ishtp/bus.c +index fddc1c4b6cedb..03c68fe40925b 100644 +--- a/drivers/hid/intel-ish-hid/ishtp/bus.c ++++ b/drivers/hid/intel-ish-hid/ishtp/bus.c +@@ -730,7 +730,7 @@ void ishtp_bus_remove_all_clients(struct ishtp_device *ishtp_dev, + spin_lock_irqsave(&ishtp_dev->cl_list_lock, flags); + list_for_each_entry(cl, &ishtp_dev->cl_list, link) { + cl->state = ISHTP_CL_DISCONNECTED; +- if (warm_reset && cl->device->reference_count) ++ if (warm_reset && cl->device && cl->device->reference_count) + continue; + + /* +-- +2.51.0 + diff --git a/queue-6.12/hid-playstation-add-missing-check-for-input_ff_creat.patch b/queue-6.12/hid-playstation-add-missing-check-for-input_ff_creat.patch new file mode 100644 index 0000000000..90c8a30eb3 --- /dev/null +++ b/queue-6.12/hid-playstation-add-missing-check-for-input_ff_creat.patch @@ -0,0 +1,41 @@ +From 237b94a085500bf8a036468dd534c71020fb7faa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 17 Nov 2025 16:28:08 +0800 +Subject: HID: playstation: Add missing check for input_ff_create_memless + +From: Haotian Zhang + +[ Upstream commit e6807641ac94e832988655a1c0e60ccc806b76dc ] + +The ps_gamepad_create() function calls input_ff_create_memless() +without verifying its return value, which can lead to incorrect +behavior or potential crashes when FF effects are triggered. + +Add a check for the return value of input_ff_create_memless(). + +Fixes: 51151098d7ab ("HID: playstation: add DualSense classic rumble support.") +Signed-off-by: Haotian Zhang +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-playstation.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c +index 71a8d4ec9913b..b13a8f27cda0c 100644 +--- a/drivers/hid/hid-playstation.c ++++ b/drivers/hid/hid-playstation.c +@@ -739,7 +739,9 @@ static struct input_dev *ps_gamepad_create(struct hid_device *hdev, + #if IS_ENABLED(CONFIG_PLAYSTATION_FF) + if (play_effect) { + input_set_capability(gamepad, EV_FF, FF_RUMBLE); +- input_ff_create_memless(gamepad, NULL, play_effect); ++ ret = input_ff_create_memless(gamepad, NULL, play_effect); ++ if (ret) ++ return ERR_PTR(ret); + } + #endif + +-- +2.51.0 + diff --git a/queue-6.12/hrtimer-fix-trace-oddity.patch b/queue-6.12/hrtimer-fix-trace-oddity.patch new file mode 100644 index 0000000000..d35b006e15 --- /dev/null +++ b/queue-6.12/hrtimer-fix-trace-oddity.patch @@ -0,0 +1,43 @@ +From 9445a02c612feee49ad0711209e4e6080d4e9b1b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 11:38:34 +0100 +Subject: hrtimer: Fix trace oddity + +From: Thomas Gleixner + +[ Upstream commit 5d6446f409da00e5a389125ddb5ce09f5bc404c9 ] + +It turns out that __run_hrtimer() will trace like: + + -0 [032] d.h2. 20705.474563: hrtimer_cancel: hrtimer=0xff2db8f77f8226e8 + -0 [032] d.h1. 20705.474563: hrtimer_expire_entry: hrtimer=0xff2db8f77f8226e8 now=20699452001850 function=tick_nohz_handler/0x0 + +Which is a bit nonsensical, the timer doesn't get canceled on +expiration. The cause is the use of the incorrect debug helper. + +Fixes: c6a2a1770245 ("hrtimer: Add tracepoint for hrtimers") +Reported-by: Peter Zijlstra (Intel) +Signed-off-by: Thomas Gleixner +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260121143208.219595606@infradead.org +Signed-off-by: Sasha Levin +--- + kernel/time/hrtimer.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c +index 184d5c3d89bac..640d2ea4bd1fa 100644 +--- a/kernel/time/hrtimer.c ++++ b/kernel/time/hrtimer.c +@@ -1714,7 +1714,7 @@ static void __run_hrtimer(struct hrtimer_cpu_base *cpu_base, + + lockdep_assert_held(&cpu_base->lock); + +- debug_deactivate(timer); ++ debug_hrtimer_deactivate(timer); + base->running = timer; + + /* +-- +2.51.0 + diff --git a/queue-6.12/hwmon-pmbus-mpq8785-add-support-for-mpm82504.patch b/queue-6.12/hwmon-pmbus-mpq8785-add-support-for-mpm82504.patch new file mode 100644 index 0000000000..76c3546bd2 --- /dev/null +++ b/queue-6.12/hwmon-pmbus-mpq8785-add-support-for-mpm82504.patch @@ -0,0 +1,153 @@ +From 7e7cc4f6171d6a8f2c1805f84209e0066ecc7cf5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 11 May 2025 05:55:47 +0200 +Subject: hwmon: pmbus: mpq8785: Add support for MPM82504 + +From: Pawel Dembicki + +[ Upstream commit c27291468eb957b11dc81cd35fad36faf0861c07 ] + +Add support for the Monolithic Power Systems MPM82504 digital voltage +regulator. MPM82504 uses PMBus direct format for voltage output. + +Tested with device tree based matching. + +Signed-off-by: Pawel Dembicki +Link: https://lore.kernel.org/r/20250511035701.2607947-5-paweldembicki@gmail.com +Signed-off-by: Guenter Roeck +Stable-dep-of: 9e33c1dba224 ("hwmon: (pmbus/mpq8785) fix VOUT_MODE mismatch during identification") +Signed-off-by: Sasha Levin +--- + Documentation/hwmon/mpq8785.rst | 20 +++++++++++++++----- + drivers/hwmon/pmbus/mpq8785.c | 29 ++++++++++++++++++++++++++++- + 2 files changed, 43 insertions(+), 6 deletions(-) + +diff --git a/Documentation/hwmon/mpq8785.rst b/Documentation/hwmon/mpq8785.rst +index bf8176b870868..b91fefb1a84cd 100644 +--- a/Documentation/hwmon/mpq8785.rst ++++ b/Documentation/hwmon/mpq8785.rst +@@ -5,6 +5,7 @@ Kernel driver mpq8785 + + Supported chips: + ++ * MPS MPM82504 + * MPS MPQ8785 + + Prefix: 'mpq8785' +@@ -14,6 +15,14 @@ Author: Charles Hsu + Description + ----------- + ++The MPM82504 is a quad 25A, scalable, fully integrated power module with a PMBus ++interface. The device offers a complete power solution that achieves up to 25A ++per output channel. The MPM82504 has four output channels that can be paralleled ++to provide 50A, 75A, or 100A of output current for flexible configurations. ++The device can also operate in parallel with the MPM3695-100 and additional ++MPM82504 devices to provide a higher output current. The MPM82504 operates ++at high efficiency across a wide load range. ++ + The MPQ8785 is a fully integrated, PMBus-compatible, high-frequency, synchronous + buck converter. The MPQ8785 offers a very compact solution that achieves up to + 40A output current per phase, with excellent load and line regulation over a +@@ -23,18 +32,19 @@ output current load range. + The PMBus interface provides converter configurations and key parameters + monitoring. + +-The MPQ8785 adopts MPS's proprietary multi-phase digital constant-on-time (MCOT) ++The devices adopts MPS's proprietary multi-phase digital constant-on-time (MCOT) + control, which provides fast transient response and eases loop stabilization. +-The MCOT scheme also allows multiple MPQ8785 devices to be connected in parallel +-with excellent current sharing and phase interleaving for high-current ++The MCOT scheme also allows multiple devices or channels to be connected in ++parallel with excellent current sharing and phase interleaving for high-current + applications. + + Fully integrated protection features include over-current protection (OCP), + over-voltage protection (OVP), under-voltage protection (UVP), and + over-temperature protection (OTP). + +-The MPQ8785 requires a minimal number of readily available, standard external +-components, and is available in a TLGA (5mmx6mm) package. ++All supported modules require a minimal number of readily available, standard ++external components. The MPM82504 is available in a BGA (15mmx30mmx5.18mm) ++package and the MPQ8785 is available in a TLGA (5mmx6mm) package. + + Device compliant with: + +diff --git a/drivers/hwmon/pmbus/mpq8785.c b/drivers/hwmon/pmbus/mpq8785.c +index 1f13959c381eb..c8343fee38d9a 100644 +--- a/drivers/hwmon/pmbus/mpq8785.c ++++ b/drivers/hwmon/pmbus/mpq8785.c +@@ -4,14 +4,18 @@ + */ + + #include ++#include + #include + #include + #include + #include "pmbus.h" + +-enum chips { mpq8785 }; ++#define MPM82504_READ_TEMPERATURE_1_SIGN_POS 9 ++ ++enum chips { mpm82504, mpq8785 }; + + static u16 voltage_scale_loop_max_val[] = { ++ [mpm82504] = GENMASK(9, 0), + [mpq8785] = GENMASK(10, 0), + }; + +@@ -41,6 +45,20 @@ static int mpq8785_identify(struct i2c_client *client, + return 0; + }; + ++static int mpm82504_read_word_data(struct i2c_client *client, int page, ++ int phase, int reg) ++{ ++ int ret; ++ ++ ret = pmbus_read_word_data(client, page, phase, reg); ++ ++ if (ret < 0 || reg != PMBUS_READ_TEMPERATURE_1) ++ return ret; ++ ++ /* Fix PMBUS_READ_TEMPERATURE_1 signedness */ ++ return sign_extend32(ret, MPM82504_READ_TEMPERATURE_1_SIGN_POS) & 0xffff; ++} ++ + static struct pmbus_driver_info mpq8785_info = { + .pages = 1, + .format[PSC_VOLTAGE_IN] = direct, +@@ -63,12 +81,14 @@ static struct pmbus_driver_info mpq8785_info = { + }; + + static const struct i2c_device_id mpq8785_id[] = { ++ { "mpm82504", mpm82504 }, + { "mpq8785", mpq8785 }, + { }, + }; + MODULE_DEVICE_TABLE(i2c, mpq8785_id); + + static const struct of_device_id __maybe_unused mpq8785_of_match[] = { ++ { .compatible = "mps,mpm82504", .data = (void *)mpm82504 }, + { .compatible = "mps,mpq8785", .data = (void *)mpq8785 }, + {} + }; +@@ -92,6 +112,13 @@ static int mpq8785_probe(struct i2c_client *client) + chip_id = (kernel_ulong_t)i2c_get_match_data(client); + + switch (chip_id) { ++ case mpm82504: ++ info->format[PSC_VOLTAGE_OUT] = direct; ++ info->m[PSC_VOLTAGE_OUT] = 8; ++ info->b[PSC_VOLTAGE_OUT] = 0; ++ info->R[PSC_VOLTAGE_OUT] = 2; ++ info->read_word_data = mpm82504_read_word_data; ++ break; + case mpq8785: + info->identify = mpq8785_identify; + break; +-- +2.51.0 + diff --git a/queue-6.12/hwmon-pmbus-mpq8785-fix-vout_mode-mismatch-during-id.patch b/queue-6.12/hwmon-pmbus-mpq8785-fix-vout_mode-mismatch-during-id.patch new file mode 100644 index 0000000000..f56ce73cf6 --- /dev/null +++ b/queue-6.12/hwmon-pmbus-mpq8785-fix-vout_mode-mismatch-during-id.patch @@ -0,0 +1,81 @@ +From be0f8d85038a6ca67fb45a188f5609dc11f87e96 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Feb 2026 15:26:34 +0800 +Subject: hwmon: (pmbus/mpq8785) fix VOUT_MODE mismatch during identification + +From: Carl Lee + +[ Upstream commit 9e33c1dba22431bea9b2bf48adf56859e52fc7ec ] + +When MPQ8785 reports VOUT_MODE as VID mode, mpq8785_identify() +configures the driver for direct mode. The subsequent +pmbus_identify_common() check then fails due to a mismatch +between the reported mode and the configured mode, causing +device initialization to fail. + +Override the reported VOUT_MODE to direct mode to keep the +driver configuration consistent with the reported mode and +allow successful device initialization. + +This does not change how voltages are interpreted, but avoids +a false identification failure caused by mismatched mode +handling. + +Fixes: f20b4a931130c ("hwmon: Add driver for MPS MPQ8785 Synchronous Step-Down Converter") +Signed-off-by: Carl Lee +Link: https://lore.kernel.org/r/20260210-dt-bindings-hwmon-pmbus-mpq8785-add-mpq8786-support-v3-1-84636ccfe76f@amd.com +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + drivers/hwmon/pmbus/mpq8785.c | 28 ++++++++++++++++++++++++++++ + 1 file changed, 28 insertions(+) + +diff --git a/drivers/hwmon/pmbus/mpq8785.c b/drivers/hwmon/pmbus/mpq8785.c +index c8343fee38d9a..7c08f64a7f0a9 100644 +--- a/drivers/hwmon/pmbus/mpq8785.c ++++ b/drivers/hwmon/pmbus/mpq8785.c +@@ -45,6 +45,33 @@ static int mpq8785_identify(struct i2c_client *client, + return 0; + }; + ++static int mpq8785_read_byte_data(struct i2c_client *client, int page, int reg) ++{ ++ int ret; ++ ++ switch (reg) { ++ case PMBUS_VOUT_MODE: ++ ret = pmbus_read_byte_data(client, page, reg); ++ if (ret < 0) ++ return ret; ++ ++ if ((ret >> 5) == 1) { ++ /* ++ * The MPQ8785 chip reports VOUT_MODE as VID mode, but the driver ++ * treats VID as direct mode. Without this, identification would fail ++ * due to mode mismatch. ++ * This override ensures the reported mode matches the driver ++ * configuration, allowing successful initialization. ++ */ ++ return PB_VOUT_MODE_DIRECT; ++ } ++ ++ return ret; ++ default: ++ return -ENODATA; ++ } ++} ++ + static int mpm82504_read_word_data(struct i2c_client *client, int page, + int phase, int reg) + { +@@ -121,6 +148,7 @@ static int mpq8785_probe(struct i2c_client *client) + break; + case mpq8785: + info->identify = mpq8785_identify; ++ info->read_byte_data = mpq8785_read_byte_data; + break; + default: + return -ENODEV; +-- +2.51.0 + diff --git a/queue-6.12/hwmon-pmbus-mpq8785-implement-vout-feedback-resistor.patch b/queue-6.12/hwmon-pmbus-mpq8785-implement-vout-feedback-resistor.patch new file mode 100644 index 0000000000..26a9452458 --- /dev/null +++ b/queue-6.12/hwmon-pmbus-mpq8785-implement-vout-feedback-resistor.patch @@ -0,0 +1,78 @@ +From 3d7f3726d319bcb508a472acc58066e6ae80219e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 11 May 2025 05:55:46 +0200 +Subject: hwmon: pmbus: mpq8785: Implement VOUT feedback resistor divider ratio + configuration + +From: Pawel Dembicki + +[ Upstream commit dc1a4bab48d513e426118e42b9c371d942ddb04b ] + +Implement support for setting the VOUT_SCALE_LOOP PMBus register +based on an optional device tree property +"mps,vout-fb-divider-ratio-permille". + +This allows the driver to provide the correct VOUT value depending +on the feedback voltage divider configuration for chips where the +bootloader does not configure the VOUT_SCALE_LOOP register. + +Signed-off-by: Pawel Dembicki +Link: https://lore.kernel.org/r/20250511035701.2607947-4-paweldembicki@gmail.com +Signed-off-by: Guenter Roeck +Stable-dep-of: 9e33c1dba224 ("hwmon: (pmbus/mpq8785) fix VOUT_MODE mismatch during identification") +Signed-off-by: Sasha Levin +--- + drivers/hwmon/pmbus/mpq8785.c | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/drivers/hwmon/pmbus/mpq8785.c b/drivers/hwmon/pmbus/mpq8785.c +index e260cb3b34c45..1f13959c381eb 100644 +--- a/drivers/hwmon/pmbus/mpq8785.c ++++ b/drivers/hwmon/pmbus/mpq8785.c +@@ -5,11 +5,16 @@ + + #include + #include ++#include + #include + #include "pmbus.h" + + enum chips { mpq8785 }; + ++static u16 voltage_scale_loop_max_val[] = { ++ [mpq8785] = GENMASK(10, 0), ++}; ++ + static int mpq8785_identify(struct i2c_client *client, + struct pmbus_driver_info *info) + { +@@ -74,6 +79,8 @@ static int mpq8785_probe(struct i2c_client *client) + struct device *dev = &client->dev; + struct pmbus_driver_info *info; + enum chips chip_id; ++ u32 voltage_scale; ++ int ret; + + info = devm_kmemdup(dev, &mpq8785_info, sizeof(*info), GFP_KERNEL); + if (!info) +@@ -92,6 +99,17 @@ static int mpq8785_probe(struct i2c_client *client) + return -ENODEV; + } + ++ if (!device_property_read_u32(dev, "mps,vout-fb-divider-ratio-permille", ++ &voltage_scale)) { ++ if (voltage_scale > voltage_scale_loop_max_val[chip_id]) ++ return -EINVAL; ++ ++ ret = i2c_smbus_write_word_data(client, PMBUS_VOUT_SCALE_LOOP, ++ voltage_scale); ++ if (ret) ++ return ret; ++ } ++ + return pmbus_do_probe(client, info); + }; + +-- +2.51.0 + diff --git a/queue-6.12/hwmon-pmbus-mpq8785-prepare-driver-for-multiple-devi.patch b/queue-6.12/hwmon-pmbus-mpq8785-prepare-driver-for-multiple-devi.patch new file mode 100644 index 0000000000..74d6072beb --- /dev/null +++ b/queue-6.12/hwmon-pmbus-mpq8785-prepare-driver-for-multiple-devi.patch @@ -0,0 +1,94 @@ +From 0600625f0443348f814a40459fd8efe77c336a28 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 11 May 2025 05:55:45 +0200 +Subject: hwmon: pmbus: mpq8785: Prepare driver for multiple device support + +From: Pawel Dembicki + +[ Upstream commit 1bc6020dc400ea8290a7b26aa4365d4568e23e27 ] + +Refactor the driver to support multiple Monolithic Power Systems devices. +Introduce chip ID handling based on device tree matching. + +No functional changes intended. + +Signed-off-by: Pawel Dembicki +Link: https://lore.kernel.org/r/20250511035701.2607947-3-paweldembicki@gmail.com +Signed-off-by: Guenter Roeck +Stable-dep-of: 9e33c1dba224 ("hwmon: (pmbus/mpq8785) fix VOUT_MODE mismatch during identification") +Signed-off-by: Sasha Levin +--- + drivers/hwmon/pmbus/mpq8785.c | 38 +++++++++++++++++++++++++++-------- + 1 file changed, 30 insertions(+), 8 deletions(-) + +diff --git a/drivers/hwmon/pmbus/mpq8785.c b/drivers/hwmon/pmbus/mpq8785.c +index 7f87e117b49de..e260cb3b34c45 100644 +--- a/drivers/hwmon/pmbus/mpq8785.c ++++ b/drivers/hwmon/pmbus/mpq8785.c +@@ -8,6 +8,8 @@ + #include + #include "pmbus.h" + ++enum chips { mpq8785 }; ++ + static int mpq8785_identify(struct i2c_client *client, + struct pmbus_driver_info *info) + { +@@ -53,26 +55,46 @@ static struct pmbus_driver_info mpq8785_info = { + PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | + PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | + PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, +- .identify = mpq8785_identify, +-}; +- +-static int mpq8785_probe(struct i2c_client *client) +-{ +- return pmbus_do_probe(client, &mpq8785_info); + }; + + static const struct i2c_device_id mpq8785_id[] = { +- { "mpq8785" }, ++ { "mpq8785", mpq8785 }, + { }, + }; + MODULE_DEVICE_TABLE(i2c, mpq8785_id); + + static const struct of_device_id __maybe_unused mpq8785_of_match[] = { +- { .compatible = "mps,mpq8785" }, ++ { .compatible = "mps,mpq8785", .data = (void *)mpq8785 }, + {} + }; + MODULE_DEVICE_TABLE(of, mpq8785_of_match); + ++static int mpq8785_probe(struct i2c_client *client) ++{ ++ struct device *dev = &client->dev; ++ struct pmbus_driver_info *info; ++ enum chips chip_id; ++ ++ info = devm_kmemdup(dev, &mpq8785_info, sizeof(*info), GFP_KERNEL); ++ if (!info) ++ return -ENOMEM; ++ ++ if (dev->of_node) ++ chip_id = (kernel_ulong_t)of_device_get_match_data(dev); ++ else ++ chip_id = (kernel_ulong_t)i2c_get_match_data(client); ++ ++ switch (chip_id) { ++ case mpq8785: ++ info->identify = mpq8785_identify; ++ break; ++ default: ++ return -ENODEV; ++ } ++ ++ return pmbus_do_probe(client, info); ++}; ++ + static struct i2c_driver mpq8785_driver = { + .driver = { + .name = "mpq8785", +-- +2.51.0 + diff --git a/queue-6.12/hwrng-core-allow-runtime-disabling-of-the-hw-rng.patch b/queue-6.12/hwrng-core-allow-runtime-disabling-of-the-hw-rng.patch new file mode 100644 index 0000000000..1779b2c22b --- /dev/null +++ b/queue-6.12/hwrng-core-allow-runtime-disabling-of-the-hw-rng.patch @@ -0,0 +1,95 @@ +From 1dd80bb4513280c6b9491a0bba2a69292d3048a3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 23 Sep 2025 14:33:05 +0100 +Subject: hwrng: core - Allow runtime disabling of the HW RNG + +From: Jonathan McDowell + +[ Upstream commit e74b96d77da9eb5ee1b603c937c2adab5134a04b ] + +The HW RNG core allows for manual selection of which RNG device to use, +but does not allow for no device to be enabled. It may be desirable to +do this on systems with only a single suitable hardware RNG, where we +need exclusive access to other functionality on this device. In +particular when performing TPM firmware upgrades this lets us ensure the +kernel does not try to access the device. + +Before: + +root@debian-qemu-efi:~# grep "" /sys/devices/virtual/misc/hw_random/rng_* +/sys/devices/virtual/misc/hw_random/rng_available:tpm-rng-0 +/sys/devices/virtual/misc/hw_random/rng_current:tpm-rng-0 +/sys/devices/virtual/misc/hw_random/rng_quality:1024 +/sys/devices/virtual/misc/hw_random/rng_selected:0 + +After: + +root@debian-qemu-efi:~# grep "" /sys/devices/virtual/misc/hw_random/rng_* +/sys/devices/virtual/misc/hw_random/rng_available:tpm-rng-0 none +/sys/devices/virtual/misc/hw_random/rng_current:tpm-rng-0 +/sys/devices/virtual/misc/hw_random/rng_quality:1024 +/sys/devices/virtual/misc/hw_random/rng_selected:0 + +root@debian-qemu-efi:~# echo none > /sys/devices/virtual/misc/hw_random/rng_current +root@debian-qemu-efi:~# grep "" /sys/devices/virtual/misc/hw_random/rng_* +/sys/devices/virtual/misc/hw_random/rng_available:tpm-rng-0 none +/sys/devices/virtual/misc/hw_random/rng_current:none +grep: /sys/devices/virtual/misc/hw_random/rng_quality: No such device +/sys/devices/virtual/misc/hw_random/rng_selected:1 + +(Observe using bpftrace no calls to TPM being made) + +root@debian-qemu-efi:~# echo "" > /sys/devices/virtual/misc/hw_random/rng_current +root@debian-qemu-efi:~# grep "" /sys/devices/virtual/misc/hw_random/rng_* +/sys/devices/virtual/misc/hw_random/rng_available:tpm-rng-0 none +/sys/devices/virtual/misc/hw_random/rng_current:tpm-rng-0 +/sys/devices/virtual/misc/hw_random/rng_quality:1024 +/sys/devices/virtual/misc/hw_random/rng_selected:0 + +(Observe using bpftrace that calls to the TPM resume) + +Signed-off-by: Jonathan McDowell +Signed-off-by: Herbert Xu +Stable-dep-of: cc2f39d6ac48 ("hwrng: core - use RCU and work_struct to fix race condition") +Signed-off-by: Sasha Levin +--- + drivers/char/hw_random/core.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c +index 57c51efa56131..7be3d504d8c01 100644 +--- a/drivers/char/hw_random/core.c ++++ b/drivers/char/hw_random/core.c +@@ -334,6 +334,9 @@ static ssize_t rng_current_store(struct device *dev, + + if (sysfs_streq(buf, "")) { + err = enable_best_rng(); ++ } else if (sysfs_streq(buf, "none")) { ++ cur_rng_set_by_user = 1; ++ drop_current_rng(); + } else { + list_for_each_entry(rng, &rng_list, list) { + if (sysfs_streq(rng->name, buf)) { +@@ -385,7 +388,7 @@ static ssize_t rng_available_show(struct device *dev, + strlcat(buf, rng->name, PAGE_SIZE); + strlcat(buf, " ", PAGE_SIZE); + } +- strlcat(buf, "\n", PAGE_SIZE); ++ strlcat(buf, "none\n", PAGE_SIZE); + mutex_unlock(&rng_mutex); + + return strlen(buf); +@@ -537,8 +540,8 @@ int hwrng_register(struct hwrng *rng) + /* Adjust quality field to always have a proper value */ + rng->quality = min_t(u16, min_t(u16, default_quality, 1024), rng->quality ?: 1024); + +- if (!current_rng || +- (!cur_rng_set_by_user && rng->quality > current_rng->quality)) { ++ if (!cur_rng_set_by_user && ++ (!current_rng || rng->quality > current_rng->quality)) { + /* + * Set new rng as current as the new rng source + * provides better entropy quality and was not +-- +2.51.0 + diff --git a/queue-6.12/hwrng-core-use-rcu-and-work_struct-to-fix-race-condi.patch b/queue-6.12/hwrng-core-use-rcu-and-work_struct-to-fix-race-condi.patch new file mode 100644 index 0000000000..673baea8cd --- /dev/null +++ b/queue-6.12/hwrng-core-use-rcu-and-work_struct-to-fix-race-condi.patch @@ -0,0 +1,446 @@ +From 027c0288cf3b1a82a4cb4b18f5d8ea93b3f1145e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 06:50:16 +0900 +Subject: hwrng: core - use RCU and work_struct to fix race condition + +From: Lianjie Wang + +[ Upstream commit cc2f39d6ac48e6e3cb2d6240bc0d6df839dd0828 ] + +Currently, hwrng_fill is not cleared until the hwrng_fillfn() thread +exits. Since hwrng_unregister() reads hwrng_fill outside the rng_mutex +lock, a concurrent hwrng_unregister() may call kthread_stop() again on +the same task. + +Additionally, if hwrng_unregister() is called immediately after +hwrng_register(), the stopped thread may have never been executed. Thus, +hwrng_fill remains dirty even after hwrng_unregister() returns. In this +case, subsequent calls to hwrng_register() will fail to start new +threads, and hwrng_unregister() will call kthread_stop() on the same +freed task. In both cases, a use-after-free occurs: + +refcount_t: addition on 0; use-after-free. +WARNING: ... at lib/refcount.c:25 refcount_warn_saturate+0xec/0x1c0 +Call Trace: + kthread_stop+0x181/0x360 + hwrng_unregister+0x288/0x380 + virtrng_remove+0xe3/0x200 + +This patch fixes the race by protecting the global hwrng_fill pointer +inside the rng_mutex lock, so that hwrng_fillfn() thread is stopped only +once, and calls to kthread_run() and kthread_stop() are serialized +with the lock held. + +To avoid deadlock in hwrng_fillfn() while being stopped with the lock +held, we convert current_rng to RCU, so that get_current_rng() can read +current_rng without holding the lock. To remove the lock from put_rng(), +we also delay the actual cleanup into a work_struct. + +Since get_current_rng() no longer returns ERR_PTR values, the IS_ERR() +checks are removed from its callers. + +With hwrng_fill protected by the rng_mutex lock, hwrng_fillfn() can no +longer clear hwrng_fill itself. Therefore, if hwrng_fillfn() returns +directly after current_rng is dropped, kthread_stop() would be called on +a freed task_struct later. To fix this, hwrng_fillfn() calls schedule() +now to keep the task alive until being stopped. The kthread_stop() call +is also moved from hwrng_unregister() to drop_current_rng(), ensuring +kthread_stop() is called on all possible paths where current_rng becomes +NULL, so that the thread would not wait forever. + +Fixes: be4000bc4644 ("hwrng: create filler thread") +Suggested-by: Herbert Xu +Signed-off-by: Lianjie Wang +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/char/hw_random/core.c | 168 +++++++++++++++++++++------------- + include/linux/hw_random.h | 2 + + 2 files changed, 107 insertions(+), 63 deletions(-) + +diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c +index 7be3d504d8c01..c6e913497e1df 100644 +--- a/drivers/char/hw_random/core.c ++++ b/drivers/char/hw_random/core.c +@@ -20,23 +20,25 @@ + #include + #include + #include ++#include + #include + #include + #include + #include + #include ++#include + + #define RNG_MODULE_NAME "hw_random" + + #define RNG_BUFFER_SIZE (SMP_CACHE_BYTES < 32 ? 32 : SMP_CACHE_BYTES) + +-static struct hwrng *current_rng; ++static struct hwrng __rcu *current_rng; + /* the current rng has been explicitly chosen by user via sysfs */ + static int cur_rng_set_by_user; + static struct task_struct *hwrng_fill; + /* list of registered rngs */ + static LIST_HEAD(rng_list); +-/* Protects rng_list and current_rng */ ++/* Protects rng_list, hwrng_fill and updating on current_rng */ + static DEFINE_MUTEX(rng_mutex); + /* Protects rng read functions, data_avail, rng_buffer and rng_fillbuf */ + static DEFINE_MUTEX(reading_mutex); +@@ -64,18 +66,39 @@ static size_t rng_buffer_size(void) + return RNG_BUFFER_SIZE; + } + +-static inline void cleanup_rng(struct kref *kref) ++static void cleanup_rng_work(struct work_struct *work) + { +- struct hwrng *rng = container_of(kref, struct hwrng, ref); ++ struct hwrng *rng = container_of(work, struct hwrng, cleanup_work); ++ ++ /* ++ * Hold rng_mutex here so we serialize in case they set_current_rng ++ * on rng again immediately. ++ */ ++ mutex_lock(&rng_mutex); ++ ++ /* Skip if rng has been reinitialized. */ ++ if (kref_read(&rng->ref)) { ++ mutex_unlock(&rng_mutex); ++ return; ++ } + + if (rng->cleanup) + rng->cleanup(rng); + + complete(&rng->cleanup_done); ++ mutex_unlock(&rng_mutex); ++} ++ ++static inline void cleanup_rng(struct kref *kref) ++{ ++ struct hwrng *rng = container_of(kref, struct hwrng, ref); ++ ++ schedule_work(&rng->cleanup_work); + } + + static int set_current_rng(struct hwrng *rng) + { ++ struct hwrng *old_rng; + int err; + + BUG_ON(!mutex_is_locked(&rng_mutex)); +@@ -84,8 +107,14 @@ static int set_current_rng(struct hwrng *rng) + if (err) + return err; + +- drop_current_rng(); +- current_rng = rng; ++ old_rng = rcu_dereference_protected(current_rng, ++ lockdep_is_held(&rng_mutex)); ++ rcu_assign_pointer(current_rng, rng); ++ ++ if (old_rng) { ++ synchronize_rcu(); ++ kref_put(&old_rng->ref, cleanup_rng); ++ } + + /* if necessary, start hwrng thread */ + if (!hwrng_fill) { +@@ -101,47 +130,56 @@ static int set_current_rng(struct hwrng *rng) + + static void drop_current_rng(void) + { +- BUG_ON(!mutex_is_locked(&rng_mutex)); +- if (!current_rng) ++ struct hwrng *rng; ++ ++ rng = rcu_dereference_protected(current_rng, ++ lockdep_is_held(&rng_mutex)); ++ if (!rng) + return; + ++ RCU_INIT_POINTER(current_rng, NULL); ++ synchronize_rcu(); ++ ++ if (hwrng_fill) { ++ kthread_stop(hwrng_fill); ++ hwrng_fill = NULL; ++ } ++ + /* decrease last reference for triggering the cleanup */ +- kref_put(¤t_rng->ref, cleanup_rng); +- current_rng = NULL; ++ kref_put(&rng->ref, cleanup_rng); + } + +-/* Returns ERR_PTR(), NULL or refcounted hwrng */ ++/* Returns NULL or refcounted hwrng */ + static struct hwrng *get_current_rng_nolock(void) + { +- if (current_rng) +- kref_get(¤t_rng->ref); ++ struct hwrng *rng; ++ ++ rng = rcu_dereference_protected(current_rng, ++ lockdep_is_held(&rng_mutex)); ++ if (rng) ++ kref_get(&rng->ref); + +- return current_rng; ++ return rng; + } + + static struct hwrng *get_current_rng(void) + { + struct hwrng *rng; + +- if (mutex_lock_interruptible(&rng_mutex)) +- return ERR_PTR(-ERESTARTSYS); ++ rcu_read_lock(); ++ rng = rcu_dereference(current_rng); ++ if (rng) ++ kref_get(&rng->ref); + +- rng = get_current_rng_nolock(); ++ rcu_read_unlock(); + +- mutex_unlock(&rng_mutex); + return rng; + } + + static void put_rng(struct hwrng *rng) + { +- /* +- * Hold rng_mutex here so we serialize in case they set_current_rng +- * on rng again immediately. +- */ +- mutex_lock(&rng_mutex); + if (rng) + kref_put(&rng->ref, cleanup_rng); +- mutex_unlock(&rng_mutex); + } + + static int hwrng_init(struct hwrng *rng) +@@ -206,10 +244,6 @@ static ssize_t rng_dev_read(struct file *filp, char __user *buf, + + while (size) { + rng = get_current_rng(); +- if (IS_ERR(rng)) { +- err = PTR_ERR(rng); +- goto out; +- } + if (!rng) { + err = -ENODEV; + goto out; +@@ -296,7 +330,7 @@ static struct miscdevice rng_miscdev = { + + static int enable_best_rng(void) + { +- struct hwrng *rng, *new_rng = NULL; ++ struct hwrng *rng, *cur_rng, *new_rng = NULL; + int ret = -ENODEV; + + BUG_ON(!mutex_is_locked(&rng_mutex)); +@@ -314,7 +348,9 @@ static int enable_best_rng(void) + new_rng = rng; + } + +- ret = ((new_rng == current_rng) ? 0 : set_current_rng(new_rng)); ++ cur_rng = rcu_dereference_protected(current_rng, ++ lockdep_is_held(&rng_mutex)); ++ ret = ((new_rng == cur_rng) ? 0 : set_current_rng(new_rng)); + if (!ret) + cur_rng_set_by_user = 0; + +@@ -364,8 +400,6 @@ static ssize_t rng_current_show(struct device *dev, + struct hwrng *rng; + + rng = get_current_rng(); +- if (IS_ERR(rng)) +- return PTR_ERR(rng); + + ret = sysfs_emit(buf, "%s\n", rng ? rng->name : "none"); + put_rng(rng); +@@ -409,8 +443,6 @@ static ssize_t rng_quality_show(struct device *dev, + struct hwrng *rng; + + rng = get_current_rng(); +- if (IS_ERR(rng)) +- return PTR_ERR(rng); + + if (!rng) /* no need to put_rng */ + return -ENODEV; +@@ -425,6 +457,7 @@ static ssize_t rng_quality_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) + { ++ struct hwrng *rng; + u16 quality; + int ret = -EINVAL; + +@@ -441,12 +474,13 @@ static ssize_t rng_quality_store(struct device *dev, + goto out; + } + +- if (!current_rng) { ++ rng = rcu_dereference_protected(current_rng, lockdep_is_held(&rng_mutex)); ++ if (!rng) { + ret = -ENODEV; + goto out; + } + +- current_rng->quality = quality; ++ rng->quality = quality; + current_quality = quality; /* obsolete */ + + /* the best available RNG may have changed */ +@@ -482,8 +516,20 @@ static int hwrng_fillfn(void *unused) + struct hwrng *rng; + + rng = get_current_rng(); +- if (IS_ERR(rng) || !rng) ++ if (!rng) { ++ /* ++ * Keep the task_struct alive until kthread_stop() ++ * is called to avoid UAF in drop_current_rng(). ++ */ ++ while (!kthread_should_stop()) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ if (!kthread_should_stop()) ++ schedule(); ++ } ++ set_current_state(TASK_RUNNING); + break; ++ } ++ + mutex_lock(&reading_mutex); + rc = rng_get_data(rng, rng_fillbuf, + rng_buffer_size(), 1); +@@ -511,14 +557,13 @@ static int hwrng_fillfn(void *unused) + add_hwgenerator_randomness((void *)rng_fillbuf, rc, + entropy >> 10, true); + } +- hwrng_fill = NULL; + return 0; + } + + int hwrng_register(struct hwrng *rng) + { + int err = -EINVAL; +- struct hwrng *tmp; ++ struct hwrng *cur_rng, *tmp; + + if (!rng->name || (!rng->data_read && !rng->read)) + goto out; +@@ -533,6 +578,7 @@ int hwrng_register(struct hwrng *rng) + } + list_add_tail(&rng->list, &rng_list); + ++ INIT_WORK(&rng->cleanup_work, cleanup_rng_work); + init_completion(&rng->cleanup_done); + complete(&rng->cleanup_done); + init_completion(&rng->dying); +@@ -540,16 +586,19 @@ int hwrng_register(struct hwrng *rng) + /* Adjust quality field to always have a proper value */ + rng->quality = min_t(u16, min_t(u16, default_quality, 1024), rng->quality ?: 1024); + +- if (!cur_rng_set_by_user && +- (!current_rng || rng->quality > current_rng->quality)) { +- /* +- * Set new rng as current as the new rng source +- * provides better entropy quality and was not +- * chosen by userspace. +- */ +- err = set_current_rng(rng); +- if (err) +- goto out_unlock; ++ if (!cur_rng_set_by_user) { ++ cur_rng = rcu_dereference_protected(current_rng, ++ lockdep_is_held(&rng_mutex)); ++ if (!cur_rng || rng->quality > cur_rng->quality) { ++ /* ++ * Set new rng as current as the new rng source ++ * provides better entropy quality and was not ++ * chosen by userspace. ++ */ ++ err = set_current_rng(rng); ++ if (err) ++ goto out_unlock; ++ } + } + mutex_unlock(&rng_mutex); + return 0; +@@ -562,14 +611,17 @@ EXPORT_SYMBOL_GPL(hwrng_register); + + void hwrng_unregister(struct hwrng *rng) + { +- struct hwrng *new_rng; ++ struct hwrng *cur_rng; + int err; + + mutex_lock(&rng_mutex); + + list_del(&rng->list); + complete_all(&rng->dying); +- if (current_rng == rng) { ++ ++ cur_rng = rcu_dereference_protected(current_rng, ++ lockdep_is_held(&rng_mutex)); ++ if (cur_rng == rng) { + err = enable_best_rng(); + if (err) { + drop_current_rng(); +@@ -577,17 +629,7 @@ void hwrng_unregister(struct hwrng *rng) + } + } + +- new_rng = get_current_rng_nolock(); +- if (list_empty(&rng_list)) { +- mutex_unlock(&rng_mutex); +- if (hwrng_fill) +- kthread_stop(hwrng_fill); +- } else +- mutex_unlock(&rng_mutex); +- +- if (new_rng) +- put_rng(new_rng); +- ++ mutex_unlock(&rng_mutex); + wait_for_completion(&rng->cleanup_done); + } + EXPORT_SYMBOL_GPL(hwrng_unregister); +@@ -675,7 +717,7 @@ static int __init hwrng_modinit(void) + static void __exit hwrng_modexit(void) + { + mutex_lock(&rng_mutex); +- BUG_ON(current_rng); ++ WARN_ON(rcu_access_pointer(current_rng)); + kfree(rng_buffer); + kfree(rng_fillbuf); + mutex_unlock(&rng_mutex); +diff --git a/include/linux/hw_random.h b/include/linux/hw_random.h +index b424555753b11..b77bc55a4cf35 100644 +--- a/include/linux/hw_random.h ++++ b/include/linux/hw_random.h +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + + /** + * struct hwrng - Hardware Random Number Generator driver +@@ -48,6 +49,7 @@ struct hwrng { + /* internal. */ + struct list_head list; + struct kref ref; ++ struct work_struct cleanup_work; + struct completion cleanup_done; + struct completion dying; + }; +-- +2.51.0 + diff --git a/queue-6.12/hwspinlock-omap-handle-devm_pm_runtime_enable-errors.patch b/queue-6.12/hwspinlock-omap-handle-devm_pm_runtime_enable-errors.patch new file mode 100644 index 0000000000..7163c21996 --- /dev/null +++ b/queue-6.12/hwspinlock-omap-handle-devm_pm_runtime_enable-errors.patch @@ -0,0 +1,44 @@ +From 5abd03426bf02adbef9e89460db82ee1baf7c236 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 24 Nov 2025 18:48:05 +0800 +Subject: hwspinlock: omap: Handle devm_pm_runtime_enable() errors + +From: Haotian Zhang + +[ Upstream commit 3bd4edd67b034f8e1f61c86e0eb098de6179e3f2 ] + +Although unlikely, devm_pm_runtime_enable() can fail due to memory +allocations. Without proper error handling, the subsequent +pm_runtime_resume_and_get() call may operate on incorrectly +initialized runtime PM state. + +Add error handling to check the return value of +devm_pm_runtime_enable() and return on failure. + +Fixes: 25f7d74d4514 ("hwspinlock: omap: Use devm_pm_runtime_enable() helper") +Signed-off-by: Haotian Zhang +Link: https://patch.msgid.link/20251124104805.135-1-vulab@iscas.ac.cn +Signed-off-by: Kevin Hilman +Signed-off-by: Sasha Levin +--- + drivers/hwspinlock/omap_hwspinlock.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/hwspinlock/omap_hwspinlock.c b/drivers/hwspinlock/omap_hwspinlock.c +index 27b47b8623c09..2d8de835bc242 100644 +--- a/drivers/hwspinlock/omap_hwspinlock.c ++++ b/drivers/hwspinlock/omap_hwspinlock.c +@@ -88,7 +88,9 @@ static int omap_hwspinlock_probe(struct platform_device *pdev) + * make sure the module is enabled and clocked before reading + * the module SYSSTATUS register + */ +- devm_pm_runtime_enable(&pdev->dev); ++ ret = devm_pm_runtime_enable(&pdev->dev); ++ if (ret) ++ return ret; + ret = pm_runtime_resume_and_get(&pdev->dev); + if (ret < 0) + return ret; +-- +2.51.0 + diff --git a/queue-6.12/i3c-dw-fix-memory-leak-in-dw_i3c_master_i2c_xfers.patch b/queue-6.12/i3c-dw-fix-memory-leak-in-dw_i3c_master_i2c_xfers.patch new file mode 100644 index 0000000000..4ddad91d8a --- /dev/null +++ b/queue-6.12/i3c-dw-fix-memory-leak-in-dw_i3c_master_i2c_xfers.patch @@ -0,0 +1,45 @@ +From c7ed19a3ead19382b0afcdfe4b3533b75eee3389 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 08:11:21 +0000 +Subject: i3c: dw: Fix memory leak in dw_i3c_master_i2c_xfers() + +From: Zilin Guan + +[ Upstream commit 2537089413514caaa9a5fdeeac3a34d45100f747 ] + +The dw_i3c_master_i2c_xfers() function allocates memory for the xfer +structure using dw_i3c_master_alloc_xfer(). If pm_runtime_resume_and_get() +fails, the function returns without freeing the allocated xfer, resulting +in a memory leak. + +Add a dw_i3c_master_free_xfer() call to the error path to ensure the +allocated memory is properly freed. + +Compile tested only. Issue found using a prototype static analysis tool +and code review. + +Fixes: 62fe9d06f570 ("i3c: dw: Add power management support") +Signed-off-by: Zilin Guan +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260126081121.644099-1-zilin@seu.edu.cn +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master/dw-i3c-master.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c +index eca54cbc1c29a..4c019c746f231 100644 +--- a/drivers/i3c/master/dw-i3c-master.c ++++ b/drivers/i3c/master/dw-i3c-master.c +@@ -1102,6 +1102,7 @@ static int dw_i3c_master_i2c_xfers(struct i2c_dev_desc *dev, + dev_err(master->dev, + "<%s> cannot resume i3c bus master, err: %d\n", + __func__, ret); ++ dw_i3c_master_free_xfer(xfer); + return ret; + } + +-- +2.51.0 + diff --git a/queue-6.12/i3c-dw-initialize-spinlock-to-avoid-upsetting-lockde.patch b/queue-6.12/i3c-dw-initialize-spinlock-to-avoid-upsetting-lockde.patch new file mode 100644 index 0000000000..ad1bcbd7d3 --- /dev/null +++ b/queue-6.12/i3c-dw-initialize-spinlock-to-avoid-upsetting-lockde.patch @@ -0,0 +1,39 @@ +From cb38de644b2f9098cda21dec2b13cfdbcf17d628 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 15:29:42 +0100 +Subject: i3c: dw: Initialize spinlock to avoid upsetting lockdep + +From: Fredrik Markstrom + +[ Upstream commit b58eaa4761ab02fc38c39d674a6bcdd55e00f388 ] + +The devs_lock spinlock introduced when adding support for ibi:s was +never initialized. + +Fixes: e389b1d72a624 ("i3c: dw: Add support for in-band interrupts") +Suggested-by: Jani Nurminen +Signed-off-by: Fredrik Markstrom +Reviewed-by: Ivar Holmqvist +Link: https://patch.msgid.link/20260116-i3c_dw_initialize_spinlock-v3-1-cf707b6ed75f@est.tech +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master/dw-i3c-master.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c +index dbcd3984f2578..eca54cbc1c29a 100644 +--- a/drivers/i3c/master/dw-i3c-master.c ++++ b/drivers/i3c/master/dw-i3c-master.c +@@ -1575,6 +1575,8 @@ int dw_i3c_common_probe(struct dw_i3c_master *master, + spin_lock_init(&master->xferqueue.lock); + INIT_LIST_HEAD(&master->xferqueue.list); + ++ spin_lock_init(&master->devs_lock); ++ + writel(INTR_ALL, master->regs + INTR_STATUS); + irq = platform_get_irq(pdev, 0); + ret = devm_request_irq(&pdev->dev, irq, +-- +2.51.0 + diff --git a/queue-6.12/i3c-master-update-hot-join-flag-only-on-success.patch b/queue-6.12/i3c-master-update-hot-join-flag-only-on-success.patch new file mode 100644 index 0000000000..e97cf1e6ce --- /dev/null +++ b/queue-6.12/i3c-master-update-hot-join-flag-only-on-success.patch @@ -0,0 +1,39 @@ +From 7bbf31c182f76a145126116a34bcb5355e8a17e1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Jan 2026 09:26:44 +0200 +Subject: i3c: master: Update hot-join flag only on success + +From: Adrian Hunter + +[ Upstream commit f0775157b9f9a28ae3eabc8d05b0bc52e8056c80 ] + +To prevent inconsistent state when an error occurs, ensure the hot-join +flag is updated only when enabling or disabling hot-join succeeds. + +Fixes: 317bacf960a48 ("i3c: master: add enable(disable) hot join in sys entry") +Signed-off-by: Adrian Hunter +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260113072702.16268-4-adrian.hunter@intel.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c +index 5c0cb3f38c90b..fe6f956cc3111 100644 +--- a/drivers/i3c/master.c ++++ b/drivers/i3c/master.c +@@ -619,7 +619,8 @@ static int i3c_set_hotjoin(struct i3c_master_controller *master, bool enable) + else + ret = master->ops->disable_hotjoin(master); + +- master->hotjoin = enable; ++ if (!ret) ++ master->hotjoin = enable; + + i3c_bus_normaluse_unlock(&master->bus); + +-- +2.51.0 + diff --git a/queue-6.12/i3c-move-device-name-assignment-after-i3c_bus_init.patch b/queue-6.12/i3c-move-device-name-assignment-after-i3c_bus_init.patch new file mode 100644 index 0000000000..ddf1df97e2 --- /dev/null +++ b/queue-6.12/i3c-move-device-name-assignment-after-i3c_bus_init.patch @@ -0,0 +1,46 @@ +From 4b60e47108adcb904efda9e7c864851ed2856a12 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 14:07:22 +0800 +Subject: i3c: Move device name assignment after i3c_bus_init + +From: Billy Tsai + +[ Upstream commit 3502cea99c7ceb331458cbd34ef6792c83144687 ] + +Move device name initialization to occur after i3c_bus_init() +so that i3cbus->id is guaranteed to be assigned before it is used. + +Fixes: 9d4f219807d5 ("i3c: fix refcount inconsistency in i3c_master_register") +Signed-off-by: Billy Tsai +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260112-upstream_i3c_fix-v1-1-cbbf2cb71809@aspeedtech.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c +index 6eb779affaba8..5c0cb3f38c90b 100644 +--- a/drivers/i3c/master.c ++++ b/drivers/i3c/master.c +@@ -2810,7 +2810,6 @@ int i3c_master_register(struct i3c_master_controller *master, + INIT_LIST_HEAD(&master->boardinfo.i3c); + + device_initialize(&master->dev); +- dev_set_name(&master->dev, "i3c-%d", i3cbus->id); + + master->dev.dma_mask = parent->dma_mask; + master->dev.coherent_dma_mask = parent->coherent_dma_mask; +@@ -2820,6 +2819,8 @@ int i3c_master_register(struct i3c_master_controller *master, + if (ret) + goto err_put_dev; + ++ dev_set_name(&master->dev, "i3c-%d", i3cbus->id); ++ + ret = of_populate_i3c_bus(master); + if (ret) + goto err_put_dev; +-- +2.51.0 + diff --git a/queue-6.12/ib-cache-update-gid-cache-on-client-reregister-event.patch b/queue-6.12/ib-cache-update-gid-cache-on-client-reregister-event.patch new file mode 100644 index 0000000000..3cdf82479a --- /dev/null +++ b/queue-6.12/ib-cache-update-gid-cache-on-client-reregister-event.patch @@ -0,0 +1,54 @@ +From 9af26f449533bbc5f85f12e0b3f080a578c9b48a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 31 Dec 2025 14:07:45 +0100 +Subject: IB/cache: update gid cache on client reregister event +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Etienne AUJAMES + +[ Upstream commit ddd6c8c873e912cb1ead79def54de5e24ff71c80 ] + +Some HCAs (e.g: ConnectX4) do not trigger a IB_EVENT_GID_CHANGE on +subnet prefix update from SM (PortInfo). + +Since the commit d58c23c92548 ("IB/core: Only update PKEY and GID caches +on respective events"), the GID cache is updated exclusively on +IB_EVENT_GID_CHANGE. If this event is not emitted, the subnet prefix in the +IPoIB interface’s hardware address remains set to its default value +(0xfe80000000000000). + +Then rdma_bind_addr() failed because it relies on hardware address to +find the port GID (subnet_prefix + port GUID). + +This patch fixes this issue by updating the GID cache on +IB_EVENT_CLIENT_REREGISTER event (emitted on PortInfo::ClientReregister=1). + +Fixes: d58c23c92548 ("IB/core: Only update PKEY and GID caches on respective events") +Signed-off-by: Etienne AUJAMES +Link: https://patch.msgid.link/aVUfsO58QIDn5bGX@eaujamesFR0130 +Reviewed-by: Parav Pandit +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/cache.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c +index a1291f475466d..19851d05b4f88 100644 +--- a/drivers/infiniband/core/cache.c ++++ b/drivers/infiniband/core/cache.c +@@ -1566,7 +1566,8 @@ static void ib_cache_event_task(struct work_struct *_work) + * the cache. + */ + ret = ib_cache_update(work->event.device, work->event.element.port_num, +- work->event.event == IB_EVENT_GID_CHANGE, ++ work->event.event == IB_EVENT_GID_CHANGE || ++ work->event.event == IB_EVENT_CLIENT_REREGISTER, + work->event.event == IB_EVENT_PKEY_CHANGE, + work->enforce_security); + +-- +2.51.0 + diff --git a/queue-6.12/ib-mlx5-fix-port-speed-query-for-representors.patch b/queue-6.12/ib-mlx5-fix-port-speed-query-for-representors.patch new file mode 100644 index 0000000000..8ce536807d --- /dev/null +++ b/queue-6.12/ib-mlx5-fix-port-speed-query-for-representors.patch @@ -0,0 +1,63 @@ +From e664669df527713d8f94879a9d9a0322d6f5c9cc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 14:26:45 +0200 +Subject: IB/mlx5: Fix port speed query for representors + +From: Or Har-Toov + +[ Upstream commit 18ea78e2ae83d1d86a72d21d9511927e57e2c0e1 ] + +When querying speed information for a representor in switchdev mode, +the code previously used the first device in the eswitch, which may not +match the device that actually owns the representor. In setups such as +multi-port eswitch or LAG, this led to incorrect port attributes being +reported. + +Fix this by retrieving the correct core device from the representor's +eswitch before querying its port attributes. + +Fixes: 27f9e0ccb6da ("net/mlx5: Lag, Add single RDMA device in multiport mode") +Signed-off-by: Or Har-Toov +Reviewed-by: Mark Bloch +Signed-off-by: Edward Srouji +Link: https://patch.msgid.link/20260115-port-speed-query-fix-v2-1-3bde6a3c78e7@nvidia.com +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/hw/mlx5/main.c | 20 ++++++++++++++------ + 1 file changed, 14 insertions(+), 6 deletions(-) + +diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c +index 10bda03eb3388..8b2e13f1a2159 100644 +--- a/drivers/infiniband/hw/mlx5/main.c ++++ b/drivers/infiniband/hw/mlx5/main.c +@@ -539,12 +539,20 @@ static int mlx5_query_port_roce(struct ib_device *device, u32 port_num, + * of an error it will still be zeroed out. + * Use native port in case of reps + */ +- if (dev->is_rep) +- err = mlx5_query_port_ptys(mdev, out, sizeof(out), MLX5_PTYS_EN, +- 1, 0); +- else +- err = mlx5_query_port_ptys(mdev, out, sizeof(out), MLX5_PTYS_EN, +- mdev_port_num, 0); ++ if (dev->is_rep) { ++ struct mlx5_eswitch_rep *rep; ++ ++ rep = dev->port[port_num - 1].rep; ++ if (rep) { ++ mdev = mlx5_eswitch_get_core_dev(rep->esw); ++ WARN_ON(!mdev); ++ } ++ mdev_port_num = 1; ++ } ++ ++ err = mlx5_query_port_ptys(mdev, out, sizeof(out), MLX5_PTYS_EN, ++ mdev_port_num, 0); ++ + if (err) + goto out; + ext = !!MLX5_GET_ETH_PROTO(ptys_reg, out, true, eth_proto_capability); +-- +2.51.0 + diff --git a/queue-6.12/iio-pressure-mprls0025pa-fix-interrupt-flag.patch b/queue-6.12/iio-pressure-mprls0025pa-fix-interrupt-flag.patch new file mode 100644 index 0000000000..3d9900cb2d --- /dev/null +++ b/queue-6.12/iio-pressure-mprls0025pa-fix-interrupt-flag.patch @@ -0,0 +1,40 @@ +From 3a8e5f2b7fde333ddc716ff144b3b3ac5f6abfe9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:55:32 +0200 +Subject: iio: pressure: mprls0025pa: fix interrupt flag + +From: Petre Rodan + +[ Upstream commit fff3f1a7d805684e4701a70bfaeba39622b59dbc ] + +Interrupt falling/rising flags should only be defined in the device tree. + +Fixes: 713337d9143e ("iio: pressure: Honeywell mprls0025pa pressure sensor") +Signed-off-by: Petre Rodan +Reviewed-by: Andy Shevchenko +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/pressure/mprls0025pa.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/iio/pressure/mprls0025pa.c b/drivers/iio/pressure/mprls0025pa.c +index 3b6145348c2e3..7ecb928655421 100644 +--- a/drivers/iio/pressure/mprls0025pa.c ++++ b/drivers/iio/pressure/mprls0025pa.c +@@ -418,10 +418,8 @@ int mpr_common_probe(struct device *dev, const struct mpr_ops *ops, int irq) + data->offset = div_s64_rem(offset, NANO, &data->offset2); + + if (data->irq > 0) { +- ret = devm_request_irq(dev, data->irq, mpr_eoc_handler, +- IRQF_TRIGGER_RISING, +- dev_name(dev), +- data); ++ ret = devm_request_irq(dev, data->irq, mpr_eoc_handler, 0, ++ dev_name(dev), data); + if (ret) + return dev_err_probe(dev, ret, + "request irq %d failed\n", data->irq); +-- +2.51.0 + diff --git a/queue-6.12/iio-pressure-mprls0025pa-fix-pressure-calculation.patch b/queue-6.12/iio-pressure-mprls0025pa-fix-pressure-calculation.patch new file mode 100644 index 0000000000..bacaaa8fd0 --- /dev/null +++ b/queue-6.12/iio-pressure-mprls0025pa-fix-pressure-calculation.patch @@ -0,0 +1,110 @@ +From 230e8800ce4588d5b7a095d819c4de5bbb1457d7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:55:34 +0200 +Subject: iio: pressure: mprls0025pa: fix pressure calculation + +From: Petre Rodan + +[ Upstream commit d63403d4e31ae537fefc5c0ee9d90f29b4fc532b ] + +A sign change is needed for proper calculation of the pressure. + +This is a minor fix since it only affects users that might have custom +silicon from Honeywell that has honeywell,pmin-pascal != 0. + +Also due to the fact that raw pressure values can not be lower +than output_min (400k-3.3M) there is no need to calculate a decimal for +the offset. + +Fixes: 713337d9143e ("iio: pressure: Honeywell mprls0025pa pressure sensor") +Signed-off-by: Petre Rodan +Reviewed-by: Andy Shevchenko +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/pressure/mprls0025pa.c | 26 +++++++++++--------------- + drivers/iio/pressure/mprls0025pa.h | 2 -- + 2 files changed, 11 insertions(+), 17 deletions(-) + +diff --git a/drivers/iio/pressure/mprls0025pa.c b/drivers/iio/pressure/mprls0025pa.c +index 367644269fec4..e13e6a7ef8db9 100644 +--- a/drivers/iio/pressure/mprls0025pa.c ++++ b/drivers/iio/pressure/mprls0025pa.c +@@ -59,7 +59,7 @@ + * + * Values given to the userspace in sysfs interface: + * * raw - press_cnt +- * * offset - (-1 * outputmin) - pmin / scale ++ * * offset - (-1 * outputmin) + pmin / scale + * note: With all sensors from the datasheet pmin = 0 + * which reduces the offset to (-1 * outputmin) + */ +@@ -313,8 +313,7 @@ static int mpr_read_raw(struct iio_dev *indio_dev, + return IIO_VAL_INT_PLUS_NANO; + case IIO_CHAN_INFO_OFFSET: + *val = data->offset; +- *val2 = data->offset2; +- return IIO_VAL_INT_PLUS_NANO; ++ return IIO_VAL_INT; + default: + return -EINVAL; + } +@@ -330,8 +329,9 @@ int mpr_common_probe(struct device *dev, const struct mpr_ops *ops, int irq) + struct mpr_data *data; + struct iio_dev *indio_dev; + const char *triplet; +- s64 scale, offset; ++ s64 odelta, pdelta; + u32 func; ++ s32 tmp; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) +@@ -405,17 +405,13 @@ int mpr_common_probe(struct device *dev, const struct mpr_ops *ops, int irq) + data->outmin = mpr_func_spec[data->function].output_min; + data->outmax = mpr_func_spec[data->function].output_max; + +- /* use 64 bit calculation for preserving a reasonable precision */ +- scale = div_s64(((s64)(data->pmax - data->pmin)) * NANO, +- data->outmax - data->outmin); +- data->scale = div_s64_rem(scale, NANO, &data->scale2); +- /* +- * multiply with NANO before dividing by scale and later divide by NANO +- * again. +- */ +- offset = ((-1LL) * (s64)data->outmin) * NANO - +- div_s64(div_s64((s64)data->pmin * NANO, scale), NANO); +- data->offset = div_s64_rem(offset, NANO, &data->offset2); ++ odelta = data->outmax - data->outmin; ++ pdelta = data->pmax - data->pmin; ++ ++ data->scale = div_s64_rem(div_s64(pdelta * NANO, odelta), NANO, &tmp); ++ data->scale2 = tmp; ++ ++ data->offset = div_s64(odelta * data->pmin, pdelta) - data->outmin; + + if (data->irq > 0) { + ret = devm_request_irq(dev, data->irq, mpr_eoc_handler, 0, +diff --git a/drivers/iio/pressure/mprls0025pa.h b/drivers/iio/pressure/mprls0025pa.h +index d62a018eaff32..b6944b3051267 100644 +--- a/drivers/iio/pressure/mprls0025pa.h ++++ b/drivers/iio/pressure/mprls0025pa.h +@@ -53,7 +53,6 @@ enum mpr_func_id { + * @scale: pressure scale + * @scale2: pressure scale, decimal number + * @offset: pressure offset +- * @offset2: pressure offset, decimal number + * @gpiod_reset: reset + * @irq: end of conversion irq. used to distinguish between irq mode and + * reading in a loop until data is ready +@@ -75,7 +74,6 @@ struct mpr_data { + int scale; + int scale2; + int offset; +- int offset2; + struct gpio_desc *gpiod_reset; + int irq; + struct completion completion; +-- +2.51.0 + diff --git a/queue-6.12/iio-pressure-mprls0025pa-fix-scan_type-struct.patch b/queue-6.12/iio-pressure-mprls0025pa-fix-scan_type-struct.patch new file mode 100644 index 0000000000..b479eec450 --- /dev/null +++ b/queue-6.12/iio-pressure-mprls0025pa-fix-scan_type-struct.patch @@ -0,0 +1,47 @@ +From 374833c11895401e99adc1a230581fe133a4dfd2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:55:33 +0200 +Subject: iio: pressure: mprls0025pa: fix scan_type struct + +From: Petre Rodan + +[ Upstream commit 8a228e036926f7e57421d750c3724e63f11b808a ] + +Fix the scan_type sign and realbits assignment. + +The pressure is a 24bit unsigned int between output_min and output_max. + + transfer function A: 10% to 90% of 2^24 + transfer function B: 2.5% to 22.5% of 2^24 + transfer function C: 20% to 80% of 2^24 +[MPR_FUNCTION_A] = { .output_min = 1677722, .output_max = 15099494 } +[MPR_FUNCTION_B] = { .output_min = 419430, .output_max = 3774874 } +[MPR_FUNCTION_C] = { .output_min = 3355443, .output_max = 13421773 } + +Fixes: 713337d9143e ("iio: pressure: Honeywell mprls0025pa pressure sensor") +Signed-off-by: Petre Rodan +Reviewed-by: Andy Shevchenko +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/pressure/mprls0025pa.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/iio/pressure/mprls0025pa.c b/drivers/iio/pressure/mprls0025pa.c +index 7ecb928655421..367644269fec4 100644 +--- a/drivers/iio/pressure/mprls0025pa.c ++++ b/drivers/iio/pressure/mprls0025pa.c +@@ -160,8 +160,8 @@ static const struct iio_chan_spec mpr_channels[] = { + BIT(IIO_CHAN_INFO_OFFSET), + .scan_index = 0, + .scan_type = { +- .sign = 's', +- .realbits = 32, ++ .sign = 'u', ++ .realbits = 24, + .storagebits = 32, + .endianness = IIO_CPU, + }, +-- +2.51.0 + diff --git a/queue-6.12/iio-pressure-mprls0025pa-fix-spi-cs-delay-violation.patch b/queue-6.12/iio-pressure-mprls0025pa-fix-spi-cs-delay-violation.patch new file mode 100644 index 0000000000..089d536d02 --- /dev/null +++ b/queue-6.12/iio-pressure-mprls0025pa-fix-spi-cs-delay-violation.patch @@ -0,0 +1,71 @@ +From fd72e05793228eb1f6f106f84259b5c1b111bb6f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:55:31 +0200 +Subject: iio: pressure: mprls0025pa: fix SPI CS delay violation + +From: Petre Rodan + +[ Upstream commit 583fa86ca581595b1f534a8de6d49ba8b3bf7196 ] + +Based on the sensor datasheet in chapter 7.6 SPI timing, Table 20, +during the SPI transfer there is a minimum time interval requirement +between the CS being asserted and the first clock edge (tHDSS). +This minimum interval of 2.5us is being violated if two consecutive SPI +transfers are queued up. + +Fixes: a0858f0cd28e ("iio: pressure: mprls0025pa add SPI driver") +Datasheet: https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/micropressure-mpr-series/documents/sps-siot-mpr-series-datasheet-32332628-ciid-172626.pdf?download=false +Signed-off-by: Petre Rodan +Reviewed-by: Andy Shevchenko +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/pressure/mprls0025pa_spi.c | 19 ++++++++++++++----- + 1 file changed, 14 insertions(+), 5 deletions(-) + +diff --git a/drivers/iio/pressure/mprls0025pa_spi.c b/drivers/iio/pressure/mprls0025pa_spi.c +index f4807dac61e0f..241ad36f6501a 100644 +--- a/drivers/iio/pressure/mprls0025pa_spi.c ++++ b/drivers/iio/pressure/mprls0025pa_spi.c +@@ -8,6 +8,7 @@ + * https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/micropressure-mpr-series/documents/sps-siot-mpr-series-datasheet-32332628-ciid-172626.pdf + */ + ++#include + #include + #include + #include +@@ -40,17 +41,25 @@ static int mpr_spi_xfer(struct mpr_data *data, const u8 cmd, const u8 pkt_len) + { + struct spi_device *spi = to_spi_device(data->dev); + struct mpr_spi_buf *buf = spi_get_drvdata(spi); +- struct spi_transfer xfer = { }; ++ struct spi_transfer xfers[2] = { }; + + if (pkt_len > MPR_MEASUREMENT_RD_SIZE) + return -EOVERFLOW; + + buf->tx[0] = cmd; +- xfer.tx_buf = buf->tx; +- xfer.rx_buf = data->buffer; +- xfer.len = pkt_len; + +- return spi_sync_transfer(spi, &xfer, 1); ++ /* ++ * Dummy transfer with no data, just cause a 2.5us+ delay between the CS assert ++ * and the first clock edge as per the datasheet tHDSS timing requirement. ++ */ ++ xfers[0].delay.value = 2500; ++ xfers[0].delay.unit = SPI_DELAY_UNIT_NSECS; ++ ++ xfers[1].tx_buf = buf->tx; ++ xfers[1].rx_buf = data->buffer; ++ xfers[1].len = pkt_len; ++ ++ return spi_sync_transfer(spi, xfers, ARRAY_SIZE(xfers)); + } + + static const struct mpr_ops mpr_spi_ops = { +-- +2.51.0 + diff --git a/queue-6.12/iio-pressure-mprls0025pa-fix-spi_transfer-struct-ini.patch b/queue-6.12/iio-pressure-mprls0025pa-fix-spi_transfer-struct-ini.patch new file mode 100644 index 0000000000..bf47c61ddf --- /dev/null +++ b/queue-6.12/iio-pressure-mprls0025pa-fix-spi_transfer-struct-ini.patch @@ -0,0 +1,36 @@ +From 2ef2294331fa1b334b2ce8ed6f3dfca08f2561e3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:55:30 +0200 +Subject: iio: pressure: mprls0025pa: fix spi_transfer struct initialisation + +From: Petre Rodan + +[ Upstream commit 1e0ac56c92e26115cbc8cfc639843725cb3a7d6a ] + +Make sure that the spi_transfer struct is zeroed out before use. + +Fixes: a0858f0cd28e ("iio: pressure: mprls0025pa add SPI driver") +Signed-off-by: Petre Rodan +Reviewed-by: Andy Shevchenko +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/pressure/mprls0025pa_spi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/iio/pressure/mprls0025pa_spi.c b/drivers/iio/pressure/mprls0025pa_spi.c +index 3aed14cd95c5a..f4807dac61e0f 100644 +--- a/drivers/iio/pressure/mprls0025pa_spi.c ++++ b/drivers/iio/pressure/mprls0025pa_spi.c +@@ -40,7 +40,7 @@ static int mpr_spi_xfer(struct mpr_data *data, const u8 cmd, const u8 pkt_len) + { + struct spi_device *spi = to_spi_device(data->dev); + struct mpr_spi_buf *buf = spi_get_drvdata(spi); +- struct spi_transfer xfer; ++ struct spi_transfer xfer = { }; + + if (pkt_len > MPR_MEASUREMENT_RD_SIZE) + return -EOVERFLOW; +-- +2.51.0 + diff --git a/queue-6.12/iio-sca3000-fix-a-resource-leak-in-sca3000_probe.patch b/queue-6.12/iio-sca3000-fix-a-resource-leak-in-sca3000_probe.patch new file mode 100644 index 0000000000..ea6133da84 --- /dev/null +++ b/queue-6.12/iio-sca3000-fix-a-resource-leak-in-sca3000_probe.patch @@ -0,0 +1,42 @@ +From cda9380d1805df3593ca6fefa84b8fce2bbb4695 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 22:49:49 -0800 +Subject: iio: sca3000: Fix a resource leak in sca3000_probe() + +From: Harshit Mogalapalli + +[ Upstream commit 62b44ebc1f2c71db3ca2d4737c52e433f6f03038 ] + +spi->irq from request_threaded_irq() not released when +iio_device_register() fails. Add an return value check and jump to a +common error handler when iio_device_register() fails. + +Fixes: 9a4936dc89a3 ("staging:iio:accel:sca3000 Tidy up probe order to avoid a race.") +Signed-off-by: Harshit Mogalapalli +Reviewed-by: Andy Shevchenko +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/accel/sca3000.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/iio/accel/sca3000.c b/drivers/iio/accel/sca3000.c +index 87c54e41f6ccd..2b87f7f5508bb 100644 +--- a/drivers/iio/accel/sca3000.c ++++ b/drivers/iio/accel/sca3000.c +@@ -1496,7 +1496,11 @@ static int sca3000_probe(struct spi_device *spi) + if (ret) + goto error_free_irq; + +- return iio_device_register(indio_dev); ++ ret = iio_device_register(indio_dev); ++ if (ret) ++ goto error_free_irq; ++ ++ return 0; + + error_free_irq: + if (spi->irq) +-- +2.51.0 + diff --git a/queue-6.12/iio-test-drop-dangling-symbol-in-gain-time-scale-hel.patch b/queue-6.12/iio-test-drop-dangling-symbol-in-gain-time-scale-hel.patch new file mode 100644 index 0000000000..9d57a1bada --- /dev/null +++ b/queue-6.12/iio-test-drop-dangling-symbol-in-gain-time-scale-hel.patch @@ -0,0 +1,36 @@ +From 51de4e1a7f2ab9e5782138dffcdf0078d7162997 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 27 Dec 2025 23:10:29 -0800 +Subject: iio: test: drop dangling symbol in gain-time-scale helpers + +From: Randy Dunlap + +[ Upstream commit d63d868b312478523670b76007dcc5eaedc3ee07 ] + +The code for this never went upstream. It was replaced by other code, +so this should be dropped. + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=216748 +Fixes: cf996f039679 ("iio: test: test gain-time-scale helpers") +Signed-off-by: Randy Dunlap +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/test/Kconfig | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/iio/test/Kconfig b/drivers/iio/test/Kconfig +index 33cca49c8058a..3b6d9b1476d8c 100644 +--- a/drivers/iio/test/Kconfig ++++ b/drivers/iio/test/Kconfig +@@ -8,7 +8,6 @@ config IIO_GTS_KUNIT_TEST + tristate "Test IIO formatting functions" if !KUNIT_ALL_TESTS + depends on KUNIT + select IIO_GTS_HELPER +- select TEST_KUNIT_DEVICE_HELPERS + default KUNIT_ALL_TESTS + help + build unit tests for the IIO light sensor gain-time-scale helpers. +-- +2.51.0 + diff --git a/queue-6.12/inet-raw-sockets-using-ipproto_raw-must-drop-incomin.patch b/queue-6.12/inet-raw-sockets-using-ipproto_raw-must-drop-incomin.patch new file mode 100644 index 0000000000..9accb510de --- /dev/null +++ b/queue-6.12/inet-raw-sockets-using-ipproto_raw-must-drop-incomin.patch @@ -0,0 +1,94 @@ +From cc76adddd26abce2f18876a3da05d1cf6958e311 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 19:25:09 +0000 +Subject: inet: RAW sockets using IPPROTO_RAW MUST drop incoming ICMP + +From: Eric Dumazet + +[ Upstream commit c89477ad79446867394360b29bb801010fc3ff22 ] + +Yizhou Zhao reported that simply having one RAW socket on protocol +IPPROTO_RAW (255) was dangerous. + + socket(AF_INET, SOCK_RAW, 255); + +A malicious incoming ICMP packet can set the protocol field to 255 +and match this socket, leading to FNHE cache changes. + +inner = IP(src="192.168.2.1", dst="8.8.8.8", proto=255)/Raw("TEST") +pkt = IP(src="192.168.1.1", dst="192.168.2.1")/ICMP(type=3, code=4, nexthopmtu=576)/inner + +"man 7 raw" states: + + A protocol of IPPROTO_RAW implies enabled IP_HDRINCL and is able + to send any IP protocol that is specified in the passed header. + Receiving of all IP protocols via IPPROTO_RAW is not possible + using raw sockets. + +Make sure we drop these malicious packets. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: Yizhou Zhao +Link: https://lore.kernel.org/netdev/20251109134600.292125-1-zhaoyz24@mails.tsinghua.edu.cn/ +Signed-off-by: Eric Dumazet +Reviewed-by: David Ahern +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260203192509.682208-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/icmp.c | 14 ++++++++++---- + net/ipv6/icmp.c | 6 ++++++ + 2 files changed, 16 insertions(+), 4 deletions(-) + +diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c +index 508b23204edc5..c0373d1172d73 100644 +--- a/net/ipv4/icmp.c ++++ b/net/ipv4/icmp.c +@@ -840,16 +840,22 @@ static void icmp_socket_deliver(struct sk_buff *skb, u32 info) + /* Checkin full IP header plus 8 bytes of protocol to + * avoid additional coding at protocol handlers. + */ +- if (!pskb_may_pull(skb, iph->ihl * 4 + 8)) { +- __ICMP_INC_STATS(dev_net_rcu(skb->dev), ICMP_MIB_INERRORS); +- return; +- } ++ if (!pskb_may_pull(skb, iph->ihl * 4 + 8)) ++ goto out; ++ ++ /* IPPROTO_RAW sockets are not supposed to receive anything. */ ++ if (protocol == IPPROTO_RAW) ++ goto out; + + raw_icmp_error(skb, protocol, info); + + ipprot = rcu_dereference(inet_protos[protocol]); + if (ipprot && ipprot->err_handler) + ipprot->err_handler(skb, info); ++ return; ++ ++out: ++ __ICMP_INC_STATS(dev_net_rcu(skb->dev), ICMP_MIB_INERRORS); + } + + static bool icmp_tag_validation(int proto) +diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c +index 13a796bfc2f93..c8609147fce89 100644 +--- a/net/ipv6/icmp.c ++++ b/net/ipv6/icmp.c +@@ -871,6 +871,12 @@ enum skb_drop_reason icmpv6_notify(struct sk_buff *skb, u8 type, + if (reason != SKB_NOT_DROPPED_YET) + goto out; + ++ if (nexthdr == IPPROTO_RAW) { ++ /* Add a more specific reason later ? */ ++ reason = SKB_DROP_REASON_NOT_SPECIFIED; ++ goto out; ++ } ++ + /* BUGGG_FUTURE: we should try to parse exthdrs in this packet. + Without this we will not able f.e. to make source routed + pmtu discovery. +-- +2.51.0 + diff --git a/queue-6.12/interconnect-mediatek-aggregate-bandwidth-with-satur.patch b/queue-6.12/interconnect-mediatek-aggregate-bandwidth-with-satur.patch new file mode 100644 index 0000000000..bb1f59ba9b --- /dev/null +++ b/queue-6.12/interconnect-mediatek-aggregate-bandwidth-with-satur.patch @@ -0,0 +1,54 @@ +From 7737e7a3db982c39c8edc43ddb5e6761e8210b12 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 24 Nov 2025 12:07:02 +0100 +Subject: interconnect: mediatek: Aggregate bandwidth with saturating add + +From: Nicolas Frattaroli + +[ Upstream commit 6ffd02b82243d9907b5f5d2c7a2fc6a62669eece ] + +By using a regular non-overflow-checking add, the MediaTek icc-emi +driver will happy wrap at U32_MAX + 1 to 0. As it's common for the +interconnect core to fill in INT_MAX values, this is not a hypothetical +situation, but something that actually happens in regular use. This +would be pretty disasterous if anything used this driver. + +Replace the addition with an overflow-checked addition from overflow.h, +and saturate to U32_MAX if an overflow is detected. + +Fixes: b45293799f75 ("interconnect: mediatek: Add MediaTek MT8183/8195 EMI Interconnect driver") +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Nicolas Frattaroli +Link: https://lore.kernel.org/r/20251124-mt8196-dvfsrc-v2-13-d9c1334db9f3@collabora.com +Signed-off-by: Georgi Djakov +Signed-off-by: Sasha Levin +--- + drivers/interconnect/mediatek/icc-emi.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/interconnect/mediatek/icc-emi.c b/drivers/interconnect/mediatek/icc-emi.c +index 182aa2b0623af..dfa3a9cd93998 100644 +--- a/drivers/interconnect/mediatek/icc-emi.c ++++ b/drivers/interconnect/mediatek/icc-emi.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -22,7 +23,9 @@ static int mtk_emi_icc_aggregate(struct icc_node *node, u32 tag, u32 avg_bw, + { + struct mtk_icc_node *in = node->data; + +- *agg_avg += avg_bw; ++ if (check_add_overflow(*agg_avg, avg_bw, agg_avg)) ++ *agg_avg = U32_MAX; ++ + *agg_peak = max_t(u32, *agg_peak, peak_bw); + + in->sum_avg = *agg_avg; +-- +2.51.0 + diff --git a/queue-6.12/interconnect-mediatek-don-t-hijack-parent-device.patch b/queue-6.12/interconnect-mediatek-don-t-hijack-parent-device.patch new file mode 100644 index 0000000000..472b5df4e4 --- /dev/null +++ b/queue-6.12/interconnect-mediatek-don-t-hijack-parent-device.patch @@ -0,0 +1,53 @@ +From 3fdd5d52c18fd64066313cf827cf5f998d1a89f2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 24 Nov 2025 12:07:01 +0100 +Subject: interconnect: mediatek: Don't hijack parent device + +From: Nicolas Frattaroli + +[ Upstream commit 510f8214440c553e81774c5822437ccf154e9e38 ] + +If the intention is that users of the interconnect declare their +relationship to the child icc_emi node of the dvfsrc controller, then +this code never worked. That's because it uses the parent dvfsrc device +as the device it passes to the interconnect core framework, which means +all the OF parsing is broken. + +Use the actual device instead, and pass the dvfsrc parent into the +dvfsrc calls. + +Fixes: b45293799f75 ("interconnect: mediatek: Add MediaTek MT8183/8195 EMI Interconnect driver") +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Nicolas Frattaroli +Link: https://lore.kernel.org/r/20251124-mt8196-dvfsrc-v2-12-d9c1334db9f3@collabora.com +Signed-off-by: Georgi Djakov +Signed-off-by: Sasha Levin +--- + drivers/interconnect/mediatek/icc-emi.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/interconnect/mediatek/icc-emi.c b/drivers/interconnect/mediatek/icc-emi.c +index 7da740b5fa8d6..182aa2b0623af 100644 +--- a/drivers/interconnect/mediatek/icc-emi.c ++++ b/drivers/interconnect/mediatek/icc-emi.c +@@ -40,7 +40,7 @@ static int mtk_emi_icc_set(struct icc_node *src, struct icc_node *dst) + if (unlikely(!src->provider)) + return -EINVAL; + +- dev = src->provider->dev; ++ dev = src->provider->dev->parent; + + switch (node->ep) { + case 0: +@@ -97,7 +97,7 @@ int mtk_emi_icc_probe(struct platform_device *pdev) + if (!data) + return -ENOMEM; + +- provider->dev = pdev->dev.parent; ++ provider->dev = dev; + provider->set = mtk_emi_icc_set; + provider->aggregate = mtk_emi_icc_aggregate; + provider->xlate = of_icc_xlate_onecell; +-- +2.51.0 + diff --git a/queue-6.12/io_uring-cancel-de-unionize-file-and-user_data-in-st.patch b/queue-6.12/io_uring-cancel-de-unionize-file-and-user_data-in-st.patch new file mode 100644 index 0000000000..f8b78f67d0 --- /dev/null +++ b/queue-6.12/io_uring-cancel-de-unionize-file-and-user_data-in-st.patch @@ -0,0 +1,45 @@ +From 9f970902e8634397533b002dae1ab7a4e42e3c31 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 14:16:27 -0700 +Subject: io_uring/cancel: de-unionize file and user_data in struct + io_cancel_data + +From: Jens Axboe + +[ Upstream commit 22dbb0987bd1e0ec3b1e4ad20756a98f99aa4a08 ] + +By having them share the same space in struct io_cancel_data, it ends up +disallowing IORING_ASYNC_CANCEL_FD|IORING_ASYNC_CANCEL_USERDATA from +working. Eg you cannot match on both a file and user_data for +cancelation purposes. This obviously isn't a common use case as nobody +has reported this, but it does result in -ENOENT potentially being +returned when trying to match on both, rather than actually doing what +the API says it would. + +Fixes: 4bf94615b888 ("io_uring: allow IORING_OP_ASYNC_CANCEL with 'fd' key") +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + io_uring/cancel.h | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/io_uring/cancel.h b/io_uring/cancel.h +index b33995e00ba90..da13a1d820622 100644 +--- a/io_uring/cancel.h ++++ b/io_uring/cancel.h +@@ -6,10 +6,8 @@ + + struct io_cancel_data { + struct io_ring_ctx *ctx; +- union { +- u64 data; +- struct file *file; +- }; ++ u64 data; ++ struct file *file; + u8 opcode; + u32 flags; + int seq; +-- +2.51.0 + diff --git a/queue-6.12/io_uring-sync-validate-passed-in-offset.patch b/queue-6.12/io_uring-sync-validate-passed-in-offset.patch new file mode 100644 index 0000000000..b60d2b6500 --- /dev/null +++ b/queue-6.12/io_uring-sync-validate-passed-in-offset.patch @@ -0,0 +1,36 @@ +From b7e17026b0857818921738da5b4aed5bf84969a4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 11:48:56 -0700 +Subject: io_uring/sync: validate passed in offset + +From: Jens Axboe + +[ Upstream commit 649dd18f559891bdafc5532d737c7dfb56060a6d ] + +Check if the passed in offset is negative once cast to sync->off. This +ensures that -EINVAL is returned for that case, like it would be for +sync_file_range(2). + +Fixes: c992fe2925d7 ("io_uring: add fsync support") +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + io_uring/sync.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/io_uring/sync.c b/io_uring/sync.c +index 255f68c37e55c..27bd0a26500bc 100644 +--- a/io_uring/sync.c ++++ b/io_uring/sync.c +@@ -62,6 +62,8 @@ int io_fsync_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) + return -EINVAL; + + sync->off = READ_ONCE(sqe->off); ++ if (sync->off < 0) ++ return -EINVAL; + sync->len = READ_ONCE(sqe->len); + req->flags |= REQ_F_FORCE_ASYNC; + return 0; +-- +2.51.0 + diff --git a/queue-6.12/io_uring-use-release-acquire-ordering-for-ioring_set.patch b/queue-6.12/io_uring-use-release-acquire-ordering-for-ioring_set.patch new file mode 100644 index 0000000000..6bf0d0fe0d --- /dev/null +++ b/queue-6.12/io_uring-use-release-acquire-ordering-for-ioring_set.patch @@ -0,0 +1,93 @@ +From bba9a9701ab2fd918ebee4b4a15b1e3529631458 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Jan 2026 14:05:40 -0700 +Subject: io_uring: use release-acquire ordering for IORING_SETUP_R_DISABLED + +From: Caleb Sander Mateos + +[ Upstream commit 7a8737e1132ff07ca225aa7a4008f87319b5b1ca ] + +io_uring_enter(), __io_msg_ring_data(), and io_msg_send_fd() read +ctx->flags and ctx->submitter_task without holding the ctx's uring_lock. +This means they may race with the assignment to ctx->submitter_task and +the clearing of IORING_SETUP_R_DISABLED from ctx->flags in +io_register_enable_rings(). Ensure the correct ordering of the +ctx->flags and ctx->submitter_task memory accesses by storing to +ctx->flags using release ordering and loading it using acquire ordering. + +Signed-off-by: Caleb Sander Mateos +Fixes: 4add705e4eeb ("io_uring: remove io_register_submitter") +Reviewed-by: Joanne Koong +Reviewed-by: Gabriel Krisman Bertazi +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + io_uring/io_uring.c | 6 +++++- + io_uring/msg_ring.c | 12 ++++++++++-- + io_uring/register.c | 3 ++- + 3 files changed, 17 insertions(+), 4 deletions(-) + +diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c +index 99b0b1ba0fe22..5c60442e67028 100644 +--- a/io_uring/io_uring.c ++++ b/io_uring/io_uring.c +@@ -3312,7 +3312,11 @@ SYSCALL_DEFINE6(io_uring_enter, unsigned int, fd, u32, to_submit, + + ctx = file->private_data; + ret = -EBADFD; +- if (unlikely(ctx->flags & IORING_SETUP_R_DISABLED)) ++ /* ++ * Keep IORING_SETUP_R_DISABLED check before submitter_task load ++ * in io_uring_add_tctx_node() -> __io_uring_add_tctx_node_from_submit() ++ */ ++ if (unlikely(smp_load_acquire(&ctx->flags) & IORING_SETUP_R_DISABLED)) + goto out; + + /* +diff --git a/io_uring/msg_ring.c b/io_uring/msg_ring.c +index 97708e5132bc4..3cf59d8c58073 100644 +--- a/io_uring/msg_ring.c ++++ b/io_uring/msg_ring.c +@@ -126,7 +126,11 @@ static int io_msg_ring_data(struct io_kiocb *req, unsigned int issue_flags) + return -EINVAL; + if (!(msg->flags & IORING_MSG_RING_FLAGS_PASS) && msg->dst_fd) + return -EINVAL; +- if (target_ctx->flags & IORING_SETUP_R_DISABLED) ++ /* ++ * Keep IORING_SETUP_R_DISABLED check before submitter_task load ++ * in io_msg_data_remote() -> io_msg_remote_post() ++ */ ++ if (smp_load_acquire(&target_ctx->flags) & IORING_SETUP_R_DISABLED) + return -EBADFD; + + if (io_msg_need_remote(target_ctx)) +@@ -237,7 +241,11 @@ static int io_msg_send_fd(struct io_kiocb *req, unsigned int issue_flags) + return -EINVAL; + if (target_ctx == ctx) + return -EINVAL; +- if (target_ctx->flags & IORING_SETUP_R_DISABLED) ++ /* ++ * Keep IORING_SETUP_R_DISABLED check before submitter_task load ++ * in io_msg_fd_remote() ++ */ ++ if (smp_load_acquire(&target_ctx->flags) & IORING_SETUP_R_DISABLED) + return -EBADFD; + if (!src_file) { + src_file = io_msg_grab_file(req, issue_flags); +diff --git a/io_uring/register.c b/io_uring/register.c +index a325b493ae121..f700ddf1f1d1f 100644 +--- a/io_uring/register.c ++++ b/io_uring/register.c +@@ -190,7 +190,8 @@ static int io_register_enable_rings(struct io_ring_ctx *ctx) + if (ctx->restrictions.registered) + ctx->restricted = 1; + +- ctx->flags &= ~IORING_SETUP_R_DISABLED; ++ /* Keep submitter_task store before clearing IORING_SETUP_R_DISABLED */ ++ smp_store_release(&ctx->flags, ctx->flags & ~IORING_SETUP_R_DISABLED); + if (ctx->sq_data && wq_has_sleeper(&ctx->sq_data->wait)) + wake_up(&ctx->sq_data->wait); + return 0; +-- +2.51.0 + diff --git a/queue-6.12/iomap-fix-submission-side-handling-of-completion-sid.patch b/queue-6.12/iomap-fix-submission-side-handling-of-completion-sid.patch new file mode 100644 index 0000000000..72111529a5 --- /dev/null +++ b/queue-6.12/iomap-fix-submission-side-handling-of-completion-sid.patch @@ -0,0 +1,49 @@ +From 0f5992bc004af063db88ed22f4aed0680b3df827 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 06:53:38 +0100 +Subject: iomap: fix submission side handling of completion side errors + +From: Christoph Hellwig + +[ Upstream commit 4ad357e39b2ecd5da7bcc7e840ee24d179593cd5 ] + +The "if (dio->error)" in iomap_dio_bio_iter exists to stop submitting +more bios when a completion already return an error. Commit cfe057f7db1f +("iomap_dio_actor(): fix iov_iter bugs") made it revert the iov by +"copied", which is very wrong given that we've already consumed that +range and submitted a bio for it. + +Fixes: cfe057f7db1f ("iomap_dio_actor(): fix iov_iter bugs") +Signed-off-by: Christoph Hellwig +Reviewed-by: Damien Le Moal +Reviewed-by: Darrick J. Wong +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + fs/iomap/direct-io.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/fs/iomap/direct-io.c b/fs/iomap/direct-io.c +index 52dd8c9c3f6f0..5ccf215f932db 100644 +--- a/fs/iomap/direct-io.c ++++ b/fs/iomap/direct-io.c +@@ -398,9 +398,13 @@ static loff_t iomap_dio_bio_iter(const struct iomap_iter *iter, + nr_pages = bio_iov_vecs_to_alloc(dio->submit.iter, BIO_MAX_VECS); + do { + size_t n; +- if (dio->error) { +- iov_iter_revert(dio->submit.iter, copied); +- copied = ret = 0; ++ ++ /* ++ * If completions already occurred and reported errors, give up now and ++ * don't bother submitting more bios. ++ */ ++ if (unlikely(data_race(dio->error))) { ++ ret = 0; + goto out; + } + +-- +2.51.0 + diff --git a/queue-6.12/iommu-vt-d-avoid-draining-prq-in-sva-mm-release-path.patch b/queue-6.12/iommu-vt-d-avoid-draining-prq-in-sva-mm-release-path.patch new file mode 100644 index 0000000000..b278327ccc --- /dev/null +++ b/queue-6.12/iommu-vt-d-avoid-draining-prq-in-sva-mm-release-path.patch @@ -0,0 +1,61 @@ +From 68fbed3bf41b19b4787b828fcf8a77ff9ef1aba0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Dec 2024 09:17:52 +0800 +Subject: iommu/vt-d: Avoid draining PRQ in sva mm release path + +From: Lu Baolu + +[ Upstream commit dda2b8c3c6ccc50deae65cc75f246577348e2ec5 ] + +When a PASID is used for SVA by a device, it's possible that the PASID +entry is cleared before the device flushes all ongoing DMA requests and +removes the SVA domain. This can occur when an exception happens and the +process terminates before the device driver stops DMA and calls the +iommu driver to unbind the PASID. + +There's no need to drain the PRQ in the mm release path. Instead, the PRQ +will be drained in the SVA unbind path. + +Unfortunately, commit c43e1ccdebf2 ("iommu/vt-d: Drain PRQs when domain +removed from RID") changed this behavior by unconditionally draining the +PRQ in intel_pasid_tear_down_entry(). This can lead to a potential +sleeping-in-atomic-context issue. + +Smatch static checker warning: + + drivers/iommu/intel/prq.c:95 intel_iommu_drain_pasid_prq() + warn: sleeping in atomic context + +To avoid this issue, prevent draining the PRQ in the SVA mm release path +and restore the previous behavior. + +Fixes: c43e1ccdebf2 ("iommu/vt-d: Drain PRQs when domain removed from RID") +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/linux-iommu/c5187676-2fa2-4e29-94e0-4a279dc88b49@stanley.mountain/ +Signed-off-by: Lu Baolu +Reviewed-by: Kevin Tian +Link: https://lore.kernel.org/r/20241212021529.1104745-1-baolu.lu@linux.intel.com +Signed-off-by: Joerg Roedel +Stable-dep-of: 75ed00055c05 ("iommu/vt-d: Clear Present bit before tearing down PASID entry") +Signed-off-by: Sasha Levin +--- + drivers/iommu/intel/pasid.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c +index 4e4d167720ba8..57969ba2d3975 100644 +--- a/drivers/iommu/intel/pasid.c ++++ b/drivers/iommu/intel/pasid.c +@@ -266,7 +266,8 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev, + iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH); + + devtlb_invalidation_with_pasid(iommu, dev, pasid); +- intel_iommu_drain_pasid_prq(dev, pasid); ++ if (!fault_ignore) ++ intel_iommu_drain_pasid_prq(dev, pasid); + } + + /* +-- +2.51.0 + diff --git a/queue-6.12/iommu-vt-d-clear-present-bit-before-tearing-down-pas.patch b/queue-6.12/iommu-vt-d-clear-present-bit-before-tearing-down-pas.patch new file mode 100644 index 0000000000..51ddcf107f --- /dev/null +++ b/queue-6.12/iommu-vt-d-clear-present-bit-before-tearing-down-pas.patch @@ -0,0 +1,104 @@ +From c875c0c38ba8cc45d2a066d44a966e8bd09d9da7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 09:48:54 +0800 +Subject: iommu/vt-d: Clear Present bit before tearing down PASID entry + +From: Lu Baolu + +[ Upstream commit 75ed00055c059dedc47b5daaaa2f8a7a019138ff ] + +The Intel VT-d Scalable Mode PASID table entry consists of 512 bits (64 +bytes). When tearing down an entry, the current implementation zeros the +entire 64-byte structure immediately using multiple 64-bit writes. + +Since the IOMMU hardware may fetch these 64 bytes using multiple +internal transactions (e.g., four 128-bit bursts), updating or zeroing +the entire entry while it is active (P=1) risks a "torn" read. If a +hardware fetch occurs simultaneously with the CPU zeroing the entry, the +hardware could observe an inconsistent state, leading to unpredictable +behavior or spurious faults. + +Follow the "Guidance to Software for Invalidations" in the VT-d spec +(Section 6.5.3.3) by implementing the recommended ownership handshake: + +1. Clear only the 'Present' (P) bit of the PASID entry. +2. Use a dma_wmb() to ensure the cleared bit is visible to hardware + before proceeding. +3. Execute the required invalidation sequence (PASID cache, IOTLB, and + Device-TLB flush) to ensure the hardware has released all cached + references. +4. Only after the flushes are complete, zero out the remaining fields + of the PASID entry. + +Also, add a dma_wmb() in pasid_set_present() to ensure that all other +fields of the PASID entry are visible to the hardware before the Present +bit is set. + +Fixes: 0bbeb01a4faf ("iommu/vt-d: Manage scalalble mode PASID tables") +Signed-off-by: Lu Baolu +Reviewed-by: Dmytro Maluka +Reviewed-by: Samiullah Khawaja +Reviewed-by: Kevin Tian +Link: https://lore.kernel.org/r/20260120061816.2132558-2-baolu.lu@linux.intel.com +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/intel/pasid.c | 6 +++++- + drivers/iommu/intel/pasid.h | 14 ++++++++++++++ + 2 files changed, 19 insertions(+), 1 deletion(-) + +diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c +index 57969ba2d3975..7fa3efb8c223e 100644 +--- a/drivers/iommu/intel/pasid.c ++++ b/drivers/iommu/intel/pasid.c +@@ -252,7 +252,7 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev, + + did = pasid_get_domain_id(pte); + pgtt = pasid_pte_get_pgtt(pte); +- intel_pasid_clear_entry(dev, pasid, fault_ignore); ++ pasid_clear_present(pte); + spin_unlock(&iommu->lock); + + if (!ecap_coherent(iommu->ecap)) +@@ -266,6 +266,10 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev, + iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH); + + devtlb_invalidation_with_pasid(iommu, dev, pasid); ++ intel_pasid_clear_entry(dev, pasid, fault_ignore); ++ if (!ecap_coherent(iommu->ecap)) ++ clflush_cache_range(pte, sizeof(*pte)); ++ + if (!fault_ignore) + intel_iommu_drain_pasid_prq(dev, pasid); + } +diff --git a/drivers/iommu/intel/pasid.h b/drivers/iommu/intel/pasid.h +index dde6d3ba5ae0f..55cad7bfa294e 100644 +--- a/drivers/iommu/intel/pasid.h ++++ b/drivers/iommu/intel/pasid.h +@@ -235,9 +235,23 @@ static inline void pasid_set_wpe(struct pasid_entry *pe) + */ + static inline void pasid_set_present(struct pasid_entry *pe) + { ++ dma_wmb(); + pasid_set_bits(&pe->val[0], 1 << 0, 1); + } + ++/* ++ * Clear the Present (P) bit (bit 0) of a scalable-mode PASID table entry. ++ * This initiates the transition of the entry's ownership from hardware ++ * to software. The caller is responsible for fulfilling the invalidation ++ * handshake recommended by the VT-d spec, Section 6.5.3.3 (Guidance to ++ * Software for Invalidations). ++ */ ++static inline void pasid_clear_present(struct pasid_entry *pe) ++{ ++ pasid_set_bits(&pe->val[0], 1 << 0, 0); ++ dma_wmb(); ++} ++ + /* + * Setup Page Walk Snoop bit (Bit 87) of a scalable mode PASID + * entry. +-- +2.51.0 + diff --git a/queue-6.12/iommu-vt-d-drain-prqs-when-domain-removed-from-rid.patch b/queue-6.12/iommu-vt-d-drain-prqs-when-domain-removed-from-rid.patch new file mode 100644 index 0000000000..f932f54810 --- /dev/null +++ b/queue-6.12/iommu-vt-d-drain-prqs-when-domain-removed-from-rid.patch @@ -0,0 +1,117 @@ +From 63de813e33ea56822ebd23a241f7e11701c5c169 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 4 Nov 2024 09:40:39 +0800 +Subject: iommu/vt-d: Drain PRQs when domain removed from RID + +From: Lu Baolu + +[ Upstream commit c43e1ccdebf2c950545fdf12c5796ad6f7bad7ee ] + +As this iommu driver now supports page faults for requests without +PASID, page requests should be drained when a domain is removed from +the RID2PASID entry. + +This results in the intel_iommu_drain_pasid_prq() call being moved to +intel_pasid_tear_down_entry(). This indicates that when a translation +is removed from any PASID entry and the PRI has been enabled on the +device, page requests are drained in the domain detachment path. + +The intel_iommu_drain_pasid_prq() helper has been modified to support +sending device TLB invalidation requests for both PASID and non-PASID +cases. + +Signed-off-by: Lu Baolu +Reviewed-by: Yi Liu +Link: https://lore.kernel.org/r/20241101045543.70086-1-baolu.lu@linux.intel.com +Signed-off-by: Joerg Roedel +Stable-dep-of: 75ed00055c05 ("iommu/vt-d: Clear Present bit before tearing down PASID entry") +Signed-off-by: Sasha Levin +--- + drivers/iommu/intel/iommu.c | 1 - + drivers/iommu/intel/pasid.c | 1 + + drivers/iommu/intel/prq.c | 26 +++++++++----------------- + 3 files changed, 10 insertions(+), 18 deletions(-) + +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index 936db952f4385..d4f852f712aa8 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -4333,7 +4333,6 @@ static void intel_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid, + kfree(dev_pasid); + } + intel_pasid_tear_down_entry(iommu, dev, pasid, false); +- intel_iommu_drain_pasid_prq(dev, pasid); + } + + static int intel_iommu_set_dev_pasid(struct iommu_domain *domain, +diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c +index 2ec76333b6973..4e4d167720ba8 100644 +--- a/drivers/iommu/intel/pasid.c ++++ b/drivers/iommu/intel/pasid.c +@@ -266,6 +266,7 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev, + iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH); + + devtlb_invalidation_with_pasid(iommu, dev, pasid); ++ intel_iommu_drain_pasid_prq(dev, pasid); + } + + /* +diff --git a/drivers/iommu/intel/prq.c b/drivers/iommu/intel/prq.c +index edda5da8ba159..853d1cbb635fd 100644 +--- a/drivers/iommu/intel/prq.c ++++ b/drivers/iommu/intel/prq.c +@@ -63,26 +63,18 @@ void intel_iommu_drain_pasid_prq(struct device *dev, u32 pasid) + struct dmar_domain *domain; + struct intel_iommu *iommu; + struct qi_desc desc[3]; +- struct pci_dev *pdev; + int head, tail; + u16 sid, did; +- int qdep; + + info = dev_iommu_priv_get(dev); +- if (WARN_ON(!info || !dev_is_pci(dev))) +- return; +- + if (!info->pri_enabled) + return; + + iommu = info->iommu; + domain = info->domain; +- pdev = to_pci_dev(dev); + sid = PCI_DEVID(info->bus, info->devfn); + did = domain ? domain_id_iommu(domain, iommu) : FLPT_DEFAULT_DID; + +- qdep = pci_ats_queue_depth(pdev); +- + /* + * Check and wait until all pending page requests in the queue are + * handled by the prq handling thread. +@@ -114,15 +106,15 @@ void intel_iommu_drain_pasid_prq(struct device *dev, u32 pasid) + desc[0].qw0 = QI_IWD_STATUS_DATA(QI_DONE) | + QI_IWD_FENCE | + QI_IWD_TYPE; +- desc[1].qw0 = QI_EIOTLB_PASID(pasid) | +- QI_EIOTLB_DID(did) | +- QI_EIOTLB_GRAN(QI_GRAN_NONG_PASID) | +- QI_EIOTLB_TYPE; +- desc[2].qw0 = QI_DEV_EIOTLB_PASID(pasid) | +- QI_DEV_EIOTLB_SID(sid) | +- QI_DEV_EIOTLB_QDEP(qdep) | +- QI_DEIOTLB_TYPE | +- QI_DEV_IOTLB_PFSID(info->pfsid); ++ if (pasid == IOMMU_NO_PASID) { ++ qi_desc_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH, &desc[1]); ++ qi_desc_dev_iotlb(sid, info->pfsid, info->ats_qdep, 0, ++ MAX_AGAW_PFN_WIDTH, &desc[2]); ++ } else { ++ qi_desc_piotlb(did, pasid, 0, -1, 0, &desc[1]); ++ qi_desc_dev_iotlb_pasid(sid, info->pfsid, pasid, info->ats_qdep, ++ 0, MAX_AGAW_PFN_WIDTH, &desc[2]); ++ } + qi_retry: + reinit_completion(&iommu->prq_complete); + qi_submit_sync(iommu, desc, 3, QI_OPT_WAIT_DRAIN); +-- +2.51.0 + diff --git a/queue-6.12/iommu-vt-d-flush-cache-for-pasid-table-before-using-.patch b/queue-6.12/iommu-vt-d-flush-cache-for-pasid-table-before-using-.patch new file mode 100644 index 0000000000..3e5a187cc1 --- /dev/null +++ b/queue-6.12/iommu-vt-d-flush-cache-for-pasid-table-before-using-.patch @@ -0,0 +1,55 @@ +From e933b920015284a9a4199a22c0d0eaf24ec37ea9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 09:48:52 +0800 +Subject: iommu/vt-d: Flush cache for PASID table before using it + +From: Dmytro Maluka + +[ Upstream commit 22d169bdd2849fe6bd18c2643742e1c02be6451c ] + +When writing the address of a freshly allocated zero-initialized PASID +table to a PASID directory entry, do that after the CPU cache flush for +this PASID table, not before it, to avoid the time window when this +PASID table may be already used by non-coherent IOMMU hardware while +its contents in RAM is still some random old data, not zero-initialized. + +Fixes: 194b3348bdbb ("iommu/vt-d: Fix PASID directory pointer coherency") +Signed-off-by: Dmytro Maluka +Reviewed-by: Kevin Tian +Link: https://lore.kernel.org/r/20251221123508.37495-1-dmaluka@chromium.org +Signed-off-by: Lu Baolu +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/intel/pasid.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c +index 2e5fa0a232999..2ec76333b6973 100644 +--- a/drivers/iommu/intel/pasid.c ++++ b/drivers/iommu/intel/pasid.c +@@ -152,6 +152,9 @@ static struct pasid_entry *intel_pasid_get_entry(struct device *dev, u32 pasid) + if (!entries) + return NULL; + ++ if (!ecap_coherent(info->iommu->ecap)) ++ clflush_cache_range(entries, VTD_PAGE_SIZE); ++ + /* + * The pasid directory table entry won't be freed after + * allocation. No worry about the race with free and +@@ -164,10 +167,8 @@ static struct pasid_entry *intel_pasid_get_entry(struct device *dev, u32 pasid) + iommu_free_page(entries); + goto retry; + } +- if (!ecap_coherent(info->iommu->ecap)) { +- clflush_cache_range(entries, VTD_PAGE_SIZE); ++ if (!ecap_coherent(info->iommu->ecap)) + clflush_cache_range(&dir[dir_index].val, sizeof(*dir)); +- } + } + + return &entries[index]; +-- +2.51.0 + diff --git a/queue-6.12/iommu-vt-d-separate-page-request-queue-from-svm.patch b/queue-6.12/iommu-vt-d-separate-page-request-queue-from-svm.patch new file mode 100644 index 0000000000..e9771d549c --- /dev/null +++ b/queue-6.12/iommu-vt-d-separate-page-request-queue-from-svm.patch @@ -0,0 +1,996 @@ +From 186e187c5ffe9833618304c0c5da734c8377cd24 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 4 Nov 2024 09:40:34 +0800 +Subject: iommu/vt-d: Separate page request queue from SVM + +From: Joel Granados + +[ Upstream commit 4d5440957641fb5652cbef8df6183baf473cab6b ] + +IO page faults are no longer dependent on CONFIG_INTEL_IOMMU_SVM. Move +all Page Request Queue (PRQ) functions that handle prq events to a new +file in drivers/iommu/intel/prq.c. The page_req_des struct is now +declared in drivers/iommu/intel/prq.c. + +No functional changes are intended. This is a preparation patch to +enable the use of IO page faults outside the SVM/PASID use cases. + +Signed-off-by: Joel Granados +Link: https://lore.kernel.org/r/20241015-jag-iopfv8-v4-1-b696ca89ba29@kernel.org +Signed-off-by: Lu Baolu +Signed-off-by: Joerg Roedel +Stable-dep-of: 75ed00055c05 ("iommu/vt-d: Clear Present bit before tearing down PASID entry") +Signed-off-by: Sasha Levin +--- + drivers/iommu/intel/Makefile | 2 +- + drivers/iommu/intel/iommu.c | 20 +- + drivers/iommu/intel/iommu.h | 14 +- + drivers/iommu/intel/prq.c | 410 +++++++++++++++++++++++++++++++++++ + drivers/iommu/intel/svm.c | 397 --------------------------------- + 5 files changed, 424 insertions(+), 419 deletions(-) + create mode 100644 drivers/iommu/intel/prq.c + +diff --git a/drivers/iommu/intel/Makefile b/drivers/iommu/intel/Makefile +index c8beb0281559f..d3bb0798092df 100644 +--- a/drivers/iommu/intel/Makefile ++++ b/drivers/iommu/intel/Makefile +@@ -1,6 +1,6 @@ + # SPDX-License-Identifier: GPL-2.0 + obj-$(CONFIG_DMAR_TABLE) += dmar.o +-obj-$(CONFIG_INTEL_IOMMU) += iommu.o pasid.o nested.o cache.o ++obj-$(CONFIG_INTEL_IOMMU) += iommu.o pasid.o nested.o cache.o prq.o + obj-$(CONFIG_DMAR_TABLE) += trace.o cap_audit.o + obj-$(CONFIG_DMAR_PERF) += perf.o + obj-$(CONFIG_INTEL_IOMMU_DEBUGFS) += debugfs.o +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index c799cc67db34e..936db952f4385 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -1440,12 +1440,10 @@ static void free_dmar_iommu(struct intel_iommu *iommu) + /* free context mapping */ + free_context_table(iommu); + +-#ifdef CONFIG_INTEL_IOMMU_SVM + if (pasid_supported(iommu)) { + if (ecap_prs(iommu->ecap)) +- intel_svm_finish_prq(iommu); ++ intel_iommu_finish_prq(iommu); + } +-#endif + } + + /* +@@ -2386,19 +2384,18 @@ static int __init init_dmars(void) + + iommu_flush_write_buffer(iommu); + +-#ifdef CONFIG_INTEL_IOMMU_SVM + if (pasid_supported(iommu) && ecap_prs(iommu->ecap)) { + /* + * Call dmar_alloc_hwirq() with dmar_global_lock held, + * could cause possible lock race condition. + */ + up_write(&dmar_global_lock); +- ret = intel_svm_enable_prq(iommu); ++ ret = intel_iommu_enable_prq(iommu); + down_write(&dmar_global_lock); + if (ret) + goto free_iommu; + } +-#endif ++ + ret = dmar_set_interrupt(iommu); + if (ret) + goto free_iommu; +@@ -2818,13 +2815,12 @@ static int intel_iommu_add(struct dmar_drhd_unit *dmaru) + intel_iommu_init_qi(iommu); + iommu_flush_write_buffer(iommu); + +-#ifdef CONFIG_INTEL_IOMMU_SVM + if (pasid_supported(iommu) && ecap_prs(iommu->ecap)) { +- ret = intel_svm_enable_prq(iommu); ++ ret = intel_iommu_enable_prq(iommu); + if (ret) + goto disable_iommu; + } +-#endif ++ + ret = dmar_set_interrupt(iommu); + if (ret) + goto disable_iommu; +@@ -4337,7 +4333,7 @@ static void intel_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid, + kfree(dev_pasid); + } + intel_pasid_tear_down_entry(iommu, dev, pasid, false); +- intel_drain_pasid_prq(dev, pasid); ++ intel_iommu_drain_pasid_prq(dev, pasid); + } + + static int intel_iommu_set_dev_pasid(struct iommu_domain *domain, +@@ -4665,9 +4661,7 @@ const struct iommu_ops intel_iommu_ops = { + .def_domain_type = device_def_domain_type, + .remove_dev_pasid = intel_iommu_remove_dev_pasid, + .pgsize_bitmap = SZ_4K, +-#ifdef CONFIG_INTEL_IOMMU_SVM +- .page_response = intel_svm_page_response, +-#endif ++ .page_response = intel_iommu_page_response, + .default_domain_ops = &(const struct iommu_domain_ops) { + .attach_dev = intel_iommu_attach_device, + .set_dev_pasid = intel_iommu_set_dev_pasid, +diff --git a/drivers/iommu/intel/iommu.h b/drivers/iommu/intel/iommu.h +index 5b5f57d694afd..b33d8888d7ebd 100644 +--- a/drivers/iommu/intel/iommu.h ++++ b/drivers/iommu/intel/iommu.h +@@ -734,12 +734,10 @@ struct intel_iommu { + + struct iommu_flush flush; + #endif +-#ifdef CONFIG_INTEL_IOMMU_SVM + struct page_req_dsc *prq; + unsigned char prq_name[16]; /* Name for PRQ interrupt */ + unsigned long prq_seq_number; + struct completion prq_complete; +-#endif + struct iopf_queue *iopf_queue; + unsigned char iopfq_name[16]; + /* Synchronization between fault report and iommu device release. */ +@@ -1283,18 +1281,18 @@ void intel_context_flush_present(struct device_domain_info *info, + struct context_entry *context, + u16 did, bool affect_domains); + ++int intel_iommu_enable_prq(struct intel_iommu *iommu); ++int intel_iommu_finish_prq(struct intel_iommu *iommu); ++void intel_iommu_page_response(struct device *dev, struct iopf_fault *evt, ++ struct iommu_page_response *msg); ++void intel_iommu_drain_pasid_prq(struct device *dev, u32 pasid); ++ + #ifdef CONFIG_INTEL_IOMMU_SVM + void intel_svm_check(struct intel_iommu *iommu); +-int intel_svm_enable_prq(struct intel_iommu *iommu); +-int intel_svm_finish_prq(struct intel_iommu *iommu); +-void intel_svm_page_response(struct device *dev, struct iopf_fault *evt, +- struct iommu_page_response *msg); + struct iommu_domain *intel_svm_domain_alloc(struct device *dev, + struct mm_struct *mm); +-void intel_drain_pasid_prq(struct device *dev, u32 pasid); + #else + static inline void intel_svm_check(struct intel_iommu *iommu) {} +-static inline void intel_drain_pasid_prq(struct device *dev, u32 pasid) {} + static inline struct iommu_domain *intel_svm_domain_alloc(struct device *dev, + struct mm_struct *mm) + { +diff --git a/drivers/iommu/intel/prq.c b/drivers/iommu/intel/prq.c +new file mode 100644 +index 0000000000000..edda5da8ba159 +--- /dev/null ++++ b/drivers/iommu/intel/prq.c +@@ -0,0 +1,410 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Copyright (C) 2015 Intel Corporation ++ * ++ * Originally split from drivers/iommu/intel/svm.c ++ */ ++ ++#include ++#include ++ ++#include "iommu.h" ++#include "pasid.h" ++#include "../iommu-pages.h" ++#include "trace.h" ++ ++/* Page request queue descriptor */ ++struct page_req_dsc { ++ union { ++ struct { ++ u64 type:8; ++ u64 pasid_present:1; ++ u64 rsvd:7; ++ u64 rid:16; ++ u64 pasid:20; ++ u64 exe_req:1; ++ u64 pm_req:1; ++ u64 rsvd2:10; ++ }; ++ u64 qw_0; ++ }; ++ union { ++ struct { ++ u64 rd_req:1; ++ u64 wr_req:1; ++ u64 lpig:1; ++ u64 prg_index:9; ++ u64 addr:52; ++ }; ++ u64 qw_1; ++ }; ++ u64 qw_2; ++ u64 qw_3; ++}; ++ ++/** ++ * intel_iommu_drain_pasid_prq - Drain page requests and responses for a pasid ++ * @dev: target device ++ * @pasid: pasid for draining ++ * ++ * Drain all pending page requests and responses related to @pasid in both ++ * software and hardware. This is supposed to be called after the device ++ * driver has stopped DMA, the pasid entry has been cleared, and both IOTLB ++ * and DevTLB have been invalidated. ++ * ++ * It waits until all pending page requests for @pasid in the page fault ++ * queue are completed by the prq handling thread. Then follow the steps ++ * described in VT-d spec CH7.10 to drain all page requests and page ++ * responses pending in the hardware. ++ */ ++void intel_iommu_drain_pasid_prq(struct device *dev, u32 pasid) ++{ ++ struct device_domain_info *info; ++ struct dmar_domain *domain; ++ struct intel_iommu *iommu; ++ struct qi_desc desc[3]; ++ struct pci_dev *pdev; ++ int head, tail; ++ u16 sid, did; ++ int qdep; ++ ++ info = dev_iommu_priv_get(dev); ++ if (WARN_ON(!info || !dev_is_pci(dev))) ++ return; ++ ++ if (!info->pri_enabled) ++ return; ++ ++ iommu = info->iommu; ++ domain = info->domain; ++ pdev = to_pci_dev(dev); ++ sid = PCI_DEVID(info->bus, info->devfn); ++ did = domain ? domain_id_iommu(domain, iommu) : FLPT_DEFAULT_DID; ++ ++ qdep = pci_ats_queue_depth(pdev); ++ ++ /* ++ * Check and wait until all pending page requests in the queue are ++ * handled by the prq handling thread. ++ */ ++prq_retry: ++ reinit_completion(&iommu->prq_complete); ++ tail = dmar_readq(iommu->reg + DMAR_PQT_REG) & PRQ_RING_MASK; ++ head = dmar_readq(iommu->reg + DMAR_PQH_REG) & PRQ_RING_MASK; ++ while (head != tail) { ++ struct page_req_dsc *req; ++ ++ req = &iommu->prq[head / sizeof(*req)]; ++ if (!req->pasid_present || req->pasid != pasid) { ++ head = (head + sizeof(*req)) & PRQ_RING_MASK; ++ continue; ++ } ++ ++ wait_for_completion(&iommu->prq_complete); ++ goto prq_retry; ++ } ++ ++ iopf_queue_flush_dev(dev); ++ ++ /* ++ * Perform steps described in VT-d spec CH7.10 to drain page ++ * requests and responses in hardware. ++ */ ++ memset(desc, 0, sizeof(desc)); ++ desc[0].qw0 = QI_IWD_STATUS_DATA(QI_DONE) | ++ QI_IWD_FENCE | ++ QI_IWD_TYPE; ++ desc[1].qw0 = QI_EIOTLB_PASID(pasid) | ++ QI_EIOTLB_DID(did) | ++ QI_EIOTLB_GRAN(QI_GRAN_NONG_PASID) | ++ QI_EIOTLB_TYPE; ++ desc[2].qw0 = QI_DEV_EIOTLB_PASID(pasid) | ++ QI_DEV_EIOTLB_SID(sid) | ++ QI_DEV_EIOTLB_QDEP(qdep) | ++ QI_DEIOTLB_TYPE | ++ QI_DEV_IOTLB_PFSID(info->pfsid); ++qi_retry: ++ reinit_completion(&iommu->prq_complete); ++ qi_submit_sync(iommu, desc, 3, QI_OPT_WAIT_DRAIN); ++ if (readl(iommu->reg + DMAR_PRS_REG) & DMA_PRS_PRO) { ++ wait_for_completion(&iommu->prq_complete); ++ goto qi_retry; ++ } ++} ++ ++static bool is_canonical_address(u64 addr) ++{ ++ int shift = 64 - (__VIRTUAL_MASK_SHIFT + 1); ++ long saddr = (long)addr; ++ ++ return (((saddr << shift) >> shift) == saddr); ++} ++ ++static void handle_bad_prq_event(struct intel_iommu *iommu, ++ struct page_req_dsc *req, int result) ++{ ++ struct qi_desc desc = { }; ++ ++ pr_err("%s: Invalid page request: %08llx %08llx\n", ++ iommu->name, ((unsigned long long *)req)[0], ++ ((unsigned long long *)req)[1]); ++ ++ if (!req->lpig) ++ return; ++ ++ desc.qw0 = QI_PGRP_PASID(req->pasid) | ++ QI_PGRP_DID(req->rid) | ++ QI_PGRP_PASID_P(req->pasid_present) | ++ QI_PGRP_RESP_CODE(result) | ++ QI_PGRP_RESP_TYPE; ++ desc.qw1 = QI_PGRP_IDX(req->prg_index) | ++ QI_PGRP_LPIG(req->lpig); ++ ++ qi_submit_sync(iommu, &desc, 1, 0); ++} ++ ++static int prq_to_iommu_prot(struct page_req_dsc *req) ++{ ++ int prot = 0; ++ ++ if (req->rd_req) ++ prot |= IOMMU_FAULT_PERM_READ; ++ if (req->wr_req) ++ prot |= IOMMU_FAULT_PERM_WRITE; ++ if (req->exe_req) ++ prot |= IOMMU_FAULT_PERM_EXEC; ++ if (req->pm_req) ++ prot |= IOMMU_FAULT_PERM_PRIV; ++ ++ return prot; ++} ++ ++static void intel_prq_report(struct intel_iommu *iommu, struct device *dev, ++ struct page_req_dsc *desc) ++{ ++ struct iopf_fault event = { }; ++ ++ /* Fill in event data for device specific processing */ ++ event.fault.type = IOMMU_FAULT_PAGE_REQ; ++ event.fault.prm.addr = (u64)desc->addr << VTD_PAGE_SHIFT; ++ event.fault.prm.pasid = desc->pasid; ++ event.fault.prm.grpid = desc->prg_index; ++ event.fault.prm.perm = prq_to_iommu_prot(desc); ++ ++ if (desc->lpig) ++ event.fault.prm.flags |= IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE; ++ if (desc->pasid_present) { ++ event.fault.prm.flags |= IOMMU_FAULT_PAGE_REQUEST_PASID_VALID; ++ event.fault.prm.flags |= IOMMU_FAULT_PAGE_RESPONSE_NEEDS_PASID; ++ } ++ ++ iommu_report_device_fault(dev, &event); ++} ++ ++static irqreturn_t prq_event_thread(int irq, void *d) ++{ ++ struct intel_iommu *iommu = d; ++ struct page_req_dsc *req; ++ int head, tail, handled; ++ struct device *dev; ++ u64 address; ++ ++ /* ++ * Clear PPR bit before reading head/tail registers, to ensure that ++ * we get a new interrupt if needed. ++ */ ++ writel(DMA_PRS_PPR, iommu->reg + DMAR_PRS_REG); ++ ++ tail = dmar_readq(iommu->reg + DMAR_PQT_REG) & PRQ_RING_MASK; ++ head = dmar_readq(iommu->reg + DMAR_PQH_REG) & PRQ_RING_MASK; ++ handled = (head != tail); ++ while (head != tail) { ++ req = &iommu->prq[head / sizeof(*req)]; ++ address = (u64)req->addr << VTD_PAGE_SHIFT; ++ ++ if (unlikely(!req->pasid_present)) { ++ pr_err("IOMMU: %s: Page request without PASID\n", ++ iommu->name); ++bad_req: ++ handle_bad_prq_event(iommu, req, QI_RESP_INVALID); ++ goto prq_advance; ++ } ++ ++ if (unlikely(!is_canonical_address(address))) { ++ pr_err("IOMMU: %s: Address is not canonical\n", ++ iommu->name); ++ goto bad_req; ++ } ++ ++ if (unlikely(req->pm_req && (req->rd_req | req->wr_req))) { ++ pr_err("IOMMU: %s: Page request in Privilege Mode\n", ++ iommu->name); ++ goto bad_req; ++ } ++ ++ if (unlikely(req->exe_req && req->rd_req)) { ++ pr_err("IOMMU: %s: Execution request not supported\n", ++ iommu->name); ++ goto bad_req; ++ } ++ ++ /* Drop Stop Marker message. No need for a response. */ ++ if (unlikely(req->lpig && !req->rd_req && !req->wr_req)) ++ goto prq_advance; ++ ++ /* ++ * If prq is to be handled outside iommu driver via receiver of ++ * the fault notifiers, we skip the page response here. ++ */ ++ mutex_lock(&iommu->iopf_lock); ++ dev = device_rbtree_find(iommu, req->rid); ++ if (!dev) { ++ mutex_unlock(&iommu->iopf_lock); ++ goto bad_req; ++ } ++ ++ intel_prq_report(iommu, dev, req); ++ trace_prq_report(iommu, dev, req->qw_0, req->qw_1, ++ req->qw_2, req->qw_3, ++ iommu->prq_seq_number++); ++ mutex_unlock(&iommu->iopf_lock); ++prq_advance: ++ head = (head + sizeof(*req)) & PRQ_RING_MASK; ++ } ++ ++ dmar_writeq(iommu->reg + DMAR_PQH_REG, tail); ++ ++ /* ++ * Clear the page request overflow bit and wake up all threads that ++ * are waiting for the completion of this handling. ++ */ ++ if (readl(iommu->reg + DMAR_PRS_REG) & DMA_PRS_PRO) { ++ pr_info_ratelimited("IOMMU: %s: PRQ overflow detected\n", ++ iommu->name); ++ head = dmar_readq(iommu->reg + DMAR_PQH_REG) & PRQ_RING_MASK; ++ tail = dmar_readq(iommu->reg + DMAR_PQT_REG) & PRQ_RING_MASK; ++ if (head == tail) { ++ iopf_queue_discard_partial(iommu->iopf_queue); ++ writel(DMA_PRS_PRO, iommu->reg + DMAR_PRS_REG); ++ pr_info_ratelimited("IOMMU: %s: PRQ overflow cleared", ++ iommu->name); ++ } ++ } ++ ++ if (!completion_done(&iommu->prq_complete)) ++ complete(&iommu->prq_complete); ++ ++ return IRQ_RETVAL(handled); ++} ++ ++int intel_iommu_enable_prq(struct intel_iommu *iommu) ++{ ++ struct iopf_queue *iopfq; ++ int irq, ret; ++ ++ iommu->prq = iommu_alloc_pages_node(iommu->node, GFP_KERNEL, PRQ_ORDER); ++ if (!iommu->prq) { ++ pr_warn("IOMMU: %s: Failed to allocate page request queue\n", ++ iommu->name); ++ return -ENOMEM; ++ } ++ ++ irq = dmar_alloc_hwirq(IOMMU_IRQ_ID_OFFSET_PRQ + iommu->seq_id, iommu->node, iommu); ++ if (irq <= 0) { ++ pr_err("IOMMU: %s: Failed to create IRQ vector for page request queue\n", ++ iommu->name); ++ ret = -EINVAL; ++ goto free_prq; ++ } ++ iommu->pr_irq = irq; ++ ++ snprintf(iommu->iopfq_name, sizeof(iommu->iopfq_name), ++ "dmar%d-iopfq", iommu->seq_id); ++ iopfq = iopf_queue_alloc(iommu->iopfq_name); ++ if (!iopfq) { ++ pr_err("IOMMU: %s: Failed to allocate iopf queue\n", iommu->name); ++ ret = -ENOMEM; ++ goto free_hwirq; ++ } ++ iommu->iopf_queue = iopfq; ++ ++ snprintf(iommu->prq_name, sizeof(iommu->prq_name), "dmar%d-prq", iommu->seq_id); ++ ++ ret = request_threaded_irq(irq, NULL, prq_event_thread, IRQF_ONESHOT, ++ iommu->prq_name, iommu); ++ if (ret) { ++ pr_err("IOMMU: %s: Failed to request IRQ for page request queue\n", ++ iommu->name); ++ goto free_iopfq; ++ } ++ dmar_writeq(iommu->reg + DMAR_PQH_REG, 0ULL); ++ dmar_writeq(iommu->reg + DMAR_PQT_REG, 0ULL); ++ dmar_writeq(iommu->reg + DMAR_PQA_REG, virt_to_phys(iommu->prq) | PRQ_ORDER); ++ ++ init_completion(&iommu->prq_complete); ++ ++ return 0; ++ ++free_iopfq: ++ iopf_queue_free(iommu->iopf_queue); ++ iommu->iopf_queue = NULL; ++free_hwirq: ++ dmar_free_hwirq(irq); ++ iommu->pr_irq = 0; ++free_prq: ++ iommu_free_pages(iommu->prq, PRQ_ORDER); ++ iommu->prq = NULL; ++ ++ return ret; ++} ++ ++int intel_iommu_finish_prq(struct intel_iommu *iommu) ++{ ++ dmar_writeq(iommu->reg + DMAR_PQH_REG, 0ULL); ++ dmar_writeq(iommu->reg + DMAR_PQT_REG, 0ULL); ++ dmar_writeq(iommu->reg + DMAR_PQA_REG, 0ULL); ++ ++ if (iommu->pr_irq) { ++ free_irq(iommu->pr_irq, iommu); ++ dmar_free_hwirq(iommu->pr_irq); ++ iommu->pr_irq = 0; ++ } ++ ++ if (iommu->iopf_queue) { ++ iopf_queue_free(iommu->iopf_queue); ++ iommu->iopf_queue = NULL; ++ } ++ ++ iommu_free_pages(iommu->prq, PRQ_ORDER); ++ iommu->prq = NULL; ++ ++ return 0; ++} ++ ++void intel_iommu_page_response(struct device *dev, struct iopf_fault *evt, ++ struct iommu_page_response *msg) ++{ ++ struct device_domain_info *info = dev_iommu_priv_get(dev); ++ struct intel_iommu *iommu = info->iommu; ++ u8 bus = info->bus, devfn = info->devfn; ++ struct iommu_fault_page_request *prm; ++ struct qi_desc desc; ++ bool pasid_present; ++ bool last_page; ++ u16 sid; ++ ++ prm = &evt->fault.prm; ++ sid = PCI_DEVID(bus, devfn); ++ pasid_present = prm->flags & IOMMU_FAULT_PAGE_REQUEST_PASID_VALID; ++ last_page = prm->flags & IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE; ++ ++ desc.qw0 = QI_PGRP_PASID(prm->pasid) | QI_PGRP_DID(sid) | ++ QI_PGRP_PASID_P(pasid_present) | ++ QI_PGRP_RESP_CODE(msg->code) | ++ QI_PGRP_RESP_TYPE; ++ desc.qw1 = QI_PGRP_IDX(prm->grpid) | QI_PGRP_LPIG(last_page); ++ desc.qw2 = 0; ++ desc.qw3 = 0; ++ ++ qi_submit_sync(iommu, &desc, 1, 0); ++} +diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c +index 078d1e32a24ee..3cc43a958b4dc 100644 +--- a/drivers/iommu/intel/svm.c ++++ b/drivers/iommu/intel/svm.c +@@ -25,92 +25,6 @@ + #include "../iommu-pages.h" + #include "trace.h" + +-static irqreturn_t prq_event_thread(int irq, void *d); +- +-int intel_svm_enable_prq(struct intel_iommu *iommu) +-{ +- struct iopf_queue *iopfq; +- int irq, ret; +- +- iommu->prq = iommu_alloc_pages_node(iommu->node, GFP_KERNEL, PRQ_ORDER); +- if (!iommu->prq) { +- pr_warn("IOMMU: %s: Failed to allocate page request queue\n", +- iommu->name); +- return -ENOMEM; +- } +- +- irq = dmar_alloc_hwirq(IOMMU_IRQ_ID_OFFSET_PRQ + iommu->seq_id, iommu->node, iommu); +- if (irq <= 0) { +- pr_err("IOMMU: %s: Failed to create IRQ vector for page request queue\n", +- iommu->name); +- ret = -EINVAL; +- goto free_prq; +- } +- iommu->pr_irq = irq; +- +- snprintf(iommu->iopfq_name, sizeof(iommu->iopfq_name), +- "dmar%d-iopfq", iommu->seq_id); +- iopfq = iopf_queue_alloc(iommu->iopfq_name); +- if (!iopfq) { +- pr_err("IOMMU: %s: Failed to allocate iopf queue\n", iommu->name); +- ret = -ENOMEM; +- goto free_hwirq; +- } +- iommu->iopf_queue = iopfq; +- +- snprintf(iommu->prq_name, sizeof(iommu->prq_name), "dmar%d-prq", iommu->seq_id); +- +- ret = request_threaded_irq(irq, NULL, prq_event_thread, IRQF_ONESHOT, +- iommu->prq_name, iommu); +- if (ret) { +- pr_err("IOMMU: %s: Failed to request IRQ for page request queue\n", +- iommu->name); +- goto free_iopfq; +- } +- dmar_writeq(iommu->reg + DMAR_PQH_REG, 0ULL); +- dmar_writeq(iommu->reg + DMAR_PQT_REG, 0ULL); +- dmar_writeq(iommu->reg + DMAR_PQA_REG, virt_to_phys(iommu->prq) | PRQ_ORDER); +- +- init_completion(&iommu->prq_complete); +- +- return 0; +- +-free_iopfq: +- iopf_queue_free(iommu->iopf_queue); +- iommu->iopf_queue = NULL; +-free_hwirq: +- dmar_free_hwirq(irq); +- iommu->pr_irq = 0; +-free_prq: +- iommu_free_pages(iommu->prq, PRQ_ORDER); +- iommu->prq = NULL; +- +- return ret; +-} +- +-int intel_svm_finish_prq(struct intel_iommu *iommu) +-{ +- dmar_writeq(iommu->reg + DMAR_PQH_REG, 0ULL); +- dmar_writeq(iommu->reg + DMAR_PQT_REG, 0ULL); +- dmar_writeq(iommu->reg + DMAR_PQA_REG, 0ULL); +- +- if (iommu->pr_irq) { +- free_irq(iommu->pr_irq, iommu); +- dmar_free_hwirq(iommu->pr_irq); +- iommu->pr_irq = 0; +- } +- +- if (iommu->iopf_queue) { +- iopf_queue_free(iommu->iopf_queue); +- iommu->iopf_queue = NULL; +- } +- +- iommu_free_pages(iommu->prq, PRQ_ORDER); +- iommu->prq = NULL; +- +- return 0; +-} +- + void intel_svm_check(struct intel_iommu *iommu) + { + if (!pasid_supported(iommu)) +@@ -240,317 +154,6 @@ static int intel_svm_set_dev_pasid(struct iommu_domain *domain, + return ret; + } + +-/* Page request queue descriptor */ +-struct page_req_dsc { +- union { +- struct { +- u64 type:8; +- u64 pasid_present:1; +- u64 rsvd:7; +- u64 rid:16; +- u64 pasid:20; +- u64 exe_req:1; +- u64 pm_req:1; +- u64 rsvd2:10; +- }; +- u64 qw_0; +- }; +- union { +- struct { +- u64 rd_req:1; +- u64 wr_req:1; +- u64 lpig:1; +- u64 prg_index:9; +- u64 addr:52; +- }; +- u64 qw_1; +- }; +- u64 qw_2; +- u64 qw_3; +-}; +- +-static bool is_canonical_address(u64 addr) +-{ +- int shift = 64 - (__VIRTUAL_MASK_SHIFT + 1); +- long saddr = (long) addr; +- +- return (((saddr << shift) >> shift) == saddr); +-} +- +-/** +- * intel_drain_pasid_prq - Drain page requests and responses for a pasid +- * @dev: target device +- * @pasid: pasid for draining +- * +- * Drain all pending page requests and responses related to @pasid in both +- * software and hardware. This is supposed to be called after the device +- * driver has stopped DMA, the pasid entry has been cleared, and both IOTLB +- * and DevTLB have been invalidated. +- * +- * It waits until all pending page requests for @pasid in the page fault +- * queue are completed by the prq handling thread. Then follow the steps +- * described in VT-d spec CH7.10 to drain all page requests and page +- * responses pending in the hardware. +- */ +-void intel_drain_pasid_prq(struct device *dev, u32 pasid) +-{ +- struct device_domain_info *info; +- struct dmar_domain *domain; +- struct intel_iommu *iommu; +- struct qi_desc desc[3]; +- struct pci_dev *pdev; +- int head, tail; +- u16 sid, did; +- int qdep; +- +- info = dev_iommu_priv_get(dev); +- if (WARN_ON(!info || !dev_is_pci(dev))) +- return; +- +- if (!info->pri_enabled) +- return; +- +- iommu = info->iommu; +- domain = info->domain; +- pdev = to_pci_dev(dev); +- sid = PCI_DEVID(info->bus, info->devfn); +- did = domain ? domain_id_iommu(domain, iommu) : FLPT_DEFAULT_DID; +- qdep = pci_ats_queue_depth(pdev); +- +- /* +- * Check and wait until all pending page requests in the queue are +- * handled by the prq handling thread. +- */ +-prq_retry: +- reinit_completion(&iommu->prq_complete); +- tail = dmar_readq(iommu->reg + DMAR_PQT_REG) & PRQ_RING_MASK; +- head = dmar_readq(iommu->reg + DMAR_PQH_REG) & PRQ_RING_MASK; +- while (head != tail) { +- struct page_req_dsc *req; +- +- req = &iommu->prq[head / sizeof(*req)]; +- if (!req->pasid_present || req->pasid != pasid) { +- head = (head + sizeof(*req)) & PRQ_RING_MASK; +- continue; +- } +- +- wait_for_completion(&iommu->prq_complete); +- goto prq_retry; +- } +- +- iopf_queue_flush_dev(dev); +- +- /* +- * Perform steps described in VT-d spec CH7.10 to drain page +- * requests and responses in hardware. +- */ +- memset(desc, 0, sizeof(desc)); +- desc[0].qw0 = QI_IWD_STATUS_DATA(QI_DONE) | +- QI_IWD_FENCE | +- QI_IWD_TYPE; +- desc[1].qw0 = QI_EIOTLB_PASID(pasid) | +- QI_EIOTLB_DID(did) | +- QI_EIOTLB_GRAN(QI_GRAN_NONG_PASID) | +- QI_EIOTLB_TYPE; +- desc[2].qw0 = QI_DEV_EIOTLB_PASID(pasid) | +- QI_DEV_EIOTLB_SID(sid) | +- QI_DEV_EIOTLB_QDEP(qdep) | +- QI_DEIOTLB_TYPE | +- QI_DEV_IOTLB_PFSID(info->pfsid); +-qi_retry: +- reinit_completion(&iommu->prq_complete); +- qi_submit_sync(iommu, desc, 3, QI_OPT_WAIT_DRAIN); +- if (readl(iommu->reg + DMAR_PRS_REG) & DMA_PRS_PRO) { +- wait_for_completion(&iommu->prq_complete); +- goto qi_retry; +- } +-} +- +-static int prq_to_iommu_prot(struct page_req_dsc *req) +-{ +- int prot = 0; +- +- if (req->rd_req) +- prot |= IOMMU_FAULT_PERM_READ; +- if (req->wr_req) +- prot |= IOMMU_FAULT_PERM_WRITE; +- if (req->exe_req) +- prot |= IOMMU_FAULT_PERM_EXEC; +- if (req->pm_req) +- prot |= IOMMU_FAULT_PERM_PRIV; +- +- return prot; +-} +- +-static void intel_svm_prq_report(struct intel_iommu *iommu, struct device *dev, +- struct page_req_dsc *desc) +-{ +- struct iopf_fault event = { }; +- +- /* Fill in event data for device specific processing */ +- event.fault.type = IOMMU_FAULT_PAGE_REQ; +- event.fault.prm.addr = (u64)desc->addr << VTD_PAGE_SHIFT; +- event.fault.prm.pasid = desc->pasid; +- event.fault.prm.grpid = desc->prg_index; +- event.fault.prm.perm = prq_to_iommu_prot(desc); +- +- if (desc->lpig) +- event.fault.prm.flags |= IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE; +- if (desc->pasid_present) { +- event.fault.prm.flags |= IOMMU_FAULT_PAGE_REQUEST_PASID_VALID; +- event.fault.prm.flags |= IOMMU_FAULT_PAGE_RESPONSE_NEEDS_PASID; +- } +- +- iommu_report_device_fault(dev, &event); +-} +- +-static void handle_bad_prq_event(struct intel_iommu *iommu, +- struct page_req_dsc *req, int result) +-{ +- struct qi_desc desc = { }; +- +- pr_err("%s: Invalid page request: %08llx %08llx\n", +- iommu->name, ((unsigned long long *)req)[0], +- ((unsigned long long *)req)[1]); +- +- if (!req->lpig) +- return; +- +- desc.qw0 = QI_PGRP_PASID(req->pasid) | +- QI_PGRP_DID(req->rid) | +- QI_PGRP_PASID_P(req->pasid_present) | +- QI_PGRP_RESP_CODE(result) | +- QI_PGRP_RESP_TYPE; +- desc.qw1 = QI_PGRP_IDX(req->prg_index) | +- QI_PGRP_LPIG(req->lpig); +- +- qi_submit_sync(iommu, &desc, 1, 0); +-} +- +-static irqreturn_t prq_event_thread(int irq, void *d) +-{ +- struct intel_iommu *iommu = d; +- struct page_req_dsc *req; +- int head, tail, handled; +- struct device *dev; +- u64 address; +- +- /* +- * Clear PPR bit before reading head/tail registers, to ensure that +- * we get a new interrupt if needed. +- */ +- writel(DMA_PRS_PPR, iommu->reg + DMAR_PRS_REG); +- +- tail = dmar_readq(iommu->reg + DMAR_PQT_REG) & PRQ_RING_MASK; +- head = dmar_readq(iommu->reg + DMAR_PQH_REG) & PRQ_RING_MASK; +- handled = (head != tail); +- while (head != tail) { +- req = &iommu->prq[head / sizeof(*req)]; +- address = (u64)req->addr << VTD_PAGE_SHIFT; +- +- if (unlikely(!req->pasid_present)) { +- pr_err("IOMMU: %s: Page request without PASID\n", +- iommu->name); +-bad_req: +- handle_bad_prq_event(iommu, req, QI_RESP_INVALID); +- goto prq_advance; +- } +- +- if (unlikely(!is_canonical_address(address))) { +- pr_err("IOMMU: %s: Address is not canonical\n", +- iommu->name); +- goto bad_req; +- } +- +- if (unlikely(req->pm_req && (req->rd_req | req->wr_req))) { +- pr_err("IOMMU: %s: Page request in Privilege Mode\n", +- iommu->name); +- goto bad_req; +- } +- +- if (unlikely(req->exe_req && req->rd_req)) { +- pr_err("IOMMU: %s: Execution request not supported\n", +- iommu->name); +- goto bad_req; +- } +- +- /* Drop Stop Marker message. No need for a response. */ +- if (unlikely(req->lpig && !req->rd_req && !req->wr_req)) +- goto prq_advance; +- +- /* +- * If prq is to be handled outside iommu driver via receiver of +- * the fault notifiers, we skip the page response here. +- */ +- mutex_lock(&iommu->iopf_lock); +- dev = device_rbtree_find(iommu, req->rid); +- if (!dev) { +- mutex_unlock(&iommu->iopf_lock); +- goto bad_req; +- } +- +- intel_svm_prq_report(iommu, dev, req); +- trace_prq_report(iommu, dev, req->qw_0, req->qw_1, +- req->qw_2, req->qw_3, +- iommu->prq_seq_number++); +- mutex_unlock(&iommu->iopf_lock); +-prq_advance: +- head = (head + sizeof(*req)) & PRQ_RING_MASK; +- } +- +- dmar_writeq(iommu->reg + DMAR_PQH_REG, tail); +- +- /* +- * Clear the page request overflow bit and wake up all threads that +- * are waiting for the completion of this handling. +- */ +- if (readl(iommu->reg + DMAR_PRS_REG) & DMA_PRS_PRO) { +- pr_info_ratelimited("IOMMU: %s: PRQ overflow detected\n", +- iommu->name); +- head = dmar_readq(iommu->reg + DMAR_PQH_REG) & PRQ_RING_MASK; +- tail = dmar_readq(iommu->reg + DMAR_PQT_REG) & PRQ_RING_MASK; +- if (head == tail) { +- iopf_queue_discard_partial(iommu->iopf_queue); +- writel(DMA_PRS_PRO, iommu->reg + DMAR_PRS_REG); +- pr_info_ratelimited("IOMMU: %s: PRQ overflow cleared", +- iommu->name); +- } +- } +- +- if (!completion_done(&iommu->prq_complete)) +- complete(&iommu->prq_complete); +- +- return IRQ_RETVAL(handled); +-} +- +-void intel_svm_page_response(struct device *dev, struct iopf_fault *evt, +- struct iommu_page_response *msg) +-{ +- struct device_domain_info *info = dev_iommu_priv_get(dev); +- struct intel_iommu *iommu = info->iommu; +- u8 bus = info->bus, devfn = info->devfn; +- struct iommu_fault_page_request *prm; +- struct qi_desc desc; +- bool pasid_present; +- bool last_page; +- u16 sid; +- +- prm = &evt->fault.prm; +- sid = PCI_DEVID(bus, devfn); +- pasid_present = prm->flags & IOMMU_FAULT_PAGE_REQUEST_PASID_VALID; +- last_page = prm->flags & IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE; +- +- desc.qw0 = QI_PGRP_PASID(prm->pasid) | QI_PGRP_DID(sid) | +- QI_PGRP_PASID_P(pasid_present) | +- QI_PGRP_RESP_CODE(msg->code) | +- QI_PGRP_RESP_TYPE; +- desc.qw1 = QI_PGRP_IDX(prm->grpid) | QI_PGRP_LPIG(last_page); +- desc.qw2 = 0; +- desc.qw3 = 0; +- +- qi_submit_sync(iommu, &desc, 1, 0); +-} +- + static void intel_svm_domain_free(struct iommu_domain *domain) + { + struct dmar_domain *dmar_domain = to_dmar_domain(domain); +-- +2.51.0 + diff --git a/queue-6.12/ionic-rate-limit-unknown-xcvr-type-messages.patch b/queue-6.12/ionic-rate-limit-unknown-xcvr-type-messages.patch new file mode 100644 index 0000000000..12acdd2031 --- /dev/null +++ b/queue-6.12/ionic-rate-limit-unknown-xcvr-type-messages.patch @@ -0,0 +1,51 @@ +From 9a213a8df5438b76c9f8ab837cc290c0240e9053 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 14:46:51 -0800 +Subject: ionic: Rate limit unknown xcvr type messages + +From: Eric Joyner + +[ Upstream commit cdb1634de3bf197c0d86487d1fb84c128a79cc7c ] + +Running ethtool repeatedly with a transceiver unknown to the driver or +firmware will cause the driver to spam the kernel logs with "unknown +xcvr type" messages which can distract from real issues; and this isn't +interesting information outside of debugging. Fix this by rate limiting +the output so that there are still notifications but not so many that +they flood the log. + +Using dev_dbg_once() would reduce the number of messages further, but +this would miss the case where a different unknown transceiver type is +plugged in, and its status is requested. + +Fixes: 4d03e00a2140 ("ionic: Add initial ethtool support") +Signed-off-by: Eric Joyner +Reviewed-by: Brett Creeley +Link: https://patch.msgid.link/20260206224651.1491-1-eric.joyner@amd.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/pensando/ionic/ionic_ethtool.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c +index 9b7f78b6cdb1e..a632536bd7f2f 100644 +--- a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c ++++ b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c +@@ -224,9 +224,10 @@ static int ionic_get_link_ksettings(struct net_device *netdev, + /* This means there's no module plugged in */ + break; + default: +- dev_info(lif->ionic->dev, "unknown xcvr type pid=%d / 0x%x\n", +- idev->port_info->status.xcvr.pid, +- idev->port_info->status.xcvr.pid); ++ dev_dbg_ratelimited(lif->ionic->dev, ++ "unknown xcvr type pid=%d / 0x%x\n", ++ idev->port_info->status.xcvr.pid, ++ idev->port_info->status.xcvr.pid); + break; + } + +-- +2.51.0 + diff --git a/queue-6.12/ipc-don-t-audit-capability-check-in-ipc_permissions.patch b/queue-6.12/ipc-don-t-audit-capability-check-in-ipc_permissions.patch new file mode 100644 index 0000000000..5740e42835 --- /dev/null +++ b/queue-6.12/ipc-don-t-audit-capability-check-in-ipc_permissions.patch @@ -0,0 +1,66 @@ +From 3b1454967f222f2415bd76c44a367d4a0e5f4f54 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 15:13:03 +0100 +Subject: ipc: don't audit capability check in ipc_permissions() + +From: Ondrej Mosnacek + +[ Upstream commit 071588136007482d70fd2667b827036bc60b1f8f ] + +The IPC sysctls implement the ctl_table_root::permissions hook and +they override the file access mode based on the CAP_CHECKPOINT_RESTORE +capability, which is being checked regardless of whether any access is +actually denied or not, so if an LSM denies the capability, an audit +record may be logged even when access is in fact granted. + +It wouldn't be viable to restructure the sysctl permission logic to only +check the capability when the access would be actually denied if it's +not granted. Thus, do the same as in net_ctl_permissions() +(net/sysctl_net.c) - switch from ns_capable() to ns_capable_noaudit(), +so that the check never emits an audit record. + +Fixes: 0889f44e2810 ("ipc: Check permissions for checkpoint_restart sysctls at open time") +Signed-off-by: Ondrej Mosnacek +Acked-by: Alexey Gladkov +Acked-by: Serge Hallyn +Signed-off-by: Serge Hallyn +Stable-dep-of: 8924336531e2 ("ipc: don't audit capability check in ipc_permissions()") +Signed-off-by: Sasha Levin +--- + include/linux/capability.h | 6 ++++++ + ipc/ipc_sysctl.c | 2 +- + 2 files changed, 7 insertions(+), 1 deletion(-) + +diff --git a/include/linux/capability.h b/include/linux/capability.h +index 0c356a5179917..767c535dbd38e 100644 +--- a/include/linux/capability.h ++++ b/include/linux/capability.h +@@ -208,6 +208,12 @@ static inline bool checkpoint_restore_ns_capable(struct user_namespace *ns) + ns_capable(ns, CAP_SYS_ADMIN); + } + ++static inline bool checkpoint_restore_ns_capable_noaudit(struct user_namespace *ns) ++{ ++ return ns_capable_noaudit(ns, CAP_CHECKPOINT_RESTORE) || ++ ns_capable_noaudit(ns, CAP_SYS_ADMIN); ++} ++ + /* audit system wants to get cap info from files as well */ + int get_vfs_caps_from_disk(struct mnt_idmap *idmap, + const struct dentry *dentry, +diff --git a/ipc/ipc_sysctl.c b/ipc/ipc_sysctl.c +index 54318e0b45578..61ce52ce30530 100644 +--- a/ipc/ipc_sysctl.c ++++ b/ipc/ipc_sysctl.c +@@ -214,7 +214,7 @@ static int ipc_permissions(struct ctl_table_header *head, const struct ctl_table + if (((table->data == &ns->ids[IPC_SEM_IDS].next_id) || + (table->data == &ns->ids[IPC_MSG_IDS].next_id) || + (table->data == &ns->ids[IPC_SHM_IDS].next_id)) && +- checkpoint_restore_ns_capable(ns->user_ns)) ++ checkpoint_restore_ns_capable_noaudit(ns->user_ns)) + mode = 0666; + else + #endif +-- +2.51.0 + diff --git a/queue-6.12/kallsyms-ftrace-set-module-buildid-in-ftrace_mod_add.patch b/queue-6.12/kallsyms-ftrace-set-module-buildid-in-ftrace_mod_add.patch new file mode 100644 index 0000000000..3978de25d3 --- /dev/null +++ b/queue-6.12/kallsyms-ftrace-set-module-buildid-in-ftrace_mod_add.patch @@ -0,0 +1,100 @@ +From b5aeca387ff86f7ed91d83903c7740c4e546c6ee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 14:59:19 +0100 +Subject: kallsyms/ftrace: set module buildid in ftrace_mod_address_lookup() + +From: Petr Mladek + +[ Upstream commit e8a1e7eaa19d0b757b06a2f913e3eeb4b1c002c6 ] + +__sprint_symbol() might access an invalid pointer when +kallsyms_lookup_buildid() returns a symbol found by +ftrace_mod_address_lookup(). + +The ftrace lookup function must set both @modname and @modbuildid the same +way as module_address_lookup(). + +Link: https://lkml.kernel.org/r/20251128135920.217303-7-pmladek@suse.com +Fixes: 9294523e3768 ("module: add printk formats to add module build ID to stacktraces") +Signed-off-by: Petr Mladek +Reviewed-by: Aaron Tomlin +Acked-by: Steven Rostedt (Google) +Cc: Alexei Starovoitov +Cc: Daniel Borkman +Cc: Daniel Gomez +Cc: John Fastabend +Cc: Kees Cook +Cc: Luis Chamberalin +Cc: Marc Rutland +Cc: "Masami Hiramatsu (Google)" +Cc: Petr Pavlu +Cc: Sami Tolvanen +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + include/linux/ftrace.h | 6 ++++-- + kernel/kallsyms.c | 4 ++-- + kernel/trace/ftrace.c | 5 ++++- + 3 files changed, 10 insertions(+), 5 deletions(-) + +diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h +index 079a8152855b2..34b283dc07a47 100644 +--- a/include/linux/ftrace.h ++++ b/include/linux/ftrace.h +@@ -87,11 +87,13 @@ struct ftrace_hash; + defined(CONFIG_DYNAMIC_FTRACE) + int + ftrace_mod_address_lookup(unsigned long addr, unsigned long *size, +- unsigned long *off, char **modname, char *sym); ++ unsigned long *off, char **modname, ++ const unsigned char **modbuildid, char *sym); + #else + static inline int + ftrace_mod_address_lookup(unsigned long addr, unsigned long *size, +- unsigned long *off, char **modname, char *sym) ++ unsigned long *off, char **modname, ++ const unsigned char **modbuildid, char *sym) + { + return 0; + } +diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c +index 9e4bf061bb834..9d3f0c1cca8e2 100644 +--- a/kernel/kallsyms.c ++++ b/kernel/kallsyms.c +@@ -389,8 +389,8 @@ static int kallsyms_lookup_buildid(unsigned long addr, + offset, modname, namebuf); + + if (!ret) +- ret = ftrace_mod_address_lookup(addr, symbolsize, +- offset, modname, namebuf); ++ ret = ftrace_mod_address_lookup(addr, symbolsize, offset, ++ modname, modbuildid, namebuf); + + return ret; + } +diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c +index 27718845f86d8..c8a6c0bb907ea 100644 +--- a/kernel/trace/ftrace.c ++++ b/kernel/trace/ftrace.c +@@ -7566,7 +7566,8 @@ ftrace_func_address_lookup(struct ftrace_mod_map *mod_map, + + int + ftrace_mod_address_lookup(unsigned long addr, unsigned long *size, +- unsigned long *off, char **modname, char *sym) ++ unsigned long *off, char **modname, ++ const unsigned char **modbuildid, char *sym) + { + struct ftrace_mod_map *mod_map; + int ret = 0; +@@ -7578,6 +7579,8 @@ ftrace_mod_address_lookup(unsigned long addr, unsigned long *size, + if (ret) { + if (modname) + *modname = mod_map->mod->name; ++ if (modbuildid) ++ *modbuildid = module_buildid(mod_map->mod); + break; + } + } +-- +2.51.0 + diff --git a/queue-6.12/leds-qcom-lpg-check-the-return-value-of-regmap_bulk_.patch b/queue-6.12/leds-qcom-lpg-check-the-return-value-of-regmap_bulk_.patch new file mode 100644 index 0000000000..490bea4910 --- /dev/null +++ b/queue-6.12/leds-qcom-lpg-check-the-return-value-of-regmap_bulk_.patch @@ -0,0 +1,55 @@ +From 082af26ed6c92b77492aedb085b6bc14a5921575 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 01:51:33 +0800 +Subject: leds: qcom-lpg: Check the return value of regmap_bulk_write() + +From: Haotian Zhang + +[ Upstream commit f42033b5ce8c79c5db645916c9a72ee3e10cecfa ] + +The lpg_lut_store() function currently ignores the return value of +regmap_bulk_write() and always returns 0. This can cause hardware write +failures to go undetected, leading the caller to believe LUT programming +succeeded when it may have failed. + +Check the return value of regmap_bulk_write() in lpg_lut_store and return +the error to the caller on failure. + +Fixes: 24e2d05d1b68 ("leds: Add driver for Qualcomm LPG") +Signed-off-by: Haotian Zhang +Link: https://patch.msgid.link/20260108175133.638-1-vulab@iscas.ac.cn +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/leds/rgb/leds-qcom-lpg.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/leds/rgb/leds-qcom-lpg.c b/drivers/leds/rgb/leds-qcom-lpg.c +index 84e02867f3b43..98c60e971b48f 100644 +--- a/drivers/leds/rgb/leds-qcom-lpg.c ++++ b/drivers/leds/rgb/leds-qcom-lpg.c +@@ -368,7 +368,7 @@ static int lpg_lut_store(struct lpg *lpg, struct led_pattern *pattern, + { + unsigned int idx; + u16 val; +- int i; ++ int i, ret; + + idx = bitmap_find_next_zero_area(lpg->lut_bitmap, lpg->lut_size, + 0, len, 0); +@@ -378,8 +378,10 @@ static int lpg_lut_store(struct lpg *lpg, struct led_pattern *pattern, + for (i = 0; i < len; i++) { + val = pattern[i].brightness; + +- regmap_bulk_write(lpg->map, lpg->lut_base + LPG_LUT_REG(idx + i), +- &val, sizeof(val)); ++ ret = regmap_bulk_write(lpg->map, lpg->lut_base + LPG_LUT_REG(idx + i), ++ &val, sizeof(val)); ++ if (ret) ++ return ret; + } + + bitmap_set(lpg->lut_bitmap, idx, len); +-- +2.51.0 + diff --git a/queue-6.12/libbpf-fix-oob-read-in-btf_dump_get_bitfield_value.patch b/queue-6.12/libbpf-fix-oob-read-in-btf_dump_get_bitfield_value.patch new file mode 100644 index 0000000000..72e0150be8 --- /dev/null +++ b/queue-6.12/libbpf-fix-oob-read-in-btf_dump_get_bitfield_value.patch @@ -0,0 +1,59 @@ +From eab67af9ac448dba88c67b77cdddd626249766b1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 05:05:27 +0530 +Subject: libbpf: Fix OOB read in btf_dump_get_bitfield_value + +From: Varun R Mallya + +[ Upstream commit 5714ca8cba5ed736f3733663c446cbee63a10a64 ] + +When dumping bitfield data, btf_dump_get_bitfield_value() reads data +based on the underlying type's size (t->size). However, it does not +verify that the provided data buffer (data_sz) is large enough to +contain these bytes. + +If btf_dump__dump_type_data() is called with a buffer smaller than +the type's size, this leads to an out-of-bounds read. This was +confirmed by AddressSanitizer in the linked issue. + +Fix this by ensuring we do not read past the provided data_sz limit. + +Fixes: a1d3cc3c5eca ("libbpf: Avoid use of __int128 in typed dump display") +Reported-by: Harrison Green +Suggested-by: Alan Maguire +Signed-off-by: Varun R Mallya +Signed-off-by: Andrii Nakryiko +Link: https://lore.kernel.org/bpf/20260106233527.163487-1-varunrmallya@gmail.com + +Closes: https://github.com/libbpf/libbpf/issues/928 +Signed-off-by: Sasha Levin +--- + tools/lib/bpf/btf_dump.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/tools/lib/bpf/btf_dump.c b/tools/lib/bpf/btf_dump.c +index 12306b5de3efb..a833d91886f87 100644 +--- a/tools/lib/bpf/btf_dump.c ++++ b/tools/lib/bpf/btf_dump.c +@@ -1758,9 +1758,18 @@ static int btf_dump_get_bitfield_value(struct btf_dump *d, + __u16 left_shift_bits, right_shift_bits; + const __u8 *bytes = data; + __u8 nr_copy_bits; ++ __u8 start_bit, nr_bytes; + __u64 num = 0; + int i; + ++ /* Calculate how many bytes cover the bitfield */ ++ start_bit = bits_offset % 8; ++ nr_bytes = (start_bit + bit_sz + 7) / 8; ++ ++ /* Bound check */ ++ if (data + nr_bytes > d->typed_dump->data_end) ++ return -E2BIG; ++ + /* Maximum supported bitfield size is 64 bits */ + if (t->size > 8) { + pr_warn("unexpected bitfield size %d\n", t->size); +-- +2.51.0 + diff --git a/queue-6.12/mctp-i2c-initialise-event-handler-read-bytes.patch b/queue-6.12/mctp-i2c-initialise-event-handler-read-bytes.patch new file mode 100644 index 0000000000..07d5321c28 --- /dev/null +++ b/queue-6.12/mctp-i2c-initialise-event-handler-read-bytes.patch @@ -0,0 +1,43 @@ +From 5db8af5dc4c13779cd6171e053b7690f2a739836 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Jan 2026 17:01:16 +0800 +Subject: mctp i2c: initialise event handler read bytes + +From: Matt Johnston + +[ Upstream commit 2a14e91b6d76639dac70ea170f4384c1ee3cb48d ] + +Set a 0xff value for i2c reads of an mctp-i2c device. Otherwise reads +will return "val" from the i2c bus driver. For i2c-aspeed and +i2c-npcm7xx that is a stack uninitialised u8. + +Tested with "i2ctransfer -y 1 r10@0x34" where 0x34 is a mctp-i2c +instance, now it returns all 0xff. + +Fixes: f5b8abf9fc3d ("mctp i2c: MCTP I2C binding driver") +Signed-off-by: Matt Johnston +Link: https://patch.msgid.link/20260113-mctp-read-fix-v1-1-70c4b59c741c@codeconstruct.com.au +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/mctp/mctp-i2c.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/mctp/mctp-i2c.c b/drivers/net/mctp/mctp-i2c.c +index 8a30d0559d60d..617333343ca00 100644 +--- a/drivers/net/mctp/mctp-i2c.c ++++ b/drivers/net/mctp/mctp-i2c.c +@@ -244,7 +244,10 @@ static int mctp_i2c_slave_cb(struct i2c_client *client, + + switch (event) { + case I2C_SLAVE_READ_REQUESTED: ++ case I2C_SLAVE_READ_PROCESSED: ++ /* MCTP I2C transport only uses writes */ + midev->rx_pos = 0; ++ *val = 0xff; + break; + case I2C_SLAVE_WRITE_RECEIVED: + if (midev->rx_pos < MCTP_I2C_BUFSZ) { +-- +2.51.0 + diff --git a/queue-6.12/md-raid1-fix-memory-leak-in-raid1_run-if-no-active-r.patch b/queue-6.12/md-raid1-fix-memory-leak-in-raid1_run-if-no-active-r.patch new file mode 100644 index 0000000000..5d9fd7f8af --- /dev/null +++ b/queue-6.12/md-raid1-fix-memory-leak-in-raid1_run-if-no-active-r.patch @@ -0,0 +1,61 @@ +From 1775e700d772ff8c19423048c55c3e3d876e2da3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 15 Feb 2025 10:01:37 +0800 +Subject: md/raid1: fix memory leak in raid1_run() if no active rdev + +From: Zheng Qixing + +[ Upstream commit 5fbcf76e0dfe68578ffa2a8a691cc44cf586ae35 ] + +When `raid1_set_limits()` fails or when the array has no active +`rdev`, the allocated memory for `conf` is not properly freed. + +Add raid1_free() call to properly free the conf in error path. + +Fixes: 799af947ed13 ("md/raid1: don't free conf on raid0_run failure") +Signed-off-by: Zheng Qixing +Link: https://lore.kernel.org/linux-raid/20250215020137.3703757-1-zhengqixing@huaweicloud.com +Singed-off-by: Yu Kuai +Stable-dep-of: 6abc7d5dcf0e ("md/raid1: fix memory leak in raid1_run()") +Signed-off-by: Sasha Levin +--- + drivers/md/raid1.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c +index 4c6b1bd6da9bb..f9c18ade06f15 100644 +--- a/drivers/md/raid1.c ++++ b/drivers/md/raid1.c +@@ -45,6 +45,7 @@ + + static void allow_barrier(struct r1conf *conf, sector_t sector_nr); + static void lower_barrier(struct r1conf *conf, sector_t sector_nr); ++static void raid1_free(struct mddev *mddev, void *priv); + + #define RAID_1_10_NAME "raid1" + #include "raid1-10.c" +@@ -3245,8 +3246,11 @@ static int raid1_run(struct mddev *mddev) + + if (!mddev_is_dm(mddev)) { + ret = raid1_set_limits(mddev); +- if (ret) ++ if (ret) { ++ if (!mddev->private) ++ raid1_free(mddev, conf); + return ret; ++ } + } + + mddev->degraded = 0; +@@ -3260,6 +3264,8 @@ static int raid1_run(struct mddev *mddev) + */ + if (conf->raid_disks - mddev->degraded < 1) { + md_unregister_thread(mddev, &conf->thread); ++ if (!mddev->private) ++ raid1_free(mddev, conf); + return -EINVAL; + } + +-- +2.51.0 + diff --git a/queue-6.12/md-raid1-fix-memory-leak-in-raid1_run.patch b/queue-6.12/md-raid1-fix-memory-leak-in-raid1_run.patch new file mode 100644 index 0000000000..0576f38b9c --- /dev/null +++ b/queue-6.12/md-raid1-fix-memory-leak-in-raid1_run.patch @@ -0,0 +1,46 @@ +From f9ea2ba4d0c6c25b95608f06fedde121a24e7637 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 07:15:33 +0000 +Subject: md/raid1: fix memory leak in raid1_run() + +From: Zilin Guan + +[ Upstream commit 6abc7d5dcf0ee0f85e16e41c87fbd06231f28753 ] + +raid1_run() calls setup_conf() which registers a thread via +md_register_thread(). If raid1_set_limits() fails, the previously +registered thread is not unregistered, resulting in a memory leak +of the md_thread structure and the thread resource itself. + +Add md_unregister_thread() to the error path to properly cleanup +the thread, which aligns with the error handling logic of other paths +in this function. + +Compile tested only. Issue found using a prototype static analysis tool +and code review. + +Link: https://lore.kernel.org/linux-raid/20260126071533.606263-1-zilin@seu.edu.cn +Fixes: 97894f7d3c29 ("md/raid1: use the atomic queue limit update APIs") +Signed-off-by: Zilin Guan +Reviewed-by: Li Nan +Signed-off-by: Yu Kuai +Signed-off-by: Sasha Levin +--- + drivers/md/raid1.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c +index f9c18ade06f15..093b04e6be675 100644 +--- a/drivers/md/raid1.c ++++ b/drivers/md/raid1.c +@@ -3247,6 +3247,7 @@ static int raid1_run(struct mddev *mddev) + if (!mddev_is_dm(mddev)) { + ret = raid1_set_limits(mddev); + if (ret) { ++ md_unregister_thread(mddev, &conf->thread); + if (!mddev->private) + raid1_free(mddev, conf); + return ret; +-- +2.51.0 + diff --git a/queue-6.12/md-raid10-fix-any_working-flag-handling-in-raid10_sy.patch b/queue-6.12/md-raid10-fix-any_working-flag-handling-in-raid10_sy.patch new file mode 100644 index 0000000000..18b56f9bd3 --- /dev/null +++ b/queue-6.12/md-raid10-fix-any_working-flag-handling-in-raid10_sy.patch @@ -0,0 +1,47 @@ +From c9e8c912ca0f6074a235c310e5ca291b3cfdcc3f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Jan 2026 19:02:58 +0800 +Subject: md/raid10: fix any_working flag handling in raid10_sync_request + +From: Li Nan + +[ Upstream commit 99582edb3f62e8ee6c34512021368f53f9b091f2 ] + +In raid10_sync_request(), 'any_working' indicates if any IO will +be submitted. When there's only one In_sync disk with badblocks, +'any_working' might be set to 1 but no IO is submitted. Fix it by +setting 'any_working' after badblock checks. + +Link: https://lore.kernel.org/linux-raid/20260105110300.1442509-11-linan666@huaweicloud.com +Fixes: e875ecea266a ("md/raid10 record bad blocks as needed during recovery.") +Signed-off-by: Li Nan +Reviewed-by: Yu Kuai +Signed-off-by: Yu Kuai +Signed-off-by: Sasha Levin +--- + drivers/md/raid10.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c +index a91911a9fc036..db07c99c4d947 100644 +--- a/drivers/md/raid10.c ++++ b/drivers/md/raid10.c +@@ -3417,7 +3417,6 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr, + !test_bit(In_sync, &rdev->flags)) + continue; + /* This is where we read from */ +- any_working = 1; + sector = r10_bio->devs[j].addr; + + if (is_badblock(rdev, sector, max_sync, +@@ -3432,6 +3431,7 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr, + continue; + } + } ++ any_working = 1; + bio = r10_bio->devs[0].bio; + bio->bi_next = biolist; + biolist = bio; +-- +2.51.0 + diff --git a/queue-6.12/md-raid5-fix-raid5_run-to-return-error-when-log_init.patch b/queue-6.12/md-raid5-fix-raid5_run-to-return-error-when-log_init.patch new file mode 100644 index 0000000000..04906bdea0 --- /dev/null +++ b/queue-6.12/md-raid5-fix-raid5_run-to-return-error-when-log_init.patch @@ -0,0 +1,47 @@ +From 7c478fa615e5e6f2a26a28173e86d6edf33828cf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 01:12:29 +0800 +Subject: md/raid5: fix raid5_run() to return error when log_init() fails + +From: Yu Kuai + +[ Upstream commit 2d9f7150ac197ce79c9c917a004d4cf0b26ad7e0 ] + +Since commit f63f17350e53 ("md/raid5: use the atomic queue limit +update APIs"), the abort path in raid5_run() returns 'ret' instead of +-EIO. However, if log_init() fails, 'ret' is still 0 from the previous +successful call, causing raid5_run() to return success despite the +failure. + +Fix this by capturing the return value from log_init(). + +Link: https://lore.kernel.org/linux-raid/20260114171241.3043364-2-yukuai@fnnas.com +Fixes: f63f17350e53 ("md/raid5: use the atomic queue limit update APIs") +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/r/202601130531.LGfcZsa4-lkp@intel.com/ +Signed-off-by: Yu Kuai +Reviewed-by: Li Nan +Reviewed-by: Xiao Ni +Reviewed-by: Christoph Hellwig +Signed-off-by: Sasha Levin +--- + drivers/md/raid5.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c +index 7262b77a8e022..5079943046743 100644 +--- a/drivers/md/raid5.c ++++ b/drivers/md/raid5.c +@@ -8049,7 +8049,8 @@ static int raid5_run(struct mddev *mddev) + goto abort; + } + +- if (log_init(conf, journal_dev, raid5_has_ppl(conf))) ++ ret = log_init(conf, journal_dev, raid5_has_ppl(conf)); ++ if (ret) + goto abort; + + return 0; +-- +2.51.0 + diff --git a/queue-6.12/media-ccs-accommodate-c-phy-into-the-calculation.patch b/queue-6.12/media-ccs-accommodate-c-phy-into-the-calculation.patch new file mode 100644 index 0000000000..507e5977c0 --- /dev/null +++ b/queue-6.12/media-ccs-accommodate-c-phy-into-the-calculation.patch @@ -0,0 +1,53 @@ +From 811908abb433afbf6854ff591ded97deeaa7e281 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 18:57:07 +0100 +Subject: media: ccs: Accommodate C-PHY into the calculation + +From: David Heidelberg + +[ Upstream commit 3085977e734dab74adebb1dda195befce25addff ] + +We need to set correct mode for PLL to calculate correct frequency. +Signalling mode is known at this point, so use it for that. + +Fixes: 47b6eaf36eba ("media: ccs-pll: Differentiate between CSI-2 D-PHY and C-PHY") +Reviewed-by: Mehdi Djait +Signed-off-by: David Heidelberg +[Sakari Ailus: Drop extra newline.] +Signed-off-by: Sakari Ailus +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/i2c/ccs/ccs-core.c | 16 +++++++++++++++- + 1 file changed, 15 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c +index 4b7d8039b1c9f..4c1dbd42342ce 100644 +--- a/drivers/media/i2c/ccs/ccs-core.c ++++ b/drivers/media/i2c/ccs/ccs-core.c +@@ -3436,7 +3436,21 @@ static int ccs_probe(struct i2c_client *client) + sensor->scale_m = CCS_LIM(sensor, SCALER_N_MIN); + + /* prepare PLL configuration input values */ +- sensor->pll.bus_type = CCS_PLL_BUS_TYPE_CSI2_DPHY; ++ switch (sensor->hwcfg.csi_signalling_mode) { ++ case CCS_CSI_SIGNALING_MODE_CSI_2_CPHY: ++ sensor->pll.bus_type = CCS_PLL_BUS_TYPE_CSI2_CPHY; ++ break; ++ case CCS_CSI_SIGNALING_MODE_CSI_2_DPHY: ++ case SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK: ++ case SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_STROBE: ++ sensor->pll.bus_type = CCS_PLL_BUS_TYPE_CSI2_DPHY; ++ break; ++ default: ++ dev_err(&client->dev, "unsupported signalling mode %u\n", ++ sensor->hwcfg.csi_signalling_mode); ++ rval = -EINVAL; ++ goto out_cleanup; ++ } + sensor->pll.csi2.lanes = sensor->hwcfg.lanes; + if (CCS_LIM(sensor, CLOCK_CALCULATION) & + CCS_CLOCK_CALCULATION_LANE_SPEED) { +-- +2.51.0 + diff --git a/queue-6.12/media-chips-media-wave5-fix-memory-leak-on-codec_inf.patch b/queue-6.12/media-chips-media-wave5-fix-memory-leak-on-codec_inf.patch new file mode 100644 index 0000000000..30bb8fa448 --- /dev/null +++ b/queue-6.12/media-chips-media-wave5-fix-memory-leak-on-codec_inf.patch @@ -0,0 +1,63 @@ +From 8740e2bec823ed8a669458afb0b6f7eb1b685074 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 11 Nov 2025 14:57:06 +0000 +Subject: media: chips-media: wave5: Fix memory leak on codec_info allocation + failure + +From: Zilin Guan + +[ Upstream commit a519e21e32398459ba357e67b541402f7295ee1b ] + +In wave5_vpu_open_enc() and wave5_vpu_open_dec(), a vpu instance is +allocated via kzalloc(). If the subsequent allocation for inst->codec_info +fails, the functions return -ENOMEM without freeing the previously +allocated instance, causing a memory leak. + +Fix this by calling kfree() on the instance in this error path to ensure +it is properly released. + +Fixes: 9707a6254a8a6 ("media: chips-media: wave5: Add the v4l2 layer") +Signed-off-by: Zilin Guan +Signed-off-by: Nicolas Dufresne +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c | 4 +++- + drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c | 4 +++- + 2 files changed, 6 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c +index e238447c88bbf..8f7154932d24c 100644 +--- a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c ++++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c +@@ -1835,8 +1835,10 @@ static int wave5_vpu_open_dec(struct file *filp) + spin_lock_init(&inst->state_spinlock); + + inst->codec_info = kzalloc(sizeof(*inst->codec_info), GFP_KERNEL); +- if (!inst->codec_info) ++ if (!inst->codec_info) { ++ kfree(inst); + return -ENOMEM; ++ } + + v4l2_fh_init(&inst->v4l2_fh, vdev); + filp->private_data = &inst->v4l2_fh; +diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c +index 3e35a05c2d8df..a1330c54b17e6 100644 +--- a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c ++++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c +@@ -1546,8 +1546,10 @@ static int wave5_vpu_open_enc(struct file *filp) + inst->ops = &wave5_vpu_enc_inst_ops; + + inst->codec_info = kzalloc(sizeof(*inst->codec_info), GFP_KERNEL); +- if (!inst->codec_info) ++ if (!inst->codec_info) { ++ kfree(inst); + return -ENOMEM; ++ } + + v4l2_fh_init(&inst->v4l2_fh, vdev); + filp->private_data = &inst->v4l2_fh; +-- +2.51.0 + diff --git a/queue-6.12/media-pci-mg4b-use-irqf_no_thread.patch b/queue-6.12/media-pci-mg4b-use-irqf_no_thread.patch new file mode 100644 index 0000000000..00dfd2f53e --- /dev/null +++ b/queue-6.12/media-pci-mg4b-use-irqf_no_thread.patch @@ -0,0 +1,39 @@ +From ad67d65dd95c6e50b95e029e4818d863d48b6470 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:55:40 +0100 +Subject: media: pci: mg4b: Use IRQF_NO_THREAD + +From: Sebastian Andrzej Siewior + +[ Upstream commit ef92b98f5f6758a049898b53aa30476010db04fa ] + +The interrupt handler iio_trigger_generic_data_rdy_poll() will invoke other +interrupt handlers and this supposed to happen from hard interrupt context. + +Use IRQF_NO_THREAD to forbid forced-threading. + +Fixes: 0ab13674a9bd1 ("media: pci: mgb4: Added Digiteq Automotive MGB4 driver") +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260128095540.863589-21-bigeasy@linutronix.de +Signed-off-by: Sasha Levin +--- + drivers/media/pci/mgb4/mgb4_trigger.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/media/pci/mgb4/mgb4_trigger.c b/drivers/media/pci/mgb4/mgb4_trigger.c +index d7dddc5c8728e..10c23f0c833d5 100644 +--- a/drivers/media/pci/mgb4/mgb4_trigger.c ++++ b/drivers/media/pci/mgb4/mgb4_trigger.c +@@ -114,7 +114,7 @@ static int probe_trigger(struct iio_dev *indio_dev, int irq) + if (!st->trig) + return -ENOMEM; + +- ret = request_irq(irq, &iio_trigger_generic_data_rdy_poll, 0, ++ ret = request_irq(irq, &iio_trigger_generic_data_rdy_poll, IRQF_NO_THREAD, + "mgb4-trigger", st->trig); + if (ret) + goto error_free_trig; +-- +2.51.0 + diff --git a/queue-6.12/media-uvcvideo-fix-allocation-for-small-frame-sizes.patch b/queue-6.12/media-uvcvideo-fix-allocation-for-small-frame-sizes.patch new file mode 100644 index 0000000000..dcd26b074c --- /dev/null +++ b/queue-6.12/media-uvcvideo-fix-allocation-for-small-frame-sizes.patch @@ -0,0 +1,57 @@ +From c074e887e15dbd4c0d61b9a8d0f4b933ed96ae19 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 10:32:13 +0000 +Subject: media: uvcvideo: Fix allocation for small frame sizes + +From: Ricardo Ribalda + +[ Upstream commit 40d3ac25c11310bfaa50ed7614846ef75cb69a1e ] + +If a frame has size of less or equal than one packet size +uvc_alloc_urb_buffers() is unable to allocate memory for it due to a +off-by-one error. + +Fix the off-by-one-error and now that we are at it, make sure that +stream->urb_size has always a valid value when we return from the +function, even when an error happens. + +Fixes: efdc8a9585ce ("V4L/DVB (10295): uvcvideo: Retry URB buffers allocation when the system is low on memory.") +Reported-by: Itay Chamiel +Closes: https://lore.kernel.org/linux-media/CANiDSCsSoZf2LsCCoWAUbCg6tJT-ypXR1B85aa6rAdMVYr2iBQ@mail.gmail.com/T/#t +Co-developed-by: Itay Chamiel +Signed-off-by: Itay Chamiel +Signed-off-by: Ricardo Ribalda +Reviewed-by: Laurent Pinchart +Tested-by: Itay Chamiel +Link: https://patch.msgid.link/20260114-uvc-alloc-urb-v1-1-cedf3fb66711@chromium.org +Signed-off-by: Laurent Pinchart +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/usb/uvc/uvc_video.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c +index 57e6f9af536ff..57bccbf17f6dc 100644 +--- a/drivers/media/usb/uvc/uvc_video.c ++++ b/drivers/media/usb/uvc/uvc_video.c +@@ -1842,7 +1842,7 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream, + npackets = UVC_MAX_PACKETS; + + /* Retry allocations until one succeed. */ +- for (; npackets > 1; npackets /= 2) { ++ for (; npackets > 0; npackets /= 2) { + stream->urb_size = psize * npackets; + + for (i = 0; i < UVC_URBS; ++i) { +@@ -1867,6 +1867,7 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream, + uvc_dbg(stream->dev, VIDEO, + "Failed to allocate URB buffers (%u bytes per packet)\n", + psize); ++ stream->urb_size = 0; + return 0; + } + +-- +2.51.0 + diff --git a/queue-6.12/mfd-arizona-fix-regulator-resource-leak-on-wm5102_cl.patch b/queue-6.12/mfd-arizona-fix-regulator-resource-leak-on-wm5102_cl.patch new file mode 100644 index 0000000000..045c34f94e --- /dev/null +++ b/queue-6.12/mfd-arizona-fix-regulator-resource-leak-on-wm5102_cl.patch @@ -0,0 +1,43 @@ +From 1c83dc865a1e997c5dad4d91c7fcb9b1a2086641 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 14 Dec 2025 22:58:03 +0800 +Subject: mfd: arizona: Fix regulator resource leak on + wm5102_clear_write_sequencer() failure + +From: Haotian Zhang + +[ Upstream commit 4feb753ba6e5e5bbaba868b841a2db41c21e56fa ] + +The wm5102_clear_write_sequencer() helper may return an error +and just return, bypassing the cleanup sequence and causing +regulators to remain enabled, leading to a resource leak. + +Change the direct return to jump to the err_reset label to +properly free the resources. + +Fixes: 1c1c6bba57f5 ("mfd: wm5102: Ensure we always boot the device fully") +Signed-off-by: Haotian Zhang +Reviewed-by: Charles Keepax +Link: https://patch.msgid.link/20251214145804.2037-1-vulab@iscas.ac.cn +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/mfd/arizona-core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c +index 85ff8717d8504..91975536d14d2 100644 +--- a/drivers/mfd/arizona-core.c ++++ b/drivers/mfd/arizona-core.c +@@ -1100,7 +1100,7 @@ int arizona_dev_init(struct arizona *arizona) + } else if (val & 0x01) { + ret = wm5102_clear_write_sequencer(arizona); + if (ret) +- return ret; ++ goto err_reset; + } + break; + default: +-- +2.51.0 + diff --git a/queue-6.12/mfd-simple-mfd-i2c-add-compatible-strings-for-layers.patch b/queue-6.12/mfd-simple-mfd-i2c-add-compatible-strings-for-layers.patch new file mode 100644 index 0000000000..719f86204c --- /dev/null +++ b/queue-6.12/mfd-simple-mfd-i2c-add-compatible-strings-for-layers.patch @@ -0,0 +1,40 @@ +From 2fe64fdbf771c645f07cb8225aec91c1cf468a9b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 7 Jul 2025 18:31:20 +0300 +Subject: mfd: simple-mfd-i2c: Add compatible strings for Layerscape QIXIS FPGA + +From: Ioana Ciornei + +[ Upstream commit 81a2c31257411296862487aaade98b7d9e25dc72 ] + +The QIXIS FPGA found on Layerscape boards such as LX2160AQDS, LS1028AQDS +etc deals with power-on-reset timing, muxing etc. Use the simple-mfd-i2c +as its core driver by adding its compatible string (already found in +some dt files). By using the simple-mfd-i2c driver, any child device +will have access to the i2c regmap created by it. + +Signed-off-by: Ioana Ciornei +Link: https://lore.kernel.org/r/20250707153120.1371719-1-ioana.ciornei@nxp.com +Signed-off-by: Lee Jones +Stable-dep-of: 8f34c1a64c53 ("mfd: simple-mfd-i2c: Add Delta TN48M CPLD support") +Signed-off-by: Sasha Levin +--- + drivers/mfd/simple-mfd-i2c.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/mfd/simple-mfd-i2c.c b/drivers/mfd/simple-mfd-i2c.c +index 22159913bea03..f7798bd922224 100644 +--- a/drivers/mfd/simple-mfd-i2c.c ++++ b/drivers/mfd/simple-mfd-i2c.c +@@ -99,6 +99,8 @@ static const struct of_device_id simple_mfd_i2c_of_match[] = { + { .compatible = "maxim,max5970", .data = &maxim_max5970}, + { .compatible = "maxim,max5978", .data = &maxim_max5970}, + { .compatible = "maxim,max77705-battery", .data = &maxim_mon_max77705}, ++ { .compatible = "fsl,lx2160aqds-fpga" }, ++ { .compatible = "fsl,ls1028aqds-fpga" }, + {} + }; + MODULE_DEVICE_TABLE(of, simple_mfd_i2c_of_match); +-- +2.51.0 + diff --git a/queue-6.12/mfd-simple-mfd-i2c-add-delta-tn48m-cpld-support.patch b/queue-6.12/mfd-simple-mfd-i2c-add-delta-tn48m-cpld-support.patch new file mode 100644 index 0000000000..ea5a541715 --- /dev/null +++ b/queue-6.12/mfd-simple-mfd-i2c-add-delta-tn48m-cpld-support.patch @@ -0,0 +1,67 @@ +From 97ee4b8cb25cd8f8ded6c86aa06ee6a483a5d411 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 17:14:52 +0100 +Subject: mfd: simple-mfd-i2c: Add Delta TN48M CPLD support + +From: Robert Marko + +[ Upstream commit 8f34c1a64c5394d2b51d3fba197947dc4b0b48a0 ] + +Delta TN48M switches have a Lattice CPLD that serves +multiple purposes including being a GPIO expander. + +So, lets use the simple I2C MFD driver to provide the MFD core. + +Also add a virtual symbol which pulls in the simple-mfd-i2c driver and +provide a common symbol on which the subdevice drivers can depend on. + +Fixes: b3dcb5de6209 ("gpio: Add Delta TN48M CPLD GPIO driver") +Signed-off-by: Robert Marko +Link: https://lore.kernel.org/20220131133049.77780-2-robert.marko@sartura.hr +Link: https://lore.kernel.org/linux-gpio/20260112064950.3837737-1-rdunlap@infradead.org/ +Signed-off-by: Linus Walleij +Link: https://patch.msgid.link/20260112-mfd-tn48m-v11-1-00c798d8cd2a@kernel.org +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/mfd/Kconfig | 11 +++++++++++ + drivers/mfd/simple-mfd-i2c.c | 1 + + 2 files changed, 12 insertions(+) + +diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig +index 4c56330b15eda..f08b8009eeea0 100644 +--- a/drivers/mfd/Kconfig ++++ b/drivers/mfd/Kconfig +@@ -347,6 +347,17 @@ config MFD_CS47L92 + help + Support for Cirrus Logic CS42L92, CS47L92 and CS47L93 Smart Codecs + ++config MFD_TN48M_CPLD ++ tristate "Delta Networks TN48M switch CPLD driver" ++ depends on I2C ++ depends on ARCH_MVEBU || COMPILE_TEST ++ select MFD_SIMPLE_MFD_I2C ++ help ++ Select this option to enable support for Delta Networks TN48M switch ++ CPLD. It consists of reset and GPIO drivers. CPLD provides GPIOS-s ++ for the SFP slots as well as power supply related information. ++ SFP support depends on the GPIO driver being selected. ++ + config PMIC_DA903X + bool "Dialog Semiconductor DA9030/DA9034 PMIC Support" + depends on I2C=y +diff --git a/drivers/mfd/simple-mfd-i2c.c b/drivers/mfd/simple-mfd-i2c.c +index 0cca7a9044cd4..908eae338fee0 100644 +--- a/drivers/mfd/simple-mfd-i2c.c ++++ b/drivers/mfd/simple-mfd-i2c.c +@@ -110,6 +110,7 @@ static const struct simple_mfd_data spacemit_p1 = { + }; + + static const struct of_device_id simple_mfd_i2c_of_match[] = { ++ { .compatible = "delta,tn48m-cpld" }, + { .compatible = "fsl,ls1028aqds-fpga" }, + { .compatible = "fsl,lx2160aqds-fpga" }, + { .compatible = "kontron,sl28cpld" }, +-- +2.51.0 + diff --git a/queue-6.12/mfd-simple-mfd-i2c-add-max77705-support.patch b/queue-6.12/mfd-simple-mfd-i2c-add-max77705-support.patch new file mode 100644 index 0000000000..be73c09c29 --- /dev/null +++ b/queue-6.12/mfd-simple-mfd-i2c-add-max77705-support.patch @@ -0,0 +1,52 @@ +From 515d2b38ee4d84536d8feae256792a2d15ecfa65 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Jan 2025 18:04:29 +0300 +Subject: mfd: simple-mfd-i2c: Add MAX77705 support + +From: Dzmitry Sankouski + +[ Upstream commit 7b591ef98b3fc1ce20c3ccb86715429b72e2e6f0 ] + +Add MAX77705 support - fuel gauge and hwmon devices. +Hwmon provides charger input and system bus measurements. + +Signed-off-by: Dzmitry Sankouski +Reviewed-by: Krzysztof Kozlowski +Link: https://lore.kernel.org/r/20250123-starqltechn_integration_upstream-v17-4-8b06685b6612@gmail.com +Signed-off-by: Lee Jones +Stable-dep-of: 8f34c1a64c53 ("mfd: simple-mfd-i2c: Add Delta TN48M CPLD support") +Signed-off-by: Sasha Levin +--- + drivers/mfd/simple-mfd-i2c.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/drivers/mfd/simple-mfd-i2c.c b/drivers/mfd/simple-mfd-i2c.c +index 6eda79533208a..22159913bea03 100644 +--- a/drivers/mfd/simple-mfd-i2c.c ++++ b/drivers/mfd/simple-mfd-i2c.c +@@ -83,11 +83,22 @@ static const struct simple_mfd_data maxim_max5970 = { + .mfd_cell_size = ARRAY_SIZE(max5970_cells), + }; + ++static const struct mfd_cell max77705_sensor_cells[] = { ++ { .name = "max77705-battery" }, ++ { .name = "max77705-hwmon", }, ++}; ++ ++static const struct simple_mfd_data maxim_mon_max77705 = { ++ .mfd_cell = max77705_sensor_cells, ++ .mfd_cell_size = ARRAY_SIZE(max77705_sensor_cells), ++}; ++ + static const struct of_device_id simple_mfd_i2c_of_match[] = { + { .compatible = "kontron,sl28cpld" }, + { .compatible = "silergy,sy7636a", .data = &silergy_sy7636a}, + { .compatible = "maxim,max5970", .data = &maxim_max5970}, + { .compatible = "maxim,max5978", .data = &maxim_max5970}, ++ { .compatible = "maxim,max77705-battery", .data = &maxim_mon_max77705}, + {} + }; + MODULE_DEVICE_TABLE(of, simple_mfd_i2c_of_match); +-- +2.51.0 + diff --git a/queue-6.12/mfd-simple-mfd-i2c-add-spacemit-p1-support.patch b/queue-6.12/mfd-simple-mfd-i2c-add-spacemit-p1-support.patch new file mode 100644 index 0000000000..e07f25d841 --- /dev/null +++ b/queue-6.12/mfd-simple-mfd-i2c-add-spacemit-p1-support.patch @@ -0,0 +1,89 @@ +From e8872274f51a9d3344f3597de5d17211aff381a1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Aug 2025 12:20:51 -0500 +Subject: mfd: simple-mfd-i2c: Add SpacemiT P1 support + +From: Alex Elder + +[ Upstream commit 6fc5d415c10e98ac1b31dd1d5653443e691cdcff ] + +Enable support for the RTC and regulators found in the SpacemiT P1 +PMIC. Support is implemented by the simple I2C MFD driver. + +The P1 PMIC is normally implemented with the SpacemiT K1 SoC. This +PMIC provides 6 buck converters and 12 LDO regulators. It also +implements a switch, watchdog timer, real-time clock, and more. +Initially its RTC and regulators are supported. + +Signed-off-by: Alex Elder +Link: https://lore.kernel.org/r/20250825172057.163883-3-elder@riscstar.com +Signed-off-by: Lee Jones +Stable-dep-of: 8f34c1a64c53 ("mfd: simple-mfd-i2c: Add Delta TN48M CPLD support") +Signed-off-by: Sasha Levin +--- + drivers/mfd/Kconfig | 13 +++++++++++++ + drivers/mfd/simple-mfd-i2c.c | 17 +++++++++++++++++ + 2 files changed, 30 insertions(+) + +diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig +index f9325bcce1b94..4c56330b15eda 100644 +--- a/drivers/mfd/Kconfig ++++ b/drivers/mfd/Kconfig +@@ -1161,6 +1161,19 @@ config MFD_QCOM_RPM + Say M here if you want to include support for the Qualcomm RPM as a + module. This will build a module called "qcom_rpm". + ++config MFD_SPACEMIT_P1 ++ tristate "SpacemiT P1 PMIC" ++ depends on ARCH_SPACEMIT || COMPILE_TEST ++ depends on I2C ++ select I2C_K1 ++ select MFD_SIMPLE_MFD_I2C ++ help ++ This option supports the I2C-based SpacemiT P1 PMIC, which ++ contains regulators, a power switch, GPIOs, an RTC, and more. ++ This option is selected when any of the supported sub-devices ++ is configured. The basic functionality is implemented by the ++ simple MFD I2C driver. ++ + config MFD_SPMI_PMIC + tristate "Qualcomm SPMI PMICs" + depends on ARCH_QCOM || COMPILE_TEST +diff --git a/drivers/mfd/simple-mfd-i2c.c b/drivers/mfd/simple-mfd-i2c.c +index f7798bd922224..63ac263888606 100644 +--- a/drivers/mfd/simple-mfd-i2c.c ++++ b/drivers/mfd/simple-mfd-i2c.c +@@ -93,6 +93,22 @@ static const struct simple_mfd_data maxim_mon_max77705 = { + .mfd_cell_size = ARRAY_SIZE(max77705_sensor_cells), + }; + ++static const struct regmap_config spacemit_p1_regmap_config = { ++ .reg_bits = 8, ++ .val_bits = 8, ++}; ++ ++static const struct mfd_cell spacemit_p1_cells[] = { ++ { .name = "spacemit-p1-regulator", }, ++ { .name = "spacemit-p1-rtc", }, ++}; ++ ++static const struct simple_mfd_data spacemit_p1 = { ++ .regmap_config = &spacemit_p1_regmap_config, ++ .mfd_cell = spacemit_p1_cells, ++ .mfd_cell_size = ARRAY_SIZE(spacemit_p1_cells), ++}; ++ + static const struct of_device_id simple_mfd_i2c_of_match[] = { + { .compatible = "kontron,sl28cpld" }, + { .compatible = "silergy,sy7636a", .data = &silergy_sy7636a}, +@@ -101,6 +117,7 @@ static const struct of_device_id simple_mfd_i2c_of_match[] = { + { .compatible = "maxim,max77705-battery", .data = &maxim_mon_max77705}, + { .compatible = "fsl,lx2160aqds-fpga" }, + { .compatible = "fsl,ls1028aqds-fpga" }, ++ { .compatible = "spacemit,p1", .data = &spacemit_p1, }, + {} + }; + MODULE_DEVICE_TABLE(of, simple_mfd_i2c_of_match); +-- +2.51.0 + diff --git a/queue-6.12/mfd-simple-mfd-i2c-keep-compatible-strings-in-alphab.patch b/queue-6.12/mfd-simple-mfd-i2c-keep-compatible-strings-in-alphab.patch new file mode 100644 index 0000000000..cdeaa8a18e --- /dev/null +++ b/queue-6.12/mfd-simple-mfd-i2c-keep-compatible-strings-in-alphab.patch @@ -0,0 +1,44 @@ +From ff4e2b385dedb3bba63c71301cc9684db4eb9b0b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 22 Sep 2025 17:24:19 +0300 +Subject: mfd: simple-mfd-i2c: Keep compatible strings in alphabetical order + +From: Ioana Ciornei + +[ Upstream commit 3ed50d77924ff2e35918739df145dd429cee0ce4 ] + +Reorder the of_device_id structures so that they are in alphabetical +order. + +Signed-off-by: Ioana Ciornei +Signed-off-by: Lee Jones +Stable-dep-of: 8f34c1a64c53 ("mfd: simple-mfd-i2c: Add Delta TN48M CPLD support") +Signed-off-by: Sasha Levin +--- + drivers/mfd/simple-mfd-i2c.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/mfd/simple-mfd-i2c.c b/drivers/mfd/simple-mfd-i2c.c +index 63ac263888606..0cca7a9044cd4 100644 +--- a/drivers/mfd/simple-mfd-i2c.c ++++ b/drivers/mfd/simple-mfd-i2c.c +@@ -110,13 +110,13 @@ static const struct simple_mfd_data spacemit_p1 = { + }; + + static const struct of_device_id simple_mfd_i2c_of_match[] = { ++ { .compatible = "fsl,ls1028aqds-fpga" }, ++ { .compatible = "fsl,lx2160aqds-fpga" }, + { .compatible = "kontron,sl28cpld" }, +- { .compatible = "silergy,sy7636a", .data = &silergy_sy7636a}, + { .compatible = "maxim,max5970", .data = &maxim_max5970}, + { .compatible = "maxim,max5978", .data = &maxim_max5970}, + { .compatible = "maxim,max77705-battery", .data = &maxim_mon_max77705}, +- { .compatible = "fsl,lx2160aqds-fpga" }, +- { .compatible = "fsl,ls1028aqds-fpga" }, ++ { .compatible = "silergy,sy7636a", .data = &silergy_sy7636a}, + { .compatible = "spacemit,p1", .data = &spacemit_p1, }, + {} + }; +-- +2.51.0 + diff --git a/queue-6.12/mfd-wm8350-core-use-irqf_oneshot.patch b/queue-6.12/mfd-wm8350-core-use-irqf_oneshot.patch new file mode 100644 index 0000000000..e0d56389a3 --- /dev/null +++ b/queue-6.12/mfd-wm8350-core-use-irqf_oneshot.patch @@ -0,0 +1,48 @@ +From 77bcdfc9119bcb626c73c3aec04a817312c1e441 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:55:35 +0100 +Subject: mfd: wm8350-core: Use IRQF_ONESHOT + +From: Sebastian Andrzej Siewior + +[ Upstream commit 553b4999cbe231b5011cb8db05a3092dec168aca ] + +Using a threaded interrupt without a dedicated primary handler mandates +the IRQF_ONESHOT flag to mask the interrupt source while the threaded +handler is active. Otherwise the interrupt can fire again before the +threaded handler had a chance to run. + +Mark explained that this should not happen with this hardware since it +is a slow irqchip which is behind an I2C/ SPI bus but the IRQ-core will +refuse to accept such a handler. + +Set IRQF_ONESHOT so the interrupt source is masked until the secondary +handler is done. + +Fixes: 1c6c69525b40e ("genirq: Reject bogus threaded irq requests") +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Reviewed-by: Charles Keepax +Reviewed-by: Andy Shevchenko +Link: https://patch.msgid.link/20260128095540.863589-16-bigeasy@linutronix.de +Signed-off-by: Sasha Levin +--- + include/linux/mfd/wm8350/core.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/linux/mfd/wm8350/core.h b/include/linux/mfd/wm8350/core.h +index a3241e4d75486..4816d4f472101 100644 +--- a/include/linux/mfd/wm8350/core.h ++++ b/include/linux/mfd/wm8350/core.h +@@ -663,7 +663,7 @@ static inline int wm8350_register_irq(struct wm8350 *wm8350, int irq, + return -ENODEV; + + return request_threaded_irq(irq + wm8350->irq_base, NULL, +- handler, flags, name, data); ++ handler, flags | IRQF_ONESHOT, name, data); + } + + static inline void wm8350_free_irq(struct wm8350 *wm8350, int irq, void *data) +-- +2.51.0 + diff --git a/queue-6.12/mmc-rtsx_pci_sdmmc-increase-power-on-settling-delay-.patch b/queue-6.12/mmc-rtsx_pci_sdmmc-increase-power-on-settling-delay-.patch new file mode 100644 index 0000000000..eb7522657c --- /dev/null +++ b/queue-6.12/mmc-rtsx_pci_sdmmc-increase-power-on-settling-delay-.patch @@ -0,0 +1,40 @@ +From 6dc4752f750b5030546e3e0ada82f06558fe1f31 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 4 Jan 2026 22:02:36 -0800 +Subject: mmc: rtsx_pci_sdmmc: increase power-on settling delay to 5ms + +From: Matthew Schwartz + +[ Upstream commit aced969e9bf3701dc75cfca57c78c031b7875b9d ] + +The existing 1ms delay in sd_power_on is insufficient and causes resume +errors around 4% of the time. + +Increasing the delay to 5ms resolves this issue after testing 300 +s2idle cycles. + +Fixes: 1f311c94aabd ("mmc: rtsx: add 74 Clocks in power on flow") +Signed-off-by: Matthew Schwartz +Link: https://patch.msgid.link/20260105060236.400366-3-matthew.schwartz@linux.dev +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/mmc/host/rtsx_pci_sdmmc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c +index 04aa47f1a24fb..f5bc757ddaa27 100644 +--- a/drivers/mmc/host/rtsx_pci_sdmmc.c ++++ b/drivers/mmc/host/rtsx_pci_sdmmc.c +@@ -939,7 +939,7 @@ static int sd_power_on(struct realtek_pci_sdmmc *host, unsigned char power_mode) + if (err < 0) + return err; + +- mdelay(1); ++ mdelay(5); + + err = rtsx_pci_write_register(pcr, CARD_OE, SD_OUTPUT_EN, SD_OUTPUT_EN); + if (err < 0) +-- +2.51.0 + diff --git a/queue-6.12/module-add-helper-function-for-reading-module_buildi.patch b/queue-6.12/module-add-helper-function-for-reading-module_buildi.patch new file mode 100644 index 0000000000..210016294b --- /dev/null +++ b/queue-6.12/module-add-helper-function-for-reading-module_buildi.patch @@ -0,0 +1,80 @@ +From 6c4cd030963fb01846355776511a5791e3e070ad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 14:59:16 +0100 +Subject: module: add helper function for reading module_buildid() + +From: Petr Mladek + +[ Upstream commit acfdbb4ab2910ff6f03becb569c23ac7b2223913 ] + +Add a helper function for reading the optional "build_id" member of struct +module. It is going to be used also in ftrace_mod_address_lookup(). + +Use "#ifdef" instead of "#if IS_ENABLED()" to match the declaration of the +optional field in struct module. + +Link: https://lkml.kernel.org/r/20251128135920.217303-4-pmladek@suse.com +Signed-off-by: Petr Mladek +Reviewed-by: Daniel Gomez +Reviewed-by: Petr Pavlu +Cc: Aaron Tomlin +Cc: Alexei Starovoitov +Cc: Daniel Borkman +Cc: John Fastabend +Cc: Kees Cook +Cc: Luis Chamberalin +Cc: Marc Rutland +Cc: "Masami Hiramatsu (Google)" +Cc: Sami Tolvanen +Cc: Steven Rostedt (Google) +Signed-off-by: Andrew Morton +Stable-dep-of: e8a1e7eaa19d ("kallsyms/ftrace: set module buildid in ftrace_mod_address_lookup()") +Signed-off-by: Sasha Levin +--- + include/linux/module.h | 9 +++++++++ + kernel/module/kallsyms.c | 9 ++------- + 2 files changed, 11 insertions(+), 7 deletions(-) + +diff --git a/include/linux/module.h b/include/linux/module.h +index 7886217c99881..1cb6f80e1b485 100644 +--- a/include/linux/module.h ++++ b/include/linux/module.h +@@ -750,6 +750,15 @@ static inline void __module_get(struct module *module) + __mod ? __mod->name : "kernel"; \ + }) + ++static inline const unsigned char *module_buildid(struct module *mod) ++{ ++#ifdef CONFIG_STACKTRACE_BUILD_ID ++ return mod->build_id; ++#else ++ return NULL; ++#endif ++} ++ + /* Dereference module function descriptor */ + void *dereference_module_function_descriptor(struct module *mod, void *ptr); + +diff --git a/kernel/module/kallsyms.c b/kernel/module/kallsyms.c +index bf65e0c3c86fc..30d0798f114f1 100644 +--- a/kernel/module/kallsyms.c ++++ b/kernel/module/kallsyms.c +@@ -337,13 +337,8 @@ int module_address_lookup(unsigned long addr, + if (mod) { + if (modname) + *modname = mod->name; +- if (modbuildid) { +-#if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID) +- *modbuildid = mod->build_id; +-#else +- *modbuildid = NULL; +-#endif +- } ++ if (modbuildid) ++ *modbuildid = module_buildid(mod); + + sym = find_kallsyms_symbol(mod, addr, size, offset); + +-- +2.51.0 + diff --git a/queue-6.12/mptcp-fix-receive-space-timestamp-initialization.patch b/queue-6.12/mptcp-fix-receive-space-timestamp-initialization.patch new file mode 100644 index 0000000000..087e360409 --- /dev/null +++ b/queue-6.12/mptcp-fix-receive-space-timestamp-initialization.patch @@ -0,0 +1,92 @@ +From 670518be179cf26c031ff06c09977b7797b94235 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 19:41:18 +0100 +Subject: mptcp: fix receive space timestamp initialization + +From: Paolo Abeni + +[ Upstream commit 70274765fef555af92a1532d5bd5450c691fca9d ] + +MPTCP initialize the receive buffer stamp in mptcp_rcv_space_init(), +using the provided subflow stamp. Such helper is invoked in several +places; for passive sockets, space init happened at clone time. + +In such scenario, MPTCP ends-up accesses the subflow stamp before +its initialization, leading to quite randomic timing for the first +receive buffer auto-tune event, as the timestamp for newly created +subflow is not refreshed there. + +Fix the issue moving the stamp initialization out of the mentioned helper, +at the data transfer start, and always using a fresh timestamp. + +Fixes: 013e3179dbd2 ("mptcp: fix rcv space initialization") +Reviewed-by: Mat Martineau +Signed-off-by: Paolo Abeni +Signed-off-by: Matthieu Baerts (NGI0) +Link: https://patch.msgid.link/20260203-net-next-mptcp-misc-feat-6-20-v1-2-31ec8bfc56d1@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/mptcp/protocol.c | 8 ++++---- + net/mptcp/protocol.h | 5 +++++ + 2 files changed, 9 insertions(+), 4 deletions(-) + +diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c +index f2bf78c019df4..e682d52a06b7e 100644 +--- a/net/mptcp/protocol.c ++++ b/net/mptcp/protocol.c +@@ -2085,8 +2085,8 @@ static void mptcp_rcv_space_adjust(struct mptcp_sock *msk, int copied) + + msk->rcvq_space.copied += copied; + +- mstamp = div_u64(tcp_clock_ns(), NSEC_PER_USEC); +- time = tcp_stamp_us_delta(mstamp, msk->rcvq_space.time); ++ mstamp = mptcp_stamp(); ++ time = tcp_stamp_us_delta(mstamp, READ_ONCE(msk->rcvq_space.time)); + + rtt_us = msk->rcvq_space.rtt_us; + if (rtt_us && time < (rtt_us >> 3)) +@@ -3493,6 +3493,7 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk, + __mptcp_propagate_sndbuf(nsk, ssk); + + mptcp_rcv_space_init(msk, ssk); ++ msk->rcvq_space.time = mptcp_stamp(); + + if (mp_opt->suboptions & OPTION_MPTCP_MPC_ACK) + __mptcp_subflow_fully_established(msk, subflow, mp_opt); +@@ -3510,8 +3511,6 @@ void mptcp_rcv_space_init(struct mptcp_sock *msk, const struct sock *ssk) + msk->rcvq_space.copied = 0; + msk->rcvq_space.rtt_us = 0; + +- msk->rcvq_space.time = tp->tcp_mstamp; +- + /* initial rcv_space offering made to peer */ + msk->rcvq_space.space = min_t(u32, tp->rcv_wnd, + TCP_INIT_CWND * tp->advmss); +@@ -3727,6 +3726,7 @@ void mptcp_finish_connect(struct sock *ssk) + * accessing the field below + */ + WRITE_ONCE(msk->local_key, subflow->local_key); ++ WRITE_ONCE(msk->rcvq_space.time, mptcp_stamp()); + + mptcp_pm_new_connection(msk, ssk, 0); + } +diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h +index bdec5ad9defb9..b266002660d70 100644 +--- a/net/mptcp/protocol.h ++++ b/net/mptcp/protocol.h +@@ -861,6 +861,11 @@ static inline bool mptcp_is_fully_established(struct sock *sk) + READ_ONCE(mptcp_sk(sk)->fully_established); + } + ++static inline u64 mptcp_stamp(void) ++{ ++ return div_u64(tcp_clock_ns(), NSEC_PER_USEC); ++} ++ + void mptcp_rcv_space_init(struct mptcp_sock *msk, const struct sock *ssk); + void mptcp_data_ready(struct sock *sk, struct sock *ssk); + bool mptcp_finish_join(struct sock *sk); +-- +2.51.0 + diff --git a/queue-6.12/mtd-parsers-fix-memory-leak-in-mtd_parser_tplink_saf.patch b/queue-6.12/mtd-parsers-fix-memory-leak-in-mtd_parser_tplink_saf.patch new file mode 100644 index 0000000000..8ab0764856 --- /dev/null +++ b/queue-6.12/mtd-parsers-fix-memory-leak-in-mtd_parser_tplink_saf.patch @@ -0,0 +1,42 @@ +From c5c23f8f562ff139ee30d20521829f7e99722c4a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 13:09:50 +0000 +Subject: mtd: parsers: Fix memory leak in mtd_parser_tplink_safeloader_parse() + +From: Zilin Guan + +[ Upstream commit 980ce2b02dd06a4fdf5fee38b2e14becf9cf7b8b ] + +The function mtd_parser_tplink_safeloader_parse() allocates buf via +mtd_parser_tplink_safeloader_read_table(). If the allocation for +parts[idx].name fails inside the loop, the code jumps to the err_free +label without freeing buf, leading to a memory leak. + +Fix this by freeing the temporary buffer buf in the err_free label. + +Compile tested only. Issue found using a prototype static analysis tool +and code review. + +Fixes: 00a3588084be ("mtd: parsers: add TP-Link SafeLoader partitions table parser") +Signed-off-by: Zilin Guan +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/parsers/tplink_safeloader.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/mtd/parsers/tplink_safeloader.c b/drivers/mtd/parsers/tplink_safeloader.c +index e358a029dc70c..4fcaf92d22e4f 100644 +--- a/drivers/mtd/parsers/tplink_safeloader.c ++++ b/drivers/mtd/parsers/tplink_safeloader.c +@@ -116,6 +116,7 @@ static int mtd_parser_tplink_safeloader_parse(struct mtd_info *mtd, + return idx; + + err_free: ++ kfree(buf); + for (idx -= 1; idx >= 0; idx--) + kfree(parts[idx].name); + err_free_parts: +-- +2.51.0 + diff --git a/queue-6.12/mtd-parsers-ofpart-fix-of-node-refcount-leak-in-pars.patch b/queue-6.12/mtd-parsers-ofpart-fix-of-node-refcount-leak-in-pars.patch new file mode 100644 index 0000000000..7c726a22e3 --- /dev/null +++ b/queue-6.12/mtd-parsers-ofpart-fix-of-node-refcount-leak-in-pars.patch @@ -0,0 +1,84 @@ +From f525f28b3893f640ff2e78c6c5353f71dd1d6834 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 05:26:08 +0000 +Subject: mtd: parsers: ofpart: fix OF node refcount leak in + parse_fixed_partitions() + +From: Weigang He + +[ Upstream commit 7cce81df7d26d44123bd7620715c8349d96793d7 ] + +of_get_child_by_name() returns a node pointer with refcount incremented, +which must be released with of_node_put() when done. However, in +parse_fixed_partitions(), when dedicated is true (i.e., a "partitions" +subnode was found), the ofpart_node obtained from of_get_child_by_name() +is never released on any code path. + +Add of_node_put(ofpart_node) calls on all exit paths when dedicated is +true to fix the reference count leak. + +This bug was detected by our static analysis tool. + +Fixes: 562b4e91d3b2 ("mtd: parsers: ofpart: fix parsing subpartitions") +Signed-off-by: Weigang He +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/parsers/ofpart_core.c | 16 ++++++++++++++-- + 1 file changed, 14 insertions(+), 2 deletions(-) + +diff --git a/drivers/mtd/parsers/ofpart_core.c b/drivers/mtd/parsers/ofpart_core.c +index abfa687989182..09961c6f39496 100644 +--- a/drivers/mtd/parsers/ofpart_core.c ++++ b/drivers/mtd/parsers/ofpart_core.c +@@ -77,6 +77,7 @@ static int parse_fixed_partitions(struct mtd_info *master, + of_id = of_match_node(parse_ofpart_match_table, ofpart_node); + if (dedicated && !of_id) { + /* The 'partitions' subnode might be used by another parser */ ++ of_node_put(ofpart_node); + return 0; + } + +@@ -91,12 +92,18 @@ static int parse_fixed_partitions(struct mtd_info *master, + nr_parts++; + } + +- if (nr_parts == 0) ++ if (nr_parts == 0) { ++ if (dedicated) ++ of_node_put(ofpart_node); + return 0; ++ } + + parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL); +- if (!parts) ++ if (!parts) { ++ if (dedicated) ++ of_node_put(ofpart_node); + return -ENOMEM; ++ } + + i = 0; + for_each_child_of_node(ofpart_node, pp) { +@@ -175,6 +182,9 @@ static int parse_fixed_partitions(struct mtd_info *master, + if (quirks && quirks->post_parse) + quirks->post_parse(master, parts, nr_parts); + ++ if (dedicated) ++ of_node_put(ofpart_node); ++ + *pparts = parts; + return nr_parts; + +@@ -183,6 +193,8 @@ static int parse_fixed_partitions(struct mtd_info *master, + master->name, pp, mtd_node); + ret = -EINVAL; + ofpart_none: ++ if (dedicated) ++ of_node_put(ofpart_node); + of_node_put(pp); + kfree(parts); + return ret; +-- +2.51.0 + diff --git a/queue-6.12/mtd-rawnand-cadence-fix-return-type-of-cdma-send-and.patch b/queue-6.12/mtd-rawnand-cadence-fix-return-type-of-cdma-send-and.patch new file mode 100644 index 0000000000..d1b9c796c6 --- /dev/null +++ b/queue-6.12/mtd-rawnand-cadence-fix-return-type-of-cdma-send-and.patch @@ -0,0 +1,40 @@ +From 7fcdf3b8c5e13e86df6c1780ce2def0efb36a4e2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 19 Dec 2025 03:09:30 -0800 +Subject: mtd: rawnand: cadence: Fix return type of CDMA send-and-wait helper + +From: Alok Tiwari + +[ Upstream commit 6d8226cbbf124bb5613b532216b74c886a4361b7 ] + +cadence_nand_cdma_send_and_wait() propagates negative errno values +from cadence_nand_cdma_send(), returns -ETIMEDOUT on failure and -EIO +when the CDMA engine reports a command failure. + +However, it is declared as u32, causing error codes to wrap. +Change the return type to int to correctly propagate errors. + +Fixes: ec4ba01e894d ("mtd: rawnand: Add new Cadence NAND driver to MTD subsystem") +Signed-off-by: Alok Tiwari +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/nand/raw/cadence-nand-controller.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/nand/raw/cadence-nand-controller.c b/drivers/mtd/nand/raw/cadence-nand-controller.c +index 443202b942e1f..5872f1dfe7016 100644 +--- a/drivers/mtd/nand/raw/cadence-nand-controller.c ++++ b/drivers/mtd/nand/raw/cadence-nand-controller.c +@@ -1015,7 +1015,7 @@ static int cadence_nand_cdma_send(struct cdns_nand_ctrl *cdns_ctrl, + } + + /* Send SDMA command and wait for finish. */ +-static u32 ++static int + cadence_nand_cdma_send_and_wait(struct cdns_nand_ctrl *cdns_ctrl, + u8 thread) + { +-- +2.51.0 + diff --git a/queue-6.12/mtd-spinand-fix-kernel-doc.patch b/queue-6.12/mtd-spinand-fix-kernel-doc.patch new file mode 100644 index 0000000000..be2b4ddbcf --- /dev/null +++ b/queue-6.12/mtd-spinand-fix-kernel-doc.patch @@ -0,0 +1,36 @@ +From b9ba5d12d3cc42888adc1fc867971a14164a6e54 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 18:18:02 +0100 +Subject: mtd: spinand: Fix kernel doc + +From: Miquel Raynal + +[ Upstream commit a57b1f07d2d35843a7ada30c8cf9a215c0931868 ] + +The @data buffer is 5 bytes, not 4, it has been extended for the need of +devices with an extra ID bytes. + +Fixes: 34a956739d29 ("mtd: spinand: Add support for 5-byte IDs") +Reviewed-by: Tudor Ambarus +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + include/linux/mtd/spinand.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h +index 702e5fb13dae7..4bf33cefbae5f 100644 +--- a/include/linux/mtd/spinand.h ++++ b/include/linux/mtd/spinand.h +@@ -195,7 +195,7 @@ struct spinand_device; + + /** + * struct spinand_id - SPI NAND id structure +- * @data: buffer containing the id bytes. Currently 4 bytes large, but can ++ * @data: buffer containing the id bytes. Currently 5 bytes large, but can + * be extended if required + * @len: ID length + */ +-- +2.51.0 + diff --git a/queue-6.12/net-add-skb_dstref_steal-and-skb_dstref_restore.patch b/queue-6.12/net-add-skb_dstref_steal-and-skb_dstref_restore.patch new file mode 100644 index 0000000000..5dab4af2c5 --- /dev/null +++ b/queue-6.12/net-add-skb_dstref_steal-and-skb_dstref_restore.patch @@ -0,0 +1,73 @@ +From dc298d04aa1ad8447e60ecc785dc964253a722bf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 18 Aug 2025 08:40:26 -0700 +Subject: net: Add skb_dstref_steal and skb_dstref_restore + +From: Stanislav Fomichev + +[ Upstream commit c3f0c02997c7f8489fec259e28e0e04e9811edac ] + +Going forward skb_dst_set will assert that skb dst_entry +is empty during skb_dst_set to prevent potential leaks. There +are few places that still manually manage dst_entry not using +the helpers. Convert them to the following new helpers: +- skb_dstref_steal that resets dst_entry and returns previous dst_entry + value +- skb_dstref_restore that restores dst_entry previously reset via + skb_dstref_steal + +Signed-off-by: Stanislav Fomichev +Link: https://patch.msgid.link/20250818154032.3173645-2-sdf@fomichev.me +Signed-off-by: Jakub Kicinski +Stable-dep-of: 81b84de32bb2 ("xfrm: fix ip_rt_bug race in icmp_route_lookup reverse path") +Signed-off-by: Sasha Levin +--- + include/linux/skbuff.h | 32 ++++++++++++++++++++++++++++++++ + 1 file changed, 32 insertions(+) + +diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h +index 2e26a054d260c..4344724a97821 100644 +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -1146,6 +1146,38 @@ static inline struct dst_entry *skb_dst(const struct sk_buff *skb) + return (struct dst_entry *)(skb->_skb_refdst & SKB_DST_PTRMASK); + } + ++/** ++ * skb_dstref_steal() - return current dst_entry value and clear it ++ * @skb: buffer ++ * ++ * Resets skb dst_entry without adjusting its reference count. Useful in ++ * cases where dst_entry needs to be temporarily reset and restored. ++ * Note that the returned value cannot be used directly because it ++ * might contain SKB_DST_NOREF bit. ++ * ++ * When in doubt, prefer skb_dst_drop() over skb_dstref_steal() to correctly ++ * handle dst_entry reference counting. ++ * ++ * Returns: original skb dst_entry. ++ */ ++static inline unsigned long skb_dstref_steal(struct sk_buff *skb) ++{ ++ unsigned long refdst = skb->_skb_refdst; ++ ++ skb->_skb_refdst = 0; ++ return refdst; ++} ++ ++/** ++ * skb_dstref_restore() - restore skb dst_entry removed via skb_dstref_steal() ++ * @skb: buffer ++ * @refdst: dst entry from a call to skb_dstref_steal() ++ */ ++static inline void skb_dstref_restore(struct sk_buff *skb, unsigned long refdst) ++{ ++ skb->_skb_refdst = refdst; ++} ++ + /** + * skb_dst_set - sets skb dst + * @skb: buffer +-- +2.51.0 + diff --git a/queue-6.12/net-atm-fix-crash-due-to-unvalidated-vcc-pointer-in-.patch b/queue-6.12/net-atm-fix-crash-due-to-unvalidated-vcc-pointer-in-.patch new file mode 100644 index 0000000000..6988e9d7f6 --- /dev/null +++ b/queue-6.12/net-atm-fix-crash-due-to-unvalidated-vcc-pointer-in-.patch @@ -0,0 +1,154 @@ +From cdb19e1fd7d95b0df66756badce5d66f7d835f39 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 17:54:51 +0800 +Subject: net: atm: fix crash due to unvalidated vcc pointer in sigd_send() + +From: Jiayuan Chen + +[ Upstream commit ae88a5d2f29b69819dc7b04086734439d074a643 ] + +Reproducer available at [1]. + +The ATM send path (sendmsg -> vcc_sendmsg -> sigd_send) reads the vcc +pointer from msg->vcc and uses it directly without any validation. This +pointer comes from userspace via sendmsg() and can be arbitrarily forged: + + int fd = socket(AF_ATMSVC, SOCK_DGRAM, 0); + ioctl(fd, ATMSIGD_CTRL); // become ATM signaling daemon + struct msghdr msg = { .msg_iov = &iov, ... }; + *(unsigned long *)(buf + 4) = 0xdeadbeef; // fake vcc pointer + sendmsg(fd, &msg, 0); // kernel dereferences 0xdeadbeef + +In normal operation, the kernel sends the vcc pointer to the signaling +daemon via sigd_enq() when processing operations like connect(), bind(), +or listen(). The daemon is expected to return the same pointer when +responding. However, a malicious daemon can send arbitrary pointer values. + +Fix this by introducing find_get_vcc() which validates the pointer by +searching through vcc_hash (similar to how sigd_close() iterates over +all VCCs), and acquires a reference via sock_hold() if found. + +Since struct atm_vcc embeds struct sock as its first member, they share +the same lifetime. Therefore using sock_hold/sock_put is sufficient to +keep the vcc alive while it is being used. + +Note that there may be a race with sigd_close() which could mark the vcc +with various flags (e.g., ATM_VF_RELEASED) after find_get_vcc() returns. +However, sock_hold() guarantees the memory remains valid, so this race +only affects the logical state, not memory safety. + +[1]: https://gist.github.com/mrpre/1ba5949c45529c511152e2f4c755b0f3 +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: syzbot+1f22cb1769f249df9fa0@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/69039850.a70a0220.5b2ed.005d.GAE@google.com/T/ +Signed-off-by: Jiayuan Chen +Link: https://patch.msgid.link/20260205095501.131890-1-jiayuan.chen@linux.dev +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/atm/signaling.c | 56 +++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 54 insertions(+), 2 deletions(-) + +diff --git a/net/atm/signaling.c b/net/atm/signaling.c +index e70ae2c113f95..358fbe5e4d1d0 100644 +--- a/net/atm/signaling.c ++++ b/net/atm/signaling.c +@@ -22,6 +22,36 @@ + + struct atm_vcc *sigd = NULL; + ++/* ++ * find_get_vcc - validate and get a reference to a vcc pointer ++ * @vcc: the vcc pointer to validate ++ * ++ * This function validates that @vcc points to a registered VCC in vcc_hash. ++ * If found, it increments the socket reference count and returns the vcc. ++ * The caller must call sock_put(sk_atm(vcc)) when done. ++ * ++ * Returns the vcc pointer if valid, NULL otherwise. ++ */ ++static struct atm_vcc *find_get_vcc(struct atm_vcc *vcc) ++{ ++ int i; ++ ++ read_lock(&vcc_sklist_lock); ++ for (i = 0; i < VCC_HTABLE_SIZE; i++) { ++ struct sock *s; ++ ++ sk_for_each(s, &vcc_hash[i]) { ++ if (atm_sk(s) == vcc) { ++ sock_hold(s); ++ read_unlock(&vcc_sklist_lock); ++ return vcc; ++ } ++ } ++ } ++ read_unlock(&vcc_sklist_lock); ++ return NULL; ++} ++ + static void sigd_put_skb(struct sk_buff *skb) + { + if (!sigd) { +@@ -69,7 +99,14 @@ static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb) + + msg = (struct atmsvc_msg *) skb->data; + WARN_ON(refcount_sub_and_test(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc)); +- vcc = *(struct atm_vcc **) &msg->vcc; ++ ++ vcc = find_get_vcc(*(struct atm_vcc **)&msg->vcc); ++ if (!vcc) { ++ pr_debug("invalid vcc pointer in msg\n"); ++ dev_kfree_skb(skb); ++ return -EINVAL; ++ } ++ + pr_debug("%d (0x%lx)\n", (int)msg->type, (unsigned long)vcc); + sk = sk_atm(vcc); + +@@ -100,7 +137,16 @@ static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb) + clear_bit(ATM_VF_WAITING, &vcc->flags); + break; + case as_indicate: +- vcc = *(struct atm_vcc **)&msg->listen_vcc; ++ /* Release the reference from msg->vcc, we'll use msg->listen_vcc instead */ ++ sock_put(sk); ++ ++ vcc = find_get_vcc(*(struct atm_vcc **)&msg->listen_vcc); ++ if (!vcc) { ++ pr_debug("invalid listen_vcc pointer in msg\n"); ++ dev_kfree_skb(skb); ++ return -EINVAL; ++ } ++ + sk = sk_atm(vcc); + pr_debug("as_indicate!!!\n"); + lock_sock(sk); +@@ -115,6 +161,8 @@ static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb) + sk->sk_state_change(sk); + as_indicate_complete: + release_sock(sk); ++ /* Paired with find_get_vcc(msg->listen_vcc) above */ ++ sock_put(sk); + return 0; + case as_close: + set_bit(ATM_VF_RELEASED, &vcc->flags); +@@ -131,11 +179,15 @@ static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb) + break; + default: + pr_alert("bad message type %d\n", (int)msg->type); ++ /* Paired with find_get_vcc(msg->vcc) above */ ++ sock_put(sk); + return -EINVAL; + } + sk->sk_state_change(sk); + out: + dev_kfree_skb(skb); ++ /* Paired with find_get_vcc(msg->vcc) above */ ++ sock_put(sk); + return 0; + } + +-- +2.51.0 + diff --git a/queue-6.12/net-hns3-fix-double-free-issue-for-tx-spare-buffer.patch b/queue-6.12/net-hns3-fix-double-free-issue-for-tx-spare-buffer.patch new file mode 100644 index 0000000000..dbfad04b6c --- /dev/null +++ b/queue-6.12/net-hns3-fix-double-free-issue-for-tx-spare-buffer.patch @@ -0,0 +1,74 @@ +From 5a1788770889c736f52556a8de2dcdf820d20c04 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 20:17:19 +0800 +Subject: net: hns3: fix double free issue for tx spare buffer + +From: Jian Shen + +[ Upstream commit 6d2f142b1e4b203387a92519d9d2e34752a79dbb ] + +In hns3_set_ringparam(), a temporary copy (tmp_rings) of the ring structure +is created for rollback. However, the tx_spare pointer in the original +ring handle is incorrectly left pointing to the old backup memory. + +Later, if memory allocation fails in hns3_init_all_ring() during the setup, +the error path attempts to free all newly allocated rings. Since tx_spare +contains a stale (non-NULL) pointer from the backup, it is mistaken for +a newly allocated buffer and is erroneously freed, leading to a double-free +of the backup memory. + +The root cause is that the tx_spare field was not cleared after its value +was saved in tmp_rings, leaving a dangling pointer. + +Fix this by setting tx_spare to NULL in the original ring structure +when the creation of the new `tx_spare` fails. This ensures the +error cleanup path only frees genuinely newly allocated buffers. + +Fixes: 907676b130711 ("net: hns3: use tx bounce buffer for small packets") +Signed-off-by: Jian Shen +Signed-off-by: Jijie Shao +Reviewed-by: Jacob Keller +Link: https://patch.msgid.link/20260205121719.3285730-1-shaojijie@huawei.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +index b477bd286ed72..803da392c8efe 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +@@ -1048,13 +1048,13 @@ static void hns3_init_tx_spare_buffer(struct hns3_enet_ring *ring) + int order; + + if (!alloc_size) +- return; ++ goto not_init; + + order = get_order(alloc_size); + if (order > MAX_PAGE_ORDER) { + if (net_ratelimit()) + dev_warn(ring_to_dev(ring), "failed to allocate tx spare buffer, exceed to max order\n"); +- return; ++ goto not_init; + } + + tx_spare = devm_kzalloc(ring_to_dev(ring), sizeof(*tx_spare), +@@ -1092,6 +1092,13 @@ static void hns3_init_tx_spare_buffer(struct hns3_enet_ring *ring) + devm_kfree(ring_to_dev(ring), tx_spare); + devm_kzalloc_error: + ring->tqp->handle->kinfo.tx_spare_buf_size = 0; ++not_init: ++ /* When driver init or reset_init, the ring->tx_spare is always NULL; ++ * but when called from hns3_set_ringparam, it's usually not NULL, and ++ * will be restored if hns3_init_all_ring() failed. So it's safe to set ++ * ring->tx_spare to NULL here. ++ */ ++ ring->tx_spare = NULL; + } + + /* Use hns3_tx_spare_space() to make sure there is enough buffer +-- +2.51.0 + diff --git a/queue-6.12/net-mctp-i2c-fix-duplicate-reception-of-old-data.patch b/queue-6.12/net-mctp-i2c-fix-duplicate-reception-of-old-data.patch new file mode 100644 index 0000000000..365735ebf4 --- /dev/null +++ b/queue-6.12/net-mctp-i2c-fix-duplicate-reception-of-old-data.patch @@ -0,0 +1,49 @@ +From 59ded7506cb80a23d1153e68e50861cad4d5f2f7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 18:18:29 +0800 +Subject: net: mctp-i2c: fix duplicate reception of old data + +From: Jian Zhang + +[ Upstream commit ae4744e173fadd092c43eda4ca92dcb74645225a ] + +The MCTP I2C slave callback did not handle I2C_SLAVE_READ_REQUESTED +events. As a result, i2c read event will trigger repeated reception of +old data, reset rx_pos when a read request is received. + +Signed-off-by: Jian Zhang +Link: https://patch.msgid.link/20260108101829.1140448-1-zhangjian.3032@bytedance.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 2a14e91b6d76 ("mctp i2c: initialise event handler read bytes") +Signed-off-by: Sasha Levin +--- + drivers/net/mctp/mctp-i2c.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/mctp/mctp-i2c.c b/drivers/net/mctp/mctp-i2c.c +index 503a9174321c6..8a30d0559d60d 100644 +--- a/drivers/net/mctp/mctp-i2c.c ++++ b/drivers/net/mctp/mctp-i2c.c +@@ -243,6 +243,9 @@ static int mctp_i2c_slave_cb(struct i2c_client *client, + return 0; + + switch (event) { ++ case I2C_SLAVE_READ_REQUESTED: ++ midev->rx_pos = 0; ++ break; + case I2C_SLAVE_WRITE_RECEIVED: + if (midev->rx_pos < MCTP_I2C_BUFSZ) { + midev->rx_buffer[midev->rx_pos] = *val; +@@ -280,6 +283,9 @@ static int mctp_i2c_recv(struct mctp_i2c_dev *midev) + size_t recvlen; + int status; + ++ if (midev->rx_pos == 0) ++ return 0; ++ + /* + 1 for the PEC */ + if (midev->rx_pos < MCTP_I2C_MINLEN + 1) { + ndev->stats.rx_length_errors++; +-- +2.51.0 + diff --git a/queue-6.12/net-sunhme-fix-sbus-regression.patch b/queue-6.12/net-sunhme-fix-sbus-regression.patch new file mode 100644 index 0000000000..baed51063d --- /dev/null +++ b/queue-6.12/net-sunhme-fix-sbus-regression.patch @@ -0,0 +1,73 @@ +From 17fab306962d25fe585ac9333d8d86235c93afcd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 17:09:59 +0100 +Subject: net: sunhme: Fix sbus regression +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: René Rebe + +[ Upstream commit 8c5d17834ec104d0abd1bda52fbc04e647fab274 ] + +Commit cc216e4b44ce ("net: sunhme: Switch SBUS to devres") changed +explicit sized of_ioremap with BMAC_REG_SIZEs to +devm_platform_ioremap_resource mapping all the resource. However, +this does not work on my Sun Ultra 2 with SBUS HMEs: + +hme f0072f38: error -EBUSY: can't request region for resource [mem 0x1ffe8c07000-0x1ffe8c0701f] +hme f0072f38: Cannot map TCVR registers. +hme f0072f38: probe with driver hme failed with error -16 +hme f007ab44: error -EBUSY: can't request region for resource [mem 0x1ff28c07000-0x1ff28c0701f] +hme f007ab44: Cannot map TCVR registers. +hme f007ab44: probe with driver hme failed with error -16 + +Turns out the open-firmware resources overlap, at least on this +machines and PROM version: + +hexdump /proc/device-tree/sbus@1f,0/SUNW,hme@2,8c00000/reg: +00 00 00 02 08 c0 00 00 00 00 01 08 +00 00 00 02 08 c0 20 00 00 00 20 00 +00 00 00 02 08 c0 40 00 00 00 20 00 +00 00 00 02 08 c0 60 00 00 00 20 00 +00 00 00 02 08 c0 70 00 00 00 00 20 + +And the driver previously explicitly mapped way smaller mmio regions: + +/proc/iomem: +1ff28c00000-1ff28c00107 : HME Global Regs +1ff28c02000-1ff28c02033 : HME TX Regs +1ff28c04000-1ff28c0401f : HME RX Regs +1ff28c06000-1ff28c0635f : HME BIGMAC Regs +1ff28c07000-1ff28c0701f : HME Tranceiver Regs + +Quirk this specific issue by truncating the previous resource to not +overlap into the TCVR registers. + +Fixes: cc216e4b44ce ("net: sunhme: Switch SBUS to devres") +Signed-off-by: René Rebe +Reviewed-by: Sean Anderson +Link: https://patch.msgid.link/20260205.170959.89574674688839340.rene@exactco.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/sun/sunhme.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/ethernet/sun/sunhme.c b/drivers/net/ethernet/sun/sunhme.c +index 50ace461a1af4..89ac15190770d 100644 +--- a/drivers/net/ethernet/sun/sunhme.c ++++ b/drivers/net/ethernet/sun/sunhme.c +@@ -2551,6 +2551,9 @@ static int happy_meal_sbus_probe_one(struct platform_device *op, int is_qfe) + goto err_out_clear_quattro; + } + ++ /* BIGMAC may have bogus sizes */ ++ if ((op->resource[3].end - op->resource[3].start) >= BMAC_REG_SIZE) ++ op->resource[3].end = op->resource[3].start + BMAC_REG_SIZE - 1; + hp->bigmacregs = devm_platform_ioremap_resource(op, 3); + if (IS_ERR(hp->bigmacregs)) { + dev_err(&op->dev, "Cannot map BIGMAC registers.\n"); +-- +2.51.0 + diff --git a/queue-6.12/net-switch-to-skb_dstref_steal-skb_dstref_restore-fo.patch b/queue-6.12/net-switch-to-skb_dstref_steal-skb_dstref_restore-fo.patch new file mode 100644 index 0000000000..569007fc36 --- /dev/null +++ b/queue-6.12/net-switch-to-skb_dstref_steal-skb_dstref_restore-fo.patch @@ -0,0 +1,75 @@ +From ba8e033fd4caf27ce04b6cf1e1d1b96b57f5b292 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 18 Aug 2025 08:40:29 -0700 +Subject: net: Switch to skb_dstref_steal/skb_dstref_restore for ip_route_input + callers + +From: Stanislav Fomichev + +[ Upstream commit e97e6a1830ddb5885ba312e56b6fa3aa39b5f47e ] + +Going forward skb_dst_set will assert that skb dst_entry +is empty during skb_dst_set. skb_dstref_steal is added to reset +existing entry without doing refcnt. skb_dstref_restore should +be used to restore the previous entry. Convert icmp_route_lookup +and ip_options_rcv_srr to these helpers. Add extra call to +skb_dstref_reset to icmp_route_lookup to clear the ip_route_input +entry. + +Signed-off-by: Stanislav Fomichev +Link: https://patch.msgid.link/20250818154032.3173645-5-sdf@fomichev.me +Signed-off-by: Jakub Kicinski +Stable-dep-of: 81b84de32bb2 ("xfrm: fix ip_rt_bug race in icmp_route_lookup reverse path") +Signed-off-by: Sasha Levin +--- + net/ipv4/icmp.c | 7 ++++--- + net/ipv4/ip_options.c | 5 ++--- + 2 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c +index c0373d1172d73..2bda14908273c 100644 +--- a/net/ipv4/icmp.c ++++ b/net/ipv4/icmp.c +@@ -546,14 +546,15 @@ static struct rtable *icmp_route_lookup(struct net *net, struct flowi4 *fl4, + goto relookup_failed; + } + /* Ugh! */ +- orefdst = skb_in->_skb_refdst; /* save old refdst */ +- skb_dst_set(skb_in, NULL); ++ orefdst = skb_dstref_steal(skb_in); + err = ip_route_input(skb_in, fl4_dec.daddr, fl4_dec.saddr, + dscp, rt2->dst.dev); + + dst_release(&rt2->dst); + rt2 = skb_rtable(skb_in); +- skb_in->_skb_refdst = orefdst; /* restore old refdst */ ++ /* steal dst entry from skb_in, don't drop refcnt */ ++ skb_dstref_steal(skb_in); ++ skb_dstref_restore(skb_in, orefdst); + } + + if (err) +diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c +index 81e86e5defee6..3d154bc7e1f2e 100644 +--- a/net/ipv4/ip_options.c ++++ b/net/ipv4/ip_options.c +@@ -615,14 +615,13 @@ int ip_options_rcv_srr(struct sk_buff *skb, struct net_device *dev) + } + memcpy(&nexthop, &optptr[srrptr-1], 4); + +- orefdst = skb->_skb_refdst; +- skb_dst_set(skb, NULL); ++ orefdst = skb_dstref_steal(skb); + err = ip_route_input(skb, nexthop, iph->saddr, ip4h_dscp(iph), + dev); + rt2 = skb_rtable(skb); + if (err || (rt2->rt_type != RTN_UNICAST && rt2->rt_type != RTN_LOCAL)) { + skb_dst_drop(skb); +- skb->_skb_refdst = orefdst; ++ skb_dstref_restore(skb, orefdst); + return -EINVAL; + } + refdst_drop(orefdst); +-- +2.51.0 + diff --git a/queue-6.12/netfilter-nf_conncount-fix-tracking-of-connections-f.patch b/queue-6.12/netfilter-nf_conncount-fix-tracking-of-connections-f.patch new file mode 100644 index 0000000000..506774b9e7 --- /dev/null +++ b/queue-6.12/netfilter-nf_conncount-fix-tracking-of-connections-f.patch @@ -0,0 +1,69 @@ +From b5ad792a39282abef63da6b58d5ecff6afa63ba3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 21:35:46 +0100 +Subject: netfilter: nf_conncount: fix tracking of connections from localhost + +From: Fernando Fernandez Mancera + +[ Upstream commit de8a70cefcb26cdceaafdc5ac144712681419c29 ] + +Since commit be102eb6a0e7 ("netfilter: nf_conncount: rework API to use +sk_buff directly"), we skip the adding and trigger a GC when the ct is +confirmed. For connections originated from local to local it doesn't +work because the connection is confirmed on POSTROUTING, therefore +tracking on the INPUT hook is always skipped. + +In order to fix this, we check whether skb input ifindex is set to +loopback ifindex. If it is then we fallback on a GC plus track operation +skipping the optimization. This fallback is necessary to avoid +duplicated tracking of a packet train e.g 10 UDP datagrams sent on a +burst when initiating the connection. + +Tested with xt_connlimit/nft_connlimit and OVS limit and with a HTTP +server and iperf3 on UDP mode. + +Fixes: be102eb6a0e7 ("netfilter: nf_conncount: rework API to use sk_buff directly") +Reported-by: Michal Slabihoudek +Closes: https://lore.kernel.org/netfilter/6989BD9F-8C24-4397-9AD7-4613B28BF0DB@gooddata.com/ +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_conncount.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +diff --git a/net/netfilter/nf_conncount.c b/net/netfilter/nf_conncount.c +index 288936f5c1bf9..14e62b3263cd9 100644 +--- a/net/netfilter/nf_conncount.c ++++ b/net/netfilter/nf_conncount.c +@@ -179,14 +179,25 @@ static int __nf_conncount_add(struct net *net, + return -ENOENT; + + if (ct && nf_ct_is_confirmed(ct)) { +- err = -EEXIST; +- goto out_put; ++ /* local connections are confirmed in postrouting so confirmation ++ * might have happened before hitting connlimit ++ */ ++ if (skb->skb_iif != LOOPBACK_IFINDEX) { ++ err = -EEXIST; ++ goto out_put; ++ } ++ ++ /* this is likely a local connection, skip optimization to avoid ++ * adding duplicates from a 'packet train' ++ */ ++ goto check_connections; + } + + if ((u32)jiffies == list->last_gc && + (list->count - list->last_gc_count) < CONNCOUNT_GC_MAX_COLLECT) + goto add_new_node; + ++check_connections: + /* check the saved connections */ + list_for_each_entry_safe(conn, conn_n, &list->head, node) { + if (collect > CONNCOUNT_GC_MAX_COLLECT) +-- +2.51.0 + diff --git a/queue-6.12/netfilter-nf_conncount-increase-the-connection-clean.patch b/queue-6.12/netfilter-nf_conncount-increase-the-connection-clean.patch new file mode 100644 index 0000000000..4a02f68be8 --- /dev/null +++ b/queue-6.12/netfilter-nf_conncount-increase-the-connection-clean.patch @@ -0,0 +1,123 @@ +From 333eb5aabc02145f39b0ad37d760beb84372dda4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 17 Dec 2025 15:46:41 +0100 +Subject: netfilter: nf_conncount: increase the connection clean up limit to 64 + +From: Fernando Fernandez Mancera + +[ Upstream commit 21d033e472735ecec677f1ae46d6740b5e47a4f3 ] + +After the optimization to only perform one GC per jiffy, a new problem +was introduced. If more than 8 new connections are tracked per jiffy the +list won't be cleaned up fast enough possibly reaching the limit +wrongly. + +In order to prevent this issue, only skip the GC if it was already +triggered during the same jiffy and the increment is lower than the +clean up limit. In addition, increase the clean up limit to 64 +connections to avoid triggering GC too often and do more effective GCs. + +This has been tested using a HTTP server and several +performance tools while having nft_connlimit/xt_connlimit or OVS limit +configured. + +Output of slowhttptest + OVS limit at 52000 connections: + + slow HTTP test status on 340th second: + initializing: 0 + pending: 432 + connected: 51998 + error: 0 + closed: 0 + service available: YES + +Fixes: d265929930e2 ("netfilter: nf_conncount: reduce unnecessary GC") +Reported-by: Aleksandra Rukomoinikova +Closes: https://lore.kernel.org/netfilter/b2064e7b-0776-4e14-adb6-c68080987471@k2.cloud/ +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + include/net/netfilter/nf_conntrack_count.h | 1 + + net/netfilter/nf_conncount.c | 15 ++++++++++----- + 2 files changed, 11 insertions(+), 5 deletions(-) + +diff --git a/include/net/netfilter/nf_conntrack_count.h b/include/net/netfilter/nf_conntrack_count.h +index 52a06de41aa0f..cf0166520cf33 100644 +--- a/include/net/netfilter/nf_conntrack_count.h ++++ b/include/net/netfilter/nf_conntrack_count.h +@@ -13,6 +13,7 @@ struct nf_conncount_list { + u32 last_gc; /* jiffies at most recent gc */ + struct list_head head; /* connections with the same filtering key */ + unsigned int count; /* length of list */ ++ unsigned int last_gc_count; /* length of list at most recent gc */ + }; + + struct nf_conncount_data *nf_conncount_init(struct net *net, unsigned int keylen); +diff --git a/net/netfilter/nf_conncount.c b/net/netfilter/nf_conncount.c +index 8487808c87614..288936f5c1bf9 100644 +--- a/net/netfilter/nf_conncount.c ++++ b/net/netfilter/nf_conncount.c +@@ -34,8 +34,9 @@ + + #define CONNCOUNT_SLOTS 256U + +-#define CONNCOUNT_GC_MAX_NODES 8 +-#define MAX_KEYLEN 5 ++#define CONNCOUNT_GC_MAX_NODES 8 ++#define CONNCOUNT_GC_MAX_COLLECT 64 ++#define MAX_KEYLEN 5 + + /* we will save the tuples of all connections we care about */ + struct nf_conncount_tuple { +@@ -182,12 +183,13 @@ static int __nf_conncount_add(struct net *net, + goto out_put; + } + +- if ((u32)jiffies == list->last_gc) ++ if ((u32)jiffies == list->last_gc && ++ (list->count - list->last_gc_count) < CONNCOUNT_GC_MAX_COLLECT) + goto add_new_node; + + /* check the saved connections */ + list_for_each_entry_safe(conn, conn_n, &list->head, node) { +- if (collect > CONNCOUNT_GC_MAX_NODES) ++ if (collect > CONNCOUNT_GC_MAX_COLLECT) + break; + + found = find_or_evict(net, list, conn); +@@ -230,6 +232,7 @@ static int __nf_conncount_add(struct net *net, + nf_ct_put(found_ct); + } + list->last_gc = (u32)jiffies; ++ list->last_gc_count = list->count; + + add_new_node: + if (WARN_ON_ONCE(list->count > INT_MAX)) { +@@ -277,6 +280,7 @@ void nf_conncount_list_init(struct nf_conncount_list *list) + spin_lock_init(&list->list_lock); + INIT_LIST_HEAD(&list->head); + list->count = 0; ++ list->last_gc_count = 0; + list->last_gc = (u32)jiffies; + } + EXPORT_SYMBOL_GPL(nf_conncount_list_init); +@@ -316,13 +320,14 @@ static bool __nf_conncount_gc_list(struct net *net, + } + + nf_ct_put(found_ct); +- if (collected > CONNCOUNT_GC_MAX_NODES) ++ if (collected > CONNCOUNT_GC_MAX_COLLECT) + break; + } + + if (!list->count) + ret = true; + list->last_gc = (u32)jiffies; ++ list->last_gc_count = list->count; + + return ret; + } +-- +2.51.0 + diff --git a/queue-6.12/netfilter-nf_conncount-make-nf_conncount_gc_list-to-.patch b/queue-6.12/netfilter-nf_conncount-make-nf_conncount_gc_list-to-.patch new file mode 100644 index 0000000000..6791706988 --- /dev/null +++ b/queue-6.12/netfilter-nf_conncount-make-nf_conncount_gc_list-to-.patch @@ -0,0 +1,93 @@ +From 598fcb8cc83bcb67a447c688263daa82d71266ad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 21 Nov 2025 01:14:31 +0100 +Subject: netfilter: nf_conncount: make nf_conncount_gc_list() to disable BH + +From: Fernando Fernandez Mancera + +[ Upstream commit c0362b5748282e22fa1592a8d3474f726ad964c2 ] + +For convenience when performing GC over the connection list, make +nf_conncount_gc_list() to disable BH. This unifies the behavior with +nf_conncount_add() and nf_conncount_count(). + +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: 21d033e47273 ("netfilter: nf_conncount: increase the connection clean up limit to 64") +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_conncount.c | 24 +++++++++++++++++------- + net/netfilter/nft_connlimit.c | 7 +------ + 2 files changed, 18 insertions(+), 13 deletions(-) + +diff --git a/net/netfilter/nf_conncount.c b/net/netfilter/nf_conncount.c +index 828d5c64c68a3..8487808c87614 100644 +--- a/net/netfilter/nf_conncount.c ++++ b/net/netfilter/nf_conncount.c +@@ -282,8 +282,8 @@ void nf_conncount_list_init(struct nf_conncount_list *list) + EXPORT_SYMBOL_GPL(nf_conncount_list_init); + + /* Return true if the list is empty. Must be called with BH disabled. */ +-bool nf_conncount_gc_list(struct net *net, +- struct nf_conncount_list *list) ++static bool __nf_conncount_gc_list(struct net *net, ++ struct nf_conncount_list *list) + { + const struct nf_conntrack_tuple_hash *found; + struct nf_conncount_tuple *conn, *conn_n; +@@ -295,10 +295,6 @@ bool nf_conncount_gc_list(struct net *net, + if ((u32)jiffies == READ_ONCE(list->last_gc)) + return false; + +- /* don't bother if other cpu is already doing GC */ +- if (!spin_trylock(&list->list_lock)) +- return false; +- + list_for_each_entry_safe(conn, conn_n, &list->head, node) { + found = find_or_evict(net, list, conn); + if (IS_ERR(found)) { +@@ -327,7 +323,21 @@ bool nf_conncount_gc_list(struct net *net, + if (!list->count) + ret = true; + list->last_gc = (u32)jiffies; +- spin_unlock(&list->list_lock); ++ ++ return ret; ++} ++ ++bool nf_conncount_gc_list(struct net *net, ++ struct nf_conncount_list *list) ++{ ++ bool ret; ++ ++ /* don't bother if other cpu is already doing GC */ ++ if (!spin_trylock_bh(&list->list_lock)) ++ return false; ++ ++ ret = __nf_conncount_gc_list(net, list); ++ spin_unlock_bh(&list->list_lock); + + return ret; + } +diff --git a/net/netfilter/nft_connlimit.c b/net/netfilter/nft_connlimit.c +index 83a7d5769396c..5dd50b3ab5a45 100644 +--- a/net/netfilter/nft_connlimit.c ++++ b/net/netfilter/nft_connlimit.c +@@ -232,13 +232,8 @@ static void nft_connlimit_destroy_clone(const struct nft_ctx *ctx, + static bool nft_connlimit_gc(struct net *net, const struct nft_expr *expr) + { + struct nft_connlimit *priv = nft_expr_priv(expr); +- bool ret; + +- local_bh_disable(); +- ret = nf_conncount_gc_list(net, priv->list); +- local_bh_enable(); +- +- return ret; ++ return nf_conncount_gc_list(net, priv->list); + } + + static struct nft_expr_type nft_connlimit_type; +-- +2.51.0 + diff --git a/queue-6.12/netfilter-nf_tables-reset-table-validation-state-on-.patch b/queue-6.12/netfilter-nf_tables-reset-table-validation-state-on-.patch new file mode 100644 index 0000000000..e2280b5504 --- /dev/null +++ b/queue-6.12/netfilter-nf_tables-reset-table-validation-state-on-.patch @@ -0,0 +1,59 @@ +From baee83d7a659683d424680a821b259c809355c3b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 12:26:54 +0100 +Subject: netfilter: nf_tables: reset table validation state on abort + +From: Florian Westphal + +[ Upstream commit 6f93616a7323d646d18db9c09f147e453b40fdd7 ] + +If a transaction fails the final validation in the commit hook, the table +validation state is changed to NFT_VALIDATE_DO and a replay of the batch is +performed. Every rule insert will then do a graph validation. + +This is much slower, but provides better error reporting to the user +because we can point at the rule that introduces the validation issue. + +Without this reset the affected table(s) remain in full validation mode, +i.e. on next transaction we start with slow-mode. + +This makes the next transaction after a failed incremental update very slow: + + # time iptables-restore < /tmp/ruleset + real 0m0.496s [..] + # time iptables -A CALLEE -j CALLER + iptables v1.8.11 (nf_tables): RULE_APPEND failed (Too many links): rule in chain CALLEE + real 0m0.022s [..] + # time iptables-restore < /tmp/ruleset + real 1m22.355s [..] + +After this patch, 2nd iptables-restore is back to ~0.5s. + +Fixes: 9a32e9850686 ("netfilter: nf_tables: don't write table validation state without mutex") +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_tables_api.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c +index 3bf88c137868a..42105628d4b98 100644 +--- a/net/netfilter/nf_tables_api.c ++++ b/net/netfilter/nf_tables_api.c +@@ -11071,6 +11071,13 @@ static int nf_tables_abort(struct net *net, struct sk_buff *skb, + ret = __nf_tables_abort(net, action); + nft_gc_seq_end(nft_net, gc_seq); + ++ if (action == NFNL_ABORT_NONE) { ++ struct nft_table *table; ++ ++ list_for_each_entry(table, &nft_net->tables, list) ++ table->validate_state = NFT_VALIDATE_SKIP; ++ } ++ + WARN_ON_ONCE(!list_empty(&nft_net->commit_list)); + + /* module autoload needs to happen after GC sequence update because it +-- +2.51.0 + diff --git a/queue-6.12/netfilter-nfnetlink_queue-do-shared-unconfirmed-chec.patch b/queue-6.12/netfilter-nfnetlink_queue-do-shared-unconfirmed-chec.patch new file mode 100644 index 0000000000..bd73113a35 --- /dev/null +++ b/queue-6.12/netfilter-nfnetlink_queue-do-shared-unconfirmed-chec.patch @@ -0,0 +1,246 @@ +From e284d826df411f8fc17b18bf4a90240c3d338969 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 20 Nov 2025 17:17:06 +0100 +Subject: netfilter: nfnetlink_queue: do shared-unconfirmed check before + segmentation + +From: Florian Westphal + +[ Upstream commit 207b3ebacb6113acaaec0d171d5307032c690004 ] + +Ulrich reports a regression with nfqueue: + +If an application did not set the 'F_GSO' capability flag and a gso +packet with an unconfirmed nf_conn entry is received all packets are +now dropped instead of queued, because the check happens after +skb_gso_segment(). In that case, we did have exclusive ownership +of the skb and its associated conntrack entry. The elevated use +count is due to skb_clone happening via skb_gso_segment(). + +Move the check so that its peformed vs. the aggregated packet. + +Then, annotate the individual segments except the first one so we +can do a 2nd check at reinject time. + +For the normal case, where userspace does in-order reinjects, this avoids +packet drops: first reinjected segment continues traversal and confirms +entry, remaining segments observe the confirmed entry. + +While at it, simplify nf_ct_drop_unconfirmed(): We only care about +unconfirmed entries with a refcnt > 1, there is no need to special-case +dying entries. + +This only happens with UDP. With TCP, the only unconfirmed packet will +be the TCP SYN, those aren't aggregated by GRO. + +Next patch adds a udpgro test case to cover this scenario. + +Reported-by: Ulrich Weber +Fixes: 7d8dc1c7be8d ("netfilter: nf_queue: drop packets with cloned unconfirmed conntracks") +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + include/net/netfilter/nf_queue.h | 1 + + net/netfilter/nfnetlink_queue.c | 123 +++++++++++++++++++------------ + 2 files changed, 75 insertions(+), 49 deletions(-) + +diff --git a/include/net/netfilter/nf_queue.h b/include/net/netfilter/nf_queue.h +index e6803831d6af5..45eb26b2e95b3 100644 +--- a/include/net/netfilter/nf_queue.h ++++ b/include/net/netfilter/nf_queue.h +@@ -21,6 +21,7 @@ struct nf_queue_entry { + struct net_device *physout; + #endif + struct nf_hook_state state; ++ bool nf_ct_is_unconfirmed; + u16 size; /* sizeof(entry) + saved route keys */ + u16 queue_num; + +diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c +index fb074e95a767d..af35dbc19864a 100644 +--- a/net/netfilter/nfnetlink_queue.c ++++ b/net/netfilter/nfnetlink_queue.c +@@ -438,6 +438,34 @@ static void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict) + nf_queue_entry_free(entry); + } + ++/* return true if the entry has an unconfirmed conntrack attached that isn't owned by us ++ * exclusively. ++ */ ++static bool nf_ct_drop_unconfirmed(const struct nf_queue_entry *entry, bool *is_unconfirmed) ++{ ++#if IS_ENABLED(CONFIG_NF_CONNTRACK) ++ struct nf_conn *ct = (void *)skb_nfct(entry->skb); ++ ++ if (!ct || nf_ct_is_confirmed(ct)) ++ return false; ++ ++ if (is_unconfirmed) ++ *is_unconfirmed = true; ++ ++ /* in some cases skb_clone() can occur after initial conntrack ++ * pickup, but conntrack assumes exclusive skb->_nfct ownership for ++ * unconfirmed entries. ++ * ++ * This happens for br_netfilter and with ip multicast routing. ++ * This can't be solved with serialization here because one clone ++ * could have been queued for local delivery or could be transmitted ++ * in parallel on another CPU. ++ */ ++ return refcount_read(&ct->ct_general.use) > 1; ++#endif ++ return false; ++} ++ + static void nfqnl_reinject(struct nf_queue_entry *entry, unsigned int verdict) + { + const struct nf_ct_hook *ct_hook; +@@ -465,6 +493,24 @@ static void nfqnl_reinject(struct nf_queue_entry *entry, unsigned int verdict) + break; + } + } ++ ++ if (verdict != NF_DROP && entry->nf_ct_is_unconfirmed) { ++ /* If first queued segment was already reinjected then ++ * there is a good chance the ct entry is now confirmed. ++ * ++ * Handle the rare cases: ++ * - out-of-order verdict ++ * - threaded userspace reinjecting in parallel ++ * - first segment was dropped ++ * ++ * In all of those cases we can't handle this packet ++ * because we can't be sure that another CPU won't modify ++ * nf_conn->ext in parallel which isn't allowed. ++ */ ++ if (nf_ct_drop_unconfirmed(entry, NULL)) ++ verdict = NF_DROP; ++ } ++ + nf_reinject(entry, verdict); + } + +@@ -892,49 +938,6 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue, + return NULL; + } + +-static bool nf_ct_drop_unconfirmed(const struct nf_queue_entry *entry) +-{ +-#if IS_ENABLED(CONFIG_NF_CONNTRACK) +- static const unsigned long flags = IPS_CONFIRMED | IPS_DYING; +- struct nf_conn *ct = (void *)skb_nfct(entry->skb); +- unsigned long status; +- unsigned int use; +- +- if (!ct) +- return false; +- +- status = READ_ONCE(ct->status); +- if ((status & flags) == IPS_DYING) +- return true; +- +- if (status & IPS_CONFIRMED) +- return false; +- +- /* in some cases skb_clone() can occur after initial conntrack +- * pickup, but conntrack assumes exclusive skb->_nfct ownership for +- * unconfirmed entries. +- * +- * This happens for br_netfilter and with ip multicast routing. +- * We can't be solved with serialization here because one clone could +- * have been queued for local delivery. +- */ +- use = refcount_read(&ct->ct_general.use); +- if (likely(use == 1)) +- return false; +- +- /* Can't decrement further? Exclusive ownership. */ +- if (!refcount_dec_not_one(&ct->ct_general.use)) +- return false; +- +- skb_set_nfct(entry->skb, 0); +- /* No nf_ct_put(): we already decremented .use and it cannot +- * drop down to 0. +- */ +- return true; +-#endif +- return false; +-} +- + static int + __nfqnl_enqueue_packet(struct net *net, struct nfqnl_instance *queue, + struct nf_queue_entry *entry) +@@ -951,9 +954,6 @@ __nfqnl_enqueue_packet(struct net *net, struct nfqnl_instance *queue, + } + spin_lock_bh(&queue->lock); + +- if (nf_ct_drop_unconfirmed(entry)) +- goto err_out_free_nskb; +- + if (queue->queue_total >= queue->queue_maxlen) + goto err_out_queue_drop; + +@@ -996,7 +996,6 @@ __nfqnl_enqueue_packet(struct net *net, struct nfqnl_instance *queue, + else + net_warn_ratelimited("nf_queue: hash insert failed: %d\n", err); + } +-err_out_free_nskb: + kfree_skb(nskb); + err_out_unlock: + spin_unlock_bh(&queue->lock); +@@ -1075,9 +1074,10 @@ __nfqnl_enqueue_packet_gso(struct net *net, struct nfqnl_instance *queue, + static int + nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) + { +- unsigned int queued; +- struct nfqnl_instance *queue; + struct sk_buff *skb, *segs, *nskb; ++ bool ct_is_unconfirmed = false; ++ struct nfqnl_instance *queue; ++ unsigned int queued; + int err = -ENOBUFS; + struct net *net = entry->state.net; + struct nfnl_queue_net *q = nfnl_queue_pernet(net); +@@ -1101,6 +1101,15 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) + break; + } + ++ /* Check if someone already holds another reference to ++ * unconfirmed ct. If so, we cannot queue the skb: ++ * concurrent modifications of nf_conn->ext are not ++ * allowed and we can't know if another CPU isn't ++ * processing the same nf_conn entry in parallel. ++ */ ++ if (nf_ct_drop_unconfirmed(entry, &ct_is_unconfirmed)) ++ return -EINVAL; ++ + if (!skb_is_gso(skb) || ((queue->flags & NFQA_CFG_F_GSO) && !skb_is_gso_sctp(skb))) + return __nfqnl_enqueue_packet(net, queue, entry); + +@@ -1114,7 +1123,23 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) + goto out_err; + queued = 0; + err = 0; ++ + skb_list_walk_safe(segs, segs, nskb) { ++ if (ct_is_unconfirmed && queued > 0) { ++ /* skb_gso_segment() increments the ct refcount. ++ * This is a problem for unconfirmed (not in hash) ++ * entries, those can race when reinjections happen ++ * in parallel. ++ * ++ * Annotate this for all queued entries except the ++ * first one. ++ * ++ * As long as the first one is reinjected first it ++ * will do the confirmation for us. ++ */ ++ entry->nf_ct_is_unconfirmed = ct_is_unconfirmed; ++ } ++ + if (err == 0) + err = __nfqnl_enqueue_packet_gso(net, queue, + segs, entry); +-- +2.51.0 + diff --git a/queue-6.12/netfilter-nfnetlink_queue-optimize-verdict-lookup-wi.patch b/queue-6.12/netfilter-nfnetlink_queue-optimize-verdict-lookup-wi.patch new file mode 100644 index 0000000000..befa9c209b --- /dev/null +++ b/queue-6.12/netfilter-nfnetlink_queue-optimize-verdict-lookup-wi.patch @@ -0,0 +1,318 @@ +From cdfc24a5331733141f78ac0ec7604b21caecbbed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 14:09:30 -0800 +Subject: netfilter: nfnetlink_queue: optimize verdict lookup with hash table + +From: Scott Mitchell + +[ Upstream commit e19079adcd26a25d7d3e586b1837493361fdf8b6 ] + +The current implementation uses a linear list to find queued packets by +ID when processing verdicts from userspace. With large queue depths and +out-of-order verdicting, this O(n) lookup becomes a significant +bottleneck, causing userspace verdict processing to dominate CPU time. + +Replace the linear search with a hash table for O(1) average-case +packet lookup by ID. A global rhashtable spanning all network +namespaces attributes hash bucket memory to kernel but is subject to +fixed upper bound. + +Signed-off-by: Scott Mitchell +Signed-off-by: Florian Westphal +Stable-dep-of: 207b3ebacb61 ("netfilter: nfnetlink_queue: do shared-unconfirmed check before segmentation") +Signed-off-by: Sasha Levin +--- + include/net/netfilter/nf_queue.h | 3 + + net/netfilter/nfnetlink_queue.c | 146 ++++++++++++++++++++++++------- + 2 files changed, 119 insertions(+), 30 deletions(-) + +diff --git a/include/net/netfilter/nf_queue.h b/include/net/netfilter/nf_queue.h +index 4aeffddb75861..e6803831d6af5 100644 +--- a/include/net/netfilter/nf_queue.h ++++ b/include/net/netfilter/nf_queue.h +@@ -6,11 +6,13 @@ + #include + #include + #include ++#include + #include + + /* Each queued (to userspace) skbuff has one of these. */ + struct nf_queue_entry { + struct list_head list; ++ struct rhash_head hash_node; + struct sk_buff *skb; + unsigned int id; + unsigned int hook_index; /* index in hook_entries->hook[] */ +@@ -20,6 +22,7 @@ struct nf_queue_entry { + #endif + struct nf_hook_state state; + u16 size; /* sizeof(entry) + saved route keys */ ++ u16 queue_num; + + /* extra space to store route keys */ + }; +diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c +index d2773ce9b5853..fb074e95a767d 100644 +--- a/net/netfilter/nfnetlink_queue.c ++++ b/net/netfilter/nfnetlink_queue.c +@@ -30,6 +30,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -47,6 +49,8 @@ + #endif + + #define NFQNL_QMAX_DEFAULT 1024 ++#define NFQNL_HASH_MIN 1024 ++#define NFQNL_HASH_MAX 1048576 + + /* We're using struct nlattr which has 16bit nla_len. Note that nla_len + * includes the header length. Thus, the maximum packet length that we +@@ -56,6 +60,26 @@ + */ + #define NFQNL_MAX_COPY_RANGE (0xffff - NLA_HDRLEN) + ++/* Composite key for packet lookup: (net, queue_num, packet_id) */ ++struct nfqnl_packet_key { ++ possible_net_t net; ++ u32 packet_id; ++ u16 queue_num; ++} __aligned(sizeof(u32)); /* jhash2 requires 32-bit alignment */ ++ ++/* Global rhashtable - one for entire system, all netns */ ++static struct rhashtable nfqnl_packet_map __read_mostly; ++ ++/* Helper to initialize composite key */ ++static inline void nfqnl_init_key(struct nfqnl_packet_key *key, ++ struct net *net, u32 packet_id, u16 queue_num) ++{ ++ memset(key, 0, sizeof(*key)); ++ write_pnet(&key->net, net); ++ key->packet_id = packet_id; ++ key->queue_num = queue_num; ++} ++ + struct nfqnl_instance { + struct hlist_node hlist; /* global list of queues */ + struct rcu_head rcu; +@@ -100,6 +124,39 @@ static inline u_int8_t instance_hashfn(u_int16_t queue_num) + return ((queue_num >> 8) ^ queue_num) % INSTANCE_BUCKETS; + } + ++/* Extract composite key from nf_queue_entry for hashing */ ++static u32 nfqnl_packet_obj_hashfn(const void *data, u32 len, u32 seed) ++{ ++ const struct nf_queue_entry *entry = data; ++ struct nfqnl_packet_key key; ++ ++ nfqnl_init_key(&key, entry->state.net, entry->id, entry->queue_num); ++ ++ return jhash2((u32 *)&key, sizeof(key) / sizeof(u32), seed); ++} ++ ++/* Compare stack-allocated key against entry */ ++static int nfqnl_packet_obj_cmpfn(struct rhashtable_compare_arg *arg, ++ const void *obj) ++{ ++ const struct nfqnl_packet_key *key = arg->key; ++ const struct nf_queue_entry *entry = obj; ++ ++ return !net_eq(entry->state.net, read_pnet(&key->net)) || ++ entry->queue_num != key->queue_num || ++ entry->id != key->packet_id; ++} ++ ++static const struct rhashtable_params nfqnl_rhashtable_params = { ++ .head_offset = offsetof(struct nf_queue_entry, hash_node), ++ .key_len = sizeof(struct nfqnl_packet_key), ++ .obj_hashfn = nfqnl_packet_obj_hashfn, ++ .obj_cmpfn = nfqnl_packet_obj_cmpfn, ++ .automatic_shrinking = true, ++ .min_size = NFQNL_HASH_MIN, ++ .max_size = NFQNL_HASH_MAX, ++}; ++ + static struct nfqnl_instance * + instance_lookup(struct nfnl_queue_net *q, u_int16_t queue_num) + { +@@ -191,33 +248,45 @@ instance_destroy(struct nfnl_queue_net *q, struct nfqnl_instance *inst) + spin_unlock(&q->instances_lock); + } + +-static inline void ++static int + __enqueue_entry(struct nfqnl_instance *queue, struct nf_queue_entry *entry) + { +- list_add_tail(&entry->list, &queue->queue_list); +- queue->queue_total++; ++ int err; ++ ++ entry->queue_num = queue->queue_num; ++ ++ err = rhashtable_insert_fast(&nfqnl_packet_map, &entry->hash_node, ++ nfqnl_rhashtable_params); ++ if (unlikely(err)) ++ return err; ++ ++ list_add_tail(&entry->list, &queue->queue_list); ++ queue->queue_total++; ++ ++ return 0; + } + + static void + __dequeue_entry(struct nfqnl_instance *queue, struct nf_queue_entry *entry) + { ++ rhashtable_remove_fast(&nfqnl_packet_map, &entry->hash_node, ++ nfqnl_rhashtable_params); + list_del(&entry->list); + queue->queue_total--; + } + + static struct nf_queue_entry * +-find_dequeue_entry(struct nfqnl_instance *queue, unsigned int id) ++find_dequeue_entry(struct nfqnl_instance *queue, unsigned int id, ++ struct net *net) + { +- struct nf_queue_entry *entry = NULL, *i; ++ struct nfqnl_packet_key key; ++ struct nf_queue_entry *entry; + +- spin_lock_bh(&queue->lock); ++ nfqnl_init_key(&key, net, id, queue->queue_num); + +- list_for_each_entry(i, &queue->queue_list, list) { +- if (i->id == id) { +- entry = i; +- break; +- } +- } ++ spin_lock_bh(&queue->lock); ++ entry = rhashtable_lookup_fast(&nfqnl_packet_map, &key, ++ nfqnl_rhashtable_params); + + if (entry) + __dequeue_entry(queue, entry); +@@ -407,8 +476,7 @@ nfqnl_flush(struct nfqnl_instance *queue, nfqnl_cmpfn cmpfn, unsigned long data) + spin_lock_bh(&queue->lock); + list_for_each_entry_safe(entry, next, &queue->queue_list, list) { + if (!cmpfn || cmpfn(entry, data)) { +- list_del(&entry->list); +- queue->queue_total--; ++ __dequeue_entry(queue, entry); + nfqnl_reinject(entry, NF_DROP); + } + } +@@ -886,23 +954,23 @@ __nfqnl_enqueue_packet(struct net *net, struct nfqnl_instance *queue, + if (nf_ct_drop_unconfirmed(entry)) + goto err_out_free_nskb; + +- if (queue->queue_total >= queue->queue_maxlen) { +- if (queue->flags & NFQA_CFG_F_FAIL_OPEN) { +- failopen = 1; +- err = 0; +- } else { +- queue->queue_dropped++; +- net_warn_ratelimited("nf_queue: full at %d entries, dropping packets(s)\n", +- queue->queue_total); +- } +- goto err_out_free_nskb; +- } ++ if (queue->queue_total >= queue->queue_maxlen) ++ goto err_out_queue_drop; ++ + entry->id = ++queue->id_sequence; + *packet_id_ptr = htonl(entry->id); + ++ /* Insert into hash BEFORE unicast. If failure don't send to userspace. */ ++ err = __enqueue_entry(queue, entry); ++ if (unlikely(err)) ++ goto err_out_queue_drop; ++ + /* nfnetlink_unicast will either free the nskb or add it to a socket */ + err = nfnetlink_unicast(nskb, net, queue->peer_portid); + if (err < 0) { ++ /* Unicast failed - remove entry we just inserted */ ++ __dequeue_entry(queue, entry); ++ + if (queue->flags & NFQA_CFG_F_FAIL_OPEN) { + failopen = 1; + err = 0; +@@ -912,11 +980,22 @@ __nfqnl_enqueue_packet(struct net *net, struct nfqnl_instance *queue, + goto err_out_unlock; + } + +- __enqueue_entry(queue, entry); +- + spin_unlock_bh(&queue->lock); + return 0; + ++err_out_queue_drop: ++ if (queue->flags & NFQA_CFG_F_FAIL_OPEN) { ++ failopen = 1; ++ err = 0; ++ } else { ++ queue->queue_dropped++; ++ ++ if (queue->queue_total >= queue->queue_maxlen) ++ net_warn_ratelimited("nf_queue: full at %d entries, dropping packets(s)\n", ++ queue->queue_total); ++ else ++ net_warn_ratelimited("nf_queue: hash insert failed: %d\n", err); ++ } + err_out_free_nskb: + kfree_skb(nskb); + err_out_unlock: +@@ -1428,7 +1507,7 @@ static int nfqnl_recv_verdict(struct sk_buff *skb, const struct nfnl_info *info, + + verdict = ntohl(vhdr->verdict); + +- entry = find_dequeue_entry(queue, ntohl(vhdr->id)); ++ entry = find_dequeue_entry(queue, ntohl(vhdr->id), info->net); + if (entry == NULL) + return -ENOENT; + +@@ -1779,10 +1858,14 @@ static int __init nfnetlink_queue_init(void) + { + int status; + ++ status = rhashtable_init(&nfqnl_packet_map, &nfqnl_rhashtable_params); ++ if (status < 0) ++ return status; ++ + status = register_pernet_subsys(&nfnl_queue_net_ops); + if (status < 0) { + pr_err("failed to register pernet ops\n"); +- goto out; ++ goto cleanup_rhashtable; + } + + netlink_register_notifier(&nfqnl_rtnl_notifier); +@@ -1807,7 +1890,8 @@ static int __init nfnetlink_queue_init(void) + cleanup_netlink_notifier: + netlink_unregister_notifier(&nfqnl_rtnl_notifier); + unregister_pernet_subsys(&nfnl_queue_net_ops); +-out: ++cleanup_rhashtable: ++ rhashtable_destroy(&nfqnl_packet_map); + return status; + } + +@@ -1819,6 +1903,8 @@ static void __exit nfnetlink_queue_fini(void) + netlink_unregister_notifier(&nfqnl_rtnl_notifier); + unregister_pernet_subsys(&nfnl_queue_net_ops); + ++ rhashtable_destroy(&nfqnl_packet_map); ++ + rcu_barrier(); /* Wait for completion of call_rcu()'s */ + } + +-- +2.51.0 + diff --git a/queue-6.12/netfilter-nft_compat-add-more-restrictions-on-netlin.patch b/queue-6.12/netfilter-nft_compat-add-more-restrictions-on-netlin.patch new file mode 100644 index 0000000000..829a9bf245 --- /dev/null +++ b/queue-6.12/netfilter-nft_compat-add-more-restrictions-on-netlin.patch @@ -0,0 +1,71 @@ +From 70abd8fbd55d56a02d480a28c0b20e0a9d44a0a7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 19 Aug 2022 16:16:07 +0200 +Subject: netfilter: nft_compat: add more restrictions on netlink attributes + +From: Florian Westphal + +[ Upstream commit cda26c645946b08f070f20c166d4736767e4a805 ] + +As far as I can see nothing bad can happen when NFTA_TARGET/MATCH_NAME +are too large because this calls x_tables helpers which check for the +length, but it seems better to already reject it during netlink parsing. + +Rest of the changes avoid silent u8/u16 truncations. + +For _TYPE, its expected to be only 1 or 0. In x_tables world, this +variable is set by kernel, for IPT_SO_GET_REVISION_TARGET its 1, for +all others its set to 0. + +As older versions of nf_tables permitted any value except 1 to mean 'match', +keep this as-is but sanitize the value for consistency. + +Fixes: 0ca743a55991 ("netfilter: nf_tables: add compatibility layer for x_tables") +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_compat.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/net/netfilter/nft_compat.c b/net/netfilter/nft_compat.c +index 72711d62fddfa..08f620311b03f 100644 +--- a/net/netfilter/nft_compat.c ++++ b/net/netfilter/nft_compat.c +@@ -134,7 +134,8 @@ static void nft_target_eval_bridge(const struct nft_expr *expr, + } + + static const struct nla_policy nft_target_policy[NFTA_TARGET_MAX + 1] = { +- [NFTA_TARGET_NAME] = { .type = NLA_NUL_STRING }, ++ [NFTA_TARGET_NAME] = { .type = NLA_NUL_STRING, ++ .len = XT_EXTENSION_MAXNAMELEN, }, + [NFTA_TARGET_REV] = NLA_POLICY_MAX(NLA_BE32, 255), + [NFTA_TARGET_INFO] = { .type = NLA_BINARY }, + }; +@@ -434,7 +435,8 @@ static void nft_match_eval(const struct nft_expr *expr, + } + + static const struct nla_policy nft_match_policy[NFTA_MATCH_MAX + 1] = { +- [NFTA_MATCH_NAME] = { .type = NLA_NUL_STRING }, ++ [NFTA_MATCH_NAME] = { .type = NLA_NUL_STRING, ++ .len = XT_EXTENSION_MAXNAMELEN }, + [NFTA_MATCH_REV] = NLA_POLICY_MAX(NLA_BE32, 255), + [NFTA_MATCH_INFO] = { .type = NLA_BINARY }, + }; +@@ -693,7 +695,12 @@ static int nfnl_compat_get_rcu(struct sk_buff *skb, + + name = nla_data(tb[NFTA_COMPAT_NAME]); + rev = ntohl(nla_get_be32(tb[NFTA_COMPAT_REV])); +- target = ntohl(nla_get_be32(tb[NFTA_COMPAT_TYPE])); ++ /* x_tables api checks for 'target == 1' to mean target, ++ * everything else means 'match'. ++ * In x_tables world, the number is set by kernel, not ++ * userspace. ++ */ ++ target = nla_get_be32(tb[NFTA_COMPAT_TYPE]) == htonl(1); + + switch(family) { + case AF_INET: +-- +2.51.0 + diff --git a/queue-6.12/netfilter-nft_counter-fix-reset-of-counters-on-32bit.patch b/queue-6.12/netfilter-nft_counter-fix-reset-of-counters-on-32bit.patch new file mode 100644 index 0000000000..9faa636622 --- /dev/null +++ b/queue-6.12/netfilter-nft_counter-fix-reset-of-counters-on-32bit.patch @@ -0,0 +1,75 @@ +From edc531bbb32248d819ad441346d3c1c81834f2a0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 14:48:30 +0100 +Subject: netfilter: nft_counter: fix reset of counters on 32bit archs + +From: Anders Grahn + +[ Upstream commit 1e13f27e0675552161ab1778be9a23a636dde8a7 ] + +nft_counter_reset() calls u64_stats_add() with a negative value to reset +the counter. This will work on 64bit archs, hence the negative value +added will wrap as a 64bit value which then can wrap the stat counter as +well. + +On 32bit archs, the added negative value will wrap as a 32bit value and +_not_ wrapping the stat counter properly. In most cases, this would just +lead to a very large 32bit value being added to the stat counter. + +Fix by introducing u64_stats_sub(). + +Fixes: 4a1d3acd6ea8 ("netfilter: nft_counter: Use u64_stats_t for statistic.") +Signed-off-by: Anders Grahn +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + include/linux/u64_stats_sync.h | 10 ++++++++++ + net/netfilter/nft_counter.c | 4 ++-- + 2 files changed, 12 insertions(+), 2 deletions(-) + +diff --git a/include/linux/u64_stats_sync.h b/include/linux/u64_stats_sync.h +index 457879938fc19..3366090a86bd2 100644 +--- a/include/linux/u64_stats_sync.h ++++ b/include/linux/u64_stats_sync.h +@@ -89,6 +89,11 @@ static inline void u64_stats_add(u64_stats_t *p, unsigned long val) + local64_add(val, &p->v); + } + ++static inline void u64_stats_sub(u64_stats_t *p, s64 val) ++{ ++ local64_sub(val, &p->v); ++} ++ + static inline void u64_stats_inc(u64_stats_t *p) + { + local64_inc(&p->v); +@@ -130,6 +135,11 @@ static inline void u64_stats_add(u64_stats_t *p, unsigned long val) + p->v += val; + } + ++static inline void u64_stats_sub(u64_stats_t *p, s64 val) ++{ ++ p->v -= val; ++} ++ + static inline void u64_stats_inc(u64_stats_t *p) + { + p->v++; +diff --git a/net/netfilter/nft_counter.c b/net/netfilter/nft_counter.c +index cc73253294963..0d70325280cc5 100644 +--- a/net/netfilter/nft_counter.c ++++ b/net/netfilter/nft_counter.c +@@ -117,8 +117,8 @@ static void nft_counter_reset(struct nft_counter_percpu_priv *priv, + nft_sync = this_cpu_ptr(&nft_counter_sync); + + u64_stats_update_begin(nft_sync); +- u64_stats_add(&this_cpu->packets, -total->packets); +- u64_stats_add(&this_cpu->bytes, -total->bytes); ++ u64_stats_sub(&this_cpu->packets, total->packets); ++ u64_stats_sub(&this_cpu->bytes, total->bytes); + u64_stats_update_end(nft_sync); + + local_bh_enable(); +-- +2.51.0 + diff --git a/queue-6.12/netfilter-nft_set_hash-fix-get-operation-on-big-endi.patch b/queue-6.12/netfilter-nft_set_hash-fix-get-operation-on-big-endi.patch new file mode 100644 index 0000000000..a312a3b9dc --- /dev/null +++ b/queue-6.12/netfilter-nft_set_hash-fix-get-operation-on-big-endi.patch @@ -0,0 +1,57 @@ +From e81ab864b25a6d2d401d12fa6f49937204c116a9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 20:13:45 +0100 +Subject: netfilter: nft_set_hash: fix get operation on big endian + +From: Florian Westphal + +[ Upstream commit 2f635adbe2642d398a0be3ab245accd2987be0c3 ] + +tests/shell/testcases/packetpath/set_match_nomatch_hash_fast +fails on big endian with: + +Error: Could not process rule: No such file or directory +reset element ip test s { 244.147.90.126 } +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Fatal: Cannot fetch element "244.147.90.126" + +... because the wrong bucket is searched, jhash() and jhash1_word are +not interchangeable on big endian. + +Fixes: 3b02b0adc242 ("netfilter: nft_set_hash: fix lookups with fixed size hash on big endian") +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_set_hash.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/net/netfilter/nft_set_hash.c b/net/netfilter/nft_set_hash.c +index 900eddb93dcc8..e87398cefef00 100644 +--- a/net/netfilter/nft_set_hash.c ++++ b/net/netfilter/nft_set_hash.c +@@ -527,15 +527,20 @@ static struct nft_elem_priv * + nft_hash_get(const struct net *net, const struct nft_set *set, + const struct nft_set_elem *elem, unsigned int flags) + { ++ const u32 *key = (const u32 *)&elem->key.val; + struct nft_hash *priv = nft_set_priv(set); + u8 genmask = nft_genmask_cur(net); + struct nft_hash_elem *he; + u32 hash; + +- hash = jhash(elem->key.val.data, set->klen, priv->seed); ++ if (set->klen == 4) ++ hash = jhash_1word(*key, priv->seed); ++ else ++ hash = jhash(key, set->klen, priv->seed); ++ + hash = reciprocal_scale(hash, priv->buckets); + hlist_for_each_entry_rcu(he, &priv->table[hash], node) { +- if (!memcmp(nft_set_ext_key(&he->ext), elem->key.val.data, set->klen) && ++ if (!memcmp(nft_set_ext_key(&he->ext), key, set->klen) && + nft_set_elem_active(&he->ext, genmask)) + return &he->priv; + } +-- +2.51.0 + diff --git a/queue-6.12/netfilter-nft_set_rbtree-check-for-partial-overlaps-.patch b/queue-6.12/netfilter-nft_set_rbtree-check-for-partial-overlaps-.patch new file mode 100644 index 0000000000..e4bf644fdf --- /dev/null +++ b/queue-6.12/netfilter-nft_set_rbtree-check-for-partial-overlaps-.patch @@ -0,0 +1,90 @@ +From 8dd332773ca9bc7310b3768c21bb67bed22aaf9d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 13:33:44 +0100 +Subject: netfilter: nft_set_rbtree: check for partial overlaps in anonymous + sets + +From: Pablo Neira Ayuso + +[ Upstream commit 4780ec142cbb24b794129d3080eee5cac2943ffc ] + +Userspace provides an optimized representation in case intervals are +adjacent, where the end element is omitted. + +The existing partial overlap detection logic skips anonymous set checks +on start elements for this reason. + +However, it is possible to add intervals that overlap to this anonymous +where two start elements with the same, eg. A-B, A-C where C < B. + + start end + A B + start end + A C + +Restore the check on overlapping start elements to report an overlap. + +Fixes: c9e6978e2725 ("netfilter: nft_set_rbtree: Switch to node list walk for overlap detection") +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_set_rbtree.c | 30 +++++++++++++++++++++++++----- + 1 file changed, 25 insertions(+), 5 deletions(-) + +diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c +index 0bbce4505b977..48ad51a448e7b 100644 +--- a/net/netfilter/nft_set_rbtree.c ++++ b/net/netfilter/nft_set_rbtree.c +@@ -309,11 +309,23 @@ static bool nft_rbtree_update_first(const struct nft_set *set, + return false; + } + ++/* Only for anonymous sets which do not allow updates, all element are active. */ ++static struct nft_rbtree_elem *nft_rbtree_prev_active(struct nft_rbtree_elem *rbe) ++{ ++ struct rb_node *node; ++ ++ node = rb_prev(&rbe->node); ++ if (!node) ++ return NULL; ++ ++ return rb_entry(node, struct nft_rbtree_elem, node); ++} ++ + static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set, + struct nft_rbtree_elem *new, + struct nft_elem_priv **elem_priv) + { +- struct nft_rbtree_elem *rbe, *rbe_le = NULL, *rbe_ge = NULL; ++ struct nft_rbtree_elem *rbe, *rbe_le = NULL, *rbe_ge = NULL, *rbe_prev; + struct rb_node *node, *next, *parent, **p, *first = NULL; + struct nft_rbtree *priv = nft_set_priv(set); + u8 cur_genmask = nft_genmask_cur(net); +@@ -451,11 +463,19 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set, + /* - new start element with existing closest, less or equal key value + * being a start element: partial overlap, reported as -ENOTEMPTY. + * Anonymous sets allow for two consecutive start element since they +- * are constant, skip them to avoid bogus overlap reports. ++ * are constant, but validate that this new start element does not ++ * sit in between an existing start and end elements: partial overlap, ++ * reported as -ENOTEMPTY. + */ +- if (!nft_set_is_anonymous(set) && rbe_le && +- nft_rbtree_interval_start(rbe_le) && nft_rbtree_interval_start(new)) +- return -ENOTEMPTY; ++ if (rbe_le && ++ nft_rbtree_interval_start(rbe_le) && nft_rbtree_interval_start(new)) { ++ if (!nft_set_is_anonymous(set)) ++ return -ENOTEMPTY; ++ ++ rbe_prev = nft_rbtree_prev_active(rbe_le); ++ if (rbe_prev && nft_rbtree_interval_end(rbe_prev)) ++ return -ENOTEMPTY; ++ } + + /* - new end element with existing closest, less or equal key value + * being a end element: partial overlap, reported as -ENOTEMPTY. +-- +2.51.0 + diff --git a/queue-6.12/netfilter-nft_set_rbtree-fix-bogus-eexist-with-nlm_f.patch b/queue-6.12/netfilter-nft_set_rbtree-fix-bogus-eexist-with-nlm_f.patch new file mode 100644 index 0000000000..5e999f374f --- /dev/null +++ b/queue-6.12/netfilter-nft_set_rbtree-fix-bogus-eexist-with-nlm_f.patch @@ -0,0 +1,80 @@ +From d47b308958ca38d677f15ed8342668ca29a5ae70 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 13:33:43 +0100 +Subject: netfilter: nft_set_rbtree: fix bogus EEXIST with NLM_F_CREATE with + null interval + +From: Pablo Neira Ayuso + +[ Upstream commit 7f9203f41aae8eea74fba6a3370da41332eabcda ] + +Userspace adds a non-matching null element to the kernel for historical +reasons. This null element is added when the set is populated with +elements. Inclusion of this element is conditional, therefore, +userspace needs to dump the set content to check for its presence. + +If the NLM_F_CREATE flag is turned on, this becomes an issue because +kernel bogusly reports EEXIST. + +Add special case to ignore NLM_F_CREATE in this case, therefore, +re-adding the nul-element never fails. + +Fixes: c016c7e45ddf ("netfilter: nf_tables: honor NLM_F_EXCL flag in set element insertion") +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_tables_api.c | 5 +++++ + net/netfilter/nft_set_rbtree.c | 13 +++++++++++++ + 2 files changed, 18 insertions(+) + +diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c +index 42105628d4b98..f10be72021ddd 100644 +--- a/net/netfilter/nf_tables_api.c ++++ b/net/netfilter/nf_tables_api.c +@@ -7322,6 +7322,11 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, + * and an existing one. + */ + err = -EEXIST; ++ } else if (err == -ECANCELED) { ++ /* ECANCELED reports an existing nul-element in ++ * interval sets. ++ */ ++ err = 0; + } + goto err_element_clash; + } +diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c +index b1f04168ec937..0bbce4505b977 100644 +--- a/net/netfilter/nft_set_rbtree.c ++++ b/net/netfilter/nft_set_rbtree.c +@@ -39,6 +39,13 @@ static bool nft_rbtree_interval_start(const struct nft_rbtree_elem *rbe) + return !nft_rbtree_interval_end(rbe); + } + ++static bool nft_rbtree_interval_null(const struct nft_set *set, ++ const struct nft_rbtree_elem *rbe) ++{ ++ return (!memchr_inv(nft_set_ext_key(&rbe->ext), 0, set->klen) && ++ nft_rbtree_interval_end(rbe)); ++} ++ + static int nft_rbtree_cmp(const struct nft_set *set, + const struct nft_rbtree_elem *e1, + const struct nft_rbtree_elem *e2) +@@ -431,6 +438,12 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set, + */ + if (rbe_le && !nft_rbtree_cmp(set, new, rbe_le) && + nft_rbtree_interval_end(rbe_le) == nft_rbtree_interval_end(new)) { ++ /* - ignore null interval, otherwise NLM_F_CREATE bogusly ++ * reports EEXIST. ++ */ ++ if (nft_rbtree_interval_null(set, new)) ++ return -ECANCELED; ++ + *elem_priv = &rbe_le->priv; + return -EEXIST; + } +-- +2.51.0 + diff --git a/queue-6.12/nfc-hci-shdlc-stop-timers-and-work-before-freeing-co.patch b/queue-6.12/nfc-hci-shdlc-stop-timers-and-work-before-freeing-co.patch new file mode 100644 index 0000000000..fa276075b3 --- /dev/null +++ b/queue-6.12/nfc-hci-shdlc-stop-timers-and-work-before-freeing-co.patch @@ -0,0 +1,52 @@ +From d3e1e6a3a908f028612a5ba1fafc0ff5ecef3438 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 14:31:57 +0300 +Subject: nfc: hci: shdlc: Stop timers and work before freeing context + +From: Votokina Victoria + +[ Upstream commit c9efde1e537baed7648a94022b43836a348a074f ] + +llc_shdlc_deinit() purges SHDLC skb queues and frees the llc_shdlc +structure while its timers and state machine work may still be active. + +Timer callbacks can schedule sm_work, and sm_work accesses SHDLC state +and the skb queues. If teardown happens in parallel with a queued/running +work item, it can lead to UAF and other shutdown races. + +Stop all SHDLC timers and cancel sm_work synchronously before purging the +queues and freeing the context. + +Found by Linux Verification Center (linuxtesting.org) with SVACE. + +Fixes: 4a61cd6687fc ("NFC: Add an shdlc llc module to llc core") +Signed-off-by: Votokina Victoria +Link: https://patch.msgid.link/20260203113158.2008723-1-Victoria.Votokina@kaspersky.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/nfc/hci/llc_shdlc.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/net/nfc/hci/llc_shdlc.c b/net/nfc/hci/llc_shdlc.c +index e90f70385813a..a106f4352356d 100644 +--- a/net/nfc/hci/llc_shdlc.c ++++ b/net/nfc/hci/llc_shdlc.c +@@ -762,6 +762,14 @@ static void llc_shdlc_deinit(struct nfc_llc *llc) + { + struct llc_shdlc *shdlc = nfc_llc_get_data(llc); + ++ timer_shutdown_sync(&shdlc->connect_timer); ++ timer_shutdown_sync(&shdlc->t1_timer); ++ timer_shutdown_sync(&shdlc->t2_timer); ++ shdlc->t1_active = false; ++ shdlc->t2_active = false; ++ ++ cancel_work_sync(&shdlc->sm_work); ++ + skb_queue_purge(&shdlc->rcv_q); + skb_queue_purge(&shdlc->send_q); + skb_queue_purge(&shdlc->ack_pending_q); +-- +2.51.0 + diff --git a/queue-6.12/nfs-localio-eliminate-unnecessary-kref-in-nfs_local_.patch b/queue-6.12/nfs-localio-eliminate-unnecessary-kref-in-nfs_local_.patch new file mode 100644 index 0000000000..5713cc0e71 --- /dev/null +++ b/queue-6.12/nfs-localio-eliminate-unnecessary-kref-in-nfs_local_.patch @@ -0,0 +1,84 @@ +From 5e8021d431eda66a1cc8204375c624f7d14c48a9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 3 Oct 2024 15:35:02 -0400 +Subject: nfs/localio: eliminate unnecessary kref in nfs_local_fsync_ctx + +From: Mike Snitzer + +[ Upstream commit 894f5c5593cdb57841318597a800ad1d3cb45a52 ] + +nfs_local_commit() doesn't need async cleanup of nfs_local_fsync_ctx, +so there is no need to use a kref. + +Signed-off-by: Mike Snitzer +Signed-off-by: Trond Myklebust +Stable-dep-of: 9bb0060f7860 ("NFS/localio: use GFP_NOIO and non-memreclaim workqueue in nfs_local_commit") +Signed-off-by: Sasha Levin +--- + fs/nfs/localio.c | 20 +++----------------- + 1 file changed, 3 insertions(+), 17 deletions(-) + +diff --git a/fs/nfs/localio.c b/fs/nfs/localio.c +index 82a053304ad59..70dfcca96f922 100644 +--- a/fs/nfs/localio.c ++++ b/fs/nfs/localio.c +@@ -43,7 +43,6 @@ struct nfs_local_fsync_ctx { + struct nfsd_file *localio; + struct nfs_commit_data *data; + struct work_struct work; +- struct kref kref; + struct completion *done; + }; + static void nfs_local_fsync_work(struct work_struct *work); +@@ -775,30 +774,17 @@ nfs_local_fsync_ctx_alloc(struct nfs_commit_data *data, + ctx->localio = localio; + ctx->data = data; + INIT_WORK(&ctx->work, nfs_local_fsync_work); +- kref_init(&ctx->kref); + ctx->done = NULL; + } + return ctx; + } + +-static void +-nfs_local_fsync_ctx_kref_free(struct kref *kref) +-{ +- kfree(container_of(kref, struct nfs_local_fsync_ctx, kref)); +-} +- +-static void +-nfs_local_fsync_ctx_put(struct nfs_local_fsync_ctx *ctx) +-{ +- kref_put(&ctx->kref, nfs_local_fsync_ctx_kref_free); +-} +- + static void + nfs_local_fsync_ctx_free(struct nfs_local_fsync_ctx *ctx) + { + nfs_local_release_commit_data(ctx->localio, ctx->data, + ctx->data->task.tk_ops); +- nfs_local_fsync_ctx_put(ctx); ++ kfree(ctx); + } + + static void +@@ -831,7 +817,7 @@ int nfs_local_commit(struct nfsd_file *localio, + } + + nfs_local_init_commit(data, call_ops); +- kref_get(&ctx->kref); ++ + if (how & FLUSH_SYNC) { + DECLARE_COMPLETION_ONSTACK(done); + ctx->done = &done; +@@ -839,6 +825,6 @@ int nfs_local_commit(struct nfsd_file *localio, + wait_for_completion(&done); + } else + queue_work(nfsiod_workqueue, &ctx->work); +- nfs_local_fsync_ctx_put(ctx); ++ + return 0; + } +-- +2.51.0 + diff --git a/queue-6.12/nfs-localio-use-gfp_noio-and-non-memreclaim-workqueu.patch b/queue-6.12/nfs-localio-use-gfp_noio-and-non-memreclaim-workqueu.patch new file mode 100644 index 0000000000..eb6834bb13 --- /dev/null +++ b/queue-6.12/nfs-localio-use-gfp_noio-and-non-memreclaim-workqueu.patch @@ -0,0 +1,80 @@ +From 1272230096ddd2a9816b4acca24957942b0b067d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 11:08:56 -0500 +Subject: NFS/localio: use GFP_NOIO and non-memreclaim workqueue in + nfs_local_commit + +From: Mike Snitzer + +[ Upstream commit 9bb0060f7860aa4561c5b21163dd45ceb66946a9 ] + +nfslocaliod_workqueue is a non-memreclaim workqueue (it isn't +initialized with WQ_MEM_RECLAIM), see commit b9f5dd57f4a5 +("nfs/localio: use dedicated workqueues for filesystem read and +write"). + +Use nfslocaliod_workqueue for LOCALIO's SYNC work. + +Also, set PF_LOCAL_THROTTLE | PF_MEMALLOC_NOIO in +nfs_local_fsync_work. + +Fixes: b9f5dd57f4a5 ("nfs/localio: use dedicated workqueues for filesystem read and write") +Signed-off-by: Mike Snitzer +Signed-off-by: Anna Schumaker +Signed-off-by: Sasha Levin +--- + fs/nfs/localio.c | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +diff --git a/fs/nfs/localio.c b/fs/nfs/localio.c +index 70dfcca96f922..84fe3ef21b6da 100644 +--- a/fs/nfs/localio.c ++++ b/fs/nfs/localio.c +@@ -790,17 +790,22 @@ nfs_local_fsync_ctx_free(struct nfs_local_fsync_ctx *ctx) + static void + nfs_local_fsync_work(struct work_struct *work) + { ++ unsigned long old_flags = current->flags; + struct nfs_local_fsync_ctx *ctx; + int status; + + ctx = container_of(work, struct nfs_local_fsync_ctx, work); + ++ current->flags |= PF_LOCAL_THROTTLE | PF_MEMALLOC_NOIO; ++ + status = nfs_local_run_commit(nfs_to->nfsd_file_file(ctx->localio), + ctx->data); + nfs_local_commit_done(ctx->data, status); + if (ctx->done != NULL) + complete(ctx->done); + nfs_local_fsync_ctx_free(ctx); ++ ++ current->flags = old_flags; + } + + int nfs_local_commit(struct nfsd_file *localio, +@@ -809,7 +814,7 @@ int nfs_local_commit(struct nfsd_file *localio, + { + struct nfs_local_fsync_ctx *ctx; + +- ctx = nfs_local_fsync_ctx_alloc(data, localio, GFP_KERNEL); ++ ctx = nfs_local_fsync_ctx_alloc(data, localio, GFP_NOIO); + if (!ctx) { + nfs_local_commit_done(data, -ENOMEM); + nfs_local_release_commit_data(localio, data, call_ops); +@@ -821,10 +826,10 @@ int nfs_local_commit(struct nfsd_file *localio, + if (how & FLUSH_SYNC) { + DECLARE_COMPLETION_ONSTACK(done); + ctx->done = &done; +- queue_work(nfsiod_workqueue, &ctx->work); ++ queue_work(nfslocaliod_workqueue, &ctx->work); + wait_for_completion(&done); + } else +- queue_work(nfsiod_workqueue, &ctx->work); ++ queue_work(nfslocaliod_workqueue, &ctx->work); + + return 0; + } +-- +2.51.0 + diff --git a/queue-6.12/nfs-nfserr_inval-is-not-defined-by-nfsv2.patch b/queue-6.12/nfs-nfserr_inval-is-not-defined-by-nfsv2.patch new file mode 100644 index 0000000000..829da026d7 --- /dev/null +++ b/queue-6.12/nfs-nfserr_inval-is-not-defined-by-nfsv2.patch @@ -0,0 +1,78 @@ +From 100b7ece52f5ded20de985d601716374d3b073cd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 19:28:50 -0500 +Subject: NFS: NFSERR_INVAL is not defined by NFSv2 + +From: Chuck Lever + +[ Upstream commit 0ac903d1bfdce8ff40657c2b7d996947b72b6645 ] + +A documenting comment in include/uapi/linux/nfs.h claims incorrectly +that NFSv2 defines NFSERR_INVAL. There is no such definition in either +RFC 1094 or https://pubs.opengroup.org/onlinepubs/9629799/chap7.htm + +NFS3ERR_INVAL is introduced in RFC 1813. + +NFSD returns NFSERR_INVAL for PROC_GETACL, which has no +specification (yet). + +However, nfsd_map_status() maps nfserr_symlink and nfserr_wrong_type +to nfserr_inval, which does not align with RFC 1094. This logic was +introduced only recently by commit 438f81e0e92a ("nfsd: move error +choice for incorrect object types to version-specific code."). Given +that we have no INVAL or SERVERFAULT status in NFSv2, probably the +only choice is NFSERR_IO. + +Fixes: 438f81e0e92a ("nfsd: move error choice for incorrect object types to version-specific code.") +Reviewed-by: NeilBrown +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs2acl.c | 2 +- + fs/nfsd/nfsproc.c | 2 +- + include/uapi/linux/nfs.h | 2 +- + 3 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c +index 5fb202acb0fd0..0ac538c761800 100644 +--- a/fs/nfsd/nfs2acl.c ++++ b/fs/nfsd/nfs2acl.c +@@ -45,7 +45,7 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst *rqstp) + inode = d_inode(fh->fh_dentry); + + if (argp->mask & ~NFS_ACL_MASK) { +- resp->status = nfserr_inval; ++ resp->status = nfserr_io; + goto out; + } + resp->mask = argp->mask; +diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c +index 6dda081eb24c0..664171bdefb65 100644 +--- a/fs/nfsd/nfsproc.c ++++ b/fs/nfsd/nfsproc.c +@@ -32,7 +32,7 @@ static __be32 nfsd_map_status(__be32 status) + break; + case nfserr_symlink: + case nfserr_wrong_type: +- status = nfserr_inval; ++ status = nfserr_io; + break; + } + return status; +diff --git a/include/uapi/linux/nfs.h b/include/uapi/linux/nfs.h +index 71c7196d32817..e629c49535345 100644 +--- a/include/uapi/linux/nfs.h ++++ b/include/uapi/linux/nfs.h +@@ -55,7 +55,7 @@ + NFSERR_NODEV = 19, /* v2 v3 v4 */ + NFSERR_NOTDIR = 20, /* v2 v3 v4 */ + NFSERR_ISDIR = 21, /* v2 v3 v4 */ +- NFSERR_INVAL = 22, /* v2 v3 v4 */ ++ NFSERR_INVAL = 22, /* v3 v4 */ + NFSERR_FBIG = 27, /* v2 v3 v4 */ + NFSERR_NOSPC = 28, /* v2 v3 v4 */ + NFSERR_ROFS = 30, /* v2 v3 v4 */ +-- +2.51.0 + diff --git a/queue-6.12/nfsd-never-defer-requests-during-idmap-lookup.patch b/queue-6.12/nfsd-never-defer-requests-during-idmap-lookup.patch new file mode 100644 index 0000000000..3d434c5138 --- /dev/null +++ b/queue-6.12/nfsd-never-defer-requests-during-idmap-lookup.patch @@ -0,0 +1,152 @@ +From 8bca811f1f9452d036b9b3f0fd743919063baf54 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 22 Dec 2025 14:30:04 -0500 +Subject: nfsd: never defer requests during idmap lookup + +From: Anthony Iliopoulos + +[ Upstream commit f9c206cdc4266caad6a9a7f46341420a10f03ccb ] + +During v4 request compound arg decoding, some ops (e.g. SETATTR) +can trigger idmap lookup upcalls. When those upcall responses get +delayed beyond the allowed time limit, cache_check() will mark the +request for deferral and cause it to be dropped. + +This prevents nfs4svc_encode_compoundres from being executed, and +thus the session slot flag NFSD4_SLOT_INUSE never gets cleared. +Subsequent client requests will fail with NFSERR_JUKEBOX, given +that the slot will be marked as in-use, making the SEQUENCE op +fail. + +Fix this by making sure that the RQ_USEDEFERRAL flag is always +clear during nfs4svc_decode_compoundargs(), since no v4 request +should ever be deferred. + +Fixes: 2f425878b6a7 ("nfsd: don't use the deferral service, return NFS4ERR_DELAY") +Signed-off-by: Anthony Iliopoulos +Reviewed-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4idmap.c | 48 +++++++++++++++++++++++++++++++++++++++------ + fs/nfsd/nfs4proc.c | 2 -- + fs/nfsd/nfs4xdr.c | 16 +++++++++++++++ + 3 files changed, 58 insertions(+), 8 deletions(-) + +diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c +index 8cca1329f3485..b5b3d45979c9b 100644 +--- a/fs/nfsd/nfs4idmap.c ++++ b/fs/nfsd/nfs4idmap.c +@@ -643,13 +643,31 @@ static __be32 encode_name_from_id(struct xdr_stream *xdr, + return idmap_id_to_name(xdr, rqstp, type, id); + } + +-__be32 +-nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen, +- kuid_t *uid) ++/** ++ * nfsd_map_name_to_uid - Map user@domain to local UID ++ * @rqstp: RPC execution context ++ * @name: user@domain name to be mapped ++ * @namelen: length of name, in bytes ++ * @uid: OUT: mapped local UID value ++ * ++ * Returns nfs_ok on success or an NFSv4 status code on failure. ++ */ ++__be32 nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, ++ size_t namelen, kuid_t *uid) + { + __be32 status; + u32 id = -1; + ++ /* ++ * The idmap lookup below triggers an upcall that invokes ++ * cache_check(). RQ_USEDEFERRAL must be clear to prevent ++ * cache_check() from setting RQ_DROPME via svc_defer(). ++ * NFSv4 servers are not permitted to drop requests. Also ++ * RQ_DROPME will force NFSv4.1 session slot processing to ++ * be skipped. ++ */ ++ WARN_ON_ONCE(test_bit(RQ_USEDEFERRAL, &rqstp->rq_flags)); ++ + if (name == NULL || namelen == 0) + return nfserr_inval; + +@@ -660,13 +678,31 @@ nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen, + return status; + } + +-__be32 +-nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, size_t namelen, +- kgid_t *gid) ++/** ++ * nfsd_map_name_to_gid - Map user@domain to local GID ++ * @rqstp: RPC execution context ++ * @name: user@domain name to be mapped ++ * @namelen: length of name, in bytes ++ * @gid: OUT: mapped local GID value ++ * ++ * Returns nfs_ok on success or an NFSv4 status code on failure. ++ */ ++__be32 nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, ++ size_t namelen, kgid_t *gid) + { + __be32 status; + u32 id = -1; + ++ /* ++ * The idmap lookup below triggers an upcall that invokes ++ * cache_check(). RQ_USEDEFERRAL must be clear to prevent ++ * cache_check() from setting RQ_DROPME via svc_defer(). ++ * NFSv4 servers are not permitted to drop requests. Also ++ * RQ_DROPME will force NFSv4.1 session slot processing to ++ * be skipped. ++ */ ++ WARN_ON_ONCE(test_bit(RQ_USEDEFERRAL, &rqstp->rq_flags)); ++ + if (name == NULL || namelen == 0) + return nfserr_inval; + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 05efa10ed84b7..2c7a8943cad9c 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -2818,8 +2818,6 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) + BUG_ON(cstate->replay_owner); + out: + cstate->status = status; +- /* Reset deferral mechanism for RPC deferrals */ +- set_bit(RQ_USEDEFERRAL, &rqstp->rq_flags); + return rpc_success; + } + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index fd81db17691a1..b7bdb9b44440b 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -5876,6 +5876,22 @@ nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + args->ops = args->iops; + args->rqstp = rqstp; + ++ /* ++ * NFSv4 operation decoders can invoke svc cache lookups ++ * that trigger svc_defer() when RQ_USEDEFERRAL is set, ++ * setting RQ_DROPME. This creates two problems: ++ * ++ * 1. Non-idempotency: Compounds make it too hard to avoid ++ * problems if a request is deferred and replayed. ++ * ++ * 2. Session slot leakage (NFSv4.1+): If RQ_DROPME is set ++ * during decode but SEQUENCE executes successfully, the ++ * session slot will be marked INUSE. The request is then ++ * dropped before encoding, so the slot is never released, ++ * rendering it permanently unusable by the client. ++ */ ++ clear_bit(RQ_USEDEFERRAL, &rqstp->rq_flags); ++ + return nfsd4_decode_compound(args); + } + +-- +2.51.0 + diff --git a/queue-6.12/nvdimm-virtio_pmem-serialize-flush-requests.patch b/queue-6.12/nvdimm-virtio_pmem-serialize-flush-requests.patch new file mode 100644 index 0000000000..94a6e01ffc --- /dev/null +++ b/queue-6.12/nvdimm-virtio_pmem-serialize-flush-requests.patch @@ -0,0 +1,98 @@ +From cfa58837ea67bb466941daddf9af56e796fadd1e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 10:13:51 +0800 +Subject: nvdimm: virtio_pmem: serialize flush requests + +From: Li Chen + +[ Upstream commit a9ba6733c7f1096c4506bf4e34a546e07242df74 ] + +Under heavy concurrent flush traffic, virtio-pmem can overflow its request +virtqueue (req_vq): virtqueue_add_sgs() starts returning -ENOSPC and the +driver logs "no free slots in the virtqueue". Shortly after that the +device enters VIRTIO_CONFIG_S_NEEDS_RESET and flush requests fail with +"virtio pmem device needs a reset". + +Serialize virtio_pmem_flush() with a per-device mutex so only one flush +request is in-flight at a time. This prevents req_vq descriptor overflow +under high concurrency. + +Reproducer (guest with virtio-pmem): + - mkfs.ext4 -F /dev/pmem0 + - mount -t ext4 -o dax,noatime /dev/pmem0 /mnt/bench + - fio: ioengine=io_uring rw=randwrite bs=4k iodepth=64 numjobs=64 + direct=1 fsync=1 runtime=30s time_based=1 + - dmesg: "no free slots in the virtqueue" + "virtio pmem device needs a reset" + +Fixes: 6e84200c0a29 ("virtio-pmem: Add virtio pmem driver") +Signed-off-by: Li Chen +Acked-by: Pankaj Gupta +Acked-by: Michael S. Tsirkin +Link: https://patch.msgid.link/20260203021353.121091-1-me@linux.beauty +Signed-off-by: Ira Weiny +Signed-off-by: Sasha Levin +--- + drivers/nvdimm/nd_virtio.c | 3 ++- + drivers/nvdimm/virtio_pmem.c | 1 + + drivers/nvdimm/virtio_pmem.h | 4 ++++ + 3 files changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/nvdimm/nd_virtio.c b/drivers/nvdimm/nd_virtio.c +index f55d60922b87d..e8ac7425c97cd 100644 +--- a/drivers/nvdimm/nd_virtio.c ++++ b/drivers/nvdimm/nd_virtio.c +@@ -44,6 +44,8 @@ static int virtio_pmem_flush(struct nd_region *nd_region) + unsigned long flags; + int err, err1; + ++ guard(mutex)(&vpmem->flush_lock); ++ + /* + * Don't bother to submit the request to the device if the device is + * not activated. +@@ -53,7 +55,6 @@ static int virtio_pmem_flush(struct nd_region *nd_region) + return -EIO; + } + +- might_sleep(); + req_data = kmalloc(sizeof(*req_data), GFP_KERNEL); + if (!req_data) + return -ENOMEM; +diff --git a/drivers/nvdimm/virtio_pmem.c b/drivers/nvdimm/virtio_pmem.c +index c9b97aeabf854..89d3d4fc3ce89 100644 +--- a/drivers/nvdimm/virtio_pmem.c ++++ b/drivers/nvdimm/virtio_pmem.c +@@ -64,6 +64,7 @@ static int virtio_pmem_probe(struct virtio_device *vdev) + goto out_err; + } + ++ mutex_init(&vpmem->flush_lock); + vpmem->vdev = vdev; + vdev->priv = vpmem; + err = init_vq(vpmem); +diff --git a/drivers/nvdimm/virtio_pmem.h b/drivers/nvdimm/virtio_pmem.h +index 0dddefe594c46..f72cf17f9518f 100644 +--- a/drivers/nvdimm/virtio_pmem.h ++++ b/drivers/nvdimm/virtio_pmem.h +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + #include + + struct virtio_pmem_request { +@@ -35,6 +36,9 @@ struct virtio_pmem { + /* Virtio pmem request queue */ + struct virtqueue *req_vq; + ++ /* Serialize flush requests to the device. */ ++ struct mutex flush_lock; ++ + /* nvdimm bus registers virtio pmem device */ + struct nvdimm_bus *nvdimm_bus; + struct nvdimm_bus_descriptor nd_desc; +-- +2.51.0 + diff --git a/queue-6.12/octeon_ep-disable-per-ring-interrupts.patch b/queue-6.12/octeon_ep-disable-per-ring-interrupts.patch new file mode 100644 index 0000000000..68a4f32314 --- /dev/null +++ b/queue-6.12/octeon_ep-disable-per-ring-interrupts.patch @@ -0,0 +1,119 @@ +From b5b111f5081a33b1bd637ed3ea3ca0fb0f608de0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 11:15:06 +0000 +Subject: octeon_ep: disable per ring interrupts + +From: Vimlesh Kumar + +[ Upstream commit 73e6ffa37cebee152c07c5f2b8bc70fd2899ea6e ] + +Disable the MSI-X per ring interrupt for every PF ring when PF +netdev goes down. + +Fixes: 1f2c2d0cee023 ("octeon_ep: add hardware configuration APIs") +Signed-off-by: Sathesh Edara +Signed-off-by: Shinas Rasheed +Signed-off-by: Vimlesh Kumar +Link: https://patch.msgid.link/20260206111510.1045092-2-vimleshk@marvell.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + .../ethernet/marvell/octeon_ep/octep_cn9k_pf.c | 18 +++++++++++++++--- + .../ethernet/marvell/octeon_ep/octep_cnxk_pf.c | 18 +++++++++++++++--- + .../marvell/octeon_ep/octep_regs_cn9k_pf.h | 1 + + .../marvell/octeon_ep/octep_regs_cnxk_pf.h | 1 + + 4 files changed, 32 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c b/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c +index b5805969404fa..f0bcb5f3c1474 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c +@@ -696,14 +696,26 @@ static void octep_enable_interrupts_cn93_pf(struct octep_device *oct) + /* Disable all interrupts */ + static void octep_disable_interrupts_cn93_pf(struct octep_device *oct) + { +- u64 intr_mask = 0ULL; ++ u64 reg_val, intr_mask = 0ULL; + int srn, num_rings, i; + + srn = CFG_GET_PORTS_PF_SRN(oct->conf); + num_rings = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); + +- for (i = 0; i < num_rings; i++) +- intr_mask |= (0x1ULL << (srn + i)); ++ for (i = 0; i < num_rings; i++) { ++ intr_mask |= BIT_ULL(srn + i); ++ reg_val = octep_read_csr64(oct, ++ CN93_SDP_R_IN_INT_LEVELS(srn + i)); ++ reg_val &= ~CN93_INT_ENA_BIT; ++ octep_write_csr64(oct, ++ CN93_SDP_R_IN_INT_LEVELS(srn + i), reg_val); ++ ++ reg_val = octep_read_csr64(oct, ++ CN93_SDP_R_OUT_INT_LEVELS(srn + i)); ++ reg_val &= ~CN93_INT_ENA_BIT; ++ octep_write_csr64(oct, ++ CN93_SDP_R_OUT_INT_LEVELS(srn + i), reg_val); ++ } + + octep_write_csr64(oct, CN93_SDP_EPF_IRERR_RINT_ENA_W1C, intr_mask); + octep_write_csr64(oct, CN93_SDP_EPF_ORERR_RINT_ENA_W1C, intr_mask); +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c b/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c +index 5de0b5ecbc5fd..07e00887c6940 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c +@@ -720,14 +720,26 @@ static void octep_enable_interrupts_cnxk_pf(struct octep_device *oct) + /* Disable all interrupts */ + static void octep_disable_interrupts_cnxk_pf(struct octep_device *oct) + { +- u64 intr_mask = 0ULL; ++ u64 reg_val, intr_mask = 0ULL; + int srn, num_rings, i; + + srn = CFG_GET_PORTS_PF_SRN(oct->conf); + num_rings = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); + +- for (i = 0; i < num_rings; i++) +- intr_mask |= (0x1ULL << (srn + i)); ++ for (i = 0; i < num_rings; i++) { ++ intr_mask |= BIT_ULL(srn + i); ++ reg_val = octep_read_csr64(oct, ++ CNXK_SDP_R_IN_INT_LEVELS(srn + i)); ++ reg_val &= ~CNXK_INT_ENA_BIT; ++ octep_write_csr64(oct, ++ CNXK_SDP_R_IN_INT_LEVELS(srn + i), reg_val); ++ ++ reg_val = octep_read_csr64(oct, ++ CNXK_SDP_R_OUT_INT_LEVELS(srn + i)); ++ reg_val &= ~CNXK_INT_ENA_BIT; ++ octep_write_csr64(oct, ++ CNXK_SDP_R_OUT_INT_LEVELS(srn + i), reg_val); ++ } + + octep_write_csr64(oct, CNXK_SDP_EPF_IRERR_RINT_ENA_W1C, intr_mask); + octep_write_csr64(oct, CNXK_SDP_EPF_ORERR_RINT_ENA_W1C, intr_mask); +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cn9k_pf.h b/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cn9k_pf.h +index ca473502d7a02..95f1dfff90cce 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cn9k_pf.h ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cn9k_pf.h +@@ -386,5 +386,6 @@ + #define CN93_PEM_BAR4_INDEX 7 + #define CN93_PEM_BAR4_INDEX_SIZE 0x400000ULL + #define CN93_PEM_BAR4_INDEX_OFFSET (CN93_PEM_BAR4_INDEX * CN93_PEM_BAR4_INDEX_SIZE) ++#define CN93_INT_ENA_BIT BIT_ULL(62) + + #endif /* _OCTEP_REGS_CN9K_PF_H_ */ +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h b/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h +index e637d7c8224d4..4d172a552f80c 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h +@@ -412,5 +412,6 @@ + #define CNXK_PEM_BAR4_INDEX 7 + #define CNXK_PEM_BAR4_INDEX_SIZE 0x400000ULL + #define CNXK_PEM_BAR4_INDEX_OFFSET (CNXK_PEM_BAR4_INDEX * CNXK_PEM_BAR4_INDEX_SIZE) ++#define CNXK_INT_ENA_BIT BIT_ULL(62) + + #endif /* _OCTEP_REGS_CNXK_PF_H_ */ +-- +2.51.0 + diff --git a/queue-6.12/octeon_ep-ensure-dbell-baddr-updation.patch b/queue-6.12/octeon_ep-ensure-dbell-baddr-updation.patch new file mode 100644 index 0000000000..556e575132 --- /dev/null +++ b/queue-6.12/octeon_ep-ensure-dbell-baddr-updation.patch @@ -0,0 +1,186 @@ +From 418e5e56e09413cfd9f10fb81a49ee5ca4ccb333 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 11:15:07 +0000 +Subject: octeon_ep: ensure dbell BADDR updation + +From: Vimlesh Kumar + +[ Upstream commit ce8fe3fc4f99efd872120301c0f72f2e90ab9769 ] + +Make sure the OUT DBELL base address reflects the +latest values written to it. + +Fix: +Add a wait until the OUT DBELL base address register +is updated with the DMA ring descriptor address, +and modify the setup_oq function to properly +handle failures. + +Fixes: 0807dc76f3bf5 ("octeon_ep: support Octeon CN10K devices") +Signed-off-by: Sathesh Edara +Signed-off-by: Shinas Rasheed +Signed-off-by: Vimlesh Kumar +Link: https://patch.msgid.link/20260206111510.1045092-3-vimleshk@marvell.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + .../marvell/octeon_ep/octep_cn9k_pf.c | 3 +- + .../marvell/octeon_ep/octep_cnxk_pf.c | 46 +++++++++++++++---- + .../ethernet/marvell/octeon_ep/octep_main.h | 2 +- + .../net/ethernet/marvell/octeon_ep/octep_rx.c | 8 +++- + 4 files changed, 48 insertions(+), 11 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c b/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c +index f0bcb5f3c1474..01e82d0b6b2cd 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c +@@ -307,7 +307,7 @@ static void octep_setup_iq_regs_cn93_pf(struct octep_device *oct, int iq_no) + } + + /* Setup registers for a hardware Rx Queue */ +-static void octep_setup_oq_regs_cn93_pf(struct octep_device *oct, int oq_no) ++static int octep_setup_oq_regs_cn93_pf(struct octep_device *oct, int oq_no) + { + u64 reg_val; + u64 oq_ctl = 0ULL; +@@ -355,6 +355,7 @@ static void octep_setup_oq_regs_cn93_pf(struct octep_device *oct, int oq_no) + reg_val = ((u64)time_threshold << 32) | + CFG_GET_OQ_INTR_PKT(oct->conf); + octep_write_csr64(oct, CN93_SDP_R_OUT_INT_LEVELS(oq_no), reg_val); ++ return 0; + } + + /* Setup registers for a PF mailbox */ +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c b/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c +index 07e00887c6940..09a3f1d0645b8 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + + #include "octep_config.h" + #include "octep_main.h" +@@ -327,12 +328,14 @@ static void octep_setup_iq_regs_cnxk_pf(struct octep_device *oct, int iq_no) + } + + /* Setup registers for a hardware Rx Queue */ +-static void octep_setup_oq_regs_cnxk_pf(struct octep_device *oct, int oq_no) ++static int octep_setup_oq_regs_cnxk_pf(struct octep_device *oct, int oq_no) + { +- u64 reg_val; +- u64 oq_ctl = 0ULL; +- u32 time_threshold = 0; + struct octep_oq *oq = oct->oq[oq_no]; ++ unsigned long t_out_jiffies; ++ u32 time_threshold = 0; ++ u64 oq_ctl = 0ULL; ++ u64 reg_ba_val; ++ u64 reg_val; + + oq_no += CFG_GET_PORTS_PF_SRN(oct->conf); + reg_val = octep_read_csr64(oct, CNXK_SDP_R_OUT_CONTROL(oq_no)); +@@ -343,6 +346,36 @@ static void octep_setup_oq_regs_cnxk_pf(struct octep_device *oct, int oq_no) + reg_val = octep_read_csr64(oct, CNXK_SDP_R_OUT_CONTROL(oq_no)); + } while (!(reg_val & CNXK_R_OUT_CTL_IDLE)); + } ++ octep_write_csr64(oct, CNXK_SDP_R_OUT_WMARK(oq_no), oq->max_count); ++ /* Wait for WMARK to get applied */ ++ usleep_range(10, 15); ++ ++ octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_BADDR(oq_no), ++ oq->desc_ring_dma); ++ octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_RSIZE(oq_no), ++ oq->max_count); ++ reg_ba_val = octep_read_csr64(oct, CNXK_SDP_R_OUT_SLIST_BADDR(oq_no)); ++ ++ if (reg_ba_val != oq->desc_ring_dma) { ++ t_out_jiffies = jiffies + 10 * HZ; ++ do { ++ if (reg_ba_val == ULLONG_MAX) ++ return -EFAULT; ++ octep_write_csr64(oct, ++ CNXK_SDP_R_OUT_SLIST_BADDR(oq_no), ++ oq->desc_ring_dma); ++ octep_write_csr64(oct, ++ CNXK_SDP_R_OUT_SLIST_RSIZE(oq_no), ++ oq->max_count); ++ reg_ba_val = ++ octep_read_csr64(oct, ++ CNXK_SDP_R_OUT_SLIST_BADDR(oq_no)); ++ } while ((reg_ba_val != oq->desc_ring_dma) && ++ time_before(jiffies, t_out_jiffies)); ++ ++ if (reg_ba_val != oq->desc_ring_dma) ++ return -EAGAIN; ++ } + + reg_val &= ~(CNXK_R_OUT_CTL_IMODE); + reg_val &= ~(CNXK_R_OUT_CTL_ROR_P); +@@ -356,10 +389,6 @@ static void octep_setup_oq_regs_cnxk_pf(struct octep_device *oct, int oq_no) + reg_val |= (CNXK_R_OUT_CTL_ES_P); + + octep_write_csr64(oct, CNXK_SDP_R_OUT_CONTROL(oq_no), reg_val); +- octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_BADDR(oq_no), +- oq->desc_ring_dma); +- octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_RSIZE(oq_no), +- oq->max_count); + + oq_ctl = octep_read_csr64(oct, CNXK_SDP_R_OUT_CONTROL(oq_no)); + +@@ -385,6 +414,7 @@ static void octep_setup_oq_regs_cnxk_pf(struct octep_device *oct, int oq_no) + reg_val &= ~0xFFFFFFFFULL; + reg_val |= CFG_GET_OQ_WMARK(oct->conf); + octep_write_csr64(oct, CNXK_SDP_R_OUT_WMARK(oq_no), reg_val); ++ return 0; + } + + /* Setup registers for a PF mailbox */ +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_main.h b/drivers/net/ethernet/marvell/octeon_ep/octep_main.h +index 936b786f42816..c063c8451d47a 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_main.h ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_main.h +@@ -77,7 +77,7 @@ struct octep_pci_win_regs { + + struct octep_hw_ops { + void (*setup_iq_regs)(struct octep_device *oct, int q); +- void (*setup_oq_regs)(struct octep_device *oct, int q); ++ int (*setup_oq_regs)(struct octep_device *oct, int q); + void (*setup_mbox_regs)(struct octep_device *oct, int mbox); + + irqreturn_t (*mbox_intr_handler)(void *ioq_vector); +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c b/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c +index 82b6b19e76b47..f2a7c6a76c742 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c +@@ -12,6 +12,8 @@ + #include "octep_config.h" + #include "octep_main.h" + ++static void octep_oq_free_ring_buffers(struct octep_oq *oq); ++ + static void octep_oq_reset_indices(struct octep_oq *oq) + { + oq->host_read_idx = 0; +@@ -170,11 +172,15 @@ static int octep_setup_oq(struct octep_device *oct, int q_no) + goto oq_fill_buff_err; + + octep_oq_reset_indices(oq); +- oct->hw_ops.setup_oq_regs(oct, q_no); ++ if (oct->hw_ops.setup_oq_regs(oct, q_no)) ++ goto oq_setup_err; ++ + oct->num_oqs++; + + return 0; + ++oq_setup_err: ++ octep_oq_free_ring_buffers(oq); + oq_fill_buff_err: + vfree(oq->buff_info); + oq->buff_info = NULL; +-- +2.51.0 + diff --git a/queue-6.12/octeon_ep_vf-ensure-dbell-baddr-updation.patch b/queue-6.12/octeon_ep_vf-ensure-dbell-baddr-updation.patch new file mode 100644 index 0000000000..fd4053834d --- /dev/null +++ b/queue-6.12/octeon_ep_vf-ensure-dbell-baddr-updation.patch @@ -0,0 +1,174 @@ +From 0423bc85385ffea752540f96c0b073b8c7bab4a2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 11:15:08 +0000 +Subject: octeon_ep_vf: ensure dbell BADDR updation + +From: Vimlesh Kumar + +[ Upstream commit 484e834d53cffa91c311631271f83130cf6e9e7c ] + +Make sure the OUT DBELL base address reflects the +latest values written to it. + +Fix: +Add a wait until the OUT DBELL base address register +is updated with the DMA ring descriptor address, +and modify the setup_oq function to properly +handle failures. + +Fixes: 2c0c32c72be29 ("octeon_ep_vf: add hardware configuration APIs") +Signed-off-by: Sathesh Edara +Signed-off-by: Shinas Rasheed +Signed-off-by: Vimlesh Kumar +Link: https://patch.msgid.link/20260206111510.1045092-4-vimleshk@marvell.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + .../marvell/octeon_ep_vf/octep_vf_cn9k.c | 3 +- + .../marvell/octeon_ep_vf/octep_vf_cnxk.c | 39 +++++++++++++++++-- + .../marvell/octeon_ep_vf/octep_vf_main.h | 2 +- + .../marvell/octeon_ep_vf/octep_vf_rx.c | 8 +++- + 4 files changed, 46 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cn9k.c b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cn9k.c +index 88937fce75f14..4c769b27c2789 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cn9k.c ++++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cn9k.c +@@ -196,7 +196,7 @@ static void octep_vf_setup_iq_regs_cn93(struct octep_vf_device *oct, int iq_no) + } + + /* Setup registers for a hardware Rx Queue */ +-static void octep_vf_setup_oq_regs_cn93(struct octep_vf_device *oct, int oq_no) ++static int octep_vf_setup_oq_regs_cn93(struct octep_vf_device *oct, int oq_no) + { + struct octep_vf_oq *oq = oct->oq[oq_no]; + u32 time_threshold = 0; +@@ -239,6 +239,7 @@ static void octep_vf_setup_oq_regs_cn93(struct octep_vf_device *oct, int oq_no) + time_threshold = CFG_GET_OQ_INTR_TIME(oct->conf); + reg_val = ((u64)time_threshold << 32) | CFG_GET_OQ_INTR_PKT(oct->conf); + octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_INT_LEVELS(oq_no), reg_val); ++ return 0; + } + + /* Setup registers for a VF mailbox */ +diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cnxk.c b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cnxk.c +index 1f79dfad42c62..a968b93a67943 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cnxk.c ++++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cnxk.c +@@ -199,11 +199,13 @@ static void octep_vf_setup_iq_regs_cnxk(struct octep_vf_device *oct, int iq_no) + } + + /* Setup registers for a hardware Rx Queue */ +-static void octep_vf_setup_oq_regs_cnxk(struct octep_vf_device *oct, int oq_no) ++static int octep_vf_setup_oq_regs_cnxk(struct octep_vf_device *oct, int oq_no) + { + struct octep_vf_oq *oq = oct->oq[oq_no]; ++ unsigned long t_out_jiffies; + u32 time_threshold = 0; + u64 oq_ctl = ULL(0); ++ u64 reg_ba_val; + u64 reg_val; + + reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_CONTROL(oq_no)); +@@ -214,6 +216,38 @@ static void octep_vf_setup_oq_regs_cnxk(struct octep_vf_device *oct, int oq_no) + reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_CONTROL(oq_no)); + } while (!(reg_val & CNXK_VF_R_OUT_CTL_IDLE)); + } ++ octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_WMARK(oq_no), ++ oq->max_count); ++ /* Wait for WMARK to get applied */ ++ usleep_range(10, 15); ++ ++ octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_SLIST_BADDR(oq_no), ++ oq->desc_ring_dma); ++ octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_SLIST_RSIZE(oq_no), ++ oq->max_count); ++ reg_ba_val = octep_vf_read_csr64(oct, ++ CNXK_VF_SDP_R_OUT_SLIST_BADDR(oq_no)); ++ if (reg_ba_val != oq->desc_ring_dma) { ++ t_out_jiffies = jiffies + 10 * HZ; ++ do { ++ if (reg_ba_val == ULLONG_MAX) ++ return -EFAULT; ++ octep_vf_write_csr64(oct, ++ CNXK_VF_SDP_R_OUT_SLIST_BADDR ++ (oq_no), oq->desc_ring_dma); ++ octep_vf_write_csr64(oct, ++ CNXK_VF_SDP_R_OUT_SLIST_RSIZE ++ (oq_no), oq->max_count); ++ reg_ba_val = ++ octep_vf_read_csr64(oct, ++ CNXK_VF_SDP_R_OUT_SLIST_BADDR ++ (oq_no)); ++ } while ((reg_ba_val != oq->desc_ring_dma) && ++ time_before(jiffies, t_out_jiffies)); ++ ++ if (reg_ba_val != oq->desc_ring_dma) ++ return -EAGAIN; ++ } + + reg_val &= ~(CNXK_VF_R_OUT_CTL_IMODE); + reg_val &= ~(CNXK_VF_R_OUT_CTL_ROR_P); +@@ -227,8 +261,6 @@ static void octep_vf_setup_oq_regs_cnxk(struct octep_vf_device *oct, int oq_no) + reg_val |= (CNXK_VF_R_OUT_CTL_ES_P); + + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_CONTROL(oq_no), reg_val); +- octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_SLIST_BADDR(oq_no), oq->desc_ring_dma); +- octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_SLIST_RSIZE(oq_no), oq->max_count); + + oq_ctl = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_CONTROL(oq_no)); + /* Clear the ISIZE and BSIZE (22-0) */ +@@ -250,6 +282,7 @@ static void octep_vf_setup_oq_regs_cnxk(struct octep_vf_device *oct, int oq_no) + reg_val &= ~GENMASK_ULL(31, 0); + reg_val |= CFG_GET_OQ_WMARK(oct->conf); + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_WMARK(oq_no), reg_val); ++ return 0; + } + + /* Setup registers for a VF mailbox */ +diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.h b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.h +index 1a352f41f823c..4ee6b4d568ede 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.h ++++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.h +@@ -55,7 +55,7 @@ struct octep_vf_mmio { + + struct octep_vf_hw_ops { + void (*setup_iq_regs)(struct octep_vf_device *oct, int q); +- void (*setup_oq_regs)(struct octep_vf_device *oct, int q); ++ int (*setup_oq_regs)(struct octep_vf_device *oct, int q); + void (*setup_mbox_regs)(struct octep_vf_device *oct, int mbox); + + irqreturn_t (*non_ioq_intr_handler)(void *ioq_vector); +diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c +index d70c8be3cfc40..6f865dbbba6c6 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c ++++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c +@@ -12,6 +12,8 @@ + #include "octep_vf_config.h" + #include "octep_vf_main.h" + ++static void octep_vf_oq_free_ring_buffers(struct octep_vf_oq *oq); ++ + static void octep_vf_oq_reset_indices(struct octep_vf_oq *oq) + { + oq->host_read_idx = 0; +@@ -171,11 +173,15 @@ static int octep_vf_setup_oq(struct octep_vf_device *oct, int q_no) + goto oq_fill_buff_err; + + octep_vf_oq_reset_indices(oq); +- oct->hw_ops.setup_oq_regs(oct, q_no); ++ if (oct->hw_ops.setup_oq_regs(oct, q_no)) ++ goto oq_setup_err; ++ + oct->num_oqs++; + + return 0; + ++oq_setup_err: ++ octep_vf_oq_free_ring_buffers(oq); + oq_fill_buff_err: + vfree(oq->buff_info); + oq->buff_info = NULL; +-- +2.51.0 + diff --git a/queue-6.12/octeontx2-af-fix-pf-driver-crash-with-kexec-kernel-b.patch b/queue-6.12/octeontx2-af-fix-pf-driver-crash-with-kexec-kernel-b.patch new file mode 100644 index 0000000000..e378480211 --- /dev/null +++ b/queue-6.12/octeontx2-af-fix-pf-driver-crash-with-kexec-kernel-b.patch @@ -0,0 +1,62 @@ +From 79e3b148cf96aab35c2ece1801a00e6c72d9c0bf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 10:37:01 +0530 +Subject: octeontx2-af: Fix PF driver crash with kexec kernel booting + +From: Anshumali Gaur + +[ Upstream commit 2d2d574309e3ae84ee794869a5da8b4c38753a94 ] + +During a kexec reboot the hardware is not power-cycled, so AF state from +the old kernel can persist into the new kernel. When AF and PF drivers +are built as modules, the PF driver may probe before AF reinitializes +the hardware. + +The PF driver treats the RVUM block revision as an indication that AF +initialization is complete. If this value is left uncleared at shutdown, +PF may incorrectly assume AF is ready and access stale hardware state, +leading to a crash. + +Clear the RVUM block revision during AF shutdown to avoid PF +mis-detecting AF readiness after kexec. + +Fixes: 54494aa5d1e6 ("octeontx2-af: Add Marvell OcteonTX2 RVU AF driver") +Signed-off-by: Anshumali Gaur +Reviewed-by: Jacob Keller +Link: https://patch.msgid.link/20260203050701.2616685-1-agaur@marvell.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/octeontx2/af/rvu.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +index 74201e0210bbf..d5e2ebedd433e 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +@@ -3529,11 +3529,22 @@ static void rvu_remove(struct pci_dev *pdev) + devm_kfree(&pdev->dev, rvu); + } + ++static void rvu_shutdown(struct pci_dev *pdev) ++{ ++ struct rvu *rvu = pci_get_drvdata(pdev); ++ ++ if (!rvu) ++ return; ++ ++ rvu_clear_rvum_blk_revid(rvu); ++} ++ + static struct pci_driver rvu_driver = { + .name = DRV_NAME, + .id_table = rvu_id_table, + .probe = rvu_probe, + .remove = rvu_remove, ++ .shutdown = rvu_shutdown, + }; + + static int __init rvu_init_module(void) +-- +2.51.0 + diff --git a/queue-6.12/octeontx2-pf-unregister-devlink-on-probe-failure.patch b/queue-6.12/octeontx2-pf-unregister-devlink-on-probe-failure.patch new file mode 100644 index 0000000000..208449ea37 --- /dev/null +++ b/queue-6.12/octeontx2-pf-unregister-devlink-on-probe-failure.patch @@ -0,0 +1,36 @@ +From 86b503a734b610467097627e1267b95dfab9c109 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 23:56:45 +0530 +Subject: octeontx2-pf: Unregister devlink on probe failure + +From: Hariprasad Kelam + +[ Upstream commit 943f3b8bfbf297cf74392b50a7108ce1fe4cbd8c ] + +When probe fails after devlink registration, the missing devlink unregister +call causing a memory leak. + +Fixes: 2da489432747 ("octeontx2-pf: devlink params support to set mcam entry count") +Signed-off-by: Hariprasad Kelam +Link: https://patch.msgid.link/20260206182645.4032737-1-hkelam@marvell.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +index 5492dea547a19..2de9c44ef57c7 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c ++++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +@@ -3101,6 +3101,7 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id) + return 0; + + err_pf_sriov_init: ++ otx2_unregister_dl(pf); + otx2_shutdown_tc(pf); + err_mcam_flow_del: + otx2_mcam_flow_del(pf); +-- +2.51.0 + diff --git a/queue-6.12/of-unittest-fix-possible-null-pointer-dereferences-i.patch b/queue-6.12/of-unittest-fix-possible-null-pointer-dereferences-i.patch new file mode 100644 index 0000000000..085ba52b84 --- /dev/null +++ b/queue-6.12/of-unittest-fix-possible-null-pointer-dereferences-i.patch @@ -0,0 +1,49 @@ +From 9e172aae498aad0b323b99d3f5a1d15e0bd29192 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Jan 2026 15:14:38 +0800 +Subject: of: unittest: fix possible null-pointer dereferences in + of_unittest_property_copy() + +From: Tuo Li + +[ Upstream commit d289cb7fcefe41a54d8f9c6d0e0947f5f82b15c6 ] + +This function first duplicates p1 and p2 into new, and then checks whether +the duplication succeeds. However, if the duplication fails (e.g., +kzalloc() returns NULL in __of_prop_dup()), new will be NULL but is still +dereferenced in __of_prop_free(). To ensure that the unit test continues to +run even when duplication fails, add a NULL check before calling +__of_prop_free(). + +Fixes: 1c5e3d9bf33b ("of: Add a helper to free property struct") +Signed-off-by: Tuo Li +Link: https://patch.msgid.link/20260105071438.156186-1-islituo@gmail.com +Signed-off-by: Rob Herring (Arm) +Signed-off-by: Sasha Levin +--- + drivers/of/unittest.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c +index 63b5b435bd3ae..ba223736237e8 100644 +--- a/drivers/of/unittest.c ++++ b/drivers/of/unittest.c +@@ -795,11 +795,13 @@ static void __init of_unittest_property_copy(void) + + new = __of_prop_dup(&p1, GFP_KERNEL); + unittest(new && propcmp(&p1, new), "empty property didn't copy correctly\n"); +- __of_prop_free(new); ++ if (new) ++ __of_prop_free(new); + + new = __of_prop_dup(&p2, GFP_KERNEL); + unittest(new && propcmp(&p2, new), "non-empty property didn't copy correctly\n"); +- __of_prop_free(new); ++ if (new) ++ __of_prop_free(new); + #endif + } + +-- +2.51.0 + diff --git a/queue-6.12/opp-return-correct-value-in-dev_pm_opp_get_level.patch b/queue-6.12/opp-return-correct-value-in-dev_pm_opp_get_level.patch new file mode 100644 index 0000000000..afd17078dc --- /dev/null +++ b/queue-6.12/opp-return-correct-value-in-dev_pm_opp_get_level.patch @@ -0,0 +1,40 @@ +From 19bda529a7c5565fa6e1222932b64c3126854e53 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 14:03:44 +0000 +Subject: OPP: Return correct value in dev_pm_opp_get_level + +From: Aleks Todorov + +[ Upstream commit 0b7277e02dabba2a9921a7f4761ae6e627e7297a ] + +Commit 073d3d2ca7d4 ("OPP: Level zero is valid") modified the +documentation for this function to indicate that errors should return a +non-zero value to avoid colliding with the OPP level zero, however +forgot to actually update the return. + +No in-tree kernel code depends on the error value being 0. + +Fixes: 073d3d2ca7d4 ("OPP: Level zero is valid") +Signed-off-by: Aleks Todorov +Signed-off-by: Viresh Kumar +Signed-off-by: Sasha Levin +--- + drivers/opp/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/opp/core.c b/drivers/opp/core.c +index 5ac209472c0cf..b5df41ce3afff 100644 +--- a/drivers/opp/core.c ++++ b/drivers/opp/core.c +@@ -226,7 +226,7 @@ unsigned int dev_pm_opp_get_level(struct dev_pm_opp *opp) + { + if (IS_ERR_OR_NULL(opp) || !opp->available) { + pr_err("%s: Invalid parameters\n", __func__); +- return 0; ++ return U32_MAX; + } + + return opp->level; +-- +2.51.0 + diff --git a/queue-6.12/ovl-fix-uninit-value-in-ovl_fill_real.patch b/queue-6.12/ovl-fix-uninit-value-in-ovl_fill_real.patch new file mode 100644 index 0000000000..e923f03654 --- /dev/null +++ b/queue-6.12/ovl-fix-uninit-value-in-ovl_fill_real.patch @@ -0,0 +1,58 @@ +From d7ea74e13a95a44ba7fa848bee51f223405518bf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 14:24:04 +0100 +Subject: ovl: Fix uninit-value in ovl_fill_real + +From: Qing Wang + +[ Upstream commit 1992330d90dd766fcf1730fd7bf2d6af65370ac4 ] + +Syzbot reported a KMSAN uninit-value issue in ovl_fill_real. + +This iusse's call chain is: +__do_sys_getdents64() + -> iterate_dir() + ... + -> ext4_readdir() + -> fscrypt_fname_alloc_buffer() // alloc + -> fscrypt_fname_disk_to_usr // write without tail '\0' + -> dir_emit() + -> ovl_fill_real() // read by strcmp() + +The string is used to store the decrypted directory entry name for an +encrypted inode. As shown in the call chain, fscrypt_fname_disk_to_usr() +write it without null-terminate. However, ovl_fill_real() uses strcmp() to +compare the name against "..", which assumes a null-terminated string and +may trigger a KMSAN uninit-value warning when the buffer tail contains +uninit data. + +Reported-by: syzbot+d130f98b2c265fae5297@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=d130f98b2c265fae5297 +Fixes: 4edb83bb1041 ("ovl: constant d_ino for non-merge dirs") +Signed-off-by: Qing Wang +Signed-off-by: Amir Goldstein +Link: https://patch.msgid.link/20260128132406.23768-2-amir73il@gmail.com +Acked-by: Miklos Szeredi +Reviewed-by: Eric Biggers +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/overlayfs/readdir.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c +index 0ca8af060b0c1..e185f4f668b54 100644 +--- a/fs/overlayfs/readdir.c ++++ b/fs/overlayfs/readdir.c +@@ -673,7 +673,7 @@ static bool ovl_fill_real(struct dir_context *ctx, const char *name, + container_of(ctx, struct ovl_readdir_translate, ctx); + struct dir_context *orig_ctx = rdt->orig_ctx; + +- if (rdt->parent_ino && strcmp(name, "..") == 0) { ++ if (rdt->parent_ino && namelen == 2 && !strncmp(name, "..", 2)) { + ino = rdt->parent_ino; + } else if (rdt->cache) { + struct ovl_cache_entry *p; +-- +2.51.0 + diff --git a/queue-6.12/partial-revert-x86-xen-fix-balloon-target-initializa.patch b/queue-6.12/partial-revert-x86-xen-fix-balloon-target-initializa.patch new file mode 100644 index 0000000000..67e58fdc83 --- /dev/null +++ b/queue-6.12/partial-revert-x86-xen-fix-balloon-target-initializa.patch @@ -0,0 +1,140 @@ +From e18f7a425eb5623d5440522ddec65e7add51aa26 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 12:05:08 +0100 +Subject: Partial revert "x86/xen: fix balloon target initialization for PVH + dom0" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Roger Pau Monne + +[ Upstream commit 0949c646d64697428ff6257d52efa5093566868d ] + +This partially reverts commit 87af633689ce16ddb166c80f32b120e50b1295de so +the current memory target for PV guests is still fetched from +start_info->nr_pages, which matches exactly what the toolstack sets the +initial memory target to. + +Using get_num_physpages() is possible on PV also, but needs adjusting to +take into account the ISA hole and the PFN at 0 not considered usable +memory despite being populated, and hence would need extra adjustments. +Instead of carrying those extra adjustments switch back to the previous +code. That leaves Linux with a difference in how current memory target is +obtained for HVM vs PV, but that's better than adding extra logic just for +PV. + +However if switching to start_info->nr_pages for PV domains we need to +differentiate between released pages (freed back to the hypervisor) as +opposed to pages in the physmap which are not populated to start with. +Introduce a new xen_unpopulated_pages to account for papges that have +never been populated, and hence in the PV case don't need subtracting. + +Fixes: 87af633689ce ("x86/xen: fix balloon target initialization for PVH dom0") +Reported-by: James Dingwall +Signed-off-by: Roger Pau Monné +Reviewed-by: Juergen Gross +Signed-off-by: Juergen Gross +Message-ID: <20260128110510.46425-2-roger.pau@citrix.com> +Signed-off-by: Sasha Levin +--- + arch/x86/xen/enlighten.c | 2 +- + drivers/xen/balloon.c | 19 +++++++++++++++---- + drivers/xen/unpopulated-alloc.c | 3 +++ + include/xen/xen.h | 2 ++ + 4 files changed, 21 insertions(+), 5 deletions(-) + +diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c +index 0c950bbca309f..86dd33f1aeaab 100644 +--- a/arch/x86/xen/enlighten.c ++++ b/arch/x86/xen/enlighten.c +@@ -474,7 +474,7 @@ int __init arch_xen_unpopulated_init(struct resource **res) + * driver to know how much of the physmap is unpopulated and + * set an accurate initial memory target. + */ +- xen_released_pages += xen_extra_mem[i].n_pfns; ++ xen_unpopulated_pages += xen_extra_mem[i].n_pfns; + /* Zero so region is not also added to the balloon driver. */ + xen_extra_mem[i].n_pfns = 0; + } +diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c +index e47bb157aa090..88511187458a9 100644 +--- a/drivers/xen/balloon.c ++++ b/drivers/xen/balloon.c +@@ -720,6 +720,7 @@ static int __init balloon_add_regions(void) + static int __init balloon_init(void) + { + struct task_struct *task; ++ unsigned long current_pages; + int rc; + + if (!xen_domain()) +@@ -727,12 +728,18 @@ static int __init balloon_init(void) + + pr_info("Initialising balloon driver\n"); + +- if (xen_released_pages >= get_num_physpages()) { +- WARN(1, "Released pages underflow current target"); +- return -ERANGE; ++ if (xen_pv_domain()) { ++ if (xen_released_pages >= xen_start_info->nr_pages) ++ goto underflow; ++ current_pages = min(xen_start_info->nr_pages - ++ xen_released_pages, max_pfn); ++ } else { ++ if (xen_unpopulated_pages >= get_num_physpages()) ++ goto underflow; ++ current_pages = get_num_physpages() - xen_unpopulated_pages; + } + +- balloon_stats.current_pages = get_num_physpages() - xen_released_pages; ++ balloon_stats.current_pages = current_pages; + balloon_stats.target_pages = balloon_stats.current_pages; + balloon_stats.balloon_low = 0; + balloon_stats.balloon_high = 0; +@@ -763,6 +770,10 @@ static int __init balloon_init(void) + xen_balloon_init(); + + return 0; ++ ++ underflow: ++ WARN(1, "Released pages underflow current target"); ++ return -ERANGE; + } + subsys_initcall(balloon_init); + +diff --git a/drivers/xen/unpopulated-alloc.c b/drivers/xen/unpopulated-alloc.c +index a39f2d36dd9cf..ae46291e99a9d 100644 +--- a/drivers/xen/unpopulated-alloc.c ++++ b/drivers/xen/unpopulated-alloc.c +@@ -18,6 +18,9 @@ static unsigned int list_count; + + static struct resource *target_resource; + ++/* Pages to subtract from the memory count when setting balloon target. */ ++unsigned long xen_unpopulated_pages __initdata; ++ + /* + * If arch is not happy with system "iomem_resource" being used for + * the region allocation it can provide it's own view by creating specific +diff --git a/include/xen/xen.h b/include/xen/xen.h +index a1e5b3f18d69f..86fe96fe51834 100644 +--- a/include/xen/xen.h ++++ b/include/xen/xen.h +@@ -62,11 +62,13 @@ extern u64 xen_saved_max_mem_size; + #endif + + #ifdef CONFIG_XEN_UNPOPULATED_ALLOC ++extern unsigned long xen_unpopulated_pages; + int xen_alloc_unpopulated_pages(unsigned int nr_pages, struct page **pages); + void xen_free_unpopulated_pages(unsigned int nr_pages, struct page **pages); + #include + int arch_xen_unpopulated_init(struct resource **res); + #else ++#define xen_unpopulated_pages 0UL + #include + static inline int xen_alloc_unpopulated_pages(unsigned int nr_pages, + struct page **pages) +-- +2.51.0 + diff --git a/queue-6.12/pci-acpi-restrict-program_hpx_type2-to-aer-bits.patch b/queue-6.12/pci-acpi-restrict-program_hpx_type2-to-aer-bits.patch new file mode 100644 index 0000000000..dd01528ac7 --- /dev/null +++ b/queue-6.12/pci-acpi-restrict-program_hpx_type2-to-aer-bits.patch @@ -0,0 +1,200 @@ +From 2ae8539798bb715073fc4d00fb1384a89c7bec52 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 18:52:33 +0100 +Subject: PCI/ACPI: Restrict program_hpx_type2() to AER bits +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: HÃ¥kon Bugge + +[ Upstream commit 9abf79c8d7b40db0e5a34aa8c744ea60ff9a3fcf ] + +Previously program_hpx_type2() applied PCIe settings unconditionally, +which could incorrectly change bits like Extended Tag Field Enable and +Enable Relaxed Ordering. + +When _HPX was added to ACPI r3.0, the intent of the PCIe Setting +Record (Type 2) in sec 6.2.7.3 was to configure AER registers when the +OS does not own the AER Capability: + + The PCI Express setting record contains ... [the AER] Uncorrectable + Error Mask, Uncorrectable Error Severity, Correctable Error Mask + ... to be used when configuring registers in the Advanced Error + Reporting Extended Capability Structure ... + + OSPM [1] will only evaluate _HPX with Setting Record – Type 2 if + OSPM is not controlling the PCI Express Advanced Error Reporting + capability. + +ACPI r3.0b, sec 6.2.7.3, added more AER registers, including registers +in the PCIe Capability with AER-related bits, and the restriction that +the OS use this only when it owns PCIe native hotplug: + + ... when configuring PCI Express registers in the Advanced Error + Reporting Extended Capability Structure *or PCI Express Capability + Structure* ... + + An OS that has assumed ownership of native hot plug but does not + ... have ownership of the AER register set must use ... the Type 2 + record to program the AER registers ... + + However, since the Type 2 record also includes register bits that + have functions other than AER, the OS must ignore values ... that + are not applicable. + +Restrict program_hpx_type2() to only the intended purpose: + + - Apply settings only when OS owns PCIe native hotplug but not AER, + + - Only touch the AER-related bits (Error Reporting Enables) in Device + Control + + - Don't touch Link Control at all, since nothing there seems AER-related, + but log _HPX settings for debugging purposes + +Note that Read Completion Boundary is now configured elsewhere, since it is +unrelated to _HPX. + +[1] Operating System-directed configuration and Power Management + +Fixes: 40abb96c51bb ("[PATCH] pciehp: Fix programming hotplug parameters") +Signed-off-by: HÃ¥kon Bugge +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260129175237.727059-3-haakon.bugge@oracle.com +Signed-off-by: Sasha Levin +--- + drivers/pci/pci-acpi.c | 59 +++++++++++++++++------------------------- + drivers/pci/pci.h | 3 +++ + drivers/pci/pcie/aer.c | 3 --- + 3 files changed, 27 insertions(+), 38 deletions(-) + +diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c +index 0cd8a75e22580..3d02959e222fc 100644 +--- a/drivers/pci/pci-acpi.c ++++ b/drivers/pci/pci-acpi.c +@@ -271,21 +271,6 @@ static acpi_status decode_type1_hpx_record(union acpi_object *record, + return AE_OK; + } + +-static bool pcie_root_rcb_set(struct pci_dev *dev) +-{ +- struct pci_dev *rp = pcie_find_root_port(dev); +- u16 lnkctl; +- +- if (!rp) +- return false; +- +- pcie_capability_read_word(rp, PCI_EXP_LNKCTL, &lnkctl); +- if (lnkctl & PCI_EXP_LNKCTL_RCB) +- return true; +- +- return false; +-} +- + /* _HPX PCI Express Setting Record (Type 2) */ + struct hpx_type2 { + u32 revision; +@@ -311,6 +296,7 @@ static void program_hpx_type2(struct pci_dev *dev, struct hpx_type2 *hpx) + { + int pos; + u32 reg32; ++ const struct pci_host_bridge *host; + + if (!hpx) + return; +@@ -318,6 +304,15 @@ static void program_hpx_type2(struct pci_dev *dev, struct hpx_type2 *hpx) + if (!pci_is_pcie(dev)) + return; + ++ host = pci_find_host_bridge(dev->bus); ++ ++ /* ++ * Only do the _HPX Type 2 programming if OS owns PCIe native ++ * hotplug but not AER. ++ */ ++ if (!host->native_pcie_hotplug || host->native_aer) ++ return; ++ + if (hpx->revision > 1) { + pci_warn(dev, "PCIe settings rev %d not supported\n", + hpx->revision); +@@ -325,33 +320,27 @@ static void program_hpx_type2(struct pci_dev *dev, struct hpx_type2 *hpx) + } + + /* +- * Don't allow _HPX to change MPS or MRRS settings. We manage +- * those to make sure they're consistent with the rest of the +- * platform. ++ * We only allow _HPX to program DEVCTL bits related to AER, namely ++ * PCI_EXP_DEVCTL_CERE, PCI_EXP_DEVCTL_NFERE, PCI_EXP_DEVCTL_FERE, ++ * and PCI_EXP_DEVCTL_URRE. ++ * ++ * The rest of DEVCTL is managed by the OS to make sure it's ++ * consistent with the rest of the platform. + */ +- hpx->pci_exp_devctl_and |= PCI_EXP_DEVCTL_PAYLOAD | +- PCI_EXP_DEVCTL_READRQ; +- hpx->pci_exp_devctl_or &= ~(PCI_EXP_DEVCTL_PAYLOAD | +- PCI_EXP_DEVCTL_READRQ); ++ hpx->pci_exp_devctl_and |= ~PCI_EXP_AER_FLAGS; ++ hpx->pci_exp_devctl_or &= PCI_EXP_AER_FLAGS; + + /* Initialize Device Control Register */ + pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL, + ~hpx->pci_exp_devctl_and, hpx->pci_exp_devctl_or); + +- /* Initialize Link Control Register */ ++ /* Log if _HPX attempts to modify Link Control Register */ + if (pcie_cap_has_lnkctl(dev)) { +- +- /* +- * If the Root Port supports Read Completion Boundary of +- * 128, set RCB to 128. Otherwise, clear it. +- */ +- hpx->pci_exp_lnkctl_and |= PCI_EXP_LNKCTL_RCB; +- hpx->pci_exp_lnkctl_or &= ~PCI_EXP_LNKCTL_RCB; +- if (pcie_root_rcb_set(dev)) +- hpx->pci_exp_lnkctl_or |= PCI_EXP_LNKCTL_RCB; +- +- pcie_capability_clear_and_set_word(dev, PCI_EXP_LNKCTL, +- ~hpx->pci_exp_lnkctl_and, hpx->pci_exp_lnkctl_or); ++ if (hpx->pci_exp_lnkctl_and != 0xffff || ++ hpx->pci_exp_lnkctl_or != 0) ++ pci_info(dev, "_HPX attempts Link Control setting (AND %#06x OR %#06x)\n", ++ hpx->pci_exp_lnkctl_and, ++ hpx->pci_exp_lnkctl_or); + } + + /* Find Advanced Error Reporting Enhanced Capability */ +diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h +index 50da47c3fe72d..b1f393a42a875 100644 +--- a/drivers/pci/pci.h ++++ b/drivers/pci/pci.h +@@ -84,6 +84,9 @@ + #define PCI_BUS_BRIDGE_MEM_WINDOW 1 + #define PCI_BUS_BRIDGE_PREF_MEM_WINDOW 2 + ++#define PCI_EXP_AER_FLAGS (PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE | \ ++ PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE) ++ + extern const unsigned char pcie_link_speed[]; + extern bool pci_early_dump; + +diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c +index e5cbea3a4968b..36b6188a3a46f 100644 +--- a/drivers/pci/pcie/aer.c ++++ b/drivers/pci/pcie/aer.c +@@ -218,9 +218,6 @@ void pcie_ecrc_get_policy(char *str) + } + #endif /* CONFIG_PCIE_ECRC */ + +-#define PCI_EXP_AER_FLAGS (PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE | \ +- PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE) +- + int pcie_aer_is_native(struct pci_dev *dev) + { + struct pci_host_bridge *host = pci_find_host_bridge(dev->bus); +-- +2.51.0 + diff --git a/queue-6.12/pci-add-acs-quirk-for-pericom-pi7c9x2g404-switches-1.patch b/queue-6.12/pci-add-acs-quirk-for-pericom-pi7c9x2g404-switches-1.patch new file mode 100644 index 0000000000..e47f2ca38e --- /dev/null +++ b/queue-6.12/pci-add-acs-quirk-for-pericom-pi7c9x2g404-switches-1.patch @@ -0,0 +1,46 @@ +From 783e7c4a1b36c49960a0a52d190c3c9b2dbef83a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 17:08:33 +0100 +Subject: PCI: Add ACS quirk for Pericom PI7C9X2G404 switches [12d8:b404] + +From: Nicolas Cavallari + +[ Upstream commit 5907a90551e9f7968781f3a6ab8684458959beb3 ] + +12d8:b404 is apparently another PCI ID for Pericom PI7C9X2G404 (as +identified by the chip silkscreen and lspci). + +It is also affected by the PI7C9X2G errata (e.g. a network card attached +to it fails under load when P2P Redirect Request is enabled), so apply +the same quirk to this PCI ID too. + +PCI bridge [0604]: Pericom Semiconductor PI7C9X2G404 EV/SV PCIe2 4-Port/4-Lane Packet Switch [12d8:b404] (rev 01) + +Fixes: acd61ffb2f16 ("PCI: Add ACS quirk for Pericom PI7C9X2G switches") +Closes: https://lore.kernel.org/all/a1d926f0-4cb5-4877-a4df-617902648d80@green-communications.fr/ +Signed-off-by: Nicolas Cavallari +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260119160915.26456-1-nicolas.cavallari@green-communications.fr +Signed-off-by: Sasha Levin +--- + drivers/pci/quirks.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index 49a2d6858b4b7..d9ba1786fc1ae 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -6189,6 +6189,10 @@ DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_PERICOM, 0x2303, + pci_fixup_pericom_acs_store_forward); + DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_PERICOM, 0x2303, + pci_fixup_pericom_acs_store_forward); ++DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_PERICOM, 0xb404, ++ pci_fixup_pericom_acs_store_forward); ++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_PERICOM, 0xb404, ++ pci_fixup_pericom_acs_store_forward); + + static void nvidia_ion_ahci_fixup(struct pci_dev *pdev) + { +-- +2.51.0 + diff --git a/queue-6.12/pci-add-defines-for-bridge-window-indexing.patch b/queue-6.12/pci-add-defines-for-bridge-window-indexing.patch new file mode 100644 index 0000000000..cc8902c94b --- /dev/null +++ b/queue-6.12/pci-add-defines-for-bridge-window-indexing.patch @@ -0,0 +1,69 @@ +From ee07490c678b2dfeecf435a6b6e0084129f31ee4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 Aug 2025 16:11:00 +0300 +Subject: PCI: Add defines for bridge window indexing +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ilpo Järvinen + +[ Upstream commit e4934832c588f72bcc139d3ca0acc490c63a821c ] + +include/linux/pci.h provides PCI_BRIDGE_{IO,MEM,PREF_MEM}_WINDOW defines, +however, they're based on the resource array indexing in the pci_dev +struct. The struct pci_bus also has pointers to those same resources but +they start from zeroth index. + +Add PCI_BUS_BRIDGE_{IO,MEM,PREF_MEM}_WINDOW defines to get rid of literal +indexing. + +Signed-off-by: Ilpo Järvinen +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20250829131113.36754-12-ilpo.jarvinen@linux.intel.com +Stable-dep-of: 9abf79c8d7b4 ("PCI/ACPI: Restrict program_hpx_type2() to AER bits") +Signed-off-by: Sasha Levin +--- + drivers/pci/pci.h | 4 ++++ + drivers/pci/probe.c | 10 +++++++--- + 2 files changed, 11 insertions(+), 3 deletions(-) + +diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h +index c951f861a69b2..50da47c3fe72d 100644 +--- a/drivers/pci/pci.h ++++ b/drivers/pci/pci.h +@@ -80,6 +80,10 @@ + #define PCIE_MSG_CODE_DEASSERT_INTC 0x26 + #define PCIE_MSG_CODE_DEASSERT_INTD 0x27 + ++#define PCI_BUS_BRIDGE_IO_WINDOW 0 ++#define PCI_BUS_BRIDGE_MEM_WINDOW 1 ++#define PCI_BUS_BRIDGE_PREF_MEM_WINDOW 2 ++ + extern const unsigned char pcie_link_speed[]; + extern bool pci_early_dump; + +diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c +index 8d85810ab2f1f..9e419f14738a2 100644 +--- a/drivers/pci/probe.c ++++ b/drivers/pci/probe.c +@@ -539,9 +539,13 @@ void pci_read_bridge_bases(struct pci_bus *child) + for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++) + child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i]; + +- pci_read_bridge_io(child->self, child->resource[0], false); +- pci_read_bridge_mmio(child->self, child->resource[1], false); +- pci_read_bridge_mmio_pref(child->self, child->resource[2], false); ++ pci_read_bridge_io(child->self, ++ child->resource[PCI_BUS_BRIDGE_IO_WINDOW], false); ++ pci_read_bridge_mmio(child->self, ++ child->resource[PCI_BUS_BRIDGE_MEM_WINDOW], false); ++ pci_read_bridge_mmio_pref(child->self, ++ child->resource[PCI_BUS_BRIDGE_PREF_MEM_WINDOW], ++ false); + + if (dev->transparent) { + pci_bus_for_each_resource(child->parent, res) { +-- +2.51.0 + diff --git a/queue-6.12/pci-check-parent-for-null-in-of_pci_bus_release_doma.patch b/queue-6.12/pci-check-parent-for-null-in-of_pci_bus_release_doma.patch new file mode 100644 index 0000000000..32d87cbc54 --- /dev/null +++ b/queue-6.12/pci-check-parent-for-null-in-of_pci_bus_release_doma.patch @@ -0,0 +1,42 @@ +From 166e92aec2babf4eeba8b292af7e14b970c95663 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 23:39:42 +0300 +Subject: PCI: Check parent for NULL in of_pci_bus_release_domain_nr() + +From: Sergey Shtylyov + +[ Upstream commit f7245901de8978d829f80b3d8e36ed9a8fd18049 ] + +of_pci_bus_find_domain_nr() allows its parent parameter to be NULL but +of_pci_bus_release_domain_nr() (that undoes its effect) doesn't -- that +means it's going to blow up while calling of_get_pci_domain_nr() if the +parent parameter indeed happens to be NULL. Add the missing NULL check. + +Found by Linux Verification Center (linuxtesting.org) with the Svace static +analysis tool. + +Fixes: c14f7ccc9f5d ("PCI: Assign PCI domain IDs by ida_alloc()") +Signed-off-by: Sergey Shtylyov +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260127203944.28588-1-s.shtylyov@auroraos.dev +Signed-off-by: Sasha Levin +--- + drivers/pci/pci.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c +index cc6e0377a998a..aad6cb7949ff9 100644 +--- a/drivers/pci/pci.c ++++ b/drivers/pci/pci.c +@@ -6886,7 +6886,7 @@ static void of_pci_bus_release_domain_nr(struct device *parent, int domain_nr) + return; + + /* Release domain from IDA where it was allocated. */ +- if (of_get_pci_domain_nr(parent->of_node) == domain_nr) ++ if (parent && of_get_pci_domain_nr(parent->of_node) == domain_nr) + ida_free(&pci_domain_nr_static_ida, domain_nr); + else + ida_free(&pci_domain_nr_dynamic_ida, domain_nr); +-- +2.51.0 + diff --git a/queue-6.12/pci-do-not-attempt-to-set-exttag-for-vfs.patch b/queue-6.12/pci-do-not-attempt-to-set-exttag-for-vfs.patch new file mode 100644 index 0000000000..634f0309c3 --- /dev/null +++ b/queue-6.12/pci-do-not-attempt-to-set-exttag-for-vfs.patch @@ -0,0 +1,49 @@ +From 6a6f904d931ca622b7ee0725066ac119a41d42a2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 12 Nov 2025 10:54:40 +0100 +Subject: PCI: Do not attempt to set ExtTag for VFs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: HÃ¥kon Bugge + +[ Upstream commit 73711730a1128d91ebca1a6994ceeb18f36cb0cd ] + +The bit for enabling extended tags is Reserved and Preserved (RsvdP) for +VFs, according to PCIe r7.0 section 7.5.3.4 table 7.21. Hence, bail out +early from pci_configure_extended_tags() if the device is a VF. + +Otherwise, we may see incorrect log messages such as: + + kernel: pci 0000:af:00.2: enabling Extended Tags + +(af:00.2 is a VF) + +Fixes: 60db3a4d8cc9 ("PCI: Enable PCIe Extended Tags if supported") +Signed-off-by: HÃ¥kon Bugge +Signed-off-by: Bjorn Helgaas +Reviewed-by: Zhu Yanjun +Link: https://patch.msgid.link/20251112095442.1913258-1-haakon.bugge@oracle.com +Signed-off-by: Sasha Levin +--- + drivers/pci/probe.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c +index b358b93a02753..7010f74f1336a 100644 +--- a/drivers/pci/probe.c ++++ b/drivers/pci/probe.c +@@ -2175,7 +2175,8 @@ int pci_configure_extended_tags(struct pci_dev *dev, void *ign) + u16 ctl; + int ret; + +- if (!pci_is_pcie(dev)) ++ /* PCI_EXP_DEVCTL_EXT_TAG is RsvdP in VFs */ ++ if (!pci_is_pcie(dev) || dev->is_virtfn) + return 0; + + ret = pcie_capability_read_dword(dev, PCI_EXP_DEVCAP, &cap); +-- +2.51.0 + diff --git a/queue-6.12/pci-initialize-rcb-from-pci_configure_device.patch b/queue-6.12/pci-initialize-rcb-from-pci_configure_device.patch new file mode 100644 index 0000000000..6a9bfb5e1b --- /dev/null +++ b/queue-6.12/pci-initialize-rcb-from-pci_configure_device.patch @@ -0,0 +1,90 @@ +From 51a30f3e43dd0a26ee15f1e55751d29a6a78dffc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 18:52:32 +0100 +Subject: PCI: Initialize RCB from pci_configure_device() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: HÃ¥kon Bugge + +[ Upstream commit 1a6845aaa6de81f95959b380b45de8f10d6a8502 ] + +Commit e42010d8207f ("PCI: Set Read Completion Boundary to 128 iff Root +Port supports it (_HPX)") worked around a bogus _HPX type 2 record, which +caused program_hpx_type2() to set the RCB in an endpoint even though the +Root Port did not have the RCB bit set. + +e42010d8207f fixed that by setting the RCB in the endpoint only when it was +set in the Root Port. + +In retrospect, program_hpx_type2() is intended for AER-related settings, +and the RCB should be configured elsewhere so it doesn't depend on the +presence or contents of an _HPX record. + +Explicitly program the RCB from pci_configure_device() so it matches the +Root Port's RCB. The Root Port may not be visible to virtualized guests; +in that case, leave RCB alone. + +Fixes: e42010d8207f ("PCI: Set Read Completion Boundary to 128 iff Root Port supports it (_HPX)") +Signed-off-by: HÃ¥kon Bugge +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260129175237.727059-2-haakon.bugge@oracle.com +Signed-off-by: Sasha Levin +--- + drivers/pci/probe.c | 32 ++++++++++++++++++++++++++++++++ + 1 file changed, 32 insertions(+) + +diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c +index 7010f74f1336a..8d85810ab2f1f 100644 +--- a/drivers/pci/probe.c ++++ b/drivers/pci/probe.c +@@ -2301,6 +2301,37 @@ static void pci_configure_serr(struct pci_dev *dev) + } + } + ++static void pci_configure_rcb(struct pci_dev *dev) ++{ ++ struct pci_dev *rp; ++ u16 rp_lnkctl; ++ ++ /* ++ * Per PCIe r7.0, sec 7.5.3.7, RCB is only meaningful in Root Ports ++ * (where it is read-only), Endpoints, and Bridges. It may only be ++ * set for Endpoints and Bridges if it is set in the Root Port. For ++ * Endpoints, it is 'RsvdP' for Virtual Functions. ++ */ ++ if (!pci_is_pcie(dev) || ++ pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT || ++ pci_pcie_type(dev) == PCI_EXP_TYPE_UPSTREAM || ++ pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM || ++ pci_pcie_type(dev) == PCI_EXP_TYPE_RC_EC || ++ dev->is_virtfn) ++ return; ++ ++ /* Root Port often not visible to virtualized guests */ ++ rp = pcie_find_root_port(dev); ++ if (!rp) ++ return; ++ ++ pcie_capability_read_word(rp, PCI_EXP_LNKCTL, &rp_lnkctl); ++ pcie_capability_clear_and_set_word(dev, PCI_EXP_LNKCTL, ++ PCI_EXP_LNKCTL_RCB, ++ (rp_lnkctl & PCI_EXP_LNKCTL_RCB) ? ++ PCI_EXP_LNKCTL_RCB : 0); ++} ++ + static void pci_configure_device(struct pci_dev *dev) + { + pci_configure_mps(dev); +@@ -2310,6 +2341,7 @@ static void pci_configure_device(struct pci_dev *dev) + pci_configure_aspm_l1ss(dev); + pci_configure_eetlp_prefix(dev); + pci_configure_serr(dev); ++ pci_configure_rcb(dev); + + pci_acpi_program_hp_params(dev); + } +-- +2.51.0 + diff --git a/queue-6.12/pci-mark-3ware-9650sa-root-port-extended-tags-as-bro.patch b/queue-6.12/pci-mark-3ware-9650sa-root-port-extended-tags-as-bro.patch new file mode 100644 index 0000000000..d571ce4efd --- /dev/null +++ b/queue-6.12/pci-mark-3ware-9650sa-root-port-extended-tags-as-bro.patch @@ -0,0 +1,56 @@ +From 93ddccd29d54fc10e8cc10b09bd814abb0952f96 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 15:31:10 +0100 +Subject: PCI: Mark 3ware-9650SA Root Port Extended Tags as broken +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jörg Wedekind + +[ Upstream commit 959ac08a2c2811305be8c2779779e8b0932e5a99 ] + +Per PCIe r7.0, sec 2.2.6.2.1 and 7.5.3.4, a Requester may not use 8-bit Tags +unless its Extended Tag Field Enable is set, but all Receivers/Completers +must handle 8-bit Tags correctly regardless of their Extended Tag Field +Enable. + +Some devices do not handle 8-bit Tags as Completers, so add a quirk for +them. If we find such a device, we disable Extended Tags for the entire +hierarchy to make peer-to-peer DMA possible. + +The 3ware 9650SA seems to have issues with handling 8-bit tags. Mark it as +broken. + +This fixes PCI Parity Errors like : + + 3w-9xxx: scsi0: ERROR: (0x06:0x000C): PCI Parity Error: clearing. + 3w-9xxx: scsi0: ERROR: (0x06:0x000D): PCI Abort: clearing. + 3w-9xxx: scsi0: ERROR: (0x06:0x000E): Controller Queue Error: clearing. + 3w-9xxx: scsi0: ERROR: (0x06:0x0010): Microcontroller Error: clearing. + +Fixes: 60db3a4d8cc9 ("PCI: Enable PCIe Extended Tags if supported") +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=202425 +Signed-off-by: Jörg Wedekind +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260119143114.21948-1-joerg@wedekind.de +Signed-off-by: Sasha Levin +--- + drivers/pci/quirks.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index 18fa918b4e537..49a2d6858b4b7 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -5581,6 +5581,7 @@ static void quirk_no_ext_tags(struct pci_dev *pdev) + pci_walk_bus(bridge->bus, pci_configure_extended_tags, NULL); + } + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_3WARE, 0x1004, quirk_no_ext_tags); ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_3WARE, 0x1005, quirk_no_ext_tags); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0132, quirk_no_ext_tags); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0140, quirk_no_ext_tags); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0141, quirk_no_ext_tags); +-- +2.51.0 + diff --git a/queue-6.12/pci-mediatek-fix-irq-domain-leak-when-msi-allocation.patch b/queue-6.12/pci-mediatek-fix-irq-domain-leak-when-msi-allocation.patch new file mode 100644 index 0000000000..601ac2155d --- /dev/null +++ b/queue-6.12/pci-mediatek-fix-irq-domain-leak-when-msi-allocation.patch @@ -0,0 +1,45 @@ +From 6e8270121c5df565f84d1507552799be49dabed8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 19 Nov 2025 10:33:08 +0800 +Subject: PCI: mediatek: Fix IRQ domain leak when MSI allocation fails + +From: Haotian Zhang + +[ Upstream commit 7f0cdcddf8bef1c8c18f9be6708073fd3790a20f ] + +In mtk_pcie_init_irq_domain(), if mtk_pcie_allocate_msi_domains() +fails after port->irq_domain has been successfully created via +irq_domain_create_linear(), the function returns directly without +cleaning up the allocated IRQ domain, resulting in a resource leak. + +Add irq_domain_remove() call in the error path to properly release the +INTx IRQ domain before returning the error. + +Fixes: 43e6409db64d ("PCI: mediatek: Add MSI support for MT2712 and MT7622") +Signed-off-by: Haotian Zhang +Signed-off-by: Manivannan Sadhasivam +Link: https://patch.msgid.link/20251119023308.476-1-vulab@iscas.ac.cn +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/pcie-mediatek.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c +index 7f7d04c2ea573..c4cc9d76b42a0 100644 +--- a/drivers/pci/controller/pcie-mediatek.c ++++ b/drivers/pci/controller/pcie-mediatek.c +@@ -579,8 +579,10 @@ static int mtk_pcie_init_irq_domain(struct mtk_pcie_port *port, + + if (IS_ENABLED(CONFIG_PCI_MSI)) { + ret = mtk_pcie_allocate_msi_domains(port); +- if (ret) ++ if (ret) { ++ irq_domain_remove(port->irq_domain); + return ret; ++ } + } + + return 0; +-- +2.51.0 + diff --git a/queue-6.12/pci-p2pdma-release-per-cpu-pgmap-ref-when-vm_insert_.patch b/queue-6.12/pci-p2pdma-release-per-cpu-pgmap-ref-when-vm_insert_.patch new file mode 100644 index 0000000000..4065f0e0aa --- /dev/null +++ b/queue-6.12/pci-p2pdma-release-per-cpu-pgmap-ref-when-vm_insert_.patch @@ -0,0 +1,42 @@ +From e30b2db247509e3237a72a532a92f9a9a9f0e8a6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 12:04:34 +0800 +Subject: PCI/P2PDMA: Release per-CPU pgmap ref when vm_insert_page() fails + +From: Hou Tao + +[ Upstream commit 6220694c52a5a04102b48109e4f24e958b559bd3 ] + +When vm_insert_page() fails in p2pmem_alloc_mmap(), p2pmem_alloc_mmap() +doesn't invoke percpu_ref_put() to free the per-CPU ref of pgmap acquired +after gen_pool_alloc_owner(), and memunmap_pages() will hang forever when +trying to remove the PCI device. + +Fix it by adding the missed percpu_ref_put(). + +Fixes: 7e9c7ef83d78 ("PCI/P2PDMA: Allow userspace VMA allocations through sysfs") +Signed-off-by: Hou Tao +Signed-off-by: Bjorn Helgaas +Reviewed-by: Logan Gunthorpe +Reviewed-by: Alistair Popple +Link: https://patch.msgid.link/20251220040446.274991-2-houtao@huaweicloud.com +Signed-off-by: Sasha Levin +--- + drivers/pci/p2pdma.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c +index 52e1564eadd0b..ec53b2b0d57fe 100644 +--- a/drivers/pci/p2pdma.c ++++ b/drivers/pci/p2pdma.c +@@ -143,6 +143,7 @@ static int p2pmem_alloc_mmap(struct file *filp, struct kobject *kobj, + ret = vm_insert_page(vma, vaddr, virt_to_page(kaddr)); + if (ret) { + gen_pool_free(p2pdma->pool, (uintptr_t)kaddr, len); ++ percpu_ref_put(ref); + return ret; + } + percpu_ref_get(ref); +-- +2.51.0 + diff --git a/queue-6.12/pci-pm-avoid-redundant-delays-on-d3hot-d3cold.patch b/queue-6.12/pci-pm-avoid-redundant-delays-on-d3hot-d3cold.patch new file mode 100644 index 0000000000..fa475f573f --- /dev/null +++ b/queue-6.12/pci-pm-avoid-redundant-delays-on-d3hot-d3cold.patch @@ -0,0 +1,56 @@ +From 28da351cc2e385faf47a70cb4ba24f711a52ac71 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Oct 2025 15:40:09 -0700 +Subject: PCI/PM: Avoid redundant delays on D3hot->D3cold + +From: Brian Norris + +[ Upstream commit 4d982084507d663df160546c4c48066a8887ed89 ] + +When transitioning to D3cold, __pci_set_power_state() first transitions to +D3hot. If the device was already in D3hot, this adds excess work: + + (a) read/modify/write PMCSR; and + (b) excess delay (pci_dev_d3_sleep()). + +For (b), we already performed the necessary delay on the previous D3hot +entry; this was extra noticeable when evaluating runtime PM transition +latency. + +Check whether we're already in the target state before continuing. + +Note that __pci_set_power_state() already does this same check for other +state transitions, but D3cold is special because __pci_set_power_state() +converts it to D3hot for the purposes of PMCSR. + +This seems to be an oversight in commit 0aacdc957401 ("PCI/PM: Clean up +pci_set_low_power_state()"). + +Fixes: 0aacdc957401 ("PCI/PM: Clean up pci_set_low_power_state()") +Signed-off-by: Brian Norris +Signed-off-by: Brian Norris +[bhelgaas: reverse test to match other "dev->current_state == state" cases] +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20251003154008.1.I7a21c240b30062c66471329567a96dceb6274358@changeid +Signed-off-by: Sasha Levin +--- + drivers/pci/pci.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c +index 963436edea1cb..cc6e0377a998a 100644 +--- a/drivers/pci/pci.c ++++ b/drivers/pci/pci.c +@@ -1573,6 +1573,9 @@ static int pci_set_low_power_state(struct pci_dev *dev, pci_power_t state, bool + || (state == PCI_D2 && !dev->d2_support)) + return -EIO; + ++ if (dev->current_state == state) ++ return 0; ++ + pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr); + if (PCI_POSSIBLE_ERROR(pmcsr)) { + pci_err(dev, "Unable to change power state from %s to %s, device inaccessible\n", +-- +2.51.0 + diff --git a/queue-6.12/pci-portdrv-fix-potential-resource-leak.patch b/queue-6.12/pci-portdrv-fix-potential-resource-leak.patch new file mode 100644 index 0000000000..d26121bc87 --- /dev/null +++ b/queue-6.12/pci-portdrv-fix-potential-resource-leak.patch @@ -0,0 +1,48 @@ +From 12f66a54e39095a97e5f1d870e1932cb72b0869e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Dec 2025 16:13:49 +0100 +Subject: PCI/portdrv: Fix potential resource leak +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Uwe Kleine-König + +[ Upstream commit 01464a3fdf91c041a381d93a1b6fefbdb819a46f ] + +pcie_port_probe_service() unconditionally calls get_device() (unless it +fails). So drop that reference also unconditionally as it's fine for a +PCIe driver to not have a remove callback. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Uwe Kleine-König +Signed-off-by: Bjorn Helgaas +Reviewed-by: Ilpo Järvinen +Reviewed-by: Jonathan Cameron +Link: https://patch.msgid.link/e1c68c3b3f1af8427e98ca5e2c79f8bf0ebe2ce4.1764688034.git.u.kleine-koenig@baylibre.com +Signed-off-by: Sasha Levin +--- + drivers/pci/pcie/portdrv.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/pci/pcie/portdrv.c b/drivers/pci/pcie/portdrv.c +index ec2c768c687f0..75068c5029b01 100644 +--- a/drivers/pci/pcie/portdrv.c ++++ b/drivers/pci/pcie/portdrv.c +@@ -555,10 +555,10 @@ static int pcie_port_remove_service(struct device *dev) + + pciedev = to_pcie_device(dev); + driver = to_service_driver(dev->driver); +- if (driver && driver->remove) { ++ if (driver && driver->remove) + driver->remove(pciedev); +- put_device(dev); +- } ++ ++ put_device(dev); + return 0; + } + +-- +2.51.0 + diff --git a/queue-6.12/perf-arm_spe-properly-set-hw.state-on-failures.patch b/queue-6.12/perf-arm_spe-properly-set-hw.state-on-failures.patch new file mode 100644 index 0000000000..2269897c36 --- /dev/null +++ b/queue-6.12/perf-arm_spe-properly-set-hw.state-on-failures.patch @@ -0,0 +1,108 @@ +From 21a7535524be03e60baecc34d672ace0695463ca Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 14:40:43 +0000 +Subject: perf: arm_spe: Properly set hw.state on failures + +From: Leo Yan + +[ Upstream commit 283182c1c239f6873d1a50e9e710c1a699f2256b ] + +When arm_spe_pmu_next_off() fails to calculate a valid limit, it returns +zero to indicate that tracing should not start. However, the caller +arm_spe_perf_aux_output_begin() does not propagate this failure by +updating hwc->state, cause the error to be silently ignored by upper +layers. + +Because hwc->state remains zero after a failure, arm_spe_pmu_start() +continues to programs filter registers unnecessarily. The driver +still reports success to the perf core, so the core assumes the SPE +event was enabled and proceeds to enable other events. This breaks +event group semantics: SPE is already stopped while other events in the +same group are enabled. + +Fix this by updating arm_spe_perf_aux_output_begin() to return a status +code indicating success (0) or failure (-EIO). Both the interrupt +handler and arm_spe_pmu_start() check the return value and call +arm_spe_pmu_stop() to set PERF_HES_STOPPED in hwc->state. + +In the interrupt handler, the period (e.g., period_left) needs to be +updated, so PERF_EF_UPDATE is passed to arm_spe_pmu_stop(). When the +error occurs during event start, the trace unit is not yet enabled, so +a flag '0' is used to drain buffer and update state only. + +Fixes: d5d9696b0380 ("drivers/perf: Add support for ARMv8.2 Statistical Profiling Extension") +Signed-off-by: Leo Yan +Signed-off-by: Will Deacon +Signed-off-by: Sasha Levin +--- + drivers/perf/arm_spe_pmu.c | 18 ++++++++++++------ + 1 file changed, 12 insertions(+), 6 deletions(-) + +diff --git a/drivers/perf/arm_spe_pmu.c b/drivers/perf/arm_spe_pmu.c +index abd23430dc033..2fce871a1882d 100644 +--- a/drivers/perf/arm_spe_pmu.c ++++ b/drivers/perf/arm_spe_pmu.c +@@ -102,6 +102,8 @@ struct arm_spe_pmu { + /* Keep track of our dynamic hotplug state */ + static enum cpuhp_state arm_spe_pmu_online; + ++static void arm_spe_pmu_stop(struct perf_event *event, int flags); ++ + enum arm_spe_pmu_buf_fault_action { + SPE_PMU_BUF_FAULT_ACT_SPURIOUS, + SPE_PMU_BUF_FAULT_ACT_FATAL, +@@ -497,8 +499,8 @@ static u64 arm_spe_pmu_next_off(struct perf_output_handle *handle) + return limit; + } + +-static void arm_spe_perf_aux_output_begin(struct perf_output_handle *handle, +- struct perf_event *event) ++static int arm_spe_perf_aux_output_begin(struct perf_output_handle *handle, ++ struct perf_event *event) + { + u64 base, limit; + struct arm_spe_pmu_buf *buf; +@@ -506,7 +508,6 @@ static void arm_spe_perf_aux_output_begin(struct perf_output_handle *handle, + /* Start a new aux session */ + buf = perf_aux_output_begin(handle, event); + if (!buf) { +- event->hw.state |= PERF_HES_STOPPED; + /* + * We still need to clear the limit pointer, since the + * profiler might only be disabled by virtue of a fault. +@@ -526,6 +527,7 @@ static void arm_spe_perf_aux_output_begin(struct perf_output_handle *handle, + + out_write_limit: + write_sysreg_s(limit, SYS_PMBLIMITR_EL1); ++ return (limit & PMBLIMITR_EL1_E) ? 0 : -EIO; + } + + static void arm_spe_perf_aux_output_end(struct perf_output_handle *handle) +@@ -665,7 +667,10 @@ static irqreturn_t arm_spe_pmu_irq_handler(int irq, void *dev) + * when we get to it. + */ + if (!(handle->aux_flags & PERF_AUX_FLAG_TRUNCATED)) { +- arm_spe_perf_aux_output_begin(handle, event); ++ if (arm_spe_perf_aux_output_begin(handle, event)) { ++ arm_spe_pmu_stop(event, PERF_EF_UPDATE); ++ break; ++ } + isb(); + } + break; +@@ -760,9 +765,10 @@ static void arm_spe_pmu_start(struct perf_event *event, int flags) + struct perf_output_handle *handle = this_cpu_ptr(spe_pmu->handle); + + hwc->state = 0; +- arm_spe_perf_aux_output_begin(handle, event); +- if (hwc->state) ++ if (arm_spe_perf_aux_output_begin(handle, event)) { ++ arm_spe_pmu_stop(event, 0); + return; ++ } + + reg = arm_spe_event_to_pmsfcr(event); + write_sysreg_s(reg, SYS_PMSFCR_EL1); +-- +2.51.0 + diff --git a/queue-6.12/perf-x86-core-do-not-set-bit-width-for-unavailable-c.patch b/queue-6.12/perf-x86-core-do-not-set-bit-width-for-unavailable-c.patch new file mode 100644 index 0000000000..49005af0f0 --- /dev/null +++ b/queue-6.12/perf-x86-core-do-not-set-bit-width-for-unavailable-c.patch @@ -0,0 +1,46 @@ +From ec81912f7db1ee6d8b1dcf282cdbcb6fcee94b5c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Dec 2025 16:16:46 -0800 +Subject: perf/x86/core: Do not set bit width for unavailable counters + +From: Sandipan Das + +[ Upstream commit b456a6ba5756b6fb7e651775343e713bd08418e7 ] + +Not all x86 processors have fixed counters. It may also be the case that +a processor has only fixed counters and no general-purpose counters. Set +the bit widths corresponding to each counter type only if such counters +are available. + +Fixes: b3d9468a8bd2 ("perf, x86: Expose perf capability to other modules") +Signed-off-by: Sandipan Das +Co-developed-by: Dapeng Mi +Signed-off-by: Dapeng Mi +Signed-off-by: Mingwei Zhang +Signed-off-by: Sean Christopherson +Signed-off-by: Peter Zijlstra (Intel) +Tested-by: Xudong Hao +Link: https://patch.msgid.link/20251206001720.468579-11-seanjc@google.com +Signed-off-by: Sasha Levin +--- + arch/x86/events/core.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c +index 86ba035f17a35..0f935cced0b7d 100644 +--- a/arch/x86/events/core.c ++++ b/arch/x86/events/core.c +@@ -3051,8 +3051,8 @@ void perf_get_x86_pmu_capability(struct x86_pmu_capability *cap) + cap->version = x86_pmu.version; + cap->num_counters_gp = x86_pmu_num_counters(NULL); + cap->num_counters_fixed = x86_pmu_num_counters_fixed(NULL); +- cap->bit_width_gp = x86_pmu.cntval_bits; +- cap->bit_width_fixed = x86_pmu.cntval_bits; ++ cap->bit_width_gp = cap->num_counters_gp ? x86_pmu.cntval_bits : 0; ++ cap->bit_width_fixed = cap->num_counters_fixed ? x86_pmu.cntval_bits : 0; + cap->events_mask = (unsigned int)x86_pmu.events_maskl; + cap->events_mask_len = x86_pmu.events_mask_len; + cap->pebs_ept = x86_pmu.pebs_ept; +-- +2.51.0 + diff --git a/queue-6.12/phy-freescale-imx8qm-hsio-fix-null-pointer-dereferen.patch b/queue-6.12/phy-freescale-imx8qm-hsio-fix-null-pointer-dereferen.patch new file mode 100644 index 0000000000..67d708be20 --- /dev/null +++ b/queue-6.12/phy-freescale-imx8qm-hsio-fix-null-pointer-dereferen.patch @@ -0,0 +1,41 @@ +From 17574d76c97c67d44c93910d7704eb156bba889b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 17:50:23 +0100 +Subject: phy: freescale: imx8qm-hsio: fix NULL pointer dereference + +From: Thomas Richard + +[ Upstream commit 4dd5d4c0361af0a3fd24f45c815996abf4429770 ] + +During the probe the refclk_pad pointer is set to NULL if the +'fsl,refclk-pad-mode' property is not defined in the devicetree node. But +in imx_hsio_configure_clk_pad() this pointer is unconditionally used which +could result in a NULL pointer dereference. So check the pointer before to +use it. + +Fixes: 82c56b6dd24f ("phy: freescale: imx8qm-hsio: Add i.MX8QM HSIO PHY driver support") +Signed-off-by: Thomas Richard +Reviewed-by: Richard Zhu +Link: https://patch.msgid.link/20260114-phy-fsl-imx8qm-hsio-fix-null-pointer-dereference-v1-1-730e941be464@bootlin.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/phy/freescale/phy-fsl-imx8qm-hsio.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/phy/freescale/phy-fsl-imx8qm-hsio.c b/drivers/phy/freescale/phy-fsl-imx8qm-hsio.c +index 977d21d753a59..279b8ac7822df 100644 +--- a/drivers/phy/freescale/phy-fsl-imx8qm-hsio.c ++++ b/drivers/phy/freescale/phy-fsl-imx8qm-hsio.c +@@ -251,7 +251,7 @@ static void imx_hsio_configure_clk_pad(struct phy *phy) + struct imx_hsio_lane *lane = phy_get_drvdata(phy); + struct imx_hsio_priv *priv = lane->priv; + +- if (strncmp(priv->refclk_pad, "output", 6) == 0) { ++ if (priv->refclk_pad && strncmp(priv->refclk_pad, "output", 6) == 0) { + pll = true; + regmap_update_bits(priv->misc, HSIO_CTRL0, + HSIO_IOB_A_0_TXOE | HSIO_IOB_A_0_M1M0_MASK, +-- +2.51.0 + diff --git a/queue-6.12/pinctrl-equilibrium-fix-device-node-reference-leak-i.patch b/queue-6.12/pinctrl-equilibrium-fix-device-node-reference-leak-i.patch new file mode 100644 index 0000000000..06352bd5fe --- /dev/null +++ b/queue-6.12/pinctrl-equilibrium-fix-device-node-reference-leak-i.patch @@ -0,0 +1,44 @@ +From 83a5b9ff282959a8eab2e45a17f53614be6a1bff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 01:30:07 +0800 +Subject: pinctrl: equilibrium: Fix device node reference leak in + pinbank_init() + +From: Felix Gu + +[ Upstream commit c0b4a4feeb43305a754893d8d9c6b2b5a52d45ac ] + +When calling of_parse_phandle_with_fixed_args(), the caller is +responsible to call of_node_put() to release the reference of device +node. + +In pinbank_init(), the reference of the node obtained from the +"gpio-ranges" property is never released, resulting in a reference +count leak. + +Add the missing of_node_put() call to fix the leak. + +Fixes: 1948d5c51dba ("pinctrl: Add pinmux & GPIO controller driver for a new SoC") +Signed-off-by: Felix Gu +Acked-by: Andy Shevchenko +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-equilibrium.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/pinctrl/pinctrl-equilibrium.c b/drivers/pinctrl/pinctrl-equilibrium.c +index 3a9a0f059090f..c82491da2cc9f 100644 +--- a/drivers/pinctrl/pinctrl-equilibrium.c ++++ b/drivers/pinctrl/pinctrl-equilibrium.c +@@ -841,6 +841,7 @@ static int pinbank_init(struct device_node *np, + + bank->pin_base = spec.args[1]; + bank->nr_pins = spec.args[2]; ++ of_node_put(spec.np); + + bank->aval_pinmap = readl(bank->membase + REG_AVAIL); + bank->id = id; +-- +2.51.0 + diff --git a/queue-6.12/pinctrl-qcom-sm8250-lpass-lpi-fix-i2s2_data_groups-d.patch b/queue-6.12/pinctrl-qcom-sm8250-lpass-lpi-fix-i2s2_data_groups-d.patch new file mode 100644 index 0000000000..3d1d768906 --- /dev/null +++ b/queue-6.12/pinctrl-qcom-sm8250-lpass-lpi-fix-i2s2_data_groups-d.patch @@ -0,0 +1,38 @@ +From 0cfff0df2d7d57b199c0a150dc38ffa525880e86 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 12:22:28 +0100 +Subject: pinctrl: qcom: sm8250-lpass-lpi: Fix i2s2_data_groups definition + +From: Luca Weiss + +[ Upstream commit eabf273c8466af3f033473c2d2267a6ea7946d57 ] + +The i2s2_data function is available on both gpio12 and gpio13. Fix the +groups definition. + +Fixes: 6e261d1090d6 ("pinctrl: qcom: Add sm8250 lpass lpi pinctrl driver") +Signed-off-by: Luca Weiss +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c +index 9791d9ba5087c..4e90b29640ff0 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c ++++ b/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c +@@ -73,7 +73,7 @@ static const char * const i2s1_ws_groups[] = { "gpio7" }; + static const char * const i2s1_data_groups[] = { "gpio8", "gpio9" }; + static const char * const wsa_swr_clk_groups[] = { "gpio10" }; + static const char * const wsa_swr_data_groups[] = { "gpio11" }; +-static const char * const i2s2_data_groups[] = { "gpio12", "gpio12" }; ++static const char * const i2s2_data_groups[] = { "gpio12", "gpio13" }; + + static const struct lpi_pingroup sm8250_groups[] = { + LPI_PINGROUP(0, 0, swr_tx_clk, qua_mi2s_sclk, _, _), +-- +2.51.0 + diff --git a/queue-6.12/pinctrl-single-fix-refcount-leak-in-pcs_add_gpio_fun.patch b/queue-6.12/pinctrl-single-fix-refcount-leak-in-pcs_add_gpio_fun.patch new file mode 100644 index 0000000000..6dbeee226b --- /dev/null +++ b/queue-6.12/pinctrl-single-fix-refcount-leak-in-pcs_add_gpio_fun.patch @@ -0,0 +1,50 @@ +From 1f614a4772c9f9995b3d3944dc1f0fb942cd4218 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 08:07:35 +0000 +Subject: pinctrl: single: fix refcount leak in pcs_add_gpio_func() + +From: Wei Li + +[ Upstream commit 353353309b0f7afa407df29e455f9d15b5acc296 ] + +of_parse_phandle_with_args() returns a device_node pointer with refcount +incremented in gpiospec.np. The loop iterates through all phandles but +never releases the reference, causing a refcount leak on each iteration. + +Add of_node_put() calls to release the reference after extracting the +needed arguments and on the error path when devm_kzalloc() fails. + +This bug was detected by our static analysis tool and verified by my +code review. + +Fixes: a1a277eb76b3 ("pinctrl: single: create new gpio function range") +Signed-off-by: Wei Li +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-single.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c +index 2218d65a7d842..a2fb549307adb 100644 +--- a/drivers/pinctrl/pinctrl-single.c ++++ b/drivers/pinctrl/pinctrl-single.c +@@ -1359,6 +1359,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) + } + range = devm_kzalloc(pcs->dev, sizeof(*range), GFP_KERNEL); + if (!range) { ++ of_node_put(gpiospec.np); + ret = -ENOMEM; + break; + } +@@ -1368,6 +1369,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) + mutex_lock(&pcs->mutex); + list_add_tail(&range->node, &pcs->gpiofuncs); + mutex_unlock(&pcs->mutex); ++ of_node_put(gpiospec.np); + } + return ret; + } +-- +2.51.0 + diff --git a/queue-6.12/platform-chrome-cros_ec_lightbar-fix-response-size-i.patch b/queue-6.12/platform-chrome-cros_ec_lightbar-fix-response-size-i.patch new file mode 100644 index 0000000000..4c7798abea --- /dev/null +++ b/queue-6.12/platform-chrome-cros_ec_lightbar-fix-response-size-i.patch @@ -0,0 +1,43 @@ +From 9f2890df2c85fd159dce181b6aedd8f803f62b8d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 04:03:35 +0000 +Subject: platform/chrome: cros_ec_lightbar: Fix response size initialization + +From: Tzung-Bi Shih + +[ Upstream commit ec0dd36dbf8b0b209e63d0cd795451fa2203c736 ] + +Commit 1e7913ff5f9f ("platform/chrome: cros_ec_lightbar: Reduce +ligthbar get version command") meant to set smaller values for both +request and response sizes. + +However, it incorrectly assigned the response size to the `result` field +instead of `insize`. Fix it. + +Reported-by: Gwendal Grignou +Closes: https://lore.kernel.org/chrome-platform/CAMHSBOVrrYaB=1nEqZk09VkczCrj=6B-P8Fe29TpPdSDgT2CCQ@mail.gmail.com +Fixes: 1e7913ff5f9f ("platform/chrome: cros_ec_lightbar: Reduce ligthbar get version command") +Link: https://lore.kernel.org/r/20260130040335.361997-1-tzungbi@kernel.org +Reviewed-by: Gwendal Grignou +Signed-off-by: Tzung-Bi Shih +Signed-off-by: Sasha Levin +--- + drivers/platform/chrome/cros_ec_lightbar.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/platform/chrome/cros_ec_lightbar.c b/drivers/platform/chrome/cros_ec_lightbar.c +index 1e69f61115a4d..de64292faa24e 100644 +--- a/drivers/platform/chrome/cros_ec_lightbar.c ++++ b/drivers/platform/chrome/cros_ec_lightbar.c +@@ -119,7 +119,7 @@ static int get_lightbar_version(struct cros_ec_dev *ec, + param = (struct ec_params_lightbar *)msg->data; + param->cmd = LIGHTBAR_CMD_VERSION; + msg->outsize = sizeof(param->cmd); +- msg->result = sizeof(resp->version); ++ msg->insize = sizeof(resp->version); + ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg); + if (ret < 0 && ret != -EINVAL) { + ret = 0; +-- +2.51.0 + diff --git a/queue-6.12/platform-chrome-cros_typec_switch-don-t-touch-struct.patch b/queue-6.12/platform-chrome-cros_typec_switch-don-t-touch-struct.patch new file mode 100644 index 0000000000..555006ed9d --- /dev/null +++ b/queue-6.12/platform-chrome-cros_typec_switch-don-t-touch-struct.patch @@ -0,0 +1,54 @@ +From c3143833729e1b20adc2c55cdaa244a9d0ca3215 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 14:12:30 +0100 +Subject: platform/chrome: cros_typec_switch: Don't touch struct + fwnode_handle::dev + +From: Andy Shevchenko + +[ Upstream commit e1adf48853bc715f4deea074932aa1c44eb7abea ] + +The 'dev' field in struct fwnode is special and related to device links, +There no driver should use it for printing messages. Fix incorrect use +of private field. + +Fixes: affc804c44c8 ("platform/chrome: cros_typec_switch: Add switch driver") +Signed-off-by: Andy Shevchenko +Link: https://lore.kernel.org/r/20260120131413.1697891-2-andriy.shevchenko@linux.intel.com +Signed-off-by: Tzung-Bi Shih +Signed-off-by: Sasha Levin +--- + drivers/platform/chrome/cros_typec_switch.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/platform/chrome/cros_typec_switch.c b/drivers/platform/chrome/cros_typec_switch.c +index 07a19386dc4ee..b50e4651c6470 100644 +--- a/drivers/platform/chrome/cros_typec_switch.c ++++ b/drivers/platform/chrome/cros_typec_switch.c +@@ -230,20 +230,20 @@ static int cros_typec_register_switches(struct cros_typec_switch_data *sdata) + + adev = to_acpi_device_node(fwnode); + if (!adev) { +- dev_err(fwnode->dev, "Couldn't get ACPI device handle\n"); ++ dev_err(dev, "Couldn't get ACPI device handle for %pfwP\n", fwnode); + ret = -ENODEV; + goto err_switch; + } + + ret = acpi_evaluate_integer(adev->handle, "_ADR", NULL, &index); + if (ACPI_FAILURE(ret)) { +- dev_err(fwnode->dev, "_ADR wasn't evaluated\n"); ++ dev_err(dev, "_ADR wasn't evaluated for %pfwP\n", fwnode); + ret = -ENODATA; + goto err_switch; + } + + if (index >= EC_USB_PD_MAX_PORTS) { +- dev_err(fwnode->dev, "Invalid port index number: %llu\n", index); ++ dev_err(dev, "%pfwP: Invalid port index number: %llu\n", fwnode, index); + ret = -EINVAL; + goto err_switch; + } +-- +2.51.0 + diff --git a/queue-6.12/platform-x86-amd-pmf-prevent-tee-errors-after-hibern.patch b/queue-6.12/platform-x86-amd-pmf-prevent-tee-errors-after-hibern.patch new file mode 100644 index 0000000000..e7aefc8884 --- /dev/null +++ b/queue-6.12/platform-x86-amd-pmf-prevent-tee-errors-after-hibern.patch @@ -0,0 +1,193 @@ +From b99185359c27b98cdeebf52e09eb9d50d9b3b78f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 22:11:28 -0600 +Subject: platform/x86/amd/pmf: Prevent TEE errors after hibernate +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Shyam Sundar S K + +[ Upstream commit 48d229c7047128dd52eaf863881bb3e62b5896e5 ] + +After resuming from hibernate, TEE commands can time out and cause PSP +disables. Fix this by reinitializing the Trusted Application (TA) and +cancelling the pb workqueue in the hibernate callbacks to avoid these +errors. + +ccp 0000:c4:00.2: tee: command 0x5 timed out, disabling PSP +amd-pmf AMDI0107:00: TEE enact cmd failed. err: ffff000e, ret:0 +amd-pmf AMDI0107:00: TEE enact cmd failed. err: ffff000e, ret:0 +amd-pmf AMDI0107:00: TEE enact cmd failed. err: ffff000e, ret:0 + +Fixes: ae82cef7d9c5 ("platform/x86/amd/pmf: Add support for PMF-TA interaction") +Reported-by: Lars Francke +Closes: https://lore.kernel.org/platform-driver-x86/CAD-Ua_gfJnQSo8ucS_7ZwzuhoBRJ14zXP7s8b-zX3ZcxcyWePw@mail.gmail.com/ +Tested-by: Yijun Shen +Co-developed-by: Patil Rajesh Reddy +Signed-off-by: Patil Rajesh Reddy +Signed-off-by: Shyam Sundar S K +[ML: Add more tags] +Signed-off-by: Mario Limonciello (AMD) +Link: https://patch.msgid.link/20260116041132.153674-2-superm1@kernel.org +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/amd/pmf/core.c | 62 ++++++++++++++++++++++++++- + drivers/platform/x86/amd/pmf/pmf.h | 10 +++++ + drivers/platform/x86/amd/pmf/tee-if.c | 12 ++---- + 3 files changed, 74 insertions(+), 10 deletions(-) + +diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c +index 8a1e2268d301a..2e352e475b562 100644 +--- a/drivers/platform/x86/amd/pmf/core.c ++++ b/drivers/platform/x86/amd/pmf/core.c +@@ -316,6 +316,61 @@ int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev) + return 0; + } + ++static int amd_pmf_reinit_ta(struct amd_pmf_dev *pdev) ++{ ++ bool status; ++ int ret, i; ++ ++ for (i = 0; i < ARRAY_SIZE(amd_pmf_ta_uuid); i++) { ++ ret = amd_pmf_tee_init(pdev, &amd_pmf_ta_uuid[i]); ++ if (ret) { ++ dev_err(pdev->dev, "TEE init failed for UUID[%d] ret: %d\n", i, ret); ++ return ret; ++ } ++ ++ ret = amd_pmf_start_policy_engine(pdev); ++ dev_dbg(pdev->dev, "start policy engine ret: %d (UUID idx: %d)\n", ret, i); ++ status = ret == TA_PMF_TYPE_SUCCESS; ++ if (status) ++ break; ++ amd_pmf_tee_deinit(pdev); ++ } ++ ++ return 0; ++} ++ ++static int amd_pmf_restore_handler(struct device *dev) ++{ ++ struct amd_pmf_dev *pdev = dev_get_drvdata(dev); ++ int ret; ++ ++ if (pdev->buf) { ++ ret = amd_pmf_set_dram_addr(pdev, false); ++ if (ret) ++ return ret; ++ } ++ ++ if (pdev->smart_pc_enabled) ++ amd_pmf_reinit_ta(pdev); ++ ++ return 0; ++} ++ ++static int amd_pmf_freeze_handler(struct device *dev) ++{ ++ struct amd_pmf_dev *pdev = dev_get_drvdata(dev); ++ ++ if (!pdev->smart_pc_enabled) ++ return 0; ++ ++ cancel_delayed_work_sync(&pdev->pb_work); ++ /* Clear all TEE resources */ ++ amd_pmf_tee_deinit(pdev); ++ pdev->session_id = 0; ++ ++ return 0; ++} ++ + static int amd_pmf_suspend_handler(struct device *dev) + { + struct amd_pmf_dev *pdev = dev_get_drvdata(dev); +@@ -349,7 +404,12 @@ static int amd_pmf_resume_handler(struct device *dev) + return 0; + } + +-static DEFINE_SIMPLE_DEV_PM_OPS(amd_pmf_pm, amd_pmf_suspend_handler, amd_pmf_resume_handler); ++static const struct dev_pm_ops amd_pmf_pm = { ++ .suspend = amd_pmf_suspend_handler, ++ .resume = amd_pmf_resume_handler, ++ .freeze = amd_pmf_freeze_handler, ++ .restore = amd_pmf_restore_handler, ++}; + + static void amd_pmf_init_features(struct amd_pmf_dev *dev) + { +diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h +index 34ba0309a33a2..b857ef4498903 100644 +--- a/drivers/platform/x86/amd/pmf/pmf.h ++++ b/drivers/platform/x86/amd/pmf/pmf.h +@@ -116,6 +116,12 @@ struct cookie_header { + + #define APTS_MAX_STATES 16 + ++static const uuid_t amd_pmf_ta_uuid[] __used = { UUID_INIT(0xd9b39bf2, 0x66bd, 0x4154, 0xaf, 0xb8, ++ 0x8a, 0xcc, 0x2b, 0x2b, 0x60, 0xd6), ++ UUID_INIT(0x6fd93b77, 0x3fb8, 0x524d, 0xb1, 0x2d, ++ 0xc5, 0x29, 0xb1, 0x3d, 0x85, 0x43), ++ }; ++ + /* APTS PMF BIOS Interface */ + struct amd_pmf_apts_output { + u16 table_version; +@@ -802,4 +808,8 @@ void amd_pmf_dump_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table * + /* Quirk infrastructure */ + void amd_pmf_quirks_init(struct amd_pmf_dev *dev); + ++int amd_pmf_tee_init(struct amd_pmf_dev *dev, const uuid_t *uuid); ++void amd_pmf_tee_deinit(struct amd_pmf_dev *dev); ++int amd_pmf_start_policy_engine(struct amd_pmf_dev *dev); ++ + #endif /* PMF_H */ +diff --git a/drivers/platform/x86/amd/pmf/tee-if.c b/drivers/platform/x86/amd/pmf/tee-if.c +index a9b195ec6f33f..6254423d05b06 100644 +--- a/drivers/platform/x86/amd/pmf/tee-if.c ++++ b/drivers/platform/x86/amd/pmf/tee-if.c +@@ -27,12 +27,6 @@ module_param(pb_side_load, bool, 0444); + MODULE_PARM_DESC(pb_side_load, "Sideload policy binaries debug policy failures"); + #endif + +-static const uuid_t amd_pmf_ta_uuid[] = { UUID_INIT(0xd9b39bf2, 0x66bd, 0x4154, 0xaf, 0xb8, 0x8a, +- 0xcc, 0x2b, 0x2b, 0x60, 0xd6), +- UUID_INIT(0x6fd93b77, 0x3fb8, 0x524d, 0xb1, 0x2d, 0xc5, +- 0x29, 0xb1, 0x3d, 0x85, 0x43), +- }; +- + static const char *amd_pmf_uevent_as_str(unsigned int state) + { + switch (state) { +@@ -296,7 +290,7 @@ static void amd_pmf_invoke_cmd(struct work_struct *work) + schedule_delayed_work(&dev->pb_work, msecs_to_jiffies(pb_actions_ms)); + } + +-static int amd_pmf_start_policy_engine(struct amd_pmf_dev *dev) ++int amd_pmf_start_policy_engine(struct amd_pmf_dev *dev) + { + struct cookie_header *header; + int res; +@@ -454,7 +448,7 @@ static int amd_pmf_register_input_device(struct amd_pmf_dev *dev) + return 0; + } + +-static int amd_pmf_tee_init(struct amd_pmf_dev *dev, const uuid_t *uuid) ++int amd_pmf_tee_init(struct amd_pmf_dev *dev, const uuid_t *uuid) + { + u32 size; + int ret; +@@ -502,7 +496,7 @@ static int amd_pmf_tee_init(struct amd_pmf_dev *dev, const uuid_t *uuid) + return ret; + } + +-static void amd_pmf_tee_deinit(struct amd_pmf_dev *dev) ++void amd_pmf_tee_deinit(struct amd_pmf_dev *dev) + { + if (!dev->tee_ctx) + return; +-- +2.51.0 + diff --git a/queue-6.12/platform-x86-int0002-remove-irqf_oneshot-from-reques.patch b/queue-6.12/platform-x86-int0002-remove-irqf_oneshot-from-reques.patch new file mode 100644 index 0000000000..e70876e86d --- /dev/null +++ b/queue-6.12/platform-x86-int0002-remove-irqf_oneshot-from-reques.patch @@ -0,0 +1,57 @@ +From 5d63773b6509cff013b11982be1b48712c553d8c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:55:22 +0100 +Subject: platform/x86: int0002: Remove IRQF_ONESHOT from request_irq() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Sebastian Andrzej Siewior + +[ Upstream commit f6bc712877f24dc89bdfd7bdbf1a32f3b9960b34 ] + +Passing IRQF_ONESHOT ensures that the interrupt source is masked until the +secondary (threaded) handler is done. If only a primary handler is used +then the flag makes no sense because the interrupt cannot fire (again) +while its handler is running. + +The flag also prevents force-threading of the primary handler and the +irq-core will warn about this. + +The flag was added to match the flag on the shared handler which uses a +threaded handler and therefore IRQF_ONESHOT. This is no longer needed +because devm_request_irq() now passes IRQF_COND_ONESHOT for this case. + +Revert adding IRQF_ONESHOT to irqflags. + +Fixes: 8f812373d1958 ("platform/x86: intel: int0002_vgpio: Pass IRQF_ONESHOT to request_irq()") +Reported-by: Borah, Chaitanya Kumar +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Reviewed-by: Hans de Goede +Acked-by: Ilpo Järvinen +Link: https://patch.msgid.link/20260128095540.863589-3-bigeasy@linutronix.de +Closes: https://lore.kernel.org/all/555f1c56-0f74-41bf-8bd2-6217e0aab0c6@intel.com +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/intel/int0002_vgpio.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/platform/x86/intel/int0002_vgpio.c b/drivers/platform/x86/intel/int0002_vgpio.c +index 0171be8867fce..c5c70319b0f37 100644 +--- a/drivers/platform/x86/intel/int0002_vgpio.c ++++ b/drivers/platform/x86/intel/int0002_vgpio.c +@@ -195,8 +195,8 @@ static int int0002_probe(struct platform_device *pdev) + * FIXME: augment this if we managed to pull handling of shared + * IRQs into gpiolib. + */ +- ret = devm_request_irq(dev, irq, int0002_irq, +- IRQF_ONESHOT | IRQF_SHARED, "INT0002", chip); ++ ret = devm_request_irq(dev, irq, int0002_irq, IRQF_SHARED, "INT0002", ++ chip); + if (ret) { + dev_err(dev, "Error requesting IRQ %d: %d\n", irq, ret); + return ret; +-- +2.51.0 + diff --git a/queue-6.12/pm-sleep-wakeirq-harden-dev_pm_clear_wake_irq-agains.patch b/queue-6.12/pm-sleep-wakeirq-harden-dev_pm_clear_wake_irq-agains.patch new file mode 100644 index 0000000000..6d875d37de --- /dev/null +++ b/queue-6.12/pm-sleep-wakeirq-harden-dev_pm_clear_wake_irq-agains.patch @@ -0,0 +1,65 @@ +From 1e96e745967665283fbdcf584de2daca8269f5c8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 11:19:43 +0800 +Subject: PM: sleep: wakeirq: harden dev_pm_clear_wake_irq() against races + +From: Gui-Dong Han + +[ Upstream commit 5c9ecd8e6437cd55a38ea4f1e1d19cee8e226cb8 ] + +dev_pm_clear_wake_irq() currently uses a dangerous pattern where +dev->power.wakeirq is read and checked for NULL outside the lock. +If two callers invoke this function concurrently, both might see +a valid pointer and proceed. This could result in a double-free +when the second caller acquires the lock and tries to release the +same object. + +Address this by removing the lockless check of dev->power.wakeirq. +Instead, acquire dev->power.lock immediately to ensure the check and +the subsequent operations are atomic. If dev->power.wakeirq is NULL +under the lock, simply unlock and return. This guarantees that +concurrent calls cannot race to free the same object. + +Based on a quick scan of current users, I did not find an actual bug as +drivers seem to rely on their own synchronization. However, since +asynchronous usage patterns exist (e.g., in +drivers/net/wireless/ti/wlcore), I believe a race is theoretically +possible if the API is used less carefully in the future. This change +hardens the API to be robust against such cases. + +Fixes: 4990d4fe327b ("PM / Wakeirq: Add automated device wake IRQ handling") +Signed-off-by: Gui-Dong Han +Link: https://patch.msgid.link/20260203031943.1924-1-hanguidong02@gmail.com +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/base/power/wakeirq.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/drivers/base/power/wakeirq.c b/drivers/base/power/wakeirq.c +index 5a5a9e978e85f..ddbe9cc91d23d 100644 +--- a/drivers/base/power/wakeirq.c ++++ b/drivers/base/power/wakeirq.c +@@ -83,13 +83,16 @@ EXPORT_SYMBOL_GPL(dev_pm_set_wake_irq); + */ + void dev_pm_clear_wake_irq(struct device *dev) + { +- struct wake_irq *wirq = dev->power.wakeirq; ++ struct wake_irq *wirq; + unsigned long flags; + +- if (!wirq) ++ spin_lock_irqsave(&dev->power.lock, flags); ++ wirq = dev->power.wakeirq; ++ if (!wirq) { ++ spin_unlock_irqrestore(&dev->power.lock, flags); + return; ++ } + +- spin_lock_irqsave(&dev->power.lock, flags); + device_wakeup_detach_irq(dev); + dev->power.wakeirq = NULL; + spin_unlock_irqrestore(&dev->power.lock, flags); +-- +2.51.0 + diff --git a/queue-6.12/pm-wakeup-handle-empty-list-in-wakeup_sources_walk_s.patch b/queue-6.12/pm-wakeup-handle-empty-list-in-wakeup_sources_walk_s.patch new file mode 100644 index 0000000000..38c67a786d --- /dev/null +++ b/queue-6.12/pm-wakeup-handle-empty-list-in-wakeup_sources_walk_s.patch @@ -0,0 +1,44 @@ +From 26cdd1dc44deeba41050fdd5e863945daf684cba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 17:21:29 -0800 +Subject: PM: wakeup: Handle empty list in wakeup_sources_walk_start() + +From: Samuel Wu + +[ Upstream commit 75ce02f4bc9a8b8350b6b1b01872467b0cc960cc ] + +In the case of an empty wakeup_sources list, wakeup_sources_walk_start() +will return an invalid but non-NULL address. This also affects wrappers +of the aforementioned function, like for_each_wakeup_source(). + +Update wakeup_sources_walk_start() to return NULL in case of an empty +list. + +Fixes: b4941adb24c0 ("PM: wakeup: Add routine to help fetch wakeup source object.") +Signed-off-by: Samuel Wu +[ rjw: Subject and changelog edits ] +Link: https://patch.msgid.link/20260124012133.2451708-2-wusamuel@google.com +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/base/power/wakeup.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c +index 752b417e81290..706cd556a0d69 100644 +--- a/drivers/base/power/wakeup.c ++++ b/drivers/base/power/wakeup.c +@@ -280,9 +280,7 @@ EXPORT_SYMBOL_GPL(wakeup_sources_read_unlock); + */ + struct wakeup_source *wakeup_sources_walk_start(void) + { +- struct list_head *ws_head = &wakeup_sources; +- +- return list_entry_rcu(ws_head->next, struct wakeup_source, entry); ++ return list_first_or_null_rcu(&wakeup_sources, struct wakeup_source, entry); + } + EXPORT_SYMBOL_GPL(wakeup_sources_walk_start); + +-- +2.51.0 + diff --git a/queue-6.12/pnfs-fix-a-missing-wake-up-while-waiting-on-nfs_layo.patch b/queue-6.12/pnfs-fix-a-missing-wake-up-while-waiting-on-nfs_layo.patch new file mode 100644 index 0000000000..2acf1c2ff0 --- /dev/null +++ b/queue-6.12/pnfs-fix-a-missing-wake-up-while-waiting-on-nfs_layo.patch @@ -0,0 +1,61 @@ +From fbc9aecdca1b52359997ae3a722700e8c3c425ec Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 14:15:39 -0500 +Subject: pNFS: fix a missing wake up while waiting on NFS_LAYOUT_DRAIN + +From: Olga Kornievskaia + +[ Upstream commit 5248d8474e594d156bee1ed10339cc16e207a28b ] + +It is possible to have a task get stuck on waiting on the +NFS_LAYOUT_DRAIN in the following scenario + +1. cpu a: waiter test NFS_LAYOUT_DRAIN (1) and plh_outstanding (1) +2. cpu b: atomic_dec_and_test() -> clear bit -> wake up +3. cpu c: sets NFS_LAYOUT_DRAIN again +4. cpu a: calls wait_on_bit() sleeps forever. + +To expand on this we have say 2 outstanding pnfs write IO that get +ESTALE which causes both to call pnfs_destroy_layout() and set the +NFS_LAYOUT_DRAIN bit but the 1st one doesn't call the +pnfs_put_layout_hdr() yet (as that would prevent the 2nd ESTALE write +from trying to call pnfs_destroy_layout()). If the 1st ESTALE write +is the one that initially sets the NFS_LAYOUT_DRAIN so that new IO +on this file initiates new LAYOUTGET. Another new write would find +NFS_LAYOUT_DRAIN set and phl_outstanding>0 (step 1) and would +wait_on_bit(). LAYOUTGET completes doing step 2. Now, the 2nd of +ESTALE writes is calling pnfs_destory_layout() and set the +NFS_LAYOUT_DRAIN bit (step 3). Finally, the waiting write wakes up +to check the bit and goes back to sleep. + +The problem revolves around the fact that if NFS_LAYOUT_INVALID_STID +was already set, it should not do the work of +pnfs_mark_layout_stateid_invalid(), thus NFS_LAYOUT_DRAIN will not +be set more than once for an invalid layout. + +Suggested-by: Trond Myklebust +Fixes: 880265c77ac4 ("pNFS: Avoid a live lock condition in pnfs_update_layout()") +Signed-off-by: Olga Kornievskaia +Signed-off-by: Anna Schumaker +Signed-off-by: Sasha Levin +--- + fs/nfs/pnfs.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c +index 16981d0389c4c..116499e0f5cee 100644 +--- a/fs/nfs/pnfs.c ++++ b/fs/nfs/pnfs.c +@@ -465,7 +465,8 @@ pnfs_mark_layout_stateid_invalid(struct pnfs_layout_hdr *lo, + }; + struct pnfs_layout_segment *lseg, *next; + +- set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags); ++ if (test_and_set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags)) ++ return !list_empty(&lo->plh_segs); + clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(lo->plh_inode)->flags); + list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list) + pnfs_clear_lseg_state(lseg, lseg_list); +-- +2.51.0 + diff --git a/queue-6.12/power-reset-nvmem-reboot-mode-respect-cell-size-for-.patch b/queue-6.12/power-reset-nvmem-reboot-mode-respect-cell-size-for-.patch new file mode 100644 index 0000000000..dfaec89e32 --- /dev/null +++ b/queue-6.12/power-reset-nvmem-reboot-mode-respect-cell-size-for-.patch @@ -0,0 +1,64 @@ +From 664fa09412e6dd8861f0a26f4b1dae14b3eb5c46 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 14 Dec 2025 19:16:18 +0000 +Subject: power: reset: nvmem-reboot-mode: respect cell size for + nvmem_cell_write + +From: Alexander Koskovich + +[ Upstream commit 36b05629226413836cfbb3fbe6689cd188bca156 ] + +Some platforms expose reboot mode cells that are smaller than an +unsigned int, in which cases lead to write failures. Read the cell +first to determine actual size and only write the number of bytes the +cell can hold. + +Fixes: 7a78a7f7695b ("power: reset: nvmem-reboot-mode: use NVMEM as reboot mode write interface") +Signed-off-by: Alexander Koskovich +Link: https://patch.msgid.link/20251214191529.2470580-1-akoskovich@pm.me +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/reset/nvmem-reboot-mode.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +diff --git a/drivers/power/reset/nvmem-reboot-mode.c b/drivers/power/reset/nvmem-reboot-mode.c +index 41530b70cfc48..d260715fccf67 100644 +--- a/drivers/power/reset/nvmem-reboot-mode.c ++++ b/drivers/power/reset/nvmem-reboot-mode.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + + struct nvmem_reboot_mode { + struct reboot_mode_driver reboot; +@@ -19,12 +20,22 @@ struct nvmem_reboot_mode { + static int nvmem_reboot_mode_write(struct reboot_mode_driver *reboot, + unsigned int magic) + { +- int ret; + struct nvmem_reboot_mode *nvmem_rbm; ++ size_t buf_len; ++ void *buf; ++ int ret; + + nvmem_rbm = container_of(reboot, struct nvmem_reboot_mode, reboot); + +- ret = nvmem_cell_write(nvmem_rbm->cell, &magic, sizeof(magic)); ++ buf = nvmem_cell_read(nvmem_rbm->cell, &buf_len); ++ if (IS_ERR(buf)) ++ return PTR_ERR(buf); ++ kfree(buf); ++ ++ if (buf_len > sizeof(magic)) ++ return -EINVAL; ++ ++ ret = nvmem_cell_write(nvmem_rbm->cell, &magic, buf_len); + if (ret < 0) + dev_err(reboot->dev, "update reboot mode bits failed\n"); + +-- +2.51.0 + diff --git a/queue-6.12/power-supply-ab8500-fix-use-after-free-in-power_supp.patch b/queue-6.12/power-supply-ab8500-fix-use-after-free-in-power_supp.patch new file mode 100644 index 0000000000..03775bb335 --- /dev/null +++ b/queue-6.12/power-supply-ab8500-fix-use-after-free-in-power_supp.patch @@ -0,0 +1,104 @@ +From 4daf5c8895403dae9b76b3d4c82002bb60a55226 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:35:58 +0100 +Subject: power: supply: ab8500: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit c4af8a98bb52825a5331ae1d0604c0ea6956ba4b ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Commit 1c1f13a006ed ("power: supply: ab8500: Move to componentized +binding") introduced this issue during a refactorization. Fix this racy +use-after-free by making sure the IRQ is requested _after_ the +registration of the `power_supply` handle. + +Fixes: 1c1f13a006ed ("power: supply: ab8500: Move to componentized binding") +Signed-off-by: Waqar Hameed +Reviewed-by: Linus Walleij +Link: https://patch.msgid.link/ccf83a09942cb8dda3dff70b2682f2c2e9cb97f2.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/ab8500_charger.c | 40 +++++++++++++-------------- + 1 file changed, 20 insertions(+), 20 deletions(-) + +diff --git a/drivers/power/supply/ab8500_charger.c b/drivers/power/supply/ab8500_charger.c +index 93181ebfb3247..5da3b12d9f0bb 100644 +--- a/drivers/power/supply/ab8500_charger.c ++++ b/drivers/power/supply/ab8500_charger.c +@@ -3467,26 +3467,6 @@ static int ab8500_charger_probe(struct platform_device *pdev) + return ret; + } + +- /* Request interrupts */ +- for (i = 0; i < ARRAY_SIZE(ab8500_charger_irq); i++) { +- irq = platform_get_irq_byname(pdev, ab8500_charger_irq[i].name); +- if (irq < 0) +- return irq; +- +- ret = devm_request_threaded_irq(dev, +- irq, NULL, ab8500_charger_irq[i].isr, +- IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT, +- ab8500_charger_irq[i].name, di); +- +- if (ret != 0) { +- dev_err(dev, "failed to request %s IRQ %d: %d\n" +- , ab8500_charger_irq[i].name, irq, ret); +- return ret; +- } +- dev_dbg(dev, "Requested %s IRQ %d: %d\n", +- ab8500_charger_irq[i].name, irq, ret); +- } +- + /* initialize lock */ + spin_lock_init(&di->usb_state.usb_lock); + mutex_init(&di->usb_ipt_crnt_lock); +@@ -3615,6 +3595,26 @@ static int ab8500_charger_probe(struct platform_device *pdev) + return PTR_ERR(di->usb_chg.psy); + } + ++ /* Request interrupts */ ++ for (i = 0; i < ARRAY_SIZE(ab8500_charger_irq); i++) { ++ irq = platform_get_irq_byname(pdev, ab8500_charger_irq[i].name); ++ if (irq < 0) ++ return irq; ++ ++ ret = devm_request_threaded_irq(dev, ++ irq, NULL, ab8500_charger_irq[i].isr, ++ IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT, ++ ab8500_charger_irq[i].name, di); ++ ++ if (ret != 0) { ++ dev_err(dev, "failed to request %s IRQ %d: %d\n" ++ , ab8500_charger_irq[i].name, irq, ret); ++ return ret; ++ } ++ dev_dbg(dev, "Requested %s IRQ %d: %d\n", ++ ab8500_charger_irq[i].name, irq, ret); ++ } ++ + /* + * Check what battery we have, since we always have the USB + * psy, use that as a handle. +-- +2.51.0 + diff --git a/queue-6.12/power-supply-act8945a-fix-use-after-free-in-power_su.patch b/queue-6.12/power-supply-act8945a-fix-use-after-free-in-power_su.patch new file mode 100644 index 0000000000..44d5003bac --- /dev/null +++ b/queue-6.12/power-supply-act8945a-fix-use-after-free-in-power_su.patch @@ -0,0 +1,77 @@ +From 1be972790cbb93a0f8231522256978918a4e8792 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:35:59 +0100 +Subject: power: supply: act8945a: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 3291c51d4684d048dd2eb91b5b65fcfdaf72141f ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: a09209acd6a8 ("power: supply: act8945a_charger: Add status change update support") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/bcf3a23b5187df0bba54a8c8fe09f8b8a0031dee.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/act8945a_charger.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/drivers/power/supply/act8945a_charger.c b/drivers/power/supply/act8945a_charger.c +index 51122bfbf196c..699030bfa296a 100644 +--- a/drivers/power/supply/act8945a_charger.c ++++ b/drivers/power/supply/act8945a_charger.c +@@ -597,14 +597,6 @@ static int act8945a_charger_probe(struct platform_device *pdev) + return irq ?: -ENXIO; + } + +- ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, +- IRQF_TRIGGER_FALLING, "act8945a_interrupt", +- charger); +- if (ret) { +- dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); +- return ret; +- } +- + charger->desc.name = "act8945a-charger"; + charger->desc.get_property = act8945a_charger_get_property; + charger->desc.properties = act8945a_charger_props; +@@ -625,6 +617,14 @@ static int act8945a_charger_probe(struct platform_device *pdev) + return PTR_ERR(charger->psy); + } + ++ ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, ++ IRQF_TRIGGER_FALLING, "act8945a_interrupt", ++ charger); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); ++ return ret; ++ } ++ + platform_set_drvdata(pdev, charger); + + INIT_WORK(&charger->work, act8945a_work); +-- +2.51.0 + diff --git a/queue-6.12/power-supply-bq256xx-fix-use-after-free-in-power_sup.patch b/queue-6.12/power-supply-bq256xx-fix-use-after-free-in-power_sup.patch new file mode 100644 index 0000000000..ca5c0c73e0 --- /dev/null +++ b/queue-6.12/power-supply-bq256xx-fix-use-after-free-in-power_sup.patch @@ -0,0 +1,73 @@ +From 94e2b7c2f5b8b91bcc07c9d33ea8e542d2436fd4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:35:59 +0100 +Subject: power: supply: bq256xx: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 8005843369723d9c8975b7c4202d1b85d6125302 ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: 32e4978bb920 ("power: supply: bq256xx: Introduce the BQ256XX charger driver") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/39da6da8cc060fa0382ca859f65071e791cb6119.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/bq256xx_charger.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/power/supply/bq256xx_charger.c b/drivers/power/supply/bq256xx_charger.c +index 5514d1896bb84..b47b73ed642e5 100644 +--- a/drivers/power/supply/bq256xx_charger.c ++++ b/drivers/power/supply/bq256xx_charger.c +@@ -1741,6 +1741,12 @@ static int bq256xx_probe(struct i2c_client *client) + usb_register_notifier(bq->usb3_phy, &bq->usb_nb); + } + ++ ret = bq256xx_power_supply_init(bq, &psy_cfg, dev); ++ if (ret) { ++ dev_err(dev, "Failed to register power supply\n"); ++ return ret; ++ } ++ + if (client->irq) { + ret = devm_request_threaded_irq(dev, client->irq, NULL, + bq256xx_irq_handler_thread, +@@ -1753,12 +1759,6 @@ static int bq256xx_probe(struct i2c_client *client) + } + } + +- ret = bq256xx_power_supply_init(bq, &psy_cfg, dev); +- if (ret) { +- dev_err(dev, "Failed to register power supply\n"); +- return ret; +- } +- + ret = bq256xx_hw_init(bq); + if (ret) { + dev_err(dev, "Cannot initialize the chip.\n"); +-- +2.51.0 + diff --git a/queue-6.12/power-supply-bq25980-fix-use-after-free-in-power_sup.patch b/queue-6.12/power-supply-bq25980-fix-use-after-free-in-power_sup.patch new file mode 100644 index 0000000000..893fa8eadb --- /dev/null +++ b/queue-6.12/power-supply-bq25980-fix-use-after-free-in-power_sup.patch @@ -0,0 +1,73 @@ +From b9f1b4b09ed9bd8938842ea7b81c1edeb9810f8b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:35:59 +0100 +Subject: power: supply: bq25980: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 5f0b1cb41906e86b64bf69f5ededb83b0d757c27 ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: 5069185fc18e ("power: supply: bq25980: Add support for the BQ259xx family") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/8763035cadb959e14787b3837f2d3db61f6e1c34.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/bq25980_charger.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/power/supply/bq25980_charger.c b/drivers/power/supply/bq25980_charger.c +index 0c5e2938bb36d..b3060df9449eb 100644 +--- a/drivers/power/supply/bq25980_charger.c ++++ b/drivers/power/supply/bq25980_charger.c +@@ -1241,6 +1241,12 @@ static int bq25980_probe(struct i2c_client *client) + return ret; + } + ++ ret = bq25980_power_supply_init(bq, dev); ++ if (ret) { ++ dev_err(dev, "Failed to register power supply\n"); ++ return ret; ++ } ++ + if (client->irq) { + ret = devm_request_threaded_irq(dev, client->irq, NULL, + bq25980_irq_handler_thread, +@@ -1251,12 +1257,6 @@ static int bq25980_probe(struct i2c_client *client) + return ret; + } + +- ret = bq25980_power_supply_init(bq, dev); +- if (ret) { +- dev_err(dev, "Failed to register power supply\n"); +- return ret; +- } +- + ret = bq25980_hw_init(bq); + if (ret) { + dev_err(dev, "Cannot initialize the chip.\n"); +-- +2.51.0 + diff --git a/queue-6.12/power-supply-bq27xxx-fix-wrong-errno-when-bus-ops-ar.patch b/queue-6.12/power-supply-bq27xxx-fix-wrong-errno-when-bus-ops-ar.patch new file mode 100644 index 0000000000..a693950ef1 --- /dev/null +++ b/queue-6.12/power-supply-bq27xxx-fix-wrong-errno-when-bus-ops-ar.patch @@ -0,0 +1,61 @@ +From 9e809b4d6096ba38d7690d8e439cf7c3ed6bbaf5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Dec 2025 16:34:36 +0800 +Subject: power: supply: bq27xxx: fix wrong errno when bus ops are unsupported + +From: Haotian Zhang + +[ Upstream commit 688364a11647dc09ba1e4429313e0008066ec790 ] + +bq27xxx_write(), bq27xxx_read_block(), and bq27xxx_write_block() +return -EPERM when the bus callback pointer is NULL. A NULL callback +indicates the operation is not supported by the bus/driver, +not that permission is denied. + +Return -EOPNOTSUPP instead of -EPERM when di->bus.write/ +read_bulk/write_bulk is NULL. + +Fixes: 14073f6614f6 ("power: supply: bq27xxx: Add bulk transfer bus methods") +Signed-off-by: Haotian Zhang +Reviewed-by: Matt Ranostay +Link: https://patch.msgid.link/20251204083436.1367-1-vulab@iscas.ac.cn +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/bq27xxx_battery.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c +index 14be797e89c3d..a5a3ab4f8a631 100644 +--- a/drivers/power/supply/bq27xxx_battery.c ++++ b/drivers/power/supply/bq27xxx_battery.c +@@ -1162,7 +1162,7 @@ static inline int bq27xxx_write(struct bq27xxx_device_info *di, int reg_index, + return -EINVAL; + + if (!di->bus.write) +- return -EPERM; ++ return -EOPNOTSUPP; + + ret = di->bus.write(di, di->regs[reg_index], value, single); + if (ret < 0) +@@ -1181,7 +1181,7 @@ static inline int bq27xxx_read_block(struct bq27xxx_device_info *di, int reg_ind + return -EINVAL; + + if (!di->bus.read_bulk) +- return -EPERM; ++ return -EOPNOTSUPP; + + ret = di->bus.read_bulk(di, di->regs[reg_index], data, len); + if (ret < 0) +@@ -1200,7 +1200,7 @@ static inline int bq27xxx_write_block(struct bq27xxx_device_info *di, int reg_in + return -EINVAL; + + if (!di->bus.write_bulk) +- return -EPERM; ++ return -EOPNOTSUPP; + + ret = di->bus.write_bulk(di, di->regs[reg_index], data, len); + if (ret < 0) +-- +2.51.0 + diff --git a/queue-6.12/power-supply-cpcap-battery-fix-use-after-free-in-pow.patch b/queue-6.12/power-supply-cpcap-battery-fix-use-after-free-in-pow.patch new file mode 100644 index 0000000000..1ddc158b96 --- /dev/null +++ b/queue-6.12/power-supply-cpcap-battery-fix-use-after-free-in-pow.patch @@ -0,0 +1,70 @@ +From 5244a14fc694790667c637c4157b0f5b1119c220 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:36:00 +0100 +Subject: power: supply: cpcap-battery: Fix use-after-free in + power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 642f33e34b969eedec334738fd5df95d2dc42742 ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: 874b2adbed12 ("power: supply: cpcap-battery: Add a battery driver") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/81db58d610c9a51a68184f856cd431a934cccee2.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/cpcap-battery.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/power/supply/cpcap-battery.c b/drivers/power/supply/cpcap-battery.c +index 30ec76cdf34b0..eaad9f53bb5cc 100644 +--- a/drivers/power/supply/cpcap-battery.c ++++ b/drivers/power/supply/cpcap-battery.c +@@ -1122,10 +1122,6 @@ static int cpcap_battery_probe(struct platform_device *pdev) + + platform_set_drvdata(pdev, ddata); + +- error = cpcap_battery_init_interrupts(pdev, ddata); +- if (error) +- return error; +- + error = cpcap_battery_init_iio(ddata); + if (error) + return error; +@@ -1142,6 +1138,10 @@ static int cpcap_battery_probe(struct platform_device *pdev) + return error; + } + ++ error = cpcap_battery_init_interrupts(pdev, ddata); ++ if (error) ++ return error; ++ + atomic_set(&ddata->active, 1); + + error = cpcap_battery_calibrate(ddata); +-- +2.51.0 + diff --git a/queue-6.12/power-supply-goldfish-fix-use-after-free-in-power_su.patch b/queue-6.12/power-supply-goldfish-fix-use-after-free-in-power_su.patch new file mode 100644 index 0000000000..256df981ee --- /dev/null +++ b/queue-6.12/power-supply-goldfish-fix-use-after-free-in-power_su.patch @@ -0,0 +1,73 @@ +From 82e2f4400b48fdc70d5c245a8d7080f23ce6cbf2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:36:00 +0100 +Subject: power: supply: goldfish: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit b2ce982e2e0c888dc55c888ad0e20ea04daf2e6b ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: 84d7b7687489 ("power: Add battery driver for goldfish emulator") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/500a606bb6fb6f2bb8d797e19a00cea9dd7b03c1.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/goldfish_battery.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/power/supply/goldfish_battery.c b/drivers/power/supply/goldfish_battery.c +index 479195e35d734..5aa24e4dc4455 100644 +--- a/drivers/power/supply/goldfish_battery.c ++++ b/drivers/power/supply/goldfish_battery.c +@@ -224,12 +224,6 @@ static int goldfish_battery_probe(struct platform_device *pdev) + if (data->irq < 0) + return -ENODEV; + +- ret = devm_request_irq(&pdev->dev, data->irq, +- goldfish_battery_interrupt, +- IRQF_SHARED, pdev->name, data); +- if (ret) +- return ret; +- + psy_cfg.drv_data = data; + + data->ac = devm_power_supply_register(&pdev->dev, +@@ -244,6 +238,12 @@ static int goldfish_battery_probe(struct platform_device *pdev) + if (IS_ERR(data->battery)) + return PTR_ERR(data->battery); + ++ ret = devm_request_irq(&pdev->dev, data->irq, ++ goldfish_battery_interrupt, ++ IRQF_SHARED, pdev->name, data); ++ if (ret) ++ return ret; ++ + GOLDFISH_BATTERY_WRITE(data, BATTERY_INT_ENABLE, BATTERY_INT_MASK); + return 0; + } +-- +2.51.0 + diff --git a/queue-6.12/power-supply-pm8916_bms_vm-fix-use-after-free-in-pow.patch b/queue-6.12/power-supply-pm8916_bms_vm-fix-use-after-free-in-pow.patch new file mode 100644 index 0000000000..2343f78388 --- /dev/null +++ b/queue-6.12/power-supply-pm8916_bms_vm-fix-use-after-free-in-pow.patch @@ -0,0 +1,81 @@ +From 5f74aa17745da0d271b83f7544e1b2fd8335a02b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:36:01 +0100 +Subject: power: supply: pm8916_bms_vm: Fix use-after-free in + power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 62914959b35e9a1e29cc0f64cb8cfc5075a5366f ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: 098bce1838e0 ("power: supply: Add pm8916 VM-BMS support") +Signed-off-by: Waqar Hameed +Reviewed-by: Nikita Travkin +Link: https://patch.msgid.link/2749c09ff81fcac87ae48147e216135450d8c067.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/pm8916_bms_vm.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/drivers/power/supply/pm8916_bms_vm.c b/drivers/power/supply/pm8916_bms_vm.c +index 5d0dd842509c4..9b069af077be5 100644 +--- a/drivers/power/supply/pm8916_bms_vm.c ++++ b/drivers/power/supply/pm8916_bms_vm.c +@@ -167,15 +167,6 @@ static int pm8916_bms_vm_battery_probe(struct platform_device *pdev) + if (ret < 0) + return -EINVAL; + +- irq = platform_get_irq_byname(pdev, "fifo"); +- if (irq < 0) +- return irq; +- +- ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_bms_vm_fifo_update_done_irq, +- IRQF_ONESHOT, "pm8916_vm_bms", bat); +- if (ret) +- return ret; +- + ret = regmap_bulk_read(bat->regmap, bat->reg + PM8916_PERPH_TYPE, &tmp, 2); + if (ret) + goto comm_error; +@@ -220,6 +211,15 @@ static int pm8916_bms_vm_battery_probe(struct platform_device *pdev) + if (ret) + return dev_err_probe(dev, ret, "Unable to get battery info\n"); + ++ irq = platform_get_irq_byname(pdev, "fifo"); ++ if (irq < 0) ++ return irq; ++ ++ ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_bms_vm_fifo_update_done_irq, ++ IRQF_ONESHOT, "pm8916_vm_bms", bat); ++ if (ret) ++ return ret; ++ + platform_set_drvdata(pdev, bat); + + return 0; +-- +2.51.0 + diff --git a/queue-6.12/power-supply-pm8916_lbc-fix-use-after-free-for-extco.patch b/queue-6.12/power-supply-pm8916_lbc-fix-use-after-free-for-extco.patch new file mode 100644 index 0000000000..58adb9ffb0 --- /dev/null +++ b/queue-6.12/power-supply-pm8916_lbc-fix-use-after-free-for-extco.patch @@ -0,0 +1,67 @@ +From 7d0a693536236f15b785f4a900a8b1be65265019 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 11:24:20 +0100 +Subject: power: supply: pm8916_lbc: Fix use-after-free for extcon in IRQ + handler + +From: Waqar Hameed + +[ Upstream commit 23067259919663580c6f81801847cfc7bd54fd1f ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `extcon` handle, means that the +`extcon` handle will be deallocated/unregistered _before_ the interrupt +handler (since `devm_` naturally deallocates in reverse allocation +order). This means that during removal, there is a race condition where +an interrupt can fire just _after_ the `extcon` handle has been +freed, *but* just _before_ the corresponding unregistration of the IRQ +handler has run. + +This will lead to the IRQ handler calling `extcon_set_state_sync()` with +a freed `extcon` handle. Which usually crashes the system or otherwise +silently corrupts the memory... + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `extcon` handle. + +Fixes: f8d7a3d21160 ("power: supply: Add driver for pm8916 lbc") +Signed-off-by: Waqar Hameed +Reviewed-by: Nikita Travkin +Link: https://patch.msgid.link/e2a4cd2fcd42b6cd97d856c17c097289a2aed393.1769163273.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/pm8916_lbc.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/power/supply/pm8916_lbc.c b/drivers/power/supply/pm8916_lbc.c +index ab324ce3b8721..e6c44f342eeb4 100644 +--- a/drivers/power/supply/pm8916_lbc.c ++++ b/drivers/power/supply/pm8916_lbc.c +@@ -327,11 +327,6 @@ static int pm8916_lbc_charger_probe(struct platform_device *pdev) + if (irq < 0) + return irq; + +- ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_lbc_charger_state_changed_irq, +- IRQF_ONESHOT, "pm8916_lbc", chg); +- if (ret) +- return ret; +- + chg->edev = devm_extcon_dev_allocate(dev, pm8916_lbc_charger_cable); + if (IS_ERR(chg->edev)) + return PTR_ERR(chg->edev); +@@ -340,6 +335,11 @@ static int pm8916_lbc_charger_probe(struct platform_device *pdev) + if (ret < 0) + return dev_err_probe(dev, ret, "failed to register extcon device\n"); + ++ ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_lbc_charger_state_changed_irq, ++ IRQF_ONESHOT, "pm8916_lbc", chg); ++ if (ret) ++ return ret; ++ + ret = regmap_read(chg->regmap, chg->reg[LBC_USB] + PM8916_INT_RT_STS, &tmp); + if (ret) + goto comm_error; +-- +2.51.0 + diff --git a/queue-6.12/power-supply-pm8916_lbc-fix-use-after-free-in-power_.patch b/queue-6.12/power-supply-pm8916_lbc-fix-use-after-free-in-power_.patch new file mode 100644 index 0000000000..cadeaaedb3 --- /dev/null +++ b/queue-6.12/power-supply-pm8916_lbc-fix-use-after-free-in-power_.patch @@ -0,0 +1,81 @@ +From d59f3d64fb367c2d5236e1a472261589e9f6c277 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:36:01 +0100 +Subject: power: supply: pm8916_lbc: Fix use-after-free in + power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit b7508129978ae1e2ed9b0410396abc05def9c4eb ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: f8d7a3d21160 ("power: supply: Add driver for pm8916 lbc") +Signed-off-by: Waqar Hameed +Reviewed-by: Nikita Travkin +Link: https://patch.msgid.link/64d8dd3675a4e59fa32c3e0ef451f12d1f7ed18f.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/pm8916_lbc.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/drivers/power/supply/pm8916_lbc.c b/drivers/power/supply/pm8916_lbc.c +index 6d92e98cbecc6..ab324ce3b8721 100644 +--- a/drivers/power/supply/pm8916_lbc.c ++++ b/drivers/power/supply/pm8916_lbc.c +@@ -274,15 +274,6 @@ static int pm8916_lbc_charger_probe(struct platform_device *pdev) + return dev_err_probe(dev, -EINVAL, + "Wrong amount of reg values: %d (4 expected)\n", len); + +- irq = platform_get_irq_byname(pdev, "usb_vbus"); +- if (irq < 0) +- return irq; +- +- ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_lbc_charger_state_changed_irq, +- IRQF_ONESHOT, "pm8916_lbc", chg); +- if (ret) +- return ret; +- + ret = device_property_read_u32_array(dev, "reg", chg->reg, len); + if (ret) + return ret; +@@ -332,6 +323,15 @@ static int pm8916_lbc_charger_probe(struct platform_device *pdev) + if (ret) + return dev_err_probe(dev, ret, "Unable to get battery info\n"); + ++ irq = platform_get_irq_byname(pdev, "usb_vbus"); ++ if (irq < 0) ++ return irq; ++ ++ ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_lbc_charger_state_changed_irq, ++ IRQF_ONESHOT, "pm8916_lbc", chg); ++ if (ret) ++ return ret; ++ + chg->edev = devm_extcon_dev_allocate(dev, pm8916_lbc_charger_cable); + if (IS_ERR(chg->edev)) + return PTR_ERR(chg->edev); +-- +2.51.0 + diff --git a/queue-6.12/power-supply-qcom_battmgr-recognize-lip-as-lithium-p.patch b/queue-6.12/power-supply-qcom_battmgr-recognize-lip-as-lithium-p.patch new file mode 100644 index 0000000000..4bba14d746 --- /dev/null +++ b/queue-6.12/power-supply-qcom_battmgr-recognize-lip-as-lithium-p.patch @@ -0,0 +1,42 @@ +From 8c9117db2c6f47129d94d32c3ec08c6f1f1b0f09 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 20:57:58 -0300 +Subject: power: supply: qcom_battmgr: Recognize "LiP" as lithium-polymer + +From: Val Packett + +[ Upstream commit c655f45480637aee326b5bd96488d35ab90db2b0 ] + +On the Dell Latitude 7455, the firmware uses "LiP" with a lowercase 'i' +for the battery chemistry type, but only all-uppercase "LIP" was being +recognized. Add the CamelCase variant to the check to fix the "Unknown +battery technology" warning. + +Fixes: 202ac22b8e2e ("power: supply: qcom_battmgr: Add lithium-polymer entry") +Signed-off-by: Val Packett +Reviewed-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Link: https://patch.msgid.link/20260120235831.479038-1-val@packett.cool +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/qcom_battmgr.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/power/supply/qcom_battmgr.c b/drivers/power/supply/qcom_battmgr.c +index f8bea732ba7f2..a6576248e761e 100644 +--- a/drivers/power/supply/qcom_battmgr.c ++++ b/drivers/power/supply/qcom_battmgr.c +@@ -984,7 +984,8 @@ static unsigned int qcom_battmgr_sc8280xp_parse_technology(const char *chemistry + if ((!strncmp(chemistry, "LIO", BATTMGR_CHEMISTRY_LEN)) || + (!strncmp(chemistry, "OOI", BATTMGR_CHEMISTRY_LEN))) + return POWER_SUPPLY_TECHNOLOGY_LION; +- if (!strncmp(chemistry, "LIP", BATTMGR_CHEMISTRY_LEN)) ++ if (!strncmp(chemistry, "LIP", BATTMGR_CHEMISTRY_LEN) || ++ !strncmp(chemistry, "LiP", BATTMGR_CHEMISTRY_LEN)) + return POWER_SUPPLY_TECHNOLOGY_LIPO; + + pr_err("Unknown battery technology '%s'\n", chemistry); +-- +2.51.0 + diff --git a/queue-6.12/power-supply-rt9455-fix-use-after-free-in-power_supp.patch b/queue-6.12/power-supply-rt9455-fix-use-after-free-in-power_supp.patch new file mode 100644 index 0000000000..838d6f8223 --- /dev/null +++ b/queue-6.12/power-supply-rt9455-fix-use-after-free-in-power_supp.patch @@ -0,0 +1,78 @@ +From 6e5a8f237f4aa961a909834644f4253a514cf744 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:36:02 +0100 +Subject: power: supply: rt9455: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit e2febe375e5ea5afed92f4cd9711bde8f24ee6d2 ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: e86d69dd786e ("power_supply: Add support for Richtek RT9455 battery charger") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/1567d831e04c3e2fcb9e18dd36b7bcba4634581a.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/rt9455_charger.c | 17 +++++++++-------- + 1 file changed, 9 insertions(+), 8 deletions(-) + +diff --git a/drivers/power/supply/rt9455_charger.c b/drivers/power/supply/rt9455_charger.c +index 64a23e3d7bb00..803f4d258da9e 100644 +--- a/drivers/power/supply/rt9455_charger.c ++++ b/drivers/power/supply/rt9455_charger.c +@@ -1663,6 +1663,15 @@ static int rt9455_probe(struct i2c_client *client) + rt9455_charger_config.supplied_to = rt9455_charger_supplied_to; + rt9455_charger_config.num_supplicants = + ARRAY_SIZE(rt9455_charger_supplied_to); ++ ++ info->charger = devm_power_supply_register(dev, &rt9455_charger_desc, ++ &rt9455_charger_config); ++ if (IS_ERR(info->charger)) { ++ dev_err(dev, "Failed to register charger\n"); ++ ret = PTR_ERR(info->charger); ++ goto put_usb_notifier; ++ } ++ + ret = devm_request_threaded_irq(dev, client->irq, NULL, + rt9455_irq_handler_thread, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, +@@ -1678,14 +1687,6 @@ static int rt9455_probe(struct i2c_client *client) + goto put_usb_notifier; + } + +- info->charger = devm_power_supply_register(dev, &rt9455_charger_desc, +- &rt9455_charger_config); +- if (IS_ERR(info->charger)) { +- dev_err(dev, "Failed to register charger\n"); +- ret = PTR_ERR(info->charger); +- goto put_usb_notifier; +- } +- + return 0; + + put_usb_notifier: +-- +2.51.0 + diff --git a/queue-6.12/power-supply-sbs-battery-fix-use-after-free-in-power.patch b/queue-6.12/power-supply-sbs-battery-fix-use-after-free-in-power.patch new file mode 100644 index 0000000000..07eddb2367 --- /dev/null +++ b/queue-6.12/power-supply-sbs-battery-fix-use-after-free-in-power.patch @@ -0,0 +1,101 @@ +From a3b2750c7153862738cc49fc08f45294c91039e9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:36:02 +0100 +Subject: power: supply: sbs-battery: Fix use-after-free in + power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 8d59cf3887fbabacef53bfba473e33e8a8d9d07b ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. Keep the old behavior of +just printing a warning in case of any failures during the IRQ request +and finishing the probe successfully. + +Fixes: d2cec82c2880 ("power: sbs-battery: Request threaded irq and fix dev callback cookie") +Signed-off-by: Waqar Hameed +Reviewed-by: Phil Reid +Link: https://patch.msgid.link/0ef896e002495e615157b482d18a437af19ddcd0.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/sbs-battery.c | 36 +++++++++++++++--------------- + 1 file changed, 18 insertions(+), 18 deletions(-) + +diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c +index a6c204c08232a..f80edceafc3cf 100644 +--- a/drivers/power/supply/sbs-battery.c ++++ b/drivers/power/supply/sbs-battery.c +@@ -1173,24 +1173,6 @@ static int sbs_probe(struct i2c_client *client) + + i2c_set_clientdata(client, chip); + +- if (!chip->gpio_detect) +- goto skip_gpio; +- +- irq = gpiod_to_irq(chip->gpio_detect); +- if (irq <= 0) { +- dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq); +- goto skip_gpio; +- } +- +- rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq, +- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, +- dev_name(&client->dev), chip); +- if (rc) { +- dev_warn(&client->dev, "Failed to request irq: %d\n", rc); +- goto skip_gpio; +- } +- +-skip_gpio: + /* + * Before we register, we might need to make sure we can actually talk + * to the battery. +@@ -1216,6 +1198,24 @@ static int sbs_probe(struct i2c_client *client) + return dev_err_probe(&client->dev, PTR_ERR(chip->power_supply), + "Failed to register power supply\n"); + ++ if (!chip->gpio_detect) ++ goto out; ++ ++ irq = gpiod_to_irq(chip->gpio_detect); ++ if (irq <= 0) { ++ dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq); ++ goto out; ++ } ++ ++ rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq, ++ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, ++ dev_name(&client->dev), chip); ++ if (rc) { ++ dev_warn(&client->dev, "Failed to request irq: %d\n", rc); ++ goto out; ++ } ++ ++out: + dev_info(&client->dev, + "%s: battery gas gauge device registered\n", client->name); + +-- +2.51.0 + diff --git a/queue-6.12/power-supply-wm97xx-fix-null-pointer-dereference-in-.patch b/queue-6.12/power-supply-wm97xx-fix-null-pointer-dereference-in-.patch new file mode 100644 index 0000000000..7d7f1a133c --- /dev/null +++ b/queue-6.12/power-supply-wm97xx-fix-null-pointer-dereference-in-.patch @@ -0,0 +1,98 @@ +From 12f588124f08c5a33cbf10d27e1e721a07ddce11 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:46:24 +0100 +Subject: power: supply: wm97xx: Fix NULL pointer dereference in + power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 39fe0eac6d755ef215026518985fcf8de9360e9e ] + +In `probe()`, `request_irq()` is called before allocating/registering a +`power_supply` handle. If an interrupt is fired between the call to +`request_irq()` and `power_supply_register()`, the `power_supply` handle +will be used uninitialized in `power_supply_changed()` in +`wm97xx_bat_update()` (triggered from the interrupt handler). This will +lead to a `NULL` pointer dereference since + +Fix this racy `NULL` pointer dereference by making sure the IRQ is +requested _after_ the registration of the `power_supply` handle. Since +the IRQ is the last thing requests in the `probe()` now, remove the +error path for freeing it. Instead add one for unregistering the +`power_supply` handle when IRQ request fails. + +Fixes: 7c87942aef52 ("wm97xx_battery: Use irq to detect charger state") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/97b55f0479a932eea7213844bf66f28a974e27a2.1766270196.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/wm97xx_battery.c | 34 +++++++++++++++------------ + 1 file changed, 19 insertions(+), 15 deletions(-) + +diff --git a/drivers/power/supply/wm97xx_battery.c b/drivers/power/supply/wm97xx_battery.c +index 1cc38d1437d91..181bb7ab64d60 100644 +--- a/drivers/power/supply/wm97xx_battery.c ++++ b/drivers/power/supply/wm97xx_battery.c +@@ -178,12 +178,6 @@ static int wm97xx_bat_probe(struct platform_device *dev) + "failed to get charge GPIO\n"); + if (charge_gpiod) { + gpiod_set_consumer_name(charge_gpiod, "BATT CHRG"); +- ret = request_irq(gpiod_to_irq(charge_gpiod), +- wm97xx_chrg_irq, 0, +- "AC Detect", dev); +- if (ret) +- return dev_err_probe(&dev->dev, ret, +- "failed to request GPIO irq\n"); + props++; /* POWER_SUPPLY_PROP_STATUS */ + } + +@@ -199,10 +193,8 @@ static int wm97xx_bat_probe(struct platform_device *dev) + props++; /* POWER_SUPPLY_PROP_VOLTAGE_MIN */ + + prop = kcalloc(props, sizeof(*prop), GFP_KERNEL); +- if (!prop) { +- ret = -ENOMEM; +- goto err3; +- } ++ if (!prop) ++ return -ENOMEM; + + prop[i++] = POWER_SUPPLY_PROP_PRESENT; + if (charge_gpiod) +@@ -236,15 +228,27 @@ static int wm97xx_bat_probe(struct platform_device *dev) + schedule_work(&bat_work); + } else { + ret = PTR_ERR(bat_psy); +- goto err4; ++ goto free; ++ } ++ ++ if (charge_gpiod) { ++ ret = request_irq(gpiod_to_irq(charge_gpiod), wm97xx_chrg_irq, ++ 0, "AC Detect", dev); ++ if (ret) { ++ dev_err_probe(&dev->dev, ret, ++ "failed to request GPIO irq\n"); ++ goto unregister; ++ } + } + + return 0; +-err4: ++ ++unregister: ++ power_supply_unregister(bat_psy); ++ ++free: + kfree(prop); +-err3: +- if (charge_gpiod) +- free_irq(gpiod_to_irq(charge_gpiod), dev); ++ + return ret; + } + +-- +2.51.0 + diff --git a/queue-6.12/powerpc-eeh-fix-recursive-pci_lock_rescan_remove-loc.patch b/queue-6.12/powerpc-eeh-fix-recursive-pci_lock_rescan_remove-loc.patch new file mode 100644 index 0000000000..3b7533d90b --- /dev/null +++ b/queue-6.12/powerpc-eeh-fix-recursive-pci_lock_rescan_remove-loc.patch @@ -0,0 +1,275 @@ +From 77e78e28dfcac0763a694185f452aa5023590cf1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 10 Dec 2025 08:25:59 -0600 +Subject: powerpc/eeh: fix recursive pci_lock_rescan_remove locking in EEH + event handling +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Narayana Murty N + +[ Upstream commit 815a8d2feb5615ae7f0b5befd206af0b0160614c ] + +The recent commit 1010b4c012b0 ("powerpc/eeh: Make EEH driver device +hotplug safe") restructured the EEH driver to improve synchronization +with the PCI hotplug layer. + +However, it inadvertently moved pci_lock_rescan_remove() outside its +intended scope in eeh_handle_normal_event(), leading to broken PCI +error reporting and improper EEH event triggering. Specifically, +eeh_handle_normal_event() acquired pci_lock_rescan_remove() before +calling eeh_pe_bus_get(), but eeh_pe_bus_get() itself attempts to +acquire the same lock internally, causing nested locking and disrupting +normal EEH event handling paths. + +This patch adds a boolean parameter do_lock to _eeh_pe_bus_get(), +with two public wrappers: + eeh_pe_bus_get() with locking enabled. + eeh_pe_bus_get_nolock() that skips locking. + +Callers that already hold pci_lock_rescan_remove() now use +eeh_pe_bus_get_nolock() to avoid recursive lock acquisition. + +Additionally, pci_lock_rescan_remove() calls are restored to the correct +position—after eeh_pe_bus_get() and immediately before iterating affected +PEs and devices. This ensures EEH-triggered PCI removes occur under proper +bus rescan locking without recursive lock contention. + +The eeh_pe_loc_get() function has been split into two functions: + eeh_pe_loc_get(struct eeh_pe *pe) which retrieves the loc for given PE. + eeh_pe_loc_get_bus(struct pci_bus *bus) which retrieves the location + code for given bus. + +This resolves lockdep warnings such as: + +[ 84.964298] [ T928] ============================================ +[ 84.964304] [ T928] WARNING: possible recursive locking detected +[ 84.964311] [ T928] 6.18.0-rc3 #51 Not tainted +[ 84.964315] [ T928] -------------------------------------------- +[ 84.964320] [ T928] eehd/928 is trying to acquire lock: +[ 84.964324] [ T928] c000000003b29d58 (pci_rescan_remove_lock){+.+.}-{3:3}, at: pci_lock_rescan_remove+0x28/0x40 +[ 84.964342] [ T928] + but task is already holding lock: +[ 84.964347] [ T928] c000000003b29d58 (pci_rescan_remove_lock){+.+.}-{3:3}, at: pci_lock_rescan_remove+0x28/0x40 +[ 84.964357] [ T928] + other info that might help us debug this: +[ 84.964363] [ T928] Possible unsafe locking scenario: + +[ 84.964367] [ T928] CPU0 +[ 84.964370] [ T928] ---- +[ 84.964373] [ T928] lock(pci_rescan_remove_lock); +[ 84.964378] [ T928] lock(pci_rescan_remove_lock); +[ 84.964383] [ T928] + *** DEADLOCK *** + +[ 84.964388] [ T928] May be due to missing lock nesting notation + +[ 84.964393] [ T928] 1 lock held by eehd/928: +[ 84.964397] [ T928] #0: c000000003b29d58 (pci_rescan_remove_lock){+.+.}-{3:3}, at: pci_lock_rescan_remove+0x28/0x40 +[ 84.964408] [ T928] + stack backtrace: +[ 84.964414] [ T928] CPU: 2 UID: 0 PID: 928 Comm: eehd Not tainted 6.18.0-rc3 #51 VOLUNTARY +[ 84.964417] [ T928] Hardware name: IBM,9080-HEX POWER10 (architected) 0x800200 0xf000006 of:IBM,FW1060.00 (NH1060_022) hv:phyp pSeries +[ 84.964419] [ T928] Call Trace: +[ 84.964420] [ T928] [c0000011a7157990] [c000000001705de4] dump_stack_lvl+0xc8/0x130 (unreliable) +[ 84.964424] [ T928] [c0000011a71579d0] [c0000000002f66e0] print_deadlock_bug+0x430/0x440 +[ 84.964428] [ T928] [c0000011a7157a70] [c0000000002fd0c0] __lock_acquire+0x1530/0x2d80 +[ 84.964431] [ T928] [c0000011a7157ba0] [c0000000002fea54] lock_acquire+0x144/0x410 +[ 84.964433] [ T928] [c0000011a7157cb0] [c0000011a7157cb0] __mutex_lock+0xf4/0x1050 +[ 84.964436] [ T928] [c0000011a7157e00] [c000000000de21d8] pci_lock_rescan_remove+0x28/0x40 +[ 84.964439] [ T928] [c0000011a7157e20] [c00000000004ed98] eeh_pe_bus_get+0x48/0xc0 +[ 84.964442] [ T928] [c0000011a7157e50] [c000000000050434] eeh_handle_normal_event+0x64/0xa60 +[ 84.964446] [ T928] [c0000011a7157f30] [c000000000051de8] eeh_event_handler+0xf8/0x190 +[ 84.964450] [ T928] [c0000011a7157f90] [c0000000002747ac] kthread+0x16c/0x180 +[ 84.964453] [ T928] [c0000011a7157fe0] [c00000000000ded8] start_kernel_thread+0x14/0x18 + + +Fixes: 1010b4c012b0 ("powerpc/eeh: Make EEH driver device hotplug safe") +Signed-off-by: Narayana Murty N +Reviewed-by: Sourabh Jain +Reviewed-by: Mahesh Salgaonkar +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/20251210142559.8874-1-nnmlinux@linux.ibm.com +Signed-off-by: Sasha Levin +--- + arch/powerpc/include/asm/eeh.h | 2 + + arch/powerpc/kernel/eeh_driver.c | 11 ++--- + arch/powerpc/kernel/eeh_pe.c | 74 ++++++++++++++++++++++++++++++-- + 3 files changed, 78 insertions(+), 9 deletions(-) + +diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h +index 5e34611de9ef4..b7ebb4ac2c710 100644 +--- a/arch/powerpc/include/asm/eeh.h ++++ b/arch/powerpc/include/asm/eeh.h +@@ -289,6 +289,8 @@ void eeh_pe_dev_traverse(struct eeh_pe *root, + void eeh_pe_restore_bars(struct eeh_pe *pe); + const char *eeh_pe_loc_get(struct eeh_pe *pe); + struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe); ++const char *eeh_pe_loc_get_bus(struct pci_bus *bus); ++struct pci_bus *eeh_pe_bus_get_nolock(struct eeh_pe *pe); + + void eeh_show_enabled(void); + int __init eeh_init(struct eeh_ops *ops); +diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c +index c73e4225e84a5..51a6d881c2292 100644 +--- a/arch/powerpc/kernel/eeh_driver.c ++++ b/arch/powerpc/kernel/eeh_driver.c +@@ -846,7 +846,7 @@ void eeh_handle_normal_event(struct eeh_pe *pe) + + pci_lock_rescan_remove(); + +- bus = eeh_pe_bus_get(pe); ++ bus = eeh_pe_bus_get_nolock(pe); + if (!bus) { + pr_err("%s: Cannot find PCI bus for PHB#%x-PE#%x\n", + __func__, pe->phb->global_number, pe->addr); +@@ -886,14 +886,15 @@ void eeh_handle_normal_event(struct eeh_pe *pe) + /* Log the event */ + if (pe->type & EEH_PE_PHB) { + pr_err("EEH: Recovering PHB#%x, location: %s\n", +- pe->phb->global_number, eeh_pe_loc_get(pe)); ++ pe->phb->global_number, eeh_pe_loc_get_bus(bus)); + } else { + struct eeh_pe *phb_pe = eeh_phb_pe_get(pe->phb); + + pr_err("EEH: Recovering PHB#%x-PE#%x\n", + pe->phb->global_number, pe->addr); + pr_err("EEH: PE location: %s, PHB location: %s\n", +- eeh_pe_loc_get(pe), eeh_pe_loc_get(phb_pe)); ++ eeh_pe_loc_get_bus(bus), ++ eeh_pe_loc_get_bus(eeh_pe_bus_get_nolock(phb_pe))); + } + + #ifdef CONFIG_STACKTRACE +@@ -1098,7 +1099,7 @@ void eeh_handle_normal_event(struct eeh_pe *pe) + eeh_pe_state_clear(pe, EEH_PE_PRI_BUS, true); + eeh_pe_dev_mode_mark(pe, EEH_DEV_REMOVED); + +- bus = eeh_pe_bus_get(pe); ++ bus = eeh_pe_bus_get_nolock(pe); + if (bus) + pci_hp_remove_devices(bus); + else +@@ -1222,7 +1223,7 @@ void eeh_handle_special_event(void) + (phb_pe->state & EEH_PE_RECOVERING)) + continue; + +- bus = eeh_pe_bus_get(phb_pe); ++ bus = eeh_pe_bus_get_nolock(phb_pe); + if (!bus) { + pr_err("%s: Cannot find PCI bus for " + "PHB#%x-PE#%x\n", +diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c +index e740101fadf3b..040e8f69a4aa8 100644 +--- a/arch/powerpc/kernel/eeh_pe.c ++++ b/arch/powerpc/kernel/eeh_pe.c +@@ -812,6 +812,24 @@ void eeh_pe_restore_bars(struct eeh_pe *pe) + const char *eeh_pe_loc_get(struct eeh_pe *pe) + { + struct pci_bus *bus = eeh_pe_bus_get(pe); ++ return eeh_pe_loc_get_bus(bus); ++} ++ ++/** ++ * eeh_pe_loc_get_bus - Retrieve location code binding to the given PCI bus ++ * @bus: PCI bus ++ * ++ * Retrieve the location code associated with the given PCI bus. If the bus ++ * is a root bus, the location code is fetched from the PHB device tree node ++ * or root port. Otherwise, the location code is obtained from the device ++ * tree node of the upstream bridge of the bus. The function walks up the ++ * bus hierarchy if necessary, checking each node for the appropriate ++ * location code property ("ibm,io-base-loc-code" for root buses, ++ * "ibm,slot-location-code" for others). If no location code is found, ++ * returns "N/A". ++ */ ++const char *eeh_pe_loc_get_bus(struct pci_bus *bus) ++{ + struct device_node *dn; + const char *loc = NULL; + +@@ -838,8 +856,9 @@ const char *eeh_pe_loc_get(struct eeh_pe *pe) + } + + /** +- * eeh_pe_bus_get - Retrieve PCI bus according to the given PE ++ * _eeh_pe_bus_get - Retrieve PCI bus according to the given PE + * @pe: EEH PE ++ * @do_lock: Is the caller already held the pci_lock_rescan_remove? + * + * Retrieve the PCI bus according to the given PE. Basically, + * there're 3 types of PEs: PHB/Bus/Device. For PHB PE, the +@@ -847,7 +866,7 @@ const char *eeh_pe_loc_get(struct eeh_pe *pe) + * returned for BUS PE. However, we don't have associated PCI + * bus for DEVICE PE. + */ +-struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe) ++static struct pci_bus *_eeh_pe_bus_get(struct eeh_pe *pe, bool do_lock) + { + struct eeh_dev *edev; + struct pci_dev *pdev; +@@ -862,11 +881,58 @@ struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe) + + /* Retrieve the parent PCI bus of first (top) PCI device */ + edev = list_first_entry_or_null(&pe->edevs, struct eeh_dev, entry); +- pci_lock_rescan_remove(); ++ if (do_lock) ++ pci_lock_rescan_remove(); + pdev = eeh_dev_to_pci_dev(edev); + if (pdev) + bus = pdev->bus; +- pci_unlock_rescan_remove(); ++ if (do_lock) ++ pci_unlock_rescan_remove(); + + return bus; + } ++ ++/** ++ * eeh_pe_bus_get - Retrieve PCI bus associated with the given EEH PE, locking ++ * if needed ++ * @pe: Pointer to the EEH PE ++ * ++ * This function is a wrapper around _eeh_pe_bus_get(), which retrieves the PCI ++ * bus associated with the provided EEH PE structure. It acquires the PCI ++ * rescans lock to ensure safe access to shared data during the retrieval ++ * process. This function should be used when the caller requires the PCI bus ++ * while holding the rescan/remove lock, typically during operations that modify ++ * or inspect PCIe device state in a safe manner. ++ * ++ * RETURNS: ++ * A pointer to the PCI bus associated with the EEH PE, or NULL if none found. ++ */ ++ ++struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe) ++{ ++ return _eeh_pe_bus_get(pe, true); ++} ++ ++/** ++ * eeh_pe_bus_get_nolock - Retrieve PCI bus associated with the given EEH PE ++ * without locking ++ * @pe: Pointer to the EEH PE ++ * ++ * This function is a variant of _eeh_pe_bus_get() that retrieves the PCI bus ++ * associated with the specified EEH PE without acquiring the ++ * pci_lock_rescan_remove lock. It should only be used when the caller can ++ * guarantee safe access to PE structures without the need for that lock, ++ * typically in contexts where the lock is already held locking is otherwise ++ * managed. ++ * ++ * RETURNS: ++ * pointer to the PCI bus associated with the EEH PE, or NULL if none is found. ++ * ++ * NOTE: ++ * Use this function carefully to avoid race conditions and data corruption. ++ */ ++ ++struct pci_bus *eeh_pe_bus_get_nolock(struct eeh_pe *pe) ++{ ++ return _eeh_pe_bus_get(pe, false); ++} +-- +2.51.0 + diff --git a/queue-6.12/powerpc-uaccess-move-barrier_nospec-out-of-allow_rea.patch b/queue-6.12/powerpc-uaccess-move-barrier_nospec-out-of-allow_rea.patch new file mode 100644 index 0000000000..79005a37e9 --- /dev/null +++ b/queue-6.12/powerpc-uaccess-move-barrier_nospec-out-of-allow_rea.patch @@ -0,0 +1,98 @@ +From 88f6af9ecd20b49f6e4472cb7346a1f0bf01043d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Dec 2025 12:20:49 +0100 +Subject: powerpc/uaccess: Move barrier_nospec() out of + allow_read_{from/write}_user() + +From: Christophe Leroy + +[ Upstream commit 5fbc09eb0b4f4b1a4b33abebacbeee0d29f195e9 ] + +Commit 74e19ef0ff80 ("uaccess: Add speculation barrier to +copy_from_user()") added a redundant barrier_nospec() in +copy_from_user(), because powerpc is already calling +barrier_nospec() in allow_read_from_user() and +allow_read_write_user(). But on other architectures that +call to barrier_nospec() was missing. So change powerpc +instead of reverting the above commit and having to fix +other architectures one by one. This is now possible +because barrier_nospec() has also been added in +copy_from_user_iter(). + +Move barrier_nospec() out of allow_read_from_user() and +allow_read_write_user(). This will also allow reuse of those +functions when implementing masked user access which doesn't +require barrier_nospec(). + +Don't add it back in raw_copy_from_user() as it is already called +by copy_from_user() and copy_from_user_iter(). + +Fixes: 74e19ef0ff80 ("uaccess: Add speculation barrier to copy_from_user()") +Signed-off-by: Christophe Leroy +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/f29612105c5fcbc8ceb7303808ddc1a781f0f6b5.1766574657.git.chleroy@kernel.org +Signed-off-by: Sasha Levin +--- + arch/powerpc/include/asm/kup.h | 2 -- + arch/powerpc/include/asm/uaccess.h | 4 ++++ + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/arch/powerpc/include/asm/kup.h b/arch/powerpc/include/asm/kup.h +index 2bb03d941e3e8..6737416dde9f0 100644 +--- a/arch/powerpc/include/asm/kup.h ++++ b/arch/powerpc/include/asm/kup.h +@@ -134,7 +134,6 @@ static __always_inline void kuap_assert_locked(void) + + static __always_inline void allow_read_from_user(const void __user *from, unsigned long size) + { +- barrier_nospec(); + allow_user_access(NULL, from, size, KUAP_READ); + } + +@@ -146,7 +145,6 @@ static __always_inline void allow_write_to_user(void __user *to, unsigned long s + static __always_inline void allow_read_write_user(void __user *to, const void __user *from, + unsigned long size) + { +- barrier_nospec(); + allow_user_access(to, from, size, KUAP_READ_WRITE); + } + +diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h +index 4f5a46a77fa2b..3987a5c33558b 100644 +--- a/arch/powerpc/include/asm/uaccess.h ++++ b/arch/powerpc/include/asm/uaccess.h +@@ -301,6 +301,7 @@ do { \ + __typeof__(sizeof(*(ptr))) __gu_size = sizeof(*(ptr)); \ + \ + might_fault(); \ ++ barrier_nospec(); \ + allow_read_from_user(__gu_addr, __gu_size); \ + __get_user_size_allowed(__gu_val, __gu_addr, __gu_size, __gu_err); \ + prevent_read_from_user(__gu_addr, __gu_size); \ +@@ -329,6 +330,7 @@ raw_copy_in_user(void __user *to, const void __user *from, unsigned long n) + { + unsigned long ret; + ++ barrier_nospec(); + allow_read_write_user(to, from, n); + ret = __copy_tofrom_user(to, from, n); + prevent_read_write_user(to, from, n); +@@ -415,6 +417,7 @@ static __must_check __always_inline bool user_access_begin(const void __user *pt + + might_fault(); + ++ barrier_nospec(); + allow_read_write_user((void __user *)ptr, ptr, len); + return true; + } +@@ -431,6 +434,7 @@ user_read_access_begin(const void __user *ptr, size_t len) + + might_fault(); + ++ barrier_nospec(); + allow_read_from_user(ptr, len); + return true; + } +-- +2.51.0 + diff --git a/queue-6.12/printk-vt-fbcon-remove-console_conditional_schedule.patch b/queue-6.12/printk-vt-fbcon-remove-console_conditional_schedule.patch new file mode 100644 index 0000000000..2a880d8120 --- /dev/null +++ b/queue-6.12/printk-vt-fbcon-remove-console_conditional_schedule.patch @@ -0,0 +1,176 @@ +From 1a2e9dd9b43f1731d59e6f4a3f66207623db5f48 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 19:08:36 +0100 +Subject: printk, vt, fbcon: Remove console_conditional_schedule() + +From: Sebastian Andrzej Siewior + +[ Upstream commit 8e9bf8b9e8c0a3e1ef16dd48260a113f65ed01d2 ] + +do_con_write(), fbcon_redraw.*() invoke console_conditional_schedule() +which is a conditional scheduling point based on printk's internal +variables console_may_schedule. It may only be used if the console lock +is acquired for instance via console_lock() or console_trylock(). + +Prinkt sets the internal variable to 1 (and allows to schedule) +if the console lock has been acquired via console_lock(). The trylock +does not allow it. + +The console_conditional_schedule() invocation in do_con_write() is +invoked shortly before console_unlock(). +The console_conditional_schedule() invocation in fbcon_redraw.*() +original from fbcon_scroll() / vt's con_scroll() which originate from a +line feed. + +In console_unlock() the variable is set to 0 (forbids to schedule) and +it tries to schedule while making progress printing. This is brand new +compared to when console_conditional_schedule() was added in v2.4.9.11. + +In v2.6.38-rc3, console_unlock() (started its existence) iterated over +all consoles and flushed them with disabled interrupts. A scheduling +attempt here was not possible, it relied that a long print scheduled +before console_unlock(). + +Since commit 8d91f8b15361d ("printk: do cond_resched() between lines +while outputting to consoles"), which appeared in v4.5-rc1, +console_unlock() attempts to schedule if it was allowed to schedule +while during console_lock(). Each record is idealy one line so after +every line feed. + +This console_conditional_schedule() is also only relevant on +PREEMPT_NONE and PREEMPT_VOLUNTARY builds. In other configurations +cond_resched() becomes a nop and has no impact. + +I'm bringing this all up just proof that it is not required anymore. It +becomes a problem on a PREEMPT_RT build with debug code enabled because +that might_sleep() in cond_resched() remains and triggers a warnings. +This is due to + + legacy_kthread_func-> console_flush_one_record -> vt_console_print-> lf + -> con_scroll -> fbcon_scroll + +and vt_console_print() acquires a spinlock_t which does not allow a +voluntary schedule. There is no need to fb_scroll() to schedule since +console_flush_one_record() attempts to schedule after each line. +!PREEMPT_RT is not affected because the legacy printing thread is only +enabled on PREEMPT_RT builds. + +Therefore I suggest to remove console_conditional_schedule(). + +Cc: Simona Vetter +Cc: Helge Deller +Cc: linux-fbdev@vger.kernel.org +Cc: dri-devel@lists.freedesktop.org +Fixes: 5f53ca3ff83b4 ("printk: Implement legacy printer kthread for PREEMPT_RT") +Signed-off-by: Sebastian Andrzej Siewior +Acked-by: Greg Kroah-Hartman +Acked-by: Petr Mladek # from printk() POV +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/tty/vt/vt.c | 1 - + drivers/video/fbdev/core/fbcon.c | 6 ------ + include/linux/console.h | 1 - + kernel/printk/printk.c | 16 ---------------- + 4 files changed, 24 deletions(-) + +diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c +index 5b09ce71345b6..b5dff1344a441 100644 +--- a/drivers/tty/vt/vt.c ++++ b/drivers/tty/vt/vt.c +@@ -3100,7 +3100,6 @@ static int do_con_write(struct tty_struct *tty, const u8 *buf, int count) + goto rescan_last_byte; + } + con_flush(vc, &draw); +- console_conditional_schedule(); + notify_update(vc); + console_unlock(); + return n; +diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c +index 3cc68324f297b..350c4d80b745d 100644 +--- a/drivers/video/fbdev/core/fbcon.c ++++ b/drivers/video/fbdev/core/fbcon.c +@@ -1593,12 +1593,10 @@ static void fbcon_redraw_move(struct vc_data *vc, struct fbcon_display *p, + start = s; + } + } +- console_conditional_schedule(); + s++; + } while (s < le); + if (s > start) + fbcon_putcs(vc, start, s - start, dy, x); +- console_conditional_schedule(); + dy++; + } + } +@@ -1634,14 +1632,12 @@ static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info, + } + + scr_writew(c, d); +- console_conditional_schedule(); + s++; + d++; + } while (s < le); + if (s > start) + par->bitops->bmove(vc, info, line + ycount, x, line, x, 1, + s - start); +- console_conditional_schedule(); + if (ycount > 0) + line++; + else { +@@ -1689,13 +1685,11 @@ static void fbcon_redraw(struct vc_data *vc, int line, int count, int offset) + } + } + scr_writew(c, d); +- console_conditional_schedule(); + s++; + d++; + } while (s < le); + if (s > start) + fbcon_putcs(vc, start, s - start, line, x); +- console_conditional_schedule(); + if (offset > 0) + line++; + else { +diff --git a/include/linux/console.h b/include/linux/console.h +index eba367bf605da..409bfd5ac88a1 100644 +--- a/include/linux/console.h ++++ b/include/linux/console.h +@@ -629,7 +629,6 @@ extern int unregister_console(struct console *); + extern void console_lock(void); + extern int console_trylock(void); + extern void console_unlock(void); +-extern void console_conditional_schedule(void); + extern void console_unblank(void); + extern void console_flush_on_panic(enum con_flush_mode mode); + extern struct tty_driver *console_device(int *); +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index 3a91b739e8f30..95f49feeb29fe 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -3280,22 +3280,6 @@ void console_unlock(void) + } + EXPORT_SYMBOL(console_unlock); + +-/** +- * console_conditional_schedule - yield the CPU if required +- * +- * If the console code is currently allowed to sleep, and +- * if this CPU should yield the CPU to another task, do +- * so here. +- * +- * Must be called within console_lock();. +- */ +-void __sched console_conditional_schedule(void) +-{ +- if (console_may_schedule) +- cond_resched(); +-} +-EXPORT_SYMBOL(console_conditional_schedule); +- + void console_unblank(void) + { + bool found_unblank = false; +-- +2.51.0 + diff --git a/queue-6.12/procfs-fix-missing-rcu-protection-when-reading-real_.patch b/queue-6.12/procfs-fix-missing-rcu-protection-when-reading-real_.patch new file mode 100644 index 0000000000..5767cacd7a --- /dev/null +++ b/queue-6.12/procfs-fix-missing-rcu-protection-when-reading-real_.patch @@ -0,0 +1,59 @@ +From dd9e1ab61a9b16e1a82989bb09922a4b6d3df34f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 16:30:07 +0800 +Subject: procfs: fix missing RCU protection when reading real_parent in + do_task_stat() + +From: Jinliang Zheng + +[ Upstream commit 76149d53502cf17ef3ae454ff384551236fba867 ] + +When reading /proc/[pid]/stat, do_task_stat() accesses task->real_parent +without proper RCU protection, which leads to: + + cpu 0 cpu 1 + ----- ----- + do_task_stat + var = task->real_parent + release_task + call_rcu(delayed_put_task_struct) + task_tgid_nr_ns(var) + rcu_read_lock <--- Too late to protect task->real_parent! + task_pid_ptr <--- UAF! + rcu_read_unlock + +This patch uses task_ppid_nr_ns() instead of task_tgid_nr_ns() to add +proper RCU protection for accessing task->real_parent. + +Link: https://lkml.kernel.org/r/20260128083007.3173016-1-alexjlzheng@tencent.com +Fixes: 06fffb1267c9 ("do_task_stat: don't take rcu_read_lock()") +Signed-off-by: Jinliang Zheng +Acked-by: Oleg Nesterov +Cc: David Hildenbrand +Cc: Ingo Molnar +Cc: Lorenzo Stoakes +Cc: Mateusz Guzik +Cc: ruippan +Cc: Usama Arif +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/proc/array.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/proc/array.c b/fs/proc/array.c +index 5e4f7b411fbdb..363d9331216b9 100644 +--- a/fs/proc/array.c ++++ b/fs/proc/array.c +@@ -531,7 +531,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, + } + + sid = task_session_nr_ns(task, ns); +- ppid = task_tgid_nr_ns(task->real_parent, ns); ++ ppid = task_ppid_nr_ns(task, ns); + pgid = task_pgrp_nr_ns(task, ns); + + unlock_task_sighand(task, &flags); +-- +2.51.0 + diff --git a/queue-6.12/pstore-ram-fix-buffer-overflow-in-persistent_ram_sav.patch b/queue-6.12/pstore-ram-fix-buffer-overflow-in-persistent_ram_sav.patch new file mode 100644 index 0000000000..f8b84ce604 --- /dev/null +++ b/queue-6.12/pstore-ram-fix-buffer-overflow-in-persistent_ram_sav.patch @@ -0,0 +1,92 @@ +From 1559674d7c9e05fbaf6e2b4b8146a784b0cfae1d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 1 Feb 2026 13:22:40 +0000 +Subject: pstore/ram: fix buffer overflow in persistent_ram_save_old() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Sai Ritvik Tanksalkar + +[ Upstream commit 5669645c052f235726a85f443769b6fc02f66762 ] + +persistent_ram_save_old() can be called multiple times for the same +persistent_ram_zone (e.g., via ramoops_pstore_read -> ramoops_get_next_prz +for PSTORE_TYPE_DMESG records). + +Currently, the function only allocates prz->old_log when it is NULL, +but it unconditionally updates prz->old_log_size to the current buffer +size and then performs memcpy_fromio() using this new size. If the +buffer size has grown since the first allocation (which can happen +across different kernel boot cycles), this leads to: + +1. A heap buffer overflow (OOB write) in the memcpy_fromio() calls +2. A subsequent OOB read when ramoops_pstore_read() accesses the buffer + using the incorrect (larger) old_log_size + +The KASAN splat would look similar to: + BUG: KASAN: slab-out-of-bounds in ramoops_pstore_read+0x... + Read of size N at addr ... by task ... + +The conditions are likely extremely hard to hit: + + 0. Crash with a ramoops write of less-than-record-max-size bytes. + 1. Reboot: ramoops registers, pstore_get_records(0) reads old crash, + allocates old_log with size X + 2. Crash handler registered, timer started (if pstore_update_ms >= 0) + 3. Oops happens (non-fatal, system continues) + 4. pstore_dump() writes oops via ramoops_pstore_write() size Y (>X) + 5. pstore_new_entry = 1, pstore_timer_kick() called + 6. System continues running (not a panic oops) + 7. Timer fires after pstore_update_ms milliseconds + 8. pstore_timefunc() → schedule_work() → pstore_dowork() → pstore_get_records(1) + 9. ramoops_get_next_prz() → persistent_ram_save_old() + 10. buffer_size() returns Y, but old_log is X bytes + 11. Y > X: memcpy_fromio() overflows heap + + Requirements: + - a prior crash record exists that did not fill the record size + (almost impossible since the crash handler writes as much as it + can possibly fit into the record, capped by max record size and + the kmsg buffer almost always exceeds the max record size) + - pstore_update_ms >= 0 (disabled by default) + - Non-fatal oops (system survives) + +Free and reallocate the buffer when the new size differs from the +previously allocated size. This ensures old_log always has sufficient +space for the data being copied. + +Fixes: 201e4aca5aa1 ("pstore/ram: Should update old dmesg buffer before reading") +Signed-off-by: Sai Ritvik Tanksalkar +Link: https://patch.msgid.link/20260201132240.2948732-1-stanksal@purdue.edu +Signed-off-by: Kees Cook +Signed-off-by: Sasha Levin +--- + fs/pstore/ram_core.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c +index f1848cdd6d348..c9eaacdec37e4 100644 +--- a/fs/pstore/ram_core.c ++++ b/fs/pstore/ram_core.c +@@ -298,6 +298,17 @@ void persistent_ram_save_old(struct persistent_ram_zone *prz) + if (!size) + return; + ++ /* ++ * If the existing buffer is differently sized, free it so a new ++ * one is allocated. This can happen when persistent_ram_save_old() ++ * is called early in boot and later for a timer-triggered ++ * survivable crash when the crash dumps don't match in size ++ * (which would be extremely unlikely given kmsg buffers usually ++ * exceed prz buffer sizes). ++ */ ++ if (prz->old_log && prz->old_log_size != size) ++ persistent_ram_free_old(prz); ++ + if (!prz->old_log) { + persistent_ram_ecc_old(prz); + prz->old_log = kvzalloc(size, GFP_KERNEL); +-- +2.51.0 + diff --git a/queue-6.12/quota-fix-livelock-between-quotactl-and-freeze_super.patch b/queue-6.12/quota-fix-livelock-between-quotactl-and-freeze_super.patch new file mode 100644 index 0000000000..8fd4eb147a --- /dev/null +++ b/queue-6.12/quota-fix-livelock-between-quotactl-and-freeze_super.patch @@ -0,0 +1,73 @@ +From 3d30dd15d2f28e394890646a79faa50353416e9e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 21:31:03 +0000 +Subject: quota: fix livelock between quotactl and freeze_super + +From: Abhishek Bapat + +[ Upstream commit 77449e453dfc006ad738dec55374c4cbc056fd39 ] + +When a filesystem is frozen, quotactl_block() enters a retry loop +waiting for the filesystem to thaw. It acquires s_umount, checks the +freeze state, drops s_umount and uses sb_start_write() - sb_end_write() +pair to wait for the unfreeze. + +However, this retry loop can trigger a livelock issue, specifically on +kernels with preemption disabled. + +The mechanism is as follows: +1. freeze_super() sets SB_FREEZE_WRITE and calls sb_wait_write(). +2. sb_wait_write() calls percpu_down_write(), which initiates + synchronize_rcu(). +3. Simultaneously, quotactl_block() spins in its retry loop, immediately + executing the sb_start_write() - sb_end_write() pair. +4. Because the kernel is non-preemptible and the loop contains no + scheduling points, quotactl_block() never yields the CPU. This + prevents that CPU from reaching an RCU quiescent state. +5. synchronize_rcu() in the freezer thread waits indefinitely for the + quotactl_block() CPU to report a quiescent state. +6. quotactl_block() spins indefinitely waiting for the freezer to + advance, which it cannot do as it is blocked on the RCU sync. + +This results in a hang of the freezer process and 100% CPU usage by the +quota process. + +While this can occur intermittently on multi-core systems, it is +reliably reproducing on a node with the following script, running both +the freezer and the quota toggle on the same CPU: + + # mkfs.ext4 -O quota /dev/sda 2g && mkdir a_mount + # mount /dev/sda -o quota,usrquota,grpquota a_mount + # taskset -c 3 bash -c "while true; do xfs_freeze -f a_mount; \ + xfs_freeze -u a_mount; done" & + # taskset -c 3 bash -c "while true; do quotaon a_mount; \ + quotaoff a_mount; done" & + +Adding cond_resched() to the retry loop fixes the issue. It acts as an +RCU quiescent state, allowing synchronize_rcu() in percpu_down_write() +to complete. + +Fixes: 576215cffdef ("fs: Drop wait_unfrozen wait queue") +Signed-off-by: Abhishek Bapat +Link: https://patch.msgid.link/20260115213103.1089129-1-abhishekbapat@google.com +Signed-off-by: Jan Kara +Signed-off-by: Sasha Levin +--- + fs/quota/quota.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/quota/quota.c b/fs/quota/quota.c +index 290157bc7bec2..04c6712d4031c 100644 +--- a/fs/quota/quota.c ++++ b/fs/quota/quota.c +@@ -899,6 +899,7 @@ static struct super_block *quotactl_block(const char __user *special, int cmd) + sb_start_write(sb); + sb_end_write(sb); + put_super(sb); ++ cond_resched(); + goto retry; + } + return sb; +-- +2.51.0 + diff --git a/queue-6.12/rcu-fix-rcu_read_unlock-deadloop-due-to-softirq.patch b/queue-6.12/rcu-fix-rcu_read_unlock-deadloop-due-to-softirq.patch new file mode 100644 index 0000000000..4097ad52e7 --- /dev/null +++ b/queue-6.12/rcu-fix-rcu_read_unlock-deadloop-due-to-softirq.patch @@ -0,0 +1,168 @@ +From 2ce2c637af0daac1ac2a270b4f8cdd60b9b7afca Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 1 Jan 2026 11:34:10 -0500 +Subject: rcu: Fix rcu_read_unlock() deadloop due to softirq + +From: Yao Kai + +[ Upstream commit d41e37f26b3157b3f1d10223863519a943aa239b ] + +Commit 5f5fa7ea89dc ("rcu: Don't use negative nesting depth in +__rcu_read_unlock()") removes the recursion-protection code from +__rcu_read_unlock(). Therefore, we could invoke the deadloop in +raise_softirq_irqoff() with ftrace enabled as follows: + +WARNING: CPU: 0 PID: 0 at kernel/trace/trace.c:3021 __ftrace_trace_stack.constprop.0+0x172/0x180 +Modules linked in: my_irq_work(O) +CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Tainted: G O 6.18.0-rc7-dirty #23 PREEMPT(full) +Tainted: [O]=OOT_MODULE +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014 +RIP: 0010:__ftrace_trace_stack.constprop.0+0x172/0x180 +RSP: 0018:ffffc900000034a8 EFLAGS: 00010002 +RAX: 0000000000000000 RBX: 0000000000000004 RCX: 0000000000000000 +RDX: 0000000000000003 RSI: ffffffff826d7b87 RDI: ffffffff826e9329 +RBP: 0000000000090009 R08: 0000000000000005 R09: ffffffff82afbc4c +R10: 0000000000000008 R11: 0000000000011d7a R12: 0000000000000000 +R13: ffff888003874100 R14: 0000000000000003 R15: ffff8880038c1054 +FS: 0000000000000000(0000) GS:ffff8880fa8ea000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 000055b31fa7f540 CR3: 00000000078f4005 CR4: 0000000000770ef0 +PKRU: 55555554 +Call Trace: + + trace_buffer_unlock_commit_regs+0x6d/0x220 + trace_event_buffer_commit+0x5c/0x260 + trace_event_raw_event_softirq+0x47/0x80 + raise_softirq_irqoff+0x6e/0xa0 + rcu_read_unlock_special+0xb1/0x160 + unwind_next_frame+0x203/0x9b0 + __unwind_start+0x15d/0x1c0 + arch_stack_walk+0x62/0xf0 + stack_trace_save+0x48/0x70 + __ftrace_trace_stack.constprop.0+0x144/0x180 + trace_buffer_unlock_commit_regs+0x6d/0x220 + trace_event_buffer_commit+0x5c/0x260 + trace_event_raw_event_softirq+0x47/0x80 + raise_softirq_irqoff+0x6e/0xa0 + rcu_read_unlock_special+0xb1/0x160 + unwind_next_frame+0x203/0x9b0 + __unwind_start+0x15d/0x1c0 + arch_stack_walk+0x62/0xf0 + stack_trace_save+0x48/0x70 + __ftrace_trace_stack.constprop.0+0x144/0x180 + trace_buffer_unlock_commit_regs+0x6d/0x220 + trace_event_buffer_commit+0x5c/0x260 + trace_event_raw_event_softirq+0x47/0x80 + raise_softirq_irqoff+0x6e/0xa0 + rcu_read_unlock_special+0xb1/0x160 + unwind_next_frame+0x203/0x9b0 + __unwind_start+0x15d/0x1c0 + arch_stack_walk+0x62/0xf0 + stack_trace_save+0x48/0x70 + __ftrace_trace_stack.constprop.0+0x144/0x180 + trace_buffer_unlock_commit_regs+0x6d/0x220 + trace_event_buffer_commit+0x5c/0x260 + trace_event_raw_event_softirq+0x47/0x80 + raise_softirq_irqoff+0x6e/0xa0 + rcu_read_unlock_special+0xb1/0x160 + __is_insn_slot_addr+0x54/0x70 + kernel_text_address+0x48/0xc0 + __kernel_text_address+0xd/0x40 + unwind_get_return_address+0x1e/0x40 + arch_stack_walk+0x9c/0xf0 + stack_trace_save+0x48/0x70 + __ftrace_trace_stack.constprop.0+0x144/0x180 + trace_buffer_unlock_commit_regs+0x6d/0x220 + trace_event_buffer_commit+0x5c/0x260 + trace_event_raw_event_softirq+0x47/0x80 + __raise_softirq_irqoff+0x61/0x80 + __flush_smp_call_function_queue+0x115/0x420 + __sysvec_call_function_single+0x17/0xb0 + sysvec_call_function_single+0x8c/0xc0 + + +Commit b41642c87716 ("rcu: Fix rcu_read_unlock() deadloop due to IRQ work") +fixed the infinite loop in rcu_read_unlock_special() for IRQ work by +setting a flag before calling irq_work_queue_on(). We fix this issue by +setting the same flag before calling raise_softirq_irqoff() and rename the +flag to defer_qs_pending for more common. + +Fixes: 5f5fa7ea89dc ("rcu: Don't use negative nesting depth in __rcu_read_unlock()") +Reported-by: Tengda Wu +Signed-off-by: Yao Kai +Reviewed-by: Joel Fernandes +Tested-by: Paul E. McKenney +Signed-off-by: Joel Fernandes +Signed-off-by: Boqun Feng +Signed-off-by: Sasha Levin +--- + kernel/rcu/tree.h | 2 +- + kernel/rcu/tree_plugin.h | 15 +++++++++------ + 2 files changed, 10 insertions(+), 7 deletions(-) + +diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h +index 8ba04b179416a..08c020e01425d 100644 +--- a/kernel/rcu/tree.h ++++ b/kernel/rcu/tree.h +@@ -202,7 +202,7 @@ struct rcu_data { + /* during and after the last grace */ + /* period it is aware of. */ + struct irq_work defer_qs_iw; /* Obtain later scheduler attention. */ +- int defer_qs_iw_pending; /* Scheduler attention pending? */ ++ int defer_qs_pending; /* irqwork or softirq pending? */ + struct work_struct strict_work; /* Schedule readers for strict GPs. */ + + /* 2) batch handling */ +diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h +index ada3cf2e72fc6..47a44f6dede0c 100644 +--- a/kernel/rcu/tree_plugin.h ++++ b/kernel/rcu/tree_plugin.h +@@ -486,8 +486,8 @@ rcu_preempt_deferred_qs_irqrestore(struct task_struct *t, unsigned long flags) + union rcu_special special; + + rdp = this_cpu_ptr(&rcu_data); +- if (rdp->defer_qs_iw_pending == DEFER_QS_PENDING) +- rdp->defer_qs_iw_pending = DEFER_QS_IDLE; ++ if (rdp->defer_qs_pending == DEFER_QS_PENDING) ++ rdp->defer_qs_pending = DEFER_QS_IDLE; + + /* + * If RCU core is waiting for this CPU to exit its critical section, +@@ -645,7 +645,7 @@ static void rcu_preempt_deferred_qs_handler(struct irq_work *iwp) + * 5. Deferred QS reporting does not happen. + */ + if (rcu_preempt_depth() > 0) +- WRITE_ONCE(rdp->defer_qs_iw_pending, DEFER_QS_IDLE); ++ WRITE_ONCE(rdp->defer_qs_pending, DEFER_QS_IDLE); + } + + /* +@@ -747,7 +747,10 @@ static void rcu_read_unlock_special(struct task_struct *t) + // Using softirq, safe to awaken, and either the + // wakeup is free or there is either an expedited + // GP in flight or a potential need to deboost. +- raise_softirq_irqoff(RCU_SOFTIRQ); ++ if (rdp->defer_qs_pending != DEFER_QS_PENDING) { ++ rdp->defer_qs_pending = DEFER_QS_PENDING; ++ raise_softirq_irqoff(RCU_SOFTIRQ); ++ } + } else { + // Enabling BH or preempt does reschedule, so... + // Also if no expediting and no possible deboosting, +@@ -756,11 +759,11 @@ static void rcu_read_unlock_special(struct task_struct *t) + set_tsk_need_resched(current); + set_preempt_need_resched(); + if (IS_ENABLED(CONFIG_IRQ_WORK) && irqs_were_disabled && +- needs_exp && rdp->defer_qs_iw_pending != DEFER_QS_PENDING && ++ needs_exp && rdp->defer_qs_pending != DEFER_QS_PENDING && + cpu_online(rdp->cpu)) { + // Get scheduler to re-evaluate and call hooks. + // If !IRQ_WORK, FQS scan will eventually IPI. +- rdp->defer_qs_iw_pending = DEFER_QS_PENDING; ++ rdp->defer_qs_pending = DEFER_QS_PENDING; + irq_work_queue_on(&rdp->defer_qs_iw, rdp->cpu); + } + } +-- +2.51.0 + diff --git a/queue-6.12/rcu-refactor-expedited-handling-check-in-rcu_read_un.patch b/queue-6.12/rcu-refactor-expedited-handling-check-in-rcu_read_un.patch new file mode 100644 index 0000000000..537606c998 --- /dev/null +++ b/queue-6.12/rcu-refactor-expedited-handling-check-in-rcu_read_un.patch @@ -0,0 +1,139 @@ +From eaa96baa62c7be29fa290442c089796b8cc33782 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 15 Jul 2025 16:01:52 -0400 +Subject: rcu: Refactor expedited handling check in rcu_read_unlock_special() + +From: Joel Fernandes + +[ Upstream commit 908a97eba8c8b510996bf5d77d1e3070d59caa6d ] + +Extract the complex expedited handling condition in rcu_read_unlock_special() +into a separate function rcu_unlock_needs_exp_handling() with detailed +comments explaining each condition. + +This improves code readability. No functional change intended. + +Reviewed-by: "Paul E. McKenney" +Signed-off-by: Joel Fernandes +Signed-off-by: Neeraj Upadhyay (AMD) +Stable-dep-of: d41e37f26b31 ("rcu: Fix rcu_read_unlock() deadloop due to softirq") +Signed-off-by: Sasha Levin +--- + kernel/rcu/tree_plugin.h | 83 +++++++++++++++++++++++++++++++++++----- + 1 file changed, 74 insertions(+), 9 deletions(-) + +diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h +index 2d865b2096beb..8a75ddcff8c40 100644 +--- a/kernel/rcu/tree_plugin.h ++++ b/kernel/rcu/tree_plugin.h +@@ -651,6 +651,75 @@ static void rcu_preempt_deferred_qs_handler(struct irq_work *iwp) + local_irq_restore(flags); + } + ++/* ++ * Check if expedited grace period processing during unlock is needed. ++ * ++ * This function determines whether expedited handling is required based on: ++ * 1. Task blocking an expedited grace period (based on a heuristic, could be ++ * false-positive, see below.) ++ * 2. CPU participating in an expedited grace period ++ * 3. Strict grace period mode requiring expedited handling ++ * 4. RCU priority deboosting needs when interrupts were disabled ++ * ++ * @t: The task being checked ++ * @rdp: The per-CPU RCU data ++ * @rnp: The RCU node for this CPU ++ * @irqs_were_disabled: Whether interrupts were disabled before rcu_read_unlock() ++ * ++ * Returns true if expedited processing of the rcu_read_unlock() is needed. ++ */ ++static bool rcu_unlock_needs_exp_handling(struct task_struct *t, ++ struct rcu_data *rdp, ++ struct rcu_node *rnp, ++ bool irqs_were_disabled) ++{ ++ /* ++ * Check if this task is blocking an expedited grace period. If the ++ * task was preempted within an RCU read-side critical section and is ++ * on the expedited grace period blockers list (exp_tasks), we need ++ * expedited handling to unblock the expedited GP. This is not an exact ++ * check because 't' might not be on the exp_tasks list at all - its ++ * just a fast heuristic that can be false-positive sometimes. ++ */ ++ if (t->rcu_blocked_node && READ_ONCE(t->rcu_blocked_node->exp_tasks)) ++ return true; ++ ++ /* ++ * Check if this CPU is participating in an expedited grace period. ++ * The expmask bitmap tracks which CPUs need to check in for the ++ * current expedited GP. If our CPU's bit is set, we need expedited ++ * handling to help complete the expedited GP. ++ */ ++ if (rdp->grpmask & READ_ONCE(rnp->expmask)) ++ return true; ++ ++ /* ++ * In CONFIG_RCU_STRICT_GRACE_PERIOD=y kernels, all grace periods ++ * are treated as short for testing purposes even if that means ++ * disturbing the system more. Check if either: ++ * - This CPU has not yet reported a quiescent state, or ++ * - This task was preempted within an RCU critical section ++ * In either case, require expedited handling for strict GP mode. ++ */ ++ if (IS_ENABLED(CONFIG_RCU_STRICT_GRACE_PERIOD) && ++ ((rdp->grpmask & READ_ONCE(rnp->qsmask)) || t->rcu_blocked_node)) ++ return true; ++ ++ /* ++ * RCU priority boosting case: If a task is subject to RCU priority ++ * boosting and exits an RCU read-side critical section with interrupts ++ * disabled, we need expedited handling to ensure timely deboosting. ++ * Without this, a low-priority task could incorrectly run at high ++ * real-time priority for an extended period degrading real-time ++ * responsiveness. This applies to all CONFIG_RCU_BOOST=y kernels, ++ * not just to PREEMPT_RT. ++ */ ++ if (IS_ENABLED(CONFIG_RCU_BOOST) && irqs_were_disabled && t->rcu_blocked_node) ++ return true; ++ ++ return false; ++} ++ + /* + * Handle special cases during rcu_read_unlock(), such as needing to + * notify RCU core processing or task having blocked during the RCU +@@ -670,18 +739,14 @@ static void rcu_read_unlock_special(struct task_struct *t) + local_irq_save(flags); + irqs_were_disabled = irqs_disabled_flags(flags); + if (preempt_bh_were_disabled || irqs_were_disabled) { +- bool expboost; // Expedited GP in flight or possible boosting. ++ bool needs_exp; // Expedited handling needed. + struct rcu_data *rdp = this_cpu_ptr(&rcu_data); + struct rcu_node *rnp = rdp->mynode; + +- expboost = (t->rcu_blocked_node && READ_ONCE(t->rcu_blocked_node->exp_tasks)) || +- (rdp->grpmask & READ_ONCE(rnp->expmask)) || +- (IS_ENABLED(CONFIG_RCU_STRICT_GRACE_PERIOD) && +- ((rdp->grpmask & READ_ONCE(rnp->qsmask)) || t->rcu_blocked_node)) || +- (IS_ENABLED(CONFIG_RCU_BOOST) && irqs_were_disabled && +- t->rcu_blocked_node); ++ needs_exp = rcu_unlock_needs_exp_handling(t, rdp, rnp, irqs_were_disabled); ++ + // Need to defer quiescent state until everything is enabled. +- if (use_softirq && (in_hardirq() || (expboost && !irqs_were_disabled))) { ++ if (use_softirq && (in_hardirq() || (needs_exp && !irqs_were_disabled))) { + // Using softirq, safe to awaken, and either the + // wakeup is free or there is either an expedited + // GP in flight or a potential need to deboost. +@@ -694,7 +759,7 @@ static void rcu_read_unlock_special(struct task_struct *t) + set_tsk_need_resched(current); + set_preempt_need_resched(); + if (IS_ENABLED(CONFIG_IRQ_WORK) && irqs_were_disabled && +- expboost && rdp->defer_qs_iw_pending != DEFER_QS_PENDING && ++ needs_exp && rdp->defer_qs_iw_pending != DEFER_QS_PENDING && + cpu_online(rdp->cpu)) { + // Get scheduler to re-evaluate and call hooks. + // If !IRQ_WORK, FQS scan will eventually IPI. +-- +2.51.0 + diff --git a/queue-6.12/rcu-remove-local_irq_save-restore-in-rcu_preempt_def.patch b/queue-6.12/rcu-remove-local_irq_save-restore-in-rcu_preempt_def.patch new file mode 100644 index 0000000000..b599535b94 --- /dev/null +++ b/queue-6.12/rcu-remove-local_irq_save-restore-in-rcu_preempt_def.patch @@ -0,0 +1,55 @@ +From 1ecf1b8340000e96461786fbd6597e88f9a1d402 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 Aug 2025 21:30:02 +0800 +Subject: rcu: Remove local_irq_save/restore() in + rcu_preempt_deferred_qs_handler() + +From: Zqiang + +[ Upstream commit 42d590d100f2e47e47d974a902b9ed610e464824 ] + +The per-CPU rcu_data structure's ->defer_qs_iw field is initialized +by IRQ_WORK_INIT_HARD(), which means that the subsequent invocation of +rcu_preempt_deferred_qs_handler() will always be executed with interrupts +disabled. This commit therefore removes the local_irq_save/restore() +operations from rcu_preempt_deferred_qs_handler() and adds a call to +lockdep_assert_irqs_disabled() in order to enable lockdep to diagnose +mistaken invocations of this function from interrupts-enabled code. + +Signed-off-by: Zqiang +Signed-off-by: Paul E. McKenney +Stable-dep-of: d41e37f26b31 ("rcu: Fix rcu_read_unlock() deadloop due to softirq") +Signed-off-by: Sasha Levin +--- + kernel/rcu/tree_plugin.h | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h +index 8a75ddcff8c40..ada3cf2e72fc6 100644 +--- a/kernel/rcu/tree_plugin.h ++++ b/kernel/rcu/tree_plugin.h +@@ -626,11 +626,10 @@ notrace void rcu_preempt_deferred_qs(struct task_struct *t) + */ + static void rcu_preempt_deferred_qs_handler(struct irq_work *iwp) + { +- unsigned long flags; + struct rcu_data *rdp; + ++ lockdep_assert_irqs_disabled(); + rdp = container_of(iwp, struct rcu_data, defer_qs_iw); +- local_irq_save(flags); + + /* + * If the IRQ work handler happens to run in the middle of RCU read-side +@@ -647,8 +646,6 @@ static void rcu_preempt_deferred_qs_handler(struct irq_work *iwp) + */ + if (rcu_preempt_depth() > 0) + WRITE_ONCE(rdp->defer_qs_iw_pending, DEFER_QS_IDLE); +- +- local_irq_restore(flags); + } + + /* +-- +2.51.0 + diff --git a/queue-6.12/rdma-core-add-rdma_rw_max_sge-helper-for-sq-sizing.patch b/queue-6.12/rdma-core-add-rdma_rw_max_sge-helper-for-sq-sizing.patch new file mode 100644 index 0000000000..6cfca211d1 --- /dev/null +++ b/queue-6.12/rdma-core-add-rdma_rw_max_sge-helper-for-sq-sizing.patch @@ -0,0 +1,159 @@ +From 6451d4a0ae9bb776beab355c22a2fb547c8b143c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 19:53:59 -0500 +Subject: RDMA/core: add rdma_rw_max_sge() helper for SQ sizing + +From: Chuck Lever + +[ Upstream commit afcae7d7b8a278a6c29e064f99e5bafd4ac1fb37 ] + +svc_rdma_accept() computes sc_sq_depth as the sum of rq_depth and the +number of rdma_rw contexts (ctxts). This value is used to allocate the +Send CQ and to initialize the sc_sq_avail credit pool. + +However, when the device uses memory registration for RDMA operations, +rdma_rw_init_qp() inflates the QP's max_send_wr by a factor of three +per context to account for REG and INV work requests. The Send CQ and +credit pool remain sized for only one work request per context, +causing Send Queue exhaustion under heavy NFS WRITE workloads. + +Introduce rdma_rw_max_sge() to compute the actual number of Send Queue +entries required for a given number of rdma_rw contexts. Upper layer +protocols call this helper before creating a Queue Pair so that their +Send CQs and credit accounting match the QP's true capacity. + +Update svc_rdma_accept() to use rdma_rw_max_sge() when computing +sc_sq_depth, ensuring the credit pool reflects the work requests +that rdma_rw_init_qp() will reserve. + +Reviewed-by: Christoph Hellwig +Fixes: 00bd1439f464 ("RDMA/rw: Support threshold for registration vs scattering to local pages") +Signed-off-by: Chuck Lever +Link: https://patch.msgid.link/20260128005400.25147-5-cel@kernel.org +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/rw.c | 53 +++++++++++++++++------- + include/rdma/rw.h | 2 + + net/sunrpc/xprtrdma/svc_rdma_transport.c | 8 +++- + 3 files changed, 46 insertions(+), 17 deletions(-) + +diff --git a/drivers/infiniband/core/rw.c b/drivers/infiniband/core/rw.c +index 6354ddf2a274c..2522ff1cc462c 100644 +--- a/drivers/infiniband/core/rw.c ++++ b/drivers/infiniband/core/rw.c +@@ -651,34 +651,57 @@ unsigned int rdma_rw_mr_factor(struct ib_device *device, u32 port_num, + } + EXPORT_SYMBOL(rdma_rw_mr_factor); + ++/** ++ * rdma_rw_max_send_wr - compute max Send WRs needed for RDMA R/W contexts ++ * @dev: RDMA device ++ * @port_num: port number ++ * @max_rdma_ctxs: number of rdma_rw_ctx structures ++ * @create_flags: QP create flags (pass IB_QP_CREATE_INTEGRITY_EN if ++ * data integrity will be enabled on the QP) ++ * ++ * Returns the total number of Send Queue entries needed for ++ * @max_rdma_ctxs. The result accounts for memory registration and ++ * invalidation work requests when the device requires them. ++ * ++ * ULPs use this to size Send Queues and Send CQs before creating a ++ * Queue Pair. ++ */ ++unsigned int rdma_rw_max_send_wr(struct ib_device *dev, u32 port_num, ++ unsigned int max_rdma_ctxs, u32 create_flags) ++{ ++ unsigned int factor = 1; ++ unsigned int result; ++ ++ if (create_flags & IB_QP_CREATE_INTEGRITY_EN || ++ rdma_rw_can_use_mr(dev, port_num)) ++ factor += 2; /* reg + inv */ ++ ++ if (check_mul_overflow(factor, max_rdma_ctxs, &result)) ++ return UINT_MAX; ++ return result; ++} ++EXPORT_SYMBOL(rdma_rw_max_send_wr); ++ + void rdma_rw_init_qp(struct ib_device *dev, struct ib_qp_init_attr *attr) + { +- u32 factor; ++ unsigned int factor = 1; + + WARN_ON_ONCE(attr->port_num == 0); + + /* +- * Each context needs at least one RDMA READ or WRITE WR. +- * +- * For some hardware we might need more, eventually we should ask the +- * HCA driver for a multiplier here. +- */ +- factor = 1; +- +- /* +- * If the device needs MRs to perform RDMA READ or WRITE operations, +- * we'll need two additional MRs for the registrations and the +- * invalidation. ++ * If the device uses MRs to perform RDMA READ or WRITE operations, ++ * or if data integrity is enabled, account for registration and ++ * invalidation work requests. + */ + if (attr->create_flags & IB_QP_CREATE_INTEGRITY_EN || + rdma_rw_can_use_mr(dev, attr->port_num)) +- factor += 2; /* inv + reg */ ++ factor += 2; /* reg + inv */ + + attr->cap.max_send_wr += factor * attr->cap.max_rdma_ctxs; + + /* +- * But maybe we were just too high in the sky and the device doesn't +- * even support all we need, and we'll have to live with what we get.. ++ * The device might not support all we need, and we'll have to ++ * live with what we get. + */ + attr->cap.max_send_wr = + min_t(u32, attr->cap.max_send_wr, dev->attrs.max_qp_wr); +diff --git a/include/rdma/rw.h b/include/rdma/rw.h +index d606cac482338..9a8f4b76ce588 100644 +--- a/include/rdma/rw.h ++++ b/include/rdma/rw.h +@@ -66,6 +66,8 @@ int rdma_rw_ctx_post(struct rdma_rw_ctx *ctx, struct ib_qp *qp, u32 port_num, + + unsigned int rdma_rw_mr_factor(struct ib_device *device, u32 port_num, + unsigned int maxpages); ++unsigned int rdma_rw_max_send_wr(struct ib_device *dev, u32 port_num, ++ unsigned int max_rdma_ctxs, u32 create_flags); + void rdma_rw_init_qp(struct ib_device *dev, struct ib_qp_init_attr *attr); + int rdma_rw_init_mrs(struct ib_qp *qp, struct ib_qp_init_attr *attr); + void rdma_rw_cleanup_mrs(struct ib_qp *qp); +diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c +index 3d7f1413df023..12857381e8610 100644 +--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c ++++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c +@@ -462,7 +462,10 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + newxprt->sc_max_bc_requests = 2; + } + +- /* Arbitrary estimate of the needed number of rdma_rw contexts. ++ /* Estimate the needed number of rdma_rw contexts. The maximum ++ * Read and Write chunks have one segment each. Each request ++ * can involve one Read chunk and either a Write chunk or Reply ++ * chunk; thus a factor of three. + */ + maxpayload = min(xprt->xpt_server->sv_max_payload, + RPCSVC_MAXPAYLOAD_RDMA); +@@ -470,7 +473,8 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + rdma_rw_mr_factor(dev, newxprt->sc_port_num, + maxpayload >> PAGE_SHIFT); + +- newxprt->sc_sq_depth = rq_depth + ctxts; ++ newxprt->sc_sq_depth = rq_depth + ++ rdma_rw_max_send_wr(dev, newxprt->sc_port_num, ctxts, 0); + if (newxprt->sc_sq_depth > dev->attrs.max_qp_wr) + newxprt->sc_sq_depth = dev->attrs.max_qp_wr; + atomic_set(&newxprt->sc_sq_avail, newxprt->sc_sq_depth); +-- +2.51.0 + diff --git a/queue-6.12/rdma-hns-fix-rocev1-failure-due-to-dscp.patch b/queue-6.12/rdma-hns-fix-rocev1-failure-due-to-dscp.patch new file mode 100644 index 0000000000..083c19935a --- /dev/null +++ b/queue-6.12/rdma-hns-fix-rocev1-failure-due-to-dscp.patch @@ -0,0 +1,112 @@ +From 58d951445bfa47f35fde45ad9d5140931cc592e0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 4 Jan 2026 14:40:56 +0800 +Subject: RDMA/hns: Fix RoCEv1 failure due to DSCP + +From: Junxian Huang + +[ Upstream commit 84bd5d60f0a2b9c763c5e6d0b3d8f4f61f6c5470 ] + +DSCP is not supported in RoCEv1, but get_dscp() is still called. If +get_dscp() returns an error, it'll eventually cause create_ah to fail +even when using RoCEv1. + +Correct the return value and avoid calling get_dscp() when using +RoCEv1. + +Fixes: ee20cc17e9d8 ("RDMA/hns: Support DSCP") +Signed-off-by: Junxian Huang +Link: https://patch.msgid.link/20260104064057.1582216-4-huangjunxian6@hisilicon.com +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/hw/hns/hns_roce_ah.c | 23 +++++++++--------- + drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 28 ++++++++++++---------- + 2 files changed, 26 insertions(+), 25 deletions(-) + +diff --git a/drivers/infiniband/hw/hns/hns_roce_ah.c b/drivers/infiniband/hw/hns/hns_roce_ah.c +index 307c35888b300..3b6c6a6e9f977 100644 +--- a/drivers/infiniband/hw/hns/hns_roce_ah.c ++++ b/drivers/infiniband/hw/hns/hns_roce_ah.c +@@ -61,7 +61,7 @@ int hns_roce_create_ah(struct ib_ah *ibah, struct rdma_ah_init_attr *init_attr, + u8 tclass = get_tclass(grh); + u8 priority = 0; + u8 tc_mode = 0; +- int ret; ++ int ret = 0; + + if (hr_dev->pci_dev->revision == PCI_REVISION_ID_HIP08 && udata) { + ret = -EOPNOTSUPP; +@@ -78,19 +78,18 @@ int hns_roce_create_ah(struct ib_ah *ibah, struct rdma_ah_init_attr *init_attr, + ah->av.flowlabel = grh->flow_label; + ah->av.udp_sport = get_ah_udp_sport(ah_attr); + ah->av.tclass = tclass; ++ ah->av.sl = rdma_ah_get_sl(ah_attr); + +- ret = hr_dev->hw->get_dscp(hr_dev, tclass, &tc_mode, &priority); +- if (ret == -EOPNOTSUPP) +- ret = 0; +- +- if (ret && grh->sgid_attr->gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) +- goto err_out; ++ if (grh->sgid_attr->gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) { ++ ret = hr_dev->hw->get_dscp(hr_dev, tclass, &tc_mode, &priority); ++ if (ret == -EOPNOTSUPP) ++ ret = 0; ++ else if (ret) ++ goto err_out; + +- if (tc_mode == HNAE3_TC_MAP_MODE_DSCP && +- grh->sgid_attr->gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) +- ah->av.sl = priority; +- else +- ah->av.sl = rdma_ah_get_sl(ah_attr); ++ if (tc_mode == HNAE3_TC_MAP_MODE_DSCP) ++ ah->av.sl = priority; ++ } + + if (!check_sl_valid(hr_dev, ah->av.sl)) { + ret = -EINVAL; +diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +index 82895859c90db..1e9f6415077a0 100644 +--- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c ++++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +@@ -4999,20 +4999,22 @@ static int hns_roce_set_sl(struct ib_qp *ibqp, + struct ib_device *ibdev = &hr_dev->ib_dev; + int ret; + +- ret = hns_roce_hw_v2_get_dscp(hr_dev, get_tclass(&attr->ah_attr.grh), +- &hr_qp->tc_mode, &hr_qp->priority); +- if (ret && ret != -EOPNOTSUPP && +- grh->sgid_attr->gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) { +- ibdev_err_ratelimited(ibdev, +- "failed to get dscp, ret = %d.\n", ret); +- return ret; +- } ++ hr_qp->sl = rdma_ah_get_sl(&attr->ah_attr); + +- if (hr_qp->tc_mode == HNAE3_TC_MAP_MODE_DSCP && +- grh->sgid_attr->gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) +- hr_qp->sl = hr_qp->priority; +- else +- hr_qp->sl = rdma_ah_get_sl(&attr->ah_attr); ++ if (grh->sgid_attr->gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) { ++ ret = hns_roce_hw_v2_get_dscp(hr_dev, ++ get_tclass(&attr->ah_attr.grh), ++ &hr_qp->tc_mode, &hr_qp->priority); ++ if (ret && ret != -EOPNOTSUPP) { ++ ibdev_err_ratelimited(ibdev, ++ "failed to get dscp, ret = %d.\n", ++ ret); ++ return ret; ++ } ++ ++ if (hr_qp->tc_mode == HNAE3_TC_MAP_MODE_DSCP) ++ hr_qp->sl = hr_qp->priority; ++ } + + if (!check_sl_valid(hr_dev, hr_qp->sl)) + return -EINVAL; +-- +2.51.0 + diff --git a/queue-6.12/rdma-hns-fix-wq_mem_reclaim-warning.patch b/queue-6.12/rdma-hns-fix-wq_mem_reclaim-warning.patch new file mode 100644 index 0000000000..4c0beca634 --- /dev/null +++ b/queue-6.12/rdma-hns-fix-wq_mem_reclaim-warning.patch @@ -0,0 +1,62 @@ +From b477bed016d2837a0538b408d3a456cac67752d9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 4 Jan 2026 14:40:54 +0800 +Subject: RDMA/hns: Fix WQ_MEM_RECLAIM warning + +From: Chengchang Tang + +[ Upstream commit c0a26bbd3f99b7b03f072e3409aff4e6ec8af6f6 ] + +When sunrpc is used, if a reset triggered, our wq may lead the +following trace: + +workqueue: WQ_MEM_RECLAIM xprtiod:xprt_rdma_connect_worker [rpcrdma] +is flushing !WQ_MEM_RECLAIM hns_roce_irq_workq:flush_work_handle +[hns_roce_hw_v2] +WARNING: CPU: 0 PID: 8250 at kernel/workqueue.c:2644 check_flush_dependency+0xe0/0x144 +Call trace: + check_flush_dependency+0xe0/0x144 + start_flush_work.constprop.0+0x1d0/0x2f0 + __flush_work.isra.0+0x40/0xb0 + flush_work+0x14/0x30 + hns_roce_v2_destroy_qp+0xac/0x1e0 [hns_roce_hw_v2] + ib_destroy_qp_user+0x9c/0x2b4 + rdma_destroy_qp+0x34/0xb0 + rpcrdma_ep_destroy+0x28/0xcc [rpcrdma] + rpcrdma_ep_put+0x74/0xb4 [rpcrdma] + rpcrdma_xprt_disconnect+0x1d8/0x260 [rpcrdma] + xprt_rdma_connect_worker+0xc0/0x120 [rpcrdma] + process_one_work+0x1cc/0x4d0 + worker_thread+0x154/0x414 + kthread+0x104/0x144 + ret_from_fork+0x10/0x18 + +Since QP destruction frees memory, this wq should have the WQ_MEM_RECLAIM. + +Fixes: ffd541d45726 ("RDMA/hns: Add the workqueue framework for flush cqe handler") +Signed-off-by: Chengchang Tang +Signed-off-by: Junxian Huang +Link: https://patch.msgid.link/20260104064057.1582216-2-huangjunxian6@hisilicon.com +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +index f9356cb89497b..82895859c90db 100644 +--- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c ++++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +@@ -6899,7 +6899,8 @@ static int hns_roce_v2_init_eq_table(struct hns_roce_dev *hr_dev) + + INIT_WORK(&hr_dev->ecc_work, fmea_ram_ecc_work); + +- hr_dev->irq_workq = alloc_ordered_workqueue("hns_roce_irq_workq", 0); ++ hr_dev->irq_workq = alloc_ordered_workqueue("hns_roce_irq_workq", ++ WQ_MEM_RECLAIM); + if (!hr_dev->irq_workq) { + dev_err(dev, "failed to create irq workqueue.\n"); + ret = -ENOMEM; +-- +2.51.0 + diff --git a/queue-6.12/rdma-hns-notify-ulp-of-remaining-soft-wcs-during-res.patch b/queue-6.12/rdma-hns-notify-ulp-of-remaining-soft-wcs-during-res.patch new file mode 100644 index 0000000000..86982c7a09 --- /dev/null +++ b/queue-6.12/rdma-hns-notify-ulp-of-remaining-soft-wcs-during-res.patch @@ -0,0 +1,70 @@ +From e31b72a9be5e29043b6e26c0982eb4cafe06c2cd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 4 Jan 2026 14:40:57 +0800 +Subject: RDMA/hns: Notify ULP of remaining soft-WCs during reset + +From: Chengchang Tang + +[ Upstream commit 0789f929900d85b80b343c5f04f8b9444e991384 ] + +During a reset, software-generated WCs cannot be reported via +interrupts. This may cause the ULP to miss some WCs. + +To avoid this, add check in the CQ arm process: if a hardware reset +has occurred and there are still unreported soft-WCs, notify the ULP +to handle the remaining WCs, thereby preventing any loss of completions. + +Fixes: 626903e9355b ("RDMA/hns: Add support for reporting wc as software mode") +Signed-off-by: Chengchang Tang +Signed-off-by: Junxian Huang +Link: https://patch.msgid.link/20260104064057.1582216-5-huangjunxian6@hisilicon.com +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 23 ++++++++++++++++++++++ + 1 file changed, 23 insertions(+) + +diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +index 1e9f6415077a0..5e1ea6335c113 100644 +--- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c ++++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +@@ -3683,6 +3683,23 @@ static void hns_roce_v2_write_cqc(struct hns_roce_dev *hr_dev, + HNS_ROCE_V2_CQ_DEFAULT_INTERVAL); + } + ++static bool left_sw_wc(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq) ++{ ++ struct hns_roce_qp *hr_qp; ++ ++ list_for_each_entry(hr_qp, &hr_cq->sq_list, sq_node) { ++ if (hr_qp->sq.head != hr_qp->sq.tail) ++ return true; ++ } ++ ++ list_for_each_entry(hr_qp, &hr_cq->rq_list, rq_node) { ++ if (hr_qp->rq.head != hr_qp->rq.tail) ++ return true; ++ } ++ ++ return false; ++} ++ + static int hns_roce_v2_req_notify_cq(struct ib_cq *ibcq, + enum ib_cq_notify_flags flags) + { +@@ -3691,6 +3708,12 @@ static int hns_roce_v2_req_notify_cq(struct ib_cq *ibcq, + struct hns_roce_v2_db cq_db = {}; + u32 notify_flag; + ++ if (hr_dev->state >= HNS_ROCE_DEVICE_STATE_RST_DOWN) { ++ if ((flags & IB_CQ_REPORT_MISSED_EVENTS) && ++ left_sw_wc(hr_dev, hr_cq)) ++ return 1; ++ return 0; ++ } + /* + * flags = 0, then notify_flag : next + * flags = 1, then notify flag : solocited +-- +2.51.0 + diff --git a/queue-6.12/rdma-iwcm-fix-workqueue-list-corruption-by-removing-.patch b/queue-6.12/rdma-iwcm-fix-workqueue-list-corruption-by-removing-.patch new file mode 100644 index 0000000000..1d3ad33842 --- /dev/null +++ b/queue-6.12/rdma-iwcm-fix-workqueue-list-corruption-by-removing-.patch @@ -0,0 +1,206 @@ +From e7a8870250cf5a8f5aa34ae51332918b7a5f36c5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 02:00:06 +0000 +Subject: RDMA/iwcm: Fix workqueue list corruption by removing work_list + +From: Jacob Moroni + +[ Upstream commit 7874eeacfa42177565c01d5198726671acf7adf2 ] + +The commit e1168f0 ("RDMA/iwcm: Simplify cm_event_handler()") +changed the work submission logic to unconditionally call +queue_work() with the expectation that queue_work() would +have no effect if work was already pending. The problem is +that a free list of struct iwcm_work is used (for which +struct work_struct is embedded), so each call to queue_work() +is basically unique and therefore does indeed queue the work. + +This causes a problem in the work handler which walks the work_list +until it's empty to process entries. This means that a single +run of the work handler could process item N+1 and release it +back to the free list while the actual workqueue entry is still +queued. It could then get reused (INIT_WORK...) and lead to +list corruption in the workqueue logic. + +Fix this by just removing the work_list. The workqueue already +does this for us. + +This fixes the following error that was observed when stress +testing with ucmatose on an Intel E830 in iWARP mode: + +[ 151.465780] list_del corruption. next->prev should be ffff9f0915c69c08, but was ffff9f0a1116be08. (next=ffff9f0a15b11c08) +[ 151.466639] ------------[ cut here ]------------ +[ 151.466986] kernel BUG at lib/list_debug.c:67! +[ 151.467349] Oops: invalid opcode: 0000 [#1] SMP NOPTI +[ 151.467753] CPU: 14 UID: 0 PID: 2306 Comm: kworker/u64:18 Not tainted 6.19.0-rc4+ #1 PREEMPT(voluntary) +[ 151.468466] Hardware name: QEMU Ubuntu 24.04 PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 +[ 151.469192] Workqueue: 0x0 (iw_cm_wq) +[ 151.469478] RIP: 0010:__list_del_entry_valid_or_report+0xf0/0x100 +[ 151.469942] Code: c7 58 5f 4c b2 e8 10 50 aa ff 0f 0b 48 89 ef e8 36 57 cb ff 48 8b 55 08 48 89 e9 48 89 de 48 c7 c7 a8 5f 4c b2 e8 f0 4f aa ff <0f> 0b 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 90 90 90 90 90 90 +[ 151.471323] RSP: 0000:ffffb15644e7bd68 EFLAGS: 00010046 +[ 151.471712] RAX: 000000000000006d RBX: ffff9f0915c69c08 RCX: 0000000000000027 +[ 151.472243] RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff9f0a37d9c600 +[ 151.472768] RBP: ffff9f0a15b11c08 R08: 0000000000000000 R09: c0000000ffff7fff +[ 151.473294] R10: 0000000000000001 R11: ffffb15644e7bba8 R12: ffff9f092339ee68 +[ 151.473817] R13: ffff9f0900059c28 R14: ffff9f092339ee78 R15: 0000000000000000 +[ 151.474344] FS: 0000000000000000(0000) GS:ffff9f0a847b5000(0000) knlGS:0000000000000000 +[ 151.474934] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 151.475362] CR2: 0000559e233a9088 CR3: 000000020296b004 CR4: 0000000000770ef0 +[ 151.475895] PKRU: 55555554 +[ 151.476118] Call Trace: +[ 151.476331] +[ 151.476497] move_linked_works+0x49/0xa0 +[ 151.476792] __pwq_activate_work.isra.46+0x2f/0xa0 +[ 151.477151] pwq_dec_nr_in_flight+0x1e0/0x2f0 +[ 151.477479] process_scheduled_works+0x1c8/0x410 +[ 151.477823] worker_thread+0x125/0x260 +[ 151.478108] ? __pfx_worker_thread+0x10/0x10 +[ 151.478430] kthread+0xfe/0x240 +[ 151.478671] ? __pfx_kthread+0x10/0x10 +[ 151.478955] ? __pfx_kthread+0x10/0x10 +[ 151.479240] ret_from_fork+0x208/0x270 +[ 151.479523] ? __pfx_kthread+0x10/0x10 +[ 151.479806] ret_from_fork_asm+0x1a/0x30 +[ 151.480103] + +Fixes: e1168f09b331 ("RDMA/iwcm: Simplify cm_event_handler()") +Signed-off-by: Jacob Moroni +Link: https://patch.msgid.link/20260112020006.1352438-1-jmoroni@google.com +Reviewed-by: Bart Van Assche +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/iwcm.c | 56 +++++++++++++--------------------- + drivers/infiniband/core/iwcm.h | 1 - + 2 files changed, 21 insertions(+), 36 deletions(-) + +diff --git a/drivers/infiniband/core/iwcm.c b/drivers/infiniband/core/iwcm.c +index 96a678250e553..3758ee7698224 100644 +--- a/drivers/infiniband/core/iwcm.c ++++ b/drivers/infiniband/core/iwcm.c +@@ -95,7 +95,6 @@ static struct workqueue_struct *iwcm_wq; + struct iwcm_work { + struct work_struct work; + struct iwcm_id_private *cm_id; +- struct list_head list; + struct iw_cm_event event; + struct list_head free_list; + }; +@@ -176,7 +175,6 @@ static int alloc_work_entries(struct iwcm_id_private *cm_id_priv, int count) + return -ENOMEM; + } + work->cm_id = cm_id_priv; +- INIT_LIST_HEAD(&work->list); + put_work(work); + } + return 0; +@@ -211,7 +209,6 @@ static void free_cm_id(struct iwcm_id_private *cm_id_priv) + static bool iwcm_deref_id(struct iwcm_id_private *cm_id_priv) + { + if (refcount_dec_and_test(&cm_id_priv->refcount)) { +- BUG_ON(!list_empty(&cm_id_priv->work_list)); + free_cm_id(cm_id_priv); + return true; + } +@@ -258,7 +255,6 @@ struct iw_cm_id *iw_create_cm_id(struct ib_device *device, + refcount_set(&cm_id_priv->refcount, 1); + init_waitqueue_head(&cm_id_priv->connect_wait); + init_completion(&cm_id_priv->destroy_comp); +- INIT_LIST_HEAD(&cm_id_priv->work_list); + INIT_LIST_HEAD(&cm_id_priv->work_free_list); + + return &cm_id_priv->id; +@@ -1005,13 +1001,13 @@ static int process_event(struct iwcm_id_private *cm_id_priv, + } + + /* +- * Process events on the work_list for the cm_id. If the callback +- * function requests that the cm_id be deleted, a flag is set in the +- * cm_id flags to indicate that when the last reference is +- * removed, the cm_id is to be destroyed. This is necessary to +- * distinguish between an object that will be destroyed by the app +- * thread asleep on the destroy_comp list vs. an object destroyed +- * here synchronously when the last reference is removed. ++ * Process events for the cm_id. If the callback function requests ++ * that the cm_id be deleted, a flag is set in the cm_id flags to ++ * indicate that when the last reference is removed, the cm_id is ++ * to be destroyed. This is necessary to distinguish between an ++ * object that will be destroyed by the app thread asleep on the ++ * destroy_comp list vs. an object destroyed here synchronously ++ * when the last reference is removed. + */ + static void cm_work_handler(struct work_struct *_work) + { +@@ -1022,35 +1018,26 @@ static void cm_work_handler(struct work_struct *_work) + int ret = 0; + + spin_lock_irqsave(&cm_id_priv->lock, flags); +- while (!list_empty(&cm_id_priv->work_list)) { +- work = list_first_entry(&cm_id_priv->work_list, +- struct iwcm_work, list); +- list_del_init(&work->list); +- levent = work->event; +- put_work(work); +- spin_unlock_irqrestore(&cm_id_priv->lock, flags); +- +- if (!test_bit(IWCM_F_DROP_EVENTS, &cm_id_priv->flags)) { +- ret = process_event(cm_id_priv, &levent); +- if (ret) { +- destroy_cm_id(&cm_id_priv->id); +- WARN_ON_ONCE(iwcm_deref_id(cm_id_priv)); +- } +- } else +- pr_debug("dropping event %d\n", levent.event); +- if (iwcm_deref_id(cm_id_priv)) +- return; +- spin_lock_irqsave(&cm_id_priv->lock, flags); +- } ++ levent = work->event; ++ put_work(work); + spin_unlock_irqrestore(&cm_id_priv->lock, flags); ++ ++ if (!test_bit(IWCM_F_DROP_EVENTS, &cm_id_priv->flags)) { ++ ret = process_event(cm_id_priv, &levent); ++ if (ret) { ++ destroy_cm_id(&cm_id_priv->id); ++ WARN_ON_ONCE(iwcm_deref_id(cm_id_priv)); ++ } ++ } else ++ pr_debug("dropping event %d\n", levent.event); ++ if (iwcm_deref_id(cm_id_priv)) ++ return; + } + + /* + * This function is called on interrupt context. Schedule events on + * the iwcm_wq thread to allow callback functions to downcall into +- * the CM and/or block. Events are queued to a per-CM_ID +- * work_list. If this is the first event on the work_list, the work +- * element is also queued on the iwcm_wq thread. ++ * the CM and/or block. + * + * Each event holds a reference on the cm_id. Until the last posted + * event has been delivered and processed, the cm_id cannot be +@@ -1092,7 +1079,6 @@ static int cm_event_handler(struct iw_cm_id *cm_id, + } + + refcount_inc(&cm_id_priv->refcount); +- list_add_tail(&work->list, &cm_id_priv->work_list); + queue_work(iwcm_wq, &work->work); + out: + spin_unlock_irqrestore(&cm_id_priv->lock, flags); +diff --git a/drivers/infiniband/core/iwcm.h b/drivers/infiniband/core/iwcm.h +index bf74639be1287..b56fb12edece4 100644 +--- a/drivers/infiniband/core/iwcm.h ++++ b/drivers/infiniband/core/iwcm.h +@@ -50,7 +50,6 @@ struct iwcm_id_private { + struct ib_qp *qp; + struct completion destroy_comp; + wait_queue_head_t connect_wait; +- struct list_head work_list; + spinlock_t lock; + refcount_t refcount; + struct list_head work_free_list; +-- +2.51.0 + diff --git a/queue-6.12/rdma-mlx5-fix-memory-leak-in-get_data_direct_sysfs_p.patch b/queue-6.12/rdma-mlx5-fix-memory-leak-in-get_data_direct_sysfs_p.patch new file mode 100644 index 0000000000..5b169b5eab --- /dev/null +++ b/queue-6.12/rdma-mlx5-fix-memory-leak-in-get_data_direct_sysfs_p.patch @@ -0,0 +1,57 @@ +From 0f60b2709c3581913fb7ae106eff4b9a81cd9a65 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 07:48:01 +0000 +Subject: RDMA/mlx5: Fix memory leak in GET_DATA_DIRECT_SYSFS_PATH handler + +From: Zilin Guan + +[ Upstream commit 9b9d253908478f504297ac283c514e5953ddafa6 ] + +The UVERBS_HANDLER(MLX5_IB_METHOD_GET_DATA_DIRECT_SYSFS_PATH) function +allocates memory for the device path using kobject_get_path(). If the +length of the device path exceeds the output buffer length, the function +returns -ENOSPC but does not free the allocated memory, resulting in a +memory leak. + +Add a kfree() call to the error path to ensure the allocated memory is +properly freed. + +Compile tested only. Issue found using a prototype static analysis tool +and code review. + +Fixes: ec7ad6530909 ("RDMA/mlx5: Introduce GET_DATA_DIRECT_SYSFS_PATH ioctl") +Signed-off-by: Zilin Guan +Link: https://patch.msgid.link/20260126074801.627898-1-zilin@seu.edu.cn +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/hw/mlx5/std_types.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/infiniband/hw/mlx5/std_types.c b/drivers/infiniband/hw/mlx5/std_types.c +index bdb568411091c..d0137ab7c645c 100644 +--- a/drivers/infiniband/hw/mlx5/std_types.c ++++ b/drivers/infiniband/hw/mlx5/std_types.c +@@ -214,7 +214,7 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_GET_DATA_DIRECT_SYSFS_PATH)( + int out_len = uverbs_attr_get_len(attrs, + MLX5_IB_ATTR_GET_DATA_DIRECT_SYSFS_PATH); + u32 dev_path_len; +- char *dev_path; ++ char *dev_path = NULL; + int ret; + + c = to_mucontext(ib_uverbs_get_ucontext(attrs)); +@@ -242,9 +242,9 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_GET_DATA_DIRECT_SYSFS_PATH)( + + ret = uverbs_copy_to(attrs, MLX5_IB_ATTR_GET_DATA_DIRECT_SYSFS_PATH, dev_path, + dev_path_len); +- kfree(dev_path); + + end: ++ kfree(dev_path); + mutex_unlock(&dev->data_direct_lock); + return ret; + } +-- +2.51.0 + diff --git a/queue-6.12/rdma-mlx5-fix-umr-hang-in-lag-error-state-unload.patch b/queue-6.12/rdma-mlx5-fix-umr-hang-in-lag-error-state-unload.patch new file mode 100644 index 0000000000..cf00f84e78 --- /dev/null +++ b/queue-6.12/rdma-mlx5-fix-umr-hang-in-lag-error-state-unload.patch @@ -0,0 +1,220 @@ +From c2fa0b26ab71f2cf6aa690cc68dda50d5a9c4031 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Jan 2026 15:37:10 +0200 +Subject: RDMA/mlx5: Fix UMR hang in LAG error state unload + +From: Chiara Meiohas + +[ Upstream commit ebc2164a4cd4314503f1a0c8e7aaf76d7e5fa211 ] + +During firmware reset in LAG mode, a race condition causes the driver +to hang indefinitely while waiting for UMR completion during device +unload. See [1]. + +In LAG mode the bond device is only registered on the master, so it +never sees sys_error events from the slave. +During firmware reset this causes UMR waits to hang forever on unload +as the slave is dead but the master hasn't entered error state yet, so +UMR posts succeed but completions never arrive. + +Fix this by adding a sys_error notifier that gets registered before +MLX5_IB_STAGE_IB_REG and stays alive until after ib_unregister_device(). +This ensures error events reach the bond device throughout teardown. + +[1] +Call Trace: + __schedule+0x2bd/0x760 + schedule+0x37/0xa0 + schedule_preempt_disabled+0xa/0x10 + __mutex_lock.isra.6+0x2b5/0x4a0 + __mlx5_ib_dereg_mr+0x606/0x870 [mlx5_ib] + ? __xa_erase+0x4a/0xa0 + ? _cond_resched+0x15/0x30 + ? wait_for_completion+0x31/0x100 + ib_dereg_mr_user+0x48/0xc0 [ib_core] + ? rdmacg_uncharge_hierarchy+0xa0/0x100 + destroy_hw_idr_uobject+0x20/0x50 [ib_uverbs] + uverbs_destroy_uobject+0x37/0x150 [ib_uverbs] + __uverbs_cleanup_ufile+0xda/0x140 [ib_uverbs] + uverbs_destroy_ufile_hw+0x3a/0xf0 [ib_uverbs] + ib_uverbs_remove_one+0xc3/0x140 [ib_uverbs] + remove_client_context+0x8b/0xd0 [ib_core] + disable_device+0x8c/0x130 [ib_core] + __ib_unregister_device+0x10d/0x180 [ib_core] + ib_unregister_device+0x21/0x30 [ib_core] + __mlx5_ib_remove+0x1e4/0x1f0 [mlx5_ib] + auxiliary_bus_remove+0x1e/0x30 + device_release_driver_internal+0x103/0x1f0 + bus_remove_device+0xf7/0x170 + device_del+0x181/0x410 + mlx5_rescan_drivers_locked.part.10+0xa9/0x1d0 [mlx5_core] + mlx5_disable_lag+0x253/0x260 [mlx5_core] + mlx5_lag_disable_change+0x89/0xc0 [mlx5_core] + mlx5_eswitch_disable+0x67/0xa0 [mlx5_core] + mlx5_unload+0x15/0xd0 [mlx5_core] + mlx5_unload_one+0x71/0xc0 [mlx5_core] + mlx5_sync_reset_reload_work+0x83/0x100 [mlx5_core] + process_one_work+0x1a7/0x360 + worker_thread+0x30/0x390 + ? create_worker+0x1a0/0x1a0 + kthread+0x116/0x130 + ? kthread_flush_work_fn+0x10/0x10 + ret_from_fork+0x22/0x40 + +Fixes: ede132a5cf55 ("RDMA/mlx5: Move events notifier registration to be after device registration") +Signed-off-by: Chiara Meiohas +Signed-off-by: Maher Sanalla +Reviewed-by: Mark Bloch +Signed-off-by: Edward Srouji +Link: https://patch.msgid.link/20260113-umr-hand-lag-fix-v1-1-3dc476e00cd9@nvidia.com +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/hw/mlx5/main.c | 75 ++++++++++++++++++++++++---- + drivers/infiniband/hw/mlx5/mlx5_ib.h | 2 + + 2 files changed, 68 insertions(+), 9 deletions(-) + +diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c +index f3e58797705d7..10bda03eb3388 100644 +--- a/drivers/infiniband/hw/mlx5/main.c ++++ b/drivers/infiniband/hw/mlx5/main.c +@@ -2826,7 +2826,6 @@ static void mlx5_ib_handle_event(struct work_struct *_work) + container_of(_work, struct mlx5_ib_event_work, work); + struct mlx5_ib_dev *ibdev; + struct ib_event ibev; +- bool fatal = false; + + if (work->is_slave) { + ibdev = mlx5_ib_get_ibdev_from_mpi(work->mpi); +@@ -2837,12 +2836,6 @@ static void mlx5_ib_handle_event(struct work_struct *_work) + } + + switch (work->event) { +- case MLX5_DEV_EVENT_SYS_ERROR: +- ibev.event = IB_EVENT_DEVICE_FATAL; +- mlx5_ib_handle_internal_error(ibdev); +- ibev.element.port_num = (u8)(unsigned long)work->param; +- fatal = true; +- break; + case MLX5_EVENT_TYPE_PORT_CHANGE: + if (handle_port_change(ibdev, work->param, &ibev)) + goto out; +@@ -2864,8 +2857,6 @@ static void mlx5_ib_handle_event(struct work_struct *_work) + if (ibdev->ib_active) + ib_dispatch_event(&ibev); + +- if (fatal) +- ibdev->ib_active = false; + out: + kfree(work); + } +@@ -2909,6 +2900,66 @@ static int mlx5_ib_event_slave_port(struct notifier_block *nb, + return NOTIFY_OK; + } + ++static void mlx5_ib_handle_sys_error_event(struct work_struct *_work) ++{ ++ struct mlx5_ib_event_work *work = ++ container_of(_work, struct mlx5_ib_event_work, work); ++ struct mlx5_ib_dev *ibdev = work->dev; ++ struct ib_event ibev; ++ ++ ibev.event = IB_EVENT_DEVICE_FATAL; ++ mlx5_ib_handle_internal_error(ibdev); ++ ibev.element.port_num = (u8)(unsigned long)work->param; ++ ibev.device = &ibdev->ib_dev; ++ ++ if (!rdma_is_port_valid(&ibdev->ib_dev, ibev.element.port_num)) { ++ mlx5_ib_warn(ibdev, "warning: event on port %d\n", ibev.element.port_num); ++ goto out; ++ } ++ ++ if (ibdev->ib_active) ++ ib_dispatch_event(&ibev); ++ ++ ibdev->ib_active = false; ++out: ++ kfree(work); ++} ++ ++static int mlx5_ib_sys_error_event(struct notifier_block *nb, ++ unsigned long event, void *param) ++{ ++ struct mlx5_ib_event_work *work; ++ ++ if (event != MLX5_DEV_EVENT_SYS_ERROR) ++ return NOTIFY_DONE; ++ ++ work = kmalloc(sizeof(*work), GFP_ATOMIC); ++ if (!work) ++ return NOTIFY_DONE; ++ ++ INIT_WORK(&work->work, mlx5_ib_handle_sys_error_event); ++ work->dev = container_of(nb, struct mlx5_ib_dev, sys_error_events); ++ work->is_slave = false; ++ work->param = param; ++ work->event = event; ++ ++ queue_work(mlx5_ib_event_wq, &work->work); ++ ++ return NOTIFY_OK; ++} ++ ++static int mlx5_ib_stage_sys_error_notifier_init(struct mlx5_ib_dev *dev) ++{ ++ dev->sys_error_events.notifier_call = mlx5_ib_sys_error_event; ++ mlx5_notifier_register(dev->mdev, &dev->sys_error_events); ++ return 0; ++} ++ ++static void mlx5_ib_stage_sys_error_notifier_cleanup(struct mlx5_ib_dev *dev) ++{ ++ mlx5_notifier_unregister(dev->mdev, &dev->sys_error_events); ++} ++ + static int mlx5_ib_get_plane_num(struct mlx5_core_dev *mdev, u8 *num_plane) + { + struct mlx5_hca_vport_context vport_ctx; +@@ -4682,6 +4733,9 @@ static const struct mlx5_ib_profile pf_profile = { + STAGE_CREATE(MLX5_IB_STAGE_WHITELIST_UID, + mlx5_ib_devx_init, + mlx5_ib_devx_cleanup), ++ STAGE_CREATE(MLX5_IB_STAGE_SYS_ERROR_NOTIFIER, ++ mlx5_ib_stage_sys_error_notifier_init, ++ mlx5_ib_stage_sys_error_notifier_cleanup), + STAGE_CREATE(MLX5_IB_STAGE_IB_REG, + mlx5_ib_stage_ib_reg_init, + mlx5_ib_stage_ib_reg_cleanup), +@@ -4742,6 +4796,9 @@ const struct mlx5_ib_profile raw_eth_profile = { + STAGE_CREATE(MLX5_IB_STAGE_WHITELIST_UID, + mlx5_ib_devx_init, + mlx5_ib_devx_cleanup), ++ STAGE_CREATE(MLX5_IB_STAGE_SYS_ERROR_NOTIFIER, ++ mlx5_ib_stage_sys_error_notifier_init, ++ mlx5_ib_stage_sys_error_notifier_cleanup), + STAGE_CREATE(MLX5_IB_STAGE_IB_REG, + mlx5_ib_stage_ib_reg_init, + mlx5_ib_stage_ib_reg_cleanup), +diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h +index f49cb588a856d..3135519f1cfdf 100644 +--- a/drivers/infiniband/hw/mlx5/mlx5_ib.h ++++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h +@@ -979,6 +979,7 @@ enum mlx5_ib_stages { + MLX5_IB_STAGE_BFREG, + MLX5_IB_STAGE_PRE_IB_REG_UMR, + MLX5_IB_STAGE_WHITELIST_UID, ++ MLX5_IB_STAGE_SYS_ERROR_NOTIFIER, + MLX5_IB_STAGE_IB_REG, + MLX5_IB_STAGE_DEVICE_NOTIFIER, + MLX5_IB_STAGE_POST_IB_REG_UMR, +@@ -1137,6 +1138,7 @@ struct mlx5_ib_dev { + /* protect accessing data_direct_dev */ + struct mutex data_direct_lock; + struct notifier_block mdev_events; ++ struct notifier_block sys_error_events; + struct notifier_block lag_events; + int num_ports; + /* serialize update of capability mask +-- +2.51.0 + diff --git a/queue-6.12/rdma-rtrs-server-remove-dead-code.patch b/queue-6.12/rdma-rtrs-server-remove-dead-code.patch new file mode 100644 index 0000000000..8531d0cec8 --- /dev/null +++ b/queue-6.12/rdma-rtrs-server-remove-dead-code.patch @@ -0,0 +1,57 @@ +From d287d94af02f710a195657bd5d5b74d5bf46b7d9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Dec 2025 10:38:19 +0800 +Subject: RDMA/rtrs: server: remove dead code + +From: Honggang LI + +[ Upstream commit a3572bdc3a028ca47f77d7166ac95b719cf77d50 ] + +As rkey had been initialized to zero, the WARN_ON_ONCE should never been +triggered. Remove it. + +Fixes: 9cb837480424 ("RDMA/rtrs: server: main functionality") +Signed-off-by: Honggang LI +Link: https://patch.msgid.link/20251224023819.138846-1-honggangli@163.com +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/ulp/rtrs/rtrs-srv.c | 8 +------- + 1 file changed, 1 insertion(+), 7 deletions(-) + +diff --git a/drivers/infiniband/ulp/rtrs/rtrs-srv.c b/drivers/infiniband/ulp/rtrs/rtrs-srv.c +index 9ecc6343455d6..7a402eb8e0bf0 100644 +--- a/drivers/infiniband/ulp/rtrs/rtrs-srv.c ++++ b/drivers/infiniband/ulp/rtrs/rtrs-srv.c +@@ -208,7 +208,6 @@ static int rdma_write_sg(struct rtrs_srv_op *id) + size_t sg_cnt; + int err, offset; + bool need_inval; +- u32 rkey = 0; + struct ib_reg_wr rwr; + struct ib_sge *plist; + struct ib_sge list; +@@ -240,11 +239,6 @@ static int rdma_write_sg(struct rtrs_srv_op *id) + wr->wr.num_sge = 1; + wr->remote_addr = le64_to_cpu(id->rd_msg->desc[0].addr); + wr->rkey = le32_to_cpu(id->rd_msg->desc[0].key); +- if (rkey == 0) +- rkey = wr->rkey; +- else +- /* Only one key is actually used */ +- WARN_ON_ONCE(rkey != wr->rkey); + + wr->wr.opcode = IB_WR_RDMA_WRITE; + wr->wr.wr_cqe = &io_comp_cqe; +@@ -277,7 +271,7 @@ static int rdma_write_sg(struct rtrs_srv_op *id) + inv_wr.opcode = IB_WR_SEND_WITH_INV; + inv_wr.wr_cqe = &io_comp_cqe; + inv_wr.send_flags = 0; +- inv_wr.ex.invalidate_rkey = rkey; ++ inv_wr.ex.invalidate_rkey = wr->rkey; + } + + imm_wr.wr.next = NULL; +-- +2.51.0 + diff --git a/queue-6.12/rdma-rtrs-srv-fix-sg-mapping.patch b/queue-6.12/rdma-rtrs-srv-fix-sg-mapping.patch new file mode 100644 index 0000000000..9ba5de498d --- /dev/null +++ b/queue-6.12/rdma-rtrs-srv-fix-sg-mapping.patch @@ -0,0 +1,85 @@ +From d498ec9687561ee70aebf0552f2597b34bd96af8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 17:15:08 +0100 +Subject: RDMA/rtrs-srv: fix SG mapping + +From: Roman Penyaev + +[ Upstream commit 83835f7c07b523c7ca2a5ad0a511670b5810539e ] + +This fixes the following error on the server side: + + RTRS server session allocation failed: -EINVAL + +caused by the caller of the `ib_dma_map_sg()`, which does not expect +less mapped entries, than requested, which is in the order of things +and can be easily reproduced on the machine with enabled IOMMU. + +The fix is to treat any positive number of mapped sg entries as a +successful mapping and cache DMA addresses by traversing modified +SG table. + +Fixes: 9cb837480424 ("RDMA/rtrs: server: main functionality") +Signed-off-by: Roman Penyaev +Signed-off-by: Jack Wang +Signed-off-by: Grzegorz Prajsner +Link: https://patch.msgid.link/20260107161517.56357-2-haris.iqbal@ionos.com +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/ulp/rtrs/rtrs-srv.c | 25 ++++++++++++++++++++----- + 1 file changed, 20 insertions(+), 5 deletions(-) + +diff --git a/drivers/infiniband/ulp/rtrs/rtrs-srv.c b/drivers/infiniband/ulp/rtrs/rtrs-srv.c +index 7a402eb8e0bf0..adb798e2a54ae 100644 +--- a/drivers/infiniband/ulp/rtrs/rtrs-srv.c ++++ b/drivers/infiniband/ulp/rtrs/rtrs-srv.c +@@ -595,7 +595,7 @@ static int map_cont_bufs(struct rtrs_srv_path *srv_path) + srv_path->mrs_num++) { + struct rtrs_srv_mr *srv_mr = &srv_path->mrs[srv_path->mrs_num]; + struct scatterlist *s; +- int nr, nr_sgt, chunks; ++ int nr, nr_sgt, chunks, ind; + + sgt = &srv_mr->sgt; + chunks = chunks_per_mr * srv_path->mrs_num; +@@ -625,7 +625,7 @@ static int map_cont_bufs(struct rtrs_srv_path *srv_path) + } + nr = ib_map_mr_sg(mr, sgt->sgl, nr_sgt, + NULL, max_chunk_size); +- if (nr != nr_sgt) { ++ if (nr < nr_sgt) { + err = nr < 0 ? nr : -EINVAL; + goto dereg_mr; + } +@@ -641,9 +641,24 @@ static int map_cont_bufs(struct rtrs_srv_path *srv_path) + goto dereg_mr; + } + } +- /* Eventually dma addr for each chunk can be cached */ +- for_each_sg(sgt->sgl, s, nr_sgt, i) +- srv_path->dma_addr[chunks + i] = sg_dma_address(s); ++ ++ /* ++ * Cache DMA addresses by traversing sg entries. If ++ * regions were merged, an inner loop is required to ++ * populate the DMA address array by traversing larger ++ * regions. ++ */ ++ ind = chunks; ++ for_each_sg(sgt->sgl, s, nr_sgt, i) { ++ unsigned int dma_len = sg_dma_len(s); ++ u64 dma_addr = sg_dma_address(s); ++ u64 dma_addr_end = dma_addr + dma_len; ++ ++ do { ++ srv_path->dma_addr[ind++] = dma_addr; ++ dma_addr += max_chunk_size; ++ } while (dma_addr < dma_addr_end); ++ } + + ib_update_fast_reg_key(mr, ib_inc_rkey(mr->rkey)); + srv_mr->mr = mr; +-- +2.51.0 + diff --git a/queue-6.12/rdma-rxe-fix-double-free-in-rxe_srq_from_init.patch b/queue-6.12/rdma-rxe-fix-double-free-in-rxe_srq_from_init.patch new file mode 100644 index 0000000000..168d52ae19 --- /dev/null +++ b/queue-6.12/rdma-rxe-fix-double-free-in-rxe_srq_from_init.patch @@ -0,0 +1,67 @@ +From 16b7b19b2baa2a7fa66211461e6cf91ff42ff674 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 01:54:12 +0000 +Subject: RDMA/rxe: Fix double free in rxe_srq_from_init + +From: Jiasheng Jiang + +[ Upstream commit 0beefd0e15d962f497aad750b2d5e9c3570b66d1 ] + +In rxe_srq_from_init(), the queue pointer 'q' is assigned to +'srq->rq.queue' before copying the SRQ number to user space. +If copy_to_user() fails, the function calls rxe_queue_cleanup() +to free the queue, but leaves the now-invalid pointer in +'srq->rq.queue'. + +The caller of rxe_srq_from_init() (rxe_create_srq) eventually +calls rxe_srq_cleanup() upon receiving the error, which triggers +a second rxe_queue_cleanup() on the same memory, leading to a +double free. + +The call trace looks like this: + kmem_cache_free+0x.../0x... + rxe_queue_cleanup+0x1a/0x30 [rdma_rxe] + rxe_srq_cleanup+0x42/0x60 [rdma_rxe] + rxe_elem_release+0x31/0x70 [rdma_rxe] + rxe_create_srq+0x12b/0x1a0 [rdma_rxe] + ib_create_srq_user+0x9a/0x150 [ib_core] + +Fix this by moving 'srq->rq.queue = q' after copy_to_user. + +Fixes: aae0484e15f0 ("IB/rxe: avoid srq memory leak") +Signed-off-by: Jiasheng Jiang +Link: https://patch.msgid.link/20260112015412.29458-1-jiashengjiangcool@gmail.com +Reviewed-by: Zhu Yanjun +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/sw/rxe/rxe_srq.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/infiniband/sw/rxe/rxe_srq.c b/drivers/infiniband/sw/rxe/rxe_srq.c +index 2a234f26ac104..c9a7cd38953d3 100644 +--- a/drivers/infiniband/sw/rxe/rxe_srq.c ++++ b/drivers/infiniband/sw/rxe/rxe_srq.c +@@ -77,9 +77,6 @@ int rxe_srq_from_init(struct rxe_dev *rxe, struct rxe_srq *srq, + goto err_free; + } + +- srq->rq.queue = q; +- init->attr.max_wr = srq->rq.max_wr; +- + if (uresp) { + if (copy_to_user(&uresp->srq_num, &srq->srq_num, + sizeof(uresp->srq_num))) { +@@ -88,6 +85,9 @@ int rxe_srq_from_init(struct rxe_dev *rxe, struct rxe_srq *srq, + } + } + ++ srq->rq.queue = q; ++ init->attr.max_wr = srq->rq.max_wr; ++ + return 0; + + err_free: +-- +2.51.0 + diff --git a/queue-6.12/rdma-rxe-fix-race-condition-in-qp-timer-handlers.patch b/queue-6.12/rdma-rxe-fix-race-condition-in-qp-timer-handlers.patch new file mode 100644 index 0000000000..b27ed04a51 --- /dev/null +++ b/queue-6.12/rdma-rxe-fix-race-condition-in-qp-timer-handlers.patch @@ -0,0 +1,116 @@ +From bc72e9d19fe49ac2e98c0388f417dd38fee494ee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 15:44:37 +0800 +Subject: RDMA/rxe: Fix race condition in QP timer handlers + +From: Li Zhijian + +[ Upstream commit 87bf646921430e303176edc4eb07c30160361b73 ] + +I encontered the following warning: + WARNING: drivers/infiniband/sw/rxe/rxe_task.c:249 at rxe_sched_task+0x1c8/0x238 [rdma_rxe], CPU#0: swapper/0/0 +... + libsha1 [last unloaded: ip6_udp_tunnel] + CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Tainted: G C 6.19.0-rc5-64k-v8+ #37 PREEMPT + Tainted: [C]=CRAP + Hardware name: Raspberry Pi 4 Model B Rev 1.2 + Call trace: + rxe_sched_task+0x1c8/0x238 [rdma_rxe] (P) + retransmit_timer+0x130/0x188 [rdma_rxe] + call_timer_fn+0x68/0x4d0 + __run_timers+0x630/0x888 +... + WARNING: drivers/infiniband/sw/rxe/rxe_task.c:38 at rxe_sched_task+0x1c0/0x238 [rdma_rxe], CPU#0: swapper/0/0 +... + WARNING: drivers/infiniband/sw/rxe/rxe_task.c:111 at do_work+0x488/0x5c8 [rdma_rxe], CPU#3: kworker/u17:4/93400 +... + refcount_t: underflow; use-after-free. + WARNING: lib/refcount.c:28 at refcount_warn_saturate+0x138/0x1a0, CPU#3: kworker/u17:4/93400 + +The issue is caused by a race condition between retransmit_timer() and +rxe_destroy_qp, leading to the Queue Pair's (QP) reference count dropping +to zero during timer handler execution. + +It seems this warning is harmless because rxe_qp_do_cleanup() will flush +all pending timers and requests. + +Example of flow causing the issue: + +CPU0 CPU1 +retransmit_timer() { + spin_lock_irqsave + rxe_destroy_qp() + __rxe_cleanup() + __rxe_put() // qp->ref_count decrease to 0 + rxe_qp_do_cleanup() { + if (qp->valid) { + rxe_sched_task() { + WARN_ON(rxe_read(task->qp) <= 0); + } + } + spin_unlock_irqrestore +} + spin_lock_irqsave + qp->valid = 0 + spin_unlock_irqrestore + } + +Ensure the QP's reference count is maintained and its validity is checked +within the timer callbacks by adding calls to rxe_get(qp) and corresponding +rxe_put(qp) after use. + +Signed-off-by: Li Zhijian +Fixes: d94671632572 ("RDMA/rxe: Rewrite rxe_task.c") +Link: https://patch.msgid.link/20260120074437.623018-1-lizhijian@fujitsu.com +Reviewed-by: Zhu Yanjun +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/sw/rxe/rxe_comp.c | 3 +++ + drivers/infiniband/sw/rxe/rxe_req.c | 3 +++ + 2 files changed, 6 insertions(+) + +diff --git a/drivers/infiniband/sw/rxe/rxe_comp.c b/drivers/infiniband/sw/rxe/rxe_comp.c +index d48af21807458..e02c5df0bef14 100644 +--- a/drivers/infiniband/sw/rxe/rxe_comp.c ++++ b/drivers/infiniband/sw/rxe/rxe_comp.c +@@ -119,12 +119,15 @@ void retransmit_timer(struct timer_list *t) + + rxe_dbg_qp(qp, "retransmit timer fired\n"); + ++ if (!rxe_get(qp)) ++ return; + spin_lock_irqsave(&qp->state_lock, flags); + if (qp->valid) { + qp->comp.timeout = 1; + rxe_sched_task(&qp->send_task); + } + spin_unlock_irqrestore(&qp->state_lock, flags); ++ rxe_put(qp); + } + + void rxe_comp_queue_pkt(struct rxe_qp *qp, struct sk_buff *skb) +diff --git a/drivers/infiniband/sw/rxe/rxe_req.c b/drivers/infiniband/sw/rxe/rxe_req.c +index 87a02f0deb000..d08ebb048cb0f 100644 +--- a/drivers/infiniband/sw/rxe/rxe_req.c ++++ b/drivers/infiniband/sw/rxe/rxe_req.c +@@ -103,6 +103,8 @@ void rnr_nak_timer(struct timer_list *t) + + rxe_dbg_qp(qp, "nak timer fired\n"); + ++ if (!rxe_get(qp)) ++ return; + spin_lock_irqsave(&qp->state_lock, flags); + if (qp->valid) { + /* request a send queue retry */ +@@ -111,6 +113,7 @@ void rnr_nak_timer(struct timer_list *t) + rxe_sched_task(&qp->send_task); + } + spin_unlock_irqrestore(&qp->state_lock, flags); ++ rxe_put(qp); + } + + static void req_check_sq_drain_done(struct rxe_qp *qp) +-- +2.51.0 + diff --git a/queue-6.12/rdma-uverbs-add-__gfp_nowarn-to-ib_uverbs_unmarshall.patch b/queue-6.12/rdma-uverbs-add-__gfp_nowarn-to-ib_uverbs_unmarshall.patch new file mode 100644 index 0000000000..1860146f02 --- /dev/null +++ b/queue-6.12/rdma-uverbs-add-__gfp_nowarn-to-ib_uverbs_unmarshall.patch @@ -0,0 +1,39 @@ +From 1a2d42477c7fb214f3f38622e12a6759b1b969f7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 17:49:00 +0800 +Subject: RDMA/uverbs: Add __GFP_NOWARN to ib_uverbs_unmarshall_recv() kmalloc + +From: Yi Liu + +[ Upstream commit 58b604dfc7bb753f91bc0ccd3fa705e14e6edfb4 ] + +Since wqe_size in ib_uverbs_unmarshall_recv() is user-provided and already +validated, but can still be large, add __GFP_NOWARN to suppress memory +allocation warnings for large sizes, consistent with the similar fix in +ib_uverbs_post_send(). + +Fixes: 67cdb40ca444 ("[IB] uverbs: Implement more commands") +Signed-off-by: Yi Liu +Link: https://patch.msgid.link/20260129094900.3517706-1-liuy22@mails.tsinghua.edu.cn +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/uverbs_cmd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c +index 2c1eb8a45f673..ac81b7d1eec96 100644 +--- a/drivers/infiniband/core/uverbs_cmd.c ++++ b/drivers/infiniband/core/uverbs_cmd.c +@@ -2224,7 +2224,7 @@ ib_uverbs_unmarshall_recv(struct uverbs_req_iter *iter, u32 wr_count, + if (ret) + return ERR_PTR(ret); + +- user_wr = kmalloc(wqe_size, GFP_KERNEL); ++ user_wr = kmalloc(wqe_size, GFP_KERNEL | __GFP_NOWARN); + if (!user_wr) + return ERR_PTR(-ENOMEM); + +-- +2.51.0 + diff --git a/queue-6.12/rdma-uverbs-validate-wqe_size-before-using-it-in-ib_.patch b/queue-6.12/rdma-uverbs-validate-wqe_size-before-using-it-in-ib_.patch new file mode 100644 index 0000000000..5bb07d4507 --- /dev/null +++ b/queue-6.12/rdma-uverbs-validate-wqe_size-before-using-it-in-ib_.patch @@ -0,0 +1,57 @@ +From aece95dfcfff603cfc9ddaa8546fab877370af6d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 22:29:00 +0800 +Subject: RDMA/uverbs: Validate wqe_size before using it in ib_uverbs_post_send + +From: Yi Liu + +[ Upstream commit 1956f0a74ccf5dc9c3ef717f2985c3ed3400aab0 ] + +ib_uverbs_post_send() uses cmd.wqe_size from userspace without any +validation before passing it to kmalloc() and using the allocated +buffer as struct ib_uverbs_send_wr. + +If a user provides a small wqe_size value (e.g., 1), kmalloc() will +succeed, but subsequent accesses to user_wr->opcode, user_wr->num_sge, +and other fields will read beyond the allocated buffer, resulting in +an out-of-bounds read from kernel heap memory. This could potentially +leak sensitive kernel information to userspace. + +Additionally, providing an excessively large wqe_size can trigger a +WARNING in the memory allocation path, as reported by syzkaller. + +This is inconsistent with ib_uverbs_unmarshall_recv() which properly +validates that wqe_size >= sizeof(struct ib_uverbs_recv_wr) before +proceeding. + +Add the same validation for ib_uverbs_post_send() to ensure wqe_size +is at least sizeof(struct ib_uverbs_send_wr). + +Fixes: c3bea3d2dc53 ("RDMA/uverbs: Use the iterator for ib_uverbs_unmarshall_recv()") +Signed-off-by: Yi Liu +Link: https://patch.msgid.link/20260122142900.2356276-2-liuy22@mails.tsinghua.edu.cn +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/uverbs_cmd.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c +index 535bb99ed9f5f..2c1eb8a45f673 100644 +--- a/drivers/infiniband/core/uverbs_cmd.c ++++ b/drivers/infiniband/core/uverbs_cmd.c +@@ -2031,7 +2031,10 @@ static int ib_uverbs_post_send(struct uverbs_attr_bundle *attrs) + if (ret) + return ret; + +- user_wr = kmalloc(cmd.wqe_size, GFP_KERNEL); ++ if (cmd.wqe_size < sizeof(struct ib_uverbs_send_wr)) ++ return -EINVAL; ++ ++ user_wr = kmalloc(cmd.wqe_size, GFP_KERNEL | __GFP_NOWARN); + if (!user_wr) + return -ENOMEM; + +-- +2.51.0 + diff --git a/queue-6.12/regulator-core-move-supply-check-earlier-in-set_mach.patch b/queue-6.12/regulator-core-move-supply-check-earlier-in-set_mach.patch new file mode 100644 index 0000000000..87ef71ca36 --- /dev/null +++ b/queue-6.12/regulator-core-move-supply-check-earlier-in-set_mach.patch @@ -0,0 +1,121 @@ +From 9a8f0f3411cd4185bfea113e7c0a30047e24df77 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 08:38:39 +0000 +Subject: regulator: core: move supply check earlier in + set_machine_constraints() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: André Draszik + +[ Upstream commit 86a8eeb0e913f4b6a55dabba5122098d4e805e55 ] + +Since commit 98e48cd9283d ("regulator: core: resolve supply for +boot-on/always-on regulators"), set_machine_constraints() can return +-EPROBE_DEFER very late, after it has done a lot of work and +configuration of the regulator. + +This means that configuration will happen multiple times for no +benefit in that case. Furthermore, this can lead to timing-dependent +voltage glitches as mentioned e.g. in commit 8a866d527ac0 ("regulator: +core: Resolve supply name earlier to prevent double-init"). + +We can know that it's going to fail very early, in particular before +going through the complete regulator configuration by moving some code +around a little. + +Do so to avoid re-configuring the regulator multiple times, also +avoiding the voltage glitches if we can. + +Fixes: 98e48cd9283d ("regulator: core: resolve supply for boot-on/always-on regulators") +Signed-off-by: André Draszik +Link: https://patch.msgid.link/20260109-regulators-defer-v2-3-1a25dc968e60@linaro.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/regulator/core.c | 55 ++++++++++++++++++++++------------------ + 1 file changed, 30 insertions(+), 25 deletions(-) + +diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c +index 1c0748fee6846..078d3dc50aa3f 100644 +--- a/drivers/regulator/core.c ++++ b/drivers/regulator/core.c +@@ -1406,6 +1406,33 @@ static int set_machine_constraints(struct regulator_dev *rdev) + int ret = 0; + const struct regulator_ops *ops = rdev->desc->ops; + ++ /* ++ * If there is no mechanism for controlling the regulator then ++ * flag it as always_on so we don't end up duplicating checks ++ * for this so much. Note that we could control the state of ++ * a supply to control the output on a regulator that has no ++ * direct control. ++ */ ++ if (!rdev->ena_pin && !ops->enable) { ++ if (rdev->supply_name && !rdev->supply) ++ return -EPROBE_DEFER; ++ ++ if (rdev->supply) ++ rdev->constraints->always_on = ++ rdev->supply->rdev->constraints->always_on; ++ else ++ rdev->constraints->always_on = true; ++ } ++ ++ /* ++ * If we want to enable this regulator, make sure that we know the ++ * supplying regulator. ++ */ ++ if (rdev->constraints->always_on || rdev->constraints->boot_on) { ++ if (rdev->supply_name && !rdev->supply) ++ return -EPROBE_DEFER; ++ } ++ + ret = machine_constraints_voltage(rdev, rdev->constraints); + if (ret != 0) + return ret; +@@ -1571,37 +1598,15 @@ static int set_machine_constraints(struct regulator_dev *rdev) + } + } + +- /* +- * If there is no mechanism for controlling the regulator then +- * flag it as always_on so we don't end up duplicating checks +- * for this so much. Note that we could control the state of +- * a supply to control the output on a regulator that has no +- * direct control. +- */ +- if (!rdev->ena_pin && !ops->enable) { +- if (rdev->supply_name && !rdev->supply) +- return -EPROBE_DEFER; +- +- if (rdev->supply) +- rdev->constraints->always_on = +- rdev->supply->rdev->constraints->always_on; +- else +- rdev->constraints->always_on = true; +- } +- + /* If the constraints say the regulator should be on at this point + * and we have control then make sure it is enabled. + */ + if (rdev->constraints->always_on || rdev->constraints->boot_on) { + bool supply_enabled = false; + +- /* If we want to enable this regulator, make sure that we know +- * the supplying regulator. +- */ +- if (rdev->supply_name && !rdev->supply) +- return -EPROBE_DEFER; +- +- /* If supplying regulator has already been enabled, ++ /* We have ensured a potential supply has been resolved above. ++ * ++ * If supplying regulator has already been enabled, + * it's not intended to have use_count increment + * when rdev is only boot-on. + */ +-- +2.51.0 + diff --git a/queue-6.12/revert-hwmon-ibmpex-fix-use-after-free-in-high-low-s.patch b/queue-6.12/revert-hwmon-ibmpex-fix-use-after-free-in-high-low-s.patch new file mode 100644 index 0000000000..2c1368ab99 --- /dev/null +++ b/queue-6.12/revert-hwmon-ibmpex-fix-use-after-free-in-high-low-s.patch @@ -0,0 +1,89 @@ +From 7020189b2c6cbb2f25fda1908106771b00e7541e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Feb 2026 08:12:25 -0800 +Subject: Revert "hwmon: (ibmpex) fix use-after-free in high/low store" + +From: Guenter Roeck + +[ Upstream commit 8bde3e395a85017f12af2b0ba5c3684f5af9c006 ] + +This reverts commit 6946c726c3f4c36f0f049e6f97e88c510b15f65d. + +Jean Delvare points out that the patch does not completely +fix the reported problem, that it in fact introduces a +(new) race condition, and that it may actually not be needed in +the first place. + +Various AI reviews agree. Specific and relevant AI feedback: + +" +This reordering sets the driver data to NULL before removing the sensor +attributes in the loop below. + +ibmpex_show_sensor() retrieves this driver data via dev_get_drvdata() but +does not check if it is NULL before dereferencing it to access +data->sensors[]. + +If a userspace process reads a sensor file (like temp1_input) while this +delete function is running, could it race with the dev_set_drvdata(..., +NULL) call here and crash in ibmpex_show_sensor()? + +Would it be safer to keep the original order where device_remove_file() is +called before clearing the driver data? device_remove_file() should wait +for any active sysfs callbacks to complete, which might already prevent the +use-after-free this patch intends to fix. +" + +Revert the offending patch. If it can be shown that the originally reported +alleged race condition does indeed exist, it can always be re-introduced +with a complete fix. + +Reported-by: Jean Delvare +Closes: https://lore.kernel.org/linux-hwmon/20260121095342.73e723cb@endymion/ +Cc: Jean Delvare +Cc: Junrui Luo +Fixes: 6946c726c3f4 ("hwmon: (ibmpex) fix use-after-free in high/low store") +Reviewed-by: Jean Delvare +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + drivers/hwmon/ibmpex.c | 9 ++------- + 1 file changed, 2 insertions(+), 7 deletions(-) + +diff --git a/drivers/hwmon/ibmpex.c b/drivers/hwmon/ibmpex.c +index 129f3a9e8fe96..228c5f6c6f383 100644 +--- a/drivers/hwmon/ibmpex.c ++++ b/drivers/hwmon/ibmpex.c +@@ -277,9 +277,6 @@ static ssize_t ibmpex_high_low_store(struct device *dev, + { + struct ibmpex_bmc_data *data = dev_get_drvdata(dev); + +- if (!data) +- return -ENODEV; +- + ibmpex_reset_high_low_data(data); + + return count; +@@ -511,9 +508,6 @@ static void ibmpex_bmc_delete(struct ibmpex_bmc_data *data) + { + int i, j; + +- hwmon_device_unregister(data->hwmon_dev); +- dev_set_drvdata(data->bmc_device, NULL); +- + device_remove_file(data->bmc_device, + &sensor_dev_attr_reset_high_low.dev_attr); + device_remove_file(data->bmc_device, &dev_attr_name.attr); +@@ -527,7 +521,8 @@ static void ibmpex_bmc_delete(struct ibmpex_bmc_data *data) + } + + list_del(&data->list); +- ++ dev_set_drvdata(data->bmc_device, NULL); ++ hwmon_device_unregister(data->hwmon_dev); + ipmi_destroy_user(data->user); + kfree(data->sensors); + kfree(data); +-- +2.51.0 + diff --git a/queue-6.12/revert-mmc-rtsx_pci_sdmmc-increase-power-on-settling.patch b/queue-6.12/revert-mmc-rtsx_pci_sdmmc-increase-power-on-settling.patch new file mode 100644 index 0000000000..3f9095ab40 --- /dev/null +++ b/queue-6.12/revert-mmc-rtsx_pci_sdmmc-increase-power-on-settling.patch @@ -0,0 +1,39 @@ +From 4e876d4b8c4628ef6f31bc8036288752a75b0341 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 15:49:31 +0100 +Subject: Revert "mmc: rtsx_pci_sdmmc: increase power-on settling delay to 5ms" + +From: Greg Kroah-Hartman + +[ Upstream commit ff112f1ecd10b72004eac05bae395e1c65f0c63c ] + +This reverts commit aced969e9bf3701dc75cfca57c78c031b7875b9d. + +It was determined that this was not the correct "fix", so should be +reverted. + +Fixes: aced969e9bf3 ("mmc: rtsx_pci_sdmmc: increase power-on settling delay to 5ms") +Cc: Matthew Schwartz +Cc: Ulf Hansson +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/mmc/host/rtsx_pci_sdmmc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c +index f5bc757ddaa27..04aa47f1a24fb 100644 +--- a/drivers/mmc/host/rtsx_pci_sdmmc.c ++++ b/drivers/mmc/host/rtsx_pci_sdmmc.c +@@ -939,7 +939,7 @@ static int sd_power_on(struct realtek_pci_sdmmc *host, unsigned char power_mode) + if (err < 0) + return err; + +- mdelay(5); ++ mdelay(1); + + err = rtsx_pci_write_register(pcr, CARD_OE, SD_OUTPUT_EN, SD_OUTPUT_EN); + if (err < 0) +-- +2.51.0 + diff --git a/queue-6.12/rnbd-srv-fix-server-side-setting-of-bi_size-for-spec.patch b/queue-6.12/rnbd-srv-fix-server-side-setting-of-bi_size-for-spec.patch new file mode 100644 index 0000000000..919ab3a9e0 --- /dev/null +++ b/queue-6.12/rnbd-srv-fix-server-side-setting-of-bi_size-for-spec.patch @@ -0,0 +1,80 @@ +From 838440fce5922226cc55f2a93c7106944298b369 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Dec 2025 13:47:32 +0100 +Subject: rnbd-srv: Fix server side setting of bi_size for special IOs + +From: Florian-Ewald Mueller + +[ Upstream commit 4ac9690d4b9456ca1d5276d86547fa2e7cd47684 ] + +On rnbd-srv, the bi_size of the bio is set during the bio_add_page +function, to which datalen is passed. But for special IOs like DISCARD +and WRITE_ZEROES, datalen is 0, since there is no data to write. For +these special IOs, use the bi_size of the rnbd_msg_io. + +Fixes: f6f84be089c9 ("block/rnbd-srv: Add sanity check and remove redundant assignment") +Signed-off-by: Florian-Ewald Mueller +Signed-off-by: Md Haris Iqbal +Signed-off-by: Grzegorz Prajsner +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/block/rnbd/rnbd-srv.c | 33 +++++++++++++++++++++++---------- + 1 file changed, 23 insertions(+), 10 deletions(-) + +diff --git a/drivers/block/rnbd/rnbd-srv.c b/drivers/block/rnbd/rnbd-srv.c +index dd4d813718fd2..ba44018b00af5 100644 +--- a/drivers/block/rnbd/rnbd-srv.c ++++ b/drivers/block/rnbd/rnbd-srv.c +@@ -145,18 +145,30 @@ static int process_rdma(struct rnbd_srv_session *srv_sess, + priv->sess_dev = sess_dev; + priv->id = id; + +- bio = bio_alloc(file_bdev(sess_dev->bdev_file), 1, ++ bio = bio_alloc(file_bdev(sess_dev->bdev_file), !!datalen, + rnbd_to_bio_flags(le32_to_cpu(msg->rw)), GFP_KERNEL); +- bio_add_virt_nofail(bio, data, datalen); +- +- bio->bi_opf = rnbd_to_bio_flags(le32_to_cpu(msg->rw)); +- if (bio_has_data(bio) && +- bio->bi_iter.bi_size != le32_to_cpu(msg->bi_size)) { +- rnbd_srv_err_rl(sess_dev, "Datalen mismatch: bio bi_size (%u), bi_size (%u)\n", +- bio->bi_iter.bi_size, msg->bi_size); +- err = -EINVAL; +- goto bio_put; ++ if (unlikely(!bio)) { ++ err = -ENOMEM; ++ goto put_sess_dev; + } ++ ++ if (!datalen) { ++ /* ++ * For special requests like DISCARD and WRITE_ZEROES, the datalen is zero. ++ */ ++ bio->bi_iter.bi_size = le32_to_cpu(msg->bi_size); ++ } else { ++ bio_add_virt_nofail(bio, data, datalen); ++ bio->bi_opf = rnbd_to_bio_flags(le32_to_cpu(msg->rw)); ++ if (bio->bi_iter.bi_size != le32_to_cpu(msg->bi_size)) { ++ rnbd_srv_err_rl(sess_dev, ++ "Datalen mismatch: bio bi_size (%u), bi_size (%u)\n", ++ bio->bi_iter.bi_size, msg->bi_size); ++ err = -EINVAL; ++ goto bio_put; ++ } ++ } ++ + bio->bi_end_io = rnbd_dev_bi_end_io; + bio->bi_private = priv; + bio->bi_iter.bi_sector = le64_to_cpu(msg->sector); +@@ -170,6 +182,7 @@ static int process_rdma(struct rnbd_srv_session *srv_sess, + + bio_put: + bio_put(bio); ++put_sess_dev: + rnbd_put_sess_dev(sess_dev); + err: + kfree(priv); +-- +2.51.0 + diff --git a/queue-6.12/rnbd-srv-use-bio_add_virt_nofail.patch b/queue-6.12/rnbd-srv-use-bio_add_virt_nofail.patch new file mode 100644 index 0000000000..141c02f24d --- /dev/null +++ b/queue-6.12/rnbd-srv-use-bio_add_virt_nofail.patch @@ -0,0 +1,45 @@ +From bae220a9673f8345aad7dde96b3b0e0e8c5a2cbd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 May 2025 14:04:33 +0200 +Subject: rnbd-srv: use bio_add_virt_nofail + +From: Christoph Hellwig + +[ Upstream commit a216081323a1391991c9073fed2459265bfc7f5c ] + +Use the bio_add_virt_nofail to add a single kernel virtual address +to a bio as that can't fail. + +Signed-off-by: Christoph Hellwig +Acked-by: Jack Wang +Reviewed-by: Damien Le Moal +Reviewed-by: Johannes Thumshirn +Link: https://lore.kernel.org/r/20250507120451.4000627-10-hch@lst.de +Signed-off-by: Jens Axboe +Stable-dep-of: 4ac9690d4b94 ("rnbd-srv: Fix server side setting of bi_size for special IOs") +Signed-off-by: Sasha Levin +--- + drivers/block/rnbd/rnbd-srv.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/drivers/block/rnbd/rnbd-srv.c b/drivers/block/rnbd/rnbd-srv.c +index 08ce6d96d04cf..dd4d813718fd2 100644 +--- a/drivers/block/rnbd/rnbd-srv.c ++++ b/drivers/block/rnbd/rnbd-srv.c +@@ -147,12 +147,7 @@ static int process_rdma(struct rnbd_srv_session *srv_sess, + + bio = bio_alloc(file_bdev(sess_dev->bdev_file), 1, + rnbd_to_bio_flags(le32_to_cpu(msg->rw)), GFP_KERNEL); +- if (bio_add_page(bio, virt_to_page(data), datalen, +- offset_in_page(data)) != datalen) { +- rnbd_srv_err_rl(sess_dev, "Failed to map data to bio\n"); +- err = -EINVAL; +- goto bio_put; +- } ++ bio_add_virt_nofail(bio, data, datalen); + + bio->bi_opf = rnbd_to_bio_flags(le32_to_cpu(msg->rw)); + if (bio_has_data(bio) && +-- +2.51.0 + diff --git a/queue-6.12/s390-cio-fix-device-lifecycle-handling-in-css_alloc_.patch b/queue-6.12/s390-cio-fix-device-lifecycle-handling-in-css_alloc_.patch new file mode 100644 index 0000000000..05395a9e26 --- /dev/null +++ b/queue-6.12/s390-cio-fix-device-lifecycle-handling-in-css_alloc_.patch @@ -0,0 +1,49 @@ +From e2d135966920d1bf6860f5b6b9be16073e97438e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 21:47:59 +0100 +Subject: s390/cio: Fix device lifecycle handling in css_alloc_subchannel() + +From: Salah Triki + +[ Upstream commit f65c75b0b9b5a390bc3beadcde0a6fbc3ad118f7 ] + +`css_alloc_subchannel()` calls `device_initialize()` before setting up +the DMA masks. If `dma_set_coherent_mask()` or `dma_set_mask()` fails, +the error path frees the subchannel structure directly, bypassing +the device model reference counting. + +Once `device_initialize()` has been called, the embedded struct device +must be released via `put_device()`, allowing the release callback to +free the container structure. + +Fix the error path by dropping the initial device reference with +`put_device()` instead of calling `kfree()` directly. + +This ensures correct device lifetime handling and avoids potential +use-after-free or double-free issues. + +Fixes: e5dcf0025d7af ("s390/css: move subchannel lock allocation") +Signed-off-by: Salah Triki +Reviewed-by: Vineeth Vijayan +Signed-off-by: Heiko Carstens +Signed-off-by: Sasha Levin +--- + drivers/s390/cio/css.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c +index 7b59d20bf7850..61be7c0550bc4 100644 +--- a/drivers/s390/cio/css.c ++++ b/drivers/s390/cio/css.c +@@ -236,7 +236,7 @@ struct subchannel *css_alloc_subchannel(struct subchannel_id schid, + return sch; + + err: +- kfree(sch); ++ put_device(&sch->dev); + return ERR_PTR(ret); + } + +-- +2.51.0 + diff --git a/queue-6.12/sched-deadline-clear-the-defer-params.patch b/queue-6.12/sched-deadline-clear-the-defer-params.patch new file mode 100644 index 0000000000..d1b0c56da0 --- /dev/null +++ b/queue-6.12/sched-deadline-clear-the-defer-params.patch @@ -0,0 +1,43 @@ +From f8574b229870dd94923d856de72182e1e9468b30 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 10:58:59 +0100 +Subject: sched/deadline: Clear the defer params + +From: Joel Fernandes + +[ Upstream commit 3cb3b27693bf30defb16aa096158a3b24583b8d2 ] + +The defer params were not cleared in __dl_clear_params. Clear them. + +Without this is some of my test cases are flaking and the DL timer is +not starting correctly AFAICS. + +Fixes: a110a81c52a9 ("sched/deadline: Deferrable dl server") +Signed-off-by: Joel Fernandes +Signed-off-by: Peter Zijlstra (Intel) +Reviewed-by: Andrea Righi +Acked-by: Juri Lelli +Tested-by: Christian Loehle +Link: https://patch.msgid.link/20260126100050.3854740-2-arighi@nvidia.com +Signed-off-by: Sasha Levin +--- + kernel/sched/deadline.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c +index 1689d190dea8f..8acdd97538546 100644 +--- a/kernel/sched/deadline.c ++++ b/kernel/sched/deadline.c +@@ -3649,6 +3649,9 @@ static void __dl_clear_params(struct sched_dl_entity *dl_se) + dl_se->dl_non_contending = 0; + dl_se->dl_overrun = 0; + dl_se->dl_server = 0; ++ dl_se->dl_defer = 0; ++ dl_se->dl_defer_running = 0; ++ dl_se->dl_defer_armed = 0; + + #ifdef CONFIG_RT_MUTEXES + dl_se->pi_se = dl_se; +-- +2.51.0 + diff --git a/queue-6.12/sched-rt-skip-currently-executing-cpu-in-rto_next_cp.patch b/queue-6.12/sched-rt-skip-currently-executing-cpu-in-rto_next_cp.patch new file mode 100644 index 0000000000..a896410797 --- /dev/null +++ b/queue-6.12/sched-rt-skip-currently-executing-cpu-in-rto_next_cp.patch @@ -0,0 +1,87 @@ +From d13ffc8aee46b26254b3a1395f8ca225a9ec19ff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 01:25:33 +0000 +Subject: sched/rt: Skip currently executing CPU in rto_next_cpu() + +From: Chen Jinghuang + +[ Upstream commit 94894c9c477e53bcea052e075c53f89df3d2a33e ] + +CPU0 becomes overloaded when hosting a CPU-bound RT task, a non-CPU-bound +RT task, and a CFS task stuck in kernel space. When other CPUs switch from +RT to non-RT tasks, RT load balancing (LB) is triggered; with +HAVE_RT_PUSH_IPI enabled, they send IPIs to CPU0 to drive the execution +of rto_push_irq_work_func. During push_rt_task on CPU0, +if next_task->prio < rq->donor->prio, resched_curr() sets NEED_RESCHED +and after the push operation completes, CPU0 calls rto_next_cpu(). +Since only CPU0 is overloaded in this scenario, rto_next_cpu() should +ideally return -1 (no further IPI needed). + +However, multiple CPUs invoking tell_cpu_to_push() during LB increments +rd->rto_loop_next. Even when rd->rto_cpu is set to -1, the mismatch between +rd->rto_loop and rd->rto_loop_next forces rto_next_cpu() to restart its +search from -1. With CPU0 remaining overloaded (satisfying rt_nr_migratory +&& rt_nr_total > 1), it gets reselected, causing CPU0 to queue irq_work to +itself and send self-IPIs repeatedly. As long as CPU0 stays overloaded and +other CPUs run pull_rt_tasks(), it falls into an infinite self-IPI loop, +which triggers a CPU hardlockup due to continuous self-interrupts. + +The trigging scenario is as follows: + + cpu0 cpu1 cpu2 + pull_rt_task + tell_cpu_to_push + <------------irq_work_queue_on +rto_push_irq_work_func + push_rt_task + resched_curr(rq) pull_rt_task + rto_next_cpu tell_cpu_to_push + <-------------------------- atomic_inc(rto_loop_next) +rd->rto_loop != next + rto_next_cpu + irq_work_queue_on +rto_push_irq_work_func + +Fix redundant self-IPI by filtering the initiating CPU in rto_next_cpu(). +This solution has been verified to effectively eliminate spurious self-IPIs +and prevent CPU hardlockup scenarios. + +Fixes: 4bdced5c9a29 ("sched/rt: Simplify the IPI based RT balancing logic") +Suggested-by: Steven Rostedt (Google) +Suggested-by: K Prateek Nayak +Signed-off-by: Chen Jinghuang +Signed-off-by: Peter Zijlstra (Intel) +Reviewed-by: Steven Rostedt (Google) +Reviewed-by: Valentin Schneider +Link: https://patch.msgid.link/20260122012533.673768-1-chenjinghuang2@huawei.com +Signed-off-by: Sasha Levin +--- + kernel/sched/rt.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c +index c437a15026238..ffcce501ed40c 100644 +--- a/kernel/sched/rt.c ++++ b/kernel/sched/rt.c +@@ -2151,6 +2151,7 @@ static void push_rt_tasks(struct rq *rq) + */ + static int rto_next_cpu(struct root_domain *rd) + { ++ int this_cpu = smp_processor_id(); + int next; + int cpu; + +@@ -2174,6 +2175,10 @@ static int rto_next_cpu(struct root_domain *rd) + + rd->rto_cpu = cpu; + ++ /* Do not send IPI to self */ ++ if (cpu == this_cpu) ++ continue; ++ + if (cpu < nr_cpu_ids) + return cpu; + +-- +2.51.0 + diff --git a/queue-6.12/scsi-csiostor-fix-dereference-of-null-pointer-rn.patch b/queue-6.12/scsi-csiostor-fix-dereference-of-null-pointer-rn.patch new file mode 100644 index 0000000000..941735a3e8 --- /dev/null +++ b/queue-6.12/scsi-csiostor-fix-dereference-of-null-pointer-rn.patch @@ -0,0 +1,46 @@ +From 00cf8015531d47ab723e0057346b9c9cedc44886 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 15:53:32 +0000 +Subject: scsi: csiostor: Fix dereference of null pointer rn + +From: Colin Ian King + +[ Upstream commit 1982257570b84dc33753d536dd969fd357a014e9 ] + +The error exit path when rn is NULL ends up deferencing the null pointer rn +via the use of the macro CSIO_INC_STATS. Fix this by adding a new error +return path label after the use of the macro to avoid the deference. + +Fixes: a3667aaed569 ("[SCSI] csiostor: Chelsio FCoE offload driver") +Signed-off-by: Colin Ian King +Link: https://patch.msgid.link/20260129155332.196338-1-colin.i.king@gmail.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/csiostor/csio_scsi.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/scsi/csiostor/csio_scsi.c b/drivers/scsi/csiostor/csio_scsi.c +index 8329f0cab4e7d..b0467251cece0 100644 +--- a/drivers/scsi/csiostor/csio_scsi.c ++++ b/drivers/scsi/csiostor/csio_scsi.c +@@ -2074,7 +2074,7 @@ csio_eh_lun_reset_handler(struct scsi_cmnd *cmnd) + struct csio_scsi_level_data sld; + + if (!rn) +- goto fail; ++ goto fail_ret; + + csio_dbg(hw, "Request to reset LUN:%llu (ssni:0x%x tgtid:%d)\n", + cmnd->device->lun, rn->flowid, rn->scsi_id); +@@ -2220,6 +2220,7 @@ csio_eh_lun_reset_handler(struct scsi_cmnd *cmnd) + csio_put_scsi_ioreq_lock(hw, scsim, ioreq); + fail: + CSIO_INC_STATS(rn, n_lun_rst_fail); ++fail_ret: + return FAILED; + } + +-- +2.51.0 + diff --git a/queue-6.12/scsi-efct-use-irqf_oneshot-and-default-primary-handl.patch b/queue-6.12/scsi-efct-use-irqf_oneshot-and-default-primary-handl.patch new file mode 100644 index 0000000000..22e586a674 --- /dev/null +++ b/queue-6.12/scsi-efct-use-irqf_oneshot-and-default-primary-handl.patch @@ -0,0 +1,59 @@ +From 3f07edcbb4c89ba9352236a84274e9b377aaff08 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:55:27 +0100 +Subject: scsi: efct: Use IRQF_ONESHOT and default primary handler + +From: Sebastian Andrzej Siewior + +[ Upstream commit bd81f07e9a27c341cd7e72be95eb0b7cf3910926 ] + +There is no added value in efct_intr_msix() compared to +irq_default_primary_handler(). + +Using a threaded interrupt without a dedicated primary handler mandates +the IRQF_ONESHOT flag to mask the interrupt source while the threaded +handler is active. Otherwise the interrupt can fire again before the +threaded handler had a chance to run. + +Use the default primary interrupt handler by specifying NULL and set +IRQF_ONESHOT so the interrupt source is masked until the secondary +handler is done. + +Fixes: 4df84e8466242 ("scsi: elx: efct: Driver initialization routines") +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260128095540.863589-8-bigeasy@linutronix.de +Signed-off-by: Sasha Levin +--- + drivers/scsi/elx/efct/efct_driver.c | 8 +------- + 1 file changed, 1 insertion(+), 7 deletions(-) + +diff --git a/drivers/scsi/elx/efct/efct_driver.c b/drivers/scsi/elx/efct/efct_driver.c +index 55d2301bfd7de..d1a73cc2398ec 100644 +--- a/drivers/scsi/elx/efct/efct_driver.c ++++ b/drivers/scsi/elx/efct/efct_driver.c +@@ -415,12 +415,6 @@ efct_intr_thread(int irq, void *handle) + return IRQ_HANDLED; + } + +-static irqreturn_t +-efct_intr_msix(int irq, void *handle) +-{ +- return IRQ_WAKE_THREAD; +-} +- + static int + efct_setup_msix(struct efct *efct, u32 num_intrs) + { +@@ -450,7 +444,7 @@ efct_setup_msix(struct efct *efct, u32 num_intrs) + intr_ctx->index = i; + + rc = request_threaded_irq(pci_irq_vector(efct->pci, i), +- efct_intr_msix, efct_intr_thread, 0, ++ NULL, efct_intr_thread, IRQF_ONESHOT, + EFCT_DRIVER_NAME, intr_ctx); + if (rc) { + dev_err(&efct->pci->dev, +-- +2.51.0 + diff --git a/queue-6.12/scsi-smartpqi-fix-memory-leak-in-pqi_report_phys_lun.patch b/queue-6.12/scsi-smartpqi-fix-memory-leak-in-pqi_report_phys_lun.patch new file mode 100644 index 0000000000..a604594881 --- /dev/null +++ b/queue-6.12/scsi-smartpqi-fix-memory-leak-in-pqi_report_phys_lun.patch @@ -0,0 +1,72 @@ +From f477ef9359da82d11cdf6ad971a6336f27c53889 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Jan 2026 09:36:41 +0000 +Subject: scsi: smartpqi: Fix memory leak in pqi_report_phys_luns() + +From: Zilin Guan + +[ Upstream commit 41b37312bd9722af77ec7817ccf22d7a4880c289 ] + +pqi_report_phys_luns() fails to release the rpl_list buffer when +encountering an unsupported data format or when the allocation for +rpl_16byte_wwid_list fails. These early returns bypass the cleanup logic, +leading to memory leaks. + +Consolidate the error handling by adding an out_free_rpl_list label and use +goto statements to ensure rpl_list is consistently freed on failure. + +Compile tested only. Issue found using a prototype static analysis tool and +code review. + +Fixes: 28ca6d876c5a ("scsi: smartpqi: Add extended report physical LUNs") +Signed-off-by: Zilin Guan +Tested-by: Don Brace +Acked-by: Don Brace +Link: https://patch.msgid.link/20260131093641.1008117-1-zilin@seu.edu.cn +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/smartpqi/smartpqi_init.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c +index f0fb22e4117eb..e7836f66c89ad 100644 +--- a/drivers/scsi/smartpqi/smartpqi_init.c ++++ b/drivers/scsi/smartpqi/smartpqi_init.c +@@ -1239,7 +1239,8 @@ static inline int pqi_report_phys_luns(struct pqi_ctrl_info *ctrl_info, void **b + dev_err(&ctrl_info->pci_dev->dev, + "RPL returned unsupported data format %u\n", + rpl_response_format); +- return -EINVAL; ++ rc = -EINVAL; ++ goto out_free_rpl_list; + } else { + dev_warn(&ctrl_info->pci_dev->dev, + "RPL returned extended format 2 instead of 4\n"); +@@ -1251,8 +1252,10 @@ static inline int pqi_report_phys_luns(struct pqi_ctrl_info *ctrl_info, void **b + + rpl_16byte_wwid_list = kmalloc(struct_size(rpl_16byte_wwid_list, lun_entries, + num_physicals), GFP_KERNEL); +- if (!rpl_16byte_wwid_list) +- return -ENOMEM; ++ if (!rpl_16byte_wwid_list) { ++ rc = -ENOMEM; ++ goto out_free_rpl_list; ++ } + + put_unaligned_be32(num_physicals * sizeof(struct report_phys_lun_16byte_wwid), + &rpl_16byte_wwid_list->header.list_length); +@@ -1273,6 +1276,10 @@ static inline int pqi_report_phys_luns(struct pqi_ctrl_info *ctrl_info, void **b + *buffer = rpl_16byte_wwid_list; + + return 0; ++ ++out_free_rpl_list: ++ kfree(rpl_list); ++ return rc; + } + + static inline int pqi_report_logical_luns(struct pqi_ctrl_info *ctrl_info, void **buffer) +-- +2.51.0 + diff --git a/queue-6.12/scsi-ufs-host-mediatek-require-config_pm.patch b/queue-6.12/scsi-ufs-host-mediatek-require-config_pm.patch new file mode 100644 index 0000000000..08c867d15b --- /dev/null +++ b/queue-6.12/scsi-ufs-host-mediatek-require-config_pm.patch @@ -0,0 +1,116 @@ +From 8867434f5d67eef4732753f9e2bb9d79a0c7b1b8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 10:50:18 +0100 +Subject: scsi: ufs: host: mediatek: Require CONFIG_PM + +From: Arnd Bergmann + +[ Upstream commit bbb8d98fb4536594cb104fd630ea0f7dce3771d6 ] + +The added print statement from a recent fix causes the driver to fail +building when CONFIG_PM is disabled: + +drivers/ufs/host/ufs-mediatek.c: In function 'ufs_mtk_resume': +drivers/ufs/host/ufs-mediatek.c:1890:40: error: 'struct dev_pm_info' has no member named 'request' + 1890 | hba->dev->power.request, + +It seems unlikely that the driver can work at all without CONFIG_PM, so +just add a dependency and remove the existing ifdef checks, rather than +adding another ifdef. + +Fixes: 15ef3f5aa822 ("scsi: ufs: host: mediatek: Enhance recovery on resume failure") +Signed-off-by: Arnd Bergmann +Reviewed-by: AngeloGioacchino Del Regno +Link: https://patch.msgid.link/20260202095052.1232703-1-arnd@kernel.org +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/ufs/host/Kconfig | 1 + + drivers/ufs/host/ufs-mediatek.c | 12 +++--------- + include/ufs/ufshcd.h | 4 ---- + 3 files changed, 4 insertions(+), 13 deletions(-) + +diff --git a/drivers/ufs/host/Kconfig b/drivers/ufs/host/Kconfig +index 580c8d0bd8bbd..626bb9002f4a1 100644 +--- a/drivers/ufs/host/Kconfig ++++ b/drivers/ufs/host/Kconfig +@@ -72,6 +72,7 @@ config SCSI_UFS_QCOM + config SCSI_UFS_MEDIATEK + tristate "Mediatek specific hooks to UFS controller platform driver" + depends on SCSI_UFSHCD_PLATFORM && ARCH_MEDIATEK ++ depends on PM + depends on RESET_CONTROLLER + select PHY_MTK_UFS + select RESET_TI_SYSCON +diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c +index 1fb98af4ac564..e4156238f51d9 100644 +--- a/drivers/ufs/host/ufs-mediatek.c ++++ b/drivers/ufs/host/ufs-mediatek.c +@@ -1987,7 +1987,6 @@ static void ufs_mtk_remove(struct platform_device *pdev) + ufshcd_pltfrm_remove(pdev); + } + +-#ifdef CONFIG_PM_SLEEP + static int ufs_mtk_system_suspend(struct device *dev) + { + struct ufs_hba *hba = dev_get_drvdata(dev); +@@ -2034,9 +2033,7 @@ static int ufs_mtk_system_resume(struct device *dev) + + return ret; + } +-#endif + +-#ifdef CONFIG_PM + static int ufs_mtk_runtime_suspend(struct device *dev) + { + struct ufs_hba *hba = dev_get_drvdata(dev); +@@ -2067,13 +2064,10 @@ static int ufs_mtk_runtime_resume(struct device *dev) + + return ufshcd_runtime_resume(dev); + } +-#endif + + static const struct dev_pm_ops ufs_mtk_pm_ops = { +- SET_SYSTEM_SLEEP_PM_OPS(ufs_mtk_system_suspend, +- ufs_mtk_system_resume) +- SET_RUNTIME_PM_OPS(ufs_mtk_runtime_suspend, +- ufs_mtk_runtime_resume, NULL) ++ SYSTEM_SLEEP_PM_OPS(ufs_mtk_system_suspend, ufs_mtk_system_resume) ++ RUNTIME_PM_OPS(ufs_mtk_runtime_suspend, ufs_mtk_runtime_resume, NULL) + .prepare = ufshcd_suspend_prepare, + .complete = ufshcd_resume_complete, + }; +@@ -2083,7 +2077,7 @@ static struct platform_driver ufs_mtk_pltform = { + .remove_new = ufs_mtk_remove, + .driver = { + .name = "ufshcd-mtk", +- .pm = &ufs_mtk_pm_ops, ++ .pm = pm_ptr(&ufs_mtk_pm_ops), + .of_match_table = ufs_mtk_of_match, + }, + }; +diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h +index bdc5564b16fba..e68ce42eaff4d 100644 +--- a/include/ufs/ufshcd.h ++++ b/include/ufs/ufshcd.h +@@ -1356,17 +1356,13 @@ static inline void *ufshcd_get_variant(struct ufs_hba *hba) + return hba->priv; + } + +-#ifdef CONFIG_PM + extern int ufshcd_runtime_suspend(struct device *dev); + extern int ufshcd_runtime_resume(struct device *dev); +-#endif +-#ifdef CONFIG_PM_SLEEP + extern int ufshcd_system_suspend(struct device *dev); + extern int ufshcd_system_resume(struct device *dev); + extern int ufshcd_system_freeze(struct device *dev); + extern int ufshcd_system_thaw(struct device *dev); + extern int ufshcd_system_restore(struct device *dev); +-#endif + + extern int ufshcd_dme_configure_adapt(struct ufs_hba *hba, + int agreed_gear, +-- +2.51.0 + diff --git a/queue-6.12/selftests-bpf-fix-resource-leak-in-serial_test_wq-on.patch b/queue-6.12/selftests-bpf-fix-resource-leak-in-serial_test_wq-on.patch new file mode 100644 index 0000000000..4d4ef09717 --- /dev/null +++ b/queue-6.12/selftests-bpf-fix-resource-leak-in-serial_test_wq-on.patch @@ -0,0 +1,60 @@ +From 46fab7c10e243b222255b8ebeac07b61539cb8ac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 17:41:16 +0800 +Subject: selftests/bpf: Fix resource leak in serial_test_wq on attach failure + +From: Kery Qi + +[ Upstream commit a32ae2658471dd87a2f7a438388ed7d9a5767212 ] + +When wq__attach() fails, serial_test_wq() returns early without calling +wq__destroy(), leaking the skeleton resources allocated by +wq__open_and_load(). This causes ASAN leak reports in selftests runs. + +Fix this by jumping to a common clean_up label that calls wq__destroy() +on all exit paths after successful open_and_load. + +Note that the early return after wq__open_and_load() failure is correct +and doesn't need fixing, since that function returns NULL on failure +(after internally cleaning up any partial allocations). + +Fixes: 8290dba51910 ("selftests/bpf: wq: add bpf_wq_start() checks") +Signed-off-by: Kery Qi +Signed-off-by: Andrii Nakryiko +Acked-by: Yonghong Song +Link: https://lore.kernel.org/bpf/20260121094114.1801-3-qikeyu2017@gmail.com +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/bpf/prog_tests/wq.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/tools/testing/selftests/bpf/prog_tests/wq.c b/tools/testing/selftests/bpf/prog_tests/wq.c +index 99e438fe12acd..15ac8e6d17450 100644 +--- a/tools/testing/selftests/bpf/prog_tests/wq.c ++++ b/tools/testing/selftests/bpf/prog_tests/wq.c +@@ -16,12 +16,12 @@ void serial_test_wq(void) + /* re-run the success test to check if the timer was actually executed */ + + wq_skel = wq__open_and_load(); +- if (!ASSERT_OK_PTR(wq_skel, "wq_skel_load")) ++ if (!ASSERT_OK_PTR(wq_skel, "wq__open_and_load")) + return; + + err = wq__attach(wq_skel); + if (!ASSERT_OK(err, "wq_attach")) +- return; ++ goto clean_up; + + prog_fd = bpf_program__fd(wq_skel->progs.test_syscall_array_sleepable); + err = bpf_prog_test_run_opts(prog_fd, &topts); +@@ -31,6 +31,7 @@ void serial_test_wq(void) + usleep(50); /* 10 usecs should be enough, but give it extra */ + + ASSERT_EQ(wq_skel->bss->ok_sleepable, (1 << 1), "ok_sleepable"); ++clean_up: + wq__destroy(wq_skel); + } + +-- +2.51.0 + diff --git a/queue-6.12/selftests-bpf-veristat-fix-printing-order-in-output_.patch b/queue-6.12/selftests-bpf-veristat-fix-printing-order-in-output_.patch new file mode 100644 index 0000000000..7ca6984d6a --- /dev/null +++ b/queue-6.12/selftests-bpf-veristat-fix-printing-order-in-output_.patch @@ -0,0 +1,46 @@ +From a531ed09ffaa2f5256e75c218a7b3a640a1c9325 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 31 Dec 2025 14:10:50 -0800 +Subject: selftests/bpf: veristat: fix printing order in output_stats() + +From: Puranjay Mohan + +[ Upstream commit c286e7e9d1f1f3d90ad11c37e896f582b02d19c4 ] + +The order of the variables in the printf() doesn't match the text and +therefore veristat prints something like this: + +Done. Processed 24 files, 0 programs. Skipped 62 files, 0 programs. + +When it should print: + +Done. Processed 24 files, 62 programs. Skipped 0 files, 0 programs. + +Fix the order of variables in the printf() call. + +Fixes: 518fee8bfaf2 ("selftests/bpf: make veristat skip non-BPF and failing-to-open BPF objects") +Tested-by: Eduard Zingerman +Signed-off-by: Puranjay Mohan +Link: https://lore.kernel.org/r/20251231221052.759396-1-puranjay@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/bpf/veristat.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/testing/selftests/bpf/veristat.c b/tools/testing/selftests/bpf/veristat.c +index 7b6b9c4cadb57..e9d7acff6bbbc 100644 +--- a/tools/testing/selftests/bpf/veristat.c ++++ b/tools/testing/selftests/bpf/veristat.c +@@ -1424,7 +1424,7 @@ static void output_stats(const struct verif_stats *s, enum resfmt fmt, bool last + if (last && fmt == RESFMT_TABLE) { + output_header_underlines(); + printf("Done. Processed %d files, %d programs. Skipped %d files, %d programs.\n", +- env.files_processed, env.files_skipped, env.progs_processed, env.progs_skipped); ++ env.files_processed, env.progs_processed, env.files_skipped, env.progs_skipped); + } + } + +-- +2.51.0 + diff --git a/queue-6.12/selftests-mm-convert-page_size-to-unsigned-long.patch b/queue-6.12/selftests-mm-convert-page_size-to-unsigned-long.patch new file mode 100644 index 0000000000..5768a882fe --- /dev/null +++ b/queue-6.12/selftests-mm-convert-page_size-to-unsigned-long.patch @@ -0,0 +1,90 @@ +From 778d826b562463d7b12d0beb2e30de8195179359 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 3 Apr 2025 15:43:45 +0530 +Subject: selftests/mm: convert page_size to unsigned long + +From: Siddarth G + +[ Upstream commit 0bf19a357e0eaf03e757ac9482c45a797e40157a ] + +Cppcheck warning: +int result is assigned to long long variable. If the variable is long long +to avoid loss of information, then you have loss of information. + +This patch changes the type of page_size from 'unsigned int' to +'unsigned long' instead of using ULL suffixes. Changing hpage_size to +'unsigned long' was considered, but since gethugepage() expects an int, +this change was avoided. + +Link: https://lkml.kernel.org/r/20250403101345.29226-1-siddarthsgml@gmail.com +Signed-off-by: Siddarth G +Reported-by: David Binderman +Closes: https://lore.kernel.org/all/AS8PR02MB10217315060BBFDB21F19643E9CA62@AS8PR02MB10217.eurprd02.prod.outlook.com/ +Signed-off-by: Andrew Morton +Stable-dep-of: 7e938f00b003 ("selftests/mm: fix faulting-in code in pagemap_ioctl test") +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/mm/pagemap_ioctl.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/tools/testing/selftests/mm/pagemap_ioctl.c b/tools/testing/selftests/mm/pagemap_ioctl.c +index c3b0f6bf9d0b2..805017fd9bdbf 100644 +--- a/tools/testing/selftests/mm/pagemap_ioctl.c ++++ b/tools/testing/selftests/mm/pagemap_ioctl.c +@@ -34,7 +34,7 @@ + #define PAGEMAP "/proc/self/pagemap" + int pagemap_fd; + int uffd; +-unsigned int page_size; ++unsigned long page_size; + unsigned int hpage_size; + const char *progname; + +@@ -184,7 +184,7 @@ void *gethugetlb_mem(int size, int *shmid) + + int userfaultfd_tests(void) + { +- int mem_size, vec_size, written, num_pages = 16; ++ long mem_size, vec_size, written, num_pages = 16; + char *mem, *vec; + + mem_size = num_pages * page_size; +@@ -213,7 +213,7 @@ int userfaultfd_tests(void) + written = pagemap_ioctl(mem, mem_size, vec, 1, PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, + vec_size - 2, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN); + if (written < 0) +- ksft_exit_fail_msg("error %d %d %s\n", written, errno, strerror(errno)); ++ ksft_exit_fail_msg("error %ld %d %s\n", written, errno, strerror(errno)); + + ksft_test_result(written == 0, "%s all new pages must not be written (dirty)\n", __func__); + +@@ -995,7 +995,7 @@ int unmapped_region_tests(void) + { + void *start = (void *)0x10000000; + int written, len = 0x00040000; +- int vec_size = len / page_size; ++ long vec_size = len / page_size; + struct page_region *vec = malloc(sizeof(struct page_region) * vec_size); + + /* 1. Get written pages */ +@@ -1051,7 +1051,7 @@ static void test_simple(void) + int sanity_tests(void) + { + unsigned long long mem_size, vec_size; +- int ret, fd, i, buf_size; ++ long ret, fd, i, buf_size; + struct page_region *vec; + char *mem, *fmem; + struct stat sbuf; +@@ -1160,7 +1160,7 @@ int sanity_tests(void) + + ret = stat(progname, &sbuf); + if (ret < 0) +- ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); ++ ksft_exit_fail_msg("error %ld %d %s\n", ret, errno, strerror(errno)); + + fmem = mmap(NULL, sbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (fmem == MAP_FAILED) +-- +2.51.0 + diff --git a/queue-6.12/selftests-mm-fix-faulting-in-code-in-pagemap_ioctl-t.patch b/queue-6.12/selftests-mm-fix-faulting-in-code-in-pagemap_ioctl-t.patch new file mode 100644 index 0000000000..4a04698236 --- /dev/null +++ b/queue-6.12/selftests-mm-fix-faulting-in-code-in-pagemap_ioctl-t.patch @@ -0,0 +1,80 @@ +From 34073d07beb1eaf3b9d9fc3da363f048d438ccc8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 17:02:22 +0000 +Subject: selftests/mm: fix faulting-in code in pagemap_ioctl test + +From: Kevin Brodsky + +[ Upstream commit 7e938f00b00319510ae097e20b7487dfa578d53f ] + +One of the pagemap_ioctl tests attempts to fault in pages by memcpy()'ing +them to an unused buffer. This probably worked originally, but since +commit 46036188ea1f ("selftests/mm: build with -O2") the compiler is free +to optimise away that unused buffer and the memcpy() with it. As a result +there might not be any resident page in the mapping and the test may fail. + +We don't need to copy all that memory anyway. Just fault in every page. + +While at it also make sure to compute the number of pages once using +simple integer arithmetic instead of ceilf() and implicit conversions. + +Link: https://lkml.kernel.org/r/20260122170224.4056513-8-kevin.brodsky@arm.com +Fixes: 46036188ea1f ("selftests/mm: build with -O2") +Signed-off-by: Kevin Brodsky +Acked-by: David Hildenbrand (Red Hat) +Reviewed-by: Dev Jain +Reviewed-by: Muhammad Usama Anjum +Cc: Jason Gunthorpe +Cc: John Hubbard +Cc: Lorenzo Stoakes +Cc: Mark Brown +Cc: Paolo Abeni +Cc: Ryan Roberts +Cc: SeongJae Park +Cc: Shuah Khan +Cc: wang lian +Cc: Yunsheng Lin +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/mm/pagemap_ioctl.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/tools/testing/selftests/mm/pagemap_ioctl.c b/tools/testing/selftests/mm/pagemap_ioctl.c +index 805017fd9bdbf..c0e4b6a57ce55 100644 +--- a/tools/testing/selftests/mm/pagemap_ioctl.c ++++ b/tools/testing/selftests/mm/pagemap_ioctl.c +@@ -1051,11 +1051,10 @@ static void test_simple(void) + int sanity_tests(void) + { + unsigned long long mem_size, vec_size; +- long ret, fd, i, buf_size; ++ long ret, fd, i, buf_size, nr_pages; + struct page_region *vec; + char *mem, *fmem; + struct stat sbuf; +- char *tmp_buf; + + /* 1. wrong operation */ + mem_size = 10 * page_size; +@@ -1166,14 +1165,14 @@ int sanity_tests(void) + if (fmem == MAP_FAILED) + ksft_exit_fail_msg("error nomem %d %s\n", errno, strerror(errno)); + +- tmp_buf = malloc(sbuf.st_size); +- memcpy(tmp_buf, fmem, sbuf.st_size); ++ nr_pages = (sbuf.st_size + page_size - 1) / page_size; ++ force_read_pages(fmem, nr_pages, page_size); + + ret = pagemap_ioctl(fmem, sbuf.st_size, vec, vec_size, 0, 0, + 0, PAGEMAP_NON_WRITTEN_BITS, 0, PAGEMAP_NON_WRITTEN_BITS); + + ksft_test_result(ret >= 0 && vec[0].start == (uintptr_t)fmem && +- LEN(vec[0]) == ceilf((float)sbuf.st_size/page_size) && ++ LEN(vec[0]) == nr_pages && + (vec[0].categories & PAGE_IS_FILE), + "%s Memory mapped file\n", __func__); + +-- +2.51.0 + diff --git a/queue-6.12/selftests-mm-pagemap_ioctl-fix-types-mismatches-show.patch b/queue-6.12/selftests-mm-pagemap_ioctl-fix-types-mismatches-show.patch new file mode 100644 index 0000000000..8ce7a8802e --- /dev/null +++ b/queue-6.12/selftests-mm-pagemap_ioctl-fix-types-mismatches-show.patch @@ -0,0 +1,406 @@ +From 474b179305b19dc1fc48efa0f101df4efbb418e1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Dec 2024 23:56:22 +0500 +Subject: selftests/mm: pagemap_ioctl: Fix types mismatches shown by compiler + options + +From: Muhammad Usama Anjum + +[ Upstream commit 43448e5bbbad1fb168b728b8a7c0058ab1397375 ] + +Fix following warnings caught by compiler: + +- There are several type mismatches among different variables. +- Remove unused variable warnings. + +Link: https://lkml.kernel.org/r/20241209185624.2245158-3-usama.anjum@collabora.com +Signed-off-by: Muhammad Usama Anjum +Signed-off-by: Andrew Morton +Stable-dep-of: 7e938f00b003 ("selftests/mm: fix faulting-in code in pagemap_ioctl test") +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/mm/pagemap_ioctl.c | 108 +++++++++++---------- + tools/testing/selftests/mm/vm_util.c | 2 +- + 2 files changed, 59 insertions(+), 51 deletions(-) + +diff --git a/tools/testing/selftests/mm/pagemap_ioctl.c b/tools/testing/selftests/mm/pagemap_ioctl.c +index bcc73b4e805c6..c3b0f6bf9d0b2 100644 +--- a/tools/testing/selftests/mm/pagemap_ioctl.c ++++ b/tools/testing/selftests/mm/pagemap_ioctl.c +@@ -34,8 +34,8 @@ + #define PAGEMAP "/proc/self/pagemap" + int pagemap_fd; + int uffd; +-int page_size; +-int hpage_size; ++unsigned int page_size; ++unsigned int hpage_size; + const char *progname; + + #define LEN(region) ((region.end - region.start)/page_size) +@@ -235,7 +235,9 @@ int get_reads(struct page_region *vec, int vec_size) + + int sanity_tests_sd(void) + { +- int mem_size, vec_size, ret, ret2, ret3, i, num_pages = 1000, total_pages = 0; ++ unsigned long long mem_size, vec_size, i, total_pages = 0; ++ long ret, ret2, ret3; ++ int num_pages = 1000; + int total_writes, total_reads, reads, count; + struct page_region *vec, *vec2; + char *mem, *m[2]; +@@ -321,9 +323,9 @@ int sanity_tests_sd(void) + ret = pagemap_ioctl(mem, mem_size, vec, vec_size, 0, 0, PAGE_IS_WRITTEN, 0, + 0, PAGE_IS_WRITTEN); + if (ret < 0) +- ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); ++ ksft_exit_fail_msg("error %ld %d %s\n", ret, errno, strerror(errno)); + +- ksft_test_result(ret == mem_size/(page_size * 2), ++ ksft_test_result((unsigned long long)ret == mem_size/(page_size * 2), + "%s Repeated pattern of written and non-written pages\n", __func__); + + /* 4. Repeated pattern of written and non-written pages in parts */ +@@ -331,21 +333,21 @@ int sanity_tests_sd(void) + PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, + num_pages/2 - 2, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN); + if (ret < 0) +- ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); ++ ksft_exit_fail_msg("error %ld %d %s\n", ret, errno, strerror(errno)); + + ret2 = pagemap_ioctl(mem, mem_size, vec, 2, 0, 0, PAGE_IS_WRITTEN, 0, 0, + PAGE_IS_WRITTEN); + if (ret2 < 0) +- ksft_exit_fail_msg("error %d %d %s\n", ret2, errno, strerror(errno)); ++ ksft_exit_fail_msg("error %ld %d %s\n", ret2, errno, strerror(errno)); + + ret3 = pagemap_ioctl(mem, mem_size, vec, vec_size, + PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, + 0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN); + if (ret3 < 0) +- ksft_exit_fail_msg("error %d %d %s\n", ret3, errno, strerror(errno)); ++ ksft_exit_fail_msg("error %ld %d %s\n", ret3, errno, strerror(errno)); + + ksft_test_result((ret + ret3) == num_pages/2 && ret2 == 2, +- "%s Repeated pattern of written and non-written pages in parts %d %d %d\n", ++ "%s Repeated pattern of written and non-written pages in parts %ld %ld %ld\n", + __func__, ret, ret3, ret2); + + /* 5. Repeated pattern of written and non-written pages max_pages */ +@@ -357,13 +359,13 @@ int sanity_tests_sd(void) + PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, + num_pages/2, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN); + if (ret < 0) +- ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); ++ ksft_exit_fail_msg("error %ld %d %s\n", ret, errno, strerror(errno)); + + ret2 = pagemap_ioctl(mem, mem_size, vec, vec_size, + PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, + 0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN); + if (ret2 < 0) +- ksft_exit_fail_msg("error %d %d %s\n", ret2, errno, strerror(errno)); ++ ksft_exit_fail_msg("error %ld %d %s\n", ret2, errno, strerror(errno)); + + ksft_test_result(ret == num_pages/2 && ret2 == 1, + "%s Repeated pattern of written and non-written pages max_pages\n", +@@ -378,12 +380,12 @@ int sanity_tests_sd(void) + PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, + 2, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN); + if (ret < 0) +- ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); ++ ksft_exit_fail_msg("error %ld %d %s\n", ret, errno, strerror(errno)); + + ret2 = pagemap_ioctl(mem, mem_size, vec2, vec_size, 0, 0, + PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN); + if (ret2 < 0) +- ksft_exit_fail_msg("error %d %d %s\n", ret2, errno, strerror(errno)); ++ ksft_exit_fail_msg("error %ld %d %s\n", ret2, errno, strerror(errno)); + + ksft_test_result(ret == 1 && LEN(vec[0]) == 2 && + vec[0].start == (uintptr_t)(mem + page_size) && +@@ -416,7 +418,7 @@ int sanity_tests_sd(void) + ret = pagemap_ioctl(m[1], mem_size, vec, 1, 0, 0, PAGE_IS_WRITTEN, 0, 0, + PAGE_IS_WRITTEN); + if (ret < 0) +- ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); ++ ksft_exit_fail_msg("error %ld %d %s\n", ret, errno, strerror(errno)); + + ksft_test_result(ret == 1 && LEN(vec[0]) == mem_size/page_size, + "%s Two regions\n", __func__); +@@ -448,7 +450,7 @@ int sanity_tests_sd(void) + PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, 0, + PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN); + if (ret < 0) +- ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); ++ ksft_exit_fail_msg("error %ld %d %s\n", ret, errno, strerror(errno)); + + for (i = 0; i < mem_size/page_size; i += 2) + mem[i * page_size]++; +@@ -457,7 +459,7 @@ int sanity_tests_sd(void) + PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, + mem_size/(page_size*5), PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN); + if (ret < 0) +- ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); ++ ksft_exit_fail_msg("error %ld %d %s\n", ret, errno, strerror(errno)); + + total_pages += ret; + +@@ -465,7 +467,7 @@ int sanity_tests_sd(void) + PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, + mem_size/(page_size*5), PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN); + if (ret < 0) +- ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); ++ ksft_exit_fail_msg("error %ld %d %s\n", ret, errno, strerror(errno)); + + total_pages += ret; + +@@ -473,7 +475,7 @@ int sanity_tests_sd(void) + PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, + mem_size/(page_size*5), PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN); + if (ret < 0) +- ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); ++ ksft_exit_fail_msg("error %ld %d %s\n", ret, errno, strerror(errno)); + + total_pages += ret; + +@@ -515,9 +517,9 @@ int sanity_tests_sd(void) + vec_size, PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, + 0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end); + if (ret < 0) +- ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); ++ ksft_exit_fail_msg("error %ld %d %s\n", ret, errno, strerror(errno)); + +- if (ret > vec_size) ++ if ((unsigned long)ret > vec_size) + break; + + reads = get_reads(vec, ret); +@@ -554,63 +556,63 @@ int sanity_tests_sd(void) + ret = pagemap_ioc(mem, 0, vec, vec_size, 0, + 0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end); + if (ret < 0) +- ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); ++ ksft_exit_fail_msg("error %ld %d %s\n", ret, errno, strerror(errno)); + ksft_test_result(ret == 0 && walk_end == (long)mem, + "Walk_end: Same start and end address\n"); + + ret = pagemap_ioc(mem, 0, vec, vec_size, PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, + 0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end); + if (ret < 0) +- ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); ++ ksft_exit_fail_msg("error %ld %d %s\n", ret, errno, strerror(errno)); + ksft_test_result(ret == 0 && walk_end == (long)mem, + "Walk_end: Same start and end with WP\n"); + + ret = pagemap_ioc(mem, 0, vec, 0, PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, + 0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end); + if (ret < 0) +- ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); ++ ksft_exit_fail_msg("error %ld %d %s\n", ret, errno, strerror(errno)); + ksft_test_result(ret == 0 && walk_end == (long)mem, + "Walk_end: Same start and end with 0 output buffer\n"); + + ret = pagemap_ioc(mem, mem_size, vec, vec_size, 0, + 0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end); + if (ret < 0) +- ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); ++ ksft_exit_fail_msg("error %ld %d %s\n", ret, errno, strerror(errno)); + ksft_test_result(ret == 1 && walk_end == (long)(mem + mem_size), + "Walk_end: Big vec\n"); + + ret = pagemap_ioc(mem, mem_size, vec, 1, 0, + 0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end); + if (ret < 0) +- ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); ++ ksft_exit_fail_msg("error %ld %d %s\n", ret, errno, strerror(errno)); + ksft_test_result(ret == 1 && walk_end == (long)(mem + mem_size), + "Walk_end: vec of minimum length\n"); + + ret = pagemap_ioc(mem, mem_size, vec, 1, 0, + vec_size, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end); + if (ret < 0) +- ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); ++ ksft_exit_fail_msg("error %ld %d %s\n", ret, errno, strerror(errno)); + ksft_test_result(ret == 1 && walk_end == (long)(mem + mem_size), + "Walk_end: Max pages specified\n"); + + ret = pagemap_ioc(mem, mem_size, vec, vec_size, 0, + vec_size/2, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end); + if (ret < 0) +- ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); ++ ksft_exit_fail_msg("error %ld %d %s\n", ret, errno, strerror(errno)); + ksft_test_result(ret == 1 && walk_end == (long)(mem + mem_size/2), + "Walk_end: Half max pages\n"); + + ret = pagemap_ioc(mem, mem_size, vec, vec_size, 0, + 1, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end); + if (ret < 0) +- ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); ++ ksft_exit_fail_msg("error %ld %d %s\n", ret, errno, strerror(errno)); + ksft_test_result(ret == 1 && walk_end == (long)(mem + page_size), + "Walk_end: 1 max page\n"); + + ret = pagemap_ioc(mem, mem_size, vec, vec_size, 0, + -1, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end); + if (ret < 0) +- ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); ++ ksft_exit_fail_msg("error %ld %d %s\n", ret, errno, strerror(errno)); + ksft_test_result(ret == 1 && walk_end == (long)(mem + mem_size), + "Walk_end: max pages\n"); + +@@ -621,49 +623,49 @@ int sanity_tests_sd(void) + ret = pagemap_ioc(mem, mem_size, vec, vec_size, 0, + 0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end); + if (ret < 0) +- ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); +- ksft_test_result(ret == vec_size/2 && walk_end == (long)(mem + mem_size), ++ ksft_exit_fail_msg("error %ld %d %s\n", ret, errno, strerror(errno)); ++ ksft_test_result((unsigned long)ret == vec_size/2 && walk_end == (long)(mem + mem_size), + "Walk_end sparse: Big vec\n"); + + ret = pagemap_ioc(mem, mem_size, vec, 1, 0, + 0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end); + if (ret < 0) +- ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); ++ ksft_exit_fail_msg("error %ld %d %s\n", ret, errno, strerror(errno)); + ksft_test_result(ret == 1 && walk_end == (long)(mem + page_size * 2), + "Walk_end sparse: vec of minimum length\n"); + + ret = pagemap_ioc(mem, mem_size, vec, 1, 0, + vec_size, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end); + if (ret < 0) +- ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); ++ ksft_exit_fail_msg("error %ld %d %s\n", ret, errno, strerror(errno)); + ksft_test_result(ret == 1 && walk_end == (long)(mem + page_size * 2), + "Walk_end sparse: Max pages specified\n"); + + ret = pagemap_ioc(mem, mem_size, vec, vec_size/2, 0, + vec_size, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end); + if (ret < 0) +- ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); +- ksft_test_result(ret == vec_size/2 && walk_end == (long)(mem + mem_size), ++ ksft_exit_fail_msg("error %ld %d %s\n", ret, errno, strerror(errno)); ++ ksft_test_result((unsigned long)ret == vec_size/2 && walk_end == (long)(mem + mem_size), + "Walk_end sparse: Max pages specified\n"); + + ret = pagemap_ioc(mem, mem_size, vec, vec_size, 0, + vec_size, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end); + if (ret < 0) +- ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); +- ksft_test_result(ret == vec_size/2 && walk_end == (long)(mem + mem_size), ++ ksft_exit_fail_msg("error %ld %d %s\n", ret, errno, strerror(errno)); ++ ksft_test_result((unsigned long)ret == vec_size/2 && walk_end == (long)(mem + mem_size), + "Walk_end sparse: Max pages specified\n"); + + ret = pagemap_ioc(mem, mem_size, vec, vec_size, 0, + vec_size/2, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end); + if (ret < 0) +- ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); +- ksft_test_result(ret == vec_size/2 && walk_end == (long)(mem + mem_size), ++ ksft_exit_fail_msg("error %ld %d %s\n", ret, errno, strerror(errno)); ++ ksft_test_result((unsigned long)ret == vec_size/2 && walk_end == (long)(mem + mem_size), + "Walk_endsparse : Half max pages\n"); + + ret = pagemap_ioc(mem, mem_size, vec, vec_size, 0, + 1, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end); + if (ret < 0) +- ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); ++ ksft_exit_fail_msg("error %ld %d %s\n", ret, errno, strerror(errno)); + ksft_test_result(ret == 1 && walk_end == (long)(mem + page_size * 2), + "Walk_end: 1 max page\n"); + +@@ -674,9 +676,10 @@ int sanity_tests_sd(void) + return 0; + } + +-int base_tests(char *prefix, char *mem, int mem_size, int skip) ++int base_tests(char *prefix, char *mem, unsigned long long mem_size, int skip) + { +- int vec_size, written; ++ unsigned long long vec_size; ++ int written; + struct page_region *vec, *vec2; + + if (skip) { +@@ -799,8 +802,8 @@ int hpage_unit_tests(void) + char *map; + int ret, ret2; + size_t num_pages = 10; +- int map_size = hpage_size * num_pages; +- int vec_size = map_size/page_size; ++ unsigned long long map_size = hpage_size * num_pages; ++ unsigned long long vec_size = map_size/page_size; + struct page_region *vec, *vec2; + + vec = malloc(sizeof(struct page_region) * vec_size); +@@ -1047,7 +1050,8 @@ static void test_simple(void) + + int sanity_tests(void) + { +- int mem_size, vec_size, ret, fd, i, buf_size; ++ unsigned long long mem_size, vec_size; ++ int ret, fd, i, buf_size; + struct page_region *vec; + char *mem, *fmem; + struct stat sbuf; +@@ -1312,7 +1316,9 @@ static ssize_t get_dirty_pages_reset(char *mem, unsigned int count, + { + struct pm_scan_arg arg = {0}; + struct page_region rgns[256]; +- int i, j, cnt, ret; ++ unsigned long long i, j; ++ long ret; ++ int cnt; + + arg.size = sizeof(struct pm_scan_arg); + arg.start = (uintptr_t)mem; +@@ -1330,7 +1336,7 @@ static ssize_t get_dirty_pages_reset(char *mem, unsigned int count, + ksft_exit_fail_msg("ioctl failed\n"); + + cnt = 0; +- for (i = 0; i < ret; ++i) { ++ for (i = 0; i < (unsigned long)ret; ++i) { + if (rgns[i].categories != PAGE_IS_WRITTEN) + ksft_exit_fail_msg("wrong flags\n"); + +@@ -1384,9 +1390,10 @@ void *thread_proc(void *mem) + static void transact_test(int page_size) + { + unsigned int i, count, extra_pages; ++ unsigned int c; + pthread_t th; + char *mem; +- int ret, c; ++ int ret; + + if (pthread_barrier_init(&start_barrier, NULL, nthreads + 1)) + ksft_exit_fail_msg("pthread_barrier_init\n"); +@@ -1473,9 +1480,10 @@ static void transact_test(int page_size) + extra_thread_faults); + } + +-int main(int argc, char *argv[]) ++int main(int __attribute__((unused)) argc, char *argv[]) + { +- int mem_size, shmid, buf_size, fd, i, ret; ++ int shmid, buf_size, fd, i, ret; ++ unsigned long long mem_size; + char *mem, *map, *fmem; + struct stat sbuf; + +diff --git a/tools/testing/selftests/mm/vm_util.c b/tools/testing/selftests/mm/vm_util.c +index a4a2805d3d3e7..4fa66a50e81a4 100644 +--- a/tools/testing/selftests/mm/vm_util.c ++++ b/tools/testing/selftests/mm/vm_util.c +@@ -138,7 +138,7 @@ void clear_softdirty(void) + ksft_exit_fail_msg("opening clear_refs failed\n"); + ret = write(fd, ctrl, strlen(ctrl)); + close(fd); +- if (ret != strlen(ctrl)) ++ if (ret != (signed int)strlen(ctrl)) + ksft_exit_fail_msg("writing clear_refs failed\n"); + } + +-- +2.51.0 + diff --git a/queue-6.12/serial-caif-fix-use-after-free-in-caif_serial-ldisc_.patch b/queue-6.12/serial-caif-fix-use-after-free-in-caif_serial-ldisc_.patch new file mode 100644 index 0000000000..ca07b3a9b5 --- /dev/null +++ b/queue-6.12/serial-caif-fix-use-after-free-in-caif_serial-ldisc_.patch @@ -0,0 +1,152 @@ +From 7ae747d1e0064bbfd3445c12dd2d52e8689fc018 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 15:44:44 +0800 +Subject: serial: caif: fix use-after-free in caif_serial ldisc_close() + +From: Jiayuan Chen + +[ Upstream commit 308e7e4d0a846359685f40aade023aee7b27284c ] + +There is a use-after-free bug in caif_serial where handle_tx() may +access ser->tty after the tty has been freed. + +The race condition occurs between ldisc_close() and packet transmission: + + CPU 0 (close) CPU 1 (xmit) + ------------- ------------ + ldisc_close() + tty_kref_put(ser->tty) + [tty may be freed here] + <-- race window --> + caif_xmit() + handle_tx() + tty = ser->tty // dangling ptr + tty->ops->write() // UAF! + schedule_work() + ser_release() + unregister_netdevice() + +The root cause is that tty_kref_put() is called in ldisc_close() while +the network device is still active and can receive packets. + +Since ser and tty have a 1:1 binding relationship with consistent +lifecycles (ser is allocated in ldisc_open and freed in ser_release +via unregister_netdevice, and each ser binds exactly one tty), we can +safely defer the tty reference release to ser_release() where the +network device is unregistered. + +Fix this by moving tty_kref_put() from ldisc_close() to ser_release(), +after unregister_netdevice(). This ensures the tty reference is held +as long as the network device exists, preventing the UAF. + +Note: We save ser->tty before unregister_netdevice() because ser is +embedded in netdev's private data and will be freed along with netdev +(needs_free_netdev = true). + +How to reproduce: Add mdelay(500) at the beginning of ldisc_close() +to widen the race window, then run the reproducer program [1]. + +Note: There is a separate deadloop issue in handle_tx() when using +PORT_UNKNOWN serial ports (e.g., /dev/ttyS3 in QEMU without proper +serial backend). This deadloop exists even without this patch, +and is likely caused by inconsistency between uart_write_room() and +uart_write() in serial core. It has been addressed in a separate +patch [2]. + +KASAN report: + +================================================================== +BUG: KASAN: slab-use-after-free in handle_tx+0x5d1/0x620 +Read of size 1 at addr ffff8881131e1490 by task caif_uaf_trigge/9929 + +Call Trace: + + dump_stack_lvl+0x10e/0x1f0 + print_report+0xd0/0x630 + kasan_report+0xe4/0x120 + handle_tx+0x5d1/0x620 + dev_hard_start_xmit+0x9d/0x6c0 + __dev_queue_xmit+0x6e2/0x4410 + packet_xmit+0x243/0x360 + packet_sendmsg+0x26cf/0x5500 + __sys_sendto+0x4a3/0x520 + __x64_sys_sendto+0xe0/0x1c0 + do_syscall_64+0xc9/0xf80 + entry_SYSCALL_64_after_hwframe+0x77/0x7f +RIP: 0033:0x7f615df2c0d7 + +Allocated by task 9930: + +Freed by task 64: + +Last potentially related work creation: + +The buggy address belongs to the object at ffff8881131e1000 + which belongs to the cache kmalloc-cg-2k of size 2048 +The buggy address is located 1168 bytes inside of + freed 2048-byte region [ffff8881131e1000, ffff8881131e1800) + +The buggy address belongs to the physical page: +page_owner tracks the page as allocated +page last free pid 9778 tgid 9778 stack trace: + +Memory state around the buggy address: + ffff8881131e1380: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb + ffff8881131e1400: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb +>ffff8881131e1480: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb + ^ + ffff8881131e1500: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb + ffff8881131e1580: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb +================================================================== +[1]: https://gist.github.com/mrpre/f683f244544f7b11e7fa87df9e6c2eeb +[2]: https://lore.kernel.org/linux-serial/20260204074327.226165-1-jiayuan.chen@linux.dev/T/#u + +Reported-by: syzbot+827272712bd6d12c79a4@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/000000000000a4a7550611e234f5@google.com/T/ +Fixes: 56e0ef527b18 ("drivers/net: caif: fix wrong rtnl_is_locked() usage") +Reviewed-by: Greg Kroah-Hartman +Signed-off-by: Jiayuan Chen +Reviewed-by: Jijie Shao +Link: https://patch.msgid.link/20260206074450.154267-1-jiayuan.chen@linux.dev +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/caif/caif_serial.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c +index ed3a589def6b1..699ed0ff461e8 100644 +--- a/drivers/net/caif/caif_serial.c ++++ b/drivers/net/caif/caif_serial.c +@@ -298,6 +298,7 @@ static void ser_release(struct work_struct *work) + { + struct list_head list; + struct ser_device *ser, *tmp; ++ struct tty_struct *tty; + + spin_lock(&ser_lock); + list_replace_init(&ser_release_list, &list); +@@ -306,9 +307,11 @@ static void ser_release(struct work_struct *work) + if (!list_empty(&list)) { + rtnl_lock(); + list_for_each_entry_safe(ser, tmp, &list, node) { ++ tty = ser->tty; + dev_close(ser->dev); + unregister_netdevice(ser->dev); + debugfs_deinit(ser); ++ tty_kref_put(tty); + } + rtnl_unlock(); + } +@@ -369,8 +372,6 @@ static void ldisc_close(struct tty_struct *tty) + { + struct ser_device *ser = tty->disc_data; + +- tty_kref_put(ser->tty); +- + spin_lock(&ser_lock); + list_move(&ser->node, &ser_release_list); + spin_unlock(&ser_lock); +-- +2.51.0 + diff --git a/queue-6.12/serial-imx-change-serial_imx_console-to-bool.patch b/queue-6.12/serial-imx-change-serial_imx_console-to-bool.patch new file mode 100644 index 0000000000..1539e5d5ae --- /dev/null +++ b/queue-6.12/serial-imx-change-serial_imx_console-to-bool.patch @@ -0,0 +1,50 @@ +From 3a0906a16c3dac2d5da73579152a6a832cf0bcba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 10 Jan 2026 15:26:40 -0800 +Subject: serial: imx: change SERIAL_IMX_CONSOLE to bool + +From: Randy Dunlap + +[ Upstream commit 79527d86ba91c2d9354832d19fd12b3baa66bd10 ] + +SERIAL_IMX_CONSOLE is a build option for the imx driver (SERIAL_IMX). +It does not build a separate console driver file, so it can't be built +as a module since it isn't built at all. + +Change the Kconfig symbol from tristate to bool and update the help +text accordingly. + +Fixes: 0db4f9b91c86 ("tty: serial: imx: enable imx serial console port as module") +Signed-off-by: Randy Dunlap +Link: https://patch.msgid.link/20260110232643.3533351-2-rdunlap@infradead.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/Kconfig | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig +index 4fd789a77a13b..09987529b8ba4 100644 +--- a/drivers/tty/serial/Kconfig ++++ b/drivers/tty/serial/Kconfig +@@ -482,14 +482,14 @@ config SERIAL_IMX + can enable its onboard serial port by enabling this option. + + config SERIAL_IMX_CONSOLE +- tristate "Console on IMX serial port" ++ bool "Console on IMX serial port" + depends on SERIAL_IMX + select SERIAL_CORE_CONSOLE + help + If you have enabled the serial port on the Freescale IMX +- CPU you can make it the console by answering Y/M to this option. ++ CPU you can make it the console by answering Y to this option. + +- Even if you say Y/M here, the currently visible virtual console ++ Even if you say Y here, the currently visible virtual console + (/dev/tty0) will still be used as the system console by default, but + you can alter that using a kernel command line option such as + "console=ttymxc0". (Try "man bootparam" or see the documentation of +-- +2.51.0 + diff --git a/queue-6.12/serial-sh_sci-improve-dma-support-prompt.patch b/queue-6.12/serial-sh_sci-improve-dma-support-prompt.patch new file mode 100644 index 0000000000..54e850a312 --- /dev/null +++ b/queue-6.12/serial-sh_sci-improve-dma-support-prompt.patch @@ -0,0 +1,39 @@ +From e23382362784fa47db6ad6f7643e7c9a6340a23b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 10 Jan 2026 15:26:43 -0800 +Subject: serial: SH_SCI: improve "DMA support" prompt + +From: Randy Dunlap + +[ Upstream commit 93bb95a11238d66a4c9aa6eabf9774b073a5895c ] + +Having a prompt of "DMA support" suddenly appear during a +"make oldconfig" can be confusing. Add a little helpful text to +the prompt message. + +Fixes: 73a19e4c0301 ("serial: sh-sci: Add DMA support.") +Signed-off-by: Randy Dunlap +Reviewed-by: Geert Uytterhoeven +Link: https://patch.msgid.link/20260110232643.3533351-5-rdunlap@infradead.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig +index 09987529b8ba4..1e92b16b6b95e 100644 +--- a/drivers/tty/serial/Kconfig ++++ b/drivers/tty/serial/Kconfig +@@ -667,7 +667,7 @@ config SERIAL_SH_SCI_EARLYCON + default ARCH_RENESAS + + config SERIAL_SH_SCI_DMA +- bool "DMA support" if EXPERT ++ bool "Support for DMA on SuperH SCI(F)" if EXPERT + depends on SERIAL_SH_SCI && DMA_ENGINE + default ARCH_RENESAS + +-- +2.51.0 + diff --git a/queue-6.12/series b/queue-6.12/series index 0b63edc9fd..b5b2f435a4 100644 --- a/queue-6.12/series +++ b/queue-6.12/series @@ -1,2 +1,364 @@ rdma-siw-fix-potential-null-pointer-dereference-in-header-processing.patch rdma-umad-reject-negative-data_len-in-ib_umad_write.patch +auxdisplay-arm-charlcd-fix-release_mem_region-size.patch +hfsplus-return-error-when-node-already-exists-in-hfs.patch +rcu-refactor-expedited-handling-check-in-rcu_read_un.patch +rcu-remove-local_irq_save-restore-in-rcu_preempt_def.patch +rcu-fix-rcu_read_unlock-deadloop-due-to-softirq.patch +audit-move-the-compat_xxx_class-extern-declarations-.patch +i3c-move-device-name-assignment-after-i3c_bus_init.patch +fs-add-linux-init_task.h-for-init_fs.patch +i3c-master-update-hot-join-flag-only-on-success.patch +gfs2-retries-missing-in-gfs2_-rename-exchange.patch +gfs2-fix-slab-use-after-free-in-qd_put.patch +gfs2-fix-use-after-free-in-iomap-inline-data-write-p.patch +i3c-dw-initialize-spinlock-to-avoid-upsetting-lockde.patch +i3c-dw-fix-memory-leak-in-dw_i3c_master_i2c_xfers.patch +tpm-tpm_i2c_infineon-fix-locality-leak-on-get_burstc.patch +tpm-st33zp24-fix-missing-cleanup-on-get_burstcount-e.patch +erofs-get-rid-of-raw-bi_end_io-usage.patch +erofs-handle-end-of-filesystem-properly-for-file-bac.patch +btrfs-qgroup-return-correct-error-when-deleting-qgro.patch +btrfs-fix-block_group_tree-dirty_list-corruption.patch +smb-client-fix-potential-uaf-and-double-free-in-smb2.patch +block-add-a-bio_add_virt_nofail-helper.patch +rnbd-srv-use-bio_add_virt_nofail.patch +rnbd-srv-fix-server-side-setting-of-bi_size-for-spec.patch +xen-virtio-don-t-use-grant-dma-ops-when-running-as-d.patch +io_uring-use-release-acquire-ordering-for-ioring_set.patch +acpica-fix-null-pointer-dereference-in-acpi_ev_addre.patch +io_uring-sync-validate-passed-in-offset.patch +cpuidle-governors-menu-always-check-timers-with-tick.patch +thermal-intel-x86_pkg_temp_thermal-handle-invalid-te.patch +md-raid5-fix-raid5_run-to-return-error-when-log_init.patch +md-raid10-fix-any_working-flag-handling-in-raid10_sy.patch +opp-return-correct-value-in-dev_pm_opp_get_level.patch +cpufreq-scmi-correct-scmi-explanation.patch +cpufreq-scmi-fix-device_node-reference-leak-in-scmi_.patch +iomap-fix-submission-side-handling-of-completion-sid.patch +thermal-of-fix-reference-leak-in-thermal_of_cm_looku.patch +ublk-validate-sqe128-flag-before-accessing-the-cmd.patch +partial-revert-x86-xen-fix-balloon-target-initializa.patch +md-raid1-fix-memory-leak-in-raid1_run-if-no-active-r.patch +md-raid1-fix-memory-leak-in-raid1_run.patch +pm-wakeup-handle-empty-list-in-wakeup_sources_walk_s.patch +perf-arm_spe-properly-set-hw.state-on-failures.patch +cpufreq-intel_pstate-enable-asym-capacity-only-when-.patch +pm-sleep-wakeirq-harden-dev_pm_clear_wake_irq-agains.patch +s390-cio-fix-device-lifecycle-handling-in-css_alloc_.patch +perf-x86-core-do-not-set-bit-width-for-unavailable-c.patch +crypto-qat-fix-warning-on-adf_pfvf_pf_proto.c.patch +selftests-bpf-veristat-fix-printing-order-in-output_.patch +libbpf-fix-oob-read-in-btf_dump_get_bitfield_value.patch +arm-vdso-patch-out-__vdso_clock_getres-if-unavailabl.patch +crypto-cavium-fix-dma_free_coherent-size.patch +crypto-octeontx-fix-dma_free_coherent-size.patch +crypto-hisilicon-zip-adjust-the-way-to-obtain-the-re.patch +crypto-hisilicon-hpre-extend-tag-field-to-64-bits-fo.patch +crypto-hisilicon-sec2-support-skcipher-aead-fallback.patch +bpf-preserve-id-of-register-in-sync_linked_regs.patch +selftests-bpf-fix-resource-leak-in-serial_test_wq-on.patch +hrtimer-fix-trace-oddity.patch +crypto-ccp-ensure-implicit-sev-snp-init-and-shutdown.patch +crypto-ccp-narrow-scope-of-snp_range_list.patch +bpf-sockmap-fix-incorrect-copied_seq-calculation.patch +bpf-sockmap-fix-fionread-for-sockmap.patch +tracing-add-a-comment-about-ftrace_regs-definition.patch +ftrace-make-ftrace_regs-abstract-from-direct-use.patch +ftrace-consolidate-ftrace_regs-accessor-functions-fo.patch +ftrace-use-arch_ftrace_regs-for-ftrace_regs_-macros.patch +ftrace-rename-ftrace_regs_return_value-to-ftrace_reg.patch +fgraph-replace-fgraph_ret_regs-with-ftrace_regs.patch +tracing-add-ftrace_partial_regs-for-converting-ftrac.patch +tracing-add-ftrace_fill_perf_regs-for-perf-event.patch +x86-fgraph-bpf-fix-stack-orc-unwind-from-kprobe_mult.patch +x86-fgraph-bpf-switch-kprobe_multi-program-stack-unw.patch +crypto-hisilicon-trng-support-tfms-sharing-the-devic.patch +crypto-caam-fix-netdev-memory-leak-in-dpaa2_caam_pro.patch +bpf-fix-bpf_xdp_store_bytes-proto-for-read-only-arg.patch +genirq-set-irqf_cond_oneshot-in-devm_request_irq.patch +platform-x86-int0002-remove-irqf_oneshot-from-reques.patch +bluetooth-btintel_pcie-use-irqf_oneshot-and-default-.patch +scsi-efct-use-irqf_oneshot-and-default-primary-handl.patch +edac-altera-remove-irqf_oneshot.patch +mfd-wm8350-core-use-irqf_oneshot.patch +media-pci-mg4b-use-irqf_no_thread.patch +sched-deadline-clear-the-defer-params.patch +sched-rt-skip-currently-executing-cpu-in-rto_next_cp.patch +fs-tests-exec-drop-duplicate-bprm_stack_limits-test-.patch +crypto-starfive-fix-memory-leak-in-starfive_aes_aead.patch +hwrng-core-allow-runtime-disabling-of-the-hw-rng.patch +hwrng-core-use-rcu-and-work_struct-to-fix-race-condi.patch +pstore-ram-fix-buffer-overflow-in-persistent_ram_sav.patch +soc-qcom-smem-handle-enomem-error-during-probe.patch +edac-i5000-fix-snprintf-size-calculation-in-calculat.patch +edac-i5400-fix-snprintf-limit-calculation-in-calcula.patch +firmware-arm_ffa-correct-32-bit-response-handling-in.patch +arm64-dts-tqma8mpql-mba8mpxl-fix-hdmi-cec-pad-contro.patch +arm64-dts-tqma8mpql-mba8mp-ras314-fix-hdmi-cec-pad-c.patch +clk-qcom-return-correct-error-code-in-qcom_cc_probe_.patch +arm64-dts-qcom-sdm630-fix-gpu_speed_bin-size.patch +arm64-dts-qcom-sdm845-oneplus-don-t-mark-ts-supply-b.patch +arm64-dts-qcom-sdm845-oneplus-don-t-keep-panel-regul.patch +arm64-dts-qcom-sdm845-oneplus-mark-l14a-regulator-as.patch +arm64-dts-qcom-x1e80100-fix-usb-combo-phys-ss1-and-s.patch +arm64-dts-qcom-msm8994-octagon-fix-analog-devices-ve.patch +arm-dts-allwinner-sun5i-a13-utoo-p66-delete-power-gp.patch +powerpc-uaccess-move-barrier_nospec-out-of-allow_rea.patch +soc-qcom-cmd-db-use-devm_memremap-to-fix-memory-leak.patch +soc-mediatek-svs-fix-memory-leak-in-svs_enable_debug.patch +powerpc-eeh-fix-recursive-pci_lock_rescan_remove-loc.patch +arm-dts-lpc32xx-set-motor-pwm-pwm-cells-property-val.patch +arm-dts-lpc32xx-add-clocks-property-to-motor-control.patch +arm64-dts-mediatek-mt8183-jacuzzi-pico6-fix-typo-in-.patch +arm64-dts-amlogic-s4-assign-mmc-b-clock-to-24mhz.patch +arm64-dts-amlogic-s4-fix-mmc-clock-assignment.patch +arm64-dts-ti-k3-j784s4-main.dtsi-move-c71_3-node-to-.patch +arm64-dts-ti-k3-j784s4-j742s2-main-common.dtsi-refac.patch +hwspinlock-omap-handle-devm_pm_runtime_enable-errors.patch +arm64-dts-amlogic-c3-assign-the-mmc-signal-clocks.patch +arm64-dts-amlogic-axg-assign-the-mmc-signal-clocks.patch +arm64-dts-amlogic-gx-assign-the-mmc-signal-clocks.patch +arm64-dts-amlogic-g12-assign-the-mmc-b-and-c-signal-.patch +arm64-dts-amlogic-g12-assign-the-mmc-a-signal-clock.patch +arm64-dts-qcom-qrb4210-rb2-fix-uart3-wakeup-irq-stor.patch +arm64-dts-qcom-sdm845-db845c-drop-cs-from-spio0.patch +arm64-dts-qcom-sdm845-db845c-specify-power-for-wifi-.patch +arm64-dts-qcom-x1e-bus-is-40-bits-fix-64gb-models.patch +arm64-dts-qcom-agatti-add-cx_mem-dbgc-gpu-regions.patch +arm64-dts-qcom-sm6115-add-cx_mem-dbgc-gpu-regions.patch +drm-panthor-recover-from-panthor_gpu_flush_caches-fa.patch +drm-panthor-fix-the-full_tick-check.patch +drm-panthor-fix-the-group-priority-rotation-logic.patch +drm-panthor-fix-immediate-ticking-on-a-disabled-tick.patch +drm-panthor-fix-the-logic-that-decides-when-to-stop-.patch +drm-panthor-make-sure-we-resume-the-tick-when-new-jo.patch +workqueue-factor-out-assign_rescuer_work.patch +workqueue-only-assign-rescuer-work-when-really-neede.patch +workqueue-process-rescuer-work-items-one-by-one-usin.patch +drm-panel-sw43408-remove-manual-invocation-of-unprep.patch +alsa-pcm-use-new-array-copying-wrapper.patch +alsa-pcm-relax-__free-variable-declarations.patch +alsa-vmaster-relax-__free-variable-declarations.patch +drm-panthor-evict-groups-before-vm-termination.patch +smack-smack-doi-must-be-0.patch +smack-smack-doi-accept-previously-used-values.patch +asoc-nau8821-consistently-clear-interrupts-before-un.patch +asoc-nau8821-avoid-unnecessary-blocking-in-irq-handl.patch +asoc-nau8821-fixup-nau8821_enable_jack_detect.patch +media-chips-media-wave5-fix-memory-leak-on-codec_inf.patch +drm-amd-drop-amdgpu-kernel-modesetting-enabled-messa.patch +drm-amdkfd-fix-signal_eviction_fence-bool-return-val.patch +drm-amdgpu-use-explicit-vcn-instance-0-in-sr-iov-ini.patch +drm-msm-disp-dpu-add-merge3d-support-for-sc7280.patch +drm-msm-dpu-set-vsync-source-irrespective-of-mdp-top.patch +drm-msm-dpu-fix-wd-timer-handling-on-dpu-8.x.patch +regulator-core-move-supply-check-earlier-in-set_mach.patch +hid-playstation-add-missing-check-for-input_ff_creat.patch +drm-msm-disp-set-num_planes-to-1-for-interleaved-yuv.patch +drm-msm-dpu-fix-cmd-panels-on-dpu-1.x-3.x.patch +media-ccs-accommodate-c-phy-into-the-calculation.patch +drm-msm-a2xx-fix-pixel-shader-start-on-a225.patch +drm-buddy-release-free_trees-array-on-buddy-mm-teard.patch +platform-chrome-cros_typec_switch-don-t-touch-struct.patch +media-uvcvideo-fix-allocation-for-small-frame-sizes.patch +evm-use-ordered-xattrs-list-to-calculate-hmac-in-evm.patch +drm-xe-unregister-drm-device-on-probe-error.patch +platform-chrome-cros_ec_lightbar-fix-response-size-i.patch +hid-intel-ish-hid-fix-null-ptr-deref-in-ishtp_bus_re.patch +spi-tools-add-include-folder-to-.gitignore.patch +revert-hwmon-ibmpex-fix-use-after-free-in-high-low-s.patch +hwmon-pmbus-mpq8785-prepare-driver-for-multiple-devi.patch +hwmon-pmbus-mpq8785-implement-vout-feedback-resistor.patch +hwmon-pmbus-mpq8785-add-support-for-mpm82504.patch +hwmon-pmbus-mpq8785-fix-vout_mode-mismatch-during-id.patch +pci-mediatek-fix-irq-domain-leak-when-msi-allocation.patch +documentation-pci-endpoint-fix-ntb-vntb-copy-paste-e.patch +pci-pm-avoid-redundant-delays-on-d3hot-d3cold.patch +wifi-cfg80211-fix-use_for-flag-update-on-bss-refresh.patch +pci-p2pdma-release-per-cpu-pgmap-ref-when-vm_insert_.patch +docs-fix-warning-document-not-included-in-any-toctre.patch +documentation-trace-refactor-toctree.patch +documentation-tracing-add-pci-tracepoint-documentati.patch +pci-do-not-attempt-to-set-exttag-for-vfs.patch +pci-portdrv-fix-potential-resource-leak.patch +dm-fix-unlocked-test-for-dm_suspended_md.patch +dm-use-read_once-in-dm_blk_report_zones.patch +quota-fix-livelock-between-quotactl-and-freeze_super.patch +net-mctp-i2c-fix-duplicate-reception-of-old-data.patch +mctp-i2c-initialise-event-handler-read-bytes.patch +wifi-cfg80211-stop-nan-and-p2p-in-cfg80211_leave.patch +netfilter-nf_tables-reset-table-validation-state-on-.patch +netfilter-nf_conncount-make-nf_conncount_gc_list-to-.patch +netfilter-nf_conncount-increase-the-connection-clean.patch +netfilter-nft_compat-add-more-restrictions-on-netlin.patch +netfilter-nf_conncount-fix-tracking-of-connections-f.patch +module-add-helper-function-for-reading-module_buildi.patch +kallsyms-ftrace-set-module-buildid-in-ftrace_mod_add.patch +pci-mark-3ware-9650sa-root-port-extended-tags-as-bro.patch +iommu-vt-d-flush-cache-for-pasid-table-before-using-.patch +iommu-vt-d-separate-page-request-queue-from-svm.patch +iommu-vt-d-drain-prqs-when-domain-removed-from-rid.patch +iommu-vt-d-avoid-draining-prq-in-sva-mm-release-path.patch +iommu-vt-d-clear-present-bit-before-tearing-down-pas.patch +dm-use-bio_clone_blkg_association.patch +xdrgen-fix-struct-prefix-for-typedef-types-in-progra.patch +nfs-nfserr_inval-is-not-defined-by-nfsv2.patch +xdrgen-initialize-data-pointer-for-zero-length-items.patch +nfsd-never-defer-requests-during-idmap-lookup.patch +fat-avoid-parent-link-count-underflow-in-rmdir.patch +tcp-tcp_tx_timestamp-must-look-at-the-rtx-queue.patch +pci-check-parent-for-null-in-of_pci_bus_release_doma.patch +wifi-ath10k-sdio-add-missing-lock-protection-in-ath1.patch +pci-initialize-rcb-from-pci_configure_device.patch +pci-add-defines-for-bridge-window-indexing.patch +pci-acpi-restrict-program_hpx_type2-to-aer-bits.patch +selftests-mm-pagemap_ioctl-fix-types-mismatches-show.patch +selftests-mm-convert-page_size-to-unsigned-long.patch +selftests-mm-fix-faulting-in-code-in-pagemap_ioctl-t.patch +ipc-don-t-audit-capability-check-in-ipc_permissions.patch +ucount-check-for-cap_sys_resource-using-ns_capable_n.patch +of-unittest-fix-possible-null-pointer-dereferences-i.patch +mptcp-fix-receive-space-timestamp-initialization.patch +octeontx2-af-fix-pf-driver-crash-with-kexec-kernel-b.patch +bonding-only-set-speed-duplex-to-unknown-if-getting-.patch +inet-raw-sockets-using-ipproto_raw-must-drop-incomin.patch +nfc-hci-shdlc-stop-timers-and-work-before-freeing-co.patch +netfilter-nfnetlink_queue-optimize-verdict-lookup-wi.patch +netfilter-nfnetlink_queue-do-shared-unconfirmed-chec.patch +netfilter-nft_set_hash-fix-get-operation-on-big-endi.patch +netfilter-nft_counter-fix-reset-of-counters-on-32bit.patch +netfilter-nft_set_rbtree-fix-bogus-eexist-with-nlm_f.patch +netfilter-nft_set_rbtree-check-for-partial-overlaps-.patch +pci-add-acs-quirk-for-pericom-pi7c9x2g404-switches-1.patch +net-hns3-fix-double-free-issue-for-tx-spare-buffer.patch +procfs-fix-missing-rcu-protection-when-reading-real_.patch +smb-client-correct-value-for-smbd_max_fragmented_rec.patch +net-atm-fix-crash-due-to-unvalidated-vcc-pointer-in-.patch +net-sunhme-fix-sbus-regression.patch +net-add-skb_dstref_steal-and-skb_dstref_restore.patch +net-switch-to-skb_dstref_steal-skb_dstref_restore-fo.patch +xfrm-fix-ip_rt_bug-race-in-icmp_route_lookup-reverse.patch +serial-caif-fix-use-after-free-in-caif_serial-ldisc_.patch +octeon_ep-disable-per-ring-interrupts.patch +octeon_ep-ensure-dbell-baddr-updation.patch +octeon_ep_vf-ensure-dbell-baddr-updation.patch +ionic-rate-limit-unknown-xcvr-type-messages.patch +octeontx2-pf-unregister-devlink-on-probe-failure.patch +rdma-rtrs-server-remove-dead-code.patch +ib-cache-update-gid-cache-on-client-reregister-event.patch +rdma-hns-fix-wq_mem_reclaim-warning.patch +rdma-hns-fix-rocev1-failure-due-to-dscp.patch +rdma-hns-notify-ulp-of-remaining-soft-wcs-during-res.patch +power-supply-ab8500-fix-use-after-free-in-power_supp.patch +power-supply-act8945a-fix-use-after-free-in-power_su.patch +power-supply-bq256xx-fix-use-after-free-in-power_sup.patch +power-supply-bq25980-fix-use-after-free-in-power_sup.patch +power-supply-cpcap-battery-fix-use-after-free-in-pow.patch +power-supply-goldfish-fix-use-after-free-in-power_su.patch +power-supply-pm8916_bms_vm-fix-use-after-free-in-pow.patch +power-supply-pm8916_lbc-fix-use-after-free-in-power_.patch +power-supply-rt9455-fix-use-after-free-in-power_supp.patch +power-supply-sbs-battery-fix-use-after-free-in-power.patch +power-reset-nvmem-reboot-mode-respect-cell-size-for-.patch +power-supply-bq27xxx-fix-wrong-errno-when-bus-ops-ar.patch +power-supply-wm97xx-fix-null-pointer-dereference-in-.patch +rdma-rtrs-srv-fix-sg-mapping.patch +rdma-rxe-fix-double-free-in-rxe_srq_from_init.patch +rdma-iwcm-fix-workqueue-list-corruption-by-removing-.patch +tools-power-x86-intel-speed-select-fix-file-descript.patch +rdma-mlx5-fix-umr-hang-in-lag-error-state-unload.patch +ib-mlx5-fix-port-speed-query-for-representors.patch +mtd-rawnand-cadence-fix-return-type-of-cdma-send-and.patch +vfio-pci-lock-upstream-bridge-for-vfio_pci_core_disa.patch +platform-x86-amd-pmf-prevent-tee-errors-after-hibern.patch +crypto-ccp-declare-psp-dead-if-psp_cmd_tee_ring_init.patch +crypto-ccp-add-an-s4-restore-flow.patch +crypto-ccp-factor-out-ring-destroy-handling-to-a-hel.patch +crypto-ccp-send-psp_cmd_tee_ring_destroy-when-psp_cm.patch +mtd-parsers-fix-memory-leak-in-mtd_parser_tplink_saf.patch +nfs-localio-eliminate-unnecessary-kref-in-nfs_local_.patch +nfs-localio-use-gfp_noio-and-non-memreclaim-workqueu.patch +rdma-uverbs-validate-wqe_size-before-using-it-in-ib_.patch +rdma-mlx5-fix-memory-leak-in-get_data_direct_sysfs_p.patch +rdma-rxe-fix-race-condition-in-qp-timer-handlers.patch +rdma-core-add-rdma_rw_max_sge-helper-for-sq-sizing.patch +cxl-fix-premature-commit_end-increment-on-decoder-co.patch +mtd-parsers-ofpart-fix-of-node-refcount-leak-in-pars.patch +mtd-spinand-fix-kernel-doc.patch +power-supply-pm8916_lbc-fix-use-after-free-for-extco.patch +power-supply-qcom_battmgr-recognize-lip-as-lithium-p.patch +rdma-uverbs-add-__gfp_nowarn-to-ib_uverbs_unmarshall.patch +pnfs-fix-a-missing-wake-up-while-waiting-on-nfs_layo.patch +scsi-smartpqi-fix-memory-leak-in-pqi_report_phys_lun.patch +scsi-ufs-host-mediatek-require-config_pm.patch +scsi-csiostor-fix-dereference-of-null-pointer-rn.patch +nvdimm-virtio_pmem-serialize-flush-requests.patch +fs-nfs-fix-readdir-slow-start-regression.patch +tracing-properly-process-error-handling-in-event_his.patch +tracing-remove-duplicate-enable_event_str-and-disabl.patch +fbcon-fbcon_cursor_noblink-fbcon_cursor_blink.patch +fbcon-fbcon_is_inactive-fbcon_is_active.patch +fbcon-introduce-get_-fg-bg-_color.patch +fbcon-rename-struct-fbcon_ops-to-struct-fbcon_par.patch +fbcon-set-rotate_font-callback-with-related-callback.patch +fbcon-move-fbcon-callbacks-into-struct-fbcon_bitops.patch +printk-vt-fbcon-remove-console_conditional_schedule.patch +fbdev-of_display_timing-fix-device-node-reference-le.patch +fbdev-au1200fb-fix-a-memory-leak-in-au1200fb_drv_pro.patch +clk-qcom-gcc-sm8550-use-floor-ops-for-sdcc-rcgs.patch +clk-qcom-gcc-sm8650-use-floor-ops-for-sdcc-rcgs.patch +clk-qcom-rcg2-compute-2d-using-duty-fraction-directl.patch +clk-meson-gxbb-limit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch +clk-qcom-gcc-sm8450-update-the-sdcc-rcgs-to-use-shar.patch +clk-qcom-gcc-sm4450-update-the-sdcc-rcgs-to-use-shar.patch +clk-qcom-gcc-sdx75-update-the-sdcc-rcgs-to-use-share.patch +clk-qcom-gcc-x1e80100-update-the-sdcc-rcgs-to-use-sh.patch +clk-qcom-gcc-qdu1000-update-the-sdcc-rcgs-to-use-sha.patch +clk-qcom-gcc-msm8953-remove-always_on-flag-from-cpp_.patch +clk-qcom-gcc-msm8917-remove-always_on-flag-from-cpp_.patch +clk-qcom-gcc-ipq5018-flag-sleep-clock-as-critical.patch +clk-move-clk_-save-restore-_context-to-common_clk-se.patch +clk-qcom-dispcc-sdm845-enable-parents-for-pixel-cloc.patch +clk-qcom-dispcc-sm7150-fix-dispcc_mdss_pclk1_clk_src.patch +clk-qcom-gfx3d-add-parent-to-parent-request-map.patch +clk-mediatek-fix-error-handling-in-runtime-pm-setup.patch +interconnect-mediatek-don-t-hijack-parent-device.patch +interconnect-mediatek-aggregate-bandwidth-with-satur.patch +dmaengine-mediatek-uart-apdma-fix-above-4g-addressin.patch +dma-dma-axi-dmac-fix-sw-cyclic-transfers.patch +dma-dma-axi-dmac-fix-hw-scatter-gather-not-looking-a.patch +soundwire-intel_ace2x-add-snd_hda_core-dependency.patch +iio-test-drop-dangling-symbol-in-gain-time-scale-hel.patch +staging-greybus-lights-avoid-null-deref.patch +serial-imx-change-serial_imx_console-to-bool.patch +serial-sh_sci-improve-dma-support-prompt.patch +mmc-rtsx_pci_sdmmc-increase-power-on-settling-delay-.patch +iio-pressure-mprls0025pa-fix-spi_transfer-struct-ini.patch +iio-pressure-mprls0025pa-fix-spi-cs-delay-violation.patch +iio-pressure-mprls0025pa-fix-interrupt-flag.patch +iio-pressure-mprls0025pa-fix-scan_type-struct.patch +iio-pressure-mprls0025pa-fix-pressure-calculation.patch +watchdog-starfive-wdt-fix-pm-reference-leak-in-probe.patch +coresight-etm3x-fix-cpulocked-warning-on-cpuhp.patch +phy-freescale-imx8qm-hsio-fix-null-pointer-dereferen.patch +revert-mmc-rtsx_pci_sdmmc-increase-power-on-settling.patch +mfd-arizona-fix-regulator-resource-leak-on-wm5102_cl.patch +mfd-simple-mfd-i2c-add-max77705-support.patch +mfd-simple-mfd-i2c-add-compatible-strings-for-layers.patch +mfd-simple-mfd-i2c-add-spacemit-p1-support.patch +mfd-simple-mfd-i2c-keep-compatible-strings-in-alphab.patch +mfd-simple-mfd-i2c-add-delta-tn48m-cpld-support.patch +drivers-iio-mpu3050-use-dev_err_probe-for-regulator-.patch +usb-bdc-fix-sleep-during-atomic.patch +pinctrl-equilibrium-fix-device-node-reference-leak-i.patch +ovl-fix-uninit-value-in-ovl_fill_real.patch +iio-sca3000-fix-a-resource-leak-in-sca3000_probe.patch +pinctrl-qcom-sm8250-lpass-lpi-fix-i2s2_data_groups-d.patch +pinctrl-single-fix-refcount-leak-in-pcs_add_gpio_fun.patch +leds-qcom-lpg-check-the-return-value-of-regmap_bulk_.patch +backlight-qcom-wled-support-ovp-values-for-pmi8994.patch +backlight-qcom-wled-change-pm8950-wled-configuration.patch +dmaengine-fsl-edma-don-t-explicitly-disable-clocks-i.patch +drbd-always-set-blk_feat_stable_writes.patch +io_uring-cancel-de-unionize-file-and-user_data-in-st.patch diff --git a/queue-6.12/smack-smack-doi-accept-previously-used-values.patch b/queue-6.12/smack-smack-doi-accept-previously-used-values.patch new file mode 100644 index 0000000000..45d994338d --- /dev/null +++ b/queue-6.12/smack-smack-doi-accept-previously-used-values.patch @@ -0,0 +1,233 @@ +From 402b7704594ccba92311c44edb6161d59ec29493 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Sep 2025 15:31:53 +0300 +Subject: smack: /smack/doi: accept previously used values +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Konstantin Andreev + +[ Upstream commit 33d589ed60ae433b483761987b85e0d24e54584e ] + +Writing to /smack/doi a value that has ever been +written there in the past disables networking for +non-ambient labels. +E.g. + + # cat /smack/doi + 3 + # netlabelctl -p cipso list + Configured CIPSO mappings (1) + DOI value : 3 + mapping type : PASS_THROUGH + # netlabelctl -p map list + Configured NetLabel domain mappings (3) + domain: "_" (IPv4) + protocol: UNLABELED + domain: DEFAULT (IPv4) + protocol: CIPSO, DOI = 3 + domain: DEFAULT (IPv6) + protocol: UNLABELED + + # cat /smack/ambient + _ + # cat /proc/$$/attr/smack/current + _ + # ping -c1 10.1.95.12 + 64 bytes from 10.1.95.12: icmp_seq=1 ttl=64 time=0.964 ms + # echo foo >/proc/$$/attr/smack/current + # ping -c1 10.1.95.12 + 64 bytes from 10.1.95.12: icmp_seq=1 ttl=64 time=0.956 ms + unknown option 86 + + # echo 4 >/smack/doi + # echo 3 >/smack/doi +!> [ 214.050395] smk_cipso_doi:691 cipso add rc = -17 + # echo 3 >/smack/doi +!> [ 249.402261] smk_cipso_doi:678 remove rc = -2 +!> [ 249.402261] smk_cipso_doi:691 cipso add rc = -17 + + # ping -c1 10.1.95.12 +!!> ping: 10.1.95.12: Address family for hostname not supported + + # echo _ >/proc/$$/attr/smack/current + # ping -c1 10.1.95.12 + 64 bytes from 10.1.95.12: icmp_seq=1 ttl=64 time=0.617 ms + +This happens because Smack keeps decommissioned DOIs, +fails to re-add them, and consequently refuses to add +the “default” domain map: + + # netlabelctl -p cipso list + Configured CIPSO mappings (2) + DOI value : 3 + mapping type : PASS_THROUGH + DOI value : 4 + mapping type : PASS_THROUGH + # netlabelctl -p map list + Configured NetLabel domain mappings (2) + domain: "_" (IPv4) + protocol: UNLABELED +!> (no ipv4 map for default domain here) + domain: DEFAULT (IPv6) + protocol: UNLABELED + +Fix by clearing decommissioned DOI definitions and +serializing concurrent DOI updates with a new lock. + +Also: +- allow /smack/doi to live unconfigured, since + adding a map (netlbl_cfg_cipsov4_map_add) may fail. + CIPSO_V4_DOI_UNKNOWN(0) indicates the unconfigured DOI +- add new DOI before removing the old default map, + so the old map remains if the add fails + +(2008-02-04, Casey Schaufler) +Fixes: e114e473771c ("Smack: Simplified Mandatory Access Control Kernel") + +Signed-off-by: Konstantin Andreev +Signed-off-by: Casey Schaufler +Signed-off-by: Sasha Levin +--- + security/smack/smackfs.c | 71 +++++++++++++++++++++++++--------------- + 1 file changed, 45 insertions(+), 26 deletions(-) + +diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c +index a130007397562..109ad155ffc2a 100644 +--- a/security/smack/smackfs.c ++++ b/security/smack/smackfs.c +@@ -68,6 +68,7 @@ enum smk_inos { + static DEFINE_MUTEX(smack_cipso_lock); + static DEFINE_MUTEX(smack_ambient_lock); + static DEFINE_MUTEX(smk_net4addr_lock); ++static DEFINE_MUTEX(smk_cipso_doi_lock); + #if IS_ENABLED(CONFIG_IPV6) + static DEFINE_MUTEX(smk_net6addr_lock); + #endif /* CONFIG_IPV6 */ +@@ -139,7 +140,7 @@ struct smack_parsed_rule { + int smk_access2; + }; + +-static u32 smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; ++static u32 smk_cipso_doi_value = CIPSO_V4_DOI_UNKNOWN; + + /* + * Values for parsing cipso rules +@@ -679,43 +680,60 @@ static const struct file_operations smk_load_ops = { + }; + + /** +- * smk_cipso_doi - initialize the CIPSO domain ++ * smk_cipso_doi - set netlabel maps ++ * @ndoi: new value for our CIPSO DOI ++ * @gfp_flags: kmalloc allocation context + */ +-static void smk_cipso_doi(void) ++static int ++smk_cipso_doi(u32 ndoi, gfp_t gfp_flags) + { +- int rc; ++ int rc = 0; + struct cipso_v4_doi *doip; + struct netlbl_audit nai; + +- smk_netlabel_audit_set(&nai); ++ mutex_lock(&smk_cipso_doi_lock); + +- rc = netlbl_cfg_map_del(NULL, PF_INET, NULL, NULL, &nai); +- if (rc != 0) +- printk(KERN_WARNING "%s:%d remove rc = %d\n", +- __func__, __LINE__, rc); ++ if (smk_cipso_doi_value == ndoi) ++ goto clr_doi_lock; ++ ++ smk_netlabel_audit_set(&nai); + +- doip = kmalloc(sizeof(struct cipso_v4_doi), GFP_KERNEL | __GFP_NOFAIL); ++ doip = kmalloc(sizeof(struct cipso_v4_doi), gfp_flags); ++ if (!doip) { ++ rc = -ENOMEM; ++ goto clr_doi_lock; ++ } + doip->map.std = NULL; +- doip->doi = smk_cipso_doi_value; ++ doip->doi = ndoi; + doip->type = CIPSO_V4_MAP_PASS; + doip->tags[0] = CIPSO_V4_TAG_RBITMAP; + for (rc = 1; rc < CIPSO_V4_TAG_MAXCNT; rc++) + doip->tags[rc] = CIPSO_V4_TAG_INVALID; + + rc = netlbl_cfg_cipsov4_add(doip, &nai); +- if (rc != 0) { +- printk(KERN_WARNING "%s:%d cipso add rc = %d\n", +- __func__, __LINE__, rc); ++ if (rc) { + kfree(doip); +- return; ++ goto clr_doi_lock; + } +- rc = netlbl_cfg_cipsov4_map_add(doip->doi, NULL, NULL, NULL, &nai); +- if (rc != 0) { +- printk(KERN_WARNING "%s:%d map add rc = %d\n", +- __func__, __LINE__, rc); +- netlbl_cfg_cipsov4_del(doip->doi, &nai); +- return; ++ ++ if (smk_cipso_doi_value != CIPSO_V4_DOI_UNKNOWN) { ++ rc = netlbl_cfg_map_del(NULL, PF_INET, NULL, NULL, &nai); ++ if (rc && rc != -ENOENT) ++ goto clr_ndoi_def; ++ ++ netlbl_cfg_cipsov4_del(smk_cipso_doi_value, &nai); + } ++ ++ rc = netlbl_cfg_cipsov4_map_add(ndoi, NULL, NULL, NULL, &nai); ++ if (rc) { ++ smk_cipso_doi_value = CIPSO_V4_DOI_UNKNOWN; // no default map ++clr_ndoi_def: netlbl_cfg_cipsov4_del(ndoi, &nai); ++ } else ++ smk_cipso_doi_value = ndoi; ++ ++clr_doi_lock: ++ mutex_unlock(&smk_cipso_doi_lock); ++ return rc; + } + + /** +@@ -1617,11 +1635,8 @@ static ssize_t smk_write_doi(struct file *file, const char __user *buf, + + if (u == CIPSO_V4_DOI_UNKNOWN || u > U32_MAX) + return -EINVAL; +- smk_cipso_doi_value = u; +- +- smk_cipso_doi(); + +- return count; ++ return smk_cipso_doi(u, GFP_KERNEL) ? : count; + } + + static const struct file_operations smk_doi_ops = { +@@ -2998,6 +3013,7 @@ static int __init init_smk_fs(void) + { + int err; + int rc; ++ struct netlbl_audit nai; + + if (smack_enabled == 0) + return 0; +@@ -3016,7 +3032,10 @@ static int __init init_smk_fs(void) + } + } + +- smk_cipso_doi(); ++ smk_netlabel_audit_set(&nai); ++ (void) netlbl_cfg_map_del(NULL, PF_INET, NULL, NULL, &nai); ++ (void) smk_cipso_doi(SMACK_CIPSO_DOI_DEFAULT, ++ GFP_KERNEL | __GFP_NOFAIL); + smk_unlbl_ambient(NULL); + + rc = smack_populate_secattr(&smack_known_floor); +-- +2.51.0 + diff --git a/queue-6.12/smack-smack-doi-must-be-0.patch b/queue-6.12/smack-smack-doi-must-be-0.patch new file mode 100644 index 0000000000..446de37bc3 --- /dev/null +++ b/queue-6.12/smack-smack-doi-must-be-0.patch @@ -0,0 +1,71 @@ +From 2624b09c23cec4ab15b2cba21c5bcbe0af8fdd3f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Sep 2025 15:16:02 +0300 +Subject: smack: /smack/doi must be > 0 + +From: Konstantin Andreev + +[ Upstream commit 19c013e1551bf51e1493da1270841d60e4fd3f15 ] + +/smack/doi allows writing and keeping negative doi values. +Correct values are 0 < doi <= (max 32-bit positive integer) + +(2008-02-04, Casey Schaufler) +Fixes: e114e473771c ("Smack: Simplified Mandatory Access Control Kernel") + +Signed-off-by: Konstantin Andreev +Signed-off-by: Casey Schaufler +Signed-off-by: Sasha Levin +--- + security/smack/smackfs.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c +index 1e35c9f807b2b..a130007397562 100644 +--- a/security/smack/smackfs.c ++++ b/security/smack/smackfs.c +@@ -139,7 +139,7 @@ struct smack_parsed_rule { + int smk_access2; + }; + +-static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; ++static u32 smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; + + /* + * Values for parsing cipso rules +@@ -1580,7 +1580,7 @@ static ssize_t smk_read_doi(struct file *filp, char __user *buf, + if (*ppos != 0) + return 0; + +- sprintf(temp, "%d", smk_cipso_doi_value); ++ sprintf(temp, "%lu", (unsigned long)smk_cipso_doi_value); + rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp)); + + return rc; +@@ -1599,7 +1599,7 @@ static ssize_t smk_write_doi(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) + { + char temp[80]; +- int i; ++ unsigned long u; + + if (!smack_privileged(CAP_MAC_ADMIN)) + return -EPERM; +@@ -1612,10 +1612,12 @@ static ssize_t smk_write_doi(struct file *file, const char __user *buf, + + temp[count] = '\0'; + +- if (sscanf(temp, "%d", &i) != 1) ++ if (kstrtoul(temp, 10, &u)) + return -EINVAL; + +- smk_cipso_doi_value = i; ++ if (u == CIPSO_V4_DOI_UNKNOWN || u > U32_MAX) ++ return -EINVAL; ++ smk_cipso_doi_value = u; + + smk_cipso_doi(); + +-- +2.51.0 + diff --git a/queue-6.12/smb-client-correct-value-for-smbd_max_fragmented_rec.patch b/queue-6.12/smb-client-correct-value-for-smbd_max_fragmented_rec.patch new file mode 100644 index 0000000000..01b3e79a07 --- /dev/null +++ b/queue-6.12/smb-client-correct-value-for-smbd_max_fragmented_rec.patch @@ -0,0 +1,78 @@ +From 6d02ff33a5bf480e5927781b571fb431a13bb0de Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 17:14:14 +0100 +Subject: smb: client: correct value for smbd_max_fragmented_recv_size + +From: Stefan Metzmacher + +[ Upstream commit 4a93d1ee2d0206970b6eb13fbffe07938cd95948 ] + +When we download a file without rdma offload or get +a large directly enumeration from the server, +the server might want to send up to smbd_max_fragmented_recv_size +bytes, but if it is too large all our recv buffers +might already be moved to the recv_io.reassembly.list +and we're no longer able to grant recv credits. + +The maximum fragmented upper-layer payload receive size supported + +Assume max_payload_per_credit is +smbd_max_receive_size - 24 = 1340 + +The maximum number would be +smbd_receive_credit_max * max_payload_per_credit + + 1340 * 255 = 341700 (0x536C4) + +The minimum value from the spec is 131072 (0x20000) + +For now we use the logic we used in ksmbd before: + (1364 * 255) / 2 = 173910 (0x2A756) + +Fixes: 03bee01d6215 ("CIFS: SMBD: Add SMB Direct protocol initial values and constants") +Cc: Steve French +Cc: Tom Talpey +Cc: Long Li +Cc: Namjae Jeon +Cc: linux-cifs@vger.kernel.org +Cc: samba-technical@lists.samba.org +Signed-off-by: Stefan Metzmacher +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/client/smbdirect.c | 19 +++++++++++++++++-- + 1 file changed, 17 insertions(+), 2 deletions(-) + +diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c +index b1548269c308a..07f71a9481a36 100644 +--- a/fs/smb/client/smbdirect.c ++++ b/fs/smb/client/smbdirect.c +@@ -86,8 +86,23 @@ int smbd_send_credit_target = 255; + /* The maximum single message size can be sent to remote peer */ + int smbd_max_send_size = 1364; + +-/* The maximum fragmented upper-layer payload receive size supported */ +-int smbd_max_fragmented_recv_size = 1024 * 1024; ++/* ++ * The maximum fragmented upper-layer payload receive size supported ++ * ++ * Assume max_payload_per_credit is ++ * smbd_max_receive_size - 24 = 1340 ++ * ++ * The maximum number would be ++ * smbd_receive_credit_max * max_payload_per_credit ++ * ++ * 1340 * 255 = 341700 (0x536C4) ++ * ++ * The minimum value from the spec is 131072 (0x20000) ++ * ++ * For now we use the logic we used in ksmbd before: ++ * (1364 * 255) / 2 = 173910 (0x2A756) ++ */ ++int smbd_max_fragmented_recv_size = (1364 * 255) / 2; + + /* The maximum single-message size which can be received */ + int smbd_max_receive_size = 1364; +-- +2.51.0 + diff --git a/queue-6.12/smb-client-fix-potential-uaf-and-double-free-in-smb2.patch b/queue-6.12/smb-client-fix-potential-uaf-and-double-free-in-smb2.patch new file mode 100644 index 0000000000..863028733f --- /dev/null +++ b/queue-6.12/smb-client-fix-potential-uaf-and-double-free-in-smb2.patch @@ -0,0 +1,41 @@ +From 0181410f00be793f7de9d75203fe749fe7a7afae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 13:19:52 -0300 +Subject: smb: client: fix potential UAF and double free in smb2_open_file() + +From: Paulo Alcantara + +[ Upstream commit ebbbc4bfad4cb355d17c671223d0814ee3ef4eda ] + +Zero out @err_iov and @err_buftype before retrying SMB2_open() to +prevent an UAF bug if @data != NULL, otherwise a double free. + +Fixes: e3a43633023e ("smb/client: fix memory leak in smb2_open_file()") +Reported-by: David Howells +Closes: https://lore.kernel.org/r/2892312.1770306653@warthog.procyon.org.uk +Signed-off-by: Paulo Alcantara (Red Hat) +Reviewed-by: David Howells +Reviewed-by: ChenXiaoSong +Cc: linux-cifs@vger.kernel.org +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/client/smb2file.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/fs/smb/client/smb2file.c b/fs/smb/client/smb2file.c +index 414242a33d61a..b7ab18d4bedca 100644 +--- a/fs/smb/client/smb2file.c ++++ b/fs/smb/client/smb2file.c +@@ -123,6 +123,8 @@ int smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, __u32 + &err_buftype); + if (rc == -EACCES && retry_without_read_attributes) { + free_rsp_buf(err_buftype, err_iov.iov_base); ++ memset(&err_iov, 0, sizeof(err_iov)); ++ err_buftype = CIFS_NO_BUFFER; + oparms->desired_access &= ~FILE_READ_ATTRIBUTES; + rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, smb2_data, NULL, &err_iov, + &err_buftype); +-- +2.51.0 + diff --git a/queue-6.12/soc-mediatek-svs-fix-memory-leak-in-svs_enable_debug.patch b/queue-6.12/soc-mediatek-svs-fix-memory-leak-in-svs_enable_debug.patch new file mode 100644 index 0000000000..2c75df7370 --- /dev/null +++ b/queue-6.12/soc-mediatek-svs-fix-memory-leak-in-svs_enable_debug.patch @@ -0,0 +1,59 @@ +From ccb0095621599d44696b797bb5c3e2d949aa9bc3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 28 Dec 2025 16:26:36 +0000 +Subject: soc: mediatek: svs: Fix memory leak in svs_enable_debug_write() + +From: Zilin Guan + +[ Upstream commit 6259094ee806fb813ca95894c65fb80e2ec98bf1 ] + +In svs_enable_debug_write(), the buf allocated by memdup_user_nul() +is leaked if kstrtoint() fails. + +Fix this by using __free(kfree) to automatically free buf, eliminating +the need for explicit kfree() calls and preventing leaks. + +Fixes: 13f1bbcfb582 ("soc: mediatek: SVS: add debug commands") +Co-developed-by: Jianhao Xu +Signed-off-by: Jianhao Xu +Signed-off-by: Zilin Guan +[Angelo: Added missing cleanup.h inclusion] +Signed-off-by: AngeloGioacchino Del Regno +Signed-off-by: Sasha Levin +--- + drivers/soc/mediatek/mtk-svs.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/soc/mediatek/mtk-svs.c b/drivers/soc/mediatek/mtk-svs.c +index 4cb8169aec6b5..07ab261e1269d 100644 +--- a/drivers/soc/mediatek/mtk-svs.c ++++ b/drivers/soc/mediatek/mtk-svs.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -789,7 +790,7 @@ static ssize_t svs_enable_debug_write(struct file *filp, + struct svs_bank *svsb = file_inode(filp)->i_private; + struct svs_platform *svsp = dev_get_drvdata(svsb->dev); + int enabled, ret; +- char *buf = NULL; ++ char *buf __free(kfree) = NULL; + + if (count >= PAGE_SIZE) + return -EINVAL; +@@ -807,8 +808,6 @@ static ssize_t svs_enable_debug_write(struct file *filp, + svsb->mode_support = SVSB_MODE_ALL_DISABLE; + } + +- kfree(buf); +- + return count; + } + +-- +2.51.0 + diff --git a/queue-6.12/soc-qcom-cmd-db-use-devm_memremap-to-fix-memory-leak.patch b/queue-6.12/soc-qcom-cmd-db-use-devm_memremap-to-fix-memory-leak.patch new file mode 100644 index 0000000000..65729855f9 --- /dev/null +++ b/queue-6.12/soc-qcom-cmd-db-use-devm_memremap-to-fix-memory-leak.patch @@ -0,0 +1,53 @@ +From a9065ea235be97c485ceab3b37f4466f788bc4e4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Dec 2025 09:39:32 +0800 +Subject: soc: qcom: cmd-db: Use devm_memremap() to fix memory leak in + cmd_db_dev_probe + +From: Haotian Zhang + +[ Upstream commit 0da7824734d8d83e6a844dd0207f071cb0c50cf4 ] + +If cmd_db_magic_matches() fails after memremap() succeeds, the function +returns -EINVAL without unmapping the memory region, causing a +potential resource leak. + +Switch to devm_memremap to automatically manage the map resource. + +Fixes: 312416d9171a ("drivers: qcom: add command DB driver") +Suggested-by: Dmitry Baryshkov +Signed-off-by: Haotian Zhang +Link: https://lore.kernel.org/r/20251216013933.773-1-vulab@iscas.ac.cn +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/cmd-db.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/soc/qcom/cmd-db.c b/drivers/soc/qcom/cmd-db.c +index ae66c2623d250..84a75d8c4b702 100644 +--- a/drivers/soc/qcom/cmd-db.c ++++ b/drivers/soc/qcom/cmd-db.c +@@ -349,15 +349,16 @@ static int cmd_db_dev_probe(struct platform_device *pdev) + return -EINVAL; + } + +- cmd_db_header = memremap(rmem->base, rmem->size, MEMREMAP_WC); +- if (!cmd_db_header) { +- ret = -ENOMEM; ++ cmd_db_header = devm_memremap(&pdev->dev, rmem->base, rmem->size, MEMREMAP_WC); ++ if (IS_ERR(cmd_db_header)) { ++ ret = PTR_ERR(cmd_db_header); + cmd_db_header = NULL; + return ret; + } + + if (!cmd_db_magic_matches(cmd_db_header)) { + dev_err(&pdev->dev, "Invalid Command DB Magic\n"); ++ cmd_db_header = NULL; + return -EINVAL; + } + +-- +2.51.0 + diff --git a/queue-6.12/soc-qcom-smem-handle-enomem-error-during-probe.patch b/queue-6.12/soc-qcom-smem-handle-enomem-error-during-probe.patch new file mode 100644 index 0000000000..6d96c81384 --- /dev/null +++ b/queue-6.12/soc-qcom-smem-handle-enomem-error-during-probe.patch @@ -0,0 +1,39 @@ +From b22ed3dc4eff173ea56e92d40fbc2cd2a5fb0cd0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 08:45:37 +0100 +Subject: soc: qcom: smem: handle ENOMEM error during probe + +From: Jorge Ramirez-Ortiz + +[ Upstream commit 0fe01a7955f4fef97e7cc6d14bfc5931c660402b ] + +Fail the driver probe if the region can't be mapped + +Signed-off-by: Jorge Ramirez-Ortiz +Fixes: 20bb6c9de1b7 ("soc: qcom: smem: map only partitions used by local HOST") +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20251209074610.3751781-1-jorge.ramirez@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/smem.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c +index 170f88ce0e50e..493e218c5fd4e 100644 +--- a/drivers/soc/qcom/smem.c ++++ b/drivers/soc/qcom/smem.c +@@ -1211,7 +1211,9 @@ static int qcom_smem_probe(struct platform_device *pdev) + smem->item_count = qcom_smem_get_item_count(smem); + break; + case SMEM_GLOBAL_HEAP_VERSION: +- qcom_smem_map_global(smem, size); ++ ret = qcom_smem_map_global(smem, size); ++ if (ret < 0) ++ return ret; + smem->item_count = SMEM_ITEM_COUNT; + break; + default: +-- +2.51.0 + diff --git a/queue-6.12/soundwire-intel_ace2x-add-snd_hda_core-dependency.patch b/queue-6.12/soundwire-intel_ace2x-add-snd_hda_core-dependency.patch new file mode 100644 index 0000000000..cbd8900449 --- /dev/null +++ b/queue-6.12/soundwire-intel_ace2x-add-snd_hda_core-dependency.patch @@ -0,0 +1,45 @@ +From 7d23065ddae1c0edea252a5fbc0cfea740420809 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 23 Dec 2025 22:50:01 +0100 +Subject: soundwire: intel_ace2x: add SND_HDA_CORE dependency + +From: Arnd Bergmann + +[ Upstream commit dc3a6a942e9ee3f18560bfcb16c06bb94f37fabf ] + +The ace2x driver can optionally use the HDA infrastructure, but can still +build without that. However, with SND_HDA_CORE=m and SND_HDA_ALIGNED_MMIO=y, +it fails to link as built-in: + +aarch64-linux-ld: drivers/soundwire/intel_ace2x.o: in function `intel_shim_wake': +intel_ace2x.c:(.text+0x2518): undefined reference to `snd_hdac_aligned_read' +aarch64-linux-ld: intel_ace2x.c:(.text+0x25d4): undefined reference to `snd_hdac_aligned_read' +aarch64-linux-ld: intel_ace2x.c:(.text+0x268c): undefined reference to `snd_hdac_aligned_write' + +Add a Kconfig dependency that forces the soundwire driver to be a loadable +module if necessary. + +Fixes: 79e7123c078d ("soundwire: intel_ace2x: fix wakeup handling") +Signed-off-by: Arnd Bergmann +Link: https://patch.msgid.link/20251223215014.534756-1-arnd@kernel.org +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/soundwire/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/soundwire/Kconfig b/drivers/soundwire/Kconfig +index 4d8f3b7024ae5..a057c64d93f0b 100644 +--- a/drivers/soundwire/Kconfig ++++ b/drivers/soundwire/Kconfig +@@ -38,6 +38,7 @@ config SOUNDWIRE_INTEL + select AUXILIARY_BUS + depends on ACPI && SND_SOC + depends on SND_SOC_SOF_HDA_MLINK || !SND_SOC_SOF_HDA_MLINK ++ depends on SND_HDA_CORE || !SND_HDA_ALIGNED_MMIO + help + SoundWire Intel Master driver. + If you have an Intel platform which has a SoundWire Master then +-- +2.51.0 + diff --git a/queue-6.12/spi-tools-add-include-folder-to-.gitignore.patch b/queue-6.12/spi-tools-add-include-folder-to-.gitignore.patch new file mode 100644 index 0000000000..48094c66c3 --- /dev/null +++ b/queue-6.12/spi-tools-add-include-folder-to-.gitignore.patch @@ -0,0 +1,35 @@ +From 7513aff688ad109ff26f6c5021fc065cd1f46f38 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 10:50:01 +0100 +Subject: spi: tools: Add include folder to .gitignore + +From: Francesco Lavra + +[ Upstream commit 5af56f30c4fcbade4a92f94dadfea517d1db9703 ] + +The Makefile for the SPI tools creates an include/linux/spi folder and some +symlinks inside it. After running `make -C spi/tools`, this folder shows up +as untracked in the git status. +Add the above folder to the .gitignore file. + +Fixes: f325b73dc4db ("spi: tools: move to tools buildsystem") +Signed-off-by: Francesco Lavra +Link: https://patch.msgid.link/20260209095001.556495-1-flavra@baylibre.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + tools/spi/.gitignore | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/tools/spi/.gitignore b/tools/spi/.gitignore +index 14ddba3d21957..038261b34ed83 100644 +--- a/tools/spi/.gitignore ++++ b/tools/spi/.gitignore +@@ -1,3 +1,4 @@ + # SPDX-License-Identifier: GPL-2.0-only + spidev_fdx + spidev_test ++include/ +-- +2.51.0 + diff --git a/queue-6.12/staging-greybus-lights-avoid-null-deref.patch b/queue-6.12/staging-greybus-lights-avoid-null-deref.patch new file mode 100644 index 0000000000..0b0ac4b2fe --- /dev/null +++ b/queue-6.12/staging-greybus-lights-avoid-null-deref.patch @@ -0,0 +1,55 @@ +From 867a1625ee2631f1ac8d33de9f0c320b9339a4d7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 20:42:54 +0530 +Subject: staging: greybus: lights: avoid NULL deref + +From: Chaitanya Mishra + +[ Upstream commit efcffd9a6ad8d190651498d5eda53bfc7cf683a7 ] + +gb_lights_light_config() stores channel_count before allocating the +channels array. If kcalloc() fails, gb_lights_release() iterates the +non-zero count and dereferences light->channels, which is NULL. + +Allocate channels first and only then publish channels_count so the +cleanup path can't walk a NULL pointer. + +Fixes: 2870b52bae4c ("greybus: lights: add lights implementation") +Link: https://lore.kernel.org/all/20260108103700.15384-1-chaitanyamishra.ai@gmail.com/ +Reviewed-by: Rui Miguel Silva +Signed-off-by: Chaitanya Mishra +Link: https://patch.msgid.link/20260108151254.81553-1-chaitanyamishra.ai@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/staging/greybus/light.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/drivers/staging/greybus/light.c b/drivers/staging/greybus/light.c +index e509fdc715dbb..38c233a706c48 100644 +--- a/drivers/staging/greybus/light.c ++++ b/drivers/staging/greybus/light.c +@@ -1008,14 +1008,18 @@ static int gb_lights_light_config(struct gb_lights *glights, u8 id) + if (!strlen(conf.name)) + return -EINVAL; + +- light->channels_count = conf.channel_count; + light->name = kstrndup(conf.name, NAMES_MAX, GFP_KERNEL); + if (!light->name) + return -ENOMEM; +- light->channels = kcalloc(light->channels_count, ++ light->channels = kcalloc(conf.channel_count, + sizeof(struct gb_channel), GFP_KERNEL); + if (!light->channels) + return -ENOMEM; ++ /* ++ * Publish channels_count only after channels allocation so cleanup ++ * doesn't walk a NULL channels pointer on allocation failure. ++ */ ++ light->channels_count = conf.channel_count; + + /* First we collect all the configurations for all channels */ + for (i = 0; i < light->channels_count; i++) { +-- +2.51.0 + diff --git a/queue-6.12/tcp-tcp_tx_timestamp-must-look-at-the-rtx-queue.patch b/queue-6.12/tcp-tcp_tx_timestamp-must-look-at-the-rtx-queue.patch new file mode 100644 index 0000000000..4b4da7b087 --- /dev/null +++ b/queue-6.12/tcp-tcp_tx_timestamp-must-look-at-the-rtx-queue.patch @@ -0,0 +1,44 @@ +From f163e2e259f81345175f6254181812dbf6c15c40 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 12:38:27 +0000 +Subject: tcp: tcp_tx_timestamp() must look at the rtx queue + +From: Eric Dumazet + +[ Upstream commit 838eb9687691d29915797a885b861fd09353386e ] + +tcp_tx_timestamp() is only called at the end of tcp_sendmsg_locked() +before the final tcp_push(). + +By the time it is called, it is possible all the copied data +has been sent already (transmit queue is empty). + +If this is the case, use the last skb in the rtx queue. + +Fixes: 75c119afe14f ("tcp: implement rb-tree based retransmit queue") +Signed-off-by: Eric Dumazet +Reviewed-by: Jason Xing +Link: https://patch.msgid.link/20260127123828.4098577-2-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index ad5f30cefdf96..4090107b0c4d5 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -481,6 +481,9 @@ static void tcp_tx_timestamp(struct sock *sk, u16 tsflags) + { + struct sk_buff *skb = tcp_write_queue_tail(sk); + ++ if (unlikely(!skb)) ++ skb = skb_rb_last(&sk->tcp_rtx_queue); ++ + if (tsflags && skb) { + struct skb_shared_info *shinfo = skb_shinfo(skb); + struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); +-- +2.51.0 + diff --git a/queue-6.12/thermal-intel-x86_pkg_temp_thermal-handle-invalid-te.patch b/queue-6.12/thermal-intel-x86_pkg_temp_thermal-handle-invalid-te.patch new file mode 100644 index 0000000000..72964ae5d5 --- /dev/null +++ b/queue-6.12/thermal-intel-x86_pkg_temp_thermal-handle-invalid-te.patch @@ -0,0 +1,43 @@ +From 8bec0b185b07f51d91acd1b8b101cd55e8d9f92d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 16:23:41 +0100 +Subject: thermal: intel: x86_pkg_temp_thermal: Handle invalid temperature + +From: Rafael J. Wysocki + +[ Upstream commit 9635c586a559ba0e45b2bfbff79c937ddbaf1a62 ] + +After commit be0a3600aa1e ("thermal: sysfs: Rework the handling of trip +point updates"), THERMAL_TEMP_INVALID can be passed to sys_set_trip_temp() +and it is treated as a regular temperature value there, so the sysfs +write fails even though it is expected to succeed and disable the given +trip point. + +Address this by making sys_set_trip_temp() clear its temp variable when +it is equal to THERMAL_TEMP_INVALID. + +Fixes: be0a3600aa1e ("thermal: sysfs: Rework the handling of trip point updates") +Signed-off-by: Rafael J. Wysocki +Link: https://patch.msgid.link/2815400.mvXUDI8C0e@rafael.j.wysocki +Signed-off-by: Sasha Levin +--- + drivers/thermal/intel/x86_pkg_temp_thermal.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/thermal/intel/x86_pkg_temp_thermal.c b/drivers/thermal/intel/x86_pkg_temp_thermal.c +index 8c44f378b61ef..29af9510a6161 100644 +--- a/drivers/thermal/intel/x86_pkg_temp_thermal.c ++++ b/drivers/thermal/intel/x86_pkg_temp_thermal.c +@@ -127,6 +127,9 @@ sys_set_trip_temp(struct thermal_zone_device *tzd, + u32 l, h, mask, shift, intr; + int tj_max, val, ret; + ++ if (temp == THERMAL_TEMP_INVALID) ++ temp = 0; ++ + tj_max = intel_tcc_get_tjmax(zonedev->cpu); + if (tj_max < 0) + return tj_max; +-- +2.51.0 + diff --git a/queue-6.12/thermal-of-fix-reference-leak-in-thermal_of_cm_looku.patch b/queue-6.12/thermal-of-fix-reference-leak-in-thermal_of_cm_looku.patch new file mode 100644 index 0000000000..78e2866b0b --- /dev/null +++ b/queue-6.12/thermal-of-fix-reference-leak-in-thermal_of_cm_looku.patch @@ -0,0 +1,46 @@ +From 1c4beb4d25facb5cd58021106092bda9414a0b90 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 24 Jan 2026 03:06:40 +0800 +Subject: thermal/of: Fix reference leak in thermal_of_cm_lookup() + +From: Felix Gu + +[ Upstream commit a1fe789a96fe47733c133134fd264cb7ca832395 ] + +In thermal_of_cm_lookup(), tr_np is obtained via of_parse_phandle(), but +never released. + +Use the __free(device_node) cleanup attribute to automatically release +the node and fix the leak. + +Fixes: 423de5b5bc5b ("thermal/of: Fix cdev lookup in thermal_of_should_bind()") +Signed-off-by: Felix Gu +Reviewed-by: Lukasz Luba +[ rjw: Changelog edits ] +Link: https://patch.msgid.link/20260124-thermal_of-v1-1-54d3416948cf@gmail.com +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/thermal/thermal_of.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/thermal/thermal_of.c b/drivers/thermal/thermal_of.c +index e0aa9d9d5604b..3e674f2d66316 100644 +--- a/drivers/thermal/thermal_of.c ++++ b/drivers/thermal/thermal_of.c +@@ -299,10 +299,10 @@ static bool thermal_of_cm_lookup(struct device_node *cm_np, + struct cooling_spec *c) + { + for_each_child_of_node_scoped(cm_np, child) { +- struct device_node *tr_np; + int count, i; + +- tr_np = of_parse_phandle(child, "trip", 0); ++ struct device_node *tr_np __free(device_node) = ++ of_parse_phandle(child, "trip", 0); + if (tr_np != trip->priv) + continue; + +-- +2.51.0 + diff --git a/queue-6.12/tools-power-x86-intel-speed-select-fix-file-descript.patch b/queue-6.12/tools-power-x86-intel-speed-select-fix-file-descript.patch new file mode 100644 index 0000000000..62df018eff --- /dev/null +++ b/queue-6.12/tools-power-x86-intel-speed-select-fix-file-descript.patch @@ -0,0 +1,50 @@ +From 12e3b2adbc78932bd20f16d7867b988cd376077f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 15:33:33 +0530 +Subject: tools/power/x86/intel-speed-select: Fix file descriptor leak in + isolate_cpus() + +From: Malaya Kumar Rout + +[ Upstream commit 56c17ee151c6e1a73d77e15b82a8e2130cd8dd16 ] + +The file descriptor opened in isolate_cpus() when (!level) is true was +not being closed before returning, causing a file descriptor leak in +both the error path and the success path. + +When write() fails at line 950, the function returns at line 953 without +closing the file descriptor. Similarly, on success, the function returns +at line 956 without closing the file descriptor. + +Add close(fd) calls before both return statements to fix the resource +leak. This follows the same pattern used elsewhere in the same function +where file descriptors are properly closed before returning (see lines +1005 and 1027). + +Fixes: 997074df658e ("tools/power/x86/intel-speed-select: Use cgroup v2 isolation") +Signed-off-by: Malaya Kumar Rout +Signed-off-by: Srinivas Pandruvada +Signed-off-by: Sasha Levin +--- + tools/power/x86/intel-speed-select/isst-config.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/tools/power/x86/intel-speed-select/isst-config.c b/tools/power/x86/intel-speed-select/isst-config.c +index 5127be34869eb..07729d376f018 100644 +--- a/tools/power/x86/intel-speed-select/isst-config.c ++++ b/tools/power/x86/intel-speed-select/isst-config.c +@@ -932,9 +932,11 @@ int isolate_cpus(struct isst_id *id, int mask_size, cpu_set_t *cpu_mask, int lev + ret = write(fd, "member", strlen("member")); + if (ret == -1) { + printf("Can't update to member\n"); ++ close(fd); + return ret; + } + ++ close(fd); + return 0; + } + +-- +2.51.0 + diff --git a/queue-6.12/tpm-st33zp24-fix-missing-cleanup-on-get_burstcount-e.patch b/queue-6.12/tpm-st33zp24-fix-missing-cleanup-on-get_burstcount-e.patch new file mode 100644 index 0000000000..d4698f281e --- /dev/null +++ b/queue-6.12/tpm-st33zp24-fix-missing-cleanup-on-get_burstcount-e.patch @@ -0,0 +1,43 @@ +From c4b7747b5e915b998ac984d0975b20943fcc6df3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Dec 2025 15:09:27 +0300 +Subject: tpm: st33zp24: Fix missing cleanup on get_burstcount() error + +From: Alper Ak + +[ Upstream commit 3e91b44c93ad2871f89fc2a98c5e4fe6ca5db3d9 ] + +get_burstcount() can return -EBUSY on timeout. When this happens, +st33zp24_send() returns directly without releasing the locality +acquired earlier. + +Use goto out_err to ensure proper cleanup when get_burstcount() fails. + +Fixes: bf38b8710892 ("tpm/tpm_i2c_stm_st33: Split tpm_i2c_tpm_st33 in 2 layers (core + phy)") +Signed-off-by: Alper Ak +Signed-off-by: Jarkko Sakkinen +Signed-off-by: Sasha Levin +--- + drivers/char/tpm/st33zp24/st33zp24.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/char/tpm/st33zp24/st33zp24.c b/drivers/char/tpm/st33zp24/st33zp24.c +index c0771980bc2ff..06caf53a42ee5 100644 +--- a/drivers/char/tpm/st33zp24/st33zp24.c ++++ b/drivers/char/tpm/st33zp24/st33zp24.c +@@ -328,8 +328,10 @@ static int st33zp24_send(struct tpm_chip *chip, unsigned char *buf, + + for (i = 0; i < len - 1;) { + burstcnt = get_burstcount(chip); +- if (burstcnt < 0) +- return burstcnt; ++ if (burstcnt < 0) { ++ ret = burstcnt; ++ goto out_err; ++ } + size = min_t(int, len - i - 1, burstcnt); + ret = tpm_dev->ops->send(tpm_dev->phy_id, TPM_DATA_FIFO, + buf + i, size); +-- +2.51.0 + diff --git a/queue-6.12/tpm-tpm_i2c_infineon-fix-locality-leak-on-get_burstc.patch b/queue-6.12/tpm-tpm_i2c_infineon-fix-locality-leak-on-get_burstc.patch new file mode 100644 index 0000000000..4a07527f5d --- /dev/null +++ b/queue-6.12/tpm-tpm_i2c_infineon-fix-locality-leak-on-get_burstc.patch @@ -0,0 +1,44 @@ +From 779e9ea1b90cff1c75e5d04ca99d1c80ec2a1f8c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Dec 2025 13:23:38 +0300 +Subject: tpm: tpm_i2c_infineon: Fix locality leak on get_burstcount() failure + +From: Alper Ak + +[ Upstream commit bbd6e97c836cbeb9606d7b7e5dcf8a1d89525713 ] + +get_burstcount() can return -EBUSY on timeout. When this happens, the +function returns directly without releasing the locality that was +acquired at the beginning of tpm_tis_i2c_send(). + +Use goto out_err to ensure proper cleanup when get_burstcount() fails. + +Fixes: aad628c1d91a ("char/tpm: Add new driver for Infineon I2C TIS TPM") +Signed-off-by: Alper Ak +Reviewed-by: Jarkko Sakkinen +Signed-off-by: Jarkko Sakkinen +Signed-off-by: Sasha Levin +--- + drivers/char/tpm/tpm_i2c_infineon.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c +index 81d8a78dc6552..3675faa4a00c7 100644 +--- a/drivers/char/tpm/tpm_i2c_infineon.c ++++ b/drivers/char/tpm/tpm_i2c_infineon.c +@@ -543,8 +543,10 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len) + burstcnt = get_burstcount(chip); + + /* burstcnt < 0 = TPM is busy */ +- if (burstcnt < 0) +- return burstcnt; ++ if (burstcnt < 0) { ++ rc = burstcnt; ++ goto out_err; ++ } + + if (burstcnt > (len - 1 - count)) + burstcnt = len - 1 - count; +-- +2.51.0 + diff --git a/queue-6.12/tracing-add-a-comment-about-ftrace_regs-definition.patch b/queue-6.12/tracing-add-a-comment-about-ftrace_regs-definition.patch new file mode 100644 index 0000000000..d772506435 --- /dev/null +++ b/queue-6.12/tracing-add-a-comment-about-ftrace_regs-definition.patch @@ -0,0 +1,61 @@ +From f09309e302f7ccdd7472dee0c1bd5a3723d1b80e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 18 Aug 2024 21:48:13 +0900 +Subject: tracing: Add a comment about ftrace_regs definition + +From: Masami Hiramatsu (Google) + +[ Upstream commit a370b72ec7165ebe1230d0225cbe66f6526e68ef ] + +To clarify what will be expected on ftrace_regs, add a comment to the +architecture independent definition of the ftrace_regs. + +Signed-off-by: Masami Hiramatsu (Google) +Acked-by: Mark Rutland +Signed-off-by: Steven Rostedt (Google) +Stable-dep-of: aea251799998 ("x86/fgraph,bpf: Switch kprobe_multi program stack unwind to hw_regs path") +Signed-off-by: Sasha Levin +--- + include/linux/ftrace.h | 26 ++++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h +index fd5e84d0ec478..42106b3de3961 100644 +--- a/include/linux/ftrace.h ++++ b/include/linux/ftrace.h +@@ -117,6 +117,32 @@ extern int ftrace_enabled; + + #ifndef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS + ++/** ++ * ftrace_regs - ftrace partial/optimal register set ++ * ++ * ftrace_regs represents a group of registers which is used at the ++ * function entry and exit. There are three types of registers. ++ * ++ * - Registers for passing the parameters to callee, including the stack ++ * pointer. (e.g. rcx, rdx, rdi, rsi, r8, r9 and rsp on x86_64) ++ * - Registers for passing the return values to caller. ++ * (e.g. rax and rdx on x86_64) ++ * - Registers for hooking the function call and return including the ++ * frame pointer (the frame pointer is architecture/config dependent) ++ * (e.g. rip, rbp and rsp for x86_64) ++ * ++ * Also, architecture dependent fields can be used for internal process. ++ * (e.g. orig_ax on x86_64) ++ * ++ * On the function entry, those registers will be restored except for ++ * the stack pointer, so that user can change the function parameters ++ * and instruction pointer (e.g. live patching.) ++ * On the function exit, only registers which is used for return values ++ * are restored. ++ * ++ * NOTE: user *must not* access regs directly, only do it via APIs, because ++ * the member can be changed according to the architecture. ++ */ + struct ftrace_regs { + struct pt_regs regs; + }; +-- +2.51.0 + diff --git a/queue-6.12/tracing-add-ftrace_fill_perf_regs-for-perf-event.patch b/queue-6.12/tracing-add-ftrace_fill_perf_regs-for-perf-event.patch new file mode 100644 index 0000000000..31b35211a1 --- /dev/null +++ b/queue-6.12/tracing-add-ftrace_fill_perf_regs-for-perf-event.patch @@ -0,0 +1,171 @@ +From c8d167edd9e9b35f4bfaddab654c00f4f12a6948 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Dec 2024 14:12:59 +0900 +Subject: tracing: Add ftrace_fill_perf_regs() for perf event + +From: Masami Hiramatsu (Google) + +[ Upstream commit d5d01b71996ec03af51b3c0736c92d0fc89703b5 ] + +Add ftrace_fill_perf_regs() which should be compatible with the +perf_fetch_caller_regs(). In other words, the pt_regs returned from the +ftrace_fill_perf_regs() must satisfy 'user_mode(regs) == false' and can be +used for stack tracing. + +Signed-off-by: Masami Hiramatsu (Google) +Acked-by: Will Deacon +Acked-by: Heiko Carstens # s390 +Cc: Alexei Starovoitov +Cc: Florent Revest +Cc: Martin KaFai Lau +Cc: bpf +Cc: Alexei Starovoitov +Cc: Jiri Olsa +Cc: Alan Maguire +Cc: Heiko Carstens +Cc: Mark Rutland +Cc: Catalin Marinas +Cc: Will Deacon +Cc: Michael Ellerman +Cc: Nicholas Piggin +Cc: Christophe Leroy +Cc: Naveen N Rao +Cc: Madhavan Srinivasan +Cc: Vasily Gorbik +Cc: Alexander Gordeev +Cc: Christian Borntraeger +Cc: Sven Schnelle +Cc: Thomas Gleixner +Cc: Ingo Molnar +Cc: Borislav Petkov +Cc: Dave Hansen +Cc: x86@kernel.org +Cc: "H. Peter Anvin" +Link: https://lore.kernel.org/173518997908.391279.15910334347345106424.stgit@devnote2 +Signed-off-by: Steven Rostedt (Google) +Stable-dep-of: aea251799998 ("x86/fgraph,bpf: Switch kprobe_multi program stack unwind to hw_regs path") +Signed-off-by: Sasha Levin +--- + arch/arm64/include/asm/ftrace.h | 7 +++++++ + arch/powerpc/include/asm/ftrace.h | 7 +++++++ + arch/s390/include/asm/ftrace.h | 6 ++++++ + arch/x86/include/asm/ftrace.h | 7 +++++++ + include/linux/ftrace.h | 31 +++++++++++++++++++++++++++++++ + 5 files changed, 58 insertions(+) + +diff --git a/arch/arm64/include/asm/ftrace.h b/arch/arm64/include/asm/ftrace.h +index 09210f853f12d..10e56522122aa 100644 +--- a/arch/arm64/include/asm/ftrace.h ++++ b/arch/arm64/include/asm/ftrace.h +@@ -148,6 +148,13 @@ ftrace_partial_regs(const struct ftrace_regs *fregs, struct pt_regs *regs) + return regs; + } + ++#define arch_ftrace_fill_perf_regs(fregs, _regs) do { \ ++ (_regs)->pc = arch_ftrace_regs(fregs)->pc; \ ++ (_regs)->regs[29] = arch_ftrace_regs(fregs)->fp; \ ++ (_regs)->sp = arch_ftrace_regs(fregs)->sp; \ ++ (_regs)->pstate = PSR_MODE_EL1h; \ ++ } while (0) ++ + int ftrace_regs_query_register_offset(const char *name); + + int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec); +diff --git a/arch/powerpc/include/asm/ftrace.h b/arch/powerpc/include/asm/ftrace.h +index 0edfb874eb02b..407ce6eccc04f 100644 +--- a/arch/powerpc/include/asm/ftrace.h ++++ b/arch/powerpc/include/asm/ftrace.h +@@ -40,6 +40,13 @@ static __always_inline struct pt_regs *arch_ftrace_get_regs(struct ftrace_regs * + return arch_ftrace_regs(fregs)->regs.msr ? &arch_ftrace_regs(fregs)->regs : NULL; + } + ++#define arch_ftrace_fill_perf_regs(fregs, _regs) do { \ ++ (_regs)->result = 0; \ ++ (_regs)->nip = arch_ftrace_regs(fregs)->regs.nip; \ ++ (_regs)->gpr[1] = arch_ftrace_regs(fregs)->regs.gpr[1]; \ ++ asm volatile("mfmsr %0" : "=r" ((_regs)->msr)); \ ++ } while (0) ++ + static __always_inline void + ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs, + unsigned long ip) +diff --git a/arch/s390/include/asm/ftrace.h b/arch/s390/include/asm/ftrace.h +index 5c94c1fc1bc1c..5b7cb49c41ee0 100644 +--- a/arch/s390/include/asm/ftrace.h ++++ b/arch/s390/include/asm/ftrace.h +@@ -76,6 +76,12 @@ ftrace_regs_get_frame_pointer(struct ftrace_regs *fregs) + return ftrace_regs_get_stack_pointer(fregs); + } + ++#define arch_ftrace_fill_perf_regs(fregs, _regs) do { \ ++ (_regs)->psw.mask = 0; \ ++ (_regs)->psw.addr = arch_ftrace_regs(fregs)->regs.psw.addr; \ ++ (_regs)->gprs[15] = arch_ftrace_regs(fregs)->regs.gprs[15]; \ ++ } while (0) ++ + #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS + /* + * When an ftrace registered caller is tracing a function that is +diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h +index d61407c680c28..7e06f8c7937aa 100644 +--- a/arch/x86/include/asm/ftrace.h ++++ b/arch/x86/include/asm/ftrace.h +@@ -47,6 +47,13 @@ arch_ftrace_get_regs(struct ftrace_regs *fregs) + return &arch_ftrace_regs(fregs)->regs; + } + ++#define arch_ftrace_fill_perf_regs(fregs, _regs) do { \ ++ (_regs)->ip = arch_ftrace_regs(fregs)->regs.ip; \ ++ (_regs)->sp = arch_ftrace_regs(fregs)->regs.sp; \ ++ (_regs)->cs = __KERNEL_CS; \ ++ (_regs)->flags = 0; \ ++ } while (0) ++ + #define ftrace_regs_set_instruction_pointer(fregs, _ip) \ + do { arch_ftrace_regs(fregs)->regs.ip = (_ip); } while (0) + +diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h +index c912798ec61d5..4c47fe1e8d113 100644 +--- a/include/linux/ftrace.h ++++ b/include/linux/ftrace.h +@@ -201,6 +201,37 @@ ftrace_partial_regs(struct ftrace_regs *fregs, struct pt_regs *regs) + + #endif /* !CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS || CONFIG_HAVE_FTRACE_REGS_HAVING_PT_REGS */ + ++#ifdef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS ++ ++/* ++ * Please define arch dependent pt_regs which compatible to the ++ * perf_arch_fetch_caller_regs() but based on ftrace_regs. ++ * This requires ++ * - user_mode(_regs) returns false (always kernel mode). ++ * - able to use the _regs for stack trace. ++ */ ++#ifndef arch_ftrace_fill_perf_regs ++/* As same as perf_arch_fetch_caller_regs(), do nothing by default */ ++#define arch_ftrace_fill_perf_regs(fregs, _regs) do {} while (0) ++#endif ++ ++static __always_inline struct pt_regs * ++ftrace_fill_perf_regs(struct ftrace_regs *fregs, struct pt_regs *regs) ++{ ++ arch_ftrace_fill_perf_regs(fregs, regs); ++ return regs; ++} ++ ++#else /* !CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS */ ++ ++static __always_inline struct pt_regs * ++ftrace_fill_perf_regs(struct ftrace_regs *fregs, struct pt_regs *regs) ++{ ++ return &arch_ftrace_regs(fregs)->regs; ++} ++ ++#endif ++ + /* + * When true, the ftrace_regs_{get,set}_*() functions may be used on fregs. + * Note: this can be true even when ftrace_get_regs() cannot provide a pt_regs. +-- +2.51.0 + diff --git a/queue-6.12/tracing-add-ftrace_partial_regs-for-converting-ftrac.patch b/queue-6.12/tracing-add-ftrace_partial_regs-for-converting-ftrac.patch new file mode 100644 index 0000000000..de2d5936c3 --- /dev/null +++ b/queue-6.12/tracing-add-ftrace_partial_regs-for-converting-ftrac.patch @@ -0,0 +1,124 @@ +From 31298c2a2e3e5c0f26bd6b329f67f6497598d5ee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Dec 2024 14:12:47 +0900 +Subject: tracing: Add ftrace_partial_regs() for converting ftrace_regs to + pt_regs + +From: Masami Hiramatsu (Google) + +[ Upstream commit b9b55c8912ce1e5555715d126486bdd63ddfeaec ] + +Add ftrace_partial_regs() which converts the ftrace_regs to pt_regs. +This is for the eBPF which needs this to keep the same pt_regs interface +to access registers. +Thus when replacing the pt_regs with ftrace_regs in fprobes (which is +used by kprobe_multi eBPF event), this will be used. + +If the architecture defines its own ftrace_regs, this copies partial +registers to pt_regs and returns it. If not, ftrace_regs is the same as +pt_regs and ftrace_partial_regs() will return ftrace_regs::regs. + +Signed-off-by: Masami Hiramatsu (Google) +Acked-by: Florent Revest +Cc: Alexei Starovoitov +Cc: Martin KaFai Lau +Cc: bpf +Cc: Alexei Starovoitov +Cc: Jiri Olsa +Cc: Alan Maguire +Cc: Mark Rutland +Cc: Catalin Marinas +Cc: Will Deacon +Cc: Paul Walmsley +Cc: Palmer Dabbelt +Cc: Albert Ou +Link: https://lore.kernel.org/173518996761.391279.4987911298206448122.stgit@devnote2 +Signed-off-by: Steven Rostedt (Google) +Stable-dep-of: aea251799998 ("x86/fgraph,bpf: Switch kprobe_multi program stack unwind to hw_regs path") +Signed-off-by: Sasha Levin +--- + arch/arm64/include/asm/ftrace.h | 13 +++++++++++++ + arch/riscv/include/asm/ftrace.h | 14 ++++++++++++++ + include/linux/ftrace.h | 17 +++++++++++++++++ + 3 files changed, 44 insertions(+) + +diff --git a/arch/arm64/include/asm/ftrace.h b/arch/arm64/include/asm/ftrace.h +index b5fa57b61378e..09210f853f12d 100644 +--- a/arch/arm64/include/asm/ftrace.h ++++ b/arch/arm64/include/asm/ftrace.h +@@ -135,6 +135,19 @@ ftrace_regs_get_frame_pointer(const struct ftrace_regs *fregs) + return arch_ftrace_regs(fregs)->fp; + } + ++static __always_inline struct pt_regs * ++ftrace_partial_regs(const struct ftrace_regs *fregs, struct pt_regs *regs) ++{ ++ struct __arch_ftrace_regs *afregs = arch_ftrace_regs(fregs); ++ ++ memcpy(regs->regs, afregs->regs, sizeof(afregs->regs)); ++ regs->sp = afregs->sp; ++ regs->pc = afregs->pc; ++ regs->regs[29] = afregs->fp; ++ regs->regs[30] = afregs->lr; ++ return regs; ++} ++ + int ftrace_regs_query_register_offset(const char *name); + + int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec); +diff --git a/arch/riscv/include/asm/ftrace.h b/arch/riscv/include/asm/ftrace.h +index d9b80a42fa4df..6c3ae13d1514c 100644 +--- a/arch/riscv/include/asm/ftrace.h ++++ b/arch/riscv/include/asm/ftrace.h +@@ -197,6 +197,20 @@ static __always_inline void ftrace_override_function_with_return(struct ftrace_r + arch_ftrace_regs(fregs)->epc = arch_ftrace_regs(fregs)->ra; + } + ++static __always_inline struct pt_regs * ++ftrace_partial_regs(const struct ftrace_regs *fregs, struct pt_regs *regs) ++{ ++ struct __arch_ftrace_regs *afregs = arch_ftrace_regs(fregs); ++ ++ memcpy(®s->a0, afregs->args, sizeof(afregs->args)); ++ regs->epc = afregs->epc; ++ regs->ra = afregs->ra; ++ regs->sp = afregs->sp; ++ regs->s0 = afregs->s0; ++ regs->t1 = afregs->t1; ++ return regs; ++} ++ + int ftrace_regs_query_register_offset(const char *name); + + void ftrace_graph_func(unsigned long ip, unsigned long parent_ip, +diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h +index b71ad5c04f482..c912798ec61d5 100644 +--- a/include/linux/ftrace.h ++++ b/include/linux/ftrace.h +@@ -184,6 +184,23 @@ static __always_inline struct pt_regs *ftrace_get_regs(struct ftrace_regs *fregs + return arch_ftrace_get_regs(fregs); + } + ++#if !defined(CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS) || \ ++ defined(CONFIG_HAVE_FTRACE_REGS_HAVING_PT_REGS) ++ ++static __always_inline struct pt_regs * ++ftrace_partial_regs(struct ftrace_regs *fregs, struct pt_regs *regs) ++{ ++ /* ++ * If CONFIG_HAVE_FTRACE_REGS_HAVING_PT_REGS=y, ftrace_regs memory ++ * layout is including pt_regs. So always returns that address. ++ * Since arch_ftrace_get_regs() will check some members and may return ++ * NULL, we can not use it. ++ */ ++ return &arch_ftrace_regs(fregs)->regs; ++} ++ ++#endif /* !CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS || CONFIG_HAVE_FTRACE_REGS_HAVING_PT_REGS */ ++ + /* + * When true, the ftrace_regs_{get,set}_*() functions may be used on fregs. + * Note: this can be true even when ftrace_get_regs() cannot provide a pt_regs. +-- +2.51.0 + diff --git a/queue-6.12/tracing-properly-process-error-handling-in-event_his.patch b/queue-6.12/tracing-properly-process-error-handling-in-event_his.patch new file mode 100644 index 0000000000..e131958bce --- /dev/null +++ b/queue-6.12/tracing-properly-process-error-handling-in-event_his.patch @@ -0,0 +1,51 @@ +From 69ba246196a8804ed0f2cc67ecb1428abbf2cfb4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 11 Dec 2025 14:00:58 +0400 +Subject: tracing: Properly process error handling in + event_hist_trigger_parse() + +From: Miaoqian Lin + +[ Upstream commit 0550069cc25f513ce1f109c88f7c1f01d63297db ] + +Memory allocated with trigger_data_alloc() requires trigger_data_free() +for proper cleanup. + +Replace kfree() with trigger_data_free() to fix this. + +Found via static analysis and code review. + +This isn't a real bug due to the current code basically being an open +coded version of trigger_data_free() without the synchronization. The +synchronization isn't needed as this is the error path of creation and +there's nothing to synchronize against yet. Replace the kfree() to be +consistent with the allocation. + +Cc: Masami Hiramatsu +Cc: Mathieu Desnoyers +Cc: Tom Zanussi +Link: https://patch.msgid.link/20251211100058.2381268-1-linmq006@gmail.com +Fixes: e1f187d09e11 ("tracing: Have existing event_command.parse() implementations use helpers") +Signed-off-by: Miaoqian Lin +Signed-off-by: Steven Rostedt (Google) +Signed-off-by: Sasha Levin +--- + kernel/trace/trace_events_hist.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c +index 761d56ed9b8e5..c51c07b2f774f 100644 +--- a/kernel/trace/trace_events_hist.c ++++ b/kernel/trace/trace_events_hist.c +@@ -6881,7 +6881,7 @@ static int event_hist_trigger_parse(struct event_command *cmd_ops, + + remove_hist_vars(hist_data); + +- kfree(trigger_data); ++ trigger_data_free(trigger_data); + + destroy_hist_data(hist_data); + goto out; +-- +2.51.0 + diff --git a/queue-6.12/tracing-remove-duplicate-enable_event_str-and-disabl.patch b/queue-6.12/tracing-remove-duplicate-enable_event_str-and-disabl.patch new file mode 100644 index 0000000000..8e3993c708 --- /dev/null +++ b/queue-6.12/tracing-remove-duplicate-enable_event_str-and-disabl.patch @@ -0,0 +1,44 @@ +From 09ac167b74312df755b912092e1badf17b8f22f1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 13:00:37 -0500 +Subject: tracing: Remove duplicate ENABLE_EVENT_STR and DISABLE_EVENT_STR + macros + +From: Steven Rostedt + +[ Upstream commit 9df0e49c5b9b8d051529be9994e4f92f2d20be6f ] + +The macros ENABLE_EVENT_STR and DISABLE_EVENT_STR were added to trace.h so +that more than one file can have access to them, but was never removed +from their original location. Remove the duplicates. + +Cc: Masami Hiramatsu +Cc: Mathieu Desnoyers +Cc: Tom Zanussi +Link: https://patch.msgid.link/20260126130037.4ba201f9@gandalf.local.home +Fixes: d0bad49bb0a09 ("tracing: Add enable_hist/disable_hist triggers") +Signed-off-by: Steven Rostedt (Google) +Signed-off-by: Sasha Levin +--- + kernel/trace/trace_events.c | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c +index a3d7067eae654..284ea3c3f46a7 100644 +--- a/kernel/trace/trace_events.c ++++ b/kernel/trace/trace_events.c +@@ -3609,11 +3609,6 @@ void trace_put_event_file(struct trace_event_file *file) + EXPORT_SYMBOL_GPL(trace_put_event_file); + + #ifdef CONFIG_DYNAMIC_FTRACE +- +-/* Avoid typos */ +-#define ENABLE_EVENT_STR "enable_event" +-#define DISABLE_EVENT_STR "disable_event" +- + struct event_probe_data { + struct trace_event_file *file; + unsigned long count; +-- +2.51.0 + diff --git a/queue-6.12/ublk-validate-sqe128-flag-before-accessing-the-cmd.patch b/queue-6.12/ublk-validate-sqe128-flag-before-accessing-the-cmd.patch new file mode 100644 index 0000000000..4e022a05a5 --- /dev/null +++ b/queue-6.12/ublk-validate-sqe128-flag-before-accessing-the-cmd.patch @@ -0,0 +1,47 @@ +From e9ebc50512775431d400f4598eb6f0e80245dbba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 10:14:12 -0700 +Subject: ublk: Validate SQE128 flag before accessing the cmd + +From: Govindarajulu Varadarajan + +[ Upstream commit da7e4b75e50c087d2031a92f6646eb90f7045a67 ] + +ublk_ctrl_cmd_dump() accesses (header *)sqe->cmd before +IO_URING_F_SQE128 flag check. This could cause out of boundary memory +access. + +Move the SQE128 flag check earlier in ublk_ctrl_uring_cmd() to return +-EINVAL immediately if the flag is not set. + +Fixes: 71f28f3136af ("ublk_drv: add io_uring based userspace block driver") +Signed-off-by: Govindarajulu Varadarajan +Reviewed-by: Caleb Sander Mateos +Reviewed-by: Ming Lei +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/block/ublk_drv.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c +index 2d46383e8d26b..c6a59f02944fc 100644 +--- a/drivers/block/ublk_drv.c ++++ b/drivers/block/ublk_drv.c +@@ -3026,10 +3026,10 @@ static int ublk_ctrl_uring_cmd(struct io_uring_cmd *cmd, + if (issue_flags & IO_URING_F_NONBLOCK) + return -EAGAIN; + +- ublk_ctrl_cmd_dump(cmd); +- + if (!(issue_flags & IO_URING_F_SQE128)) +- goto out; ++ return -EINVAL; ++ ++ ublk_ctrl_cmd_dump(cmd); + + ret = ublk_check_cmd_op(cmd_op); + if (ret) +-- +2.51.0 + diff --git a/queue-6.12/ucount-check-for-cap_sys_resource-using-ns_capable_n.patch b/queue-6.12/ucount-check-for-cap_sys_resource-using-ns_capable_n.patch new file mode 100644 index 0000000000..fb78a2ce12 --- /dev/null +++ b/queue-6.12/ucount-check-for-cap_sys_resource-using-ns_capable_n.patch @@ -0,0 +1,51 @@ +From 7eb52a620b79558e37ef03e7c79c586e37f38ceb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 15:07:45 +0100 +Subject: ucount: check for CAP_SYS_RESOURCE using ns_capable_noaudit() + +From: Ondrej Mosnacek + +[ Upstream commit 0895a000e4fff9e950a7894210db45973e485c35 ] + +The user.* sysctls implement the ctl_table_root::permissions hook and they +override the file access mode based on the CAP_SYS_RESOURCE capability (at +most rwx if capable, at most r-- if not). The capability is being checked +unconditionally, so if an LSM denies the capability, an audit record may +be logged even when access is in fact granted. + +Given the logic in the set_permissions() function in kernel/ucount.c and +the unfortunate way the permission checking is implemented, it doesn't +seem viable to avoid false positive denials by deferring the capability +check. Thus, do the same as in net_ctl_permissions() (net/sysctl_net.c) - +switch from ns_capable() to ns_capable_noaudit(), so that the check never +logs an audit record. + +Link: https://lkml.kernel.org/r/20260122140745.239428-1-omosnace@redhat.com +Fixes: dbec28460a89 ("userns: Add per user namespace sysctls.") +Signed-off-by: Ondrej Mosnacek +Reviewed-by: Paul Moore +Acked-by: Serge Hallyn +Cc: Eric Biederman +Cc: Alexey Gladkov +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + kernel/ucount.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/ucount.c b/kernel/ucount.c +index 78f4c4255358f..8340f767c1aea 100644 +--- a/kernel/ucount.c ++++ b/kernel/ucount.c +@@ -45,7 +45,7 @@ static int set_permissions(struct ctl_table_header *head, + int mode; + + /* Allow users with CAP_SYS_RESOURCE unrestrained access */ +- if (ns_capable(user_ns, CAP_SYS_RESOURCE)) ++ if (ns_capable_noaudit(user_ns, CAP_SYS_RESOURCE)) + mode = (table->mode & S_IRWXU) >> 6; + else + /* Allow all others at most read-only access */ +-- +2.51.0 + diff --git a/queue-6.12/usb-bdc-fix-sleep-during-atomic.patch b/queue-6.12/usb-bdc-fix-sleep-during-atomic.patch new file mode 100644 index 0000000000..4f00a44205 --- /dev/null +++ b/queue-6.12/usb-bdc-fix-sleep-during-atomic.patch @@ -0,0 +1,41 @@ +From 70732231c6e84aa09ac1777b09e3d70c76f235b9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 12:07:54 -0800 +Subject: usb: bdc: fix sleep during atomic + +From: Justin Chen + +[ Upstream commit f1195ca3b4bbd001d3f1264dce91f83dec7777f5 ] + +bdc_run() can be ran during atomic context leading to a sleep during +atomic warning. Fix this by replacing read_poll_timeout() with +read_poll_timeout_atomic(). + +Fixes: 75ae051efc9b ("usb: gadget: bdc: use readl_poll_timeout() to simplify code") +Signed-off-by: Justin Chen +Reviewed-by: Florian Fainelli +Link: https://patch.msgid.link/20260120200754.2488765-1-justin.chen@broadcom.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/gadget/udc/bdc/bdc_core.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/usb/gadget/udc/bdc/bdc_core.c b/drivers/usb/gadget/udc/bdc/bdc_core.c +index 5149e2b7f0508..7fded329076cc 100644 +--- a/drivers/usb/gadget/udc/bdc/bdc_core.c ++++ b/drivers/usb/gadget/udc/bdc/bdc_core.c +@@ -35,8 +35,8 @@ static int poll_oip(struct bdc *bdc, u32 usec) + u32 status; + int ret; + +- ret = readl_poll_timeout(bdc->regs + BDC_BDCSC, status, +- (BDC_CSTS(status) != BDC_OIP), 10, usec); ++ ret = readl_poll_timeout_atomic(bdc->regs + BDC_BDCSC, status, ++ (BDC_CSTS(status) != BDC_OIP), 10, usec); + if (ret) + dev_err(bdc->dev, "operation timedout BDCSC: 0x%08x\n", status); + else +-- +2.51.0 + diff --git a/queue-6.12/vfio-pci-lock-upstream-bridge-for-vfio_pci_core_disa.patch b/queue-6.12/vfio-pci-lock-upstream-bridge-for-vfio_pci_core_disa.patch new file mode 100644 index 0000000000..6d47515786 --- /dev/null +++ b/queue-6.12/vfio-pci-lock-upstream-bridge-for-vfio_pci_core_disa.patch @@ -0,0 +1,74 @@ +From ac802dde4a264d958dffefb8ee17fc1b5dbd85ad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 15:31:26 +0000 +Subject: vfio/pci: Lock upstream bridge for vfio_pci_core_disable() + +From: Anthony Pighin (Nokia) + +[ Upstream commit 962ae6892d8bd208b2d1e2b358f07551ddc8d32f ] + +The commit 7e89efc6e9e4 ("Lock upstream bridge for pci_reset_function()") +added locking of the upstream bridge to the reset function. To catch +paths that are not properly locked, the commit 920f6468924f ("Warn on +missing cfg_access_lock during secondary bus reset") added a warning +if the PCI configuration space was not locked during a secondary bus reset +request. + +When a VFIO PCI device is released from userspace ownership, an attempt +to reset the PCI device function may be made. If so, and the upstream bridge +is not locked, the release request results in a warning: + + pcieport 0000:00:00.0: unlocked secondary bus reset via: + pci_reset_bus_function+0x188/0x1b8 + +Add missing upstream bridge locking to vfio_pci_core_disable(). + +Fixes: 7e89efc6e9e4 ("PCI: Lock upstream bridge for pci_reset_function()") +Signed-off-by: Anthony Pighin +Link: https://lore.kernel.org/r/BN0PR08MB695171D3AB759C65B6438B5D838DA@BN0PR08MB6951.namprd08.prod.outlook.com +Signed-off-by: Alex Williamson +Signed-off-by: Sasha Levin +--- + drivers/vfio/pci/vfio_pci_core.c | 17 +++++++++++++---- + 1 file changed, 13 insertions(+), 4 deletions(-) + +diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c +index c7ea0b23924af..5f545b45078f8 100644 +--- a/drivers/vfio/pci/vfio_pci_core.c ++++ b/drivers/vfio/pci/vfio_pci_core.c +@@ -590,6 +590,7 @@ EXPORT_SYMBOL_GPL(vfio_pci_core_enable); + + void vfio_pci_core_disable(struct vfio_pci_core_device *vdev) + { ++ struct pci_dev *bridge; + struct pci_dev *pdev = vdev->pdev; + struct vfio_pci_dummy_resource *dummy_res, *tmp; + struct vfio_pci_ioeventfd *ioeventfd, *ioeventfd_tmp; +@@ -696,12 +697,20 @@ void vfio_pci_core_disable(struct vfio_pci_core_device *vdev) + * We can not use the "try" reset interface here, which will + * overwrite the previously restored configuration information. + */ +- if (vdev->reset_works && pci_dev_trylock(pdev)) { +- if (!__pci_reset_function_locked(pdev)) +- vdev->needs_reset = false; +- pci_dev_unlock(pdev); ++ if (vdev->reset_works) { ++ bridge = pci_upstream_bridge(pdev); ++ if (bridge && !pci_dev_trylock(bridge)) ++ goto out_restore_state; ++ if (pci_dev_trylock(pdev)) { ++ if (!__pci_reset_function_locked(pdev)) ++ vdev->needs_reset = false; ++ pci_dev_unlock(pdev); ++ } ++ if (bridge) ++ pci_dev_unlock(bridge); + } + ++out_restore_state: + pci_restore_state(pdev); + out: + pci_disable_device(pdev); +-- +2.51.0 + diff --git a/queue-6.12/watchdog-starfive-wdt-fix-pm-reference-leak-in-probe.patch b/queue-6.12/watchdog-starfive-wdt-fix-pm-reference-leak-in-probe.patch new file mode 100644 index 0000000000..c3baca0e1a --- /dev/null +++ b/queue-6.12/watchdog-starfive-wdt-fix-pm-reference-leak-in-probe.patch @@ -0,0 +1,45 @@ +From f026da91a76b9d12efe3722b6a28b9abf4c1c3f3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 01:29:15 +0800 +Subject: watchdog: starfive-wdt: Fix PM reference leak in probe error path + +From: Kery Qi + +[ Upstream commit 3f2d8d79cceb05a8b8dd200fa81c0dffc59ec46f ] + +The PM reference count is not expected to be incremented on return in +functions starfive_wdt_probe. + +However, pm_runtime_get_sync will increment pm usage counter +even failed. Forgetting to putting operation will result in a +reference leak here. + +Replace it with pm_runtime_resume_and_get to keep usage +counter balanced. + +Fixes: db728ea9c7be ("drivers: watchdog: Add StarFive Watchdog driver") +Signed-off-by: Kery Qi +Reviewed-by: Guenter Roeck +Signed-off-by: Guenter Roeck +Signed-off-by: Wim Van Sebroeck +Signed-off-by: Sasha Levin +--- + drivers/watchdog/starfive-wdt.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/watchdog/starfive-wdt.c b/drivers/watchdog/starfive-wdt.c +index 763b11b6f402c..8244f282bee86 100644 +--- a/drivers/watchdog/starfive-wdt.c ++++ b/drivers/watchdog/starfive-wdt.c +@@ -446,7 +446,7 @@ static int starfive_wdt_probe(struct platform_device *pdev) + platform_set_drvdata(pdev, wdt); + pm_runtime_enable(&pdev->dev); + if (pm_runtime_enabled(&pdev->dev)) { +- ret = pm_runtime_get_sync(&pdev->dev); ++ ret = pm_runtime_resume_and_get(&pdev->dev); + if (ret < 0) + return ret; + } else { +-- +2.51.0 + diff --git a/queue-6.12/wifi-ath10k-sdio-add-missing-lock-protection-in-ath1.patch b/queue-6.12/wifi-ath10k-sdio-add-missing-lock-protection-in-ath1.patch new file mode 100644 index 0000000000..f5a2ac2174 --- /dev/null +++ b/queue-6.12/wifi-ath10k-sdio-add-missing-lock-protection-in-ath1.patch @@ -0,0 +1,62 @@ +From dd1b936df60ab770df09a08457fa59c6ab6fe8a4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 04:58:22 +0000 +Subject: wifi: ath10k: sdio: add missing lock protection in + ath10k_sdio_fw_crashed_dump() + +From: Ziyi Guo + +[ Upstream commit e55ac348089e579fc224569c7bd90340bf2439f9 ] + +ath10k_sdio_fw_crashed_dump() calls ath10k_coredump_new() which requires +ar->dump_mutex to be held, as indicated by lockdep_assert_held() in that +function. However, the SDIO implementation does not acquire this lock, +unlike the PCI and SNOC implementations which properly hold the mutex. + +Additionally, ar->stats.fw_crash_counter is documented as protected by +ar->data_lock in core.h, but the SDIO implementation modifies it without +holding this spinlock. + +Add the missing mutex_lock()/mutex_unlock() around the coredump +operations, and add spin_lock_bh()/spin_unlock_bh() around the +fw_crash_counter increment, following the pattern used in +ath10k_pci_fw_dump_work() and ath10k_snoc_fw_crashed_dump(). + +Fixes: 3c45f21af84e ("ath10k: sdio: add firmware coredump support") +Signed-off-by: Ziyi Guo +Reviewed-by: Baochen Qiang +Link: https://patch.msgid.link/20260123045822.2221549-1-n7l8m4@u.northwestern.edu +Signed-off-by: Jeff Johnson +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/ath/ath10k/sdio.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c +index 6805357ee29e6..2ff2dc4a3f58b 100644 +--- a/drivers/net/wireless/ath/ath10k/sdio.c ++++ b/drivers/net/wireless/ath/ath10k/sdio.c +@@ -2486,7 +2486,11 @@ void ath10k_sdio_fw_crashed_dump(struct ath10k *ar) + if (fast_dump) + ath10k_bmi_start(ar); + ++ mutex_lock(&ar->dump_mutex); ++ ++ spin_lock_bh(&ar->data_lock); + ar->stats.fw_crash_counter++; ++ spin_unlock_bh(&ar->data_lock); + + ath10k_sdio_disable_intrs(ar); + +@@ -2504,6 +2508,8 @@ void ath10k_sdio_fw_crashed_dump(struct ath10k *ar) + + ath10k_sdio_enable_intrs(ar); + ++ mutex_unlock(&ar->dump_mutex); ++ + ath10k_core_start_recovery(ar); + } + +-- +2.51.0 + diff --git a/queue-6.12/wifi-cfg80211-fix-use_for-flag-update-on-bss-refresh.patch b/queue-6.12/wifi-cfg80211-fix-use_for-flag-update-on-bss-refresh.patch new file mode 100644 index 0000000000..fbd2b6a3cb --- /dev/null +++ b/queue-6.12/wifi-cfg80211-fix-use_for-flag-update-on-bss-refresh.patch @@ -0,0 +1,54 @@ +From 2903942ccdb64d6178d850c1699635d6e9521707 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 08:27:33 +0530 +Subject: wifi: cfg80211: Fix use_for flag update on BSS refresh +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Huang Chenming + +[ Upstream commit 4073ea516106e5f98ed0476f89cdede8baa98d37 ] + +Userspace may fail to connect to certain BSS that were initially +marked as unusable due to regulatory restrictions (use_for = 0, +e.g., 6 GHz power type mismatch). Even after these restrictions +are removed and the BSS becomes usable, connection attempts still +fail. + +The issue occurs in cfg80211_update_known_bss() where the use_for +flag is updated using bitwise AND (&=) instead of direct assignment. +Once a BSS is marked with use_for = 0, the AND operation masks out +any subsequent non-zero values, permanently keeping the flag at 0. +This causes __cfg80211_get_bss(), invoked by nl80211_assoc_bss(), to +fail the check "(bss->pub.use_for & use_for) != use_for", thereby +blocking association. + +Replace the bitwise AND operation with direct assignment so the use_for +flag accurately reflects the current BSS state. + +Fixes: d02a12b8e4bb ("wifi: cfg80211: add BSS usage reporting") +Signed-off-by: Huang Chenming +Link: https://patch.msgid.link/20251209025733.2098456-1-chenming.huang@oss.qualcomm.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/wireless/scan.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/wireless/scan.c b/net/wireless/scan.c +index f00ccc6d803be..f9aff1c58e800 100644 +--- a/net/wireless/scan.c ++++ b/net/wireless/scan.c +@@ -1906,7 +1906,7 @@ cfg80211_update_known_bss(struct cfg80211_registered_device *rdev, + ether_addr_copy(known->parent_bssid, new->parent_bssid); + known->pub.max_bssid_indicator = new->pub.max_bssid_indicator; + known->pub.bssid_index = new->pub.bssid_index; +- known->pub.use_for &= new->pub.use_for; ++ known->pub.use_for = new->pub.use_for; + known->pub.cannot_use_reasons = new->pub.cannot_use_reasons; + known->bss_source = new->bss_source; + +-- +2.51.0 + diff --git a/queue-6.12/wifi-cfg80211-stop-nan-and-p2p-in-cfg80211_leave.patch b/queue-6.12/wifi-cfg80211-stop-nan-and-p2p-in-cfg80211_leave.patch new file mode 100644 index 0000000000..86cd9bbc06 --- /dev/null +++ b/queue-6.12/wifi-cfg80211-stop-nan-and-p2p-in-cfg80211_leave.patch @@ -0,0 +1,47 @@ +From 86168dcebd00cffb7e9e7c91d690948ece09516e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 14:04:51 +0200 +Subject: wifi: cfg80211: stop NAN and P2P in cfg80211_leave + +From: Miri Korenblit + +[ Upstream commit e1696c8bd0056bc1a5f7766f58ac333adc203e8a ] + +Seems that there is an assumption that this function should be called +only for netdev interfaces, but it can also be called in suspend, or +from nl80211_netlink_notify (indirectly). +Note that the documentation of NL80211_ATTR_SOCKET_OWNER explicitly +says that NAN interfaces would be destroyed as well in the +nl80211_netlink_notify case. + +Fix this by also stopping P2P and NAN. + +Fixes: cb3b7d87652a ("cfg80211: add start / stop NAN commands") +Reviewed-by: Johannes Berg +Signed-off-by: Miri Korenblit +Link: https://patch.msgid.link/20260107140430.dab142cbef0b.I290cc47836d56dd7e35012ce06bec36c6da688cd@changeid +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/wireless/core.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/net/wireless/core.c b/net/wireless/core.c +index 6bb8a7037d24d..ad32386ed2e11 100644 +--- a/net/wireless/core.c ++++ b/net/wireless/core.c +@@ -1378,8 +1378,10 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev, + cfg80211_leave_ocb(rdev, dev); + break; + case NL80211_IFTYPE_P2P_DEVICE: ++ cfg80211_stop_p2p_device(rdev, wdev); ++ break; + case NL80211_IFTYPE_NAN: +- /* cannot happen, has no netdev */ ++ cfg80211_stop_nan(rdev, wdev); + break; + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_MONITOR: +-- +2.51.0 + diff --git a/queue-6.12/workqueue-factor-out-assign_rescuer_work.patch b/queue-6.12/workqueue-factor-out-assign_rescuer_work.patch new file mode 100644 index 0000000000..c49b5c98a2 --- /dev/null +++ b/queue-6.12/workqueue-factor-out-assign_rescuer_work.patch @@ -0,0 +1,78 @@ +From f6dd385090d93434388162cc3fd36b948bf063d3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 21 Nov 2025 22:57:14 +0800 +Subject: workqueue: Factor out assign_rescuer_work() + +From: Lai Jiangshan + +[ Upstream commit 99ed6f62a46e91dc796b785618d646eeded1b230 ] + +Move the code to assign work to rescuer and assign_rescuer_work(). + +Signed-off-by: Lai Jiangshan +Signed-off-by: Tejun Heo +Stable-dep-of: e5a30c303b07 ("workqueue: Process rescuer work items one-by-one using a cursor") +Signed-off-by: Sasha Levin +--- + kernel/workqueue.c | 29 ++++++++++++++++++----------- + 1 file changed, 18 insertions(+), 11 deletions(-) + +diff --git a/kernel/workqueue.c b/kernel/workqueue.c +index 3c87eb98609c0..256d91aff181d 100644 +--- a/kernel/workqueue.c ++++ b/kernel/workqueue.c +@@ -3407,6 +3407,23 @@ static int worker_thread(void *__worker) + goto woke_up; + } + ++static bool assign_rescuer_work(struct pool_workqueue *pwq, struct worker *rescuer) ++{ ++ struct worker_pool *pool = pwq->pool; ++ struct work_struct *work, *n; ++ ++ /* ++ * Slurp in all works issued via this workqueue and ++ * process'em. ++ */ ++ list_for_each_entry_safe(work, n, &pool->worklist, entry) { ++ if (get_work_pwq(work) == pwq && assign_work(work, rescuer, &n)) ++ pwq->stats[PWQ_STAT_RESCUED]++; ++ } ++ ++ return !list_empty(&rescuer->scheduled); ++} ++ + /** + * rescuer_thread - the rescuer thread function + * @__rescuer: self +@@ -3461,7 +3478,6 @@ static int rescuer_thread(void *__rescuer) + struct pool_workqueue *pwq = list_first_entry(&wq->maydays, + struct pool_workqueue, mayday_node); + struct worker_pool *pool = pwq->pool; +- struct work_struct *work, *n; + + __set_current_state(TASK_RUNNING); + list_del_init(&pwq->mayday_node); +@@ -3472,18 +3488,9 @@ static int rescuer_thread(void *__rescuer) + + raw_spin_lock_irq(&pool->lock); + +- /* +- * Slurp in all works issued via this workqueue and +- * process'em. +- */ + WARN_ON_ONCE(!list_empty(&rescuer->scheduled)); +- list_for_each_entry_safe(work, n, &pool->worklist, entry) { +- if (get_work_pwq(work) == pwq && +- assign_work(work, rescuer, &n)) +- pwq->stats[PWQ_STAT_RESCUED]++; +- } + +- if (!list_empty(&rescuer->scheduled)) { ++ if (assign_rescuer_work(pwq, rescuer)) { + process_scheduled_works(rescuer); + + /* +-- +2.51.0 + diff --git a/queue-6.12/workqueue-only-assign-rescuer-work-when-really-neede.patch b/queue-6.12/workqueue-only-assign-rescuer-work-when-really-neede.patch new file mode 100644 index 0000000000..5872d1f325 --- /dev/null +++ b/queue-6.12/workqueue-only-assign-rescuer-work-when-really-neede.patch @@ -0,0 +1,39 @@ +From 88c23c0acf3de24f108ec65662514cbc5ef2f7e9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 21 Nov 2025 22:57:15 +0800 +Subject: workqueue: Only assign rescuer work when really needed + +From: Lai Jiangshan + +[ Upstream commit 7b05c90b3302cf3d830dfa6f8961376bcaf43b94 ] + +If the pwq does not need rescue (normal workers have been created or +become available), the rescuer can immediately move on to other stalled +pwqs. + +Signed-off-by: Lai Jiangshan +Signed-off-by: Tejun Heo +Stable-dep-of: e5a30c303b07 ("workqueue: Process rescuer work items one-by-one using a cursor") +Signed-off-by: Sasha Levin +--- + kernel/workqueue.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/kernel/workqueue.c b/kernel/workqueue.c +index 256d91aff181d..162b661057330 100644 +--- a/kernel/workqueue.c ++++ b/kernel/workqueue.c +@@ -3412,6 +3412,10 @@ static bool assign_rescuer_work(struct pool_workqueue *pwq, struct worker *rescu + struct worker_pool *pool = pwq->pool; + struct work_struct *work, *n; + ++ /* need rescue? */ ++ if (!pwq->nr_active || !need_to_create_worker(pool)) ++ return false; ++ + /* + * Slurp in all works issued via this workqueue and + * process'em. +-- +2.51.0 + diff --git a/queue-6.12/workqueue-process-rescuer-work-items-one-by-one-usin.patch b/queue-6.12/workqueue-process-rescuer-work-items-one-by-one-usin.patch new file mode 100644 index 0000000000..baf4b53936 --- /dev/null +++ b/queue-6.12/workqueue-process-rescuer-work-items-one-by-one-usin.patch @@ -0,0 +1,202 @@ +From 3af1f54900f554b88e6bc37ee27888c7872c726b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Dec 2025 21:25:18 +0800 +Subject: workqueue: Process rescuer work items one-by-one using a cursor + +From: Lai Jiangshan + +[ Upstream commit e5a30c303b07a4d6083e0f7f051b53add6d93c5d ] + +Previously, the rescuer scanned for all matching work items at once and +processed them within a single rescuer thread, which could cause one +blocking work item to stall all others. + +Make the rescuer process work items one-by-one instead of slurping all +matches in a single pass. + +Break the rescuer loop after finding and processing the first matching +work item, then restart the search to pick up the next. This gives +normal worker threads a chance to process other items which gives them +the opportunity to be processed instead of waiting on the rescuer's +queue and prevents a blocking work item from stalling the rest once +memory pressure is relieved. + +Introduce a dummy cursor work item to avoid potentially O(N^2) +rescans of the work list. The marker records the resume position for +the next scan, eliminating redundant traversals. + +Also introduce RESCUER_BATCH to control the maximum number of work items +the rescuer processes in each turn, and move on to other PWQs when the +limit is reached. + +Cc: ying chen +Reported-by: ying chen +Fixes: e22bee782b3b ("workqueue: implement concurrency managed dynamic worker pool") +Signed-off-by: Lai Jiangshan +Signed-off-by: Tejun Heo +Signed-off-by: Sasha Levin +--- + kernel/workqueue.c | 75 ++++++++++++++++++++++++++++++++++++---------- + 1 file changed, 59 insertions(+), 16 deletions(-) + +diff --git a/kernel/workqueue.c b/kernel/workqueue.c +index 162b661057330..9f7f7244bdc8e 100644 +--- a/kernel/workqueue.c ++++ b/kernel/workqueue.c +@@ -117,6 +117,8 @@ enum wq_internal_consts { + MAYDAY_INTERVAL = HZ / 10, /* and then every 100ms */ + CREATE_COOLDOWN = HZ, /* time to breath after fail */ + ++ RESCUER_BATCH = 16, /* process items per turn */ ++ + /* + * Rescue workers are used only on emergencies and shared by + * all cpus. Give MIN_NICE. +@@ -284,6 +286,7 @@ struct pool_workqueue { + struct list_head pending_node; /* LN: node on wq_node_nr_active->pending_pwqs */ + struct list_head pwqs_node; /* WR: node on wq->pwqs */ + struct list_head mayday_node; /* MD: node on wq->maydays */ ++ struct work_struct mayday_cursor; /* L: cursor on pool->worklist */ + + u64 stats[PWQ_NR_STATS]; + +@@ -1120,6 +1123,12 @@ static struct worker *find_worker_executing_work(struct worker_pool *pool, + return NULL; + } + ++static void mayday_cursor_func(struct work_struct *work) ++{ ++ /* should not be processed, only for marking position */ ++ BUG(); ++} ++ + /** + * move_linked_works - move linked works to a list + * @work: start of series of works to be scheduled +@@ -1182,6 +1191,16 @@ static bool assign_work(struct work_struct *work, struct worker *worker, + + lockdep_assert_held(&pool->lock); + ++ /* The cursor work should not be processed */ ++ if (unlikely(work->func == mayday_cursor_func)) { ++ /* only worker_thread() can possibly take this branch */ ++ WARN_ON_ONCE(worker->rescue_wq); ++ if (nextp) ++ *nextp = list_next_entry(work, entry); ++ list_del_init(&work->entry); ++ return false; ++ } ++ + /* + * A single work shouldn't be executed concurrently by multiple workers. + * __queue_work() ensures that @work doesn't jump to a different pool +@@ -3410,22 +3429,30 @@ static int worker_thread(void *__worker) + static bool assign_rescuer_work(struct pool_workqueue *pwq, struct worker *rescuer) + { + struct worker_pool *pool = pwq->pool; ++ struct work_struct *cursor = &pwq->mayday_cursor; + struct work_struct *work, *n; + + /* need rescue? */ + if (!pwq->nr_active || !need_to_create_worker(pool)) + return false; + +- /* +- * Slurp in all works issued via this workqueue and +- * process'em. +- */ +- list_for_each_entry_safe(work, n, &pool->worklist, entry) { +- if (get_work_pwq(work) == pwq && assign_work(work, rescuer, &n)) ++ /* search from the start or cursor if available */ ++ if (list_empty(&cursor->entry)) ++ work = list_first_entry(&pool->worklist, struct work_struct, entry); ++ else ++ work = list_next_entry(cursor, entry); ++ ++ /* find the next work item to rescue */ ++ list_for_each_entry_safe_from(work, n, &pool->worklist, entry) { ++ if (get_work_pwq(work) == pwq && assign_work(work, rescuer, &n)) { + pwq->stats[PWQ_STAT_RESCUED]++; ++ /* put the cursor for next search */ ++ list_move_tail(&cursor->entry, &n->entry); ++ return true; ++ } + } + +- return !list_empty(&rescuer->scheduled); ++ return false; + } + + /** +@@ -3482,6 +3509,7 @@ static int rescuer_thread(void *__rescuer) + struct pool_workqueue *pwq = list_first_entry(&wq->maydays, + struct pool_workqueue, mayday_node); + struct worker_pool *pool = pwq->pool; ++ unsigned int count = 0; + + __set_current_state(TASK_RUNNING); + list_del_init(&pwq->mayday_node); +@@ -3494,19 +3522,16 @@ static int rescuer_thread(void *__rescuer) + + WARN_ON_ONCE(!list_empty(&rescuer->scheduled)); + +- if (assign_rescuer_work(pwq, rescuer)) { ++ while (assign_rescuer_work(pwq, rescuer)) { + process_scheduled_works(rescuer); + + /* +- * The above execution of rescued work items could +- * have created more to rescue through +- * pwq_activate_first_inactive() or chained +- * queueing. Let's put @pwq back on mayday list so +- * that such back-to-back work items, which may be +- * being used to relieve memory pressure, don't +- * incur MAYDAY_INTERVAL delay inbetween. ++ * If the per-turn work item limit is reached and other ++ * PWQs are in mayday, requeue mayday for this PWQ and ++ * let the rescuer handle the other PWQs first. + */ +- if (pwq->nr_active && need_to_create_worker(pool)) { ++ if (++count > RESCUER_BATCH && !list_empty(&pwq->wq->maydays) && ++ pwq->nr_active && need_to_create_worker(pool)) { + raw_spin_lock(&wq_mayday_lock); + /* + * Queue iff we aren't racing destruction +@@ -3517,9 +3542,14 @@ static int rescuer_thread(void *__rescuer) + list_add_tail(&pwq->mayday_node, &wq->maydays); + } + raw_spin_unlock(&wq_mayday_lock); ++ break; + } + } + ++ /* The cursor can not be left behind without the rescuer watching it. */ ++ if (!list_empty(&pwq->mayday_cursor.entry) && list_empty(&pwq->mayday_node)) ++ list_del_init(&pwq->mayday_cursor.entry); ++ + /* + * Leave this pool. Notify regular workers; otherwise, we end up + * with 0 concurrency and stalling the execution. +@@ -5119,6 +5149,19 @@ static void init_pwq(struct pool_workqueue *pwq, struct workqueue_struct *wq, + INIT_LIST_HEAD(&pwq->pwqs_node); + INIT_LIST_HEAD(&pwq->mayday_node); + kthread_init_work(&pwq->release_work, pwq_release_workfn); ++ ++ /* ++ * Set the dummy cursor work with valid function and get_work_pwq(). ++ * ++ * The cursor work should only be in the pwq->pool->worklist, and ++ * should not be treated as a processable work item. ++ * ++ * WORK_STRUCT_PENDING and WORK_STRUCT_INACTIVE just make it less ++ * surprise for kernel debugging tools and reviewers. ++ */ ++ INIT_WORK(&pwq->mayday_cursor, mayday_cursor_func); ++ atomic_long_set(&pwq->mayday_cursor.data, (unsigned long)pwq | ++ WORK_STRUCT_PENDING | WORK_STRUCT_PWQ | WORK_STRUCT_INACTIVE); + } + + /* sync @pwq with the current state of its associated wq and link it */ +-- +2.51.0 + diff --git a/queue-6.12/x86-fgraph-bpf-fix-stack-orc-unwind-from-kprobe_mult.patch b/queue-6.12/x86-fgraph-bpf-fix-stack-orc-unwind-from-kprobe_mult.patch new file mode 100644 index 0000000000..81c648eefb --- /dev/null +++ b/queue-6.12/x86-fgraph-bpf-fix-stack-orc-unwind-from-kprobe_mult.patch @@ -0,0 +1,118 @@ +From 2b0ada9cdfd8e4368db3ab976d019f54e9bcdfd4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Nov 2025 22:54:03 +0100 +Subject: x86/fgraph,bpf: Fix stack ORC unwind from kprobe_multi return probe + +From: Jiri Olsa + +[ Upstream commit 20a0bc10272fa17a44fc857c31574a8306f60d20 ] + +Currently we don't get stack trace via ORC unwinder on top of fgraph exit +handler. We can see that when generating stacktrace from kretprobe_multi +bpf program which is based on fprobe/fgraph. + +The reason is that the ORC unwind code won't get pass the return_to_handler +callback installed by fgraph return probe machinery. + +Solving this by creating stack frame in return_to_handler expected by +ftrace_graph_ret_addr function to recover original return address and +continue with the unwind. + +Also updating the pt_regs data with cs/flags/rsp which are needed for +successful stack retrieval from ebpf bpf_get_stackid helper. + - in get_perf_callchain we check user_mode(regs) so CS has to be set + - in perf_callchain_kernel we call perf_hw_regs(regs), so EFLAGS/FIXED + has to be unset + +Acked-by: Masami Hiramatsu (Google) +Signed-off-by: Jiri Olsa +Link: https://lore.kernel.org/r/20251104215405.168643-3-jolsa@kernel.org +Signed-off-by: Alexei Starovoitov +Acked-by: Steven Rostedt (Google) +Stable-dep-of: aea251799998 ("x86/fgraph,bpf: Switch kprobe_multi program stack unwind to hw_regs path") +Signed-off-by: Sasha Levin +--- + arch/x86/include/asm/ftrace.h | 5 +++++ + arch/x86/kernel/ftrace_64.S | 8 +++++++- + include/linux/ftrace.h | 10 +++++++++- + 3 files changed, 21 insertions(+), 2 deletions(-) + +diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h +index 7e06f8c7937aa..bb72bf879aed6 100644 +--- a/arch/x86/include/asm/ftrace.h ++++ b/arch/x86/include/asm/ftrace.h +@@ -47,6 +47,11 @@ arch_ftrace_get_regs(struct ftrace_regs *fregs) + return &arch_ftrace_regs(fregs)->regs; + } + ++#define arch_ftrace_partial_regs(regs) do { \ ++ regs->flags &= ~X86_EFLAGS_FIXED; \ ++ regs->cs = __KERNEL_CS; \ ++} while (0) ++ + #define arch_ftrace_fill_perf_regs(fregs, _regs) do { \ + (_regs)->ip = arch_ftrace_regs(fregs)->regs.ip; \ + (_regs)->sp = arch_ftrace_regs(fregs)->regs.sp; \ +diff --git a/arch/x86/kernel/ftrace_64.S b/arch/x86/kernel/ftrace_64.S +index d516472285967..8a3cff618692c 100644 +--- a/arch/x86/kernel/ftrace_64.S ++++ b/arch/x86/kernel/ftrace_64.S +@@ -349,12 +349,17 @@ SYM_CODE_START(return_to_handler) + UNWIND_HINT_UNDEFINED + ANNOTATE_NOENDBR + ++ /* Restore return_to_handler value that got eaten by previous ret instruction. */ ++ subq $8, %rsp ++ UNWIND_HINT_FUNC ++ + /* Save ftrace_regs for function exit context */ + subq $(FRAME_SIZE), %rsp + + movq %rax, RAX(%rsp) + movq %rdx, RDX(%rsp) + movq %rbp, RBP(%rsp) ++ movq %rsp, RSP(%rsp) + movq %rsp, %rdi + + call ftrace_return_to_handler +@@ -363,7 +368,8 @@ SYM_CODE_START(return_to_handler) + movq RDX(%rsp), %rdx + movq RAX(%rsp), %rax + +- addq $(FRAME_SIZE), %rsp ++ addq $(FRAME_SIZE) + 8, %rsp ++ + /* + * Jump back to the old return address. This cannot be JMP_NOSPEC rdi + * since IBT would demand that contain ENDBR, which simply isn't so for +diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h +index 4c47fe1e8d113..079a8152855b2 100644 +--- a/include/linux/ftrace.h ++++ b/include/linux/ftrace.h +@@ -187,6 +187,10 @@ static __always_inline struct pt_regs *ftrace_get_regs(struct ftrace_regs *fregs + #if !defined(CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS) || \ + defined(CONFIG_HAVE_FTRACE_REGS_HAVING_PT_REGS) + ++#ifndef arch_ftrace_partial_regs ++#define arch_ftrace_partial_regs(regs) do {} while (0) ++#endif ++ + static __always_inline struct pt_regs * + ftrace_partial_regs(struct ftrace_regs *fregs, struct pt_regs *regs) + { +@@ -196,7 +200,11 @@ ftrace_partial_regs(struct ftrace_regs *fregs, struct pt_regs *regs) + * Since arch_ftrace_get_regs() will check some members and may return + * NULL, we can not use it. + */ +- return &arch_ftrace_regs(fregs)->regs; ++ regs = &arch_ftrace_regs(fregs)->regs; ++ ++ /* Allow arch specific updates to regs. */ ++ arch_ftrace_partial_regs(regs); ++ return regs; + } + + #endif /* !CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS || CONFIG_HAVE_FTRACE_REGS_HAVING_PT_REGS */ +-- +2.51.0 + diff --git a/queue-6.12/x86-fgraph-bpf-switch-kprobe_multi-program-stack-unw.patch b/queue-6.12/x86-fgraph-bpf-switch-kprobe_multi-program-stack-unw.patch new file mode 100644 index 0000000000..03c8f21dd7 --- /dev/null +++ b/queue-6.12/x86-fgraph-bpf-switch-kprobe_multi-program-stack-unw.patch @@ -0,0 +1,111 @@ +From 570f8ecf8ba0c72f646e3d77d8fd0e88ab7d48ff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 22:18:33 +0100 +Subject: x86/fgraph,bpf: Switch kprobe_multi program stack unwind to hw_regs + path +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jiri Olsa + +[ Upstream commit aea251799998aa1b78eacdfb308f18ea114ea5b3 ] + +Mahe reported missing function from stack trace on top of kprobe +multi program. The missing function is the very first one in the +stacktrace, the one that the bpf program is attached to. + + # bpftrace -e 'kprobe:__x64_sys_newuname* { print(kstack)}' + Attaching 1 probe... + + do_syscall_64+134 + entry_SYSCALL_64_after_hwframe+118 + + ('*' is used for kprobe_multi attachment) + +The reason is that the previous change (the Fixes commit) fixed +stack unwind for tracepoint, but removed attached function address +from the stack trace on top of kprobe multi programs, which I also +overlooked in the related test (check following patch). + +The tracepoint and kprobe_multi have different stack setup, but use +same unwind path. I think it's better to keep the previous change, +which fixed tracepoint unwind and instead change the kprobe multi +unwind as explained below. + +The bpf program stack unwind calls perf_callchain_kernel for kernel +portion and it follows two unwind paths based on X86_EFLAGS_FIXED +bit in pt_regs.flags. + +When the bit set we unwind from stack represented by pt_regs argument, +otherwise we unwind currently executed stack up to 'first_frame' +boundary. + +The 'first_frame' value is taken from regs.rsp value, but ftrace_caller +and ftrace_regs_caller (ftrace trampoline) functions set the regs.rsp +to the previous stack frame, so we skip the attached function entry. + +If we switch kprobe_multi unwind to use the X86_EFLAGS_FIXED bit, +we set the start of the unwind to the attached function address. +As another benefit we also cut extra unwind cycles needed to reach +the 'first_frame' boundary. + +The speedup can be measured with trigger bench for kprobe_multi +program and stacktrace support. + +- trigger bench with stacktrace on current code: + + kprobe-multi : 0.810 ± 0.001M/s + kretprobe-multi: 0.808 ± 0.001M/s + +- and with the fix: + + kprobe-multi : 1.264 ± 0.001M/s + kretprobe-multi: 1.401 ± 0.002M/s + +With the fix, the entry probe stacktrace: + + # bpftrace -e 'kprobe:__x64_sys_newuname* { print(kstack)}' + Attaching 1 probe... + + __x64_sys_newuname+9 + do_syscall_64+134 + entry_SYSCALL_64_after_hwframe+118 + +The return probe skips the attached function, because it's no longer +on the stack at the point of the unwind and this way is the same how +standard kretprobe works. + + # bpftrace -e 'kretprobe:__x64_sys_newuname* { print(kstack)}' + Attaching 1 probe... + + do_syscall_64+134 + entry_SYSCALL_64_after_hwframe+118 + +Fixes: 6d08340d1e35 ("Revert "perf/x86: Always store regs->ip in perf_callchain_kernel()"") +Reported-by: Mahe Tardy +Signed-off-by: Jiri Olsa +Signed-off-by: Andrii Nakryiko +Acked-by: Steven Rostedt (Google) +Link: https://lore.kernel.org/bpf/20260126211837.472802-3-jolsa@kernel.org +Signed-off-by: Sasha Levin +--- + arch/x86/include/asm/ftrace.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h +index bb72bf879aed6..c42f7169fc1c0 100644 +--- a/arch/x86/include/asm/ftrace.h ++++ b/arch/x86/include/asm/ftrace.h +@@ -48,7 +48,7 @@ arch_ftrace_get_regs(struct ftrace_regs *fregs) + } + + #define arch_ftrace_partial_regs(regs) do { \ +- regs->flags &= ~X86_EFLAGS_FIXED; \ ++ regs->flags |= X86_EFLAGS_FIXED; \ + regs->cs = __KERNEL_CS; \ + } while (0) + +-- +2.51.0 + diff --git a/queue-6.12/xdrgen-fix-struct-prefix-for-typedef-types-in-progra.patch b/queue-6.12/xdrgen-fix-struct-prefix-for-typedef-types-in-progra.patch new file mode 100644 index 0000000000..39a5a6c0c0 --- /dev/null +++ b/queue-6.12/xdrgen-fix-struct-prefix-for-typedef-types-in-progra.patch @@ -0,0 +1,83 @@ +From db346321c0231b106b0623546e6ca2335515a46f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Dec 2025 11:15:32 -0500 +Subject: xdrgen: Fix struct prefix for typedef types in program wrappers + +From: Chuck Lever + +[ Upstream commit bf0fe9ad3d597d8e1378dc9953ca96dfc3addb2b ] + +The program templates for decoder/argument.j2 and encoder/result.j2 +unconditionally add 'struct' prefix to all types. This is incorrect +when an RPC protocol specification lists a typedef'd basic type or +an enum as a procedure argument or result (e.g., NFSv2's fhandle or +stat), resulting in compiler errors when building generated C code. + +Fixes: 4b132aacb076 ("tools: Add xdrgen") +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + tools/net/sunrpc/xdrgen/generators/__init__.py | 3 ++- + .../sunrpc/xdrgen/templates/C/program/decoder/argument.j2 | 4 ++++ + .../net/sunrpc/xdrgen/templates/C/program/encoder/result.j2 | 6 ++++++ + 3 files changed, 12 insertions(+), 1 deletion(-) + +diff --git a/tools/net/sunrpc/xdrgen/generators/__init__.py b/tools/net/sunrpc/xdrgen/generators/__init__.py +index fd24574612742..49191cd10ab70 100644 +--- a/tools/net/sunrpc/xdrgen/generators/__init__.py ++++ b/tools/net/sunrpc/xdrgen/generators/__init__.py +@@ -6,7 +6,7 @@ import sys + from jinja2 import Environment, FileSystemLoader, Template + + from xdr_ast import _XdrAst, Specification, _RpcProgram, _XdrTypeSpecifier +-from xdr_ast import public_apis, pass_by_reference, get_header_name ++from xdr_ast import public_apis, pass_by_reference, structs, get_header_name + from xdr_parse import get_xdr_annotate + + +@@ -22,6 +22,7 @@ def create_jinja2_environment(language: str, xdr_type: str) -> Environment: + environment.globals["annotate"] = get_xdr_annotate() + environment.globals["public_apis"] = public_apis + environment.globals["pass_by_reference"] = pass_by_reference ++ environment.globals["structs"] = structs + return environment + case _: + raise NotImplementedError("Language not supported") +diff --git a/tools/net/sunrpc/xdrgen/templates/C/program/decoder/argument.j2 b/tools/net/sunrpc/xdrgen/templates/C/program/decoder/argument.j2 +index 0b1709cca0d4a..19b219dd276d3 100644 +--- a/tools/net/sunrpc/xdrgen/templates/C/program/decoder/argument.j2 ++++ b/tools/net/sunrpc/xdrgen/templates/C/program/decoder/argument.j2 +@@ -14,7 +14,11 @@ bool {{ program }}_svc_decode_{{ argument }}(struct svc_rqst *rqstp, struct xdr_ + {% if argument == 'void' %} + return xdrgen_decode_void(xdr); + {% else %} ++{% if argument in structs %} + struct {{ argument }} *argp = rqstp->rq_argp; ++{% else %} ++ {{ argument }} *argp = rqstp->rq_argp; ++{% endif %} + + return xdrgen_decode_{{ argument }}(xdr, argp); + {% endif %} +diff --git a/tools/net/sunrpc/xdrgen/templates/C/program/encoder/result.j2 b/tools/net/sunrpc/xdrgen/templates/C/program/encoder/result.j2 +index 6fc61a5d47b7f..746592cfda562 100644 +--- a/tools/net/sunrpc/xdrgen/templates/C/program/encoder/result.j2 ++++ b/tools/net/sunrpc/xdrgen/templates/C/program/encoder/result.j2 +@@ -14,8 +14,14 @@ bool {{ program }}_svc_encode_{{ result }}(struct svc_rqst *rqstp, struct xdr_st + {% if result == 'void' %} + return xdrgen_encode_void(xdr); + {% else %} ++{% if result in structs %} + struct {{ result }} *resp = rqstp->rq_resp; + + return xdrgen_encode_{{ result }}(xdr, resp); ++{% else %} ++ {{ result }} *resp = rqstp->rq_resp; ++ ++ return xdrgen_encode_{{ result }}(xdr, *resp); ++{% endif %} + {% endif %} + } +-- +2.51.0 + diff --git a/queue-6.12/xdrgen-initialize-data-pointer-for-zero-length-items.patch b/queue-6.12/xdrgen-initialize-data-pointer-for-zero-length-items.patch new file mode 100644 index 0000000000..a556115ab2 --- /dev/null +++ b/queue-6.12/xdrgen-initialize-data-pointer-for-zero-length-items.patch @@ -0,0 +1,70 @@ +From 223f22b4887ce954ea6ec8d40ee1a88d8283a48d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 10:41:09 -0500 +Subject: xdrgen: Initialize data pointer for zero-length items + +From: Chuck Lever + +[ Upstream commit 27b0fcae8f535fb882b1876227a935dcfdf576aa ] + +The xdrgen decoders for strings and opaque data had an +optimization that skipped calling xdr_inline_decode() when the +item length was zero. This left the data pointer uninitialized, +which could lead to unpredictable behavior when callers access +it. + +Remove the zero-length check and always call xdr_inline_decode(). +When passed a length of zero, xdr_inline_decode() returns the +current buffer position, which is valid and matches the behavior +of hand-coded XDR decoders throughout the kernel. + +Fixes: 4b132aacb076 ("tools: Add xdrgen") +Reviewed-by: Jeff Layton +Reviewed-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + include/linux/sunrpc/xdrgen/_builtins.h | 20 ++++++++------------ + 1 file changed, 8 insertions(+), 12 deletions(-) + +diff --git a/include/linux/sunrpc/xdrgen/_builtins.h b/include/linux/sunrpc/xdrgen/_builtins.h +index 66ca3ece951ab..a5ab75d2db044 100644 +--- a/include/linux/sunrpc/xdrgen/_builtins.h ++++ b/include/linux/sunrpc/xdrgen/_builtins.h +@@ -188,12 +188,10 @@ xdrgen_decode_string(struct xdr_stream *xdr, string *ptr, u32 maxlen) + return false; + if (unlikely(maxlen && len > maxlen)) + return false; +- if (len != 0) { +- p = xdr_inline_decode(xdr, len); +- if (unlikely(!p)) +- return false; +- ptr->data = (unsigned char *)p; +- } ++ p = xdr_inline_decode(xdr, len); ++ if (unlikely(!p)) ++ return false; ++ ptr->data = (unsigned char *)p; + ptr->len = len; + return true; + } +@@ -219,12 +217,10 @@ xdrgen_decode_opaque(struct xdr_stream *xdr, opaque *ptr, u32 maxlen) + return false; + if (unlikely(maxlen && len > maxlen)) + return false; +- if (len != 0) { +- p = xdr_inline_decode(xdr, len); +- if (unlikely(!p)) +- return false; +- ptr->data = (u8 *)p; +- } ++ p = xdr_inline_decode(xdr, len); ++ if (unlikely(!p)) ++ return false; ++ ptr->data = (u8 *)p; + ptr->len = len; + return true; + } +-- +2.51.0 + diff --git a/queue-6.12/xen-virtio-don-t-use-grant-dma-ops-when-running-as-d.patch b/queue-6.12/xen-virtio-don-t-use-grant-dma-ops-when-running-as-d.patch new file mode 100644 index 0000000000..7e2d059998 --- /dev/null +++ b/queue-6.12/xen-virtio-don-t-use-grant-dma-ops-when-running-as-d.patch @@ -0,0 +1,45 @@ +From 21847c5c0702710c3c4dd62c118ac8195896e5d7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Jan 2026 17:36:50 +0000 +Subject: xen/virtio: Don't use grant-dma-ops when running as Dom0 + +From: Teddy Astie + +[ Upstream commit dc8ea8714311e549ee93a2b0bdd5487d20bfadbf ] + +Dom0 inherit devices from the machine and is usually in PV mode. +If we are running in a virtual that has virtio devices, these devices +would be considered as using grants with Dom0 as backend, while being +the said Dom0 itself, while we want to use these devices like regular +PCI devices. + +Fix this by preventing grant-dma-ops from being used when running as Dom0 +(initial domain). We still keep the device-tree logic as-is. + +Signed-off-by: Teddy Astie +Fixes: 61367688f1fb0 ("xen/virtio: enable grant based virtio on x86") +Reviewed-by: Juergen Gross +Signed-off-by: Juergen Gross +Message-ID: <6698564dd2270a9f7377b78ebfb20cb425cabbe8.1767720955.git.teddy.astie@vates.tech> +Signed-off-by: Sasha Levin +--- + drivers/xen/grant-dma-ops.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/xen/grant-dma-ops.c b/drivers/xen/grant-dma-ops.c +index 29257d2639dbf..43a918c498c6c 100644 +--- a/drivers/xen/grant-dma-ops.c ++++ b/drivers/xen/grant-dma-ops.c +@@ -362,7 +362,8 @@ static int xen_grant_init_backend_domid(struct device *dev, + if (np) { + ret = xen_dt_grant_init_backend_domid(dev, np, backend_domid); + of_node_put(np); +- } else if (IS_ENABLED(CONFIG_XEN_VIRTIO_FORCE_GRANT) || xen_pv_domain()) { ++ } else if (!xen_initial_domain() && ++ (IS_ENABLED(CONFIG_XEN_VIRTIO_FORCE_GRANT) || xen_pv_domain())) { + dev_info(dev, "Using dom0 as backend\n"); + *backend_domid = 0; + ret = 0; +-- +2.51.0 + diff --git a/queue-6.12/xfrm-fix-ip_rt_bug-race-in-icmp_route_lookup-reverse.patch b/queue-6.12/xfrm-fix-ip_rt_bug-race-in-icmp_route_lookup-reverse.patch new file mode 100644 index 0000000000..ecb7593fa8 --- /dev/null +++ b/queue-6.12/xfrm-fix-ip_rt_bug-race-in-icmp_route_lookup-reverse.patch @@ -0,0 +1,100 @@ +From a1d79332adab326efca0f3bae346fdbcff7eb128 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 13:02:19 +0800 +Subject: xfrm: fix ip_rt_bug race in icmp_route_lookup reverse path + +From: Jiayuan Chen + +[ Upstream commit 81b84de32bb27ae1ae2eb9acf0420e9d0d14bf00 ] + +icmp_route_lookup() performs multiple route lookups to find a suitable +route for sending ICMP error messages, with special handling for XFRM +(IPsec) policies. + +The lookup sequence is: +1. First, lookup output route for ICMP reply (dst = original src) +2. Pass through xfrm_lookup() for policy check +3. If blocked (-EPERM) or dst is not local, enter "reverse path" +4. In reverse path, call xfrm_decode_session_reverse() to get fl4_dec + which reverses the original packet's flow (saddr<->daddr swapped) +5. If fl4_dec.saddr is local (we are the original destination), use + __ip_route_output_key() for output route lookup +6. If fl4_dec.saddr is NOT local (we are a forwarding node), use + ip_route_input() to simulate the reverse packet's input path +7. Finally, pass rt2 through xfrm_lookup() with XFRM_LOOKUP_ICMP flag + +The bug occurs in step 6: ip_route_input() is called with fl4_dec.daddr +(original packet's source) as destination. If this address becomes local +between the initial check and ip_route_input() call (e.g., due to +concurrent "ip addr add"), ip_route_input() returns a LOCAL route with +dst.output set to ip_rt_bug. + +This route is then used for ICMP output, causing dst_output() to call +ip_rt_bug(), triggering a WARN_ON: + + ------------[ cut here ]------------ + WARNING: net/ipv4/route.c:1275 at ip_rt_bug+0x21/0x30, CPU#1 + Call Trace: + + ip_push_pending_frames+0x202/0x240 + icmp_push_reply+0x30d/0x430 + __icmp_send+0x1149/0x24f0 + ip_options_compile+0xa2/0xd0 + ip_rcv_finish_core+0x829/0x1950 + ip_rcv+0x2d7/0x420 + __netif_receive_skb_one_core+0x185/0x1f0 + netif_receive_skb+0x90/0x450 + tun_get_user+0x3413/0x3fb0 + tun_chr_write_iter+0xe4/0x220 + ... + +Fix this by checking rt2->rt_type after ip_route_input(). If it's +RTN_LOCAL, the route cannot be used for output, so treat it as an error. + +The reproducer requires kernel modification to widen the race window, +making it unsuitable as a selftest. It is available at: + + https://gist.github.com/mrpre/eae853b72ac6a750f5d45d64ddac1e81 + +Reported-by: syzbot+e738404dcd14b620923c@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/000000000000b1060905eada8881@google.com/T/ +Closes: https://lore.kernel.org/r/20260128090523.356953-1-jiayuan.chen@linux.dev +Fixes: 8b7817f3a959 ("[IPSEC]: Add ICMP host relookup support") +Signed-off-by: Jiayuan Chen +Signed-off-by: Jiayuan Chen +Link: https://patch.msgid.link/20260206050220.59642-1-jiayuan.chen@linux.dev +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/ipv4/icmp.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c +index 2bda14908273c..ee24728fc60bf 100644 +--- a/net/ipv4/icmp.c ++++ b/net/ipv4/icmp.c +@@ -555,6 +555,21 @@ static struct rtable *icmp_route_lookup(struct net *net, struct flowi4 *fl4, + /* steal dst entry from skb_in, don't drop refcnt */ + skb_dstref_steal(skb_in); + skb_dstref_restore(skb_in, orefdst); ++ ++ /* ++ * At this point, fl4_dec.daddr should NOT be local (we ++ * checked fl4_dec.saddr above). However, a race condition ++ * may occur if the address is added to the interface ++ * concurrently. In that case, ip_route_input() returns a ++ * LOCAL route with dst.output=ip_rt_bug, which must not ++ * be used for output. ++ */ ++ if (!err && rt2 && rt2->rt_type == RTN_LOCAL) { ++ net_warn_ratelimited("detected local route for %pI4 during ICMP sending, src %pI4\n", ++ &fl4_dec.daddr, &fl4_dec.saddr); ++ dst_release(&rt2->dst); ++ err = -EINVAL; ++ } + } + + if (err) +-- +2.51.0 + diff --git a/queue-6.18/accel-amdxdna-fix-incorrect-error-code-returned-for-.patch b/queue-6.18/accel-amdxdna-fix-incorrect-error-code-returned-for-.patch new file mode 100644 index 0000000000..e4f56d10b4 --- /dev/null +++ b/queue-6.18/accel-amdxdna-fix-incorrect-error-code-returned-for-.patch @@ -0,0 +1,40 @@ +From f83a177f60b0ca1983231b4bae4d6317778c5a00 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 10:40:37 -0800 +Subject: accel/amdxdna: Fix incorrect error code returned for failed chain + command + +From: Lizhi Hou + +[ Upstream commit 750817a7c41de083ca5d73052e97bb7b67d7c394 ] + +The driver currently returns an incorrect error code when a chain command +fails. In this case, ERT_CMD_STATE_ERROR is expected to be reported for +failed chain commands. + +Fixes: aac243092b70 ("accel/amdxdna: Add command execution") +Reviewed-by: Mario Limonciello (AMD) +Reviewed-by: Maciej Falkowski +Signed-off-by: Lizhi Hou +Link: https://patch.msgid.link/20260203184037.2751889-1-lizhi.hou@amd.com +Signed-off-by: Sasha Levin +--- + drivers/accel/amdxdna/aie2_ctx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/accel/amdxdna/aie2_ctx.c b/drivers/accel/amdxdna/aie2_ctx.c +index c3cb24d96cee3..4610f491f0881 100644 +--- a/drivers/accel/amdxdna/aie2_ctx.c ++++ b/drivers/accel/amdxdna/aie2_ctx.c +@@ -294,7 +294,7 @@ aie2_sched_cmdlist_resp_handler(void *handle, void __iomem *data, size_t size) + ret = -EINVAL; + goto out; + } +- amdxdna_cmd_set_state(cmd_abo, fail_cmd_status); ++ amdxdna_cmd_set_state(cmd_abo, ERT_CMD_STATE_ERROR); + + if (amdxdna_cmd_get_op(cmd_abo) == ERT_CMD_CHAIN) { + struct amdxdna_cmd_chain *cc = amdxdna_cmd_get_payload(cmd_abo, NULL); +-- +2.51.0 + diff --git a/queue-6.18/accel-amdxdna-fix-memory-leak-in-amdxdna_ubuf_map.patch b/queue-6.18/accel-amdxdna-fix-memory-leak-in-amdxdna_ubuf_map.patch new file mode 100644 index 0000000000..5a433c8627 --- /dev/null +++ b/queue-6.18/accel-amdxdna-fix-memory-leak-in-amdxdna_ubuf_map.patch @@ -0,0 +1,55 @@ +From e950f055d49bb0f163523e3c1e582adfbfe0762f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 01:10:22 +0800 +Subject: accel/amdxdna: Fix memory leak in amdxdna_ubuf_map + +From: Zishun Yi + +[ Upstream commit 84dd57fb0359500092f1101409ca32091731490d ] + +The amdxdna_ubuf_map() function allocates memory for sg and +internal sg table structures, but it fails to free them if subsequent +operations (sg_alloc_table_from_pages or dma_map_sgtable) fail. + +Fixes: bd72d4acda10 ("accel/amdxdna: Support user space allocated buffer") +Signed-off-by: Zishun Yi +Reviewed-by: Lizhi Hou +Reviewed-by: Min Ma +Signed-off-by: Lizhi Hou +Link: https://patch.msgid.link/20260129171022.68578-1-zishun.yi.dev@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/accel/amdxdna/amdxdna_ubuf.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/drivers/accel/amdxdna/amdxdna_ubuf.c b/drivers/accel/amdxdna/amdxdna_ubuf.c +index 077b2261cf2a0..9e3b3b055caa8 100644 +--- a/drivers/accel/amdxdna/amdxdna_ubuf.c ++++ b/drivers/accel/amdxdna/amdxdna_ubuf.c +@@ -34,15 +34,21 @@ static struct sg_table *amdxdna_ubuf_map(struct dma_buf_attachment *attach, + ret = sg_alloc_table_from_pages(sg, ubuf->pages, ubuf->nr_pages, 0, + ubuf->nr_pages << PAGE_SHIFT, GFP_KERNEL); + if (ret) +- return ERR_PTR(ret); ++ goto err_free_sg; + + if (ubuf->flags & AMDXDNA_UBUF_FLAG_MAP_DMA) { + ret = dma_map_sgtable(attach->dev, sg, direction, 0); + if (ret) +- return ERR_PTR(ret); ++ goto err_free_table; + } + + return sg; ++ ++err_free_table: ++ sg_free_table(sg); ++err_free_sg: ++ kfree(sg); ++ return ERR_PTR(ret); + } + + static void amdxdna_ubuf_unmap(struct dma_buf_attachment *attach, +-- +2.51.0 + diff --git a/queue-6.18/accel-amdxdna-fix-notifier_wq-flushing-warning.patch b/queue-6.18/accel-amdxdna-fix-notifier_wq-flushing-warning.patch new file mode 100644 index 0000000000..1261f1cdb9 --- /dev/null +++ b/queue-6.18/accel-amdxdna-fix-notifier_wq-flushing-warning.patch @@ -0,0 +1,39 @@ +From 7e3fcf5629946bef74e82f2e08b5fe7aad9dbcd6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Jan 2026 09:36:24 -0800 +Subject: accel/amdxdna: Fix notifier_wq flushing warning + +From: Lizhi Hou + +[ Upstream commit b36178488d479e9a53bbef2b01280378b5586e60 ] + +Create notifier_wq with WQ_MEM_RECLAIM flag to fix the possible warning. + + workqueue: WQ_MEM_RECLAIM amdxdna_js:drm_sched_free_job_work [gpu_sched] is flushing !WQ_MEM_RECLAIM notifier_wq:0x0 + +Fixes: e486147c912f ("accel/amdxdna: Add BO import and export") +Reviewed-by: Mario Limonciello (AMD) +Reviewed-by: Maciej Falkowski +Signed-off-by: Lizhi Hou +Link: https://patch.msgid.link/20260113173624.256053-1-lizhi.hou@amd.com +Signed-off-by: Sasha Levin +--- + drivers/accel/amdxdna/amdxdna_pci_drv.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/accel/amdxdna/amdxdna_pci_drv.c b/drivers/accel/amdxdna/amdxdna_pci_drv.c +index 569cd703729d3..ccf2d1de558c0 100644 +--- a/drivers/accel/amdxdna/amdxdna_pci_drv.c ++++ b/drivers/accel/amdxdna/amdxdna_pci_drv.c +@@ -292,7 +292,7 @@ static int amdxdna_probe(struct pci_dev *pdev, const struct pci_device_id *id) + fs_reclaim_release(GFP_KERNEL); + } + +- xdna->notifier_wq = alloc_ordered_workqueue("notifier_wq", 0); ++ xdna->notifier_wq = alloc_ordered_workqueue("notifier_wq", WQ_MEM_RECLAIM); + if (!xdna->notifier_wq) + return -ENOMEM; + +-- +2.51.0 + diff --git a/queue-6.18/accel-amdxdna-fix-race-where-send-ring-appears-full-.patch b/queue-6.18/accel-amdxdna-fix-race-where-send-ring-appears-full-.patch new file mode 100644 index 0000000000..0087e6b795 --- /dev/null +++ b/queue-6.18/accel-amdxdna-fix-race-where-send-ring-appears-full-.patch @@ -0,0 +1,92 @@ +From 930e2e3bc0f6707d105617ec88110a77eb2d5399 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 10 Dec 2025 20:51:25 -0800 +Subject: accel/amdxdna: Fix race where send ring appears full due to delayed + head update + +From: Lizhi Hou + +[ Upstream commit 343f5683cfa443000904c88ce2e23656375fc51c ] + +The firmware sends a response and interrupts the driver before advancing +the mailbox send ring head pointer. As a result, the driver may observe +the response and attempt to send a new request before the firmware has +updated the head pointer. In this window, the send ring still appears +full, causing the driver to incorrectly fail the send operation. + +This race can be triggered more easily in a multithreaded environment, +leading to unexpected and spurious "send ring full" failures. + +To address this, poll the send ring head pointer for up to 100us before +returning a full-ring condition. This allows the firmware time to update +the head pointer. + +Fixes: b87f920b9344 ("accel/amdxdna: Support hardware mailbox") +Reviewed-by: Mario Limonciello (AMD) +Signed-off-by: Lizhi Hou +Link: https://patch.msgid.link/20251211045125.1724604-1-lizhi.hou@amd.com +Signed-off-by: Sasha Levin +--- + drivers/accel/amdxdna/amdxdna_mailbox.c | 27 +++++++++++++++---------- + 1 file changed, 16 insertions(+), 11 deletions(-) + +diff --git a/drivers/accel/amdxdna/amdxdna_mailbox.c b/drivers/accel/amdxdna/amdxdna_mailbox.c +index 6634a4d5717ff..a80c77a478bff 100644 +--- a/drivers/accel/amdxdna/amdxdna_mailbox.c ++++ b/drivers/accel/amdxdna/amdxdna_mailbox.c +@@ -206,26 +206,34 @@ mailbox_send_msg(struct mailbox_channel *mb_chann, struct mailbox_msg *mb_msg) + u32 head, tail; + u32 start_addr; + u32 tmp_tail; ++ int ret; + + head = mailbox_get_headptr(mb_chann, CHAN_RES_X2I); + tail = mb_chann->x2i_tail; +- ringbuf_size = mailbox_get_ringbuf_size(mb_chann, CHAN_RES_X2I); ++ ringbuf_size = mailbox_get_ringbuf_size(mb_chann, CHAN_RES_X2I) - sizeof(u32); + start_addr = mb_chann->res[CHAN_RES_X2I].rb_start_addr; + tmp_tail = tail + mb_msg->pkg_size; + +- if (tail < head && tmp_tail >= head) +- goto no_space; +- +- if (tail >= head && (tmp_tail > ringbuf_size - sizeof(u32) && +- mb_msg->pkg_size >= head)) +- goto no_space; + +- if (tail >= head && tmp_tail > ringbuf_size - sizeof(u32)) { ++check_again: ++ if (tail >= head && tmp_tail > ringbuf_size) { + write_addr = mb_chann->mb->res.ringbuf_base + start_addr + tail; + writel(TOMBSTONE, write_addr); + + /* tombstone is set. Write from the start of the ringbuf */ + tail = 0; ++ tmp_tail = tail + mb_msg->pkg_size; ++ } ++ ++ if (tail < head && tmp_tail >= head) { ++ ret = read_poll_timeout(mailbox_get_headptr, head, ++ tmp_tail < head || tail >= head, ++ 1, 100, false, mb_chann, CHAN_RES_X2I); ++ if (ret) ++ return ret; ++ ++ if (tail >= head) ++ goto check_again; + } + + write_addr = mb_chann->mb->res.ringbuf_base + start_addr + tail; +@@ -237,9 +245,6 @@ mailbox_send_msg(struct mailbox_channel *mb_chann, struct mailbox_msg *mb_msg) + mb_msg->pkg.header.id); + + return 0; +- +-no_space: +- return -ENOSPC; + } + + static int +-- +2.51.0 + diff --git a/queue-6.18/accel-amdxdna-hold-mm-structure-across-iommu_sva_unb.patch b/queue-6.18/accel-amdxdna-hold-mm-structure-across-iommu_sva_unb.patch new file mode 100644 index 0000000000..60db5cbee4 --- /dev/null +++ b/queue-6.18/accel-amdxdna-hold-mm-structure-across-iommu_sva_unb.patch @@ -0,0 +1,64 @@ +From 1dce966e7ef82dc3b2265d8e5b484d7cad293324 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 16:23:56 -0800 +Subject: accel/amdxdna: Hold mm structure across iommu_sva_unbind_device() + +From: Lizhi Hou + +[ Upstream commit a9162439ad792afcddc04718408ec1380b7a5f63 ] + +Some tests trigger a crash in iommu_sva_unbind_device() due to +accessing iommu_mm after the associated mm structure has been +freed. + +Fix this by taking an explicit reference to the mm structure +after successfully binding the device, and releasing it only +after the device is unbound. This ensures the mm remains valid +for the entire SVA bind/unbind lifetime. + +Fixes: be462c97b7df ("accel/amdxdna: Add hardware context") +Reviewed-by: Mario Limonciello (AMD) +Signed-off-by: Lizhi Hou +Link: https://patch.msgid.link/20260128002356.1858122-1-lizhi.hou@amd.com +Signed-off-by: Sasha Levin +--- + drivers/accel/amdxdna/amdxdna_pci_drv.c | 3 +++ + drivers/accel/amdxdna/amdxdna_pci_drv.h | 1 + + 2 files changed, 4 insertions(+) + +diff --git a/drivers/accel/amdxdna/amdxdna_pci_drv.c b/drivers/accel/amdxdna/amdxdna_pci_drv.c +index ccf2d1de558c0..88643e28af84b 100644 +--- a/drivers/accel/amdxdna/amdxdna_pci_drv.c ++++ b/drivers/accel/amdxdna/amdxdna_pci_drv.c +@@ -88,6 +88,8 @@ static int amdxdna_drm_open(struct drm_device *ddev, struct drm_file *filp) + ret = -ENODEV; + goto unbind_sva; + } ++ client->mm = current->mm; ++ mmgrab(client->mm); + init_srcu_struct(&client->hwctx_srcu); + xa_init_flags(&client->hwctx_xa, XA_FLAGS_ALLOC); + mutex_init(&client->mm_lock); +@@ -127,6 +129,7 @@ static void amdxdna_drm_close(struct drm_device *ddev, struct drm_file *filp) + drm_gem_object_put(to_gobj(client->dev_heap)); + + iommu_sva_unbind_device(client->sva); ++ mmdrop(client->mm); + + XDNA_DBG(xdna, "pid %d closed", client->pid); + kfree(client); +diff --git a/drivers/accel/amdxdna/amdxdna_pci_drv.h b/drivers/accel/amdxdna/amdxdna_pci_drv.h +index 72d6696d49da8..64009ca249827 100644 +--- a/drivers/accel/amdxdna/amdxdna_pci_drv.h ++++ b/drivers/accel/amdxdna/amdxdna_pci_drv.h +@@ -128,6 +128,7 @@ struct amdxdna_client { + + struct iommu_sva *sva; + int pasid; ++ struct mm_struct *mm; + }; + + #define amdxdna_for_each_hwctx(client, hwctx_id, entry) \ +-- +2.51.0 + diff --git a/queue-6.18/accel-amdxdna-stop-job-scheduling-across-aie2_releas.patch b/queue-6.18/accel-amdxdna-stop-job-scheduling-across-aie2_releas.patch new file mode 100644 index 0000000000..ad52bb93b1 --- /dev/null +++ b/queue-6.18/accel-amdxdna-stop-job-scheduling-across-aie2_releas.patch @@ -0,0 +1,54 @@ +From 3e313503f9f68a5aff8f311e16177099a5f33645 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 16:32:55 -0800 +Subject: accel/amdxdna: Stop job scheduling across aie2_release_resource() + +From: Lizhi Hou + +[ Upstream commit f1370241fe8045702bc9d0812b996791f0500f1b ] + +Running jobs on a hardware context while it is in the process of +releasing resources can lead to use-after-free and crashes. + +Fix this by stopping job scheduling before calling +aie2_release_resource() and restarting it after the release completes. +Additionally, aie2_sched_job_run() now checks whether the hardware +context is still active. + +Fixes: 4fd6ca90fc7f ("accel/amdxdna: Refactor hardware context destroy routine") +Reviewed-by: Mario Limonciello (AMD) +Signed-off-by: Lizhi Hou +Link: https://patch.msgid.link/20260130003255.2083255-1-lizhi.hou@amd.com +Signed-off-by: Sasha Levin +--- + drivers/accel/amdxdna/aie2_ctx.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/accel/amdxdna/aie2_ctx.c b/drivers/accel/amdxdna/aie2_ctx.c +index 75246c481fa50..c3cb24d96cee3 100644 +--- a/drivers/accel/amdxdna/aie2_ctx.c ++++ b/drivers/accel/amdxdna/aie2_ctx.c +@@ -317,6 +317,9 @@ aie2_sched_job_run(struct drm_sched_job *sched_job) + struct dma_fence *fence; + int ret; + ++ if (hwctx->status != HWCTX_STAT_READY) ++ return NULL; ++ + if (!mmget_not_zero(job->mm)) + return ERR_PTR(-ESRCH); + +@@ -684,7 +687,10 @@ void aie2_hwctx_fini(struct amdxdna_hwctx *hwctx) + aie2_hwctx_wait_for_idle(hwctx); + + /* Request fw to destroy hwctx and cancel the rest pending requests */ ++ drm_sched_stop(&hwctx->priv->sched, NULL); + aie2_release_resource(hwctx); ++ hwctx->status = HWCTX_STAT_STOP; ++ drm_sched_start(&hwctx->priv->sched, 0); + + mutex_unlock(&xdna->dev_lock); + drm_sched_entity_destroy(&hwctx->priv->entity); +-- +2.51.0 + diff --git a/queue-6.18/acpi-processor-update-cpuidle-driver-check-in-__acpi.patch b/queue-6.18/acpi-processor-update-cpuidle-driver-check-in-__acpi.patch new file mode 100644 index 0000000000..49496ecdfc --- /dev/null +++ b/queue-6.18/acpi-processor-update-cpuidle-driver-check-in-__acpi.patch @@ -0,0 +1,48 @@ +From f9435dc84dc7c5ba0691ad2906b8b8abaf0f51e3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 23 Dec 2025 18:09:11 +0800 +Subject: ACPI: processor: Update cpuidle driver check in + __acpi_processor_start() + +From: Rafael J. Wysocki + +[ Upstream commit 0089ce1c056aee547115bdc25c223f8f88c08498 ] + +Commit 7a8c994cbb2d ("ACPI: processor: idle: Optimize ACPI idle +driver registration") moved the ACPI idle driver registration to +acpi_processor_driver_init() and acpi_processor_power_init() does +not register an idle driver any more. + +Accordingly, the cpuidle driver check in __acpi_processor_start() needs +to be updated to avoid calling acpi_processor_power_init() without a +cpuidle driver, in which case the registration of the cpuidle device +in that function would lead to a NULL pointer dereference in +__cpuidle_register_device(). + +Fixes: 7a8c994cbb2d ("ACPI: processor: idle: Optimize ACPI idle driver registration") +Signed-off-by: Rafael J. Wysocki +Reviewed-by: Mario Limonciello (AMD) +Tested-by: Borislav Petkov (AMD) +Link: https://patch.msgid.link/20251223100914.2407069-4-lihuisong@huawei.com +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/processor_driver.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c +index 65e779be64ffc..7644de24d2faa 100644 +--- a/drivers/acpi/processor_driver.c ++++ b/drivers/acpi/processor_driver.c +@@ -166,7 +166,7 @@ static int __acpi_processor_start(struct acpi_device *device) + if (result && !IS_ENABLED(CONFIG_ACPI_CPU_FREQ_PSS)) + dev_dbg(&device->dev, "CPPC data invalid or not present\n"); + +- if (!cpuidle_get_driver() || cpuidle_get_driver() == &acpi_idle_driver) ++ if (cpuidle_get_driver() == &acpi_idle_driver) + acpi_processor_power_init(pr); + + acpi_pss_perf_init(pr); +-- +2.51.0 + diff --git a/queue-6.18/acpica-fix-null-pointer-dereference-in-acpi_ev_addre.patch b/queue-6.18/acpica-fix-null-pointer-dereference-in-acpi_ev_addre.patch new file mode 100644 index 0000000000..8dcbaee98d --- /dev/null +++ b/queue-6.18/acpica-fix-null-pointer-dereference-in-acpi_ev_addre.patch @@ -0,0 +1,40 @@ +From 1938634d11d5cc994bac395a8a0cb756bd542629 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 13:20:17 +0100 +Subject: ACPICA: Fix NULL pointer dereference in + acpi_ev_address_space_dispatch() + +From: Alexey Simakov + +[ Upstream commit f851e03bce968ff9b3faad1b616062e1244fd38d ] + +Cover a missed execution path with a new check. + +Fixes: 0acf24ad7e10 ("ACPICA: Add support for PCC Opregion special context data") +Link: https://github.com/acpica/acpica/commit/f421dd9dd897 +Signed-off-by: Alexey Simakov +Signed-off-by: Rafael J. Wysocki +Link: https://patch.msgid.link/3030574.e9J7NaK4W3@rafael.j.wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/acpica/evregion.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c +index fa3475da7ea9b..b6198f73c81df 100644 +--- a/drivers/acpi/acpica/evregion.c ++++ b/drivers/acpi/acpica/evregion.c +@@ -163,7 +163,9 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, + return_ACPI_STATUS(AE_NOT_EXIST); + } + +- if (region_obj->region.space_id == ACPI_ADR_SPACE_PLATFORM_COMM) { ++ if (field_obj ++ && region_obj->region.space_id == ++ ACPI_ADR_SPACE_PLATFORM_COMM) { + struct acpi_pcc_info *ctx = + handler_desc->address_space.context; + +-- +2.51.0 + diff --git a/queue-6.18/af_unix-fix-memleak-of-newsk-in-unix_stream_connect.patch b/queue-6.18/af_unix-fix-memleak-of-newsk-in-unix_stream_connect.patch new file mode 100644 index 0000000000..2f268b50c9 --- /dev/null +++ b/queue-6.18/af_unix-fix-memleak-of-newsk-in-unix_stream_connect.patch @@ -0,0 +1,56 @@ +From 308d6c1f67b34dbd3bfa4b317913ab71ec0041db Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Feb 2026 23:22:34 +0000 +Subject: af_unix: Fix memleak of newsk in unix_stream_connect(). + +From: Kuniyuki Iwashima + +[ Upstream commit 6884028cd7f275f8bcb854a347265cb1fb0e4bea ] + +When prepare_peercred() fails in unix_stream_connect(), +unix_release_sock() is not called for newsk, and the memory +is leaked. + +Let's move prepare_peercred() before unix_create1(). + +Fixes: fd0a109a0f6b ("net, pidfs: prepare for handing out pidfds for reaped sk->sk_peer_pid") +Signed-off-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260207232236.2557549-1-kuniyu@google.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/unix/af_unix.c | 11 +++-------- + 1 file changed, 3 insertions(+), 8 deletions(-) + +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index c634a7fc86090..9dad3af700af3 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -1671,10 +1671,9 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr, + + timeo = sock_sndtimeo(sk, flags & O_NONBLOCK); + +- /* First of all allocate resources. +- * If we will make it after state is locked, +- * we will have to recheck all again in any case. +- */ ++ err = prepare_peercred(&peercred); ++ if (err) ++ goto out; + + /* create new sock for complete connection */ + newsk = unix_create1(net, NULL, 0, sock->type); +@@ -1683,10 +1682,6 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr, + goto out; + } + +- err = prepare_peercred(&peercred); +- if (err) +- goto out; +- + /* Allocate skb for sending to listening sock */ + skb = sock_wmalloc(newsk, 1, 0, GFP_KERNEL); + if (!skb) { +-- +2.51.0 + diff --git a/queue-6.18/alsa-pcm-relax-__free-variable-declarations.patch b/queue-6.18/alsa-pcm-relax-__free-variable-declarations.patch new file mode 100644 index 0000000000..39f361a566 --- /dev/null +++ b/queue-6.18/alsa-pcm-relax-__free-variable-declarations.patch @@ -0,0 +1,268 @@ +From fca8fd9bd8b3c0becf7a65e93050857cb32579fe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Dec 2025 15:06:25 +0100 +Subject: ALSA: pcm: Relax __free() variable declarations + +From: Takashi Iwai + +[ Upstream commit f3d233daf011abbad2f6ebd0e545b42d2f378a4f ] + +We used to have a variable declaration with __free() initialized with +NULL. This was to keep the old coding style rule, but recently it's +relaxed and rather recommends to follow the new rule to declare in +place of use for __free() -- which avoids potential deadlocks or UAFs +with nested cleanups. + +Although the current code has no bug, per se, let's follow the new +standard and move the declaration to the place of assignment (or +directly assign the allocated result) instead of NULL initializations. + +Fixes: ae9213984864 ("ALSA: pcm: Use automatic cleanup of kfree()") +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20251216140634.171890-4-tiwai@suse.de +Signed-off-by: Sasha Levin +--- + sound/core/pcm.c | 4 ++-- + sound/core/pcm_compat.c | 9 ++++---- + sound/core/pcm_native.c | 50 +++++++++++++++++++++-------------------- + 3 files changed, 33 insertions(+), 30 deletions(-) + +diff --git a/sound/core/pcm.c b/sound/core/pcm.c +index 283aac441fa0a..0b512085eb63f 100644 +--- a/sound/core/pcm.c ++++ b/sound/core/pcm.c +@@ -328,13 +328,13 @@ static const char *snd_pcm_oss_format_name(int format) + static void snd_pcm_proc_info_read(struct snd_pcm_substream *substream, + struct snd_info_buffer *buffer) + { +- struct snd_pcm_info *info __free(kfree) = NULL; + int err; + + if (! substream) + return; + +- info = kmalloc(sizeof(*info), GFP_KERNEL); ++ struct snd_pcm_info *info __free(kfree) = ++ kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return; + +diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c +index 54eb9bd8eb218..e86f68f1f23c1 100644 +--- a/sound/core/pcm_compat.c ++++ b/sound/core/pcm_compat.c +@@ -235,7 +235,6 @@ static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream, + int refine, + struct snd_pcm_hw_params32 __user *data32) + { +- struct snd_pcm_hw_params *data __free(kfree) = NULL; + struct snd_pcm_runtime *runtime; + int err; + +@@ -243,7 +242,8 @@ static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream, + if (!runtime) + return -ENOTTY; + +- data = kmalloc(sizeof(*data), GFP_KERNEL); ++ struct snd_pcm_hw_params *data __free(kfree) = ++ kmalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + +@@ -332,7 +332,6 @@ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream, + compat_caddr_t buf; + compat_caddr_t __user *bufptr; + u32 frames; +- void __user **bufs __free(kfree) = NULL; + int err, ch, i; + + if (! substream->runtime) +@@ -349,7 +348,9 @@ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream, + get_user(frames, &data32->frames)) + return -EFAULT; + bufptr = compat_ptr(buf); +- bufs = kmalloc_array(ch, sizeof(void __user *), GFP_KERNEL); ++ ++ void __user **bufs __free(kfree) = ++ kmalloc_array(ch, sizeof(void __user *), GFP_KERNEL); + if (bufs == NULL) + return -ENOMEM; + for (i = 0; i < ch; i++) { +diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c +index 932a9bf98cbc0..844ee1b4d286f 100644 +--- a/sound/core/pcm_native.c ++++ b/sound/core/pcm_native.c +@@ -242,10 +242,10 @@ int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info) + int snd_pcm_info_user(struct snd_pcm_substream *substream, + struct snd_pcm_info __user * _info) + { +- struct snd_pcm_info *info __free(kfree) = NULL; + int err; ++ struct snd_pcm_info *info __free(kfree) = ++ kmalloc(sizeof(*info), GFP_KERNEL); + +- info = kmalloc(sizeof(*info), GFP_KERNEL); + if (! info) + return -ENOMEM; + err = snd_pcm_info(substream, info); +@@ -364,7 +364,6 @@ static int constrain_params_by_rules(struct snd_pcm_substream *substream, + struct snd_pcm_hw_constraints *constrs = + &substream->runtime->hw_constraints; + unsigned int k; +- unsigned int *rstamps __free(kfree) = NULL; + unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1]; + unsigned int stamp; + struct snd_pcm_hw_rule *r; +@@ -380,7 +379,8 @@ static int constrain_params_by_rules(struct snd_pcm_substream *substream, + * Each member of 'rstamps' array represents the sequence number of + * recent application of corresponding rule. + */ +- rstamps = kcalloc(constrs->rules_num, sizeof(unsigned int), GFP_KERNEL); ++ unsigned int *rstamps __free(kfree) = ++ kcalloc(constrs->rules_num, sizeof(unsigned int), GFP_KERNEL); + if (!rstamps) + return -ENOMEM; + +@@ -583,10 +583,10 @@ EXPORT_SYMBOL(snd_pcm_hw_refine); + static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params __user * _params) + { +- struct snd_pcm_hw_params *params __free(kfree) = NULL; + int err; ++ struct snd_pcm_hw_params *params __free(kfree) = ++ memdup_user(_params, sizeof(*params)); + +- params = memdup_user(_params, sizeof(*params)); + if (IS_ERR(params)) + return PTR_ERR(params); + +@@ -889,10 +889,10 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, + static int snd_pcm_hw_params_user(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params __user * _params) + { +- struct snd_pcm_hw_params *params __free(kfree) = NULL; + int err; ++ struct snd_pcm_hw_params *params __free(kfree) = ++ memdup_user(_params, sizeof(*params)); + +- params = memdup_user(_params, sizeof(*params)); + if (IS_ERR(params)) + return PTR_ERR(params); + +@@ -2267,7 +2267,6 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) + { + struct snd_pcm_file *pcm_file; + struct snd_pcm_substream *substream1; +- struct snd_pcm_group *group __free(kfree) = NULL; + struct snd_pcm_group *target_group; + bool nonatomic = substream->pcm->nonatomic; + CLASS(fd, f)(fd); +@@ -2283,7 +2282,8 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) + if (substream == substream1) + return -EINVAL; + +- group = kzalloc(sizeof(*group), GFP_KERNEL); ++ struct snd_pcm_group *group __free(kfree) = ++ kzalloc(sizeof(*group), GFP_KERNEL); + if (!group) + return -ENOMEM; + snd_pcm_group_init(group); +@@ -3291,7 +3291,6 @@ static int snd_pcm_xfern_frames_ioctl(struct snd_pcm_substream *substream, + { + struct snd_xfern xfern; + struct snd_pcm_runtime *runtime = substream->runtime; +- void *bufs __free(kfree) = NULL; + snd_pcm_sframes_t result; + + if (runtime->state == SNDRV_PCM_STATE_OPEN) +@@ -3303,7 +3302,8 @@ static int snd_pcm_xfern_frames_ioctl(struct snd_pcm_substream *substream, + if (copy_from_user(&xfern, _xfern, sizeof(xfern))) + return -EFAULT; + +- bufs = memdup_array_user(xfern.bufs, runtime->channels, sizeof(void *)); ++ void *bufs __free(kfree) = ++ memdup_array_user(xfern.bufs, runtime->channels, sizeof(void *)); + if (IS_ERR(bufs)) + return PTR_ERR(bufs); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) +@@ -3577,7 +3577,6 @@ static ssize_t snd_pcm_readv(struct kiocb *iocb, struct iov_iter *to) + struct snd_pcm_runtime *runtime; + snd_pcm_sframes_t result; + unsigned long i; +- void __user **bufs __free(kfree) = NULL; + snd_pcm_uframes_t frames; + const struct iovec *iov = iter_iov(to); + +@@ -3596,7 +3595,9 @@ static ssize_t snd_pcm_readv(struct kiocb *iocb, struct iov_iter *to) + if (!frame_aligned(runtime, iov->iov_len)) + return -EINVAL; + frames = bytes_to_samples(runtime, iov->iov_len); +- bufs = kmalloc_array(to->nr_segs, sizeof(void *), GFP_KERNEL); ++ ++ void __user **bufs __free(kfree) = ++ kmalloc_array(to->nr_segs, sizeof(void *), GFP_KERNEL); + if (bufs == NULL) + return -ENOMEM; + for (i = 0; i < to->nr_segs; ++i) { +@@ -3616,7 +3617,6 @@ static ssize_t snd_pcm_writev(struct kiocb *iocb, struct iov_iter *from) + struct snd_pcm_runtime *runtime; + snd_pcm_sframes_t result; + unsigned long i; +- void __user **bufs __free(kfree) = NULL; + snd_pcm_uframes_t frames; + const struct iovec *iov = iter_iov(from); + +@@ -3634,7 +3634,9 @@ static ssize_t snd_pcm_writev(struct kiocb *iocb, struct iov_iter *from) + !frame_aligned(runtime, iov->iov_len)) + return -EINVAL; + frames = bytes_to_samples(runtime, iov->iov_len); +- bufs = kmalloc_array(from->nr_segs, sizeof(void *), GFP_KERNEL); ++ ++ void __user **bufs __free(kfree) = ++ kmalloc_array(from->nr_segs, sizeof(void *), GFP_KERNEL); + if (bufs == NULL) + return -ENOMEM; + for (i = 0; i < from->nr_segs; ++i) { +@@ -4106,15 +4108,15 @@ static void snd_pcm_hw_convert_to_old_params(struct snd_pcm_hw_params_old *opara + static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params_old __user * _oparams) + { +- struct snd_pcm_hw_params *params __free(kfree) = NULL; +- struct snd_pcm_hw_params_old *oparams __free(kfree) = NULL; + int err; + +- params = kmalloc(sizeof(*params), GFP_KERNEL); ++ struct snd_pcm_hw_params *params __free(kfree) = ++ kmalloc(sizeof(*params), GFP_KERNEL); + if (!params) + return -ENOMEM; + +- oparams = memdup_user(_oparams, sizeof(*oparams)); ++ struct snd_pcm_hw_params_old *oparams __free(kfree) = ++ memdup_user(_oparams, sizeof(*oparams)); + if (IS_ERR(oparams)) + return PTR_ERR(oparams); + snd_pcm_hw_convert_from_old_params(params, oparams); +@@ -4135,15 +4137,15 @@ static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream, + static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params_old __user * _oparams) + { +- struct snd_pcm_hw_params *params __free(kfree) = NULL; +- struct snd_pcm_hw_params_old *oparams __free(kfree) = NULL; + int err; + +- params = kmalloc(sizeof(*params), GFP_KERNEL); ++ struct snd_pcm_hw_params *params __free(kfree) = ++ kmalloc(sizeof(*params), GFP_KERNEL); + if (!params) + return -ENOMEM; + +- oparams = memdup_user(_oparams, sizeof(*oparams)); ++ struct snd_pcm_hw_params_old *oparams __free(kfree) = ++ memdup_user(_oparams, sizeof(*oparams)); + if (IS_ERR(oparams)) + return PTR_ERR(oparams); + +-- +2.51.0 + diff --git a/queue-6.18/alsa-vmaster-relax-__free-variable-declarations.patch b/queue-6.18/alsa-vmaster-relax-__free-variable-declarations.patch new file mode 100644 index 0000000000..0cd17c211c --- /dev/null +++ b/queue-6.18/alsa-vmaster-relax-__free-variable-declarations.patch @@ -0,0 +1,77 @@ +From c9ea3b88522f32ce634fdeb2b56f24441dc0c38a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Dec 2025 15:06:30 +0100 +Subject: ALSA: vmaster: Relax __free() variable declarations + +From: Takashi Iwai + +[ Upstream commit 3b7c7bda39e1e48f926fb3d280a5f5d20a939857 ] + +We used to have a variable declaration with __free() initialized with +NULL. This was to keep the old coding style rule, but recently it's +relaxed and rather recommends to follow the new rule to declare in +place of use for __free() -- which avoids potential deadlocks or UAFs +with nested cleanups. + +Although the current code has no bug, per se, let's follow the new +standard and move the declaration to the place of assignment (or +directly assign the allocated result) instead of NULL initializations. + +Fixes: fb9e197f3f27 ("ALSA: vmaster: Use automatic cleanup of kfree()") +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20251216140634.171890-9-tiwai@suse.de +Signed-off-by: Sasha Levin +--- + sound/core/vmaster.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/sound/core/vmaster.c b/sound/core/vmaster.c +index c657659b236c4..76cc64245f5df 100644 +--- a/sound/core/vmaster.c ++++ b/sound/core/vmaster.c +@@ -56,10 +56,10 @@ struct link_follower { + + static int follower_update(struct link_follower *follower) + { +- struct snd_ctl_elem_value *uctl __free(kfree) = NULL; + int err, ch; ++ struct snd_ctl_elem_value *uctl __free(kfree) = ++ kzalloc(sizeof(*uctl), GFP_KERNEL); + +- uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); + if (!uctl) + return -ENOMEM; + uctl->id = follower->follower.id; +@@ -74,7 +74,6 @@ static int follower_update(struct link_follower *follower) + /* get the follower ctl info and save the initial values */ + static int follower_init(struct link_follower *follower) + { +- struct snd_ctl_elem_info *uinfo __free(kfree) = NULL; + int err; + + if (follower->info.count) { +@@ -84,7 +83,8 @@ static int follower_init(struct link_follower *follower) + return 0; + } + +- uinfo = kmalloc(sizeof(*uinfo), GFP_KERNEL); ++ struct snd_ctl_elem_info *uinfo __free(kfree) = ++ kmalloc(sizeof(*uinfo), GFP_KERNEL); + if (!uinfo) + return -ENOMEM; + uinfo->id = follower->follower.id; +@@ -341,9 +341,9 @@ static int master_get(struct snd_kcontrol *kcontrol, + static int sync_followers(struct link_master *master, int old_val, int new_val) + { + struct link_follower *follower; +- struct snd_ctl_elem_value *uval __free(kfree) = NULL; ++ struct snd_ctl_elem_value *uval __free(kfree) = ++ kmalloc(sizeof(*uval), GFP_KERNEL); + +- uval = kmalloc(sizeof(*uval), GFP_KERNEL); + if (!uval) + return -ENOMEM; + list_for_each_entry(follower, &master->followers, list) { +-- +2.51.0 + diff --git a/queue-6.18/arm-dts-allwinner-sun5i-a13-utoo-p66-delete-power-gp.patch b/queue-6.18/arm-dts-allwinner-sun5i-a13-utoo-p66-delete-power-gp.patch new file mode 100644 index 0000000000..8cad44cbe7 --- /dev/null +++ b/queue-6.18/arm-dts-allwinner-sun5i-a13-utoo-p66-delete-power-gp.patch @@ -0,0 +1,46 @@ +From 04bfcf910f21ca5e8e959df6b988102d5bdbc082 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 25 Dec 2025 18:36:14 +0800 +Subject: ARM: dts: allwinner: sun5i-a13-utoo-p66: delete "power-gpios" + property + +From: Chen-Yu Tsai + +[ Upstream commit 0b2761eb1287bd9f62367cccf6626eb3107cef6f ] + +The P66's device tree includes the reference design dtsi files, which +defines a node and properties for the touchpanel in the common design. +The P66 dts file then overrides all the properties to match its own +design, but as the touchpanel model is different, a different schema +is matched. This other schema uses a different name for the GPIO. + +The original submission added the correct GPIO property, but did not +delete the one inherited from the reference design, causing validation +errors. + +Explicitly delete the incorrect GPIO property. + +Fixes: 2a53aff27236 ("ARM: dts: sun5i: Enable touchscreen on Utoo P66") +Reviewed-by: Jernej Skrabec +Link: https://patch.msgid.link/20251225103616.3203473-4-wens@kernel.org +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Sasha Levin +--- + arch/arm/boot/dts/allwinner/sun5i-a13-utoo-p66.dts | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/boot/dts/allwinner/sun5i-a13-utoo-p66.dts b/arch/arm/boot/dts/allwinner/sun5i-a13-utoo-p66.dts +index be486d28d04fa..428cab5a0e906 100644 +--- a/arch/arm/boot/dts/allwinner/sun5i-a13-utoo-p66.dts ++++ b/arch/arm/boot/dts/allwinner/sun5i-a13-utoo-p66.dts +@@ -102,6 +102,7 @@ &touchscreen { + /* The P66 uses a different EINT then the reference design */ + interrupts = <6 9 IRQ_TYPE_EDGE_FALLING>; /* EINT9 (PG9) */ + /* The icn8318 binding expects wake-gpios instead of power-gpios */ ++ /delete-property/ power-gpios; + wake-gpios = <&pio 1 3 GPIO_ACTIVE_HIGH>; /* PB3 */ + touchscreen-size-x = <800>; + touchscreen-size-y = <480>; +-- +2.51.0 + diff --git a/queue-6.18/arm-dts-lpc32xx-add-clocks-property-to-motor-control.patch b/queue-6.18/arm-dts-lpc32xx-add-clocks-property-to-motor-control.patch new file mode 100644 index 0000000000..01b172e231 --- /dev/null +++ b/queue-6.18/arm-dts-lpc32xx-add-clocks-property-to-motor-control.patch @@ -0,0 +1,35 @@ +From 699c672db2256258a36fcb97beabdbce64750292 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Dec 2025 00:49:07 +0200 +Subject: arm: dts: lpc32xx: add clocks property to Motor Control PWM device + tree node + +From: Vladimir Zapolskiy + +[ Upstream commit 71630e581a0e34c03757f5c1706f57c853b92555 ] + +Motor Control PWM depends on its own supply clock, the clock gate control +is present in TIMCLK_CTRL1 register. + +Fixes: b7d41c937ed7 ("ARM: LPC32xx: Add the motor PWM to base dts file") +Signed-off-by: Vladimir Zapolskiy +Signed-off-by: Sasha Levin +--- + arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi +index 2236901a00313..8e9ed93da129e 100644 +--- a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi ++++ b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi +@@ -302,6 +302,7 @@ i2c2: i2c@400a8000 { + mpwm: pwm@400e8000 { + compatible = "nxp,lpc3220-motor-pwm"; + reg = <0x400e8000 0x78>; ++ clocks = <&clk LPC32XX_CLK_MCPWM>; + #pwm-cells = <3>; + status = "disabled"; + }; +-- +2.51.0 + diff --git a/queue-6.18/arm-vdso-patch-out-__vdso_clock_getres-if-unavailabl.patch b/queue-6.18/arm-vdso-patch-out-__vdso_clock_getres-if-unavailabl.patch new file mode 100644 index 0000000000..7cfcf53d26 --- /dev/null +++ b/queue-6.18/arm-vdso-patch-out-__vdso_clock_getres-if-unavailabl.patch @@ -0,0 +1,39 @@ +From 858245058a2f77f8e027d6a0fcfccb3422bf266b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 23 Dec 2025 07:59:17 +0100 +Subject: ARM: VDSO: Patch out __vdso_clock_getres() if unavailable +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh + +[ Upstream commit b9fecf0dddfc55cd7d02b0011494da3c613f7cde ] + +The vDSO code hides symbols which are non-functional. +__vdso_clock_getres() was not added to this list when it got introduced. + +Fixes: 052e76a31b4a ("ARM: 8931/1: Add clock_getres entry point") +Signed-off-by: Thomas Weißschuh +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20251223-vdso-compat-time32-v1-6-97ea7a06a543@linutronix.de +Signed-off-by: Sasha Levin +--- + arch/arm/kernel/vdso.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/kernel/vdso.c b/arch/arm/kernel/vdso.c +index e38a30477f3d7..566c40f0f7c77 100644 +--- a/arch/arm/kernel/vdso.c ++++ b/arch/arm/kernel/vdso.c +@@ -161,6 +161,7 @@ static void __init patch_vdso(void *ehdr) + vdso_nullpatch_one(&einfo, "__vdso_gettimeofday"); + vdso_nullpatch_one(&einfo, "__vdso_clock_gettime"); + vdso_nullpatch_one(&einfo, "__vdso_clock_gettime64"); ++ vdso_nullpatch_one(&einfo, "__vdso_clock_getres"); + } + } + +-- +2.51.0 + diff --git a/queue-6.18/arm64-dts-amlogic-axg-assign-the-mmc-signal-clocks.patch b/queue-6.18/arm64-dts-amlogic-axg-assign-the-mmc-signal-clocks.patch new file mode 100644 index 0000000000..c8ea377aa4 --- /dev/null +++ b/queue-6.18/arm64-dts-amlogic-axg-assign-the-mmc-signal-clocks.patch @@ -0,0 +1,52 @@ +From 020572c99720a826c700205f2527ee76d570bc1c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:08:50 +0100 +Subject: arm64: dts: amlogic: axg: assign the MMC signal clocks + +From: Jerome Brunet + +[ Upstream commit 13d3fe2318ef6e46d6fcfe13bc373827fdf2aeac ] + +The amlogic MMC driver operate with the assumption that MMC clock +is configured to provide 24MHz. It uses this path for low +rates such as 400kHz. + +Assign the clocks to make sure they are properly configured + +Fixes: 221cf34bac54 ("ARM64: dts: meson-axg: enable the eMMC controller") +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Link: https://patch.msgid.link/20260114-amlogic-mmc-clocks-followup-v1-3-a999fafbe0aa@baylibre.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-axg.dtsi | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi +index 04fb130ac7c6a..bbf94a1f92a10 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi +@@ -1960,6 +1960,9 @@ sd_emmc_b: mmc@5000 { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_B>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_B_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + sd_emmc_c: mmc@7000 { +@@ -1972,6 +1975,9 @@ sd_emmc_c: mmc@7000 { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_C>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_C_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + nfc: nand-controller@7800 { +-- +2.51.0 + diff --git a/queue-6.18/arm64-dts-amlogic-c3-assign-the-mmc-signal-clocks.patch b/queue-6.18/arm64-dts-amlogic-c3-assign-the-mmc-signal-clocks.patch new file mode 100644 index 0000000000..3b116f6ffe --- /dev/null +++ b/queue-6.18/arm64-dts-amlogic-c3-assign-the-mmc-signal-clocks.patch @@ -0,0 +1,53 @@ +From 4f1190dba194ee488a64ca5fa6ad4053b056b5e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:08:48 +0100 +Subject: arm64: dts: amlogic: c3: assign the MMC signal clocks + +From: Jerome Brunet + +[ Upstream commit 69330fd2368371c4eb47d60ace6bca09763d24a0 ] + +The amlogic MMC driver operate with the assumption that MMC clock +is configured to provide 24MHz. It uses this path for low +rates such as 400kHz. + +Assign the clocks to make sure they are properly configured + +Fixes: 520b792e8317 ("arm64: dts: amlogic: add some device nodes for C3") +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Link: https://patch.msgid.link/20260114-amlogic-mmc-clocks-followup-v1-1-a999fafbe0aa@baylibre.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi b/arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi +index 07aaaf71ea9ae..f226df3ce153b 100644 +--- a/arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi ++++ b/arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi +@@ -969,6 +969,10 @@ sdio: mmc@88000 { + no-sd; + resets = <&reset RESET_SD_EMMC_A>; + status = "disabled"; ++ ++ assigned-clocks = <&clkc_periphs CLKID_SD_EMMC_A>; ++ assigned-clock-rates = <24000000>; ++ + }; + + sd: mmc@8a000 { +@@ -984,6 +988,9 @@ sd: mmc@8a000 { + no-sdio; + resets = <&reset RESET_SD_EMMC_B>; + status = "disabled"; ++ ++ assigned-clocks = <&clkc_periphs CLKID_SD_EMMC_B>; ++ assigned-clock-rates = <24000000>; + }; + + nand: nand-controller@8d000 { +-- +2.51.0 + diff --git a/queue-6.18/arm64-dts-amlogic-g12-assign-the-mmc-a-signal-clock.patch b/queue-6.18/arm64-dts-amlogic-g12-assign-the-mmc-a-signal-clock.patch new file mode 100644 index 0000000000..5926312554 --- /dev/null +++ b/queue-6.18/arm64-dts-amlogic-g12-assign-the-mmc-a-signal-clock.patch @@ -0,0 +1,42 @@ +From 922e4d09769515b0594ee6c6624f247468617137 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:08:53 +0100 +Subject: arm64: dts: amlogic: g12: assign the MMC A signal clock + +From: Jerome Brunet + +[ Upstream commit 3c941feaa363f1573a501452391ddf513394c84b ] + +The amlogic MMC driver operate with the assumption that MMC clock +is configured to provide 24MHz. It uses this path for low +rates such as 400kHz. + +Assign the clock to make sure it is properly configured + +Fixes: 8a6b3ca2d361 ("arm64: dts: meson: g12a: add SDIO controller") +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Link: https://patch.msgid.link/20260114-amlogic-mmc-clocks-followup-v1-6-a999fafbe0aa@baylibre.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +index 6724405eaa6f5..8d8ab775404d9 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +@@ -2431,6 +2431,9 @@ sd_emmc_a: mmc@ffe03000 { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_A>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_A_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + sd_emmc_b: mmc@ffe05000 { +-- +2.51.0 + diff --git a/queue-6.18/arm64-dts-amlogic-g12-assign-the-mmc-b-and-c-signal-.patch b/queue-6.18/arm64-dts-amlogic-g12-assign-the-mmc-b-and-c-signal-.patch new file mode 100644 index 0000000000..395ee6eb7c --- /dev/null +++ b/queue-6.18/arm64-dts-amlogic-g12-assign-the-mmc-b-and-c-signal-.patch @@ -0,0 +1,52 @@ +From 84280934a8907c2fddad87ffb064f0807ca1186c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:08:52 +0100 +Subject: arm64: dts: amlogic: g12: assign the MMC B and C signal clocks + +From: Jerome Brunet + +[ Upstream commit be2ff5fdb0e83e32d4ec4e68a69875cec0d14621 ] + +The amlogic MMC driver operate with the assumption that MMC clock +is configured to provide 24MHz. It uses this path for low +rates such as 400kHz. + +Assign the clocks to make sure they are properly configured + +Fixes: 4759fd87b928 ("arm64: dts: meson: g12a: add mmc nodes") +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Link: https://patch.msgid.link/20260114-amlogic-mmc-clocks-followup-v1-5-a999fafbe0aa@baylibre.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +index dcc927a9da802..6724405eaa6f5 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +@@ -2443,6 +2443,9 @@ sd_emmc_b: mmc@ffe05000 { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_B>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_B_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + sd_emmc_c: mmc@ffe07000 { +@@ -2455,6 +2458,9 @@ sd_emmc_c: mmc@ffe07000 { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_C>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_C_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + usb: usb@ffe09000 { +-- +2.51.0 + diff --git a/queue-6.18/arm64-dts-amlogic-gx-assign-the-mmc-signal-clocks.patch b/queue-6.18/arm64-dts-amlogic-gx-assign-the-mmc-signal-clocks.patch new file mode 100644 index 0000000000..217977f321 --- /dev/null +++ b/queue-6.18/arm64-dts-amlogic-gx-assign-the-mmc-signal-clocks.patch @@ -0,0 +1,97 @@ +From dab7430afdb1561506ad5ae28e5514f22214fa2e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:08:51 +0100 +Subject: arm64: dts: amlogic: gx: assign the MMC signal clocks + +From: Jerome Brunet + +[ Upstream commit 406706559046eebc09a31e8ae5e78620bfd746fe ] + +The amlogic MMC driver operate with the assumption that MMC clock +is configured to provide 24MHz. It uses this path for low +rates such as 400kHz. + +Assign the clocks to make sure they are properly configured + +Fixes: 50662499f911 ("ARM64: dts: meson-gx: Use correct mmc clock source 0") +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Link: https://patch.msgid.link/20260114-amlogic-mmc-clocks-followup-v1-4-a999fafbe0aa@baylibre.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 9 +++++++++ + arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 9 +++++++++ + 2 files changed, 18 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi +index f69923da07feb..a9c830a570cc6 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi +@@ -824,6 +824,9 @@ &sd_emmc_a { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_A>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_A_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &sd_emmc_b { +@@ -832,6 +835,9 @@ &sd_emmc_b { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_B>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_B_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &sd_emmc_c { +@@ -840,6 +846,9 @@ &sd_emmc_c { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_C>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_C_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &simplefb_hdmi { +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi +index ba535010a3c91..e202d84f06720 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi +@@ -894,6 +894,9 @@ &sd_emmc_a { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_A>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_A_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &sd_emmc_b { +@@ -902,6 +905,9 @@ &sd_emmc_b { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_B>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_B_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &sd_emmc_c { +@@ -910,6 +916,9 @@ &sd_emmc_c { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_C>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_C_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &simplefb_hdmi { +-- +2.51.0 + diff --git a/queue-6.18/arm64-dts-amlogic-s4-assign-mmc-b-clock-to-24mhz.patch b/queue-6.18/arm64-dts-amlogic-s4-assign-mmc-b-clock-to-24mhz.patch new file mode 100644 index 0000000000..33f11484e7 --- /dev/null +++ b/queue-6.18/arm64-dts-amlogic-s4-assign-mmc-b-clock-to-24mhz.patch @@ -0,0 +1,51 @@ +From ddd974d1b3789362b290dc0f34b471126b9e2348 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 11:43:11 +0100 +Subject: arm64: dts: amlogic: s4: assign mmc b clock to 24MHz + +From: Jerome Brunet + +[ Upstream commit 86124a8becb43eed3103f2459399daee8af2c99d ] + +The amlogic MMC driver operate with the assumption that MMC clock +is configured to provide 24MHz. It uses this path for low +rates such as 400kHz. + +This assumption did hold true until but it now, but it is apparently +not the case with s4. The clock has been reported to provide 1GHz +instead. This is most likely due to how the bootloader is using the MMC +clock on this platform. + +Regardless of why the MMC clock rate is 1GHz, if the MMC driver expects +24MHz, the clock should be properly assigned, so assign it. + +Reported-by: Nick Xie +Closes: https://lore.kernel.org/linux-amlogic/20260113011931.40424-1-nick@khadas.com/ +Fixes: 3ab9d54b5d84 ("arm64: dts: amlogic: enable some device nodes for S4") +Tested-by: Nick Xie +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Link: https://patch.msgid.link/20260114-amlogic-s4-mmc-fixup-v3-1-a4d3e136b3f2@baylibre.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-s4.dtsi | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-s4.dtsi b/arch/arm64/boot/dts/amlogic/meson-s4.dtsi +index 9d99ed2994dfa..f314f07062abe 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-s4.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-s4.dtsi +@@ -838,6 +838,9 @@ sd: mmc@fe08a000 { + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_B>; + status = "disabled"; ++ ++ assigned-clocks = <&clkc_periphs CLKID_SD_EMMC_B>; ++ assigned-clock-rates = <24000000>; + }; + + emmc: mmc@fe08c000 { +-- +2.51.0 + diff --git a/queue-6.18/arm64-dts-amlogic-s4-fix-mmc-clock-assignment.patch b/queue-6.18/arm64-dts-amlogic-s4-fix-mmc-clock-assignment.patch new file mode 100644 index 0000000000..63ed28f115 --- /dev/null +++ b/queue-6.18/arm64-dts-amlogic-s4-fix-mmc-clock-assignment.patch @@ -0,0 +1,70 @@ +From 3d918b263423cdaaa0ac0fb20e4713d35493f56e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 11:43:12 +0100 +Subject: arm64: dts: amlogic: s4: fix mmc clock assignment + +From: Jerome Brunet + +[ Upstream commit 3a115d42922cffc91b303992eadf220111d66c31 ] + +MMC A and C are mis-represented as having their "clkin0" input connected to +xtal while it is actually connected to the MMC clock, probably in an +attempt to provide 24MHz to the device on this input. + +Fix this and assign the clock to 24MHz to actually provide the required +rate. + +Fixes: 3ab9d54b5d84 ("arm64: dts: amlogic: enable some device nodes for S4") +Tested-by: Nick Xie +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Link: https://patch.msgid.link/20260114-amlogic-s4-mmc-fixup-v3-2-a4d3e136b3f2@baylibre.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-s4.dtsi | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-s4.dtsi b/arch/arm64/boot/dts/amlogic/meson-s4.dtsi +index f314f07062abe..dfc0a30a6e61b 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-s4.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-s4.dtsi +@@ -819,13 +819,16 @@ sdio: mmc@fe088000 { + reg = <0x0 0xfe088000 0x0 0x800>; + interrupts = ; + clocks = <&clkc_periphs CLKID_SDEMMC_A>, +- <&xtal>, ++ <&clkc_periphs CLKID_SD_EMMC_A>, + <&clkc_pll CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_A>; + cap-sdio-irq; + keep-power-in-suspend; + status = "disabled"; ++ ++ assigned-clocks = <&clkc_periphs CLKID_SD_EMMC_A>; ++ assigned-clock-rates = <24000000>; + }; + + sd: mmc@fe08a000 { +@@ -848,13 +851,16 @@ emmc: mmc@fe08c000 { + reg = <0x0 0xfe08c000 0x0 0x800>; + interrupts = ; + clocks = <&clkc_periphs CLKID_NAND>, +- <&xtal>, ++ <&clkc_periphs CLKID_SD_EMMC_C>, + <&clkc_pll CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_NAND_EMMC>; + no-sdio; + no-sd; + status = "disabled"; ++ ++ assigned-clocks = <&clkc_periphs CLKID_SD_EMMC_C>; ++ assigned-clock-rates = <24000000>; + }; + }; + }; +-- +2.51.0 + diff --git a/queue-6.18/arm64-dts-mediatek-mt8183-jacuzzi-pico6-fix-typo-in-.patch b/queue-6.18/arm64-dts-mediatek-mt8183-jacuzzi-pico6-fix-typo-in-.patch new file mode 100644 index 0000000000..f5f1ae9976 --- /dev/null +++ b/queue-6.18/arm64-dts-mediatek-mt8183-jacuzzi-pico6-fix-typo-in-.patch @@ -0,0 +1,36 @@ +From 32ae65c3f0a3c59b40dcfab7480cf53c6d068a74 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 12:47:41 +0100 +Subject: arm64: dts: mediatek: mt8183-jacuzzi-pico6: Fix typo in pinmux node + +From: AngeloGioacchino Del Regno + +[ Upstream commit b1fc81a986c9b8089db31e21a372cc8b6514e900 ] + +Rename "piins-bt-wakeup" to "pins-bt-wakeup" to fix a dtbs_check +warning happening due to this typo. + +Fixes: 055ef10ccdd4 ("arm64: dts: mt8183: Add jacuzzi pico/pico6 board") +Reviewed-by: Chen-Yu Tsai +Signed-off-by: AngeloGioacchino Del Regno +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-pico6.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-pico6.dts b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-pico6.dts +index cce326aec1aa5..40af5656d6f15 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-pico6.dts ++++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-pico6.dts +@@ -91,7 +91,7 @@ bluetooth@2 { + + &pio { + bt_pins_wakeup: bt-pins-wakeup { +- piins-bt-wakeup { ++ pins-bt-wakeup { + pinmux = ; + input-enable; + }; +-- +2.51.0 + diff --git a/queue-6.18/arm64-dts-qcom-agatti-add-cx_mem-dbgc-gpu-regions.patch b/queue-6.18/arm64-dts-qcom-agatti-add-cx_mem-dbgc-gpu-regions.patch new file mode 100644 index 0000000000..cf294f2bd4 --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-agatti-add-cx_mem-dbgc-gpu-regions.patch @@ -0,0 +1,49 @@ +From de6e4cde83f20130308090c36df6c2a3734b4a23 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Dec 2025 21:47:40 +0100 +Subject: arm64: dts: qcom: agatti: Add CX_MEM/DBGC GPU regions + +From: Konrad Dybcio + +[ Upstream commit 0fdcc948929a6d673bd0f90631dd6e42090c3dbd ] + +Describe the GPU register regions, with the former existing but not +being used much if at all on this silicon, and the latter containing +various debugging levers generally related to dumping the state of +the IP upon a crash. + +Fixes: 4faeef52c8e6 ("arm64: dts: qcom: qcm2290: Add GPU nodes") +Reported-by: Krzysztof Kozlowski +Closes: https://lore.kernel.org/linux-arm-msm/8a64f70b-8034-45e7-86a3-0015cf357132@oss.qualcomm.com/T/#m404f1425c36b61467760f058b696b8910340a063 +Signed-off-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Akhil P Oommen +Link: https://lore.kernel.org/r/20251229-topic-6115_2290_gpu_dbgc-v1-2-4a24d196389c@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/qcm2290.dtsi | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/qcm2290.dtsi b/arch/arm64/boot/dts/qcom/qcm2290.dtsi +index 3b0ba590ee825..e0e400fdd2497 100644 +--- a/arch/arm64/boot/dts/qcom/qcm2290.dtsi ++++ b/arch/arm64/boot/dts/qcom/qcm2290.dtsi +@@ -1503,8 +1503,12 @@ usb_dwc3_ss: endpoint { + + gpu: gpu@5900000 { + compatible = "qcom,adreno-07000200", "qcom,adreno"; +- reg = <0x0 0x05900000 0x0 0x40000>; +- reg-names = "kgsl_3d0_reg_memory"; ++ reg = <0x0 0x05900000 0x0 0x40000>, ++ <0x0 0x0599e000 0x0 0x1000>, ++ <0x0 0x05961000 0x0 0x800>; ++ reg-names = "kgsl_3d0_reg_memory", ++ "cx_mem", ++ "cx_dbgc"; + + interrupts = ; + +-- +2.51.0 + diff --git a/queue-6.18/arm64-dts-qcom-msm8994-octagon-fix-analog-devices-ve.patch b/queue-6.18/arm64-dts-qcom-msm8994-octagon-fix-analog-devices-ve.patch new file mode 100644 index 0000000000..a42b39157a --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-msm8994-octagon-fix-analog-devices-ve.patch @@ -0,0 +1,43 @@ +From 015696f82fd963a857bc664d1b15246d47bcf8a7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Dec 2025 02:39:23 +0200 +Subject: arm64: dts: qcom: msm8994-octagon: Fix Analog Devices vendor prefix + of AD7147 + +From: Vladimir Zapolskiy + +[ Upstream commit 7db5fbe508deedec6c183d5056cf3c504c027f40 ] + +Trivial change, Analog Devices vendor prefix is "adi", but there is +a valid "ad" vendor prefix of another company, this may explain why +the issue hasn't been discovered by the automatic tests. + +A problem of not described compatible value is out of this change scope. + +Fixes: c636eeb751f6 ("arm64: dts: qcom: msm8994-octagon: Add AD7147 and APDS9930 sensors") +Signed-off-by: Vladimir Zapolskiy +Reviewed-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20251226003923.3341904-1-vladimir.zapolskiy@linaro.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/msm8994-msft-lumia-octagon.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/msm8994-msft-lumia-octagon.dtsi b/arch/arm64/boot/dts/qcom/msm8994-msft-lumia-octagon.dtsi +index 4c983b10dd925..7ace3540ef0a0 100644 +--- a/arch/arm64/boot/dts/qcom/msm8994-msft-lumia-octagon.dtsi ++++ b/arch/arm64/boot/dts/qcom/msm8994-msft-lumia-octagon.dtsi +@@ -378,7 +378,7 @@ &blsp2_i2c1 { + status = "okay"; + + sideinteraction: touch@2c { +- compatible = "ad,ad7147_captouch"; ++ compatible = "adi,ad7147_captouch"; + reg = <0x2c>; + + pinctrl-names = "default", "sleep"; +-- +2.51.0 + diff --git a/queue-6.18/arm64-dts-qcom-qrb4210-rb2-fix-uart3-wakeup-irq-stor.patch b/queue-6.18/arm64-dts-qcom-qrb4210-rb2-fix-uart3-wakeup-irq-stor.patch new file mode 100644 index 0000000000..7b451d5989 --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-qrb4210-rb2-fix-uart3-wakeup-irq-stor.patch @@ -0,0 +1,43 @@ +From a12f2c507556a928fbbc38d980dcc12d146938eb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Jan 2026 03:01:16 +0200 +Subject: arm64: dts: qcom: qrb4210-rb2: Fix UART3 wakeup IRQ storm + +From: Dmitry Baryshkov + +[ Upstream commit c5dc4812f6bf397b82290c540085e9ec98b47b30 ] + +Follow commit 9c92d36b0b1e ("arm64: dts: qcom: qrb2210-rb1: Fix UART3 +wakeup IRQ storm") and apply the similar fix to the RB2 platform. + +Having RX / TX pins as pull up and wakup interrupt as high-level +triggered generates an interrupt storm when trying to suspend the +device. Avoid the storm by using the falling edge trigger (as all other +platforms do). + +Fixes: cab60b166575 ("arm64: dts: qcom: qrb4210-rb2: Enable bluetooth") +Reviewed-by: Konrad Dybcio +Signed-off-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260106-wcn3990-pwrctl-v2-6-0386204328be@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/qrb4210-rb2.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts b/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts +index bdf2d66e40c62..44ca3e61c33d4 100644 +--- a/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts ++++ b/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts +@@ -694,7 +694,7 @@ sdc2_card_det_n: sd-card-det-n-state { + + &uart3 { + interrupts-extended = <&intc GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH>, +- <&tlmm 11 IRQ_TYPE_LEVEL_HIGH>; ++ <&tlmm 11 IRQ_TYPE_EDGE_FALLING>; + pinctrl-0 = <&uart3_default>; + pinctrl-1 = <&uart3_sleep>; + pinctrl-names = "default", "sleep"; +-- +2.51.0 + diff --git a/queue-6.18/arm64-dts-qcom-sdm630-fix-gpu_speed_bin-size.patch b/queue-6.18/arm64-dts-qcom-sdm630-fix-gpu_speed_bin-size.patch new file mode 100644 index 0000000000..e89b138844 --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-sdm630-fix-gpu_speed_bin-size.patch @@ -0,0 +1,49 @@ +From f309ef79f893ac6b2231e5b6c100ade7c3fa78f7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 11 Dec 2025 03:27:45 +0200 +Subject: arm64: dts: qcom: sdm630: fix gpu_speed_bin size + +From: Dmitry Baryshkov + +[ Upstream commit e814796dfcae8905682ac3ac2dd57f512a9f6726 ] + +Historically sdm630.dtsi has used 1 byte length for the gpu_speed_bin +cell, although it spans two bytes (offset 5, size 7 bits). It was being +accepted by the kernel because before the commit 7a06ef751077 ("nvmem: +core: fix bit offsets of more than one byte") the kernel didn't have +length check. After this commit nvmem core rejects QFPROM on sdm630 / +sdm660, making GPU and USB unusable on those platforms. + +Set the size of the gpu_speed_bin cell to 2 bytes, fixing the parsing +error. While we are at it, update the length to 8 bits as pointed out by +Alexey Minnekhanov. + +Fixes: b190fb010664 ("arm64: dts: qcom: sdm630: Add sdm630 dts file") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Reviewed-by: Alexey Minnekhanov +Link: https://lore.kernel.org/r/20251211-sdm630-fix-gpu-v2-1-92f0e736dba0@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm630.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/sdm630.dtsi b/arch/arm64/boot/dts/qcom/sdm630.dtsi +index 8b1a45a4e56ed..b383e480a394d 100644 +--- a/arch/arm64/boot/dts/qcom/sdm630.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm630.dtsi +@@ -598,8 +598,8 @@ qusb2_hstx_trim: hstx-trim@240 { + }; + + gpu_speed_bin: gpu-speed-bin@41a0 { +- reg = <0x41a2 0x1>; +- bits = <5 7>; ++ reg = <0x41a2 0x2>; ++ bits = <5 8>; + }; + }; + +-- +2.51.0 + diff --git a/queue-6.18/arm64-dts-qcom-sdm845-db845c-drop-cs-from-spio0.patch b/queue-6.18/arm64-dts-qcom-sdm845-db845c-drop-cs-from-spio0.patch new file mode 100644 index 0000000000..aaedbebf43 --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-sdm845-db845c-drop-cs-from-spio0.patch @@ -0,0 +1,40 @@ +From 9292bdcd7aac1336dc22357ec789f96b614dcde4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Jan 2026 03:01:17 +0200 +Subject: arm64: dts: qcom: sdm845-db845c: drop CS from SPIO0 + +From: Dmitry Baryshkov + +[ Upstream commit 8bfb696ccdc5bcfad7a45b84c2c8a36757070e19 ] + +On SDM845 SPI uses hardware-provided chip select, while specifying +cs-gpio makes the driver request GPIO pin, which on DB845c conflicts +with the normal host controllers pinctrl entry. + +Drop the cs-gpios property to restore SPI functionality. + +Fixes: cb29e7106d4e ("arm64: dts: qcom: db845c: Add support for MCP2517FD") +Reviewed-by: Konrad Dybcio +Signed-off-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260106-wcn3990-pwrctl-v2-7-0386204328be@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm845-db845c.dts | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts +index 8abf3e909502f..384be2f8b1411 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts ++++ b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts +@@ -850,7 +850,6 @@ &spi0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&qup_spi0_default>; +- cs-gpios = <&tlmm 3 GPIO_ACTIVE_LOW>; + + can@0 { + compatible = "microchip,mcp2517fd"; +-- +2.51.0 + diff --git a/queue-6.18/arm64-dts-qcom-sdm845-db845c-specify-power-for-wifi-.patch b/queue-6.18/arm64-dts-qcom-sdm845-db845c-specify-power-for-wifi-.patch new file mode 100644 index 0000000000..ac1ca1617e --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-sdm845-db845c-specify-power-for-wifi-.patch @@ -0,0 +1,50 @@ +From 9278c922c2dc7225bc17d8099ca6951b3342897d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Jan 2026 03:01:18 +0200 +Subject: arm64: dts: qcom: sdm845-db845c: specify power for WiFi CH1 + +From: Dmitry Baryshkov + +[ Upstream commit c303e89f7f17c29981d09f8beaaf60937ae8b1f2 ] + +Specify power supply for the second chain / antenna output of the +onboard WiFi chip. + +Fixes: 3f72e2d3e682 ("arm64: dts: qcom: Add Dragonboard 845c") +Reviewed-by: Konrad Dybcio +Signed-off-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260106-wcn3990-pwrctl-v2-8-0386204328be@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm845-db845c.dts | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts +index 384be2f8b1411..5147d6d3cc26b 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts ++++ b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts +@@ -379,6 +379,12 @@ vreg_l21a_2p95: ldo21 { + regulator-initial-mode = ; + }; + ++ vreg_l23a_3p3: ldo23 { ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3312000>; ++ regulator-initial-mode = ; ++ }; ++ + vreg_l24a_3p075: ldo24 { + regulator-min-microvolt = <3088000>; + regulator-max-microvolt = <3088000>; +@@ -1155,6 +1161,7 @@ &wifi { + vdd-1.8-xo-supply = <&vreg_l7a_1p8>; + vdd-1.3-rfa-supply = <&vreg_l17a_1p3>; + vdd-3.3-ch0-supply = <&vreg_l25a_3p3>; ++ vdd-3.3-ch1-supply = <&vreg_l23a_3p3>; + + qcom,snoc-host-cap-8bit-quirk; + qcom,calibration-variant = "Thundercomm_DB845C"; +-- +2.51.0 + diff --git a/queue-6.18/arm64-dts-qcom-sdm845-oneplus-don-t-keep-panel-regul.patch b/queue-6.18/arm64-dts-qcom-sdm845-oneplus-don-t-keep-panel-regul.patch new file mode 100644 index 0000000000..a43ec08470 --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-sdm845-oneplus-don-t-keep-panel-regul.patch @@ -0,0 +1,39 @@ +From e8f05a8127317bc8608b9b15afc69f9cb8fa682e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 18 Nov 2025 15:52:26 +0100 +Subject: arm64: dts: qcom: sdm845-oneplus: Don't keep panel regulator always + on + +From: Casey Connolly + +[ Upstream commit 45d1f42d3e84b5880cf9fab1eb24a7818320eeb7 ] + +The panel regulator doesn't need to be always on, so remove this +property. + +Fixes: 288ef8a42612 ("arm64: dts: sdm845: add oneplus6/6t devices") +Signed-off-by: Casey Connolly +Signed-off-by: David Heidelberg +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251118-dts-oneplus-regulators-v2-2-3e67cea1e4e7@ixit.cz +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +index 35d105ff689b9..7169da658dcd0 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +@@ -256,7 +256,6 @@ vreg_l14a_1p88: ldo14 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; +- regulator-always-on; + }; + + vreg_l17a_1p3: ldo17 { +-- +2.51.0 + diff --git a/queue-6.18/arm64-dts-qcom-sdm845-oneplus-don-t-mark-ts-supply-b.patch b/queue-6.18/arm64-dts-qcom-sdm845-oneplus-don-t-mark-ts-supply-b.patch new file mode 100644 index 0000000000..b44ea7f227 --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-sdm845-oneplus-don-t-mark-ts-supply-b.patch @@ -0,0 +1,39 @@ +From a42c02dab93f82bec564bc5c9ad8e0ca6e161c97 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 18 Nov 2025 15:52:25 +0100 +Subject: arm64: dts: qcom: sdm845-oneplus: Don't mark ts supply boot-on + +From: Casey Connolly + +[ Upstream commit c9b98b9dad9749bf2eb7336a6fca31a6af1039d7 ] + +The touchscreen isn't enabled by bootloader and doesn't need to be +enabled at boot, only when the driver probes, thus remove the +regulator-boot-on property. + +Fixes: 288ef8a42612 ("arm64: dts: sdm845: add oneplus6/6t devices") +Signed-off-by: Casey Connolly +Signed-off-by: David Heidelberg +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251118-dts-oneplus-regulators-v2-1-3e67cea1e4e7@ixit.cz +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +index 51a9a276399ac..35d105ff689b9 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +@@ -160,7 +160,6 @@ ts_1p8_supply: ts-1p8-regulator { + + gpio = <&tlmm 88 0>; + enable-active-high; +- regulator-boot-on; + }; + }; + +-- +2.51.0 + diff --git a/queue-6.18/arm64-dts-qcom-sdm845-oneplus-mark-l14a-regulator-as.patch b/queue-6.18/arm64-dts-qcom-sdm845-oneplus-mark-l14a-regulator-as.patch new file mode 100644 index 0000000000..f526965908 --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-sdm845-oneplus-mark-l14a-regulator-as.patch @@ -0,0 +1,38 @@ +From e778cc28965ad6ff6d79cfe7a31eccab6cfd5d31 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 18 Nov 2025 15:52:27 +0100 +Subject: arm64: dts: qcom: sdm845-oneplus: Mark l14a regulator as boot-on + +From: Casey Connolly + +[ Upstream commit ad33ee060be46794a03d033894c9db3a9d6c1a0f ] + +This regulator is used only for the display, which is enabled by the +bootloader and left on for continuous splash. Mark it as such. + +Fixes: 288ef8a42612 ("arm64: dts: sdm845: add oneplus6/6t devices") +Signed-off-by: Casey Connolly +Signed-off-by: David Heidelberg +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251118-dts-oneplus-regulators-v2-3-3e67cea1e4e7@ixit.cz +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +index 7169da658dcd0..1036305231b20 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +@@ -256,6 +256,7 @@ vreg_l14a_1p88: ldo14 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; ++ regulator-boot-on; + }; + + vreg_l17a_1p3: ldo17 { +-- +2.51.0 + diff --git a/queue-6.18/arm64-dts-qcom-sm6115-add-cx_mem-dbgc-gpu-regions.patch b/queue-6.18/arm64-dts-qcom-sm6115-add-cx_mem-dbgc-gpu-regions.patch new file mode 100644 index 0000000000..10db2180cc --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-sm6115-add-cx_mem-dbgc-gpu-regions.patch @@ -0,0 +1,49 @@ +From 5b147bf0e4e9983ebdf730889e3abbbcd576afdb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Dec 2025 21:47:41 +0100 +Subject: arm64: dts: qcom: sm6115: Add CX_MEM/DBGC GPU regions + +From: Konrad Dybcio + +[ Upstream commit 78c13dac18cf0e6f6cbc6ea85d4f967e6cca9562 ] + +Describe the GPU register regions, with the former existing but not +being used much if at all on this silicon, and the latter containing +various debugging levers generally related to dumping the state of +the IP upon a crash. + +Fixes: 11750af256f8 ("arm64: dts: qcom: sm6115: Add GPU nodes") +Reported-by: Krzysztof Kozlowski +Closes: https://lore.kernel.org/linux-arm-msm/8a64f70b-8034-45e7-86a3-0015cf357132@oss.qualcomm.com/T/#m404f1425c36b61467760f058b696b8910340a063 +Signed-off-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Akhil P Oommen +Link: https://lore.kernel.org/r/20251229-topic-6115_2290_gpu_dbgc-v1-3-4a24d196389c@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm6115.dtsi | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm6115.dtsi b/arch/arm64/boot/dts/qcom/sm6115.dtsi +index 91fc36b59abf9..8b8395f6a2dfc 100644 +--- a/arch/arm64/boot/dts/qcom/sm6115.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm6115.dtsi +@@ -1715,8 +1715,12 @@ usb_dwc3_ss: endpoint { + + gpu: gpu@5900000 { + compatible = "qcom,adreno-610.0", "qcom,adreno"; +- reg = <0x0 0x05900000 0x0 0x40000>; +- reg-names = "kgsl_3d0_reg_memory"; ++ reg = <0x0 0x05900000 0x0 0x40000>, ++ <0x0 0x0599e000 0x0 0x1000>, ++ <0x0 0x05961000 0x0 0x800>; ++ reg-names = "kgsl_3d0_reg_memory", ++ "cx_mem", ++ "cx_dbgc"; + + /* There's no (real) GMU, so we have to handle quite a bunch of clocks! */ + clocks = <&gpucc GPU_CC_GX_GFX3D_CLK>, +-- +2.51.0 + diff --git a/queue-6.18/arm64-dts-qcom-talos-drop-opp-shared-from-qup-opp-ta.patch b/queue-6.18/arm64-dts-qcom-talos-drop-opp-shared-from-qup-opp-ta.patch new file mode 100644 index 0000000000..deef688e32 --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-talos-drop-opp-shared-from-qup-opp-ta.patch @@ -0,0 +1,43 @@ +From 5704e0ef7a19b21df9dea06d8faf4b029db4851c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 11 Nov 2025 22:33:50 +0530 +Subject: arm64: dts: qcom: talos: Drop opp-shared from QUP OPP table + +From: Viken Dadhaniya + +[ Upstream commit dda4bdd325326dd67ae4401f4f3d35b9cf781e3f ] + +QUP devices are currently marked with opp-shared in their OPP table, +causing the kernel to treat them as part of a shared OPP domain. This +leads to the qcom_geni_serial driver failing to probe with error +-EBUSY (-16). + +Remove the opp-shared property to ensure the OPP framework treats the +QUP OPP table as device-specific, allowing the serial driver to probe +successfully + +Fixes: f6746dc9e379 ("arm64: dts: qcom: qcs615: Add QUPv3 configuration") +Signed-off-by: Viken Dadhaniya +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251111170350.525832-1-viken.dadhaniya@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm6150.dtsi | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi +index 64e7c9dbafc70..363b9f436cd0a 100644 +--- a/arch/arm64/boot/dts/qcom/sm6150.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi +@@ -398,7 +398,6 @@ cdsp_smp2p_in: slave-kernel { + + qup_opp_table: opp-table-qup { + compatible = "operating-points-v2"; +- opp-shared; + + opp-75000000 { + opp-hz = /bits/ 64 <75000000>; +-- +2.51.0 + diff --git a/queue-6.18/arm64-dts-qcom-x1e-bus-is-40-bits-fix-64gb-models.patch b/queue-6.18/arm64-dts-qcom-x1e-bus-is-40-bits-fix-64gb-models.patch new file mode 100644 index 0000000000..81c93195a3 --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-x1e-bus-is-40-bits-fix-64gb-models.patch @@ -0,0 +1,42 @@ +From 06646dd4e60047dcf22d69a806d6a2410c21ff82 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Nov 2025 16:29:42 -0500 +Subject: arm64: dts: qcom: x1e: bus is 40-bits (fix 64GB models) + +From: Jonathan Marek + +[ Upstream commit b38dd256e11a4c8bd5a893e11fc42d493939c907 ] + +Unlike the phone SoCs this was copied from, x1e has a 40-bit physical bus. +The upper address space is used to support more than 32GB of memory. + +This fixes issues when DMA buffers are allocated outside the 36-bit range. + +Fixes: af16b00578a7 ("arm64: dts: qcom: Add base X1E80100 dtsi and the QCP dts") +Signed-off-by: Jonathan Marek +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251127212943.24480-1-jonathan@marek.ca +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/x1e80100.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/x1e80100.dtsi b/arch/arm64/boot/dts/qcom/x1e80100.dtsi +index 3290fd8c2d6e6..512a75da4f13f 100644 +--- a/arch/arm64/boot/dts/qcom/x1e80100.dtsi ++++ b/arch/arm64/boot/dts/qcom/x1e80100.dtsi +@@ -791,8 +791,8 @@ soc: soc@0 { + + #address-cells = <2>; + #size-cells = <2>; +- dma-ranges = <0 0 0 0 0x10 0>; +- ranges = <0 0 0 0 0x10 0>; ++ dma-ranges = <0 0 0 0 0x100 0>; ++ ranges = <0 0 0 0 0x100 0>; + + gcc: clock-controller@100000 { + compatible = "qcom,x1e80100-gcc"; +-- +2.51.0 + diff --git a/queue-6.18/arm64-dts-qcom-x1e80100-fix-usb-combo-phys-ss1-and-s.patch b/queue-6.18/arm64-dts-qcom-x1e80100-fix-usb-combo-phys-ss1-and-s.patch new file mode 100644 index 0000000000..daf19878bf --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-x1e80100-fix-usb-combo-phys-ss1-and-s.patch @@ -0,0 +1,61 @@ +From 2055aa26c023b3d60b451389660382840c622894 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 3 Nov 2025 18:51:40 +0200 +Subject: arm64: dts: qcom: x1e80100: Fix USB combo PHYs SS1 and SS2 ref clocks + +From: Abel Vesa + +[ Upstream commit 3af51501e2b8c87564b5cda43b0e5c316cf54717 ] + +It seems the USB combo SS1 and SS2 ref clocks have another gate, unlike +the SS0. These gates are part of the TCSR clock controller. + +At least on Dell XPS 13 (9345), if the ref clock provided by the TCSR +clock controller for SS1 PHY is disabled on the clk_disable_unused late +initcall, the PHY fails to initialize. It doesn't happen on the SS0 PHY +and the SS2 is not used on this device. + +This doesn't seem to be a problem on CRD though. It might be that the +RPMh has a vote for it from some other consumer and does not actually +disable it when ther kernel drops its vote. + +Either way, these TCSR provided clocks seem to be the correct ones for +the SS1 and SS2, so use them instead. + +Fixes: 4af46b7bd66f ("arm64: dts: qcom: x1e80100: Add USB nodes") +Signed-off-by: Abel Vesa +Reviewed-by: Neil Armstrong +Reviewed-by: Taniya Das +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251103-dts-qcom-x1e80100-fix-combo-ref-clks-v1-1-f395ec3cb7e8@linaro.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/x1e80100.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/x1e80100.dtsi b/arch/arm64/boot/dts/qcom/x1e80100.dtsi +index 662ad694cd914..3290fd8c2d6e6 100644 +--- a/arch/arm64/boot/dts/qcom/x1e80100.dtsi ++++ b/arch/arm64/boot/dts/qcom/x1e80100.dtsi +@@ -2910,7 +2910,7 @@ usb_1_ss1_qmpphy: phy@fda000 { + reg = <0 0x00fda000 0 0x4000>; + + clocks = <&gcc GCC_USB3_SEC_PHY_AUX_CLK>, +- <&rpmhcc RPMH_CXO_CLK>, ++ <&tcsr TCSR_USB4_1_CLKREF_EN>, + <&gcc GCC_USB3_SEC_PHY_COM_AUX_CLK>, + <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>; + clock-names = "aux", +@@ -2981,7 +2981,7 @@ usb_1_ss2_qmpphy: phy@fdf000 { + reg = <0 0x00fdf000 0 0x4000>; + + clocks = <&gcc GCC_USB3_TERT_PHY_AUX_CLK>, +- <&rpmhcc RPMH_CXO_CLK>, ++ <&tcsr TCSR_USB4_2_CLKREF_EN>, + <&gcc GCC_USB3_TERT_PHY_COM_AUX_CLK>, + <&gcc GCC_USB3_TERT_PHY_PIPE_CLK>; + clock-names = "aux", +-- +2.51.0 + diff --git a/queue-6.18/arm64-dts-renesas-r9a09g047e57-smarc-remove-duplicat.patch b/queue-6.18/arm64-dts-renesas-r9a09g047e57-smarc-remove-duplicat.patch new file mode 100644 index 0000000000..ca2bb67baf --- /dev/null +++ b/queue-6.18/arm64-dts-renesas-r9a09g047e57-smarc-remove-duplicat.patch @@ -0,0 +1,34 @@ +From ea4b6ce7694f3a0970705dcd8f0e7f75fdbd14af Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 25 Nov 2025 17:52:06 +0100 +Subject: arm64: dts: renesas: r9a09g047e57-smarc: Remove duplicate SW_LCD_EN + +From: Geert Uytterhoeven + +[ Upstream commit 44cfd102ce28e749a07bb0f1668cf932077b1175 ] + +SW_LCD_EN is defined twice. + +Fixes: 9e95446b0cf93a91 ("arm64: dts: renesas: r9a09g047e57-smarc: Add gpio keys") +Signed-off-by: Geert Uytterhoeven +Link: https://patch.msgid.link/1f93558c62f4461f50935644ec831a7d2cb52630.1764089463.git.geert+renesas@glider.be +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/renesas/r9a09g047e57-smarc.dts | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/renesas/r9a09g047e57-smarc.dts b/arch/arm64/boot/dts/renesas/r9a09g047e57-smarc.dts +index 08e814c03fa85..ed6fcdc337a0b 100644 +--- a/arch/arm64/boot/dts/renesas/r9a09g047e57-smarc.dts ++++ b/arch/arm64/boot/dts/renesas/r9a09g047e57-smarc.dts +@@ -8,7 +8,6 @@ + /dts-v1/; + + /* Switch selection settings */ +-#define SW_LCD_EN 0 + #define SW_GPIO8_CAN0_STB 0 + #define SW_GPIO9_CAN1_STB 0 + #define SW_LCD_EN 0 +-- +2.51.0 + diff --git a/queue-6.18/arm64-dts-renesas-rzt2h-n2h-evk-common-use-gpio-for-.patch b/queue-6.18/arm64-dts-renesas-rzt2h-n2h-evk-common-use-gpio-for-.patch new file mode 100644 index 0000000000..8123334fca --- /dev/null +++ b/queue-6.18/arm64-dts-renesas-rzt2h-n2h-evk-common-use-gpio-for-.patch @@ -0,0 +1,54 @@ +From ff53409b69af1abf367faa232e48baa475fd437a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Jan 2026 13:13:19 +0000 +Subject: arm64: dts: renesas: rzt2h-n2h-evk-common: Use GPIO for SD0 write + protect + +From: Lad Prabhakar + +[ Upstream commit a1b1ee0348f889ec262482e16e9ff670617db7b0 ] + +Switch SD0 write-protect detection to a GPIO on the RZ/T2H and RZ/N2H +EVKs. Both boards use a full-size SD card slot on the SD0 channel with +a dedicated WP pin. + +The RZ/T2H and RZ/N2H SoCs use of_data_rcar_gen3, which sets +MMC_CAP2_NO_WRITE_PROTECT and causes the core to ignore the WP signal +unless a wp-gpios property is provided. Describe the WP pin as a GPIO +to allow the MMC core to evaluate the write-protect status correctly. + +Fixes: d065453e5ee0 ("arm64: dts: renesas: rzt2h-rzn2h-evk: Enable SD card slot") +Signed-off-by: Lad Prabhakar +Reviewed-by: Geert Uytterhoeven +Link: https://patch.msgid.link/20260106131319.643084-1-prabhakar.mahadev-lad.rj@bp.renesas.com +Signed-off-by: Geert Uytterhoeven +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/renesas/rzt2h-n2h-evk-common.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/renesas/rzt2h-n2h-evk-common.dtsi b/arch/arm64/boot/dts/renesas/rzt2h-n2h-evk-common.dtsi +index 5c91002c99c48..5384a43837c1d 100644 +--- a/arch/arm64/boot/dts/renesas/rzt2h-n2h-evk-common.dtsi ++++ b/arch/arm64/boot/dts/renesas/rzt2h-n2h-evk-common.dtsi +@@ -154,8 +154,7 @@ data-pins { + ctrl-pins { + pinmux = , /* SD0_CLK */ + , /* SD0_CMD */ +- , /* SD0_CD */ +- ; /* SD0_WP */ ++ ; /* SD0_CD */ + }; + }; + +@@ -212,6 +211,7 @@ &sdhi0 { + pinctrl-names = "default", "state_uhs"; + vmmc-supply = <®_3p3v>; + vqmmc-supply = <&vqmmc_sdhi0>; ++ wp-gpios = <&pinctrl RZT2H_GPIO(22, 6) GPIO_ACTIVE_HIGH>; + bus-width = <4>; + sd-uhs-sdr50; + sd-uhs-sdr104; +-- +2.51.0 + diff --git a/queue-6.18/arm64-dts-ti-k3-j784s4-j742s2-main-common.dtsi-refac.patch b/queue-6.18/arm64-dts-ti-k3-j784s4-j742s2-main-common.dtsi-refac.patch new file mode 100644 index 0000000000..d127fb0c1f --- /dev/null +++ b/queue-6.18/arm64-dts-ti-k3-j784s4-j742s2-main-common.dtsi-refac.patch @@ -0,0 +1,125 @@ +From 9e5d25a3c3eb8878e0ea5f69fccce2ee1e9a79a5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 14:21:13 +0530 +Subject: arm64: dts: ti: k3-j784s4-j742s2-main-common.dtsi: Refactor watchdog + instances for j784s4 + +From: Abhash Kumar Jha + +[ Upstream commit 61acc4428a7f52e0a13e226ba76f2ce2ca66c065 ] + +Each A72 core has one watchdog instance associated with it. Since j742s2 +has 4 A72 cores, the common file should not define 8 watchdog instances. + +Refactor the last 4 extra watchdogs from the common file to j784s4 +specific file, as j784s4 has 8 A72 cores and thus hardware description +requires 8 watchdog instances. + +Fixes: 9cc161a4509c ("arm64: dts: ti: Refactor J784s4 SoC files to a common file") +Signed-off-by: Abhash Kumar Jha +Reviewed-by: Udit Kumar +Link: https://patch.msgid.link/20260112085113.3476193-3-a-kumar2@ti.com +Signed-off-by: Nishanth Menon +Signed-off-by: Sasha Levin +--- + .../dts/ti/k3-j784s4-j742s2-main-common.dtsi | 36 ------------------- + arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi | 36 +++++++++++++++++++ + 2 files changed, 36 insertions(+), 36 deletions(-) + +diff --git a/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-main-common.dtsi b/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-main-common.dtsi +index 9cc0901d58fbf..c2636e624f18b 100644 +--- a/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-main-common.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-main-common.dtsi +@@ -2378,42 +2378,6 @@ watchdog3: watchdog@2230000 { + assigned-clock-parents = <&k3_clks 351 4>; + }; + +- watchdog4: watchdog@2240000 { +- compatible = "ti,j7-rti-wdt"; +- reg = <0x00 0x2240000 0x00 0x100>; +- clocks = <&k3_clks 352 0>; +- power-domains = <&k3_pds 352 TI_SCI_PD_EXCLUSIVE>; +- assigned-clocks = <&k3_clks 352 0>; +- assigned-clock-parents = <&k3_clks 352 4>; +- }; +- +- watchdog5: watchdog@2250000 { +- compatible = "ti,j7-rti-wdt"; +- reg = <0x00 0x2250000 0x00 0x100>; +- clocks = <&k3_clks 353 0>; +- power-domains = <&k3_pds 353 TI_SCI_PD_EXCLUSIVE>; +- assigned-clocks = <&k3_clks 353 0>; +- assigned-clock-parents = <&k3_clks 353 4>; +- }; +- +- watchdog6: watchdog@2260000 { +- compatible = "ti,j7-rti-wdt"; +- reg = <0x00 0x2260000 0x00 0x100>; +- clocks = <&k3_clks 354 0>; +- power-domains = <&k3_pds 354 TI_SCI_PD_EXCLUSIVE>; +- assigned-clocks = <&k3_clks 354 0>; +- assigned-clock-parents = <&k3_clks 354 4>; +- }; +- +- watchdog7: watchdog@2270000 { +- compatible = "ti,j7-rti-wdt"; +- reg = <0x00 0x2270000 0x00 0x100>; +- clocks = <&k3_clks 355 0>; +- power-domains = <&k3_pds 355 TI_SCI_PD_EXCLUSIVE>; +- assigned-clocks = <&k3_clks 355 0>; +- assigned-clock-parents = <&k3_clks 355 4>; +- }; +- + /* + * The following RTI instances are coupled with MCU R5Fs, c7x and + * GPU so keeping them reserved as these will be used by their +diff --git a/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi b/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi +index 5b7830a3c0975..78fcd0c40abcf 100644 +--- a/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi +@@ -6,6 +6,42 @@ + */ + + &cbass_main { ++ watchdog4: watchdog@2240000 { ++ compatible = "ti,j7-rti-wdt"; ++ reg = <0x00 0x2240000 0x00 0x100>; ++ clocks = <&k3_clks 352 0>; ++ power-domains = <&k3_pds 352 TI_SCI_PD_EXCLUSIVE>; ++ assigned-clocks = <&k3_clks 352 0>; ++ assigned-clock-parents = <&k3_clks 352 4>; ++ }; ++ ++ watchdog5: watchdog@2250000 { ++ compatible = "ti,j7-rti-wdt"; ++ reg = <0x00 0x2250000 0x00 0x100>; ++ clocks = <&k3_clks 353 0>; ++ power-domains = <&k3_pds 353 TI_SCI_PD_EXCLUSIVE>; ++ assigned-clocks = <&k3_clks 353 0>; ++ assigned-clock-parents = <&k3_clks 353 4>; ++ }; ++ ++ watchdog6: watchdog@2260000 { ++ compatible = "ti,j7-rti-wdt"; ++ reg = <0x00 0x2260000 0x00 0x100>; ++ clocks = <&k3_clks 354 0>; ++ power-domains = <&k3_pds 354 TI_SCI_PD_EXCLUSIVE>; ++ assigned-clocks = <&k3_clks 354 0>; ++ assigned-clock-parents = <&k3_clks 354 4>; ++ }; ++ ++ watchdog7: watchdog@2270000 { ++ compatible = "ti,j7-rti-wdt"; ++ reg = <0x00 0x2270000 0x00 0x100>; ++ clocks = <&k3_clks 355 0>; ++ power-domains = <&k3_pds 355 TI_SCI_PD_EXCLUSIVE>; ++ assigned-clocks = <&k3_clks 355 0>; ++ assigned-clock-parents = <&k3_clks 355 4>; ++ }; ++ + pcie2_rc: pcie@2920000 { + compatible = "ti,j784s4-pcie-host"; + reg = <0x00 0x02920000 0x00 0x1000>, +-- +2.51.0 + diff --git a/queue-6.18/arm64-dts-ti-k3-j784s4-main.dtsi-move-c71_3-node-to-.patch b/queue-6.18/arm64-dts-ti-k3-j784s4-main.dtsi-move-c71_3-node-to-.patch new file mode 100644 index 0000000000..9c628696f5 --- /dev/null +++ b/queue-6.18/arm64-dts-ti-k3-j784s4-main.dtsi-move-c71_3-node-to-.patch @@ -0,0 +1,73 @@ +From de92cad71b4a56a174e3c02c7599c657761a7fb7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 14:21:12 +0530 +Subject: arm64: dts: ti: k3-j784s4-main.dtsi: Move c71_3 node to appropriate + order + +From: Abhash Kumar Jha + +[ Upstream commit 24c9d5fb8bbf5e8c9e6fc2beffeb80ac2da83de4 ] + +The device tree nodes should be ordered by unit addresses in ascending +order. + +Correct the order by moving the c71_3 DSP node at the end as it has a +higher unit address. + +Signed-off-by: Abhash Kumar Jha +Reviewed-by: Udit Kumar +Link: https://patch.msgid.link/20260112085113.3476193-2-a-kumar2@ti.com +Signed-off-by: Nishanth Menon +Stable-dep-of: 61acc4428a7f ("arm64: dts: ti: k3-j784s4-j742s2-main-common.dtsi: Refactor watchdog instances for j784s4") +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi | 26 +++++++++++----------- + 1 file changed, 13 insertions(+), 13 deletions(-) + +diff --git a/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi b/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi +index 0160fe0da9838..5b7830a3c0975 100644 +--- a/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi +@@ -6,19 +6,6 @@ + */ + + &cbass_main { +- c71_3: dsp@67800000 { +- compatible = "ti,j721s2-c71-dsp"; +- reg = <0x00 0x67800000 0x00 0x00080000>, +- <0x00 0x67e00000 0x00 0x0000c000>; +- reg-names = "l2sram", "l1dram"; +- resets = <&k3_reset 40 1>; +- firmware-name = "j784s4-c71_3-fw"; +- ti,sci = <&sms>; +- ti,sci-dev-id = <40>; +- ti,sci-proc-ids = <0x33 0xff>; +- status = "disabled"; +- }; +- + pcie2_rc: pcie@2920000 { + compatible = "ti,j784s4-pcie-host"; + reg = <0x00 0x02920000 0x00 0x1000>, +@@ -113,6 +100,19 @@ serdes2: serdes@5020000 { + status = "disabled"; + }; + }; ++ ++ c71_3: dsp@67800000 { ++ compatible = "ti,j721s2-c71-dsp"; ++ reg = <0x00 0x67800000 0x00 0x00080000>, ++ <0x00 0x67e00000 0x00 0x0000c000>; ++ reg-names = "l2sram", "l1dram"; ++ resets = <&k3_reset 40 1>; ++ firmware-name = "j784s4-c71_3-fw"; ++ ti,sci = <&sms>; ++ ti,sci-dev-id = <40>; ++ ti,sci-proc-ids = <0x33 0xff>; ++ status = "disabled"; ++ }; + }; + + &scm_conf { +-- +2.51.0 + diff --git a/queue-6.18/arm64-dts-tqma8mpql-mba8mp-ras314-fix-hdmi-cec-pad-c.patch b/queue-6.18/arm64-dts-tqma8mpql-mba8mp-ras314-fix-hdmi-cec-pad-c.patch new file mode 100644 index 0000000000..5318e3fb5c --- /dev/null +++ b/queue-6.18/arm64-dts-tqma8mpql-mba8mp-ras314-fix-hdmi-cec-pad-c.patch @@ -0,0 +1,37 @@ +From d48b4ec8592dd238fdc23beaf79802ef76db870d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 11:53:13 +0100 +Subject: arm64: dts: tqma8mpql-mba8mp-ras314: Fix HDMI CEC pad control + settings + +From: Alexander Stein + +[ Upstream commit 53a5c1d98d1155ece4c9446c0fea55e17d08774a ] + +As per datasheet of the HDMI protection IC the CEC_IC pin has been +configured as open-drain. + +Fixes: ddabb3ce3f90 ("arm64: dts: freescale: add TQMa8MPQL on MBa8MP-RAS314") +Signed-off-by: Alexander Stein +Signed-off-by: Shawn Guo +Signed-off-by: Sasha Levin +--- + .../arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts +index f7346b3d35fe5..a122f2ed5f531 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts +@@ -704,7 +704,7 @@ pinctrl_hdmi: hdmigrp { + fsl,pins = , + , + , +- ; ++ ; + }; + + pinctrl_gpt1: gpt1grp { +-- +2.51.0 + diff --git a/queue-6.18/arm64-dts-tqma8mpql-mba8mpxl-fix-hdmi-cec-pad-contro.patch b/queue-6.18/arm64-dts-tqma8mpql-mba8mpxl-fix-hdmi-cec-pad-contro.patch new file mode 100644 index 0000000000..a0c5fe99cb --- /dev/null +++ b/queue-6.18/arm64-dts-tqma8mpql-mba8mpxl-fix-hdmi-cec-pad-contro.patch @@ -0,0 +1,36 @@ +From eff20bf56d0f8386070460ffd444a87546fdaa07 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 11:53:09 +0100 +Subject: arm64: dts: tqma8mpql-mba8mpxl: Fix HDMI CEC pad control settings + +From: Alexander Stein + +[ Upstream commit 8401527abb5e3a00c867b6597b8e1b29c80c9824 ] + +As per datasheet of the HDMI protection IC the CEC_IC pin has been +configured as open-drain. + +Fixes: 418d1d840e42 ("arm64: dts: freescale: add initial device tree for TQMa8MPQL with i.MX8MP") +Signed-off-by: Alexander Stein +Signed-off-by: Shawn Guo +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts +index 4eedd00d83b9f..ac05c05193c5b 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts +@@ -860,7 +860,7 @@ pinctrl_hdmi: hdmigrp { + fsl,pins = , + , + , +- ; ++ ; + }; + + pinctrl_hoggpio2: hoggpio2grp { +-- +2.51.0 + diff --git a/queue-6.18/arm64-gcs-fix-error-handling-in-arch_set_shadow_stac.patch b/queue-6.18/arm64-gcs-fix-error-handling-in-arch_set_shadow_stac.patch new file mode 100644 index 0000000000..1d3c6a7a19 --- /dev/null +++ b/queue-6.18/arm64-gcs-fix-error-handling-in-arch_set_shadow_stac.patch @@ -0,0 +1,45 @@ +From 50a48b124f42a0e21d52f9b231a4dd1aa607118e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 10:32:51 -0800 +Subject: arm64/gcs: Fix error handling in arch_set_shadow_stack_status() + +From: Breno Leitao + +[ Upstream commit 53c998527ffa60f9deda8974a11ad39790684159 ] + +alloc_gcs() returns an error-encoded pointer on failure, which comes +from do_mmap(), not NULL. + +The current NULL check fails to detect errors, which could lead to using +an invalid GCS address. + +Use IS_ERR_VALUE() to properly detect errors, consistent with the +check in gcs_alloc_thread_stack(). + +Fixes: b57180c75c7e ("arm64/gcs: Implement shadow stack prctl() interface") +Reviewed-by: Mark Brown +Signed-off-by: Breno Leitao +Signed-off-by: Will Deacon +Signed-off-by: Sasha Levin +--- + arch/arm64/mm/gcs.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/mm/gcs.c b/arch/arm64/mm/gcs.c +index 6e93f78de79b1..04a23a497f205 100644 +--- a/arch/arm64/mm/gcs.c ++++ b/arch/arm64/mm/gcs.c +@@ -199,8 +199,8 @@ int arch_set_shadow_stack_status(struct task_struct *task, unsigned long arg) + + size = gcs_size(0); + gcs = alloc_gcs(0, size); +- if (!gcs) +- return -ENOMEM; ++ if (IS_ERR_VALUE(gcs)) ++ return gcs; + + task->thread.gcspr_el0 = gcs + size - sizeof(u64); + task->thread.gcs_base = gcs; +-- +2.51.0 + diff --git a/queue-6.18/asoc-nau8821-fixup-nau8821_enable_jack_detect.patch b/queue-6.18/asoc-nau8821-fixup-nau8821_enable_jack_detect.patch new file mode 100644 index 0000000000..177c11c498 --- /dev/null +++ b/queue-6.18/asoc-nau8821-fixup-nau8821_enable_jack_detect.patch @@ -0,0 +1,84 @@ +From 6c76cbfa953d23a2cd6e7817d140f8df4d866333 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 31 Dec 2025 22:04:15 +0200 +Subject: ASoC: nau8821: Fixup nau8821_enable_jack_detect() + +From: Cristian Ciocaltea + +[ Upstream commit 70237853edf0a69773a7370eb74ea2a44dfe3050 ] + +The nau8821_enable_jack_detect() function was supposed to allow enabling +or disabling jack events reporting. However, once enabled, any +subsequent invocation would fail and the following splat is shown: + +[ 3136.996771] Hardware name: Valve Jupiter/Jupiter, BIOS F7A0131 01/30/2024 +[ 3136.996773] Workqueue: events_unbound deferred_probe_work_func +[ 3136.996780] Call Trace: +[ 3136.996782] +[ 3136.996787] dump_stack_lvl+0x6e/0xa0 +[ 3136.996796] __setup_irq.cold+0x9c/0xce +[ 3136.996803] ? __pfx_irq_default_primary_handler+0x10/0x10 +[ 3136.996812] ? __pfx_nau8821_interrupt+0x10/0x10 [snd_soc_nau8821] +[ 3136.996825] request_threaded_irq+0xd9/0x160 +[ 3136.996853] devm_request_threaded_irq+0x71/0xd0 +[ 3136.996859] ? __pfx_nau8821_interrupt+0x10/0x10 [snd_soc_nau8821] +[ 3136.996882] nau8821_enable_jack_detect+0xa5/0xc0 [snd_soc_nau8821] +[ 3136.996901] acp5x_8821_init+0x8d/0xa0 [snd_soc_acp5x_mach] +[ 3136.996917] snd_soc_link_init+0x25/0x50 [snd_soc_core] +[ 3136.996958] snd_soc_bind_card+0x615/0xd00 [snd_soc_core] +[ 3136.997026] snd_soc_register_card+0x1b2/0x1c0 [snd_soc_core] +[ 3136.997064] devm_snd_soc_register_card+0x47/0x90 [snd_soc_core] +[ 3136.997108] acp5x_probe+0x72/0xb0 [snd_soc_acp5x_mach] +[...] +[ 3136.997508] nau8821 i2c-NVTN2020:00: Cannot request irq 58 (-16) + +Introduce jdet_active flag to driver data structure and use it to +provide one-time initialization of the jack detection work queue and +related interrupt line. + +Note this is also a prerequisite for additional fixes around module +unloading and suspend handling. + +Fixes: aab1ad11d69f ("ASoC: nau8821: new driver") +Signed-off-by: Cristian Ciocaltea +Link: https://patch.msgid.link/20251231-nau8821-cleanup-v1-1-6b0b76cbbb64@collabora.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/nau8821.c | 5 +++++ + sound/soc/codecs/nau8821.h | 1 + + 2 files changed, 6 insertions(+) + +diff --git a/sound/soc/codecs/nau8821.c b/sound/soc/codecs/nau8821.c +index 4fa9a785513e5..dfb9630bffe29 100644 +--- a/sound/soc/codecs/nau8821.c ++++ b/sound/soc/codecs/nau8821.c +@@ -1661,8 +1661,13 @@ int nau8821_enable_jack_detect(struct snd_soc_component *component, + int ret; + + nau8821->jack = jack; ++ ++ if (nau8821->jdet_active) ++ return 0; ++ + /* Initiate jack detection work queue */ + INIT_DELAYED_WORK(&nau8821->jdet_work, nau8821_jdet_work); ++ nau8821->jdet_active = true; + + ret = devm_request_threaded_irq(nau8821->dev, nau8821->irq, NULL, + nau8821_interrupt, IRQF_TRIGGER_LOW | IRQF_ONESHOT, +diff --git a/sound/soc/codecs/nau8821.h b/sound/soc/codecs/nau8821.h +index 88602923780d8..f9d7cd8cbd211 100644 +--- a/sound/soc/codecs/nau8821.h ++++ b/sound/soc/codecs/nau8821.h +@@ -562,6 +562,7 @@ struct nau8821 { + struct snd_soc_dapm_context *dapm; + struct snd_soc_jack *jack; + struct delayed_work jdet_work; ++ bool jdet_active; + int irq; + int clk_id; + int micbias_voltage; +-- +2.51.0 + diff --git a/queue-6.18/asoc-sdca-allow-sample-width-wild-cards-in-set_usage.patch b/queue-6.18/asoc-sdca-allow-sample-width-wild-cards-in-set_usage.patch new file mode 100644 index 0000000000..e7a4a99b26 --- /dev/null +++ b/queue-6.18/asoc-sdca-allow-sample-width-wild-cards-in-set_usage.patch @@ -0,0 +1,39 @@ +From e9a2ac7358e38550577a1366e077beac285baff3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Dec 2025 14:22:04 +0000 +Subject: ASoC: SDCA: Allow sample width wild cards in set_usage() + +From: Simon Trimmer + +[ Upstream commit 87783532d34050e2bff6749a4fe9860e624a0540 ] + +The SDCA spec allows the sample rate and width to be wild cards, but the +current implementation of set_usage() only checked for a wild card of +the sample rate. + +Fixes: 4ed357f72a0e ("ASoC: SDCA: Add hw_params() helper function") +Signed-off-by: Simon Trimmer +Reviewed-by: Charles Keepax +Link: https://patch.msgid.link/20251216142204.183958-1-simont@opensource.cirrus.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sdca/sdca_asoc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/soc/sdca/sdca_asoc.c b/sound/soc/sdca/sdca_asoc.c +index 892b7c028faea..7e986870d48c5 100644 +--- a/sound/soc/sdca/sdca_asoc.c ++++ b/sound/soc/sdca/sdca_asoc.c +@@ -1519,7 +1519,7 @@ static int set_usage(struct device *dev, struct regmap *regmap, + unsigned int rate = sdca_range(range, SDCA_USAGE_SAMPLE_RATE, i); + unsigned int width = sdca_range(range, SDCA_USAGE_SAMPLE_WIDTH, i); + +- if ((!rate || rate == target_rate) && width == target_width) { ++ if ((!rate || rate == target_rate) && (!width || width == target_width)) { + unsigned int usage = sdca_range(range, SDCA_USAGE_NUMBER, i); + unsigned int reg = SDW_SDCA_CTL(function->desc->adr, + entity->id, sel, 0); +-- +2.51.0 + diff --git a/queue-6.18/asoc-sdca-force-some-sdca-controls-to-be-volatile.patch b/queue-6.18/asoc-sdca-force-some-sdca-controls-to-be-volatile.patch new file mode 100644 index 0000000000..928d0d1ef2 --- /dev/null +++ b/queue-6.18/asoc-sdca-force-some-sdca-controls-to-be-volatile.patch @@ -0,0 +1,139 @@ +From db671553a69cd924369234f20a0202a9306c61b0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Oct 2025 16:55:02 +0100 +Subject: ASoC: SDCA: Force some SDCA Controls to be volatile + +From: Charles Keepax + +[ Upstream commit c7b6c6b60594fd1efe35c61bc6a2176b25263ccc ] + +Whilst SDCA does specify an Access Mode for each Control, there is not a +1-to-1 mapping between that and ASoC's internal representation. Some +registers require being treated as volatile from the hosts perspective +even in their Access Mode is Read-Write. Add an explicit list of SDCA +controls that should be forced volatile. + +Reviewed-by: Bard Liao +Signed-off-by: Charles Keepax +Reviewed-by: Pierre-Louis Bossart +Link: https://patch.msgid.link/20251020155512.353774-10-ckeepax@opensource.cirrus.com +Signed-off-by: Mark Brown +Stable-dep-of: 9fad74b79e5f ("ASoC: SDCA: Handle volatile controls correctly") +Signed-off-by: Sasha Levin +--- + include/sound/sdca_function.h | 1 + + sound/soc/sdca/sdca_functions.c | 58 +++++++++++++++++++++++++++++++++ + sound/soc/sdca/sdca_regmap.c | 9 +---- + 3 files changed, 60 insertions(+), 8 deletions(-) + +diff --git a/include/sound/sdca_function.h b/include/sound/sdca_function.h +index ea68856e4c8c4..86fd74146c33d 100644 +--- a/include/sound/sdca_function.h ++++ b/include/sound/sdca_function.h +@@ -771,6 +771,7 @@ struct sdca_control { + u8 layers; + + bool deferrable; ++ bool is_volatile; + bool has_default; + bool has_fixed; + }; +diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c +index 7adbf653bd8ac..4417278e39bb1 100644 +--- a/sound/soc/sdca/sdca_functions.c ++++ b/sound/soc/sdca/sdca_functions.c +@@ -779,6 +779,62 @@ find_sdca_control_datatype(const struct sdca_entity *entity, + } + } + ++static bool find_sdca_control_volatile(const struct sdca_entity *entity, ++ const struct sdca_control *control) ++{ ++ switch (control->mode) { ++ case SDCA_ACCESS_MODE_DC: ++ return false; ++ case SDCA_ACCESS_MODE_RO: ++ case SDCA_ACCESS_MODE_RW1S: ++ case SDCA_ACCESS_MODE_RW1C: ++ return true; ++ default: ++ break; ++ } ++ ++ switch (SDCA_CTL_TYPE(entity->type, control->sel)) { ++ case SDCA_CTL_TYPE_S(XU, FDL_CURRENTOWNER): ++ case SDCA_CTL_TYPE_S(XU, FDL_MESSAGEOFFSET): ++ case SDCA_CTL_TYPE_S(XU, FDL_MESSAGELENGTH): ++ case SDCA_CTL_TYPE_S(XU, FDL_STATUS): ++ case SDCA_CTL_TYPE_S(XU, FDL_HOST_REQUEST): ++ case SDCA_CTL_TYPE_S(SPE, AUTHTX_CURRENTOWNER): ++ case SDCA_CTL_TYPE_S(SPE, AUTHTX_MESSAGEOFFSET): ++ case SDCA_CTL_TYPE_S(SPE, AUTHTX_MESSAGELENGTH): ++ case SDCA_CTL_TYPE_S(SPE, AUTHRX_CURRENTOWNER): ++ case SDCA_CTL_TYPE_S(SPE, AUTHRX_MESSAGEOFFSET): ++ case SDCA_CTL_TYPE_S(SPE, AUTHRX_MESSAGELENGTH): ++ case SDCA_CTL_TYPE_S(MFPU, AE_CURRENTOWNER): ++ case SDCA_CTL_TYPE_S(MFPU, AE_MESSAGEOFFSET): ++ case SDCA_CTL_TYPE_S(MFPU, AE_MESSAGELENGTH): ++ case SDCA_CTL_TYPE_S(SMPU, HIST_CURRENTOWNER): ++ case SDCA_CTL_TYPE_S(SMPU, HIST_MESSAGEOFFSET): ++ case SDCA_CTL_TYPE_S(SMPU, HIST_MESSAGELENGTH): ++ case SDCA_CTL_TYPE_S(SMPU, DTODTX_CURRENTOWNER): ++ case SDCA_CTL_TYPE_S(SMPU, DTODTX_MESSAGEOFFSET): ++ case SDCA_CTL_TYPE_S(SMPU, DTODTX_MESSAGELENGTH): ++ case SDCA_CTL_TYPE_S(SMPU, DTODRX_CURRENTOWNER): ++ case SDCA_CTL_TYPE_S(SMPU, DTODRX_MESSAGEOFFSET): ++ case SDCA_CTL_TYPE_S(SMPU, DTODRX_MESSAGELENGTH): ++ case SDCA_CTL_TYPE_S(SAPU, DTODTX_CURRENTOWNER): ++ case SDCA_CTL_TYPE_S(SAPU, DTODTX_MESSAGEOFFSET): ++ case SDCA_CTL_TYPE_S(SAPU, DTODTX_MESSAGELENGTH): ++ case SDCA_CTL_TYPE_S(SAPU, DTODRX_CURRENTOWNER): ++ case SDCA_CTL_TYPE_S(SAPU, DTODRX_MESSAGEOFFSET): ++ case SDCA_CTL_TYPE_S(SAPU, DTODRX_MESSAGELENGTH): ++ case SDCA_CTL_TYPE_S(HIDE, HIDTX_CURRENTOWNER): ++ case SDCA_CTL_TYPE_S(HIDE, HIDTX_MESSAGEOFFSET): ++ case SDCA_CTL_TYPE_S(HIDE, HIDTX_MESSAGELENGTH): ++ case SDCA_CTL_TYPE_S(HIDE, HIDRX_CURRENTOWNER): ++ case SDCA_CTL_TYPE_S(HIDE, HIDRX_MESSAGEOFFSET): ++ case SDCA_CTL_TYPE_S(HIDE, HIDRX_MESSAGELENGTH): ++ return true; ++ default: ++ return false; ++ } ++} ++ + static int find_sdca_control_range(struct device *dev, + struct fwnode_handle *control_node, + struct sdca_control_range *range) +@@ -927,6 +983,8 @@ static int find_sdca_entity_control(struct device *dev, struct sdca_entity *enti + break; + } + ++ control->is_volatile = find_sdca_control_volatile(entity, control); ++ + ret = find_sdca_control_range(dev, control_node, &control->range); + if (ret) { + dev_err(dev, "%s: control %#x: range missing: %d\n", +diff --git a/sound/soc/sdca/sdca_regmap.c b/sound/soc/sdca/sdca_regmap.c +index 72f893e00ff50..8fa138fca00ff 100644 +--- a/sound/soc/sdca/sdca_regmap.c ++++ b/sound/soc/sdca/sdca_regmap.c +@@ -147,14 +147,7 @@ bool sdca_regmap_volatile(struct sdca_function_data *function, unsigned int reg) + if (!control) + return false; + +- switch (control->mode) { +- case SDCA_ACCESS_MODE_RO: +- case SDCA_ACCESS_MODE_RW1S: +- case SDCA_ACCESS_MODE_RW1C: +- return true; +- default: +- return false; +- } ++ return control->is_volatile; + } + EXPORT_SYMBOL_NS(sdca_regmap_volatile, "SND_SOC_SDCA"); + +-- +2.51.0 + diff --git a/queue-6.18/asoc-sdca-handle-volatile-controls-correctly.patch b/queue-6.18/asoc-sdca-handle-volatile-controls-correctly.patch new file mode 100644 index 0000000000..5986be79bb --- /dev/null +++ b/queue-6.18/asoc-sdca-handle-volatile-controls-correctly.patch @@ -0,0 +1,108 @@ +From 1c536285dd75ee650f880d703f5c8b6c485f0127 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 12:59:39 +0000 +Subject: ASoC: SDCA: Handle volatile controls correctly + +From: Charles Keepax + +[ Upstream commit 9fad74b79e5ff353fe156c4b685cceffa5afdb1d ] + +There are very few volatile controls in SDCA that are exported +as ALSA controls, typically Detected Mode is the only common +one. However, the current code does not resume the device when +these ALSA controls are accessed, which will result in the +read/write failing. + +Add a new wrapper specifically for volatile controls that will do +the required pm_runtime operations before accessing the register. + +Fixes: c3ca24e3fcb6 ("ASoC: SDCA: Create ALSA controls from DisCo") +Signed-off-by: Charles Keepax +Link: https://patch.msgid.link/20260204125944.1134011-3-ckeepax@opensource.cirrus.com +Reviewed-by: Pierre-Louis Bossart +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sdca/sdca_asoc.c | 52 ++++++++++++++++++++++++++++++++++++-- + 1 file changed, 50 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/sdca/sdca_asoc.c b/sound/soc/sdca/sdca_asoc.c +index 7e986870d48c5..197a592ec2f16 100644 +--- a/sound/soc/sdca/sdca_asoc.c ++++ b/sound/soc/sdca/sdca_asoc.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -836,6 +837,48 @@ static int control_limit_kctl(struct device *dev, + return 0; + } + ++static int volatile_get_volsw(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); ++ struct device *dev = component->dev; ++ int ret; ++ ++ ret = pm_runtime_resume_and_get(dev); ++ if (ret < 0) { ++ dev_err(dev, "failed to resume reading %s: %d\n", ++ kcontrol->id.name, ret); ++ return ret; ++ } ++ ++ ret = snd_soc_get_volsw(kcontrol, ucontrol); ++ ++ pm_runtime_put(dev); ++ ++ return ret; ++} ++ ++static int volatile_put_volsw(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); ++ struct device *dev = component->dev; ++ int ret; ++ ++ ret = pm_runtime_resume_and_get(dev); ++ if (ret < 0) { ++ dev_err(dev, "failed to resume writing %s: %d\n", ++ kcontrol->id.name, ret); ++ return ret; ++ } ++ ++ ret = snd_soc_put_volsw(kcontrol, ucontrol); ++ ++ pm_runtime_put(dev); ++ ++ return ret; ++} ++ + static int populate_control(struct device *dev, + struct sdca_function_data *function, + struct sdca_entity *entity, +@@ -890,8 +933,13 @@ static int populate_control(struct device *dev, + (*kctl)->private_value = (unsigned long)mc; + (*kctl)->iface = SNDRV_CTL_ELEM_IFACE_MIXER; + (*kctl)->info = snd_soc_info_volsw; +- (*kctl)->get = snd_soc_get_volsw; +- (*kctl)->put = snd_soc_put_volsw; ++ if (control->is_volatile) { ++ (*kctl)->get = volatile_get_volsw; ++ (*kctl)->put = volatile_put_volsw; ++ } else { ++ (*kctl)->get = snd_soc_get_volsw; ++ (*kctl)->put = snd_soc_put_volsw; ++ } + + if (readonly_control(control)) + (*kctl)->access = SNDRV_CTL_ELEM_ACCESS_READ; +-- +2.51.0 + diff --git a/queue-6.18/asoc-sdca-remove-outdated-todo-comment.patch b/queue-6.18/asoc-sdca-remove-outdated-todo-comment.patch new file mode 100644 index 0000000000..14d792bb60 --- /dev/null +++ b/queue-6.18/asoc-sdca-remove-outdated-todo-comment.patch @@ -0,0 +1,41 @@ +From 3553e445b124cd27efb40e44fb73e23c991d3215 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 12:59:38 +0000 +Subject: ASoC: SDCA: Remove outdated todo comment + +From: Charles Keepax + +[ Upstream commit b27b57f85fe3f0eca479556ac55bc9cbd1a5685a ] + +Support for -cn- properties has already been added, however the TODO +comment noting this feature was required was not removed. Remove the +now redundant comment. + +Fixes: 50a479527ef01 ("ASoC: SDCA: Add support for -cn- value properties") +Signed-off-by: Charles Keepax +Link: https://patch.msgid.link/20260204125944.1134011-2-ckeepax@opensource.cirrus.com +Reviewed-by: Pierre-Louis Bossart +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sdca/sdca_functions.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c +index 19b12564f822e..7adbf653bd8ac 100644 +--- a/sound/soc/sdca/sdca_functions.c ++++ b/sound/soc/sdca/sdca_functions.c +@@ -854,10 +854,6 @@ static int find_sdca_control_value(struct device *dev, struct sdca_entity *entit + return 0; + } + +-/* +- * TODO: Add support for -cn- properties, allowing different channels to have +- * different defaults etc. +- */ + static int find_sdca_entity_control(struct device *dev, struct sdca_entity *entity, + struct fwnode_handle *control_node, + struct sdca_control *control) +-- +2.51.0 + diff --git a/queue-6.18/asoc-tegra-add-ahub-writeable_reg-for-rx-holes.patch b/queue-6.18/asoc-tegra-add-ahub-writeable_reg-for-rx-holes.patch new file mode 100644 index 0000000000..739413d0fd --- /dev/null +++ b/queue-6.18/asoc-tegra-add-ahub-writeable_reg-for-rx-holes.patch @@ -0,0 +1,151 @@ +From 221552a1b931df3c98a111fe59c1f268ff7be83d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 15:23:43 +0530 +Subject: ASoC: tegra: Add AHUB writeable_reg for RX holes + +From: Sheetal + +[ Upstream commit 0ba6286a71581aaf8413a55b9bd90ea3463fd23b ] + +Add writeable_reg callbacks for Tegra210/186 AHUB RX registers so the +flat cache only treats valid RX locations as writable, avoiding holes +in the register map. + +Fixes: 16e1bcc2caf4 ("ASoC: tegra: Add Tegra210 based AHUB driver") +Signed-off-by: Sheetal +Reviewed-by: Jon Hunter +Tested-by: Jon Hunter +Link: https://patch.msgid.link/20260123095346.1258556-2-sheetal@nvidia.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/tegra/tegra210_ahub.c | 57 +++++++++++++++++++++++++++++++++ + sound/soc/tegra/tegra210_ahub.h | 30 +++++++++++++++++ + 2 files changed, 87 insertions(+) + +diff --git a/sound/soc/tegra/tegra210_ahub.c b/sound/soc/tegra/tegra210_ahub.c +index 21aeaeba0b107..01d60a74ad1c3 100644 +--- a/sound/soc/tegra/tegra210_ahub.c ++++ b/sound/soc/tegra/tegra210_ahub.c +@@ -2049,6 +2049,61 @@ static const struct snd_soc_component_driver tegra264_ahub_component = { + .num_dapm_routes = ARRAY_SIZE(tegra264_ahub_routes), + }; + ++static bool tegra210_ahub_wr_reg(struct device *dev, unsigned int reg) ++{ ++ int part; ++ ++ if (reg % TEGRA210_XBAR_RX_STRIDE) ++ return false; ++ ++ for (part = 0; part < TEGRA210_XBAR_UPDATE_MAX_REG; part++) { ++ switch (reg & ~(part * TEGRA210_XBAR_PART1_RX)) { ++ case TEGRA210_AXBAR_PART_0_ADMAIF_RX1_0 ... TEGRA210_AXBAR_PART_0_ADMAIF_RX10_0: ++ case TEGRA210_AXBAR_PART_0_I2S1_RX1_0 ... TEGRA210_AXBAR_PART_0_I2S5_RX1_0: ++ case TEGRA210_AXBAR_PART_0_SFC1_RX1_0 ... TEGRA210_AXBAR_PART_0_SFC4_RX1_0: ++ case TEGRA210_AXBAR_PART_0_MIXER1_RX1_0 ... TEGRA210_AXBAR_PART_0_MIXER1_RX10_0: ++ case TEGRA210_AXBAR_PART_0_SPDIF1_RX1_0 ... TEGRA210_AXBAR_PART_0_SPDIF1_RX2_0: ++ case TEGRA210_AXBAR_PART_0_AFC1_RX1_0 ... TEGRA210_AXBAR_PART_0_AFC6_RX1_0: ++ case TEGRA210_AXBAR_PART_0_OPE1_RX1_0 ... TEGRA210_AXBAR_PART_0_OPE2_RX1_0: ++ case TEGRA210_AXBAR_PART_0_SPKPROT1_RX1_0: ++ case TEGRA210_AXBAR_PART_0_MVC1_RX1_0 ... TEGRA210_AXBAR_PART_0_MVC2_RX1_0: ++ case TEGRA210_AXBAR_PART_0_AMX1_RX1_0 ... TEGRA210_AXBAR_PART_0_ADX2_RX1_0: ++ return true; ++ default: ++ break; ++ } ++ } ++ ++ return false; ++} ++ ++static bool tegra186_ahub_wr_reg(struct device *dev, unsigned int reg) ++{ ++ int part; ++ ++ if (reg % TEGRA210_XBAR_RX_STRIDE) ++ return false; ++ ++ for (part = 0; part < TEGRA186_XBAR_UPDATE_MAX_REG; part++) { ++ switch (reg & ~(part * TEGRA210_XBAR_PART1_RX)) { ++ case TEGRA210_AXBAR_PART_0_ADMAIF_RX1_0 ... TEGRA186_AXBAR_PART_0_I2S6_RX1_0: ++ case TEGRA210_AXBAR_PART_0_SFC1_RX1_0 ... TEGRA210_AXBAR_PART_0_SFC4_RX1_0: ++ case TEGRA210_AXBAR_PART_0_MIXER1_RX1_0 ... TEGRA210_AXBAR_PART_0_MIXER1_RX10_0: ++ case TEGRA186_AXBAR_PART_0_DSPK1_RX1_0 ... TEGRA186_AXBAR_PART_0_DSPK2_RX1_0: ++ case TEGRA210_AXBAR_PART_0_AFC1_RX1_0 ... TEGRA210_AXBAR_PART_0_AFC6_RX1_0: ++ case TEGRA210_AXBAR_PART_0_OPE1_RX1_0: ++ case TEGRA186_AXBAR_PART_0_MVC1_RX1_0 ... TEGRA186_AXBAR_PART_0_MVC2_RX1_0: ++ case TEGRA186_AXBAR_PART_0_AMX1_RX1_0 ... TEGRA186_AXBAR_PART_0_AMX3_RX4_0: ++ case TEGRA210_AXBAR_PART_0_ADX1_RX1_0 ... TEGRA186_AXBAR_PART_0_ASRC1_RX7_0: ++ return true; ++ default: ++ break; ++ } ++ } ++ ++ return false; ++} ++ + static bool tegra264_ahub_wr_reg(struct device *dev, unsigned int reg) + { + int part; +@@ -2076,6 +2131,7 @@ static const struct regmap_config tegra210_ahub_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, ++ .writeable_reg = tegra210_ahub_wr_reg, + .max_register = TEGRA210_MAX_REGISTER_ADDR, + .cache_type = REGCACHE_FLAT, + }; +@@ -2084,6 +2140,7 @@ static const struct regmap_config tegra186_ahub_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, ++ .writeable_reg = tegra186_ahub_wr_reg, + .max_register = TEGRA186_MAX_REGISTER_ADDR, + .cache_type = REGCACHE_FLAT, + }; +diff --git a/sound/soc/tegra/tegra210_ahub.h b/sound/soc/tegra/tegra210_ahub.h +index f355b2cfd19b2..acbe640dd3b57 100644 +--- a/sound/soc/tegra/tegra210_ahub.h ++++ b/sound/soc/tegra/tegra210_ahub.h +@@ -68,6 +68,36 @@ + #define TEGRA210_MAX_REGISTER_ADDR (TEGRA210_XBAR_PART2_RX + \ + (TEGRA210_XBAR_RX_STRIDE * (TEGRA210_XBAR_AUDIO_RX_COUNT - 1))) + ++/* AXBAR register offsets */ ++#define TEGRA186_AXBAR_PART_0_AMX1_RX1_0 0x120 ++#define TEGRA186_AXBAR_PART_0_AMX3_RX4_0 0x14c ++#define TEGRA186_AXBAR_PART_0_ASRC1_RX7_0 0x1a8 ++#define TEGRA186_AXBAR_PART_0_DSPK1_RX1_0 0xc0 ++#define TEGRA186_AXBAR_PART_0_DSPK2_RX1_0 0xc4 ++#define TEGRA186_AXBAR_PART_0_I2S6_RX1_0 0x54 ++#define TEGRA186_AXBAR_PART_0_MVC1_RX1_0 0x110 ++#define TEGRA186_AXBAR_PART_0_MVC2_RX1_0 0x114 ++#define TEGRA210_AXBAR_PART_0_ADMAIF_RX10_0 0x24 ++#define TEGRA210_AXBAR_PART_0_ADMAIF_RX1_0 0x0 ++#define TEGRA210_AXBAR_PART_0_ADX1_RX1_0 0x160 ++#define TEGRA210_AXBAR_PART_0_ADX2_RX1_0 0x164 ++#define TEGRA210_AXBAR_PART_0_AFC1_RX1_0 0xd0 ++#define TEGRA210_AXBAR_PART_0_AFC6_RX1_0 0xe4 ++#define TEGRA210_AXBAR_PART_0_AMX1_RX1_0 0x140 ++#define TEGRA210_AXBAR_PART_0_I2S1_RX1_0 0x40 ++#define TEGRA210_AXBAR_PART_0_I2S5_RX1_0 0x50 ++#define TEGRA210_AXBAR_PART_0_MIXER1_RX10_0 0xa4 ++#define TEGRA210_AXBAR_PART_0_MIXER1_RX1_0 0x80 ++#define TEGRA210_AXBAR_PART_0_MVC1_RX1_0 0x120 ++#define TEGRA210_AXBAR_PART_0_MVC2_RX1_0 0x124 ++#define TEGRA210_AXBAR_PART_0_OPE1_RX1_0 0x100 ++#define TEGRA210_AXBAR_PART_0_OPE2_RX1_0 0x104 ++#define TEGRA210_AXBAR_PART_0_SFC1_RX1_0 0x60 ++#define TEGRA210_AXBAR_PART_0_SFC4_RX1_0 0x6c ++#define TEGRA210_AXBAR_PART_0_SPDIF1_RX1_0 0xc0 ++#define TEGRA210_AXBAR_PART_0_SPDIF1_RX2_0 0xc4 ++#define TEGRA210_AXBAR_PART_0_SPKPROT1_RX1_0 0x110 ++ + #define MUX_REG(id) (TEGRA210_XBAR_RX_STRIDE * (id)) + + #define MUX_VALUE(npart, nbit) (1 + (nbit) + (npart) * 32) +-- +2.51.0 + diff --git a/queue-6.18/audit-move-the-compat_xxx_class-extern-declarations-.patch b/queue-6.18/audit-move-the-compat_xxx_class-extern-declarations-.patch new file mode 100644 index 0000000000..37efd4494c --- /dev/null +++ b/queue-6.18/audit-move-the-compat_xxx_class-extern-declarations-.patch @@ -0,0 +1,77 @@ +From 2f5be7c68762c4829da9d8aeab2fbe27abdcdb6a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 13:39:38 +0000 +Subject: audit: move the compat_xxx_class[] extern declarations to + audit_arch.h + +From: Ben Dooks + +[ Upstream commit 76489955c6d4a065ca69dc88faf7a50a59b66f35 ] + +The comapt_xxx_class symbols aren't declared in anything that +lib/comapt_audit.c is including (arm64 build) which is causing +the following sparse warnings: + +lib/compat_audit.c:7:10: warning: symbol 'compat_dir_class' + was not declared. Should it be static? +lib/compat_audit.c:12:10: warning: symbol 'compat_read_class' + was not declared. Should it be static? +lib/compat_audit.c:17:10: warning: symbol 'compat_write_class' + was not declared. Should it be static? +lib/compat_audit.c:22:10: warning: symbol 'compat_chattr_class' + was not declared. Should it be static? +lib/compat_audit.c:27:10: warning: symbol 'compat_signal_class' + was not declared. Should it be static? + +Trying to fix this by chaning compat_audit.c to inclde +does not work on arm64 due to compile errors with the extra includes +that changing this header makes. The simpler thing would be just to +move the definitons of these symbols out of into + which is included. + +Fixes: 4b58841149dca ("audit: Add generic compat syscall support") +Signed-off-by: Ben Dooks +[PM: rewrite subject line, fixed line length in description] +Signed-off-by: Paul Moore +Signed-off-by: Sasha Levin +--- + include/linux/audit.h | 6 ------ + include/linux/audit_arch.h | 7 +++++++ + 2 files changed, 7 insertions(+), 6 deletions(-) + +diff --git a/include/linux/audit.h b/include/linux/audit.h +index 536f8ee8da818..b8d8029c6c480 100644 +--- a/include/linux/audit.h ++++ b/include/linux/audit.h +@@ -128,12 +128,6 @@ enum audit_nfcfgop { + extern int __init audit_register_class(int class, unsigned *list); + extern int audit_classify_syscall(int abi, unsigned syscall); + extern int audit_classify_arch(int arch); +-/* only for compat system calls */ +-extern unsigned compat_write_class[]; +-extern unsigned compat_read_class[]; +-extern unsigned compat_dir_class[]; +-extern unsigned compat_chattr_class[]; +-extern unsigned compat_signal_class[]; + + /* audit_names->type values */ + #define AUDIT_TYPE_UNKNOWN 0 /* we don't know yet */ +diff --git a/include/linux/audit_arch.h b/include/linux/audit_arch.h +index 0e34d673ef171..2b8153791e6a5 100644 +--- a/include/linux/audit_arch.h ++++ b/include/linux/audit_arch.h +@@ -23,4 +23,11 @@ enum auditsc_class_t { + + extern int audit_classify_compat_syscall(int abi, unsigned syscall); + ++/* only for compat system calls */ ++extern unsigned compat_write_class[]; ++extern unsigned compat_read_class[]; ++extern unsigned compat_dir_class[]; ++extern unsigned compat_chattr_class[]; ++extern unsigned compat_signal_class[]; ++ + #endif +-- +2.51.0 + diff --git a/queue-6.18/auxdisplay-arm-charlcd-fix-release_mem_region-size.patch b/queue-6.18/auxdisplay-arm-charlcd-fix-release_mem_region-size.patch new file mode 100644 index 0000000000..c7407fc6f7 --- /dev/null +++ b/queue-6.18/auxdisplay-arm-charlcd-fix-release_mem_region-size.patch @@ -0,0 +1,39 @@ +From 8918c67c1a2a8125f14b8db93086c3f4a5c92edf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Dec 2025 18:47:13 +0100 +Subject: auxdisplay: arm-charlcd: fix release_mem_region() size + +From: Thomas Fourier + +[ Upstream commit b5c23a4d291d2ac1dfdd574a68a3a68c8da3069e ] + +It seems like, after the request_mem_region(), the corresponding +release_mem_region() must take the same size. This was done +in (now removed due to previous refactoring) charlcd_remove() +but not in the error path in charlcd_probe(). + +Fixes: ce8962455e90 ("ARM: 6214/2: driver for the character LCD found in ARM refdesigns") +Signed-off-by: Thomas Fourier +Reviewed-by: Geert Uytterhoeven +Signed-off-by: Andy Shevchenko +Signed-off-by: Sasha Levin +--- + drivers/auxdisplay/arm-charlcd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/auxdisplay/arm-charlcd.c b/drivers/auxdisplay/arm-charlcd.c +index a7eae99a48f77..4e22882f57c9c 100644 +--- a/drivers/auxdisplay/arm-charlcd.c ++++ b/drivers/auxdisplay/arm-charlcd.c +@@ -323,7 +323,7 @@ static int __init charlcd_probe(struct platform_device *pdev) + out_no_irq: + iounmap(lcd->virtbase); + out_no_memregion: +- release_mem_region(lcd->phybase, SZ_4K); ++ release_mem_region(lcd->phybase, lcd->physize); + out_no_resource: + kfree(lcd); + return ret; +-- +2.51.0 + diff --git a/queue-6.18/backlight-qcom-wled-change-pm8950-wled-configuration.patch b/queue-6.18/backlight-qcom-wled-change-pm8950-wled-configuration.patch new file mode 100644 index 0000000000..1a518ea794 --- /dev/null +++ b/queue-6.18/backlight-qcom-wled-change-pm8950-wled-configuration.patch @@ -0,0 +1,42 @@ +From 104a0cd3c9afb3ed08f0465f10e9bb2f946ce5fa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 08:07:36 +0100 +Subject: backlight: qcom-wled: Change PM8950 WLED configurations +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Czémán + +[ Upstream commit 83333aa97441ba7ce32b91e8a007c72d316a1c67 ] + +PMI8950 WLED needs same configurations as PMI8994 WLED. + +Fixes: 10258bf4534b ("backlight: qcom-wled: Add PMI8950 compatible") +Signed-off-by: Barnabás Czémán +Reviewed-by: Konrad Dybcio +Reviewed-by: Daniel Thompson (RISCstar) +Link: https://patch.msgid.link/20260116-pmi8950-wled-v3-4-e6c93de84079@mainlining.org +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/video/backlight/qcom-wled.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c +index 5decbd39b7899..8054e4787725e 100644 +--- a/drivers/video/backlight/qcom-wled.c ++++ b/drivers/video/backlight/qcom-wled.c +@@ -1455,7 +1455,8 @@ static int wled_configure(struct wled *wled) + break; + + case 4: +- if (of_device_is_compatible(dev->of_node, "qcom,pmi8994-wled")) { ++ if (of_device_is_compatible(dev->of_node, "qcom,pmi8950-wled") || ++ of_device_is_compatible(dev->of_node, "qcom,pmi8994-wled")) { + u32_opts = pmi8994_wled_opts; + size = ARRAY_SIZE(pmi8994_wled_opts); + } else { +-- +2.51.0 + diff --git a/queue-6.18/backlight-qcom-wled-support-ovp-values-for-pmi8994.patch b/queue-6.18/backlight-qcom-wled-support-ovp-values-for-pmi8994.patch new file mode 100644 index 0000000000..20ac5c61c8 --- /dev/null +++ b/queue-6.18/backlight-qcom-wled-support-ovp-values-for-pmi8994.patch @@ -0,0 +1,94 @@ +From e9d92cac657287a89352fd09525d907ca360c359 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 08:07:34 +0100 +Subject: backlight: qcom-wled: Support ovp values for PMI8994 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Czémán + +[ Upstream commit f29f972a6e7e3f187ea4d89b98a76c1981ca4d53 ] + +WLED4 found in PMI8994 supports different ovp values. + +Fixes: 6fc632d3e3e0 ("video: backlight: qcom-wled: Add PMI8994 compatible") +Signed-off-by: Barnabás Czémán +Reviewed-by: Konrad Dybcio +Reviewed-by: Daniel Thompson (RISCstar) +Link: https://patch.msgid.link/20260116-pmi8950-wled-v3-2-e6c93de84079@mainlining.org +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/video/backlight/qcom-wled.c | 41 +++++++++++++++++++++++++++-- + 1 file changed, 39 insertions(+), 2 deletions(-) + +diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c +index a63bb42c8f8b0..5decbd39b7899 100644 +--- a/drivers/video/backlight/qcom-wled.c ++++ b/drivers/video/backlight/qcom-wled.c +@@ -1244,6 +1244,15 @@ static const struct wled_var_cfg wled4_ovp_cfg = { + .size = ARRAY_SIZE(wled4_ovp_values), + }; + ++static const u32 pmi8994_wled_ovp_values[] = { ++ 31000, 29500, 19400, 17800, ++}; ++ ++static const struct wled_var_cfg pmi8994_wled_ovp_cfg = { ++ .values = pmi8994_wled_ovp_values, ++ .size = ARRAY_SIZE(pmi8994_wled_ovp_values), ++}; ++ + static inline u32 wled5_ovp_values_fn(u32 idx) + { + /* +@@ -1357,6 +1366,29 @@ static int wled_configure(struct wled *wled) + }, + }; + ++ const struct wled_u32_opts pmi8994_wled_opts[] = { ++ { ++ .name = "qcom,current-boost-limit", ++ .val_ptr = &cfg->boost_i_limit, ++ .cfg = &wled4_boost_i_limit_cfg, ++ }, ++ { ++ .name = "qcom,current-limit-microamp", ++ .val_ptr = &cfg->string_i_limit, ++ .cfg = &wled4_string_i_limit_cfg, ++ }, ++ { ++ .name = "qcom,ovp-millivolt", ++ .val_ptr = &cfg->ovp, ++ .cfg = &pmi8994_wled_ovp_cfg, ++ }, ++ { ++ .name = "qcom,switching-freq", ++ .val_ptr = &cfg->switch_freq, ++ .cfg = &wled3_switch_freq_cfg, ++ }, ++ }; ++ + const struct wled_u32_opts wled5_opts[] = { + { + .name = "qcom,current-boost-limit", +@@ -1423,8 +1455,13 @@ static int wled_configure(struct wled *wled) + break; + + case 4: +- u32_opts = wled4_opts; +- size = ARRAY_SIZE(wled4_opts); ++ if (of_device_is_compatible(dev->of_node, "qcom,pmi8994-wled")) { ++ u32_opts = pmi8994_wled_opts; ++ size = ARRAY_SIZE(pmi8994_wled_opts); ++ } else { ++ u32_opts = wled4_opts; ++ size = ARRAY_SIZE(wled4_opts); ++ } + *cfg = wled4_config_defaults; + wled->wled_set_brightness = wled4_set_brightness; + wled->wled_sync_toggle = wled3_sync_toggle; +-- +2.51.0 + diff --git a/queue-6.18/bluetooth-btintel_pcie-use-irqf_oneshot-and-default-.patch b/queue-6.18/bluetooth-btintel_pcie-use-irqf_oneshot-and-default-.patch new file mode 100644 index 0000000000..d0574b42e9 --- /dev/null +++ b/queue-6.18/bluetooth-btintel_pcie-use-irqf_oneshot-and-default-.patch @@ -0,0 +1,61 @@ +From 6652eb132d0bc67d4776131b08b261631239e5ce Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:55:26 +0100 +Subject: Bluetooth: btintel_pcie: Use IRQF_ONESHOT and default primary handler + +From: Sebastian Andrzej Siewior + +[ Upstream commit 28abed6569c87eab9071ab56c64433c2f0d9ce51 ] + +There is no added value in btintel_pcie_msix_isr() compared to +irq_default_primary_handler(). + +Using a threaded interrupt without a dedicated primary handler mandates +the IRQF_ONESHOT flag to mask the interrupt source while the threaded +handler is active. Otherwise the interrupt can fire again before the +threaded handler had a chance to run. + +Use the default primary interrupt handler by specifying NULL and set +IRQF_ONESHOT so the interrupt source is masked until the secondary +handler is done. + +Fixes: c2b636b3f788d ("Bluetooth: btintel_pcie: Add support for PCIe transport") +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260128095540.863589-7-bigeasy@linutronix.de +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/btintel_pcie.c | 9 ++------- + 1 file changed, 2 insertions(+), 7 deletions(-) + +diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c +index f280bcc61bbfb..c68a8de3025b0 100644 +--- a/drivers/bluetooth/btintel_pcie.c ++++ b/drivers/bluetooth/btintel_pcie.c +@@ -1430,11 +1430,6 @@ static void btintel_pcie_msix_rx_handle(struct btintel_pcie_data *data) + } + } + +-static irqreturn_t btintel_pcie_msix_isr(int irq, void *data) +-{ +- return IRQ_WAKE_THREAD; +-} +- + static inline bool btintel_pcie_is_rxq_empty(struct btintel_pcie_data *data) + { + return data->ia.cr_hia[BTINTEL_PCIE_RXQ_NUM] == data->ia.cr_tia[BTINTEL_PCIE_RXQ_NUM]; +@@ -1536,9 +1531,9 @@ static int btintel_pcie_setup_irq(struct btintel_pcie_data *data) + + err = devm_request_threaded_irq(&data->pdev->dev, + msix_entry->vector, +- btintel_pcie_msix_isr, ++ NULL, + btintel_pcie_irq_msix_handler, +- IRQF_SHARED, ++ IRQF_ONESHOT | IRQF_SHARED, + KBUILD_MODNAME, + msix_entry); + if (err) { +-- +2.51.0 + diff --git a/queue-6.18/bonding-only-set-speed-duplex-to-unknown-if-getting-.patch b/queue-6.18/bonding-only-set-speed-duplex-to-unknown-if-getting-.patch new file mode 100644 index 0000000000..c5d67dc00c --- /dev/null +++ b/queue-6.18/bonding-only-set-speed-duplex-to-unknown-if-getting-.patch @@ -0,0 +1,74 @@ +From 3a33fb9387db9e1f68f5811d8ba23af683f948e2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 15:11:52 +0100 +Subject: bonding: only set speed/duplex to unknown, if getting speed failed + +From: Thomas Bogendoerfer + +[ Upstream commit 48dec8d88af96039a4a17b8c2f148f2a4066e195 ] + +bond_update_speed_duplex() first set speed/duplex to unknown and +then asks slave driver for current speed/duplex. Since getting +speed/duplex might take longer there is a race, where this false state +is visible by /proc/net/bonding. With commit 691b2bf14946 ("bonding: + update port speed when getting bond speed") this race gets more visible, +if user space is calling ethtool on a regular base. + +Fix this by only setting speed/duplex to unknown, if link speed is +really unknown/unusable. + +Fixes: 98f41f694f46 ("bonding:update speed/duplex for NETDEV_CHANGE") +Signed-off-by: Thomas Bogendoerfer +Acked-by: Jay Vosburgh +Reviewed-by: Nikolay Aleksandrov +Reviewed-by: Hangbin Liu +Link: https://patch.msgid.link/20260203141153.51581-1-tbogendoerfer@suse.de +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/bonding/bond_main.c | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c +index 51733fb29bd77..166dff47a029f 100644 +--- a/drivers/net/bonding/bond_main.c ++++ b/drivers/net/bonding/bond_main.c +@@ -791,26 +791,29 @@ static int bond_update_speed_duplex(struct slave *slave) + struct ethtool_link_ksettings ecmd; + int res; + +- slave->speed = SPEED_UNKNOWN; +- slave->duplex = DUPLEX_UNKNOWN; +- + res = __ethtool_get_link_ksettings(slave_dev, &ecmd); + if (res < 0) +- return 1; ++ goto speed_duplex_unknown; + if (ecmd.base.speed == 0 || ecmd.base.speed == ((__u32)-1)) +- return 1; ++ goto speed_duplex_unknown; + switch (ecmd.base.duplex) { + case DUPLEX_FULL: + case DUPLEX_HALF: + break; + default: +- return 1; ++ goto speed_duplex_unknown; + } + + slave->speed = ecmd.base.speed; + slave->duplex = ecmd.base.duplex; + + return 0; ++ ++speed_duplex_unknown: ++ slave->speed = SPEED_UNKNOWN; ++ slave->duplex = DUPLEX_UNKNOWN; ++ ++ return 1; + } + + const char *bond_slave_link_status(s8 link) +-- +2.51.0 + diff --git a/queue-6.18/bpf-fix-bpf_xdp_store_bytes-proto-for-read-only-arg.patch b/queue-6.18/bpf-fix-bpf_xdp_store_bytes-proto-for-read-only-arg.patch new file mode 100644 index 0000000000..f562e7f430 --- /dev/null +++ b/queue-6.18/bpf-fix-bpf_xdp_store_bytes-proto-for-read-only-arg.patch @@ -0,0 +1,60 @@ +From 5703d952c9d51fd5fde77a20b4345949dae6907b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Jan 2026 17:08:37 +0100 +Subject: bpf: Fix bpf_xdp_store_bytes proto for read-only arg + +From: Paul Chaignon + +[ Upstream commit 6557f1565d779851c4db9c488c49c05a47a6e72f ] + +While making some maps in Cilium read-only from the BPF side, we noticed +that the bpf_xdp_store_bytes proto is incorrect. In particular, the +verifier was throwing the following error: + + ; ret = ctx_store_bytes(ctx, l3_off + offsetof(struct iphdr, saddr), + &nat->address, 4, 0); + 635: (79) r1 = *(u64 *)(r10 -144) ; R1=ctx() R10=fp0 fp-144=ctx() + 636: (b4) w2 = 26 ; R2=26 + 637: (b4) w4 = 4 ; R4=4 + 638: (b4) w5 = 0 ; R5=0 + 639: (85) call bpf_xdp_store_bytes#190 + write into map forbidden, value_size=6 off=0 size=4 + +nat comes from a BPF_F_RDONLY_PROG map, so R3 is a PTR_TO_MAP_VALUE. +The verifier checks the helper's memory access to R3 in +check_mem_size_reg, as it reaches ARG_CONST_SIZE argument. The third +argument has expected type ARG_PTR_TO_UNINIT_MEM, which includes the +MEM_WRITE flag. The verifier thus checks for a BPF_WRITE access on R3. +Given R3 points to a read-only map, the check fails. + +Conversely, ARG_PTR_TO_UNINIT_MEM can also lead to the helper reading +from uninitialized memory. + +This patch simply fixes the expected argument type to match that of +bpf_skb_store_bytes. + +Fixes: 3f364222d032 ("net: xdp: introduce bpf_xdp_pointer utility routine") +Signed-off-by: Paul Chaignon +Link: https://lore.kernel.org/r/9fa3c9f72d806e82541071c4df88b8cba28ad6a9.1769875479.git.paul.chaignon@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + net/core/filter.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/core/filter.c b/net/core/filter.c +index b9a51f322b655..d93f7dea828e5 100644 +--- a/net/core/filter.c ++++ b/net/core/filter.c +@@ -4133,7 +4133,7 @@ static const struct bpf_func_proto bpf_xdp_store_bytes_proto = { + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_CTX, + .arg2_type = ARG_ANYTHING, +- .arg3_type = ARG_PTR_TO_UNINIT_MEM, ++ .arg3_type = ARG_PTR_TO_MEM | MEM_RDONLY, + .arg4_type = ARG_CONST_SIZE, + }; + +-- +2.51.0 + diff --git a/queue-6.18/bpf-fix-memory-access-flags-in-helper-prototypes.patch b/queue-6.18/bpf-fix-memory-access-flags-in-helper-prototypes.patch new file mode 100644 index 0000000000..8b5c442546 --- /dev/null +++ b/queue-6.18/bpf-fix-memory-access-flags-in-helper-prototypes.patch @@ -0,0 +1,179 @@ +From 3dd2533882c3eb11e34f37e7c84b5ef82faadadd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 16:28:46 +0800 +Subject: bpf: Fix memory access flags in helper prototypes + +From: Zesen Liu + +[ Upstream commit 802eef5afb1865bc5536a5302c068ba2215a1f72 ] + +After commit 37cce22dbd51 ("bpf: verifier: Refactor helper access type tracking"), +the verifier started relying on the access type flags in helper +function prototypes to perform memory access optimizations. + +Currently, several helper functions utilizing ARG_PTR_TO_MEM lack the +corresponding MEM_RDONLY or MEM_WRITE flags. This omission causes the +verifier to incorrectly assume that the buffer contents are unchanged +across the helper call. Consequently, the verifier may optimize away +subsequent reads based on this wrong assumption, leading to correctness +issues. + +For bpf_get_stack_proto_raw_tp, the original MEM_RDONLY was incorrect +since the helper writes to the buffer. Change it to ARG_PTR_TO_UNINIT_MEM +which correctly indicates write access to potentially uninitialized memory. + +Similar issues were recently addressed for specific helpers in commit +ac44dcc788b9 ("bpf: Fix verifier assumptions of bpf_d_path's output buffer") +and commit 2eb7648558a7 ("bpf: Specify access type of bpf_sysctl_get_name args"). + +Fix these prototypes by adding the correct memory access flags. + +Fixes: 37cce22dbd51 ("bpf: verifier: Refactor helper access type tracking") +Co-developed-by: Shuran Liu +Signed-off-by: Shuran Liu +Co-developed-by: Peili Gao +Signed-off-by: Peili Gao +Co-developed-by: Haoran Ni +Signed-off-by: Haoran Ni +Signed-off-by: Zesen Liu +Acked-by: Eduard Zingerman +Link: https://lore.kernel.org/r/20260120-helper_proto-v3-1-27b0180b4e77@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/helpers.c | 2 +- + kernel/bpf/syscall.c | 2 +- + kernel/trace/bpf_trace.c | 6 +++--- + net/core/filter.c | 20 ++++++++++---------- + 4 files changed, 15 insertions(+), 15 deletions(-) + +diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c +index 81ef159ef89bd..68da6dcfb4bb7 100644 +--- a/kernel/bpf/helpers.c ++++ b/kernel/bpf/helpers.c +@@ -1080,7 +1080,7 @@ const struct bpf_func_proto bpf_snprintf_proto = { + .func = bpf_snprintf, + .gpl_only = true, + .ret_type = RET_INTEGER, +- .arg1_type = ARG_PTR_TO_MEM_OR_NULL, ++ .arg1_type = ARG_PTR_TO_MEM_OR_NULL | MEM_WRITE, + .arg2_type = ARG_CONST_SIZE_OR_ZERO, + .arg3_type = ARG_PTR_TO_CONST_STR, + .arg4_type = ARG_PTR_TO_MEM | PTR_MAYBE_NULL | MEM_RDONLY, +diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c +index df219e7259099..e9cf69594824c 100644 +--- a/kernel/bpf/syscall.c ++++ b/kernel/bpf/syscall.c +@@ -6396,7 +6396,7 @@ static const struct bpf_func_proto bpf_kallsyms_lookup_name_proto = { + .func = bpf_kallsyms_lookup_name, + .gpl_only = false, + .ret_type = RET_INTEGER, +- .arg1_type = ARG_PTR_TO_MEM, ++ .arg1_type = ARG_PTR_TO_MEM | MEM_RDONLY, + .arg2_type = ARG_CONST_SIZE_OR_ZERO, + .arg3_type = ARG_ANYTHING, + .arg4_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_WRITE | MEM_ALIGNED, +diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c +index 49e0bdaa7a1bf..e7f1fe44352af 100644 +--- a/kernel/trace/bpf_trace.c ++++ b/kernel/trace/bpf_trace.c +@@ -1022,7 +1022,7 @@ const struct bpf_func_proto bpf_snprintf_btf_proto = { + .func = bpf_snprintf_btf, + .gpl_only = false, + .ret_type = RET_INTEGER, +- .arg1_type = ARG_PTR_TO_MEM, ++ .arg1_type = ARG_PTR_TO_MEM | MEM_WRITE, + .arg2_type = ARG_CONST_SIZE, + .arg3_type = ARG_PTR_TO_MEM | MEM_RDONLY, + .arg4_type = ARG_CONST_SIZE, +@@ -1526,7 +1526,7 @@ static const struct bpf_func_proto bpf_read_branch_records_proto = { + .gpl_only = true, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_CTX, +- .arg2_type = ARG_PTR_TO_MEM_OR_NULL, ++ .arg2_type = ARG_PTR_TO_MEM_OR_NULL | MEM_WRITE, + .arg3_type = ARG_CONST_SIZE_OR_ZERO, + .arg4_type = ARG_ANYTHING, + }; +@@ -1661,7 +1661,7 @@ static const struct bpf_func_proto bpf_get_stack_proto_raw_tp = { + .gpl_only = true, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_CTX, +- .arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY, ++ .arg2_type = ARG_PTR_TO_UNINIT_MEM, + .arg3_type = ARG_CONST_SIZE_OR_ZERO, + .arg4_type = ARG_ANYTHING, + }; +diff --git a/net/core/filter.c b/net/core/filter.c +index 88b265f6ccf89..b9a51f322b655 100644 +--- a/net/core/filter.c ++++ b/net/core/filter.c +@@ -6325,7 +6325,7 @@ static const struct bpf_func_proto bpf_xdp_fib_lookup_proto = { + .gpl_only = true, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_CTX, +- .arg2_type = ARG_PTR_TO_MEM, ++ .arg2_type = ARG_PTR_TO_MEM | MEM_WRITE, + .arg3_type = ARG_CONST_SIZE, + .arg4_type = ARG_ANYTHING, + }; +@@ -6380,7 +6380,7 @@ static const struct bpf_func_proto bpf_skb_fib_lookup_proto = { + .gpl_only = true, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_CTX, +- .arg2_type = ARG_PTR_TO_MEM, ++ .arg2_type = ARG_PTR_TO_MEM | MEM_WRITE, + .arg3_type = ARG_CONST_SIZE, + .arg4_type = ARG_ANYTHING, + }; +@@ -7934,9 +7934,9 @@ static const struct bpf_func_proto bpf_tcp_raw_gen_syncookie_ipv4_proto = { + .gpl_only = true, /* __cookie_v4_init_sequence() is GPL */ + .pkt_access = true, + .ret_type = RET_INTEGER, +- .arg1_type = ARG_PTR_TO_FIXED_SIZE_MEM, ++ .arg1_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_RDONLY, + .arg1_size = sizeof(struct iphdr), +- .arg2_type = ARG_PTR_TO_MEM, ++ .arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY, + .arg3_type = ARG_CONST_SIZE_OR_ZERO, + }; + +@@ -7966,9 +7966,9 @@ static const struct bpf_func_proto bpf_tcp_raw_gen_syncookie_ipv6_proto = { + .gpl_only = true, /* __cookie_v6_init_sequence() is GPL */ + .pkt_access = true, + .ret_type = RET_INTEGER, +- .arg1_type = ARG_PTR_TO_FIXED_SIZE_MEM, ++ .arg1_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_RDONLY, + .arg1_size = sizeof(struct ipv6hdr), +- .arg2_type = ARG_PTR_TO_MEM, ++ .arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY, + .arg3_type = ARG_CONST_SIZE_OR_ZERO, + }; + +@@ -7986,9 +7986,9 @@ static const struct bpf_func_proto bpf_tcp_raw_check_syncookie_ipv4_proto = { + .gpl_only = true, /* __cookie_v4_check is GPL */ + .pkt_access = true, + .ret_type = RET_INTEGER, +- .arg1_type = ARG_PTR_TO_FIXED_SIZE_MEM, ++ .arg1_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_RDONLY, + .arg1_size = sizeof(struct iphdr), +- .arg2_type = ARG_PTR_TO_FIXED_SIZE_MEM, ++ .arg2_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_RDONLY, + .arg2_size = sizeof(struct tcphdr), + }; + +@@ -8010,9 +8010,9 @@ static const struct bpf_func_proto bpf_tcp_raw_check_syncookie_ipv6_proto = { + .gpl_only = true, /* __cookie_v6_check is GPL */ + .pkt_access = true, + .ret_type = RET_INTEGER, +- .arg1_type = ARG_PTR_TO_FIXED_SIZE_MEM, ++ .arg1_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_RDONLY, + .arg1_size = sizeof(struct ipv6hdr), +- .arg2_type = ARG_PTR_TO_FIXED_SIZE_MEM, ++ .arg2_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_RDONLY, + .arg2_size = sizeof(struct tcphdr), + }; + #endif /* CONFIG_SYN_COOKIES */ +-- +2.51.0 + diff --git a/queue-6.18/bpf-fix-tcx-netkit-detach-permissions-when-prog-fd-i.patch b/queue-6.18/bpf-fix-tcx-netkit-detach-permissions-when-prog-fd-i.patch new file mode 100644 index 0000000000..f86a2adae5 --- /dev/null +++ b/queue-6.18/bpf-fix-tcx-netkit-detach-permissions-when-prog-fd-i.patch @@ -0,0 +1,88 @@ +From 4e2184ef19d4078ca15685b36ac3895bc84959e0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 17:02:00 +0100 +Subject: bpf: Fix tcx/netkit detach permissions when prog fd isn't given + +From: Guillaume Gonnet + +[ Upstream commit ae23bc81ddf7c17b663c4ed1b21e35527b0a7131 ] + +This commit fixes a security issue where BPF_PROG_DETACH on tcx or +netkit devices could be executed by any user when no program fd was +provided, bypassing permission checks. The fix adds a capability +check for CAP_NET_ADMIN or CAP_SYS_ADMIN in this case. + +Fixes: e420bed02507 ("bpf: Add fd-based tcx multi-prog infra with link support") +Signed-off-by: Guillaume Gonnet +Link: https://lore.kernel.org/r/20260127160200.10395-1-ggonnet.linux@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + include/linux/bpf.h | 5 +++++ + include/linux/bpf_mprog.h | 10 ++++++++++ + kernel/bpf/syscall.c | 7 ++----- + 3 files changed, 17 insertions(+), 5 deletions(-) + +diff --git a/include/linux/bpf.h b/include/linux/bpf.h +index d808253f2e945..e2dd3a6d495af 100644 +--- a/include/linux/bpf.h ++++ b/include/linux/bpf.h +@@ -3200,6 +3200,11 @@ static inline void bpf_prog_report_arena_violation(bool write, unsigned long add + } + #endif /* CONFIG_BPF_SYSCALL */ + ++static inline bool bpf_net_capable(void) ++{ ++ return capable(CAP_NET_ADMIN) || capable(CAP_SYS_ADMIN); ++} ++ + static __always_inline int + bpf_probe_read_kernel_common(void *dst, u32 size, const void *unsafe_ptr) + { +diff --git a/include/linux/bpf_mprog.h b/include/linux/bpf_mprog.h +index 929225f7b0959..0b9f4caeeb0a3 100644 +--- a/include/linux/bpf_mprog.h ++++ b/include/linux/bpf_mprog.h +@@ -340,4 +340,14 @@ static inline bool bpf_mprog_supported(enum bpf_prog_type type) + return false; + } + } ++ ++static inline bool bpf_mprog_detach_empty(enum bpf_prog_type type) ++{ ++ switch (type) { ++ case BPF_PROG_TYPE_SCHED_CLS: ++ return bpf_net_capable(); ++ default: ++ return false; ++ } ++} + #endif /* __BPF_MPROG_H */ +diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c +index e9cf69594824c..f39367765f0c4 100644 +--- a/kernel/bpf/syscall.c ++++ b/kernel/bpf/syscall.c +@@ -1365,11 +1365,6 @@ static int map_check_btf(struct bpf_map *map, struct bpf_token *token, + return ret; + } + +-static bool bpf_net_capable(void) +-{ +- return capable(CAP_NET_ADMIN) || capable(CAP_SYS_ADMIN); +-} +- + #define BPF_MAP_CREATE_LAST_FIELD excl_prog_hash_size + /* called via syscall */ + static int map_create(union bpf_attr *attr, bpfptr_t uattr) +@@ -4554,6 +4549,8 @@ static int bpf_prog_detach(const union bpf_attr *attr) + prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype); + if (IS_ERR(prog)) + return PTR_ERR(prog); ++ } else if (!bpf_mprog_detach_empty(ptype)) { ++ return -EPERM; + } + } else if (is_cgroup_prog_type(ptype, 0, false)) { + if (attr->attach_flags || attr->relative_fd) +-- +2.51.0 + diff --git a/queue-6.18/bpf-fix-verifier_bug_if-to-account-for-bpf_call.patch b/queue-6.18/bpf-fix-verifier_bug_if-to-account-for-bpf_call.patch new file mode 100644 index 0000000000..a5e2938dcb --- /dev/null +++ b/queue-6.18/bpf-fix-verifier_bug_if-to-account-for-bpf_call.patch @@ -0,0 +1,108 @@ +From 5d73bc81fd44c9e0982a33022a7b7c5be39609a7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 12:59:11 +0100 +Subject: bpf: Fix verifier_bug_if to account for BPF_CALL +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Luis Gerhorst + +[ Upstream commit cd3b6a3d49f8061d0c4c7e4226783051fe592ae7 ] + +The BPF verifier assumes `insn_aux->nospec_result` is only set for +direct memory writes (e.g., `*(u32*)(r1+off) = r2`). However, the +assertion fails to account for helper calls (e.g., +`bpf_skb_load_bytes_relative`) that perform writes to stack memory. Make +the check more precise to resolve this. + +The problem is that `BPF_CALL` instructions have `BPF_CLASS(insn->code) +== BPF_JMP`, which triggers the warning check: + +- Helpers like `bpf_skb_load_bytes_relative` write to stack memory +- `check_helper_call()` loops through `meta.access_size`, calling + `check_mem_access(..., BPF_WRITE)` +- `check_stack_write()` sets `insn_aux->nospec_result = 1` +- Since `BPF_CALL` is encoded as `BPF_JMP | BPF_CALL`, the warning fires + +Execution flow: + +``` +1. Drop capabilities → Enable Spectre mitigation +2. Load BPF program + └─> do_check() + ├─> check_cond_jmp_op() → Marks dead branch as speculative + │ └─> push_stack(..., speculative=true) + ├─> pop_stack() → state->speculative = 1 + ├─> check_helper_call() → Processes helper in dead branch + │ └─> check_mem_access(..., BPF_WRITE) + │ └─> insn_aux->nospec_result = 1 + └─> Checks: state->speculative && insn_aux->nospec_result + └─> BPF_CLASS(insn->code) == BPF_JMP → WARNING +``` + +To fix the assert, it would be nice to be able to reuse +bpf_insn_successors() here, but bpf_insn_successors()->cnt is not +exactly what we want as it may also be 1 for BPF_JA. Instead, we could +check opcode_info.can_jump, but then we would have to share the table +between the functions. This would mean moving the table out of the +function and adding bpf_opcode_info(). As the verifier_bug_if() only +runs for insns with nospec_result set, the impact on verification time +would likely still be negligible. However, I assume sharing +bpf_opcode_info() between liveness.c and verifier.c will not be worth +it. It seems as only adjust_jmp_off() could also be simplified using it, +and there imm/off is touched. Thus it is maybe better to rely on exact +opcode/class matching there. + +Therefore, to avoid this sharing only for a verifier_bug_if(), just +check the opcode. This should now cover all opcodes for which can_jump +in bpf_insn_successors() is true. + +Parts of the description and example are taken from the bug report. + +Fixes: dadb59104c64 ("bpf: Fix aux usage after do_check_insn()") +Signed-off-by: Luis Gerhorst +Reported-by: Yinhao Hu +Reported-by: Kaiyan Mei +Reported-by: Dongliang Mu +Closes: https://lore.kernel.org/bpf/7678017d-b760-4053-a2d8-a6879b0dbeeb@hust.edu.cn/ +Link: https://lore.kernel.org/r/20260127115912.3026761-2-luis.gerhorst@fau.de +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/verifier.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index 14546d1bdb52c..4338d233beecf 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -20149,17 +20149,19 @@ static int do_check(struct bpf_verifier_env *env) + * may skip a nospec patched-in after the jump. This can + * currently never happen because nospec_result is only + * used for the write-ops +- * `*(size*)(dst_reg+off)=src_reg|imm32` which must +- * never skip the following insn. Still, add a warning +- * to document this in case nospec_result is used +- * elsewhere in the future. ++ * `*(size*)(dst_reg+off)=src_reg|imm32` and helper ++ * calls. These must never skip the following insn ++ * (i.e., bpf_insn_successors()'s opcode_info.can_jump ++ * is false). Still, add a warning to document this in ++ * case nospec_result is used elsewhere in the future. + * + * All non-branch instructions have a single + * fall-through edge. For these, nospec_result should + * already work. + */ +- if (verifier_bug_if(BPF_CLASS(insn->code) == BPF_JMP || +- BPF_CLASS(insn->code) == BPF_JMP32, env, ++ if (verifier_bug_if((BPF_CLASS(insn->code) == BPF_JMP || ++ BPF_CLASS(insn->code) == BPF_JMP32) && ++ BPF_OP(insn->code) != BPF_CALL, env, + "speculation barrier after jump instruction may not have the desired effect")) + return -EFAULT; + process_bpf_exit: +-- +2.51.0 + diff --git a/queue-6.18/bpf-limit-bpf-program-signature-size.patch b/queue-6.18/bpf-limit-bpf-program-signature-size.patch new file mode 100644 index 0000000000..e2b708a51a --- /dev/null +++ b/queue-6.18/bpf-limit-bpf-program-signature-size.patch @@ -0,0 +1,48 @@ +From 267e54468a68225a99ba740bf097f8102ed5804f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 07:38:07 +0100 +Subject: bpf: Limit bpf program signature size + +From: KP Singh + +[ Upstream commit ea1535e28bb3773fc0b3cbd1f3842b808016990c ] + +Practical BPF signatures are significantly smaller than +KMALLOC_MAX_CACHE_SIZE + +Allowing larger sizes opens the door for abuse by passing excessive +size values and forcing the kernel into expensive allocation paths (via +kmalloc_large or vmalloc). + +Fixes: 349271568303 ("bpf: Implement signature verification for BPF programs") +Reported-by: Chris Mason +Signed-off-by: KP Singh +Acked-by: Daniel Borkmann +Link: https://lore.kernel.org/r/20260205063807.690823-1-kpsingh@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/syscall.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c +index f39367765f0c4..2649e0472dfe0 100644 +--- a/kernel/bpf/syscall.c ++++ b/kernel/bpf/syscall.c +@@ -2825,6 +2825,13 @@ static int bpf_prog_verify_signature(struct bpf_prog *prog, union bpf_attr *attr + void *sig; + int err = 0; + ++ /* ++ * Don't attempt to use kmalloc_large or vmalloc for signatures. ++ * Practical signature for BPF program should be below this limit. ++ */ ++ if (attr->signature_size > KMALLOC_MAX_CACHE_SIZE) ++ return -EINVAL; ++ + if (system_keyring_id_check(attr->keyring_id) == 0) + key = bpf_lookup_system_key(attr->keyring_id); + else +-- +2.51.0 + diff --git a/queue-6.18/bpf-preserve-id-of-register-in-sync_linked_regs.patch b/queue-6.18/bpf-preserve-id-of-register-in-sync_linked_regs.patch new file mode 100644 index 0000000000..0e6101868e --- /dev/null +++ b/queue-6.18/bpf-preserve-id-of-register-in-sync_linked_regs.patch @@ -0,0 +1,95 @@ +From 0a71c6e50c433c8d9ec34551020a51e4a282c85b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 07:11:40 -0800 +Subject: bpf: Preserve id of register in sync_linked_regs() + +From: Puranjay Mohan + +[ Upstream commit af9e89d8dd39530c8bd14c33ddf6b502df1071b6 ] + +sync_linked_regs() copies the id of known_reg to reg when propagating +bounds of known_reg to reg using the off of known_reg, but when +known_reg was linked to reg like: + +known_reg = reg ; both known_reg and reg get same id +known_reg += 4 ; known_reg gets off = 4, and its id gets BPF_ADD_CONST + +now when a call to sync_linked_regs() happens, let's say with the following: + +if known_reg >= 10 goto pc+2 + +known_reg's new bounds are propagated to reg but now reg gets +BPF_ADD_CONST from the copy. + +This means if another link to reg is created like: + +another_reg = reg ; another_reg should get the id of reg but + assign_scalar_id_before_mov() sees + BPF_ADD_CONST on reg and assigns a new id to it. + +As reg has a new id now, known_reg's link to reg is broken. If we find +new bounds for known_reg, they will not be propagated to reg. + +This can be seen in the selftest added in the next commit: + +0: (85) call bpf_get_prandom_u32#7 ; R0=scalar() +1: (57) r0 &= 255 ; R0=scalar(smin=smin32=0,smax=umax=smax32=umax32=255,var_off=(0x0; 0xff)) +2: (bf) r1 = r0 ; R0=scalar(id=1,smin=smin32=0,smax=umax=smax32=umax32=255,var_off=(0x0; 0xff)) R1=scalar(id=1,smin=smin32=0,smax=umax=smax32=umax32=255,var_off=(0x0; 0xff)) +3: (07) r1 += 4 ; R1=scalar(id=1+4,smin=umin=smin32=umin32=4,smax=umax=smax32=umax32=259,var_off=(0x0; 0x1ff)) +4: (a5) if r1 < 0xa goto pc+4 ; R1=scalar(id=1+4,smin=umin=smin32=umin32=10,smax=umax=smax32=umax32=259,var_off=(0x0; 0x1ff)) +5: (bf) r2 = r0 ; R0=scalar(id=2,smin=umin=smin32=umin32=6,smax=umax=smax32=umax32=255) R2=scalar(id=2,smin=umin=smin32=umin32=6,smax=umax=smax32=umax32=255) +6: (a5) if r1 < 0xe goto pc+2 ; R1=scalar(id=1+4,smin=umin=smin32=umin32=14,smax=umax=smax32=umax32=259,var_off=(0x0; 0x1ff)) +7: (35) if r0 >= 0xa goto pc+1 ; R0=scalar(id=2,smin=umin=smin32=umin32=6,smax=umax=smax32=umax32=9,var_off=(0x0; 0xf)) +8: (37) r0 /= 0 +div by zero + +When 4 is verified, r1's bounds are propagated to r0 but r0 also gets +BPF_ADD_CONST (bug). +When 5 is verified, r0 gets a new id (2) and its link with r1 is broken. + +After 6 we know r1 has bounds [14, 259] and therefore r0 should have +bounds [10, 255], therefore the branch at 7 is always taken. But because +r0's id was changed to 2, r1's new bounds are not propagated to r0. +The verifier still thinks r0 has bounds [6, 255] before 7 and execution +can reach div by zero. + +Fix this by preserving id in sync_linked_regs() like off and subreg_def. + +Fixes: 98d7ca374ba4 ("bpf: Track delta between "linked" registers.") +Signed-off-by: Puranjay Mohan +Acked-by: Eduard Zingerman +Link: https://lore.kernel.org/r/20260115151143.1344724-2-puranjay@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/verifier.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index 89560e455ce7b..14546d1bdb52c 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -16715,6 +16715,7 @@ static void sync_linked_regs(struct bpf_verifier_state *vstate, struct bpf_reg_s + } else { + s32 saved_subreg_def = reg->subreg_def; + s32 saved_off = reg->off; ++ u32 saved_id = reg->id; + + fake_reg.type = SCALAR_VALUE; + __mark_reg_known(&fake_reg, (s32)reg->off - (s32)known_reg->off); +@@ -16722,10 +16723,11 @@ static void sync_linked_regs(struct bpf_verifier_state *vstate, struct bpf_reg_s + /* reg = known_reg; reg += delta */ + copy_register_state(reg, known_reg); + /* +- * Must preserve off, id and add_const flag, ++ * Must preserve off, id and subreg_def flag, + * otherwise another sync_linked_regs() will be incorrect. + */ + reg->off = saved_off; ++ reg->id = saved_id; + reg->subreg_def = saved_subreg_def; + + scalar32_min_max_add(reg, &fake_reg); +-- +2.51.0 + diff --git a/queue-6.18/bpf-require-frozen-map-for-calculating-map-hash.patch b/queue-6.18/bpf-require-frozen-map-for-calculating-map-hash.patch new file mode 100644 index 0000000000..5e64888c8a --- /dev/null +++ b/queue-6.18/bpf-require-frozen-map-for-calculating-map-hash.patch @@ -0,0 +1,51 @@ +From 5689a0b03138eaa6f1efe31c4d0b30c5daa136d6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 08:07:55 +0100 +Subject: bpf: Require frozen map for calculating map hash + +From: KP Singh + +[ Upstream commit a2c86aa621c22f2a7e26c654f936d65cfff0aa91 ] + +Currently, bpf_map_get_info_by_fd calculates and caches the hash of the +map regardless of the map's frozen state. + +This leads to a TOCTOU bug where userspace can call +BPF_OBJ_GET_INFO_BY_FD to cache the hash and then modify the map +contents before freezing. + +Therefore, a trusted loader can be tricked into verifying the stale hash +while loading the modified contents. + +Fix this by returning -EPERM if the map is not frozen when the hash is +requested. This ensures the hash is only generated for the final, +immutable state of the map. + +Fixes: ea2e6467ac36 ("bpf: Return hashes of maps in BPF_OBJ_GET_INFO_BY_FD") +Reported-by: Toshi Piazza +Signed-off-by: KP Singh +Acked-by: Daniel Borkmann +Link: https://lore.kernel.org/r/20260205070755.695776-1-kpsingh@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/syscall.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c +index 2649e0472dfe0..586ece78f783a 100644 +--- a/kernel/bpf/syscall.c ++++ b/kernel/bpf/syscall.c +@@ -5303,6 +5303,9 @@ static int bpf_map_get_info_by_fd(struct file *file, + if (info.hash_size != SHA256_DIGEST_SIZE) + return -EINVAL; + ++ if (!READ_ONCE(map->frozen)) ++ return -EPERM; ++ + err = map->ops->map_get_hash(map, SHA256_DIGEST_SIZE, map->sha); + if (err != 0) + return err; +-- +2.51.0 + diff --git a/queue-6.18/bpf-sockmap-fix-fionread-for-sockmap.patch b/queue-6.18/bpf-sockmap-fix-fionread-for-sockmap.patch new file mode 100644 index 0000000000..890d7c6294 --- /dev/null +++ b/queue-6.18/bpf-sockmap-fix-fionread-for-sockmap.patch @@ -0,0 +1,293 @@ +From f97f59ce2304efbc118b1af27ca7bebc818f95d3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 24 Jan 2026 19:32:44 +0800 +Subject: bpf, sockmap: Fix FIONREAD for sockmap + +From: Jiayuan Chen + +[ Upstream commit 929e30f9312514902133c45e51c79088421ab084 ] + +A socket using sockmap has its own independent receive queue: ingress_msg. +This queue may contain data from its own protocol stack or from other +sockets. + +Therefore, for sockmap, relying solely on copied_seq and rcv_nxt to +calculate FIONREAD is not enough. + +This patch adds a new msg_tot_len field in the psock structure to record +the data length in ingress_msg. Additionally, we implement new ioctl +interfaces for TCP and UDP to intercept FIONREAD operations. + +Note that we intentionally do not include sk_receive_queue data in the +FIONREAD result. Data in sk_receive_queue has not yet been processed by +the BPF verdict program, and may be redirected to other sockets or +dropped. Including it would create semantic ambiguity since this data +may never be readable by the user. + +Unix and VSOCK sockets have similar issues, but fixing them is outside +the scope of this patch as it would require more intrusive changes. + +Previous work by John Fastabend made some efforts towards FIONREAD support: +commit e5c6de5fa025 ("bpf, sockmap: Incorrectly handling copied_seq") +Although the current patch is based on the previous work by John Fastabend, +it is acceptable for our Fixes tag to point to the same commit. + + FD1:read() + -- FD1->copied_seq++ + | [read data] + | + [enqueue data] v + [sockmap] -> ingress to self -> ingress_msg queue +FD1 native stack ------> ^ +-- FD1->rcv_nxt++ -> redirect to other | [enqueue data] + | | + | ingress to FD1 + v ^ + ... | [sockmap] + FD2 native stack + +Fixes: 04919bed948dc ("tcp: Introduce tcp_read_skb()") +Signed-off-by: Jiayuan Chen +Reviewed-by: Jakub Sitnicki +Link: https://lore.kernel.org/r/20260124113314.113584-3-jiayuan.chen@linux.dev +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + include/linux/skmsg.h | 68 +++++++++++++++++++++++++++++++++++++++++-- + net/core/skmsg.c | 3 ++ + net/ipv4/tcp_bpf.c | 20 +++++++++++++ + net/ipv4/udp_bpf.c | 23 ++++++++++++--- + 4 files changed, 108 insertions(+), 6 deletions(-) + +diff --git a/include/linux/skmsg.h b/include/linux/skmsg.h +index dfdc158ab88c8..829b281d6c9c2 100644 +--- a/include/linux/skmsg.h ++++ b/include/linux/skmsg.h +@@ -97,6 +97,8 @@ struct sk_psock { + struct sk_buff_head ingress_skb; + struct list_head ingress_msg; + spinlock_t ingress_lock; ++ /** @msg_tot_len: Total bytes queued in ingress_msg list. */ ++ u32 msg_tot_len; + unsigned long state; + struct list_head link; + spinlock_t link_lock; +@@ -321,6 +323,27 @@ static inline void sock_drop(struct sock *sk, struct sk_buff *skb) + kfree_skb(skb); + } + ++static inline u32 sk_psock_get_msg_len_nolock(struct sk_psock *psock) ++{ ++ /* Used by ioctl to read msg_tot_len only; lock-free for performance */ ++ return READ_ONCE(psock->msg_tot_len); ++} ++ ++static inline void sk_psock_msg_len_add_locked(struct sk_psock *psock, int diff) ++{ ++ /* Use WRITE_ONCE to ensure correct read in sk_psock_get_msg_len_nolock(). ++ * ingress_lock should be held to prevent concurrent updates to msg_tot_len ++ */ ++ WRITE_ONCE(psock->msg_tot_len, psock->msg_tot_len + diff); ++} ++ ++static inline void sk_psock_msg_len_add(struct sk_psock *psock, int diff) ++{ ++ spin_lock_bh(&psock->ingress_lock); ++ sk_psock_msg_len_add_locked(psock, diff); ++ spin_unlock_bh(&psock->ingress_lock); ++} ++ + static inline bool sk_psock_queue_msg(struct sk_psock *psock, + struct sk_msg *msg) + { +@@ -329,6 +352,7 @@ static inline bool sk_psock_queue_msg(struct sk_psock *psock, + spin_lock_bh(&psock->ingress_lock); + if (sk_psock_test_state(psock, SK_PSOCK_TX_ENABLED)) { + list_add_tail(&msg->list, &psock->ingress_msg); ++ sk_psock_msg_len_add_locked(psock, msg->sg.size); + ret = true; + } else { + sk_msg_free(psock->sk, msg); +@@ -345,18 +369,25 @@ static inline struct sk_msg *sk_psock_dequeue_msg(struct sk_psock *psock) + + spin_lock_bh(&psock->ingress_lock); + msg = list_first_entry_or_null(&psock->ingress_msg, struct sk_msg, list); +- if (msg) ++ if (msg) { + list_del(&msg->list); ++ sk_psock_msg_len_add_locked(psock, -msg->sg.size); ++ } + spin_unlock_bh(&psock->ingress_lock); + return msg; + } + ++static inline struct sk_msg *sk_psock_peek_msg_locked(struct sk_psock *psock) ++{ ++ return list_first_entry_or_null(&psock->ingress_msg, struct sk_msg, list); ++} ++ + static inline struct sk_msg *sk_psock_peek_msg(struct sk_psock *psock) + { + struct sk_msg *msg; + + spin_lock_bh(&psock->ingress_lock); +- msg = list_first_entry_or_null(&psock->ingress_msg, struct sk_msg, list); ++ msg = sk_psock_peek_msg_locked(psock); + spin_unlock_bh(&psock->ingress_lock); + return msg; + } +@@ -523,6 +554,39 @@ static inline bool sk_psock_strp_enabled(struct sk_psock *psock) + return !!psock->saved_data_ready; + } + ++/* for tcp only, sk is locked */ ++static inline ssize_t sk_psock_msg_inq(struct sock *sk) ++{ ++ struct sk_psock *psock; ++ ssize_t inq = 0; ++ ++ psock = sk_psock_get(sk); ++ if (likely(psock)) { ++ inq = sk_psock_get_msg_len_nolock(psock); ++ sk_psock_put(sk, psock); ++ } ++ return inq; ++} ++ ++/* for udp only, sk is not locked */ ++static inline ssize_t sk_msg_first_len(struct sock *sk) ++{ ++ struct sk_psock *psock; ++ struct sk_msg *msg; ++ ssize_t inq = 0; ++ ++ psock = sk_psock_get(sk); ++ if (likely(psock)) { ++ spin_lock_bh(&psock->ingress_lock); ++ msg = sk_psock_peek_msg_locked(psock); ++ if (msg) ++ inq = msg->sg.size; ++ spin_unlock_bh(&psock->ingress_lock); ++ sk_psock_put(sk, psock); ++ } ++ return inq; ++} ++ + #if IS_ENABLED(CONFIG_NET_SOCK_MSG) + + #define BPF_F_STRPARSER (1UL << 1) +diff --git a/net/core/skmsg.c b/net/core/skmsg.c +index d402da5caadd6..ddde93dd8bc6d 100644 +--- a/net/core/skmsg.c ++++ b/net/core/skmsg.c +@@ -458,6 +458,7 @@ int __sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg + atomic_sub(copy, &sk->sk_rmem_alloc); + } + msg_rx->sg.size -= copy; ++ sk_psock_msg_len_add(psock, -copy); + + if (!sge->length) { + sk_msg_iter_var_next(i); +@@ -821,9 +822,11 @@ static void __sk_psock_purge_ingress_msg(struct sk_psock *psock) + list_del(&msg->list); + if (!msg->skb) + atomic_sub(msg->sg.size, &psock->sk->sk_rmem_alloc); ++ sk_psock_msg_len_add(psock, -msg->sg.size); + sk_msg_free(psock->sk, msg); + kfree(msg); + } ++ WARN_ON_ONCE(psock->msg_tot_len); + } + + static void __sk_psock_zap_ingress(struct sk_psock *psock) +diff --git a/net/ipv4/tcp_bpf.c b/net/ipv4/tcp_bpf.c +index 5c698fd7fbf81..ca8a5cb8e569d 100644 +--- a/net/ipv4/tcp_bpf.c ++++ b/net/ipv4/tcp_bpf.c +@@ -10,6 +10,7 @@ + + #include + #include ++#include + + void tcp_eat_skb(struct sock *sk, struct sk_buff *skb) + { +@@ -332,6 +333,24 @@ static int tcp_bpf_recvmsg_parser(struct sock *sk, + return copied; + } + ++static int tcp_bpf_ioctl(struct sock *sk, int cmd, int *karg) ++{ ++ bool slow; ++ ++ if (cmd != SIOCINQ) ++ return tcp_ioctl(sk, cmd, karg); ++ ++ /* works similar as tcp_ioctl */ ++ if (sk->sk_state == TCP_LISTEN) ++ return -EINVAL; ++ ++ slow = lock_sock_fast(sk); ++ *karg = sk_psock_msg_inq(sk); ++ unlock_sock_fast(sk, slow); ++ ++ return 0; ++} ++ + static int tcp_bpf_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, + int flags, int *addr_len) + { +@@ -610,6 +629,7 @@ static void tcp_bpf_rebuild_protos(struct proto prot[TCP_BPF_NUM_CFGS], + prot[TCP_BPF_BASE].close = sock_map_close; + prot[TCP_BPF_BASE].recvmsg = tcp_bpf_recvmsg; + prot[TCP_BPF_BASE].sock_is_readable = sk_msg_is_readable; ++ prot[TCP_BPF_BASE].ioctl = tcp_bpf_ioctl; + + prot[TCP_BPF_TX] = prot[TCP_BPF_BASE]; + prot[TCP_BPF_TX].sendmsg = tcp_bpf_sendmsg; +diff --git a/net/ipv4/udp_bpf.c b/net/ipv4/udp_bpf.c +index 0735d820e413f..91233e37cd97a 100644 +--- a/net/ipv4/udp_bpf.c ++++ b/net/ipv4/udp_bpf.c +@@ -5,6 +5,7 @@ + #include + #include + #include ++#include + + #include "udp_impl.h" + +@@ -111,12 +112,26 @@ enum { + static DEFINE_SPINLOCK(udpv6_prot_lock); + static struct proto udp_bpf_prots[UDP_BPF_NUM_PROTS]; + ++static int udp_bpf_ioctl(struct sock *sk, int cmd, int *karg) ++{ ++ if (cmd != SIOCINQ) ++ return udp_ioctl(sk, cmd, karg); ++ ++ /* Since we don't hold a lock, sk_receive_queue may contain data. ++ * BPF might only be processing this data at the moment. We only ++ * care about the data in the ingress_msg here. ++ */ ++ *karg = sk_msg_first_len(sk); ++ return 0; ++} ++ + static void udp_bpf_rebuild_protos(struct proto *prot, const struct proto *base) + { +- *prot = *base; +- prot->close = sock_map_close; +- prot->recvmsg = udp_bpf_recvmsg; +- prot->sock_is_readable = sk_msg_is_readable; ++ *prot = *base; ++ prot->close = sock_map_close; ++ prot->recvmsg = udp_bpf_recvmsg; ++ prot->sock_is_readable = sk_msg_is_readable; ++ prot->ioctl = udp_bpf_ioctl; + } + + static void udp_bpf_check_v6_needs_rebuild(struct proto *ops) +-- +2.51.0 + diff --git a/queue-6.18/bpf-sockmap-fix-incorrect-copied_seq-calculation.patch b/queue-6.18/bpf-sockmap-fix-incorrect-copied_seq-calculation.patch new file mode 100644 index 0000000000..c26edd0d1a --- /dev/null +++ b/queue-6.18/bpf-sockmap-fix-incorrect-copied_seq-calculation.patch @@ -0,0 +1,178 @@ +From 93ca4270d2234bbb0fc2b8be10196e9577ac9d93 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 24 Jan 2026 19:32:43 +0800 +Subject: bpf, sockmap: Fix incorrect copied_seq calculation + +From: Jiayuan Chen + +[ Upstream commit b40cc5adaa80e1471095a62d78233b611d7a558c ] + +A socket using sockmap has its own independent receive queue: ingress_msg. +This queue may contain data from its own protocol stack or from other +sockets. + +The issue is that when reading from ingress_msg, we update tp->copied_seq +by default. However, if the data is not from its own protocol stack, +tcp->rcv_nxt is not increased. Later, if we convert this socket to a +native socket, reading from this socket may fail because copied_seq might +be significantly larger than rcv_nxt. + +This fix also addresses the syzkaller-reported bug referenced in the +Closes tag. + +This patch marks the skmsg objects in ingress_msg. When reading, we update +copied_seq only if the data is from its own protocol stack. + + FD1:read() + -- FD1->copied_seq++ + | [read data] + | + [enqueue data] v + [sockmap] -> ingress to self -> ingress_msg queue +FD1 native stack ------> ^ +-- FD1->rcv_nxt++ -> redirect to other | [enqueue data] + | | + | ingress to FD1 + v ^ + ... | [sockmap] + FD2 native stack + +Closes: https://syzkaller.appspot.com/bug?extid=06dbd397158ec0ea4983 +Fixes: 04919bed948dc ("tcp: Introduce tcp_read_skb()") +Reviewed-by: Jakub Sitnicki +Reviewed-by: John Fastabend +Signed-off-by: Jiayuan Chen +Link: https://lore.kernel.org/r/20260124113314.113584-2-jiayuan.chen@linux.dev +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + include/linux/skmsg.h | 2 ++ + net/core/skmsg.c | 27 ++++++++++++++++++++++++--- + net/ipv4/tcp_bpf.c | 5 +++-- + 3 files changed, 29 insertions(+), 5 deletions(-) + +diff --git a/include/linux/skmsg.h b/include/linux/skmsg.h +index 49847888c287a..dfdc158ab88c8 100644 +--- a/include/linux/skmsg.h ++++ b/include/linux/skmsg.h +@@ -141,6 +141,8 @@ int sk_msg_memcopy_from_iter(struct sock *sk, struct iov_iter *from, + struct sk_msg *msg, u32 bytes); + int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, + int len, int flags); ++int __sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, ++ int len, int flags, int *copied_from_self); + bool sk_msg_is_readable(struct sock *sk); + + static inline void sk_msg_check_to_free(struct sk_msg *msg, u32 i, u32 bytes) +diff --git a/net/core/skmsg.c b/net/core/skmsg.c +index 2ac7731e1e0a7..d402da5caadd6 100644 +--- a/net/core/skmsg.c ++++ b/net/core/skmsg.c +@@ -409,22 +409,26 @@ int sk_msg_memcopy_from_iter(struct sock *sk, struct iov_iter *from, + } + EXPORT_SYMBOL_GPL(sk_msg_memcopy_from_iter); + +-/* Receive sk_msg from psock->ingress_msg to @msg. */ +-int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, +- int len, int flags) ++int __sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, ++ int len, int flags, int *copied_from_self) + { + struct iov_iter *iter = &msg->msg_iter; + int peek = flags & MSG_PEEK; + struct sk_msg *msg_rx; + int i, copied = 0; ++ bool from_self; + + msg_rx = sk_psock_peek_msg(psock); ++ if (copied_from_self) ++ *copied_from_self = 0; ++ + while (copied != len) { + struct scatterlist *sge; + + if (unlikely(!msg_rx)) + break; + ++ from_self = msg_rx->sk == sk; + i = msg_rx->sg.start; + do { + struct page *page; +@@ -443,6 +447,9 @@ int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, + } + + copied += copy; ++ if (from_self && copied_from_self) ++ *copied_from_self += copy; ++ + if (likely(!peek)) { + sge->offset += copy; + sge->length -= copy; +@@ -487,6 +494,13 @@ int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, + out: + return copied; + } ++ ++/* Receive sk_msg from psock->ingress_msg to @msg. */ ++int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, ++ int len, int flags) ++{ ++ return __sk_msg_recvmsg(sk, psock, msg, len, flags, NULL); ++} + EXPORT_SYMBOL_GPL(sk_msg_recvmsg); + + bool sk_msg_is_readable(struct sock *sk) +@@ -616,6 +630,12 @@ static int sk_psock_skb_ingress_self(struct sk_psock *psock, struct sk_buff *skb + if (unlikely(!msg)) + return -EAGAIN; + skb_set_owner_r(skb, sk); ++ ++ /* This is used in tcp_bpf_recvmsg_parser() to determine whether the ++ * data originates from the socket's own protocol stack. No need to ++ * refcount sk because msg's lifetime is bound to sk via the ingress_msg. ++ */ ++ msg->sk = sk; + err = sk_psock_skb_ingress_enqueue(skb, off, len, psock, sk, msg, take_ref); + if (err < 0) + kfree(msg); +@@ -909,6 +929,7 @@ int sk_psock_msg_verdict(struct sock *sk, struct sk_psock *psock, + sk_msg_compute_data_pointers(msg); + msg->sk = sk; + ret = bpf_prog_run_pin_on_cpu(prog, msg); ++ msg->sk = NULL; + ret = sk_psock_map_verd(ret, msg->sk_redir); + psock->apply_bytes = msg->apply_bytes; + if (ret == __SK_REDIRECT) { +diff --git a/net/ipv4/tcp_bpf.c b/net/ipv4/tcp_bpf.c +index a268e1595b22a..5c698fd7fbf81 100644 +--- a/net/ipv4/tcp_bpf.c ++++ b/net/ipv4/tcp_bpf.c +@@ -226,6 +226,7 @@ static int tcp_bpf_recvmsg_parser(struct sock *sk, + int peek = flags & MSG_PEEK; + struct sk_psock *psock; + struct tcp_sock *tcp; ++ int copied_from_self = 0; + int copied = 0; + u32 seq; + +@@ -262,7 +263,7 @@ static int tcp_bpf_recvmsg_parser(struct sock *sk, + } + + msg_bytes_ready: +- copied = sk_msg_recvmsg(sk, psock, msg, len, flags); ++ copied = __sk_msg_recvmsg(sk, psock, msg, len, flags, &copied_from_self); + /* The typical case for EFAULT is the socket was gracefully + * shutdown with a FIN pkt. So check here the other case is + * some error on copy_page_to_iter which would be unexpected. +@@ -277,7 +278,7 @@ static int tcp_bpf_recvmsg_parser(struct sock *sk, + goto out; + } + } +- seq += copied; ++ seq += copied_from_self; + if (!copied) { + long timeo; + int data; +-- +2.51.0 + diff --git a/queue-6.18/btrfs-add-orig_logical-to-btrfs_bio-for-encryption.patch b/queue-6.18/btrfs-add-orig_logical-to-btrfs_bio-for-encryption.patch new file mode 100644 index 0000000000..412ef01849 --- /dev/null +++ b/queue-6.18/btrfs-add-orig_logical-to-btrfs_bio-for-encryption.patch @@ -0,0 +1,98 @@ +From c433e314ab179a0f0506d002f55c50a0e6d076f1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 18 Nov 2025 17:08:40 +0100 +Subject: btrfs: add orig_logical to btrfs_bio for encryption + +From: Josef Bacik + +[ Upstream commit bd45e9e3f6232f76fa9bd0e40c1e3409e4449f5e ] + +When checksumming the encrypted bio on writes we need to know which +logical address this checksum is for. At the point where we get the +encrypted bio the bi_sector is the physical location on the target disk, +so we need to save the original logical offset in the btrfs_bio. Then +we can use this when checksumming the bio instead of the +bio->iter.bi_sector. + +Note: The patch was taken from v5 of fscrypt patchset +(https://lore.kernel.org/linux-btrfs/cover.1706116485.git.josef@toxicpanda.com/) +which was handled over time by various people: Omar Sandoval, Sweet Tea +Dorminy, Josef Bacik. + +Signed-off-by: Josef Bacik +Signed-off-by: Daniel Vacek +Reviewed-by: David Sterba +[ add note ] +Signed-off-by: David Sterba +Stable-dep-of: b39b26e017c7 ("btrfs: zoned: don't zone append to conventional zone") +Signed-off-by: Sasha Levin +--- + fs/btrfs/bio.c | 10 ++++++++++ + fs/btrfs/bio.h | 2 ++ + fs/btrfs/file-item.c | 2 +- + 3 files changed, 13 insertions(+), 1 deletion(-) + +diff --git a/fs/btrfs/bio.c b/fs/btrfs/bio.c +index 1286c1ac19404..c3d860a2bca42 100644 +--- a/fs/btrfs/bio.c ++++ b/fs/btrfs/bio.c +@@ -94,6 +94,8 @@ static struct btrfs_bio *btrfs_split_bio(struct btrfs_fs_info *fs_info, + if (bbio_has_ordered_extent(bbio)) { + refcount_inc(&orig_bbio->ordered->refs); + bbio->ordered = orig_bbio->ordered; ++ bbio->orig_logical = orig_bbio->orig_logical; ++ orig_bbio->orig_logical += map_length; + } + bbio->csum_search_commit_root = orig_bbio->csum_search_commit_root; + atomic_inc(&orig_bbio->pending_ios); +@@ -726,6 +728,14 @@ static bool btrfs_submit_chunk(struct btrfs_bio *bbio, int mirror_num) + goto end_bbio; + } + ++ /* ++ * For fscrypt writes we will get the encrypted bio after we've remapped ++ * our bio to the physical disk location, so we need to save the ++ * original bytenr so we know what we're checksumming. ++ */ ++ if (bio_op(bio) == REQ_OP_WRITE && is_data_bbio(bbio)) ++ bbio->orig_logical = logical; ++ + map_length = min(map_length, length); + if (use_append) + map_length = btrfs_append_map_length(bbio, map_length); +diff --git a/fs/btrfs/bio.h b/fs/btrfs/bio.h +index 9a44b86d561b1..488cdbdd9e2f8 100644 +--- a/fs/btrfs/bio.h ++++ b/fs/btrfs/bio.h +@@ -59,6 +59,7 @@ struct btrfs_bio { + * - pointer to the checksums for this bio + * - original physical address from the allocator + * (for zone append only) ++ * - original logical address, used for checksumming fscrypt bios + */ + struct { + struct btrfs_ordered_extent *ordered; +@@ -67,6 +68,7 @@ struct btrfs_bio { + struct completion csum_done; + struct bvec_iter csum_saved_iter; + u64 orig_physical; ++ u64 orig_logical; + }; + + /* For metadata reads: parentness verification. */ +diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c +index 4b7c40f05e8f9..48f444bde5fa9 100644 +--- a/fs/btrfs/file-item.c ++++ b/fs/btrfs/file-item.c +@@ -815,7 +815,7 @@ int btrfs_csum_one_bio(struct btrfs_bio *bbio, bool async) + if (!sums) + return -ENOMEM; + +- sums->logical = bio->bi_iter.bi_sector << SECTOR_SHIFT; ++ sums->logical = bbio->orig_logical; + sums->len = bio->bi_iter.bi_size; + INIT_LIST_HEAD(&sums->list); + bbio->sums = sums; +-- +2.51.0 + diff --git a/queue-6.18/btrfs-fix-block_group_tree-dirty_list-corruption.patch b/queue-6.18/btrfs-fix-block_group_tree-dirty_list-corruption.patch new file mode 100644 index 0000000000..3e8ae5d6ae --- /dev/null +++ b/queue-6.18/btrfs-fix-block_group_tree-dirty_list-corruption.patch @@ -0,0 +1,150 @@ +From fc013f4868851e965b7c0220f11dea9722d999e5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 22 Dec 2025 16:15:44 -0800 +Subject: btrfs: fix block_group_tree dirty_list corruption + +From: Boris Burkov + +[ Upstream commit 3a1f4264daed4b419c325a7fe35e756cada3cf82 ] + +When the incompat flag EXTENT_TREE_V2 is set, we unconditionally add the +block group tree to the switch_commits list before calling +switch_commit_roots, as we do for the tree root and the chunk root. +However, the block group tree uses normal root dirty tracking and in any +transaction that does an allocation and dirties a block group, the block +group root will already be linked to a list by the dirty_list field and +this use of list_add_tail() is invalid and corrupts the prev/next +members of block_group_root->dirty_list. + +This is apparent on a subsequent list_del on the prev if we enable +CONFIG_DEBUG_LIST: + + [32.1571] ------------[ cut here ]------------ + [32.1572] list_del corruption. next->prev should beffff958890202538, but was ffff9588992bd538. (next=ffff958890201538) + [32.1575] WARNING: lib/list_debug.c:65 at 0x0, CPU#3: sync/607 + [32.1583] CPU: 3 UID: 0 PID: 607 Comm: sync Not tainted 6.18.0 #24PREEMPT(none) + [32.1585] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS1.17.0-4.fc41 04/01/2014 + [32.1587] RIP: 0010:__list_del_entry_valid_or_report+0x108/0x120 + [32.1593] RSP: 0018:ffffaa288287fdd0 EFLAGS: 00010202 + [32.1594] RAX: 0000000000000001 RBX: ffff95889326e800 RCX:ffff958890201538 + [32.1596] RDX: ffff9588992bd538 RSI: ffff958890202538 RDI:ffffffff82a41e00 + [32.1597] RBP: ffff958890202538 R08: ffffffff828fc1e8 R09:00000000ffffefff + [32.1599] R10: ffffffff8288c200 R11: ffffffff828e4200 R12:ffff958890201538 + [32.1601] R13: ffff95889326e958 R14: ffff958895c24000 R15:ffff958890202538 + [32.1603] FS: 00007f0c28eb5740(0000) GS:ffff958af2bd2000(0000)knlGS:0000000000000000 + [32.1605] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + [32.1607] CR2: 00007f0c28e8a3cc CR3: 0000000109942005 CR4:0000000000370ef0 + [32.1609] Call Trace: + [32.1610] + [32.1611] switch_commit_roots+0x82/0x1d0 [btrfs] + [32.1615] btrfs_commit_transaction+0x968/0x1550 [btrfs] + [32.1618] ? btrfs_attach_transaction_barrier+0x23/0x60 [btrfs] + [32.1621] __iterate_supers+0xe8/0x190 + [32.1622] ? __pfx_sync_fs_one_sb+0x10/0x10 + [32.1623] ksys_sync+0x63/0xb0 + [32.1624] __do_sys_sync+0xe/0x20 + [32.1625] do_syscall_64+0x73/0x450 + [32.1626] entry_SYSCALL_64_after_hwframe+0x76/0x7e + [32.1627] RIP: 0033:0x7f0c28d05d2b + [32.1632] RSP: 002b:00007ffc9d988048 EFLAGS: 00000246 ORIG_RAX:00000000000000a2 + [32.1634] RAX: ffffffffffffffda RBX: 00007ffc9d988228 RCX:00007f0c28d05d2b + [32.1636] RDX: 00007f0c28e02301 RSI: 00007ffc9d989b21 RDI:00007f0c28dba90d + [32.1637] RBP: 0000000000000001 R08: 0000000000000001 R09:0000000000000000 + [32.1639] R10: 0000000000000000 R11: 0000000000000246 R12:000055b96572cb80 + [32.1641] R13: 000055b96572b19f R14: 00007f0c28dfa434 R15:000055b96572b034 + [32.1643] + [32.1644] irq event stamp: 0 + [32.1644] hardirqs last enabled at (0): [<0000000000000000>] 0x0 + [32.1646] hardirqs last disabled at (0): []copy_process+0xb37/0x2260 + [32.1648] softirqs last enabled at (0): []copy_process+0xb37/0x2260 + [32.1650] softirqs last disabled at (0): [<0000000000000000>] 0x0 + [32.1652] ---[ end trace 0000000000000000 ]--- + +Furthermore, this list corruption eventually (when we happen to add a +new block group) results in getting the switch_commits and +dirty_cowonly_roots lists mixed up and attempting to call update_root +on the tree root which can't be found in the tree root, resulting in a +transaction abort: + + [87.8269] BTRFS critical (device nvme1n1): unable to find root key (1 0 0) in tree 1 + [87.8272] ------------[ cut here ]------------ + [87.8274] BTRFS: Transaction aborted (error -117) + [87.8275] WARNING: fs/btrfs/root-tree.c:153 at 0x0, CPU#4: sync/703 + [87.8285] CPU: 4 UID: 0 PID: 703 Comm: sync Not tainted 6.18.0 #25 PREEMPT(none) + [87.8287] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.17.0-4.fc41 04/01/2014 + [87.8289] RIP: 0010:btrfs_update_root+0x296/0x790 [btrfs] + [87.8295] RSP: 0018:ffffa58d035dfd60 EFLAGS: 00010282 + [87.8297] RAX: ffff9a59126ddb68 RBX: ffff9a59126dc000 RCX: 0000000000000000 + [87.8299] RDX: 0000000000000000 RSI: 00000000ffffff8b RDI: ffffffffc0b28270 + [87.8301] RBP: ffff9a5904aec000 R08: 0000000000000000 R09: 00000000ffffefff + [87.8303] R10: ffffffff9ac8c200 R11: ffffffff9ace4200 R12: 0000000000000001 + [87.8305] R13: ffff9a59041740e8 R14: ffff9a5904aec1f7 R15: ffff9a590fdefaf0 + [87.8307] FS: 00007f54cde6b740(0000) GS:ffff9a5b5a81c000(0000) knlGS:0000000000000000 + [87.8309] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + [87.8310] CR2: 00007f54cde403cc CR3: 0000000112902004 CR4: 0000000000370ef0 + [87.8312] Call Trace: + [87.8313] + [87.8314] ? _raw_spin_unlock+0x23/0x40 + [87.8315] commit_cowonly_roots+0x1ad/0x250 [btrfs] + [87.8317] ? btrfs_commit_transaction+0x79b/0x1560 [btrfs] + [87.8320] btrfs_commit_transaction+0x8aa/0x1560 [btrfs] + [87.8322] ? btrfs_attach_transaction_barrier+0x23/0x60 [btrfs] + [87.8325] __iterate_supers+0xf1/0x170 + [87.8326] ? __pfx_sync_fs_one_sb+0x10/0x10 + [87.8327] ksys_sync+0x63/0xb0 + [87.8328] __do_sys_sync+0xe/0x20 + [87.8329] do_syscall_64+0x73/0x450 + [87.8330] entry_SYSCALL_64_after_hwframe+0x76/0x7e + [87.8331] RIP: 0033:0x7f54cdd05d2b + [87.8336] RSP: 002b:00007fff1b58ff78 EFLAGS: 00000246 ORIG_RAX: 00000000000000a2 + [87.8338] RAX: ffffffffffffffda RBX: 00007fff1b590158 RCX: 00007f54cdd05d2b + [87.8340] RDX: 00007f54cde02301 RSI: 00007fff1b592b66 RDI: 00007f54cddba90d + [87.8342] RBP: 0000000000000001 R08: 0000000000000001 R09: 0000000000000000 + [87.8344] R10: 0000000000000000 R11: 0000000000000246 R12: 000055e07ca96b80 + [87.8346] R13: 000055e07ca9519f R14: 00007f54cddfa434 R15: 000055e07ca95034 + [87.8348] + [87.8348] irq event stamp: 0 + [87.8349] hardirqs last enabled at (0): [<0000000000000000>] 0x0 + [87.8351] hardirqs last disabled at (0): [] copy_process+0xb37/0x21e0 + [87.8353] softirqs last enabled at (0): [] copy_process+0xb37/0x21e0 + [87.8355] softirqs last disabled at (0): [<0000000000000000>] 0x0 + [87.8357] ---[ end trace 0000000000000000 ]--- + [87.8358] BTRFS: error (device nvme1n1 state A) in btrfs_update_root:153: errno=-117 Filesystem corrupted + [87.8360] BTRFS info (device nvme1n1 state EA): forced readonly + [87.8362] BTRFS warning (device nvme1n1 state EA): Skipping commit of aborted transaction. + [87.8364] BTRFS: error (device nvme1n1 state EA) in cleanup_transaction:2037: errno=-117 Filesystem corrupted + +Since the block group tree was pulled out of the extent tree and uses +normal root dirty tracking, remove the offending extra list_add. This +fixes the list corruption and the resulting fs corruption. + +Fixes: 14033b08a029 ("btrfs: don't save block group root into super block") +Reviewed-by: Filipe Manana +Signed-off-by: Boris Burkov +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/transaction.c | 7 ------- + 1 file changed, 7 deletions(-) + +diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c +index 041f4781956cf..b537bba767806 100644 +--- a/fs/btrfs/transaction.c ++++ b/fs/btrfs/transaction.c +@@ -2484,13 +2484,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans) + list_add_tail(&fs_info->chunk_root->dirty_list, + &cur_trans->switch_commits); + +- if (btrfs_fs_incompat(fs_info, EXTENT_TREE_V2)) { +- btrfs_set_root_node(&fs_info->block_group_root->root_item, +- fs_info->block_group_root->node); +- list_add_tail(&fs_info->block_group_root->dirty_list, +- &cur_trans->switch_commits); +- } +- + switch_commit_roots(trans); + + ASSERT(list_empty(&cur_trans->dirty_bgs)); +-- +2.51.0 + diff --git a/queue-6.18/btrfs-fix-eexist-abort-due-to-non-consecutive-gaps-i.patch b/queue-6.18/btrfs-fix-eexist-abort-due-to-non-consecutive-gaps-i.patch new file mode 100644 index 0000000000..29db845c87 --- /dev/null +++ b/queue-6.18/btrfs-fix-eexist-abort-due-to-non-consecutive-gaps-i.patch @@ -0,0 +1,496 @@ +From ee7c156054006cb23e9c362bc5c643cc889172b0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 16:11:21 -0800 +Subject: btrfs: fix EEXIST abort due to non-consecutive gaps in chunk + allocation + +From: Boris Burkov + +[ Upstream commit b14c5e04bd0f722ed631845599d52d03fcae1bc1 ] + +I have been observing a number of systems aborting at +insert_dev_extents() in btrfs_create_pending_block_groups(). The +following is a sample stack trace of such an abort coming from forced +chunk allocation (typically behind CONFIG_BTRFS_EXPERIMENTAL) but this +can theoretically happen to any DUP chunk allocation. + + [81.801] ------------[ cut here ]------------ + [81.801] BTRFS: Transaction aborted (error -17) + [81.801] WARNING: fs/btrfs/block-group.c:2876 at btrfs_create_pending_block_groups+0x721/0x770 [btrfs], CPU#1: bash/319 + [81.802] Modules linked in: virtio_net btrfs xor zstd_compress raid6_pq null_blk + [81.803] CPU: 1 UID: 0 PID: 319 Comm: bash Kdump: loaded Not tainted 6.19.0-rc6+ #319 NONE + [81.803] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Arch Linux 1.17.0-2-2 04/01/2014 + [81.804] RIP: 0010:btrfs_create_pending_block_groups+0x723/0x770 [btrfs] + [81.806] RSP: 0018:ffffa36241a6bce8 EFLAGS: 00010282 + [81.806] RAX: 000000000000000d RBX: ffff8e699921e400 RCX: 0000000000000000 + [81.807] RDX: 0000000002040001 RSI: 00000000ffffffef RDI: ffffffffc0608bf0 + [81.807] RBP: 00000000ffffffef R08: ffff8e69830f6000 R09: 0000000000000007 + [81.808] R10: ffff8e699921e5e8 R11: 0000000000000000 R12: ffff8e6999228000 + [81.808] R13: ffff8e6984d82000 R14: ffff8e69966a69c0 R15: ffff8e69aa47b000 + [81.809] FS: 00007fec6bdd9740(0000) GS:ffff8e6b1b379000(0000) knlGS:0000000000000000 + [81.809] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + [81.810] CR2: 00005604833670f0 CR3: 0000000116679000 CR4: 00000000000006f0 + [81.810] Call Trace: + [81.810] + [81.810] __btrfs_end_transaction+0x3e/0x2b0 [btrfs] + [81.811] btrfs_force_chunk_alloc_store+0xcd/0x140 [btrfs] + [81.811] kernfs_fop_write_iter+0x15f/0x240 + [81.812] vfs_write+0x264/0x500 + [81.812] ksys_write+0x6c/0xe0 + [81.812] do_syscall_64+0x66/0x770 + [81.812] entry_SYSCALL_64_after_hwframe+0x76/0x7e + [81.813] RIP: 0033:0x7fec6be66197 + [81.814] RSP: 002b:00007fffb159dd30 EFLAGS: 00000202 ORIG_RAX: 0000000000000001 + [81.815] RAX: ffffffffffffffda RBX: 00007fec6bdd9740 RCX: 00007fec6be66197 + [81.815] RDX: 0000000000000002 RSI: 0000560483374f80 RDI: 0000000000000001 + [81.816] RBP: 0000560483374f80 R08: 0000000000000000 R09: 0000000000000000 + [81.816] R10: 0000000000000000 R11: 0000000000000202 R12: 0000000000000002 + [81.817] R13: 00007fec6bfb85c0 R14: 00007fec6bfb5ee0 R15: 00005604833729c0 + [81.817] + [81.817] irq event stamp: 20039 + [81.818] hardirqs last enabled at (20047): [] __up_console_sem+0x52/0x60 + [81.818] hardirqs last disabled at (20056): [] __up_console_sem+0x37/0x60 + [81.819] softirqs last enabled at (19470): [] __irq_exit_rcu+0x96/0xc0 + [81.819] softirqs last disabled at (19463): [] __irq_exit_rcu+0x96/0xc0 + [81.820] ---[ end trace 0000000000000000 ]--- + [81.820] BTRFS: error (device dm-7 state A) in btrfs_create_pending_block_groups:2876: errno=-17 Object already exists + +Inspecting these aborts with drgn, I observed a pattern of overlapping +chunk_maps. Note how stripe 1 of the first chunk overlaps in physical +address with stripe 0 of the second chunk. + +Physical Start Physical End Length Logical Type Stripe +---------------------------------------------------------------------------------------------------- +0x0000000102500000 0x0000000142500000 1.0G 0x0000000641d00000 META|DUP 0/2 +0x0000000142500000 0x0000000182500000 1.0G 0x0000000641d00000 META|DUP 1/2 +0x0000000142500000 0x0000000182500000 1.0G 0x0000000601d00000 META|DUP 0/2 +0x0000000182500000 0x00000001c2500000 1.0G 0x0000000601d00000 META|DUP 1/2 + +Now how could this possibly happen? All chunk allocation is protected by +the chunk_mutex so racing allocations should see a consistent view of +the CHUNK_ALLOCATED bit in the chunk allocation extent-io-tree +(device->alloc_state as set by chunk_map_device_set_bits()) The tree +itself is protected by a spin lock, and clearing/setting the bits is +always protected by fs_info->mapping_tree_lock, so no race is apparent. + +It turns out that there is a subtle bug in the logic regarding chunk +allocations that have happened in the current transaction, known as +"pending extents". The chunk allocation as defined in +find_free_dev_extent() is a loop which searches the commit root of the +dev_root and looks for gaps between DEV_EXTENT items. For those gaps, it +then checks alloc_state bitmap for any pending extents and adjusts the +hole that it finds accordingly. However, the logic in that adjustment +assumes that the first pending extent is the only one in that range. + +e.g., given a layout with two non-consecutive pending extents in a hole +passed to dev_extent_hole_check() via *hole_start and *hole_size: + + |----pending A----| real hole |----pending B----| + | candidate hole | + *hole_start *hole_start + *hole_size + +the code incorrectly returns a "hole" from the end of pending extent A +until the passed in hole end, failing to account for pending B. + +However, it is not entirely obvious that it is actually possible to +produce such a layout. I was able to reproduce it, but with some +contortions: I continued to use the force chunk allocation sysfs file +and I introduced a long delay (10 seconds) into the start of the cleaner +thread. I also prevented the unused bgs cleaning logic from ever +deleting metadata bgs. These help make it easier to deterministically +produce the condition but shouldn't really matter if you imagine the +conditions happening by race/luck. Allocations/frees can happen +concurrently with the cleaner thread preparing to process an unused +extent and both create some used chunks with an unused chunk +interleaved, all during one transaction. Then btrfs_delete_unused_bgs() +sees the unused one and clears it, leaving a range with several pending +chunk allocations and a gap in the middle. + +The basic idea is that the unused_bgs cleanup work happens on a worker +so if we allocate 3 block groups in one transaction, then the cleaner +work kicked off by the previous transaction comes through and deletes +the middle one of the 3, then the commit root shows no dev extents and +we have the bad pattern in the extent-io-tree. One final consideration +is that the code happens to loop to the next hole if there are no more +extents at all, so we need one more dev extent way past the area we are +working in. Something like the following demonstrates the technique: + + # push the BG frontier out to 20G + fallocate -l 20G $mnt/foo + # allocate one more that will prevent the "no more dev extents" luck + fallocate -l 1G $mnt/sticky + # sync + sync + # clear out the allocation area + rm $mnt/foo + sync + _cleaner + # let everything quiesce + sleep 20 + sync + + # dev tree should have one bg 20G out and the rest at the beginning.. + # sort of like an empty FS but with a random sticky chunk. + + # kick off the cleaner in the background, remember it will sleep 10s + # before doing interesting work + _cleaner & + + sleep 3 + + # create 3 trivial block groups, all empty, all immediately marked as unused. + echo 1 > "$(_btrfs_sysfs_space_info $dev metadata)/force_chunk_alloc" + echo 1 > "$(_btrfs_sysfs_space_info $dev data)/force_chunk_alloc" + echo 1 > "$(_btrfs_sysfs_space_info $dev metadata)/force_chunk_alloc" + + # let the cleaner thread definitely finish, it will remove the data bg + sleep 10 + + # this allocation sees the non-consecutive pending metadata chunks with + # data chunk gap of 1G and allocates a 2G extent in that hole. ENOSPC! + echo 1 > "$(_btrfs_sysfs_space_info $dev metadata)/force_chunk_alloc" + +As for the fix, it is not that obvious. I could not see a trivial way to +do it even by adding backup loops into find_free_dev_extent(), so I +opted to change the semantics of dev_extent_hole_check() to not stop +looping until it finds a sufficiently big hole. For clarity, this also +required changing the helper function contains_pending_extent() into two +new helpers which find the first pending extent and the first suitable +hole in a range. + +I attempted to clean up the documentation and range calculations to be +as consistent and clear as possible for the future. + +I also looked at the zoned case and concluded that the loop there is +different and not to be unified with this one. As far as I can tell, the +zoned check will only further constrain the hole so looping back to find +more holes is acceptable. Though given that zoned really only appends, I +find it highly unlikely that it is susceptible to this bug. + +Fixes: 1b9845081633 ("Btrfs: fix find_free_dev_extent() malfunction in case device tree has hole") +Reported-by: Dimitrios Apostolou +Closes: https://lore.kernel.org/linux-btrfs/q7760374-q1p4-029o-5149-26p28421s468@tzk.arg/ +Reviewed-by: Qu Wenruo +Signed-off-by: Boris Burkov +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/volumes.c | 243 ++++++++++++++++++++++++++++++++++----------- + 1 file changed, 183 insertions(+), 60 deletions(-) + +diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c +index 8e7dcb12af4c4..645bf98a9571b 100644 +--- a/fs/btrfs/volumes.c ++++ b/fs/btrfs/volumes.c +@@ -1506,30 +1506,158 @@ struct btrfs_device *btrfs_scan_one_device(const char *path, + } + + /* +- * Try to find a chunk that intersects [start, start + len] range and when one +- * such is found, record the end of it in *start ++ * Find the first pending extent intersecting a range. ++ * ++ * @device: the device to search ++ * @start: start of the range to check ++ * @len: length of the range to check ++ * @pending_start: output pointer for the start of the found pending extent ++ * @pending_end: output pointer for the end of the found pending extent (inclusive) ++ * ++ * Search for a pending chunk allocation that intersects the half-open range ++ * [start, start + len). ++ * ++ * Return: true if a pending extent was found, false otherwise. ++ * If the return value is true, store the first pending extent in ++ * [*pending_start, *pending_end]. Otherwise, the two output variables ++ * may still be modified, to something outside the range and should not ++ * be used. + */ +-static bool contains_pending_extent(struct btrfs_device *device, u64 *start, +- u64 len) ++static bool first_pending_extent(struct btrfs_device *device, u64 start, u64 len, ++ u64 *pending_start, u64 *pending_end) + { +- u64 physical_start, physical_end; +- + lockdep_assert_held(&device->fs_info->chunk_mutex); + +- if (btrfs_find_first_extent_bit(&device->alloc_state, *start, +- &physical_start, &physical_end, ++ if (btrfs_find_first_extent_bit(&device->alloc_state, start, ++ pending_start, pending_end, + CHUNK_ALLOCATED, NULL)) { + +- if (in_range(physical_start, *start, len) || +- in_range(*start, physical_start, +- physical_end + 1 - physical_start)) { +- *start = physical_end + 1; ++ if (in_range(*pending_start, start, len) || ++ in_range(start, *pending_start, *pending_end + 1 - *pending_start)) { + return true; + } + } + return false; + } + ++/* ++ * Find the first real hole accounting for pending extents. ++ * ++ * @device: the device containing the candidate hole ++ * @start: input/output pointer for the hole start position ++ * @len: input/output pointer for the hole length ++ * @min_hole_size: the size of hole we are looking for ++ * ++ * Given a potential hole specified by [*start, *start + *len), check for pending ++ * chunk allocations within that range. If pending extents are found, the hole is ++ * adjusted to represent the first true free space that is large enough when ++ * accounting for pending chunks. ++ * ++ * Note that this function must handle various cases involving non consecutive ++ * pending extents. ++ * ++ * Returns: true if a suitable hole was found and false otherwise. ++ * If the return value is true, then *start and *len are set to represent the hole. ++ * If the return value is false, then *start is set to the largest hole we ++ * found and *len is set to its length. ++ * If there are no holes at all, then *start is set to the end of the range and ++ * *len is set to 0. ++ */ ++static bool find_hole_in_pending_extents(struct btrfs_device *device, u64 *start, ++ u64 *len, u64 min_hole_size) ++{ ++ u64 pending_start, pending_end; ++ u64 end; ++ u64 max_hole_start = 0; ++ u64 max_hole_len = 0; ++ ++ lockdep_assert_held(&device->fs_info->chunk_mutex); ++ ++ if (*len == 0) ++ return false; ++ ++ end = *start + *len - 1; ++ ++ /* ++ * Loop until we either see a large enough hole or check every pending ++ * extent overlapping the candidate hole. ++ * At every hole that we observe, record it if it is the new max. ++ * At the end of the iteration, set the output variables to the max hole. ++ */ ++ while (true) { ++ if (first_pending_extent(device, *start, *len, &pending_start, &pending_end)) { ++ /* ++ * Case 1: the pending extent overlaps the start of ++ * candidate hole. That means the true hole is after the ++ * pending extent, but we need to find the next pending ++ * extent to properly size the hole. In the next loop, ++ * we will reduce to case 2 or 3. ++ * e.g., ++ * ++ * |----pending A----| real hole |----pending B----| ++ * | candidate hole | ++ * *start end ++ */ ++ if (pending_start <= *start) { ++ *start = pending_end + 1; ++ goto next; ++ } ++ /* ++ * Case 2: The pending extent starts after *start (and overlaps ++ * [*start, end), so the first hole just goes up to the start ++ * of the pending extent. ++ * e.g., ++ * ++ * | real hole |----pending A----| ++ * | candidate hole | ++ * *start end ++ */ ++ *len = pending_start - *start; ++ if (*len > max_hole_len) { ++ max_hole_start = *start; ++ max_hole_len = *len; ++ } ++ if (*len >= min_hole_size) ++ break; ++ /* ++ * If the hole wasn't big enough, then we advance past ++ * the pending extent and keep looking. ++ */ ++ *start = pending_end + 1; ++ goto next; ++ } else { ++ /* ++ * Case 3: There is no pending extent overlapping the ++ * range [*start, *start + *len - 1], so the only remaining ++ * hole is the remaining range. ++ * e.g., ++ * ++ * | candidate hole | ++ * | real hole | ++ * *start end ++ */ ++ ++ if (*len > max_hole_len) { ++ max_hole_start = *start; ++ max_hole_len = *len; ++ } ++ break; ++ } ++next: ++ if (*start > end) ++ break; ++ *len = end - *start + 1; ++ } ++ if (max_hole_len) { ++ *start = max_hole_start; ++ *len = max_hole_len; ++ } else { ++ *start = end + 1; ++ *len = 0; ++ } ++ return max_hole_len >= min_hole_size; ++} ++ + static u64 dev_extent_search_start(struct btrfs_device *device) + { + switch (device->fs_devices->chunk_alloc_policy) { +@@ -1594,59 +1722,57 @@ static bool dev_extent_hole_check_zoned(struct btrfs_device *device, + } + + /* +- * Check if specified hole is suitable for allocation. ++ * Validate and adjust a hole for chunk allocation ++ * ++ * @device: the device containing the candidate hole ++ * @hole_start: input/output pointer for the hole start position ++ * @hole_size: input/output pointer for the hole size ++ * @num_bytes: minimum allocation size required + * +- * @device: the device which we have the hole +- * @hole_start: starting position of the hole +- * @hole_size: the size of the hole +- * @num_bytes: the size of the free space that we need ++ * Check if the specified hole is suitable for allocation and adjust it if ++ * necessary. The hole may be modified to skip over pending chunk allocations ++ * and to satisfy stricter zoned requirements on zoned filesystems. + * +- * This function may modify @hole_start and @hole_size to reflect the suitable +- * position for allocation. Returns 1 if hole position is updated, 0 otherwise. ++ * For regular (non-zoned) allocation, if the hole after adjustment is smaller ++ * than @num_bytes, the search continues past additional pending extents until ++ * either a sufficiently large hole is found or no more pending extents exist. ++ * ++ * Return: true if a suitable hole was found and false otherwise. ++ * If the return value is true, then *hole_start and *hole_size are set to ++ * represent the hole we found. ++ * If the return value is false, then *hole_start is set to the largest ++ * hole we found and *hole_size is set to its length. ++ * If there are no holes at all, then *hole_start is set to the end of the range ++ * and *hole_size is set to 0. + */ + static bool dev_extent_hole_check(struct btrfs_device *device, u64 *hole_start, + u64 *hole_size, u64 num_bytes) + { +- bool changed = false; +- u64 hole_end = *hole_start + *hole_size; ++ bool found = false; ++ const u64 hole_end = *hole_start + *hole_size - 1; + +- for (;;) { +- /* +- * Check before we set max_hole_start, otherwise we could end up +- * sending back this offset anyway. +- */ +- if (contains_pending_extent(device, hole_start, *hole_size)) { +- if (hole_end >= *hole_start) +- *hole_size = hole_end - *hole_start; +- else +- *hole_size = 0; +- changed = true; +- } ++ ASSERT(*hole_size > 0); + +- switch (device->fs_devices->chunk_alloc_policy) { +- default: +- btrfs_warn_unknown_chunk_allocation(device->fs_devices->chunk_alloc_policy); +- fallthrough; +- case BTRFS_CHUNK_ALLOC_REGULAR: +- /* No extra check */ +- break; +- case BTRFS_CHUNK_ALLOC_ZONED: +- if (dev_extent_hole_check_zoned(device, hole_start, +- hole_size, num_bytes)) { +- changed = true; +- /* +- * The changed hole can contain pending extent. +- * Loop again to check that. +- */ +- continue; +- } +- break; +- } ++again: ++ *hole_size = hole_end - *hole_start + 1; ++ found = find_hole_in_pending_extents(device, hole_start, hole_size, num_bytes); ++ if (!found) ++ return found; ++ ASSERT(*hole_size >= num_bytes); + ++ switch (device->fs_devices->chunk_alloc_policy) { ++ default: ++ btrfs_warn_unknown_chunk_allocation(device->fs_devices->chunk_alloc_policy); ++ fallthrough; ++ case BTRFS_CHUNK_ALLOC_REGULAR: ++ return found; ++ case BTRFS_CHUNK_ALLOC_ZONED: ++ if (dev_extent_hole_check_zoned(device, hole_start, hole_size, num_bytes)) ++ goto again; + break; + } + +- return changed; ++ return found; + } + + /* +@@ -1705,7 +1831,7 @@ static int find_free_dev_extent(struct btrfs_device *device, u64 num_bytes, + ret = -ENOMEM; + goto out; + } +-again: ++ + if (search_start >= search_end || + test_bit(BTRFS_DEV_STATE_REPLACE_TGT, &device->dev_state)) { + ret = -ENOSPC; +@@ -1792,11 +1918,7 @@ static int find_free_dev_extent(struct btrfs_device *device, u64 num_bytes, + */ + if (search_end > search_start) { + hole_size = search_end - search_start; +- if (dev_extent_hole_check(device, &search_start, &hole_size, +- num_bytes)) { +- btrfs_release_path(path); +- goto again; +- } ++ dev_extent_hole_check(device, &search_start, &hole_size, num_bytes); + + if (hole_size > max_hole_size) { + max_hole_start = search_start; +@@ -4882,6 +5004,7 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size) + u64 diff; + u64 start; + u64 free_diff = 0; ++ u64 pending_start, pending_end; + + new_size = round_down(new_size, fs_info->sectorsize); + start = new_size; +@@ -4927,7 +5050,7 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size) + * in-memory chunks are synced to disk so that the loop below sees them + * and relocates them accordingly. + */ +- if (contains_pending_extent(device, &start, diff)) { ++ if (first_pending_extent(device, start, diff, &pending_start, &pending_end)) { + mutex_unlock(&fs_info->chunk_mutex); + ret = btrfs_commit_transaction(trans); + if (ret) +-- +2.51.0 + diff --git a/queue-6.18/btrfs-headers-cleanup-to-remove-unnecessary-local-in.patch b/queue-6.18/btrfs-headers-cleanup-to-remove-unnecessary-local-in.patch new file mode 100644 index 0000000000..7057240235 --- /dev/null +++ b/queue-6.18/btrfs-headers-cleanup-to-remove-unnecessary-local-in.patch @@ -0,0 +1,368 @@ +From a733c71cd1e4cd4a75a21f26746e9cf41d957fd5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Oct 2025 10:06:36 +1030 +Subject: btrfs: headers cleanup to remove unnecessary local includes + +From: Qu Wenruo + +[ Upstream commit c5667f9c8eb90293dfa4e52c65eb89fe39f5652d ] + +[BUG] +When I tried to remove btrfs_bio::fs_info and use btrfs_bio::inode to +grab the fs_info, the header "btrfs_inode.h" is needed to access the +full btrfs_inode structure. + +Then btrfs will fail to compile. + +[CAUSE] +There is a recursive including chain: + + "bio.h" -> "btrfs_inode.h" -> "extent_map.h" -> "compression.h" -> + "bio.h" + +That recursive including is causing problems for btrfs. + +[ENHANCEMENT] +To reduce the risk of recursive including: + +- Remove unnecessary local includes from btrfs headers + Either the included header is pulled in by other headers, or is + completely unnecessary. + +- Remove btrfs local includes if the header only requires a pointer + In that case let the implementing C file to pull the required header. + + This is especially important for headers like "btrfs_inode.h" which + pulls in a lot of other btrfs headers, thus it's a mine field of + recursive including. + +- Remove unnecessary temporary structure definition + Either if we have included the header defining the structure, or + completely unused. + +Now including "btrfs_inode.h" inside "bio.h" is completely fine, +although "btrfs_inode.h" still includes "extent_map.h", but that header +only includes "fs.h", no more chain back to "bio.h". + +Signed-off-by: Qu Wenruo +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Stable-dep-of: b39b26e017c7 ("btrfs: zoned: don't zone append to conventional zone") +Signed-off-by: Sasha Levin +--- + fs/btrfs/accessors.h | 1 + + fs/btrfs/btrfs_inode.h | 8 ++++---- + fs/btrfs/compression.h | 3 --- + fs/btrfs/ctree.h | 2 -- + fs/btrfs/defrag.c | 1 + + fs/btrfs/dir-item.c | 1 + + fs/btrfs/direct-io.c | 2 ++ + fs/btrfs/disk-io.c | 1 + + fs/btrfs/disk-io.h | 3 ++- + fs/btrfs/extent-tree.c | 1 + + fs/btrfs/extent_io.h | 1 - + fs/btrfs/extent_map.h | 3 +-- + fs/btrfs/file-item.h | 2 +- + fs/btrfs/inode.c | 1 + + fs/btrfs/space-info.c | 1 + + fs/btrfs/subpage.h | 1 - + fs/btrfs/transaction.c | 2 ++ + fs/btrfs/transaction.h | 4 ---- + fs/btrfs/tree-log.c | 1 + + fs/btrfs/tree-log.h | 3 +-- + fs/btrfs/zoned.h | 1 - + 21 files changed, 21 insertions(+), 22 deletions(-) + +diff --git a/fs/btrfs/accessors.h b/fs/btrfs/accessors.h +index 99b3ced12805b..78721412951c5 100644 +--- a/fs/btrfs/accessors.h ++++ b/fs/btrfs/accessors.h +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include "fs.h" + #include "extent_io.h" + + struct extent_buffer; +diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h +index af373d50a901f..a66ca5531b5c5 100644 +--- a/fs/btrfs/btrfs_inode.h ++++ b/fs/btrfs/btrfs_inode.h +@@ -18,20 +18,20 @@ + #include + #include + #include ++#include "ctree.h" + #include "block-rsv.h" + #include "extent_map.h" +-#include "extent_io.h" + #include "extent-io-tree.h" +-#include "ordered-data.h" +-#include "delayed-inode.h" + +-struct extent_state; + struct posix_acl; + struct iov_iter; + struct writeback_control; + struct btrfs_root; + struct btrfs_fs_info; + struct btrfs_trans_handle; ++struct btrfs_bio; ++struct btrfs_file_extent; ++struct btrfs_delayed_node; + + /* + * Since we search a directory based on f_pos (struct dir_context::pos) we have +diff --git a/fs/btrfs/compression.h b/fs/btrfs/compression.h +index eba188a9e3bb5..c6812d5fcab79 100644 +--- a/fs/btrfs/compression.h ++++ b/fs/btrfs/compression.h +@@ -14,14 +14,11 @@ + #include + #include "bio.h" + #include "fs.h" +-#include "messages.h" + + struct address_space; +-struct page; + struct inode; + struct btrfs_inode; + struct btrfs_ordered_extent; +-struct btrfs_bio; + + /* + * We want to make sure that amount of RAM required to uncompress an extent is +diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h +index fe70b593c7cd9..16dd11c485313 100644 +--- a/fs/btrfs/ctree.h ++++ b/fs/btrfs/ctree.h +@@ -17,9 +17,7 @@ + #include + #include + #include "locking.h" +-#include "fs.h" + #include "accessors.h" +-#include "extent-io-tree.h" + + struct extent_buffer; + struct btrfs_block_rsv; +diff --git a/fs/btrfs/defrag.c b/fs/btrfs/defrag.c +index 7b277934f66f9..a4cc1bc635622 100644 +--- a/fs/btrfs/defrag.c ++++ b/fs/btrfs/defrag.c +@@ -15,6 +15,7 @@ + #include "defrag.h" + #include "file-item.h" + #include "super.h" ++#include "compression.h" + + static struct kmem_cache *btrfs_inode_defrag_cachep; + +diff --git a/fs/btrfs/dir-item.c b/fs/btrfs/dir-item.c +index 69863e398e223..77e1bcb2a74bf 100644 +--- a/fs/btrfs/dir-item.c ++++ b/fs/btrfs/dir-item.c +@@ -9,6 +9,7 @@ + #include "transaction.h" + #include "accessors.h" + #include "dir-item.h" ++#include "delayed-inode.h" + + /* + * insert a name into a directory, doing overflow properly if there is a hash +diff --git a/fs/btrfs/direct-io.c b/fs/btrfs/direct-io.c +index 802d4dbe5b381..8888ef4ae6064 100644 +--- a/fs/btrfs/direct-io.c ++++ b/fs/btrfs/direct-io.c +@@ -10,6 +10,8 @@ + #include "fs.h" + #include "transaction.h" + #include "volumes.h" ++#include "bio.h" ++#include "ordered-data.h" + + struct btrfs_dio_data { + ssize_t submitted; +diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c +index 745ae698bbc8a..3fd5d6a27d4c0 100644 +--- a/fs/btrfs/disk-io.c ++++ b/fs/btrfs/disk-io.c +@@ -50,6 +50,7 @@ + #include "relocation.h" + #include "scrub.h" + #include "super.h" ++#include "delayed-inode.h" + + #define BTRFS_SUPER_FLAG_SUPP (BTRFS_HEADER_FLAG_WRITTEN |\ + BTRFS_HEADER_FLAG_RELOC |\ +diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h +index 57920f2c6fe4e..5320da83d0cf8 100644 +--- a/fs/btrfs/disk-io.h ++++ b/fs/btrfs/disk-io.h +@@ -9,7 +9,8 @@ + #include + #include + #include "ctree.h" +-#include "fs.h" ++#include "bio.h" ++#include "ordered-data.h" + + struct block_device; + struct super_block; +diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c +index dc4ca98c37800..01337e3f2879c 100644 +--- a/fs/btrfs/extent-tree.c ++++ b/fs/btrfs/extent-tree.c +@@ -40,6 +40,7 @@ + #include "orphan.h" + #include "tree-checker.h" + #include "raid-stripe-tree.h" ++#include "delayed-inode.h" + + #undef SCRAMBLE_DELAYED_REFS + +diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h +index 559bec44a7a8e..73571d5d3d5ad 100644 +--- a/fs/btrfs/extent_io.h ++++ b/fs/btrfs/extent_io.h +@@ -12,7 +12,6 @@ + #include + #include + #include +-#include "compression.h" + #include "messages.h" + #include "ulist.h" + #include "misc.h" +diff --git a/fs/btrfs/extent_map.h b/fs/btrfs/extent_map.h +index d4b81ee4d97bd..6f685f3c93272 100644 +--- a/fs/btrfs/extent_map.h ++++ b/fs/btrfs/extent_map.h +@@ -8,8 +8,7 @@ + #include + #include + #include +-#include "misc.h" +-#include "compression.h" ++#include "fs.h" + + struct btrfs_inode; + struct btrfs_fs_info; +diff --git a/fs/btrfs/file-item.h b/fs/btrfs/file-item.h +index 63216c43676de..0d59e830018a6 100644 +--- a/fs/btrfs/file-item.h ++++ b/fs/btrfs/file-item.h +@@ -7,7 +7,7 @@ + #include + #include + #include "ctree.h" +-#include "accessors.h" ++#include "ordered-data.h" + + struct extent_map; + struct btrfs_file_extent_item; +diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c +index 76a66c74249a2..b261dbeb29040 100644 +--- a/fs/btrfs/inode.c ++++ b/fs/btrfs/inode.c +@@ -71,6 +71,7 @@ + #include "backref.h" + #include "raid-stripe-tree.h" + #include "fiemap.h" ++#include "delayed-inode.h" + + #define COW_FILE_RANGE_KEEP_LOCKED (1UL << 0) + #define COW_FILE_RANGE_NO_INLINE (1UL << 1) +diff --git a/fs/btrfs/space-info.c b/fs/btrfs/space-info.c +index a6f94e9f55915..e5c18a29eb7e6 100644 +--- a/fs/btrfs/space-info.c ++++ b/fs/btrfs/space-info.c +@@ -15,6 +15,7 @@ + #include "accessors.h" + #include "extent-tree.h" + #include "zoned.h" ++#include "delayed-inode.h" + + /* + * HOW DOES SPACE RESERVATION WORK +diff --git a/fs/btrfs/subpage.h b/fs/btrfs/subpage.h +index ad0552db7c7dc..d81a0ade559fd 100644 +--- a/fs/btrfs/subpage.h ++++ b/fs/btrfs/subpage.h +@@ -7,7 +7,6 @@ + #include + #include + #include "btrfs_inode.h" +-#include "fs.h" + + struct address_space; + struct folio; +diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c +index c457316c2788b..041f4781956cf 100644 +--- a/fs/btrfs/transaction.c ++++ b/fs/btrfs/transaction.c +@@ -32,6 +32,8 @@ + #include "ioctl.h" + #include "relocation.h" + #include "scrub.h" ++#include "ordered-data.h" ++#include "delayed-inode.h" + + static struct kmem_cache *btrfs_trans_handle_cachep; + +diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h +index 9f7c777af6356..18ef069197e5b 100644 +--- a/fs/btrfs/transaction.h ++++ b/fs/btrfs/transaction.h +@@ -14,10 +14,6 @@ + #include + #include "btrfs_inode.h" + #include "delayed-ref.h" +-#include "extent-io-tree.h" +-#include "block-rsv.h" +-#include "messages.h" +-#include "misc.h" + + struct dentry; + struct inode; +diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c +index ae2e035d013e2..6c5db73c3e85f 100644 +--- a/fs/btrfs/tree-log.c ++++ b/fs/btrfs/tree-log.c +@@ -29,6 +29,7 @@ + #include "orphan.h" + #include "print-tree.h" + #include "tree-checker.h" ++#include "delayed-inode.h" + + #define MAX_CONFLICT_INODES 10 + +diff --git a/fs/btrfs/tree-log.h b/fs/btrfs/tree-log.h +index dc313e6bb2faa..4f149d7d4fdee 100644 +--- a/fs/btrfs/tree-log.h ++++ b/fs/btrfs/tree-log.h +@@ -8,8 +8,7 @@ + + #include + #include +-#include "messages.h" +-#include "ctree.h" ++#include + #include "transaction.h" + + struct inode; +diff --git a/fs/btrfs/zoned.h b/fs/btrfs/zoned.h +index 17c5656580dd9..2b807a02d1a8a 100644 +--- a/fs/btrfs/zoned.h ++++ b/fs/btrfs/zoned.h +@@ -15,7 +15,6 @@ + #include "disk-io.h" + #include "block-group.h" + #include "btrfs_inode.h" +-#include "fs.h" + + struct block_device; + struct extent_buffer; +-- +2.51.0 + diff --git a/queue-6.18/btrfs-introduce-btrfs_bio-async_csum.patch b/queue-6.18/btrfs-introduce-btrfs_bio-async_csum.patch new file mode 100644 index 0000000000..a8a5c4a639 --- /dev/null +++ b/queue-6.18/btrfs-introduce-btrfs_bio-async_csum.patch @@ -0,0 +1,262 @@ +From 69c20363d1e3e00004d0e85f2ea860dd61e0a7b9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Oct 2025 15:08:34 +1030 +Subject: btrfs: introduce btrfs_bio::async_csum + +From: Qu Wenruo + +[ Upstream commit dd57c78aec398717a2fa6488d87b1a6cd43c7d0d ] + +[ENHANCEMENT] +Btrfs currently calculates data checksums then submits the bio. + +But after commit 968f19c5b1b7 ("btrfs: always fallback to buffered write +if the inode requires checksum"), any writes with data checksum will +fallback to buffered IO, meaning the content will not change during +writeback. + +This means we're safe to calculate the data checksum and submit the bio +in parallel, and only need the following new behavior: + +- Wait the csum generation to finish before calling btrfs_bio::end_io() + Or this can lead to use-after-free for the csum generation worker. + +- Save the current bi_iter for csum_one_bio() + As the submission part can advance btrfs_bio::bio.bi_iter, if not + saved csum_one_bio() may got an empty bi_iter and do not generate any + checksum. + + Unfortunately this means we have to increase the size of btrfs_bio for + 16 bytes, but this is still acceptable. + +As usual, such new feature is hidden behind the experimental flag. + +[THEORETIC ANALYZE] +Consider the following theoretic hardware performance, which should be +more or less close to modern mainstream hardware: + + Memory bandwidth: 50GiB/s + CRC32C bandwidth: 45GiB/s + SSD bandwidth: 8GiB/s + +Then write bandwidth with data checksum before the patch is: + + 1 / ( 1 / 50 + 1 / 45 + 1 / 8) = 5.98 GiB/s + +After the patch, the bandwidth is: + + 1 / ( 1 / 50 + max( 1 / 45 + 1 / 8)) = 6.90 GiB/s + +The difference is 15.32% improvement. + +[REAL WORLD BENCHMARK] +I'm using a Zen5 (HX 370) as the host, the VM has 4GiB memory, 10 vCPUs, the +storage is backed by a PCIe gen3 x4 NVMe. + +The test is a direct IO write, with 1MiB block size, write 7GiB data +into a btrfs mount with data checksum. Thus the direct write will +fallback to buffered one: + +Vanilla Datasum: 1619.97 GiB/s +Patched Datasum: 1792.26 GiB/s +Diff +10.6 % + +In my case, the bottleneck is the storage, thus the improvement is not +reaching the theoretic one, but still some observable improvement. + +Signed-off-by: Qu Wenruo +Signed-off-by: David Sterba +Stable-dep-of: b39b26e017c7 ("btrfs: zoned: don't zone append to conventional zone") +Signed-off-by: Sasha Levin +--- + fs/btrfs/bio.c | 21 ++++++++++++---- + fs/btrfs/bio.h | 7 ++++++ + fs/btrfs/file-item.c | 60 +++++++++++++++++++++++++++++++------------- + fs/btrfs/file-item.h | 2 +- + 4 files changed, 67 insertions(+), 23 deletions(-) + +diff --git a/fs/btrfs/bio.c b/fs/btrfs/bio.c +index 52b8893f26f16..1286c1ac19404 100644 +--- a/fs/btrfs/bio.c ++++ b/fs/btrfs/bio.c +@@ -105,6 +105,9 @@ void btrfs_bio_end_io(struct btrfs_bio *bbio, blk_status_t status) + /* Make sure we're already in task context. */ + ASSERT(in_task()); + ++ if (bbio->async_csum) ++ wait_for_completion(&bbio->csum_done); ++ + bbio->bio.bi_status = status; + if (bbio->bio.bi_pool == &btrfs_clone_bioset) { + struct btrfs_bio *orig_bbio = bbio->private; +@@ -538,7 +541,11 @@ static int btrfs_bio_csum(struct btrfs_bio *bbio) + { + if (bbio->bio.bi_opf & REQ_META) + return btree_csum_one_bio(bbio); +- return btrfs_csum_one_bio(bbio); ++#ifdef CONFIG_BTRFS_EXPERIMENTAL ++ return btrfs_csum_one_bio(bbio, true); ++#else ++ return btrfs_csum_one_bio(bbio, false); ++#endif + } + + /* +@@ -617,10 +624,14 @@ static bool should_async_write(struct btrfs_bio *bbio) + struct btrfs_fs_devices *fs_devices = fs_info->fs_devices; + enum btrfs_offload_csum_mode csum_mode = READ_ONCE(fs_devices->offload_csum_mode); + +- if (csum_mode == BTRFS_OFFLOAD_CSUM_FORCE_OFF) +- return false; +- +- auto_csum_mode = (csum_mode == BTRFS_OFFLOAD_CSUM_AUTO); ++ if (csum_mode == BTRFS_OFFLOAD_CSUM_FORCE_ON) ++ return true; ++ /* ++ * Write bios will calculate checksum and submit bio at the same time. ++ * Unless explicitly required don't offload serial csum calculate and bio ++ * submit into a workqueue. ++ */ ++ return false; + #endif + + /* Submit synchronously if the checksum implementation is fast. */ +diff --git a/fs/btrfs/bio.h b/fs/btrfs/bio.h +index b7a0de6f97840..9a44b86d561b1 100644 +--- a/fs/btrfs/bio.h ++++ b/fs/btrfs/bio.h +@@ -63,6 +63,9 @@ struct btrfs_bio { + struct { + struct btrfs_ordered_extent *ordered; + struct btrfs_ordered_sum *sums; ++ struct work_struct csum_work; ++ struct completion csum_done; ++ struct bvec_iter csum_saved_iter; + u64 orig_physical; + }; + +@@ -90,6 +93,10 @@ struct btrfs_bio { + * scrub bios. + */ + bool is_scrub; ++ ++ /* Whether the csum generation for data write is async. */ ++ bool async_csum; ++ + /* + * This member must come last, bio_alloc_bioset will allocate enough + * bytes for entire btrfs_bio but relies on bio being last. +diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c +index a42e6d54e7cd7..4b7c40f05e8f9 100644 +--- a/fs/btrfs/file-item.c ++++ b/fs/btrfs/file-item.c +@@ -18,6 +18,7 @@ + #include "fs.h" + #include "accessors.h" + #include "file-item.h" ++#include "volumes.h" + + #define __MAX_CSUM_ITEMS(r, size) ((unsigned long)(((BTRFS_LEAF_DATA_SIZE(r) - \ + sizeof(struct btrfs_item) * 2) / \ +@@ -764,21 +765,46 @@ int btrfs_lookup_csums_bitmap(struct btrfs_root *root, struct btrfs_path *path, + return ret; + } + ++static void csum_one_bio(struct btrfs_bio *bbio, struct bvec_iter *src) ++{ ++ struct btrfs_inode *inode = bbio->inode; ++ struct btrfs_fs_info *fs_info = inode->root->fs_info; ++ SHASH_DESC_ON_STACK(shash, fs_info->csum_shash); ++ struct bio *bio = &bbio->bio; ++ struct btrfs_ordered_sum *sums = bbio->sums; ++ struct bvec_iter iter = *src; ++ phys_addr_t paddr; ++ const u32 blocksize = fs_info->sectorsize; ++ int index = 0; ++ ++ shash->tfm = fs_info->csum_shash; ++ ++ btrfs_bio_for_each_block(paddr, bio, &iter, blocksize) { ++ btrfs_calculate_block_csum(fs_info, paddr, sums->sums + index); ++ index += fs_info->csum_size; ++ } ++} ++ ++static void csum_one_bio_work(struct work_struct *work) ++{ ++ struct btrfs_bio *bbio = container_of(work, struct btrfs_bio, csum_work); ++ ++ ASSERT(btrfs_op(&bbio->bio) == BTRFS_MAP_WRITE); ++ ASSERT(bbio->async_csum == true); ++ csum_one_bio(bbio, &bbio->csum_saved_iter); ++ complete(&bbio->csum_done); ++} ++ + /* + * Calculate checksums of the data contained inside a bio. + */ +-int btrfs_csum_one_bio(struct btrfs_bio *bbio) ++int btrfs_csum_one_bio(struct btrfs_bio *bbio, bool async) + { + struct btrfs_ordered_extent *ordered = bbio->ordered; + struct btrfs_inode *inode = bbio->inode; + struct btrfs_fs_info *fs_info = inode->root->fs_info; +- SHASH_DESC_ON_STACK(shash, fs_info->csum_shash); + struct bio *bio = &bbio->bio; + struct btrfs_ordered_sum *sums; +- struct bvec_iter iter = bio->bi_iter; +- phys_addr_t paddr; +- const u32 blocksize = fs_info->sectorsize; +- int index; + unsigned nofs_flag; + + nofs_flag = memalloc_nofs_save(); +@@ -789,21 +815,21 @@ int btrfs_csum_one_bio(struct btrfs_bio *bbio) + if (!sums) + return -ENOMEM; + ++ sums->logical = bio->bi_iter.bi_sector << SECTOR_SHIFT; + sums->len = bio->bi_iter.bi_size; + INIT_LIST_HEAD(&sums->list); +- +- sums->logical = bio->bi_iter.bi_sector << SECTOR_SHIFT; +- index = 0; +- +- shash->tfm = fs_info->csum_shash; +- +- btrfs_bio_for_each_block(paddr, bio, &iter, blocksize) { +- btrfs_calculate_block_csum(fs_info, paddr, sums->sums + index); +- index += fs_info->csum_size; +- } +- + bbio->sums = sums; + btrfs_add_ordered_sum(ordered, sums); ++ ++ if (!async) { ++ csum_one_bio(bbio, &bbio->bio.bi_iter); ++ return 0; ++ } ++ init_completion(&bbio->csum_done); ++ bbio->async_csum = true; ++ bbio->csum_saved_iter = bbio->bio.bi_iter; ++ INIT_WORK(&bbio->csum_work, csum_one_bio_work); ++ schedule_work(&bbio->csum_work); + return 0; + } + +diff --git a/fs/btrfs/file-item.h b/fs/btrfs/file-item.h +index 0d59e830018a6..5645c5e3abdb7 100644 +--- a/fs/btrfs/file-item.h ++++ b/fs/btrfs/file-item.h +@@ -64,7 +64,7 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, + int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, + struct btrfs_root *root, + struct btrfs_ordered_sum *sums); +-int btrfs_csum_one_bio(struct btrfs_bio *bbio); ++int btrfs_csum_one_bio(struct btrfs_bio *bbio, bool async); + int btrfs_alloc_dummy_sum(struct btrfs_bio *bbio); + int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, + struct list_head *list, int search_commit, +-- +2.51.0 + diff --git a/queue-6.18/btrfs-make-sure-all-btrfs_bio-end_io-are-called-in-t.patch b/queue-6.18/btrfs-make-sure-all-btrfs_bio-end_io-are-called-in-t.patch new file mode 100644 index 0000000000..b200266553 --- /dev/null +++ b/queue-6.18/btrfs-make-sure-all-btrfs_bio-end_io-are-called-in-t.patch @@ -0,0 +1,200 @@ +From 9a6d68b39e3bc4c0c41a4262b9a800e828974305 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Oct 2025 15:19:16 +1030 +Subject: btrfs: make sure all btrfs_bio::end_io are called in task context + +From: Qu Wenruo + +[ Upstream commit 4591c3ef751d861d7dd95ff4d2aadb1b5e95854e ] + +[BACKGROUND] +Btrfs has a lot of different bi_end_io functions, to handle different +raid profiles. But they introduced a lot of different contexts for +btrfs_bio::end_io() calls: + +- Simple read bios + Run in task context, backed by either endio_meta_workers or + endio_workers. + +- Simple write bios + Run in IRQ context. + +- RAID56 write or rebuild bios + Run in task context, backed by rmw_workers. + +- Mirrored write bios + Run in irq context. + +This is inconsistent, and contributes to the number of workqueues used +in btrfs. + +[ENHANCEMENT] +Make all the above bios call their btrfs_bio::end_io() in task context, +backed by either endio_meta_workers for metadata, or endio_workers for +data. + +For simple write bios, merge the handling into simple_end_io_work(). + +For mirrored write bios, it will be a little more complex, since both +the original or the cloned bios can run the final btrfs_bio::end_io(). + +Here we make sure the cloned bios are using btrfs_bioset, to reuse the +end_io_work, and run both original and cloned work inside the workqueue. + +Add extra ASSERT()s to make sure btrfs_bio_end_io() is running in task +context. + +This not only unifies the context for btrfs_bio::end_io() functions, but +also opens a new door for further btrfs_bio::end_io() related cleanups. + +Signed-off-by: Qu Wenruo +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Stable-dep-of: b39b26e017c7 ("btrfs: zoned: don't zone append to conventional zone") +Signed-off-by: Sasha Levin +--- + fs/btrfs/bio.c | 64 ++++++++++++++++++++++++++++++++++++-------------- + 1 file changed, 46 insertions(+), 18 deletions(-) + +diff --git a/fs/btrfs/bio.c b/fs/btrfs/bio.c +index b85b6b21b5450..52b8893f26f16 100644 +--- a/fs/btrfs/bio.c ++++ b/fs/btrfs/bio.c +@@ -102,6 +102,9 @@ static struct btrfs_bio *btrfs_split_bio(struct btrfs_fs_info *fs_info, + + void btrfs_bio_end_io(struct btrfs_bio *bbio, blk_status_t status) + { ++ /* Make sure we're already in task context. */ ++ ASSERT(in_task()); ++ + bbio->bio.bi_status = status; + if (bbio->bio.bi_pool == &btrfs_clone_bioset) { + struct btrfs_bio *orig_bbio = bbio->private; +@@ -318,15 +321,20 @@ static struct workqueue_struct *btrfs_end_io_wq(const struct btrfs_fs_info *fs_i + return fs_info->endio_workers; + } + +-static void btrfs_end_bio_work(struct work_struct *work) ++static void simple_end_io_work(struct work_struct *work) + { + struct btrfs_bio *bbio = container_of(work, struct btrfs_bio, end_io_work); ++ struct bio *bio = &bbio->bio; + +- /* Metadata reads are checked and repaired by the submitter. */ +- if (is_data_bbio(bbio)) +- btrfs_check_read_bio(bbio, bbio->bio.bi_private); +- else +- btrfs_bio_end_io(bbio, bbio->bio.bi_status); ++ if (bio_op(bio) == REQ_OP_READ) { ++ /* Metadata reads are checked and repaired by the submitter. */ ++ if (is_data_bbio(bbio)) ++ return btrfs_check_read_bio(bbio, bbio->bio.bi_private); ++ return btrfs_bio_end_io(bbio, bbio->bio.bi_status); ++ } ++ if (bio_is_zone_append(bio) && !bio->bi_status) ++ btrfs_record_physical_zoned(bbio); ++ btrfs_bio_end_io(bbio, bbio->bio.bi_status); + } + + static void btrfs_simple_end_io(struct bio *bio) +@@ -340,14 +348,8 @@ static void btrfs_simple_end_io(struct bio *bio) + if (bio->bi_status) + btrfs_log_dev_io_error(bio, dev); + +- if (bio_op(bio) == REQ_OP_READ) { +- INIT_WORK(&bbio->end_io_work, btrfs_end_bio_work); +- queue_work(btrfs_end_io_wq(fs_info, bio), &bbio->end_io_work); +- } else { +- if (bio_is_zone_append(bio) && !bio->bi_status) +- btrfs_record_physical_zoned(bbio); +- btrfs_bio_end_io(bbio, bbio->bio.bi_status); +- } ++ INIT_WORK(&bbio->end_io_work, simple_end_io_work); ++ queue_work(btrfs_end_io_wq(fs_info, bio), &bbio->end_io_work); + } + + static void btrfs_raid56_end_io(struct bio *bio) +@@ -355,6 +357,9 @@ static void btrfs_raid56_end_io(struct bio *bio) + struct btrfs_io_context *bioc = bio->bi_private; + struct btrfs_bio *bbio = btrfs_bio(bio); + ++ /* RAID56 endio is always handled in workqueue. */ ++ ASSERT(in_task()); ++ + btrfs_bio_counter_dec(bioc->fs_info); + bbio->mirror_num = bioc->mirror_num; + if (bio_op(bio) == REQ_OP_READ && is_data_bbio(bbio)) +@@ -365,11 +370,12 @@ static void btrfs_raid56_end_io(struct bio *bio) + btrfs_put_bioc(bioc); + } + +-static void btrfs_orig_write_end_io(struct bio *bio) ++static void orig_write_end_io_work(struct work_struct *work) + { ++ struct btrfs_bio *bbio = container_of(work, struct btrfs_bio, end_io_work); ++ struct bio *bio = &bbio->bio; + struct btrfs_io_stripe *stripe = bio->bi_private; + struct btrfs_io_context *bioc = stripe->bioc; +- struct btrfs_bio *bbio = btrfs_bio(bio); + + btrfs_bio_counter_dec(bioc->fs_info); + +@@ -394,8 +400,18 @@ static void btrfs_orig_write_end_io(struct bio *bio) + btrfs_put_bioc(bioc); + } + +-static void btrfs_clone_write_end_io(struct bio *bio) ++static void btrfs_orig_write_end_io(struct bio *bio) ++{ ++ struct btrfs_bio *bbio = btrfs_bio(bio); ++ ++ INIT_WORK(&bbio->end_io_work, orig_write_end_io_work); ++ queue_work(btrfs_end_io_wq(bbio->inode->root->fs_info, bio), &bbio->end_io_work); ++} ++ ++static void clone_write_end_io_work(struct work_struct *work) + { ++ struct btrfs_bio *bbio = container_of(work, struct btrfs_bio, end_io_work); ++ struct bio *bio = &bbio->bio; + struct btrfs_io_stripe *stripe = bio->bi_private; + + if (bio->bi_status) { +@@ -410,6 +426,14 @@ static void btrfs_clone_write_end_io(struct bio *bio) + bio_put(bio); + } + ++static void btrfs_clone_write_end_io(struct bio *bio) ++{ ++ struct btrfs_bio *bbio = btrfs_bio(bio); ++ ++ INIT_WORK(&bbio->end_io_work, clone_write_end_io_work); ++ queue_work(btrfs_end_io_wq(bbio->inode->root->fs_info, bio), &bbio->end_io_work); ++} ++ + static void btrfs_submit_dev_bio(struct btrfs_device *dev, struct bio *bio) + { + if (!dev || !dev->bdev || +@@ -456,6 +480,7 @@ static void btrfs_submit_dev_bio(struct btrfs_device *dev, struct bio *bio) + static void btrfs_submit_mirrored_bio(struct btrfs_io_context *bioc, int dev_nr) + { + struct bio *orig_bio = bioc->orig_bio, *bio; ++ struct btrfs_bio *orig_bbio = btrfs_bio(orig_bio); + + ASSERT(bio_op(orig_bio) != REQ_OP_READ); + +@@ -464,8 +489,11 @@ static void btrfs_submit_mirrored_bio(struct btrfs_io_context *bioc, int dev_nr) + bio = orig_bio; + bio->bi_end_io = btrfs_orig_write_end_io; + } else { +- bio = bio_alloc_clone(NULL, orig_bio, GFP_NOFS, &fs_bio_set); ++ /* We need to use endio_work to run end_io in task context. */ ++ bio = bio_alloc_clone(NULL, orig_bio, GFP_NOFS, &btrfs_bioset); + bio_inc_remaining(orig_bio); ++ btrfs_bio_init(btrfs_bio(bio), orig_bbio->inode, ++ orig_bbio->file_offset, NULL, NULL); + bio->bi_end_io = btrfs_clone_write_end_io; + } + +-- +2.51.0 + diff --git a/queue-6.18/btrfs-qgroup-return-correct-error-when-deleting-qgro.patch b/queue-6.18/btrfs-qgroup-return-correct-error-when-deleting-qgro.patch new file mode 100644 index 0000000000..ae704daee2 --- /dev/null +++ b/queue-6.18/btrfs-qgroup-return-correct-error-when-deleting-qgro.patch @@ -0,0 +1,43 @@ +From eecfcca071d462f8699978f5ff2a2dab7ce72b42 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 19:35:23 +0000 +Subject: btrfs: qgroup: return correct error when deleting qgroup relation + item + +From: Filipe Manana + +[ Upstream commit 51b1fcf71c88c3c89e7dcf07869c5de837b1f428 ] + +If we fail to delete the second qgroup relation item, we end up returning +success or -ENOENT in case the first item does not exist, instead of +returning the error from the second item deletion. + +Fixes: 73798c465b66 ("btrfs: qgroup: Try our best to delete qgroup relations") +Reviewed-by: Johannes Thumshirn +Signed-off-by: Filipe Manana +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/qgroup.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c +index febc22d1b6487..7a1dd250e92c0 100644 +--- a/fs/btrfs/qgroup.c ++++ b/fs/btrfs/qgroup.c +@@ -1627,8 +1627,10 @@ static int __del_qgroup_relation(struct btrfs_trans_handle *trans, u64 src, + if (ret < 0 && ret != -ENOENT) + goto out; + ret2 = del_qgroup_relation_item(trans, dst, src); +- if (ret2 < 0 && ret2 != -ENOENT) ++ if (ret2 < 0 && ret2 != -ENOENT) { ++ ret = ret2; + goto out; ++ } + + /* At least one deletion succeeded, return 0 */ + if (!ret || !ret2) +-- +2.51.0 + diff --git a/queue-6.18/btrfs-remove-btrfs_bio-fs_info-by-extracting-it-from.patch b/queue-6.18/btrfs-remove-btrfs_bio-fs_info-by-extracting-it-from.patch new file mode 100644 index 0000000000..4d7d13fe49 --- /dev/null +++ b/queue-6.18/btrfs-remove-btrfs_bio-fs_info-by-extracting-it-from.patch @@ -0,0 +1,584 @@ +From 0de0eefeb97207a5ee1e5897022952942e7389c3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Oct 2025 08:35:33 +1030 +Subject: btrfs: remove btrfs_bio::fs_info by extracting it from + btrfs_bio::inode + +From: Qu Wenruo + +[ Upstream commit 81cea6cd7041ebd42281e0517f856d88527d3326 ] + +Currently there is only one caller which doesn't populate +btrfs_bio::inode, and that's scrub. + +The idea is scrub doesn't want any automatic csum verification nor +read-repair, as everything will be handled by scrub itself. + +However that behavior is really no different than metadata inode, thus +we can reuse btree_inode as btrfs_bio::inode for scrub. + +The only exception is in btrfs_submit_chunk() where if a bbio is from +scrub or data reloc inode, we set rst_search_commit_root to true. +This means we still need a way to distinguish scrub from metadata, but +that can be done by a new flag inside btrfs_bio. + +Now btrfs_bio::inode is a mandatory parameter, we can extract fs_info +from that inode thus can remove btrfs_bio::fs_info to save 8 bytes from +btrfs_bio structure. + +Signed-off-by: Qu Wenruo +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Stable-dep-of: b39b26e017c7 ("btrfs: zoned: don't zone append to conventional zone") +Signed-off-by: Sasha Levin +--- + fs/btrfs/bio.c | 53 ++++++++++++++++++++++-------------------- + fs/btrfs/bio.h | 18 +++++++++----- + fs/btrfs/compression.c | 6 ++--- + fs/btrfs/compression.h | 3 ++- + fs/btrfs/direct-io.c | 4 +--- + fs/btrfs/extent_io.c | 22 +++++++----------- + fs/btrfs/inode.c | 7 ++---- + fs/btrfs/scrub.c | 51 ++++++++++++++++++++++------------------ + fs/btrfs/zoned.c | 4 ++-- + 9 files changed, 87 insertions(+), 81 deletions(-) + +diff --git a/fs/btrfs/bio.c b/fs/btrfs/bio.c +index 21df48e6c4fa2..b85b6b21b5450 100644 +--- a/fs/btrfs/bio.c ++++ b/fs/btrfs/bio.c +@@ -41,13 +41,17 @@ static bool bbio_has_ordered_extent(const struct btrfs_bio *bbio) + * Initialize a btrfs_bio structure. This skips the embedded bio itself as it + * is already initialized by the block layer. + */ +-void btrfs_bio_init(struct btrfs_bio *bbio, struct btrfs_fs_info *fs_info, ++void btrfs_bio_init(struct btrfs_bio *bbio, struct btrfs_inode *inode, u64 file_offset, + btrfs_bio_end_io_t end_io, void *private) + { ++ /* @inode parameter is mandatory. */ ++ ASSERT(inode); ++ + memset(bbio, 0, offsetof(struct btrfs_bio, bio)); +- bbio->fs_info = fs_info; ++ bbio->inode = inode; + bbio->end_io = end_io; + bbio->private = private; ++ bbio->file_offset = file_offset; + atomic_set(&bbio->pending_ios, 1); + WRITE_ONCE(bbio->status, BLK_STS_OK); + } +@@ -60,7 +64,7 @@ void btrfs_bio_init(struct btrfs_bio *bbio, struct btrfs_fs_info *fs_info, + * a mempool. + */ + struct btrfs_bio *btrfs_bio_alloc(unsigned int nr_vecs, blk_opf_t opf, +- struct btrfs_fs_info *fs_info, ++ struct btrfs_inode *inode, u64 file_offset, + btrfs_bio_end_io_t end_io, void *private) + { + struct btrfs_bio *bbio; +@@ -68,7 +72,7 @@ struct btrfs_bio *btrfs_bio_alloc(unsigned int nr_vecs, blk_opf_t opf, + + bio = bio_alloc_bioset(NULL, nr_vecs, opf, GFP_NOFS, &btrfs_bioset); + bbio = btrfs_bio(bio); +- btrfs_bio_init(bbio, fs_info, end_io, private); ++ btrfs_bio_init(bbio, inode, file_offset, end_io, private); + return bbio; + } + +@@ -85,9 +89,7 @@ static struct btrfs_bio *btrfs_split_bio(struct btrfs_fs_info *fs_info, + return ERR_CAST(bio); + + bbio = btrfs_bio(bio); +- btrfs_bio_init(bbio, fs_info, NULL, orig_bbio); +- bbio->inode = orig_bbio->inode; +- bbio->file_offset = orig_bbio->file_offset; ++ btrfs_bio_init(bbio, orig_bbio->inode, orig_bbio->file_offset, NULL, orig_bbio); + orig_bbio->file_offset += map_length; + if (bbio_has_ordered_extent(bbio)) { + refcount_inc(&orig_bbio->ordered->refs); +@@ -244,9 +246,8 @@ static struct btrfs_failed_bio *repair_one_sector(struct btrfs_bio *failed_bbio, + bio_add_folio_nofail(repair_bio, folio, sectorsize, foff); + + repair_bbio = btrfs_bio(repair_bio); +- btrfs_bio_init(repair_bbio, fs_info, NULL, fbio); +- repair_bbio->inode = failed_bbio->inode; +- repair_bbio->file_offset = failed_bbio->file_offset + bio_offset; ++ btrfs_bio_init(repair_bbio, failed_bbio->inode, failed_bbio->file_offset + bio_offset, ++ NULL, fbio); + + mirror = next_repair_mirror(fbio, failed_bbio->mirror_num); + btrfs_debug(fs_info, "submitting repair read to mirror %d", mirror); +@@ -332,7 +333,7 @@ static void btrfs_simple_end_io(struct bio *bio) + { + struct btrfs_bio *bbio = btrfs_bio(bio); + struct btrfs_device *dev = bio->bi_private; +- struct btrfs_fs_info *fs_info = bbio->fs_info; ++ struct btrfs_fs_info *fs_info = bbio->inode->root->fs_info; + + btrfs_bio_counter_dec(fs_info); + +@@ -581,10 +582,11 @@ static void run_one_async_done(struct btrfs_work *work, bool do_free) + + static bool should_async_write(struct btrfs_bio *bbio) + { ++ struct btrfs_fs_info *fs_info = bbio->inode->root->fs_info; + bool auto_csum_mode = true; + + #ifdef CONFIG_BTRFS_EXPERIMENTAL +- struct btrfs_fs_devices *fs_devices = bbio->fs_info->fs_devices; ++ struct btrfs_fs_devices *fs_devices = fs_info->fs_devices; + enum btrfs_offload_csum_mode csum_mode = READ_ONCE(fs_devices->offload_csum_mode); + + if (csum_mode == BTRFS_OFFLOAD_CSUM_FORCE_OFF) +@@ -594,7 +596,7 @@ static bool should_async_write(struct btrfs_bio *bbio) + #endif + + /* Submit synchronously if the checksum implementation is fast. */ +- if (auto_csum_mode && test_bit(BTRFS_FS_CSUM_IMPL_FAST, &bbio->fs_info->flags)) ++ if (auto_csum_mode && test_bit(BTRFS_FS_CSUM_IMPL_FAST, &fs_info->flags)) + return false; + + /* +@@ -605,7 +607,7 @@ static bool should_async_write(struct btrfs_bio *bbio) + return false; + + /* Zoned devices require I/O to be submitted in order. */ +- if ((bbio->bio.bi_opf & REQ_META) && btrfs_is_zoned(bbio->fs_info)) ++ if ((bbio->bio.bi_opf & REQ_META) && btrfs_is_zoned(fs_info)) + return false; + + return true; +@@ -620,7 +622,7 @@ static bool btrfs_wq_submit_bio(struct btrfs_bio *bbio, + struct btrfs_io_context *bioc, + struct btrfs_io_stripe *smap, int mirror_num) + { +- struct btrfs_fs_info *fs_info = bbio->fs_info; ++ struct btrfs_fs_info *fs_info = bbio->inode->root->fs_info; + struct async_submit_bio *async; + + async = kmalloc(sizeof(*async), GFP_NOFS); +@@ -639,11 +641,12 @@ static bool btrfs_wq_submit_bio(struct btrfs_bio *bbio, + + static u64 btrfs_append_map_length(struct btrfs_bio *bbio, u64 map_length) + { ++ struct btrfs_fs_info *fs_info = bbio->inode->root->fs_info; + unsigned int nr_segs; + int sector_offset; + +- map_length = min(map_length, bbio->fs_info->max_zone_append_size); +- sector_offset = bio_split_rw_at(&bbio->bio, &bbio->fs_info->limits, ++ map_length = min(map_length, fs_info->max_zone_append_size); ++ sector_offset = bio_split_rw_at(&bbio->bio, &fs_info->limits, + &nr_segs, map_length); + if (sector_offset) { + /* +@@ -651,7 +654,7 @@ static u64 btrfs_append_map_length(struct btrfs_bio *bbio, u64 map_length) + * sectorsize and thus cause unaligned I/Os. Fix that by + * always rounding down to the nearest boundary. + */ +- return ALIGN_DOWN(sector_offset << SECTOR_SHIFT, bbio->fs_info->sectorsize); ++ return ALIGN_DOWN(sector_offset << SECTOR_SHIFT, fs_info->sectorsize); + } + return map_length; + } +@@ -659,7 +662,7 @@ static u64 btrfs_append_map_length(struct btrfs_bio *bbio, u64 map_length) + static bool btrfs_submit_chunk(struct btrfs_bio *bbio, int mirror_num) + { + struct btrfs_inode *inode = bbio->inode; +- struct btrfs_fs_info *fs_info = bbio->fs_info; ++ struct btrfs_fs_info *fs_info = inode->root->fs_info; + struct bio *bio = &bbio->bio; + u64 logical = bio->bi_iter.bi_sector << SECTOR_SHIFT; + u64 length = bio->bi_iter.bi_size; +@@ -670,7 +673,7 @@ static bool btrfs_submit_chunk(struct btrfs_bio *bbio, int mirror_num) + blk_status_t status; + int ret; + +- if (!bbio->inode || btrfs_is_data_reloc_root(inode->root)) ++ if (bbio->is_scrub || btrfs_is_data_reloc_root(inode->root)) + smap.rst_search_commit_root = true; + else + smap.rst_search_commit_root = false; +@@ -734,7 +737,7 @@ static bool btrfs_submit_chunk(struct btrfs_bio *bbio, int mirror_num) + * Csum items for reloc roots have already been cloned at this + * point, so they are handled as part of the no-checksum case. + */ +- if (inode && !(inode->flags & BTRFS_INODE_NODATASUM) && ++ if (!(inode->flags & BTRFS_INODE_NODATASUM) && + !test_bit(BTRFS_FS_STATE_NO_DATA_CSUMS, &fs_info->fs_state) && + !btrfs_is_data_reloc_root(inode->root)) { + if (should_async_write(bbio) && +@@ -782,7 +785,7 @@ static bool btrfs_submit_chunk(struct btrfs_bio *bbio, int mirror_num) + static void assert_bbio_alignment(struct btrfs_bio *bbio) + { + #ifdef CONFIG_BTRFS_ASSERT +- struct btrfs_fs_info *fs_info = bbio->fs_info; ++ struct btrfs_fs_info *fs_info = bbio->inode->root->fs_info; + struct bio_vec bvec; + struct bvec_iter iter; + const u32 blocksize = fs_info->sectorsize; +@@ -885,16 +888,16 @@ int btrfs_repair_io_failure(struct btrfs_fs_info *fs_info, u64 ino, u64 start, + */ + void btrfs_submit_repair_write(struct btrfs_bio *bbio, int mirror_num, bool dev_replace) + { +- struct btrfs_fs_info *fs_info = bbio->fs_info; ++ struct btrfs_fs_info *fs_info = bbio->inode->root->fs_info; + u64 logical = bbio->bio.bi_iter.bi_sector << SECTOR_SHIFT; + u64 length = bbio->bio.bi_iter.bi_size; + struct btrfs_io_stripe smap = { 0 }; + int ret; + +- ASSERT(fs_info); + ASSERT(mirror_num > 0); + ASSERT(btrfs_op(&bbio->bio) == BTRFS_MAP_WRITE); +- ASSERT(!bbio->inode); ++ ASSERT(!is_data_inode(bbio->inode)); ++ ASSERT(bbio->is_scrub); + + btrfs_bio_counter_inc_blocked(fs_info); + ret = btrfs_map_repair_block(fs_info, &smap, logical, length, mirror_num); +diff --git a/fs/btrfs/bio.h b/fs/btrfs/bio.h +index 00883aea55d70..b7a0de6f97840 100644 +--- a/fs/btrfs/bio.h ++++ b/fs/btrfs/bio.h +@@ -34,7 +34,10 @@ typedef void (*btrfs_bio_end_io_t)(struct btrfs_bio *bbio); + struct btrfs_bio { + /* + * Inode and offset into it that this I/O operates on. +- * Only set for data I/O. ++ * ++ * If the inode is a data one, csum verification and read-repair ++ * will be done automatically. ++ * If the inode is a metadata one, everything is handled by the caller. + */ + struct btrfs_inode *inode; + u64 file_offset; +@@ -76,14 +79,17 @@ struct btrfs_bio { + atomic_t pending_ios; + struct work_struct end_io_work; + +- /* File system that this I/O operates on. */ +- struct btrfs_fs_info *fs_info; +- + /* Save the first error status of split bio. */ + blk_status_t status; + + /* Use the commit root to look up csums (data read bio only). */ + bool csum_search_commit_root; ++ ++ /* ++ * Since scrub will reuse btree inode, we need this flag to distinguish ++ * scrub bios. ++ */ ++ bool is_scrub; + /* + * This member must come last, bio_alloc_bioset will allocate enough + * bytes for entire btrfs_bio but relies on bio being last. +@@ -99,10 +105,10 @@ static inline struct btrfs_bio *btrfs_bio(struct bio *bio) + int __init btrfs_bioset_init(void); + void __cold btrfs_bioset_exit(void); + +-void btrfs_bio_init(struct btrfs_bio *bbio, struct btrfs_fs_info *fs_info, ++void btrfs_bio_init(struct btrfs_bio *bbio, struct btrfs_inode *inode, u64 file_offset, + btrfs_bio_end_io_t end_io, void *private); + struct btrfs_bio *btrfs_bio_alloc(unsigned int nr_vecs, blk_opf_t opf, +- struct btrfs_fs_info *fs_info, ++ struct btrfs_inode *inode, u64 file_offset, + btrfs_bio_end_io_t end_io, void *private); + void btrfs_bio_end_io(struct btrfs_bio *bbio, blk_status_t status); + +diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c +index bacad18357b33..8c3899832a1aa 100644 +--- a/fs/btrfs/compression.c ++++ b/fs/btrfs/compression.c +@@ -67,9 +67,7 @@ static struct compressed_bio *alloc_compressed_bio(struct btrfs_inode *inode, + + bbio = btrfs_bio(bio_alloc_bioset(NULL, BTRFS_MAX_COMPRESSED_PAGES, op, + GFP_NOFS, &btrfs_compressed_bioset)); +- btrfs_bio_init(bbio, inode->root->fs_info, end_io, NULL); +- bbio->inode = inode; +- bbio->file_offset = start; ++ btrfs_bio_init(bbio, inode, start, end_io, NULL); + return to_compressed_bio(bbio); + } + +@@ -354,7 +352,7 @@ static void end_bbio_compressed_write(struct btrfs_bio *bbio) + + static void btrfs_add_compressed_bio_folios(struct compressed_bio *cb) + { +- struct btrfs_fs_info *fs_info = cb->bbio.fs_info; ++ struct btrfs_fs_info *fs_info = cb->bbio.inode->root->fs_info; + struct bio *bio = &cb->bbio.bio; + u32 offset = 0; + +diff --git a/fs/btrfs/compression.h b/fs/btrfs/compression.h +index c6812d5fcab79..062ebd9c2d32d 100644 +--- a/fs/btrfs/compression.h ++++ b/fs/btrfs/compression.h +@@ -14,6 +14,7 @@ + #include + #include "bio.h" + #include "fs.h" ++#include "btrfs_inode.h" + + struct address_space; + struct inode; +@@ -74,7 +75,7 @@ struct compressed_bio { + + static inline struct btrfs_fs_info *cb_to_fs_info(const struct compressed_bio *cb) + { +- return cb->bbio.fs_info; ++ return cb->bbio.inode->root->fs_info; + } + + /* @range_end must be exclusive. */ +diff --git a/fs/btrfs/direct-io.c b/fs/btrfs/direct-io.c +index 8888ef4ae6064..e29ea28ce90b9 100644 +--- a/fs/btrfs/direct-io.c ++++ b/fs/btrfs/direct-io.c +@@ -715,10 +715,8 @@ static void btrfs_dio_submit_io(const struct iomap_iter *iter, struct bio *bio, + container_of(bbio, struct btrfs_dio_private, bbio); + struct btrfs_dio_data *dio_data = iter->private; + +- btrfs_bio_init(bbio, BTRFS_I(iter->inode)->root->fs_info, ++ btrfs_bio_init(bbio, BTRFS_I(iter->inode), file_offset, + btrfs_dio_end_io, bio->bi_private); +- bbio->inode = BTRFS_I(iter->inode); +- bbio->file_offset = file_offset; + + dip->file_offset = file_offset; + dip->bytes = bio->bi_iter.bi_size; +diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c +index e6ffa12f57535..c3524401ff03e 100644 +--- a/fs/btrfs/extent_io.c ++++ b/fs/btrfs/extent_io.c +@@ -518,7 +518,7 @@ static void end_folio_read(struct folio *folio, bool uptodate, u64 start, u32 le + */ + static void end_bbio_data_write(struct btrfs_bio *bbio) + { +- struct btrfs_fs_info *fs_info = bbio->fs_info; ++ struct btrfs_fs_info *fs_info = bbio->inode->root->fs_info; + struct bio *bio = &bbio->bio; + int error = blk_status_to_errno(bio->bi_status); + struct folio_iter fi; +@@ -574,7 +574,7 @@ static void begin_folio_read(struct btrfs_fs_info *fs_info, struct folio *folio) + */ + static void end_bbio_data_read(struct btrfs_bio *bbio) + { +- struct btrfs_fs_info *fs_info = bbio->fs_info; ++ struct btrfs_fs_info *fs_info = bbio->inode->root->fs_info; + struct bio *bio = &bbio->bio; + struct folio_iter fi; + +@@ -739,12 +739,10 @@ static void alloc_new_bio(struct btrfs_inode *inode, + struct btrfs_fs_info *fs_info = inode->root->fs_info; + struct btrfs_bio *bbio; + +- bbio = btrfs_bio_alloc(BIO_MAX_VECS, bio_ctrl->opf, fs_info, +- bio_ctrl->end_io_func, NULL); ++ bbio = btrfs_bio_alloc(BIO_MAX_VECS, bio_ctrl->opf, inode, ++ file_offset, bio_ctrl->end_io_func, NULL); + bbio->bio.bi_iter.bi_sector = disk_bytenr >> SECTOR_SHIFT; + bbio->bio.bi_write_hint = inode->vfs_inode.i_write_hint; +- bbio->inode = inode; +- bbio->file_offset = file_offset; + bio_ctrl->bbio = bbio; + bio_ctrl->len_to_oe_boundary = U32_MAX; + bio_ctrl->next_file_offset = file_offset; +@@ -2223,12 +2221,11 @@ static noinline_for_stack void write_one_eb(struct extent_buffer *eb, + + bbio = btrfs_bio_alloc(INLINE_EXTENT_BUFFER_PAGES, + REQ_OP_WRITE | REQ_META | wbc_to_write_flags(wbc), +- eb->fs_info, end_bbio_meta_write, eb); ++ BTRFS_I(fs_info->btree_inode), eb->start, ++ end_bbio_meta_write, eb); + bbio->bio.bi_iter.bi_sector = eb->start >> SECTOR_SHIFT; + bio_set_dev(&bbio->bio, fs_info->fs_devices->latest_dev->bdev); + wbc_init_bio(wbc, &bbio->bio); +- bbio->inode = BTRFS_I(eb->fs_info->btree_inode); +- bbio->file_offset = eb->start; + for (int i = 0; i < num_extent_folios(eb); i++) { + struct folio *folio = eb->folios[i]; + u64 range_start = max_t(u64, eb->start, folio_pos(folio)); +@@ -3842,6 +3839,7 @@ static void end_bbio_meta_read(struct btrfs_bio *bbio) + int read_extent_buffer_pages_nowait(struct extent_buffer *eb, int mirror_num, + const struct btrfs_tree_parent_check *check) + { ++ struct btrfs_fs_info *fs_info = eb->fs_info; + struct btrfs_bio *bbio; + + if (test_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags)) +@@ -3875,11 +3873,9 @@ int read_extent_buffer_pages_nowait(struct extent_buffer *eb, int mirror_num, + refcount_inc(&eb->refs); + + bbio = btrfs_bio_alloc(INLINE_EXTENT_BUFFER_PAGES, +- REQ_OP_READ | REQ_META, eb->fs_info, +- end_bbio_meta_read, eb); ++ REQ_OP_READ | REQ_META, BTRFS_I(fs_info->btree_inode), ++ eb->start, end_bbio_meta_read, eb); + bbio->bio.bi_iter.bi_sector = eb->start >> SECTOR_SHIFT; +- bbio->inode = BTRFS_I(eb->fs_info->btree_inode); +- bbio->file_offset = eb->start; + memcpy(&bbio->parent_check, check, sizeof(*check)); + for (int i = 0; i < num_extent_folios(eb); i++) { + struct folio *folio = eb->folios[i]; +diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c +index b261dbeb29040..47e762856521d 100644 +--- a/fs/btrfs/inode.c ++++ b/fs/btrfs/inode.c +@@ -9423,7 +9423,6 @@ int btrfs_encoded_read_regular_fill_pages(struct btrfs_inode *inode, + u64 disk_bytenr, u64 disk_io_size, + struct page **pages, void *uring_ctx) + { +- struct btrfs_fs_info *fs_info = inode->root->fs_info; + struct btrfs_encoded_read_private *priv, sync_priv; + struct completion sync_reads; + unsigned long i = 0; +@@ -9448,10 +9447,9 @@ int btrfs_encoded_read_regular_fill_pages(struct btrfs_inode *inode, + priv->status = 0; + priv->uring_ctx = uring_ctx; + +- bbio = btrfs_bio_alloc(BIO_MAX_VECS, REQ_OP_READ, fs_info, ++ bbio = btrfs_bio_alloc(BIO_MAX_VECS, REQ_OP_READ, inode, 0, + btrfs_encoded_read_endio, priv); + bbio->bio.bi_iter.bi_sector = disk_bytenr >> SECTOR_SHIFT; +- bbio->inode = inode; + + do { + size_t bytes = min_t(u64, disk_io_size, PAGE_SIZE); +@@ -9460,10 +9458,9 @@ int btrfs_encoded_read_regular_fill_pages(struct btrfs_inode *inode, + refcount_inc(&priv->pending_refs); + btrfs_submit_bbio(bbio, 0); + +- bbio = btrfs_bio_alloc(BIO_MAX_VECS, REQ_OP_READ, fs_info, ++ bbio = btrfs_bio_alloc(BIO_MAX_VECS, REQ_OP_READ, inode, 0, + btrfs_encoded_read_endio, priv); + bbio->bio.bi_iter.bi_sector = disk_bytenr >> SECTOR_SHIFT; +- bbio->inode = inode; + continue; + } + +diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c +index b6a7ea105eb13..747e2c748376a 100644 +--- a/fs/btrfs/scrub.c ++++ b/fs/btrfs/scrub.c +@@ -929,10 +929,11 @@ static int calc_next_mirror(int mirror, int num_copies) + static void scrub_bio_add_sector(struct btrfs_bio *bbio, struct scrub_stripe *stripe, + int sector_nr) + { ++ struct btrfs_fs_info *fs_info = bbio->inode->root->fs_info; + void *kaddr = scrub_stripe_get_kaddr(stripe, sector_nr); + int ret; + +- ret = bio_add_page(&bbio->bio, virt_to_page(kaddr), bbio->fs_info->sectorsize, ++ ret = bio_add_page(&bbio->bio, virt_to_page(kaddr), fs_info->sectorsize, + offset_in_page(kaddr)); + /* + * Caller should ensure the bbio has enough size. +@@ -942,7 +943,21 @@ static void scrub_bio_add_sector(struct btrfs_bio *bbio, struct scrub_stripe *st + * to create the minimal amount of bio vectors, for fs block size < page + * size cases. + */ +- ASSERT(ret == bbio->fs_info->sectorsize); ++ ASSERT(ret == fs_info->sectorsize); ++} ++ ++static struct btrfs_bio *alloc_scrub_bbio(struct btrfs_fs_info *fs_info, ++ unsigned int nr_vecs, blk_opf_t opf, ++ u64 logical, ++ btrfs_bio_end_io_t end_io, void *private) ++{ ++ struct btrfs_bio *bbio; ++ ++ bbio = btrfs_bio_alloc(nr_vecs, opf, BTRFS_I(fs_info->btree_inode), ++ logical, end_io, private); ++ bbio->is_scrub = true; ++ bbio->bio.bi_iter.bi_sector = logical >> SECTOR_SHIFT; ++ return bbio; + } + + static void scrub_stripe_submit_repair_read(struct scrub_stripe *stripe, +@@ -968,12 +983,10 @@ static void scrub_stripe_submit_repair_read(struct scrub_stripe *stripe, + bbio = NULL; + } + +- if (!bbio) { +- bbio = btrfs_bio_alloc(stripe->nr_sectors, REQ_OP_READ, +- fs_info, scrub_repair_read_endio, stripe); +- bbio->bio.bi_iter.bi_sector = (stripe->logical + +- (i << fs_info->sectorsize_bits)) >> SECTOR_SHIFT; +- } ++ if (!bbio) ++ bbio = alloc_scrub_bbio(fs_info, stripe->nr_sectors, REQ_OP_READ, ++ stripe->logical + (i << fs_info->sectorsize_bits), ++ scrub_repair_read_endio, stripe); + + scrub_bio_add_sector(bbio, stripe, i); + } +@@ -1352,13 +1365,10 @@ static void scrub_write_sectors(struct scrub_ctx *sctx, struct scrub_stripe *str + scrub_submit_write_bio(sctx, stripe, bbio, dev_replace); + bbio = NULL; + } +- if (!bbio) { +- bbio = btrfs_bio_alloc(stripe->nr_sectors, REQ_OP_WRITE, +- fs_info, scrub_write_endio, stripe); +- bbio->bio.bi_iter.bi_sector = (stripe->logical + +- (sector_nr << fs_info->sectorsize_bits)) >> +- SECTOR_SHIFT; +- } ++ if (!bbio) ++ bbio = alloc_scrub_bbio(fs_info, stripe->nr_sectors, REQ_OP_WRITE, ++ stripe->logical + (sector_nr << fs_info->sectorsize_bits), ++ scrub_write_endio, stripe); + scrub_bio_add_sector(bbio, stripe, sector_nr); + } + if (bbio) +@@ -1849,9 +1859,8 @@ static void scrub_submit_extent_sector_read(struct scrub_stripe *stripe) + continue; + } + +- bbio = btrfs_bio_alloc(stripe->nr_sectors, REQ_OP_READ, +- fs_info, scrub_read_endio, stripe); +- bbio->bio.bi_iter.bi_sector = logical >> SECTOR_SHIFT; ++ bbio = alloc_scrub_bbio(fs_info, stripe->nr_sectors, REQ_OP_READ, ++ logical, scrub_read_endio, stripe); + } + + scrub_bio_add_sector(bbio, stripe, i); +@@ -1888,10 +1897,8 @@ static void scrub_submit_initial_read(struct scrub_ctx *sctx, + return; + } + +- bbio = btrfs_bio_alloc(BTRFS_STRIPE_LEN >> min_folio_shift, REQ_OP_READ, fs_info, +- scrub_read_endio, stripe); +- +- bbio->bio.bi_iter.bi_sector = stripe->logical >> SECTOR_SHIFT; ++ bbio = alloc_scrub_bbio(fs_info, BTRFS_STRIPE_LEN >> min_folio_shift, REQ_OP_READ, ++ stripe->logical, scrub_read_endio, stripe); + /* Read the whole range inside the chunk boundary. */ + for (unsigned int cur = 0; cur < nr_sectors; cur++) + scrub_bio_add_sector(bbio, stripe, cur); +diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c +index d1db7fa1fe583..3afc9c0c22287 100644 +--- a/fs/btrfs/zoned.c ++++ b/fs/btrfs/zoned.c +@@ -1809,14 +1809,14 @@ bool btrfs_use_zone_append(struct btrfs_bio *bbio) + { + u64 start = (bbio->bio.bi_iter.bi_sector << SECTOR_SHIFT); + struct btrfs_inode *inode = bbio->inode; +- struct btrfs_fs_info *fs_info = bbio->fs_info; ++ struct btrfs_fs_info *fs_info = inode->root->fs_info; + struct btrfs_block_group *cache; + bool ret = false; + + if (!btrfs_is_zoned(fs_info)) + return false; + +- if (!inode || !is_data_inode(inode)) ++ if (!is_data_inode(inode)) + return false; + + if (btrfs_op(&bbio->bio) != BTRFS_MAP_WRITE) +-- +2.51.0 + diff --git a/queue-6.18/btrfs-zoned-don-t-zone-append-to-conventional-zone.patch b/queue-6.18/btrfs-zoned-don-t-zone-append-to-conventional-zone.patch new file mode 100644 index 0000000000..c106433ffa --- /dev/null +++ b/queue-6.18/btrfs-zoned-don-t-zone-append-to-conventional-zone.patch @@ -0,0 +1,117 @@ +From 9cc8fafe5b187b34cc3bd9576a6770d22cef8a5f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Dec 2025 13:42:23 +0100 +Subject: btrfs: zoned: don't zone append to conventional zone + +From: Johannes Thumshirn + +[ Upstream commit b39b26e017c7889181cb84032e22bef72e81cf29 ] + +In case of a zoned RAID, it can happen that a data write is targeting a +sequential write required zone and a conventional zone. In this case the +bio will be marked as REQ_OP_ZONE_APPEND but for the conventional zone, +this needs to be REQ_OP_WRITE. + +The setting of REQ_OP_ZONE_APPEND is deferred to the last possible time in +btrfs_submit_dev_bio(), but the decision if we can use zone append is +cached in btrfs_bio. + +CC: Naohiro Aota +Fixes: e9b9b911e03c ("btrfs: add raid stripe tree to features enabled with debug config") +Reviewed-by: Christoph Hellwig +Reviewed-by: Naohiro Aota +Signed-off-by: Johannes Thumshirn +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/bio.c | 19 +++++++++---------- + fs/btrfs/bio.h | 3 +++ + 2 files changed, 12 insertions(+), 10 deletions(-) + +diff --git a/fs/btrfs/bio.c b/fs/btrfs/bio.c +index c3d860a2bca42..9b71f3fde618b 100644 +--- a/fs/btrfs/bio.c ++++ b/fs/btrfs/bio.c +@@ -441,6 +441,8 @@ static void btrfs_clone_write_end_io(struct bio *bio) + + static void btrfs_submit_dev_bio(struct btrfs_device *dev, struct bio *bio) + { ++ u64 physical = bio->bi_iter.bi_sector << SECTOR_SHIFT; ++ + if (!dev || !dev->bdev || + test_bit(BTRFS_DEV_STATE_MISSING, &dev->dev_state) || + (btrfs_op(bio) == BTRFS_MAP_WRITE && +@@ -455,12 +457,13 @@ static void btrfs_submit_dev_bio(struct btrfs_device *dev, struct bio *bio) + * For zone append writing, bi_sector must point the beginning of the + * zone + */ +- if (bio_op(bio) == REQ_OP_ZONE_APPEND) { +- u64 physical = bio->bi_iter.bi_sector << SECTOR_SHIFT; ++ if (btrfs_bio(bio)->can_use_append && btrfs_dev_is_sequential(dev, physical)) { + u64 zone_start = round_down(physical, dev->fs_info->zone_size); + + ASSERT(btrfs_dev_is_sequential(dev, physical)); + bio->bi_iter.bi_sector = zone_start >> SECTOR_SHIFT; ++ bio->bi_opf &= ~REQ_OP_WRITE; ++ bio->bi_opf |= REQ_OP_ZONE_APPEND; + } + btrfs_debug(dev->fs_info, + "%s: rw %d 0x%x, sector=%llu, dev=%lu (%s id %llu), size=%u", +@@ -708,7 +711,6 @@ static bool btrfs_submit_chunk(struct btrfs_bio *bbio, int mirror_num) + u64 logical = bio->bi_iter.bi_sector << SECTOR_SHIFT; + u64 length = bio->bi_iter.bi_size; + u64 map_length = length; +- bool use_append = btrfs_use_zone_append(bbio); + struct btrfs_io_context *bioc = NULL; + struct btrfs_io_stripe smap; + blk_status_t status; +@@ -736,8 +738,10 @@ static bool btrfs_submit_chunk(struct btrfs_bio *bbio, int mirror_num) + if (bio_op(bio) == REQ_OP_WRITE && is_data_bbio(bbio)) + bbio->orig_logical = logical; + ++ bbio->can_use_append = btrfs_use_zone_append(bbio); ++ + map_length = min(map_length, length); +- if (use_append) ++ if (bbio->can_use_append) + map_length = btrfs_append_map_length(bbio, map_length); + + if (map_length < length) { +@@ -766,11 +770,6 @@ static bool btrfs_submit_chunk(struct btrfs_bio *bbio, int mirror_num) + } + + if (btrfs_op(bio) == BTRFS_MAP_WRITE) { +- if (use_append) { +- bio->bi_opf &= ~REQ_OP_WRITE; +- bio->bi_opf |= REQ_OP_ZONE_APPEND; +- } +- + if (is_data_bbio(bbio) && bioc && bioc->use_rst) { + /* + * No locking for the list update, as we only add to +@@ -797,7 +796,7 @@ static bool btrfs_submit_chunk(struct btrfs_bio *bbio, int mirror_num) + status = errno_to_blk_status(ret); + if (status) + goto fail; +- } else if (use_append || ++ } else if (bbio->can_use_append || + (btrfs_is_zoned(fs_info) && inode && + inode->flags & BTRFS_INODE_NODATASUM)) { + ret = btrfs_alloc_dummy_sum(bbio); +diff --git a/fs/btrfs/bio.h b/fs/btrfs/bio.h +index 488cdbdd9e2f8..126bc68c87605 100644 +--- a/fs/btrfs/bio.h ++++ b/fs/btrfs/bio.h +@@ -99,6 +99,9 @@ struct btrfs_bio { + /* Whether the csum generation for data write is async. */ + bool async_csum; + ++ /* Whether the bio is written using zone append. */ ++ bool can_use_append; ++ + /* + * This member must come last, bio_alloc_bioset will allocate enough + * bytes for entire btrfs_bio but relies on bio being last. +-- +2.51.0 + diff --git a/queue-6.18/char-misc-use-is_err-for-filp_open-return-value.patch b/queue-6.18/char-misc-use-is_err-for-filp_open-return-value.patch new file mode 100644 index 0000000000..0eac1dc8dd --- /dev/null +++ b/queue-6.18/char-misc-use-is_err-for-filp_open-return-value.patch @@ -0,0 +1,43 @@ +From 7296436ed093608b5f57684c0de2714d2df0bead Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 27 Dec 2025 02:02:48 +0300 +Subject: char: misc: Use IS_ERR() for filp_open() return value + +From: Alper Ak + +[ Upstream commit e849ada70c6b1ee22e9f4f5c0e38231dcee53f04 ] + +filp_open() never returns NULL, it returns either a valid pointer or an +error pointer. Using IS_ERR_OR_NULL() is unnecessary. Additionally, if +filp were NULL, PTR_ERR(NULL) would return 0, leading to a misleading +error message. + +Fixes: 74d8361be344 ("char: misc: add test cases") +Reported-by: kernel test robot +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/r/202506132058.thWZHlrb-lkp@intel.com/ +Signed-off-by: Alper Ak +Acked-by: Thadeu Lima de Souza Cascardo +Link: https://patch.msgid.link/20251226230248.113073-1-alperyasinak1@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/char/misc_minor_kunit.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/char/misc_minor_kunit.c b/drivers/char/misc_minor_kunit.c +index 6fc8b05169c57..e930c78e1ef97 100644 +--- a/drivers/char/misc_minor_kunit.c ++++ b/drivers/char/misc_minor_kunit.c +@@ -166,7 +166,7 @@ static void __init miscdev_test_can_open(struct kunit *test, struct miscdevice * + KUNIT_FAIL(test, "failed to create node\n"); + + filp = filp_open(devname, O_RDONLY, 0); +- if (IS_ERR_OR_NULL(filp)) ++ if (IS_ERR(filp)) + KUNIT_FAIL(test, "failed to open misc device: %ld\n", PTR_ERR(filp)); + else + fput(filp); +-- +2.51.0 + diff --git a/queue-6.18/clk-actions-owl-composite-convert-from-owl_divider_h.patch b/queue-6.18/clk-actions-owl-composite-convert-from-owl_divider_h.patch new file mode 100644 index 0000000000..607bc71652 --- /dev/null +++ b/queue-6.18/clk-actions-owl-composite-convert-from-owl_divider_h.patch @@ -0,0 +1,49 @@ +From 2de507e2a490f8ac941e54b315a857623bfa0929 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:16:22 -0500 +Subject: clk: actions: owl-composite: convert from + owl_divider_helper_round_rate() to divider_determine_rate() + +From: Brian Masney + +[ Upstream commit d0b7c5bf6c5520c35fecff34da83d390405d3eaf ] + +owl_divider_helper_round_rate() is just a wrapper for +divider_round_rate(), which is deprecated. Let's migrate to +divider_determine_rate() instead so that this deprecated API can be +removed. + +Acked-by: Manivannan Sadhasivam +Signed-off-by: Brian Masney +Stable-dep-of: 3ff3360440fa ("clk: actions: owl-divider: convert from divider_round_rate() to divider_determine_rate()") +Signed-off-by: Sasha Levin +--- + drivers/clk/actions/owl-composite.c | 11 +++-------- + 1 file changed, 3 insertions(+), 8 deletions(-) + +diff --git a/drivers/clk/actions/owl-composite.c b/drivers/clk/actions/owl-composite.c +index 00b74f8bc4375..9540444307d6c 100644 +--- a/drivers/clk/actions/owl-composite.c ++++ b/drivers/clk/actions/owl-composite.c +@@ -57,15 +57,10 @@ static int owl_comp_div_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) + { + struct owl_composite *comp = hw_to_owl_comp(hw); +- long rate; +- +- rate = owl_divider_helper_round_rate(&comp->common, &comp->rate.div_hw, +- req->rate, &req->best_parent_rate); +- if (rate < 0) +- return rate; ++ struct owl_divider_hw *div = &comp->rate.div_hw; + +- req->rate = rate; +- return 0; ++ return divider_determine_rate(&comp->common.hw, req, div->table, ++ div->width, div->div_flags); + } + + static unsigned long owl_comp_div_recalc_rate(struct clk_hw *hw, +-- +2.51.0 + diff --git a/queue-6.18/clk-actions-owl-divider-convert-from-divider_round_r.patch b/queue-6.18/clk-actions-owl-divider-convert-from-divider_round_r.patch new file mode 100644 index 0000000000..5c72cdca8e --- /dev/null +++ b/queue-6.18/clk-actions-owl-divider-convert-from-divider_round_r.patch @@ -0,0 +1,84 @@ +From 03046f00e73359351dddc3f8fe7ea4ecc9e6a6c1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:16:23 -0500 +Subject: clk: actions: owl-divider: convert from divider_round_rate() to + divider_determine_rate() + +From: Brian Masney + +[ Upstream commit 3ff3360440fa8cc7ef5a4da628d3b770b46a4f73 ] + +The divider_round_rate() function is now deprecated, so let's migrate +to divider_determine_rate() instead so that this deprecated API can be +removed. Additionally, owl_divider_helper_round_rate() is no longer used, +so let's drop that from the header file as well. + +Note that when the main function itself was migrated to use +determine_rate, this was mistakenly converted to: + + req->rate = divider_round_rate(...) + +This is invalid in the case when an error occurs since it can set the +rate to a negative value. + +Fixes: 1b04e12a8bcc ("clk: actions: owl-divider: convert from round_rate() to determine_rate()") +Acked-by: Manivannan Sadhasivam +Signed-off-by: Brian Masney +Signed-off-by: Sasha Levin +--- + drivers/clk/actions/owl-divider.c | 17 ++--------------- + drivers/clk/actions/owl-divider.h | 5 ----- + 2 files changed, 2 insertions(+), 20 deletions(-) + +diff --git a/drivers/clk/actions/owl-divider.c b/drivers/clk/actions/owl-divider.c +index 118f1393c6780..316ace80e87e3 100644 +--- a/drivers/clk/actions/owl-divider.c ++++ b/drivers/clk/actions/owl-divider.c +@@ -13,26 +13,13 @@ + + #include "owl-divider.h" + +-long owl_divider_helper_round_rate(struct owl_clk_common *common, +- const struct owl_divider_hw *div_hw, +- unsigned long rate, +- unsigned long *parent_rate) +-{ +- return divider_round_rate(&common->hw, rate, parent_rate, +- div_hw->table, div_hw->width, +- div_hw->div_flags); +-} +- + static int owl_divider_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) + { + struct owl_divider *div = hw_to_owl_divider(hw); + +- req->rate = owl_divider_helper_round_rate(&div->common, &div->div_hw, +- req->rate, +- &req->best_parent_rate); +- +- return 0; ++ return divider_determine_rate(hw, req, div->div_hw.table, ++ div->div_hw.width, div->div_hw.div_flags); + } + + unsigned long owl_divider_helper_recalc_rate(struct owl_clk_common *common, +diff --git a/drivers/clk/actions/owl-divider.h b/drivers/clk/actions/owl-divider.h +index 083be6d80954d..2ba957740c381 100644 +--- a/drivers/clk/actions/owl-divider.h ++++ b/drivers/clk/actions/owl-divider.h +@@ -56,11 +56,6 @@ static inline struct owl_divider *hw_to_owl_divider(const struct clk_hw *hw) + return container_of(common, struct owl_divider, common); + } + +-long owl_divider_helper_round_rate(struct owl_clk_common *common, +- const struct owl_divider_hw *div_hw, +- unsigned long rate, +- unsigned long *parent_rate); +- + unsigned long owl_divider_helper_recalc_rate(struct owl_clk_common *common, + const struct owl_divider_hw *div_hw, + unsigned long parent_rate); +-- +2.51.0 + diff --git a/queue-6.18/clk-bm1880-convert-from-divider_round_rate-to-divide.patch b/queue-6.18/clk-bm1880-convert-from-divider_round_rate-to-divide.patch new file mode 100644 index 0000000000..5199c3bed6 --- /dev/null +++ b/queue-6.18/clk-bm1880-convert-from-divider_round_rate-to-divide.patch @@ -0,0 +1,49 @@ +From 8be0673afabecc4019ed100635d6567e3e9595fb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:16:25 -0500 +Subject: clk: bm1880: convert from divider_round_rate() to + divider_determine_rate() + +From: Brian Masney + +[ Upstream commit 463b97bef0c9fb02b743d6b9f0d698cae81a1d9f ] + +The divider_round_rate() function is now deprecated, so let's migrate +to divider_determine_rate() instead so that this deprecated API can be +removed. + +Note that when the main function itself was migrated to use +determine_rate, this was mistakenly converted to: + + req->rate = divider_round_rate(...) + +This is invalid in the case when an error occurs since it can set the +rate to a negative value. + +Fixes: 64613d7fb42f ("clk: bm1880: convert from round_rate() to determine_rate()") +Acked-by: Manivannan Sadhasivam +Signed-off-by: Brian Masney +Signed-off-by: Sasha Levin +--- + drivers/clk/clk-bm1880.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/drivers/clk/clk-bm1880.c b/drivers/clk/clk-bm1880.c +index dac190bc6e19a..d2617fe16d2e4 100644 +--- a/drivers/clk/clk-bm1880.c ++++ b/drivers/clk/clk-bm1880.c +@@ -629,10 +629,7 @@ static int bm1880_clk_div_determine_rate(struct clk_hw *hw, + return 0; + } + +- req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, +- div->table, div->width, div->flags); +- +- return 0; ++ return divider_determine_rate(hw, req, div->table, div->width, div->flags); + } + + static int bm1880_clk_div_set_rate(struct clk_hw *hw, unsigned long rate, +-- +2.51.0 + diff --git a/queue-6.18/clk-hisilicon-clkdivider-hi6220-convert-from-divider.patch b/queue-6.18/clk-hisilicon-clkdivider-hi6220-convert-from-divider.patch new file mode 100644 index 0000000000..f0d6ec9c3b --- /dev/null +++ b/queue-6.18/clk-hisilicon-clkdivider-hi6220-convert-from-divider.patch @@ -0,0 +1,49 @@ +From 202e4f5746a2d044c8d09606e35ba728d6201242 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:16:26 -0500 +Subject: clk: hisilicon: clkdivider-hi6220: convert from divider_round_rate() + to divider_determine_rate() + +From: Brian Masney + +[ Upstream commit e3a5249c140a1ded55937ba04247d530a85f0edc ] + +The divider_round_rate() function is now deprecated, so let's migrate +to divider_determine_rate() instead so that this deprecated API can be +removed. + +Note that when the main function itself was migrated to use +determine_rate, this was mistakenly converted to: + + req->rate = divider_round_rate(...) + +This is invalid in the case when an error occurs since it can set the +rate to a negative value. + +Fixes: 619a6210f398 ("clk: hisilicon: clkdivider-hi6220: convert from round_rate() to determine_rate()") +Signed-off-by: Brian Masney +Signed-off-by: Sasha Levin +--- + drivers/clk/hisilicon/clkdivider-hi6220.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/clk/hisilicon/clkdivider-hi6220.c b/drivers/clk/hisilicon/clkdivider-hi6220.c +index 6bae18a84cb6c..fd7ceb92d6515 100644 +--- a/drivers/clk/hisilicon/clkdivider-hi6220.c ++++ b/drivers/clk/hisilicon/clkdivider-hi6220.c +@@ -60,10 +60,8 @@ static int hi6220_clkdiv_determine_rate(struct clk_hw *hw, + { + struct hi6220_clk_divider *dclk = to_hi6220_clk_divider(hw); + +- req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, dclk->table, +- dclk->width, CLK_DIVIDER_ROUND_CLOSEST); +- +- return 0; ++ return divider_determine_rate(hw, req, dclk->table, dclk->width, ++ CLK_DIVIDER_ROUND_CLOSEST); + } + + static int hi6220_clkdiv_set_rate(struct clk_hw *hw, unsigned long rate, +-- +2.51.0 + diff --git a/queue-6.18/clk-loongson1-convert-from-divider_round_rate-to-div.patch b/queue-6.18/clk-loongson1-convert-from-divider_round_rate-to-div.patch new file mode 100644 index 0000000000..6ed2f4af45 --- /dev/null +++ b/queue-6.18/clk-loongson1-convert-from-divider_round_rate-to-div.patch @@ -0,0 +1,50 @@ +From c3ad9fa4bb90eb137a4dd5adcb6419c16f86b043 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:16:27 -0500 +Subject: clk: loongson1: convert from divider_round_rate() to + divider_determine_rate() + +From: Brian Masney + +[ Upstream commit 11d3c676e7e0f00e3398199f85e47a0e22369866 ] + +The divider_round_rate() function is now deprecated, so let's migrate +to divider_determine_rate() instead so that this deprecated API can be +removed. + +Note that when the main function itself was migrated to use +determine_rate, this was mistakenly converted to: + + req->rate = divider_round_rate(...) + +This is invalid in the case when an error occurs since it can set the +rate to a negative value. + +Fixes: bb40a2ef4fc9 ("clk: loongson1: convert from round_rate() to determine_rate()") +Reviewed-by: Keguang Zhang +Tested-by: Keguang Zhang # on LS1B & LS1C +Signed-off-by: Brian Masney +Signed-off-by: Sasha Levin +--- + drivers/clk/clk-loongson1.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/drivers/clk/clk-loongson1.c b/drivers/clk/clk-loongson1.c +index f9f060d08a5fa..1674181a1107d 100644 +--- a/drivers/clk/clk-loongson1.c ++++ b/drivers/clk/clk-loongson1.c +@@ -99,10 +99,7 @@ static int ls1x_divider_determine_rate(struct clk_hw *hw, + struct ls1x_clk *ls1x_clk = to_ls1x_clk(hw); + const struct ls1x_clk_div_data *d = ls1x_clk->data; + +- req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, +- d->table, d->width, d->flags); +- +- return 0; ++ return divider_determine_rate(hw, req, d->table, d->width, d->flags); + } + + static int ls1x_divider_set_rate(struct clk_hw *hw, unsigned long rate, +-- +2.51.0 + diff --git a/queue-6.18/clk-mediatek-add-mfg_eb-as-parent-to-mt8196-mfgpll-c.patch b/queue-6.18/clk-mediatek-add-mfg_eb-as-parent-to-mt8196-mfgpll-c.patch new file mode 100644 index 0000000000..9e5e1f7cd6 --- /dev/null +++ b/queue-6.18/clk-mediatek-add-mfg_eb-as-parent-to-mt8196-mfgpll-c.patch @@ -0,0 +1,101 @@ +From 6e0af01d435cc1a3a1717ff42fdfa2807561acc0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 15 Dec 2025 11:24:02 +0100 +Subject: clk: mediatek: Add mfg_eb as parent to mt8196 mfgpll clocks + +From: Nicolas Frattaroli + +[ Upstream commit 19024c9980c331908de0680283d572b80308654e ] + +All the MFGPLL require MFG_EB to be on for any operation on them, and +they only tick when MFG_EB is on as well, therefore making this a +parent-child relationship. + +This dependency wasn't clear during the initial upstreaming of these +clock controllers, as it only made itself known when I could observe +the effects of the clock by bringing up a different piece of hardware. + +Add a new PLL_PARENT_EN flag to mediatek's clk-pll.h, and check for it +when initialising the pll to then translate it into the actual +CLK_OPS_PARENT_ENABLE flag. + +Then add the mfg_eb parent to the mfgpll clocks, and set the new +PLL_PARENT_EN flag. + +Fixes: 03dc02f8c7dc ("clk: mediatek: Add MT8196 mfg clock support") +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Nicolas Frattaroli +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + drivers/clk/mediatek/clk-mt8196-mfg.c | 13 +++++++------ + drivers/clk/mediatek/clk-pll.c | 3 +++ + drivers/clk/mediatek/clk-pll.h | 1 + + 3 files changed, 11 insertions(+), 6 deletions(-) + +diff --git a/drivers/clk/mediatek/clk-mt8196-mfg.c b/drivers/clk/mediatek/clk-mt8196-mfg.c +index ae1eb9de79ae2..f40795b47ff1f 100644 +--- a/drivers/clk/mediatek/clk-mt8196-mfg.c ++++ b/drivers/clk/mediatek/clk-mt8196-mfg.c +@@ -58,24 +58,25 @@ + .pcw_shift = _pcw_shift, \ + .pcwbits = _pcwbits, \ + .pcwibits = MT8196_INTEGER_BITS, \ ++ .parent_name = "mfg_eb", \ + } + + static const struct mtk_pll_data mfg_ao_plls[] = { +- PLL(CLK_MFG_AO_MFGPLL, "mfgpll", MFGPLL_CON0, MFGPLL_CON0, 0, 0, 0, +- BIT(0), MFGPLL_CON1, 24, 0, 0, 0, ++ PLL(CLK_MFG_AO_MFGPLL, "mfgpll", MFGPLL_CON0, MFGPLL_CON0, 0, 0, ++ PLL_PARENT_EN, BIT(0), MFGPLL_CON1, 24, 0, 0, 0, + MFGPLL_CON1, 0, 22), + }; + + static const struct mtk_pll_data mfgsc0_ao_plls[] = { + PLL(CLK_MFGSC0_AO_MFGPLL_SC0, "mfgpll-sc0", MFGPLL_SC0_CON0, +- MFGPLL_SC0_CON0, 0, 0, 0, BIT(0), MFGPLL_SC0_CON1, 24, 0, 0, 0, +- MFGPLL_SC0_CON1, 0, 22), ++ MFGPLL_SC0_CON0, 0, 0, PLL_PARENT_EN, BIT(0), MFGPLL_SC0_CON1, 24, ++ 0, 0, 0, MFGPLL_SC0_CON1, 0, 22), + }; + + static const struct mtk_pll_data mfgsc1_ao_plls[] = { + PLL(CLK_MFGSC1_AO_MFGPLL_SC1, "mfgpll-sc1", MFGPLL_SC1_CON0, +- MFGPLL_SC1_CON0, 0, 0, 0, BIT(0), MFGPLL_SC1_CON1, 24, 0, 0, 0, +- MFGPLL_SC1_CON1, 0, 22), ++ MFGPLL_SC1_CON0, 0, 0, PLL_PARENT_EN, BIT(0), MFGPLL_SC1_CON1, 24, ++ 0, 0, 0, MFGPLL_SC1_CON1, 0, 22), + }; + + static const struct of_device_id of_match_clk_mt8196_mfg[] = { +diff --git a/drivers/clk/mediatek/clk-pll.c b/drivers/clk/mediatek/clk-pll.c +index cd2b6ce551c6b..de3eb02670554 100644 +--- a/drivers/clk/mediatek/clk-pll.c ++++ b/drivers/clk/mediatek/clk-pll.c +@@ -358,6 +358,9 @@ struct clk_hw *mtk_clk_register_pll_ops(struct mtk_clk_pll *pll, + + init.name = data->name; + init.flags = (data->flags & PLL_AO) ? CLK_IS_CRITICAL : 0; ++ if (data->flags & PLL_PARENT_EN) ++ init.flags |= CLK_OPS_PARENT_ENABLE; ++ + init.ops = pll_ops; + if (data->parent_name) + init.parent_names = &data->parent_name; +diff --git a/drivers/clk/mediatek/clk-pll.h b/drivers/clk/mediatek/clk-pll.h +index d71c150ce83e4..de5a8fb7cbcfe 100644 +--- a/drivers/clk/mediatek/clk-pll.h ++++ b/drivers/clk/mediatek/clk-pll.h +@@ -21,6 +21,7 @@ struct mtk_pll_div_table { + + #define HAVE_RST_BAR BIT(0) + #define PLL_AO BIT(1) ++#define PLL_PARENT_EN BIT(2) + #define POSTDIV_MASK GENMASK(2, 0) + + struct mtk_pll_data { +-- +2.51.0 + diff --git a/queue-6.18/clk-mediatek-drop-__initconst-from-gates.patch b/queue-6.18/clk-mediatek-drop-__initconst-from-gates.patch new file mode 100644 index 0000000000..53969125ca --- /dev/null +++ b/queue-6.18/clk-mediatek-drop-__initconst-from-gates.patch @@ -0,0 +1,72 @@ +From d25b593c04332a85140c15005bc479d60f8f5820 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 23 Dec 2025 12:05:17 +0100 +Subject: clk: mediatek: Drop __initconst from gates + +From: Sjoerd Simons + +[ Upstream commit 871afb43e41ad4e8246438de495a939cd0f8113c ] + +Since commit 8ceff24a754a ("clk: mediatek: clk-gate: Refactor +mtk_clk_register_gate to use mtk_gate struct") the mtk_gate structs +are no longer just used for initialization/registration, but also at +runtime. So drop __initconst annotations. + +Fixes: 8ceff24a754a ("clk: mediatek: clk-gate: Refactor mtk_clk_register_gate to use mtk_gate struct") +Signed-off-by: Sjoerd Simons +Reviewed-by: AngeloGioacchino Del Regno +Reviewed-by: Laura Nao +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + drivers/clk/mediatek/clk-mt7981-eth.c | 6 +++--- + drivers/clk/mediatek/clk-mt8516.c | 2 +- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/clk/mediatek/clk-mt7981-eth.c b/drivers/clk/mediatek/clk-mt7981-eth.c +index 906aec9ddff54..0655ebb6c561f 100644 +--- a/drivers/clk/mediatek/clk-mt7981-eth.c ++++ b/drivers/clk/mediatek/clk-mt7981-eth.c +@@ -31,7 +31,7 @@ static const struct mtk_gate_regs sgmii0_cg_regs = { + .ops = &mtk_clk_gate_ops_no_setclr_inv, \ + } + +-static const struct mtk_gate sgmii0_clks[] __initconst = { ++static const struct mtk_gate sgmii0_clks[] = { + GATE_SGMII0(CLK_SGM0_TX_EN, "sgm0_tx_en", "usb_tx250m", 2), + GATE_SGMII0(CLK_SGM0_RX_EN, "sgm0_rx_en", "usb_eq_rx250m", 3), + GATE_SGMII0(CLK_SGM0_CK0_EN, "sgm0_ck0_en", "usb_ln0", 4), +@@ -53,7 +53,7 @@ static const struct mtk_gate_regs sgmii1_cg_regs = { + .ops = &mtk_clk_gate_ops_no_setclr_inv, \ + } + +-static const struct mtk_gate sgmii1_clks[] __initconst = { ++static const struct mtk_gate sgmii1_clks[] = { + GATE_SGMII1(CLK_SGM1_TX_EN, "sgm1_tx_en", "usb_tx250m", 2), + GATE_SGMII1(CLK_SGM1_RX_EN, "sgm1_rx_en", "usb_eq_rx250m", 3), + GATE_SGMII1(CLK_SGM1_CK1_EN, "sgm1_ck1_en", "usb_ln0", 4), +@@ -75,7 +75,7 @@ static const struct mtk_gate_regs eth_cg_regs = { + .ops = &mtk_clk_gate_ops_no_setclr_inv, \ + } + +-static const struct mtk_gate eth_clks[] __initconst = { ++static const struct mtk_gate eth_clks[] = { + GATE_ETH(CLK_ETH_FE_EN, "eth_fe_en", "netsys_2x", 6), + GATE_ETH(CLK_ETH_GP2_EN, "eth_gp2_en", "sgm_325m", 7), + GATE_ETH(CLK_ETH_GP1_EN, "eth_gp1_en", "sgm_325m", 8), +diff --git a/drivers/clk/mediatek/clk-mt8516.c b/drivers/clk/mediatek/clk-mt8516.c +index 21eb052b0a539..342a59019fea9 100644 +--- a/drivers/clk/mediatek/clk-mt8516.c ++++ b/drivers/clk/mediatek/clk-mt8516.c +@@ -544,7 +544,7 @@ static const struct mtk_gate_regs top5_cg_regs = { + #define GATE_TOP5(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &top5_cg_regs, _shift, &mtk_clk_gate_ops_setclr) + +-static const struct mtk_gate top_clks[] __initconst = { ++static const struct mtk_gate top_clks[] = { + /* TOP1 */ + GATE_TOP1(CLK_TOP_THEM, "them", "ahb_infra_sel", 1), + GATE_TOP1(CLK_TOP_APDMA, "apdma", "ahb_infra_sel", 2), +-- +2.51.0 + diff --git a/queue-6.18/clk-mediatek-fix-error-handling-in-runtime-pm-setup.patch b/queue-6.18/clk-mediatek-fix-error-handling-in-runtime-pm-setup.patch new file mode 100644 index 0000000000..8f486a4a17 --- /dev/null +++ b/queue-6.18/clk-mediatek-fix-error-handling-in-runtime-pm-setup.patch @@ -0,0 +1,66 @@ +From 98182829c4de03058361d7479d7c44df2ceeff27 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 23 Nov 2025 23:43:15 +0800 +Subject: clk: mediatek: Fix error handling in runtime PM setup + +From: Haotian Zhang + +[ Upstream commit aa2ad19210a6a444111bce55e8b69579f29318fb ] + +devm_pm_runtime_enable() can fail due to memory allocation. The current +code ignores its return value, and when pm_runtime_resume_and_get() fails, +it returns directly without unmapping the shared_io region. + +Add error handling for devm_pm_runtime_enable(). Reorder cleanup labels +to properly unmap shared_io on pm_runtime_resume_and_get() failure. + +Fixes: 2f7b1d8b5505 ("clk: mediatek: Do a runtime PM get on controllers during probe") +Signed-off-by: Haotian Zhang +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + drivers/clk/mediatek/clk-mtk.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c +index 19cd27941747a..deafe55a96cb1 100644 +--- a/drivers/clk/mediatek/clk-mtk.c ++++ b/drivers/clk/mediatek/clk-mtk.c +@@ -497,14 +497,16 @@ static int __mtk_clk_simple_probe(struct platform_device *pdev, + + + if (mcd->need_runtime_pm) { +- devm_pm_runtime_enable(&pdev->dev); ++ r = devm_pm_runtime_enable(&pdev->dev); ++ if (r) ++ goto unmap_io; + /* + * Do a pm_runtime_resume_and_get() to workaround a possible + * deadlock between clk_register() and the genpd framework. + */ + r = pm_runtime_resume_and_get(&pdev->dev); + if (r) +- return r; ++ goto unmap_io; + } + + /* Calculate how many clk_hw_onecell_data entries to allocate */ +@@ -618,11 +620,11 @@ static int __mtk_clk_simple_probe(struct platform_device *pdev, + free_data: + mtk_free_clk_data(clk_data); + free_base: +- if (mcd->shared_io && base) +- iounmap(base); +- + if (mcd->need_runtime_pm) + pm_runtime_put(&pdev->dev); ++unmap_io: ++ if (mcd->shared_io && base) ++ iounmap(base); + return r; + } + +-- +2.51.0 + diff --git a/queue-6.18/clk-meson-g12a-limit-the-hdmi-pll-od-to-4.patch b/queue-6.18/clk-meson-g12a-limit-the-hdmi-pll-od-to-4.patch new file mode 100644 index 0000000000..6e72331901 --- /dev/null +++ b/queue-6.18/clk-meson-g12a-limit-the-hdmi-pll-od-to-4.patch @@ -0,0 +1,86 @@ +From 65877a8f2ffe218c6154c0164f0f66de164329f7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Jan 2026 21:47:09 +0100 +Subject: clk: meson: g12a: Limit the HDMI PLL OD to /4 + +From: Martin Blumenstingl + +[ Upstream commit 7aa6c24697ef5db1402dd38743914493cd5b356d ] + +GXBB has the HDMI PLL OD in the HHI_HDMI_PLL_CNTL2 register while for +G12A/G12B/SM1 the OD has moved to HHI_HDMI_PLL_CNTL0. At first glance +the rest of the OD setup seems identical. + +However, looking at the downstream kernel sources as well as testing +shows that G12A/G12B/SM1 only supports three OD values: +- register value 0 means: divide by 1 +- register value 1 means: divide by 2 +- register value 2 means: divide by 4 + +Downstream sources are also only using OD register values 0, 1 and 2 +for G12A/G12B/SM1 (while for GXBB the downstream kernel sources are also +using value 3 which means: divide by 8). + +Add clk_div_table and have it replace the CLK_DIVIDER_POWER_OF_TWO flag +to make the kernel's view of this register match with how the hardware +actually works. + +Fixes: 085a4ea93d54 ("clk: meson: g12a: add peripheral clock controller") +Signed-off-by: Martin Blumenstingl +Link: https://lore.kernel.org/r/20260105204710.447779-3-martin.blumenstingl@googlemail.com +Signed-off-by: Jerome Brunet +Signed-off-by: Sasha Levin +--- + drivers/clk/meson/g12a.c | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c +index 185b6348251db..d0d4c7b6dc827 100644 +--- a/drivers/clk/meson/g12a.c ++++ b/drivers/clk/meson/g12a.c +@@ -777,12 +777,23 @@ static struct clk_regmap g12a_hdmi_pll_dco = { + }, + }; + ++/* ++ * G12/SM1 hdmi OD dividers are POWER_OF_TWO dividers but limited to /4. ++ * A divider value of 3 should map to /8 but instead map /4 so ignore it. ++ */ ++static const struct clk_div_table g12a_hdmi_pll_od_div_table[] = { ++ { .val = 0, .div = 1 }, ++ { .val = 1, .div = 2 }, ++ { .val = 2, .div = 4 }, ++ { /* sentinel */ } ++}; ++ + static struct clk_regmap g12a_hdmi_pll_od = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL0, + .shift = 16, + .width = 2, +- .flags = CLK_DIVIDER_POWER_OF_TWO, ++ .table = g12a_hdmi_pll_od_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od", +@@ -800,7 +811,7 @@ static struct clk_regmap g12a_hdmi_pll_od2 = { + .offset = HHI_HDMI_PLL_CNTL0, + .shift = 18, + .width = 2, +- .flags = CLK_DIVIDER_POWER_OF_TWO, ++ .table = g12a_hdmi_pll_od_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od2", +@@ -818,7 +829,7 @@ static struct clk_regmap g12a_hdmi_pll = { + .offset = HHI_HDMI_PLL_CNTL0, + .shift = 20, + .width = 2, +- .flags = CLK_DIVIDER_POWER_OF_TWO, ++ .table = g12a_hdmi_pll_od_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll", +-- +2.51.0 + diff --git a/queue-6.18/clk-meson-gxbb-limit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch b/queue-6.18/clk-meson-gxbb-limit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch new file mode 100644 index 0000000000..5757bcc10f --- /dev/null +++ b/queue-6.18/clk-meson-gxbb-limit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch @@ -0,0 +1,87 @@ +From 5a8ae6ea64abff70f0ffd83b76080babb1fbbe50 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Jan 2026 21:47:08 +0100 +Subject: clk: meson: gxbb: Limit the HDMI PLL OD to /4 on GXL/GXM SoCs + +From: Martin Blumenstingl + +[ Upstream commit 5b1a43950fd3162af0ce52b13c14a2d29b179d4f ] + +GXBB has the HDMI PLL OD in the HHI_HDMI_PLL_CNTL2 register while for +GXL/GXM the OD has moved to HHI_HDMI_PLL_CNTL3. At first glance the rest +of the OD setup seems identical. + +However, looking at the downstream kernel sources as well as testing +shows that GXL only supports three OD values: +- register value 0 means: divide by 1 +- register value 1 means: divide by 2 +- register value 2 means: divide by 4 + +Using register value 3 (which on GXBB means: divide by 8) still divides +by 4 as verified using meson-clk-measure. Downstream sources are also +only using OD register values 0, 1 and 2 for GXL (while for GXBB the +downstream kernel sources are also using value 3). + +Add clk_div_table and have it replace the CLK_DIVIDER_POWER_OF_TWO flag +to make the kernel's view of this register match with how the hardware +actually works. + +Fixes: 69d92293274b ("clk: meson: add the gxl hdmi pll") +Signed-off-by: Martin Blumenstingl +Link: https://lore.kernel.org/r/20260105204710.447779-2-martin.blumenstingl@googlemail.com +Signed-off-by: Jerome Brunet +Signed-off-by: Sasha Levin +--- + drivers/clk/meson/gxbb.c | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c +index 5a229c4ffae10..ec9a3414875ac 100644 +--- a/drivers/clk/meson/gxbb.c ++++ b/drivers/clk/meson/gxbb.c +@@ -349,12 +349,23 @@ static struct clk_regmap gxbb_hdmi_pll = { + }, + }; + ++/* ++ * GXL hdmi OD dividers are POWER_OF_TWO dividers but limited to /4. ++ * A divider value of 3 should map to /8 but instead map /4 so ignore it. ++ */ ++static const struct clk_div_table gxl_hdmi_pll_od_div_table[] = { ++ { .val = 0, .div = 1 }, ++ { .val = 1, .div = 2 }, ++ { .val = 2, .div = 4 }, ++ { /* sentinel */ } ++}; ++ + static struct clk_regmap gxl_hdmi_pll_od = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL + 8, + .shift = 21, + .width = 2, +- .flags = CLK_DIVIDER_POWER_OF_TWO, ++ .table = gxl_hdmi_pll_od_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od", +@@ -372,7 +383,7 @@ static struct clk_regmap gxl_hdmi_pll_od2 = { + .offset = HHI_HDMI_PLL_CNTL + 8, + .shift = 23, + .width = 2, +- .flags = CLK_DIVIDER_POWER_OF_TWO, ++ .table = gxl_hdmi_pll_od_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od2", +@@ -390,7 +401,7 @@ static struct clk_regmap gxl_hdmi_pll = { + .offset = HHI_HDMI_PLL_CNTL + 8, + .shift = 19, + .width = 2, +- .flags = CLK_DIVIDER_POWER_OF_TWO, ++ .table = gxl_hdmi_pll_od_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll", +-- +2.51.0 + diff --git a/queue-6.18/clk-microchip-core-remove-duplicate-determine_rate-o.patch b/queue-6.18/clk-microchip-core-remove-duplicate-determine_rate-o.patch new file mode 100644 index 0000000000..bda3c8b86f --- /dev/null +++ b/queue-6.18/clk-microchip-core-remove-duplicate-determine_rate-o.patch @@ -0,0 +1,65 @@ +From a7f6d480c55022c4fcd3d535dd900d2500685930 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Dec 2025 14:46:27 -0500 +Subject: clk: microchip: core: remove duplicate determine_rate on + pic32_sclk_ops + +From: Brian Masney + +[ Upstream commit d93faac66dc04650d924f8f9584216d14f48fb14 ] + +pic32_sclk_ops previously had a sclk_round_rate() member, and this was +recently converted over to sclk_determine_rate() with the help of a +Coccinelle semantic patch. pic32_sclk_ops now has two conflicting +determine_rate ops members. + +Prior to the conversion, pic32_sclk_ops already had a determine_rate +member that points to __clk_mux_determine_rate(). When both the +round_rate() and determine_rate() ops are defined, the clk core only +uses the determine_rate() op. Let's go ahead and drop the recently +converted sclk_determine_rate() to match the previous functionality +prior to the conversion. + +Fixes: e9f039c08cdc ("clk: microchip: core: convert from round_rate() to determine_rate()") +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202511222115.uvHrP95A-lkp@intel.com/ +Signed-off-by: Brian Masney +Reviewed-by: Claudiu Beznea +Link: https://lore.kernel.org/r/20251205-clk-microchip-fixes-v3-1-a02190705e47@redhat.com +Signed-off-by: Claudiu Beznea +Signed-off-by: Sasha Levin +--- + drivers/clk/microchip/clk-core.c | 10 ---------- + 1 file changed, 10 deletions(-) + +diff --git a/drivers/clk/microchip/clk-core.c b/drivers/clk/microchip/clk-core.c +index b34348d491f3e..a0163441dfe5c 100644 +--- a/drivers/clk/microchip/clk-core.c ++++ b/drivers/clk/microchip/clk-core.c +@@ -780,15 +780,6 @@ static unsigned long sclk_get_rate(struct clk_hw *hw, unsigned long parent_rate) + return parent_rate / div; + } + +-static int sclk_determine_rate(struct clk_hw *hw, +- struct clk_rate_request *req) +-{ +- req->rate = calc_best_divided_rate(req->rate, req->best_parent_rate, +- SLEW_SYSDIV, 1); +- +- return 0; +-} +- + static int sclk_set_rate(struct clk_hw *hw, + unsigned long rate, unsigned long parent_rate) + { +@@ -912,7 +903,6 @@ static int sclk_init(struct clk_hw *hw) + const struct clk_ops pic32_sclk_ops = { + .get_parent = sclk_get_parent, + .set_parent = sclk_set_parent, +- .determine_rate = sclk_determine_rate, + .set_rate = sclk_set_rate, + .recalc_rate = sclk_get_rate, + .init = sclk_init, +-- +2.51.0 + diff --git a/queue-6.18/clk-milbeaut-convert-from-divider_round_rate-to-divi.patch b/queue-6.18/clk-milbeaut-convert-from-divider_round_rate-to-divi.patch new file mode 100644 index 0000000000..9b015ed328 --- /dev/null +++ b/queue-6.18/clk-milbeaut-convert-from-divider_round_rate-to-divi.patch @@ -0,0 +1,48 @@ +From f579b3a8de86a8b72159516dfe2d293731482c12 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:16:29 -0500 +Subject: clk: milbeaut: convert from divider_round_rate() to + divider_determine_rate() + +From: Brian Masney + +[ Upstream commit 865e63b038c446d38593ddbcc362ebb62e6ff007 ] + +The divider_round_rate() function is now deprecated, so let's migrate +to divider_determine_rate() instead so that this deprecated API can be +removed. + +Note that when the main function itself was migrated to use +determine_rate, this was mistakenly converted to: + + req->rate = divider_round_rate(...) + +This is invalid in the case when an error occurs since it can set the +rate to a negative value. + +Fixes: 7b45988fcf78 ("clk: milbeaut: convert from round_rate() to determine_rate()") +Signed-off-by: Brian Masney +Signed-off-by: Sasha Levin +--- + drivers/clk/clk-milbeaut.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/drivers/clk/clk-milbeaut.c b/drivers/clk/clk-milbeaut.c +index b4f9b7143eaa6..bb94d02a76cf1 100644 +--- a/drivers/clk/clk-milbeaut.c ++++ b/drivers/clk/clk-milbeaut.c +@@ -407,10 +407,7 @@ static int m10v_clk_divider_determine_rate(struct clk_hw *hw, + return 0; + } + +- req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, +- divider->table, divider->width, divider->flags); +- +- return 0; ++ return divider_determine_rate(hw, req, divider->table, divider->width, divider->flags); + } + + static int m10v_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, +-- +2.51.0 + diff --git a/queue-6.18/clk-move-clk_-save-restore-_context-to-common_clk-se.patch b/queue-6.18/clk-move-clk_-save-restore-_context-to-common_clk-se.patch new file mode 100644 index 0000000000..249c105fe9 --- /dev/null +++ b/queue-6.18/clk-move-clk_-save-restore-_context-to-common_clk-se.patch @@ -0,0 +1,117 @@ +From beafc13b01125669d2e542a306b446851badc441 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Dec 2025 10:42:26 +0100 +Subject: clk: Move clk_{save,restore}_context() to COMMON_CLK section + +From: Geert Uytterhoeven + +[ Upstream commit f47c1b77d0a2a9c0d49ec14302e74f933398d1a3 ] + +The clk_save_context() and clk_restore_context() helpers are only +implemented by the Common Clock Framework. They are not available when +using legacy clock frameworks. Dummy implementations are provided, but +only if no clock support is available at all. + +Hence when CONFIG_HAVE_CLK=y, but CONFIG_COMMON_CLK is not enabled: + + m68k-linux-gnu-ld: drivers/net/phy/air_en8811h.o: in function `en8811h_resume': + air_en8811h.c:(.text+0x83e): undefined reference to `clk_restore_context' + m68k-linux-gnu-ld: drivers/net/phy/air_en8811h.o: in function `en8811h_suspend': + air_en8811h.c:(.text+0x856): undefined reference to `clk_save_context' + +Fix this by moving forward declarations and dummy implementions from the +HAVE_CLK to the COMMON_CLK section. + +Fixes: 8b95d1ce3300c411 ("clk: Add functions to save/restore clock context en-masse") +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202511301553.eaEz1nEW-lkp@intel.com/ +Signed-off-by: Geert Uytterhoeven +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + include/linux/clk.h | 48 ++++++++++++++++++++++----------------------- + 1 file changed, 24 insertions(+), 24 deletions(-) + +diff --git a/include/linux/clk.h b/include/linux/clk.h +index b607482ca77e9..64ff118ffb1a1 100644 +--- a/include/linux/clk.h ++++ b/include/linux/clk.h +@@ -228,6 +228,23 @@ int devm_clk_rate_exclusive_get(struct device *dev, struct clk *clk); + */ + void clk_rate_exclusive_put(struct clk *clk); + ++/** ++ * clk_save_context - save clock context for poweroff ++ * ++ * Saves the context of the clock register for powerstates in which the ++ * contents of the registers will be lost. Occurs deep within the suspend ++ * code so locking is not necessary. ++ */ ++int clk_save_context(void); ++ ++/** ++ * clk_restore_context - restore clock context after poweroff ++ * ++ * This occurs with all clocks enabled. Occurs deep within the resume code ++ * so locking is not necessary. ++ */ ++void clk_restore_context(void); ++ + #else + + static inline int clk_notifier_register(struct clk *clk, +@@ -293,6 +310,13 @@ static inline int devm_clk_rate_exclusive_get(struct device *dev, struct clk *cl + + static inline void clk_rate_exclusive_put(struct clk *clk) {} + ++static inline int clk_save_context(void) ++{ ++ return 0; ++} ++ ++static inline void clk_restore_context(void) {} ++ + #endif + + #ifdef CONFIG_HAVE_CLK_PREPARE +@@ -933,23 +957,6 @@ struct clk *clk_get_parent(struct clk *clk); + */ + struct clk *clk_get_sys(const char *dev_id, const char *con_id); + +-/** +- * clk_save_context - save clock context for poweroff +- * +- * Saves the context of the clock register for powerstates in which the +- * contents of the registers will be lost. Occurs deep within the suspend +- * code so locking is not necessary. +- */ +-int clk_save_context(void); +- +-/** +- * clk_restore_context - restore clock context after poweroff +- * +- * This occurs with all clocks enabled. Occurs deep within the resume code +- * so locking is not necessary. +- */ +-void clk_restore_context(void); +- + #else /* !CONFIG_HAVE_CLK */ + + static inline struct clk *clk_get(struct device *dev, const char *id) +@@ -1129,13 +1136,6 @@ static inline struct clk *clk_get_sys(const char *dev_id, const char *con_id) + return NULL; + } + +-static inline int clk_save_context(void) +-{ +- return 0; +-} +- +-static inline void clk_restore_context(void) {} +- + #endif + + /* clk_prepare_enable helps cases using clk_enable in non-atomic context. */ +-- +2.51.0 + diff --git a/queue-6.18/clk-nuvoton-ma35d1-divider-convert-from-divider_roun.patch b/queue-6.18/clk-nuvoton-ma35d1-divider-convert-from-divider_roun.patch new file mode 100644 index 0000000000..972133f96a --- /dev/null +++ b/queue-6.18/clk-nuvoton-ma35d1-divider-convert-from-divider_roun.patch @@ -0,0 +1,50 @@ +From 60e05658e9f20306af26a532562187d9f24b5e4e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:16:30 -0500 +Subject: clk: nuvoton: ma35d1-divider: convert from divider_round_rate() to + divider_determine_rate() + +From: Brian Masney + +[ Upstream commit 9329d784ca9aad03b12508128797d40fd1f2e0c1 ] + +The divider_round_rate() function is now deprecated, so let's migrate +to divider_determine_rate() instead so that this deprecated API can be +removed. + +Note that when the main function itself was migrated to use +determine_rate, this was mistakenly converted to: + + req->rate = divider_round_rate(...) + +This is invalid in the case when an error occurs since it can set the +rate to a negative value. + +Fixes: 215f8aa095a1 ("clk: nuvoton: ma35d1-divider: convert from round_rate() to determine_rate()") +Signed-off-by: Brian Masney +Signed-off-by: Sasha Levin +--- + drivers/clk/nuvoton/clk-ma35d1-divider.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/drivers/clk/nuvoton/clk-ma35d1-divider.c b/drivers/clk/nuvoton/clk-ma35d1-divider.c +index e39f53d5bf457..e992e7c303419 100644 +--- a/drivers/clk/nuvoton/clk-ma35d1-divider.c ++++ b/drivers/clk/nuvoton/clk-ma35d1-divider.c +@@ -44,11 +44,8 @@ static int ma35d1_clkdiv_determine_rate(struct clk_hw *hw, + { + struct ma35d1_adc_clk_div *dclk = to_ma35d1_adc_clk_div(hw); + +- req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, +- dclk->table, dclk->width, +- CLK_DIVIDER_ROUND_CLOSEST); +- +- return 0; ++ return divider_determine_rate(hw, req, dclk->table, dclk->width, ++ CLK_DIVIDER_ROUND_CLOSEST); + } + + static int ma35d1_clkdiv_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) +-- +2.51.0 + diff --git a/queue-6.18/clk-nxp-lpc32xx-convert-from-divider_round_rate-to-d.patch b/queue-6.18/clk-nxp-lpc32xx-convert-from-divider_round_rate-to-d.patch new file mode 100644 index 0000000000..5f05fef3a1 --- /dev/null +++ b/queue-6.18/clk-nxp-lpc32xx-convert-from-divider_round_rate-to-d.patch @@ -0,0 +1,51 @@ +From fe12919a15b0cd9851327402955bb9ee0e946548 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:16:31 -0500 +Subject: clk: nxp: lpc32xx: convert from divider_round_rate() to + divider_determine_rate() + +From: Brian Masney + +[ Upstream commit af943663ccc266e6346e5645b13c0fca71d24395 ] + +The divider_round_rate() function is now deprecated, so let's migrate +to divider_determine_rate() instead so that this deprecated API can be +removed. + +Note that when the main function itself was migrated to use +determine_rate, this was mistakenly converted to: + + req->rate = divider_round_rate(...) + +This is invalid in the case when an error occurs since it can set the +rate to a negative value. + +Fixes: 0879768df240 ("clk: nxp: lpc32xx: convert from round_rate() to determine_rate()") +Tested-by: Vladimir Zapolskiy +Reviewed-by: Vladimir Zapolskiy +Signed-off-by: Brian Masney +Signed-off-by: Sasha Levin +--- + drivers/clk/nxp/clk-lpc32xx.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/clk/nxp/clk-lpc32xx.c b/drivers/clk/nxp/clk-lpc32xx.c +index 23f980cf6a2b5..ae2fa5341a2e4 100644 +--- a/drivers/clk/nxp/clk-lpc32xx.c ++++ b/drivers/clk/nxp/clk-lpc32xx.c +@@ -975,10 +975,8 @@ static int clk_divider_determine_rate(struct clk_hw *hw, + return 0; + } + +- req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, +- divider->table, divider->width, divider->flags); +- +- return 0; ++ return divider_determine_rate(hw, req, divider->table, divider->width, ++ divider->flags); + } + + static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, +-- +2.51.0 + diff --git a/queue-6.18/clk-qcom-alpha-pll-convert-from-divider_round_rate-t.patch b/queue-6.18/clk-qcom-alpha-pll-convert-from-divider_round_rate-t.patch new file mode 100644 index 0000000000..19d881027b --- /dev/null +++ b/queue-6.18/clk-qcom-alpha-pll-convert-from-divider_round_rate-t.patch @@ -0,0 +1,82 @@ +From ba8d6f7b63a01868decf8605f4771183fcda74c5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:16:32 -0500 +Subject: clk: qcom: alpha-pll: convert from divider_round_rate() to + divider_determine_rate() + +From: Brian Masney + +[ Upstream commit e1f08613e113f02a3ec18c9a7964de97f940acbf ] + +The divider_round_rate() function is now deprecated, so let's migrate +to divider_determine_rate() instead so that this deprecated API can be +removed. + +Note that when the main function itself was migrated to use +determine_rate, this was mistakenly converted to: + + req->rate = divider_round_rate(...) + +This is invalid in the case when an error occurs since it can set the +rate to a negative value. + +Fixes: 0e56e3369b60 ("clk: qcom: alpha-pll: convert from round_rate() to determine_rate()") +Signed-off-by: Brian Masney +Reviewed-by: Abel Vesa +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260108-clk-divider-round-rate-v1-14-535a3ed73bf3@redhat.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/clk-alpha-pll.c | 21 ++++++--------------- + 1 file changed, 6 insertions(+), 15 deletions(-) + +diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c +index 6aeba40358c11..a84e8bee65346 100644 +--- a/drivers/clk/qcom/clk-alpha-pll.c ++++ b/drivers/clk/qcom/clk-alpha-pll.c +@@ -1257,11 +1257,8 @@ static int clk_alpha_pll_postdiv_determine_rate(struct clk_hw *hw, + else + table = clk_alpha_div_table; + +- req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, +- table, pll->width, +- CLK_DIVIDER_POWER_OF_TWO); +- +- return 0; ++ return divider_determine_rate(hw, req, table, pll->width, ++ CLK_DIVIDER_POWER_OF_TWO); + } + + static int clk_alpha_pll_postdiv_ro_determine_rate(struct clk_hw *hw, +@@ -1617,11 +1614,8 @@ static int clk_trion_pll_postdiv_determine_rate(struct clk_hw *hw, + { + struct clk_alpha_pll_postdiv *pll = to_clk_alpha_pll_postdiv(hw); + +- req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, +- pll->post_div_table, +- pll->width, CLK_DIVIDER_ROUND_CLOSEST); +- +- return 0; ++ return divider_determine_rate(hw, req, pll->post_div_table, pll->width, ++ CLK_DIVIDER_ROUND_CLOSEST); + }; + + static int +@@ -1657,11 +1651,8 @@ static int clk_alpha_pll_postdiv_fabia_determine_rate(struct clk_hw *hw, + { + struct clk_alpha_pll_postdiv *pll = to_clk_alpha_pll_postdiv(hw); + +- req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, +- pll->post_div_table, +- pll->width, CLK_DIVIDER_ROUND_CLOSEST); +- +- return 0; ++ return divider_determine_rate(hw, req, pll->post_div_table, pll->width, ++ CLK_DIVIDER_ROUND_CLOSEST); + } + + static int clk_alpha_pll_postdiv_fabia_set_rate(struct clk_hw *hw, +-- +2.51.0 + diff --git a/queue-6.18/clk-qcom-dispcc-sdm845-enable-parents-for-pixel-cloc.patch b/queue-6.18/clk-qcom-dispcc-sdm845-enable-parents-for-pixel-cloc.patch new file mode 100644 index 0000000000..4ac160e614 --- /dev/null +++ b/queue-6.18/clk-qcom-dispcc-sdm845-enable-parents-for-pixel-cloc.patch @@ -0,0 +1,49 @@ +From 5e43003635af0abf5caa7a6d3ad3d6284d158b97 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 12:44:43 +0100 +Subject: clk: qcom: dispcc-sdm845: Enable parents for pixel clocks + +From: Petr Hodina + +[ Upstream commit a1d63493634e98360140027fef49d82b1ff0a267 ] + +Add CLK_OPS_PARENT_ENABLE to MDSS pixel clock sources to ensure parent +clocks are enabled during clock operations, preventing potential +stability issues during display configuration. + +Fixes: 81351776c9fb ("clk: qcom: Add display clock controller driver for SDM845") +Signed-off-by: Petr Hodina +Reviewed-by: Dmitry Baryshkov +Reviewed-by: David Heidelberg +Link: https://lore.kernel.org/r/20260107-stability-discussion-v2-1-ef7717b435ff@protonmail.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sdm845.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/dispcc-sdm845.c b/drivers/clk/qcom/dispcc-sdm845.c +index 2f9e9665d7e93..78e43f6d75026 100644 +--- a/drivers/clk/qcom/dispcc-sdm845.c ++++ b/drivers/clk/qcom/dispcc-sdm845.c +@@ -280,7 +280,7 @@ static struct clk_rcg2 disp_cc_mdss_pclk0_clk_src = { + .name = "disp_cc_mdss_pclk0_clk_src", + .parent_data = disp_cc_parent_data_4, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_4), +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .ops = &clk_pixel_ops, + }, + }; +@@ -295,7 +295,7 @@ static struct clk_rcg2 disp_cc_mdss_pclk1_clk_src = { + .name = "disp_cc_mdss_pclk1_clk_src", + .parent_data = disp_cc_parent_data_4, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_4), +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .ops = &clk_pixel_ops, + }, + }; +-- +2.51.0 + diff --git a/queue-6.18/clk-qcom-dispcc-sm7150-fix-dispcc_mdss_pclk1_clk_src.patch b/queue-6.18/clk-qcom-dispcc-sm7150-fix-dispcc_mdss_pclk1_clk_src.patch new file mode 100644 index 0000000000..d146cae3cd --- /dev/null +++ b/queue-6.18/clk-qcom-dispcc-sm7150-fix-dispcc_mdss_pclk1_clk_src.patch @@ -0,0 +1,37 @@ +From 9cf1825e8c4ce8705c4a87b2e331729f5567ee8c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 17 Jan 2026 19:18:28 +0100 +Subject: clk: qcom: dispcc-sm7150: Fix dispcc_mdss_pclk1_clk_src + +From: David Heidelberg + +[ Upstream commit fab13d738c9bd645965464b881335f580d38a54e ] + +Set CLK_OPS_PARENT_ENABLE to ensure the parent gets prepared and enabled +when switching to it. + +Fixes: e3c13e0caa8c ("clk: qcom: dispcc-sm7150: Fix dispcc_mdss_pclk0_clk_src") +Signed-off-by: David Heidelberg +Link: https://lore.kernel.org/r/20260117-sm7150-dispcc-fix-v1-1-2f39966bcad2@ixit.cz +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sm7150.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/qcom/dispcc-sm7150.c b/drivers/clk/qcom/dispcc-sm7150.c +index ddc7230b8aea7..923f0f38e804c 100644 +--- a/drivers/clk/qcom/dispcc-sm7150.c ++++ b/drivers/clk/qcom/dispcc-sm7150.c +@@ -370,7 +370,7 @@ static struct clk_rcg2 dispcc_mdss_pclk1_clk_src = { + .name = "dispcc_mdss_pclk1_clk_src", + .parent_data = dispcc_parent_data_4, + .num_parents = ARRAY_SIZE(dispcc_parent_data_4), +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .ops = &clk_pixel_ops, + }, + }; +-- +2.51.0 + diff --git a/queue-6.18/clk-qcom-gcc-glymur-update-the-sdcc-rcgs-to-use-shar.patch b/queue-6.18/clk-qcom-gcc-glymur-update-the-sdcc-rcgs-to-use-shar.patch new file mode 100644 index 0000000000..3eb0c28302 --- /dev/null +++ b/queue-6.18/clk-qcom-gcc-glymur-update-the-sdcc-rcgs-to-use-shar.patch @@ -0,0 +1,51 @@ +From abb88455ae743cfb9fb8d52c54cd433e9b7ec661 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Nov 2025 23:27:43 +0530 +Subject: clk: qcom: gcc-glymur: Update the SDCC RCGs to use shared_floor_ops + +From: Jagadeesh Kona + +[ Upstream commit d5639a6d72810023d257c935cb763aea1ada1abc ] + +Use shared_floor_ops for the SDCC RCGs so the RCG is safely parked +during disable and the new parent configuration is programmed in +hardware only when the new parent is enabled, avoiding cases where +the RCG configuration fails to update. + +Fixes: efe504300a17 ("clk: qcom: gcc: Add support for Global Clock Controller") +Signed-off-by: Jagadeesh Kona +Reviewed-by: Imran Shaik +Reviewed-by: Taniya Das +Reviewed-by: Vladimir Zapolskiy +Link: https://lore.kernel.org/r/20251127-sdcc_shared_floor_ops-v2-8-473afc86589c@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-glymur.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-glymur.c b/drivers/clk/qcom/gcc-glymur.c +index d938e7dc5b66e..17e860307fa10 100644 +--- a/drivers/clk/qcom/gcc-glymur.c ++++ b/drivers/clk/qcom/gcc-glymur.c +@@ -2317,7 +2317,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .parent_data = gcc_parent_data_17, + .num_parents = ARRAY_SIZE(gcc_parent_data_17), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +@@ -2339,7 +2339,7 @@ static struct clk_rcg2 gcc_sdcc4_apps_clk_src = { + .parent_data = gcc_parent_data_3, + .num_parents = ARRAY_SIZE(gcc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +-- +2.51.0 + diff --git a/queue-6.18/clk-qcom-gcc-ipq5018-flag-sleep-clock-as-critical.patch b/queue-6.18/clk-qcom-gcc-ipq5018-flag-sleep-clock-as-critical.patch new file mode 100644 index 0000000000..edf36a28a1 --- /dev/null +++ b/queue-6.18/clk-qcom-gcc-ipq5018-flag-sleep-clock-as-critical.patch @@ -0,0 +1,37 @@ +From 34df16139376961b6afc2648a65ab7d11cf797ed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 15:03:19 +0400 +Subject: clk: qcom: gcc-ipq5018: flag sleep clock as critical + +From: George Moussalem + +[ Upstream commit 04c4dc1f541135708d90a9b4632af51136f93ac3 ] + +The sleep clock never be disabled. To avoid the kernel trying to disable +it and keep it always on, flag it as critical. + +Fixes: e3fdbef1bab8 ("clk: qcom: Add Global Clock controller (GCC) driver for IPQ5018") +Signed-off-by: George Moussalem +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251128-ipq5018-sleep-clk-fix-v1-1-6f4b75ec336c@outlook.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-ipq5018.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/clk/qcom/gcc-ipq5018.c b/drivers/clk/qcom/gcc-ipq5018.c +index dcda2be8c1a51..64792cda06202 100644 +--- a/drivers/clk/qcom/gcc-ipq5018.c ++++ b/drivers/clk/qcom/gcc-ipq5018.c +@@ -1340,6 +1340,7 @@ static struct clk_branch gcc_sleep_clk_src = { + .name = "gcc_sleep_clk_src", + .parent_data = gcc_sleep_clk_data, + .num_parents = ARRAY_SIZE(gcc_sleep_clk_data), ++ .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +-- +2.51.0 + diff --git a/queue-6.18/clk-qcom-gcc-milos-update-the-sdcc-rcgs-to-use-share.patch b/queue-6.18/clk-qcom-gcc-milos-update-the-sdcc-rcgs-to-use-share.patch new file mode 100644 index 0000000000..bf4df6897a --- /dev/null +++ b/queue-6.18/clk-qcom-gcc-milos-update-the-sdcc-rcgs-to-use-share.patch @@ -0,0 +1,59 @@ +From f67132eeeaff27bb6ed238ca4689f5a8ded1810f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Nov 2025 23:27:40 +0530 +Subject: clk: qcom: gcc-milos: Update the SDCC RCGs to use shared_floor_ops + +From: Jagadeesh Kona + +[ Upstream commit 08da8d7dabb161cea14c6d3ad9b5037aaf6d4b7e ] + +Use shared_floor_ops for the SDCC RCGs to avoid any overclocking +issues in SDCC usecases. + +Fixes: 88174d5d9422 ("clk: qcom: Add Global Clock controller (GCC) driver for Milos") +Reviewed-by: Taniya Das +Reviewed-by: Imran Shaik +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Vladimir Zapolskiy +Signed-off-by: Jagadeesh Kona +Link: https://lore.kernel.org/r/20251127-sdcc_shared_floor_ops-v2-5-473afc86589c@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-milos.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-milos.c b/drivers/clk/qcom/gcc-milos.c +index c9d61b05bafa1..81fa09ec55d7f 100644 +--- a/drivers/clk/qcom/gcc-milos.c ++++ b/drivers/clk/qcom/gcc-milos.c +@@ -917,7 +917,7 @@ static struct clk_rcg2 gcc_sdcc1_apps_clk_src = { + .name = "gcc_sdcc1_apps_clk_src", + .parent_data = gcc_parent_data_9, + .num_parents = ARRAY_SIZE(gcc_parent_data_9), +- .ops = &clk_rcg2_shared_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +@@ -938,7 +938,7 @@ static struct clk_rcg2 gcc_sdcc1_ice_core_clk_src = { + .name = "gcc_sdcc1_ice_core_clk_src", + .parent_data = gcc_parent_data_10, + .num_parents = ARRAY_SIZE(gcc_parent_data_10), +- .ops = &clk_rcg2_shared_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +@@ -962,7 +962,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .name = "gcc_sdcc2_apps_clk_src", + .parent_data = gcc_parent_data_11, + .num_parents = ARRAY_SIZE(gcc_parent_data_11), +- .ops = &clk_rcg2_shared_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +-- +2.51.0 + diff --git a/queue-6.18/clk-qcom-gcc-msm8917-remove-always_on-flag-from-cpp_.patch b/queue-6.18/clk-qcom-gcc-msm8917-remove-always_on-flag-from-cpp_.patch new file mode 100644 index 0000000000..eaafc15908 --- /dev/null +++ b/queue-6.18/clk-qcom-gcc-msm8917-remove-always_on-flag-from-cpp_.patch @@ -0,0 +1,39 @@ +From 8b3d0beac369ca4365c8f6c3978a2974df1b9a83 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 17 Nov 2025 18:58:48 +0100 +Subject: clk: qcom: gcc-msm8917: Remove ALWAYS_ON flag from cpp_gdsc +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Czémán + +[ Upstream commit e4eb42f290aecac0ba355b1f8d7243be6de11f32 ] + +cpp_gdsc should not be always on, ALWAYS_ON flag was set accidentally. + +Fixes: 33cc27a47d3a ("clk: qcom: Add global clock controller driver for MSM8917") +Signed-off-by: Barnabás Czémán +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251117-fix-gdsc-cpp-msm8917-msm8953-v1-2-db33adcff28a@mainlining.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-msm8917.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/clk/qcom/gcc-msm8917.c b/drivers/clk/qcom/gcc-msm8917.c +index 0a1aa623cd49a..9d1c5a9953e2c 100644 +--- a/drivers/clk/qcom/gcc-msm8917.c ++++ b/drivers/clk/qcom/gcc-msm8917.c +@@ -3409,7 +3409,6 @@ static struct gdsc cpp_gdsc = { + .pd = { + .name = "cpp_gdsc", + }, +- .flags = ALWAYS_ON, + .pwrsts = PWRSTS_OFF_ON, + }; + +-- +2.51.0 + diff --git a/queue-6.18/clk-qcom-gcc-msm8953-remove-always_on-flag-from-cpp_.patch b/queue-6.18/clk-qcom-gcc-msm8953-remove-always_on-flag-from-cpp_.patch new file mode 100644 index 0000000000..87c6a25108 --- /dev/null +++ b/queue-6.18/clk-qcom-gcc-msm8953-remove-always_on-flag-from-cpp_.patch @@ -0,0 +1,39 @@ +From abb21abcd631a2749cfefb9cf1fe6553c8a80ca7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 17 Nov 2025 18:58:47 +0100 +Subject: clk: qcom: gcc-msm8953: Remove ALWAYS_ON flag from cpp_gdsc +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Czémán + +[ Upstream commit 5f613e7034187179a9d088ff5fd02b1089d0cf20 ] + +cpp_gdsc should not be always on, ALWAYS_ON flag was set accidentally. + +Fixes: 9bb6cfc3c77e ("clk: qcom: Add Global Clock Controller driver for MSM8953") +Signed-off-by: Barnabás Czémán +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251117-fix-gdsc-cpp-msm8917-msm8953-v1-1-db33adcff28a@mainlining.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-msm8953.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/clk/qcom/gcc-msm8953.c b/drivers/clk/qcom/gcc-msm8953.c +index 8f29ecc74c50b..8fe1d3e421440 100644 +--- a/drivers/clk/qcom/gcc-msm8953.c ++++ b/drivers/clk/qcom/gcc-msm8953.c +@@ -3946,7 +3946,6 @@ static struct gdsc cpp_gdsc = { + .pd = { + .name = "cpp_gdsc", + }, +- .flags = ALWAYS_ON, + .pwrsts = PWRSTS_OFF_ON, + }; + +-- +2.51.0 + diff --git a/queue-6.18/clk-qcom-gcc-qdu1000-update-the-sdcc-rcgs-to-use-sha.patch b/queue-6.18/clk-qcom-gcc-qdu1000-update-the-sdcc-rcgs-to-use-sha.patch new file mode 100644 index 0000000000..dadf6b78cb --- /dev/null +++ b/queue-6.18/clk-qcom-gcc-qdu1000-update-the-sdcc-rcgs-to-use-sha.patch @@ -0,0 +1,51 @@ +From 09a0d22f7fa0f20bb43103fc532643dea7ad302e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Nov 2025 23:27:42 +0530 +Subject: clk: qcom: gcc-qdu1000: Update the SDCC RCGs to use shared_floor_ops + +From: Jagadeesh Kona + +[ Upstream commit 947c4b326c1f4dc64aed42170b39c2cf551ba8ca ] + +Use shared_floor_ops for the SDCC RCGs so the RCG is safely parked +during disable and the new parent configuration is programmed in +hardware only when the new parent is enabled, avoiding cases where +the RCG configuration fails to update. + +Fixes: baa316580013 ("clk: qcom: gcc-qdu1000: Update the SDCC clock RCG ops") +Signed-off-by: Jagadeesh Kona +Reviewed-by: Imran Shaik +Reviewed-by: Taniya Das +Reviewed-by: Vladimir Zapolskiy +Link: https://lore.kernel.org/r/20251127-sdcc_shared_floor_ops-v2-7-473afc86589c@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-qdu1000.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-qdu1000.c b/drivers/clk/qcom/gcc-qdu1000.c +index dbe9e9437939a..915bb9b4ff813 100644 +--- a/drivers/clk/qcom/gcc-qdu1000.c ++++ b/drivers/clk/qcom/gcc-qdu1000.c +@@ -904,7 +904,7 @@ static struct clk_rcg2 gcc_sdcc5_apps_clk_src = { + .name = "gcc_sdcc5_apps_clk_src", + .parent_data = gcc_parent_data_8, + .num_parents = ARRAY_SIZE(gcc_parent_data_8), +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +@@ -923,7 +923,7 @@ static struct clk_rcg2 gcc_sdcc5_ice_core_clk_src = { + .name = "gcc_sdcc5_ice_core_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = ARRAY_SIZE(gcc_parent_data_2), +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +-- +2.51.0 + diff --git a/queue-6.18/clk-qcom-gcc-sdx75-update-the-sdcc-rcgs-to-use-share.patch b/queue-6.18/clk-qcom-gcc-sdx75-update-the-sdcc-rcgs-to-use-share.patch new file mode 100644 index 0000000000..8cdb0434ce --- /dev/null +++ b/queue-6.18/clk-qcom-gcc-sdx75-update-the-sdcc-rcgs-to-use-share.patch @@ -0,0 +1,52 @@ +From 05c2107debeb58af30e4d10d00253b83c2e1fec8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Nov 2025 23:27:39 +0530 +Subject: clk: qcom: gcc-sdx75: Update the SDCC RCGs to use shared_floor_ops + +From: Jagadeesh Kona + +[ Upstream commit 4b057462bb61a6571608ba393e6e018c9da9c9c3 ] + +Use shared_floor_ops for the SDCC RCGs so the RCG is safely parked +during disable and the new parent configuration is programmed in +hardware only when the new parent is enabled, avoiding cases where +the RCG configuration fails to update. + +Fixes: 108cdc09b2de ("clk: qcom: Add GCC driver support for SDX75") +Reviewed-by: Taniya Das +Reviewed-by: Imran Shaik +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Vladimir Zapolskiy +Signed-off-by: Jagadeesh Kona +Link: https://lore.kernel.org/r/20251127-sdcc_shared_floor_ops-v2-4-473afc86589c@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-sdx75.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-sdx75.c b/drivers/clk/qcom/gcc-sdx75.c +index 453a6bf8e8786..1f3cd58483a2d 100644 +--- a/drivers/clk/qcom/gcc-sdx75.c ++++ b/drivers/clk/qcom/gcc-sdx75.c +@@ -1033,7 +1033,7 @@ static struct clk_rcg2 gcc_sdcc1_apps_clk_src = { + .name = "gcc_sdcc1_apps_clk_src", + .parent_data = gcc_parent_data_17, + .num_parents = ARRAY_SIZE(gcc_parent_data_17), +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +@@ -1057,7 +1057,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .name = "gcc_sdcc2_apps_clk_src", + .parent_data = gcc_parent_data_18, + .num_parents = ARRAY_SIZE(gcc_parent_data_18), +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +-- +2.51.0 + diff --git a/queue-6.18/clk-qcom-gcc-sm4450-update-the-sdcc-rcgs-to-use-shar.patch b/queue-6.18/clk-qcom-gcc-sm4450-update-the-sdcc-rcgs-to-use-shar.patch new file mode 100644 index 0000000000..bf46b9eadf --- /dev/null +++ b/queue-6.18/clk-qcom-gcc-sm4450-update-the-sdcc-rcgs-to-use-shar.patch @@ -0,0 +1,61 @@ +From 7b3a5f568e62c923924bb9cd10c44294a9ebad26 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Nov 2025 23:27:38 +0530 +Subject: clk: qcom: gcc-sm4450: Update the SDCC RCGs to use shared_floor_ops + +From: Jagadeesh Kona + +[ Upstream commit 458e8a082186335380a9ab83003a385aec9bb254 ] + +Use shared_floor_ops for the SDCC RCGs so the RCG is safely parked +during disable and the new parent configuration is programmed in +hardware only when the new parent is enabled, avoiding cases where +the RCG configuration fails to update. + +Fixes: c32c4ef98bac ("clk: qcom: Add GCC driver support for SM4450") +Reviewed-by: Taniya Das +Reviewed-by: Imran Shaik +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Vladimir Zapolskiy +Signed-off-by: Jagadeesh Kona +Link: https://lore.kernel.org/r/20251127-sdcc_shared_floor_ops-v2-3-473afc86589c@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-sm4450.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-sm4450.c b/drivers/clk/qcom/gcc-sm4450.c +index e2d9e4691c5b7..023d840e9f4ef 100644 +--- a/drivers/clk/qcom/gcc-sm4450.c ++++ b/drivers/clk/qcom/gcc-sm4450.c +@@ -769,7 +769,7 @@ static struct clk_rcg2 gcc_sdcc1_apps_clk_src = { + .parent_data = gcc_parent_data_4, + .num_parents = ARRAY_SIZE(gcc_parent_data_4), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +@@ -791,7 +791,7 @@ static struct clk_rcg2 gcc_sdcc1_ice_core_clk_src = { + .parent_data = gcc_parent_data_4, + .num_parents = ARRAY_SIZE(gcc_parent_data_4), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +@@ -815,7 +815,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .parent_data = gcc_parent_data_6, + .num_parents = ARRAY_SIZE(gcc_parent_data_6), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +-- +2.51.0 + diff --git a/queue-6.18/clk-qcom-gcc-sm8450-update-the-sdcc-rcgs-to-use-shar.patch b/queue-6.18/clk-qcom-gcc-sm8450-update-the-sdcc-rcgs-to-use-shar.patch new file mode 100644 index 0000000000..80cbc42b02 --- /dev/null +++ b/queue-6.18/clk-qcom-gcc-sm8450-update-the-sdcc-rcgs-to-use-shar.patch @@ -0,0 +1,52 @@ +From d0a82ecb847aa907223661b8119b9fef92f2ef18 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Nov 2025 23:27:36 +0530 +Subject: clk: qcom: gcc-sm8450: Update the SDCC RCGs to use shared_floor_ops + +From: Jagadeesh Kona + +[ Upstream commit 89428516f99572a9c37ebbb7859595881e7025a0 ] + +Use shared_floor_ops for the SDCC RCGs so the RCG is safely parked +during disable and the new parent configuration is programmed in +hardware only when the new parent is enabled, avoiding cases where +the RCG configuration fails to update. + +Fixes: a27ac3806b0a ("clk: qcom: gcc-sm8450: Use floor ops for SDCC RCGs") +Reviewed-by: Taniya Das +Reviewed-by: Imran Shaik +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Vladimir Zapolskiy +Signed-off-by: Jagadeesh Kona +Link: https://lore.kernel.org/r/20251127-sdcc_shared_floor_ops-v2-1-473afc86589c@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-sm8450.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-sm8450.c b/drivers/clk/qcom/gcc-sm8450.c +index 65d7d52bce034..b18bb34889ab2 100644 +--- a/drivers/clk/qcom/gcc-sm8450.c ++++ b/drivers/clk/qcom/gcc-sm8450.c +@@ -1034,7 +1034,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .parent_data = gcc_parent_data_7, + .num_parents = ARRAY_SIZE(gcc_parent_data_7), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +@@ -1057,7 +1057,7 @@ static struct clk_rcg2 gcc_sdcc4_apps_clk_src = { + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +-- +2.51.0 + diff --git a/queue-6.18/clk-qcom-gcc-sm8550-use-floor-ops-for-sdcc-rcgs.patch b/queue-6.18/clk-qcom-gcc-sm8550-use-floor-ops-for-sdcc-rcgs.patch new file mode 100644 index 0000000000..0bc4ecb3f9 --- /dev/null +++ b/queue-6.18/clk-qcom-gcc-sm8550-use-floor-ops-for-sdcc-rcgs.patch @@ -0,0 +1,55 @@ +From 6959510ff7bbd2b67d47ea76f99c23c73dff7795 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 24 Nov 2025 23:20:11 +0200 +Subject: clk: qcom: gcc-sm8550: Use floor ops for SDCC RCGs + +From: Vladimir Zapolskiy + +[ Upstream commit 1c06e3956054fb5a0930f07b02726b1774b6c700 ] + +In line with commit a27ac3806b0a ("clk: qcom: gcc-sm8450: Use floor ops +for SDCC RCGs") done to fix issues with overclocked SD cards on SM8450 +powered boards set floor clock operations for SDCC RCGs on SM8550. + +This change fixes initialization of some SD cards, where the problem +is manifested by the SDHC driver: + + mmc0: Card appears overclocked; req 50000000 Hz, actual 100000000 Hz + mmc0: error -110 whilst initialising SD card + +Fixes: 955f2ea3b9e9 ("clk: qcom: Add GCC driver for SM8550") +Signed-off-by: Vladimir Zapolskiy +Reviewed-by: Neil Armstrong +Reviewed-by: Taniya Das +Link: https://lore.kernel.org/r/20251124212012.3660189-2-vladimir.zapolskiy@linaro.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-sm8550.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-sm8550.c b/drivers/clk/qcom/gcc-sm8550.c +index 862a9bf73bcb5..36a5b7de5b55d 100644 +--- a/drivers/clk/qcom/gcc-sm8550.c ++++ b/drivers/clk/qcom/gcc-sm8550.c +@@ -1025,7 +1025,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .parent_data = gcc_parent_data_9, + .num_parents = ARRAY_SIZE(gcc_parent_data_9), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_shared_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +@@ -1048,7 +1048,7 @@ static struct clk_rcg2 gcc_sdcc4_apps_clk_src = { + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_shared_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +-- +2.51.0 + diff --git a/queue-6.18/clk-qcom-gcc-sm8650-use-floor-ops-for-sdcc-rcgs.patch b/queue-6.18/clk-qcom-gcc-sm8650-use-floor-ops-for-sdcc-rcgs.patch new file mode 100644 index 0000000000..6ce7be999d --- /dev/null +++ b/queue-6.18/clk-qcom-gcc-sm8650-use-floor-ops-for-sdcc-rcgs.patch @@ -0,0 +1,55 @@ +From 16886873766d92f6d36508a97ce1317340a93934 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 24 Nov 2025 23:20:12 +0200 +Subject: clk: qcom: gcc-sm8650: Use floor ops for SDCC RCGs + +From: Vladimir Zapolskiy + +[ Upstream commit 8c4415fd17cd5979c31a4bf303acc702e9726033 ] + +In line with commit a27ac3806b0a ("clk: qcom: gcc-sm8450: Use floor ops +for SDCC RCGs") done to fix issues with overclocked SD cards on SM8450 +powered boards set floor clock operations for SDCC RCGs on SM8650. + +This change fixes initialization of some SD cards, where the problem +is manifested by the SDHC driver: + + mmc0: Card appears overclocked; req 50000000 Hz, actual 100000000 Hz + mmc0: error -110 whilst initialising SD card + +Fixes: c58225b7e3d7 ("clk: qcom: add the SM8650 Global Clock Controller driver, part 1") +Signed-off-by: Vladimir Zapolskiy +Reviewed-by: Neil Armstrong +Reviewed-by: Taniya Das +Link: https://lore.kernel.org/r/20251124212012.3660189-3-vladimir.zapolskiy@linaro.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-sm8650.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-sm8650.c b/drivers/clk/qcom/gcc-sm8650.c +index 24f98062b9dd5..2dd6444ce0365 100644 +--- a/drivers/clk/qcom/gcc-sm8650.c ++++ b/drivers/clk/qcom/gcc-sm8650.c +@@ -1257,7 +1257,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .parent_data = gcc_parent_data_11, + .num_parents = ARRAY_SIZE(gcc_parent_data_11), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_shared_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +@@ -1279,7 +1279,7 @@ static struct clk_rcg2 gcc_sdcc4_apps_clk_src = { + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_shared_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +-- +2.51.0 + diff --git a/queue-6.18/clk-qcom-gcc-sm8750-update-the-sdcc-rcgs-to-use-shar.patch b/queue-6.18/clk-qcom-gcc-sm8750-update-the-sdcc-rcgs-to-use-shar.patch new file mode 100644 index 0000000000..fd22f269ca --- /dev/null +++ b/queue-6.18/clk-qcom-gcc-sm8750-update-the-sdcc-rcgs-to-use-shar.patch @@ -0,0 +1,52 @@ +From 84a53d661ca6f0c3696aa1425f960dace17ea564 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Nov 2025 23:27:37 +0530 +Subject: clk: qcom: gcc-sm8750: Update the SDCC RCGs to use shared_floor_ops + +From: Jagadeesh Kona + +[ Upstream commit a7231d4aa084e485394f9214ec9bcb2d1f65dde9 ] + +Use shared_floor_ops for the SDCC RCGs so the RCG is safely parked +during disable and the new parent configuration is programmed in +hardware only when the new parent is enabled, avoiding cases where +the RCG configuration fails to update. + +Fixes: 3267c774f3ff ("clk: qcom: Add support for GCC on SM8750") +Reviewed-by: Taniya Das +Reviewed-by: Imran Shaik +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Vladimir Zapolskiy +Signed-off-by: Jagadeesh Kona +Link: https://lore.kernel.org/r/20251127-sdcc_shared_floor_ops-v2-2-473afc86589c@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-sm8750.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-sm8750.c b/drivers/clk/qcom/gcc-sm8750.c +index def86b71a3da5..db81569dd4b17 100644 +--- a/drivers/clk/qcom/gcc-sm8750.c ++++ b/drivers/clk/qcom/gcc-sm8750.c +@@ -1030,7 +1030,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .parent_data = gcc_parent_data_8, + .num_parents = ARRAY_SIZE(gcc_parent_data_8), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +@@ -1052,7 +1052,7 @@ static struct clk_rcg2 gcc_sdcc4_apps_clk_src = { + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +-- +2.51.0 + diff --git a/queue-6.18/clk-qcom-gcc-x1e80100-update-the-sdcc-rcgs-to-use-sh.patch b/queue-6.18/clk-qcom-gcc-x1e80100-update-the-sdcc-rcgs-to-use-sh.patch new file mode 100644 index 0000000000..276a7d44d8 --- /dev/null +++ b/queue-6.18/clk-qcom-gcc-x1e80100-update-the-sdcc-rcgs-to-use-sh.patch @@ -0,0 +1,50 @@ +From 16e2fbfa967047b0a1493eae6319a3cea81a1a55 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Nov 2025 23:27:41 +0530 +Subject: clk: qcom: gcc-x1e80100: Update the SDCC RCGs to use shared_floor_ops + +From: Jagadeesh Kona + +[ Upstream commit a468047c4e1c56783204a3ac551b843b4277c8fc ] + +Use shared_floor_ops for the SDCC RCGs so the RCG is safely parked +during disable and the new parent configuration is programmed in +hardware only when the new parent is enabled, avoiding cases where +the RCG configuration fails to update. + +Fixes: 161b7c401f4b ("clk: qcom: Add Global Clock controller (GCC) driver for X1E80100") +Signed-off-by: Jagadeesh Kona +Reviewed-by: Imran Shaik +Reviewed-by: Vladimir Zapolskiy +Link: https://lore.kernel.org/r/20251127-sdcc_shared_floor_ops-v2-6-473afc86589c@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-x1e80100.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-x1e80100.c b/drivers/clk/qcom/gcc-x1e80100.c +index 301fc9fc32d8e..ef8d2df188d3b 100644 +--- a/drivers/clk/qcom/gcc-x1e80100.c ++++ b/drivers/clk/qcom/gcc-x1e80100.c +@@ -1123,7 +1123,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .parent_data = gcc_parent_data_9, + .num_parents = ARRAY_SIZE(gcc_parent_data_9), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +@@ -1145,7 +1145,7 @@ static struct clk_rcg2 gcc_sdcc4_apps_clk_src = { + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +-- +2.51.0 + diff --git a/queue-6.18/clk-qcom-gfx3d-add-parent-to-parent-request-map.patch b/queue-6.18/clk-qcom-gfx3d-add-parent-to-parent-request-map.patch new file mode 100644 index 0000000000..b9612b6b84 --- /dev/null +++ b/queue-6.18/clk-qcom-gfx3d-add-parent-to-parent-request-map.patch @@ -0,0 +1,67 @@ +From 2af005b1a262c407a720e62184b7829e29eff6ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 17 Jan 2026 05:54:47 +0200 +Subject: clk: qcom: gfx3d: add parent to parent request map + +From: Dmitry Baryshkov + +[ Upstream commit 2583cb925ca1ce450aa5d74a05a67448db970193 ] + +After commit d228ece36345 ("clk: divider: remove round_rate() in favor +of determine_rate()") determining GFX3D clock rate crashes, because the +passed parent map doesn't provide the expected best_parent_hw clock +(with the roundd_rate path before the offending commit the +best_parent_hw was ignored). + +Set the field in parent_req in addition to setting it in the req, +fixing the crash. + + clk_hw_round_rate (drivers/clk/clk.c:1764) (P) + clk_divider_bestdiv (drivers/clk/clk-divider.c:336) + divider_determine_rate (drivers/clk/clk-divider.c:358) + clk_alpha_pll_postdiv_determine_rate (drivers/clk/qcom/clk-alpha-pll.c:1275) + clk_core_determine_round_nolock (drivers/clk/clk.c:1606) + clk_core_round_rate_nolock (drivers/clk/clk.c:1701) + __clk_determine_rate (drivers/clk/clk.c:1741) + clk_gfx3d_determine_rate (drivers/clk/qcom/clk-rcg2.c:1268) + clk_core_determine_round_nolock (drivers/clk/clk.c:1606) + clk_core_round_rate_nolock (drivers/clk/clk.c:1701) + clk_core_round_rate_nolock (drivers/clk/clk.c:1710) + clk_round_rate (drivers/clk/clk.c:1804) + dev_pm_opp_set_rate (drivers/opp/core.c:1440 (discriminator 1)) + msm_devfreq_target (drivers/gpu/drm/msm/msm_gpu_devfreq.c:51) + devfreq_set_target (drivers/devfreq/devfreq.c:360) + devfreq_update_target (drivers/devfreq/devfreq.c:426) + devfreq_monitor (drivers/devfreq/devfreq.c:458) + process_one_work (arch/arm64/include/asm/jump_label.h:36 include/trace/events/workqueue.h:110 kernel/workqueue.c:3284) + worker_thread (kernel/workqueue.c:3356 (discriminator 2) kernel/workqueue.c:3443 (discriminator 2)) + kthread (kernel/kthread.c:467) + ret_from_fork (arch/arm64/kernel/entry.S:861) + +Fixes: 55213e1acec9 ("clk: qcom: Add gfx3d ping-pong PLL frequency switching") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Abel Vesa +Reviewed-by: Konrad Dybcio +Reviewed-by: Brian Masney +Link: https://lore.kernel.org/r/20260117-db820-fix-gfx3d-v1-1-0f8894d71d63@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/clk-rcg2.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c +index 2838d4cb2d58e..d0a5847f91114 100644 +--- a/drivers/clk/qcom/clk-rcg2.c ++++ b/drivers/clk/qcom/clk-rcg2.c +@@ -1264,6 +1264,7 @@ static int clk_gfx3d_determine_rate(struct clk_hw *hw, + if (req->max_rate < parent_req.max_rate) + parent_req.max_rate = req->max_rate; + ++ parent_req.best_parent_hw = req->best_parent_hw; + ret = __clk_determine_rate(req->best_parent_hw, &parent_req); + if (ret) + return ret; +-- +2.51.0 + diff --git a/queue-6.18/clk-qcom-rcg2-compute-2d-using-duty-fraction-directl.patch b/queue-6.18/clk-qcom-rcg2-compute-2d-using-duty-fraction-directl.patch new file mode 100644 index 0000000000..7f4698fd0a --- /dev/null +++ b/queue-6.18/clk-qcom-rcg2-compute-2d-using-duty-fraction-directl.patch @@ -0,0 +1,71 @@ +From 21ca27d3f6eb9d5118e6e54ad0b00b287af86335 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Jan 2026 16:09:50 +0530 +Subject: clk: qcom: rcg2: compute 2d using duty fraction directly +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Taniya Das + +[ Upstream commit d6205a1878dd4cc9664c4b4829b68a29c0426efc ] + +The duty-cycle calculation in clk_rcg2_set_duty_cycle() currently +derives an intermediate percentage `duty_per = (num * 100) / den` and +then computes: + + d = DIV_ROUND_CLOSEST(n * duty_per * 2, 100); + +This introduces integer truncation at the percentage step (division by +`den`) and a redundant scaling by 100, which can reduce precision for +large `den` and skew the final rounding. + +Compute `2d` directly from the duty fraction to preserve precision and +avoid the unnecessary scaling: + + d = DIV_ROUND_CLOSEST(n * duty->num * 2, duty->den); + +This keeps the intended formula `d ≈ n * 2 * (num/den)` while performing +a single, final rounded division, improving accuracy especially for small +duty cycles or large denominators. It also removes the unused `duty_per` +variable, simplifying the code. + +There is no functional changes beyond improved numerical accuracy. + +Fixes: 7f891faf596ed ("clk: qcom: clk-rcg2: Add support for duty-cycle for RCG") +Signed-off-by: Taniya Das +Link: https://lore.kernel.org/r/20260105-duty_cycle_precision-v2-1-d1d466a6330a@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/clk-rcg2.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c +index e18cb8807d735..2838d4cb2d58e 100644 +--- a/drivers/clk/qcom/clk-rcg2.c ++++ b/drivers/clk/qcom/clk-rcg2.c +@@ -755,7 +755,7 @@ static int clk_rcg2_get_duty_cycle(struct clk_hw *hw, struct clk_duty *duty) + static int clk_rcg2_set_duty_cycle(struct clk_hw *hw, struct clk_duty *duty) + { + struct clk_rcg2 *rcg = to_clk_rcg2(hw); +- u32 notn_m, n, m, d, not2d, mask, duty_per, cfg; ++ u32 notn_m, n, m, d, not2d, mask, cfg; + int ret; + + /* Duty-cycle cannot be modified for non-MND RCGs */ +@@ -774,10 +774,8 @@ static int clk_rcg2_set_duty_cycle(struct clk_hw *hw, struct clk_duty *duty) + + n = (~(notn_m) + m) & mask; + +- duty_per = (duty->num * 100) / duty->den; +- + /* Calculate 2d value */ +- d = DIV_ROUND_CLOSEST(n * duty_per * 2, 100); ++ d = DIV_ROUND_CLOSEST(n * duty->num * 2, duty->den); + + /* + * Check bit widths of 2d. If D is too big reduce duty cycle. +-- +2.51.0 + diff --git a/queue-6.18/clk-qcom-regmap-divider-convert-from-divider_ro_roun.patch b/queue-6.18/clk-qcom-regmap-divider-convert-from-divider_ro_roun.patch new file mode 100644 index 0000000000..9ce6808944 --- /dev/null +++ b/queue-6.18/clk-qcom-regmap-divider-convert-from-divider_ro_roun.patch @@ -0,0 +1,55 @@ +From f8a58230e83a4afdaa9ef1be48375e2027523285 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:16:33 -0500 +Subject: clk: qcom: regmap-divider: convert from divider_ro_round_rate() to + divider_ro_determine_rate() + +From: Brian Masney + +[ Upstream commit 349f02c0f5d4ee147c582b89cadd553bd534028a ] + +The divider_ro_round_rate() function is now deprecated, so let's migrate +to divider_ro_determine_rate() instead so that this deprecated API can +be removed. + +Note that when the main function itself was migrated to use +determine_rate, this was mistakenly converted to: + + req->rate = divider_round_rate(...) + +This is invalid in the case when an error occurs since it can set the +rate to a negative value. + +Fixes: b6f90511c165 ("clk: qcom: regmap-divider: convert from round_rate() to determine_rate()") +Signed-off-by: Brian Masney +Reviewed-by: Abel Vesa +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260108-clk-divider-round-rate-v1-15-535a3ed73bf3@redhat.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/clk-regmap-divider.c | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + +diff --git a/drivers/clk/qcom/clk-regmap-divider.c b/drivers/clk/qcom/clk-regmap-divider.c +index 4f5395f0ab6d0..af9c01dd78537 100644 +--- a/drivers/clk/qcom/clk-regmap-divider.c ++++ b/drivers/clk/qcom/clk-regmap-divider.c +@@ -26,12 +26,8 @@ static int div_ro_determine_rate(struct clk_hw *hw, + val >>= divider->shift; + val &= BIT(divider->width) - 1; + +- req->rate = divider_ro_round_rate(hw, req->rate, +- &req->best_parent_rate, NULL, +- divider->width, +- CLK_DIVIDER_ROUND_CLOSEST, val); +- +- return 0; ++ return divider_ro_determine_rate(hw, req, NULL, divider->width, ++ CLK_DIVIDER_ROUND_CLOSEST, val); + } + + static int div_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) +-- +2.51.0 + diff --git a/queue-6.18/clk-qcom-regmap-divider-convert-from-divider_round_r.patch b/queue-6.18/clk-qcom-regmap-divider-convert-from-divider_round_r.patch new file mode 100644 index 0000000000..9defbba980 --- /dev/null +++ b/queue-6.18/clk-qcom-regmap-divider-convert-from-divider_round_r.patch @@ -0,0 +1,55 @@ +From a5930603a106fb21a5a0ca09f528dcd59881080f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:16:34 -0500 +Subject: clk: qcom: regmap-divider: convert from divider_round_rate() to + divider_determine_rate() + +From: Brian Masney + +[ Upstream commit d8300e6e078a3a44ac0c75c6d8ba46d78ab94035 ] + +The divider_round_rate() function is now deprecated, so let's migrate +to divider_determine_rate() instead so that this deprecated API can be +removed. + +Note that when the main function itself was migrated to use +determine_rate, this was mistakenly converted to: + + req->rate = divider_round_rate(...) + +This is invalid in the case when an error occurs since it can set the +rate to a negative value. + +Fixes: b6f90511c165 ("clk: qcom: regmap-divider: convert from round_rate() to determine_rate()") +Signed-off-by: Brian Masney +Reviewed-by: Abel Vesa +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260108-clk-divider-round-rate-v1-16-535a3ed73bf3@redhat.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/clk-regmap-divider.c | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + +diff --git a/drivers/clk/qcom/clk-regmap-divider.c b/drivers/clk/qcom/clk-regmap-divider.c +index af9c01dd78537..672e82caf2050 100644 +--- a/drivers/clk/qcom/clk-regmap-divider.c ++++ b/drivers/clk/qcom/clk-regmap-divider.c +@@ -34,12 +34,8 @@ static int div_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) + { + struct clk_regmap_div *divider = to_clk_regmap_div(hw); + +- req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, +- NULL, +- divider->width, +- CLK_DIVIDER_ROUND_CLOSEST); +- +- return 0; ++ return divider_determine_rate(hw, req, NULL, divider->width, ++ CLK_DIVIDER_ROUND_CLOSEST); + } + + static int div_set_rate(struct clk_hw *hw, unsigned long rate, +-- +2.51.0 + diff --git a/queue-6.18/clk-qcom-return-correct-error-code-in-qcom_cc_probe_.patch b/queue-6.18/clk-qcom-return-correct-error-code-in-qcom_cc_probe_.patch new file mode 100644 index 0000000000..11b91e10c4 --- /dev/null +++ b/queue-6.18/clk-qcom-return-correct-error-code-in-qcom_cc_probe_.patch @@ -0,0 +1,42 @@ +From 6226dfacedcb96cffc2f213e81673eae7153973f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 17 Dec 2025 12:13:38 +0800 +Subject: clk: qcom: Return correct error code in qcom_cc_probe_by_index() + +From: Haotian Zhang + +[ Upstream commit 1e07ebe744fb522983bd52a4a6148601675330c7 ] + +When devm_platform_ioremap_resource() fails, it returns various +error codes. Returning a hardcoded -ENOMEM masks the actual +failure reason. + +Use PTR_ERR() to propagate the actual error code returned by +devm_platform_ioremap_resource() instead of -ENOMEM. + +Fixes: 75e0a1e30191 ("clk: qcom: define probe by index API as common API") +Signed-off-by: Haotian Zhang +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251217041338.2432-1-vulab@iscas.ac.cn +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/common.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c +index 1215918867741..eec369d2173b5 100644 +--- a/drivers/clk/qcom/common.c ++++ b/drivers/clk/qcom/common.c +@@ -454,7 +454,7 @@ int qcom_cc_probe_by_index(struct platform_device *pdev, int index, + + base = devm_platform_ioremap_resource(pdev, index); + if (IS_ERR(base)) +- return -ENOMEM; ++ return PTR_ERR(base); + + regmap = devm_regmap_init_mmio(&pdev->dev, base, desc->config); + if (IS_ERR(regmap)) +-- +2.51.0 + diff --git a/queue-6.18/clk-rockchip-fix-error-pointer-check-after-rockchip_.patch b/queue-6.18/clk-rockchip-fix-error-pointer-check-after-rockchip_.patch new file mode 100644 index 0000000000..0b77eda37f --- /dev/null +++ b/queue-6.18/clk-rockchip-fix-error-pointer-check-after-rockchip_.patch @@ -0,0 +1,39 @@ +From fe1d1d57fdc9fa4c4a6f67f26b50a0f6ab7719e0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 5 Aug 2025 07:03:58 +0400 +Subject: clk: rockchip: Fix error pointer check after + rockchip_clk_register_gate_link() + +From: Miaoqian Lin + +[ Upstream commit a8d722f03923b1c6166d39482c6df8f017e185d9 ] + +Replace NULL check with IS_ERR_OR_NULL() check after calling +rockchip_clk_register_gate_link() since this function +returns error pointers (ERR_PTR). + +Fixes: c62fa612cfa6 ("clk: rockchip: implement linked gate clock support") +Signed-off-by: Miaoqian Lin +Link: https://patch.msgid.link/20250805030358.3665878-1-linmq006@gmail.com +Signed-off-by: Heiko Stuebner +Signed-off-by: Sasha Levin +--- + drivers/clk/rockchip/clk.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c +index 19caf26c991bd..2d30b1e24f013 100644 +--- a/drivers/clk/rockchip/clk.c ++++ b/drivers/clk/rockchip/clk.c +@@ -693,7 +693,7 @@ void rockchip_clk_register_late_branches(struct device *dev, + break; + } + +- if (!pdev) ++ if (IS_ERR_OR_NULL(pdev)) + dev_err(dev, "failed to register device for clock %s\n", list->name); + } + } +-- +2.51.0 + diff --git a/queue-6.18/clk-sophgo-sg2042-clkgen-convert-from-divider_round_.patch b/queue-6.18/clk-sophgo-sg2042-clkgen-convert-from-divider_round_.patch new file mode 100644 index 0000000000..71f9b668de --- /dev/null +++ b/queue-6.18/clk-sophgo-sg2042-clkgen-convert-from-divider_round_.patch @@ -0,0 +1,72 @@ +From 5635d97b3261926595be565403a161af8d2f8c60 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:16:35 -0500 +Subject: clk: sophgo: sg2042-clkgen: convert from divider_round_rate() to + divider_determine_rate() + +From: Brian Masney + +[ Upstream commit 77b04dc19693510ce8ed1c6eda5f5b833e208816 ] + +The divider_round_rate() function is now deprecated, so let's migrate +to divider_determine_rate() instead so that this deprecated API can be +removed. + +Note that when the main function itself was migrated to use +determine_rate, this was mistakenly converted to: + + req->rate = divider_round_rate(...) + +This is invalid in the case when an error occurs since it can set the +rate to a negative value. + +Note that this commit also removes a debugging message that's not really +needed. + +Fixes: 9a3b6993613d ("clk: sophgo: sg2042-clkgen: convert from round_rate() to determine_rate()") +Tested-by: Chen Wang +Reviewed-by: Chen Wang +Signed-off-by: Brian Masney +Signed-off-by: Sasha Levin +--- + drivers/clk/sophgo/clk-sg2042-clkgen.c | 15 +++++---------- + 1 file changed, 5 insertions(+), 10 deletions(-) + +diff --git a/drivers/clk/sophgo/clk-sg2042-clkgen.c b/drivers/clk/sophgo/clk-sg2042-clkgen.c +index 683661b71787c..9725ac4e050a4 100644 +--- a/drivers/clk/sophgo/clk-sg2042-clkgen.c ++++ b/drivers/clk/sophgo/clk-sg2042-clkgen.c +@@ -180,7 +180,6 @@ static int sg2042_clk_divider_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) + { + struct sg2042_divider_clock *divider = to_sg2042_clk_divider(hw); +- unsigned long ret_rate; + u32 bestdiv; + + /* if read only, just return current value */ +@@ -191,17 +190,13 @@ static int sg2042_clk_divider_determine_rate(struct clk_hw *hw, + bestdiv = readl(divider->reg) >> divider->shift; + bestdiv &= clk_div_mask(divider->width); + } +- ret_rate = DIV_ROUND_UP_ULL((u64)req->best_parent_rate, bestdiv); +- } else { +- ret_rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, NULL, +- divider->width, divider->div_flags); +- } ++ req->rate = DIV_ROUND_UP_ULL((u64)req->best_parent_rate, bestdiv); + +- pr_debug("--> %s: divider_round_rate: val = %ld\n", +- clk_hw_get_name(hw), ret_rate); +- req->rate = ret_rate; ++ return 0; ++ } + +- return 0; ++ return divider_determine_rate(hw, req, NULL, divider->width, ++ divider->div_flags); + } + + static int sg2042_clk_divider_set_rate(struct clk_hw *hw, +-- +2.51.0 + diff --git a/queue-6.18/clk-spacemit-respect-kconfig-setting-when-building-m.patch b/queue-6.18/clk-spacemit-respect-kconfig-setting-when-building-m.patch new file mode 100644 index 0000000000..adf48d7e51 --- /dev/null +++ b/queue-6.18/clk-spacemit-respect-kconfig-setting-when-building-m.patch @@ -0,0 +1,166 @@ +From 4e58052e765c34dc759885f2c9cad097f78eb0cd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 19 Dec 2025 09:28:17 +0800 +Subject: clk: spacemit: Respect Kconfig setting when building modules + +From: Inochi Amaoto + +[ Upstream commit 5ec8cbbc54c82c0bdae4dbf0e5aecf9817bde2b9 ] + +Currently, the SPACEMIT_CCU entry is only a switch for enabling entry +SPACEMIT_K1_CCU. It does not guide the build for common clock codes +even if it is a tristate entry. This makes this entry useless. + +Change the Makefile to add a separate build for common clock logic, +so the SPACEMIT_CCU entry takes effect, also add necessary +MODULE_LICENSE()/MODULE_DESCRIPTION()/EXPORT_SYMBOL() for the module +build. + +Fixes: 1b72c59db0ad ("clk: spacemit: Add clock support for SpacemiT K1 SoC") +Signed-off-by: Inochi Amaoto +Reviewed-by: Yixun Lan +Link: https://lore.kernel.org/r/20251219012819.440972-2-inochiama@gmail.com +Signed-off-by: Yixun Lan +Signed-off-by: Sasha Levin +--- + drivers/clk/spacemit/Makefile | 9 +++++++-- + drivers/clk/spacemit/ccu-k1.c | 1 + + drivers/clk/spacemit/ccu_common.c | 6 ++++++ + drivers/clk/spacemit/ccu_ddn.c | 1 + + drivers/clk/spacemit/ccu_mix.c | 9 +++++++++ + drivers/clk/spacemit/ccu_pll.c | 1 + + 6 files changed, 25 insertions(+), 2 deletions(-) + create mode 100644 drivers/clk/spacemit/ccu_common.c + +diff --git a/drivers/clk/spacemit/Makefile b/drivers/clk/spacemit/Makefile +index 5ec6da61db98e..ad2bf315109b8 100644 +--- a/drivers/clk/spacemit/Makefile ++++ b/drivers/clk/spacemit/Makefile +@@ -1,5 +1,10 @@ + # SPDX-License-Identifier: GPL-2.0 + +-obj-$(CONFIG_SPACEMIT_K1_CCU) = spacemit-ccu-k1.o +-spacemit-ccu-k1-y = ccu_pll.o ccu_mix.o ccu_ddn.o ++obj-$(CONFIG_SPACEMIT_CCU) += spacemit-ccu.o ++spacemit-ccu-y += ccu_common.o ++spacemit-ccu-y += ccu_pll.o ++spacemit-ccu-y += ccu_mix.o ++spacemit-ccu-y += ccu_ddn.o ++ ++obj-$(CONFIG_SPACEMIT_K1_CCU) += spacemit-ccu-k1.o + spacemit-ccu-k1-y += ccu-k1.o +diff --git a/drivers/clk/spacemit/ccu-k1.c b/drivers/clk/spacemit/ccu-k1.c +index 4761bc1e3b6e6..01d9485b615d3 100644 +--- a/drivers/clk/spacemit/ccu-k1.c ++++ b/drivers/clk/spacemit/ccu-k1.c +@@ -1204,6 +1204,7 @@ static struct platform_driver k1_ccu_driver = { + }; + module_platform_driver(k1_ccu_driver); + ++MODULE_IMPORT_NS("CLK_SPACEMIT"); + MODULE_DESCRIPTION("SpacemiT K1 CCU driver"); + MODULE_AUTHOR("Haylen Chu "); + MODULE_LICENSE("GPL"); +diff --git a/drivers/clk/spacemit/ccu_common.c b/drivers/clk/spacemit/ccu_common.c +new file mode 100644 +index 0000000000000..4412c4104dabb +--- /dev/null ++++ b/drivers/clk/spacemit/ccu_common.c +@@ -0,0 +1,6 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++ ++#include ++ ++MODULE_DESCRIPTION("SpacemiT CCU common clock driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/clk/spacemit/ccu_ddn.c b/drivers/clk/spacemit/ccu_ddn.c +index 5b16e273bee5b..b5540e0781ffa 100644 +--- a/drivers/clk/spacemit/ccu_ddn.c ++++ b/drivers/clk/spacemit/ccu_ddn.c +@@ -84,3 +84,4 @@ const struct clk_ops spacemit_ccu_ddn_ops = { + .determine_rate = ccu_ddn_determine_rate, + .set_rate = ccu_ddn_set_rate, + }; ++EXPORT_SYMBOL_NS_GPL(spacemit_ccu_ddn_ops, "CLK_SPACEMIT"); +diff --git a/drivers/clk/spacemit/ccu_mix.c b/drivers/clk/spacemit/ccu_mix.c +index 7b79908753723..67f8b12b4f5b7 100644 +--- a/drivers/clk/spacemit/ccu_mix.c ++++ b/drivers/clk/spacemit/ccu_mix.c +@@ -198,24 +198,28 @@ const struct clk_ops spacemit_ccu_gate_ops = { + .enable = ccu_gate_enable, + .is_enabled = ccu_gate_is_enabled, + }; ++EXPORT_SYMBOL_NS_GPL(spacemit_ccu_gate_ops, "CLK_SPACEMIT"); + + const struct clk_ops spacemit_ccu_factor_ops = { + .determine_rate = ccu_factor_determine_rate, + .recalc_rate = ccu_factor_recalc_rate, + .set_rate = ccu_factor_set_rate, + }; ++EXPORT_SYMBOL_NS_GPL(spacemit_ccu_factor_ops, "CLK_SPACEMIT"); + + const struct clk_ops spacemit_ccu_mux_ops = { + .determine_rate = ccu_mix_determine_rate, + .get_parent = ccu_mux_get_parent, + .set_parent = ccu_mux_set_parent, + }; ++EXPORT_SYMBOL_NS_GPL(spacemit_ccu_mux_ops, "CLK_SPACEMIT"); + + const struct clk_ops spacemit_ccu_div_ops = { + .determine_rate = ccu_mix_determine_rate, + .recalc_rate = ccu_div_recalc_rate, + .set_rate = ccu_mix_set_rate, + }; ++EXPORT_SYMBOL_NS_GPL(spacemit_ccu_div_ops, "CLK_SPACEMIT"); + + const struct clk_ops spacemit_ccu_factor_gate_ops = { + .disable = ccu_gate_disable, +@@ -226,6 +230,7 @@ const struct clk_ops spacemit_ccu_factor_gate_ops = { + .recalc_rate = ccu_factor_recalc_rate, + .set_rate = ccu_factor_set_rate, + }; ++EXPORT_SYMBOL_NS_GPL(spacemit_ccu_factor_gate_ops, "CLK_SPACEMIT"); + + const struct clk_ops spacemit_ccu_mux_gate_ops = { + .disable = ccu_gate_disable, +@@ -236,6 +241,7 @@ const struct clk_ops spacemit_ccu_mux_gate_ops = { + .get_parent = ccu_mux_get_parent, + .set_parent = ccu_mux_set_parent, + }; ++EXPORT_SYMBOL_NS_GPL(spacemit_ccu_mux_gate_ops, "CLK_SPACEMIT"); + + const struct clk_ops spacemit_ccu_div_gate_ops = { + .disable = ccu_gate_disable, +@@ -246,6 +252,7 @@ const struct clk_ops spacemit_ccu_div_gate_ops = { + .recalc_rate = ccu_div_recalc_rate, + .set_rate = ccu_mix_set_rate, + }; ++EXPORT_SYMBOL_NS_GPL(spacemit_ccu_div_gate_ops, "CLK_SPACEMIT"); + + const struct clk_ops spacemit_ccu_mux_div_gate_ops = { + .disable = ccu_gate_disable, +@@ -259,6 +266,7 @@ const struct clk_ops spacemit_ccu_mux_div_gate_ops = { + .recalc_rate = ccu_div_recalc_rate, + .set_rate = ccu_mix_set_rate, + }; ++EXPORT_SYMBOL_NS_GPL(spacemit_ccu_mux_div_gate_ops, "CLK_SPACEMIT"); + + const struct clk_ops spacemit_ccu_mux_div_ops = { + .get_parent = ccu_mux_get_parent, +@@ -268,3 +276,4 @@ const struct clk_ops spacemit_ccu_mux_div_ops = { + .recalc_rate = ccu_div_recalc_rate, + .set_rate = ccu_mix_set_rate, + }; ++EXPORT_SYMBOL_NS_GPL(spacemit_ccu_mux_div_ops, "CLK_SPACEMIT"); +diff --git a/drivers/clk/spacemit/ccu_pll.c b/drivers/clk/spacemit/ccu_pll.c +index d92f0dae65a49..76d0244873d87 100644 +--- a/drivers/clk/spacemit/ccu_pll.c ++++ b/drivers/clk/spacemit/ccu_pll.c +@@ -157,3 +157,4 @@ const struct clk_ops spacemit_ccu_pll_ops = { + .determine_rate = ccu_pll_determine_rate, + .is_enabled = ccu_pll_is_enabled, + }; ++EXPORT_SYMBOL_NS_GPL(spacemit_ccu_pll_ops, "CLK_SPACEMIT"); +-- +2.51.0 + diff --git a/queue-6.18/clk-sprd-div-convert-from-divider_round_rate-to-divi.patch b/queue-6.18/clk-sprd-div-convert-from-divider_round_rate-to-divi.patch new file mode 100644 index 0000000000..50a98ac7c9 --- /dev/null +++ b/queue-6.18/clk-sprd-div-convert-from-divider_round_rate-to-divi.patch @@ -0,0 +1,49 @@ +From dd1cc8231094b872943fb38e99958c50e8d63a55 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:16:36 -0500 +Subject: clk: sprd: div: convert from divider_round_rate() to + divider_determine_rate() + +From: Brian Masney + +[ Upstream commit f78fb9422980ceeb340fa3a2e370ae8845798ec7 ] + +The divider_round_rate() function is now deprecated, so let's migrate +to divider_determine_rate() instead so that this deprecated API can be +removed. + +Note that when the main function itself was migrated to use +determine_rate, this was mistakenly converted to: + + req->rate = divider_round_rate(...) + +This is invalid in the case when an error occurs since it can set the +rate to a negative value. + +Fixes: deb4740a5ff8 ("clk: sprd: div: convert from round_rate() to determine_rate()") +Signed-off-by: Brian Masney +Signed-off-by: Sasha Levin +--- + drivers/clk/sprd/div.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/drivers/clk/sprd/div.c b/drivers/clk/sprd/div.c +index 0134238819680..cd57163a7204c 100644 +--- a/drivers/clk/sprd/div.c ++++ b/drivers/clk/sprd/div.c +@@ -14,11 +14,7 @@ static int sprd_div_determine_rate(struct clk_hw *hw, + { + struct sprd_div *cd = hw_to_sprd_div(hw); + +- req->rate = divider_round_rate(&cd->common.hw, req->rate, +- &req->best_parent_rate, +- NULL, cd->div.width, 0); +- +- return 0; ++ return divider_determine_rate(&cd->common.hw, req, NULL, cd->div.width, 0); + } + + unsigned long sprd_div_helper_recalc_rate(struct sprd_clk_common *common, +-- +2.51.0 + diff --git a/queue-6.18/clk-stm32-stm32-core-convert-from-divider_ro_round_r.patch b/queue-6.18/clk-stm32-stm32-core-convert-from-divider_ro_round_r.patch new file mode 100644 index 0000000000..1bb39625ab --- /dev/null +++ b/queue-6.18/clk-stm32-stm32-core-convert-from-divider_ro_round_r.patch @@ -0,0 +1,72 @@ +From f4f86f800328f46205eb6b028a2ad377bcdc52f1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:16:37 -0500 +Subject: clk: stm32: stm32-core: convert from divider_ro_round_rate() to + divider_ro_determine_rate() + +From: Brian Masney + +[ Upstream commit 6587c9dacc89ad7014bf601fe851955429f13230 ] + +The divider_ro_round_rate() function is now deprecated, so let's migrate +to divider_ro_determine_rate() instead so that this deprecated API can +be removed. + +Note that when the main function itself was migrated to use +determine_rate, this was mistakenly converted to: + + req->rate = divider_round_rate(...) + +This is invalid in the case when an error occurs since it can set the +rate to a negative value. + +Fixes: cd1cb38836c0 ("clk: stm32: stm32-core: convert from round_rate() to determine_rate()") +Signed-off-by: Brian Masney +Signed-off-by: Sasha Levin +--- + drivers/clk/stm32/clk-stm32-core.c | 22 +++++++--------------- + 1 file changed, 7 insertions(+), 15 deletions(-) + +diff --git a/drivers/clk/stm32/clk-stm32-core.c b/drivers/clk/stm32/clk-stm32-core.c +index 72825b9c36a4d..b95b9c591fda7 100644 +--- a/drivers/clk/stm32/clk-stm32-core.c ++++ b/drivers/clk/stm32/clk-stm32-core.c +@@ -369,13 +369,10 @@ static int clk_stm32_divider_determine_rate(struct clk_hw *hw, + val = readl(div->base + divider->offset) >> divider->shift; + val &= clk_div_mask(divider->width); + +- req->rate = divider_ro_round_rate(hw, req->rate, +- &req->best_parent_rate, +- divider->table, +- divider->width, +- divider->flags, val); +- +- return 0; ++ return divider_ro_determine_rate(hw, req, ++ divider->table, ++ divider->width, ++ divider->flags, val); + } + + req->rate = divider_round_rate_parent(hw, clk_hw_get_parent(hw), +@@ -455,14 +452,9 @@ static int clk_stm32_composite_determine_rate(struct clk_hw *hw, + val = readl(composite->base + divider->offset) >> divider->shift; + val &= clk_div_mask(divider->width); + +- rate = divider_ro_round_rate(hw, req->rate, &req->best_parent_rate, +- divider->table, divider->width, divider->flags, +- val); +- if (rate < 0) +- return rate; +- +- req->rate = rate; +- return 0; ++ return divider_ro_determine_rate(hw, req, divider->table, ++ divider->width, divider->flags, ++ val); + } + + rate = divider_round_rate_parent(hw, clk_hw_get_parent(hw), +-- +2.51.0 + diff --git a/queue-6.18/clk-stm32-stm32-core-convert-from-divider_round_rate.patch b/queue-6.18/clk-stm32-stm32-core-convert-from-divider_round_rate.patch new file mode 100644 index 0000000000..15214560f6 --- /dev/null +++ b/queue-6.18/clk-stm32-stm32-core-convert-from-divider_round_rate.patch @@ -0,0 +1,77 @@ +From 60a4a2d37be44c3b49fd2be95b71a88d83abc47d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:16:38 -0500 +Subject: clk: stm32: stm32-core: convert from divider_round_rate_parent() to + divider_determine_rate() + +From: Brian Masney + +[ Upstream commit 2532795a6d6bb9791d713ffa9d9433f293b45b14 ] + +The divider_round_rate_parent() function is now deprecated, so let's +migrate to divider_determine_rate() instead so that this deprecated API +can be removed. + +Note that when the main function itself was migrated to use +determine_rate, this was mistakenly converted to: + + req->rate = divider_round_rate(...) + +This is invalid in the case when an error occurs since it can set the +rate to a negative value. + +Fixes: cd1cb38836c0 ("clk: stm32: stm32-core: convert from round_rate() to determine_rate()") +Signed-off-by: Brian Masney +Signed-off-by: Sasha Levin +--- + drivers/clk/stm32/clk-stm32-core.c | 20 ++++---------------- + 1 file changed, 4 insertions(+), 16 deletions(-) + +diff --git a/drivers/clk/stm32/clk-stm32-core.c b/drivers/clk/stm32/clk-stm32-core.c +index b95b9c591fda7..e921c25a929c3 100644 +--- a/drivers/clk/stm32/clk-stm32-core.c ++++ b/drivers/clk/stm32/clk-stm32-core.c +@@ -375,13 +375,8 @@ static int clk_stm32_divider_determine_rate(struct clk_hw *hw, + divider->flags, val); + } + +- req->rate = divider_round_rate_parent(hw, clk_hw_get_parent(hw), +- req->rate, +- &req->best_parent_rate, +- divider->table, +- divider->width, divider->flags); +- +- return 0; ++ return divider_determine_rate(hw, req, divider->table, divider->width, ++ divider->flags); + } + + static unsigned long clk_stm32_divider_recalc_rate(struct clk_hw *hw, +@@ -438,7 +433,6 @@ static int clk_stm32_composite_determine_rate(struct clk_hw *hw, + { + struct clk_stm32_composite *composite = to_clk_stm32_composite(hw); + const struct stm32_div_cfg *divider; +- long rate; + + if (composite->div_id == NO_STM32_DIV) + return 0; +@@ -457,14 +451,8 @@ static int clk_stm32_composite_determine_rate(struct clk_hw *hw, + val); + } + +- rate = divider_round_rate_parent(hw, clk_hw_get_parent(hw), +- req->rate, &req->best_parent_rate, +- divider->table, divider->width, divider->flags); +- if (rate < 0) +- return rate; +- +- req->rate = rate; +- return 0; ++ return divider_determine_rate(hw, req, divider->table, divider->width, ++ divider->flags); + } + + static u8 clk_stm32_composite_get_parent(struct clk_hw *hw) +-- +2.51.0 + diff --git a/queue-6.18/clk-thead-th1520-ap-poll-for-pll-lock-and-wait-for-s.patch b/queue-6.18/clk-thead-th1520-ap-poll-for-pll-lock-and-wait-for-s.patch new file mode 100644 index 0000000000..b855eaebd4 --- /dev/null +++ b/queue-6.18/clk-thead-th1520-ap-poll-for-pll-lock-and-wait-for-s.patch @@ -0,0 +1,150 @@ +From ca258966678437fcf314a834943b07be84e3b551 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 20 Nov 2025 13:14:11 +0000 +Subject: clk: thead: th1520-ap: Poll for PLL lock and wait for stability + +From: Yao Zi + +[ Upstream commit 892abfbed71e8e0fc5d6ccee1e975904805c6327 ] + +All PLLs found on TH1520 SoC take 21250ns at maximum to lock, and their +lock status is indicated by register PLL_STS (offset 0x80 inside AP +clock controller). We should poll the register to ensure the PLL +actually locks after enabling it. + +Furthermore, a 30us delay is added after enabling the PLL, after which +the PLL could be considered stable as stated by vendor clock code. + +Fixes: 56a48c1833aa ("clk: thead: add support for enabling/disabling PLLs") +Reviewed-by: Drew Fustini +Signed-off-by: Yao Zi +Signed-off-by: Drew Fustini +Signed-off-by: Sasha Levin +--- + drivers/clk/thead/clk-th1520-ap.c | 34 +++++++++++++++++++++++++++++-- + 1 file changed, 32 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/thead/clk-th1520-ap.c b/drivers/clk/thead/clk-th1520-ap.c +index 71ad03a998e8e..d870f0c665f8a 100644 +--- a/drivers/clk/thead/clk-th1520-ap.c ++++ b/drivers/clk/thead/clk-th1520-ap.c +@@ -8,11 +8,14 @@ + #include + #include + #include ++#include + #include + #include + #include + #include + ++#define TH1520_PLL_STS 0x80 ++ + #define TH1520_PLL_POSTDIV2 GENMASK(26, 24) + #define TH1520_PLL_POSTDIV1 GENMASK(22, 20) + #define TH1520_PLL_FBDIV GENMASK(19, 8) +@@ -23,6 +26,13 @@ + #define TH1520_PLL_FRAC GENMASK(23, 0) + #define TH1520_PLL_FRAC_BITS 24 + ++/* ++ * All PLLs in TH1520 take 21250ns at maximum to lock, let's take its double ++ * for safety. ++ */ ++#define TH1520_PLL_LOCK_TIMEOUT_US 44 ++#define TH1520_PLL_STABLE_DELAY_US 30 ++ + struct ccu_internal { + u8 shift; + u8 width; +@@ -64,6 +74,7 @@ struct ccu_div { + + struct ccu_pll { + struct ccu_common common; ++ u32 lock_sts_mask; + }; + + #define TH_CCU_ARG(_shift, _width) \ +@@ -299,9 +310,21 @@ static void ccu_pll_disable(struct clk_hw *hw) + static int ccu_pll_enable(struct clk_hw *hw) + { + struct ccu_pll *pll = hw_to_ccu_pll(hw); ++ u32 reg; ++ int ret; + +- return regmap_clear_bits(pll->common.map, pll->common.cfg1, +- TH1520_PLL_VCO_RST); ++ regmap_clear_bits(pll->common.map, pll->common.cfg1, ++ TH1520_PLL_VCO_RST); ++ ++ ret = regmap_read_poll_timeout_atomic(pll->common.map, TH1520_PLL_STS, ++ reg, reg & pll->lock_sts_mask, ++ 5, TH1520_PLL_LOCK_TIMEOUT_US); ++ if (ret) ++ return ret; ++ ++ udelay(TH1520_PLL_STABLE_DELAY_US); ++ ++ return 0; + } + + static int ccu_pll_is_enabled(struct clk_hw *hw) +@@ -389,6 +412,7 @@ static struct ccu_pll cpu_pll0_clk = { + &clk_pll_ops, + CLK_IS_CRITICAL), + }, ++ .lock_sts_mask = BIT(1), + }; + + static struct ccu_pll cpu_pll1_clk = { +@@ -401,6 +425,7 @@ static struct ccu_pll cpu_pll1_clk = { + &clk_pll_ops, + CLK_IS_CRITICAL), + }, ++ .lock_sts_mask = BIT(4), + }; + + static struct ccu_pll gmac_pll_clk = { +@@ -413,6 +438,7 @@ static struct ccu_pll gmac_pll_clk = { + &clk_pll_ops, + CLK_IS_CRITICAL), + }, ++ .lock_sts_mask = BIT(3), + }; + + static const struct clk_hw *gmac_pll_clk_parent[] = { +@@ -433,6 +459,7 @@ static struct ccu_pll video_pll_clk = { + &clk_pll_ops, + CLK_IS_CRITICAL), + }, ++ .lock_sts_mask = BIT(7), + }; + + static const struct clk_hw *video_pll_clk_parent[] = { +@@ -453,6 +480,7 @@ static struct ccu_pll dpu0_pll_clk = { + &clk_pll_ops, + 0), + }, ++ .lock_sts_mask = BIT(8), + }; + + static const struct clk_hw *dpu0_pll_clk_parent[] = { +@@ -469,6 +497,7 @@ static struct ccu_pll dpu1_pll_clk = { + &clk_pll_ops, + 0), + }, ++ .lock_sts_mask = BIT(9), + }; + + static const struct clk_hw *dpu1_pll_clk_parent[] = { +@@ -485,6 +514,7 @@ static struct ccu_pll tee_pll_clk = { + &clk_pll_ops, + CLK_IS_CRITICAL), + }, ++ .lock_sts_mask = BIT(10), + }; + + static const struct clk_parent_data c910_i0_parents[] = { +-- +2.51.0 + diff --git a/queue-6.18/clk-versaclock3-convert-from-divider_round_rate-to-d.patch b/queue-6.18/clk-versaclock3-convert-from-divider_round_rate-to-d.patch new file mode 100644 index 0000000000..ab5ca46477 --- /dev/null +++ b/queue-6.18/clk-versaclock3-convert-from-divider_round_rate-to-d.patch @@ -0,0 +1,50 @@ +From ee835269950f3cc234a5776fa125e435339f415c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:16:39 -0500 +Subject: clk: versaclock3: convert from divider_round_rate() to + divider_determine_rate() + +From: Brian Masney + +[ Upstream commit 56c1cfb488cc17944c200edad96191a70a3783ba ] + +The divider_round_rate() function is now deprecated, so let's migrate +to divider_determine_rate() instead so that this deprecated API can be +removed. + +Note that when the main function itself was migrated to use +determine_rate, this was mistakenly converted to: + + req->rate = divider_round_rate(...) + +This is invalid in the case when an error occurs since it can set the +rate to a negative value. + +Fixes: 9e3372b2ebac ("clk: versaclock3: convert from round_rate() to determine_rate()") +Signed-off-by: Brian Masney +Signed-off-by: Sasha Levin +--- + drivers/clk/clk-versaclock3.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/drivers/clk/clk-versaclock3.c b/drivers/clk/clk-versaclock3.c +index 1849863dbd673..27b6cf70f3ae1 100644 +--- a/drivers/clk/clk-versaclock3.c ++++ b/drivers/clk/clk-versaclock3.c +@@ -523,11 +523,8 @@ static int vc3_div_determine_rate(struct clk_hw *hw, + return 0; + } + +- req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, +- div_data->table, +- div_data->width, div_data->flags); +- +- return 0; ++ return divider_determine_rate(hw, req, div_data->table, div_data->width, ++ div_data->flags); + } + + static int vc3_div_set_rate(struct clk_hw *hw, unsigned long rate, +-- +2.51.0 + diff --git a/queue-6.18/clk-x86-cgu-convert-from-divider_round_rate-to-divid.patch b/queue-6.18/clk-x86-cgu-convert-from-divider_round_rate-to-divid.patch new file mode 100644 index 0000000000..eec70514f0 --- /dev/null +++ b/queue-6.18/clk-x86-cgu-convert-from-divider_round_rate-to-divid.patch @@ -0,0 +1,49 @@ +From 18df7b9e5464443261762b63ce2d4cf9dc01ba38 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:16:40 -0500 +Subject: clk: x86: cgu: convert from divider_round_rate() to + divider_determine_rate() + +From: Brian Masney + +[ Upstream commit bb1b0e63dbbd7150324cb4d6aef7854dbe26a617 ] + +The divider_round_rate() function is now deprecated, so let's migrate +to divider_determine_rate() instead so that this deprecated API can be +removed. + +Note that when the main function itself was migrated to use +determine_rate, this was mistakenly converted to: + + req->rate = divider_round_rate(...) + +This is invalid in the case when an error occurs since it can set the +rate to a negative value. + +Fixes: f7a6bed91a19 ("clk: x86: cgu: convert from round_rate() to determine_rate()") +Signed-off-by: Brian Masney +Signed-off-by: Sasha Levin +--- + drivers/clk/x86/clk-cgu.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/clk/x86/clk-cgu.c b/drivers/clk/x86/clk-cgu.c +index d099667355f8d..92ee05d75af2b 100644 +--- a/drivers/clk/x86/clk-cgu.c ++++ b/drivers/clk/x86/clk-cgu.c +@@ -137,10 +137,8 @@ static int lgm_clk_divider_determine_rate(struct clk_hw *hw, + { + struct lgm_clk_divider *divider = to_lgm_clk_divider(hw); + +- req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, divider->table, +- divider->width, divider->flags); +- +- return 0; ++ return divider_determine_rate(hw, req, divider->table, divider->width, ++ divider->flags); + } + + static int +-- +2.51.0 + diff --git a/queue-6.18/clk-zynqmp-divider-convert-from-divider_round_rate-t.patch b/queue-6.18/clk-zynqmp-divider-convert-from-divider_round_rate-t.patch new file mode 100644 index 0000000000..0f8978b6e5 --- /dev/null +++ b/queue-6.18/clk-zynqmp-divider-convert-from-divider_round_rate-t.patch @@ -0,0 +1,48 @@ +From 36cc7a12637075ae688c0ad372d1e57654961780 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:16:41 -0500 +Subject: clk: zynqmp: divider: convert from divider_round_rate() to + divider_determine_rate() + +From: Brian Masney + +[ Upstream commit 30a807808c69a1907001ffb79289237a2ee97cfa ] + +The divider_round_rate() function is now deprecated, so let's migrate +to divider_determine_rate() instead so that this deprecated API can be +removed. + +Note that when the main function itself was migrated to use +determine_rate, this was mistakenly converted to: + + req->rate = divider_round_rate(...) + +This is invalid in the case when an error occurs since it can set the +rate to a negative value. + +Fixes: 0f9cf96a01fd ("clk: zynqmp: divider: convert from round_rate() to determine_rate()") +Signed-off-by: Brian Masney +Signed-off-by: Sasha Levin +--- + drivers/clk/zynqmp/divider.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/zynqmp/divider.c b/drivers/clk/zynqmp/divider.c +index c824eeacd8ebd..de6f478d527d8 100644 +--- a/drivers/clk/zynqmp/divider.c ++++ b/drivers/clk/zynqmp/divider.c +@@ -151,8 +151,9 @@ static int zynqmp_clk_divider_determine_rate(struct clk_hw *hw, + + width = fls(divider->max_div); + +- req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, +- NULL, width, divider->flags); ++ ret = divider_determine_rate(hw, req, NULL, width, divider->flags); ++ if (ret != 0) ++ return ret; + + if (divider->is_frac && (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) && + (req->rate % req->best_parent_rate)) +-- +2.51.0 + diff --git a/queue-6.18/clk-zynqmp-divider-fix-zynqmp_clk_divider_determine_.patch b/queue-6.18/clk-zynqmp-divider-fix-zynqmp_clk_divider_determine_.patch new file mode 100644 index 0000000000..2c53fbe9d3 --- /dev/null +++ b/queue-6.18/clk-zynqmp-divider-fix-zynqmp_clk_divider_determine_.patch @@ -0,0 +1,44 @@ +From 333acb8c40d785f667efd62756e307c30ee5387a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Dec 2025 12:42:11 +0100 +Subject: clk: zynqmp: divider: Fix zynqmp_clk_divider_determine_rate kerneldoc + +From: Krzysztof Kozlowski + +[ Upstream commit 1b8773864904c7a25e45f1b12ab505bdb7e06568 ] + +After renaming round_rate->determine, kerneldoc does not match anymore, +causing W=1 warnings: + + Warning: drivers/clk/zynqmp/divider.c:122 function parameter 'req' not described in 'zynqmp_clk_divider_determine_rate' + Warning: drivers/clk/zynqmp/divider.c:122 expecting prototype for zynqmp_clk_divider_round_rate(). Prototype was for zynqmp_clk_divider_determine_rate() instead + +Fixes: 0f9cf96a01fd ("clk: zynqmp: divider: convert from round_rate() to determine_rate()") +Signed-off-by: Krzysztof Kozlowski +Reviewed-by: Brian Masney +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + drivers/clk/zynqmp/divider.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/clk/zynqmp/divider.c b/drivers/clk/zynqmp/divider.c +index de6f478d527d8..984e577ea6711 100644 +--- a/drivers/clk/zynqmp/divider.c ++++ b/drivers/clk/zynqmp/divider.c +@@ -111,10 +111,9 @@ static unsigned long zynqmp_clk_divider_recalc_rate(struct clk_hw *hw, + } + + /** +- * zynqmp_clk_divider_round_rate() - Round rate of divider clock ++ * zynqmp_clk_divider_determine_rate() - Determine rate of divider clock + * @hw: handle between common and hardware-specific interfaces +- * @rate: rate of clock to be set +- * @prate: rate of parent clock ++ * @req: rate of clock to be set + * + * Return: 0 on success else error+reason + */ +-- +2.51.0 + diff --git a/queue-6.18/clk-zynqmp-pll-fix-zynqmp_clk_divider_determine_rate.patch b/queue-6.18/clk-zynqmp-pll-fix-zynqmp_clk_divider_determine_rate.patch new file mode 100644 index 0000000000..a4d79b7d3d --- /dev/null +++ b/queue-6.18/clk-zynqmp-pll-fix-zynqmp_clk_divider_determine_rate.patch @@ -0,0 +1,44 @@ +From 532a422eaee8c7f89dddd27ded4038276173dc26 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Dec 2025 12:42:12 +0100 +Subject: clk: zynqmp: pll: Fix zynqmp_clk_divider_determine_rate kerneldoc + +From: Krzysztof Kozlowski + +[ Upstream commit 750e0e0a1652530618d2c07697618e705bc5061b ] + +After renaming round_rate->determine, kerneldoc does not match anymore, +causing W=1 warnings: + + pll.c:102 function parameter 'req' not described in 'zynqmp_pll_determine_rate' + pll.c:102 expecting prototype for zynqmp_pll_round_rate(). Prototype was for zynqmp_pll_determine_rate() instead + +Fixes: 193650c7a873 ("clk: zynqmp: pll: convert from round_rate() to determine_rate()") +Signed-off-by: Krzysztof Kozlowski +Reviewed-by: Brian Masney +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + drivers/clk/zynqmp/pll.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/clk/zynqmp/pll.c b/drivers/clk/zynqmp/pll.c +index 630a3936c97c3..6bc2c3934f564 100644 +--- a/drivers/clk/zynqmp/pll.c ++++ b/drivers/clk/zynqmp/pll.c +@@ -91,10 +91,9 @@ static inline void zynqmp_pll_set_mode(struct clk_hw *hw, bool on) + } + + /** +- * zynqmp_pll_round_rate() - Round a clock frequency ++ * zynqmp_pll_determine_rate() - Round a clock frequency + * @hw: Handle between common and hardware-specific interfaces +- * @rate: Desired clock frequency +- * @prate: Clock frequency of parent clock ++ * @req: Desired clock frequency + * + * Return: Frequency closest to @rate the hardware can generate + */ +-- +2.51.0 + diff --git a/queue-6.18/coresight-etm3x-fix-cpulocked-warning-on-cpuhp.patch b/queue-6.18/coresight-etm3x-fix-cpulocked-warning-on-cpuhp.patch new file mode 100644 index 0000000000..56e175a1fe --- /dev/null +++ b/queue-6.18/coresight-etm3x-fix-cpulocked-warning-on-cpuhp.patch @@ -0,0 +1,67 @@ +From 8eb0a866d6d3ef3df7711ef34d07e33921f08e03 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:24:27 +0100 +Subject: coresight: etm3x: Fix cpulocked warning on cpuhp + +From: Antonio Borneo + +[ Upstream commit 1feb0377b9b816f89a04fc381eb19fc6bac9f4a4 ] + +When changes [1] and [2] have been applied to the driver etm4x, the +same modifications have been also collapsed in [3] and applied in +one shot to the driver etm3x. +While doing this, the driver etm3x has not been aligned to etm4x on +the use of non cpuslocked version of cpuhp callback setup APIs. + +The current code triggers two run-time warnings when the kernel is +compiled with CONFIG_PROVE_LOCKING=y. + +Use non cpuslocked version of cpuhp callback setup APIs in driver +etm3x, aligning it to the driver etm4x. + +[1] commit 2d1a8bfb61ec ("coresight: etm4x: Fix etm4_count race by + moving cpuhp callbacks to init") +[2] commit 22a550a306ad ("coresight: etm4x: Allow etm4x to be built + as a module") +[3] commit 97fe626ce64c ("coresight: etm3x: Allow etm3x to be built + as a module") + +Fixes: 97fe626ce64c ("coresight: etm3x: Allow etm3x to be built as a module") +Signed-off-by: Antonio Borneo +Signed-off-by: Suzuki K Poulose +Link: https://lore.kernel.org/r/20260108152427.357379-1-antonio.borneo@foss.st.com +Signed-off-by: Sasha Levin +--- + drivers/hwtracing/coresight/coresight-etm3x-core.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c +index a5e809589d3e3..0c011b7041696 100644 +--- a/drivers/hwtracing/coresight/coresight-etm3x-core.c ++++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c +@@ -795,16 +795,16 @@ static int __init etm_hp_setup(void) + { + int ret; + +- ret = cpuhp_setup_state_nocalls_cpuslocked(CPUHP_AP_ARM_CORESIGHT_STARTING, +- "arm/coresight:starting", +- etm_starting_cpu, etm_dying_cpu); ++ ret = cpuhp_setup_state_nocalls(CPUHP_AP_ARM_CORESIGHT_STARTING, ++ "arm/coresight:starting", ++ etm_starting_cpu, etm_dying_cpu); + + if (ret) + return ret; + +- ret = cpuhp_setup_state_nocalls_cpuslocked(CPUHP_AP_ONLINE_DYN, +- "arm/coresight:online", +- etm_online_cpu, NULL); ++ ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, ++ "arm/coresight:online", ++ etm_online_cpu, NULL); + + /* HP dyn state ID returned in ret on success */ + if (ret > 0) { +-- +2.51.0 + diff --git a/queue-6.18/coresight-tmc-etr-fix-race-condition-between-sysfs-a.patch b/queue-6.18/coresight-tmc-etr-fix-race-condition-between-sysfs-a.patch new file mode 100644 index 0000000000..c0ccaf46f6 --- /dev/null +++ b/queue-6.18/coresight-tmc-etr-fix-race-condition-between-sysfs-a.patch @@ -0,0 +1,97 @@ +From cd20ffde533cb81100be9e56e9346ada9fc3e212 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 18:15:42 +0800 +Subject: coresight: tmc-etr: Fix race condition between sysfs and perf mode + +From: Yicong Yang + +[ Upstream commit e6e43e82c79c97917cbe356c07e8a6f3f982ab53 ] + +When trying to run perf and sysfs mode simultaneously, the WARN_ON() +in tmc_etr_enable_hw() is triggered sometimes: + + WARNING: CPU: 42 PID: 3911571 at drivers/hwtracing/coresight/coresight-tmc-etr.c:1060 tmc_etr_enable_hw+0xc0/0xd8 [coresight_tmc] + [..snip..] + Call trace: + tmc_etr_enable_hw+0xc0/0xd8 [coresight_tmc] (P) + tmc_enable_etr_sink+0x11c/0x250 [coresight_tmc] (L) + tmc_enable_etr_sink+0x11c/0x250 [coresight_tmc] + coresight_enable_path+0x1c8/0x218 [coresight] + coresight_enable_sysfs+0xa4/0x228 [coresight] + enable_source_store+0x58/0xa8 [coresight] + dev_attr_store+0x20/0x40 + sysfs_kf_write+0x4c/0x68 + kernfs_fop_write_iter+0x120/0x1b8 + vfs_write+0x2c8/0x388 + ksys_write+0x74/0x108 + __arm64_sys_write+0x24/0x38 + el0_svc_common.constprop.0+0x64/0x148 + do_el0_svc+0x24/0x38 + el0_svc+0x3c/0x130 + el0t_64_sync_handler+0xc8/0xd0 + el0t_64_sync+0x1ac/0x1b0 + ---[ end trace 0000000000000000 ]--- + +Since the enablement of sysfs mode is separeted into two critical regions, +one for sysfs buffer allocation and another for hardware enablement, it's +possible to race with the perf mode. Fix this by double check whether +the perf mode's been used before enabling the hardware in sysfs mode. + + mode: + [sysfs mode] [perf mode] + tmc_etr_get_sysfs_buffer() + spin_lock(&drvdata->spinlock) + [sysfs buffer allocation] + spin_unlock(&drvdata->spinlock) + spin_lock(&drvdata->spinlock) + tmc_etr_enable_hw() + drvdata->etr_buf = etr_perf->etr_buf + spin_unlock(&drvdata->spinlock) + spin_lock(&drvdata->spinlock) + tmc_etr_enable_hw() + WARN_ON(drvdata->etr_buf) // WARN sicne etr_buf initialized at + the perf side + spin_unlock(&drvdata->spinlock) + +With this fix, we retain the check for CS_MODE_PERF in get_etr_sysfs_buf. +This ensures we verify whether the perf mode's already running before we +actually allocate the buffer. Then we can save the time of +allocating/freeing the sysfs buffer if race with the perf mode. + +Fixes: 296b01fd106e ("coresight: Refactor out buffer allocation function for ETR") +Signed-off-by: Yicong Yang +Signed-off-by: Junhao He +Signed-off-by: Suzuki K Poulose +Link: https://lore.kernel.org/r/20260121101543.2017014-3-wangyushan12@huawei.com +Signed-off-by: Sasha Levin +--- + drivers/hwtracing/coresight/coresight-tmc-etr.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c +index 60b0e0a6da057..9144b273d415f 100644 +--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c ++++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c +@@ -1306,6 +1306,19 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) + + raw_spin_lock_irqsave(&drvdata->spinlock, flags); + ++ /* ++ * Since the sysfs buffer allocation and the hardware enablement is not ++ * in the same critical region, it's possible to race with the perf. ++ */ ++ if (coresight_get_mode(csdev) == CS_MODE_PERF) { ++ drvdata->sysfs_buf = NULL; ++ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); ++ ++ /* Free allocated memory out side of the spinlock */ ++ tmc_etr_free_sysfs_buf(sysfs_buf); ++ return -EBUSY; ++ } ++ + /* + * In sysFS mode we can have multiple writers per sink. Since this + * sink is already enabled no memory is needed and the HW need not be +-- +2.51.0 + diff --git a/queue-6.18/cpufreq-intel_pstate-enable-asym-capacity-only-when-.patch b/queue-6.18/cpufreq-intel_pstate-enable-asym-capacity-only-when-.patch new file mode 100644 index 0000000000..79e326bc15 --- /dev/null +++ b/queue-6.18/cpufreq-intel_pstate-enable-asym-capacity-only-when-.patch @@ -0,0 +1,51 @@ +From 2b473438dc206aa0885d082c30b2703eabb93fbd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 10:48:52 +0800 +Subject: cpufreq: intel_pstate: Enable asym capacity only when CPU SMT is not + possible + +From: Yaxiong Tian + +[ Upstream commit 1fedbb589448bee9f20bb2ed9c850d1d2cf9963c ] + +According to the description in the intel_pstate.rst documentation, +Capacity-Aware Scheduling and Energy-Aware Scheduling are only +supported on a hybrid processor without SMT. Previously, the system +used sched_smt_active() for judgment, which is not a strict condition +because users can switch it on or off via /sys at any time. + +This could lead to incorrect driver settings in certain scenarios. +For example, on a CPU that supports SMT, a user can disable SMT +via the nosmt parameter to enable asym capacity, and then re-enable +SMT via /sys. In such cases, some settings in the driver would no +longer be correct. + +To address this issue, replace sched_smt_active() with cpu_smt_possible(), +and only enable asym capacity when CPU SMT is not possible. + +Fixes: 929ebc93ccaa ("cpufreq: intel_pstate: Set asymmetric CPU capacity on hybrid systems") +Signed-off-by: Yaxiong Tian +[ rjw: Subject and changelog edits ] +Link: https://patch.msgid.link/20260203024852.301066-1-tianyaxiong@kylinos.cn +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/cpufreq/intel_pstate.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c +index 492a10f1bdbfa..38333f7da40db 100644 +--- a/drivers/cpufreq/intel_pstate.c ++++ b/drivers/cpufreq/intel_pstate.c +@@ -1152,7 +1152,7 @@ static void hybrid_init_cpu_capacity_scaling(bool refresh) + * the capacity of SMT threads is not deterministic even approximately, + * do not do that when SMT is in use. + */ +- if (hwp_is_hybrid && !sched_smt_active() && arch_enable_hybrid_capacity_scale()) { ++ if (hwp_is_hybrid && !cpu_smt_possible() && arch_enable_hybrid_capacity_scale()) { + hybrid_refresh_cpu_capacity_scaling(); + /* + * Disabling ITMT causes sched domains to be rebuilt to disable asym +-- +2.51.0 + diff --git a/queue-6.18/cpufreq-scmi-correct-scmi-explanation.patch b/queue-6.18/cpufreq-scmi-correct-scmi-explanation.patch new file mode 100644 index 0000000000..8acbd9d9ea --- /dev/null +++ b/queue-6.18/cpufreq-scmi-correct-scmi-explanation.patch @@ -0,0 +1,37 @@ +From f4982356d2dc61474bac0a95bb3317faaed26a92 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Jan 2026 22:33:30 +0300 +Subject: cpufreq: scmi: correct SCMI explanation + +From: Sergey Shtylyov + +[ Upstream commit 8c376f337a7e31c42949247e24eaad9a30d6c62c ] + +SCMI stands for System Control and Management Interface, not System Control +and Power Interface -- apparently, Sudeep Holla copied this line from his +SCPI driver and then just forgot to update the acronym explanation... :-) + +Fixes: 99d6bdf33877 ("cpufreq: add support for CPU DVFS based on SCMI message protocol") +Signed-off-by: Sergey Shtylyov +Reviewed-by: Sudeep Holla +Signed-off-by: Viresh Kumar +Signed-off-by: Sasha Levin +--- + drivers/cpufreq/scmi-cpufreq.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c +index d2a110079f5fd..e0e1756180b0c 100644 +--- a/drivers/cpufreq/scmi-cpufreq.c ++++ b/drivers/cpufreq/scmi-cpufreq.c +@@ -1,6 +1,6 @@ + // SPDX-License-Identifier: GPL-2.0 + /* +- * System Control and Power Interface (SCMI) based CPUFreq Interface driver ++ * System Control and Management Interface (SCMI) based CPUFreq Interface driver + * + * Copyright (C) 2018-2021 ARM Ltd. + * Sudeep Holla +-- +2.51.0 + diff --git a/queue-6.18/cpufreq-scmi-fix-device_node-reference-leak-in-scmi_.patch b/queue-6.18/cpufreq-scmi-fix-device_node-reference-leak-in-scmi_.patch new file mode 100644 index 0000000000..75244ca76f --- /dev/null +++ b/queue-6.18/cpufreq-scmi-fix-device_node-reference-leak-in-scmi_.patch @@ -0,0 +1,36 @@ +From 691ca97de9c75c78f3384bb0190a9c29cda3910d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 23:32:06 +0800 +Subject: cpufreq: scmi: Fix device_node reference leak in scmi_cpu_domain_id() + +From: Felix Gu + +[ Upstream commit 0b7fbf9333fa4699a53145bad8ce74ea986caa13 ] + +When calling of_parse_phandle_with_args(), the caller is responsible +to call of_node_put() to release the reference of device node. +In scmi_cpu_domain_id(), it does not release the reference. + +Fixes: e336baa4193e ("cpufreq: scmi: Prepare to move OF parsing of domain-id to cpufreq") +Signed-off-by: Felix Gu +Signed-off-by: Viresh Kumar +Signed-off-by: Sasha Levin +--- + drivers/cpufreq/scmi-cpufreq.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c +index e0e1756180b0c..c7a3b038385b5 100644 +--- a/drivers/cpufreq/scmi-cpufreq.c ++++ b/drivers/cpufreq/scmi-cpufreq.c +@@ -101,6 +101,7 @@ static int scmi_cpu_domain_id(struct device *cpu_dev) + return -EINVAL; + } + ++ of_node_put(domain_id.np); + return domain_id.args[0]; + } + +-- +2.51.0 + diff --git a/queue-6.18/cpuidle-governors-menu-always-check-timers-with-tick.patch b/queue-6.18/cpuidle-governors-menu-always-check-timers-with-tick.patch new file mode 100644 index 0000000000..011946cfa0 --- /dev/null +++ b/queue-6.18/cpuidle-governors-menu-always-check-timers-with-tick.patch @@ -0,0 +1,88 @@ +From 26a0293a275b6c9ebe3940a01a43b864689aa301 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 16:26:14 +0100 +Subject: cpuidle: governors: menu: Always check timers with tick stopped + +From: Rafael J. Wysocki + +[ Upstream commit 80606f4eb8d7484ab7f7d6f0fd30d71e6fbcf328 ] + +After commit 5484e31bbbff ("cpuidle: menu: Skip tick_nohz_get_sleep_length() +call in some cases"), if the return value of get_typical_interval() +multiplied by NSEC_PER_USEC is not greater than RESIDENCY_THRESHOLD_NS, +the menu governor will skip computing the time till the closest timer. +If that happens when the tick has been stopped already, the selected +idle state may be too deep due to the subsequent check comparing +predicted_ns with TICK_NSEC and causing its value to be replaced with +the expected time till the closest timer, which is KTIME_MAX in that +case. That will cause the deepest enabled idle state to be selected, +but the time till the closest timer very well may be shorter than the +target residency of that state, in which case a shallower state should +be used. + +Address this by making menu_select() always compute the time till the +closest timer when the tick has been stopped. + +Also move the predicted_ns check mentioned above into the branch in +which the time till the closest timer is determined because it only +needs to be done in that case. + +Fixes: 5484e31bbbff ("cpuidle: menu: Skip tick_nohz_get_sleep_length() call in some cases") +Signed-off-by: Rafael J. Wysocki +Reviewed-by: Christian Loehle +Link: https://patch.msgid.link/5959091.DvuYhMxLoT@rafael.j.wysocki +Signed-off-by: Sasha Levin +--- + drivers/cpuidle/governors/menu.c | 22 +++++++++++----------- + 1 file changed, 11 insertions(+), 11 deletions(-) + +diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c +index 64d6f7a1c7766..ca863ba03d454 100644 +--- a/drivers/cpuidle/governors/menu.c ++++ b/drivers/cpuidle/governors/menu.c +@@ -239,7 +239,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, + + /* Find the shortest expected idle interval. */ + predicted_ns = get_typical_interval(data) * NSEC_PER_USEC; +- if (predicted_ns > RESIDENCY_THRESHOLD_NS) { ++ if (predicted_ns > RESIDENCY_THRESHOLD_NS || tick_nohz_tick_stopped()) { + unsigned int timer_us; + + /* Determine the time till the closest timer. */ +@@ -259,6 +259,16 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, + RESOLUTION * DECAY * NSEC_PER_USEC); + /* Use the lowest expected idle interval to pick the idle state. */ + predicted_ns = min((u64)timer_us * NSEC_PER_USEC, predicted_ns); ++ /* ++ * If the tick is already stopped, the cost of possible short ++ * idle duration misprediction is much higher, because the CPU ++ * may be stuck in a shallow idle state for a long time as a ++ * result of it. In that case, say we might mispredict and use ++ * the known time till the closest timer event for the idle ++ * state selection. ++ */ ++ if (tick_nohz_tick_stopped() && predicted_ns < TICK_NSEC) ++ predicted_ns = data->next_timer_ns; + } else { + /* + * Because the next timer event is not going to be determined +@@ -284,16 +294,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, + return 0; + } + +- /* +- * If the tick is already stopped, the cost of possible short idle +- * duration misprediction is much higher, because the CPU may be stuck +- * in a shallow idle state for a long time as a result of it. In that +- * case, say we might mispredict and use the known time till the closest +- * timer event for the idle state selection. +- */ +- if (tick_nohz_tick_stopped() && predicted_ns < TICK_NSEC) +- predicted_ns = data->next_timer_ns; +- + /* + * Find the idle state with the lowest power while satisfying + * our constraints. +-- +2.51.0 + diff --git a/queue-6.18/crypto-caam-fix-netdev-memory-leak-in-dpaa2_caam_pro.patch b/queue-6.18/crypto-caam-fix-netdev-memory-leak-in-dpaa2_caam_pro.patch new file mode 100644 index 0000000000..b67a7ad4bf --- /dev/null +++ b/queue-6.18/crypto-caam-fix-netdev-memory-leak-in-dpaa2_caam_pro.patch @@ -0,0 +1,145 @@ +From 885520c6bb188237923d3cc2731ae11456a0573d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 09:55:24 +0800 +Subject: crypto: caam - fix netdev memory leak in dpaa2_caam_probe + +From: Jianpeng Chang + +[ Upstream commit 7d43252b3060b0ba4a192dce5dba85a3f39ffe39 ] + +When commit 0e1a4d427f58 ("crypto: caam: Unembed net_dev structure in +dpaa2") converted embedded net_device to dynamically allocated pointers, +it added cleanup in dpaa2_dpseci_disable() but missed adding cleanup in +dpaa2_dpseci_free() for error paths. + +This causes memory leaks when dpaa2_dpseci_dpio_setup() fails during probe +due to DPIO devices not being ready yet. The kernel's deferred probe +mechanism handles the retry successfully, but the netdevs allocated during +the failed probe attempt are never freed, resulting in kmemleak reports +showing multiple leaked netdev-related allocations all traced back to +dpaa2_caam_probe(). + +Fix this by preserving the CPU mask of allocated netdevs during setup and +using it for cleanup in dpaa2_dpseci_free(). This approach ensures that +only the CPUs that actually had netdevs allocated will be cleaned up, +avoiding potential issues with CPU hotplug scenarios. + +Fixes: 0e1a4d427f58 ("crypto: caam: Unembed net_dev structure in dpaa2") +Signed-off-by: Jianpeng Chang +Reviewed-by: Breno Leitao +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/caam/caamalg_qi2.c | 27 +++++++++++++++------------ + drivers/crypto/caam/caamalg_qi2.h | 2 ++ + 2 files changed, 17 insertions(+), 12 deletions(-) + +diff --git a/drivers/crypto/caam/caamalg_qi2.c b/drivers/crypto/caam/caamalg_qi2.c +index 107ccb2ade420..c6117c23eb25b 100644 +--- a/drivers/crypto/caam/caamalg_qi2.c ++++ b/drivers/crypto/caam/caamalg_qi2.c +@@ -4814,7 +4814,8 @@ static void dpaa2_dpseci_free(struct dpaa2_caam_priv *priv) + { + struct device *dev = priv->dev; + struct fsl_mc_device *ls_dev = to_fsl_mc_device(dev); +- int err; ++ struct dpaa2_caam_priv_per_cpu *ppriv; ++ int i, err; + + if (DPSECI_VER(priv->major_ver, priv->minor_ver) > DPSECI_VER(5, 3)) { + err = dpseci_reset(priv->mc_io, 0, ls_dev->mc_handle); +@@ -4822,6 +4823,12 @@ static void dpaa2_dpseci_free(struct dpaa2_caam_priv *priv) + dev_err(dev, "dpseci_reset() failed\n"); + } + ++ for_each_cpu(i, priv->clean_mask) { ++ ppriv = per_cpu_ptr(priv->ppriv, i); ++ free_netdev(ppriv->net_dev); ++ } ++ free_cpumask_var(priv->clean_mask); ++ + dpaa2_dpseci_congestion_free(priv); + dpseci_close(priv->mc_io, 0, ls_dev->mc_handle); + } +@@ -5007,16 +5014,15 @@ static int __cold dpaa2_dpseci_setup(struct fsl_mc_device *ls_dev) + struct device *dev = &ls_dev->dev; + struct dpaa2_caam_priv *priv; + struct dpaa2_caam_priv_per_cpu *ppriv; +- cpumask_var_t clean_mask; + int err, cpu; + u8 i; + + err = -ENOMEM; +- if (!zalloc_cpumask_var(&clean_mask, GFP_KERNEL)) +- goto err_cpumask; +- + priv = dev_get_drvdata(dev); + ++ if (!zalloc_cpumask_var(&priv->clean_mask, GFP_KERNEL)) ++ goto err_cpumask; ++ + priv->dev = dev; + priv->dpsec_id = ls_dev->obj_desc.id; + +@@ -5118,7 +5124,7 @@ static int __cold dpaa2_dpseci_setup(struct fsl_mc_device *ls_dev) + err = -ENOMEM; + goto err_alloc_netdev; + } +- cpumask_set_cpu(cpu, clean_mask); ++ cpumask_set_cpu(cpu, priv->clean_mask); + ppriv->net_dev->dev = *dev; + + netif_napi_add_tx_weight(ppriv->net_dev, &ppriv->napi, +@@ -5126,18 +5132,16 @@ static int __cold dpaa2_dpseci_setup(struct fsl_mc_device *ls_dev) + DPAA2_CAAM_NAPI_WEIGHT); + } + +- err = 0; +- goto free_cpumask; ++ return 0; + + err_alloc_netdev: +- free_dpaa2_pcpu_netdev(priv, clean_mask); ++ free_dpaa2_pcpu_netdev(priv, priv->clean_mask); + err_get_rx_queue: + dpaa2_dpseci_congestion_free(priv); + err_get_vers: + dpseci_close(priv->mc_io, 0, ls_dev->mc_handle); + err_open: +-free_cpumask: +- free_cpumask_var(clean_mask); ++ free_cpumask_var(priv->clean_mask); + err_cpumask: + return err; + } +@@ -5182,7 +5186,6 @@ static int __cold dpaa2_dpseci_disable(struct dpaa2_caam_priv *priv) + ppriv = per_cpu_ptr(priv->ppriv, i); + napi_disable(&ppriv->napi); + netif_napi_del(&ppriv->napi); +- free_netdev(ppriv->net_dev); + } + + return 0; +diff --git a/drivers/crypto/caam/caamalg_qi2.h b/drivers/crypto/caam/caamalg_qi2.h +index 61d1219a202fc..8e65b4b28c7ba 100644 +--- a/drivers/crypto/caam/caamalg_qi2.h ++++ b/drivers/crypto/caam/caamalg_qi2.h +@@ -42,6 +42,7 @@ + * @mc_io: pointer to MC portal's I/O object + * @domain: IOMMU domain + * @ppriv: per CPU pointers to privata data ++ * @clean_mask: CPU mask of CPUs that have allocated netdevs + */ + struct dpaa2_caam_priv { + int dpsec_id; +@@ -65,6 +66,7 @@ struct dpaa2_caam_priv { + + struct dpaa2_caam_priv_per_cpu __percpu *ppriv; + struct dentry *dfs_root; ++ cpumask_var_t clean_mask; + }; + + /** +-- +2.51.0 + diff --git a/queue-6.18/crypto-cavium-fix-dma_free_coherent-size.patch b/queue-6.18/crypto-cavium-fix-dma_free_coherent-size.patch new file mode 100644 index 0000000000..fc3e112029 --- /dev/null +++ b/queue-6.18/crypto-cavium-fix-dma_free_coherent-size.patch @@ -0,0 +1,38 @@ +From 2d5a3857877b60a154518084c2f844cf9ec1fc94 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 10:56:45 +0100 +Subject: crypto: cavium - fix dma_free_coherent() size + +From: Thomas Fourier + +[ Upstream commit 941676c30ba5b40a01bed92448f457ce62fd1f07 ] + +The size of the buffer in alloc_command_queues() is +curr->size + CPT_NEXT_CHUNK_PTR_SIZE, so used that length for +dma_free_coherent(). + +Fixes: c694b233295b ("crypto: cavium - Add the Virtual Function driver for CPT") +Signed-off-by: Thomas Fourier +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/cavium/cpt/cptvf_main.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/crypto/cavium/cpt/cptvf_main.c b/drivers/crypto/cavium/cpt/cptvf_main.c +index c246920e6f540..bccd680c7f7ee 100644 +--- a/drivers/crypto/cavium/cpt/cptvf_main.c ++++ b/drivers/crypto/cavium/cpt/cptvf_main.c +@@ -180,7 +180,8 @@ static void free_command_queues(struct cpt_vf *cptvf, + + hlist_for_each_entry_safe(chunk, node, &cqinfo->queue[i].chead, + nextchunk) { +- dma_free_coherent(&pdev->dev, chunk->size, ++ dma_free_coherent(&pdev->dev, ++ chunk->size + CPT_NEXT_CHUNK_PTR_SIZE, + chunk->head, + chunk->dma_addr); + chunk->head = NULL; +-- +2.51.0 + diff --git a/queue-6.18/crypto-ccp-add-an-s4-restore-flow.patch b/queue-6.18/crypto-ccp-add-an-s4-restore-flow.patch new file mode 100644 index 0000000000..40f5d1e80c --- /dev/null +++ b/queue-6.18/crypto-ccp-add-an-s4-restore-flow.patch @@ -0,0 +1,168 @@ +From 282a76a56e6e8fd690145a53b31a1e697e013b22 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 22:11:30 -0600 +Subject: crypto: ccp - Add an S4 restore flow +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Mario Limonciello (AMD) + +[ Upstream commit 0ba2035026d0ab6c7c7e65ad8b418dc73d5700d9 ] + +The system will have lost power during S4. The ring used for TEE +communications needs to be initialized before use. + +Fixes: f892a21f51162 ("crypto: ccp - use generic power management") +Reported-by: Lars Francke +Closes: https://lore.kernel.org/platform-driver-x86/CAD-Ua_gfJnQSo8ucS_7ZwzuhoBRJ14zXP7s8b-zX3ZcxcyWePw@mail.gmail.com/ +Tested-by: Yijun Shen +Signed-off-by: Mario Limonciello (AMD) +Reviewed-by: Shyam Sundar S K +Reviewed-by: Tom Lendacky +Link: https://patch.msgid.link/20260116041132.153674-4-superm1@kernel.org +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/crypto/ccp/psp-dev.c | 11 +++++++++++ + drivers/crypto/ccp/sp-dev.c | 12 ++++++++++++ + drivers/crypto/ccp/sp-dev.h | 3 +++ + drivers/crypto/ccp/sp-pci.c | 16 +++++++++++++++- + drivers/crypto/ccp/tee-dev.c | 5 +++++ + drivers/crypto/ccp/tee-dev.h | 1 + + 6 files changed, 47 insertions(+), 1 deletion(-) + +diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c +index 9e21da0e298ad..5c7f7e02a7d8a 100644 +--- a/drivers/crypto/ccp/psp-dev.c ++++ b/drivers/crypto/ccp/psp-dev.c +@@ -351,6 +351,17 @@ struct psp_device *psp_get_master_device(void) + return sp ? sp->psp_data : NULL; + } + ++int psp_restore(struct sp_device *sp) ++{ ++ struct psp_device *psp = sp->psp_data; ++ int ret = 0; ++ ++ if (psp->tee_data) ++ ret = tee_restore(psp); ++ ++ return ret; ++} ++ + void psp_pci_init(void) + { + psp_master = psp_get_master_device(); +diff --git a/drivers/crypto/ccp/sp-dev.c b/drivers/crypto/ccp/sp-dev.c +index 3467f6db4f505..f204aa5df96e2 100644 +--- a/drivers/crypto/ccp/sp-dev.c ++++ b/drivers/crypto/ccp/sp-dev.c +@@ -230,6 +230,18 @@ int sp_resume(struct sp_device *sp) + return 0; + } + ++int sp_restore(struct sp_device *sp) ++{ ++ if (sp->psp_data) { ++ int ret = psp_restore(sp); ++ ++ if (ret) ++ return ret; ++ } ++ ++ return sp_resume(sp); ++} ++ + struct sp_device *sp_get_psp_master_device(void) + { + struct sp_device *i, *ret = NULL; +diff --git a/drivers/crypto/ccp/sp-dev.h b/drivers/crypto/ccp/sp-dev.h +index 6f9d7063257d7..c8a611ef275b5 100644 +--- a/drivers/crypto/ccp/sp-dev.h ++++ b/drivers/crypto/ccp/sp-dev.h +@@ -141,6 +141,7 @@ void sp_destroy(struct sp_device *sp); + + int sp_suspend(struct sp_device *sp); + int sp_resume(struct sp_device *sp); ++int sp_restore(struct sp_device *sp); + int sp_request_ccp_irq(struct sp_device *sp, irq_handler_t handler, + const char *name, void *data); + void sp_free_ccp_irq(struct sp_device *sp, void *data); +@@ -174,6 +175,7 @@ int psp_dev_init(struct sp_device *sp); + void psp_pci_init(void); + void psp_dev_destroy(struct sp_device *sp); + void psp_pci_exit(void); ++int psp_restore(struct sp_device *sp); + + #else /* !CONFIG_CRYPTO_DEV_SP_PSP */ + +@@ -181,6 +183,7 @@ static inline int psp_dev_init(struct sp_device *sp) { return 0; } + static inline void psp_pci_init(void) { } + static inline void psp_dev_destroy(struct sp_device *sp) { } + static inline void psp_pci_exit(void) { } ++static inline int psp_restore(struct sp_device *sp) { return 0; } + + #endif /* CONFIG_CRYPTO_DEV_SP_PSP */ + +diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c +index 8891ceee1d7d0..6ac805d99ccb3 100644 +--- a/drivers/crypto/ccp/sp-pci.c ++++ b/drivers/crypto/ccp/sp-pci.c +@@ -353,6 +353,13 @@ static int __maybe_unused sp_pci_resume(struct device *dev) + return sp_resume(sp); + } + ++static int __maybe_unused sp_pci_restore(struct device *dev) ++{ ++ struct sp_device *sp = dev_get_drvdata(dev); ++ ++ return sp_restore(sp); ++} ++ + #ifdef CONFIG_CRYPTO_DEV_SP_PSP + static const struct sev_vdata sevv1 = { + .cmdresp_reg = 0x10580, /* C2PMSG_32 */ +@@ -563,7 +570,14 @@ static const struct pci_device_id sp_pci_table[] = { + }; + MODULE_DEVICE_TABLE(pci, sp_pci_table); + +-static SIMPLE_DEV_PM_OPS(sp_pci_pm_ops, sp_pci_suspend, sp_pci_resume); ++static const struct dev_pm_ops sp_pci_pm_ops = { ++ .suspend = pm_sleep_ptr(sp_pci_suspend), ++ .resume = pm_sleep_ptr(sp_pci_resume), ++ .freeze = pm_sleep_ptr(sp_pci_suspend), ++ .thaw = pm_sleep_ptr(sp_pci_resume), ++ .poweroff = pm_sleep_ptr(sp_pci_suspend), ++ .restore_early = pm_sleep_ptr(sp_pci_restore), ++}; + + static struct pci_driver sp_pci_driver = { + .name = "ccp", +diff --git a/drivers/crypto/ccp/tee-dev.c b/drivers/crypto/ccp/tee-dev.c +index af881daa5855b..11c4b05e2f3a2 100644 +--- a/drivers/crypto/ccp/tee-dev.c ++++ b/drivers/crypto/ccp/tee-dev.c +@@ -366,3 +366,8 @@ int psp_check_tee_status(void) + return 0; + } + EXPORT_SYMBOL(psp_check_tee_status); ++ ++int tee_restore(struct psp_device *psp) ++{ ++ return tee_init_ring(psp->tee_data); ++} +diff --git a/drivers/crypto/ccp/tee-dev.h b/drivers/crypto/ccp/tee-dev.h +index ea9a2b7c05f57..c23416cb7bb37 100644 +--- a/drivers/crypto/ccp/tee-dev.h ++++ b/drivers/crypto/ccp/tee-dev.h +@@ -111,5 +111,6 @@ struct tee_ring_cmd { + + int tee_dev_init(struct psp_device *psp); + void tee_dev_destroy(struct psp_device *psp); ++int tee_restore(struct psp_device *psp); + + #endif /* __TEE_DEV_H__ */ +-- +2.51.0 + diff --git a/queue-6.18/crypto-ccp-declare-psp-dead-if-psp_cmd_tee_ring_init.patch b/queue-6.18/crypto-ccp-declare-psp-dead-if-psp_cmd_tee_ring_init.patch new file mode 100644 index 0000000000..7302c122fc --- /dev/null +++ b/queue-6.18/crypto-ccp-declare-psp-dead-if-psp_cmd_tee_ring_init.patch @@ -0,0 +1,43 @@ +From f774f6064b7d0f34388e03a23492f9850fb20022 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 22:11:29 -0600 +Subject: crypto: ccp - Declare PSP dead if PSP_CMD_TEE_RING_INIT fails +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Mario Limonciello (AMD) + +[ Upstream commit 5e599d7871bf852e94e8aa08b99724635f2cbf96 ] + +tee_init_ring() only declares PSP dead if the command times out. +If there is any other failure it is still considered fatal though. +Set psp_dead for other failures as well. + +Fixes: 949a0c8dd3c2 ("crypto: ccp - Move direct access to some PSP registers out of TEE") +Tested-by: Yijun Shen +Signed-off-by: Mario Limonciello (AMD) +Acked-by: Tom Lendacky +Reviewed-by: Shyam Sundar S K +Link: https://patch.msgid.link/20260116041132.153674-3-superm1@kernel.org +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/crypto/ccp/tee-dev.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/crypto/ccp/tee-dev.c b/drivers/crypto/ccp/tee-dev.c +index 5e1d80724678d..af881daa5855b 100644 +--- a/drivers/crypto/ccp/tee-dev.c ++++ b/drivers/crypto/ccp/tee-dev.c +@@ -125,6 +125,7 @@ static int tee_init_ring(struct psp_tee_device *tee) + dev_err(tee->dev, "tee: ring init command failed (%#010lx)\n", + FIELD_GET(PSP_CMDRESP_STS, reg)); + tee_free_ring(tee); ++ psp_dead = true; + ret = -EIO; + } + +-- +2.51.0 + diff --git a/queue-6.18/crypto-ccp-factor-out-ring-destroy-handling-to-a-hel.patch b/queue-6.18/crypto-ccp-factor-out-ring-destroy-handling-to-a-hel.patch new file mode 100644 index 0000000000..185dcd41f0 --- /dev/null +++ b/queue-6.18/crypto-ccp-factor-out-ring-destroy-handling-to-a-hel.patch @@ -0,0 +1,90 @@ +From a5c37fb54bc76a6f78d8cff5a705e52a98ffafe4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 22:11:31 -0600 +Subject: crypto: ccp - Factor out ring destroy handling to a helper +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Mario Limonciello (AMD) + +[ Upstream commit d95f87a65bce5f2f2a02ca6094ca4841d4073df3 ] + +The ring destroy command needs to be used in multiple places. Split +out the code to a helper. + +Tested-by: Yijun Shen +Signed-off-by: Mario Limonciello (AMD) +Acked-by: Tom Lendacky +Reviewed-by: Shyam Sundar S K +Link: https://patch.msgid.link/20260116041132.153674-5-superm1@kernel.org +Signed-off-by: Ilpo Järvinen +Stable-dep-of: 7b85137caf11 ("crypto: ccp - Send PSP_CMD_TEE_RING_DESTROY when PSP_CMD_TEE_RING_INIT fails") +Signed-off-by: Sasha Levin +--- + drivers/crypto/ccp/tee-dev.c | 36 ++++++++++++++++++++++++------------ + 1 file changed, 24 insertions(+), 12 deletions(-) + +diff --git a/drivers/crypto/ccp/tee-dev.c b/drivers/crypto/ccp/tee-dev.c +index 11c4b05e2f3a2..ef1430f86ad62 100644 +--- a/drivers/crypto/ccp/tee-dev.c ++++ b/drivers/crypto/ccp/tee-dev.c +@@ -86,6 +86,29 @@ static inline void tee_free_cmd_buffer(struct tee_init_ring_cmd *cmd) + kfree(cmd); + } + ++static bool tee_send_destroy_cmd(struct psp_tee_device *tee) ++{ ++ unsigned int reg; ++ int ret; ++ ++ ret = psp_mailbox_command(tee->psp, PSP_CMD_TEE_RING_DESTROY, NULL, ++ TEE_DEFAULT_CMD_TIMEOUT, ®); ++ if (ret) { ++ dev_err(tee->dev, "tee: ring destroy command timed out, disabling TEE support\n"); ++ psp_dead = true; ++ return false; ++ } ++ ++ if (FIELD_GET(PSP_CMDRESP_STS, reg)) { ++ dev_err(tee->dev, "tee: ring destroy command failed (%#010lx)\n", ++ FIELD_GET(PSP_CMDRESP_STS, reg)); ++ psp_dead = true; ++ return false; ++ } ++ ++ return true; ++} ++ + static int tee_init_ring(struct psp_tee_device *tee) + { + int ring_size = MAX_RING_BUFFER_ENTRIES * sizeof(struct tee_ring_cmd); +@@ -137,24 +160,13 @@ static int tee_init_ring(struct psp_tee_device *tee) + + static void tee_destroy_ring(struct psp_tee_device *tee) + { +- unsigned int reg; +- int ret; +- + if (!tee->rb_mgr.ring_start) + return; + + if (psp_dead) + goto free_ring; + +- ret = psp_mailbox_command(tee->psp, PSP_CMD_TEE_RING_DESTROY, NULL, +- TEE_DEFAULT_CMD_TIMEOUT, ®); +- if (ret) { +- dev_err(tee->dev, "tee: ring destroy command timed out, disabling TEE support\n"); +- psp_dead = true; +- } else if (FIELD_GET(PSP_CMDRESP_STS, reg)) { +- dev_err(tee->dev, "tee: ring destroy command failed (%#010lx)\n", +- FIELD_GET(PSP_CMDRESP_STS, reg)); +- } ++ tee_send_destroy_cmd(tee); + + free_ring: + tee_free_ring(tee); +-- +2.51.0 + diff --git a/queue-6.18/crypto-ccp-fix-a-case-where-snp_shutdown-is-missed.patch b/queue-6.18/crypto-ccp-fix-a-case-where-snp_shutdown-is-missed.patch new file mode 100644 index 0000000000..ac3d6e7ea2 --- /dev/null +++ b/queue-6.18/crypto-ccp-fix-a-case-where-snp_shutdown-is-missed.patch @@ -0,0 +1,110 @@ +From be3a133f94ee5e9f3ec3b1077999d49ab5ff3d1b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Jan 2026 10:22:17 -0700 +Subject: crypto: ccp - Fix a case where SNP_SHUTDOWN is missed + +From: Tom Lendacky + +[ Upstream commit 551120148b67e04527b405c5ec33a31593846ba4 ] + +If page reclaim fails in sev_ioctl_do_snp_platform_status() and SNP was +moved from UNINIT to INIT for the function, SNP is not moved back to +UNINIT state. Additionally, SNP is not required to be initialized in order +to execute the SNP_PLATFORM_STATUS command, so don't attempt to move to +INIT state and let SNP_PLATFORM_STATUS report the status as is. + +Fixes: ceac7fb89e8d ("crypto: ccp - Ensure implicit SEV/SNP init and shutdown in ioctls") +Signed-off-by: Tom Lendacky +Reviewed-by: Tycho Andersen (AMD) +Reviewed-by: Alexey Kardashevskiy +Signed-off-by: Tycho Andersen (AMD) +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/ccp/sev-dev.c | 46 ++++++++++++++++++------------------ + 1 file changed, 23 insertions(+), 23 deletions(-) + +diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c +index 0d13d47c164bb..3c6ee8b4e4487 100644 +--- a/drivers/crypto/ccp/sev-dev.c ++++ b/drivers/crypto/ccp/sev-dev.c +@@ -2351,11 +2351,10 @@ static int sev_ioctl_do_pdh_export(struct sev_issue_cmd *argp, bool writable) + static int sev_ioctl_do_snp_platform_status(struct sev_issue_cmd *argp) + { + struct sev_device *sev = psp_master->sev_data; +- bool shutdown_required = false; + struct sev_data_snp_addr buf; + struct page *status_page; +- int ret, error; + void *data; ++ int ret; + + if (!argp->data) + return -EINVAL; +@@ -2366,31 +2365,35 @@ static int sev_ioctl_do_snp_platform_status(struct sev_issue_cmd *argp) + + data = page_address(status_page); + +- if (!sev->snp_initialized) { +- ret = snp_move_to_init_state(argp, &shutdown_required); +- if (ret) +- goto cleanup; +- } +- + /* +- * Firmware expects status page to be in firmware-owned state, otherwise +- * it will report firmware error code INVALID_PAGE_STATE (0x1A). ++ * SNP_PLATFORM_STATUS can be executed in any SNP state. But if executed ++ * when SNP has been initialized, the status page must be firmware-owned. + */ +- if (rmp_mark_pages_firmware(__pa(data), 1, true)) { +- ret = -EFAULT; +- goto cleanup; ++ if (sev->snp_initialized) { ++ /* ++ * Firmware expects the status page to be in Firmware state, ++ * otherwise it will report an error INVALID_PAGE_STATE. ++ */ ++ if (rmp_mark_pages_firmware(__pa(data), 1, true)) { ++ ret = -EFAULT; ++ goto cleanup; ++ } + } + + buf.address = __psp_pa(data); + ret = __sev_do_cmd_locked(SEV_CMD_SNP_PLATFORM_STATUS, &buf, &argp->error); + +- /* +- * Status page will be transitioned to Reclaim state upon success, or +- * left in Firmware state in failure. Use snp_reclaim_pages() to +- * transition either case back to Hypervisor-owned state. +- */ +- if (snp_reclaim_pages(__pa(data), 1, true)) +- return -EFAULT; ++ if (sev->snp_initialized) { ++ /* ++ * The status page will be in Reclaim state on success, or left ++ * in Firmware state on failure. Use snp_reclaim_pages() to ++ * transition either case back to Hypervisor-owned state. ++ */ ++ if (snp_reclaim_pages(__pa(data), 1, true)) { ++ snp_leak_pages(__page_to_pfn(status_page), 1); ++ return -EFAULT; ++ } ++ } + + if (ret) + goto cleanup; +@@ -2400,9 +2403,6 @@ static int sev_ioctl_do_snp_platform_status(struct sev_issue_cmd *argp) + ret = -EFAULT; + + cleanup: +- if (shutdown_required) +- __sev_snp_shutdown_locked(&error, false); +- + __free_pages(status_page, 0); + return ret; + } +-- +2.51.0 + diff --git a/queue-6.18/crypto-ccp-fix-a-crash-due-to-incorrect-cleanup-usag.patch b/queue-6.18/crypto-ccp-fix-a-crash-due-to-incorrect-cleanup-usag.patch new file mode 100644 index 0000000000..449ac15e6e --- /dev/null +++ b/queue-6.18/crypto-ccp-fix-a-crash-due-to-incorrect-cleanup-usag.patch @@ -0,0 +1,43 @@ +From b5659d78c4d860c374496b692f9d3956e5192994 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 16:17:24 +0100 +Subject: crypto: ccp - Fix a crash due to incorrect cleanup usage of kfree + +From: Ella Ma + +[ Upstream commit d5abcc33ee76bc26d58b39dc1a097e43a99dd438 ] + +Annotating a local pointer variable, which will be assigned with the +kmalloc-family functions, with the `__cleanup(kfree)` attribute will +make the address of the local variable, rather than the address returned +by kmalloc, passed to kfree directly and lead to a crash due to invalid +deallocation of stack address. According to other places in the repo, +the correct usage should be `__free(kfree)`. The code coincidentally +compiled because the parameter type `void *` of kfree is compatible with +the desired type `struct { ... } **`. + +Fixes: a71475582ada ("crypto: ccp - reduce stack usage in ccp_run_aes_gcm_cmd") +Signed-off-by: Ella Ma +Acked-by: Tom Lendacky +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/ccp/ccp-ops.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/crypto/ccp/ccp-ops.c b/drivers/crypto/ccp/ccp-ops.c +index d78865d9d5f09..d0412e5847625 100644 +--- a/drivers/crypto/ccp/ccp-ops.c ++++ b/drivers/crypto/ccp/ccp-ops.c +@@ -642,7 +642,7 @@ ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) + struct ccp_data dst; + struct ccp_data aad; + struct ccp_op op; +- } *wa __cleanup(kfree) = kzalloc(sizeof *wa, GFP_KERNEL); ++ } *wa __free(kfree) = kzalloc(sizeof(*wa), GFP_KERNEL); + unsigned int dm_offset; + unsigned int authsize; + unsigned int jobid; +-- +2.51.0 + diff --git a/queue-6.18/crypto-ccp-narrow-scope-of-snp_range_list.patch b/queue-6.18/crypto-ccp-narrow-scope-of-snp_range_list.patch new file mode 100644 index 0000000000..2eb5befee3 --- /dev/null +++ b/queue-6.18/crypto-ccp-narrow-scope-of-snp_range_list.patch @@ -0,0 +1,64 @@ +From 4c66d5e0235ea085104fda9f072f34b32dbd610a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Jan 2026 10:22:18 -0700 +Subject: crypto: ccp - narrow scope of snp_range_list + +From: Tycho Andersen (AMD) + +[ Upstream commit dc8ccab15081efc4f2c5a9fc7b209cd641d29177 ] + +snp_range_list is only used in __sev_snp_init_locked() in the SNP_INIT_EX +case, move the declaration there and add a __free() cleanup helper for it +instead of waiting until shutdown. + +Fixes: 1ca5614b84ee ("crypto: ccp: Add support to initialize the AMD-SP for SEV-SNP") +Reviewed-by: Alexey Kardashevskiy +Signed-off-by: Tycho Andersen (AMD) +Reviewed-by: Tom Lendacky +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/ccp/sev-dev.c | 13 +------------ + 1 file changed, 1 insertion(+), 12 deletions(-) + +diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c +index 3c6ee8b4e4487..5fdba0fe4acce 100644 +--- a/drivers/crypto/ccp/sev-dev.c ++++ b/drivers/crypto/ccp/sev-dev.c +@@ -119,13 +119,6 @@ static size_t sev_es_tmr_size = SEV_TMR_SIZE; + #define NV_LENGTH (32 * 1024) + static void *sev_init_ex_buffer; + +-/* +- * SEV_DATA_RANGE_LIST: +- * Array containing range of pages that firmware transitions to HV-fixed +- * page state. +- */ +-static struct sev_data_range_list *snp_range_list; +- + static void __sev_firmware_shutdown(struct sev_device *sev, bool panic); + + static int snp_shutdown_on_panic(struct notifier_block *nb, +@@ -1365,6 +1358,7 @@ static int snp_filter_reserved_mem_regions(struct resource *rs, void *arg) + + static int __sev_snp_init_locked(int *error, unsigned int max_snp_asid) + { ++ struct sev_data_range_list *snp_range_list __free(kfree) = NULL; + struct psp_device *psp = psp_master; + struct sev_data_snp_init_ex data; + struct sev_device *sev; +@@ -2753,11 +2747,6 @@ static void __sev_firmware_shutdown(struct sev_device *sev, bool panic) + sev_init_ex_buffer = NULL; + } + +- if (snp_range_list) { +- kfree(snp_range_list); +- snp_range_list = NULL; +- } +- + __sev_snp_shutdown_locked(&error, panic); + } + +-- +2.51.0 + diff --git a/queue-6.18/crypto-ccp-send-psp_cmd_tee_ring_destroy-when-psp_cm.patch b/queue-6.18/crypto-ccp-send-psp_cmd_tee_ring_destroy-when-psp_cm.patch new file mode 100644 index 0000000000..9d90f3950e --- /dev/null +++ b/queue-6.18/crypto-ccp-send-psp_cmd_tee_ring_destroy-when-psp_cm.patch @@ -0,0 +1,113 @@ +From 0a0cce775ad71aeb4fbe7246a8a550a042a0b61a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 22:11:32 -0600 +Subject: crypto: ccp - Send PSP_CMD_TEE_RING_DESTROY when + PSP_CMD_TEE_RING_INIT fails +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Mario Limonciello (AMD) + +[ Upstream commit 7b85137caf110a09a4a18f00f730de4709f9afc8 ] + +The hibernate resume sequence involves loading a resume kernel that is just +used for loading the hibernate image before shifting back to the existing +kernel. + +During that hibernate resume sequence the resume kernel may have loaded +the ccp driver. If this happens the resume kernel will also have called +PSP_CMD_TEE_RING_INIT but it will never have called +PSP_CMD_TEE_RING_DESTROY. + +This is problematic because the existing kernel needs to re-initialize the +ring. One could argue that the existing kernel should call destroy +as part of restore() but there is no guarantee that the resume kernel did +or didn't load the ccp driver. There is also no callback opportunity for +the resume kernel to destroy before handing back control to the existing +kernel. + +Similar problems could potentially exist with the use of kdump and +crash handling. I actually reproduced this issue like this: + +1) rmmod ccp +2) hibernate the system +3) resume the system +4) modprobe ccp + +The resume kernel will have loaded ccp but never destroyed and then when +I try to modprobe it fails. + +Because of these possible cases add a flow that checks the error code from +the PSP_CMD_TEE_RING_INIT call and tries to call PSP_CMD_TEE_RING_DESTROY +if it failed. If this succeeds then call PSP_CMD_TEE_RING_INIT again. + +Fixes: f892a21f51162 ("crypto: ccp - use generic power management") +Reported-by: Lars Francke +Closes: https://lore.kernel.org/platform-driver-x86/CAD-Ua_gfJnQSo8ucS_7ZwzuhoBRJ14zXP7s8b-zX3ZcxcyWePw@mail.gmail.com/ +Tested-by: Yijun Shen +Signed-off-by: Mario Limonciello (AMD) +Reviewed-by: Shyam Sundar S K +Acked-by: Tom Lendacky +Link: https://patch.msgid.link/20260116041132.153674-6-superm1@kernel.org +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/crypto/ccp/tee-dev.c | 14 ++++++++++++++ + include/linux/psp.h | 1 + + 2 files changed, 15 insertions(+) + +diff --git a/drivers/crypto/ccp/tee-dev.c b/drivers/crypto/ccp/tee-dev.c +index ef1430f86ad62..92ffa412622a2 100644 +--- a/drivers/crypto/ccp/tee-dev.c ++++ b/drivers/crypto/ccp/tee-dev.c +@@ -113,6 +113,7 @@ static int tee_init_ring(struct psp_tee_device *tee) + { + int ring_size = MAX_RING_BUFFER_ENTRIES * sizeof(struct tee_ring_cmd); + struct tee_init_ring_cmd *cmd; ++ bool retry = false; + unsigned int reg; + int ret; + +@@ -135,6 +136,7 @@ static int tee_init_ring(struct psp_tee_device *tee) + /* Send command buffer details to Trusted OS by writing to + * CPU-PSP message registers + */ ++retry_init: + ret = psp_mailbox_command(tee->psp, PSP_CMD_TEE_RING_INIT, cmd, + TEE_DEFAULT_CMD_TIMEOUT, ®); + if (ret) { +@@ -145,6 +147,18 @@ static int tee_init_ring(struct psp_tee_device *tee) + } + + if (FIELD_GET(PSP_CMDRESP_STS, reg)) { ++ /* ++ * During the hibernate resume sequence driver may have gotten loaded ++ * but the ring not properly destroyed. If the ring doesn't work, try ++ * to destroy and re-init once. ++ */ ++ if (!retry && FIELD_GET(PSP_CMDRESP_STS, reg) == PSP_TEE_STS_RING_BUSY) { ++ dev_info(tee->dev, "tee: ring init command failed with busy status, retrying\n"); ++ if (tee_send_destroy_cmd(tee)) { ++ retry = true; ++ goto retry_init; ++ } ++ } + dev_err(tee->dev, "tee: ring init command failed (%#010lx)\n", + FIELD_GET(PSP_CMDRESP_STS, reg)); + tee_free_ring(tee); +diff --git a/include/linux/psp.h b/include/linux/psp.h +index 92e60aeef21e1..b337dcce1e991 100644 +--- a/include/linux/psp.h ++++ b/include/linux/psp.h +@@ -18,6 +18,7 @@ + * and should include an appropriate local definition in their source file. + */ + #define PSP_CMDRESP_STS GENMASK(15, 0) ++#define PSP_TEE_STS_RING_BUSY 0x0000000d /* Ring already initialized */ + #define PSP_CMDRESP_CMD GENMASK(23, 16) + #define PSP_CMDRESP_RESERVED GENMASK(29, 24) + #define PSP_CMDRESP_RECOVERY BIT(30) +-- +2.51.0 + diff --git a/queue-6.18/crypto-hisilicon-consolidate-qp-creation-and-start-i.patch b/queue-6.18/crypto-hisilicon-consolidate-qp-creation-and-start-i.patch new file mode 100644 index 0000000000..f92fadc43b --- /dev/null +++ b/queue-6.18/crypto-hisilicon-consolidate-qp-creation-and-start-i.patch @@ -0,0 +1,356 @@ +From a61e656b14a16ba04911ea357b85f4c6383a00d0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 21:44:47 +0800 +Subject: crypto: hisilicon - consolidate qp creation and start in + hisi_qm_alloc_qps_node + +From: Chenghai Huang + +[ Upstream commit 72f3bbebff15e87171271d643ee2672fb8e92031 ] + +Consolidate the creation and start of qp into the function +hisi_qm_alloc_qps_node. This change eliminates the need for +each module to perform these steps in two separate phases +(creation and start). + +Signed-off-by: Chenghai Huang +Signed-off-by: Weili Qian +Signed-off-by: Herbert Xu +Stable-dep-of: 6aff4d977e2d ("crypto: hisilicon/hpre - support the hpre algorithm fallback") +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/hpre/hpre_crypto.c | 40 ++---------- + drivers/crypto/hisilicon/qm.c | 70 ++++++++++++++++----- + drivers/crypto/hisilicon/sec2/sec_crypto.c | 8 --- + drivers/crypto/hisilicon/zip/zip_crypto.c | 43 ++----------- + include/linux/hisi_acc_qm.h | 1 - + 5 files changed, 66 insertions(+), 96 deletions(-) + +diff --git a/drivers/crypto/hisilicon/hpre/hpre_crypto.c b/drivers/crypto/hisilicon/hpre/hpre_crypto.c +index 220022ae7afb6..f410e610eabaa 100644 +--- a/drivers/crypto/hisilicon/hpre/hpre_crypto.c ++++ b/drivers/crypto/hisilicon/hpre/hpre_crypto.c +@@ -156,27 +156,6 @@ static void hpre_dfx_add_req_time(struct hpre_asym_request *hpre_req) + ktime_get_ts64(&hpre_req->req_time); + } + +-static struct hisi_qp *hpre_get_qp_and_start(u8 type) +-{ +- struct hisi_qp *qp; +- int ret; +- +- qp = hpre_create_qp(type); +- if (!qp) { +- pr_err("Can not create hpre qp!\n"); +- return ERR_PTR(-ENODEV); +- } +- +- ret = hisi_qm_start_qp(qp, 0); +- if (ret < 0) { +- hisi_qm_free_qps(&qp, 1); +- pci_err(qp->qm->pdev, "Can not start qp!\n"); +- return ERR_PTR(-EINVAL); +- } +- +- return qp; +-} +- + static int hpre_get_data_dma_addr(struct hpre_asym_request *hpre_req, + struct scatterlist *data, unsigned int len, + int is_src, dma_addr_t *tmp) +@@ -316,9 +295,8 @@ static int hpre_alg_res_post_hf(struct hpre_ctx *ctx, struct hpre_sqe *sqe, + + static void hpre_ctx_clear(struct hpre_ctx *ctx, bool is_clear_all) + { +- if (is_clear_all) { ++ if (is_clear_all) + hisi_qm_free_qps(&ctx->qp, 1); +- } + + ctx->crt_g2_mode = false; + ctx->key_sz = 0; +@@ -403,11 +381,10 @@ static int hpre_ctx_init(struct hpre_ctx *ctx, u8 type) + struct hisi_qp *qp; + struct hpre *hpre; + +- qp = hpre_get_qp_and_start(type); +- if (IS_ERR(qp)) +- return PTR_ERR(qp); ++ qp = hpre_create_qp(type); ++ if (!qp) ++ return -ENODEV; + +- qp->qp_ctx = ctx; + qp->req_cb = hpre_alg_cb; + ctx->qp = qp; + ctx->dev = &qp->qm->pdev->dev; +@@ -597,9 +574,6 @@ static void hpre_dh_clear_ctx(struct hpre_ctx *ctx, bool is_clear_all) + struct device *dev = ctx->dev; + unsigned int sz = ctx->key_sz; + +- if (is_clear_all) +- hisi_qm_stop_qp(ctx->qp); +- + if (ctx->dh.g) { + dma_free_coherent(dev, sz, ctx->dh.g, ctx->dh.dma_g); + ctx->dh.g = NULL; +@@ -940,9 +914,6 @@ static void hpre_rsa_clear_ctx(struct hpre_ctx *ctx, bool is_clear_all) + unsigned int half_key_sz = ctx->key_sz >> 1; + struct device *dev = ctx->dev; + +- if (is_clear_all) +- hisi_qm_stop_qp(ctx->qp); +- + if (ctx->rsa.pubkey) { + dma_free_coherent(dev, ctx->key_sz << 1, + ctx->rsa.pubkey, ctx->rsa.dma_pubkey); +@@ -1112,9 +1083,6 @@ static void hpre_ecc_clear_ctx(struct hpre_ctx *ctx, bool is_clear_all) + unsigned int sz = ctx->key_sz; + unsigned int shift = sz << 1; + +- if (is_clear_all) +- hisi_qm_stop_qp(ctx->qp); +- + if (ctx->ecdh.p) { + /* ecdh: p->a->k->b */ + memzero_explicit(ctx->ecdh.p + shift, sz); +diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c +index c2c24c3a2be86..a7c8839180ee7 100644 +--- a/drivers/crypto/hisilicon/qm.c ++++ b/drivers/crypto/hisilicon/qm.c +@@ -3516,6 +3516,14 @@ void hisi_qm_dev_err_uninit(struct hisi_qm *qm) + } + EXPORT_SYMBOL_GPL(hisi_qm_dev_err_uninit); + ++static void qm_release_qp_nolock(struct hisi_qp *qp) ++{ ++ struct hisi_qm *qm = qp->qm; ++ ++ qm->qp_in_used--; ++ idr_remove(&qm->qp_idr, qp->qp_id); ++} ++ + /** + * hisi_qm_free_qps() - free multiple queue pairs. + * @qps: The queue pairs need to be freed. +@@ -3528,8 +3536,15 @@ void hisi_qm_free_qps(struct hisi_qp **qps, int qp_num) + if (!qps || qp_num <= 0) + return; + +- for (i = qp_num - 1; i >= 0; i--) +- hisi_qm_release_qp(qps[i]); ++ down_write(&qps[0]->qm->qps_lock); ++ ++ for (i = qp_num - 1; i >= 0; i--) { ++ qm_stop_qp_nolock(qps[i]); ++ qm_release_qp_nolock(qps[i]); ++ } ++ ++ up_write(&qps[0]->qm->qps_lock); ++ qm_pm_put_sync(qps[0]->qm); + } + EXPORT_SYMBOL_GPL(hisi_qm_free_qps); + +@@ -3543,6 +3558,43 @@ static void free_list(struct list_head *head) + } + } + ++static int qm_get_and_start_qp(struct hisi_qm *qm, int qp_num, struct hisi_qp **qps, u8 *alg_type) ++{ ++ int i, ret; ++ ++ ret = qm_pm_get_sync(qm); ++ if (ret) ++ return ret; ++ ++ down_write(&qm->qps_lock); ++ for (i = 0; i < qp_num; i++) { ++ qps[i] = qm_create_qp_nolock(qm, alg_type[i]); ++ if (IS_ERR(qps[i])) { ++ ret = -ENODEV; ++ goto stop_and_free; ++ } ++ ++ ret = qm_start_qp_nolock(qps[i], 0); ++ if (ret) { ++ qm_release_qp_nolock(qps[i]); ++ goto stop_and_free; ++ } ++ } ++ up_write(&qm->qps_lock); ++ ++ return 0; ++ ++stop_and_free: ++ for (i--; i >= 0; i--) { ++ qm_stop_qp_nolock(qps[i]); ++ qm_release_qp_nolock(qps[i]); ++ } ++ up_write(&qm->qps_lock); ++ qm_pm_put_sync(qm); ++ ++ return ret; ++} ++ + static int hisi_qm_sort_devices(int node, struct list_head *head, + struct hisi_qm_list *qm_list) + { +@@ -3596,7 +3648,6 @@ int hisi_qm_alloc_qps_node(struct hisi_qm_list *qm_list, int qp_num, + struct hisi_qm_resource *tmp; + int ret = -ENODEV; + LIST_HEAD(head); +- int i; + + if (!qps || !qm_list || qp_num <= 0) + return -EINVAL; +@@ -3608,18 +3659,9 @@ int hisi_qm_alloc_qps_node(struct hisi_qm_list *qm_list, int qp_num, + } + + list_for_each_entry(tmp, &head, list) { +- for (i = 0; i < qp_num; i++) { +- qps[i] = hisi_qm_create_qp(tmp->qm, alg_type[i]); +- if (IS_ERR(qps[i])) { +- hisi_qm_free_qps(qps, i); +- break; +- } +- } +- +- if (i == qp_num) { +- ret = 0; ++ ret = qm_get_and_start_qp(tmp->qm, qp_num, qps, alg_type); ++ if (!ret) + break; +- } + } + + mutex_unlock(&qm_list->lock); +diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.c b/drivers/crypto/hisilicon/sec2/sec_crypto.c +index 364bd69c60883..d09d081f42dc7 100644 +--- a/drivers/crypto/hisilicon/sec2/sec_crypto.c ++++ b/drivers/crypto/hisilicon/sec2/sec_crypto.c +@@ -626,7 +626,6 @@ static int sec_create_qp_ctx(struct sec_ctx *ctx, int qp_ctx_id) + + qp_ctx = &ctx->qp_ctx[qp_ctx_id]; + qp = ctx->qps[qp_ctx_id]; +- qp->qp_ctx = qp_ctx; + qp_ctx->qp = qp; + qp_ctx->ctx = ctx; + +@@ -644,14 +643,8 @@ static int sec_create_qp_ctx(struct sec_ctx *ctx, int qp_ctx_id) + if (ret) + goto err_destroy_idr; + +- ret = hisi_qm_start_qp(qp, 0); +- if (ret < 0) +- goto err_resource_free; +- + return 0; + +-err_resource_free: +- sec_free_qp_ctx_resource(ctx, qp_ctx); + err_destroy_idr: + idr_destroy(&qp_ctx->req_idr); + return ret; +@@ -660,7 +653,6 @@ static int sec_create_qp_ctx(struct sec_ctx *ctx, int qp_ctx_id) + static void sec_release_qp_ctx(struct sec_ctx *ctx, + struct sec_qp_ctx *qp_ctx) + { +- hisi_qm_stop_qp(qp_ctx->qp); + sec_free_qp_ctx_resource(ctx, qp_ctx); + idr_destroy(&qp_ctx->req_idr); + } +diff --git a/drivers/crypto/hisilicon/zip/zip_crypto.c b/drivers/crypto/hisilicon/zip/zip_crypto.c +index 5fc2ed9d5eef3..e140d4f8afe0e 100644 +--- a/drivers/crypto/hisilicon/zip/zip_crypto.c ++++ b/drivers/crypto/hisilicon/zip/zip_crypto.c +@@ -381,32 +381,6 @@ static int hisi_zip_adecompress(struct acomp_req *acomp_req) + return ret; + } + +-static int hisi_zip_start_qp(struct hisi_qp *qp, struct hisi_zip_qp_ctx *qp_ctx, +- int alg_type, int req_type) +-{ +- struct device *dev = &qp->qm->pdev->dev; +- int ret; +- +- qp->alg_type = alg_type; +- qp->qp_ctx = qp_ctx; +- +- ret = hisi_qm_start_qp(qp, 0); +- if (ret < 0) { +- dev_err(dev, "failed to start qp (%d)!\n", ret); +- return ret; +- } +- +- qp_ctx->qp = qp; +- +- return 0; +-} +- +-static void hisi_zip_release_qp(struct hisi_zip_qp_ctx *qp_ctx) +-{ +- hisi_qm_stop_qp(qp_ctx->qp); +- hisi_qm_free_qps(&qp_ctx->qp, 1); +-} +- + static const struct hisi_zip_sqe_ops hisi_zip_ops = { + .sqe_type = 0x3, + .fill_addr = hisi_zip_fill_addr, +@@ -425,7 +399,7 @@ static int hisi_zip_ctx_init(struct hisi_zip_ctx *hisi_zip_ctx, u8 req_type, int + struct hisi_zip_qp_ctx *qp_ctx; + u8 alg_type[HZIP_CTX_Q_NUM]; + struct hisi_zip *hisi_zip; +- int ret, i, j; ++ int ret, i; + + /* alg_type = 0 for compress, 1 for decompress in hw sqe */ + for (i = 0; i < HZIP_CTX_Q_NUM; i++) +@@ -442,17 +416,9 @@ static int hisi_zip_ctx_init(struct hisi_zip_ctx *hisi_zip_ctx, u8 req_type, int + for (i = 0; i < HZIP_CTX_Q_NUM; i++) { + qp_ctx = &hisi_zip_ctx->qp_ctx[i]; + qp_ctx->ctx = hisi_zip_ctx; +- ret = hisi_zip_start_qp(qps[i], qp_ctx, i, req_type); +- if (ret) { +- for (j = i - 1; j >= 0; j--) +- hisi_qm_stop_qp(hisi_zip_ctx->qp_ctx[j].qp); +- +- hisi_qm_free_qps(qps, HZIP_CTX_Q_NUM); +- return ret; +- } +- + qp_ctx->zip_dev = hisi_zip; + qp_ctx->req_type = req_type; ++ qp_ctx->qp = qps[i]; + } + + hisi_zip_ctx->ops = &hisi_zip_ops; +@@ -462,10 +428,13 @@ static int hisi_zip_ctx_init(struct hisi_zip_ctx *hisi_zip_ctx, u8 req_type, int + + static void hisi_zip_ctx_exit(struct hisi_zip_ctx *hisi_zip_ctx) + { ++ struct hisi_qp *qps[HZIP_CTX_Q_NUM] = { NULL }; + int i; + + for (i = 0; i < HZIP_CTX_Q_NUM; i++) +- hisi_zip_release_qp(&hisi_zip_ctx->qp_ctx[i]); ++ qps[i] = hisi_zip_ctx->qp_ctx[i].qp; ++ ++ hisi_qm_free_qps(qps, HZIP_CTX_Q_NUM); + } + + static int hisi_zip_create_req_q(struct hisi_zip_ctx *ctx) +diff --git a/include/linux/hisi_acc_qm.h b/include/linux/hisi_acc_qm.h +index 75ae01ddaa1a8..4cf418a41fe43 100644 +--- a/include/linux/hisi_acc_qm.h ++++ b/include/linux/hisi_acc_qm.h +@@ -463,7 +463,6 @@ struct hisi_qp { + + struct hisi_qp_status qp_status; + struct hisi_qp_ops *hw_ops; +- void *qp_ctx; + void (*req_cb)(struct hisi_qp *qp, void *data); + void (*event_cb)(struct hisi_qp *qp); + +-- +2.51.0 + diff --git a/queue-6.18/crypto-hisilicon-hpre-extend-tag-field-to-64-bits-fo.patch b/queue-6.18/crypto-hisilicon-hpre-extend-tag-field-to-64-bits-fo.patch new file mode 100644 index 0000000000..c635558bd9 --- /dev/null +++ b/queue-6.18/crypto-hisilicon-hpre-extend-tag-field-to-64-bits-fo.patch @@ -0,0 +1,340 @@ +From fdaccca0ef971768c0ac2fc28f22ad6ce9371a38 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 21:44:44 +0800 +Subject: crypto: hisilicon/hpre: extend tag field to 64 bits for better + performance + +From: lizhi + +[ Upstream commit 3a1984758197f7fd4c557dd98090e8e0cf9f498e ] + +This commit expands the tag field in hpre_sqe structure from 16-bit +to 64-bit. The change enables storing request addresses directly +in the tag field, allowing callback functions to access request messages +without the previous indirection mechanism. + +By eliminating the need for lookup tables, this modification reduces lock +contention and associated overhead, leading to improved efficiency and +simplified code. + +Fixes: c8b4b477079d ("crypto: hisilicon - add HiSilicon HPRE accelerator") +Signed-off-by: lizhi +Signed-off-by: Weili Qian +Signed-off-by: Chenghai Huang +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/hpre/hpre.h | 5 +- + drivers/crypto/hisilicon/hpre/hpre_crypto.c | 142 ++++---------------- + 2 files changed, 25 insertions(+), 122 deletions(-) + +diff --git a/drivers/crypto/hisilicon/hpre/hpre.h b/drivers/crypto/hisilicon/hpre/hpre.h +index 0f3ddbadbcf99..021dbd9a1d48f 100644 +--- a/drivers/crypto/hisilicon/hpre/hpre.h ++++ b/drivers/crypto/hisilicon/hpre/hpre.h +@@ -94,9 +94,8 @@ struct hpre_sqe { + __le64 key; + __le64 in; + __le64 out; +- __le16 tag; +- __le16 resv2; +-#define _HPRE_SQE_ALIGN_EXT 7 ++ __le64 tag; ++#define _HPRE_SQE_ALIGN_EXT 6 + __le32 rsvd1[_HPRE_SQE_ALIGN_EXT]; + }; + +diff --git a/drivers/crypto/hisilicon/hpre/hpre_crypto.c b/drivers/crypto/hisilicon/hpre/hpre_crypto.c +index 21ccf879f70c5..4197281c8dff5 100644 +--- a/drivers/crypto/hisilicon/hpre/hpre_crypto.c ++++ b/drivers/crypto/hisilicon/hpre/hpre_crypto.c +@@ -108,12 +108,10 @@ struct hpre_ecdh_ctx { + struct hpre_ctx { + struct hisi_qp *qp; + struct device *dev; +- struct hpre_asym_request **req_list; + struct hpre *hpre; + spinlock_t req_lock; + unsigned int key_sz; + bool crt_g2_mode; +- struct idr req_idr; + union { + struct hpre_rsa_ctx rsa; + struct hpre_dh_ctx dh; +@@ -136,7 +134,6 @@ struct hpre_asym_request { + struct kpp_request *ecdh; + } areq; + int err; +- int req_id; + hpre_cb cb; + struct timespec64 req_time; + }; +@@ -151,58 +148,13 @@ static inline unsigned int hpre_align_pd(void) + return (hpre_align_sz() - 1) & ~(crypto_tfm_ctx_alignment() - 1); + } + +-static int hpre_alloc_req_id(struct hpre_ctx *ctx) ++static void hpre_dfx_add_req_time(struct hpre_asym_request *hpre_req) + { +- unsigned long flags; +- int id; +- +- spin_lock_irqsave(&ctx->req_lock, flags); +- id = idr_alloc(&ctx->req_idr, NULL, 0, ctx->qp->sq_depth, GFP_ATOMIC); +- spin_unlock_irqrestore(&ctx->req_lock, flags); +- +- return id; +-} +- +-static void hpre_free_req_id(struct hpre_ctx *ctx, int req_id) +-{ +- unsigned long flags; +- +- spin_lock_irqsave(&ctx->req_lock, flags); +- idr_remove(&ctx->req_idr, req_id); +- spin_unlock_irqrestore(&ctx->req_lock, flags); +-} +- +-static int hpre_add_req_to_ctx(struct hpre_asym_request *hpre_req) +-{ +- struct hpre_ctx *ctx; +- struct hpre_dfx *dfx; +- int id; +- +- ctx = hpre_req->ctx; +- id = hpre_alloc_req_id(ctx); +- if (unlikely(id < 0)) +- return -EINVAL; +- +- ctx->req_list[id] = hpre_req; +- hpre_req->req_id = id; ++ struct hpre_ctx *ctx = hpre_req->ctx; ++ struct hpre_dfx *dfx = ctx->hpre->debug.dfx; + +- dfx = ctx->hpre->debug.dfx; + if (atomic64_read(&dfx[HPRE_OVERTIME_THRHLD].value)) + ktime_get_ts64(&hpre_req->req_time); +- +- return id; +-} +- +-static void hpre_rm_req_from_ctx(struct hpre_asym_request *hpre_req) +-{ +- struct hpre_ctx *ctx = hpre_req->ctx; +- int id = hpre_req->req_id; +- +- if (hpre_req->req_id >= 0) { +- hpre_req->req_id = HPRE_INVLD_REQ_ID; +- ctx->req_list[id] = NULL; +- hpre_free_req_id(ctx, id); +- } + } + + static struct hisi_qp *hpre_get_qp_and_start(u8 type) +@@ -340,26 +292,19 @@ static void hpre_hw_data_clr_all(struct hpre_ctx *ctx, + static int hpre_alg_res_post_hf(struct hpre_ctx *ctx, struct hpre_sqe *sqe, + void **kreq) + { +- struct hpre_asym_request *req; + unsigned int err, done, alg; +- int id; + + #define HPRE_NO_HW_ERR 0 + #define HPRE_HW_TASK_DONE 3 + #define HREE_HW_ERR_MASK GENMASK(10, 0) + #define HREE_SQE_DONE_MASK GENMASK(1, 0) + #define HREE_ALG_TYPE_MASK GENMASK(4, 0) +- id = (int)le16_to_cpu(sqe->tag); +- req = ctx->req_list[id]; +- hpre_rm_req_from_ctx(req); +- *kreq = req; ++ *kreq = (void *)le64_to_cpu(sqe->tag); + + err = (le32_to_cpu(sqe->dw0) >> HPRE_SQE_ALG_BITS) & + HREE_HW_ERR_MASK; +- + done = (le32_to_cpu(sqe->dw0) >> HPRE_SQE_DONE_SHIFT) & + HREE_SQE_DONE_MASK; +- + if (likely(err == HPRE_NO_HW_ERR && done == HPRE_HW_TASK_DONE)) + return 0; + +@@ -370,34 +315,9 @@ static int hpre_alg_res_post_hf(struct hpre_ctx *ctx, struct hpre_sqe *sqe, + return -EINVAL; + } + +-static int hpre_ctx_set(struct hpre_ctx *ctx, struct hisi_qp *qp, int qlen) +-{ +- struct hpre *hpre; +- +- if (!ctx || !qp || qlen < 0) +- return -EINVAL; +- +- spin_lock_init(&ctx->req_lock); +- ctx->qp = qp; +- ctx->dev = &qp->qm->pdev->dev; +- +- hpre = container_of(ctx->qp->qm, struct hpre, qm); +- ctx->hpre = hpre; +- ctx->req_list = kcalloc(qlen, sizeof(void *), GFP_KERNEL); +- if (!ctx->req_list) +- return -ENOMEM; +- ctx->key_sz = 0; +- ctx->crt_g2_mode = false; +- idr_init(&ctx->req_idr); +- +- return 0; +-} +- + static void hpre_ctx_clear(struct hpre_ctx *ctx, bool is_clear_all) + { + if (is_clear_all) { +- idr_destroy(&ctx->req_idr); +- kfree(ctx->req_list); + hisi_qm_free_qps(&ctx->qp, 1); + } + +@@ -467,29 +387,22 @@ static void hpre_rsa_cb(struct hpre_ctx *ctx, void *resp) + + static void hpre_alg_cb(struct hisi_qp *qp, void *resp) + { +- struct hpre_ctx *ctx = qp->qp_ctx; +- struct hpre_dfx *dfx = ctx->hpre->debug.dfx; ++ struct hpre_asym_request *h_req; + struct hpre_sqe *sqe = resp; +- struct hpre_asym_request *req = ctx->req_list[le16_to_cpu(sqe->tag)]; + +- if (unlikely(!req)) { +- atomic64_inc(&dfx[HPRE_INVALID_REQ_CNT].value); ++ h_req = (struct hpre_asym_request *)le64_to_cpu(sqe->tag); ++ if (unlikely(!h_req)) { ++ pr_err("Failed to get request, and qp_id is %u\n", qp->qp_id); + return; + } + +- req->cb(ctx, resp); +-} +- +-static void hpre_stop_qp_and_put(struct hisi_qp *qp) +-{ +- hisi_qm_stop_qp(qp); +- hisi_qm_free_qps(&qp, 1); ++ h_req->cb(h_req->ctx, resp); + } + + static int hpre_ctx_init(struct hpre_ctx *ctx, u8 type) + { + struct hisi_qp *qp; +- int ret; ++ struct hpre *hpre; + + qp = hpre_get_qp_and_start(type); + if (IS_ERR(qp)) +@@ -497,19 +410,21 @@ static int hpre_ctx_init(struct hpre_ctx *ctx, u8 type) + + qp->qp_ctx = ctx; + qp->req_cb = hpre_alg_cb; ++ spin_lock_init(&ctx->req_lock); ++ ctx->qp = qp; ++ ctx->dev = &qp->qm->pdev->dev; ++ hpre = container_of(ctx->qp->qm, struct hpre, qm); ++ ctx->hpre = hpre; ++ ctx->key_sz = 0; ++ ctx->crt_g2_mode = false; + +- ret = hpre_ctx_set(ctx, qp, qp->sq_depth); +- if (ret) +- hpre_stop_qp_and_put(qp); +- +- return ret; ++ return 0; + } + + static int hpre_msg_request_set(struct hpre_ctx *ctx, void *req, bool is_rsa) + { + struct hpre_asym_request *h_req; + struct hpre_sqe *msg; +- int req_id; + void *tmp; + + if (is_rsa) { +@@ -549,11 +464,8 @@ static int hpre_msg_request_set(struct hpre_ctx *ctx, void *req, bool is_rsa) + msg->task_len1 = (ctx->key_sz >> HPRE_BITS_2_BYTES_SHIFT) - 1; + h_req->ctx = ctx; + +- req_id = hpre_add_req_to_ctx(h_req); +- if (req_id < 0) +- return -EBUSY; +- +- msg->tag = cpu_to_le16((u16)req_id); ++ hpre_dfx_add_req_time(h_req); ++ msg->tag = cpu_to_le64((uintptr_t)h_req); + + return 0; + } +@@ -619,7 +531,6 @@ static int hpre_dh_compute_value(struct kpp_request *req) + return -EINPROGRESS; + + clear_all: +- hpre_rm_req_from_ctx(hpre_req); + hpre_hw_data_clr_all(ctx, hpre_req, req->dst, req->src); + + return ret; +@@ -828,7 +739,6 @@ static int hpre_rsa_enc(struct akcipher_request *req) + return -EINPROGRESS; + + clear_all: +- hpre_rm_req_from_ctx(hpre_req); + hpre_hw_data_clr_all(ctx, hpre_req, req->dst, req->src); + + return ret; +@@ -883,7 +793,6 @@ static int hpre_rsa_dec(struct akcipher_request *req) + return -EINPROGRESS; + + clear_all: +- hpre_rm_req_from_ctx(hpre_req); + hpre_hw_data_clr_all(ctx, hpre_req, req->dst, req->src); + + return ret; +@@ -1346,7 +1255,7 @@ static int hpre_ecdh_set_param(struct hpre_ctx *ctx, struct ecdh *params) + return 0; + } + +-static bool hpre_key_is_zero(char *key, unsigned short key_sz) ++static bool hpre_key_is_zero(const char *key, unsigned short key_sz) + { + int i; + +@@ -1488,7 +1397,6 @@ static int hpre_ecdh_msg_request_set(struct hpre_ctx *ctx, + { + struct hpre_asym_request *h_req; + struct hpre_sqe *msg; +- int req_id; + void *tmp; + + if (req->dst_len < ctx->key_sz << 1) { +@@ -1510,11 +1418,8 @@ static int hpre_ecdh_msg_request_set(struct hpre_ctx *ctx, + msg->task_len1 = (ctx->key_sz >> HPRE_BITS_2_BYTES_SHIFT) - 1; + h_req->ctx = ctx; + +- req_id = hpre_add_req_to_ctx(h_req); +- if (req_id < 0) +- return -EBUSY; +- +- msg->tag = cpu_to_le16((u16)req_id); ++ hpre_dfx_add_req_time(h_req); ++ msg->tag = cpu_to_le64((uintptr_t)h_req); + return 0; + } + +@@ -1612,7 +1517,6 @@ static int hpre_ecdh_compute_value(struct kpp_request *req) + return -EINPROGRESS; + + clear_all: +- hpre_rm_req_from_ctx(hpre_req); + hpre_ecdh_hw_data_clr_all(ctx, hpre_req, req->dst, req->src); + return ret; + } +-- +2.51.0 + diff --git a/queue-6.18/crypto-hisilicon-hpre-support-the-hpre-algorithm-fal.patch b/queue-6.18/crypto-hisilicon-hpre-support-the-hpre-algorithm-fal.patch new file mode 100644 index 0000000000..e767dc60da --- /dev/null +++ b/queue-6.18/crypto-hisilicon-hpre-support-the-hpre-algorithm-fal.patch @@ -0,0 +1,527 @@ +From fa5a1fd76f2cf73a891a9772447e6f7d2ea34216 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 21:44:51 +0800 +Subject: crypto: hisilicon/hpre - support the hpre algorithm fallback + +From: Weili Qian + +[ Upstream commit 6aff4d977e2d582c5d6ff6afd5646c1a459490fa ] + +When all hardware queues are busy and no shareable queue, +new processes fail to apply for queues. To avoid affecting +tasks, support fallback mechanism when hardware queues are +unavailable. + +HPRE driver supports DH algorithm, limited to prime numbers up to 4K. +It supports prime numbers larger than 4K via fallback mechanism. + +Fixes: 05e7b906aa7c ("crypto: hisilicon/hpre - add 'ECDH' algorithm") +Signed-off-by: Weili Qian +Signed-off-by: Chenghai Huang +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/hpre/hpre_crypto.c | 238 ++++++++++++++++---- + 1 file changed, 199 insertions(+), 39 deletions(-) + +diff --git a/drivers/crypto/hisilicon/hpre/hpre_crypto.c b/drivers/crypto/hisilicon/hpre/hpre_crypto.c +index f410e610eabaa..839c1f6771436 100644 +--- a/drivers/crypto/hisilicon/hpre/hpre_crypto.c ++++ b/drivers/crypto/hisilicon/hpre/hpre_crypto.c +@@ -93,6 +93,7 @@ struct hpre_dh_ctx { + + char *g; /* m */ + dma_addr_t dma_g; ++ struct crypto_kpp *soft_tfm; + }; + + struct hpre_ecdh_ctx { +@@ -103,6 +104,7 @@ struct hpre_ecdh_ctx { + /* low address: x->y */ + unsigned char *g; + dma_addr_t dma_g; ++ struct crypto_kpp *soft_tfm; + }; + + struct hpre_ctx { +@@ -120,6 +122,7 @@ struct hpre_ctx { + unsigned int curve_id; + /* for high performance core */ + u8 enable_hpcore; ++ bool fallback; + }; + + struct hpre_asym_request { +@@ -382,8 +385,10 @@ static int hpre_ctx_init(struct hpre_ctx *ctx, u8 type) + struct hpre *hpre; + + qp = hpre_create_qp(type); +- if (!qp) ++ if (!qp) { ++ ctx->qp = NULL; + return -ENODEV; ++ } + + qp->req_cb = hpre_alg_cb; + ctx->qp = qp; +@@ -509,6 +514,48 @@ static int hpre_dh_compute_value(struct kpp_request *req) + return ret; + } + ++static struct kpp_request *hpre_dh_prepare_fb_req(struct kpp_request *req) ++{ ++ struct kpp_request *fb_req = kpp_request_ctx(req); ++ struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); ++ struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); ++ ++ kpp_request_set_tfm(fb_req, ctx->dh.soft_tfm); ++ kpp_request_set_callback(fb_req, req->base.flags, req->base.complete, req->base.data); ++ kpp_request_set_input(fb_req, req->src, req->src_len); ++ kpp_request_set_output(fb_req, req->dst, req->dst_len); ++ ++ return fb_req; ++} ++ ++static int hpre_dh_generate_public_key(struct kpp_request *req) ++{ ++ struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); ++ struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); ++ struct kpp_request *fb_req; ++ ++ if (ctx->fallback) { ++ fb_req = hpre_dh_prepare_fb_req(req); ++ return crypto_kpp_generate_public_key(fb_req); ++ } ++ ++ return hpre_dh_compute_value(req); ++} ++ ++static int hpre_dh_compute_shared_secret(struct kpp_request *req) ++{ ++ struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); ++ struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); ++ struct kpp_request *fb_req; ++ ++ if (ctx->fallback) { ++ fb_req = hpre_dh_prepare_fb_req(req); ++ return crypto_kpp_compute_shared_secret(fb_req); ++ } ++ ++ return hpre_dh_compute_value(req); ++} ++ + static int hpre_is_dh_params_length_valid(unsigned int key_sz) + { + #define _HPRE_DH_GRP1 768 +@@ -535,13 +582,6 @@ static int hpre_dh_set_params(struct hpre_ctx *ctx, struct dh *params) + struct device *dev = ctx->dev; + unsigned int sz; + +- if (params->p_size > HPRE_DH_MAX_P_SZ) +- return -EINVAL; +- +- if (hpre_is_dh_params_length_valid(params->p_size << +- HPRE_BITS_2_BYTES_SHIFT)) +- return -EINVAL; +- + sz = ctx->key_sz = params->p_size; + ctx->dh.xa_p = dma_alloc_coherent(dev, sz << 1, + &ctx->dh.dma_xa_p, GFP_KERNEL); +@@ -574,6 +614,9 @@ static void hpre_dh_clear_ctx(struct hpre_ctx *ctx, bool is_clear_all) + struct device *dev = ctx->dev; + unsigned int sz = ctx->key_sz; + ++ if (!ctx->qp) ++ return; ++ + if (ctx->dh.g) { + dma_free_coherent(dev, sz, ctx->dh.g, ctx->dh.dma_g); + ctx->dh.g = NULL; +@@ -599,6 +642,13 @@ static int hpre_dh_set_secret(struct crypto_kpp *tfm, const void *buf, + if (crypto_dh_decode_key(buf, len, ¶ms) < 0) + return -EINVAL; + ++ if (!ctx->qp) ++ goto set_soft_secret; ++ ++ if (hpre_is_dh_params_length_valid(params.p_size << ++ HPRE_BITS_2_BYTES_SHIFT)) ++ goto set_soft_secret; ++ + /* Free old secret if any */ + hpre_dh_clear_ctx(ctx, false); + +@@ -609,27 +659,55 @@ static int hpre_dh_set_secret(struct crypto_kpp *tfm, const void *buf, + memcpy(ctx->dh.xa_p + (ctx->key_sz - params.key_size), params.key, + params.key_size); + ++ ctx->fallback = false; + return 0; + + err_clear_ctx: + hpre_dh_clear_ctx(ctx, false); + return ret; ++set_soft_secret: ++ ctx->fallback = true; ++ return crypto_kpp_set_secret(ctx->dh.soft_tfm, buf, len); + } + + static unsigned int hpre_dh_max_size(struct crypto_kpp *tfm) + { + struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); + ++ if (ctx->fallback) ++ return crypto_kpp_maxsize(ctx->dh.soft_tfm); ++ + return ctx->key_sz; + } + + static int hpre_dh_init_tfm(struct crypto_kpp *tfm) + { + struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); ++ const char *alg = kpp_alg_name(tfm); ++ unsigned int reqsize; ++ int ret; ++ ++ ctx->dh.soft_tfm = crypto_alloc_kpp(alg, 0, CRYPTO_ALG_NEED_FALLBACK); ++ if (IS_ERR(ctx->dh.soft_tfm)) { ++ pr_err("Failed to alloc dh tfm!\n"); ++ return PTR_ERR(ctx->dh.soft_tfm); ++ } ++ ++ crypto_kpp_set_flags(ctx->dh.soft_tfm, crypto_kpp_get_flags(tfm)); ++ ++ reqsize = max(sizeof(struct hpre_asym_request) + hpre_align_pd(), ++ sizeof(struct kpp_request) + crypto_kpp_reqsize(ctx->dh.soft_tfm)); ++ kpp_set_reqsize(tfm, reqsize); + +- kpp_set_reqsize(tfm, sizeof(struct hpre_asym_request) + hpre_align_pd()); ++ ret = hpre_ctx_init(ctx, HPRE_V2_ALG_TYPE); ++ if (ret && ret != -ENODEV) { ++ crypto_free_kpp(ctx->dh.soft_tfm); ++ return ret; ++ } else if (ret == -ENODEV) { ++ ctx->fallback = true; ++ } + +- return hpre_ctx_init(ctx, HPRE_V2_ALG_TYPE); ++ return 0; + } + + static void hpre_dh_exit_tfm(struct crypto_kpp *tfm) +@@ -637,6 +715,7 @@ static void hpre_dh_exit_tfm(struct crypto_kpp *tfm) + struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); + + hpre_dh_clear_ctx(ctx, true); ++ crypto_free_kpp(ctx->dh.soft_tfm); + } + + static void hpre_rsa_drop_leading_zeros(const char **ptr, size_t *len) +@@ -676,9 +755,8 @@ static int hpre_rsa_enc(struct akcipher_request *req) + struct hpre_sqe *msg = &hpre_req->req; + int ret; + +- /* For 512 and 1536 bits key size, use soft tfm instead */ +- if (ctx->key_sz == HPRE_RSA_512BITS_KSZ || +- ctx->key_sz == HPRE_RSA_1536BITS_KSZ) { ++ /* For unsupported key size and unavailable devices, use soft tfm instead */ ++ if (ctx->fallback) { + akcipher_request_set_tfm(req, ctx->rsa.soft_tfm); + ret = crypto_akcipher_encrypt(req); + akcipher_request_set_tfm(req, tfm); +@@ -723,9 +801,8 @@ static int hpre_rsa_dec(struct akcipher_request *req) + struct hpre_sqe *msg = &hpre_req->req; + int ret; + +- /* For 512 and 1536 bits key size, use soft tfm instead */ +- if (ctx->key_sz == HPRE_RSA_512BITS_KSZ || +- ctx->key_sz == HPRE_RSA_1536BITS_KSZ) { ++ /* For unsupported key size and unavailable devices, use soft tfm instead */ ++ if (ctx->fallback) { + akcipher_request_set_tfm(req, ctx->rsa.soft_tfm); + ret = crypto_akcipher_decrypt(req); + akcipher_request_set_tfm(req, tfm); +@@ -778,8 +855,10 @@ static int hpre_rsa_set_n(struct hpre_ctx *ctx, const char *value, + ctx->key_sz = vlen; + + /* if invalid key size provided, we use software tfm */ +- if (!hpre_rsa_key_size_is_support(ctx->key_sz)) ++ if (!hpre_rsa_key_size_is_support(ctx->key_sz)) { ++ ctx->fallback = true; + return 0; ++ } + + ctx->rsa.pubkey = dma_alloc_coherent(ctx->dev, vlen << 1, + &ctx->rsa.dma_pubkey, +@@ -914,6 +993,9 @@ static void hpre_rsa_clear_ctx(struct hpre_ctx *ctx, bool is_clear_all) + unsigned int half_key_sz = ctx->key_sz >> 1; + struct device *dev = ctx->dev; + ++ if (!ctx->qp) ++ return; ++ + if (ctx->rsa.pubkey) { + dma_free_coherent(dev, ctx->key_sz << 1, + ctx->rsa.pubkey, ctx->rsa.dma_pubkey); +@@ -993,6 +1075,7 @@ static int hpre_rsa_setkey(struct hpre_ctx *ctx, const void *key, + goto free; + } + ++ ctx->fallback = false; + return 0; + + free: +@@ -1010,6 +1093,9 @@ static int hpre_rsa_setpubkey(struct crypto_akcipher *tfm, const void *key, + if (ret) + return ret; + ++ if (!ctx->qp) ++ return 0; ++ + return hpre_rsa_setkey(ctx, key, keylen, false); + } + +@@ -1023,6 +1109,9 @@ static int hpre_rsa_setprivkey(struct crypto_akcipher *tfm, const void *key, + if (ret) + return ret; + ++ if (!ctx->qp) ++ return 0; ++ + return hpre_rsa_setkey(ctx, key, keylen, true); + } + +@@ -1030,9 +1119,8 @@ static unsigned int hpre_rsa_max_size(struct crypto_akcipher *tfm) + { + struct hpre_ctx *ctx = akcipher_tfm_ctx(tfm); + +- /* For 512 and 1536 bits key size, use soft tfm instead */ +- if (ctx->key_sz == HPRE_RSA_512BITS_KSZ || +- ctx->key_sz == HPRE_RSA_1536BITS_KSZ) ++ /* For unsupported key size and unavailable devices, use soft tfm instead */ ++ if (ctx->fallback) + return crypto_akcipher_maxsize(ctx->rsa.soft_tfm); + + return ctx->key_sz; +@@ -1053,10 +1141,14 @@ static int hpre_rsa_init_tfm(struct crypto_akcipher *tfm) + hpre_align_pd()); + + ret = hpre_ctx_init(ctx, HPRE_V2_ALG_TYPE); +- if (ret) ++ if (ret && ret != -ENODEV) { + crypto_free_akcipher(ctx->rsa.soft_tfm); ++ return ret; ++ } else if (ret == -ENODEV) { ++ ctx->fallback = true; ++ } + +- return ret; ++ return 0; + } + + static void hpre_rsa_exit_tfm(struct crypto_akcipher *tfm) +@@ -1260,6 +1352,9 @@ static int hpre_ecdh_set_secret(struct crypto_kpp *tfm, const void *buf, + struct ecdh params; + int ret; + ++ if (ctx->fallback) ++ return crypto_kpp_set_secret(ctx->ecdh.soft_tfm, buf, len); ++ + if (crypto_ecdh_decode_key(buf, len, ¶ms) < 0) { + dev_err(dev, "failed to decode ecdh key!\n"); + return -EINVAL; +@@ -1485,23 +1580,82 @@ static int hpre_ecdh_compute_value(struct kpp_request *req) + return ret; + } + ++static int hpre_ecdh_generate_public_key(struct kpp_request *req) ++{ ++ struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); ++ struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); ++ int ret; ++ ++ if (ctx->fallback) { ++ kpp_request_set_tfm(req, ctx->ecdh.soft_tfm); ++ ret = crypto_kpp_generate_public_key(req); ++ kpp_request_set_tfm(req, tfm); ++ return ret; ++ } ++ ++ return hpre_ecdh_compute_value(req); ++} ++ ++static int hpre_ecdh_compute_shared_secret(struct kpp_request *req) ++{ ++ struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); ++ struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); ++ int ret; ++ ++ if (ctx->fallback) { ++ kpp_request_set_tfm(req, ctx->ecdh.soft_tfm); ++ ret = crypto_kpp_compute_shared_secret(req); ++ kpp_request_set_tfm(req, tfm); ++ return ret; ++ } ++ ++ return hpre_ecdh_compute_value(req); ++} ++ + static unsigned int hpre_ecdh_max_size(struct crypto_kpp *tfm) + { + struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); + ++ if (ctx->fallback) ++ return crypto_kpp_maxsize(ctx->ecdh.soft_tfm); ++ + /* max size is the pub_key_size, include x and y */ + return ctx->key_sz << 1; + } + ++static int hpre_ecdh_init_tfm(struct crypto_kpp *tfm) ++{ ++ struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); ++ const char *alg = kpp_alg_name(tfm); ++ int ret; ++ ++ ret = hpre_ctx_init(ctx, HPRE_V3_ECC_ALG_TYPE); ++ if (!ret) { ++ kpp_set_reqsize(tfm, sizeof(struct hpre_asym_request) + hpre_align_pd()); ++ return 0; ++ } else if (ret && ret != -ENODEV) { ++ return ret; ++ } ++ ++ ctx->ecdh.soft_tfm = crypto_alloc_kpp(alg, 0, CRYPTO_ALG_NEED_FALLBACK); ++ if (IS_ERR(ctx->ecdh.soft_tfm)) { ++ pr_err("Failed to alloc %s tfm!\n", alg); ++ return PTR_ERR(ctx->ecdh.soft_tfm); ++ } ++ ++ crypto_kpp_set_flags(ctx->ecdh.soft_tfm, crypto_kpp_get_flags(tfm)); ++ ctx->fallback = true; ++ ++ return 0; ++} ++ + static int hpre_ecdh_nist_p192_init_tfm(struct crypto_kpp *tfm) + { + struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); + + ctx->curve_id = ECC_CURVE_NIST_P192; + +- kpp_set_reqsize(tfm, sizeof(struct hpre_asym_request) + hpre_align_pd()); +- +- return hpre_ctx_init(ctx, HPRE_V3_ECC_ALG_TYPE); ++ return hpre_ecdh_init_tfm(tfm); + } + + static int hpre_ecdh_nist_p256_init_tfm(struct crypto_kpp *tfm) +@@ -1511,9 +1665,7 @@ static int hpre_ecdh_nist_p256_init_tfm(struct crypto_kpp *tfm) + ctx->curve_id = ECC_CURVE_NIST_P256; + ctx->enable_hpcore = 1; + +- kpp_set_reqsize(tfm, sizeof(struct hpre_asym_request) + hpre_align_pd()); +- +- return hpre_ctx_init(ctx, HPRE_V3_ECC_ALG_TYPE); ++ return hpre_ecdh_init_tfm(tfm); + } + + static int hpre_ecdh_nist_p384_init_tfm(struct crypto_kpp *tfm) +@@ -1522,15 +1674,18 @@ static int hpre_ecdh_nist_p384_init_tfm(struct crypto_kpp *tfm) + + ctx->curve_id = ECC_CURVE_NIST_P384; + +- kpp_set_reqsize(tfm, sizeof(struct hpre_asym_request) + hpre_align_pd()); +- +- return hpre_ctx_init(ctx, HPRE_V3_ECC_ALG_TYPE); ++ return hpre_ecdh_init_tfm(tfm); + } + + static void hpre_ecdh_exit_tfm(struct crypto_kpp *tfm) + { + struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); + ++ if (ctx->fallback) { ++ crypto_free_kpp(ctx->ecdh.soft_tfm); ++ return; ++ } ++ + hpre_ecc_clear_ctx(ctx, true); + } + +@@ -1548,13 +1703,14 @@ static struct akcipher_alg rsa = { + .cra_name = "rsa", + .cra_driver_name = "hpre-rsa", + .cra_module = THIS_MODULE, ++ .cra_flags = CRYPTO_ALG_NEED_FALLBACK, + }, + }; + + static struct kpp_alg dh = { + .set_secret = hpre_dh_set_secret, +- .generate_public_key = hpre_dh_compute_value, +- .compute_shared_secret = hpre_dh_compute_value, ++ .generate_public_key = hpre_dh_generate_public_key, ++ .compute_shared_secret = hpre_dh_compute_shared_secret, + .max_size = hpre_dh_max_size, + .init = hpre_dh_init_tfm, + .exit = hpre_dh_exit_tfm, +@@ -1564,14 +1720,15 @@ static struct kpp_alg dh = { + .cra_name = "dh", + .cra_driver_name = "hpre-dh", + .cra_module = THIS_MODULE, ++ .cra_flags = CRYPTO_ALG_NEED_FALLBACK, + }, + }; + + static struct kpp_alg ecdh_curves[] = { + { + .set_secret = hpre_ecdh_set_secret, +- .generate_public_key = hpre_ecdh_compute_value, +- .compute_shared_secret = hpre_ecdh_compute_value, ++ .generate_public_key = hpre_ecdh_generate_public_key, ++ .compute_shared_secret = hpre_ecdh_compute_shared_secret, + .max_size = hpre_ecdh_max_size, + .init = hpre_ecdh_nist_p192_init_tfm, + .exit = hpre_ecdh_exit_tfm, +@@ -1581,11 +1738,12 @@ static struct kpp_alg ecdh_curves[] = { + .cra_name = "ecdh-nist-p192", + .cra_driver_name = "hpre-ecdh-nist-p192", + .cra_module = THIS_MODULE, ++ .cra_flags = CRYPTO_ALG_NEED_FALLBACK, + }, + }, { + .set_secret = hpre_ecdh_set_secret, +- .generate_public_key = hpre_ecdh_compute_value, +- .compute_shared_secret = hpre_ecdh_compute_value, ++ .generate_public_key = hpre_ecdh_generate_public_key, ++ .compute_shared_secret = hpre_ecdh_compute_shared_secret, + .max_size = hpre_ecdh_max_size, + .init = hpre_ecdh_nist_p256_init_tfm, + .exit = hpre_ecdh_exit_tfm, +@@ -1595,11 +1753,12 @@ static struct kpp_alg ecdh_curves[] = { + .cra_name = "ecdh-nist-p256", + .cra_driver_name = "hpre-ecdh-nist-p256", + .cra_module = THIS_MODULE, ++ .cra_flags = CRYPTO_ALG_NEED_FALLBACK, + }, + }, { + .set_secret = hpre_ecdh_set_secret, +- .generate_public_key = hpre_ecdh_compute_value, +- .compute_shared_secret = hpre_ecdh_compute_value, ++ .generate_public_key = hpre_ecdh_generate_public_key, ++ .compute_shared_secret = hpre_ecdh_compute_shared_secret, + .max_size = hpre_ecdh_max_size, + .init = hpre_ecdh_nist_p384_init_tfm, + .exit = hpre_ecdh_exit_tfm, +@@ -1609,6 +1768,7 @@ static struct kpp_alg ecdh_curves[] = { + .cra_name = "ecdh-nist-p384", + .cra_driver_name = "hpre-ecdh-nist-p384", + .cra_module = THIS_MODULE, ++ .cra_flags = CRYPTO_ALG_NEED_FALLBACK, + }, + } + }; +-- +2.51.0 + diff --git a/queue-6.18/crypto-hisilicon-qm-centralize-the-sending-locks-of-.patch b/queue-6.18/crypto-hisilicon-qm-centralize-the-sending-locks-of-.patch new file mode 100644 index 0000000000..bc0d697325 --- /dev/null +++ b/queue-6.18/crypto-hisilicon-qm-centralize-the-sending-locks-of-.patch @@ -0,0 +1,143 @@ +From aed46e4d9be21a0a877d81eac84ba72d51b175c6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 21:44:46 +0800 +Subject: crypto: hisilicon/qm - centralize the sending locks of each module + into qm + +From: Chenghai Huang + +[ Upstream commit 8cd9b608ee8dea78cac3f373bd5e3b3de2755d46 ] + +When a single queue used by multiple tfms, the protection of shared +resources by individual module driver programs is no longer +sufficient. The hisi_qp_send needs to be ensured by the lock in qp. + +Fixes: 5fdb4b345cfb ("crypto: hisilicon - add a lock for the qp send operation") +Signed-off-by: Chenghai Huang +Signed-off-by: Weili Qian +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/hpre/hpre_crypto.c | 4 ---- + drivers/crypto/hisilicon/qm.c | 16 ++++++++++++---- + drivers/crypto/hisilicon/zip/zip_crypto.c | 3 --- + include/linux/hisi_acc_qm.h | 1 + + 4 files changed, 13 insertions(+), 11 deletions(-) + +diff --git a/drivers/crypto/hisilicon/hpre/hpre_crypto.c b/drivers/crypto/hisilicon/hpre/hpre_crypto.c +index 4197281c8dff5..220022ae7afb6 100644 +--- a/drivers/crypto/hisilicon/hpre/hpre_crypto.c ++++ b/drivers/crypto/hisilicon/hpre/hpre_crypto.c +@@ -109,7 +109,6 @@ struct hpre_ctx { + struct hisi_qp *qp; + struct device *dev; + struct hpre *hpre; +- spinlock_t req_lock; + unsigned int key_sz; + bool crt_g2_mode; + union { +@@ -410,7 +409,6 @@ static int hpre_ctx_init(struct hpre_ctx *ctx, u8 type) + + qp->qp_ctx = ctx; + qp->req_cb = hpre_alg_cb; +- spin_lock_init(&ctx->req_lock); + ctx->qp = qp; + ctx->dev = &qp->qm->pdev->dev; + hpre = container_of(ctx->qp->qm, struct hpre, qm); +@@ -478,9 +476,7 @@ static int hpre_send(struct hpre_ctx *ctx, struct hpre_sqe *msg) + + do { + atomic64_inc(&dfx[HPRE_SEND_CNT].value); +- spin_lock_bh(&ctx->req_lock); + ret = hisi_qp_send(ctx->qp, msg); +- spin_unlock_bh(&ctx->req_lock); + if (ret != -EBUSY) + break; + atomic64_inc(&dfx[HPRE_SEND_BUSY_CNT].value); +diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c +index 41b7ffa0fb1ae..c2c24c3a2be86 100644 +--- a/drivers/crypto/hisilicon/qm.c ++++ b/drivers/crypto/hisilicon/qm.c +@@ -2360,26 +2360,33 @@ EXPORT_SYMBOL_GPL(hisi_qm_stop_qp); + int hisi_qp_send(struct hisi_qp *qp, const void *msg) + { + struct hisi_qp_status *qp_status = &qp->qp_status; +- u16 sq_tail = qp_status->sq_tail; +- u16 sq_tail_next = (sq_tail + 1) % qp->sq_depth; +- void *sqe = qm_get_avail_sqe(qp); ++ u16 sq_tail, sq_tail_next; ++ void *sqe; + ++ spin_lock_bh(&qp->qp_lock); + if (unlikely(atomic_read(&qp->qp_status.flags) == QP_STOP || + atomic_read(&qp->qm->status.flags) == QM_STOP || + qp->is_resetting)) { ++ spin_unlock_bh(&qp->qp_lock); + dev_info_ratelimited(&qp->qm->pdev->dev, "QP is stopped or resetting\n"); + return -EAGAIN; + } + +- if (!sqe) ++ sqe = qm_get_avail_sqe(qp); ++ if (!sqe) { ++ spin_unlock_bh(&qp->qp_lock); + return -EBUSY; ++ } + ++ sq_tail = qp_status->sq_tail; ++ sq_tail_next = (sq_tail + 1) % qp->sq_depth; + memcpy(sqe, msg, qp->qm->sqe_size); + qp->msg[sq_tail] = msg; + + qm_db(qp->qm, qp->qp_id, QM_DOORBELL_CMD_SQ, sq_tail_next, 0); + atomic_inc(&qp->qp_status.used); + qp_status->sq_tail = sq_tail_next; ++ spin_unlock_bh(&qp->qp_lock); + + return 0; + } +@@ -2956,6 +2963,7 @@ static int hisi_qp_memory_init(struct hisi_qm *qm, size_t dma_size, int id, + qp->qm = qm; + qp->qp_id = id; + ++ spin_lock_init(&qp->qp_lock); + spin_lock_init(&qp->backlog.lock); + INIT_LIST_HEAD(&qp->backlog.list); + +diff --git a/drivers/crypto/hisilicon/zip/zip_crypto.c b/drivers/crypto/hisilicon/zip/zip_crypto.c +index 8250a33ba5862..2f9035c016f3f 100644 +--- a/drivers/crypto/hisilicon/zip/zip_crypto.c ++++ b/drivers/crypto/hisilicon/zip/zip_crypto.c +@@ -217,7 +217,6 @@ static int hisi_zip_do_work(struct hisi_zip_qp_ctx *qp_ctx, + { + struct hisi_acc_sgl_pool *pool = qp_ctx->sgl_pool; + struct hisi_zip_dfx *dfx = &qp_ctx->zip_dev->dfx; +- struct hisi_zip_req_q *req_q = &qp_ctx->req_q; + struct acomp_req *a_req = req->req; + struct hisi_qp *qp = qp_ctx->qp; + struct device *dev = &qp->qm->pdev->dev; +@@ -250,9 +249,7 @@ static int hisi_zip_do_work(struct hisi_zip_qp_ctx *qp_ctx, + + /* send command to start a task */ + atomic64_inc(&dfx->send_cnt); +- spin_lock_bh(&req_q->req_lock); + ret = hisi_qp_send(qp, &zip_sqe); +- spin_unlock_bh(&req_q->req_lock); + if (unlikely(ret < 0)) { + atomic64_inc(&dfx->send_busy_cnt); + ret = -EAGAIN; +diff --git a/include/linux/hisi_acc_qm.h b/include/linux/hisi_acc_qm.h +index 4f83f07009907..75ae01ddaa1a8 100644 +--- a/include/linux/hisi_acc_qm.h ++++ b/include/linux/hisi_acc_qm.h +@@ -473,6 +473,7 @@ struct hisi_qp { + u16 pasid; + struct uacce_queue *uacce_q; + ++ spinlock_t qp_lock; + struct instance_backlog backlog; + const void **msg; + }; +-- +2.51.0 + diff --git a/queue-6.18/crypto-hisilicon-qm-enhance-the-configuration-of-req.patch b/queue-6.18/crypto-hisilicon-qm-enhance-the-configuration-of-req.patch new file mode 100644 index 0000000000..ca8116c582 --- /dev/null +++ b/queue-6.18/crypto-hisilicon-qm-enhance-the-configuration-of-req.patch @@ -0,0 +1,248 @@ +From cbfea38bdb911bbb4fb039943fbdd61cbf47179a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 21:44:45 +0800 +Subject: crypto: hisilicon/qm - enhance the configuration of req_type in queue + attributes + +From: Chenghai Huang + +[ Upstream commit 21452eaa06edb5f6038720e643aed0bbfffad9c3 ] + +Originally, when a queue was requested, it could only be configured +with the default algorithm type of 0. Now, when multiple tfms use +the same queue, the queue must be selected based on its attributes +to meet the requirements of tfm tasks. So the algorithm type +attribute of queue need to be distinguished. Just like a queue used +for compression in ZIP cannot be used for decompression tasks. + +Fixes: 3f1ec97aacf1 ("crypto: hisilicon/qm - Put device finding logic into QM") +Signed-off-by: Chenghai Huang +Signed-off-by: Weili Qian +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/hpre/hpre_main.c | 2 +- + drivers/crypto/hisilicon/qm.c | 8 ++++---- + drivers/crypto/hisilicon/sec2/sec_crypto.c | 1 - + drivers/crypto/hisilicon/sec2/sec_main.c | 21 ++++++++++++++++----- + drivers/crypto/hisilicon/zip/zip.h | 2 +- + drivers/crypto/hisilicon/zip/zip_crypto.c | 13 +++++++++---- + drivers/crypto/hisilicon/zip/zip_main.c | 4 ++-- + include/linux/hisi_acc_qm.h | 3 +-- + 8 files changed, 34 insertions(+), 20 deletions(-) + +diff --git a/drivers/crypto/hisilicon/hpre/hpre_main.c b/drivers/crypto/hisilicon/hpre/hpre_main.c +index b94fecd765eeb..884d5d0afaf41 100644 +--- a/drivers/crypto/hisilicon/hpre/hpre_main.c ++++ b/drivers/crypto/hisilicon/hpre/hpre_main.c +@@ -465,7 +465,7 @@ struct hisi_qp *hpre_create_qp(u8 type) + * type: 0 - RSA/DH. algorithm supported in V2, + * 1 - ECC algorithm in V3. + */ +- ret = hisi_qm_alloc_qps_node(&hpre_devices, 1, type, node, &qp); ++ ret = hisi_qm_alloc_qps_node(&hpre_devices, 1, &type, node, &qp); + if (!ret) + return qp; + +diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c +index 6bf91735dfcd8..41b7ffa0fb1ae 100644 +--- a/drivers/crypto/hisilicon/qm.c ++++ b/drivers/crypto/hisilicon/qm.c +@@ -3583,7 +3583,7 @@ static int hisi_qm_sort_devices(int node, struct list_head *head, + * not meet the requirements will return error. + */ + int hisi_qm_alloc_qps_node(struct hisi_qm_list *qm_list, int qp_num, +- u8 alg_type, int node, struct hisi_qp **qps) ++ u8 *alg_type, int node, struct hisi_qp **qps) + { + struct hisi_qm_resource *tmp; + int ret = -ENODEV; +@@ -3601,7 +3601,7 @@ int hisi_qm_alloc_qps_node(struct hisi_qm_list *qm_list, int qp_num, + + list_for_each_entry(tmp, &head, list) { + for (i = 0; i < qp_num; i++) { +- qps[i] = hisi_qm_create_qp(tmp->qm, alg_type); ++ qps[i] = hisi_qm_create_qp(tmp->qm, alg_type[i]); + if (IS_ERR(qps[i])) { + hisi_qm_free_qps(qps, i); + break; +@@ -3616,8 +3616,8 @@ int hisi_qm_alloc_qps_node(struct hisi_qm_list *qm_list, int qp_num, + + mutex_unlock(&qm_list->lock); + if (ret) +- pr_info("Failed to create qps, node[%d], alg[%u], qp[%d]!\n", +- node, alg_type, qp_num); ++ pr_info("Failed to create qps, node[%d], qp[%d]!\n", ++ node, qp_num); + + err: + free_list(&head); +diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.c b/drivers/crypto/hisilicon/sec2/sec_crypto.c +index 4e41235116e15..364bd69c60883 100644 +--- a/drivers/crypto/hisilicon/sec2/sec_crypto.c ++++ b/drivers/crypto/hisilicon/sec2/sec_crypto.c +@@ -626,7 +626,6 @@ static int sec_create_qp_ctx(struct sec_ctx *ctx, int qp_ctx_id) + + qp_ctx = &ctx->qp_ctx[qp_ctx_id]; + qp = ctx->qps[qp_ctx_id]; +- qp->req_type = 0; + qp->qp_ctx = qp_ctx; + qp_ctx->qp = qp; + qp_ctx->ctx = ctx; +diff --git a/drivers/crypto/hisilicon/sec2/sec_main.c b/drivers/crypto/hisilicon/sec2/sec_main.c +index 5eb2d68207426..7dd125f5f511f 100644 +--- a/drivers/crypto/hisilicon/sec2/sec_main.c ++++ b/drivers/crypto/hisilicon/sec2/sec_main.c +@@ -417,18 +417,29 @@ struct hisi_qp **sec_create_qps(void) + int node = cpu_to_node(raw_smp_processor_id()); + u32 ctx_num = ctx_q_num; + struct hisi_qp **qps; ++ u8 *type; + int ret; + + qps = kcalloc(ctx_num, sizeof(struct hisi_qp *), GFP_KERNEL); + if (!qps) + return NULL; + +- ret = hisi_qm_alloc_qps_node(&sec_devices, ctx_num, 0, node, qps); +- if (!ret) +- return qps; ++ /* The type of SEC is all 0, so just allocated by kcalloc */ ++ type = kcalloc(ctx_num, sizeof(u8), GFP_KERNEL); ++ if (!type) { ++ kfree(qps); ++ return NULL; ++ } + +- kfree(qps); +- return NULL; ++ ret = hisi_qm_alloc_qps_node(&sec_devices, ctx_num, type, node, qps); ++ if (ret) { ++ kfree(type); ++ kfree(qps); ++ return NULL; ++ } ++ ++ kfree(type); ++ return qps; + } + + u64 sec_get_alg_bitmap(struct hisi_qm *qm, u32 high, u32 low) +diff --git a/drivers/crypto/hisilicon/zip/zip.h b/drivers/crypto/hisilicon/zip/zip.h +index 9fb2a9c01132b..b83f228281ab1 100644 +--- a/drivers/crypto/hisilicon/zip/zip.h ++++ b/drivers/crypto/hisilicon/zip/zip.h +@@ -99,7 +99,7 @@ enum zip_cap_table_type { + ZIP_CORE5_BITMAP, + }; + +-int zip_create_qps(struct hisi_qp **qps, int qp_num, int node); ++int zip_create_qps(struct hisi_qp **qps, int qp_num, int node, u8 *alg_type); + int hisi_zip_register_to_crypto(struct hisi_qm *qm); + void hisi_zip_unregister_from_crypto(struct hisi_qm *qm); + bool hisi_zip_alg_support(struct hisi_qm *qm, u32 alg); +diff --git a/drivers/crypto/hisilicon/zip/zip_crypto.c b/drivers/crypto/hisilicon/zip/zip_crypto.c +index b4a656e0177d2..8250a33ba5862 100644 +--- a/drivers/crypto/hisilicon/zip/zip_crypto.c ++++ b/drivers/crypto/hisilicon/zip/zip_crypto.c +@@ -66,6 +66,7 @@ struct hisi_zip_qp_ctx { + struct hisi_acc_sgl_pool *sgl_pool; + struct hisi_zip *zip_dev; + struct hisi_zip_ctx *ctx; ++ u8 req_type; + }; + + struct hisi_zip_sqe_ops { +@@ -245,7 +246,7 @@ static int hisi_zip_do_work(struct hisi_zip_qp_ctx *qp_ctx, + goto err_unmap_input; + } + +- hisi_zip_fill_sqe(qp_ctx->ctx, &zip_sqe, qp->req_type, req); ++ hisi_zip_fill_sqe(qp_ctx->ctx, &zip_sqe, qp_ctx->req_type, req); + + /* send command to start a task */ + atomic64_inc(&dfx->send_cnt); +@@ -360,7 +361,6 @@ static int hisi_zip_start_qp(struct hisi_qp *qp, struct hisi_zip_qp_ctx *qp_ctx, + struct device *dev = &qp->qm->pdev->dev; + int ret; + +- qp->req_type = req_type; + qp->alg_type = alg_type; + qp->qp_ctx = qp_ctx; + +@@ -397,10 +397,15 @@ static int hisi_zip_ctx_init(struct hisi_zip_ctx *hisi_zip_ctx, u8 req_type, int + { + struct hisi_qp *qps[HZIP_CTX_Q_NUM] = { NULL }; + struct hisi_zip_qp_ctx *qp_ctx; ++ u8 alg_type[HZIP_CTX_Q_NUM]; + struct hisi_zip *hisi_zip; + int ret, i, j; + +- ret = zip_create_qps(qps, HZIP_CTX_Q_NUM, node); ++ /* alg_type = 0 for compress, 1 for decompress in hw sqe */ ++ for (i = 0; i < HZIP_CTX_Q_NUM; i++) ++ alg_type[i] = i; ++ ++ ret = zip_create_qps(qps, HZIP_CTX_Q_NUM, node, alg_type); + if (ret) { + pr_err("failed to create zip qps (%d)!\n", ret); + return -ENODEV; +@@ -409,7 +414,6 @@ static int hisi_zip_ctx_init(struct hisi_zip_ctx *hisi_zip_ctx, u8 req_type, int + hisi_zip = container_of(qps[0]->qm, struct hisi_zip, qm); + + for (i = 0; i < HZIP_CTX_Q_NUM; i++) { +- /* alg_type = 0 for compress, 1 for decompress in hw sqe */ + qp_ctx = &hisi_zip_ctx->qp_ctx[i]; + qp_ctx->ctx = hisi_zip_ctx; + ret = hisi_zip_start_qp(qps[i], qp_ctx, i, req_type); +@@ -422,6 +426,7 @@ static int hisi_zip_ctx_init(struct hisi_zip_ctx *hisi_zip_ctx, u8 req_type, int + } + + qp_ctx->zip_dev = hisi_zip; ++ qp_ctx->req_type = req_type; + } + + hisi_zip_ctx->ops = &hisi_zip_ops; +diff --git a/drivers/crypto/hisilicon/zip/zip_main.c b/drivers/crypto/hisilicon/zip/zip_main.c +index 4fcbe6bada066..85b26ef175485 100644 +--- a/drivers/crypto/hisilicon/zip/zip_main.c ++++ b/drivers/crypto/hisilicon/zip/zip_main.c +@@ -446,12 +446,12 @@ static const struct pci_device_id hisi_zip_dev_ids[] = { + }; + MODULE_DEVICE_TABLE(pci, hisi_zip_dev_ids); + +-int zip_create_qps(struct hisi_qp **qps, int qp_num, int node) ++int zip_create_qps(struct hisi_qp **qps, int qp_num, int node, u8 *alg_type) + { + if (node == NUMA_NO_NODE) + node = cpu_to_node(raw_smp_processor_id()); + +- return hisi_qm_alloc_qps_node(&zip_devices, qp_num, 0, node, qps); ++ return hisi_qm_alloc_qps_node(&zip_devices, qp_num, alg_type, node, qps); + } + + bool hisi_zip_alg_support(struct hisi_qm *qm, u32 alg) +diff --git a/include/linux/hisi_acc_qm.h b/include/linux/hisi_acc_qm.h +index 2d0cc61ed8869..4f83f07009907 100644 +--- a/include/linux/hisi_acc_qm.h ++++ b/include/linux/hisi_acc_qm.h +@@ -454,7 +454,6 @@ struct hisi_qp { + u16 sq_depth; + u16 cq_depth; + u8 alg_type; +- u8 req_type; + + struct qm_dma qdma; + void *sqe; +@@ -580,7 +579,7 @@ struct hisi_acc_sgl_pool *hisi_acc_create_sgl_pool(struct device *dev, + void hisi_acc_free_sgl_pool(struct device *dev, + struct hisi_acc_sgl_pool *pool); + int hisi_qm_alloc_qps_node(struct hisi_qm_list *qm_list, int qp_num, +- u8 alg_type, int node, struct hisi_qp **qps); ++ u8 *alg_type, int node, struct hisi_qp **qps); + void hisi_qm_free_qps(struct hisi_qp **qps, int qp_num); + void hisi_qm_dev_shutdown(struct pci_dev *pdev); + void hisi_qm_wait_task_finish(struct hisi_qm *qm, struct hisi_qm_list *qm_list); +-- +2.51.0 + diff --git a/queue-6.18/crypto-hisilicon-sec-move-backlog-management-to-qp-a.patch b/queue-6.18/crypto-hisilicon-sec-move-backlog-management-to-qp-a.patch new file mode 100644 index 0000000000..86a3f4394a --- /dev/null +++ b/queue-6.18/crypto-hisilicon-sec-move-backlog-management-to-qp-a.patch @@ -0,0 +1,365 @@ +From 69e0a5e9b4caa9ec4b8047fdd96ff22fea7446c4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 21:44:43 +0800 +Subject: crypto: hisilicon/sec - move backlog management to qp and store sqe + in qp for callback + +From: Chenghai Huang + +[ Upstream commit 08eb67d23e5172a5d1e60f1f0acccee569fe10ba ] + +When multiple tfm use a same qp, the backlog data should be managed +centrally by the qp, rather than in the qp_ctx of each req. + +Additionally, since SEC_BD_TYPE1 and SEC_BD_TYPE2 cannot use the +tag of the sqe to carry the virtual address of the req, the sent +sqe is stored in the qp. This allows the callback function to get +the req address. To handle the differences between hardware types, +the callback functions are split into two separate implementations. + +Fixes: f0ae287c5045 ("crypto: hisilicon/sec2 - implement full backlog mode for sec") +Signed-off-by: Chenghai Huang +Signed-off-by: Weili Qian +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/qm.c | 20 ++++- + drivers/crypto/hisilicon/sec2/sec.h | 7 -- + drivers/crypto/hisilicon/sec2/sec_crypto.c | 88 +++++++++++----------- + include/linux/hisi_acc_qm.h | 8 ++ + 4 files changed, 69 insertions(+), 54 deletions(-) + +diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c +index 0968304c0cb51..6bf91735dfcd8 100644 +--- a/drivers/crypto/hisilicon/qm.c ++++ b/drivers/crypto/hisilicon/qm.c +@@ -2210,6 +2210,7 @@ static void qp_stop_fail_cb(struct hisi_qp *qp) + for (i = 0; i < qp_used; i++) { + pos = (i + cur_head) % sq_depth; + qp->req_cb(qp, qp->sqe + (u32)(qm->sqe_size * pos)); ++ qm_cq_head_update(qp); + atomic_dec(&qp->qp_status.used); + } + } +@@ -2374,6 +2375,7 @@ int hisi_qp_send(struct hisi_qp *qp, const void *msg) + return -EBUSY; + + memcpy(sqe, msg, qp->qm->sqe_size); ++ qp->msg[sq_tail] = msg; + + qm_db(qp->qm, qp->qp_id, QM_DOORBELL_CMD_SQ, sq_tail_next, 0); + atomic_inc(&qp->qp_status.used); +@@ -2907,12 +2909,13 @@ EXPORT_SYMBOL_GPL(hisi_qm_wait_task_finish); + static void hisi_qp_memory_uninit(struct hisi_qm *qm, int num) + { + struct device *dev = &qm->pdev->dev; +- struct qm_dma *qdma; ++ struct hisi_qp *qp; + int i; + + for (i = num - 1; i >= 0; i--) { +- qdma = &qm->qp_array[i].qdma; +- dma_free_coherent(dev, qdma->size, qdma->va, qdma->dma); ++ qp = &qm->qp_array[i]; ++ dma_free_coherent(dev, qp->qdma.size, qp->qdma.va, qp->qdma.dma); ++ kfree(qp->msg); + kfree(qm->poll_data[i].qp_finish_id); + } + +@@ -2934,10 +2937,14 @@ static int hisi_qp_memory_init(struct hisi_qm *qm, size_t dma_size, int id, + return -ENOMEM; + + qp = &qm->qp_array[id]; ++ qp->msg = kmalloc_array(sq_depth, sizeof(void *), GFP_KERNEL); ++ if (!qp->msg) ++ goto err_free_qp_finish_id; ++ + qp->qdma.va = dma_alloc_coherent(dev, dma_size, &qp->qdma.dma, + GFP_KERNEL); + if (!qp->qdma.va) +- goto err_free_qp_finish_id; ++ goto err_free_qp_msg; + + qp->sqe = qp->qdma.va; + qp->sqe_dma = qp->qdma.dma; +@@ -2949,8 +2956,13 @@ static int hisi_qp_memory_init(struct hisi_qm *qm, size_t dma_size, int id, + qp->qm = qm; + qp->qp_id = id; + ++ spin_lock_init(&qp->backlog.lock); ++ INIT_LIST_HEAD(&qp->backlog.list); ++ + return 0; + ++err_free_qp_msg: ++ kfree(qp->msg); + err_free_qp_finish_id: + kfree(qm->poll_data[id].qp_finish_id); + return ret; +diff --git a/drivers/crypto/hisilicon/sec2/sec.h b/drivers/crypto/hisilicon/sec2/sec.h +index 81d0beda93b2b..0710977861f32 100644 +--- a/drivers/crypto/hisilicon/sec2/sec.h ++++ b/drivers/crypto/hisilicon/sec2/sec.h +@@ -82,11 +82,6 @@ struct sec_aead_req { + __u8 out_mac_buf[SEC_MAX_MAC_LEN]; + }; + +-struct sec_instance_backlog { +- struct list_head list; +- spinlock_t lock; +-}; +- + /* SEC request of Crypto */ + struct sec_req { + union { +@@ -112,7 +107,6 @@ struct sec_req { + bool use_pbuf; + + struct list_head list; +- struct sec_instance_backlog *backlog; + struct sec_request_buf buf; + }; + +@@ -172,7 +166,6 @@ struct sec_qp_ctx { + spinlock_t id_lock; + struct hisi_acc_sgl_pool *c_in_pool; + struct hisi_acc_sgl_pool *c_out_pool; +- struct sec_instance_backlog backlog; + u16 send_head; + }; + +diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.c b/drivers/crypto/hisilicon/sec2/sec_crypto.c +index 31590d01139a3..4e41235116e15 100644 +--- a/drivers/crypto/hisilicon/sec2/sec_crypto.c ++++ b/drivers/crypto/hisilicon/sec2/sec_crypto.c +@@ -54,7 +54,6 @@ + #define SEC_AUTH_CIPHER_V3 0x40 + #define SEC_FLAG_OFFSET 7 + #define SEC_FLAG_MASK 0x0780 +-#define SEC_TYPE_MASK 0x0F + #define SEC_DONE_MASK 0x0001 + #define SEC_ICV_MASK 0x000E + +@@ -148,7 +147,7 @@ static void sec_free_req_id(struct sec_req *req) + spin_unlock_bh(&qp_ctx->id_lock); + } + +-static u8 pre_parse_finished_bd(struct bd_status *status, void *resp) ++static void pre_parse_finished_bd(struct bd_status *status, void *resp) + { + struct sec_sqe *bd = resp; + +@@ -158,11 +157,9 @@ static u8 pre_parse_finished_bd(struct bd_status *status, void *resp) + SEC_FLAG_MASK) >> SEC_FLAG_OFFSET; + status->tag = le16_to_cpu(bd->type2.tag); + status->err_type = bd->type2.error_type; +- +- return bd->type_cipher_auth & SEC_TYPE_MASK; + } + +-static u8 pre_parse_finished_bd3(struct bd_status *status, void *resp) ++static void pre_parse_finished_bd3(struct bd_status *status, void *resp) + { + struct sec_sqe3 *bd3 = resp; + +@@ -172,8 +169,6 @@ static u8 pre_parse_finished_bd3(struct bd_status *status, void *resp) + SEC_FLAG_MASK) >> SEC_FLAG_OFFSET; + status->tag = le64_to_cpu(bd3->tag); + status->err_type = bd3->error_type; +- +- return le32_to_cpu(bd3->bd_param) & SEC_TYPE_MASK; + } + + static int sec_cb_status_check(struct sec_req *req, +@@ -244,7 +239,7 @@ static void sec_alg_send_backlog_soft(struct sec_ctx *ctx, struct sec_qp_ctx *qp + struct sec_req *req, *tmp; + int ret; + +- list_for_each_entry_safe(req, tmp, &qp_ctx->backlog.list, list) { ++ list_for_each_entry_safe(req, tmp, &qp_ctx->qp->backlog.list, list) { + list_del(&req->list); + ctx->req_op->buf_unmap(ctx, req); + if (req->req_id >= 0) +@@ -265,11 +260,12 @@ static void sec_alg_send_backlog_soft(struct sec_ctx *ctx, struct sec_qp_ctx *qp + + static void sec_alg_send_backlog(struct sec_ctx *ctx, struct sec_qp_ctx *qp_ctx) + { ++ struct hisi_qp *qp = qp_ctx->qp; + struct sec_req *req, *tmp; + int ret; + +- spin_lock_bh(&qp_ctx->backlog.lock); +- list_for_each_entry_safe(req, tmp, &qp_ctx->backlog.list, list) { ++ spin_lock_bh(&qp->backlog.lock); ++ list_for_each_entry_safe(req, tmp, &qp->backlog.list, list) { + ret = qp_send_message(req); + switch (ret) { + case -EINPROGRESS: +@@ -287,42 +283,46 @@ static void sec_alg_send_backlog(struct sec_ctx *ctx, struct sec_qp_ctx *qp_ctx) + } + + unlock: +- spin_unlock_bh(&qp_ctx->backlog.lock); ++ spin_unlock_bh(&qp->backlog.lock); + } + + static void sec_req_cb(struct hisi_qp *qp, void *resp) + { +- struct sec_qp_ctx *qp_ctx = qp->qp_ctx; +- struct sec_dfx *dfx = &qp_ctx->ctx->sec->debug.dfx; +- u8 type_supported = qp_ctx->ctx->type_supported; ++ const struct sec_sqe *sqe = qp->msg[qp->qp_status.cq_head]; ++ struct sec_req *req = container_of(sqe, struct sec_req, sec_sqe); ++ struct sec_ctx *ctx = req->ctx; ++ struct sec_dfx *dfx = &ctx->sec->debug.dfx; + struct bd_status status; +- struct sec_ctx *ctx; +- struct sec_req *req; + int err; +- u8 type; + +- if (type_supported == SEC_BD_TYPE2) { +- type = pre_parse_finished_bd(&status, resp); +- req = qp_ctx->req_list[status.tag]; +- } else { +- type = pre_parse_finished_bd3(&status, resp); +- req = (void *)(uintptr_t)status.tag; +- } ++ pre_parse_finished_bd(&status, resp); + +- if (unlikely(type != type_supported)) { +- atomic64_inc(&dfx->err_bd_cnt); +- pr_err("err bd type [%u]\n", type); +- return; +- } ++ req->err_type = status.err_type; ++ err = sec_cb_status_check(req, &status); ++ if (err) ++ atomic64_inc(&dfx->done_flag_cnt); + +- if (unlikely(!req)) { +- atomic64_inc(&dfx->invalid_req_cnt); +- atomic_inc(&qp->qp_status.used); +- return; +- } ++ atomic64_inc(&dfx->recv_cnt); + ++ ctx->req_op->buf_unmap(ctx, req); ++ ctx->req_op->callback(ctx, req, err); ++} ++ ++static void sec_req_cb3(struct hisi_qp *qp, void *resp) ++{ ++ struct bd_status status; ++ struct sec_ctx *ctx; ++ struct sec_dfx *dfx; ++ struct sec_req *req; ++ int err; ++ ++ pre_parse_finished_bd3(&status, resp); ++ ++ req = (void *)(uintptr_t)status.tag; + req->err_type = status.err_type; + ctx = req->ctx; ++ dfx = &ctx->sec->debug.dfx; ++ + err = sec_cb_status_check(req, &status); + if (err) + atomic64_inc(&dfx->done_flag_cnt); +@@ -330,7 +330,6 @@ static void sec_req_cb(struct hisi_qp *qp, void *resp) + atomic64_inc(&dfx->recv_cnt); + + ctx->req_op->buf_unmap(ctx, req); +- + ctx->req_op->callback(ctx, req, err); + } + +@@ -348,8 +347,10 @@ static int sec_alg_send_message_retry(struct sec_req *req) + + static int sec_alg_try_enqueue(struct sec_req *req) + { ++ struct hisi_qp *qp = req->qp_ctx->qp; ++ + /* Check if any request is already backlogged */ +- if (!list_empty(&req->backlog->list)) ++ if (!list_empty(&qp->backlog.list)) + return -EBUSY; + + /* Try to enqueue to HW ring */ +@@ -359,17 +360,18 @@ static int sec_alg_try_enqueue(struct sec_req *req) + + static int sec_alg_send_message_maybacklog(struct sec_req *req) + { ++ struct hisi_qp *qp = req->qp_ctx->qp; + int ret; + + ret = sec_alg_try_enqueue(req); + if (ret != -EBUSY) + return ret; + +- spin_lock_bh(&req->backlog->lock); ++ spin_lock_bh(&qp->backlog.lock); + ret = sec_alg_try_enqueue(req); + if (ret == -EBUSY) +- list_add_tail(&req->list, &req->backlog->list); +- spin_unlock_bh(&req->backlog->lock); ++ list_add_tail(&req->list, &qp->backlog.list); ++ spin_unlock_bh(&qp->backlog.lock); + + return ret; + } +@@ -629,13 +631,14 @@ static int sec_create_qp_ctx(struct sec_ctx *ctx, int qp_ctx_id) + qp_ctx->qp = qp; + qp_ctx->ctx = ctx; + +- qp->req_cb = sec_req_cb; ++ if (ctx->type_supported == SEC_BD_TYPE3) ++ qp->req_cb = sec_req_cb3; ++ else ++ qp->req_cb = sec_req_cb; + + spin_lock_init(&qp_ctx->req_lock); + idr_init(&qp_ctx->req_idr); +- spin_lock_init(&qp_ctx->backlog.lock); + spin_lock_init(&qp_ctx->id_lock); +- INIT_LIST_HEAD(&qp_ctx->backlog.list); + qp_ctx->send_head = 0; + + ret = sec_alloc_qp_ctx_resource(ctx, qp_ctx); +@@ -1952,7 +1955,6 @@ static int sec_request_init(struct sec_ctx *ctx, struct sec_req *req) + } while (req->req_id < 0 && ++i < ctx->sec->ctx_q_num); + + req->qp_ctx = qp_ctx; +- req->backlog = &qp_ctx->backlog; + + return 0; + } +diff --git a/include/linux/hisi_acc_qm.h b/include/linux/hisi_acc_qm.h +index c4690e365ade9..2d0cc61ed8869 100644 +--- a/include/linux/hisi_acc_qm.h ++++ b/include/linux/hisi_acc_qm.h +@@ -444,6 +444,11 @@ struct hisi_qp_ops { + int (*fill_sqe)(void *sqe, void *q_parm, void *d_parm); + }; + ++struct instance_backlog { ++ struct list_head list; ++ spinlock_t lock; ++}; ++ + struct hisi_qp { + u32 qp_id; + u16 sq_depth; +@@ -468,6 +473,9 @@ struct hisi_qp { + bool is_in_kernel; + u16 pasid; + struct uacce_queue *uacce_q; ++ ++ struct instance_backlog backlog; ++ const void **msg; + }; + + static inline int vfs_num_set(const char *val, const struct kernel_param *kp) +-- +2.51.0 + diff --git a/queue-6.18/crypto-hisilicon-sec2-support-skcipher-aead-fallback.patch b/queue-6.18/crypto-hisilicon-sec2-support-skcipher-aead-fallback.patch new file mode 100644 index 0000000000..15e0959fb5 --- /dev/null +++ b/queue-6.18/crypto-hisilicon-sec2-support-skcipher-aead-fallback.patch @@ -0,0 +1,220 @@ +From eac3c2644d0c526c76e8cd07088d30b4d5acd458 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 21:44:52 +0800 +Subject: crypto: hisilicon/sec2 - support skcipher/aead fallback for hardware + queue unavailable + +From: Qi Tao + +[ Upstream commit e7507439628052363500d717caffb5c2241854dc ] + +When all hardware queues are busy and no shareable queue, +new processes fail to apply for queues. To avoid affecting +tasks, support fallback mechanism when hardware queues are +unavailable. + +Fixes: c16a70c1f253 ("crypto: hisilicon/sec - add new algorithm mode for AEAD") +Signed-off-by: Qi Tao +Signed-off-by: Chenghai Huang +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/sec2/sec_crypto.c | 62 ++++++++++++++++------ + 1 file changed, 47 insertions(+), 15 deletions(-) + +diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.c b/drivers/crypto/hisilicon/sec2/sec_crypto.c +index d09d081f42dc7..c462b58d30343 100644 +--- a/drivers/crypto/hisilicon/sec2/sec_crypto.c ++++ b/drivers/crypto/hisilicon/sec2/sec_crypto.c +@@ -663,10 +663,8 @@ static int sec_ctx_base_init(struct sec_ctx *ctx) + int i, ret; + + ctx->qps = sec_create_qps(); +- if (!ctx->qps) { +- pr_err("Can not create sec qps!\n"); ++ if (!ctx->qps) + return -ENODEV; +- } + + sec = container_of(ctx->qps[0]->qm, struct sec_dev, qm); + ctx->sec = sec; +@@ -702,6 +700,9 @@ static void sec_ctx_base_uninit(struct sec_ctx *ctx) + { + int i; + ++ if (!ctx->qps) ++ return; ++ + for (i = 0; i < ctx->sec->ctx_q_num; i++) + sec_release_qp_ctx(ctx, &ctx->qp_ctx[i]); + +@@ -713,6 +714,9 @@ static int sec_cipher_init(struct sec_ctx *ctx) + { + struct sec_cipher_ctx *c_ctx = &ctx->c_ctx; + ++ if (!ctx->qps) ++ return 0; ++ + c_ctx->c_key = dma_alloc_coherent(ctx->dev, SEC_MAX_KEY_SIZE, + &c_ctx->c_key_dma, GFP_KERNEL); + if (!c_ctx->c_key) +@@ -725,6 +729,9 @@ static void sec_cipher_uninit(struct sec_ctx *ctx) + { + struct sec_cipher_ctx *c_ctx = &ctx->c_ctx; + ++ if (!ctx->qps) ++ return; ++ + memzero_explicit(c_ctx->c_key, SEC_MAX_KEY_SIZE); + dma_free_coherent(ctx->dev, SEC_MAX_KEY_SIZE, + c_ctx->c_key, c_ctx->c_key_dma); +@@ -746,6 +753,9 @@ static void sec_auth_uninit(struct sec_ctx *ctx) + { + struct sec_auth_ctx *a_ctx = &ctx->a_ctx; + ++ if (!ctx->qps) ++ return; ++ + memzero_explicit(a_ctx->a_key, SEC_MAX_AKEY_SIZE); + dma_free_coherent(ctx->dev, SEC_MAX_AKEY_SIZE, + a_ctx->a_key, a_ctx->a_key_dma); +@@ -783,7 +793,7 @@ static int sec_skcipher_init(struct crypto_skcipher *tfm) + } + + ret = sec_ctx_base_init(ctx); +- if (ret) ++ if (ret && ret != -ENODEV) + return ret; + + ret = sec_cipher_init(ctx); +@@ -892,6 +902,9 @@ static int sec_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key, + struct device *dev = ctx->dev; + int ret; + ++ if (!ctx->qps) ++ goto set_soft_key; ++ + if (c_mode == SEC_CMODE_XTS) { + ret = xts_verify_key(tfm, key, keylen); + if (ret) { +@@ -922,13 +935,14 @@ static int sec_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key, + } + + memcpy(c_ctx->c_key, key, keylen); +- if (c_ctx->fbtfm) { +- ret = crypto_sync_skcipher_setkey(c_ctx->fbtfm, key, keylen); +- if (ret) { +- dev_err(dev, "failed to set fallback skcipher key!\n"); +- return ret; +- } ++ ++set_soft_key: ++ ret = crypto_sync_skcipher_setkey(c_ctx->fbtfm, key, keylen); ++ if (ret) { ++ dev_err(dev, "failed to set fallback skcipher key!\n"); ++ return ret; + } ++ + return 0; + } + +@@ -1392,6 +1406,9 @@ static int sec_aead_setkey(struct crypto_aead *tfm, const u8 *key, + struct crypto_authenc_keys keys; + int ret; + ++ if (!ctx->qps) ++ return sec_aead_fallback_setkey(a_ctx, tfm, key, keylen); ++ + ctx->a_ctx.a_alg = a_alg; + ctx->c_ctx.c_alg = c_alg; + c_ctx->c_mode = c_mode; +@@ -2048,6 +2065,9 @@ static int sec_skcipher_ctx_init(struct crypto_skcipher *tfm) + if (ret) + return ret; + ++ if (!ctx->qps) ++ return 0; ++ + if (ctx->sec->qm.ver < QM_HW_V3) { + ctx->type_supported = SEC_BD_TYPE2; + ctx->req_op = &sec_skcipher_req_ops; +@@ -2056,7 +2076,7 @@ static int sec_skcipher_ctx_init(struct crypto_skcipher *tfm) + ctx->req_op = &sec_skcipher_req_ops_v3; + } + +- return ret; ++ return 0; + } + + static void sec_skcipher_ctx_exit(struct crypto_skcipher *tfm) +@@ -2124,7 +2144,7 @@ static int sec_aead_ctx_init(struct crypto_aead *tfm, const char *hash_name) + int ret; + + ret = sec_aead_init(tfm); +- if (ret) { ++ if (ret && ret != -ENODEV) { + pr_err("hisi_sec2: aead init error!\n"); + return ret; + } +@@ -2166,7 +2186,7 @@ static int sec_aead_xcm_ctx_init(struct crypto_aead *tfm) + int ret; + + ret = sec_aead_init(tfm); +- if (ret) { ++ if (ret && ret != -ENODEV) { + dev_err(ctx->dev, "hisi_sec2: aead xcm init error!\n"); + return ret; + } +@@ -2311,6 +2331,9 @@ static int sec_skcipher_crypto(struct skcipher_request *sk_req, bool encrypt) + bool need_fallback = false; + int ret; + ++ if (!ctx->qps) ++ goto soft_crypto; ++ + if (!sk_req->cryptlen) { + if (ctx->c_ctx.c_mode == SEC_CMODE_XTS) + return -EINVAL; +@@ -2328,9 +2351,12 @@ static int sec_skcipher_crypto(struct skcipher_request *sk_req, bool encrypt) + return -EINVAL; + + if (unlikely(ctx->c_ctx.fallback || need_fallback)) +- return sec_skcipher_soft_crypto(ctx, sk_req, encrypt); ++ goto soft_crypto; + + return ctx->req_op->process(ctx, req); ++ ++soft_crypto: ++ return sec_skcipher_soft_crypto(ctx, sk_req, encrypt); + } + + static int sec_skcipher_encrypt(struct skcipher_request *sk_req) +@@ -2538,6 +2564,9 @@ static int sec_aead_crypto(struct aead_request *a_req, bool encrypt) + bool need_fallback = false; + int ret; + ++ if (!ctx->qps) ++ goto soft_crypto; ++ + req->flag = a_req->base.flags; + req->aead_req.aead_req = a_req; + req->c_req.encrypt = encrypt; +@@ -2548,11 +2577,14 @@ static int sec_aead_crypto(struct aead_request *a_req, bool encrypt) + ret = sec_aead_param_check(ctx, req, &need_fallback); + if (unlikely(ret)) { + if (need_fallback) +- return sec_aead_soft_crypto(ctx, a_req, encrypt); ++ goto soft_crypto; + return -EINVAL; + } + + return ctx->req_op->process(ctx, req); ++ ++soft_crypto: ++ return sec_aead_soft_crypto(ctx, a_req, encrypt); + } + + static int sec_aead_encrypt(struct aead_request *a_req) +-- +2.51.0 + diff --git a/queue-6.18/crypto-hisilicon-sgl-fix-inconsistent-map-unmap-dire.patch b/queue-6.18/crypto-hisilicon-sgl-fix-inconsistent-map-unmap-dire.patch new file mode 100644 index 0000000000..5ccb4710d9 --- /dev/null +++ b/queue-6.18/crypto-hisilicon-sgl-fix-inconsistent-map-unmap-dire.patch @@ -0,0 +1,37 @@ +From 806b12dcb390cec577cf42c6be225b80ae570471 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 19 Dec 2025 11:36:19 +0800 +Subject: crypto: hisilicon/sgl - fix inconsistent map/unmap direction issue + +From: Chenghai Huang + +[ Upstream commit 4154f7d3b1c133b909d20c44ecb8277e8482aa6b ] + +Ensure that the direction for dma_map_sg and dma_unmap_sg is +consistent. + +Fixes: 2566de3e06a3 ("crypto: hisilicon - Use fine grained DMA mapping direction") +Signed-off-by: Chenghai Huang +Reviewed-by: Zenghui Yu +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/sgl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/crypto/hisilicon/sgl.c b/drivers/crypto/hisilicon/sgl.c +index 7a9ef2a9972a2..848ad7b101d93 100644 +--- a/drivers/crypto/hisilicon/sgl.c ++++ b/drivers/crypto/hisilicon/sgl.c +@@ -265,7 +265,7 @@ hisi_acc_sg_buf_map_to_hw_sgl(struct device *dev, struct scatterlist *sgl, + return curr_hw_sgl; + + err_unmap: +- dma_unmap_sg(dev, sgl, sg_n, DMA_BIDIRECTIONAL); ++ dma_unmap_sg(dev, sgl, sg_n, dir); + + return ERR_PTR(ret); + } +-- +2.51.0 + diff --git a/queue-6.18/crypto-hisilicon-trng-support-tfms-sharing-the-devic.patch b/queue-6.18/crypto-hisilicon-trng-support-tfms-sharing-the-devic.patch new file mode 100644 index 0000000000..b8298d34c4 --- /dev/null +++ b/queue-6.18/crypto-hisilicon-trng-support-tfms-sharing-the-devic.patch @@ -0,0 +1,258 @@ +From 16dbace6056d12d244f4b3a8eae3a703067f6ca6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 17 Jan 2026 15:18:21 +0800 +Subject: crypto: hisilicon/trng - support tfms sharing the device + +From: Weili Qian + +[ Upstream commit 3d3135057ff567d5c09fff4c9ef6391a684e8042 ] + +Since the number of devices is limited, and the number +of tfms may exceed the number of devices, to ensure that +tfms can be successfully allocated, support tfms +sharing the same device. + +Fixes: e4d9d10ef4be ("crypto: hisilicon/trng - add support for PRNG") +Signed-off-by: Weili Qian +Signed-off-by: Chenghai Huang +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/trng/trng.c | 121 +++++++++++++++++++-------- + 1 file changed, 86 insertions(+), 35 deletions(-) + +diff --git a/drivers/crypto/hisilicon/trng/trng.c b/drivers/crypto/hisilicon/trng/trng.c +index ac74df4a94712..5ca0b90859a81 100644 +--- a/drivers/crypto/hisilicon/trng/trng.c ++++ b/drivers/crypto/hisilicon/trng/trng.c +@@ -40,6 +40,7 @@ + #define SEED_SHIFT_24 24 + #define SEED_SHIFT_16 16 + #define SEED_SHIFT_8 8 ++#define SW_MAX_RANDOM_BYTES 65520 + + struct hisi_trng_list { + struct mutex lock; +@@ -53,8 +54,10 @@ struct hisi_trng { + struct list_head list; + struct hwrng rng; + u32 ver; +- bool is_used; +- struct mutex mutex; ++ u32 ctx_num; ++ /* The bytes of the random number generated since the last seeding. */ ++ u32 random_bytes; ++ struct mutex lock; + }; + + struct hisi_trng_ctx { +@@ -63,10 +66,14 @@ struct hisi_trng_ctx { + + static atomic_t trng_active_devs; + static struct hisi_trng_list trng_devices; ++static int hisi_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait); + +-static void hisi_trng_set_seed(struct hisi_trng *trng, const u8 *seed) ++static int hisi_trng_set_seed(struct hisi_trng *trng, const u8 *seed) + { + u32 val, seed_reg, i; ++ int ret; ++ ++ writel(0x0, trng->base + SW_DRBG_BLOCKS); + + for (i = 0; i < SW_DRBG_SEED_SIZE; + i += SW_DRBG_SEED_SIZE / SW_DRBG_SEED_REGS_NUM) { +@@ -78,6 +85,20 @@ static void hisi_trng_set_seed(struct hisi_trng *trng, const u8 *seed) + seed_reg = (i >> SW_DRBG_NUM_SHIFT) % SW_DRBG_SEED_REGS_NUM; + writel(val, trng->base + SW_DRBG_SEED(seed_reg)); + } ++ ++ writel(SW_DRBG_BLOCKS_NUM | (0x1 << SW_DRBG_ENABLE_SHIFT), ++ trng->base + SW_DRBG_BLOCKS); ++ writel(0x1, trng->base + SW_DRBG_INIT); ++ ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS, ++ val, val & BIT(0), SLEEP_US, TIMEOUT_US); ++ if (ret) { ++ pr_err("failed to init trng(%d)\n", ret); ++ return -EIO; ++ } ++ ++ trng->random_bytes = 0; ++ ++ return 0; + } + + static int hisi_trng_seed(struct crypto_rng *tfm, const u8 *seed, +@@ -85,8 +106,7 @@ static int hisi_trng_seed(struct crypto_rng *tfm, const u8 *seed, + { + struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm); + struct hisi_trng *trng = ctx->trng; +- u32 val = 0; +- int ret = 0; ++ int ret; + + if (slen < SW_DRBG_SEED_SIZE) { + pr_err("slen(%u) is not matched with trng(%d)\n", slen, +@@ -94,43 +114,45 @@ static int hisi_trng_seed(struct crypto_rng *tfm, const u8 *seed, + return -EINVAL; + } + +- writel(0x0, trng->base + SW_DRBG_BLOCKS); +- hisi_trng_set_seed(trng, seed); ++ mutex_lock(&trng->lock); ++ ret = hisi_trng_set_seed(trng, seed); ++ mutex_unlock(&trng->lock); + +- writel(SW_DRBG_BLOCKS_NUM | (0x1 << SW_DRBG_ENABLE_SHIFT), +- trng->base + SW_DRBG_BLOCKS); +- writel(0x1, trng->base + SW_DRBG_INIT); ++ return ret; ++} + +- ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS, +- val, val & BIT(0), SLEEP_US, TIMEOUT_US); +- if (ret) +- pr_err("fail to init trng(%d)\n", ret); ++static int hisi_trng_reseed(struct hisi_trng *trng) ++{ ++ u8 seed[SW_DRBG_SEED_SIZE]; ++ int size; + +- return ret; ++ if (!trng->random_bytes) ++ return 0; ++ ++ size = hisi_trng_read(&trng->rng, seed, SW_DRBG_SEED_SIZE, false); ++ if (size != SW_DRBG_SEED_SIZE) ++ return -EIO; ++ ++ return hisi_trng_set_seed(trng, seed); + } + +-static int hisi_trng_generate(struct crypto_rng *tfm, const u8 *src, +- unsigned int slen, u8 *dstn, unsigned int dlen) ++static int hisi_trng_get_bytes(struct hisi_trng *trng, u8 *dstn, unsigned int dlen) + { +- struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm); +- struct hisi_trng *trng = ctx->trng; + u32 data[SW_DRBG_DATA_NUM]; + u32 currsize = 0; + u32 val = 0; + int ret; + u32 i; + +- if (dlen > SW_DRBG_BLOCKS_NUM * SW_DRBG_BYTES || dlen == 0) { +- pr_err("dlen(%u) exceeds limit(%d)!\n", dlen, +- SW_DRBG_BLOCKS_NUM * SW_DRBG_BYTES); +- return -EINVAL; +- } ++ ret = hisi_trng_reseed(trng); ++ if (ret) ++ return ret; + + do { + ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS, +- val, val & BIT(1), SLEEP_US, TIMEOUT_US); ++ val, val & BIT(1), SLEEP_US, TIMEOUT_US); + if (ret) { +- pr_err("fail to generate random number(%d)!\n", ret); ++ pr_err("failed to generate random number(%d)!\n", ret); + break; + } + +@@ -145,30 +167,57 @@ static int hisi_trng_generate(struct crypto_rng *tfm, const u8 *src, + currsize = dlen; + } + ++ trng->random_bytes += SW_DRBG_BYTES; + writel(0x1, trng->base + SW_DRBG_GEN); + } while (currsize < dlen); + + return ret; + } + ++static int hisi_trng_generate(struct crypto_rng *tfm, const u8 *src, ++ unsigned int slen, u8 *dstn, unsigned int dlen) ++{ ++ struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm); ++ struct hisi_trng *trng = ctx->trng; ++ unsigned int currsize = 0; ++ unsigned int block_size; ++ int ret; ++ ++ if (!dstn || !dlen) { ++ pr_err("output is error, dlen %u!\n", dlen); ++ return -EINVAL; ++ } ++ ++ do { ++ block_size = min_t(unsigned int, dlen - currsize, SW_MAX_RANDOM_BYTES); ++ mutex_lock(&trng->lock); ++ ret = hisi_trng_get_bytes(trng, dstn + currsize, block_size); ++ mutex_unlock(&trng->lock); ++ if (ret) ++ return ret; ++ currsize += block_size; ++ } while (currsize < dlen); ++ ++ return 0; ++} ++ + static int hisi_trng_init(struct crypto_tfm *tfm) + { + struct hisi_trng_ctx *ctx = crypto_tfm_ctx(tfm); + struct hisi_trng *trng; +- int ret = -EBUSY; ++ u32 ctx_num = ~0; + + mutex_lock(&trng_devices.lock); + list_for_each_entry(trng, &trng_devices.list, list) { +- if (!trng->is_used) { +- trng->is_used = true; ++ if (trng->ctx_num < ctx_num) { ++ ctx_num = trng->ctx_num; + ctx->trng = trng; +- ret = 0; +- break; + } + } ++ ctx->trng->ctx_num++; + mutex_unlock(&trng_devices.lock); + +- return ret; ++ return 0; + } + + static void hisi_trng_exit(struct crypto_tfm *tfm) +@@ -176,7 +225,7 @@ static void hisi_trng_exit(struct crypto_tfm *tfm) + struct hisi_trng_ctx *ctx = crypto_tfm_ctx(tfm); + + mutex_lock(&trng_devices.lock); +- ctx->trng->is_used = false; ++ ctx->trng->ctx_num--; + mutex_unlock(&trng_devices.lock); + } + +@@ -238,7 +287,7 @@ static int hisi_trng_del_from_list(struct hisi_trng *trng) + int ret = -EBUSY; + + mutex_lock(&trng_devices.lock); +- if (!trng->is_used) { ++ if (!trng->ctx_num) { + list_del(&trng->list); + ret = 0; + } +@@ -262,7 +311,9 @@ static int hisi_trng_probe(struct platform_device *pdev) + if (IS_ERR(trng->base)) + return PTR_ERR(trng->base); + +- trng->is_used = false; ++ trng->ctx_num = 0; ++ trng->random_bytes = SW_MAX_RANDOM_BYTES; ++ mutex_init(&trng->lock); + trng->ver = readl(trng->base + HISI_TRNG_VERSION); + if (!trng_devices.is_init) { + INIT_LIST_HEAD(&trng_devices.list); +-- +2.51.0 + diff --git a/queue-6.18/crypto-hisilicon-zip-adjust-the-way-to-obtain-the-re.patch b/queue-6.18/crypto-hisilicon-zip-adjust-the-way-to-obtain-the-re.patch new file mode 100644 index 0000000000..3fefa7fa8f --- /dev/null +++ b/queue-6.18/crypto-hisilicon-zip-adjust-the-way-to-obtain-the-re.patch @@ -0,0 +1,128 @@ +From 38e8c28b4f07d2a7cdb814713f831a97cf642456 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 21:44:42 +0800 +Subject: crypto: hisilicon/zip - adjust the way to obtain the req in the + callback function + +From: Chenghai Huang + +[ Upstream commit 19c2475ce1984cf675ebfbbeaa5509b2fb1887d6 ] + +In the shared queue design, multiple tfms use same qp, and one qp +need to corresponds to multiple qp_ctx. So use tag to obtain the +req virtual address. Build a one-to-one relationship between tfm +and qp_ctx. finaly remove the old get_tag operation. + +Fixes: 2bcf36348ce5 ("crypto: hisilicon/zip - initialize operations about 'sqe' in 'acomp_alg.init'") +Signed-off-by: Chenghai Huang +Signed-off-by: Weili Qian +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/zip/zip_crypto.c | 24 +++++++++-------------- + 1 file changed, 9 insertions(+), 15 deletions(-) + +diff --git a/drivers/crypto/hisilicon/zip/zip_crypto.c b/drivers/crypto/hisilicon/zip/zip_crypto.c +index b97513981a3b7..b4a656e0177d2 100644 +--- a/drivers/crypto/hisilicon/zip/zip_crypto.c ++++ b/drivers/crypto/hisilicon/zip/zip_crypto.c +@@ -39,6 +39,7 @@ enum { + HZIP_CTX_Q_NUM + }; + ++#define GET_REQ_FROM_SQE(sqe) ((u64)(sqe)->dw26 | (u64)(sqe)->dw27 << 32) + #define COMP_NAME_TO_TYPE(alg_name) \ + (!strcmp((alg_name), "deflate") ? HZIP_ALG_TYPE_DEFLATE : 0) + +@@ -48,6 +49,7 @@ struct hisi_zip_req { + struct hisi_acc_hw_sgl *hw_dst; + dma_addr_t dma_src; + dma_addr_t dma_dst; ++ struct hisi_zip_qp_ctx *qp_ctx; + u16 req_id; + }; + +@@ -74,7 +76,6 @@ struct hisi_zip_sqe_ops { + void (*fill_req_type)(struct hisi_zip_sqe *sqe, u8 req_type); + void (*fill_tag)(struct hisi_zip_sqe *sqe, struct hisi_zip_req *req); + void (*fill_sqe_type)(struct hisi_zip_sqe *sqe, u8 sqe_type); +- u32 (*get_tag)(struct hisi_zip_sqe *sqe); + u32 (*get_status)(struct hisi_zip_sqe *sqe); + u32 (*get_dstlen)(struct hisi_zip_sqe *sqe); + }; +@@ -131,6 +132,7 @@ static struct hisi_zip_req *hisi_zip_create_req(struct hisi_zip_qp_ctx *qp_ctx, + req_cache = q + req_id; + req_cache->req_id = req_id; + req_cache->req = req; ++ req_cache->qp_ctx = qp_ctx; + + return req_cache; + } +@@ -181,7 +183,8 @@ static void hisi_zip_fill_req_type(struct hisi_zip_sqe *sqe, u8 req_type) + + static void hisi_zip_fill_tag(struct hisi_zip_sqe *sqe, struct hisi_zip_req *req) + { +- sqe->dw26 = req->req_id; ++ sqe->dw26 = lower_32_bits((u64)req); ++ sqe->dw27 = upper_32_bits((u64)req); + } + + static void hisi_zip_fill_sqe_type(struct hisi_zip_sqe *sqe, u8 sqe_type) +@@ -237,7 +240,7 @@ static int hisi_zip_do_work(struct hisi_zip_qp_ctx *qp_ctx, + &req->dma_dst, DMA_FROM_DEVICE); + if (IS_ERR(req->hw_dst)) { + ret = PTR_ERR(req->hw_dst); +- dev_err(dev, "failed to map the dst buffer to hw slg (%d)!\n", ++ dev_err(dev, "failed to map the dst buffer to hw sgl (%d)!\n", + ret); + goto err_unmap_input; + } +@@ -265,11 +268,6 @@ static int hisi_zip_do_work(struct hisi_zip_qp_ctx *qp_ctx, + return ret; + } + +-static u32 hisi_zip_get_tag(struct hisi_zip_sqe *sqe) +-{ +- return sqe->dw26; +-} +- + static u32 hisi_zip_get_status(struct hisi_zip_sqe *sqe) + { + return sqe->dw3 & HZIP_BD_STATUS_M; +@@ -282,14 +280,12 @@ static u32 hisi_zip_get_dstlen(struct hisi_zip_sqe *sqe) + + static void hisi_zip_acomp_cb(struct hisi_qp *qp, void *data) + { +- struct hisi_zip_qp_ctx *qp_ctx = qp->qp_ctx; ++ struct hisi_zip_sqe *sqe = data; ++ struct hisi_zip_req *req = (struct hisi_zip_req *)GET_REQ_FROM_SQE(sqe); ++ struct hisi_zip_qp_ctx *qp_ctx = req->qp_ctx; + const struct hisi_zip_sqe_ops *ops = qp_ctx->ctx->ops; + struct hisi_zip_dfx *dfx = &qp_ctx->zip_dev->dfx; +- struct hisi_zip_req_q *req_q = &qp_ctx->req_q; + struct device *dev = &qp->qm->pdev->dev; +- struct hisi_zip_sqe *sqe = data; +- u32 tag = ops->get_tag(sqe); +- struct hisi_zip_req *req = req_q->q + tag; + struct acomp_req *acomp_req = req->req; + int err = 0; + u32 status; +@@ -393,7 +389,6 @@ static const struct hisi_zip_sqe_ops hisi_zip_ops = { + .fill_req_type = hisi_zip_fill_req_type, + .fill_tag = hisi_zip_fill_tag, + .fill_sqe_type = hisi_zip_fill_sqe_type, +- .get_tag = hisi_zip_get_tag, + .get_status = hisi_zip_get_status, + .get_dstlen = hisi_zip_get_dstlen, + }; +@@ -581,7 +576,6 @@ static void hisi_zip_acomp_exit(struct crypto_acomp *tfm) + { + struct hisi_zip_ctx *ctx = crypto_tfm_ctx(&tfm->base); + +- hisi_zip_set_acomp_cb(ctx, NULL); + hisi_zip_release_sgl_pool(ctx); + hisi_zip_release_req_q(ctx); + hisi_zip_ctx_exit(ctx); +-- +2.51.0 + diff --git a/queue-6.18/crypto-hisilicon-zip-support-fallback-for-zip.patch b/queue-6.18/crypto-hisilicon-zip-support-fallback-for-zip.patch new file mode 100644 index 0000000000..3243c2a8a1 --- /dev/null +++ b/queue-6.18/crypto-hisilicon-zip-support-fallback-for-zip.patch @@ -0,0 +1,152 @@ +From 750d794cb48c9323eef42dc4216ada5a826f6edd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 21:44:50 +0800 +Subject: crypto: hisilicon/zip - support fallback for zip + +From: Chenghai Huang + +[ Upstream commit 73398f85a430cfebc2ff06ab836d6d9eb1484c79 ] + +When the hardware queue resource busy(no shareable queue) +or memery alloc fail in initialization of acomp_alg, use +soft algorithm to complete the work. + +Fixes: 1a9e6f59caee ("crypto: hisilicon/zip - remove zlib and gzip") +Signed-off-by: Chenghai Huang +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/Kconfig | 1 + + drivers/crypto/hisilicon/zip/zip_crypto.c | 50 +++++++++++++++++++---- + 2 files changed, 43 insertions(+), 8 deletions(-) + +diff --git a/drivers/crypto/hisilicon/Kconfig b/drivers/crypto/hisilicon/Kconfig +index 4835bdebdbb38..a0cb1a8186ac9 100644 +--- a/drivers/crypto/hisilicon/Kconfig ++++ b/drivers/crypto/hisilicon/Kconfig +@@ -57,6 +57,7 @@ config CRYPTO_DEV_HISI_ZIP + depends on UACCE || UACCE=n + depends on ACPI + select CRYPTO_DEV_HISI_QM ++ select CRYPTO_DEFLATE + help + Support for HiSilicon ZIP Driver + +diff --git a/drivers/crypto/hisilicon/zip/zip_crypto.c b/drivers/crypto/hisilicon/zip/zip_crypto.c +index 2f9035c016f3f..5fc2ed9d5eef3 100644 +--- a/drivers/crypto/hisilicon/zip/zip_crypto.c ++++ b/drivers/crypto/hisilicon/zip/zip_crypto.c +@@ -84,6 +84,7 @@ struct hisi_zip_sqe_ops { + struct hisi_zip_ctx { + struct hisi_zip_qp_ctx qp_ctx[HZIP_CTX_Q_NUM]; + const struct hisi_zip_sqe_ops *ops; ++ bool fallback; + }; + + static int sgl_sge_nr_set(const char *val, const struct kernel_param *kp) +@@ -110,6 +111,24 @@ static u16 sgl_sge_nr = HZIP_SGL_SGE_NR; + module_param_cb(sgl_sge_nr, &sgl_sge_nr_ops, &sgl_sge_nr, 0444); + MODULE_PARM_DESC(sgl_sge_nr, "Number of sge in sgl(1-255)"); + ++static int hisi_zip_fallback_do_work(struct acomp_req *acomp_req, bool is_decompress) ++{ ++ ACOMP_FBREQ_ON_STACK(fbreq, acomp_req); ++ int ret; ++ ++ if (!is_decompress) ++ ret = crypto_acomp_compress(fbreq); ++ else ++ ret = crypto_acomp_decompress(fbreq); ++ if (ret) { ++ pr_err("failed to do fallback work, ret=%d\n", ret); ++ return ret; ++ } ++ ++ acomp_req->dlen = fbreq->dlen; ++ return ret; ++} ++ + static struct hisi_zip_req *hisi_zip_create_req(struct hisi_zip_qp_ctx *qp_ctx, + struct acomp_req *req) + { +@@ -313,10 +332,15 @@ static int hisi_zip_acompress(struct acomp_req *acomp_req) + { + struct hisi_zip_ctx *ctx = crypto_tfm_ctx(acomp_req->base.tfm); + struct hisi_zip_qp_ctx *qp_ctx = &ctx->qp_ctx[HZIP_QPC_COMP]; +- struct device *dev = &qp_ctx->qp->qm->pdev->dev; + struct hisi_zip_req *req; ++ struct device *dev; + int ret; + ++ if (ctx->fallback) ++ return hisi_zip_fallback_do_work(acomp_req, 0); ++ ++ dev = &qp_ctx->qp->qm->pdev->dev; ++ + req = hisi_zip_create_req(qp_ctx, acomp_req); + if (IS_ERR(req)) + return PTR_ERR(req); +@@ -334,10 +358,15 @@ static int hisi_zip_adecompress(struct acomp_req *acomp_req) + { + struct hisi_zip_ctx *ctx = crypto_tfm_ctx(acomp_req->base.tfm); + struct hisi_zip_qp_ctx *qp_ctx = &ctx->qp_ctx[HZIP_QPC_DECOMP]; +- struct device *dev = &qp_ctx->qp->qm->pdev->dev; + struct hisi_zip_req *req; ++ struct device *dev; + int ret; + ++ if (ctx->fallback) ++ return hisi_zip_fallback_do_work(acomp_req, 1); ++ ++ dev = &qp_ctx->qp->qm->pdev->dev; ++ + req = hisi_zip_create_req(qp_ctx, acomp_req); + if (IS_ERR(req)) + return PTR_ERR(req); +@@ -546,7 +575,7 @@ static int hisi_zip_acomp_init(struct crypto_acomp *tfm) + ret = hisi_zip_ctx_init(ctx, COMP_NAME_TO_TYPE(alg_name), tfm->base.node); + if (ret) { + pr_err("failed to init ctx (%d)!\n", ret); +- return ret; ++ goto switch_to_soft; + } + + dev = &ctx->qp_ctx[0].qp->qm->pdev->dev; +@@ -571,16 +600,20 @@ static int hisi_zip_acomp_init(struct crypto_acomp *tfm) + hisi_zip_release_req_q(ctx); + err_ctx_exit: + hisi_zip_ctx_exit(ctx); +- return ret; ++switch_to_soft: ++ ctx->fallback = true; ++ return 0; + } + + static void hisi_zip_acomp_exit(struct crypto_acomp *tfm) + { + struct hisi_zip_ctx *ctx = crypto_tfm_ctx(&tfm->base); + +- hisi_zip_release_sgl_pool(ctx); +- hisi_zip_release_req_q(ctx); +- hisi_zip_ctx_exit(ctx); ++ if (!ctx->fallback) { ++ hisi_zip_release_sgl_pool(ctx); ++ hisi_zip_release_req_q(ctx); ++ hisi_zip_ctx_exit(ctx); ++ } + } + + static struct acomp_alg hisi_zip_acomp_deflate = { +@@ -591,7 +624,8 @@ static struct acomp_alg hisi_zip_acomp_deflate = { + .base = { + .cra_name = "deflate", + .cra_driver_name = "hisi-deflate-acomp", +- .cra_flags = CRYPTO_ALG_ASYNC, ++ .cra_flags = CRYPTO_ALG_ASYNC | ++ CRYPTO_ALG_NEED_FALLBACK, + .cra_module = THIS_MODULE, + .cra_priority = HZIP_ALG_PRIORITY, + .cra_ctxsize = sizeof(struct hisi_zip_ctx), +-- +2.51.0 + diff --git a/queue-6.18/crypto-inside-secure-eip93-fix-kernel-panic-in-drive.patch b/queue-6.18/crypto-inside-secure-eip93-fix-kernel-panic-in-drive.patch new file mode 100644 index 0000000000..a3dff6a758 --- /dev/null +++ b/queue-6.18/crypto-inside-secure-eip93-fix-kernel-panic-in-drive.patch @@ -0,0 +1,37 @@ +From cf94d46ed51036c252286dc8f80f34cd507234fc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Dec 2025 22:17:17 +0100 +Subject: crypto: inside-secure/eip93 - fix kernel panic in driver detach + +From: Aleksander Jan Bajkowski + +[ Upstream commit b6e32ba6d32503440a3e3e16c8d0521cbb7e0c5d ] + +During driver detach, the same hash algorithm is unregistered multiple +times due to a wrong iterator. + +Fixes: 9739f5f93b78 ("crypto: eip93 - Add Inside Secure SafeXcel EIP-93 crypto engine support") +Signed-off-by: Aleksander Jan Bajkowski +Reviewed-by: Antoine Tenart +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/inside-secure/eip93/eip93-main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/crypto/inside-secure/eip93/eip93-main.c b/drivers/crypto/inside-secure/eip93/eip93-main.c +index 0b38a567da0e0..3cdc3308dcac8 100644 +--- a/drivers/crypto/inside-secure/eip93/eip93-main.c ++++ b/drivers/crypto/inside-secure/eip93/eip93-main.c +@@ -90,7 +90,7 @@ static void eip93_unregister_algs(unsigned int i) + crypto_unregister_aead(&eip93_algs[j]->alg.aead); + break; + case EIP93_ALG_TYPE_HASH: +- crypto_unregister_ahash(&eip93_algs[i]->alg.ahash); ++ crypto_unregister_ahash(&eip93_algs[j]->alg.ahash); + break; + } + } +-- +2.51.0 + diff --git a/queue-6.18/crypto-inside-secure-eip93-unregister-only-available.patch b/queue-6.18/crypto-inside-secure-eip93-unregister-only-available.patch new file mode 100644 index 0000000000..a3543f88f2 --- /dev/null +++ b/queue-6.18/crypto-inside-secure-eip93-unregister-only-available.patch @@ -0,0 +1,164 @@ +From d9a03ea3190f6332816d47650275e8167bd4bb64 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 11 Jan 2026 14:20:32 +0100 +Subject: crypto: inside-secure/eip93 - unregister only available algorithm + +From: Aleksander Jan Bajkowski + +[ Upstream commit 0ceeadc7b53a041d89d5843f6bf0ccb7c98b0b4f ] + +EIP93 has an options register. This register indicates which crypto +algorithms are implemented in silicon. Supported algorithms are +registered on this basis. Unregister algorithms on the same basis. +Currently, all algorithms are unregistered, even those not supported +by HW. This results in panic on platforms that don't have all options +implemented in silicon. + +Fixes: 9739f5f93b78 ("crypto: eip93 - Add Inside Secure SafeXcel EIP-93 crypto engine support") +Signed-off-by: Aleksander Jan Bajkowski +Acked-by: Antoine Tenart +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + .../crypto/inside-secure/eip93/eip93-main.c | 92 +++++++++++-------- + 1 file changed, 53 insertions(+), 39 deletions(-) + +diff --git a/drivers/crypto/inside-secure/eip93/eip93-main.c b/drivers/crypto/inside-secure/eip93/eip93-main.c +index 3cdc3308dcac8..b7fd9795062d4 100644 +--- a/drivers/crypto/inside-secure/eip93/eip93-main.c ++++ b/drivers/crypto/inside-secure/eip93/eip93-main.c +@@ -77,11 +77,44 @@ inline void eip93_irq_clear(struct eip93_device *eip93, u32 mask) + __raw_writel(mask, eip93->base + EIP93_REG_INT_CLR); + } + +-static void eip93_unregister_algs(unsigned int i) ++static int eip93_algo_is_supported(u32 alg_flags, u32 supported_algo_flags) ++{ ++ if ((IS_DES(alg_flags) || IS_3DES(alg_flags)) && ++ !(supported_algo_flags & EIP93_PE_OPTION_TDES)) ++ return 0; ++ ++ if (IS_AES(alg_flags) && ++ !(supported_algo_flags & EIP93_PE_OPTION_AES)) ++ return 0; ++ ++ if (IS_HASH_MD5(alg_flags) && ++ !(supported_algo_flags & EIP93_PE_OPTION_MD5)) ++ return 0; ++ ++ if (IS_HASH_SHA1(alg_flags) && ++ !(supported_algo_flags & EIP93_PE_OPTION_SHA_1)) ++ return 0; ++ ++ if (IS_HASH_SHA224(alg_flags) && ++ !(supported_algo_flags & EIP93_PE_OPTION_SHA_224)) ++ return 0; ++ ++ if (IS_HASH_SHA256(alg_flags) && ++ !(supported_algo_flags & EIP93_PE_OPTION_SHA_256)) ++ return 0; ++ ++ return 1; ++} ++ ++static void eip93_unregister_algs(u32 supported_algo_flags, unsigned int i) + { + unsigned int j; + + for (j = 0; j < i; j++) { ++ if (!eip93_algo_is_supported(eip93_algs[j]->flags, ++ supported_algo_flags)) ++ continue; ++ + switch (eip93_algs[j]->type) { + case EIP93_ALG_TYPE_SKCIPHER: + crypto_unregister_skcipher(&eip93_algs[j]->alg.skcipher); +@@ -106,49 +139,27 @@ static int eip93_register_algs(struct eip93_device *eip93, u32 supported_algo_fl + + eip93_algs[i]->eip93 = eip93; + +- if ((IS_DES(alg_flags) || IS_3DES(alg_flags)) && +- !(supported_algo_flags & EIP93_PE_OPTION_TDES)) ++ if (!eip93_algo_is_supported(alg_flags, supported_algo_flags)) + continue; + +- if (IS_AES(alg_flags)) { +- if (!(supported_algo_flags & EIP93_PE_OPTION_AES)) +- continue; ++ if (IS_AES(alg_flags) && !IS_HMAC(alg_flags)) { ++ if (supported_algo_flags & EIP93_PE_OPTION_AES_KEY128) ++ eip93_algs[i]->alg.skcipher.max_keysize = ++ AES_KEYSIZE_128; + +- if (!IS_HMAC(alg_flags)) { +- if (supported_algo_flags & EIP93_PE_OPTION_AES_KEY128) +- eip93_algs[i]->alg.skcipher.max_keysize = +- AES_KEYSIZE_128; ++ if (supported_algo_flags & EIP93_PE_OPTION_AES_KEY192) ++ eip93_algs[i]->alg.skcipher.max_keysize = ++ AES_KEYSIZE_192; + +- if (supported_algo_flags & EIP93_PE_OPTION_AES_KEY192) +- eip93_algs[i]->alg.skcipher.max_keysize = +- AES_KEYSIZE_192; ++ if (supported_algo_flags & EIP93_PE_OPTION_AES_KEY256) ++ eip93_algs[i]->alg.skcipher.max_keysize = ++ AES_KEYSIZE_256; + +- if (supported_algo_flags & EIP93_PE_OPTION_AES_KEY256) +- eip93_algs[i]->alg.skcipher.max_keysize = +- AES_KEYSIZE_256; +- +- if (IS_RFC3686(alg_flags)) +- eip93_algs[i]->alg.skcipher.max_keysize += +- CTR_RFC3686_NONCE_SIZE; +- } ++ if (IS_RFC3686(alg_flags)) ++ eip93_algs[i]->alg.skcipher.max_keysize += ++ CTR_RFC3686_NONCE_SIZE; + } + +- if (IS_HASH_MD5(alg_flags) && +- !(supported_algo_flags & EIP93_PE_OPTION_MD5)) +- continue; +- +- if (IS_HASH_SHA1(alg_flags) && +- !(supported_algo_flags & EIP93_PE_OPTION_SHA_1)) +- continue; +- +- if (IS_HASH_SHA224(alg_flags) && +- !(supported_algo_flags & EIP93_PE_OPTION_SHA_224)) +- continue; +- +- if (IS_HASH_SHA256(alg_flags) && +- !(supported_algo_flags & EIP93_PE_OPTION_SHA_256)) +- continue; +- + switch (eip93_algs[i]->type) { + case EIP93_ALG_TYPE_SKCIPHER: + ret = crypto_register_skcipher(&eip93_algs[i]->alg.skcipher); +@@ -167,7 +178,7 @@ static int eip93_register_algs(struct eip93_device *eip93, u32 supported_algo_fl + return 0; + + fail: +- eip93_unregister_algs(i); ++ eip93_unregister_algs(supported_algo_flags, i); + + return ret; + } +@@ -469,8 +480,11 @@ static int eip93_crypto_probe(struct platform_device *pdev) + static void eip93_crypto_remove(struct platform_device *pdev) + { + struct eip93_device *eip93 = platform_get_drvdata(pdev); ++ u32 algo_flags; ++ ++ algo_flags = readl(eip93->base + EIP93_REG_PE_OPTION_1); + +- eip93_unregister_algs(ARRAY_SIZE(eip93_algs)); ++ eip93_unregister_algs(algo_flags, ARRAY_SIZE(eip93_algs)); + eip93_cleanup(eip93); + } + +-- +2.51.0 + diff --git a/queue-6.18/crypto-octeontx-fix-dma_free_coherent-size.patch b/queue-6.18/crypto-octeontx-fix-dma_free_coherent-size.patch new file mode 100644 index 0000000000..0cbf35cff3 --- /dev/null +++ b/queue-6.18/crypto-octeontx-fix-dma_free_coherent-size.patch @@ -0,0 +1,38 @@ +From 44595a62b1f4ce14b1014f7d3304056e42c78331 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 11:12:57 +0100 +Subject: crypto: octeontx - fix dma_free_coherent() size + +From: Thomas Fourier + +[ Upstream commit 624a6760bf8464965c17c8df10b40b557eaa3002 ] + +The size of the buffer in alloc_command_queues() is +curr->size + OTX_CPT_NEXT_CHUNK_PTR_SIZE, so used that length for +dma_free_coherent(). + +Fixes: 10b4f09491bf ("crypto: marvell - add the Virtual Function driver for CPT") +Signed-off-by: Thomas Fourier +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/marvell/octeontx/otx_cptvf_main.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/crypto/marvell/octeontx/otx_cptvf_main.c b/drivers/crypto/marvell/octeontx/otx_cptvf_main.c +index 88a41d1ca5f64..6c0bfb3ea1c9f 100644 +--- a/drivers/crypto/marvell/octeontx/otx_cptvf_main.c ++++ b/drivers/crypto/marvell/octeontx/otx_cptvf_main.c +@@ -168,7 +168,8 @@ static void free_command_queues(struct otx_cptvf *cptvf, + chunk = list_first_entry(&cqinfo->queue[i].chead, + struct otx_cpt_cmd_chunk, nextchunk); + +- dma_free_coherent(&pdev->dev, chunk->size, ++ dma_free_coherent(&pdev->dev, ++ chunk->size + OTX_CPT_NEXT_CHUNK_PTR_SIZE, + chunk->head, + chunk->dma_addr); + chunk->head = NULL; +-- +2.51.0 + diff --git a/queue-6.18/crypto-qat-fix-warning-on-adf_pfvf_pf_proto.c.patch b/queue-6.18/crypto-qat-fix-warning-on-adf_pfvf_pf_proto.c.patch new file mode 100644 index 0000000000..5768ad9092 --- /dev/null +++ b/queue-6.18/crypto-qat-fix-warning-on-adf_pfvf_pf_proto.c.patch @@ -0,0 +1,63 @@ +From bb9e03a9499f513d232dd494a34d289d0b0100f1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 20 Nov 2025 16:30:46 +0000 +Subject: crypto: qat - fix warning on adf_pfvf_pf_proto.c +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Giovanni Cabiddu + +[ Upstream commit 994689b8f91b02fdb5f64cba2412cde5ef3084b5 ] + +Building the QAT driver with -Wmaybe-uninitialized triggers warnings in +qat_common/adf_pfvf_pf_proto.c. Specifically, the variables blk_type, +blk_byte, and byte_max may be used uninitialized in handle_blkmsg_req(): + + make M=drivers/crypto/intel/qat W=1 C=2 "KCFLAGS=-Werror" \ + KBUILD_CFLAGS_KERNEL=-Wmaybe-uninitialized \ + CFLAGS_MODULE=-Wmaybe-uninitialized + + ... + warning: ‘byte_max’ may be used uninitialized [-Wmaybe-uninitialized] + warning: ‘blk_type’ may be used uninitialized [-Wmaybe-uninitialized] + warning: ‘blk_byte’ may be used uninitialized [-Wmaybe-uninitialized] + +Although the caller of handle_blkmsg_req() always provides a req.type +that is handled by the switch, the compiler cannot guarantee this. + +Add a default case to the switch statement to handle an invalid req.type. + +Fixes: 673184a2a58f ("crypto: qat - introduce support for PFVF block messages") +Signed-off-by: Giovanni Cabiddu +Reviewed-by: Ahsan Atta +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + .../crypto/intel/qat/qat_common/adf_pfvf_pf_proto.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/crypto/intel/qat/qat_common/adf_pfvf_pf_proto.c b/drivers/crypto/intel/qat/qat_common/adf_pfvf_pf_proto.c +index b9b5e744a3f16..af8dbc7517cf8 100644 +--- a/drivers/crypto/intel/qat/qat_common/adf_pfvf_pf_proto.c ++++ b/drivers/crypto/intel/qat/qat_common/adf_pfvf_pf_proto.c +@@ -148,6 +148,16 @@ static struct pfvf_message handle_blkmsg_req(struct adf_accel_vf_info *vf_info, + blk_byte = FIELD_GET(ADF_VF2PF_SMALL_BLOCK_BYTE_MASK, req.data); + byte_max = ADF_VF2PF_SMALL_BLOCK_BYTE_MAX; + break; ++ default: ++ dev_err(&GET_DEV(vf_info->accel_dev), ++ "Invalid BlockMsg type 0x%.4x received from VF%u\n", ++ req.type, vf_info->vf_nr); ++ resp.type = ADF_PF2VF_MSGTYPE_BLKMSG_RESP; ++ resp.data = FIELD_PREP(ADF_PF2VF_BLKMSG_RESP_TYPE_MASK, ++ ADF_PF2VF_BLKMSG_RESP_TYPE_ERROR) | ++ FIELD_PREP(ADF_PF2VF_BLKMSG_RESP_DATA_MASK, ++ ADF_PF2VF_UNSPECIFIED_ERROR); ++ return resp; + } + + /* Is this a request for CRC or data? */ +-- +2.51.0 + diff --git a/queue-6.18/crypto-starfive-fix-memory-leak-in-starfive_aes_aead.patch b/queue-6.18/crypto-starfive-fix-memory-leak-in-starfive_aes_aead.patch new file mode 100644 index 0000000000..052a8ba97d --- /dev/null +++ b/queue-6.18/crypto-starfive-fix-memory-leak-in-starfive_aes_aead.patch @@ -0,0 +1,60 @@ +From 6b47858bbb071a9a10d5e6c89b234cf5a0c262b4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 15:10:16 +0000 +Subject: crypto: starfive - Fix memory leak in starfive_aes_aead_do_one_req() + +From: Zilin Guan + +[ Upstream commit ccb679fdae2e62ed92fd9acb25ed809c0226fcc6 ] + +The starfive_aes_aead_do_one_req() function allocates rctx->adata with +kzalloc() but fails to free it if sg_copy_to_buffer() or +starfive_aes_hw_init() fails, which lead to memory leaks. + +Since rctx->adata is unconditionally freed after the write_adata +operations, ensure consistent cleanup by freeing the allocation in these +earlier error paths as well. + +Compile tested only. Issue found using a prototype static analysis tool +and code review. + +Fixes: 7467147ef9bf ("crypto: starfive - Use dma for aes requests") +Signed-off-by: Zilin Guan +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/starfive/jh7110-aes.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/drivers/crypto/starfive/jh7110-aes.c b/drivers/crypto/starfive/jh7110-aes.c +index 426b24889af85..01195664cc7cd 100644 +--- a/drivers/crypto/starfive/jh7110-aes.c ++++ b/drivers/crypto/starfive/jh7110-aes.c +@@ -669,8 +669,10 @@ static int starfive_aes_aead_do_one_req(struct crypto_engine *engine, void *areq + return -ENOMEM; + + if (sg_copy_to_buffer(req->src, sg_nents_for_len(req->src, cryp->assoclen), +- rctx->adata, cryp->assoclen) != cryp->assoclen) ++ rctx->adata, cryp->assoclen) != cryp->assoclen) { ++ kfree(rctx->adata); + return -EINVAL; ++ } + } + + if (cryp->total_in) +@@ -681,8 +683,11 @@ static int starfive_aes_aead_do_one_req(struct crypto_engine *engine, void *areq + ctx->rctx = rctx; + + ret = starfive_aes_hw_init(ctx); +- if (ret) ++ if (ret) { ++ if (cryp->assoclen) ++ kfree(rctx->adata); + return ret; ++ } + + if (!cryp->assoclen) + goto write_text; +-- +2.51.0 + diff --git a/queue-6.18/cxl-core-fix-cxl_dport-debugfs-einj-entries.patch b/queue-6.18/cxl-core-fix-cxl_dport-debugfs-einj-entries.patch new file mode 100644 index 0000000000..15e4aa0d4b --- /dev/null +++ b/queue-6.18/cxl-core-fix-cxl_dport-debugfs-einj-entries.patch @@ -0,0 +1,61 @@ +From a28573f38806316244bdc36c3f9322e6b23f3c61 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 07:57:38 -0600 +Subject: cxl/core: Fix cxl_dport debugfs EINJ entries + +From: Cheatham, Benjamin + +[ Upstream commit 4ed7952b9e87cf731ebc8251874416e60eb15230 ] + +Protocol error injection is only valid for CXL 2.0+ root ports and CXL +1.1 memory-mapped downstream ports as per the ACPI v6.5 spec (Table +8-31). The core code currently creates an 'einj_inject' file in CXL debugfs +for all CXL 1.1 downstream ports and all PCI CXL 2.0+ downstream ports. +This results in debugfs EINJ files that won't work due to platform/spec +restrictions. + +Fix by limiting 'einj_inject' file creation to only CXL 1.1 dports and +CXL 2.0+ root ports. Update the comment above the check to more accurately +represent the requirements expected by the EINJ module and ACPI spec. + +Fixes: 8039804cfa73 ("cxl/core: Add CXL EINJ debugfs files") +Signed-off-by: Ben Cheatham +Reviewed-by: Jonathan Cameron +Reviewed-by: Alison Schofield +Reviewed-by: Dave Jiang +Link: https://patch.msgid.link/6e9fb657-8264-4028-92e2-5428e2695bf1@amd.com +Signed-off-by: Dave Jiang +Signed-off-by: Sasha Levin +--- + drivers/cxl/core/port.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c +index 804e4a48540f6..85131872d7f6e 100644 +--- a/drivers/cxl/core/port.c ++++ b/drivers/cxl/core/port.c +@@ -823,16 +823,18 @@ DEFINE_DEBUGFS_ATTRIBUTE(cxl_einj_inject_fops, NULL, cxl_einj_inject, + + static void cxl_debugfs_create_dport_dir(struct cxl_dport *dport) + { ++ struct cxl_port *parent = parent_port_of(dport->port); + struct dentry *dir; + + if (!einj_cxl_is_initialized()) + return; + + /* +- * dport_dev needs to be a PCIe port for CXL 2.0+ ports because +- * EINJ expects a dport SBDF to be specified for 2.0 error injection. ++ * Protocol error injection is only available for CXL 2.0+ root ports ++ * and CXL 1.1 downstream ports + */ +- if (!dport->rch && !dev_is_pci(dport->dport_dev)) ++ if (!dport->rch && ++ !(dev_is_pci(dport->dport_dev) && parent && is_cxl_root(parent))) + return; + + dir = cxl_debugfs_create_dir(dev_name(dport->dport_dev)); +-- +2.51.0 + diff --git a/queue-6.18/cxl-fix-premature-commit_end-increment-on-decoder-co.patch b/queue-6.18/cxl-fix-premature-commit_end-increment-on-decoder-co.patch new file mode 100644 index 0000000000..e880fa0f0e --- /dev/null +++ b/queue-6.18/cxl-fix-premature-commit_end-increment-on-decoder-co.patch @@ -0,0 +1,62 @@ +From 17f63198aba5f207819d9e1cfac365fcc5ed7a05 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 14:45:52 +0800 +Subject: cxl: Fix premature commit_end increment on decoder commit failure + +From: Yuxiong Wang + +[ Upstream commit 7b6f9d9b1ea05c9c22570126547c780e8c6c3f62 ] + +In cxl_decoder_commit(), commit_end is incremented before verifying +whether the commit succeeded, and the CXL_DECODER_F_ENABLE bit in +cxld->flags is only set after a successful commit. As a result, if the +commit fails, commit_end has been incremented and cxld->reset() has no +effect since the flag is not set, so commit_end remains incorrectly +incremented. The inconsistency between commit_end and CXL_DECODER_F_ENABLE +causes failure during subsequent either commit or reset operations. + +Fix this by incrementing commit_end only after confirming the commit +succeeded. Also, remove the ineffective cxld->reset() call. According to +CXL Spec r4.0 8.2.4.20.12 Committing Decoder Programming, since +cxld_await_commit() has cleared the decoder commit bit on failure, no +additional reset is required. + +[dj: Fixed commit log 80 char wrapping. ] +[dj: Fix "Fixes" tag to correct hash length. ] +[dj: Change spec to r4.0. ] + +Fixes: 176baefb2eb5 ("cxl/hdm: Commit decoder state to hardware") +Signed-off-by: Yuxiong Wang +Acked-by: Huang Ying +Reviewed-by: Dave Jiang +Reviewed-by: Alison Schofield +Link: https://patch.msgid.link/20260129064552.31180-1-yuxiong.wang@linux.alibaba.com +Signed-off-by: Dave Jiang +Signed-off-by: Sasha Levin +--- + drivers/cxl/core/hdm.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c +index 20dd638108062..13dafac7c6d56 100644 +--- a/drivers/cxl/core/hdm.c ++++ b/drivers/cxl/core/hdm.c +@@ -844,14 +844,13 @@ static int cxl_decoder_commit(struct cxl_decoder *cxld) + scoped_guard(rwsem_read, &cxl_rwsem.dpa) + setup_hw_decoder(cxld, hdm); + +- port->commit_end++; + rc = cxld_await_commit(hdm, cxld->id); + if (rc) { + dev_dbg(&port->dev, "%s: error %d committing decoder\n", + dev_name(&cxld->dev), rc); +- cxld->reset(cxld); + return rc; + } ++ port->commit_end++; + cxld->flags |= CXL_DECODER_F_ENABLE; + + return 0; +-- +2.51.0 + diff --git a/queue-6.18/cxl-mem-fix-devm_cxl_memdev_edac_release-confusion.patch b/queue-6.18/cxl-mem-fix-devm_cxl_memdev_edac_release-confusion.patch new file mode 100644 index 0000000000..ab0818f330 --- /dev/null +++ b/queue-6.18/cxl-mem-fix-devm_cxl_memdev_edac_release-confusion.patch @@ -0,0 +1,178 @@ +From 266590a79823eebc6f23fc1518c5019e04e551f2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 15 Dec 2025 16:56:11 -0800 +Subject: cxl/mem: Fix devm_cxl_memdev_edac_release() confusion + +From: Dan Williams + +[ Upstream commit 10016118b6fade907143a32a7aeaa777063dc79c ] + +A device release method is only for undoing allocations on the path to +preparing the device for device_add(). In contrast, devm allocations are +post device_add(), are acquired during / after ->probe() and are released +synchronous with ->remove(). + +So, a "devm" helper in a "release" method is a clear anti-pattern. + +Move this devm release action where it belongs, an action created at edac +object creation time. Otherwise, this leaks resources until +cxl_memdev_release() time which may be long after these xarray and error +record caches have gone idle. + +Note, this also fixes up the type of @cxlmd->err_rec_array which needlessly +dropped type-safety. + +Fixes: 0b5ccb0de1e2 ("cxl/edac: Support for finding memory operation attributes from the current boot") +Cc: Dave Jiang +Cc: Jonathan Cameron +Cc: Shiju Jose +Cc: Alison Schofield +Reviewed-by: Alison Schofield +Reviewed-by: Ben Cheatham +Reviewed-by: Dave Jiang +Reviewed-by: Jonathan Cameron +Tested-by: Shiju Jose +Reviewed-by: Shiju Jose +Tested-by: Alejandro Lucero +Link: https://patch.msgid.link/20251216005616.3090129-2-dan.j.williams@intel.com +Signed-off-by: Dan Williams +Signed-off-by: Dave Jiang +Signed-off-by: Sasha Levin +--- + drivers/cxl/core/edac.c | 64 ++++++++++++++++++++++----------------- + drivers/cxl/core/memdev.c | 1 - + drivers/cxl/cxlmem.h | 5 +-- + 3 files changed, 38 insertions(+), 32 deletions(-) + +diff --git a/drivers/cxl/core/edac.c b/drivers/cxl/core/edac.c +index 79994ca9bc9f3..81160260e26b7 100644 +--- a/drivers/cxl/core/edac.c ++++ b/drivers/cxl/core/edac.c +@@ -1988,6 +1988,40 @@ static int cxl_memdev_soft_ppr_init(struct cxl_memdev *cxlmd, + return 0; + } + ++static void err_rec_free(void *_cxlmd) ++{ ++ struct cxl_memdev *cxlmd = _cxlmd; ++ struct cxl_mem_err_rec *array_rec = cxlmd->err_rec_array; ++ struct cxl_event_gen_media *rec_gen_media; ++ struct cxl_event_dram *rec_dram; ++ unsigned long index; ++ ++ cxlmd->err_rec_array = NULL; ++ xa_for_each(&array_rec->rec_dram, index, rec_dram) ++ kfree(rec_dram); ++ xa_destroy(&array_rec->rec_dram); ++ ++ xa_for_each(&array_rec->rec_gen_media, index, rec_gen_media) ++ kfree(rec_gen_media); ++ xa_destroy(&array_rec->rec_gen_media); ++ kfree(array_rec); ++} ++ ++static int devm_cxl_memdev_setup_err_rec(struct cxl_memdev *cxlmd) ++{ ++ struct cxl_mem_err_rec *array_rec = ++ kzalloc(sizeof(*array_rec), GFP_KERNEL); ++ ++ if (!array_rec) ++ return -ENOMEM; ++ ++ xa_init(&array_rec->rec_gen_media); ++ xa_init(&array_rec->rec_dram); ++ cxlmd->err_rec_array = array_rec; ++ ++ return devm_add_action_or_reset(&cxlmd->dev, err_rec_free, cxlmd); ++} ++ + int devm_cxl_memdev_edac_register(struct cxl_memdev *cxlmd) + { + struct edac_dev_feature ras_features[CXL_NR_EDAC_DEV_FEATURES]; +@@ -2038,15 +2072,9 @@ int devm_cxl_memdev_edac_register(struct cxl_memdev *cxlmd) + } + + if (repair_inst) { +- struct cxl_mem_err_rec *array_rec = +- devm_kzalloc(&cxlmd->dev, sizeof(*array_rec), +- GFP_KERNEL); +- if (!array_rec) +- return -ENOMEM; +- +- xa_init(&array_rec->rec_gen_media); +- xa_init(&array_rec->rec_dram); +- cxlmd->err_rec_array = array_rec; ++ rc = devm_cxl_memdev_setup_err_rec(cxlmd); ++ if (rc) ++ return rc; + } + } + +@@ -2088,22 +2116,4 @@ int devm_cxl_region_edac_register(struct cxl_region *cxlr) + } + EXPORT_SYMBOL_NS_GPL(devm_cxl_region_edac_register, "CXL"); + +-void devm_cxl_memdev_edac_release(struct cxl_memdev *cxlmd) +-{ +- struct cxl_mem_err_rec *array_rec = cxlmd->err_rec_array; +- struct cxl_event_gen_media *rec_gen_media; +- struct cxl_event_dram *rec_dram; +- unsigned long index; +- +- if (!IS_ENABLED(CONFIG_CXL_EDAC_MEM_REPAIR) || !array_rec) +- return; +- +- xa_for_each(&array_rec->rec_dram, index, rec_dram) +- kfree(rec_dram); +- xa_destroy(&array_rec->rec_dram); + +- xa_for_each(&array_rec->rec_gen_media, index, rec_gen_media) +- kfree(rec_gen_media); +- xa_destroy(&array_rec->rec_gen_media); +-} +-EXPORT_SYMBOL_NS_GPL(devm_cxl_memdev_edac_release, "CXL"); +diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c +index e370d733e4400..4dff7f44d908e 100644 +--- a/drivers/cxl/core/memdev.c ++++ b/drivers/cxl/core/memdev.c +@@ -27,7 +27,6 @@ static void cxl_memdev_release(struct device *dev) + struct cxl_memdev *cxlmd = to_cxl_memdev(dev); + + ida_free(&cxl_memdev_ida, cxlmd->id); +- devm_cxl_memdev_edac_release(cxlmd); + kfree(cxlmd); + } + +diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h +index 434031a0c1f74..c12ab4fc95123 100644 +--- a/drivers/cxl/cxlmem.h ++++ b/drivers/cxl/cxlmem.h +@@ -63,7 +63,7 @@ struct cxl_memdev { + int depth; + u8 scrub_cycle; + int scrub_region_id; +- void *err_rec_array; ++ struct cxl_mem_err_rec *err_rec_array; + }; + + static inline struct cxl_memdev *to_cxl_memdev(struct device *dev) +@@ -877,7 +877,6 @@ int devm_cxl_memdev_edac_register(struct cxl_memdev *cxlmd); + int devm_cxl_region_edac_register(struct cxl_region *cxlr); + int cxl_store_rec_gen_media(struct cxl_memdev *cxlmd, union cxl_event *evt); + int cxl_store_rec_dram(struct cxl_memdev *cxlmd, union cxl_event *evt); +-void devm_cxl_memdev_edac_release(struct cxl_memdev *cxlmd); + #else + static inline int devm_cxl_memdev_edac_register(struct cxl_memdev *cxlmd) + { return 0; } +@@ -889,8 +888,6 @@ static inline int cxl_store_rec_gen_media(struct cxl_memdev *cxlmd, + static inline int cxl_store_rec_dram(struct cxl_memdev *cxlmd, + union cxl_event *evt) + { return 0; } +-static inline void devm_cxl_memdev_edac_release(struct cxl_memdev *cxlmd) +-{ return; } + #endif + + #ifdef CONFIG_CXL_SUSPEND +-- +2.51.0 + diff --git a/queue-6.18/device_cgroup-remove-branch-hint-after-code-refactor.patch b/queue-6.18/device_cgroup-remove-branch-hint-after-code-refactor.patch new file mode 100644 index 0000000000..336e6d9bf5 --- /dev/null +++ b/queue-6.18/device_cgroup-remove-branch-hint-after-code-refactor.patch @@ -0,0 +1,59 @@ +From 87bba5971a541021789288a8c3d7e1b3bda596a7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 06:06:36 -0800 +Subject: device_cgroup: remove branch hint after code refactor + +From: Breno Leitao + +[ Upstream commit 6784f274722559c0cdaaa418bc8b7b1d61c314f9 ] + +commit 4ef4ac360101 ("device_cgroup: avoid access to ->i_rdev in the +common case in devcgroup_inode_permission()") reordered the checks in +devcgroup_inode_permission() to check the inode mode before checking +i_rdev, for better cache behavior. + +However, the likely() annotation on the i_rdev check was not updated +to reflect the new code flow. Originally, when i_rdev was checked +first, likely(!inode->i_rdev) made sense because most inodes were(?) +regular files/directories, thus i_rdev == 0. + +After the reorder, by the time we reach the i_rdev check, we have +already confirmed the inode IS a block or character device. Block and +character special files are precisely defined by having a device number +(i_rdev), so !inode->i_rdev is now the rare edge case, not the common +case. + +Branch profiling confirmed this is 100% mispredicted: + + correct incorrect % Function File Line + ------- --------- - -------- ---- ---- + 0 2631904 100 devcgroup_inode_permission device_cgroup.h 24 + +Remove likely() to avoid giving the wrong hint to the CPU. + +Fixes: 4ef4ac360101 ("device_cgroup: avoid access to ->i_rdev in the common case in devcgroup_inode_permission()") +Signed-off-by: Breno Leitao +Link: https://patch.msgid.link/20260107-likely_device-v1-1-0c55f83a7e47@debian.org +Reviewed-by: Mateusz Guzik +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + include/linux/device_cgroup.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/linux/device_cgroup.h b/include/linux/device_cgroup.h +index 0864773a57e8f..822085bc2d202 100644 +--- a/include/linux/device_cgroup.h ++++ b/include/linux/device_cgroup.h +@@ -21,7 +21,7 @@ static inline int devcgroup_inode_permission(struct inode *inode, int mask) + if (likely(!S_ISBLK(inode->i_mode) && !S_ISCHR(inode->i_mode))) + return 0; + +- if (likely(!inode->i_rdev)) ++ if (!inode->i_rdev) + return 0; + + if (S_ISBLK(inode->i_mode)) +-- +2.51.0 + diff --git a/queue-6.18/dm-fix-unlocked-test-for-dm_suspended_md.patch b/queue-6.18/dm-fix-unlocked-test-for-dm_suspended_md.patch new file mode 100644 index 0000000000..9f3d970f34 --- /dev/null +++ b/queue-6.18/dm-fix-unlocked-test-for-dm_suspended_md.patch @@ -0,0 +1,56 @@ +From 9ea75b463e182ab62321e28f4969f8ca08f0f575 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 20:55:08 +0100 +Subject: dm: fix unlocked test for dm_suspended_md + +From: Mikulas Patocka + +[ Upstream commit 24c405fdbe215c45e57bba672cc42859038491ee ] + +The function dm_blk_report_zones tests if the device is suspended with +the "dm_suspended_md" call. However, this function is called without +holding any locks, so the device may be suspended just after it. + +Move the call to dm_suspended_md after dm_get_live_table, so that the +device can't be suspended after the suspended state was tested. + +Signed-off-by: Mikulas Patocka +Fixes: 37f53a2c60d0 ("dm: fix dm_blk_report_zones") +Reviewed-by: Benjamin Marzinski +Signed-off-by: Sasha Levin +--- + drivers/md/dm-zone.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/drivers/md/dm-zone.c b/drivers/md/dm-zone.c +index 78e17dd4d01b8..ba39c8313f32b 100644 +--- a/drivers/md/dm-zone.c ++++ b/drivers/md/dm-zone.c +@@ -66,11 +66,13 @@ int dm_blk_report_zones(struct gendisk *disk, sector_t sector, + * Zone revalidation during __bind() is in progress, but this + * call is from a different process + */ +- if (dm_suspended_md(md)) +- return -EAGAIN; +- + map = dm_get_live_table(md, &srcu_idx); + put_table = true; ++ ++ if (dm_suspended_md(md)) { ++ ret = -EAGAIN; ++ goto do_put_table; ++ } + } else { + /* Zone revalidation during __bind() */ + map = zone_revalidate_map; +@@ -80,6 +82,7 @@ int dm_blk_report_zones(struct gendisk *disk, sector_t sector, + ret = dm_blk_do_report_zones(md, map, sector, nr_zones, cb, + data); + ++do_put_table: + if (put_table) + dm_put_live_table(md, srcu_idx); + +-- +2.51.0 + diff --git a/queue-6.18/dm-use-bio_clone_blkg_association.patch b/queue-6.18/dm-use-bio_clone_blkg_association.patch new file mode 100644 index 0000000000..ca40fb1ed1 --- /dev/null +++ b/queue-6.18/dm-use-bio_clone_blkg_association.patch @@ -0,0 +1,44 @@ +From 0f7fe399026f89032e5cf409d960a7c0c655e1f9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 15:36:22 +0100 +Subject: dm: use bio_clone_blkg_association + +From: Mikulas Patocka + +[ Upstream commit 2df8b310bcfe76827fd71092f58a2493ee6590b0 ] + +The origin bio carries blk-cgroup information which could be set from +foreground(task_css(css) - wbc->wb->blkcg_css), so the blkcg won't +control buffer io since commit ca522482e3eaf ("dm: pass NULL bdev to +bio_alloc_clone"). The synchronous io is still under control by blkcg, +because 'bio->bi_blkg' is set by io submitting task which has been added +into 'cgroup.procs'. + +Fix it by using bio_clone_blkg_association when submitting a cloned bio. + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=220985 +Fixes: ca522482e3eaf ("dm: pass NULL bdev to bio_alloc_clone") +Reported-by: Zhihao Cheng +Signed-off-by: Mikulas Patocka +Tested-by: Zhihao Cheng +Signed-off-by: Sasha Levin +--- + drivers/md/dm.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/md/dm.c b/drivers/md/dm.c +index 6c83ab940af75..52f01c44e73a6 100644 +--- a/drivers/md/dm.c ++++ b/drivers/md/dm.c +@@ -1363,6 +1363,8 @@ void dm_submit_bio_remap(struct bio *clone, struct bio *tgt_clone) + if (!tgt_clone) + tgt_clone = clone; + ++ bio_clone_blkg_association(tgt_clone, io->orig_bio); ++ + /* + * Account io->origin_bio to DM dev on behalf of target + * that took ownership of IO with DM_MAPIO_SUBMITTED. +-- +2.51.0 + diff --git a/queue-6.18/dm-use-read_once-in-dm_blk_report_zones.patch b/queue-6.18/dm-use-read_once-in-dm_blk_report_zones.patch new file mode 100644 index 0000000000..c82f9f2b93 --- /dev/null +++ b/queue-6.18/dm-use-read_once-in-dm_blk_report_zones.patch @@ -0,0 +1,36 @@ +From c2c6fda861fa157635f0023abb9dc1aa06910cd5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 20:56:20 +0100 +Subject: dm: use READ_ONCE in dm_blk_report_zones + +From: Mikulas Patocka + +[ Upstream commit e9f5a55b70ae6187ab64ef2d1232ae2738e31d1f ] + +The functon dm_blk_report_zones reads md->zone_revalidate_map, however it +may change while the function is running. Use READ_ONCE. + +Signed-off-by: Mikulas Patocka +Fixes: 37f53a2c60d0 ("dm: fix dm_blk_report_zones") +Reviewed-by: Benjamin Marzinski +Signed-off-by: Sasha Levin +--- + drivers/md/dm-zone.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/md/dm-zone.c b/drivers/md/dm-zone.c +index ba39c8313f32b..f4950b5f766d3 100644 +--- a/drivers/md/dm-zone.c ++++ b/drivers/md/dm-zone.c +@@ -56,7 +56,7 @@ int dm_blk_report_zones(struct gendisk *disk, sector_t sector, + { + struct mapped_device *md = disk->private_data; + struct dm_table *map; +- struct dm_table *zone_revalidate_map = md->zone_revalidate_map; ++ struct dm_table *zone_revalidate_map = READ_ONCE(md->zone_revalidate_map); + int srcu_idx, ret = -EIO; + bool put_table = false; + +-- +2.51.0 + diff --git a/queue-6.18/dma-dma-axi-dmac-fix-hw-scatter-gather-not-looking-a.patch b/queue-6.18/dma-dma-axi-dmac-fix-hw-scatter-gather-not-looking-a.patch new file mode 100644 index 0000000000..add22cdba5 --- /dev/null +++ b/queue-6.18/dma-dma-axi-dmac-fix-hw-scatter-gather-not-looking-a.patch @@ -0,0 +1,51 @@ +From 5fc669d08560bfed3821b75120f6b6bd1735f568 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Nov 2025 16:22:26 +0000 +Subject: dma: dma-axi-dmac: fix HW scatter-gather not looking at the queue +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Nuno Sá + +[ Upstream commit bbcbafb99df41a1d81403eb4f5bb443b38228b57 ] + +For HW scatter gather transfers we still need to look for the queue. The +HW is capable of queueing 3 concurrent transfers and if we try more than +that we'll get the submit queue full and should return. Otherwise, if we +go ahead and program the new transfer, we end up discarding it. + +Fixes: e97dc7435972 ("dmaengine: axi-dmac: Add support for scatter-gather transfers") +Signed-off-by: Nuno Sá +base-commit: 398035178503bf662281bbffb4bebce1460a4bc5 +change-id: 20251104-axi-dmac-fixes-and-improvs-e3ad512a329c +Acked-by: Michael Hennerich +Link: https://patch.msgid.link/20251104-axi-dmac-fixes-and-improvs-v1-2-3e6fd9328f72@analog.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/dma/dma-axi-dmac.c | 8 +++----- + 1 file changed, 3 insertions(+), 5 deletions(-) + +diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c +index e22639822045f..0f25f6d8ae71f 100644 +--- a/drivers/dma/dma-axi-dmac.c ++++ b/drivers/dma/dma-axi-dmac.c +@@ -233,11 +233,9 @@ static void axi_dmac_start_transfer(struct axi_dmac_chan *chan) + unsigned int flags = 0; + unsigned int val; + +- if (!chan->hw_sg) { +- val = axi_dmac_read(dmac, AXI_DMAC_REG_START_TRANSFER); +- if (val) /* Queue is full, wait for the next SOT IRQ */ +- return; +- } ++ val = axi_dmac_read(dmac, AXI_DMAC_REG_START_TRANSFER); ++ if (val) /* Queue is full, wait for the next SOT IRQ */ ++ return; + + desc = chan->next_desc; + +-- +2.51.0 + diff --git a/queue-6.18/dma-dma-axi-dmac-fix-sw-cyclic-transfers.patch b/queue-6.18/dma-dma-axi-dmac-fix-sw-cyclic-transfers.patch new file mode 100644 index 0000000000..b3412ac568 --- /dev/null +++ b/queue-6.18/dma-dma-axi-dmac-fix-sw-cyclic-transfers.patch @@ -0,0 +1,57 @@ +From 3417652eef441a5bde9979cfd8eb35eda65b1c2a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Nov 2025 16:22:25 +0000 +Subject: dma: dma-axi-dmac: fix SW cyclic transfers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Nuno Sá + +[ Upstream commit 9bd257181fd5c996d922e9991500ad27987cfbf4 ] + +If 'hw_cyclic' is false we should still be able to do cyclic transfers in +"software". That was not working for the case where 'desc->num_sgs' is 1 +because 'chan->next_desc' is never set with the current desc which means +that the cyclic transfer only runs once and in the next SOT interrupt we +do nothing since vchan_next_desc() will return NULL. + +Fix it by setting 'chan->next_desc' as soon as we get a new desc via +vchan_next_desc(). + +Fixes: 0e3b67b348b8 ("dmaengine: Add support for the Analog Devices AXI-DMAC DMA controller") +Signed-off-by: Nuno Sá +base-commit: 398035178503bf662281bbffb4bebce1460a4bc5 +change-id: 20251104-axi-dmac-fixes-and-improvs-e3ad512a329c +Acked-by: Michael Hennerich +Link: https://patch.msgid.link/20251104-axi-dmac-fixes-and-improvs-v1-1-3e6fd9328f72@analog.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/dma/dma-axi-dmac.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c +index 5b06b0dc67ee1..e22639822045f 100644 +--- a/drivers/dma/dma-axi-dmac.c ++++ b/drivers/dma/dma-axi-dmac.c +@@ -247,6 +247,7 @@ static void axi_dmac_start_transfer(struct axi_dmac_chan *chan) + return; + list_move_tail(&vdesc->node, &chan->active_descs); + desc = to_axi_dmac_desc(vdesc); ++ chan->next_desc = desc; + } + sg = &desc->sg[desc->num_submitted]; + +@@ -265,8 +266,6 @@ static void axi_dmac_start_transfer(struct axi_dmac_chan *chan) + else + chan->next_desc = NULL; + flags |= AXI_DMAC_FLAG_LAST; +- } else { +- chan->next_desc = desc; + } + + sg->hw->id = axi_dmac_read(dmac, AXI_DMAC_REG_TRANSFER_ID); +-- +2.51.0 + diff --git a/queue-6.18/dmaengine-fsl-edma-don-t-explicitly-disable-clocks-i.patch b/queue-6.18/dmaengine-fsl-edma-don-t-explicitly-disable-clocks-i.patch new file mode 100644 index 0000000000..f07529d43c --- /dev/null +++ b/queue-6.18/dmaengine-fsl-edma-don-t-explicitly-disable-clocks-i.patch @@ -0,0 +1,61 @@ +From 38b65c0dd912934d68ef952887f06573aeb5bbe2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Jan 2026 11:46:50 -0800 +Subject: dmaengine: fsl-edma: don't explicitly disable clocks in .remove() + +From: Jared Kangas + +[ Upstream commit 666c53e94c1d0bf0bdf14c49505ece9ddbe725bc ] + +The clocks in fsl_edma_engine::muxclk are allocated and enabled with +devm_clk_get_enabled(), which automatically cleans these resources up, +but these clocks are also manually disabled in fsl_edma_remove(). This +causes warnings on driver removal for each clock: + + edma_module already disabled + WARNING: CPU: 0 PID: 418 at drivers/clk/clk.c:1200 clk_core_disable+0x198/0x1c8 + [...] + Call trace: + clk_core_disable+0x198/0x1c8 (P) + clk_disable+0x34/0x58 + fsl_edma_remove+0x74/0xe8 [fsl_edma] + [...] + ---[ end trace 0000000000000000 ]--- + edma_module already unprepared + WARNING: CPU: 0 PID: 418 at drivers/clk/clk.c:1059 clk_core_unprepare+0x1f8/0x220 + [...] + Call trace: + clk_core_unprepare+0x1f8/0x220 (P) + clk_unprepare+0x34/0x58 + fsl_edma_remove+0x7c/0xe8 [fsl_edma] + [...] + ---[ end trace 0000000000000000 ]--- + +Fix these warnings by removing the unnecessary fsl_disable_clocks() call +in fsl_edma_remove(). + +Fixes: a9903de3aa16 ("dmaengine: fsl-edma: refactor using devm_clk_get_enabled") +Signed-off-by: Jared Kangas +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260113-fsl-edma-clock-removal-v1-1-2025b49e7bcc@redhat.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/dma/fsl-edma-main.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/dma/fsl-edma-main.c b/drivers/dma/fsl-edma-main.c +index 97583c7d51a2e..093185768ad8e 100644 +--- a/drivers/dma/fsl-edma-main.c ++++ b/drivers/dma/fsl-edma-main.c +@@ -915,7 +915,6 @@ static void fsl_edma_remove(struct platform_device *pdev) + of_dma_controller_free(np); + dma_async_device_unregister(&fsl_edma->dma_dev); + fsl_edma_cleanup_vchan(&fsl_edma->dma_dev); +- fsl_disable_clocks(fsl_edma, fsl_edma->drvdata->dmamuxs); + } + + static int fsl_edma_suspend_late(struct device *dev) +-- +2.51.0 + diff --git a/queue-6.18/dmaengine-mediatek-uart-apdma-fix-above-4g-addressin.patch b/queue-6.18/dmaengine-mediatek-uart-apdma-fix-above-4g-addressin.patch new file mode 100644 index 0000000000..e1daad995b --- /dev/null +++ b/queue-6.18/dmaengine-mediatek-uart-apdma-fix-above-4g-addressin.patch @@ -0,0 +1,83 @@ +From 5b6cad0e54b7b88cd0c71e145ae6f0a032681882 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 13 Nov 2025 13:22:26 +0100 +Subject: dmaengine: mediatek: uart-apdma: Fix above 4G addressing TX/RX + +From: AngeloGioacchino Del Regno + +[ Upstream commit 58ab9d7b6651d21e1cff1777529f2d3dd0b4e851 ] + +The VFF_4G_SUPPORT register is named differently in datasheets, +and its name is "VFF_ADDR2"; was this named correctly from the +beginning it would've been clearer that there was a mistake in +the programming sequence. + +This register is supposed to hold the high bits to support the +DMA addressing above 4G (so, more than 32 bits) and not a bit +to "enable" the support for VFF 4G. + +Fix the name of this register, and also fix its usage by writing +the upper 32 bits of the dma_addr_t on it when the SoC supports +such feature. + +Fixes: 9135408c3ace ("dmaengine: mediatek: Add MediaTek UART APDMA support") +Signed-off-by: AngeloGioacchino Del Regno +Link: https://patch.msgid.link/20251113122229.23998-6-angelogioacchino.delregno@collabora.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/dma/mediatek/mtk-uart-apdma.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/dma/mediatek/mtk-uart-apdma.c b/drivers/dma/mediatek/mtk-uart-apdma.c +index 08e15177427b9..96c18c815f1df 100644 +--- a/drivers/dma/mediatek/mtk-uart-apdma.c ++++ b/drivers/dma/mediatek/mtk-uart-apdma.c +@@ -41,7 +41,7 @@ + #define VFF_STOP_CLR_B 0 + #define VFF_EN_CLR_B 0 + #define VFF_INT_EN_CLR_B 0 +-#define VFF_4G_SUPPORT_CLR_B 0 ++#define VFF_ADDR2_CLR_B 0 + + /* + * interrupt trigger level for tx +@@ -72,7 +72,7 @@ + /* TX: the buffer size SW can write. RX: the buffer size HW can write. */ + #define VFF_LEFT_SIZE 0x40 + #define VFF_DEBUG_STATUS 0x50 +-#define VFF_4G_SUPPORT 0x54 ++#define VFF_ADDR2 0x54 + + struct mtk_uart_apdmadev { + struct dma_device ddev; +@@ -149,7 +149,7 @@ static void mtk_uart_apdma_start_tx(struct mtk_chan *c) + mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_TX_INT_CLR_B); + + if (mtkd->support_33bits) +- mtk_uart_apdma_write(c, VFF_4G_SUPPORT, VFF_4G_EN_B); ++ mtk_uart_apdma_write(c, VFF_ADDR2, upper_32_bits(d->addr)); + } + + mtk_uart_apdma_write(c, VFF_EN, VFF_EN_B); +@@ -192,7 +192,7 @@ static void mtk_uart_apdma_start_rx(struct mtk_chan *c) + mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_RX_INT_CLR_B); + + if (mtkd->support_33bits) +- mtk_uart_apdma_write(c, VFF_4G_SUPPORT, VFF_4G_EN_B); ++ mtk_uart_apdma_write(c, VFF_ADDR2, upper_32_bits(d->addr)); + } + + mtk_uart_apdma_write(c, VFF_INT_EN, VFF_RX_INT_EN_B); +@@ -298,7 +298,7 @@ static int mtk_uart_apdma_alloc_chan_resources(struct dma_chan *chan) + } + + if (mtkd->support_33bits) +- mtk_uart_apdma_write(c, VFF_4G_SUPPORT, VFF_4G_SUPPORT_CLR_B); ++ mtk_uart_apdma_write(c, VFF_ADDR2, VFF_ADDR2_CLR_B); + + err_pm: + pm_runtime_put_noidle(mtkd->ddev.dev); +-- +2.51.0 + diff --git a/queue-6.18/documentation-pci-endpoint-fix-ntb-vntb-copy-paste-e.patch b/queue-6.18/documentation-pci-endpoint-fix-ntb-vntb-copy-paste-e.patch new file mode 100644 index 0000000000..05d6e93d17 --- /dev/null +++ b/queue-6.18/documentation-pci-endpoint-fix-ntb-vntb-copy-paste-e.patch @@ -0,0 +1,82 @@ +From c4ba2c64e167a5f7715a3f85c4c8b9028e6552c7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 3 Nov 2025 09:28:30 +0200 +Subject: Documentation: PCI: endpoint: Fix ntb/vntb copy & paste errors + +From: Baruch Siach + +[ Upstream commit ad0c6da5be901f5c181490f683d22b416059bccb ] + +Fix copy & paste errors by changing the references from 'ntb' to 'vntb'. + +Fixes: 4ac8c8e52cd9 ("Documentation: PCI: Add specification for the PCI vNTB function device") +Signed-off-by: Baruch Siach +[mani: squashed the patches and fixed more errors] +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Reviewed-by: Frank Li +Link: https://patch.msgid.link/b51c2a69ffdbfa2c359f5cf33f3ad2acc3db87e4.1762154911.git.baruch@tkos.co.il +Signed-off-by: Sasha Levin +--- + Documentation/PCI/endpoint/pci-vntb-howto.rst | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/Documentation/PCI/endpoint/pci-vntb-howto.rst b/Documentation/PCI/endpoint/pci-vntb-howto.rst +index 9a7a2f0a68498..3679f5c302549 100644 +--- a/Documentation/PCI/endpoint/pci-vntb-howto.rst ++++ b/Documentation/PCI/endpoint/pci-vntb-howto.rst +@@ -52,14 +52,14 @@ pci-epf-vntb device, the following commands can be used:: + # cd /sys/kernel/config/pci_ep/ + # mkdir functions/pci_epf_vntb/func1 + +-The "mkdir func1" above creates the pci-epf-ntb function device that will ++The "mkdir func1" above creates the pci-epf-vntb function device that will + be probed by pci_epf_vntb driver. + + The PCI endpoint framework populates the directory with the following + configurable fields:: + +- # ls functions/pci_epf_ntb/func1 +- baseclass_code deviceid msi_interrupts pci-epf-ntb.0 ++ # ls functions/pci_epf_vntb/func1 ++ baseclass_code deviceid msi_interrupts pci-epf-vntb.0 + progif_code secondary subsys_id vendorid + cache_line_size interrupt_pin msix_interrupts primary + revid subclass_code subsys_vendor_id +@@ -111,13 +111,13 @@ A sample configuration for virtual NTB driver for virtual PCI bus:: + # echo 0x080A > functions/pci_epf_vntb/func1/pci_epf_vntb.0/vntb_pid + # echo 0x10 > functions/pci_epf_vntb/func1/pci_epf_vntb.0/vbus_number + +-Binding pci-epf-ntb Device to EP Controller ++Binding pci-epf-vntb Device to EP Controller + -------------------------------------------- + + NTB function device should be attached to PCI endpoint controllers + connected to the host. + +- # ln -s controllers/5f010000.pcie_ep functions/pci-epf-ntb/func1/primary ++ # ln -s controllers/5f010000.pcie_ep functions/pci_epf_vntb/func1/primary + + Once the above step is completed, the PCI endpoint controllers are ready to + establish a link with the host. +@@ -139,7 +139,7 @@ lspci Output at Host side + ------------------------- + + Note that the devices listed here correspond to the values populated in +-"Creating pci-epf-ntb Device" section above:: ++"Creating pci-epf-vntb Device" section above:: + + # lspci + 00:00.0 PCI bridge: Freescale Semiconductor Inc Device 0000 (rev 01) +@@ -152,7 +152,7 @@ lspci Output at EP Side / Virtual PCI bus + ----------------------------------------- + + Note that the devices listed here correspond to the values populated in +-"Creating pci-epf-ntb Device" section above:: ++"Creating pci-epf-vntb Device" section above:: + + # lspci + 10:00.0 Unassigned class [ffff]: Dawicontrol Computersysteme GmbH Device 1234 (rev ff) +-- +2.51.0 + diff --git a/queue-6.18/documentation-tracing-add-pci-tracepoint-documentati.patch b/queue-6.18/documentation-tracing-add-pci-tracepoint-documentati.patch new file mode 100644 index 0000000000..c7a730ef60 --- /dev/null +++ b/queue-6.18/documentation-tracing-add-pci-tracepoint-documentati.patch @@ -0,0 +1,125 @@ +From db0571e8d114660cf11bdd19c688688f6cbc9ee7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 10 Dec 2025 21:29:07 +0800 +Subject: Documentation: tracing: Add PCI tracepoint documentation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Shuai Xue + +[ Upstream commit 8236fc613d44e59f6736d6c3e9efffaf26ab7f00 ] + +The PCI tracing system provides tracepoints to monitor critical hardware +events that can impact system performance and reliability. Add +documentation about it. + +Signed-off-by: Shuai Xue +[bhelgaas: squash fixes: +https://lore.kernel.org/r/20260108013956.14351-2-bagasdotme@gmail.com +https://lore.kernel.org/r/20260108013956.14351-3-bagasdotme@gmail.com] +Signed-off-by: Bjorn Helgaas +Reviewed-by: Ilpo Järvinen +Link: https://patch.msgid.link/20251210132907.58799-4-xueshuai@linux.alibaba.com +Signed-off-by: Sasha Levin +--- + Documentation/trace/events-pci.rst | 74 ++++++++++++++++++++++++++++++ + Documentation/trace/index.rst | 1 + + 2 files changed, 75 insertions(+) + create mode 100644 Documentation/trace/events-pci.rst + +diff --git a/Documentation/trace/events-pci.rst b/Documentation/trace/events-pci.rst +new file mode 100644 +index 0000000000000..03ff4ad30ddfa +--- /dev/null ++++ b/Documentation/trace/events-pci.rst +@@ -0,0 +1,74 @@ ++.. SPDX-License-Identifier: GPL-2.0 ++ ++=========================== ++Subsystem Trace Points: PCI ++=========================== ++ ++Overview ++======== ++The PCI tracing system provides tracepoints to monitor critical hardware events ++that can impact system performance and reliability. These events normally show ++up here: ++ ++ /sys/kernel/tracing/events/pci ++ ++Cf. include/trace/events/pci.h for the events definitions. ++ ++Available Tracepoints ++===================== ++ ++pci_hp_event ++------------ ++ ++Monitors PCI hotplug events including card insertion/removal and link ++state changes. ++:: ++ ++ pci_hp_event "%s slot:%s, event:%s\n" ++ ++**Event Types**: ++ ++* ``LINK_UP`` - PCIe link established ++* ``LINK_DOWN`` - PCIe link lost ++* ``CARD_PRESENT`` - Card detected in slot ++* ``CARD_NOT_PRESENT`` - Card removed from slot ++ ++**Example Usage**:: ++ ++ # Enable the tracepoint ++ echo 1 > /sys/kernel/debug/tracing/events/pci/pci_hp_event/enable ++ ++ # Monitor events (the following output is generated when a device is hotplugged) ++ cat /sys/kernel/debug/tracing/trace_pipe ++ irq/51-pciehp-88 [001] ..... 1311.177459: pci_hp_event: 0000:00:02.0 slot:10, event:CARD_PRESENT ++ ++ irq/51-pciehp-88 [001] ..... 1311.177566: pci_hp_event: 0000:00:02.0 slot:10, event:LINK_UP ++ ++pcie_link_event ++--------------- ++ ++Monitors PCIe link speed changes and provides detailed link status information. ++:: ++ ++ pcie_link_event "%s type:%d, reason:%d, cur_bus_speed:%d, max_bus_speed:%d, width:%u, flit_mode:%u, status:%s\n" ++ ++**Parameters**: ++ ++* ``type`` - PCIe device type (4=Root Port, etc.) ++* ``reason`` - Reason for link change: ++ ++ - ``0`` - Link retrain ++ - ``1`` - Bus enumeration ++ - ``2`` - Bandwidth notification enable ++ - ``3`` - Bandwidth notification IRQ ++ - ``4`` - Hotplug event ++ ++ ++**Example Usage**:: ++ ++ # Enable the tracepoint ++ echo 1 > /sys/kernel/debug/tracing/events/pci/pcie_link_event/enable ++ ++ # Monitor events (the following output is generated when a device is hotplugged) ++ cat /sys/kernel/debug/tracing/trace_pipe ++ irq/51-pciehp-88 [001] ..... 381.545386: pcie_link_event: 0000:00:02.0 type:4, reason:4, cur_bus_speed:20, max_bus_speed:23, width:1, flit_mode:0, status:DLLLA +diff --git a/Documentation/trace/index.rst b/Documentation/trace/index.rst +index b4a429dc4f7ad..0a40bfabcf19b 100644 +--- a/Documentation/trace/index.rst ++++ b/Documentation/trace/index.rst +@@ -54,6 +54,7 @@ applications. + events-power + events-nmi + events-msr ++ events-pci + boottime-trace + histogram + histogram-design +-- +2.51.0 + diff --git a/queue-6.18/dpll-add-phase-adjust-gran-pin-attribute.patch b/queue-6.18/dpll-add-phase-adjust-gran-pin-attribute.patch new file mode 100644 index 0000000000..f855bd28f4 --- /dev/null +++ b/queue-6.18/dpll-add-phase-adjust-gran-pin-attribute.patch @@ -0,0 +1,175 @@ +From 71f0afbfc029240446ecdc23e7592b35b7d8b8fb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Oct 2025 16:32:06 +0100 +Subject: dpll: add phase-adjust-gran pin attribute + +From: Ivan Vecera + +[ Upstream commit 30176bf7c871681df506f3165ffe76ec462db991 ] + +Phase-adjust values are currently limited by a min-max range. Some +hardware requires, for certain pin types, that values be multiples of +a specific granularity, as in the zl3073x driver. + +Add a `phase-adjust-gran` pin attribute and an appropriate field in +dpll_pin_properties. If set by the driver, use its value to validate +user-provided phase-adjust values. + +Reviewed-by: Michal Schmidt +Reviewed-by: Petr Oros +Tested-by: Prathosh Satish +Signed-off-by: Ivan Vecera +Reviewed-by: Jiri Pirko +Reviewed-by: Arkadiusz Kubalewski +Link: https://patch.msgid.link/20251029153207.178448-2-ivecera@redhat.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 5d41f95f5d0b ("dpll: zl3073x: Fix output pin phase adjustment sign") +Signed-off-by: Sasha Levin +--- + Documentation/driver-api/dpll.rst | 36 +++++++++++++++------------ + Documentation/netlink/specs/dpll.yaml | 7 ++++++ + drivers/dpll/dpll_netlink.c | 12 ++++++++- + include/linux/dpll.h | 1 + + include/uapi/linux/dpll.h | 1 + + 5 files changed, 40 insertions(+), 17 deletions(-) + +diff --git a/Documentation/driver-api/dpll.rst b/Documentation/driver-api/dpll.rst +index be1fc643b645e..83118c728ed90 100644 +--- a/Documentation/driver-api/dpll.rst ++++ b/Documentation/driver-api/dpll.rst +@@ -198,26 +198,28 @@ be requested with the same attribute with ``DPLL_CMD_DEVICE_SET`` command. + ================================== ====================================== + + Device may also provide ability to adjust a signal phase on a pin. +-If pin phase adjustment is supported, minimal and maximal values that pin +-handle shall be provide to the user on ``DPLL_CMD_PIN_GET`` respond +-with ``DPLL_A_PIN_PHASE_ADJUST_MIN`` and ``DPLL_A_PIN_PHASE_ADJUST_MAX`` ++If pin phase adjustment is supported, minimal and maximal values and ++granularity that pin handle shall be provided to the user on ++``DPLL_CMD_PIN_GET`` respond with ``DPLL_A_PIN_PHASE_ADJUST_MIN``, ++``DPLL_A_PIN_PHASE_ADJUST_MAX`` and ``DPLL_A_PIN_PHASE_ADJUST_GRAN`` + attributes. Configured phase adjust value is provided with + ``DPLL_A_PIN_PHASE_ADJUST`` attribute of a pin, and value change can be + requested with the same attribute with ``DPLL_CMD_PIN_SET`` command. + +- =============================== ====================================== +- ``DPLL_A_PIN_ID`` configured pin id +- ``DPLL_A_PIN_PHASE_ADJUST_MIN`` attr minimum value of phase adjustment +- ``DPLL_A_PIN_PHASE_ADJUST_MAX`` attr maximum value of phase adjustment +- ``DPLL_A_PIN_PHASE_ADJUST`` attr configured value of phase +- adjustment on parent dpll device +- ``DPLL_A_PIN_PARENT_DEVICE`` nested attribute for requesting +- configuration on given parent dpll +- device +- ``DPLL_A_PIN_PARENT_ID`` parent dpll device id +- ``DPLL_A_PIN_PHASE_OFFSET`` attr measured phase difference +- between a pin and parent dpll device +- =============================== ====================================== ++ ================================ ========================================== ++ ``DPLL_A_PIN_ID`` configured pin id ++ ``DPLL_A_PIN_PHASE_ADJUST_GRAN`` attr granularity of phase adjustment value ++ ``DPLL_A_PIN_PHASE_ADJUST_MIN`` attr minimum value of phase adjustment ++ ``DPLL_A_PIN_PHASE_ADJUST_MAX`` attr maximum value of phase adjustment ++ ``DPLL_A_PIN_PHASE_ADJUST`` attr configured value of phase ++ adjustment on parent dpll device ++ ``DPLL_A_PIN_PARENT_DEVICE`` nested attribute for requesting ++ configuration on given parent dpll ++ device ++ ``DPLL_A_PIN_PARENT_ID`` parent dpll device id ++ ``DPLL_A_PIN_PHASE_OFFSET`` attr measured phase difference ++ between a pin and parent dpll device ++ ================================ ========================================== + + All phase related values are provided in pico seconds, which represents + time difference between signals phase. The negative value means that +@@ -384,6 +386,8 @@ according to attribute purpose. + frequencies + ``DPLL_A_PIN_ANY_FREQUENCY_MIN`` attr minimum value of frequency + ``DPLL_A_PIN_ANY_FREQUENCY_MAX`` attr maximum value of frequency ++ ``DPLL_A_PIN_PHASE_ADJUST_GRAN`` attr granularity of phase ++ adjustment value + ``DPLL_A_PIN_PHASE_ADJUST_MIN`` attr minimum value of phase + adjustment + ``DPLL_A_PIN_PHASE_ADJUST_MAX`` attr maximum value of phase +diff --git a/Documentation/netlink/specs/dpll.yaml b/Documentation/netlink/specs/dpll.yaml +index 80728f6f9bc87..78d0724d7e12c 100644 +--- a/Documentation/netlink/specs/dpll.yaml ++++ b/Documentation/netlink/specs/dpll.yaml +@@ -440,6 +440,12 @@ attribute-sets: + doc: | + Capable pin provides list of pins that can be bound to create a + reference-sync pin pair. ++ - ++ name: phase-adjust-gran ++ type: u32 ++ doc: | ++ Granularity of phase adjustment, in picoseconds. The value of ++ phase adjustment must be a multiple of this granularity. + + - + name: pin-parent-device +@@ -616,6 +622,7 @@ operations: + - capabilities + - parent-device + - parent-pin ++ - phase-adjust-gran + - phase-adjust-min + - phase-adjust-max + - phase-adjust +diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c +index a4153bcb6dcfe..64944f601ee5a 100644 +--- a/drivers/dpll/dpll_netlink.c ++++ b/drivers/dpll/dpll_netlink.c +@@ -637,6 +637,10 @@ dpll_cmd_pin_get_one(struct sk_buff *msg, struct dpll_pin *pin, + ret = dpll_msg_add_pin_freq(msg, pin, ref, extack); + if (ret) + return ret; ++ if (prop->phase_gran && ++ nla_put_u32(msg, DPLL_A_PIN_PHASE_ADJUST_GRAN, ++ prop->phase_gran)) ++ return -EMSGSIZE; + if (nla_put_s32(msg, DPLL_A_PIN_PHASE_ADJUST_MIN, + prop->phase_range.min)) + return -EMSGSIZE; +@@ -1261,7 +1265,13 @@ dpll_pin_phase_adj_set(struct dpll_pin *pin, struct nlattr *phase_adj_attr, + if (phase_adj > pin->prop.phase_range.max || + phase_adj < pin->prop.phase_range.min) { + NL_SET_ERR_MSG_ATTR(extack, phase_adj_attr, +- "phase adjust value not supported"); ++ "phase adjust value of out range"); ++ return -EINVAL; ++ } ++ if (pin->prop.phase_gran && phase_adj % (s32)pin->prop.phase_gran) { ++ NL_SET_ERR_MSG_ATTR_FMT(extack, phase_adj_attr, ++ "phase adjust value not multiple of %u", ++ pin->prop.phase_gran); + return -EINVAL; + } + +diff --git a/include/linux/dpll.h b/include/linux/dpll.h +index 25be745bf41f1..562f520b23c27 100644 +--- a/include/linux/dpll.h ++++ b/include/linux/dpll.h +@@ -163,6 +163,7 @@ struct dpll_pin_properties { + u32 freq_supported_num; + struct dpll_pin_frequency *freq_supported; + struct dpll_pin_phase_adjust_range phase_range; ++ u32 phase_gran; + }; + + #if IS_ENABLED(CONFIG_DPLL) +diff --git a/include/uapi/linux/dpll.h b/include/uapi/linux/dpll.h +index ab1725a954d74..69d35570ac4f1 100644 +--- a/include/uapi/linux/dpll.h ++++ b/include/uapi/linux/dpll.h +@@ -251,6 +251,7 @@ enum dpll_a_pin { + DPLL_A_PIN_ESYNC_FREQUENCY_SUPPORTED, + DPLL_A_PIN_ESYNC_PULSE, + DPLL_A_PIN_REFERENCE_SYNC, ++ DPLL_A_PIN_PHASE_ADJUST_GRAN, + + __DPLL_A_PIN_MAX, + DPLL_A_PIN_MAX = (__DPLL_A_PIN_MAX - 1) +-- +2.51.0 + diff --git a/queue-6.18/dpll-zl3073x-cache-all-output-properties-in-zl3073x_.patch b/queue-6.18/dpll-zl3073x-cache-all-output-properties-in-zl3073x_.patch new file mode 100644 index 0000000000..c0b5f6258d --- /dev/null +++ b/queue-6.18/dpll-zl3073x-cache-all-output-properties-in-zl3073x_.patch @@ -0,0 +1,773 @@ +From e89b34d7c3d808aee12cc10ad70fd70474029841 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 13 Nov 2025 08:41:04 +0100 +Subject: dpll: zl3073x: Cache all output properties in zl3073x_out + +From: Ivan Vecera + +[ Upstream commit 5fb9b0d411f81ec46833ea8e43c0263515060c64 ] + +Expand the zl3073x_out structure to cache all output-related +hardware registers, including divisors, widths, embedded-sync +parameters and phase compensation. + +Modify zl3073x_out_state_fetch() to read and populate all these +new fields at once, including zero-divisor checks. Refactor all +dpll "getter" functions in dpll.c to read from this new +cached state instead of performing direct register access. + +Introduce a new function, zl3073x_out_state_set(), to handle +writing changes back to the hardware. This function compares the +provided state with the current cached state and writes *only* the +modified register values via a single mailbox sequence before +updating the local cache. + +Refactor all dpll "setter" functions to modify a local copy of +the output state and then call zl3073x_out_state_set() to +commit the changes. + +This change centralizes all output-related register I/O into +out.c, significantly reduces bus traffic, and simplifies the logic +in dpll.c. + +Reviewed-by: Petr Oros +Tested-by: Prathosh Satish +Signed-off-by: Ivan Vecera +Link: https://patch.msgid.link/20251113074105.141379-6-ivecera@redhat.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 5d41f95f5d0b ("dpll: zl3073x: Fix output pin phase adjustment sign") +Signed-off-by: Sasha Levin +--- + drivers/dpll/zl3073x/dpll.c | 380 +++++++++--------------------------- + drivers/dpll/zl3073x/out.c | 90 +++++++++ + drivers/dpll/zl3073x/out.h | 13 ++ + 3 files changed, 193 insertions(+), 290 deletions(-) + +diff --git a/drivers/dpll/zl3073x/dpll.c b/drivers/dpll/zl3073x/dpll.c +index 62996f26e065f..38551cf788494 100644 +--- a/drivers/dpll/zl3073x/dpll.c ++++ b/drivers/dpll/zl3073x/dpll.c +@@ -953,21 +953,19 @@ zl3073x_dpll_output_pin_esync_get(const struct dpll_pin *dpll_pin, + struct zl3073x_dpll *zldpll = dpll_priv; + struct zl3073x_dev *zldev = zldpll->dev; + struct zl3073x_dpll_pin *pin = pin_priv; +- struct device *dev = zldev->dev; +- u32 esync_period, esync_width; +- u8 clock_type, synth; +- u8 out, output_mode; +- u32 output_div; ++ const struct zl3073x_synth *synth; ++ const struct zl3073x_out *out; ++ u8 clock_type, out_id; + u32 synth_freq; +- int rc; + +- out = zl3073x_output_pin_out_get(pin->id); ++ out_id = zl3073x_output_pin_out_get(pin->id); ++ out = zl3073x_out_state_get(zldev, out_id); + + /* If N-division is enabled, esync is not supported. The register used + * for N-division is also used for the esync divider so both cannot + * be used. + */ +- switch (zl3073x_dev_out_signal_format_get(zldev, out)) { ++ switch (zl3073x_out_signal_format_get(out)) { + case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV: + case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV_INV: + return -EOPNOTSUPP; +@@ -975,38 +973,11 @@ zl3073x_dpll_output_pin_esync_get(const struct dpll_pin *dpll_pin, + break; + } + +- guard(mutex)(&zldev->multiop_lock); +- +- /* Read output configuration into mailbox */ +- rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD, +- ZL_REG_OUTPUT_MB_MASK, BIT(out)); +- if (rc) +- return rc; +- +- /* Read output mode */ +- rc = zl3073x_read_u8(zldev, ZL_REG_OUTPUT_MODE, &output_mode); +- if (rc) +- return rc; +- +- /* Read output divisor */ +- rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_DIV, &output_div); +- if (rc) +- return rc; +- +- /* Check output divisor for zero */ +- if (!output_div) { +- dev_err(dev, "Zero divisor for OUTPUT%u got from device\n", +- out); +- return -EINVAL; +- } +- +- /* Get synth attached to output pin */ +- synth = zl3073x_dev_out_synth_get(zldev, out); +- +- /* Get synth frequency */ +- synth_freq = zl3073x_dev_synth_freq_get(zldev, synth); ++ /* Get attached synth frequency */ ++ synth = zl3073x_synth_state_get(zldev, zl3073x_out_synth_get(out)); ++ synth_freq = zl3073x_synth_freq_get(synth); + +- clock_type = FIELD_GET(ZL_OUTPUT_MODE_CLOCK_TYPE, output_mode); ++ clock_type = FIELD_GET(ZL_OUTPUT_MODE_CLOCK_TYPE, out->mode); + if (clock_type != ZL_OUTPUT_MODE_CLOCK_TYPE_ESYNC) { + /* No need to read esync data if it is not enabled */ + esync->freq = 0; +@@ -1015,38 +986,21 @@ zl3073x_dpll_output_pin_esync_get(const struct dpll_pin *dpll_pin, + goto finish; + } + +- /* Read esync period */ +- rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_ESYNC_PERIOD, &esync_period); +- if (rc) +- return rc; +- +- /* Check esync divisor for zero */ +- if (!esync_period) { +- dev_err(dev, "Zero esync divisor for OUTPUT%u got from device\n", +- out); +- return -EINVAL; +- } +- +- /* Get esync pulse width in units of half synth cycles */ +- rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_ESYNC_WIDTH, &esync_width); +- if (rc) +- return rc; +- + /* Compute esync frequency */ +- esync->freq = synth_freq / output_div / esync_period; ++ esync->freq = synth_freq / out->div / out->esync_n_period; + + /* By comparing the esync_pulse_width to the half of the pulse width + * the esync pulse percentage can be determined. + * Note that half pulse width is in units of half synth cycles, which + * is why it reduces down to be output_div. + */ +- esync->pulse = (50 * esync_width) / output_div; ++ esync->pulse = (50 * out->esync_n_width) / out->div; + + finish: + /* Set supported esync ranges if the pin supports esync control and + * if the output frequency is > 1 Hz. + */ +- if (pin->esync_control && (synth_freq / output_div) > 1) { ++ if (pin->esync_control && (synth_freq / out->div) > 1) { + esync->range = esync_freq_ranges; + esync->range_num = ARRAY_SIZE(esync_freq_ranges); + } else { +@@ -1064,21 +1018,22 @@ zl3073x_dpll_output_pin_esync_set(const struct dpll_pin *dpll_pin, + void *dpll_priv, u64 freq, + struct netlink_ext_ack *extack) + { +- u32 esync_period, esync_width, output_div; + struct zl3073x_dpll *zldpll = dpll_priv; + struct zl3073x_dev *zldev = zldpll->dev; + struct zl3073x_dpll_pin *pin = pin_priv; +- u8 clock_type, out, output_mode, synth; ++ const struct zl3073x_synth *synth; ++ struct zl3073x_out out; ++ u8 clock_type, out_id; + u32 synth_freq; +- int rc; + +- out = zl3073x_output_pin_out_get(pin->id); ++ out_id = zl3073x_output_pin_out_get(pin->id); ++ out = *zl3073x_out_state_get(zldev, out_id); + + /* If N-division is enabled, esync is not supported. The register used + * for N-division is also used for the esync divider so both cannot + * be used. + */ +- switch (zl3073x_dev_out_signal_format_get(zldev, out)) { ++ switch (zl3073x_out_signal_format_get(&out)) { + case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV: + case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV_INV: + return -EOPNOTSUPP; +@@ -1086,19 +1041,6 @@ zl3073x_dpll_output_pin_esync_set(const struct dpll_pin *dpll_pin, + break; + } + +- guard(mutex)(&zldev->multiop_lock); +- +- /* Read output configuration into mailbox */ +- rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD, +- ZL_REG_OUTPUT_MB_MASK, BIT(out)); +- if (rc) +- return rc; +- +- /* Read output mode */ +- rc = zl3073x_read_u8(zldev, ZL_REG_OUTPUT_MODE, &output_mode); +- if (rc) +- return rc; +- + /* Select clock type */ + if (freq) + clock_type = ZL_OUTPUT_MODE_CLOCK_TYPE_ESYNC; +@@ -1106,38 +1048,19 @@ zl3073x_dpll_output_pin_esync_set(const struct dpll_pin *dpll_pin, + clock_type = ZL_OUTPUT_MODE_CLOCK_TYPE_NORMAL; + + /* Update clock type in output mode */ +- output_mode &= ~ZL_OUTPUT_MODE_CLOCK_TYPE; +- output_mode |= FIELD_PREP(ZL_OUTPUT_MODE_CLOCK_TYPE, clock_type); +- rc = zl3073x_write_u8(zldev, ZL_REG_OUTPUT_MODE, output_mode); +- if (rc) +- return rc; ++ out.mode &= ~ZL_OUTPUT_MODE_CLOCK_TYPE; ++ out.mode |= FIELD_PREP(ZL_OUTPUT_MODE_CLOCK_TYPE, clock_type); + + /* If esync is being disabled just write mailbox and finish */ + if (!freq) + goto write_mailbox; + +- /* Get synth attached to output pin */ +- synth = zl3073x_dev_out_synth_get(zldev, out); +- +- /* Get synth frequency */ +- synth_freq = zl3073x_dev_synth_freq_get(zldev, synth); +- +- rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_DIV, &output_div); +- if (rc) +- return rc; +- +- /* Check output divisor for zero */ +- if (!output_div) { +- dev_err(zldev->dev, +- "Zero divisor for OUTPUT%u got from device\n", out); +- return -EINVAL; +- } ++ /* Get attached synth frequency */ ++ synth = zl3073x_synth_state_get(zldev, zl3073x_out_synth_get(&out)); ++ synth_freq = zl3073x_synth_freq_get(synth); + + /* Compute and update esync period */ +- esync_period = synth_freq / (u32)freq / output_div; +- rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_ESYNC_PERIOD, esync_period); +- if (rc) +- return rc; ++ out.esync_n_period = synth_freq / (u32)freq / out.div; + + /* Half of the period in units of 1/2 synth cycle can be represented by + * the output_div. To get the supported esync pulse width of 25% of the +@@ -1145,15 +1068,11 @@ zl3073x_dpll_output_pin_esync_set(const struct dpll_pin *dpll_pin, + * assumes that output_div is even, otherwise some resolution will be + * lost. + */ +- esync_width = output_div / 2; +- rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_ESYNC_WIDTH, esync_width); +- if (rc) +- return rc; ++ out.esync_n_width = out.div / 2; + + write_mailbox: + /* Commit output configuration */ +- return zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_WR, +- ZL_REG_OUTPUT_MB_MASK, BIT(out)); ++ return zl3073x_out_state_set(zldev, out_id, &out); + } + + static int +@@ -1166,83 +1085,46 @@ zl3073x_dpll_output_pin_frequency_get(const struct dpll_pin *dpll_pin, + struct zl3073x_dpll *zldpll = dpll_priv; + struct zl3073x_dev *zldev = zldpll->dev; + struct zl3073x_dpll_pin *pin = pin_priv; +- struct device *dev = zldev->dev; +- u8 out, signal_format, synth; +- u32 output_div, synth_freq; +- int rc; +- +- out = zl3073x_output_pin_out_get(pin->id); +- synth = zl3073x_dev_out_synth_get(zldev, out); +- synth_freq = zl3073x_dev_synth_freq_get(zldev, synth); +- +- guard(mutex)(&zldev->multiop_lock); +- +- /* Read output configuration into mailbox */ +- rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD, +- ZL_REG_OUTPUT_MB_MASK, BIT(out)); +- if (rc) +- return rc; +- +- rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_DIV, &output_div); +- if (rc) +- return rc; ++ const struct zl3073x_synth *synth; ++ const struct zl3073x_out *out; ++ u32 synth_freq; ++ u8 out_id; + +- /* Check output divisor for zero */ +- if (!output_div) { +- dev_err(dev, "Zero divisor for output %u got from device\n", +- out); +- return -EINVAL; +- } ++ out_id = zl3073x_output_pin_out_get(pin->id); ++ out = zl3073x_out_state_get(zldev, out_id); + +- /* Read used signal format for the given output */ +- signal_format = zl3073x_dev_out_signal_format_get(zldev, out); ++ /* Get attached synth frequency */ ++ synth = zl3073x_synth_state_get(zldev, zl3073x_out_synth_get(out)); ++ synth_freq = zl3073x_synth_freq_get(synth); + +- switch (signal_format) { ++ switch (zl3073x_out_signal_format_get(out)) { + case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV: + case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV_INV: + /* In case of divided format we have to distiguish between + * given output pin type. ++ * ++ * For P-pin the resulting frequency is computed as simple ++ * division of synth frequency and output divisor. ++ * ++ * For N-pin we have to divide additionally by divisor stored ++ * in esync_n_period output mailbox register that is used as ++ * N-pin divisor for these modes. + */ +- if (zl3073x_dpll_is_p_pin(pin)) { +- /* For P-pin the resulting frequency is computed as +- * simple division of synth frequency and output +- * divisor. +- */ +- *frequency = synth_freq / output_div; +- } else { +- /* For N-pin we have to divide additionally by +- * divisor stored in esync_period output mailbox +- * register that is used as N-pin divisor for these +- * modes. +- */ +- u32 ndiv; +- +- rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_ESYNC_PERIOD, +- &ndiv); +- if (rc) +- return rc; ++ *frequency = synth_freq / out->div; + +- /* Check N-pin divisor for zero */ +- if (!ndiv) { +- dev_err(dev, +- "Zero N-pin divisor for output %u got from device\n", +- out); +- return -EINVAL; +- } ++ if (!zl3073x_dpll_is_p_pin(pin)) ++ *frequency = (u32)*frequency / out->esync_n_period; + +- /* Compute final divisor for N-pin */ +- *frequency = synth_freq / output_div / ndiv; +- } + break; + default: + /* In other modes the resulting frequency is computed as + * division of synth frequency and output divisor. + */ +- *frequency = synth_freq / output_div; ++ *frequency = synth_freq / out->div; + break; + } + +- return rc; ++ return 0; + } + + static int +@@ -1255,28 +1137,21 @@ zl3073x_dpll_output_pin_frequency_set(const struct dpll_pin *dpll_pin, + struct zl3073x_dpll *zldpll = dpll_priv; + struct zl3073x_dev *zldev = zldpll->dev; + struct zl3073x_dpll_pin *pin = pin_priv; +- struct device *dev = zldev->dev; +- u32 output_n_freq, output_p_freq; +- u8 out, signal_format, synth; +- u32 cur_div, new_div, ndiv; +- u32 synth_freq; +- int rc; ++ const struct zl3073x_synth *synth; ++ u8 out_id, signal_format; ++ u32 new_div, synth_freq; ++ struct zl3073x_out out; + +- out = zl3073x_output_pin_out_get(pin->id); +- synth = zl3073x_dev_out_synth_get(zldev, out); +- synth_freq = zl3073x_dev_synth_freq_get(zldev, synth); ++ out_id = zl3073x_output_pin_out_get(pin->id); ++ out = *zl3073x_out_state_get(zldev, out_id); ++ ++ /* Get attached synth frequency and compute new divisor */ ++ synth = zl3073x_synth_state_get(zldev, zl3073x_out_synth_get(&out)); ++ synth_freq = zl3073x_synth_freq_get(synth); + new_div = synth_freq / (u32)frequency; + + /* Get used signal format for the given output */ +- signal_format = zl3073x_dev_out_signal_format_get(zldev, out); +- +- guard(mutex)(&zldev->multiop_lock); +- +- /* Load output configuration */ +- rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD, +- ZL_REG_OUTPUT_MB_MASK, BIT(out)); +- if (rc) +- return rc; ++ signal_format = zl3073x_out_signal_format_get(&out); + + /* Check signal format */ + if (signal_format != ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV && +@@ -1284,99 +1159,50 @@ zl3073x_dpll_output_pin_frequency_set(const struct dpll_pin *dpll_pin, + /* For non N-divided signal formats the frequency is computed + * as division of synth frequency and output divisor. + */ +- rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_DIV, new_div); +- if (rc) +- return rc; ++ out.div = new_div; + + /* For 50/50 duty cycle the divisor is equal to width */ +- rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_WIDTH, new_div); +- if (rc) +- return rc; ++ out.width = new_div; + + /* Commit output configuration */ +- return zl3073x_mb_op(zldev, +- ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_WR, +- ZL_REG_OUTPUT_MB_MASK, BIT(out)); ++ return zl3073x_out_state_set(zldev, out_id, &out); + } + +- /* For N-divided signal format get current divisor */ +- rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_DIV, &cur_div); +- if (rc) +- return rc; +- +- /* Check output divisor for zero */ +- if (!cur_div) { +- dev_err(dev, "Zero divisor for output %u got from device\n", +- out); +- return -EINVAL; +- } +- +- /* Get N-pin divisor (shares the same register with esync */ +- rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_ESYNC_PERIOD, &ndiv); +- if (rc) +- return rc; +- +- /* Check N-pin divisor for zero */ +- if (!ndiv) { +- dev_err(dev, +- "Zero N-pin divisor for output %u got from device\n", +- out); +- return -EINVAL; +- } +- +- /* Compute current output frequency for P-pin */ +- output_p_freq = synth_freq / cur_div; +- +- /* Compute current N-pin frequency */ +- output_n_freq = output_p_freq / ndiv; +- + if (zl3073x_dpll_is_p_pin(pin)) { + /* We are going to change output frequency for P-pin but + * if the requested frequency is less than current N-pin + * frequency then indicate a failure as we are not able + * to compute N-pin divisor to keep its frequency unchanged. ++ * ++ * Update divisor for N-pin to keep N-pin frequency. + */ +- if (frequency <= output_n_freq) ++ out.esync_n_period = (out.esync_n_period * out.div) / new_div; ++ if (!out.esync_n_period) + return -EINVAL; + + /* Update the output divisor */ +- rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_DIV, new_div); +- if (rc) +- return rc; ++ out.div = new_div; + + /* For 50/50 duty cycle the divisor is equal to width */ +- rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_WIDTH, new_div); +- if (rc) +- return rc; +- +- /* Compute new divisor for N-pin */ +- ndiv = (u32)frequency / output_n_freq; ++ out.width = out.div; + } else { + /* We are going to change frequency of N-pin but if + * the requested freq is greater or equal than freq of P-pin + * in the output pair we cannot compute divisor for the N-pin. + * In this case indicate a failure. ++ * ++ * Update divisor for N-pin + */ +- if (output_p_freq <= frequency) ++ out.esync_n_period = div64_u64(synth_freq, frequency * out.div); ++ if (!out.esync_n_period) + return -EINVAL; +- +- /* Compute new divisor for N-pin */ +- ndiv = output_p_freq / (u32)frequency; + } + +- /* Update divisor for the N-pin */ +- rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_ESYNC_PERIOD, ndiv); +- if (rc) +- return rc; +- + /* For 50/50 duty cycle the divisor is equal to width */ +- rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_ESYNC_WIDTH, ndiv); +- if (rc) +- return rc; ++ out.esync_n_width = out.esync_n_period; + + /* Commit output configuration */ +- return zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_WR, +- ZL_REG_OUTPUT_MB_MASK, BIT(out)); ++ return zl3073x_out_state_set(zldev, out_id, &out); + } + + static int +@@ -1390,30 +1216,18 @@ zl3073x_dpll_output_pin_phase_adjust_get(const struct dpll_pin *dpll_pin, + struct zl3073x_dpll *zldpll = dpll_priv; + struct zl3073x_dev *zldev = zldpll->dev; + struct zl3073x_dpll_pin *pin = pin_priv; +- s32 phase_comp; +- u8 out; +- int rc; +- +- guard(mutex)(&zldev->multiop_lock); +- +- /* Read output configuration */ +- out = zl3073x_output_pin_out_get(pin->id); +- rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD, +- ZL_REG_OUTPUT_MB_MASK, BIT(out)); +- if (rc) +- return rc; ++ const struct zl3073x_out *out; ++ u8 out_id; + +- /* Read current output phase compensation */ +- rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_PHASE_COMP, &phase_comp); +- if (rc) +- return rc; ++ out_id = zl3073x_output_pin_out_get(pin->id); ++ out = zl3073x_out_state_get(zldev, out_id); + + /* Convert value to ps and reverse two's complement negation applied + * during 'set' + */ +- *phase_adjust = -phase_comp * pin->phase_gran; ++ *phase_adjust = -out->phase_comp * pin->phase_gran; + +- return rc; ++ return 0; + } + + static int +@@ -1427,31 +1241,19 @@ zl3073x_dpll_output_pin_phase_adjust_set(const struct dpll_pin *dpll_pin, + struct zl3073x_dpll *zldpll = dpll_priv; + struct zl3073x_dev *zldev = zldpll->dev; + struct zl3073x_dpll_pin *pin = pin_priv; +- u8 out; +- int rc; ++ struct zl3073x_out out; ++ u8 out_id; ++ ++ out_id = zl3073x_output_pin_out_get(pin->id); ++ out = *zl3073x_out_state_get(zldev, out_id); + + /* The value in the register is stored as two's complement negation + * of requested value and expressed in half synth clock cycles. + */ +- phase_adjust = -phase_adjust / pin->phase_gran; +- +- guard(mutex)(&zldev->multiop_lock); +- +- /* Read output configuration */ +- out = zl3073x_output_pin_out_get(pin->id); +- rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD, +- ZL_REG_OUTPUT_MB_MASK, BIT(out)); +- if (rc) +- return rc; +- +- /* Write the requested value into the compensation register */ +- rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_PHASE_COMP, phase_adjust); +- if (rc) +- return rc; ++ out.phase_comp = -phase_adjust / pin->phase_gran; + + /* Update output configuration from mailbox */ +- return zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_WR, +- ZL_REG_OUTPUT_MB_MASK, BIT(out)); ++ return zl3073x_out_state_set(zldev, out_id, &out); + } + + static int +@@ -1862,17 +1664,15 @@ zl3073x_dpll_pin_is_registrable(struct zl3073x_dpll *zldpll, + /* Output P&N pair shares single HW output */ + u8 out = zl3073x_output_pin_out_get(index); + +- name = "OUT"; +- + /* Skip the pin if it is connected to different DPLL channel */ + if (zl3073x_dev_out_dpll_get(zldev, out) != zldpll->id) { + dev_dbg(zldev->dev, +- "%s%u is driven by different DPLL\n", name, +- out); ++ "OUT%u is driven by different DPLL\n", out); + + return false; + } + ++ name = "OUT"; + is_diff = zl3073x_dev_out_is_diff(zldev, out); + is_enabled = zl3073x_dev_output_pin_is_enabled(zldev, index); + } +diff --git a/drivers/dpll/zl3073x/out.c b/drivers/dpll/zl3073x/out.c +index a48f6917b39fb..86829a0c1c022 100644 +--- a/drivers/dpll/zl3073x/out.c ++++ b/drivers/dpll/zl3073x/out.c +@@ -50,6 +50,46 @@ int zl3073x_out_state_fetch(struct zl3073x_dev *zldev, u8 index) + dev_dbg(zldev->dev, "OUT%u has signal format 0x%02x\n", index, + zl3073x_out_signal_format_get(out)); + ++ /* Read output divisor */ ++ rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_DIV, &out->div); ++ if (rc) ++ return rc; ++ ++ if (!out->div) { ++ dev_err(zldev->dev, "Zero divisor for OUT%u got from device\n", ++ index); ++ return -EINVAL; ++ } ++ ++ dev_dbg(zldev->dev, "OUT%u divisor: %u\n", index, out->div); ++ ++ /* Read output width */ ++ rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_WIDTH, &out->width); ++ if (rc) ++ return rc; ++ ++ rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_ESYNC_PERIOD, ++ &out->esync_n_period); ++ if (rc) ++ return rc; ++ ++ if (!out->esync_n_period) { ++ dev_err(zldev->dev, ++ "Zero esync divisor for OUT%u got from device\n", ++ index); ++ return -EINVAL; ++ } ++ ++ rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_ESYNC_WIDTH, ++ &out->esync_n_width); ++ if (rc) ++ return rc; ++ ++ rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_PHASE_COMP, ++ &out->phase_comp); ++ if (rc) ++ return rc; ++ + return rc; + } + +@@ -65,3 +105,53 @@ const struct zl3073x_out *zl3073x_out_state_get(struct zl3073x_dev *zldev, + { + return &zldev->out[index]; + } ++ ++int zl3073x_out_state_set(struct zl3073x_dev *zldev, u8 index, ++ const struct zl3073x_out *out) ++{ ++ struct zl3073x_out *dout = &zldev->out[index]; ++ int rc; ++ ++ guard(mutex)(&zldev->multiop_lock); ++ ++ /* Read output configuration into mailbox */ ++ rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD, ++ ZL_REG_OUTPUT_MB_MASK, BIT(index)); ++ if (rc) ++ return rc; ++ ++ /* Update mailbox with changed values */ ++ if (dout->div != out->div) ++ rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_DIV, out->div); ++ if (!rc && dout->width != out->width) ++ rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_WIDTH, out->width); ++ if (!rc && dout->esync_n_period != out->esync_n_period) ++ rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_ESYNC_PERIOD, ++ out->esync_n_period); ++ if (!rc && dout->esync_n_width != out->esync_n_width) ++ rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_ESYNC_WIDTH, ++ out->esync_n_width); ++ if (!rc && dout->mode != out->mode) ++ rc = zl3073x_write_u8(zldev, ZL_REG_OUTPUT_MODE, out->mode); ++ if (!rc && dout->phase_comp != out->phase_comp) ++ rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_PHASE_COMP, ++ out->phase_comp); ++ if (rc) ++ return rc; ++ ++ /* Commit output configuration */ ++ rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_WR, ++ ZL_REG_OUTPUT_MB_MASK, BIT(index)); ++ if (rc) ++ return rc; ++ ++ /* After successful commit store new state */ ++ dout->div = out->div; ++ dout->width = out->width; ++ dout->esync_n_period = out->esync_n_period; ++ dout->esync_n_width = out->esync_n_width; ++ dout->mode = out->mode; ++ dout->phase_comp = out->phase_comp; ++ ++ return 0; ++} +diff --git a/drivers/dpll/zl3073x/out.h b/drivers/dpll/zl3073x/out.h +index 986aa046221da..e8ea7a0e0f071 100644 +--- a/drivers/dpll/zl3073x/out.h ++++ b/drivers/dpll/zl3073x/out.h +@@ -12,10 +12,20 @@ struct zl3073x_dev; + + /** + * struct zl3073x_out - output state ++ * @div: output divisor ++ * @width: output pulse width ++ * @esync_n_period: embedded sync or n-pin period (for n-div formats) ++ * @esync_n_width: embedded sync or n-pin pulse width ++ * @phase_comp: phase compensation + * @ctrl: output control + * @mode: output mode + */ + struct zl3073x_out { ++ u32 div; ++ u32 width; ++ u32 esync_n_period; ++ u32 esync_n_width; ++ s32 phase_comp; + u8 ctrl; + u8 mode; + }; +@@ -24,6 +34,9 @@ int zl3073x_out_state_fetch(struct zl3073x_dev *zldev, u8 index); + const struct zl3073x_out *zl3073x_out_state_get(struct zl3073x_dev *zldev, + u8 index); + ++int zl3073x_out_state_set(struct zl3073x_dev *zldev, u8 index, ++ const struct zl3073x_out *out); ++ + /** + * zl3073x_out_signal_format_get - get output signal format + * @out: pointer to out state +-- +2.51.0 + diff --git a/queue-6.18/dpll-zl3073x-fix-output-pin-phase-adjustment-sign.patch b/queue-6.18/dpll-zl3073x-fix-output-pin-phase-adjustment-sign.patch new file mode 100644 index 0000000000..93443549ac --- /dev/null +++ b/queue-6.18/dpll-zl3073x-fix-output-pin-phase-adjustment-sign.patch @@ -0,0 +1,67 @@ +From c884e6285d36ac98c2025dce78f8bfbaad3356dd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 19:10:55 +0100 +Subject: dpll: zl3073x: Fix output pin phase adjustment sign + +From: Ivan Vecera + +[ Upstream commit 5d41f95f5d0bd9db02f3f16a649d0631f71e9fdb ] + +The output pin phase adjustment functions incorrectly negate the phase +compensation value. + +Per the ZL3073x datasheet, the output phase compensation register is +simply a signed two's complement integer where: + - Positive values move the phase later in time + - Negative values move the phase earlier in time + +No negation is required. The erroneous negation caused phase adjustments +to be applied in the wrong direction. + +Note that input pin phase adjustment correctly uses negation because the +hardware has an inverted convention for input references (positive moves +phase earlier, negative moves phase later). + +Fixes: 6287262f761e ("dpll: zl3073x: Add support to adjust phase") +Signed-off-by: Ivan Vecera +Reviewed-by: Vadim Fedorenko +Link: https://patch.msgid.link/20260205181055.129768-1-ivecera@redhat.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/dpll/zl3073x/dpll.c | 12 ++++-------- + 1 file changed, 4 insertions(+), 8 deletions(-) + +diff --git a/drivers/dpll/zl3073x/dpll.c b/drivers/dpll/zl3073x/dpll.c +index 38551cf788494..11ca32e1bb829 100644 +--- a/drivers/dpll/zl3073x/dpll.c ++++ b/drivers/dpll/zl3073x/dpll.c +@@ -1222,10 +1222,8 @@ zl3073x_dpll_output_pin_phase_adjust_get(const struct dpll_pin *dpll_pin, + out_id = zl3073x_output_pin_out_get(pin->id); + out = zl3073x_out_state_get(zldev, out_id); + +- /* Convert value to ps and reverse two's complement negation applied +- * during 'set' +- */ +- *phase_adjust = -out->phase_comp * pin->phase_gran; ++ /* The value in the register is expressed in half synth clock cycles. */ ++ *phase_adjust = out->phase_comp * pin->phase_gran; + + return 0; + } +@@ -1247,10 +1245,8 @@ zl3073x_dpll_output_pin_phase_adjust_set(const struct dpll_pin *dpll_pin, + out_id = zl3073x_output_pin_out_get(pin->id); + out = *zl3073x_out_state_get(zldev, out_id); + +- /* The value in the register is stored as two's complement negation +- * of requested value and expressed in half synth clock cycles. +- */ +- out.phase_comp = -phase_adjust / pin->phase_gran; ++ /* The value in the register is expressed in half synth clock cycles. */ ++ out.phase_comp = phase_adjust / pin->phase_gran; + + /* Update output configuration from mailbox */ + return zl3073x_out_state_set(zldev, out_id, &out); +-- +2.51.0 + diff --git a/queue-6.18/dpll-zl3073x-specify-phase-adjustment-granularity-fo.patch b/queue-6.18/dpll-zl3073x-specify-phase-adjustment-granularity-fo.patch new file mode 100644 index 0000000000..ab05ed0deb --- /dev/null +++ b/queue-6.18/dpll-zl3073x-specify-phase-adjustment-granularity-fo.patch @@ -0,0 +1,173 @@ +From 1a9eece941493dc8dd9a1a24233141b6371a6dde Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Oct 2025 16:32:07 +0100 +Subject: dpll: zl3073x: Specify phase adjustment granularity for pins + +From: Ivan Vecera + +[ Upstream commit 055a01b29fd643e33b9b1e88e24bbe1afe6fc6d9 ] + +Output pins phase adjustment values in the device are expressed +in half synth clock cycles. Use this number of cycles as output +pins' phase adjust granularity and simplify both get/set callbacks. + +Reviewed-by: Michal Schmidt +Reviewed-by: Petr Oros +Tested-by: Prathosh Satish +Signed-off-by: Ivan Vecera +Reviewed-by: Arkadiusz Kubalewski +Link: https://patch.msgid.link/20251029153207.178448-3-ivecera@redhat.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 5d41f95f5d0b ("dpll: zl3073x: Fix output pin phase adjustment sign") +Signed-off-by: Sasha Levin +--- + drivers/dpll/zl3073x/dpll.c | 58 +++++++++---------------------------- + drivers/dpll/zl3073x/prop.c | 11 +++++++ + 2 files changed, 25 insertions(+), 44 deletions(-) + +diff --git a/drivers/dpll/zl3073x/dpll.c b/drivers/dpll/zl3073x/dpll.c +index f93f9a4583243..d90150671d374 100644 +--- a/drivers/dpll/zl3073x/dpll.c ++++ b/drivers/dpll/zl3073x/dpll.c +@@ -35,6 +35,7 @@ + * @prio: pin priority <0, 14> + * @selectable: pin is selectable in automatic mode + * @esync_control: embedded sync is controllable ++ * @phase_gran: phase adjustment granularity + * @pin_state: last saved pin state + * @phase_offset: last saved pin phase offset + * @freq_offset: last saved fractional frequency offset +@@ -49,6 +50,7 @@ struct zl3073x_dpll_pin { + u8 prio; + bool selectable; + bool esync_control; ++ s32 phase_gran; + enum dpll_pin_state pin_state; + s64 phase_offset; + s64 freq_offset; +@@ -1388,25 +1390,14 @@ zl3073x_dpll_output_pin_phase_adjust_get(const struct dpll_pin *dpll_pin, + struct zl3073x_dpll *zldpll = dpll_priv; + struct zl3073x_dev *zldev = zldpll->dev; + struct zl3073x_dpll_pin *pin = pin_priv; +- u32 synth_freq; + s32 phase_comp; +- u8 out, synth; ++ u8 out; + int rc; + +- out = zl3073x_output_pin_out_get(pin->id); +- synth = zl3073x_out_synth_get(zldev, out); +- synth_freq = zl3073x_synth_freq_get(zldev, synth); +- +- /* Check synth freq for zero */ +- if (!synth_freq) { +- dev_err(zldev->dev, "Got zero synth frequency for output %u\n", +- out); +- return -EINVAL; +- } +- + guard(mutex)(&zldev->multiop_lock); + + /* Read output configuration */ ++ out = zl3073x_output_pin_out_get(pin->id); + rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD, + ZL_REG_OUTPUT_MB_MASK, BIT(out)); + if (rc) +@@ -1417,11 +1408,10 @@ zl3073x_dpll_output_pin_phase_adjust_get(const struct dpll_pin *dpll_pin, + if (rc) + return rc; + +- /* Value in register is expressed in half synth clock cycles */ +- phase_comp *= (int)div_u64(PSEC_PER_SEC, 2 * synth_freq); +- +- /* Reverse two's complement negation applied during 'set' */ +- *phase_adjust = -phase_comp; ++ /* Convert value to ps and reverse two's complement negation applied ++ * during 'set' ++ */ ++ *phase_adjust = -phase_comp * pin->phase_gran; + + return rc; + } +@@ -1437,39 +1427,18 @@ zl3073x_dpll_output_pin_phase_adjust_set(const struct dpll_pin *dpll_pin, + struct zl3073x_dpll *zldpll = dpll_priv; + struct zl3073x_dev *zldev = zldpll->dev; + struct zl3073x_dpll_pin *pin = pin_priv; +- int half_synth_cycle; +- u32 synth_freq; +- u8 out, synth; ++ u8 out; + int rc; + +- /* Get attached synth */ +- out = zl3073x_output_pin_out_get(pin->id); +- synth = zl3073x_out_synth_get(zldev, out); +- +- /* Get synth's frequency */ +- synth_freq = zl3073x_synth_freq_get(zldev, synth); +- +- /* Value in register is expressed in half synth clock cycles so +- * the given phase adjustment a multiple of half synth clock. +- */ +- half_synth_cycle = (int)div_u64(PSEC_PER_SEC, 2 * synth_freq); +- +- if ((phase_adjust % half_synth_cycle) != 0) { +- NL_SET_ERR_MSG_FMT(extack, +- "Phase adjustment value has to be multiple of %d", +- half_synth_cycle); +- return -EINVAL; +- } +- phase_adjust /= half_synth_cycle; +- + /* The value in the register is stored as two's complement negation +- * of requested value. ++ * of requested value and expressed in half synth clock cycles. + */ +- phase_adjust = -phase_adjust; ++ phase_adjust = -phase_adjust / pin->phase_gran; + + guard(mutex)(&zldev->multiop_lock); + + /* Read output configuration */ ++ out = zl3073x_output_pin_out_get(pin->id); + rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD, + ZL_REG_OUTPUT_MB_MASK, BIT(out)); + if (rc) +@@ -1758,9 +1727,10 @@ zl3073x_dpll_pin_register(struct zl3073x_dpll_pin *pin, u32 index) + if (IS_ERR(props)) + return PTR_ERR(props); + +- /* Save package label & esync capability */ ++ /* Save package label, esync capability and phase adjust granularity */ + strscpy(pin->label, props->package_label); + pin->esync_control = props->esync_control; ++ pin->phase_gran = props->dpll_props.phase_gran; + + if (zl3073x_dpll_is_input_pin(pin)) { + rc = zl3073x_dpll_ref_prio_get(pin, &pin->prio); +diff --git a/drivers/dpll/zl3073x/prop.c b/drivers/dpll/zl3073x/prop.c +index 4cf7e8aefcb37..9e1fca5cdaf1e 100644 +--- a/drivers/dpll/zl3073x/prop.c ++++ b/drivers/dpll/zl3073x/prop.c +@@ -208,7 +208,18 @@ struct zl3073x_pin_props *zl3073x_pin_props_get(struct zl3073x_dev *zldev, + DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE | + DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE; + } else { ++ u8 out, synth; ++ u32 f; ++ + props->dpll_props.type = DPLL_PIN_TYPE_GNSS; ++ ++ /* The output pin phase adjustment granularity equals half of ++ * the synth frequency count. ++ */ ++ out = zl3073x_output_pin_out_get(index); ++ synth = zl3073x_out_synth_get(zldev, out); ++ f = 2 * zl3073x_synth_freq_get(zldev, synth); ++ props->dpll_props.phase_gran = f ? div_u64(PSEC_PER_SEC, f) : 1; + } + + props->dpll_props.phase_range.min = S32_MIN; +-- +2.51.0 + diff --git a/queue-6.18/dpll-zl3073x-split-ref-out-and-synth-logic-from-core.patch b/queue-6.18/dpll-zl3073x-split-ref-out-and-synth-logic-from-core.patch new file mode 100644 index 0000000000..7073a045b0 --- /dev/null +++ b/queue-6.18/dpll-zl3073x-split-ref-out-and-synth-logic-from-core.patch @@ -0,0 +1,1314 @@ +From 14cefa5d6ad8299a6b6c002739299799b6cef93f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 13 Nov 2025 08:41:01 +0100 +Subject: dpll: zl3073x: Split ref, out, and synth logic from core + +From: Ivan Vecera + +[ Upstream commit 607f2c00c61faa3b437dbb0d38287e7a9d398a52 ] + +Refactor the zl3073x driver by splitting the logic for input +references, outputs and synthesizers out of the monolithic +core.[ch] files. + +Move the logic for each functional block into its own dedicated files: +ref.[ch], out.[ch] and synth.[ch]. + +Specifically: +- Move state structures (zl3073x_ref, zl3073x_out, zl3073x_synth) + from core.h into their respective new headers +- Move state-fetching functions (..._state_fetch) from core.c to their + new .c files +- Move the zl3073x_ref_freq_factorize helper from core.c to ref.c +- Introduce a new helper layer to decouple the core device logic from + the state-parsing logic: + 1. Move the original inline helpers (e.g., zl3073x_ref_is_enabled) + to the new headers (ref.h, etc.) and make them operate on a + const struct ... * pointer. + 2. Create new zl3073x_dev_... prefixed functions in core.h + (e.g., zl3073x_dev_ref_is_enabled) and Implement these _dev_ functions + to fetch state using a new ..._state_get() helper and then call + the non-prefixed helper. + 3. Update all driver-internal callers (in dpll.c, prop.c, etc.) to use + the new zl3073x_dev_... functions. + +Reviewed-by: Petr Oros +Tested-by: Prathosh Satish +Signed-off-by: Ivan Vecera +Link: https://patch.msgid.link/20251113074105.141379-3-ivecera@redhat.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 5d41f95f5d0b ("dpll: zl3073x: Fix output pin phase adjustment sign") +Signed-off-by: Sasha Levin +--- + drivers/dpll/zl3073x/Makefile | 3 +- + drivers/dpll/zl3073x/core.c | 194 ---------------------------------- + drivers/dpll/zl3073x/core.h | 170 +++++++++++++---------------- + drivers/dpll/zl3073x/dpll.c | 36 +++---- + drivers/dpll/zl3073x/out.c | 67 ++++++++++++ + drivers/dpll/zl3073x/out.h | 80 ++++++++++++++ + drivers/dpll/zl3073x/prop.c | 12 +-- + drivers/dpll/zl3073x/ref.c | 112 ++++++++++++++++++++ + drivers/dpll/zl3073x/ref.h | 66 ++++++++++++ + drivers/dpll/zl3073x/synth.c | 87 +++++++++++++++ + drivers/dpll/zl3073x/synth.h | 72 +++++++++++++ + 11 files changed, 584 insertions(+), 315 deletions(-) + create mode 100644 drivers/dpll/zl3073x/out.c + create mode 100644 drivers/dpll/zl3073x/out.h + create mode 100644 drivers/dpll/zl3073x/ref.c + create mode 100644 drivers/dpll/zl3073x/ref.h + create mode 100644 drivers/dpll/zl3073x/synth.c + create mode 100644 drivers/dpll/zl3073x/synth.h + +diff --git a/drivers/dpll/zl3073x/Makefile b/drivers/dpll/zl3073x/Makefile +index 84e22aae57e5f..bd324c7fe7101 100644 +--- a/drivers/dpll/zl3073x/Makefile ++++ b/drivers/dpll/zl3073x/Makefile +@@ -1,7 +1,8 @@ + # SPDX-License-Identifier: GPL-2.0 + + obj-$(CONFIG_ZL3073X) += zl3073x.o +-zl3073x-objs := core.o devlink.o dpll.o flash.o fw.o prop.o ++zl3073x-objs := core.o devlink.o dpll.o flash.o fw.o \ ++ out.o prop.o ref.o synth.o + + obj-$(CONFIG_ZL3073X_I2C) += zl3073x_i2c.o + zl3073x_i2c-objs := i2c.o +diff --git a/drivers/dpll/zl3073x/core.c b/drivers/dpll/zl3073x/core.c +index 50c1fe59bc7f0..2f340f7eb9ec3 100644 +--- a/drivers/dpll/zl3073x/core.c ++++ b/drivers/dpll/zl3073x/core.c +@@ -129,47 +129,6 @@ const struct regmap_config zl3073x_regmap_config = { + }; + EXPORT_SYMBOL_NS_GPL(zl3073x_regmap_config, "ZL3073X"); + +-/** +- * zl3073x_ref_freq_factorize - factorize given frequency +- * @freq: input frequency +- * @base: base frequency +- * @mult: multiplier +- * +- * Checks if the given frequency can be factorized using one of the +- * supported base frequencies. If so the base frequency and multiplier +- * are stored into appropriate parameters if they are not NULL. +- * +- * Return: 0 on success, -EINVAL if the frequency cannot be factorized +- */ +-int +-zl3073x_ref_freq_factorize(u32 freq, u16 *base, u16 *mult) +-{ +- static const u16 base_freqs[] = { +- 1, 2, 4, 5, 8, 10, 16, 20, 25, 32, 40, 50, 64, 80, 100, 125, +- 128, 160, 200, 250, 256, 320, 400, 500, 625, 640, 800, 1000, +- 1250, 1280, 1600, 2000, 2500, 3125, 3200, 4000, 5000, 6250, +- 6400, 8000, 10000, 12500, 15625, 16000, 20000, 25000, 31250, +- 32000, 40000, 50000, 62500, +- }; +- u32 div; +- int i; +- +- for (i = 0; i < ARRAY_SIZE(base_freqs); i++) { +- div = freq / base_freqs[i]; +- +- if (div <= U16_MAX && (freq % base_freqs[i]) == 0) { +- if (base) +- *base = base_freqs[i]; +- if (mult) +- *mult = div; +- +- return 0; +- } +- } +- +- return -EINVAL; +-} +- + static bool + zl3073x_check_reg(struct zl3073x_dev *zldev, unsigned int reg, size_t size) + { +@@ -593,159 +552,6 @@ int zl3073x_write_hwreg_seq(struct zl3073x_dev *zldev, + return rc; + } + +-/** +- * zl3073x_ref_state_fetch - get input reference state +- * @zldev: pointer to zl3073x_dev structure +- * @index: input reference index to fetch state for +- * +- * Function fetches state for the given input reference and stores it for +- * later user. +- * +- * Return: 0 on success, <0 on error +- */ +-static int +-zl3073x_ref_state_fetch(struct zl3073x_dev *zldev, u8 index) +-{ +- struct zl3073x_ref *ref = &zldev->ref[index]; +- int rc; +- +- /* If the input is differential then the configuration for N-pin +- * reference is ignored and P-pin config is used for both. +- */ +- if (zl3073x_is_n_pin(index) && zl3073x_ref_is_diff(zldev, index - 1)) { +- memcpy(ref, &zldev->ref[index - 1], sizeof(*ref)); +- +- return 0; +- } +- +- guard(mutex)(&zldev->multiop_lock); +- +- /* Read reference configuration */ +- rc = zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_RD, +- ZL_REG_REF_MB_MASK, BIT(index)); +- if (rc) +- return rc; +- +- /* Read ref_config register */ +- rc = zl3073x_read_u8(zldev, ZL_REG_REF_CONFIG, &ref->config); +- if (rc) +- return rc; +- +- dev_dbg(zldev->dev, "REF%u is %s and configured as %s\n", index, +- str_enabled_disabled(zl3073x_ref_is_enabled(zldev, index)), +- zl3073x_ref_is_diff(zldev, index) +- ? "differential" : "single-ended"); +- +- return rc; +-} +- +-/** +- * zl3073x_out_state_fetch - get output state +- * @zldev: pointer to zl3073x_dev structure +- * @index: output index to fetch state for +- * +- * Function fetches state of the given output (not output pin) and stores it +- * for later use. +- * +- * Return: 0 on success, <0 on error +- */ +-static int +-zl3073x_out_state_fetch(struct zl3073x_dev *zldev, u8 index) +-{ +- struct zl3073x_out *out = &zldev->out[index]; +- int rc; +- +- /* Read output configuration */ +- rc = zl3073x_read_u8(zldev, ZL_REG_OUTPUT_CTRL(index), &out->ctrl); +- if (rc) +- return rc; +- +- dev_dbg(zldev->dev, "OUT%u is %s and connected to SYNTH%u\n", index, +- str_enabled_disabled(zl3073x_out_is_enabled(zldev, index)), +- zl3073x_out_synth_get(zldev, index)); +- +- guard(mutex)(&zldev->multiop_lock); +- +- /* Read output configuration */ +- rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD, +- ZL_REG_OUTPUT_MB_MASK, BIT(index)); +- if (rc) +- return rc; +- +- /* Read output mode */ +- rc = zl3073x_read_u8(zldev, ZL_REG_OUTPUT_MODE, &out->mode); +- if (rc) +- return rc; +- +- dev_dbg(zldev->dev, "OUT%u has signal format 0x%02x\n", index, +- zl3073x_out_signal_format_get(zldev, index)); +- +- return rc; +-} +- +-/** +- * zl3073x_synth_state_fetch - get synth state +- * @zldev: pointer to zl3073x_dev structure +- * @index: synth index to fetch state for +- * +- * Function fetches state of the given synthesizer and stores it for later use. +- * +- * Return: 0 on success, <0 on error +- */ +-static int +-zl3073x_synth_state_fetch(struct zl3073x_dev *zldev, u8 index) +-{ +- struct zl3073x_synth *synth = &zldev->synth[index]; +- int rc; +- +- /* Read synth control register */ +- rc = zl3073x_read_u8(zldev, ZL_REG_SYNTH_CTRL(index), &synth->ctrl); +- if (rc) +- return rc; +- +- guard(mutex)(&zldev->multiop_lock); +- +- /* Read synth configuration */ +- rc = zl3073x_mb_op(zldev, ZL_REG_SYNTH_MB_SEM, ZL_SYNTH_MB_SEM_RD, +- ZL_REG_SYNTH_MB_MASK, BIT(index)); +- if (rc) +- return rc; +- +- /* The output frequency is determined by the following formula: +- * base * multiplier * numerator / denominator +- * +- * Read registers with these values +- */ +- rc = zl3073x_read_u16(zldev, ZL_REG_SYNTH_FREQ_BASE, &synth->freq_base); +- if (rc) +- return rc; +- +- rc = zl3073x_read_u32(zldev, ZL_REG_SYNTH_FREQ_MULT, &synth->freq_mult); +- if (rc) +- return rc; +- +- rc = zl3073x_read_u16(zldev, ZL_REG_SYNTH_FREQ_M, &synth->freq_m); +- if (rc) +- return rc; +- +- rc = zl3073x_read_u16(zldev, ZL_REG_SYNTH_FREQ_N, &synth->freq_n); +- if (rc) +- return rc; +- +- /* Check denominator for zero to avoid div by 0 */ +- if (!synth->freq_n) { +- dev_err(zldev->dev, +- "Zero divisor for SYNTH%u retrieved from device\n", +- index); +- return -EINVAL; +- } +- +- dev_dbg(zldev->dev, "SYNTH%u frequency: %u Hz\n", index, +- zl3073x_synth_freq_get(zldev, index)); +- +- return rc; +-} +- + static int + zl3073x_dev_state_fetch(struct zl3073x_dev *zldev) + { +diff --git a/drivers/dpll/zl3073x/core.h b/drivers/dpll/zl3073x/core.h +index 51d0fd6cfabfc..fe779fc77dd09 100644 +--- a/drivers/dpll/zl3073x/core.h ++++ b/drivers/dpll/zl3073x/core.h +@@ -9,7 +9,10 @@ + #include + #include + ++#include "out.h" ++#include "ref.h" + #include "regs.h" ++#include "synth.h" + + struct device; + struct regmap; +@@ -27,42 +30,6 @@ struct zl3073x_dpll; + #define ZL3073X_NUM_PINS (ZL3073X_NUM_INPUT_PINS + \ + ZL3073X_NUM_OUTPUT_PINS) + +-/** +- * struct zl3073x_ref - input reference invariant info +- * @ffo: current fractional frequency offset +- * @config: reference config +- */ +-struct zl3073x_ref { +- s64 ffo; +- u8 config; +-}; +- +-/** +- * struct zl3073x_out - output invariant info +- * @ctrl: output control +- * @mode: output mode +- */ +-struct zl3073x_out { +- u8 ctrl; +- u8 mode; +-}; +- +-/** +- * struct zl3073x_synth - synthesizer invariant info +- * @freq_mult: frequency multiplier +- * @freq_base: frequency base +- * @freq_m: frequency numerator +- * @freq_n: frequency denominator +- * @ctrl: synth control +- */ +-struct zl3073x_synth { +- u32 freq_mult; +- u16 freq_base; +- u16 freq_m; +- u16 freq_n; +- u8 ctrl; +-}; +- + /** + * struct zl3073x_dev - zl3073x device + * @dev: pointer to device +@@ -175,7 +142,6 @@ int zl3073x_write_hwreg_seq(struct zl3073x_dev *zldev, + * Misc operations + *****************/ + +-int zl3073x_ref_freq_factorize(u32 freq, u16 *base, u16 *mult); + int zl3073x_ref_phase_offsets_update(struct zl3073x_dev *zldev, int channel); + + static inline bool +@@ -217,181 +183,188 @@ zl3073x_output_pin_out_get(u8 id) + } + + /** +- * zl3073x_ref_ffo_get - get current fractional frequency offset ++ * zl3073x_dev_ref_ffo_get - get current fractional frequency offset + * @zldev: pointer to zl3073x device + * @index: input reference index + * + * Return: the latest measured fractional frequency offset + */ + static inline s64 +-zl3073x_ref_ffo_get(struct zl3073x_dev *zldev, u8 index) ++zl3073x_dev_ref_ffo_get(struct zl3073x_dev *zldev, u8 index) + { +- return zldev->ref[index].ffo; ++ const struct zl3073x_ref *ref = zl3073x_ref_state_get(zldev, index); ++ ++ return zl3073x_ref_ffo_get(ref); + } + + /** +- * zl3073x_ref_is_diff - check if the given input reference is differential ++ * zl3073x_dev_ref_is_diff - check if the given input reference is differential + * @zldev: pointer to zl3073x device + * @index: input reference index + * + * Return: true if reference is differential, false if reference is single-ended + */ + static inline bool +-zl3073x_ref_is_diff(struct zl3073x_dev *zldev, u8 index) ++zl3073x_dev_ref_is_diff(struct zl3073x_dev *zldev, u8 index) + { +- if (FIELD_GET(ZL_REF_CONFIG_DIFF_EN, zldev->ref[index].config)) +- return true; ++ const struct zl3073x_ref *ref = zl3073x_ref_state_get(zldev, index); + +- return false; ++ return zl3073x_ref_is_diff(ref); + } + + /** +- * zl3073x_ref_is_enabled - check if the given input reference is enabled ++ * zl3073x_dev_ref_is_enabled - check if the given input reference is enabled + * @zldev: pointer to zl3073x device + * @index: input reference index + * + * Return: true if input refernce is enabled, false otherwise + */ + static inline bool +-zl3073x_ref_is_enabled(struct zl3073x_dev *zldev, u8 index) ++zl3073x_dev_ref_is_enabled(struct zl3073x_dev *zldev, u8 index) + { +- if (FIELD_GET(ZL_REF_CONFIG_ENABLE, zldev->ref[index].config)) +- return true; ++ const struct zl3073x_ref *ref = zl3073x_ref_state_get(zldev, index); + +- return false; ++ return zl3073x_ref_is_enabled(ref); + } + + /** +- * zl3073x_synth_dpll_get - get DPLL ID the synth is driven by ++ * zl3073x_dev_synth_dpll_get - get DPLL ID the synth is driven by + * @zldev: pointer to zl3073x device + * @index: synth index + * + * Return: ID of DPLL the given synthetizer is driven by + */ + static inline u8 +-zl3073x_synth_dpll_get(struct zl3073x_dev *zldev, u8 index) ++zl3073x_dev_synth_dpll_get(struct zl3073x_dev *zldev, u8 index) + { +- return FIELD_GET(ZL_SYNTH_CTRL_DPLL_SEL, zldev->synth[index].ctrl); ++ const struct zl3073x_synth *synth; ++ ++ synth = zl3073x_synth_state_get(zldev, index); ++ return zl3073x_synth_dpll_get(synth); + } + + /** +- * zl3073x_synth_freq_get - get synth current freq ++ * zl3073x_dev_synth_freq_get - get synth current freq + * @zldev: pointer to zl3073x device + * @index: synth index + * + * Return: frequency of given synthetizer + */ + static inline u32 +-zl3073x_synth_freq_get(struct zl3073x_dev *zldev, u8 index) ++zl3073x_dev_synth_freq_get(struct zl3073x_dev *zldev, u8 index) + { +- struct zl3073x_synth *synth = &zldev->synth[index]; ++ const struct zl3073x_synth *synth; + +- return mul_u64_u32_div(synth->freq_base * synth->freq_m, +- synth->freq_mult, synth->freq_n); ++ synth = zl3073x_synth_state_get(zldev, index); ++ return zl3073x_synth_freq_get(synth); + } + + /** +- * zl3073x_synth_is_enabled - check if the given synth is enabled ++ * zl3073x_dev_synth_is_enabled - check if the given synth is enabled + * @zldev: pointer to zl3073x device + * @index: synth index + * + * Return: true if synth is enabled, false otherwise + */ + static inline bool +-zl3073x_synth_is_enabled(struct zl3073x_dev *zldev, u8 index) ++zl3073x_dev_synth_is_enabled(struct zl3073x_dev *zldev, u8 index) + { +- return FIELD_GET(ZL_SYNTH_CTRL_EN, zldev->synth[index].ctrl); ++ const struct zl3073x_synth *synth; ++ ++ synth = zl3073x_synth_state_get(zldev, index); ++ return zl3073x_synth_is_enabled(synth); + } + + /** +- * zl3073x_out_synth_get - get synth connected to given output ++ * zl3073x_dev_out_synth_get - get synth connected to given output + * @zldev: pointer to zl3073x device + * @index: output index + * + * Return: index of synth connected to given output. + */ + static inline u8 +-zl3073x_out_synth_get(struct zl3073x_dev *zldev, u8 index) ++zl3073x_dev_out_synth_get(struct zl3073x_dev *zldev, u8 index) + { +- return FIELD_GET(ZL_OUTPUT_CTRL_SYNTH_SEL, zldev->out[index].ctrl); ++ const struct zl3073x_out *out = zl3073x_out_state_get(zldev, index); ++ ++ return zl3073x_out_synth_get(out); + } + + /** +- * zl3073x_out_is_enabled - check if the given output is enabled ++ * zl3073x_dev_out_is_enabled - check if the given output is enabled + * @zldev: pointer to zl3073x device + * @index: output index + * + * Return: true if the output is enabled, false otherwise + */ + static inline bool +-zl3073x_out_is_enabled(struct zl3073x_dev *zldev, u8 index) ++zl3073x_dev_out_is_enabled(struct zl3073x_dev *zldev, u8 index) + { +- u8 synth; ++ const struct zl3073x_out *out = zl3073x_out_state_get(zldev, index); ++ const struct zl3073x_synth *synth; ++ u8 synth_id; + + /* Output is enabled only if associated synth is enabled */ +- synth = zl3073x_out_synth_get(zldev, index); +- if (!zl3073x_synth_is_enabled(zldev, synth)) +- return false; ++ synth_id = zl3073x_out_synth_get(out); ++ synth = zl3073x_synth_state_get(zldev, synth_id); + +- return FIELD_GET(ZL_OUTPUT_CTRL_EN, zldev->out[index].ctrl); ++ return zl3073x_synth_is_enabled(synth) && zl3073x_out_is_enabled(out); + } + + /** +- * zl3073x_out_signal_format_get - get output signal format ++ * zl3073x_dev_out_signal_format_get - get output signal format + * @zldev: pointer to zl3073x device + * @index: output index + * + * Return: signal format of given output + */ + static inline u8 +-zl3073x_out_signal_format_get(struct zl3073x_dev *zldev, u8 index) ++zl3073x_dev_out_signal_format_get(struct zl3073x_dev *zldev, u8 index) + { +- return FIELD_GET(ZL_OUTPUT_MODE_SIGNAL_FORMAT, zldev->out[index].mode); ++ const struct zl3073x_out *out = zl3073x_out_state_get(zldev, index); ++ ++ return zl3073x_out_signal_format_get(out); + } + + /** +- * zl3073x_out_dpll_get - get DPLL ID the output is driven by ++ * zl3073x_dev_out_dpll_get - get DPLL ID the output is driven by + * @zldev: pointer to zl3073x device + * @index: output index + * + * Return: ID of DPLL the given output is driven by + */ + static inline +-u8 zl3073x_out_dpll_get(struct zl3073x_dev *zldev, u8 index) ++u8 zl3073x_dev_out_dpll_get(struct zl3073x_dev *zldev, u8 index) + { +- u8 synth; ++ const struct zl3073x_out *out = zl3073x_out_state_get(zldev, index); ++ const struct zl3073x_synth *synth; ++ u8 synth_id; + + /* Get synthesizer connected to given output */ +- synth = zl3073x_out_synth_get(zldev, index); ++ synth_id = zl3073x_out_synth_get(out); ++ synth = zl3073x_synth_state_get(zldev, synth_id); + + /* Return DPLL that drives the synth */ +- return zl3073x_synth_dpll_get(zldev, synth); ++ return zl3073x_synth_dpll_get(synth); + } + + /** +- * zl3073x_out_is_diff - check if the given output is differential ++ * zl3073x_dev_out_is_diff - check if the given output is differential + * @zldev: pointer to zl3073x device + * @index: output index + * + * Return: true if output is differential, false if output is single-ended + */ + static inline bool +-zl3073x_out_is_diff(struct zl3073x_dev *zldev, u8 index) ++zl3073x_dev_out_is_diff(struct zl3073x_dev *zldev, u8 index) + { +- switch (zl3073x_out_signal_format_get(zldev, index)) { +- case ZL_OUTPUT_MODE_SIGNAL_FORMAT_LVDS: +- case ZL_OUTPUT_MODE_SIGNAL_FORMAT_DIFF: +- case ZL_OUTPUT_MODE_SIGNAL_FORMAT_LOWVCM: +- return true; +- default: +- break; +- } ++ const struct zl3073x_out *out = zl3073x_out_state_get(zldev, index); + +- return false; ++ return zl3073x_out_is_diff(out); + } + + /** +- * zl3073x_output_pin_is_enabled - check if the given output pin is enabled ++ * zl3073x_dev_output_pin_is_enabled - check if the given output pin is enabled + * @zldev: pointer to zl3073x device + * @id: output pin id + * +@@ -401,16 +374,21 @@ zl3073x_out_is_diff(struct zl3073x_dev *zldev, u8 index) + * Return: true if output pin is enabled, false if output pin is disabled + */ + static inline bool +-zl3073x_output_pin_is_enabled(struct zl3073x_dev *zldev, u8 id) ++zl3073x_dev_output_pin_is_enabled(struct zl3073x_dev *zldev, u8 id) + { +- u8 output = zl3073x_output_pin_out_get(id); ++ u8 out_id = zl3073x_output_pin_out_get(id); ++ const struct zl3073x_out *out; ++ ++ out = zl3073x_out_state_get(zldev, out_id); + +- /* Check if the whole output is enabled */ +- if (!zl3073x_out_is_enabled(zldev, output)) ++ /* Check if the output is enabled - call _dev_ helper that ++ * additionally checks for attached synth enablement. ++ */ ++ if (!zl3073x_dev_out_is_enabled(zldev, out_id)) + return false; + + /* Check signal format */ +- switch (zl3073x_out_signal_format_get(zldev, output)) { ++ switch (zl3073x_out_signal_format_get(out)) { + case ZL_OUTPUT_MODE_SIGNAL_FORMAT_DISABLED: + /* Both output pins are disabled by signal format */ + return false; +diff --git a/drivers/dpll/zl3073x/dpll.c b/drivers/dpll/zl3073x/dpll.c +index d90150671d374..62996f26e065f 100644 +--- a/drivers/dpll/zl3073x/dpll.c ++++ b/drivers/dpll/zl3073x/dpll.c +@@ -967,7 +967,7 @@ zl3073x_dpll_output_pin_esync_get(const struct dpll_pin *dpll_pin, + * for N-division is also used for the esync divider so both cannot + * be used. + */ +- switch (zl3073x_out_signal_format_get(zldev, out)) { ++ switch (zl3073x_dev_out_signal_format_get(zldev, out)) { + case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV: + case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV_INV: + return -EOPNOTSUPP; +@@ -1001,10 +1001,10 @@ zl3073x_dpll_output_pin_esync_get(const struct dpll_pin *dpll_pin, + } + + /* Get synth attached to output pin */ +- synth = zl3073x_out_synth_get(zldev, out); ++ synth = zl3073x_dev_out_synth_get(zldev, out); + + /* Get synth frequency */ +- synth_freq = zl3073x_synth_freq_get(zldev, synth); ++ synth_freq = zl3073x_dev_synth_freq_get(zldev, synth); + + clock_type = FIELD_GET(ZL_OUTPUT_MODE_CLOCK_TYPE, output_mode); + if (clock_type != ZL_OUTPUT_MODE_CLOCK_TYPE_ESYNC) { +@@ -1078,7 +1078,7 @@ zl3073x_dpll_output_pin_esync_set(const struct dpll_pin *dpll_pin, + * for N-division is also used for the esync divider so both cannot + * be used. + */ +- switch (zl3073x_out_signal_format_get(zldev, out)) { ++ switch (zl3073x_dev_out_signal_format_get(zldev, out)) { + case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV: + case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV_INV: + return -EOPNOTSUPP; +@@ -1117,10 +1117,10 @@ zl3073x_dpll_output_pin_esync_set(const struct dpll_pin *dpll_pin, + goto write_mailbox; + + /* Get synth attached to output pin */ +- synth = zl3073x_out_synth_get(zldev, out); ++ synth = zl3073x_dev_out_synth_get(zldev, out); + + /* Get synth frequency */ +- synth_freq = zl3073x_synth_freq_get(zldev, synth); ++ synth_freq = zl3073x_dev_synth_freq_get(zldev, synth); + + rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_DIV, &output_div); + if (rc) +@@ -1172,8 +1172,8 @@ zl3073x_dpll_output_pin_frequency_get(const struct dpll_pin *dpll_pin, + int rc; + + out = zl3073x_output_pin_out_get(pin->id); +- synth = zl3073x_out_synth_get(zldev, out); +- synth_freq = zl3073x_synth_freq_get(zldev, synth); ++ synth = zl3073x_dev_out_synth_get(zldev, out); ++ synth_freq = zl3073x_dev_synth_freq_get(zldev, synth); + + guard(mutex)(&zldev->multiop_lock); + +@@ -1195,7 +1195,7 @@ zl3073x_dpll_output_pin_frequency_get(const struct dpll_pin *dpll_pin, + } + + /* Read used signal format for the given output */ +- signal_format = zl3073x_out_signal_format_get(zldev, out); ++ signal_format = zl3073x_dev_out_signal_format_get(zldev, out); + + switch (signal_format) { + case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV: +@@ -1263,12 +1263,12 @@ zl3073x_dpll_output_pin_frequency_set(const struct dpll_pin *dpll_pin, + int rc; + + out = zl3073x_output_pin_out_get(pin->id); +- synth = zl3073x_out_synth_get(zldev, out); +- synth_freq = zl3073x_synth_freq_get(zldev, synth); ++ synth = zl3073x_dev_out_synth_get(zldev, out); ++ synth_freq = zl3073x_dev_synth_freq_get(zldev, synth); + new_div = synth_freq / (u32)frequency; + + /* Get used signal format for the given output */ +- signal_format = zl3073x_out_signal_format_get(zldev, out); ++ signal_format = zl3073x_dev_out_signal_format_get(zldev, out); + + guard(mutex)(&zldev->multiop_lock); + +@@ -1856,8 +1856,8 @@ zl3073x_dpll_pin_is_registrable(struct zl3073x_dpll *zldpll, + if (zldpll->refsel_mode == ZL_DPLL_MODE_REFSEL_MODE_NCO) + return false; + +- is_diff = zl3073x_ref_is_diff(zldev, ref); +- is_enabled = zl3073x_ref_is_enabled(zldev, ref); ++ is_diff = zl3073x_dev_ref_is_diff(zldev, ref); ++ is_enabled = zl3073x_dev_ref_is_enabled(zldev, ref); + } else { + /* Output P&N pair shares single HW output */ + u8 out = zl3073x_output_pin_out_get(index); +@@ -1865,7 +1865,7 @@ zl3073x_dpll_pin_is_registrable(struct zl3073x_dpll *zldpll, + name = "OUT"; + + /* Skip the pin if it is connected to different DPLL channel */ +- if (zl3073x_out_dpll_get(zldev, out) != zldpll->id) { ++ if (zl3073x_dev_out_dpll_get(zldev, out) != zldpll->id) { + dev_dbg(zldev->dev, + "%s%u is driven by different DPLL\n", name, + out); +@@ -1873,8 +1873,8 @@ zl3073x_dpll_pin_is_registrable(struct zl3073x_dpll *zldpll, + return false; + } + +- is_diff = zl3073x_out_is_diff(zldev, out); +- is_enabled = zl3073x_output_pin_is_enabled(zldev, index); ++ is_diff = zl3073x_dev_out_is_diff(zldev, out); ++ is_enabled = zl3073x_dev_output_pin_is_enabled(zldev, index); + } + + /* Skip N-pin if the corresponding input/output is differential */ +@@ -2124,7 +2124,7 @@ zl3073x_dpll_pin_ffo_check(struct zl3073x_dpll_pin *pin) + return false; + + /* Get the latest measured ref's ffo */ +- ffo = zl3073x_ref_ffo_get(zldev, ref); ++ ffo = zl3073x_dev_ref_ffo_get(zldev, ref); + + /* Compare with previous value */ + if (pin->freq_offset != ffo) { +diff --git a/drivers/dpll/zl3073x/out.c b/drivers/dpll/zl3073x/out.c +new file mode 100644 +index 0000000000000..a48f6917b39fb +--- /dev/null ++++ b/drivers/dpll/zl3073x/out.c +@@ -0,0 +1,67 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "core.h" ++#include "out.h" ++ ++/** ++ * zl3073x_out_state_fetch - fetch output state from hardware ++ * @zldev: pointer to zl3073x_dev structure ++ * @index: output index to fetch state for ++ * ++ * Function fetches state of the given output from hardware and stores it ++ * for later use. ++ * ++ * Return: 0 on success, <0 on error ++ */ ++int zl3073x_out_state_fetch(struct zl3073x_dev *zldev, u8 index) ++{ ++ struct zl3073x_out *out = &zldev->out[index]; ++ int rc; ++ ++ /* Read output configuration */ ++ rc = zl3073x_read_u8(zldev, ZL_REG_OUTPUT_CTRL(index), &out->ctrl); ++ if (rc) ++ return rc; ++ ++ dev_dbg(zldev->dev, "OUT%u is %s and connected to SYNTH%u\n", index, ++ str_enabled_disabled(zl3073x_out_is_enabled(out)), ++ zl3073x_out_synth_get(out)); ++ ++ guard(mutex)(&zldev->multiop_lock); ++ ++ /* Read output configuration */ ++ rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD, ++ ZL_REG_OUTPUT_MB_MASK, BIT(index)); ++ if (rc) ++ return rc; ++ ++ /* Read output mode */ ++ rc = zl3073x_read_u8(zldev, ZL_REG_OUTPUT_MODE, &out->mode); ++ if (rc) ++ return rc; ++ ++ dev_dbg(zldev->dev, "OUT%u has signal format 0x%02x\n", index, ++ zl3073x_out_signal_format_get(out)); ++ ++ return rc; ++} ++ ++/** ++ * zl3073x_out_state_get - get current output state ++ * @zldev: pointer to zl3073x_dev structure ++ * @index: output index to get state for ++ * ++ * Return: pointer to given output state ++ */ ++const struct zl3073x_out *zl3073x_out_state_get(struct zl3073x_dev *zldev, ++ u8 index) ++{ ++ return &zldev->out[index]; ++} +diff --git a/drivers/dpll/zl3073x/out.h b/drivers/dpll/zl3073x/out.h +new file mode 100644 +index 0000000000000..986aa046221da +--- /dev/null ++++ b/drivers/dpll/zl3073x/out.h +@@ -0,0 +1,80 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++ ++#ifndef _ZL3073X_OUT_H ++#define _ZL3073X_OUT_H ++ ++#include ++#include ++ ++#include "regs.h" ++ ++struct zl3073x_dev; ++ ++/** ++ * struct zl3073x_out - output state ++ * @ctrl: output control ++ * @mode: output mode ++ */ ++struct zl3073x_out { ++ u8 ctrl; ++ u8 mode; ++}; ++ ++int zl3073x_out_state_fetch(struct zl3073x_dev *zldev, u8 index); ++const struct zl3073x_out *zl3073x_out_state_get(struct zl3073x_dev *zldev, ++ u8 index); ++ ++/** ++ * zl3073x_out_signal_format_get - get output signal format ++ * @out: pointer to out state ++ * ++ * Return: signal format of given output ++ */ ++static inline u8 zl3073x_out_signal_format_get(const struct zl3073x_out *out) ++{ ++ return FIELD_GET(ZL_OUTPUT_MODE_SIGNAL_FORMAT, out->mode); ++} ++ ++/** ++ * zl3073x_out_is_diff - check if the given output is differential ++ * @out: pointer to out state ++ * ++ * Return: true if output is differential, false if output is single-ended ++ */ ++static inline bool zl3073x_out_is_diff(const struct zl3073x_out *out) ++{ ++ switch (zl3073x_out_signal_format_get(out)) { ++ case ZL_OUTPUT_MODE_SIGNAL_FORMAT_LVDS: ++ case ZL_OUTPUT_MODE_SIGNAL_FORMAT_DIFF: ++ case ZL_OUTPUT_MODE_SIGNAL_FORMAT_LOWVCM: ++ return true; ++ default: ++ break; ++ } ++ ++ return false; ++} ++ ++/** ++ * zl3073x_out_is_enabled - check if the given output is enabled ++ * @out: pointer to out state ++ * ++ * Return: true if output is enabled, false if output is disabled ++ */ ++static inline bool zl3073x_out_is_enabled(const struct zl3073x_out *out) ++{ ++ return !!FIELD_GET(ZL_OUTPUT_CTRL_EN, out->ctrl); ++} ++ ++/** ++ * zl3073x_out_synth_get - get synth connected to given output ++ * @out: pointer to out state ++ * ++ * Return: index of synth connected to given output. ++ */ ++static inline u8 zl3073x_out_synth_get(const struct zl3073x_out *out) ++{ ++ return FIELD_GET(ZL_OUTPUT_CTRL_SYNTH_SEL, out->ctrl); ++} ++ ++#endif /* _ZL3073X_OUT_H */ +diff --git a/drivers/dpll/zl3073x/prop.c b/drivers/dpll/zl3073x/prop.c +index 9e1fca5cdaf1e..4ed153087570b 100644 +--- a/drivers/dpll/zl3073x/prop.c ++++ b/drivers/dpll/zl3073x/prop.c +@@ -46,10 +46,10 @@ zl3073x_pin_check_freq(struct zl3073x_dev *zldev, enum dpll_pin_direction dir, + + /* Get output pin synthesizer */ + out = zl3073x_output_pin_out_get(id); +- synth = zl3073x_out_synth_get(zldev, out); ++ synth = zl3073x_dev_out_synth_get(zldev, out); + + /* Get synth frequency */ +- synth_freq = zl3073x_synth_freq_get(zldev, synth); ++ synth_freq = zl3073x_dev_synth_freq_get(zldev, synth); + + /* Check the frequency divides synth frequency */ + if (synth_freq % (u32)freq) +@@ -93,13 +93,13 @@ zl3073x_prop_pin_package_label_set(struct zl3073x_dev *zldev, + + prefix = "REF"; + ref = zl3073x_input_pin_ref_get(id); +- is_diff = zl3073x_ref_is_diff(zldev, ref); ++ is_diff = zl3073x_dev_ref_is_diff(zldev, ref); + } else { + u8 out; + + prefix = "OUT"; + out = zl3073x_output_pin_out_get(id); +- is_diff = zl3073x_out_is_diff(zldev, out); ++ is_diff = zl3073x_dev_out_is_diff(zldev, out); + } + + if (!is_diff) +@@ -217,8 +217,8 @@ struct zl3073x_pin_props *zl3073x_pin_props_get(struct zl3073x_dev *zldev, + * the synth frequency count. + */ + out = zl3073x_output_pin_out_get(index); +- synth = zl3073x_out_synth_get(zldev, out); +- f = 2 * zl3073x_synth_freq_get(zldev, synth); ++ synth = zl3073x_dev_out_synth_get(zldev, out); ++ f = 2 * zl3073x_dev_synth_freq_get(zldev, synth); + props->dpll_props.phase_gran = f ? div_u64(PSEC_PER_SEC, f) : 1; + } + +diff --git a/drivers/dpll/zl3073x/ref.c b/drivers/dpll/zl3073x/ref.c +new file mode 100644 +index 0000000000000..6abd6288a02ad +--- /dev/null ++++ b/drivers/dpll/zl3073x/ref.c +@@ -0,0 +1,112 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "core.h" ++#include "ref.h" ++ ++/** ++ * zl3073x_ref_freq_factorize - factorize given frequency ++ * @freq: input frequency ++ * @base: base frequency ++ * @mult: multiplier ++ * ++ * Checks if the given frequency can be factorized using one of the ++ * supported base frequencies. If so the base frequency and multiplier ++ * are stored into appropriate parameters if they are not NULL. ++ * ++ * Return: 0 on success, -EINVAL if the frequency cannot be factorized ++ */ ++int ++zl3073x_ref_freq_factorize(u32 freq, u16 *base, u16 *mult) ++{ ++ static const u16 base_freqs[] = { ++ 1, 2, 4, 5, 8, 10, 16, 20, 25, 32, 40, 50, 64, 80, 100, 125, ++ 128, 160, 200, 250, 256, 320, 400, 500, 625, 640, 800, 1000, ++ 1250, 1280, 1600, 2000, 2500, 3125, 3200, 4000, 5000, 6250, ++ 6400, 8000, 10000, 12500, 15625, 16000, 20000, 25000, 31250, ++ 32000, 40000, 50000, 62500, ++ }; ++ u32 div; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(base_freqs); i++) { ++ div = freq / base_freqs[i]; ++ ++ if (div <= U16_MAX && (freq % base_freqs[i]) == 0) { ++ if (base) ++ *base = base_freqs[i]; ++ if (mult) ++ *mult = div; ++ ++ return 0; ++ } ++ } ++ ++ return -EINVAL; ++} ++ ++/** ++ * zl3073x_ref_state_fetch - fetch input reference state from hardware ++ * @zldev: pointer to zl3073x_dev structure ++ * @index: input reference index to fetch state for ++ * ++ * Function fetches state for the given input reference from hardware and ++ * stores it for later use. ++ * ++ * Return: 0 on success, <0 on error ++ */ ++int zl3073x_ref_state_fetch(struct zl3073x_dev *zldev, u8 index) ++{ ++ struct zl3073x_ref *ref = &zldev->ref[index]; ++ int rc; ++ ++ /* For differential type inputs the N-pin reference shares ++ * part of the configuration with the P-pin counterpart. ++ */ ++ if (zl3073x_is_n_pin(index) && zl3073x_ref_is_diff(ref - 1)) { ++ struct zl3073x_ref *p_ref = &zldev->ref[index - 1]; ++ ++ /* Copy the shared items from the P-pin */ ++ ref->config = p_ref->config; ++ ++ return 0; /* Finish - no non-shared items for now */ ++ } ++ ++ guard(mutex)(&zldev->multiop_lock); ++ ++ /* Read reference configuration */ ++ rc = zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_RD, ++ ZL_REG_REF_MB_MASK, BIT(index)); ++ if (rc) ++ return rc; ++ ++ /* Read ref_config register */ ++ rc = zl3073x_read_u8(zldev, ZL_REG_REF_CONFIG, &ref->config); ++ if (rc) ++ return rc; ++ ++ dev_dbg(zldev->dev, "REF%u is %s and configured as %s\n", index, ++ str_enabled_disabled(zl3073x_ref_is_enabled(ref)), ++ zl3073x_ref_is_diff(ref) ? "differential" : "single-ended"); ++ ++ return rc; ++} ++ ++/** ++ * zl3073x_ref_state_get - get current input reference state ++ * @zldev: pointer to zl3073x_dev structure ++ * @index: input reference index to get state for ++ * ++ * Return: pointer to given input reference state ++ */ ++const struct zl3073x_ref * ++zl3073x_ref_state_get(struct zl3073x_dev *zldev, u8 index) ++{ ++ return &zldev->ref[index]; ++} +diff --git a/drivers/dpll/zl3073x/ref.h b/drivers/dpll/zl3073x/ref.h +new file mode 100644 +index 0000000000000..e72f2c8750876 +--- /dev/null ++++ b/drivers/dpll/zl3073x/ref.h +@@ -0,0 +1,66 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++ ++#ifndef _ZL3073X_REF_H ++#define _ZL3073X_REF_H ++ ++#include ++#include ++ ++#include "regs.h" ++ ++struct zl3073x_dev; ++ ++/** ++ * struct zl3073x_ref - input reference state ++ * @ffo: current fractional frequency offset ++ * @config: reference config ++ */ ++struct zl3073x_ref { ++ s64 ffo; ++ u8 config; ++}; ++ ++int zl3073x_ref_state_fetch(struct zl3073x_dev *zldev, u8 index); ++ ++const struct zl3073x_ref *zl3073x_ref_state_get(struct zl3073x_dev *zldev, ++ u8 index); ++ ++int zl3073x_ref_freq_factorize(u32 freq, u16 *base, u16 *mult); ++ ++/** ++ * zl3073x_ref_ffo_get - get current fractional frequency offset ++ * @ref: pointer to ref state ++ * ++ * Return: the latest measured fractional frequency offset ++ */ ++static inline s64 ++zl3073x_ref_ffo_get(const struct zl3073x_ref *ref) ++{ ++ return ref->ffo; ++} ++ ++/** ++ * zl3073x_ref_is_diff - check if the given input reference is differential ++ * @ref: pointer to ref state ++ * ++ * Return: true if reference is differential, false if reference is single-ended ++ */ ++static inline bool ++zl3073x_ref_is_diff(const struct zl3073x_ref *ref) ++{ ++ return !!FIELD_GET(ZL_REF_CONFIG_DIFF_EN, ref->config); ++} ++ ++/** ++ * zl3073x_ref_is_enabled - check if the given input reference is enabled ++ * @ref: pointer to ref state ++ * ++ * Return: true if input refernce is enabled, false otherwise ++ */ ++static inline bool ++zl3073x_ref_is_enabled(const struct zl3073x_ref *ref) ++{ ++ return !!FIELD_GET(ZL_REF_CONFIG_ENABLE, ref->config); ++} ++ ++#endif /* _ZL3073X_REF_H */ +diff --git a/drivers/dpll/zl3073x/synth.c b/drivers/dpll/zl3073x/synth.c +new file mode 100644 +index 0000000000000..da839572dab26 +--- /dev/null ++++ b/drivers/dpll/zl3073x/synth.c +@@ -0,0 +1,87 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "core.h" ++#include "synth.h" ++ ++/** ++ * zl3073x_synth_state_fetch - fetch synth state from hardware ++ * @zldev: pointer to zl3073x_dev structure ++ * @index: synth index to fetch state for ++ * ++ * Function fetches state of the given synthesizer from the hardware and ++ * stores it for later use. ++ * ++ * Return: 0 on success, <0 on error ++ */ ++int zl3073x_synth_state_fetch(struct zl3073x_dev *zldev, u8 index) ++{ ++ struct zl3073x_synth *synth = &zldev->synth[index]; ++ int rc; ++ ++ /* Read synth control register */ ++ rc = zl3073x_read_u8(zldev, ZL_REG_SYNTH_CTRL(index), &synth->ctrl); ++ if (rc) ++ return rc; ++ ++ guard(mutex)(&zldev->multiop_lock); ++ ++ /* Read synth configuration */ ++ rc = zl3073x_mb_op(zldev, ZL_REG_SYNTH_MB_SEM, ZL_SYNTH_MB_SEM_RD, ++ ZL_REG_SYNTH_MB_MASK, BIT(index)); ++ if (rc) ++ return rc; ++ ++ /* The output frequency is determined by the following formula: ++ * base * multiplier * numerator / denominator ++ * ++ * Read registers with these values ++ */ ++ rc = zl3073x_read_u16(zldev, ZL_REG_SYNTH_FREQ_BASE, &synth->freq_base); ++ if (rc) ++ return rc; ++ ++ rc = zl3073x_read_u32(zldev, ZL_REG_SYNTH_FREQ_MULT, &synth->freq_mult); ++ if (rc) ++ return rc; ++ ++ rc = zl3073x_read_u16(zldev, ZL_REG_SYNTH_FREQ_M, &synth->freq_m); ++ if (rc) ++ return rc; ++ ++ rc = zl3073x_read_u16(zldev, ZL_REG_SYNTH_FREQ_N, &synth->freq_n); ++ if (rc) ++ return rc; ++ ++ /* Check denominator for zero to avoid div by 0 */ ++ if (!synth->freq_n) { ++ dev_err(zldev->dev, ++ "Zero divisor for SYNTH%u retrieved from device\n", ++ index); ++ return -EINVAL; ++ } ++ ++ dev_dbg(zldev->dev, "SYNTH%u frequency: %u Hz\n", index, ++ zl3073x_synth_freq_get(synth)); ++ ++ return rc; ++} ++ ++/** ++ * zl3073x_synth_state_get - get current synth state ++ * @zldev: pointer to zl3073x_dev structure ++ * @index: synth index to get state for ++ * ++ * Return: pointer to given synth state ++ */ ++const struct zl3073x_synth *zl3073x_synth_state_get(struct zl3073x_dev *zldev, ++ u8 index) ++{ ++ return &zldev->synth[index]; ++} +diff --git a/drivers/dpll/zl3073x/synth.h b/drivers/dpll/zl3073x/synth.h +new file mode 100644 +index 0000000000000..6c55eb8a888c2 +--- /dev/null ++++ b/drivers/dpll/zl3073x/synth.h +@@ -0,0 +1,72 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++ ++#ifndef _ZL3073X_SYNTH_H ++#define _ZL3073X_SYNTH_H ++ ++#include ++#include ++#include ++ ++#include "regs.h" ++ ++struct zl3073x_dev; ++ ++/** ++ * struct zl3073x_synth - synthesizer state ++ * @freq_mult: frequency multiplier ++ * @freq_base: frequency base ++ * @freq_m: frequency numerator ++ * @freq_n: frequency denominator ++ * @ctrl: synth control ++ */ ++struct zl3073x_synth { ++ u32 freq_mult; ++ u16 freq_base; ++ u16 freq_m; ++ u16 freq_n; ++ u8 ctrl; ++}; ++ ++int zl3073x_synth_state_fetch(struct zl3073x_dev *zldev, u8 synth_id); ++ ++const struct zl3073x_synth *zl3073x_synth_state_get(struct zl3073x_dev *zldev, ++ u8 synth_id); ++ ++int zl3073x_synth_state_set(struct zl3073x_dev *zldev, u8 synth_id, ++ const struct zl3073x_synth *synth); ++ ++/** ++ * zl3073x_synth_dpll_get - get DPLL ID the synth is driven by ++ * @synth: pointer to synth state ++ * ++ * Return: ID of DPLL the given synthetizer is driven by ++ */ ++static inline u8 zl3073x_synth_dpll_get(const struct zl3073x_synth *synth) ++{ ++ return FIELD_GET(ZL_SYNTH_CTRL_DPLL_SEL, synth->ctrl); ++} ++ ++/** ++ * zl3073x_synth_freq_get - get synth current freq ++ * @synth: pointer to synth state ++ * ++ * Return: frequency of given synthetizer ++ */ ++static inline u32 zl3073x_synth_freq_get(const struct zl3073x_synth *synth) ++{ ++ return mul_u64_u32_div(synth->freq_base * synth->freq_m, ++ synth->freq_mult, synth->freq_n); ++} ++ ++/** ++ * zl3073x_synth_is_enabled - check if the given synth is enabled ++ * @synth: pointer to synth state ++ * ++ * Return: true if synth is enabled, false otherwise ++ */ ++static inline bool zl3073x_synth_is_enabled(const struct zl3073x_synth *synth) ++{ ++ return FIELD_GET(ZL_SYNTH_CTRL_EN, synth->ctrl); ++} ++ ++#endif /* _ZL3073X_SYNTH_H */ +-- +2.51.0 + diff --git a/queue-6.18/dpll-zl3073x-store-raw-register-values-instead-of-pa.patch b/queue-6.18/dpll-zl3073x-store-raw-register-values-instead-of-pa.patch new file mode 100644 index 0000000000..38f6749c5b --- /dev/null +++ b/queue-6.18/dpll-zl3073x-store-raw-register-values-instead-of-pa.patch @@ -0,0 +1,371 @@ +From bb0f6044a2b343a0ce0e64949ac0b4fd634545c9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 13 Nov 2025 08:41:00 +0100 +Subject: dpll: zl3073x: Store raw register values instead of parsed state + +From: Ivan Vecera + +[ Upstream commit 58fb88d30b0250f928e1afa0eaa4547770d86229 ] + +The zl3073x_ref, zl3073x_out and zl3073x_synth structures +previously stored state that was parsed from register reads. This +included values like boolean 'enabled' flags, synthesizer selections, +and pre-calculated frequencies. + +This commit refactors the state management to store the raw register +values directly in these structures. The various inline helper functions +are updated to parse these raw values on-demand using FIELD_GET. + +Reviewed-by: Petr Oros +Tested-by: Prathosh Satish +Signed-off-by: Ivan Vecera +Link: https://patch.msgid.link/20251113074105.141379-2-ivecera@redhat.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 5d41f95f5d0b ("dpll: zl3073x: Fix output pin phase adjustment sign") +Signed-off-by: Sasha Levin +--- + drivers/dpll/zl3073x/core.c | 81 ++++++++++++------------------------- + drivers/dpll/zl3073x/core.h | 61 ++++++++++++++++------------ + 2 files changed, 60 insertions(+), 82 deletions(-) + +diff --git a/drivers/dpll/zl3073x/core.c b/drivers/dpll/zl3073x/core.c +index e42e527813cf8..50c1fe59bc7f0 100644 +--- a/drivers/dpll/zl3073x/core.c ++++ b/drivers/dpll/zl3073x/core.c +@@ -598,25 +598,22 @@ int zl3073x_write_hwreg_seq(struct zl3073x_dev *zldev, + * @zldev: pointer to zl3073x_dev structure + * @index: input reference index to fetch state for + * +- * Function fetches information for the given input reference that are +- * invariant and stores them for later use. ++ * Function fetches state for the given input reference and stores it for ++ * later user. + * + * Return: 0 on success, <0 on error + */ + static int + zl3073x_ref_state_fetch(struct zl3073x_dev *zldev, u8 index) + { +- struct zl3073x_ref *input = &zldev->ref[index]; +- u8 ref_config; ++ struct zl3073x_ref *ref = &zldev->ref[index]; + int rc; + + /* If the input is differential then the configuration for N-pin + * reference is ignored and P-pin config is used for both. + */ +- if (zl3073x_is_n_pin(index) && +- zl3073x_ref_is_diff(zldev, index - 1)) { +- input->enabled = zl3073x_ref_is_enabled(zldev, index - 1); +- input->diff = true; ++ if (zl3073x_is_n_pin(index) && zl3073x_ref_is_diff(zldev, index - 1)) { ++ memcpy(ref, &zldev->ref[index - 1], sizeof(*ref)); + + return 0; + } +@@ -630,16 +627,14 @@ zl3073x_ref_state_fetch(struct zl3073x_dev *zldev, u8 index) + return rc; + + /* Read ref_config register */ +- rc = zl3073x_read_u8(zldev, ZL_REG_REF_CONFIG, &ref_config); ++ rc = zl3073x_read_u8(zldev, ZL_REG_REF_CONFIG, &ref->config); + if (rc) + return rc; + +- input->enabled = FIELD_GET(ZL_REF_CONFIG_ENABLE, ref_config); +- input->diff = FIELD_GET(ZL_REF_CONFIG_DIFF_EN, ref_config); +- + dev_dbg(zldev->dev, "REF%u is %s and configured as %s\n", index, +- str_enabled_disabled(input->enabled), +- input->diff ? "differential" : "single-ended"); ++ str_enabled_disabled(zl3073x_ref_is_enabled(zldev, index)), ++ zl3073x_ref_is_diff(zldev, index) ++ ? "differential" : "single-ended"); + + return rc; + } +@@ -649,8 +644,8 @@ zl3073x_ref_state_fetch(struct zl3073x_dev *zldev, u8 index) + * @zldev: pointer to zl3073x_dev structure + * @index: output index to fetch state for + * +- * Function fetches information for the given output (not output pin) +- * that are invariant and stores them for later use. ++ * Function fetches state of the given output (not output pin) and stores it ++ * for later use. + * + * Return: 0 on success, <0 on error + */ +@@ -658,22 +653,16 @@ static int + zl3073x_out_state_fetch(struct zl3073x_dev *zldev, u8 index) + { + struct zl3073x_out *out = &zldev->out[index]; +- u8 output_ctrl, output_mode; + int rc; + + /* Read output configuration */ +- rc = zl3073x_read_u8(zldev, ZL_REG_OUTPUT_CTRL(index), &output_ctrl); ++ rc = zl3073x_read_u8(zldev, ZL_REG_OUTPUT_CTRL(index), &out->ctrl); + if (rc) + return rc; + +- /* Store info about output enablement and synthesizer the output +- * is connected to. +- */ +- out->enabled = FIELD_GET(ZL_OUTPUT_CTRL_EN, output_ctrl); +- out->synth = FIELD_GET(ZL_OUTPUT_CTRL_SYNTH_SEL, output_ctrl); +- + dev_dbg(zldev->dev, "OUT%u is %s and connected to SYNTH%u\n", index, +- str_enabled_disabled(out->enabled), out->synth); ++ str_enabled_disabled(zl3073x_out_is_enabled(zldev, index)), ++ zl3073x_out_synth_get(zldev, index)); + + guard(mutex)(&zldev->multiop_lock); + +@@ -683,17 +672,13 @@ zl3073x_out_state_fetch(struct zl3073x_dev *zldev, u8 index) + if (rc) + return rc; + +- /* Read output_mode */ +- rc = zl3073x_read_u8(zldev, ZL_REG_OUTPUT_MODE, &output_mode); ++ /* Read output mode */ ++ rc = zl3073x_read_u8(zldev, ZL_REG_OUTPUT_MODE, &out->mode); + if (rc) + return rc; + +- /* Extract and store output signal format */ +- out->signal_format = FIELD_GET(ZL_OUTPUT_MODE_SIGNAL_FORMAT, +- output_mode); +- + dev_dbg(zldev->dev, "OUT%u has signal format 0x%02x\n", index, +- out->signal_format); ++ zl3073x_out_signal_format_get(zldev, index)); + + return rc; + } +@@ -703,8 +688,7 @@ zl3073x_out_state_fetch(struct zl3073x_dev *zldev, u8 index) + * @zldev: pointer to zl3073x_dev structure + * @index: synth index to fetch state for + * +- * Function fetches information for the given synthesizer that are +- * invariant and stores them for later use. ++ * Function fetches state of the given synthesizer and stores it for later use. + * + * Return: 0 on success, <0 on error + */ +@@ -712,25 +696,13 @@ static int + zl3073x_synth_state_fetch(struct zl3073x_dev *zldev, u8 index) + { + struct zl3073x_synth *synth = &zldev->synth[index]; +- u16 base, m, n; +- u8 synth_ctrl; +- u32 mult; + int rc; + + /* Read synth control register */ +- rc = zl3073x_read_u8(zldev, ZL_REG_SYNTH_CTRL(index), &synth_ctrl); ++ rc = zl3073x_read_u8(zldev, ZL_REG_SYNTH_CTRL(index), &synth->ctrl); + if (rc) + return rc; + +- /* Store info about synth enablement and DPLL channel the synth is +- * driven by. +- */ +- synth->enabled = FIELD_GET(ZL_SYNTH_CTRL_EN, synth_ctrl); +- synth->dpll = FIELD_GET(ZL_SYNTH_CTRL_DPLL_SEL, synth_ctrl); +- +- dev_dbg(zldev->dev, "SYNTH%u is %s and driven by DPLL%u\n", index, +- str_enabled_disabled(synth->enabled), synth->dpll); +- + guard(mutex)(&zldev->multiop_lock); + + /* Read synth configuration */ +@@ -744,35 +716,32 @@ zl3073x_synth_state_fetch(struct zl3073x_dev *zldev, u8 index) + * + * Read registers with these values + */ +- rc = zl3073x_read_u16(zldev, ZL_REG_SYNTH_FREQ_BASE, &base); ++ rc = zl3073x_read_u16(zldev, ZL_REG_SYNTH_FREQ_BASE, &synth->freq_base); + if (rc) + return rc; + +- rc = zl3073x_read_u32(zldev, ZL_REG_SYNTH_FREQ_MULT, &mult); ++ rc = zl3073x_read_u32(zldev, ZL_REG_SYNTH_FREQ_MULT, &synth->freq_mult); + if (rc) + return rc; + +- rc = zl3073x_read_u16(zldev, ZL_REG_SYNTH_FREQ_M, &m); ++ rc = zl3073x_read_u16(zldev, ZL_REG_SYNTH_FREQ_M, &synth->freq_m); + if (rc) + return rc; + +- rc = zl3073x_read_u16(zldev, ZL_REG_SYNTH_FREQ_N, &n); ++ rc = zl3073x_read_u16(zldev, ZL_REG_SYNTH_FREQ_N, &synth->freq_n); + if (rc) + return rc; + + /* Check denominator for zero to avoid div by 0 */ +- if (!n) { ++ if (!synth->freq_n) { + dev_err(zldev->dev, + "Zero divisor for SYNTH%u retrieved from device\n", + index); + return -EINVAL; + } + +- /* Compute and store synth frequency */ +- zldev->synth[index].freq = div_u64(mul_u32_u32(base * m, mult), n); +- + dev_dbg(zldev->dev, "SYNTH%u frequency: %u Hz\n", index, +- zldev->synth[index].freq); ++ zl3073x_synth_freq_get(zldev, index)); + + return rc; + } +diff --git a/drivers/dpll/zl3073x/core.h b/drivers/dpll/zl3073x/core.h +index 1dca4ddcf2350..51d0fd6cfabfc 100644 +--- a/drivers/dpll/zl3073x/core.h ++++ b/drivers/dpll/zl3073x/core.h +@@ -29,38 +29,38 @@ struct zl3073x_dpll; + + /** + * struct zl3073x_ref - input reference invariant info +- * @enabled: input reference is enabled or disabled +- * @diff: true if input reference is differential + * @ffo: current fractional frequency offset ++ * @config: reference config + */ + struct zl3073x_ref { +- bool enabled; +- bool diff; + s64 ffo; ++ u8 config; + }; + + /** + * struct zl3073x_out - output invariant info +- * @enabled: out is enabled or disabled +- * @synth: synthesizer the out is connected to +- * @signal_format: out signal format ++ * @ctrl: output control ++ * @mode: output mode + */ + struct zl3073x_out { +- bool enabled; +- u8 synth; +- u8 signal_format; ++ u8 ctrl; ++ u8 mode; + }; + + /** + * struct zl3073x_synth - synthesizer invariant info +- * @freq: synthesizer frequency +- * @dpll: ID of DPLL the synthesizer is driven by +- * @enabled: synth is enabled or disabled ++ * @freq_mult: frequency multiplier ++ * @freq_base: frequency base ++ * @freq_m: frequency numerator ++ * @freq_n: frequency denominator ++ * @ctrl: synth control + */ + struct zl3073x_synth { +- u32 freq; +- u8 dpll; +- bool enabled; ++ u32 freq_mult; ++ u16 freq_base; ++ u16 freq_m; ++ u16 freq_n; ++ u8 ctrl; + }; + + /** +@@ -239,7 +239,10 @@ zl3073x_ref_ffo_get(struct zl3073x_dev *zldev, u8 index) + static inline bool + zl3073x_ref_is_diff(struct zl3073x_dev *zldev, u8 index) + { +- return zldev->ref[index].diff; ++ if (FIELD_GET(ZL_REF_CONFIG_DIFF_EN, zldev->ref[index].config)) ++ return true; ++ ++ return false; + } + + /** +@@ -252,7 +255,10 @@ zl3073x_ref_is_diff(struct zl3073x_dev *zldev, u8 index) + static inline bool + zl3073x_ref_is_enabled(struct zl3073x_dev *zldev, u8 index) + { +- return zldev->ref[index].enabled; ++ if (FIELD_GET(ZL_REF_CONFIG_ENABLE, zldev->ref[index].config)) ++ return true; ++ ++ return false; + } + + /** +@@ -265,7 +271,7 @@ zl3073x_ref_is_enabled(struct zl3073x_dev *zldev, u8 index) + static inline u8 + zl3073x_synth_dpll_get(struct zl3073x_dev *zldev, u8 index) + { +- return zldev->synth[index].dpll; ++ return FIELD_GET(ZL_SYNTH_CTRL_DPLL_SEL, zldev->synth[index].ctrl); + } + + /** +@@ -278,7 +284,10 @@ zl3073x_synth_dpll_get(struct zl3073x_dev *zldev, u8 index) + static inline u32 + zl3073x_synth_freq_get(struct zl3073x_dev *zldev, u8 index) + { +- return zldev->synth[index].freq; ++ struct zl3073x_synth *synth = &zldev->synth[index]; ++ ++ return mul_u64_u32_div(synth->freq_base * synth->freq_m, ++ synth->freq_mult, synth->freq_n); + } + + /** +@@ -291,7 +300,7 @@ zl3073x_synth_freq_get(struct zl3073x_dev *zldev, u8 index) + static inline bool + zl3073x_synth_is_enabled(struct zl3073x_dev *zldev, u8 index) + { +- return zldev->synth[index].enabled; ++ return FIELD_GET(ZL_SYNTH_CTRL_EN, zldev->synth[index].ctrl); + } + + /** +@@ -304,7 +313,7 @@ zl3073x_synth_is_enabled(struct zl3073x_dev *zldev, u8 index) + static inline u8 + zl3073x_out_synth_get(struct zl3073x_dev *zldev, u8 index) + { +- return zldev->out[index].synth; ++ return FIELD_GET(ZL_OUTPUT_CTRL_SYNTH_SEL, zldev->out[index].ctrl); + } + + /** +@@ -321,10 +330,10 @@ zl3073x_out_is_enabled(struct zl3073x_dev *zldev, u8 index) + + /* Output is enabled only if associated synth is enabled */ + synth = zl3073x_out_synth_get(zldev, index); +- if (zl3073x_synth_is_enabled(zldev, synth)) +- return zldev->out[index].enabled; ++ if (!zl3073x_synth_is_enabled(zldev, synth)) ++ return false; + +- return false; ++ return FIELD_GET(ZL_OUTPUT_CTRL_EN, zldev->out[index].ctrl); + } + + /** +@@ -337,7 +346,7 @@ zl3073x_out_is_enabled(struct zl3073x_dev *zldev, u8 index) + static inline u8 + zl3073x_out_signal_format_get(struct zl3073x_dev *zldev, u8 index) + { +- return zldev->out[index].signal_format; ++ return FIELD_GET(ZL_OUTPUT_MODE_SIGNAL_FORMAT, zldev->out[index].mode); + } + + /** +-- +2.51.0 + diff --git a/queue-6.18/drbd-always-set-blk_feat_stable_writes.patch b/queue-6.18/drbd-always-set-blk_feat_stable_writes.patch new file mode 100644 index 0000000000..52e7bc6b30 --- /dev/null +++ b/queue-6.18/drbd-always-set-blk_feat_stable_writes.patch @@ -0,0 +1,94 @@ +From 45184e36cd1a999d958d4c20be0091937535fab4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 18:39:29 +0100 +Subject: drbd: always set BLK_FEAT_STABLE_WRITES +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Christoph Böhmwalder + +[ Upstream commit 2ebc8d600fb907fa6b1e7095c0b6d84fc47e91ea ] + +DRBD requires stable pages because it may read the same bio data +multiple times for local disk I/O and network transmission, and in +some cases for calculating checksums. + +The BLK_FEAT_STABLE_WRITES flag is set when the device is first +created, but blk_set_stacking_limits() clears it whenever a +backing device is attached. In some cases the flag may be +inherited from the backing device, but we want it to be enabled +at all times. + +Unconditionally re-enable BLK_FEAT_STABLE_WRITES in +drbd_reconsider_queue_parameters() after the queue parameter +negotiations. + +Also, document why we want this flag enabled in the first place. + +Fixes: 1a02f3a73f8c ("block: move the stable_writes flag to queue_limits") +Signed-off-by: Christoph Böhmwalder +Reviewed-by: Christoph Hellwig +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/block/drbd/drbd_main.c | 3 --- + drivers/block/drbd/drbd_nl.c | 20 +++++++++++++++++++- + 2 files changed, 19 insertions(+), 4 deletions(-) + +diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c +index c73376886e7a5..1f6ac9202b66a 100644 +--- a/drivers/block/drbd/drbd_main.c ++++ b/drivers/block/drbd/drbd_main.c +@@ -2659,9 +2659,6 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig + * connect. + */ + .max_hw_sectors = DRBD_MAX_BIO_SIZE_SAFE >> 8, +- .features = BLK_FEAT_WRITE_CACHE | BLK_FEAT_FUA | +- BLK_FEAT_ROTATIONAL | +- BLK_FEAT_STABLE_WRITES, + }; + + device = minor_to_device(minor); +diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c +index 91f3b8afb63ce..b502038be0a92 100644 +--- a/drivers/block/drbd/drbd_nl.c ++++ b/drivers/block/drbd/drbd_nl.c +@@ -1296,6 +1296,8 @@ void drbd_reconsider_queue_parameters(struct drbd_device *device, + lim.max_segments = drbd_backing_dev_max_segments(device); + } else { + lim.max_segments = BLK_MAX_SEGMENTS; ++ lim.features = BLK_FEAT_WRITE_CACHE | BLK_FEAT_FUA | ++ BLK_FEAT_ROTATIONAL | BLK_FEAT_STABLE_WRITES; + } + + lim.max_hw_sectors = new >> SECTOR_SHIFT; +@@ -1318,8 +1320,24 @@ void drbd_reconsider_queue_parameters(struct drbd_device *device, + lim.max_hw_discard_sectors = 0; + } + +- if (bdev) ++ if (bdev) { + blk_stack_limits(&lim, &b->limits, 0); ++ /* ++ * blk_set_stacking_limits() cleared the features, and ++ * blk_stack_limits() may or may not have inherited ++ * BLK_FEAT_STABLE_WRITES from the backing device. ++ * ++ * DRBD always requires stable writes because: ++ * 1. The same bio data is read for both local disk I/O and ++ * network transmission. If the page changes mid-flight, ++ * the local and remote copies could diverge. ++ * 2. When data integrity is enabled, DRBD calculates a ++ * checksum before sending the data. If the page changes ++ * between checksum calculation and transmission, the ++ * receiver will detect a checksum mismatch. ++ */ ++ lim.features |= BLK_FEAT_STABLE_WRITES; ++ } + + /* + * If we can handle "zeroes" efficiently on the protocol, we want to do +-- +2.51.0 + diff --git a/queue-6.18/drivers-iio-mpu3050-use-dev_err_probe-for-regulator-.patch b/queue-6.18/drivers-iio-mpu3050-use-dev_err_probe-for-regulator-.patch new file mode 100644 index 0000000000..20c7d93d08 --- /dev/null +++ b/queue-6.18/drivers-iio-mpu3050-use-dev_err_probe-for-regulator-.patch @@ -0,0 +1,42 @@ +From bd4c66d7673aab99fae2e1462316020015a09eac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 17:34:25 +0200 +Subject: drivers: iio: mpu3050: use dev_err_probe for regulator request + +From: Svyatoslav Ryhel + +[ Upstream commit b010880b9936da14f8035585ab57577aa05be23a ] + +Regulator requesting may result in deferred probing error which will +abort driver probing. To avoid this just use dev_err_probe which handles +deferred probing. + +Fixes: 3904b28efb2c ("iio: gyro: Add driver for the MPU-3050 gyroscope") +Signed-off-by: Svyatoslav Ryhel +Reviewed-by: Andy Shevchenko +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/gyro/mpu3050-core.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/iio/gyro/mpu3050-core.c b/drivers/iio/gyro/mpu3050-core.c +index 67ae7d1012bc2..ee2fcd20545de 100644 +--- a/drivers/iio/gyro/mpu3050-core.c ++++ b/drivers/iio/gyro/mpu3050-core.c +@@ -1162,10 +1162,8 @@ int mpu3050_common_probe(struct device *dev, + mpu3050->regs[1].supply = mpu3050_reg_vlogic; + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(mpu3050->regs), + mpu3050->regs); +- if (ret) { +- dev_err(dev, "Cannot get regulators\n"); +- return ret; +- } ++ if (ret) ++ return dev_err_probe(dev, ret, "Cannot get regulators\n"); + + ret = mpu3050_power_up(mpu3050); + if (ret) +-- +2.51.0 + diff --git a/queue-6.18/drm-amd-drop-amdgpu-kernel-modesetting-enabled-messa.patch b/queue-6.18/drm-amd-drop-amdgpu-kernel-modesetting-enabled-messa.patch new file mode 100644 index 0000000000..278524c271 --- /dev/null +++ b/queue-6.18/drm-amd-drop-amdgpu-kernel-modesetting-enabled-messa.patch @@ -0,0 +1,40 @@ +From 74964ba4b887597d9f8f6fdf39e863b2c406ad3e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 14 Dec 2025 19:12:19 -0600 +Subject: drm/amd: Drop "amdgpu kernel modesetting enabled" message + +From: Mario Limonciello (AMD) + +[ Upstream commit 8644084a74a4573278d6f454c6638ccd5965f4e2 ] + +The behavior for amdgpu was changed with commit e00e5c223878 +("drm/amdgpu: adjust drm_firmware_drivers_only() handling") to +potentially allow loading even if nomodeset was set, so the +message is no longer accurate. + +Just drop it to avoid confusion. + +Fixes: e00e5c223878 ("drm/amdgpu: adjust drm_firmware_drivers_only() handling") +Signed-off-by: Mario Limonciello (AMD) +Reviewed-by: Aurabindo Pillai +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +index ec9516d6ae976..3aa33c1de29b5 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +@@ -3155,7 +3155,6 @@ static int __init amdgpu_init(void) + if (r) + goto error_fence; + +- DRM_INFO("amdgpu kernel modesetting enabled.\n"); + amdgpu_register_atpx_handler(); + amdgpu_acpi_detect(); + +-- +2.51.0 + diff --git a/queue-6.18/drm-amdgpu-use-explicit-vcn-instance-0-in-sr-iov-ini.patch b/queue-6.18/drm-amdgpu-use-explicit-vcn-instance-0-in-sr-iov-ini.patch new file mode 100644 index 0000000000..4d2fed21c6 --- /dev/null +++ b/queue-6.18/drm-amdgpu-use-explicit-vcn-instance-0-in-sr-iov-ini.patch @@ -0,0 +1,179 @@ +From 66a650633b6c922ee17f71834d23d3b417a38887 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 15:25:25 +0530 +Subject: drm/amdgpu: Use explicit VCN instance 0 in SR-IOV init +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Srinivasan Shanmugam + +[ Upstream commit af26fa751c2eef66916acbf0d3c3e9159da56186 ] + +vcn_v2_0_start_sriov() declares a local variable "i" initialized to zero +and uses it only as the instance index in SOC15_REG_OFFSET(UVD, i, ...). +The value is never changed and all other fields are taken from +adev->vcn.inst[0], so this path only ever programs VCN instance 0. + +This triggered a Smatch: +warn: iterator 'i' not incremented + +Replace the dummy iterator with an explicit instance index of 0 in +SOC15_REG_OFFSET() calls. + +Fixes: dd26858a9cd8 ("drm/amdgpu: implement initialization part on VCN2.0 for SRIOV") +Reported by: Dan Carpenter +Cc: darlington Opara +Cc: Jinage Zhao +Cc: Monk Liu +Cc: Emily Deng +Cc: Christian König +Cc: Alex Deucher +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Emily Deng +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c | 45 ++++++++++++++------------- + 1 file changed, 23 insertions(+), 22 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c +index 8897dcc9c1a0a..e35fae9cdaf66 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c +@@ -1964,7 +1964,8 @@ static int vcn_v2_0_start_sriov(struct amdgpu_device *adev) + struct mmsch_v2_0_cmd_end end = { {0} }; + struct mmsch_v2_0_init_header *header; + uint32_t *init_table = adev->virt.mm_table.cpu_addr; +- uint8_t i = 0; ++ ++ /* This path only programs VCN instance 0. */ + + header = (struct mmsch_v2_0_init_header *)init_table; + direct_wt.cmd_header.command_type = MMSCH_COMMAND__DIRECT_REG_WRITE; +@@ -1983,93 +1984,93 @@ static int vcn_v2_0_start_sriov(struct amdgpu_device *adev) + size = AMDGPU_GPU_PAGE_ALIGN(adev->vcn.inst[0].fw->size + 4); + + MMSCH_V2_0_INSERT_DIRECT_RD_MOD_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_STATUS), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_STATUS), + 0xFFFFFFFF, 0x00000004); + + /* mc resume*/ + if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW), + adev->firmware.ucode[AMDGPU_UCODE_ID_VCN].tmr_mc_addr_lo); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE_64BIT_BAR_HIGH), + adev->firmware.ucode[AMDGPU_UCODE_ID_VCN].tmr_mc_addr_hi); + offset = 0; + } else { + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW), + lower_32_bits(adev->vcn.inst->gpu_addr)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE_64BIT_BAR_HIGH), + upper_32_bits(adev->vcn.inst->gpu_addr)); + offset = size; + } + + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_OFFSET0), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_OFFSET0), + 0); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_SIZE0), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_SIZE0), + size); + + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE1_64BIT_BAR_LOW), + lower_32_bits(adev->vcn.inst->gpu_addr + offset)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE1_64BIT_BAR_HIGH), + upper_32_bits(adev->vcn.inst->gpu_addr + offset)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_OFFSET1), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_OFFSET1), + 0); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_SIZE1), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_SIZE1), + AMDGPU_VCN_STACK_SIZE); + + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE2_64BIT_BAR_LOW), + lower_32_bits(adev->vcn.inst->gpu_addr + offset + + AMDGPU_VCN_STACK_SIZE)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE2_64BIT_BAR_HIGH), + upper_32_bits(adev->vcn.inst->gpu_addr + offset + + AMDGPU_VCN_STACK_SIZE)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_OFFSET2), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_OFFSET2), + 0); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_SIZE2), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_SIZE2), + AMDGPU_VCN_CONTEXT_SIZE); + + for (r = 0; r < adev->vcn.inst[0].num_enc_rings; ++r) { + ring = &adev->vcn.inst->ring_enc[r]; + ring->wptr = 0; + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_RB_BASE_LO), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_RB_BASE_LO), + lower_32_bits(ring->gpu_addr)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_RB_BASE_HI), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_RB_BASE_HI), + upper_32_bits(ring->gpu_addr)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_RB_SIZE), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_RB_SIZE), + ring->ring_size / 4); + } + + ring = &adev->vcn.inst->ring_dec; + ring->wptr = 0; + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_RBC_RB_64BIT_BAR_LOW), + lower_32_bits(ring->gpu_addr)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH), + upper_32_bits(ring->gpu_addr)); + /* force RBC into idle state */ +@@ -2080,7 +2081,7 @@ static int vcn_v2_0_start_sriov(struct amdgpu_device *adev) + tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1); + tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_RBC_RB_CNTL), tmp); ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_RBC_RB_CNTL), tmp); + + /* add end packet */ + tmp = sizeof(struct mmsch_v2_0_cmd_end); +-- +2.51.0 + diff --git a/queue-6.18/drm-amdkfd-fix-signal_eviction_fence-bool-return-val.patch b/queue-6.18/drm-amdkfd-fix-signal_eviction_fence-bool-return-val.patch new file mode 100644 index 0000000000..756862dc91 --- /dev/null +++ b/queue-6.18/drm-amdkfd-fix-signal_eviction_fence-bool-return-val.patch @@ -0,0 +1,79 @@ +From d27693b75fa0b7d25a668936b0f0586003ab9dee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 17 Dec 2025 15:21:57 +0530 +Subject: drm/amdkfd: Fix signal_eviction_fence() bool return value +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Srinivasan Shanmugam + +[ Upstream commit 31dc58adda9874420ab8fa5a2f9c43377745753a ] + +signal_eviction_fence() is declared to return bool, but returns -EINVAL +when no eviction fence is present. This makes the "no fence" or "the +NULL-fence" path evaluate to true and triggers a Smatch warning. + +v2: Return true instead to explicitly indicate that there is no eviction +fence to signal and that eviction is already complete. This matches the +existing caller logic where a NULL fence means "nothing to do" and +allows restore handling to proceed normally. (Christian) + +Fixes the below: +drivers/gpu/drm/amd/amdgpu/../amdkfd/kfd_process.c:2099 signal_eviction_fence() +warn: '(-22)' is not bool + +drivers/gpu/drm/amd/amdgpu/../amdkfd/kfd_process.c + 2090 static bool signal_eviction_fence(struct kfd_process *p) + ^^^^ + + 2091 { + 2092 struct dma_fence *ef; + 2093 bool ret; + 2094 + 2095 rcu_read_lock(); + 2096 ef = dma_fence_get_rcu_safe(&p->ef); + 2097 rcu_read_unlock(); + 2098 if (!ef) +--> 2099 return -EINVAL; + + This should be either true or false. + Probably true because presumably + it has been tested? + + 2100 + 2101 ret = dma_fence_check_and_signal(ef); + 2102 dma_fence_put(ef); + 2103 + 2104 return ret; + 2105 } + +Fixes: 37865e02e6cc ("drm/amdkfd: Fix eviction fence handling") +Reported by: Dan Carpenter +Cc: Philip Yang +Cc: Gang BA +Cc: Felix Kuehling +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Christian König +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdkfd/kfd_process.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c +index ddfe30c13e9d6..8ed513a77d38f 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c +@@ -1992,7 +1992,7 @@ static int signal_eviction_fence(struct kfd_process *p) + ef = dma_fence_get_rcu_safe(&p->ef); + rcu_read_unlock(); + if (!ef) +- return -EINVAL; ++ return true; + + ret = dma_fence_signal(ef); + dma_fence_put(ef); +-- +2.51.0 + diff --git a/queue-6.18/drm-buddy-release-free_trees-array-on-buddy-mm-teard.patch b/queue-6.18/drm-buddy-release-free_trees-array-on-buddy-mm-teard.patch new file mode 100644 index 0000000000..858ec03852 --- /dev/null +++ b/queue-6.18/drm-buddy-release-free_trees-array-on-buddy-mm-teard.patch @@ -0,0 +1,63 @@ +From c6759c03069827a81e3b34edb865affd3d3ea330 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Dec 2025 11:27:14 +0100 +Subject: drm/buddy: release free_trees array on buddy mm teardown +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Michał Grzelak + +[ Upstream commit 7d0507772406e129329983b8b807e5b499bd74fd ] + +During initialization of DRM buddy memory manager at drm_buddy_init, +mm->free_trees array is allocated for both clear and dirty RB trees. +During cleanup happening at drm_buddy_fini it is never freed, leading to +following memory leaks observed on xe module load & unload cycles: + + kmemleak_alloc+0x4a/0x90 + __kmalloc_cache_noprof+0x488/0x800 + drm_buddy_init+0xc2/0x330 [drm_buddy] + __xe_ttm_vram_mgr_init+0xc3/0x190 [xe] + xe_ttm_stolen_mgr_init+0xf5/0x9d0 [xe] + xe_device_probe+0x326/0x9e0 [xe] + xe_pci_probe+0x39a/0x610 [xe] + local_pci_probe+0x47/0xb0 + pci_device_probe+0xf3/0x260 + really_probe+0xf1/0x3c0 + __driver_probe_device+0x8c/0x180 + driver_probe_device+0x24/0xd0 + __driver_attach+0x10f/0x220 + bus_for_each_dev+0x7f/0xe0 + driver_attach+0x1e/0x30 + bus_add_driver+0x151/0x290 + +Deallocate array for free trees when cleaning up buddy memory manager +in the same way as if going through out_free_tree label. + +Fixes: d4cd665c98c1 ("drm/buddy: Separate clear and dirty free block trees") +Signed-off-by: Michał Grzelak +Reviewed-by: Lucas De Marchi +Reviewed-by: Matthew Auld +Signed-off-by: Arunpravin Paneer Selvam +Link: https://patch.msgid.link/20251208102714.4008260-2-michal.grzelak@intel.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/drm_buddy.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/drm_buddy.c b/drivers/gpu/drm/drm_buddy.c +index f2c92902e4a30..3f1a9892f2a39 100644 +--- a/drivers/gpu/drm/drm_buddy.c ++++ b/drivers/gpu/drm/drm_buddy.c +@@ -419,6 +419,7 @@ void drm_buddy_fini(struct drm_buddy *mm) + + for_each_free_tree(i) + kfree(mm->free_trees[i]); ++ kfree(mm->free_trees); + kfree(mm->roots); + } + EXPORT_SYMBOL(drm_buddy_fini); +-- +2.51.0 + diff --git a/queue-6.18/drm-hisilicon-hibmc-add-dp-mode-valid-check.patch b/queue-6.18/drm-hisilicon-hibmc-add-dp-mode-valid-check.patch new file mode 100644 index 0000000000..4f24fdbfab --- /dev/null +++ b/queue-6.18/drm-hisilicon-hibmc-add-dp-mode-valid-check.patch @@ -0,0 +1,115 @@ +From ee869c8f07c28fa50661fe4331911be4a3668c4d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 10 Dec 2025 10:37:57 +0800 +Subject: drm/hisilicon/hibmc: add dp mode valid check + +From: Baihan Li + +[ Upstream commit 607805abfb747b98f43aa57d6d9ba4caed4d106f ] + +If DP is connected, check the DP BW in mode_valid_ctx() to ensure +that DP's link rate supports high-resolution data transmission. + +Fixes: 0ab6ea261c1f ("drm/hisilicon/hibmc: add dp module in hibmc") +Signed-off-by: Baihan Li +Signed-off-by: Yongbang Shi +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Tao Tian +Link: https://patch.msgid.link/20251210023759.3944834-3-shiyongbang@huawei.com +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + .../gpu/drm/hisilicon/hibmc/dp/dp_config.h | 2 ++ + drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c | 10 ++++++++++ + drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h | 2 ++ + .../gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c | 19 +++++++++++++++++++ + 4 files changed, 33 insertions(+) + +diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_config.h b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_config.h +index 08f9e1caf7fcb..efb30a7584758 100644 +--- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_config.h ++++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_config.h +@@ -17,5 +17,7 @@ + #define HIBMC_DP_LINK_RATE_CAL 27 + #define HIBMC_DP_SYNC_DELAY(lanes) ((lanes) == 0x2 ? 86 : 46) + #define HIBMC_DP_INT_ENABLE 0xc ++/* HIBMC_DP_LINK_RATE_CAL * 10000 * 80% = 216000 */ ++#define DP_MODE_VALI_CAL 216000 + + #endif +diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c +index 0ec6ace2d0822..37549dafa06ca 100644 +--- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c ++++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c +@@ -264,6 +264,16 @@ void hibmc_dp_reset_link(struct hibmc_dp *dp) + dp->dp_dev->link.status.channel_equalized = false; + } + ++u8 hibmc_dp_get_link_rate(struct hibmc_dp *dp) ++{ ++ return dp->dp_dev->link.cap.link_rate; ++} ++ ++u8 hibmc_dp_get_lanes(struct hibmc_dp *dp) ++{ ++ return dp->dp_dev->link.cap.lanes; ++} ++ + static const struct hibmc_dp_color_raw g_rgb_raw[] = { + {CBAR_COLOR_BAR, 0x000, 0x000, 0x000}, + {CBAR_WHITE, 0xfff, 0xfff, 0xfff}, +diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h +index 59c1eae153c55..31316fe1ea8db 100644 +--- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h ++++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h +@@ -66,5 +66,7 @@ void hibmc_dp_hpd_cfg(struct hibmc_dp *dp); + void hibmc_dp_enable_int(struct hibmc_dp *dp); + void hibmc_dp_disable_int(struct hibmc_dp *dp); + bool hibmc_dp_check_hpd_status(struct hibmc_dp *dp, int exp_status); ++u8 hibmc_dp_get_link_rate(struct hibmc_dp *dp); ++u8 hibmc_dp_get_lanes(struct hibmc_dp *dp); + + #endif +diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c +index 4a66a107900a1..616821e3c933b 100644 +--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c ++++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c +@@ -13,6 +13,7 @@ + #include "hibmc_drm_drv.h" + #include "dp/dp_hw.h" + #include "dp/dp_comm.h" ++#include "dp/dp_config.h" + + #define DP_MASKED_SINK_HPD_PLUG_INT BIT(2) + +@@ -81,9 +82,27 @@ static int hibmc_dp_detect(struct drm_connector *connector, + return connector_status_disconnected; + } + ++static int hibmc_dp_mode_valid(struct drm_connector *connector, ++ const struct drm_display_mode *mode, ++ struct drm_modeset_acquire_ctx *ctx, ++ enum drm_mode_status *status) ++{ ++ struct hibmc_dp *dp = to_hibmc_dp(connector); ++ u64 cur_val, max_val; ++ ++ /* check DP link BW */ ++ cur_val = (u64)mode->clock * HIBMC_DP_BPP; ++ max_val = (u64)hibmc_dp_get_link_rate(dp) * DP_MODE_VALI_CAL * hibmc_dp_get_lanes(dp); ++ ++ *status = cur_val > max_val ? MODE_CLOCK_HIGH : MODE_OK; ++ ++ return 0; ++} ++ + static const struct drm_connector_helper_funcs hibmc_dp_conn_helper_funcs = { + .get_modes = hibmc_dp_connector_get_modes, + .detect_ctx = hibmc_dp_detect, ++ .mode_valid_ctx = hibmc_dp_mode_valid, + }; + + static int hibmc_dp_late_register(struct drm_connector *connector) +-- +2.51.0 + diff --git a/queue-6.18/drm-hisilicon-hibmc-adding-reset-colorbar-cfg-in-dp-.patch b/queue-6.18/drm-hisilicon-hibmc-adding-reset-colorbar-cfg-in-dp-.patch new file mode 100644 index 0000000000..d978c766d4 --- /dev/null +++ b/queue-6.18/drm-hisilicon-hibmc-adding-reset-colorbar-cfg-in-dp-.patch @@ -0,0 +1,42 @@ +From 38ad21b34f99ab3f4cc883c64f09d4b24b104127 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 10 Dec 2025 10:37:59 +0800 +Subject: drm/hisilicon/hibmc: Adding reset colorbar cfg in dp init. + +From: Baihan Li + +[ Upstream commit 6dad7fa8581e96321ec8a6a4f8160762466f539a ] + +Add colorbar disable operation before reset chontroller, to make sure +colorbar status is clear in the DP init, so if rmmod the driver and the +previous colorbar configuration will not affect the next time insmod the +driver. + +Fixes: 3c7623fb5bb6 ("drm/hisilicon/hibmc: Enable this hot plug detect of irq feature") +Signed-off-by: Baihan Li +Signed-off-by: Yongbang Shi +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Tao Tian +Link: https://patch.msgid.link/20251210023759.3944834-5-shiyongbang@huawei.com +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c +index 8f8ca940b6b26..d5bd3c45649b2 100644 +--- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c ++++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c +@@ -180,6 +180,8 @@ int hibmc_dp_hw_init(struct hibmc_dp *dp) + /* int init */ + writel(0, dp_dev->base + HIBMC_DP_INTR_ENABLE); + writel(HIBMC_DP_INT_RST, dp_dev->base + HIBMC_DP_INTR_ORIGINAL_STATUS); ++ /* clr colorbar */ ++ writel(0, dp_dev->base + HIBMC_DP_COLOR_BAR_CTRL); + /* rst */ + writel(0, dp_dev->base + HIBMC_DP_DPTX_RST_CTRL); + usleep_range(30, 50); +-- +2.51.0 + diff --git a/queue-6.18/drm-hisilicon-hibmc-fix-dp-probabilistical-detect-er.patch b/queue-6.18/drm-hisilicon-hibmc-fix-dp-probabilistical-detect-er.patch new file mode 100644 index 0000000000..657fafce13 --- /dev/null +++ b/queue-6.18/drm-hisilicon-hibmc-fix-dp-probabilistical-detect-er.patch @@ -0,0 +1,219 @@ +From 47fa8ab9f6ff2665dd4a33b26dd7d494ff338e5e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 10 Dec 2025 10:37:56 +0800 +Subject: drm/hisilicon/hibmc: fix dp probabilistical detect errors after HPD + irq + +From: Baihan Li + +[ Upstream commit 3906e7a3b26d683868704fe262db443207f392fe ] + +The issue is that drm_connector_helper_detect_from_ddc() returns wrong +status when plugging or unplugging the monitor, which may cause the link +failed err.[0] Use HPD pin status in DP's detect_ctx() for real physical +monitor in/out, and implement a complete DP detection including read DPCD, +check if it's a branch device and its sink count for different situations. + +[0]: + hibme-drm 0000:83:00.0: [drm] *ERROR* channel equalization failed 5 times + hibme-drm 0000:83:00.0: [drm] *ERROR* channel equalization failed 5 times + hibme-drm 0000:83:00.0: [drm] *ERROR* dp link training failed, ret: -16 + hibmc-drm 0000:83:00.0: [drm] *ERROR* hibme dp mode set failed: -16 + +Fixes: 3c7623fb5bb6 ("drm/hisilicon/hibmc: Enable this hot plug detect of irq feature") +Signed-off-by: Baihan Li +Signed-off-by: Yongbang Shi +Reviewed-by: Tao Tian +Link: https://patch.msgid.link/20251210023759.3944834-2-shiyongbang@huawei.com +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/hisilicon/hibmc/dp/dp_comm.h | 4 ++ + drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c | 19 +++++++ + drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h | 6 +++ + drivers/gpu/drm/hisilicon/hibmc/dp/dp_reg.h | 3 ++ + .../gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c | 52 +++++++++++++++++-- + 5 files changed, 80 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_comm.h b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_comm.h +index 4add05c7f161a..f9ee7ebfec55c 100644 +--- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_comm.h ++++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_comm.h +@@ -40,6 +40,10 @@ struct hibmc_dp_dev { + struct mutex lock; /* protects concurrent RW in hibmc_dp_reg_write_field() */ + struct hibmc_dp_link link; + u8 dpcd[DP_RECEIVER_CAP_SIZE]; ++ u8 downstream_ports[DP_MAX_DOWNSTREAM_PORTS]; ++ struct drm_dp_desc desc; ++ bool is_branch; ++ int hpd_status; + void __iomem *serdes_base; + }; + +diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c +index 8f0daec7d1749..0ec6ace2d0822 100644 +--- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c ++++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c +@@ -2,6 +2,7 @@ + // Copyright (c) 2024 Hisilicon Limited. + + #include ++#include + #include + #include "dp_config.h" + #include "dp_comm.h" +@@ -305,3 +306,21 @@ void hibmc_dp_set_cbar(struct hibmc_dp *dp, const struct hibmc_dp_cbar_cfg *cfg) + hibmc_dp_reg_write_field(dp_dev, HIBMC_DP_COLOR_BAR_CTRL, BIT(0), cfg->enable); + writel(HIBMC_DP_SYNC_EN_MASK, dp_dev->base + HIBMC_DP_TIMING_SYNC_CTRL); + } ++ ++bool hibmc_dp_check_hpd_status(struct hibmc_dp *dp, int exp_status) ++{ ++ u32 status; ++ int ret; ++ ++ ret = readl_poll_timeout(dp->dp_dev->base + HIBMC_DP_HPD_STATUS, status, ++ FIELD_GET(HIBMC_DP_HPD_CUR_STATE, status) == exp_status, ++ 1000, 100000); /* DP spec says 100ms */ ++ if (ret) { ++ drm_dbg_dp(dp->drm_dev, "wait hpd status timeout"); ++ return false; ++ } ++ ++ dp->dp_dev->hpd_status = exp_status; ++ ++ return true; ++} +diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h +index 665f5b166dfb5..59c1eae153c55 100644 +--- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h ++++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h +@@ -14,6 +14,11 @@ + + struct hibmc_dp_dev; + ++enum hibmc_hpd_status { ++ HIBMC_HPD_OUT, ++ HIBMC_HPD_IN, ++}; ++ + enum hibmc_dp_cbar_pattern { + CBAR_COLOR_BAR, + CBAR_WHITE, +@@ -60,5 +65,6 @@ void hibmc_dp_reset_link(struct hibmc_dp *dp); + void hibmc_dp_hpd_cfg(struct hibmc_dp *dp); + void hibmc_dp_enable_int(struct hibmc_dp *dp); + void hibmc_dp_disable_int(struct hibmc_dp *dp); ++bool hibmc_dp_check_hpd_status(struct hibmc_dp *dp, int exp_status); + + #endif +diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_reg.h b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_reg.h +index 394b1e933c3ae..64306abcd9866 100644 +--- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_reg.h ++++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_reg.h +@@ -24,6 +24,9 @@ + #define HIBMC_DP_CFG_AUX_READY_DATA_BYTE GENMASK(16, 12) + #define HIBMC_DP_CFG_AUX GENMASK(24, 17) + ++#define HIBMC_DP_HPD_STATUS 0x98 ++#define HIBMC_DP_HPD_CUR_STATE GENMASK(7, 4) ++ + #define HIBMC_DP_PHYIF_CTRL0 0xa0 + #define HIBMC_DP_CFG_SCRAMBLE_EN BIT(0) + #define HIBMC_DP_CFG_PAT_SEL GENMASK(7, 4) +diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c +index d06832e62e966..4a66a107900a1 100644 +--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c ++++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c +@@ -12,6 +12,7 @@ + + #include "hibmc_drm_drv.h" + #include "dp/dp_hw.h" ++#include "dp/dp_comm.h" + + #define DP_MASKED_SINK_HPD_PLUG_INT BIT(2) + +@@ -31,12 +32,53 @@ static int hibmc_dp_connector_get_modes(struct drm_connector *connector) + return count; + } + ++static bool hibmc_dp_get_dpcd(struct hibmc_dp_dev *dp_dev) ++{ ++ int ret; ++ ++ ret = drm_dp_read_dpcd_caps(dp_dev->aux, dp_dev->dpcd); ++ if (ret) ++ return false; ++ ++ dp_dev->is_branch = drm_dp_is_branch(dp_dev->dpcd); ++ ++ ret = drm_dp_read_desc(dp_dev->aux, &dp_dev->desc, dp_dev->is_branch); ++ if (ret) ++ return false; ++ ++ ret = drm_dp_read_downstream_info(dp_dev->aux, dp_dev->dpcd, dp_dev->downstream_ports); ++ if (ret) ++ return false; ++ ++ return true; ++} ++ + static int hibmc_dp_detect(struct drm_connector *connector, + struct drm_modeset_acquire_ctx *ctx, bool force) + { +- mdelay(200); ++ struct hibmc_dp *dp = to_hibmc_dp(connector); ++ struct hibmc_dp_dev *dp_dev = dp->dp_dev; ++ int ret; ++ ++ if (dp->irq_status) { ++ if (dp_dev->hpd_status != HIBMC_HPD_IN) ++ return connector_status_disconnected; ++ } ++ ++ if (!hibmc_dp_get_dpcd(dp_dev)) ++ return connector_status_disconnected; ++ ++ if (!dp_dev->is_branch) ++ return connector_status_connected; ++ ++ if (drm_dp_read_sink_count_cap(connector, dp_dev->dpcd, &dp_dev->desc) && ++ dp_dev->downstream_ports[0] & DP_DS_PORT_HPD) { ++ ret = drm_dp_read_sink_count(dp_dev->aux); ++ if (ret > 0) ++ return connector_status_connected; ++ } + +- return drm_connector_helper_detect_from_ddc(connector, ctx, force); ++ return connector_status_disconnected; + } + + static const struct drm_connector_helper_funcs hibmc_dp_conn_helper_funcs = { +@@ -115,7 +157,7 @@ irqreturn_t hibmc_dp_hpd_isr(int irq, void *arg) + { + struct drm_device *dev = (struct drm_device *)arg; + struct hibmc_drm_private *priv = to_hibmc_drm_private(dev); +- int idx; ++ int idx, exp_status; + + if (!drm_dev_enter(dev, &idx)) + return -ENODEV; +@@ -123,12 +165,14 @@ irqreturn_t hibmc_dp_hpd_isr(int irq, void *arg) + if (priv->dp.irq_status & DP_MASKED_SINK_HPD_PLUG_INT) { + drm_dbg_dp(&priv->dev, "HPD IN isr occur!\n"); + hibmc_dp_hpd_cfg(&priv->dp); ++ exp_status = HIBMC_HPD_IN; + } else { + drm_dbg_dp(&priv->dev, "HPD OUT isr occur!\n"); + hibmc_dp_reset_link(&priv->dp); ++ exp_status = HIBMC_HPD_OUT; + } + +- if (dev->registered) ++ if (hibmc_dp_check_hpd_status(&priv->dp, exp_status)) + drm_connector_helper_hpd_irq_event(&priv->dp.connector); + + drm_dev_exit(idx); +-- +2.51.0 + diff --git a/queue-6.18/drm-hisilicon-hibmc-fix-no-showing-problem-with-load.patch b/queue-6.18/drm-hisilicon-hibmc-fix-no-showing-problem-with-load.patch new file mode 100644 index 0000000000..529a645a5f --- /dev/null +++ b/queue-6.18/drm-hisilicon-hibmc-fix-no-showing-problem-with-load.patch @@ -0,0 +1,56 @@ +From f957e09afad9fd831cb5d2e01c7a97c88c858e30 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 10 Dec 2025 10:37:58 +0800 +Subject: drm/hisilicon/hibmc: fix no showing problem with loading hibmc + manually + +From: Baihan Li + +[ Upstream commit 0607052a6aee1e3d218a99fae70ba9f14b3b47ed ] + +When using command rmmod and insmod, there is no showing in second time +insmoding. Because DP controller won't send HPD signals, if connection +doesn't change or controller isn't reset. So add reset before unreset +in hibmc_dp_hw_init(). + +And also need to move the HDCP cfg after DP controller de-resets, so +that HDCP configuration takes effect. + +Fixes: 3c7623fb5bb6 ("drm/hisilicon/hibmc: Enable this hot plug detect of irq feature") +Signed-off-by: Baihan Li +Signed-off-by: Yongbang Shi +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Tao Tian +Link: https://patch.msgid.link/20251210023759.3944834-4-shiyongbang@huawei.com +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c +index 37549dafa06ca..8f8ca940b6b26 100644 +--- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c ++++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c +@@ -177,13 +177,16 @@ int hibmc_dp_hw_init(struct hibmc_dp *dp) + dp_dev->link.cap.lanes = 0x2; + dp_dev->link.cap.link_rate = DP_LINK_BW_8_1; + +- /* hdcp data */ +- writel(HIBMC_DP_HDCP, dp_dev->base + HIBMC_DP_HDCP_CFG); + /* int init */ + writel(0, dp_dev->base + HIBMC_DP_INTR_ENABLE); + writel(HIBMC_DP_INT_RST, dp_dev->base + HIBMC_DP_INTR_ORIGINAL_STATUS); + /* rst */ ++ writel(0, dp_dev->base + HIBMC_DP_DPTX_RST_CTRL); ++ usleep_range(30, 50); ++ /* de-rst */ + writel(HIBMC_DP_DPTX_RST, dp_dev->base + HIBMC_DP_DPTX_RST_CTRL); ++ /* hdcp data */ ++ writel(HIBMC_DP_HDCP, dp_dev->base + HIBMC_DP_HDCP_CFG); + /* clock enable */ + writel(HIBMC_DP_CLK_EN, dp_dev->base + HIBMC_DP_DPTX_CLK_CTRL); + +-- +2.51.0 + diff --git a/queue-6.18/drm-msm-a2xx-fix-pixel-shader-start-on-a225.patch b/queue-6.18/drm-msm-a2xx-fix-pixel-shader-start-on-a225.patch new file mode 100644 index 0000000000..fcca0cc4f6 --- /dev/null +++ b/queue-6.18/drm-msm-a2xx-fix-pixel-shader-start-on-a225.patch @@ -0,0 +1,42 @@ +From bcd4994c31b5bf18026999342af431307778c49b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 21 Nov 2025 18:13:03 +0200 +Subject: drm/msm/a2xx: fix pixel shader start on A225 + +From: Dmitry Baryshkov + +[ Upstream commit 6a7b0a670ba4d283285d76d45233cbecc5af5e40 ] + +A225 has a different PixelShader start address, write correct address +while initializing GPU. + +Fixes: 21af872cd8c6 ("drm/msm/adreno: add a2xx") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Patchwork: https://patchwork.freedesktop.org/patch/689906/ +Message-ID: <20251121-a225-v1-1-a1bab651d186@oss.qualcomm.com> +Signed-off-by: Rob Clark +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/adreno/a2xx_gpu.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/msm/adreno/a2xx_gpu.c b/drivers/gpu/drm/msm/adreno/a2xx_gpu.c +index 963c0f669ee50..e67ed58aa3d8f 100644 +--- a/drivers/gpu/drm/msm/adreno/a2xx_gpu.c ++++ b/drivers/gpu/drm/msm/adreno/a2xx_gpu.c +@@ -77,7 +77,10 @@ static bool a2xx_me_init(struct msm_gpu *gpu) + + /* Vertex and Pixel Shader Start Addresses in instructions + * (3 DWORDS per instruction) */ +- OUT_RING(ring, 0x80000180); ++ if (adreno_is_a225(adreno_gpu)) ++ OUT_RING(ring, 0x80000300); ++ else ++ OUT_RING(ring, 0x80000180); + /* Maximum Contexts */ + OUT_RING(ring, 0x00000001); + /* Write Confirm Interval and The CP will wait the +-- +2.51.0 + diff --git a/queue-6.18/drm-msm-disp-dpu-add-merge3d-support-for-sc7280.patch b/queue-6.18/drm-msm-disp-dpu-add-merge3d-support-for-sc7280.patch new file mode 100644 index 0000000000..9862ac5fb3 --- /dev/null +++ b/queue-6.18/drm-msm-disp-dpu-add-merge3d-support-for-sc7280.patch @@ -0,0 +1,83 @@ +From 4815583415cefc3f01ce7ea766564f79feeeff6b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 1 Jan 2026 10:34:38 +0530 +Subject: drm/msm/disp/dpu: add merge3d support for sc7280 + +From: Mahadevan P + +[ Upstream commit 2892de3f4f985fa779c330468e2f341fdb762ccd ] + +On SC7280 targets, display modes with a width greater than the +max_mixer_width (2400) are rejected during mode validation when +merge3d is disabled. This limitation exists because, without a +3D merge block, two layer mixers cannot be combined(non-DSC interface), +preventing large layers from being split across mixers. As a result, +higher resolution modes cannot be supported. + +Enable merge3d support on SC7280 to allow combining streams from +two layer mixers into a single non-DSC interface. This capability +removes the width restriction and enables buffer sizes beyond the +2400-pixel limit. + +Fixes: 591e34a091d1 ("drm/msm/disp/dpu1: add support for display for SC7280 target") +Signed-off-by: Mahadevan P +Reviewed-by: Dmitry Baryshkov +Patchwork: https://patchwork.freedesktop.org/patch/696713/ +Link: https://lore.kernel.org/r/20260101-4k-v2-1-712ae3c1f816@oss.qualcomm.com +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + .../gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h +index 8f978b9c34520..2f8688224f343 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h +@@ -13,6 +13,7 @@ static const struct dpu_caps sc7280_dpu_caps = { + .has_dim_layer = true, + .has_idle_pc = true, + .max_linewidth = 2400, ++ .has_3d_merge = true, + .pixel_ram_size = DEFAULT_PIXEL_RAM_SIZE, + }; + +@@ -134,17 +135,24 @@ static const struct dpu_pingpong_cfg sc7280_pp[] = { + .name = "pingpong_2", .id = PINGPONG_2, + .base = 0x6b000, .len = 0, + .sblk = &sc7280_pp_sblk, +- .merge_3d = 0, ++ .merge_3d = MERGE_3D_1, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 10), + }, { + .name = "pingpong_3", .id = PINGPONG_3, + .base = 0x6c000, .len = 0, + .sblk = &sc7280_pp_sblk, +- .merge_3d = 0, ++ .merge_3d = MERGE_3D_1, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 11), + }, + }; + ++static const struct dpu_merge_3d_cfg sc7280_merge_3d[] = { ++ { ++ .name = "merge_3d_1", .id = MERGE_3D_1, ++ .base = 0x4f000, .len = 0x8, ++ }, ++}; ++ + /* NOTE: sc7280 only has one DSC hard slice encoder */ + static const struct dpu_dsc_cfg sc7280_dsc[] = { + { +@@ -247,6 +255,8 @@ const struct dpu_mdss_cfg dpu_sc7280_cfg = { + .mixer = sc7280_lm, + .pingpong_count = ARRAY_SIZE(sc7280_pp), + .pingpong = sc7280_pp, ++ .merge_3d_count = ARRAY_SIZE(sc7280_merge_3d), ++ .merge_3d = sc7280_merge_3d, + .dsc_count = ARRAY_SIZE(sc7280_dsc), + .dsc = sc7280_dsc, + .wb_count = ARRAY_SIZE(sc7280_wb), +-- +2.51.0 + diff --git a/queue-6.18/drm-msm-disp-set-num_planes-to-1-for-interleaved-yuv.patch b/queue-6.18/drm-msm-disp-set-num_planes-to-1-for-interleaved-yuv.patch new file mode 100644 index 0000000000..16dee234cb --- /dev/null +++ b/queue-6.18/drm-msm-disp-set-num_planes-to-1-for-interleaved-yuv.patch @@ -0,0 +1,61 @@ +From 82175023e362b228c2f6ada414acf937425ba363 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 Nov 2025 05:43:28 +0200 +Subject: drm/msm/disp: set num_planes to 1 for interleaved YUV formats + +From: Dmitry Baryshkov + +[ Upstream commit 6421e1c5075b7e1536a8fcbe6b4086db07103048 ] + +Interleaved YUV formats use only one plane for all pixel data. Specify +num_planes = 1 for those formats. This was left unnoticed since +_dpu_format_populate_plane_sizes_linear() overrides layout->num_planes. + +Fixes: 25fdd5933e4c ("drm/msm: Add SDM845 DPU support") +Reviewed-by: Jessica Zhang +Patchwork: https://patchwork.freedesktop.org/patch/688162/ +Link: https://lore.kernel.org/r/20251114-dpu-formats-v3-1-cae312379d49@oss.qualcomm.com +Tested-by: Luca Weiss # qcm6490-fairphone-fp5 +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/disp/mdp_format.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/msm/disp/mdp_format.c b/drivers/gpu/drm/msm/disp/mdp_format.c +index 426782d50cb49..eebedb1a2636e 100644 +--- a/drivers/gpu/drm/msm/disp/mdp_format.c ++++ b/drivers/gpu/drm/msm/disp/mdp_format.c +@@ -479,25 +479,25 @@ static const struct msm_format mdp_formats[] = { + 0, BPC8, BPC8, BPC8, + C2_R_Cr, C0_G_Y, C1_B_Cb, C0_G_Y, + false, CHROMA_H2V1, 4, 2, MSM_FORMAT_FLAG_YUV, +- MDP_FETCH_LINEAR, 2), ++ MDP_FETCH_LINEAR, 1), + + INTERLEAVED_YUV_FMT(UYVY, + 0, BPC8, BPC8, BPC8, + C1_B_Cb, C0_G_Y, C2_R_Cr, C0_G_Y, + false, CHROMA_H2V1, 4, 2, MSM_FORMAT_FLAG_YUV, +- MDP_FETCH_LINEAR, 2), ++ MDP_FETCH_LINEAR, 1), + + INTERLEAVED_YUV_FMT(YUYV, + 0, BPC8, BPC8, BPC8, + C0_G_Y, C1_B_Cb, C0_G_Y, C2_R_Cr, + false, CHROMA_H2V1, 4, 2, MSM_FORMAT_FLAG_YUV, +- MDP_FETCH_LINEAR, 2), ++ MDP_FETCH_LINEAR, 1), + + INTERLEAVED_YUV_FMT(YVYU, + 0, BPC8, BPC8, BPC8, + C0_G_Y, C2_R_Cr, C0_G_Y, C1_B_Cb, + false, CHROMA_H2V1, 4, 2, MSM_FORMAT_FLAG_YUV, +- MDP_FETCH_LINEAR, 2), ++ MDP_FETCH_LINEAR, 1), + + /* 3 plane YUV */ + PLANAR_YUV_FMT(YUV420, +-- +2.51.0 + diff --git a/queue-6.18/drm-msm-dp-avoid-division-by-zero-in-msm_dp_ctrl_con.patch b/queue-6.18/drm-msm-dp-avoid-division-by-zero-in-msm_dp_ctrl_con.patch new file mode 100644 index 0000000000..0a9cff7dc1 --- /dev/null +++ b/queue-6.18/drm-msm-dp-avoid-division-by-zero-in-msm_dp_ctrl_con.patch @@ -0,0 +1,90 @@ +From e886decb9553d211ed47ffe9f69577c9aa96b49a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Jan 2026 17:00:31 -0700 +Subject: drm/msm/dp: Avoid division by zero in msm_dp_ctrl_config_msa() + +From: Nathan Chancellor + +[ Upstream commit f185076da44c774241a16a82a7773ece3c1c607b ] + +An (admittedly problematic) optimization change in LLVM 20 [1] turns +known division by zero into the equivalent of __builtin_unreachable(), +which invokes undefined behavior if it is encountered in a control flow +graph, destroying code generation. When compile testing for x86_64, +objtool flags an instance of this optimization triggering in +msm_dp_ctrl_config_msa(), inlined into msm_dp_ctrl_on_stream(): + + drivers/gpu/drm/msm/msm.o: warning: objtool: msm_dp_ctrl_on_stream(): unexpected end of section .text.msm_dp_ctrl_on_stream + +The zero division happens if the else branch in the first if statement +in msm_dp_ctrl_config_msa() is taken because pixel_div is initialized to +zero and it is not possible for LLVM to eliminate the else branch since +rate is still not known after inlining into msm_dp_ctrl_on_stream(). + +Transform the if statements into a switch statement with a default case +with the existing error print and an early return to avoid the invalid +division. Add a comment to note this helps the compiler, even though the +case is known to be unreachable. With this, pixel_dev's default zero +initialization can be dropped, as it is dead with this change. + +Fixes: c943b4948b58 ("drm/msm/dp: add displayPort driver support") +Link: https://github.com/llvm/llvm-project/commit/37932643abab699e8bb1def08b7eb4eae7ff1448 [1] +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202601081959.9UVJEOfP-lkp@intel.com/ +Suggested-by: Konrad Dybcio +Signed-off-by: Nathan Chancellor +Reviewed-by: Dmitry Baryshkov +Patchwork: https://patchwork.freedesktop.org/patch/698355/ +Link: https://lore.kernel.org/r/20260113-drm-msm-dp_ctrl-avoid-zero-div-v2-1-f1aa67bf6e8e@kernel.org +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/dp/dp_ctrl.c | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c +index c42fd2c17a328..38ed4de8313e3 100644 +--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c ++++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c +@@ -2395,20 +2395,32 @@ static void msm_dp_ctrl_config_msa(struct msm_dp_ctrl_private *ctrl, + bool is_ycbcr_420) + { + u32 pixel_m, pixel_n; +- u32 mvid, nvid, pixel_div = 0, dispcc_input_rate; ++ u32 mvid, nvid, pixel_div, dispcc_input_rate; + u32 const nvid_fixed = DP_LINK_CONSTANT_N_VALUE; + u32 const link_rate_hbr2 = 540000; + u32 const link_rate_hbr3 = 810000; + unsigned long den, num; + +- if (rate == link_rate_hbr3) ++ switch (rate) { ++ case link_rate_hbr3: + pixel_div = 6; +- else if (rate == 162000 || rate == 270000) +- pixel_div = 2; +- else if (rate == link_rate_hbr2) ++ break; ++ case link_rate_hbr2: + pixel_div = 4; +- else ++ break; ++ case 162000: ++ case 270000: ++ pixel_div = 2; ++ break; ++ default: ++ /* ++ * This cannot be reached but the compiler is not able to know ++ * that statically so return early to avoid a possibly invalid ++ * division. ++ */ + DRM_ERROR("Invalid pixel mux divider\n"); ++ return; ++ } + + dispcc_input_rate = (rate * 10) / pixel_div; + +-- +2.51.0 + diff --git a/queue-6.18/drm-msm-dp-update-msm_dp_controller-ids-for-sa8775p.patch b/queue-6.18/drm-msm-dp-update-msm_dp_controller-ids-for-sa8775p.patch new file mode 100644 index 0000000000..ef593dc341 --- /dev/null +++ b/queue-6.18/drm-msm-dp-update-msm_dp_controller-ids-for-sa8775p.patch @@ -0,0 +1,41 @@ +From 40bf0519e82342624d0aa729deecb8b777a2e4e6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 25 Nov 2025 16:26:20 +0530 +Subject: drm/msm/dp: Update msm_dp_controller IDs for sa8775p + +From: Mani Chandana Ballary Kuntumalla + +[ Upstream commit 1338e8ae4084e55c0359a79e617b2ae183d01579 ] + +The Qualcomm SA8775P platform comes with 2 DisplayPort controllers +for each mdss. Update controller id for DPTX0 and DPTX1 of mdss1. + +Fixes: dcb380d19e58 ("drm/msm/dp: Add DisplayPort controller for SA8775P") +Signed-off-by: Mani Chandana Ballary Kuntumalla +Reviewed-by: Dmitry Baryshkov +Patchwork: https://patchwork.freedesktop.org/patch/690234/ +Link: https://lore.kernel.org/r/20251125105622.1755651-2-quic_mkuntuma@quicinc.com +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/dp/dp_display.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c +index d87d47cc7ec3e..f247aad553975 100644 +--- a/drivers/gpu/drm/msm/dp/dp_display.c ++++ b/drivers/gpu/drm/msm/dp/dp_display.c +@@ -133,8 +133,8 @@ struct msm_dp_desc { + static const struct msm_dp_desc msm_dp_desc_sa8775p[] = { + { .io_start = 0x0af54000, .id = MSM_DP_CONTROLLER_0, .wide_bus_supported = true }, + { .io_start = 0x0af5c000, .id = MSM_DP_CONTROLLER_1, .wide_bus_supported = true }, +- { .io_start = 0x22154000, .id = MSM_DP_CONTROLLER_2, .wide_bus_supported = true }, +- { .io_start = 0x2215c000, .id = MSM_DP_CONTROLLER_3, .wide_bus_supported = true }, ++ { .io_start = 0x22154000, .id = MSM_DP_CONTROLLER_0, .wide_bus_supported = true }, ++ { .io_start = 0x2215c000, .id = MSM_DP_CONTROLLER_1, .wide_bus_supported = true }, + {} + }; + +-- +2.51.0 + diff --git a/queue-6.18/drm-msm-dpu-fix-cmd-panels-on-dpu-1.x-3.x.patch b/queue-6.18/drm-msm-dpu-fix-cmd-panels-on-dpu-1.x-3.x.patch new file mode 100644 index 0000000000..57a46a5422 --- /dev/null +++ b/queue-6.18/drm-msm-dpu-fix-cmd-panels-on-dpu-1.x-3.x.patch @@ -0,0 +1,48 @@ +From 5bea649d4b36f77fed8eb78b0f48ceb7c53eaacc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 28 Dec 2025 06:02:28 +0200 +Subject: drm/msm/dpu: fix CMD panels on DPU 1.x - 3.x + +From: Dmitry Baryshkov + +[ Upstream commit 59ca3d11f5311d9167015fe4f431701614ae0048 ] + +DPU units before 4.x don't have a separate CTL_START IRQ to mark the +begin of the data transfer. In such a case, wait for the frame transfer +to complete rather than trying to wait for the CTL_START interrupt (and +obviously hitting the timeout). + +Fixes: 050770cbbd26 ("drm/msm/dpu: Fix timeout issues on command mode panels") +Reported-by: Alexey Minnekhanov +Closes: https://lore.kernel.org/r/8e1d33ff-d902-4ae9-9162-e00d17a5e6d1@postmarketos.org +Patchwork: https://patchwork.freedesktop.org/patch/696490/ +Link: https://lore.kernel.org/r/20251228-mdp5-drop-dpu3-v4-2-7497c3d39179@oss.qualcomm.com +Tested-by: Alexey Minnekhanov +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c +index 0ec6d67c7c70b..93db1484f6069 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c +@@ -681,10 +681,11 @@ static int dpu_encoder_phys_cmd_wait_for_commit_done( + if (!dpu_encoder_phys_cmd_is_master(phys_enc)) + return 0; + +- if (phys_enc->hw_ctl->ops.is_started(phys_enc->hw_ctl)) +- return dpu_encoder_phys_cmd_wait_for_tx_complete(phys_enc); ++ if (phys_enc->irq[INTR_IDX_CTL_START] && ++ !phys_enc->hw_ctl->ops.is_started(phys_enc->hw_ctl)) ++ return _dpu_encoder_phys_cmd_wait_for_ctl_start(phys_enc); + +- return _dpu_encoder_phys_cmd_wait_for_ctl_start(phys_enc); ++ return dpu_encoder_phys_cmd_wait_for_tx_complete(phys_enc); + } + + static void dpu_encoder_phys_cmd_handle_post_kickoff( +-- +2.51.0 + diff --git a/queue-6.18/drm-msm-dpu-fix-wd-timer-handling-on-dpu-8.x.patch b/queue-6.18/drm-msm-dpu-fix-wd-timer-handling-on-dpu-8.x.patch new file mode 100644 index 0000000000..bb4c257059 --- /dev/null +++ b/queue-6.18/drm-msm-dpu-fix-wd-timer-handling-on-dpu-8.x.patch @@ -0,0 +1,198 @@ +From 3a8bc2a0183b7ab60cfb5caf67f1febbcc16bcbd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Dec 2025 09:17:57 +0200 +Subject: drm/msm/dpu: fix WD timer handling on DPU 8.x + +From: Dmitry Baryshkov + +[ Upstream commit 794b0e68caba49b950b42ec32e364028c2facf57 ] + +Since DPU 8.x Watchdog timer settings were moved from the TOP to the +INTF block. Support programming the timer in the INTF block. Fixes tag +points to the commit which removed register access to those registers on +DPU 8.x+ (and which also should have added proper support for WD timer +on those devices). + +Fixes: 43e3293fc614 ("drm/msm/dpu: add support for MDP_TOP blackhole") +Reviewed-by: Marijn Suijten +Signed-off-by: Dmitry Baryshkov +Patchwork: https://patchwork.freedesktop.org/patch/696586/ +Link: https://lore.kernel.org/r/20251230-intf-fix-wd-v6-2-98203d150611@oss.qualcomm.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 4 +- + drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c | 49 +++++++++++++++++++-- + drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h | 3 +- + drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c | 7 --- + drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h | 7 +++ + 5 files changed, 57 insertions(+), 13 deletions(-) + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +index 7b90c59792f6b..777eab5ad844e 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +@@ -785,13 +785,13 @@ static void _dpu_encoder_update_vsync_source(struct dpu_encoder_virt *dpu_enc, + } + + vsync_cfg.vsync_source = disp_info->vsync_source; ++ vsync_cfg.frame_rate = drm_mode_vrefresh(&dpu_enc->base.crtc->state->adjusted_mode); + + if (hw_mdptop->ops.setup_vsync_source) { + for (i = 0; i < dpu_enc->num_phys_encs; i++) + vsync_cfg.ppnumber[i] = dpu_enc->hw_pp[i]->idx; + + vsync_cfg.pp_count = dpu_enc->num_phys_encs; +- vsync_cfg.frame_rate = drm_mode_vrefresh(&dpu_enc->base.crtc->state->adjusted_mode); + + hw_mdptop->ops.setup_vsync_source(hw_mdptop, &vsync_cfg); + } +@@ -801,7 +801,7 @@ static void _dpu_encoder_update_vsync_source(struct dpu_encoder_virt *dpu_enc, + + if (phys_enc->has_intf_te && phys_enc->hw_intf->ops.vsync_sel) + phys_enc->hw_intf->ops.vsync_sel(phys_enc->hw_intf, +- vsync_cfg.vsync_source); ++ &vsync_cfg); + } + } + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c +index a80ac82a96255..7e620f5909849 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c +@@ -67,6 +67,10 @@ + #define INTF_MISR_CTRL 0x180 + #define INTF_MISR_SIGNATURE 0x184 + ++#define INTF_WD_TIMER_0_CTL 0x230 ++#define INTF_WD_TIMER_0_CTL2 0x234 ++#define INTF_WD_TIMER_0_LOAD_VALUE 0x238 ++ + #define INTF_MUX 0x25C + #define INTF_STATUS 0x26C + #define INTF_AVR_CONTROL 0x270 +@@ -475,7 +479,20 @@ static int dpu_hw_intf_get_vsync_info(struct dpu_hw_intf *intf, + } + + static void dpu_hw_intf_vsync_sel(struct dpu_hw_intf *intf, +- enum dpu_vsync_source vsync_source) ++ struct dpu_vsync_source_cfg *cfg) ++{ ++ struct dpu_hw_blk_reg_map *c; ++ ++ if (!intf) ++ return; ++ ++ c = &intf->hw; ++ ++ DPU_REG_WRITE(c, INTF_TEAR_MDP_VSYNC_SEL, (cfg->vsync_source & 0xf)); ++} ++ ++static void dpu_hw_intf_vsync_sel_v8(struct dpu_hw_intf *intf, ++ struct dpu_vsync_source_cfg *cfg) + { + struct dpu_hw_blk_reg_map *c; + +@@ -484,7 +501,30 @@ static void dpu_hw_intf_vsync_sel(struct dpu_hw_intf *intf, + + c = &intf->hw; + +- DPU_REG_WRITE(c, INTF_TEAR_MDP_VSYNC_SEL, (vsync_source & 0xf)); ++ if (cfg->vsync_source >= DPU_VSYNC_SOURCE_WD_TIMER_4 && ++ cfg->vsync_source <= DPU_VSYNC_SOURCE_WD_TIMER_1) { ++ pr_warn_once("DPU 8.x supports only GPIOs and timer0 as TE sources\n"); ++ return; ++ } ++ ++ if (cfg->vsync_source == DPU_VSYNC_SOURCE_WD_TIMER_0) { ++ u32 reg; ++ ++ DPU_REG_WRITE(c, INTF_WD_TIMER_0_LOAD_VALUE, ++ CALCULATE_WD_LOAD_VALUE(cfg->frame_rate)); ++ ++ DPU_REG_WRITE(c, INTF_WD_TIMER_0_CTL, BIT(0)); /* clear timer */ ++ ++ reg = BIT(8); /* enable heartbeat timer */ ++ reg |= BIT(0); /* enable WD timer */ ++ reg |= BIT(1); /* select default 16 clock ticks */ ++ DPU_REG_WRITE(c, INTF_WD_TIMER_0_CTL2, reg); ++ ++ /* make sure that timers are enabled/disabled for vsync state */ ++ wmb(); ++ } ++ ++ dpu_hw_intf_vsync_sel(intf, cfg); + } + + static void dpu_hw_intf_disable_autorefresh(struct dpu_hw_intf *intf, +@@ -598,7 +638,10 @@ struct dpu_hw_intf *dpu_hw_intf_init(struct drm_device *dev, + c->ops.enable_tearcheck = dpu_hw_intf_enable_te; + c->ops.disable_tearcheck = dpu_hw_intf_disable_te; + c->ops.connect_external_te = dpu_hw_intf_connect_external_te; +- c->ops.vsync_sel = dpu_hw_intf_vsync_sel; ++ if (mdss_rev->core_major_ver >= 8) ++ c->ops.vsync_sel = dpu_hw_intf_vsync_sel_v8; ++ else ++ c->ops.vsync_sel = dpu_hw_intf_vsync_sel; + c->ops.disable_autorefresh = dpu_hw_intf_disable_autorefresh; + } + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h +index f31067a9aaf1d..e84ab849d71a9 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h +@@ -12,6 +12,7 @@ + #include "dpu_hw_util.h" + + struct dpu_hw_intf; ++struct dpu_vsync_source_cfg; + + /* intf timing settings */ + struct dpu_hw_intf_timing_params { +@@ -107,7 +108,7 @@ struct dpu_hw_intf_ops { + + int (*connect_external_te)(struct dpu_hw_intf *intf, bool enable_external_te); + +- void (*vsync_sel)(struct dpu_hw_intf *intf, enum dpu_vsync_source vsync_source); ++ void (*vsync_sel)(struct dpu_hw_intf *intf, struct dpu_vsync_source_cfg *cfg); + + /** + * Disable autorefresh if enabled +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c +index 96dc10589bee6..1ebd75d4f9be8 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c +@@ -22,13 +22,6 @@ + #define TRAFFIC_SHAPER_WR_CLIENT(num) (0x060 + (num * 4)) + #define TRAFFIC_SHAPER_FIXPOINT_FACTOR 4 + +-#define MDP_TICK_COUNT 16 +-#define XO_CLK_RATE 19200 +-#define MS_TICKS_IN_SEC 1000 +- +-#define CALCULATE_WD_LOAD_VALUE(fps) \ +- ((uint32_t)((MS_TICKS_IN_SEC * XO_CLK_RATE)/(MDP_TICK_COUNT * fps))) +- + static void dpu_hw_setup_split_pipe(struct dpu_hw_mdp *mdp, + struct split_pipe_cfg *cfg) + { +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h +index 67b08e99335dc..6fe65bc3bff4e 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h +@@ -21,6 +21,13 @@ + + #define TO_S15D16(_x_)((_x_) << 7) + ++#define MDP_TICK_COUNT 16 ++#define XO_CLK_RATE 19200 ++#define MS_TICKS_IN_SEC 1000 ++ ++#define CALCULATE_WD_LOAD_VALUE(fps) \ ++ ((uint32_t)((MS_TICKS_IN_SEC * XO_CLK_RATE)/(MDP_TICK_COUNT * fps))) ++ + extern const struct dpu_csc_cfg dpu_csc_YUV2RGB_601L; + extern const struct dpu_csc_cfg dpu_csc10_YUV2RGB_601L; + extern const struct dpu_csc_cfg dpu_csc10_rgb2yuv_601l; +-- +2.51.0 + diff --git a/queue-6.18/drm-msm-dpu-offset-hbb-values-written-to-dpu-by-13.patch b/queue-6.18/drm-msm-dpu-offset-hbb-values-written-to-dpu-by-13.patch new file mode 100644 index 0000000000..78bbe39190 --- /dev/null +++ b/queue-6.18/drm-msm-dpu-offset-hbb-values-written-to-dpu-by-13.patch @@ -0,0 +1,68 @@ +From 003fbff1b9e13d196c7c03d9d00cadf334518bf7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 14:16:38 +0200 +Subject: drm/msm/dpu: offset HBB values written to DPU by -13 + +From: Dmitry Baryshkov + +[ Upstream commit 7ead14d4b9742b5ed244f35b999f0fe26dc23586 ] + +As in all other places, the Highest Bank Bit value should be programmed +into the hardware with the offset of -13. Correct the value written +into the register to prevent unpredictable results. + +Fixes: 227d4ce0b09e ("drm/msm: Offset MDSS HBB value by 13") +Tested-by: Val Packett # x1e80100-dell-latitude-7455 +Reviewed-by: Konrad Dybcio +Signed-off-by: Dmitry Baryshkov +Patchwork: https://patchwork.freedesktop.org/patch/699276/ +Link: https://lore.kernel.org/r/20260119-msm-ubwc-fixes-v4-2-0987acc0427f@oss.qualcomm.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c +index 6f1fc790ad6d8..b66c4cb5760c9 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c +@@ -270,30 +270,32 @@ static void dpu_hw_sspp_setup_format(struct dpu_sw_pipe *pipe, + ((fmt->bpp - 1) << 9); + + if (fmt->fetch_mode != MDP_FETCH_LINEAR) { ++ u32 hbb = ctx->ubwc->highest_bank_bit - 13; ++ + if (MSM_FORMAT_IS_UBWC(fmt)) + opmode |= MDSS_MDP_OP_BWC_EN; + src_format |= (fmt->fetch_mode & 3) << 30; /*FRAME_FORMAT */ + DPU_REG_WRITE(c, SSPP_FETCH_CONFIG, + DPU_FETCH_CONFIG_RESET_VALUE | +- ctx->ubwc->highest_bank_bit << 18); ++ hbb << 18); + switch (ctx->ubwc->ubwc_enc_version) { + case UBWC_1_0: + fast_clear = fmt->alpha_enable ? BIT(31) : 0; + DPU_REG_WRITE(c, SSPP_UBWC_STATIC_CTRL, + fast_clear | (ctx->ubwc->ubwc_swizzle & 0x1) | + BIT(8) | +- (ctx->ubwc->highest_bank_bit << 4)); ++ (hbb << 4)); + break; + case UBWC_2_0: + fast_clear = fmt->alpha_enable ? BIT(31) : 0; + DPU_REG_WRITE(c, SSPP_UBWC_STATIC_CTRL, + fast_clear | (ctx->ubwc->ubwc_swizzle) | +- (ctx->ubwc->highest_bank_bit << 4)); ++ (hbb << 4)); + break; + case UBWC_3_0: + DPU_REG_WRITE(c, SSPP_UBWC_STATIC_CTRL, + BIT(30) | (ctx->ubwc->ubwc_swizzle) | +- (ctx->ubwc->highest_bank_bit << 4)); ++ (hbb << 4)); + break; + case UBWC_4_0: + DPU_REG_WRITE(c, SSPP_UBWC_STATIC_CTRL, +-- +2.51.0 + diff --git a/queue-6.18/drm-msm-dpu-program-correct-register-for-ubwc-config.patch b/queue-6.18/drm-msm-dpu-program-correct-register-for-ubwc-config.patch new file mode 100644 index 0000000000..f0081e7c55 --- /dev/null +++ b/queue-6.18/drm-msm-dpu-program-correct-register-for-ubwc-config.patch @@ -0,0 +1,109 @@ +From 0c90e9de074551ac20c9c6399f5320665f867f55 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 14:16:39 +0200 +Subject: drm/msm/dpu: program correct register for UBWC config on DPU 8.x+ + +From: Dmitry Baryshkov + +[ Upstream commit 5dcec3fc1311c277369a4bdf8b292781e5cc91fd ] + +Since DPU 8.0 there is a separate register for the second rectangle, +which needs to be programmed with the UBWC config if multirect is being +used. Write pipe's UBWC configuration to the correct register. + +Fixes: 100d7ef6995d ("drm/msm/dpu: add support for SM8450") +Tested-by: Val Packett # x1e80100-dell-latitude-7455 +Reviewed-by: Konrad Dybcio +Signed-off-by: Dmitry Baryshkov +Patchwork: https://patchwork.freedesktop.org/patch/699277/ +Link: https://lore.kernel.org/r/20260119-msm-ubwc-fixes-v4-3-0987acc0427f@oss.qualcomm.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c | 25 ++++++++++++++++----- + 1 file changed, 19 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c +index b66c4cb5760c9..6ff4902fce08e 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c +@@ -72,6 +72,8 @@ + #define SSPP_EXCL_REC_XY_REC1 0x188 + #define SSPP_EXCL_REC_SIZE 0x1B4 + #define SSPP_EXCL_REC_XY 0x1B8 ++#define SSPP_UBWC_STATIC_CTRL_REC1 0x1c0 ++#define SSPP_UBWC_ERROR_STATUS_REC1 0x1c8 + #define SSPP_CLK_CTRL 0x330 + + /* SSPP_SRC_OP_MODE & OP_MODE_REC1 */ +@@ -215,7 +217,7 @@ static void dpu_hw_sspp_setup_format(struct dpu_sw_pipe *pipe, + u32 chroma_samp, unpack, src_format; + u32 opmode = 0; + u32 fast_clear = 0; +- u32 op_mode_off, unpack_pat_off, format_off; ++ u32 op_mode_off, unpack_pat_off, format_off, ubwc_ctrl_off, ubwc_error_off; + + if (!ctx || !fmt) + return; +@@ -225,10 +227,21 @@ static void dpu_hw_sspp_setup_format(struct dpu_sw_pipe *pipe, + op_mode_off = SSPP_SRC_OP_MODE; + unpack_pat_off = SSPP_SRC_UNPACK_PATTERN; + format_off = SSPP_SRC_FORMAT; ++ ubwc_ctrl_off = SSPP_UBWC_STATIC_CTRL; ++ ubwc_error_off = SSPP_UBWC_ERROR_STATUS; + } else { + op_mode_off = SSPP_SRC_OP_MODE_REC1; + unpack_pat_off = SSPP_SRC_UNPACK_PATTERN_REC1; + format_off = SSPP_SRC_FORMAT_REC1; ++ ++ /* reg wasn't present before DPU 8.0 */ ++ if (ctx->mdss_ver->core_major_ver >= 8) { ++ ubwc_ctrl_off = SSPP_UBWC_STATIC_CTRL_REC1; ++ ubwc_error_off = SSPP_UBWC_ERROR_STATUS_REC1; ++ } else { ++ ubwc_ctrl_off = SSPP_UBWC_STATIC_CTRL; ++ ubwc_error_off = SSPP_UBWC_ERROR_STATUS; ++ } + } + + c = &ctx->hw; +@@ -281,24 +294,24 @@ static void dpu_hw_sspp_setup_format(struct dpu_sw_pipe *pipe, + switch (ctx->ubwc->ubwc_enc_version) { + case UBWC_1_0: + fast_clear = fmt->alpha_enable ? BIT(31) : 0; +- DPU_REG_WRITE(c, SSPP_UBWC_STATIC_CTRL, ++ DPU_REG_WRITE(c, ubwc_ctrl_off, + fast_clear | (ctx->ubwc->ubwc_swizzle & 0x1) | + BIT(8) | + (hbb << 4)); + break; + case UBWC_2_0: + fast_clear = fmt->alpha_enable ? BIT(31) : 0; +- DPU_REG_WRITE(c, SSPP_UBWC_STATIC_CTRL, ++ DPU_REG_WRITE(c, ubwc_ctrl_off, + fast_clear | (ctx->ubwc->ubwc_swizzle) | + (hbb << 4)); + break; + case UBWC_3_0: +- DPU_REG_WRITE(c, SSPP_UBWC_STATIC_CTRL, ++ DPU_REG_WRITE(c, ubwc_ctrl_off, + BIT(30) | (ctx->ubwc->ubwc_swizzle) | + (hbb << 4)); + break; + case UBWC_4_0: +- DPU_REG_WRITE(c, SSPP_UBWC_STATIC_CTRL, ++ DPU_REG_WRITE(c, ubwc_ctrl_off, + MSM_FORMAT_IS_YUV(fmt) ? 0 : BIT(30)); + break; + } +@@ -327,7 +340,7 @@ static void dpu_hw_sspp_setup_format(struct dpu_sw_pipe *pipe, + DPU_REG_WRITE(c, op_mode_off, opmode); + + /* clear previous UBWC error */ +- DPU_REG_WRITE(c, SSPP_UBWC_ERROR_STATUS, BIT(31)); ++ DPU_REG_WRITE(c, ubwc_error_off, BIT(31)); + } + + static void dpu_hw_sspp_setup_pe_config(struct dpu_hw_sspp *ctx, +-- +2.51.0 + diff --git a/queue-6.18/drm-msm-dpu-set-vsync-source-irrespective-of-mdp-top.patch b/queue-6.18/drm-msm-dpu-set-vsync-source-irrespective-of-mdp-top.patch new file mode 100644 index 0000000000..be39cd35ce --- /dev/null +++ b/queue-6.18/drm-msm-dpu-set-vsync-source-irrespective-of-mdp-top.patch @@ -0,0 +1,68 @@ +From 672bfc1fded05feb759a42024a637af42cfa9d8b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Dec 2025 09:17:56 +0200 +Subject: drm/msm/dpu: Set vsync source irrespective of mdp top support + +From: Teguh Sobirin + +[ Upstream commit 1ad9880f059c9b0943e53714f9a59924cb035bbb ] + +Since DPU 5.x the vsync source TE setup is split between MDP TOP and +INTF blocks. Currently all code to setup vsync_source is only executed +if MDP TOP implements the setup_vsync_source() callback. However on +DPU >= 8.x this callback is not implemented, making DPU driver skip all +vsync setup. Move the INTF part out of this condition, letting DPU +driver to setup TE vsync selection on all new DPU devices. + +Signed-off-by: Teguh Sobirin +Fixes: 2f69e5458447 ("drm/msm/dpu: skip watchdog timer programming through TOP on >= SM8450") +[DB: restored top->ops.setup_vsync_source call] +Reviewed-by: Marijn Suijten +Signed-off-by: Dmitry Baryshkov +Patchwork: https://patchwork.freedesktop.org/patch/696584/ +Link: https://lore.kernel.org/r/20251230-intf-fix-wd-v6-1-98203d150611@oss.qualcomm.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +index 258edaa18fc02..7b90c59792f6b 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +@@ -784,6 +784,8 @@ static void _dpu_encoder_update_vsync_source(struct dpu_encoder_virt *dpu_enc, + return; + } + ++ vsync_cfg.vsync_source = disp_info->vsync_source; ++ + if (hw_mdptop->ops.setup_vsync_source) { + for (i = 0; i < dpu_enc->num_phys_encs; i++) + vsync_cfg.ppnumber[i] = dpu_enc->hw_pp[i]->idx; +@@ -791,17 +793,15 @@ static void _dpu_encoder_update_vsync_source(struct dpu_encoder_virt *dpu_enc, + vsync_cfg.pp_count = dpu_enc->num_phys_encs; + vsync_cfg.frame_rate = drm_mode_vrefresh(&dpu_enc->base.crtc->state->adjusted_mode); + +- vsync_cfg.vsync_source = disp_info->vsync_source; +- + hw_mdptop->ops.setup_vsync_source(hw_mdptop, &vsync_cfg); ++ } + +- for (i = 0; i < dpu_enc->num_phys_encs; i++) { +- phys_enc = dpu_enc->phys_encs[i]; ++ for (i = 0; i < dpu_enc->num_phys_encs; i++) { ++ phys_enc = dpu_enc->phys_encs[i]; + +- if (phys_enc->has_intf_te && phys_enc->hw_intf->ops.vsync_sel) +- phys_enc->hw_intf->ops.vsync_sel(phys_enc->hw_intf, +- vsync_cfg.vsync_source); +- } ++ if (phys_enc->has_intf_te && phys_enc->hw_intf->ops.vsync_sel) ++ phys_enc->hw_intf->ops.vsync_sel(phys_enc->hw_intf, ++ vsync_cfg.vsync_source); + } + } + +-- +2.51.0 + diff --git a/queue-6.18/drm-msm-dsi_phy_14nm-convert-from-divider_round_rate.patch b/queue-6.18/drm-msm-dsi_phy_14nm-convert-from-divider_round_rate.patch new file mode 100644 index 0000000000..bd6dd75f7a --- /dev/null +++ b/queue-6.18/drm-msm-dsi_phy_14nm-convert-from-divider_round_rate.patch @@ -0,0 +1,55 @@ +From afc329cbd79fa561827bd85f914f3c804d920efc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:16:42 -0500 +Subject: drm/msm/dsi_phy_14nm: convert from divider_round_rate() to + divider_determine_rate() + +From: Brian Masney + +[ Upstream commit 1d232f793d4dbffd329ad48b52954d4c8ca24db5 ] + +The divider_round_rate() function is now deprecated, so let's migrate +to divider_determine_rate() instead so that this deprecated API can be +removed. + +Note that when the main function itself was migrated to use +determine_rate, this was mistakenly converted to: + + req->rate = divider_round_rate(...) + +This is invalid in the case when an error occurs since it can set the +rate to a negative value. + +Fixes: cc41f29a6b04 ("drm/msm/dsi_phy_14nm: convert from round_rate() to determine_rate()") +Signed-off-by: Brian Masney +Reviewed-by: Konrad Dybcio +Reviewed-by: Abel Vesa +Patchwork: https://patchwork.freedesktop.org/patch/697613/ +Link: https://lore.kernel.org/r/20260108-clk-divider-round-rate-v1-24-535a3ed73bf3@redhat.com +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c +index fdefcbd9c2848..a156c7e7cea83 100644 +--- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c ++++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c +@@ -628,12 +628,7 @@ static int dsi_pll_14nm_postdiv_determine_rate(struct clk_hw *hw, + + DBG("DSI%d PLL parent rate=%lu", pll_14nm->phy->id, req->rate); + +- req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, +- NULL, +- postdiv->width, +- postdiv->flags); +- +- return 0; ++ return divider_determine_rate(hw, req, NULL, postdiv->width, postdiv->flags); + } + + static int dsi_pll_14nm_postdiv_set_rate(struct clk_hw *hw, unsigned long rate, +-- +2.51.0 + diff --git a/queue-6.18/drm-msm-mdss-correct-hbb-programmed-on-ubwc-5.x-and-.patch b/queue-6.18/drm-msm-mdss-correct-hbb-programmed-on-ubwc-5.x-and-.patch new file mode 100644 index 0000000000..d7b442aaf3 --- /dev/null +++ b/queue-6.18/drm-msm-mdss-correct-hbb-programmed-on-ubwc-5.x-and-.patch @@ -0,0 +1,41 @@ +From ee7ed9f8c5a53f74d1e4fa390edb41ec792381a1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 14:16:37 +0200 +Subject: drm/msm/mdss: correct HBB programmed on UBWC 5.x and 6.x devices + +From: Dmitry Baryshkov + +[ Upstream commit e6177c7a2401b87b016728b75992926971d871fc ] + +As in the previous generations, on UBWC 5.x and 6.x devices the Highest +Bank Bit value should be programmed into the hardware with the offset of +-13. Correct the value written into the register to prevent +unpredictable results. + +Fixes: 227d4ce0b09e ("drm/msm: Offset MDSS HBB value by 13") +Tested-by: Val Packett # x1e80100-dell-latitude-7455 +Reviewed-by: Konrad Dybcio +Signed-off-by: Dmitry Baryshkov +Patchwork: https://patchwork.freedesktop.org/patch/699274/ +Link: https://lore.kernel.org/r/20260119-msm-ubwc-fixes-v4-1-0987acc0427f@oss.qualcomm.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/msm_mdss.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/msm/msm_mdss.c b/drivers/gpu/drm/msm/msm_mdss.c +index 2d0e3e784c044..4dbb1b1d879f1 100644 +--- a/drivers/gpu/drm/msm/msm_mdss.c ++++ b/drivers/gpu/drm/msm/msm_mdss.c +@@ -229,7 +229,7 @@ static void msm_mdss_setup_ubwc_dec_50(struct msm_mdss *msm_mdss) + { + const struct qcom_ubwc_cfg_data *data = msm_mdss->mdss_data; + u32 value = MDSS_UBWC_STATIC_UBWC_SWIZZLE(data->ubwc_swizzle) | +- MDSS_UBWC_STATIC_HIGHEST_BANK_BIT(data->highest_bank_bit); ++ MDSS_UBWC_STATIC_HIGHEST_BANK_BIT(data->highest_bank_bit - 13); + + if (data->ubwc_bank_spread) + value |= MDSS_UBWC_STATIC_UBWC_BANK_SPREAD; +-- +2.51.0 + diff --git a/queue-6.18/drm-panel-sw43408-remove-manual-invocation-of-unprep.patch b/queue-6.18/drm-panel-sw43408-remove-manual-invocation-of-unprep.patch new file mode 100644 index 0000000000..7ee8c34d16 --- /dev/null +++ b/queue-6.18/drm-panel-sw43408-remove-manual-invocation-of-unprep.patch @@ -0,0 +1,40 @@ +From a3213a0d885bffc31aa409c68a94ec86db12a2fc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 14 Dec 2025 15:51:21 +0100 +Subject: drm/panel: sw43408: Remove manual invocation of unprepare at remove + +From: David Heidelberg + +[ Upstream commit cbc1e99a9e0a6c8b22ddcbb40ca37457066f9493 ] + +The drm_panel_remove should take care of disable/unprepare. Remove the +manual call from the sw43408_remove function. + +Fixes: 069a6c0e94f9 ("drm: panel: Add LG sw43408 panel driver") +Reviewed-by: Dmitry Baryshkov +Signed-off-by: David Heidelberg +Signed-off-by: Neil Armstrong +Link: https://patch.msgid.link/20251214-pixel-3-v7-5-b1c0cf6f224d@ixit.cz +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panel/panel-lg-sw43408.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/drivers/gpu/drm/panel/panel-lg-sw43408.c b/drivers/gpu/drm/panel/panel-lg-sw43408.c +index 46a56ea92ad9f..6e307fba658f7 100644 +--- a/drivers/gpu/drm/panel/panel-lg-sw43408.c ++++ b/drivers/gpu/drm/panel/panel-lg-sw43408.c +@@ -294,10 +294,6 @@ static void sw43408_remove(struct mipi_dsi_device *dsi) + struct sw43408_panel *ctx = mipi_dsi_get_drvdata(dsi); + int ret; + +- ret = sw43408_unprepare(&ctx->base); +- if (ret < 0) +- dev_err(&dsi->dev, "failed to unprepare panel: %d\n", ret); +- + ret = mipi_dsi_detach(dsi); + if (ret < 0) + dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret); +-- +2.51.0 + diff --git a/queue-6.18/drm-panthor-evict-groups-before-vm-termination.patch b/queue-6.18/drm-panthor-evict-groups-before-vm-termination.patch new file mode 100644 index 0000000000..9cd2ab9f29 --- /dev/null +++ b/queue-6.18/drm-panthor-evict-groups-before-vm-termination.patch @@ -0,0 +1,90 @@ +From 7152630695bdb3a9954c771c90fec7dc8628e5f2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 19 Dec 2025 10:35:44 +0100 +Subject: drm/panthor: Evict groups before VM termination + +From: Ketil Johnsen + +[ Upstream commit 565ed40b5fc1242f7538a016fce5a85f802d4fb5 ] + +Ensure all related groups are evicted and suspended before VM +destruction takes place. + +This fixes an issue where panthor_vm_destroy() destroys and unmaps the +heap context while there are still on slot groups using this. +The FW will do a write out to the heap context when a CSG (group) is +suspended, so a premature unmap of the heap context will cause a +GPU page fault. +This page fault is quite harmless, and do not affect the continued +operation of the GPU. + +Fixes: 647810ec2476 ("drm/panthor: Add the MMU/VM logical block") +Reviewed-by: Boris Brezillon +Signed-off-by: Ketil Johnsen +Reviewed-by: Liviu Dudau +Reviewed-by: Steven Price +Link: https://patch.msgid.link/20251219093546.1227697-1-ketil.johnsen@arm.com +Co-developed-by: Boris Brezillon +Signed-off-by: Boris Brezillon +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panthor/panthor_mmu.c | 4 ++++ + drivers/gpu/drm/panthor/panthor_sched.c | 14 ++++++++++++++ + drivers/gpu/drm/panthor/panthor_sched.h | 1 + + 3 files changed, 19 insertions(+) + +diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c +index 15961629872e1..0fd8ffec92dd0 100644 +--- a/drivers/gpu/drm/panthor/panthor_mmu.c ++++ b/drivers/gpu/drm/panthor/panthor_mmu.c +@@ -1561,6 +1561,10 @@ static void panthor_vm_destroy(struct panthor_vm *vm) + + vm->destroyed = true; + ++ /* Tell scheduler to stop all GPU work related to this VM */ ++ if (refcount_read(&vm->as.active_cnt) > 0) ++ panthor_sched_prepare_for_vm_destruction(vm->ptdev); ++ + mutex_lock(&vm->heaps.lock); + panthor_heap_pool_destroy(vm->heaps.pool); + vm->heaps.pool = NULL; +diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c +index 8f11fe73bee23..c7dd98936bd6b 100644 +--- a/drivers/gpu/drm/panthor/panthor_sched.c ++++ b/drivers/gpu/drm/panthor/panthor_sched.c +@@ -2707,6 +2707,20 @@ void panthor_sched_report_mmu_fault(struct panthor_device *ptdev) + panthor_sched_immediate_tick(ptdev); + } + ++void panthor_sched_prepare_for_vm_destruction(struct panthor_device *ptdev) ++{ ++ /* FW can write out internal state, like the heap context, during CSG ++ * suspend. It is therefore important that the scheduler has fully ++ * evicted any pending and related groups before VM destruction can ++ * safely continue. Failure to do so can lead to GPU page faults. ++ * A controlled termination of a Panthor instance involves destroying ++ * the group(s) before the VM. This means any relevant group eviction ++ * has already been initiated by this point, and we just need to ++ * ensure that any pending tick_work() has been completed. ++ */ ++ flush_work(&ptdev->scheduler->tick_work.work); ++} ++ + void panthor_sched_resume(struct panthor_device *ptdev) + { + /* Force a tick to re-evaluate after a resume. */ +diff --git a/drivers/gpu/drm/panthor/panthor_sched.h b/drivers/gpu/drm/panthor/panthor_sched.h +index 742b0b4ff3a3c..6a560ab0a5b31 100644 +--- a/drivers/gpu/drm/panthor/panthor_sched.h ++++ b/drivers/gpu/drm/panthor/panthor_sched.h +@@ -49,6 +49,7 @@ void panthor_sched_suspend(struct panthor_device *ptdev); + void panthor_sched_resume(struct panthor_device *ptdev); + + void panthor_sched_report_mmu_fault(struct panthor_device *ptdev); ++void panthor_sched_prepare_for_vm_destruction(struct panthor_device *ptdev); + void panthor_sched_report_fw_events(struct panthor_device *ptdev, u32 events); + + void panthor_fdinfo_gather_group_samples(struct panthor_file *pfile); +-- +2.51.0 + diff --git a/queue-6.18/drm-panthor-fix-immediate-ticking-on-a-disabled-tick.patch b/queue-6.18/drm-panthor-fix-immediate-ticking-on-a-disabled-tick.patch new file mode 100644 index 0000000000..3a8906f104 --- /dev/null +++ b/queue-6.18/drm-panthor-fix-immediate-ticking-on-a-disabled-tick.patch @@ -0,0 +1,61 @@ +From 97cd182ca361c071f8fd413e5d357af2c24306b2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 10:48:36 +0100 +Subject: drm/panthor: Fix immediate ticking on a disabled tick + +From: Boris Brezillon + +[ Upstream commit 4356d21994f4ff5c87305b874939b359f16f6677 ] + +We have a few paths where we schedule the tick work immediately without +changing the resched_target. If the tick was stopped, this would lead +to a remaining_jiffies that's always > 0, and it wouldn't force a full +tick in that case. Add extra checks to cover that case properly. + +v2: +- Fix typo +- Simplify the code as suggested by Steve + +v3: +- Collect R-b + +Fixes: de8548813824 ("drm/panthor: Add the scheduler logical block") +Reviewed-by: Steven Price +Reviewed-by: Chia-I Wu +Link: https://patch.msgid.link/20251128094839.3856402-6-boris.brezillon@collabora.com +Signed-off-by: Boris Brezillon +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panthor/panthor_sched.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c +index 03062169b8d33..3d4ac73999825 100644 +--- a/drivers/gpu/drm/panthor/panthor_sched.c ++++ b/drivers/gpu/drm/panthor/panthor_sched.c +@@ -2374,6 +2374,7 @@ static void tick_work(struct work_struct *work) + tick_work.work); + struct panthor_device *ptdev = sched->ptdev; + struct panthor_sched_tick_ctx ctx; ++ u64 resched_target = sched->resched_target; + u64 remaining_jiffies = 0, resched_delay; + u64 now = get_jiffies_64(); + int prio, ret, cookie; +@@ -2386,8 +2387,12 @@ static void tick_work(struct work_struct *work) + if (drm_WARN_ON(&ptdev->base, ret)) + goto out_dev_exit; + +- if (time_before64(now, sched->resched_target)) +- remaining_jiffies = sched->resched_target - now; ++ /* If the tick is stopped, calculate when the next tick would be */ ++ if (resched_target == U64_MAX) ++ resched_target = sched->last_tick + sched->tick_period; ++ ++ if (time_before64(now, resched_target)) ++ remaining_jiffies = resched_target - now; + + full_tick = remaining_jiffies == 0; + +-- +2.51.0 + diff --git a/queue-6.18/drm-panthor-fix-panthor_gpu_coherency_set.patch b/queue-6.18/drm-panthor-fix-panthor_gpu_coherency_set.patch new file mode 100644 index 0000000000..4e4cdb8edb --- /dev/null +++ b/queue-6.18/drm-panthor-fix-panthor_gpu_coherency_set.patch @@ -0,0 +1,57 @@ +From 811f93372ee624b422fe32115745978459b2bd5b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Dec 2025 11:08:29 +0100 +Subject: drm/panthor: Fix panthor_gpu_coherency_set() + +From: Boris Brezillon + +[ Upstream commit 9beb8dca9e749e9983e70b22e9823e6fcd519f91 ] + +GPU_COHERENCY_PROTOCOL takes one of GPU_COHERENCY_xx +not BIT(GPU_COHERENCY_xx). + +v3: +- New commit + +v4: +- Add Steve's R-b + +v5: +- No changes + +v6: +- No changes + +v7: +- No changes + +v8: +- No changes + +Cc: Akash Goel +Fixes: dd7db8d911a1 ("drm/panthor: Explicitly set the coherency mode") +Reported-by: Steven Price +Reviewed-by: Steven Price +Link: https://patch.msgid.link/20251208100841.730527-3-boris.brezillon@collabora.com +Signed-off-by: Boris Brezillon +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panthor/panthor_gpu.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/panthor/panthor_gpu.c b/drivers/gpu/drm/panthor/panthor_gpu.c +index b92c9e738dbfa..77d0f4ced1206 100644 +--- a/drivers/gpu/drm/panthor/panthor_gpu.c ++++ b/drivers/gpu/drm/panthor/panthor_gpu.c +@@ -49,7 +49,7 @@ struct panthor_gpu { + static void panthor_gpu_coherency_set(struct panthor_device *ptdev) + { + gpu_write(ptdev, GPU_COHERENCY_PROTOCOL, +- ptdev->coherent ? GPU_COHERENCY_PROT_BIT(ACE_LITE) : GPU_COHERENCY_NONE); ++ ptdev->coherent ? GPU_COHERENCY_ACE_LITE : GPU_COHERENCY_NONE); + } + + static void panthor_gpu_irq_handler(struct panthor_device *ptdev, u32 status) +-- +2.51.0 + diff --git a/queue-6.18/drm-panthor-fix-the-full_tick-check.patch b/queue-6.18/drm-panthor-fix-the-full_tick-check.patch new file mode 100644 index 0000000000..50bd64fe88 --- /dev/null +++ b/queue-6.18/drm-panthor-fix-the-full_tick-check.patch @@ -0,0 +1,64 @@ +From ce3a5386d76bab3b953963ed95d78442fbfa042a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 10:48:34 +0100 +Subject: drm/panthor: Fix the full_tick check + +From: Boris Brezillon + +[ Upstream commit a3c2d0b40b108bd45d44f6c1dfa33c39d577adcd ] + +We have a full tick when the remaining time to the next tick is zero, +not the other way around. Declare a full_tick variable so we don't get +that test wrong in other places. + +v2: +- Add R-b + +v3: +- Collect R-b + +Fixes: de8548813824 ("drm/panthor: Add the scheduler logical block") +Reviewed-by: Steven Price +Reviewed-by: Chia-I Wu +Link: https://patch.msgid.link/20251128094839.3856402-4-boris.brezillon@collabora.com +Signed-off-by: Boris Brezillon +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panthor/panthor_sched.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c +index 881a07ffbabc8..6e4667cbe1b82 100644 +--- a/drivers/gpu/drm/panthor/panthor_sched.c ++++ b/drivers/gpu/drm/panthor/panthor_sched.c +@@ -2387,6 +2387,7 @@ static void tick_work(struct work_struct *work) + u64 remaining_jiffies = 0, resched_delay; + u64 now = get_jiffies_64(); + int prio, ret, cookie; ++ bool full_tick; + + if (!drm_dev_enter(&ptdev->base, &cookie)) + return; +@@ -2398,15 +2399,17 @@ static void tick_work(struct work_struct *work) + if (time_before64(now, sched->resched_target)) + remaining_jiffies = sched->resched_target - now; + ++ full_tick = remaining_jiffies == 0; ++ + mutex_lock(&sched->lock); + if (panthor_device_reset_is_pending(sched->ptdev)) + goto out_unlock; + +- tick_ctx_init(sched, &ctx, remaining_jiffies != 0); ++ tick_ctx_init(sched, &ctx, full_tick); + if (ctx.csg_upd_failed_mask) + goto out_cleanup_ctx; + +- if (remaining_jiffies) { ++ if (!full_tick) { + /* Scheduling forced in the middle of a tick. Only RT groups + * can preempt non-RT ones. Currently running RT groups can't be + * preempted. +-- +2.51.0 + diff --git a/queue-6.18/drm-panthor-fix-the-group-priority-rotation-logic.patch b/queue-6.18/drm-panthor-fix-the-group-priority-rotation-logic.patch new file mode 100644 index 0000000000..4b3921dc0b --- /dev/null +++ b/queue-6.18/drm-panthor-fix-the-group-priority-rotation-logic.patch @@ -0,0 +1,140 @@ +From 7740e22481a2fcb06535261e906c91ac697111af Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 10:48:35 +0100 +Subject: drm/panthor: Fix the group priority rotation logic + +From: Boris Brezillon + +[ Upstream commit 55429c51d5db3db24c2ad561944c6a0ca922d476 ] + +When rotating group priorities, we want the group with the +highest priority to go back to the end of the queue, and all +other active groups to get their priority bumped, otherwise +some groups will never get a chance to run with the highest +priority. This implies moving the rotation itself to +tick_work(), and only dealing with old group ordering in +tick_ctx_insert_old_group(). + +v2: +- Add R-b +- Fix the commit message + +v3: +- Drop the full_tick argument in tick_ctx_init() +- Collect R-b + +Fixes: de8548813824 ("drm/panthor: Add the scheduler logical block") +Reviewed-by: Steven Price +Reviewed-by: Chia-I Wu +Link: https://patch.msgid.link/20251128094839.3856402-5-boris.brezillon@collabora.com +Signed-off-by: Boris Brezillon +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panthor/panthor_sched.c | 52 +++++++++++++++---------- + 1 file changed, 31 insertions(+), 21 deletions(-) + +diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c +index 6e4667cbe1b82..03062169b8d33 100644 +--- a/drivers/gpu/drm/panthor/panthor_sched.c ++++ b/drivers/gpu/drm/panthor/panthor_sched.c +@@ -1989,31 +1989,22 @@ tick_ctx_pick_groups_from_list(const struct panthor_scheduler *sched, + static void + tick_ctx_insert_old_group(struct panthor_scheduler *sched, + struct panthor_sched_tick_ctx *ctx, +- struct panthor_group *group, +- bool full_tick) ++ struct panthor_group *group) + { + struct panthor_csg_slot *csg_slot = &sched->csg_slots[group->csg_id]; + struct panthor_group *other_group; + +- if (!full_tick) { +- list_add_tail(&group->run_node, &ctx->old_groups[group->priority]); +- return; +- } +- +- /* Rotate to make sure groups with lower CSG slot +- * priorities have a chance to get a higher CSG slot +- * priority next time they get picked. This priority +- * has an impact on resource request ordering, so it's +- * important to make sure we don't let one group starve +- * all other groups with the same group priority. +- */ ++ /* Class groups in descending priority order so we can easily rotate. */ + list_for_each_entry(other_group, + &ctx->old_groups[csg_slot->group->priority], + run_node) { + struct panthor_csg_slot *other_csg_slot = &sched->csg_slots[other_group->csg_id]; + +- if (other_csg_slot->priority > csg_slot->priority) { +- list_add_tail(&csg_slot->group->run_node, &other_group->run_node); ++ /* Our group has a higher prio than the one we're testing against, ++ * place it just before. ++ */ ++ if (csg_slot->priority > other_csg_slot->priority) { ++ list_add_tail(&group->run_node, &other_group->run_node); + return; + } + } +@@ -2023,8 +2014,7 @@ tick_ctx_insert_old_group(struct panthor_scheduler *sched, + + static void + tick_ctx_init(struct panthor_scheduler *sched, +- struct panthor_sched_tick_ctx *ctx, +- bool full_tick) ++ struct panthor_sched_tick_ctx *ctx) + { + struct panthor_device *ptdev = sched->ptdev; + struct panthor_csg_slots_upd_ctx upd_ctx; +@@ -2062,7 +2052,7 @@ tick_ctx_init(struct panthor_scheduler *sched, + group->fatal_queues |= GENMASK(group->queue_count - 1, 0); + } + +- tick_ctx_insert_old_group(sched, ctx, group, full_tick); ++ tick_ctx_insert_old_group(sched, ctx, group); + csgs_upd_ctx_queue_reqs(ptdev, &upd_ctx, i, + csg_iface->output->ack ^ CSG_STATUS_UPDATE, + CSG_STATUS_UPDATE); +@@ -2405,7 +2395,7 @@ static void tick_work(struct work_struct *work) + if (panthor_device_reset_is_pending(sched->ptdev)) + goto out_unlock; + +- tick_ctx_init(sched, &ctx, full_tick); ++ tick_ctx_init(sched, &ctx); + if (ctx.csg_upd_failed_mask) + goto out_cleanup_ctx; + +@@ -2431,9 +2421,29 @@ static void tick_work(struct work_struct *work) + for (prio = PANTHOR_CSG_PRIORITY_COUNT - 1; + prio >= 0 && !tick_ctx_is_full(sched, &ctx); + prio--) { ++ struct panthor_group *old_highest_prio_group = ++ list_first_entry_or_null(&ctx.old_groups[prio], ++ struct panthor_group, run_node); ++ ++ /* Pull out the group with the highest prio for rotation. */ ++ if (old_highest_prio_group) ++ list_del(&old_highest_prio_group->run_node); ++ ++ /* Re-insert old active groups so they get a chance to run with higher prio. */ ++ tick_ctx_pick_groups_from_list(sched, &ctx, &ctx.old_groups[prio], true, true); ++ ++ /* Fill the remaining slots with runnable groups. */ + tick_ctx_pick_groups_from_list(sched, &ctx, &sched->groups.runnable[prio], + true, false); +- tick_ctx_pick_groups_from_list(sched, &ctx, &ctx.old_groups[prio], true, true); ++ ++ /* Re-insert the old group with the highest prio, and give it a chance to be ++ * scheduled again (but with a lower prio) if there's room left. ++ */ ++ if (old_highest_prio_group) { ++ list_add_tail(&old_highest_prio_group->run_node, &ctx.old_groups[prio]); ++ tick_ctx_pick_groups_from_list(sched, &ctx, &ctx.old_groups[prio], ++ true, true); ++ } + } + + /* If we have free CSG slots left, pick idle groups */ +-- +2.51.0 + diff --git a/queue-6.18/drm-panthor-fix-the-logic-that-decides-when-to-stop-.patch b/queue-6.18/drm-panthor-fix-the-logic-that-decides-when-to-stop-.patch new file mode 100644 index 0000000000..f6c74d7800 --- /dev/null +++ b/queue-6.18/drm-panthor-fix-the-logic-that-decides-when-to-stop-.patch @@ -0,0 +1,130 @@ +From 5c61f0076961d6845b854b0610858eb0e1a35500 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 10:48:37 +0100 +Subject: drm/panthor: Fix the logic that decides when to stop ticking + +From: Boris Brezillon + +[ Upstream commit 61d9a43d70dc3e1709ecd14a34f6d5f01e21dfc9 ] + +When we have multiple active groups with the same priority, we need to +keep ticking for the priority rotation to take place. If we don't do +that, we might starve slots with lower priorities. + +It's annoying to deal with that in tick_ctx_update_resched_target(), +so let's add a ::stop_tick field to the tick context which is +initialized to true, and downgraded to false as soon as we detect +something that requires to tick to happen. This way we can complement +the current logic with extra conditions if needed. + +v2: +- Add R-b + +v3: +- Drop panthor_sched_tick_ctx::min_priority (no longer relevant) +- Collect R-b + +Fixes: de8548813824 ("drm/panthor: Add the scheduler logical block") +Reviewed-by: Steven Price +Reviewed-by: Chia-I Wu +Link: https://patch.msgid.link/20251128094839.3856402-7-boris.brezillon@collabora.com +Signed-off-by: Boris Brezillon +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panthor/panthor_sched.c | 44 ++++++++++--------------- + 1 file changed, 17 insertions(+), 27 deletions(-) + +diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c +index 3d4ac73999825..368e7f3449105 100644 +--- a/drivers/gpu/drm/panthor/panthor_sched.c ++++ b/drivers/gpu/drm/panthor/panthor_sched.c +@@ -1902,10 +1902,10 @@ struct panthor_sched_tick_ctx { + struct list_head groups[PANTHOR_CSG_PRIORITY_COUNT]; + u32 idle_group_count; + u32 group_count; +- enum panthor_csg_priority min_priority; + struct panthor_vm *vms[MAX_CS_PER_CSG]; + u32 as_count; + bool immediate_tick; ++ bool stop_tick; + u32 csg_upd_failed_mask; + }; + +@@ -1970,17 +1970,21 @@ tick_ctx_pick_groups_from_list(const struct panthor_scheduler *sched, + if (!owned_by_tick_ctx) + group_get(group); + +- list_move_tail(&group->run_node, &ctx->groups[group->priority]); + ctx->group_count++; ++ ++ /* If we have more than one active group with the same priority, ++ * we need to keep ticking to rotate the CSG priority. ++ */ + if (group_is_idle(group)) + ctx->idle_group_count++; ++ else if (!list_empty(&ctx->groups[group->priority])) ++ ctx->stop_tick = false; ++ ++ list_move_tail(&group->run_node, &ctx->groups[group->priority]); + + if (i == ctx->as_count) + ctx->vms[ctx->as_count++] = group->vm; + +- if (ctx->min_priority > group->priority) +- ctx->min_priority = group->priority; +- + if (tick_ctx_is_full(sched, ctx)) + return; + } +@@ -2024,7 +2028,7 @@ tick_ctx_init(struct panthor_scheduler *sched, + memset(ctx, 0, sizeof(*ctx)); + csgs_upd_ctx_init(&upd_ctx); + +- ctx->min_priority = PANTHOR_CSG_PRIORITY_COUNT; ++ ctx->stop_tick = true; + for (i = 0; i < ARRAY_SIZE(ctx->groups); i++) { + INIT_LIST_HEAD(&ctx->groups[i]); + INIT_LIST_HEAD(&ctx->old_groups[i]); +@@ -2336,32 +2340,18 @@ static u64 + tick_ctx_update_resched_target(struct panthor_scheduler *sched, + const struct panthor_sched_tick_ctx *ctx) + { +- /* We had space left, no need to reschedule until some external event happens. */ +- if (!tick_ctx_is_full(sched, ctx)) +- goto no_tick; +- +- /* If idle groups were scheduled, no need to wake up until some external +- * event happens (group unblocked, new job submitted, ...). +- */ +- if (ctx->idle_group_count) +- goto no_tick; ++ u64 resched_target; + +- if (drm_WARN_ON(&sched->ptdev->base, ctx->min_priority >= PANTHOR_CSG_PRIORITY_COUNT)) ++ if (ctx->stop_tick) + goto no_tick; + +- /* If there are groups of the same priority waiting, we need to +- * keep the scheduler ticking, otherwise, we'll just wait for +- * new groups with higher priority to be queued. +- */ +- if (!list_empty(&sched->groups.runnable[ctx->min_priority])) { +- u64 resched_target = sched->last_tick + sched->tick_period; ++ resched_target = sched->last_tick + sched->tick_period; + +- if (time_before64(sched->resched_target, sched->last_tick) || +- time_before64(resched_target, sched->resched_target)) +- sched->resched_target = resched_target; ++ if (time_before64(sched->resched_target, sched->last_tick) || ++ time_before64(resched_target, sched->resched_target)) ++ sched->resched_target = resched_target; + +- return sched->resched_target - sched->last_tick; +- } ++ return sched->resched_target - sched->last_tick; + + no_tick: + sched->resched_target = U64_MAX; +-- +2.51.0 + diff --git a/queue-6.18/drm-panthor-make-sure-we-resume-the-tick-when-new-jo.patch b/queue-6.18/drm-panthor-make-sure-we-resume-the-tick-when-new-jo.patch new file mode 100644 index 0000000000..207585efda --- /dev/null +++ b/queue-6.18/drm-panthor-make-sure-we-resume-the-tick-when-new-jo.patch @@ -0,0 +1,109 @@ +From f829337d42672b492d292729a305b0828f3774ff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 10:48:38 +0100 +Subject: drm/panthor: Make sure we resume the tick when new jobs are submitted + +From: Boris Brezillon + +[ Upstream commit 99820b4b7e50d9651f01d2d55b6b9ba92dcc5b99 ] + +If the group is already assigned a slot but was idle before this job +submission, we need to make sure the priority rotation happens in the +future. Extract the existing logic living in group_schedule_locked() +and call this new sched_resume_tick() helper from the "group is +assigned a slot" path. + +v2: +- Add R-b + +v3: +- Re-use queue_mask to clear the bit +- Collect R-b + +Fixes: de8548813824 ("drm/panthor: Add the scheduler logical block") +Reviewed-by: Steven Price +Reviewed-by: Chia-I Wu +Link: https://patch.msgid.link/20251128094839.3856402-8-boris.brezillon@collabora.com +Signed-off-by: Boris Brezillon +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panthor/panthor_sched.c | 43 +++++++++++++++++++------ + 1 file changed, 34 insertions(+), 9 deletions(-) + +diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c +index 368e7f3449105..8f11fe73bee23 100644 +--- a/drivers/gpu/drm/panthor/panthor_sched.c ++++ b/drivers/gpu/drm/panthor/panthor_sched.c +@@ -2563,14 +2563,33 @@ static void sync_upd_work(struct work_struct *work) + sched_queue_delayed_work(sched, tick, 0); + } + ++static void sched_resume_tick(struct panthor_device *ptdev) ++{ ++ struct panthor_scheduler *sched = ptdev->scheduler; ++ u64 delay_jiffies, now; ++ ++ drm_WARN_ON(&ptdev->base, sched->resched_target != U64_MAX); ++ ++ /* Scheduler tick was off, recalculate the resched_target based on the ++ * last tick event, and queue the scheduler work. ++ */ ++ now = get_jiffies_64(); ++ sched->resched_target = sched->last_tick + sched->tick_period; ++ if (sched->used_csg_slot_count == sched->csg_slot_count && ++ time_before64(now, sched->resched_target)) ++ delay_jiffies = min_t(unsigned long, sched->resched_target - now, ULONG_MAX); ++ else ++ delay_jiffies = 0; ++ ++ sched_queue_delayed_work(sched, tick, delay_jiffies); ++} ++ + static void group_schedule_locked(struct panthor_group *group, u32 queue_mask) + { + struct panthor_device *ptdev = group->ptdev; + struct panthor_scheduler *sched = ptdev->scheduler; + struct list_head *queue = &sched->groups.runnable[group->priority]; +- u64 delay_jiffies = 0; + bool was_idle; +- u64 now; + + if (!group_can_run(group)) + return; +@@ -2615,13 +2634,7 @@ static void group_schedule_locked(struct panthor_group *group, u32 queue_mask) + /* Scheduler tick was off, recalculate the resched_target based on the + * last tick event, and queue the scheduler work. + */ +- now = get_jiffies_64(); +- sched->resched_target = sched->last_tick + sched->tick_period; +- if (sched->used_csg_slot_count == sched->csg_slot_count && +- time_before64(now, sched->resched_target)) +- delay_jiffies = min_t(unsigned long, sched->resched_target - now, ULONG_MAX); +- +- sched_queue_delayed_work(sched, tick, delay_jiffies); ++ sched_resume_tick(ptdev); + } + + static void queue_stop(struct panthor_queue *queue, +@@ -3222,6 +3235,18 @@ queue_run_job(struct drm_sched_job *sched_job) + + group_schedule_locked(group, BIT(job->queue_idx)); + } else { ++ u32 queue_mask = BIT(job->queue_idx); ++ bool resume_tick = group_is_idle(group) && ++ (group->idle_queues & queue_mask) && ++ !(group->blocked_queues & queue_mask) && ++ sched->resched_target == U64_MAX; ++ ++ /* We just added something to the queue, so it's no longer idle. */ ++ group->idle_queues &= ~queue_mask; ++ ++ if (resume_tick) ++ sched_resume_tick(ptdev); ++ + gpu_write(ptdev, CSF_DOORBELL(queue->doorbell_id), 1); + if (!sched->pm.has_ref && + !(group->blocked_queues & BIT(job->queue_idx))) { +-- +2.51.0 + diff --git a/queue-6.18/drm-panthor-recover-from-panthor_gpu_flush_caches-fa.patch b/queue-6.18/drm-panthor-recover-from-panthor_gpu_flush_caches-fa.patch new file mode 100644 index 0000000000..1a0fff9282 --- /dev/null +++ b/queue-6.18/drm-panthor-recover-from-panthor_gpu_flush_caches-fa.patch @@ -0,0 +1,108 @@ +From 16a446dab076f6a5ecfe4edb104ac8b151519e5e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 09:48:37 +0100 +Subject: drm/panthor: Recover from panthor_gpu_flush_caches() failures + +From: Boris Brezillon + +[ Upstream commit 3c0a60195b37af83bbbaf223cd3a78945bace49e ] + +We have seen a few cases where the whole memory subsystem is blocked +and flush operations never complete. When that happens, we want to: + +- schedule a reset, so we can recover from this situation +- in the reset path, we need to reset the pending_reqs so we can send + new commands after the reset +- if more panthor_gpu_flush_caches() operations are queued after + the timeout, we skip them and return -EIO directly to avoid needless + waits (the memory block won't miraculously work again) + +Note that we drop the WARN_ON()s because these hangs can be triggered +with buggy GPU jobs created by the UMD, and there's no way we can +prevent it. We do keep the error messages though. + +v2: +- New patch + +v3: +- Collect R-b +- Explicitly mention the fact we dropped the WARN_ON()s in the commit + message + +v4: +- No changes + +Fixes: 5cd894e258c4 ("drm/panthor: Add the GPU logical block") +Reviewed-by: Steven Price +Link: https://patch.msgid.link/20251128084841.3804658-4-boris.brezillon@collabora.com +Signed-off-by: Boris Brezillon +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panthor/panthor_gpu.c | 19 ++++++++++++------- + 1 file changed, 12 insertions(+), 7 deletions(-) + +diff --git a/drivers/gpu/drm/panthor/panthor_gpu.c b/drivers/gpu/drm/panthor/panthor_gpu.c +index db69449a5be09..b92c9e738dbfa 100644 +--- a/drivers/gpu/drm/panthor/panthor_gpu.c ++++ b/drivers/gpu/drm/panthor/panthor_gpu.c +@@ -259,38 +259,42 @@ int panthor_gpu_l2_power_on(struct panthor_device *ptdev) + int panthor_gpu_flush_caches(struct panthor_device *ptdev, + u32 l2, u32 lsc, u32 other) + { +- bool timedout = false; + unsigned long flags; ++ int ret = 0; + + /* Serialize cache flush operations. */ + guard(mutex)(&ptdev->gpu->cache_flush_lock); + + spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags); +- if (!drm_WARN_ON(&ptdev->base, +- ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED)) { ++ if (!(ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED)) { + ptdev->gpu->pending_reqs |= GPU_IRQ_CLEAN_CACHES_COMPLETED; + gpu_write(ptdev, GPU_CMD, GPU_FLUSH_CACHES(l2, lsc, other)); ++ } else { ++ ret = -EIO; + } + spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags); + ++ if (ret) ++ return ret; ++ + if (!wait_event_timeout(ptdev->gpu->reqs_acked, + !(ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED), + msecs_to_jiffies(100))) { + spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags); + if ((ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED) != 0 && + !(gpu_read(ptdev, GPU_INT_RAWSTAT) & GPU_IRQ_CLEAN_CACHES_COMPLETED)) +- timedout = true; ++ ret = -ETIMEDOUT; + else + ptdev->gpu->pending_reqs &= ~GPU_IRQ_CLEAN_CACHES_COMPLETED; + spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags); + } + +- if (timedout) { ++ if (ret) { ++ panthor_device_schedule_reset(ptdev); + drm_err(&ptdev->base, "Flush caches timeout"); +- return -ETIMEDOUT; + } + +- return 0; ++ return ret; + } + + /** +@@ -330,6 +334,7 @@ int panthor_gpu_soft_reset(struct panthor_device *ptdev) + return -ETIMEDOUT; + } + ++ ptdev->gpu->pending_reqs = 0; + return 0; + } + +-- +2.51.0 + diff --git a/queue-6.18/drm-rockchip-dw_hdmi_qp-fix-rk3576-hpd-interrupt-han.patch b/queue-6.18/drm-rockchip-dw_hdmi_qp-fix-rk3576-hpd-interrupt-han.patch new file mode 100644 index 0000000000..6491c9c8e7 --- /dev/null +++ b/queue-6.18/drm-rockchip-dw_hdmi_qp-fix-rk3576-hpd-interrupt-han.patch @@ -0,0 +1,54 @@ +From 50a1424bd2a142f88b71598a8aa86444bb7c9153 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 18:24:43 +0200 +Subject: drm/rockchip: dw_hdmi_qp: Fix RK3576 HPD interrupt handling + +From: Cristian Ciocaltea + +[ Upstream commit 5f7be8afc40c5ccf1be0410514703e50a49532c0 ] + +The threaded interrupt handler on RK3576 checks HPD IRQ status before +deciding to continue with interrupt clearing and unmasking. + +This is not only redundant, since a similar verification has been +already performed by the hard IRQ handler before masking the interrupt, +but is also error prone, because it might happen that hardware clears +the status register right after the masking operation completes, and +before the threaded handler reads its value. + +The consequence is that HPD IRQ gets never unmasked, which breaks +hotplug detection until reloading the driver or rebooting the system. + +Drop the unnecessary verification of the HPD interrupt status from the +threaded interrupt handler. + +Fixes: 36439120efbd ("drm/rockchip: dw_hdmi_qp: Add basic RK3576 HDMI output support") +Signed-off-by: Cristian Ciocaltea +Signed-off-by: Heiko Stuebner +Link: https://patch.msgid.link/20260115-dw-hdmi-qp-hpd-v1-1-e59c166eaa65@collabora.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c +index 9ac45e7bc987a..409f1a1e82a06 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c +@@ -267,12 +267,7 @@ static irqreturn_t dw_hdmi_qp_rk3576_hardirq(int irq, void *dev_id) + static irqreturn_t dw_hdmi_qp_rk3576_irq(int irq, void *dev_id) + { + struct rockchip_hdmi_qp *hdmi = dev_id; +- u32 intr_stat, val; +- +- regmap_read(hdmi->regmap, RK3576_IOC_HDMI_HPD_STATUS, &intr_stat); +- +- if (!intr_stat) +- return IRQ_NONE; ++ u32 val; + + val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_CLR, 1); + regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val); +-- +2.51.0 + diff --git a/queue-6.18/drm-xe-ptl-disable-dcc-on-ptl.patch b/queue-6.18/drm-xe-ptl-disable-dcc-on-ptl.patch new file mode 100644 index 0000000000..c6fd6f6665 --- /dev/null +++ b/queue-6.18/drm-xe-ptl-disable-dcc-on-ptl.patch @@ -0,0 +1,87 @@ +From b8637d19280586b7b383958418a81a6d20ce3577 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 16:59:17 -0800 +Subject: drm/xe/ptl: Disable DCC on PTL + +From: Vinay Belgaumkar + +[ Upstream commit 801a6e61f5fbab2c0dd76c8360f45b625b49e410 ] + +On PTL, the recommendation is to disable DCC(Duty Cycle Control) as +it may cause some regressions due to added latencies. Upcoming GuC +releases will disable DCC on PTL as well, but we need to force it in +KMD so that this behavior is propagated to older kernels. + +v2: Update commit message (Rodrigo) +v3: Rebase +v4: Fix typo: s/propagted/propagated + +Fixes: 5cdb71d3b0db ("drm/xe/ptl: Add GuC FW definition for PTL") +Cc: Daniele Ceraolo Spurio +Cc: Rodrigo Vivi +Signed-off-by: Vinay Belgaumkar +Link: https://patch.msgid.link/20260124005917.398522-1-vinay.belgaumkar@intel.com +Reviewed-by: Rodrigo Vivi +Signed-off-by: Rodrigo Vivi +(cherry picked from commit 40ee63f5df2d5c6471b583df800aac89dc0502a4) +Signed-off-by: Rodrigo Vivi +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/xe/xe_guc_pc.c | 34 ++++++++++++++++++++++++++++++++++ + 1 file changed, 34 insertions(+) + +diff --git a/drivers/gpu/drm/xe/xe_guc_pc.c b/drivers/gpu/drm/xe/xe_guc_pc.c +index 53fdf59524c41..a3e9796e6430f 100644 +--- a/drivers/gpu/drm/xe/xe_guc_pc.c ++++ b/drivers/gpu/drm/xe/xe_guc_pc.c +@@ -1231,6 +1231,36 @@ int xe_guc_pc_set_power_profile(struct xe_guc_pc *pc, const char *buf) + return ret; + } + ++static int pc_action_set_dcc(struct xe_guc_pc *pc, bool enable) ++{ ++ int ret; ++ ++ ret = pc_action_set_param(pc, ++ SLPC_PARAM_TASK_ENABLE_DCC, ++ enable); ++ if (!ret) ++ return pc_action_set_param(pc, ++ SLPC_PARAM_TASK_DISABLE_DCC, ++ !enable); ++ else ++ return ret; ++} ++ ++static int pc_modify_defaults(struct xe_guc_pc *pc) ++{ ++ struct xe_device *xe = pc_to_xe(pc); ++ struct xe_gt *gt = pc_to_gt(pc); ++ int ret = 0; ++ ++ if (xe->info.platform == XE_PANTHERLAKE) { ++ ret = pc_action_set_dcc(pc, false); ++ if (unlikely(ret)) ++ xe_gt_err(gt, "Failed to modify DCC default: %pe\n", ERR_PTR(ret)); ++ } ++ ++ return ret; ++} ++ + /** + * xe_guc_pc_start - Start GuC's Power Conservation component + * @pc: Xe_GuC_PC instance +@@ -1288,6 +1318,10 @@ int xe_guc_pc_start(struct xe_guc_pc *pc) + ktime_ms_delta(ktime_get(), earlier)); + } + ++ ret = pc_modify_defaults(pc); ++ if (ret) ++ return ret; ++ + ret = pc_init_freqs(pc); + if (ret) + goto out; +-- +2.51.0 + diff --git a/queue-6.18/drm-xe-unregister-drm-device-on-probe-error.patch b/queue-6.18/drm-xe-unregister-drm-device-on-probe-error.patch new file mode 100644 index 0000000000..beb1f96270 --- /dev/null +++ b/queue-6.18/drm-xe-unregister-drm-device-on-probe-error.patch @@ -0,0 +1,91 @@ +From 60529de4075b682d8351fd9d96a3f4f947135750 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 21:10:42 +0000 +Subject: drm/xe: Unregister drm device on probe error + +From: Shuicheng Lin + +[ Upstream commit 96c2c72b817d70e8d110e78b0162e044a0c41f9f ] + +Call drm_dev_unregister() when xe_device_probe() fails after successful +drm_dev_register(). This ensures the DRM device is promptly unregistered +before returning an error, avoiding leaving it registered on the failure +path. +Otherwise, there is warn message if xe_device_probe() is called again: +" +[ 207.322365] [drm:drm_minor_register] +[ 207.322381] debugfs: '128' already exists in 'dri' +[ 207.322432] sysfs: cannot create duplicate filename '/devices/pci0000:00/0000:00:01.0/0000:01:00.0/0000:02:01.0/0000:03:00.0/drm/renderD128' +[ 207.322435] CPU: 5 UID: 0 PID: 10261 Comm: modprobe Tainted: G B W 6.19.0-rc2-lgci-xe-kernel+ #223 PREEMPT(voluntary) +[ 207.322439] Tainted: [B]=BAD_PAGE, [W]=WARN +[ 207.322440] Hardware name: ASUS System Product Name/PRIME Z790-P WIFI, BIOS 0812 02/24/2023 +[ 207.322441] Call Trace: +[ 207.322442] +[ 207.322443] dump_stack_lvl+0xa0/0xc0 +[ 207.322446] dump_stack+0x10/0x20 +[ 207.322448] sysfs_warn_dup+0xd5/0x110 +[ 207.322451] sysfs_create_dir_ns+0x1f6/0x280 +[ 207.322453] ? __pfx_sysfs_create_dir_ns+0x10/0x10 +[ 207.322455] ? lock_acquire+0x1a4/0x2e0 +[ 207.322458] ? __kasan_check_read+0x11/0x20 +[ 207.322461] kobject_add_internal+0x28d/0x8e0 +[ 207.322464] kobject_add+0x11f/0x1f0 +[ 207.322465] ? lock_acquire+0x1a4/0x2e0 +[ 207.322467] ? __pfx_kobject_add+0x10/0x10 +[ 207.322469] ? __kasan_check_write+0x14/0x20 +[ 207.322471] ? kobject_put+0x62/0x4a0 +[ 207.322473] ? get_device_parent.isra.0+0x1bb/0x4c0 +[ 207.322475] ? kobject_put+0x62/0x4a0 +[ 207.322477] device_add+0x2d7/0x1500 +[ 207.322479] ? __pfx_device_add+0x10/0x10 +[ 207.322481] ? drm_debugfs_add_file+0xfa/0x170 +[ 207.322483] ? drm_debugfs_add_files+0x82/0xd0 +[ 207.322485] ? drm_debugfs_add_files+0x82/0xd0 +[ 207.322487] drm_minor_register+0x10a/0x2d0 +[ 207.322489] drm_dev_register+0x143/0x860 +[ 207.322491] ? xe_configfs_get_psmi_enabled+0x12/0x90 [xe] +[ 207.322667] xe_device_probe+0x185b/0x2c40 [xe] +[ 207.322812] ? __pfx___drm_dev_dbg+0x10/0x10 +[ 207.322815] ? add_dr+0x180/0x220 +[ 207.322818] ? __pfx___drmm_mutex_release+0x10/0x10 +[ 207.322821] ? __pfx_xe_device_probe+0x10/0x10 [xe] +[ 207.322966] ? xe_pm_init_early+0x33a/0x410 [xe] +[ 207.323136] xe_pci_probe+0x936/0x1250 [xe] +[ 207.323298] ? lock_acquire+0x1a4/0x2e0 +[ 207.323302] ? __pfx_xe_pci_probe+0x10/0x10 [xe] +[ 207.323464] local_pci_probe+0xe6/0x1a0 +[ 207.323468] pci_device_probe+0x523/0x840 +[ 207.323470] ? __pfx_pci_device_probe+0x10/0x10 +[ 207.323473] ? sysfs_do_create_link_sd.isra.0+0x8c/0x110 +[ 207.323476] ? sysfs_create_link+0x48/0xc0 +[ 207.323479] really_probe+0x1fd/0x8a0 +... +" + +Fixes: dd08ebf6c352 ("drm/xe: Introduce a new DRM driver for Intel GPUs") +Signed-off-by: Shuicheng Lin +Reviewed-by: Jonathan Cavitt +Link: https://patch.msgid.link/20260109211041.2446012-2-shuicheng.lin@intel.com +Signed-off-by: Matt Roper +(cherry picked from commit 60bfb8baf8f0d5b0d521744dfd01c880ce1a23f3) +Signed-off-by: Rodrigo Vivi +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/xe/xe_device.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c +index fe5aadb27b779..0d69cd0e4e798 100644 +--- a/drivers/gpu/drm/xe/xe_device.c ++++ b/drivers/gpu/drm/xe/xe_device.c +@@ -966,6 +966,7 @@ int xe_device_probe(struct xe_device *xe) + + err_unregister_display: + xe_display_unregister(xe); ++ drm_dev_unregister(&xe->drm); + + return err; + } +-- +2.51.0 + diff --git a/queue-6.18/edac-altera-remove-irqf_oneshot.patch b/queue-6.18/edac-altera-remove-irqf_oneshot.patch new file mode 100644 index 0000000000..19b64349f5 --- /dev/null +++ b/queue-6.18/edac-altera-remove-irqf_oneshot.patch @@ -0,0 +1,74 @@ +From b0ddb7d5265bc492cc3d90580cedb5dfd9637f11 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:55:30 +0100 +Subject: EDAC/altera: Remove IRQF_ONESHOT + +From: Sebastian Andrzej Siewior + +[ Upstream commit 5c858d6c66304b4c7579582ec5235f02d43578ea ] + +Passing IRQF_ONESHOT ensures that the interrupt source is masked until +the secondary (threaded) handler is done. If only a primary handler is +used then the flag makes no sense because the interrupt can not fire +(again) while its handler is running. + +The flag also prevents force-threading of the primary handler and the +irq-core will warn about this. + +Remove IRQF_ONESHOT from irqflags. + +Fixes: a29d64a45eed1 ("EDAC, altera: Add IRQ Flags to disable IRQ while handling") +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260128095540.863589-11-bigeasy@linutronix.de +Signed-off-by: Sasha Levin +--- + drivers/edac/altera_edac.c | 11 ++++------- + 1 file changed, 4 insertions(+), 7 deletions(-) + +diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c +index 0c5b94e64ea15..4edd2088c2db6 100644 +--- a/drivers/edac/altera_edac.c ++++ b/drivers/edac/altera_edac.c +@@ -1563,8 +1563,7 @@ static int altr_portb_setup(struct altr_edac_device_dev *device) + goto err_release_group_1; + } + rc = devm_request_irq(&altdev->ddev, altdev->sb_irq, +- prv->ecc_irq_handler, +- IRQF_ONESHOT | IRQF_TRIGGER_HIGH, ++ prv->ecc_irq_handler, IRQF_TRIGGER_HIGH, + ecc_name, altdev); + if (rc) { + edac_printk(KERN_ERR, EDAC_DEVICE, "PortB SBERR IRQ error\n"); +@@ -1587,8 +1586,7 @@ static int altr_portb_setup(struct altr_edac_device_dev *device) + goto err_release_group_1; + } + rc = devm_request_irq(&altdev->ddev, altdev->db_irq, +- prv->ecc_irq_handler, +- IRQF_ONESHOT | IRQF_TRIGGER_HIGH, ++ prv->ecc_irq_handler, IRQF_TRIGGER_HIGH, + ecc_name, altdev); + if (rc) { + edac_printk(KERN_ERR, EDAC_DEVICE, "PortB DBERR IRQ error\n"); +@@ -1970,8 +1968,7 @@ static int altr_edac_a10_device_add(struct altr_arria10_edac *edac, + goto err_release_group1; + } + rc = devm_request_irq(edac->dev, altdev->sb_irq, prv->ecc_irq_handler, +- IRQF_ONESHOT | IRQF_TRIGGER_HIGH, +- ecc_name, altdev); ++ IRQF_TRIGGER_HIGH, ecc_name, altdev); + if (rc) { + edac_printk(KERN_ERR, EDAC_DEVICE, "No SBERR IRQ resource\n"); + goto err_release_group1; +@@ -1993,7 +1990,7 @@ static int altr_edac_a10_device_add(struct altr_arria10_edac *edac, + goto err_release_group1; + } + rc = devm_request_irq(edac->dev, altdev->db_irq, prv->ecc_irq_handler, +- IRQF_ONESHOT | IRQF_TRIGGER_HIGH, ++ IRQF_TRIGGER_HIGH, + ecc_name, altdev); + if (rc) { + edac_printk(KERN_ERR, EDAC_DEVICE, "No DBERR IRQ resource\n"); +-- +2.51.0 + diff --git a/queue-6.18/edac-i5000-fix-snprintf-size-calculation-in-calculat.patch b/queue-6.18/edac-i5000-fix-snprintf-size-calculation-in-calculat.patch new file mode 100644 index 0000000000..632e446c3f --- /dev/null +++ b/queue-6.18/edac-i5000-fix-snprintf-size-calculation-in-calculat.patch @@ -0,0 +1,40 @@ +From db4a63c7676c6d28a5fff6ced00b01e7375cf7b4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 17:36:59 +0300 +Subject: EDAC/i5000: Fix snprintf() size calculation in calculate_dimm_size() + +From: Dan Carpenter + +[ Upstream commit 7b5c7e83ac405ff9ecbdd92b37a477f4288f8814 ] + +The snprintf() can't really overflow because we're writing a max of 42 +bytes to a PAGE_SIZE buffer. But the limit calculation doesn't take +the first 11 bytes that we wrote into consideration so the limit is +not correct. Just fix it for correctness even though it doesn't +affect runtime. + +Fixes: 64e1fdaf55d6 ("i5000_edac: Fix the logic that retrieves memory information") +Signed-off-by: Dan Carpenter +Signed-off-by: Tony Luck +Reviewed-by: Qiuxu Zhuo +Link: https://patch.msgid.link/07cd652c51e77aad5a8350e1a7cd9407e5bbe373.1765290801.git.dan.carpenter@linaro.org +Signed-off-by: Sasha Levin +--- + drivers/edac/i5000_edac.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c +index 4a1bebc1ff14d..471b8540d18b0 100644 +--- a/drivers/edac/i5000_edac.c ++++ b/drivers/edac/i5000_edac.c +@@ -1111,6 +1111,7 @@ static void calculate_dimm_size(struct i5000_pvt *pvt) + + n = snprintf(p, space, " "); + p += n; ++ space -= n; + for (branch = 0; branch < MAX_BRANCHES; branch++) { + n = snprintf(p, space, " branch %d | ", branch); + p += n; +-- +2.51.0 + diff --git a/queue-6.18/edac-i5400-fix-snprintf-limit-calculation-in-calcula.patch b/queue-6.18/edac-i5400-fix-snprintf-limit-calculation-in-calcula.patch new file mode 100644 index 0000000000..6310bc16e4 --- /dev/null +++ b/queue-6.18/edac-i5400-fix-snprintf-limit-calculation-in-calcula.patch @@ -0,0 +1,49 @@ +From b2ca5b0d620ebe65bb885f5822916c286e9134fb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 17:37:04 +0300 +Subject: EDAC/i5400: Fix snprintf() limit calculation in calculate_dimm_size() + +From: Dan Carpenter + +[ Upstream commit 72f12683611344853ab030fe7d19b23970ed2bd8 ] + +The snprintf() can't really overflow because we're writing a max of 42 +bytes to a PAGE_SIZE buffer. But my static checker complains because +the limit calculation doesn't take the first 11 space characters that +we wrote into the buffer into consideration. Fix this for the sake of +correctness even though it doesn't affect runtime. + +Also delete an earlier "space -= n;" which was not used. + +Fixes: 68d086f89b80 ("i5400_edac: improve debug messages to better represent the filled memory") +Signed-off-by: Dan Carpenter +Signed-off-by: Tony Luck +Reviewed-by: Qiuxu Zhuo +Link: https://patch.msgid.link/ccd06b91748e7ed8e33eeb2ff1e7b98700879304.1765290801.git.dan.carpenter@linaro.org +Signed-off-by: Sasha Levin +--- + drivers/edac/i5400_edac.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/edac/i5400_edac.c b/drivers/edac/i5400_edac.c +index b5cf25905b059..fb49a1d1df112 100644 +--- a/drivers/edac/i5400_edac.c ++++ b/drivers/edac/i5400_edac.c +@@ -1026,13 +1026,13 @@ static void calculate_dimm_size(struct i5400_pvt *pvt) + space -= n; + } + +- space -= n; + edac_dbg(2, "%s\n", mem_buffer); + p = mem_buffer; + space = PAGE_SIZE; + + n = snprintf(p, space, " "); + p += n; ++ space -= n; + for (branch = 0; branch < MAX_BRANCHES; branch++) { + n = snprintf(p, space, " branch %d | ", branch); + p += n; +-- +2.51.0 + diff --git a/queue-6.18/erofs-fix-inline-data-read-failure-for-ztailpacking-.patch b/queue-6.18/erofs-fix-inline-data-read-failure-for-ztailpacking-.patch new file mode 100644 index 0000000000..b5c4a011cc --- /dev/null +++ b/queue-6.18/erofs-fix-inline-data-read-failure-for-ztailpacking-.patch @@ -0,0 +1,128 @@ +From a15bd3063a40754cb25c92d4a5042291a4bd2fe5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 16:25:36 +0800 +Subject: erofs: fix inline data read failure for ztailpacking pclusters + +From: Gao Xiang + +[ Upstream commit c134a40f86efb8d6b5a949ef70e06d5752209be5 ] + +Compressed folios for ztailpacking pclusters must be valid before adding +these pclusters to I/O chains. Otherwise, z_erofs_decompress_pcluster() +may assume they are already valid and then trigger a NULL pointer +dereference. + +It is somewhat hard to reproduce because the inline data is in the same +block as the tail of the compressed indexes, which are usually read just +before. However, it may still happen if a fatal signal arrives while +read_mapping_folio() is running, as shown below: + + erofs: (device dm-1): z_erofs_pcluster_begin: failed to get inline data -4 + Unable to handle kernel NULL pointer dereference at virtual address 0000000000000008 + + ... + + pc : z_erofs_decompress_queue+0x4c8/0xa14 + lr : z_erofs_decompress_queue+0x160/0xa14 + sp : ffffffc08b3eb3a0 + x29: ffffffc08b3eb570 x28: ffffffc08b3eb418 x27: 0000000000001000 + x26: ffffff8086ebdbb8 x25: ffffff8086ebdbb8 x24: 0000000000000001 + x23: 0000000000000008 x22: 00000000fffffffb x21: dead000000000700 + x20: 00000000000015e7 x19: ffffff808babb400 x18: ffffffc089edc098 + x17: 00000000c006287d x16: 00000000c006287d x15: 0000000000000004 + x14: ffffff80ba8f8000 x13: 0000000000000004 x12: 00000006589a77c9 + x11: 0000000000000015 x10: 0000000000000000 x9 : 0000000000000000 + x8 : 0000000000000000 x7 : 0000000000000000 x6 : 000000000000003f + x5 : 0000000000000040 x4 : ffffffffffffffe0 x3 : 0000000000000020 + x2 : 0000000000000008 x1 : 0000000000000000 x0 : 0000000000000000 + Call trace: + z_erofs_decompress_queue+0x4c8/0xa14 + z_erofs_runqueue+0x908/0x97c + z_erofs_read_folio+0x128/0x228 + filemap_read_folio+0x68/0x128 + filemap_get_pages+0x44c/0x8b4 + filemap_read+0x12c/0x5b8 + generic_file_read_iter+0x4c/0x15c + do_iter_readv_writev+0x188/0x1e0 + vfs_iter_read+0xac/0x1a4 + backing_file_read_iter+0x170/0x34c + ovl_read_iter+0xf0/0x140 + vfs_read+0x28c/0x344 + ksys_read+0x80/0xf0 + __arm64_sys_read+0x24/0x34 + invoke_syscall+0x60/0x114 + el0_svc_common+0x88/0xe4 + do_el0_svc+0x24/0x30 + el0_svc+0x40/0xa8 + el0t_64_sync_handler+0x70/0xbc + el0t_64_sync+0x1bc/0x1c0 + +Fix this by reading the inline data before allocating and adding +the pclusters to the I/O chains. + +Fixes: cecf864d3d76 ("erofs: support inline data decompression") +Reported-by: Zhiguo Niu +Reviewed-and-tested-by: Zhiguo Niu +Signed-off-by: Gao Xiang +Signed-off-by: Sasha Levin +--- + fs/erofs/zdata.c | 30 ++++++++++++++++-------------- + 1 file changed, 16 insertions(+), 14 deletions(-) + +diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c +index 683703aee5ef2..98e44570841a3 100644 +--- a/fs/erofs/zdata.c ++++ b/fs/erofs/zdata.c +@@ -805,14 +805,26 @@ static int z_erofs_pcluster_begin(struct z_erofs_frontend *fe) + struct erofs_map_blocks *map = &fe->map; + struct super_block *sb = fe->inode->i_sb; + struct z_erofs_pcluster *pcl = NULL; +- void *ptr; ++ void *ptr = NULL; + int ret; + + DBG_BUGON(fe->pcl); + /* must be Z_EROFS_PCLUSTER_TAIL or pointed to previous pcluster */ + DBG_BUGON(!fe->head); + +- if (!(map->m_flags & EROFS_MAP_META)) { ++ if (map->m_flags & EROFS_MAP_META) { ++ ret = erofs_init_metabuf(&map->buf, sb, ++ erofs_inode_in_metabox(fe->inode)); ++ if (ret) ++ return ret; ++ ptr = erofs_bread(&map->buf, map->m_pa, false); ++ if (IS_ERR(ptr)) { ++ erofs_err(sb, "failed to read inline data %pe @ pa %llu of nid %llu", ++ ptr, map->m_pa, EROFS_I(fe->inode)->nid); ++ return PTR_ERR(ptr); ++ } ++ ptr = map->buf.page; ++ } else { + while (1) { + rcu_read_lock(); + pcl = xa_load(&EROFS_SB(sb)->managed_pslots, map->m_pa); +@@ -852,18 +864,8 @@ static int z_erofs_pcluster_begin(struct z_erofs_frontend *fe) + /* bind cache first when cached decompression is preferred */ + z_erofs_bind_cache(fe); + } else { +- ret = erofs_init_metabuf(&map->buf, sb, +- erofs_inode_in_metabox(fe->inode)); +- if (ret) +- return ret; +- ptr = erofs_bread(&map->buf, map->m_pa, false); +- if (IS_ERR(ptr)) { +- ret = PTR_ERR(ptr); +- erofs_err(sb, "failed to get inline folio %d", ret); +- return ret; +- } +- folio_get(page_folio(map->buf.page)); +- WRITE_ONCE(fe->pcl->compressed_bvecs[0].page, map->buf.page); ++ folio_get(page_folio((struct page *)ptr)); ++ WRITE_ONCE(fe->pcl->compressed_bvecs[0].page, ptr); + fe->pcl->pageofs_in = map->m_pa & ~PAGE_MASK; + fe->mode = Z_EROFS_PCLUSTER_FOLLOWED_NOINPLACE; + } +-- +2.51.0 + diff --git a/queue-6.18/erofs-get-rid-of-raw-bi_end_io-usage.patch b/queue-6.18/erofs-get-rid-of-raw-bi_end_io-usage.patch new file mode 100644 index 0000000000..6a9d3ffdcc --- /dev/null +++ b/queue-6.18/erofs-get-rid-of-raw-bi_end_io-usage.patch @@ -0,0 +1,71 @@ +From eba51ba3beb3a8723b2ef40427f1ef17a7788fc6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Nov 2025 16:07:56 +0800 +Subject: erofs: get rid of raw bi_end_io() usage + +From: Gao Xiang + +[ Upstream commit 80d0c27a0a4af8e0678d7412781482e6f73c22c7 ] + +These BIOs are actually harmless in practice, as they are all pseudo +BIOs and do not use advanced features like chaining. Using the BIO +interface is a more friendly and unified approach for both bdev and +and file-backed I/Os (compared to awkward bvec interfaces). + +Let's use bio_endio() instead. + +Reviewed-by: Christoph Hellwig +Reviewed-by: Ming Lei +Reviewed-by: Chao Yu +Signed-off-by: Gao Xiang +Stable-dep-of: bc804a8d7e86 ("erofs: handle end of filesystem properly for file-backed mounts") +Signed-off-by: Sasha Levin +--- + fs/erofs/fileio.c | 2 +- + fs/erofs/fscache.c | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/fs/erofs/fileio.c b/fs/erofs/fileio.c +index a47c6bab98ff9..e2eaa7119bd4f 100644 +--- a/fs/erofs/fileio.c ++++ b/fs/erofs/fileio.c +@@ -35,13 +35,13 @@ static void erofs_fileio_ki_complete(struct kiocb *iocb, long ret) + if (rq->bio.bi_end_io) { + if (ret < 0 && !rq->bio.bi_status) + rq->bio.bi_status = errno_to_blk_status(ret); +- rq->bio.bi_end_io(&rq->bio); + } else { + bio_for_each_folio_all(fi, &rq->bio) { + DBG_BUGON(folio_test_uptodate(fi.folio)); + erofs_onlinefolio_end(fi.folio, ret, false); + } + } ++ bio_endio(&rq->bio); + bio_uninit(&rq->bio); + if (refcount_dec_and_test(&rq->ref)) + kfree(rq); +diff --git a/fs/erofs/fscache.c b/fs/erofs/fscache.c +index 362acf828279f..7a346e20f7b7a 100644 +--- a/fs/erofs/fscache.c ++++ b/fs/erofs/fscache.c +@@ -185,7 +185,7 @@ static void erofs_fscache_bio_endio(void *priv, ssize_t transferred_or_error) + + if (IS_ERR_VALUE(transferred_or_error)) + io->bio.bi_status = errno_to_blk_status(transferred_or_error); +- io->bio.bi_end_io(&io->bio); ++ bio_endio(&io->bio); + BUILD_BUG_ON(offsetof(struct erofs_fscache_bio, io) != 0); + erofs_fscache_io_put(&io->io); + } +@@ -216,7 +216,7 @@ void erofs_fscache_submit_bio(struct bio *bio) + if (!ret) + return; + bio->bi_status = errno_to_blk_status(ret); +- bio->bi_end_io(bio); ++ bio_endio(bio); + } + + static int erofs_fscache_meta_read_folio(struct file *data, struct folio *folio) +-- +2.51.0 + diff --git a/queue-6.18/erofs-handle-end-of-filesystem-properly-for-file-bac.patch b/queue-6.18/erofs-handle-end-of-filesystem-properly-for-file-bac.patch new file mode 100644 index 0000000000..b68dc02cfe --- /dev/null +++ b/queue-6.18/erofs-handle-end-of-filesystem-properly-for-file-bac.patch @@ -0,0 +1,64 @@ +From d12ddd376e0c8430e760ae5d72070eaaf06061f9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 15:54:22 +0800 +Subject: erofs: handle end of filesystem properly for file-backed mounts + +From: Gao Xiang + +[ Upstream commit bc804a8d7e865ef47fb7edcaf5e77d18bf444ebc ] + +I/O requests beyond the end of the filesystem should be zeroed out, +similar to loopback devices and that is what we expect. + +Fixes: ce63cb62d794 ("erofs: support unencoded inodes for fileio") +Signed-off-by: Gao Xiang +Signed-off-by: Sasha Levin +--- + fs/erofs/fileio.c | 20 ++++++++------------ + 1 file changed, 8 insertions(+), 12 deletions(-) + +diff --git a/fs/erofs/fileio.c b/fs/erofs/fileio.c +index e2eaa7119bd4f..5b77ee8cc99f4 100644 +--- a/fs/erofs/fileio.c ++++ b/fs/erofs/fileio.c +@@ -25,21 +25,17 @@ static void erofs_fileio_ki_complete(struct kiocb *iocb, long ret) + container_of(iocb, struct erofs_fileio_rq, iocb); + struct folio_iter fi; + +- if (ret > 0) { +- if (ret != rq->bio.bi_iter.bi_size) { +- bio_advance(&rq->bio, ret); +- zero_fill_bio(&rq->bio); +- } +- ret = 0; ++ if (ret >= 0 && ret != rq->bio.bi_iter.bi_size) { ++ bio_advance(&rq->bio, ret); ++ zero_fill_bio(&rq->bio); + } +- if (rq->bio.bi_end_io) { +- if (ret < 0 && !rq->bio.bi_status) +- rq->bio.bi_status = errno_to_blk_status(ret); +- } else { ++ if (!rq->bio.bi_end_io) { + bio_for_each_folio_all(fi, &rq->bio) { + DBG_BUGON(folio_test_uptodate(fi.folio)); +- erofs_onlinefolio_end(fi.folio, ret, false); ++ erofs_onlinefolio_end(fi.folio, ret < 0, false); + } ++ } else if (ret < 0 && !rq->bio.bi_status) { ++ rq->bio.bi_status = errno_to_blk_status(ret); + } + bio_endio(&rq->bio); + bio_uninit(&rq->bio); +@@ -51,7 +47,7 @@ static void erofs_fileio_rq_submit(struct erofs_fileio_rq *rq) + { + const struct cred *old_cred; + struct iov_iter iter; +- int ret; ++ ssize_t ret; + + if (!rq) + return; +-- +2.51.0 + diff --git a/queue-6.18/evm-use-ordered-xattrs-list-to-calculate-hmac-in-evm.patch b/queue-6.18/evm-use-ordered-xattrs-list-to-calculate-hmac-in-evm.patch new file mode 100644 index 0000000000..e1f1f418da --- /dev/null +++ b/queue-6.18/evm-use-ordered-xattrs-list-to-calculate-hmac-in-evm.patch @@ -0,0 +1,70 @@ +From ee47d46ed8f81bdbd200e3c1c03618e7c06f7a91 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 15:53:41 +0100 +Subject: evm: Use ordered xattrs list to calculate HMAC in evm_init_hmac() + +From: Roberto Sassu + +[ Upstream commit 0496fc9cdc384f67be4413b1c6156eb64fccd5c4 ] + +Commit 8e5d9f916a96 ("smack: deduplicate xattr setting in +smack_inode_init_security()") introduced xattr_dupval() to simplify setting +the xattrs to be provided by the SMACK LSM on inode creation, in the +smack_inode_init_security(). + +Unfortunately, moving lsm_get_xattr_slot() caused the SMACK64TRANSMUTE +xattr be added in the array of new xattrs before SMACK64. This causes the +HMAC of xattrs calculated by evm_init_hmac() for new files to diverge from +the one calculated by both evm_calc_hmac_or_hash() and evmctl. + +evm_init_hmac() calculates the HMAC of the xattrs of new files based on the +order LSMs provide them, while evm_calc_hmac_or_hash() and evmctl calculate +the HMAC based on an ordered xattrs list. + +Fix the issue by making evm_init_hmac() calculate the HMAC of new files +based on the ordered xattrs list too. + +Fixes: 8e5d9f916a96 ("smack: deduplicate xattr setting in smack_inode_init_security()") +Signed-off-by: Roberto Sassu +Signed-off-by: Mimi Zohar +Signed-off-by: Sasha Levin +--- + security/integrity/evm/evm_crypto.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c +index a5e730ffda57f..5a8cef45bacf0 100644 +--- a/security/integrity/evm/evm_crypto.c ++++ b/security/integrity/evm/evm_crypto.c +@@ -401,6 +401,7 @@ int evm_init_hmac(struct inode *inode, const struct xattr *xattrs, + { + struct shash_desc *desc; + const struct xattr *xattr; ++ struct xattr_list *xattr_entry; + + desc = init_desc(EVM_XATTR_HMAC, HASH_ALGO_SHA1); + if (IS_ERR(desc)) { +@@ -408,11 +409,16 @@ int evm_init_hmac(struct inode *inode, const struct xattr *xattrs, + return PTR_ERR(desc); + } + +- for (xattr = xattrs; xattr->name; xattr++) { +- if (!evm_protected_xattr(xattr->name)) +- continue; ++ list_for_each_entry_lockless(xattr_entry, &evm_config_xattrnames, ++ list) { ++ for (xattr = xattrs; xattr->name; xattr++) { ++ if (strcmp(xattr_entry->name + ++ XATTR_SECURITY_PREFIX_LEN, xattr->name) != 0) ++ continue; + +- crypto_shash_update(desc, xattr->value, xattr->value_len); ++ crypto_shash_update(desc, xattr->value, ++ xattr->value_len); ++ } + } + + hmac_add_misc(desc, inode, EVM_XATTR_HMAC, hmac_val); +-- +2.51.0 + diff --git a/queue-6.18/ext4-fast-commit-make-s_fc_lock-reclaim-safe.patch b/queue-6.18/ext4-fast-commit-make-s_fc_lock-reclaim-safe.patch new file mode 100644 index 0000000000..7454c112d4 --- /dev/null +++ b/queue-6.18/ext4-fast-commit-make-s_fc_lock-reclaim-safe.patch @@ -0,0 +1,301 @@ +From f81e9b6c08ed26ab42df3f2be089bd9a2d8aad7c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Jan 2026 20:06:21 +0800 +Subject: ext4: fast commit: make s_fc_lock reclaim-safe + +From: Li Chen + +[ Upstream commit 491f2927ae097e2d405afe0b3fe841931ab8aad2 ] + +s_fc_lock can be acquired from inode eviction and thus is +reclaim unsafe. Since the fast commit path holds s_fc_lock while writing +the commit log, allocations under the lock can enter reclaim and invert +the lock order with fs_reclaim. Add ext4_fc_lock()/ext4_fc_unlock() +helpers which acquire s_fc_lock under memalloc_nofs_save()/restore() +context and use them everywhere so allocations under the lock cannot +recurse into filesystem reclaim. + +Fixes: 6593714d67ba ("ext4: hold s_fc_lock while during fast commit") +Signed-off-by: Li Chen +Reviewed-by: Baokun Li +Reviewed-by: Zhang Yi +Reviewed-by: Jan Kara +Link: https://patch.msgid.link/20260106120621.440126-1-me@linux.beauty +Signed-off-by: Theodore Ts'o +Signed-off-by: Sasha Levin +--- + fs/ext4/ext4.h | 16 ++++++++++++++ + fs/ext4/fast_commit.c | 51 ++++++++++++++++++++++++------------------- + 2 files changed, 44 insertions(+), 23 deletions(-) + +diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h +index 57087da6c7bee..933297251f66a 100644 +--- a/fs/ext4/ext4.h ++++ b/fs/ext4/ext4.h +@@ -1771,6 +1771,10 @@ struct ext4_sb_info { + * Main fast commit lock. This lock protects accesses to the + * following fields: + * ei->i_fc_list, s_fc_dentry_q, s_fc_q, s_fc_bytes, s_fc_bh. ++ * ++ * s_fc_lock can be taken from reclaim context (inode eviction) and is ++ * thus reclaim unsafe. Use ext4_fc_lock()/ext4_fc_unlock() helpers ++ * when acquiring / releasing the lock. + */ + struct mutex s_fc_lock; + struct buffer_head *s_fc_bh; +@@ -1815,6 +1819,18 @@ static inline void ext4_writepages_up_write(struct super_block *sb, int ctx) + percpu_up_write(&EXT4_SB(sb)->s_writepages_rwsem); + } + ++static inline int ext4_fc_lock(struct super_block *sb) ++{ ++ mutex_lock(&EXT4_SB(sb)->s_fc_lock); ++ return memalloc_nofs_save(); ++} ++ ++static inline void ext4_fc_unlock(struct super_block *sb, int ctx) ++{ ++ memalloc_nofs_restore(ctx); ++ mutex_unlock(&EXT4_SB(sb)->s_fc_lock); ++} ++ + static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino) + { + return ino == EXT4_ROOT_INO || +diff --git a/fs/ext4/fast_commit.c b/fs/ext4/fast_commit.c +index fa66b08de9994..5bd57d7f921b9 100644 +--- a/fs/ext4/fast_commit.c ++++ b/fs/ext4/fast_commit.c +@@ -231,16 +231,16 @@ static bool ext4_fc_disabled(struct super_block *sb) + void ext4_fc_del(struct inode *inode) + { + struct ext4_inode_info *ei = EXT4_I(inode); +- struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); + struct ext4_fc_dentry_update *fc_dentry; + wait_queue_head_t *wq; ++ int alloc_ctx; + + if (ext4_fc_disabled(inode->i_sb)) + return; + +- mutex_lock(&sbi->s_fc_lock); ++ alloc_ctx = ext4_fc_lock(inode->i_sb); + if (list_empty(&ei->i_fc_list) && list_empty(&ei->i_fc_dilist)) { +- mutex_unlock(&sbi->s_fc_lock); ++ ext4_fc_unlock(inode->i_sb, alloc_ctx); + return; + } + +@@ -275,9 +275,9 @@ void ext4_fc_del(struct inode *inode) + #endif + prepare_to_wait(wq, &wait.wq_entry, TASK_UNINTERRUPTIBLE); + if (ext4_test_inode_state(inode, EXT4_STATE_FC_FLUSHING_DATA)) { +- mutex_unlock(&sbi->s_fc_lock); ++ ext4_fc_unlock(inode->i_sb, alloc_ctx); + schedule(); +- mutex_lock(&sbi->s_fc_lock); ++ alloc_ctx = ext4_fc_lock(inode->i_sb); + } + finish_wait(wq, &wait.wq_entry); + } +@@ -288,7 +288,7 @@ void ext4_fc_del(struct inode *inode) + * dentry create references, since it is not needed to log it anyways. + */ + if (list_empty(&ei->i_fc_dilist)) { +- mutex_unlock(&sbi->s_fc_lock); ++ ext4_fc_unlock(inode->i_sb, alloc_ctx); + return; + } + +@@ -298,7 +298,7 @@ void ext4_fc_del(struct inode *inode) + list_del_init(&fc_dentry->fcd_dilist); + + WARN_ON(!list_empty(&ei->i_fc_dilist)); +- mutex_unlock(&sbi->s_fc_lock); ++ ext4_fc_unlock(inode->i_sb, alloc_ctx); + + release_dentry_name_snapshot(&fc_dentry->fcd_name); + kmem_cache_free(ext4_fc_dentry_cachep, fc_dentry); +@@ -315,6 +315,7 @@ void ext4_fc_mark_ineligible(struct super_block *sb, int reason, handle_t *handl + tid_t tid; + bool has_transaction = true; + bool is_ineligible; ++ int alloc_ctx; + + if (ext4_fc_disabled(sb)) + return; +@@ -329,12 +330,12 @@ void ext4_fc_mark_ineligible(struct super_block *sb, int reason, handle_t *handl + has_transaction = false; + read_unlock(&sbi->s_journal->j_state_lock); + } +- mutex_lock(&sbi->s_fc_lock); ++ alloc_ctx = ext4_fc_lock(sb); + is_ineligible = ext4_test_mount_flag(sb, EXT4_MF_FC_INELIGIBLE); + if (has_transaction && (!is_ineligible || tid_gt(tid, sbi->s_fc_ineligible_tid))) + sbi->s_fc_ineligible_tid = tid; + ext4_set_mount_flag(sb, EXT4_MF_FC_INELIGIBLE); +- mutex_unlock(&sbi->s_fc_lock); ++ ext4_fc_unlock(sb, alloc_ctx); + WARN_ON(reason >= EXT4_FC_REASON_MAX); + sbi->s_fc_stats.fc_ineligible_reason_count[reason]++; + } +@@ -358,6 +359,7 @@ static int ext4_fc_track_template( + struct ext4_inode_info *ei = EXT4_I(inode); + struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); + tid_t tid = 0; ++ int alloc_ctx; + int ret; + + tid = handle->h_transaction->t_tid; +@@ -373,14 +375,14 @@ static int ext4_fc_track_template( + if (!enqueue) + return ret; + +- mutex_lock(&sbi->s_fc_lock); ++ alloc_ctx = ext4_fc_lock(inode->i_sb); + if (list_empty(&EXT4_I(inode)->i_fc_list)) + list_add_tail(&EXT4_I(inode)->i_fc_list, + (sbi->s_journal->j_flags & JBD2_FULL_COMMIT_ONGOING || + sbi->s_journal->j_flags & JBD2_FAST_COMMIT_ONGOING) ? + &sbi->s_fc_q[FC_Q_STAGING] : + &sbi->s_fc_q[FC_Q_MAIN]); +- mutex_unlock(&sbi->s_fc_lock); ++ ext4_fc_unlock(inode->i_sb, alloc_ctx); + + return ret; + } +@@ -402,6 +404,7 @@ static int __track_dentry_update(handle_t *handle, struct inode *inode, + struct inode *dir = dentry->d_parent->d_inode; + struct super_block *sb = inode->i_sb; + struct ext4_sb_info *sbi = EXT4_SB(sb); ++ int alloc_ctx; + + spin_unlock(&ei->i_fc_lock); + +@@ -425,7 +428,7 @@ static int __track_dentry_update(handle_t *handle, struct inode *inode, + take_dentry_name_snapshot(&node->fcd_name, dentry); + INIT_LIST_HEAD(&node->fcd_dilist); + INIT_LIST_HEAD(&node->fcd_list); +- mutex_lock(&sbi->s_fc_lock); ++ alloc_ctx = ext4_fc_lock(sb); + if (sbi->s_journal->j_flags & JBD2_FULL_COMMIT_ONGOING || + sbi->s_journal->j_flags & JBD2_FAST_COMMIT_ONGOING) + list_add_tail(&node->fcd_list, +@@ -446,7 +449,7 @@ static int __track_dentry_update(handle_t *handle, struct inode *inode, + WARN_ON(!list_empty(&ei->i_fc_dilist)); + list_add_tail(&node->fcd_dilist, &ei->i_fc_dilist); + } +- mutex_unlock(&sbi->s_fc_lock); ++ ext4_fc_unlock(sb, alloc_ctx); + spin_lock(&ei->i_fc_lock); + + return 0; +@@ -1046,18 +1049,19 @@ static int ext4_fc_perform_commit(journal_t *journal) + struct blk_plug plug; + int ret = 0; + u32 crc = 0; ++ int alloc_ctx; + + /* + * Step 1: Mark all inodes on s_fc_q[MAIN] with + * EXT4_STATE_FC_FLUSHING_DATA. This prevents these inodes from being + * freed until the data flush is over. + */ +- mutex_lock(&sbi->s_fc_lock); ++ alloc_ctx = ext4_fc_lock(sb); + list_for_each_entry(iter, &sbi->s_fc_q[FC_Q_MAIN], i_fc_list) { + ext4_set_inode_state(&iter->vfs_inode, + EXT4_STATE_FC_FLUSHING_DATA); + } +- mutex_unlock(&sbi->s_fc_lock); ++ ext4_fc_unlock(sb, alloc_ctx); + + /* Step 2: Flush data for all the eligible inodes. */ + ret = ext4_fc_flush_data(journal); +@@ -1067,7 +1071,7 @@ static int ext4_fc_perform_commit(journal_t *journal) + * any error from step 2. This ensures that waiters waiting on + * EXT4_STATE_FC_FLUSHING_DATA can resume. + */ +- mutex_lock(&sbi->s_fc_lock); ++ alloc_ctx = ext4_fc_lock(sb); + list_for_each_entry(iter, &sbi->s_fc_q[FC_Q_MAIN], i_fc_list) { + ext4_clear_inode_state(&iter->vfs_inode, + EXT4_STATE_FC_FLUSHING_DATA); +@@ -1084,7 +1088,7 @@ static int ext4_fc_perform_commit(journal_t *journal) + * prepare_to_wait() in ext4_fc_del(). + */ + smp_mb(); +- mutex_unlock(&sbi->s_fc_lock); ++ ext4_fc_unlock(sb, alloc_ctx); + + /* + * If we encountered error in Step 2, return it now after clearing +@@ -1101,12 +1105,12 @@ static int ext4_fc_perform_commit(journal_t *journal) + * previous handles are now drained. We now mark the inodes on the + * commit queue as being committed. + */ +- mutex_lock(&sbi->s_fc_lock); ++ alloc_ctx = ext4_fc_lock(sb); + list_for_each_entry(iter, &sbi->s_fc_q[FC_Q_MAIN], i_fc_list) { + ext4_set_inode_state(&iter->vfs_inode, + EXT4_STATE_FC_COMMITTING); + } +- mutex_unlock(&sbi->s_fc_lock); ++ ext4_fc_unlock(sb, alloc_ctx); + jbd2_journal_unlock_updates(journal); + + /* +@@ -1117,6 +1121,7 @@ static int ext4_fc_perform_commit(journal_t *journal) + blkdev_issue_flush(journal->j_fs_dev); + + blk_start_plug(&plug); ++ alloc_ctx = ext4_fc_lock(sb); + /* Step 6: Write fast commit blocks to disk. */ + if (sbi->s_fc_bytes == 0) { + /* +@@ -1134,7 +1139,6 @@ static int ext4_fc_perform_commit(journal_t *journal) + } + + /* Step 6.2: Now write all the dentry updates. */ +- mutex_lock(&sbi->s_fc_lock); + ret = ext4_fc_commit_dentry_updates(journal, &crc); + if (ret) + goto out; +@@ -1156,7 +1160,7 @@ static int ext4_fc_perform_commit(journal_t *journal) + ret = ext4_fc_write_tail(sb, crc); + + out: +- mutex_unlock(&sbi->s_fc_lock); ++ ext4_fc_unlock(sb, alloc_ctx); + blk_finish_plug(&plug); + return ret; + } +@@ -1290,6 +1294,7 @@ static void ext4_fc_cleanup(journal_t *journal, int full, tid_t tid) + struct ext4_sb_info *sbi = EXT4_SB(sb); + struct ext4_inode_info *ei; + struct ext4_fc_dentry_update *fc_dentry; ++ int alloc_ctx; + + if (full && sbi->s_fc_bh) + sbi->s_fc_bh = NULL; +@@ -1297,7 +1302,7 @@ static void ext4_fc_cleanup(journal_t *journal, int full, tid_t tid) + trace_ext4_fc_cleanup(journal, full, tid); + jbd2_fc_release_bufs(journal); + +- mutex_lock(&sbi->s_fc_lock); ++ alloc_ctx = ext4_fc_lock(sb); + while (!list_empty(&sbi->s_fc_q[FC_Q_MAIN])) { + ei = list_first_entry(&sbi->s_fc_q[FC_Q_MAIN], + struct ext4_inode_info, +@@ -1356,7 +1361,7 @@ static void ext4_fc_cleanup(journal_t *journal, int full, tid_t tid) + + if (full) + sbi->s_fc_bytes = 0; +- mutex_unlock(&sbi->s_fc_lock); ++ ext4_fc_unlock(sb, alloc_ctx); + trace_ext4_fc_stats(sb); + } + +-- +2.51.0 + diff --git a/queue-6.18/fat-avoid-parent-link-count-underflow-in-rmdir.patch b/queue-6.18/fat-avoid-parent-link-count-underflow-in-rmdir.patch new file mode 100644 index 0000000000..4d75480324 --- /dev/null +++ b/queue-6.18/fat-avoid-parent-link-count-underflow-in-rmdir.patch @@ -0,0 +1,74 @@ +From 96c019f72a4a95353b0dc71b3db20295d2270e53 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 1 Jan 2026 19:11:48 +0800 +Subject: fat: avoid parent link count underflow in rmdir + +From: Zhiyu Zhang + +[ Upstream commit 8cafcb881364af5ef3a8b9fed4db254054033d8a ] + +Corrupted FAT images can leave a directory inode with an incorrect +i_nlink (e.g. 2 even though subdirectories exist). rmdir then +unconditionally calls drop_nlink(dir) and can drive i_nlink to 0, +triggering the WARN_ON in drop_nlink(). + +Add a sanity check in vfat_rmdir() and msdos_rmdir(): only drop the +parent link count when it is at least 3, otherwise report a filesystem +error. + +Link: https://lkml.kernel.org/r/20260101111148.1437-1-zhiyuzhang999@gmail.com +Fixes: 9a53c3a783c2 ("[PATCH] r/o bind mounts: unlink: monitor i_nlink") +Signed-off-by: Zhiyu Zhang +Reported-by: Zhiyu Zhang +Closes: https://lore.kernel.org/linux-fsdevel/aVN06OKsKxZe6-Kv@casper.infradead.org/T/#t +Tested-by: Zhiyu Zhang +Acked-by: OGAWA Hirofumi +Cc: Al Viro +Cc: Christian Brauner +Cc: Jan Kara +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/fat/namei_msdos.c | 7 ++++++- + fs/fat/namei_vfat.c | 7 ++++++- + 2 files changed, 12 insertions(+), 2 deletions(-) + +diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c +index 0b920ee40a7f9..262ec1b790b56 100644 +--- a/fs/fat/namei_msdos.c ++++ b/fs/fat/namei_msdos.c +@@ -325,7 +325,12 @@ static int msdos_rmdir(struct inode *dir, struct dentry *dentry) + err = fat_remove_entries(dir, &sinfo); /* and releases bh */ + if (err) + goto out; +- drop_nlink(dir); ++ if (dir->i_nlink >= 3) ++ drop_nlink(dir); ++ else { ++ fat_fs_error(sb, "parent dir link count too low (%u)", ++ dir->i_nlink); ++ } + + clear_nlink(inode); + fat_truncate_time(inode, NULL, S_CTIME); +diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c +index 5dbc4cbb8fce3..47ff083cfc7e6 100644 +--- a/fs/fat/namei_vfat.c ++++ b/fs/fat/namei_vfat.c +@@ -803,7 +803,12 @@ static int vfat_rmdir(struct inode *dir, struct dentry *dentry) + err = fat_remove_entries(dir, &sinfo); /* and releases bh */ + if (err) + goto out; +- drop_nlink(dir); ++ if (dir->i_nlink >= 3) ++ drop_nlink(dir); ++ else { ++ fat_fs_error(sb, "parent dir link count too low (%u)", ++ dir->i_nlink); ++ } + + clear_nlink(inode); + fat_truncate_time(inode, NULL, S_ATIME|S_MTIME); +-- +2.51.0 + diff --git a/queue-6.18/fbcon-move-fbcon-callbacks-into-struct-fbcon_bitops.patch b/queue-6.18/fbcon-move-fbcon-callbacks-into-struct-fbcon_bitops.patch new file mode 100644 index 0000000000..ad31011519 --- /dev/null +++ b/queue-6.18/fbcon-move-fbcon-callbacks-into-struct-fbcon_bitops.patch @@ -0,0 +1,432 @@ +From 16e324db5edd1aec01b4629613209c8a2d936a91 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Sep 2025 14:44:44 +0200 +Subject: fbcon: Move fbcon callbacks into struct fbcon_bitops + +From: Thomas Zimmermann + +[ Upstream commit 217cb07be424d127293dc0b32dbd077ad37c24f6 ] + +Depending on rotation settings, fbcon sets different callback +functions in struct fbcon_par from within fbcon_set_bitops(). Declare +the callback functions in the new type struct fbcon_bitops. Then +only replace the single bitops pointer in struct fbcon_par. + +Keeping callbacks in constant instances of struct fbcon_bitops +makes it harder to exploit the callbacks. Also makes the code slightly +easier to maintain. + +For tile-based consoles, there's a separate instance of the bitops +structure. + +Signed-off-by: Thomas Zimmermann +Reviewed-by: Sam Ravnborg +Link: https://lore.kernel.org/r/20250909124616.143365-5-tzimmermann@suse.de +Stable-dep-of: 8e9bf8b9e8c0 ("printk, vt, fbcon: Remove console_conditional_schedule()") +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/core/bitblit.c | 17 ++++--- + drivers/video/fbdev/core/fbcon.c | 67 +++++++++++++++------------- + drivers/video/fbdev/core/fbcon.h | 7 ++- + drivers/video/fbdev/core/fbcon_ccw.c | 18 +++++--- + drivers/video/fbdev/core/fbcon_cw.c | 18 +++++--- + drivers/video/fbdev/core/fbcon_ud.c | 18 +++++--- + drivers/video/fbdev/core/tileblit.c | 16 ++++--- + 7 files changed, 94 insertions(+), 67 deletions(-) + +diff --git a/drivers/video/fbdev/core/bitblit.c b/drivers/video/fbdev/core/bitblit.c +index bed8ba18222b9..8b5819877469e 100644 +--- a/drivers/video/fbdev/core/bitblit.c ++++ b/drivers/video/fbdev/core/bitblit.c +@@ -409,15 +409,18 @@ static int bit_update_start(struct fb_info *info) + return err; + } + ++static const struct fbcon_bitops bit_fbcon_bitops = { ++ .bmove = bit_bmove, ++ .clear = bit_clear, ++ .putcs = bit_putcs, ++ .clear_margins = bit_clear_margins, ++ .cursor = bit_cursor, ++ .update_start = bit_update_start, ++}; ++ + void fbcon_set_bitops(struct fbcon_par *par) + { +- par->bmove = bit_bmove; +- par->clear = bit_clear; +- par->putcs = bit_putcs; +- par->clear_margins = bit_clear_margins; +- par->cursor = bit_cursor; +- par->update_start = bit_update_start; +- par->rotate_font = NULL; ++ par->bitops = &bit_fbcon_bitops; + + if (par->rotate) + fbcon_set_rotate(par); +diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c +index 2523d8b223dc1..413aa46228549 100644 +--- a/drivers/video/fbdev/core/fbcon.c ++++ b/drivers/video/fbdev/core/fbcon.c +@@ -400,9 +400,9 @@ static void fb_flashcursor(struct work_struct *work) + + c = scr_readw((u16 *) vc->vc_pos); + enable = par->cursor_flash && !par->cursor_state.enable; +- par->cursor(vc, info, enable, +- get_fg_color(vc, info, c), +- get_bg_color(vc, info, c)); ++ par->bitops->cursor(vc, info, enable, ++ get_fg_color(vc, info, c), ++ get_bg_color(vc, info, c)); + console_unlock(); + + queue_delayed_work(system_power_efficient_wq, &par->cursor_work, +@@ -1157,7 +1157,7 @@ static void fbcon_init(struct vc_data *vc, bool init) + if (logo) + fbcon_prepare_logo(vc, info, cols, rows, new_cols, new_rows); + +- if (par->rotate_font && par->rotate_font(info, vc)) { ++ if (par->bitops->rotate_font && par->bitops->rotate_font(info, vc)) { + par->rotate = FB_ROTATE_UR; + set_blitting_type(vc, info); + } +@@ -1298,10 +1298,11 @@ static void __fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx, + y_break = p->vrows - p->yscroll; + if (sy < y_break && sy + height - 1 >= y_break) { + u_int b = y_break - sy; +- par->clear(vc, info, real_y(p, sy), sx, b, width, fg, bg); +- par->clear(vc, info, real_y(p, sy + b), sx, height - b, width, fg, bg); ++ par->bitops->clear(vc, info, real_y(p, sy), sx, b, width, fg, bg); ++ par->bitops->clear(vc, info, real_y(p, sy + b), sx, height - b, ++ width, fg, bg); + } else +- par->clear(vc, info, real_y(p, sy), sx, height, width, fg, bg); ++ par->bitops->clear(vc, info, real_y(p, sy), sx, height, width, fg, bg); + } + + static void fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx, +@@ -1318,9 +1319,9 @@ static void fbcon_putcs(struct vc_data *vc, const u16 *s, unsigned int count, + struct fbcon_par *par = info->fbcon_par; + + if (fbcon_is_active(vc, info)) +- par->putcs(vc, info, s, count, real_y(p, ypos), xpos, +- get_fg_color(vc, info, scr_readw(s)), +- get_bg_color(vc, info, scr_readw(s))); ++ par->bitops->putcs(vc, info, s, count, real_y(p, ypos), xpos, ++ get_fg_color(vc, info, scr_readw(s)), ++ get_bg_color(vc, info, scr_readw(s))); + } + + static void fbcon_clear_margins(struct vc_data *vc, int bottom_only) +@@ -1329,7 +1330,7 @@ static void fbcon_clear_margins(struct vc_data *vc, int bottom_only) + struct fbcon_par *par = info->fbcon_par; + + if (fbcon_is_active(vc, info)) +- par->clear_margins(vc, info, margin_color, bottom_only); ++ par->bitops->clear_margins(vc, info, margin_color, bottom_only); + } + + static void fbcon_cursor(struct vc_data *vc, bool enable) +@@ -1350,12 +1351,12 @@ static void fbcon_cursor(struct vc_data *vc, bool enable) + + par->cursor_flash = enable; + +- if (!par->cursor) ++ if (!par->bitops->cursor) + return; + +- par->cursor(vc, info, enable, +- get_fg_color(vc, info, c), +- get_bg_color(vc, info, c)); ++ par->bitops->cursor(vc, info, enable, ++ get_fg_color(vc, info, c), ++ get_bg_color(vc, info, c)); + } + + static int scrollback_phys_max = 0; +@@ -1439,7 +1440,7 @@ static __inline__ void ywrap_up(struct vc_data *vc, int count) + par->var.xoffset = 0; + par->var.yoffset = p->yscroll * vc->vc_font.height; + par->var.vmode |= FB_VMODE_YWRAP; +- par->update_start(info); ++ par->bitops->update_start(info); + scrollback_max += count; + if (scrollback_max > scrollback_phys_max) + scrollback_max = scrollback_phys_max; +@@ -1458,7 +1459,7 @@ static __inline__ void ywrap_down(struct vc_data *vc, int count) + par->var.xoffset = 0; + par->var.yoffset = p->yscroll * vc->vc_font.height; + par->var.vmode |= FB_VMODE_YWRAP; +- par->update_start(info); ++ par->bitops->update_start(info); + scrollback_max -= count; + if (scrollback_max < 0) + scrollback_max = 0; +@@ -1473,15 +1474,15 @@ static __inline__ void ypan_up(struct vc_data *vc, int count) + + p->yscroll += count; + if (p->yscroll > p->vrows - vc->vc_rows) { +- par->bmove(vc, info, p->vrows - vc->vc_rows, +- 0, 0, 0, vc->vc_rows, vc->vc_cols); ++ par->bitops->bmove(vc, info, p->vrows - vc->vc_rows, ++ 0, 0, 0, vc->vc_rows, vc->vc_cols); + p->yscroll -= p->vrows - vc->vc_rows; + } + + par->var.xoffset = 0; + par->var.yoffset = p->yscroll * vc->vc_font.height; + par->var.vmode &= ~FB_VMODE_YWRAP; +- par->update_start(info); ++ par->bitops->update_start(info); + fbcon_clear_margins(vc, 1); + scrollback_max += count; + if (scrollback_max > scrollback_phys_max) +@@ -1505,7 +1506,7 @@ static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count) + par->var.xoffset = 0; + par->var.yoffset = p->yscroll * vc->vc_font.height; + par->var.vmode &= ~FB_VMODE_YWRAP; +- par->update_start(info); ++ par->bitops->update_start(info); + fbcon_clear_margins(vc, 1); + scrollback_max += count; + if (scrollback_max > scrollback_phys_max) +@@ -1521,15 +1522,15 @@ static __inline__ void ypan_down(struct vc_data *vc, int count) + + p->yscroll -= count; + if (p->yscroll < 0) { +- par->bmove(vc, info, 0, 0, p->vrows - vc->vc_rows, +- 0, vc->vc_rows, vc->vc_cols); ++ par->bitops->bmove(vc, info, 0, 0, p->vrows - vc->vc_rows, ++ 0, vc->vc_rows, vc->vc_cols); + p->yscroll += p->vrows - vc->vc_rows; + } + + par->var.xoffset = 0; + par->var.yoffset = p->yscroll * vc->vc_font.height; + par->var.vmode &= ~FB_VMODE_YWRAP; +- par->update_start(info); ++ par->bitops->update_start(info); + fbcon_clear_margins(vc, 1); + scrollback_max -= count; + if (scrollback_max < 0) +@@ -1553,7 +1554,7 @@ static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count) + par->var.xoffset = 0; + par->var.yoffset = p->yscroll * vc->vc_font.height; + par->var.vmode &= ~FB_VMODE_YWRAP; +- par->update_start(info); ++ par->bitops->update_start(info); + fbcon_clear_margins(vc, 1); + scrollback_max -= count; + if (scrollback_max < 0) +@@ -1615,8 +1616,8 @@ static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info, + + if (c == scr_readw(d)) { + if (s > start) { +- par->bmove(vc, info, line + ycount, x, +- line, x, 1, s - start); ++ par->bitops->bmove(vc, info, line + ycount, x, ++ line, x, 1, s - start); + x += s - start + 1; + start = s + 1; + } else { +@@ -1631,7 +1632,8 @@ static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info, + d++; + } while (s < le); + if (s > start) +- par->bmove(vc, info, line + ycount, x, line, x, 1, s - start); ++ par->bitops->bmove(vc, info, line + ycount, x, line, x, 1, ++ s - start); + console_conditional_schedule(); + if (ycount > 0) + line++; +@@ -1736,7 +1738,8 @@ static void fbcon_bmove_rec(struct vc_data *vc, struct fbcon_display *p, int sy, + } + return; + } +- par->bmove(vc, info, real_y(p, sy), sx, real_y(p, dy), dx, height, width); ++ par->bitops->bmove(vc, info, real_y(p, sy), sx, real_y(p, dy), dx, ++ height, width); + } + + static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx, +@@ -2156,7 +2159,7 @@ static bool fbcon_switch(struct vc_data *vc) + set_blitting_type(vc, info); + par->cursor_reset = 1; + +- if (par->rotate_font && par->rotate_font(info, vc)) { ++ if (par->bitops->rotate_font && par->bitops->rotate_font(info, vc)) { + par->rotate = FB_ROTATE_UR; + set_blitting_type(vc, info); + } +@@ -2189,7 +2192,7 @@ static bool fbcon_switch(struct vc_data *vc) + + if (fbcon_is_active(vc, info)) { + par->var.xoffset = par->var.yoffset = p->yscroll = 0; +- par->update_start(info); ++ par->bitops->update_start(info); + } + + fbcon_set_palette(vc, color_table); +@@ -2695,7 +2698,7 @@ static void fbcon_modechanged(struct fb_info *info) + + if (fbcon_is_active(vc, info)) { + par->var.xoffset = par->var.yoffset = p->yscroll = 0; +- par->update_start(info); ++ par->bitops->update_start(info); + } + + fbcon_set_palette(vc, color_table); +diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h +index 31ee2d5912219..69ae6b965a103 100644 +--- a/drivers/video/fbdev/core/fbcon.h ++++ b/drivers/video/fbdev/core/fbcon.h +@@ -51,7 +51,7 @@ struct fbcon_display { + const struct fb_videomode *mode; + }; + +-struct fbcon_par { ++struct fbcon_bitops { + void (*bmove)(struct vc_data *vc, struct fb_info *info, int sy, + int sx, int dy, int dx, int height, int width); + void (*clear)(struct vc_data *vc, struct fb_info *info, int sy, +@@ -65,6 +65,9 @@ struct fbcon_par { + bool enable, int fg, int bg); + int (*update_start)(struct fb_info *info); + int (*rotate_font)(struct fb_info *info, struct vc_data *vc); ++}; ++ ++struct fbcon_par { + struct fb_var_screeninfo var; /* copy of the current fb_var_screeninfo */ + struct delayed_work cursor_work; /* Cursor timer */ + struct fb_cursor cursor_state; +@@ -86,6 +89,8 @@ struct fbcon_par { + u8 *cursor_src; + u32 cursor_size; + u32 fd_size; ++ ++ const struct fbcon_bitops *bitops; + }; + /* + * Attribute Decoding +diff --git a/drivers/video/fbdev/core/fbcon_ccw.c b/drivers/video/fbdev/core/fbcon_ccw.c +index ba744b67a4fd9..4721f4b5e29a5 100644 +--- a/drivers/video/fbdev/core/fbcon_ccw.c ++++ b/drivers/video/fbdev/core/fbcon_ccw.c +@@ -390,13 +390,17 @@ static int ccw_update_start(struct fb_info *info) + return err; + } + ++static const struct fbcon_bitops ccw_fbcon_bitops = { ++ .bmove = ccw_bmove, ++ .clear = ccw_clear, ++ .putcs = ccw_putcs, ++ .clear_margins = ccw_clear_margins, ++ .cursor = ccw_cursor, ++ .update_start = ccw_update_start, ++ .rotate_font = fbcon_rotate_font, ++}; ++ + void fbcon_rotate_ccw(struct fbcon_par *par) + { +- par->bmove = ccw_bmove; +- par->clear = ccw_clear; +- par->putcs = ccw_putcs; +- par->clear_margins = ccw_clear_margins; +- par->cursor = ccw_cursor; +- par->update_start = ccw_update_start; +- par->rotate_font = fbcon_rotate_font; ++ par->bitops = &ccw_fbcon_bitops; + } +diff --git a/drivers/video/fbdev/core/fbcon_cw.c b/drivers/video/fbdev/core/fbcon_cw.c +index 974bd9d9b7702..2771924d0fb72 100644 +--- a/drivers/video/fbdev/core/fbcon_cw.c ++++ b/drivers/video/fbdev/core/fbcon_cw.c +@@ -373,13 +373,17 @@ static int cw_update_start(struct fb_info *info) + return err; + } + ++static const struct fbcon_bitops cw_fbcon_bitops = { ++ .bmove = cw_bmove, ++ .clear = cw_clear, ++ .putcs = cw_putcs, ++ .clear_margins = cw_clear_margins, ++ .cursor = cw_cursor, ++ .update_start = cw_update_start, ++ .rotate_font = fbcon_rotate_font, ++}; ++ + void fbcon_rotate_cw(struct fbcon_par *par) + { +- par->bmove = cw_bmove; +- par->clear = cw_clear; +- par->putcs = cw_putcs; +- par->clear_margins = cw_clear_margins; +- par->cursor = cw_cursor; +- par->update_start = cw_update_start; +- par->rotate_font = fbcon_rotate_font; ++ par->bitops = &cw_fbcon_bitops; + } +diff --git a/drivers/video/fbdev/core/fbcon_ud.c b/drivers/video/fbdev/core/fbcon_ud.c +index 1a214a4d538fb..148ca9b539d19 100644 +--- a/drivers/video/fbdev/core/fbcon_ud.c ++++ b/drivers/video/fbdev/core/fbcon_ud.c +@@ -417,13 +417,17 @@ static int ud_update_start(struct fb_info *info) + return err; + } + ++static const struct fbcon_bitops ud_fbcon_bitops = { ++ .bmove = ud_bmove, ++ .clear = ud_clear, ++ .putcs = ud_putcs, ++ .clear_margins = ud_clear_margins, ++ .cursor = ud_cursor, ++ .update_start = ud_update_start, ++ .rotate_font = fbcon_rotate_font, ++}; ++ + void fbcon_rotate_ud(struct fbcon_par *par) + { +- par->bmove = ud_bmove; +- par->clear = ud_clear; +- par->putcs = ud_putcs; +- par->clear_margins = ud_clear_margins; +- par->cursor = ud_cursor; +- par->update_start = ud_update_start; +- par->rotate_font = fbcon_rotate_font; ++ par->bitops = &ud_fbcon_bitops; + } +diff --git a/drivers/video/fbdev/core/tileblit.c b/drivers/video/fbdev/core/tileblit.c +index 4428f2bcd3f8c..a9db668caf727 100644 +--- a/drivers/video/fbdev/core/tileblit.c ++++ b/drivers/video/fbdev/core/tileblit.c +@@ -161,17 +161,21 @@ static int tile_update_start(struct fb_info *info) + return err; + } + ++static const struct fbcon_bitops tile_fbcon_bitops = { ++ .bmove = tile_bmove, ++ .clear = tile_clear, ++ .putcs = tile_putcs, ++ .clear_margins = tile_clear_margins, ++ .cursor = tile_cursor, ++ .update_start = tile_update_start, ++}; ++ + void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info) + { + struct fb_tilemap map; + struct fbcon_par *par = info->fbcon_par; + +- par->bmove = tile_bmove; +- par->clear = tile_clear; +- par->putcs = tile_putcs; +- par->clear_margins = tile_clear_margins; +- par->cursor = tile_cursor; +- par->update_start = tile_update_start; ++ par->bitops = &tile_fbcon_bitops; + + if (par->p) { + map.width = vc->vc_font.width; +-- +2.51.0 + diff --git a/queue-6.18/fbcon-rename-struct-fbcon_ops-to-struct-fbcon_par.patch b/queue-6.18/fbcon-rename-struct-fbcon_ops-to-struct-fbcon_par.patch new file mode 100644 index 0000000000..e07a4eacfa --- /dev/null +++ b/queue-6.18/fbcon-rename-struct-fbcon_ops-to-struct-fbcon_par.patch @@ -0,0 +1,2478 @@ +From 8eb0675c5584d375993a6a03ff6fc8ecb5ef5ceb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Sep 2025 14:44:42 +0200 +Subject: fbcon: Rename struct fbcon_ops to struct fbcon_par + +From: Thomas Zimmermann + +[ Upstream commit a6adbbc4c32a016146e117b1e9e5242724a75e10 ] + +The type struct fbcon_ops contains fbcon state and callbacks. As the +callbacks will be removed from struct fbcon_ops, rename the data type +to struct fbcon_par. Also rename the variables from ops to par. + +The _par postfix ("private access registers") is used throughout the +fbdev subsystem for per-driver state. The fbcon pointer within struct +fb_info is also named fbcon_par. Hence, the new naming fits existing +practice. + +v2: +- rename struct fbcon_ops to struct fbcon_par +- fix build for CONFIG_FB_TILEBITTING=n (kernel test robot) +- fix indention + +Signed-off-by: Thomas Zimmermann +Reviewed-by: Sam Ravnborg +Link: https://lore.kernel.org/r/20250909124616.143365-3-tzimmermann@suse.de +Stable-dep-of: 8e9bf8b9e8c0 ("printk, vt, fbcon: Remove console_conditional_schedule()") +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/core/bitblit.c | 122 +++---- + drivers/video/fbdev/core/fbcon.c | 419 ++++++++++++------------ + drivers/video/fbdev/core/fbcon.h | 6 +- + drivers/video/fbdev/core/fbcon_ccw.c | 146 ++++----- + drivers/video/fbdev/core/fbcon_cw.c | 146 ++++----- + drivers/video/fbdev/core/fbcon_rotate.c | 40 +-- + drivers/video/fbdev/core/fbcon_rotate.h | 6 +- + drivers/video/fbdev/core/fbcon_ud.c | 162 ++++----- + drivers/video/fbdev/core/softcursor.c | 18 +- + drivers/video/fbdev/core/tileblit.c | 28 +- + 10 files changed, 541 insertions(+), 552 deletions(-) + +diff --git a/drivers/video/fbdev/core/bitblit.c b/drivers/video/fbdev/core/bitblit.c +index dc5ad3fcc7be4..bed8ba18222b9 100644 +--- a/drivers/video/fbdev/core/bitblit.c ++++ b/drivers/video/fbdev/core/bitblit.c +@@ -261,10 +261,10 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + int fg, int bg) + { + struct fb_cursor cursor; +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; + int w = DIV_ROUND_UP(vc->vc_font.width, 8), c; +- int y = real_y(ops->p, vc->state.y); ++ int y = real_y(par->p, vc->state.y); + int attribute, use_sw = vc->vc_cursor_type & CUR_SW; + int err = 1; + char *src; +@@ -278,10 +278,10 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + attribute = get_attribute(info, c); + src = vc->vc_font.data + ((c & charmask) * (w * vc->vc_font.height)); + +- if (ops->cursor_state.image.data != src || +- ops->cursor_reset) { +- ops->cursor_state.image.data = src; +- cursor.set |= FB_CUR_SETIMAGE; ++ if (par->cursor_state.image.data != src || ++ par->cursor_reset) { ++ par->cursor_state.image.data = src; ++ cursor.set |= FB_CUR_SETIMAGE; + } + + if (attribute) { +@@ -290,46 +290,46 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + dst = kmalloc_array(w, vc->vc_font.height, GFP_ATOMIC); + if (!dst) + return; +- kfree(ops->cursor_data); +- ops->cursor_data = dst; ++ kfree(par->cursor_data); ++ par->cursor_data = dst; + update_attr(dst, src, attribute, vc); + src = dst; + } + +- if (ops->cursor_state.image.fg_color != fg || +- ops->cursor_state.image.bg_color != bg || +- ops->cursor_reset) { +- ops->cursor_state.image.fg_color = fg; +- ops->cursor_state.image.bg_color = bg; ++ if (par->cursor_state.image.fg_color != fg || ++ par->cursor_state.image.bg_color != bg || ++ par->cursor_reset) { ++ par->cursor_state.image.fg_color = fg; ++ par->cursor_state.image.bg_color = bg; + cursor.set |= FB_CUR_SETCMAP; + } + +- if ((ops->cursor_state.image.dx != (vc->vc_font.width * vc->state.x)) || +- (ops->cursor_state.image.dy != (vc->vc_font.height * y)) || +- ops->cursor_reset) { +- ops->cursor_state.image.dx = vc->vc_font.width * vc->state.x; +- ops->cursor_state.image.dy = vc->vc_font.height * y; ++ if ((par->cursor_state.image.dx != (vc->vc_font.width * vc->state.x)) || ++ (par->cursor_state.image.dy != (vc->vc_font.height * y)) || ++ par->cursor_reset) { ++ par->cursor_state.image.dx = vc->vc_font.width * vc->state.x; ++ par->cursor_state.image.dy = vc->vc_font.height * y; + cursor.set |= FB_CUR_SETPOS; + } + +- if (ops->cursor_state.image.height != vc->vc_font.height || +- ops->cursor_state.image.width != vc->vc_font.width || +- ops->cursor_reset) { +- ops->cursor_state.image.height = vc->vc_font.height; +- ops->cursor_state.image.width = vc->vc_font.width; ++ if (par->cursor_state.image.height != vc->vc_font.height || ++ par->cursor_state.image.width != vc->vc_font.width || ++ par->cursor_reset) { ++ par->cursor_state.image.height = vc->vc_font.height; ++ par->cursor_state.image.width = vc->vc_font.width; + cursor.set |= FB_CUR_SETSIZE; + } + +- if (ops->cursor_state.hot.x || ops->cursor_state.hot.y || +- ops->cursor_reset) { +- ops->cursor_state.hot.x = cursor.hot.y = 0; ++ if (par->cursor_state.hot.x || par->cursor_state.hot.y || ++ par->cursor_reset) { ++ par->cursor_state.hot.x = cursor.hot.y = 0; + cursor.set |= FB_CUR_SETHOT; + } + + if (cursor.set & FB_CUR_SETSIZE || +- vc->vc_cursor_type != ops->p->cursor_shape || +- ops->cursor_state.mask == NULL || +- ops->cursor_reset) { ++ vc->vc_cursor_type != par->p->cursor_shape || ++ par->cursor_state.mask == NULL || ++ par->cursor_reset) { + char *mask = kmalloc_array(w, vc->vc_font.height, GFP_ATOMIC); + int cur_height, size, i = 0; + u8 msk = 0xff; +@@ -337,13 +337,13 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + if (!mask) + return; + +- kfree(ops->cursor_state.mask); +- ops->cursor_state.mask = mask; ++ kfree(par->cursor_state.mask); ++ par->cursor_state.mask = mask; + +- ops->p->cursor_shape = vc->vc_cursor_type; ++ par->p->cursor_shape = vc->vc_cursor_type; + cursor.set |= FB_CUR_SETSHAPE; + +- switch (CUR_SIZE(ops->p->cursor_shape)) { ++ switch (CUR_SIZE(par->p->cursor_shape)) { + case CUR_NONE: + cur_height = 0; + break; +@@ -372,19 +372,19 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + mask[i++] = msk; + } + +- ops->cursor_state.enable = enable && !use_sw; ++ par->cursor_state.enable = enable && !use_sw; + + cursor.image.data = src; +- cursor.image.fg_color = ops->cursor_state.image.fg_color; +- cursor.image.bg_color = ops->cursor_state.image.bg_color; +- cursor.image.dx = ops->cursor_state.image.dx; +- cursor.image.dy = ops->cursor_state.image.dy; +- cursor.image.height = ops->cursor_state.image.height; +- cursor.image.width = ops->cursor_state.image.width; +- cursor.hot.x = ops->cursor_state.hot.x; +- cursor.hot.y = ops->cursor_state.hot.y; +- cursor.mask = ops->cursor_state.mask; +- cursor.enable = ops->cursor_state.enable; ++ cursor.image.fg_color = par->cursor_state.image.fg_color; ++ cursor.image.bg_color = par->cursor_state.image.bg_color; ++ cursor.image.dx = par->cursor_state.image.dx; ++ cursor.image.dy = par->cursor_state.image.dy; ++ cursor.image.height = par->cursor_state.image.height; ++ cursor.image.width = par->cursor_state.image.width; ++ cursor.hot.x = par->cursor_state.hot.x; ++ cursor.hot.y = par->cursor_state.hot.y; ++ cursor.mask = par->cursor_state.mask; ++ cursor.enable = par->cursor_state.enable; + cursor.image.depth = 1; + cursor.rop = ROP_XOR; + +@@ -394,31 +394,31 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + if (err) + soft_cursor(info, &cursor); + +- ops->cursor_reset = 0; ++ par->cursor_reset = 0; + } + + static int bit_update_start(struct fb_info *info) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + int err; + +- err = fb_pan_display(info, &ops->var); +- ops->var.xoffset = info->var.xoffset; +- ops->var.yoffset = info->var.yoffset; +- ops->var.vmode = info->var.vmode; ++ err = fb_pan_display(info, &par->var); ++ par->var.xoffset = info->var.xoffset; ++ par->var.yoffset = info->var.yoffset; ++ par->var.vmode = info->var.vmode; + return err; + } + +-void fbcon_set_bitops(struct fbcon_ops *ops) ++void fbcon_set_bitops(struct fbcon_par *par) + { +- ops->bmove = bit_bmove; +- ops->clear = bit_clear; +- ops->putcs = bit_putcs; +- ops->clear_margins = bit_clear_margins; +- ops->cursor = bit_cursor; +- ops->update_start = bit_update_start; +- ops->rotate_font = NULL; +- +- if (ops->rotate) +- fbcon_set_rotate(ops); ++ par->bmove = bit_bmove; ++ par->clear = bit_clear; ++ par->putcs = bit_putcs; ++ par->clear_margins = bit_clear_margins; ++ par->cursor = bit_cursor; ++ par->update_start = bit_update_start; ++ par->rotate_font = NULL; ++ ++ if (par->rotate) ++ fbcon_set_rotate(par); + } +diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c +index e7e07eb2142eb..2523d8b223dc1 100644 +--- a/drivers/video/fbdev/core/fbcon.c ++++ b/drivers/video/fbdev/core/fbcon.c +@@ -200,27 +200,27 @@ static struct device *fbcon_device; + #ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION + static inline void fbcon_set_rotation(struct fb_info *info) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + + if (!(info->flags & FBINFO_MISC_TILEBLITTING) && +- ops->p->con_rotate < 4) +- ops->rotate = ops->p->con_rotate; ++ par->p->con_rotate < 4) ++ par->rotate = par->p->con_rotate; + else +- ops->rotate = 0; ++ par->rotate = 0; + } + + static void fbcon_rotate(struct fb_info *info, u32 rotate) + { +- struct fbcon_ops *ops= info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + struct fb_info *fb_info; + +- if (!ops || ops->currcon == -1) ++ if (!par || par->currcon == -1) + return; + +- fb_info = fbcon_info_from_console(ops->currcon); ++ fb_info = fbcon_info_from_console(par->currcon); + + if (info == fb_info) { +- struct fbcon_display *p = &fb_display[ops->currcon]; ++ struct fbcon_display *p = &fb_display[par->currcon]; + + if (rotate < 4) + p->con_rotate = rotate; +@@ -233,12 +233,12 @@ static void fbcon_rotate(struct fb_info *info, u32 rotate) + + static void fbcon_rotate_all(struct fb_info *info, u32 rotate) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + struct vc_data *vc; + struct fbcon_display *p; + int i; + +- if (!ops || ops->currcon < 0 || rotate > 3) ++ if (!par || par->currcon < 0 || rotate > 3) + return; + + for (i = first_fb_vc; i <= last_fb_vc; i++) { +@@ -256,9 +256,9 @@ static void fbcon_rotate_all(struct fb_info *info, u32 rotate) + #else + static inline void fbcon_set_rotation(struct fb_info *info) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + +- ops->rotate = FB_ROTATE_UR; ++ par->rotate = FB_ROTATE_UR; + } + + static void fbcon_rotate(struct fb_info *info, u32 rotate) +@@ -274,9 +274,9 @@ static void fbcon_rotate_all(struct fb_info *info, u32 rotate) + + static int fbcon_get_rotate(struct fb_info *info) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + +- return (ops) ? ops->rotate : 0; ++ return (par) ? par->rotate : 0; + } + + static bool fbcon_skip_panic(struct fb_info *info) +@@ -286,10 +286,10 @@ static bool fbcon_skip_panic(struct fb_info *info) + + static inline bool fbcon_is_active(struct vc_data *vc, struct fb_info *info) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + + return info->state == FBINFO_STATE_RUNNING && +- vc->vc_mode == KD_TEXT && !ops->graphics && !fbcon_skip_panic(info); ++ vc->vc_mode == KD_TEXT && !par->graphics && !fbcon_skip_panic(info); + } + + static int get_color(struct vc_data *vc, struct fb_info *info, +@@ -371,7 +371,7 @@ static int get_bg_color(struct vc_data *vc, struct fb_info *info, u16 c) + + static void fb_flashcursor(struct work_struct *work) + { +- struct fbcon_ops *ops = container_of(work, struct fbcon_ops, cursor_work.work); ++ struct fbcon_par *par = container_of(work, struct fbcon_par, cursor_work.work); + struct fb_info *info; + struct vc_data *vc = NULL; + int c; +@@ -386,10 +386,10 @@ static void fb_flashcursor(struct work_struct *work) + return; + + /* protected by console_lock */ +- info = ops->info; ++ info = par->info; + +- if (ops->currcon != -1) +- vc = vc_cons[ops->currcon].d; ++ if (par->currcon != -1) ++ vc = vc_cons[par->currcon].d; + + if (!vc || !con_is_visible(vc) || + fbcon_info_from_console(vc->vc_num) != info || +@@ -399,30 +399,30 @@ static void fb_flashcursor(struct work_struct *work) + } + + c = scr_readw((u16 *) vc->vc_pos); +- enable = ops->cursor_flash && !ops->cursor_state.enable; +- ops->cursor(vc, info, enable, ++ enable = par->cursor_flash && !par->cursor_state.enable; ++ par->cursor(vc, info, enable, + get_fg_color(vc, info, c), + get_bg_color(vc, info, c)); + console_unlock(); + +- queue_delayed_work(system_power_efficient_wq, &ops->cursor_work, +- ops->cur_blink_jiffies); ++ queue_delayed_work(system_power_efficient_wq, &par->cursor_work, ++ par->cur_blink_jiffies); + } + + static void fbcon_add_cursor_work(struct fb_info *info) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + + if (fbcon_cursor_blink) +- queue_delayed_work(system_power_efficient_wq, &ops->cursor_work, +- ops->cur_blink_jiffies); ++ queue_delayed_work(system_power_efficient_wq, &par->cursor_work, ++ par->cur_blink_jiffies); + } + + static void fbcon_del_cursor_work(struct fb_info *info) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + +- cancel_delayed_work_sync(&ops->cursor_work); ++ cancel_delayed_work_sync(&par->cursor_work); + } + + #ifndef MODULE +@@ -582,7 +582,7 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info, + int cols, int rows, int new_cols, int new_rows) + { + /* Need to make room for the logo */ +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + int cnt, erase = vc->vc_video_erase_char, step; + unsigned short *save = NULL, *r, *q; + int logo_height; +@@ -598,7 +598,7 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info, + */ + if (fb_get_color_depth(&info->var, &info->fix) == 1) + erase &= ~0x400; +- logo_height = fb_prepare_logo(info, ops->rotate); ++ logo_height = fb_prepare_logo(info, par->rotate); + logo_lines = DIV_ROUND_UP(logo_height, vc->vc_font.height); + q = (unsigned short *) (vc->vc_origin + + vc->vc_size_row * rows); +@@ -670,15 +670,15 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info, + #ifdef CONFIG_FB_TILEBLITTING + static void set_blitting_type(struct vc_data *vc, struct fb_info *info) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + +- ops->p = &fb_display[vc->vc_num]; ++ par->p = &fb_display[vc->vc_num]; + + if ((info->flags & FBINFO_MISC_TILEBLITTING)) + fbcon_set_tileops(vc, info); + else { + fbcon_set_rotation(info); +- fbcon_set_bitops(ops); ++ fbcon_set_bitops(par); + } + } + +@@ -695,12 +695,12 @@ static int fbcon_invalid_charcount(struct fb_info *info, unsigned charcount) + #else + static void set_blitting_type(struct vc_data *vc, struct fb_info *info) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + + info->flags &= ~FBINFO_MISC_TILEBLITTING; +- ops->p = &fb_display[vc->vc_num]; ++ par->p = &fb_display[vc->vc_num]; + fbcon_set_rotation(info); +- fbcon_set_bitops(ops); ++ fbcon_set_bitops(par); + } + + static int fbcon_invalid_charcount(struct fb_info *info, unsigned charcount) +@@ -720,13 +720,13 @@ static void fbcon_release(struct fb_info *info) + module_put(info->fbops->owner); + + if (info->fbcon_par) { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + + fbcon_del_cursor_work(info); +- kfree(ops->cursor_state.mask); +- kfree(ops->cursor_data); +- kfree(ops->cursor_src); +- kfree(ops->fontbuffer); ++ kfree(par->cursor_state.mask); ++ kfree(par->cursor_data); ++ kfree(par->cursor_src); ++ kfree(par->fontbuffer); + kfree(info->fbcon_par); + info->fbcon_par = NULL; + } +@@ -734,7 +734,7 @@ static void fbcon_release(struct fb_info *info) + + static int fbcon_open(struct fb_info *info) + { +- struct fbcon_ops *ops; ++ struct fbcon_par *par; + + if (!try_module_get(info->fbops->owner)) + return -ENODEV; +@@ -748,16 +748,16 @@ static int fbcon_open(struct fb_info *info) + } + unlock_fb_info(info); + +- ops = kzalloc(sizeof(struct fbcon_ops), GFP_KERNEL); +- if (!ops) { ++ par = kzalloc(sizeof(*par), GFP_KERNEL); ++ if (!par) { + fbcon_release(info); + return -ENOMEM; + } + +- INIT_DELAYED_WORK(&ops->cursor_work, fb_flashcursor); +- ops->info = info; +- info->fbcon_par = ops; +- ops->cur_blink_jiffies = HZ / 5; ++ INIT_DELAYED_WORK(&par->cursor_work, fb_flashcursor); ++ par->info = info; ++ info->fbcon_par = par; ++ par->cur_blink_jiffies = HZ / 5; + + return 0; + } +@@ -804,12 +804,12 @@ static void con2fb_release_oldinfo(struct vc_data *vc, struct fb_info *oldinfo, + static void con2fb_init_display(struct vc_data *vc, struct fb_info *info, + int unit, int show_logo) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + int ret; + +- ops->currcon = fg_console; ++ par->currcon = fg_console; + +- if (info->fbops->fb_set_par && !ops->initialized) { ++ if (info->fbops->fb_set_par && !par->initialized) { + ret = info->fbops->fb_set_par(info); + + if (ret) +@@ -818,8 +818,8 @@ static void con2fb_init_display(struct vc_data *vc, struct fb_info *info, + "error code %d\n", ret); + } + +- ops->initialized = true; +- ops->graphics = 0; ++ par->initialized = true; ++ par->graphics = 0; + fbcon_set_disp(info, &info->var, unit); + + if (show_logo) { +@@ -956,7 +956,7 @@ static const char *fbcon_startup(void) + struct vc_data *vc = vc_cons[fg_console].d; + const struct font_desc *font = NULL; + struct fb_info *info = NULL; +- struct fbcon_ops *ops; ++ struct fbcon_par *par; + int rows, cols; + + /* +@@ -976,10 +976,10 @@ static const char *fbcon_startup(void) + if (fbcon_open(info)) + return NULL; + +- ops = info->fbcon_par; +- ops->currcon = -1; +- ops->graphics = 1; +- ops->cur_rotate = -1; ++ par = info->fbcon_par; ++ par->currcon = -1; ++ par->graphics = 1; ++ par->cur_rotate = -1; + + p->con_rotate = initial_rotation; + if (p->con_rotate == -1) +@@ -1002,8 +1002,8 @@ static const char *fbcon_startup(void) + vc->vc_font.charcount = font->charcount; + } + +- cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); +- rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); ++ cols = FBCON_SWAP(par->rotate, info->var.xres, info->var.yres); ++ rows = FBCON_SWAP(par->rotate, info->var.yres, info->var.xres); + cols /= vc->vc_font.width; + rows /= vc->vc_font.height; + vc_resize(vc, cols, rows); +@@ -1021,7 +1021,7 @@ static const char *fbcon_startup(void) + static void fbcon_init(struct vc_data *vc, bool init) + { + struct fb_info *info; +- struct fbcon_ops *ops; ++ struct fbcon_par *par; + struct vc_data **default_mode = vc->vc_display_fg; + struct vc_data *svc = *default_mode; + struct fbcon_display *t, *p = &fb_display[vc->vc_num]; +@@ -1095,8 +1095,8 @@ static void fbcon_init(struct vc_data *vc, bool init) + if (!*vc->uni_pagedict_loc) + con_copy_unimap(vc, svc); + +- ops = info->fbcon_par; +- ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms); ++ par = info->fbcon_par; ++ par->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms); + + p->con_rotate = initial_rotation; + if (p->con_rotate == -1) +@@ -1108,8 +1108,8 @@ static void fbcon_init(struct vc_data *vc, bool init) + + cols = vc->vc_cols; + rows = vc->vc_rows; +- new_cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); +- new_rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); ++ new_cols = FBCON_SWAP(par->rotate, info->var.xres, info->var.yres); ++ new_rows = FBCON_SWAP(par->rotate, info->var.yres, info->var.xres); + new_cols /= vc->vc_font.width; + new_rows /= vc->vc_font.height; + +@@ -1121,7 +1121,7 @@ static void fbcon_init(struct vc_data *vc, bool init) + * We need to do it in fbcon_init() to prevent screen corruption. + */ + if (con_is_visible(vc) && vc->vc_mode == KD_TEXT) { +- if (info->fbops->fb_set_par && !ops->initialized) { ++ if (info->fbops->fb_set_par && !par->initialized) { + ret = info->fbops->fb_set_par(info); + + if (ret) +@@ -1130,10 +1130,10 @@ static void fbcon_init(struct vc_data *vc, bool init) + "error code %d\n", ret); + } + +- ops->initialized = true; ++ par->initialized = true; + } + +- ops->graphics = 0; ++ par->graphics = 0; + + #ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION + if ((info->flags & FBINFO_HWACCEL_COPYAREA) && +@@ -1157,12 +1157,12 @@ static void fbcon_init(struct vc_data *vc, bool init) + if (logo) + fbcon_prepare_logo(vc, info, cols, rows, new_cols, new_rows); + +- if (ops->rotate_font && ops->rotate_font(info, vc)) { +- ops->rotate = FB_ROTATE_UR; ++ if (par->rotate_font && par->rotate_font(info, vc)) { ++ par->rotate = FB_ROTATE_UR; + set_blitting_type(vc, info); + } + +- ops->p = &fb_display[fg_console]; ++ par->p = &fb_display[fg_console]; + } + + static void fbcon_free_font(struct fbcon_display *p) +@@ -1200,7 +1200,7 @@ static void fbcon_deinit(struct vc_data *vc) + { + struct fbcon_display *p = &fb_display[vc->vc_num]; + struct fb_info *info; +- struct fbcon_ops *ops; ++ struct fbcon_par *par; + int idx; + + fbcon_free_font(p); +@@ -1214,15 +1214,15 @@ static void fbcon_deinit(struct vc_data *vc) + if (!info) + goto finished; + +- ops = info->fbcon_par; ++ par = info->fbcon_par; + +- if (!ops) ++ if (!par) + goto finished; + + if (con_is_visible(vc)) + fbcon_del_cursor_work(info); + +- ops->initialized = false; ++ par->initialized = false; + finished: + + fbcon_free_font(p); +@@ -1269,7 +1269,7 @@ static void __fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx, + unsigned int height, unsigned int width) + { + struct fb_info *info = fbcon_info_from_console(vc->vc_num); +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + int fg, bg; + struct fbcon_display *p = &fb_display[vc->vc_num]; + u_int y_break; +@@ -1284,7 +1284,7 @@ static void __fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx, + vc->vc_top = 0; + /* + * If the font dimensions are not an integral of the display +- * dimensions then the ops->clear below won't end up clearing ++ * dimensions then the par->clear below won't end up clearing + * the margins. Call clear_margins here in case the logo + * bitmap stretched into the margin area. + */ +@@ -1298,11 +1298,10 @@ static void __fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx, + y_break = p->vrows - p->yscroll; + if (sy < y_break && sy + height - 1 >= y_break) { + u_int b = y_break - sy; +- ops->clear(vc, info, real_y(p, sy), sx, b, width, fg, bg); +- ops->clear(vc, info, real_y(p, sy + b), sx, height - b, +- width, fg, bg); ++ par->clear(vc, info, real_y(p, sy), sx, b, width, fg, bg); ++ par->clear(vc, info, real_y(p, sy + b), sx, height - b, width, fg, bg); + } else +- ops->clear(vc, info, real_y(p, sy), sx, height, width, fg, bg); ++ par->clear(vc, info, real_y(p, sy), sx, height, width, fg, bg); + } + + static void fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx, +@@ -1316,10 +1315,10 @@ static void fbcon_putcs(struct vc_data *vc, const u16 *s, unsigned int count, + { + struct fb_info *info = fbcon_info_from_console(vc->vc_num); + struct fbcon_display *p = &fb_display[vc->vc_num]; +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + + if (fbcon_is_active(vc, info)) +- ops->putcs(vc, info, s, count, real_y(p, ypos), xpos, ++ par->putcs(vc, info, s, count, real_y(p, ypos), xpos, + get_fg_color(vc, info, scr_readw(s)), + get_bg_color(vc, info, scr_readw(s))); + } +@@ -1327,19 +1326,19 @@ static void fbcon_putcs(struct vc_data *vc, const u16 *s, unsigned int count, + static void fbcon_clear_margins(struct vc_data *vc, int bottom_only) + { + struct fb_info *info = fbcon_info_from_console(vc->vc_num); +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + + if (fbcon_is_active(vc, info)) +- ops->clear_margins(vc, info, margin_color, bottom_only); ++ par->clear_margins(vc, info, margin_color, bottom_only); + } + + static void fbcon_cursor(struct vc_data *vc, bool enable) + { + struct fb_info *info = fbcon_info_from_console(vc->vc_num); +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + int c = scr_readw((u16 *) vc->vc_pos); + +- ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms); ++ par->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms); + + if (!fbcon_is_active(vc, info) || vc->vc_deccm != 1) + return; +@@ -1349,12 +1348,12 @@ static void fbcon_cursor(struct vc_data *vc, bool enable) + else + fbcon_add_cursor_work(info); + +- ops->cursor_flash = enable; ++ par->cursor_flash = enable; + +- if (!ops->cursor) ++ if (!par->cursor) + return; + +- ops->cursor(vc, info, enable, ++ par->cursor(vc, info, enable, + get_fg_color(vc, info, c), + get_bg_color(vc, info, c)); + } +@@ -1369,7 +1368,7 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, + struct fbcon_display *p, *t; + struct vc_data **default_mode, *vc; + struct vc_data *svc; +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + int rows, cols; + unsigned long ret = 0; + +@@ -1402,7 +1401,7 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, + var->yoffset = info->var.yoffset; + var->xoffset = info->var.xoffset; + fb_set_var(info, var); +- ops->var = info->var; ++ par->var = info->var; + vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1); + vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; + if (vc->vc_font.charcount == 256) { +@@ -1418,8 +1417,8 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, + if (!*vc->uni_pagedict_loc) + con_copy_unimap(vc, svc); + +- cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); +- rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); ++ cols = FBCON_SWAP(par->rotate, info->var.xres, info->var.yres); ++ rows = FBCON_SWAP(par->rotate, info->var.yres, info->var.xres); + cols /= vc->vc_font.width; + rows /= vc->vc_font.height; + ret = vc_resize(vc, cols, rows); +@@ -1431,16 +1430,16 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, + static __inline__ void ywrap_up(struct vc_data *vc, int count) + { + struct fb_info *info = fbcon_info_from_console(vc->vc_num); +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + struct fbcon_display *p = &fb_display[vc->vc_num]; + + p->yscroll += count; + if (p->yscroll >= p->vrows) /* Deal with wrap */ + p->yscroll -= p->vrows; +- ops->var.xoffset = 0; +- ops->var.yoffset = p->yscroll * vc->vc_font.height; +- ops->var.vmode |= FB_VMODE_YWRAP; +- ops->update_start(info); ++ par->var.xoffset = 0; ++ par->var.yoffset = p->yscroll * vc->vc_font.height; ++ par->var.vmode |= FB_VMODE_YWRAP; ++ par->update_start(info); + scrollback_max += count; + if (scrollback_max > scrollback_phys_max) + scrollback_max = scrollback_phys_max; +@@ -1450,16 +1449,16 @@ static __inline__ void ywrap_up(struct vc_data *vc, int count) + static __inline__ void ywrap_down(struct vc_data *vc, int count) + { + struct fb_info *info = fbcon_info_from_console(vc->vc_num); +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + struct fbcon_display *p = &fb_display[vc->vc_num]; + + p->yscroll -= count; + if (p->yscroll < 0) /* Deal with wrap */ + p->yscroll += p->vrows; +- ops->var.xoffset = 0; +- ops->var.yoffset = p->yscroll * vc->vc_font.height; +- ops->var.vmode |= FB_VMODE_YWRAP; +- ops->update_start(info); ++ par->var.xoffset = 0; ++ par->var.yoffset = p->yscroll * vc->vc_font.height; ++ par->var.vmode |= FB_VMODE_YWRAP; ++ par->update_start(info); + scrollback_max -= count; + if (scrollback_max < 0) + scrollback_max = 0; +@@ -1470,19 +1469,19 @@ static __inline__ void ypan_up(struct vc_data *vc, int count) + { + struct fb_info *info = fbcon_info_from_console(vc->vc_num); + struct fbcon_display *p = &fb_display[vc->vc_num]; +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + + p->yscroll += count; + if (p->yscroll > p->vrows - vc->vc_rows) { +- ops->bmove(vc, info, p->vrows - vc->vc_rows, ++ par->bmove(vc, info, p->vrows - vc->vc_rows, + 0, 0, 0, vc->vc_rows, vc->vc_cols); + p->yscroll -= p->vrows - vc->vc_rows; + } + +- ops->var.xoffset = 0; +- ops->var.yoffset = p->yscroll * vc->vc_font.height; +- ops->var.vmode &= ~FB_VMODE_YWRAP; +- ops->update_start(info); ++ par->var.xoffset = 0; ++ par->var.yoffset = p->yscroll * vc->vc_font.height; ++ par->var.vmode &= ~FB_VMODE_YWRAP; ++ par->update_start(info); + fbcon_clear_margins(vc, 1); + scrollback_max += count; + if (scrollback_max > scrollback_phys_max) +@@ -1493,7 +1492,7 @@ static __inline__ void ypan_up(struct vc_data *vc, int count) + static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count) + { + struct fb_info *info = fbcon_info_from_console(vc->vc_num); +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + struct fbcon_display *p = &fb_display[vc->vc_num]; + + p->yscroll += count; +@@ -1503,10 +1502,10 @@ static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count) + fbcon_redraw_move(vc, p, t + count, vc->vc_rows - count, t); + } + +- ops->var.xoffset = 0; +- ops->var.yoffset = p->yscroll * vc->vc_font.height; +- ops->var.vmode &= ~FB_VMODE_YWRAP; +- ops->update_start(info); ++ par->var.xoffset = 0; ++ par->var.yoffset = p->yscroll * vc->vc_font.height; ++ par->var.vmode &= ~FB_VMODE_YWRAP; ++ par->update_start(info); + fbcon_clear_margins(vc, 1); + scrollback_max += count; + if (scrollback_max > scrollback_phys_max) +@@ -1518,19 +1517,19 @@ static __inline__ void ypan_down(struct vc_data *vc, int count) + { + struct fb_info *info = fbcon_info_from_console(vc->vc_num); + struct fbcon_display *p = &fb_display[vc->vc_num]; +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + + p->yscroll -= count; + if (p->yscroll < 0) { +- ops->bmove(vc, info, 0, 0, p->vrows - vc->vc_rows, ++ par->bmove(vc, info, 0, 0, p->vrows - vc->vc_rows, + 0, vc->vc_rows, vc->vc_cols); + p->yscroll += p->vrows - vc->vc_rows; + } + +- ops->var.xoffset = 0; +- ops->var.yoffset = p->yscroll * vc->vc_font.height; +- ops->var.vmode &= ~FB_VMODE_YWRAP; +- ops->update_start(info); ++ par->var.xoffset = 0; ++ par->var.yoffset = p->yscroll * vc->vc_font.height; ++ par->var.vmode &= ~FB_VMODE_YWRAP; ++ par->update_start(info); + fbcon_clear_margins(vc, 1); + scrollback_max -= count; + if (scrollback_max < 0) +@@ -1541,7 +1540,7 @@ static __inline__ void ypan_down(struct vc_data *vc, int count) + static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count) + { + struct fb_info *info = fbcon_info_from_console(vc->vc_num); +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + struct fbcon_display *p = &fb_display[vc->vc_num]; + + p->yscroll -= count; +@@ -1551,10 +1550,10 @@ static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count) + fbcon_redraw_move(vc, p, t, vc->vc_rows - count, t + count); + } + +- ops->var.xoffset = 0; +- ops->var.yoffset = p->yscroll * vc->vc_font.height; +- ops->var.vmode &= ~FB_VMODE_YWRAP; +- ops->update_start(info); ++ par->var.xoffset = 0; ++ par->var.yoffset = p->yscroll * vc->vc_font.height; ++ par->var.vmode &= ~FB_VMODE_YWRAP; ++ par->update_start(info); + fbcon_clear_margins(vc, 1); + scrollback_max -= count; + if (scrollback_max < 0) +@@ -1603,7 +1602,7 @@ static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info, + unsigned short *d = (unsigned short *) + (vc->vc_origin + vc->vc_size_row * line); + unsigned short *s = d + offset; +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + + while (count--) { + unsigned short *start = s; +@@ -1616,8 +1615,8 @@ static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info, + + if (c == scr_readw(d)) { + if (s > start) { +- ops->bmove(vc, info, line + ycount, x, +- line, x, 1, s-start); ++ par->bmove(vc, info, line + ycount, x, ++ line, x, 1, s - start); + x += s - start + 1; + start = s + 1; + } else { +@@ -1632,8 +1631,7 @@ static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info, + d++; + } while (s < le); + if (s > start) +- ops->bmove(vc, info, line + ycount, x, line, x, 1, +- s-start); ++ par->bmove(vc, info, line + ycount, x, line, x, 1, s - start); + console_conditional_schedule(); + if (ycount > 0) + line++; +@@ -1704,7 +1702,7 @@ static void fbcon_bmove_rec(struct vc_data *vc, struct fbcon_display *p, int sy, + int dy, int dx, int height, int width, u_int y_break) + { + struct fb_info *info = fbcon_info_from_console(vc->vc_num); +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + u_int b; + + if (sy < y_break && sy + height > y_break) { +@@ -1738,8 +1736,7 @@ static void fbcon_bmove_rec(struct vc_data *vc, struct fbcon_display *p, int sy, + } + return; + } +- ops->bmove(vc, info, real_y(p, sy), sx, real_y(p, dy), dx, +- height, width); ++ par->bmove(vc, info, real_y(p, sy), sx, real_y(p, dy), dx, height, width); + } + + static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx, +@@ -1966,15 +1963,13 @@ static void updatescrollmode_accel(struct fbcon_display *p, + struct vc_data *vc) + { + #ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + int cap = info->flags; + u16 t = 0; +- int ypan = FBCON_SWAP(ops->rotate, info->fix.ypanstep, +- info->fix.xpanstep); +- int ywrap = FBCON_SWAP(ops->rotate, info->fix.ywrapstep, t); +- int yres = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); +- int vyres = FBCON_SWAP(ops->rotate, info->var.yres_virtual, +- info->var.xres_virtual); ++ int ypan = FBCON_SWAP(par->rotate, info->fix.ypanstep, info->fix.xpanstep); ++ int ywrap = FBCON_SWAP(par->rotate, info->fix.ywrapstep, t); ++ int yres = FBCON_SWAP(par->rotate, info->var.yres, info->var.xres); ++ int vyres = FBCON_SWAP(par->rotate, info->var.yres_virtual, info->var.xres_virtual); + int good_pan = (cap & FBINFO_HWACCEL_YPAN) && + divides(ypan, vc->vc_font.height) && vyres > yres; + int good_wrap = (cap & FBINFO_HWACCEL_YWRAP) && +@@ -2007,11 +2002,10 @@ static void updatescrollmode(struct fbcon_display *p, + struct fb_info *info, + struct vc_data *vc) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + int fh = vc->vc_font.height; +- int yres = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); +- int vyres = FBCON_SWAP(ops->rotate, info->var.yres_virtual, +- info->var.xres_virtual); ++ int yres = FBCON_SWAP(par->rotate, info->var.yres, info->var.xres); ++ int vyres = FBCON_SWAP(par->rotate, info->var.yres_virtual, info->var.xres_virtual); + + p->vrows = vyres/fh; + if (yres > (fh * (vc->vc_rows + 1))) +@@ -2030,7 +2024,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width, + unsigned int height, bool from_user) + { + struct fb_info *info = fbcon_info_from_console(vc->vc_num); +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + struct fbcon_display *p = &fb_display[vc->vc_num]; + struct fb_var_screeninfo var = info->var; + int x_diff, y_diff, virt_w, virt_h, virt_fw, virt_fh; +@@ -2053,12 +2047,10 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width, + return -EINVAL; + } + +- virt_w = FBCON_SWAP(ops->rotate, width, height); +- virt_h = FBCON_SWAP(ops->rotate, height, width); +- virt_fw = FBCON_SWAP(ops->rotate, vc->vc_font.width, +- vc->vc_font.height); +- virt_fh = FBCON_SWAP(ops->rotate, vc->vc_font.height, +- vc->vc_font.width); ++ virt_w = FBCON_SWAP(par->rotate, width, height); ++ virt_h = FBCON_SWAP(par->rotate, height, width); ++ virt_fw = FBCON_SWAP(par->rotate, vc->vc_font.width, vc->vc_font.height); ++ virt_fh = FBCON_SWAP(par->rotate, vc->vc_font.height, vc->vc_font.width); + var.xres = virt_w * virt_fw; + var.yres = virt_h * virt_fh; + x_diff = info->var.xres - var.xres; +@@ -2084,7 +2076,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width, + fb_set_var(info, &var); + } + var_to_display(p, &info->var, info); +- ops->var = info->var; ++ par->var = info->var; + } + updatescrollmode(p, info, vc); + return 0; +@@ -2093,13 +2085,13 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width, + static bool fbcon_switch(struct vc_data *vc) + { + struct fb_info *info, *old_info = NULL; +- struct fbcon_ops *ops; ++ struct fbcon_par *par; + struct fbcon_display *p = &fb_display[vc->vc_num]; + struct fb_var_screeninfo var; + int i, ret, prev_console; + + info = fbcon_info_from_console(vc->vc_num); +- ops = info->fbcon_par; ++ par = info->fbcon_par; + + if (logo_shown >= 0) { + struct vc_data *conp2 = vc_cons[logo_shown].d; +@@ -2110,7 +2102,7 @@ static bool fbcon_switch(struct vc_data *vc) + logo_shown = FBCON_LOGO_CANSHOW; + } + +- prev_console = ops->currcon; ++ prev_console = par->currcon; + if (prev_console != -1) + old_info = fbcon_info_from_console(prev_console); + /* +@@ -2123,9 +2115,9 @@ static bool fbcon_switch(struct vc_data *vc) + */ + fbcon_for_each_registered_fb(i) { + if (fbcon_registered_fb[i]->fbcon_par) { +- struct fbcon_ops *o = fbcon_registered_fb[i]->fbcon_par; ++ struct fbcon_par *par = fbcon_registered_fb[i]->fbcon_par; + +- o->currcon = vc->vc_num; ++ par->currcon = vc->vc_num; + } + } + memset(&var, 0, sizeof(struct fb_var_screeninfo)); +@@ -2139,7 +2131,7 @@ static bool fbcon_switch(struct vc_data *vc) + info->var.activate = var.activate; + var.vmode |= info->var.vmode & ~FB_VMODE_MASK; + fb_set_var(info, &var); +- ops->var = info->var; ++ par->var = info->var; + + if (old_info != NULL && (old_info != info || + info->flags & FBINFO_MISC_ALWAYS_SETPAR)) { +@@ -2156,17 +2148,16 @@ static bool fbcon_switch(struct vc_data *vc) + fbcon_del_cursor_work(old_info); + } + +- if (!fbcon_is_active(vc, info) || +- ops->blank_state != FB_BLANK_UNBLANK) ++ if (!fbcon_is_active(vc, info) || par->blank_state != FB_BLANK_UNBLANK) + fbcon_del_cursor_work(info); + else + fbcon_add_cursor_work(info); + + set_blitting_type(vc, info); +- ops->cursor_reset = 1; ++ par->cursor_reset = 1; + +- if (ops->rotate_font && ops->rotate_font(info, vc)) { +- ops->rotate = FB_ROTATE_UR; ++ if (par->rotate_font && par->rotate_font(info, vc)) { ++ par->rotate = FB_ROTATE_UR; + set_blitting_type(vc, info); + } + +@@ -2197,8 +2188,8 @@ static bool fbcon_switch(struct vc_data *vc) + scrollback_current = 0; + + if (fbcon_is_active(vc, info)) { +- ops->var.xoffset = ops->var.yoffset = p->yscroll = 0; +- ops->update_start(info); ++ par->var.xoffset = par->var.yoffset = p->yscroll = 0; ++ par->update_start(info); + } + + fbcon_set_palette(vc, color_table); +@@ -2207,7 +2198,7 @@ static bool fbcon_switch(struct vc_data *vc) + if (logo_shown == FBCON_LOGO_DRAW) { + + logo_shown = fg_console; +- fb_show_logo(info, ops->rotate); ++ fb_show_logo(info, par->rotate); + update_region(vc, + vc->vc_origin + vc->vc_size_row * vc->vc_top, + vc->vc_size_row * (vc->vc_bottom - +@@ -2236,27 +2227,27 @@ static bool fbcon_blank(struct vc_data *vc, enum vesa_blank_mode blank, + bool mode_switch) + { + struct fb_info *info = fbcon_info_from_console(vc->vc_num); +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + + if (mode_switch) { + struct fb_var_screeninfo var = info->var; + +- ops->graphics = 1; ++ par->graphics = 1; + + if (!blank) { + var.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE | + FB_ACTIVATE_KD_TEXT; + fb_set_var(info, &var); +- ops->graphics = 0; +- ops->var = info->var; ++ par->graphics = 0; ++ par->var = info->var; + } + } + + if (fbcon_is_active(vc, info)) { +- if (ops->blank_state != blank) { +- ops->blank_state = blank; ++ if (par->blank_state != blank) { ++ par->blank_state = blank; + fbcon_cursor(vc, !blank); +- ops->cursor_flash = (!blank); ++ par->cursor_flash = (!blank); + + if (fb_blank(info, blank)) + fbcon_generic_blank(vc, info, blank); +@@ -2266,8 +2257,7 @@ static bool fbcon_blank(struct vc_data *vc, enum vesa_blank_mode blank, + update_screen(vc); + } + +- if (mode_switch || !fbcon_is_active(vc, info) || +- ops->blank_state != FB_BLANK_UNBLANK) ++ if (mode_switch || !fbcon_is_active(vc, info) || par->blank_state != FB_BLANK_UNBLANK) + fbcon_del_cursor_work(info); + else + fbcon_add_cursor_work(info); +@@ -2278,10 +2268,10 @@ static bool fbcon_blank(struct vc_data *vc, enum vesa_blank_mode blank, + static void fbcon_debug_enter(struct vc_data *vc) + { + struct fb_info *info = fbcon_info_from_console(vc->vc_num); +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + +- ops->save_graphics = ops->graphics; +- ops->graphics = 0; ++ par->save_graphics = par->graphics; ++ par->graphics = 0; + if (info->fbops->fb_debug_enter) + info->fbops->fb_debug_enter(info); + fbcon_set_palette(vc, color_table); +@@ -2290,9 +2280,9 @@ static void fbcon_debug_enter(struct vc_data *vc) + static void fbcon_debug_leave(struct vc_data *vc) + { + struct fb_info *info = fbcon_info_from_console(vc->vc_num); +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + +- ops->graphics = ops->save_graphics; ++ par->graphics = par->save_graphics; + if (info->fbops->fb_debug_leave) + info->fbops->fb_debug_leave(info); + } +@@ -2427,7 +2417,7 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount, + const u8 * data, int userfont) + { + struct fb_info *info = fbcon_info_from_console(vc->vc_num); +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + struct fbcon_display *p = &fb_display[vc->vc_num]; + int resize, ret, old_userfont, old_width, old_height, old_charcount; + u8 *old_data = vc->vc_font.data; +@@ -2453,8 +2443,8 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount, + if (resize) { + int cols, rows; + +- cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); +- rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); ++ cols = FBCON_SWAP(par->rotate, info->var.xres, info->var.yres); ++ rows = FBCON_SWAP(par->rotate, info->var.yres, info->var.xres); + cols /= w; + rows /= h; + ret = vc_resize(vc, cols, rows); +@@ -2653,11 +2643,11 @@ static void fbcon_invert_region(struct vc_data *vc, u16 * p, int cnt) + void fbcon_suspended(struct fb_info *info) + { + struct vc_data *vc = NULL; +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + +- if (!ops || ops->currcon < 0) ++ if (!par || par->currcon < 0) + return; +- vc = vc_cons[ops->currcon].d; ++ vc = vc_cons[par->currcon].d; + + /* Clear cursor, restore saved data */ + fbcon_cursor(vc, false); +@@ -2666,27 +2656,27 @@ void fbcon_suspended(struct fb_info *info) + void fbcon_resumed(struct fb_info *info) + { + struct vc_data *vc; +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + +- if (!ops || ops->currcon < 0) ++ if (!par || par->currcon < 0) + return; +- vc = vc_cons[ops->currcon].d; ++ vc = vc_cons[par->currcon].d; + + update_screen(vc); + } + + static void fbcon_modechanged(struct fb_info *info) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + struct vc_data *vc; + struct fbcon_display *p; + int rows, cols; + +- if (!ops || ops->currcon < 0) ++ if (!par || par->currcon < 0) + return; +- vc = vc_cons[ops->currcon].d; ++ vc = vc_cons[par->currcon].d; + if (vc->vc_mode != KD_TEXT || +- fbcon_info_from_console(ops->currcon) != info) ++ fbcon_info_from_console(par->currcon) != info) + return; + + p = &fb_display[vc->vc_num]; +@@ -2694,8 +2684,8 @@ static void fbcon_modechanged(struct fb_info *info) + + if (con_is_visible(vc)) { + var_to_display(p, &info->var, info); +- cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); +- rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); ++ cols = FBCON_SWAP(par->rotate, info->var.xres, info->var.yres); ++ rows = FBCON_SWAP(par->rotate, info->var.yres, info->var.xres); + cols /= vc->vc_font.width; + rows /= vc->vc_font.height; + vc_resize(vc, cols, rows); +@@ -2704,8 +2694,8 @@ static void fbcon_modechanged(struct fb_info *info) + scrollback_current = 0; + + if (fbcon_is_active(vc, info)) { +- ops->var.xoffset = ops->var.yoffset = p->yscroll = 0; +- ops->update_start(info); ++ par->var.xoffset = par->var.yoffset = p->yscroll = 0; ++ par->update_start(info); + } + + fbcon_set_palette(vc, color_table); +@@ -2715,12 +2705,12 @@ static void fbcon_modechanged(struct fb_info *info) + + static void fbcon_set_all_vcs(struct fb_info *info) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + struct vc_data *vc; + struct fbcon_display *p; + int i, rows, cols, fg = -1; + +- if (!ops || ops->currcon < 0) ++ if (!par || par->currcon < 0) + return; + + for (i = first_fb_vc; i <= last_fb_vc; i++) { +@@ -2737,8 +2727,8 @@ static void fbcon_set_all_vcs(struct fb_info *info) + p = &fb_display[vc->vc_num]; + set_blitting_type(vc, info); + var_to_display(p, &info->var, info); +- cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); +- rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); ++ cols = FBCON_SWAP(par->rotate, info->var.xres, info->var.yres); ++ rows = FBCON_SWAP(par->rotate, info->var.yres, info->var.xres); + cols /= vc->vc_font.width; + rows /= vc->vc_font.height; + vc_resize(vc, cols, rows); +@@ -2761,13 +2751,13 @@ EXPORT_SYMBOL(fbcon_update_vcs); + /* let fbcon check if it supports a new screen resolution */ + int fbcon_modechange_possible(struct fb_info *info, struct fb_var_screeninfo *var) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + struct vc_data *vc; + unsigned int i; + + WARN_CONSOLE_UNLOCKED(); + +- if (!ops) ++ if (!par) + return 0; + + /* prevent setting a screen size which is smaller than font size */ +@@ -3065,15 +3055,14 @@ int fbcon_fb_registered(struct fb_info *info) + + void fbcon_fb_blanked(struct fb_info *info, int blank) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + struct vc_data *vc; + +- if (!ops || ops->currcon < 0) ++ if (!par || par->currcon < 0) + return; + +- vc = vc_cons[ops->currcon].d; +- if (vc->vc_mode != KD_TEXT || +- fbcon_info_from_console(ops->currcon) != info) ++ vc = vc_cons[par->currcon].d; ++ if (vc->vc_mode != KD_TEXT || fbcon_info_from_console(par->currcon) != info) + return; + + if (con_is_visible(vc)) { +@@ -3082,7 +3071,7 @@ void fbcon_fb_blanked(struct fb_info *info, int blank) + else + do_unblank_screen(0); + } +- ops->blank_state = blank; ++ par->blank_state = blank; + } + + void fbcon_new_modelist(struct fb_info *info) +@@ -3272,7 +3261,7 @@ static ssize_t cursor_blink_show(struct device *device, + struct device_attribute *attr, char *buf) + { + struct fb_info *info; +- struct fbcon_ops *ops; ++ struct fbcon_par *par; + int idx, blink = -1; + + console_lock(); +@@ -3282,12 +3271,12 @@ static ssize_t cursor_blink_show(struct device *device, + goto err; + + info = fbcon_registered_fb[idx]; +- ops = info->fbcon_par; ++ par = info->fbcon_par; + +- if (!ops) ++ if (!par) + goto err; + +- blink = delayed_work_pending(&ops->cursor_work); ++ blink = delayed_work_pending(&par->cursor_work); + err: + console_unlock(); + return sysfs_emit(buf, "%d\n", blink); +diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h +index 4d97e6d8a16a2..31ee2d5912219 100644 +--- a/drivers/video/fbdev/core/fbcon.h ++++ b/drivers/video/fbdev/core/fbcon.h +@@ -51,7 +51,7 @@ struct fbcon_display { + const struct fb_videomode *mode; + }; + +-struct fbcon_ops { ++struct fbcon_par { + void (*bmove)(struct vc_data *vc, struct fb_info *info, int sy, + int sx, int dy, int dx, int height, int width); + void (*clear)(struct vc_data *vc, struct fb_info *info, int sy, +@@ -186,7 +186,7 @@ static inline u_short fb_scrollmode(struct fbcon_display *fb) + #ifdef CONFIG_FB_TILEBLITTING + extern void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info); + #endif +-extern void fbcon_set_bitops(struct fbcon_ops *ops); ++extern void fbcon_set_bitops(struct fbcon_par *par); + extern int soft_cursor(struct fb_info *info, struct fb_cursor *cursor); + + #define FBCON_ATTRIBUTE_UNDERLINE 1 +@@ -225,7 +225,7 @@ static inline int get_attribute(struct fb_info *info, u16 c) + (i == FB_ROTATE_UR || i == FB_ROTATE_UD) ? _r : _v; }) + + #ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION +-extern void fbcon_set_rotate(struct fbcon_ops *ops); ++extern void fbcon_set_rotate(struct fbcon_par *par); + #else + #define fbcon_set_rotate(x) do {} while(0) + #endif /* CONFIG_FRAMEBUFFER_CONSOLE_ROTATION */ +diff --git a/drivers/video/fbdev/core/fbcon_ccw.c b/drivers/video/fbdev/core/fbcon_ccw.c +index 89ef4ba7e8672..2ba8ec4c3e2bc 100644 +--- a/drivers/video/fbdev/core/fbcon_ccw.c ++++ b/drivers/video/fbdev/core/fbcon_ccw.c +@@ -63,9 +63,9 @@ static void ccw_update_attr(u8 *dst, u8 *src, int attribute, + static void ccw_bmove(struct vc_data *vc, struct fb_info *info, int sy, + int sx, int dy, int dx, int height, int width) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + struct fb_copyarea area; +- u32 vyres = GETVYRES(ops->p, info); ++ u32 vyres = GETVYRES(par->p, info); + + area.sx = sy * vc->vc_font.height; + area.sy = vyres - ((sx + width) * vc->vc_font.width); +@@ -80,9 +80,9 @@ static void ccw_bmove(struct vc_data *vc, struct fb_info *info, int sy, + static void ccw_clear(struct vc_data *vc, struct fb_info *info, int sy, + int sx, int height, int width, int fg, int bg) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + struct fb_fillrect region; +- u32 vyres = GETVYRES(ops->p, info); ++ u32 vyres = GETVYRES(par->p, info); + + region.color = bg; + region.dx = sy * vc->vc_font.height; +@@ -99,13 +99,13 @@ static inline void ccw_putcs_aligned(struct vc_data *vc, struct fb_info *info, + u32 d_pitch, u32 s_pitch, u32 cellsize, + struct fb_image *image, u8 *buf, u8 *dst) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; + u32 idx = (vc->vc_font.height + 7) >> 3; + u8 *src; + + while (cnt--) { +- src = ops->fontbuffer + (scr_readw(s--) & charmask)*cellsize; ++ src = par->fontbuffer + (scr_readw(s--) & charmask) * cellsize; + + if (attr) { + ccw_update_attr(buf, src, attr, vc); +@@ -130,7 +130,7 @@ static void ccw_putcs(struct vc_data *vc, struct fb_info *info, + int fg, int bg) + { + struct fb_image image; +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + u32 width = (vc->vc_font.height + 7)/8; + u32 cellsize = width * vc->vc_font.width; + u32 maxcnt = info->pixmap.size/cellsize; +@@ -139,9 +139,9 @@ static void ccw_putcs(struct vc_data *vc, struct fb_info *info, + u32 cnt, pitch, size; + u32 attribute = get_attribute(info, scr_readw(s)); + u8 *dst, *buf = NULL; +- u32 vyres = GETVYRES(ops->p, info); ++ u32 vyres = GETVYRES(par->p, info); + +- if (!ops->fontbuffer) ++ if (!par->fontbuffer) + return; + + image.fg_color = fg; +@@ -221,28 +221,28 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + int fg, int bg) + { + struct fb_cursor cursor; +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; + int w = (vc->vc_font.height + 7) >> 3, c; +- int y = real_y(ops->p, vc->state.y); ++ int y = real_y(par->p, vc->state.y); + int attribute, use_sw = vc->vc_cursor_type & CUR_SW; + int err = 1, dx, dy; + char *src; +- u32 vyres = GETVYRES(ops->p, info); ++ u32 vyres = GETVYRES(par->p, info); + +- if (!ops->fontbuffer) ++ if (!par->fontbuffer) + return; + + cursor.set = 0; + + c = scr_readw((u16 *) vc->vc_pos); + attribute = get_attribute(info, c); +- src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.width)); ++ src = par->fontbuffer + ((c & charmask) * (w * vc->vc_font.width)); + +- if (ops->cursor_state.image.data != src || +- ops->cursor_reset) { +- ops->cursor_state.image.data = src; +- cursor.set |= FB_CUR_SETIMAGE; ++ if (par->cursor_state.image.data != src || ++ par->cursor_reset) { ++ par->cursor_state.image.data = src; ++ cursor.set |= FB_CUR_SETIMAGE; + } + + if (attribute) { +@@ -251,49 +251,49 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + dst = kmalloc_array(w, vc->vc_font.width, GFP_ATOMIC); + if (!dst) + return; +- kfree(ops->cursor_data); +- ops->cursor_data = dst; ++ kfree(par->cursor_data); ++ par->cursor_data = dst; + ccw_update_attr(dst, src, attribute, vc); + src = dst; + } + +- if (ops->cursor_state.image.fg_color != fg || +- ops->cursor_state.image.bg_color != bg || +- ops->cursor_reset) { +- ops->cursor_state.image.fg_color = fg; +- ops->cursor_state.image.bg_color = bg; ++ if (par->cursor_state.image.fg_color != fg || ++ par->cursor_state.image.bg_color != bg || ++ par->cursor_reset) { ++ par->cursor_state.image.fg_color = fg; ++ par->cursor_state.image.bg_color = bg; + cursor.set |= FB_CUR_SETCMAP; + } + +- if (ops->cursor_state.image.height != vc->vc_font.width || +- ops->cursor_state.image.width != vc->vc_font.height || +- ops->cursor_reset) { +- ops->cursor_state.image.height = vc->vc_font.width; +- ops->cursor_state.image.width = vc->vc_font.height; ++ if (par->cursor_state.image.height != vc->vc_font.width || ++ par->cursor_state.image.width != vc->vc_font.height || ++ par->cursor_reset) { ++ par->cursor_state.image.height = vc->vc_font.width; ++ par->cursor_state.image.width = vc->vc_font.height; + cursor.set |= FB_CUR_SETSIZE; + } + + dx = y * vc->vc_font.height; + dy = vyres - ((vc->state.x + 1) * vc->vc_font.width); + +- if (ops->cursor_state.image.dx != dx || +- ops->cursor_state.image.dy != dy || +- ops->cursor_reset) { +- ops->cursor_state.image.dx = dx; +- ops->cursor_state.image.dy = dy; ++ if (par->cursor_state.image.dx != dx || ++ par->cursor_state.image.dy != dy || ++ par->cursor_reset) { ++ par->cursor_state.image.dx = dx; ++ par->cursor_state.image.dy = dy; + cursor.set |= FB_CUR_SETPOS; + } + +- if (ops->cursor_state.hot.x || ops->cursor_state.hot.y || +- ops->cursor_reset) { +- ops->cursor_state.hot.x = cursor.hot.y = 0; ++ if (par->cursor_state.hot.x || par->cursor_state.hot.y || ++ par->cursor_reset) { ++ par->cursor_state.hot.x = cursor.hot.y = 0; + cursor.set |= FB_CUR_SETHOT; + } + + if (cursor.set & FB_CUR_SETSIZE || +- vc->vc_cursor_type != ops->p->cursor_shape || +- ops->cursor_state.mask == NULL || +- ops->cursor_reset) { ++ vc->vc_cursor_type != par->p->cursor_shape || ++ par->cursor_state.mask == NULL || ++ par->cursor_reset) { + char *tmp, *mask = kmalloc_array(w, vc->vc_font.width, + GFP_ATOMIC); + int cur_height, size, i = 0; +@@ -309,13 +309,13 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + return; + } + +- kfree(ops->cursor_state.mask); +- ops->cursor_state.mask = mask; ++ kfree(par->cursor_state.mask); ++ par->cursor_state.mask = mask; + +- ops->p->cursor_shape = vc->vc_cursor_type; ++ par->p->cursor_shape = vc->vc_cursor_type; + cursor.set |= FB_CUR_SETSHAPE; + +- switch (CUR_SIZE(ops->p->cursor_shape)) { ++ switch (CUR_SIZE(par->p->cursor_shape)) { + case CUR_NONE: + cur_height = 0; + break; +@@ -348,19 +348,19 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + kfree(tmp); + } + +- ops->cursor_state.enable = enable && !use_sw; ++ par->cursor_state.enable = enable && !use_sw; + + cursor.image.data = src; +- cursor.image.fg_color = ops->cursor_state.image.fg_color; +- cursor.image.bg_color = ops->cursor_state.image.bg_color; +- cursor.image.dx = ops->cursor_state.image.dx; +- cursor.image.dy = ops->cursor_state.image.dy; +- cursor.image.height = ops->cursor_state.image.height; +- cursor.image.width = ops->cursor_state.image.width; +- cursor.hot.x = ops->cursor_state.hot.x; +- cursor.hot.y = ops->cursor_state.hot.y; +- cursor.mask = ops->cursor_state.mask; +- cursor.enable = ops->cursor_state.enable; ++ cursor.image.fg_color = par->cursor_state.image.fg_color; ++ cursor.image.bg_color = par->cursor_state.image.bg_color; ++ cursor.image.dx = par->cursor_state.image.dx; ++ cursor.image.dy = par->cursor_state.image.dy; ++ cursor.image.height = par->cursor_state.image.height; ++ cursor.image.width = par->cursor_state.image.width; ++ cursor.hot.x = par->cursor_state.hot.x; ++ cursor.hot.y = par->cursor_state.hot.y; ++ cursor.mask = par->cursor_state.mask; ++ cursor.enable = par->cursor_state.enable; + cursor.image.depth = 1; + cursor.rop = ROP_XOR; + +@@ -370,32 +370,32 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + if (err) + soft_cursor(info, &cursor); + +- ops->cursor_reset = 0; ++ par->cursor_reset = 0; + } + + static int ccw_update_start(struct fb_info *info) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + u32 yoffset; +- u32 vyres = GETVYRES(ops->p, info); ++ u32 vyres = GETVYRES(par->p, info); + int err; + +- yoffset = (vyres - info->var.yres) - ops->var.xoffset; +- ops->var.xoffset = ops->var.yoffset; +- ops->var.yoffset = yoffset; +- err = fb_pan_display(info, &ops->var); +- ops->var.xoffset = info->var.xoffset; +- ops->var.yoffset = info->var.yoffset; +- ops->var.vmode = info->var.vmode; ++ yoffset = (vyres - info->var.yres) - par->var.xoffset; ++ par->var.xoffset = par->var.yoffset; ++ par->var.yoffset = yoffset; ++ err = fb_pan_display(info, &par->var); ++ par->var.xoffset = info->var.xoffset; ++ par->var.yoffset = info->var.yoffset; ++ par->var.vmode = info->var.vmode; + return err; + } + +-void fbcon_rotate_ccw(struct fbcon_ops *ops) ++void fbcon_rotate_ccw(struct fbcon_par *par) + { +- ops->bmove = ccw_bmove; +- ops->clear = ccw_clear; +- ops->putcs = ccw_putcs; +- ops->clear_margins = ccw_clear_margins; +- ops->cursor = ccw_cursor; +- ops->update_start = ccw_update_start; ++ par->bmove = ccw_bmove; ++ par->clear = ccw_clear; ++ par->putcs = ccw_putcs; ++ par->clear_margins = ccw_clear_margins; ++ par->cursor = ccw_cursor; ++ par->update_start = ccw_update_start; + } +diff --git a/drivers/video/fbdev/core/fbcon_cw.c b/drivers/video/fbdev/core/fbcon_cw.c +index b9dac7940fb77..4bd22d5ee5f41 100644 +--- a/drivers/video/fbdev/core/fbcon_cw.c ++++ b/drivers/video/fbdev/core/fbcon_cw.c +@@ -48,9 +48,9 @@ static void cw_update_attr(u8 *dst, u8 *src, int attribute, + static void cw_bmove(struct vc_data *vc, struct fb_info *info, int sy, + int sx, int dy, int dx, int height, int width) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + struct fb_copyarea area; +- u32 vxres = GETVXRES(ops->p, info); ++ u32 vxres = GETVXRES(par->p, info); + + area.sx = vxres - ((sy + height) * vc->vc_font.height); + area.sy = sx * vc->vc_font.width; +@@ -65,9 +65,9 @@ static void cw_bmove(struct vc_data *vc, struct fb_info *info, int sy, + static void cw_clear(struct vc_data *vc, struct fb_info *info, int sy, + int sx, int height, int width, int fg, int bg) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + struct fb_fillrect region; +- u32 vxres = GETVXRES(ops->p, info); ++ u32 vxres = GETVXRES(par->p, info); + + region.color = bg; + region.dx = vxres - ((sy + height) * vc->vc_font.height); +@@ -84,13 +84,13 @@ static inline void cw_putcs_aligned(struct vc_data *vc, struct fb_info *info, + u32 d_pitch, u32 s_pitch, u32 cellsize, + struct fb_image *image, u8 *buf, u8 *dst) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; + u32 idx = (vc->vc_font.height + 7) >> 3; + u8 *src; + + while (cnt--) { +- src = ops->fontbuffer + (scr_readw(s++) & charmask)*cellsize; ++ src = par->fontbuffer + (scr_readw(s++) & charmask) * cellsize; + + if (attr) { + cw_update_attr(buf, src, attr, vc); +@@ -115,7 +115,7 @@ static void cw_putcs(struct vc_data *vc, struct fb_info *info, + int fg, int bg) + { + struct fb_image image; +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + u32 width = (vc->vc_font.height + 7)/8; + u32 cellsize = width * vc->vc_font.width; + u32 maxcnt = info->pixmap.size/cellsize; +@@ -124,9 +124,9 @@ static void cw_putcs(struct vc_data *vc, struct fb_info *info, + u32 cnt, pitch, size; + u32 attribute = get_attribute(info, scr_readw(s)); + u8 *dst, *buf = NULL; +- u32 vxres = GETVXRES(ops->p, info); ++ u32 vxres = GETVXRES(par->p, info); + +- if (!ops->fontbuffer) ++ if (!par->fontbuffer) + return; + + image.fg_color = fg; +@@ -204,28 +204,28 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + int fg, int bg) + { + struct fb_cursor cursor; +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; + int w = (vc->vc_font.height + 7) >> 3, c; +- int y = real_y(ops->p, vc->state.y); ++ int y = real_y(par->p, vc->state.y); + int attribute, use_sw = vc->vc_cursor_type & CUR_SW; + int err = 1, dx, dy; + char *src; +- u32 vxres = GETVXRES(ops->p, info); ++ u32 vxres = GETVXRES(par->p, info); + +- if (!ops->fontbuffer) ++ if (!par->fontbuffer) + return; + + cursor.set = 0; + + c = scr_readw((u16 *) vc->vc_pos); + attribute = get_attribute(info, c); +- src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.width)); ++ src = par->fontbuffer + ((c & charmask) * (w * vc->vc_font.width)); + +- if (ops->cursor_state.image.data != src || +- ops->cursor_reset) { +- ops->cursor_state.image.data = src; +- cursor.set |= FB_CUR_SETIMAGE; ++ if (par->cursor_state.image.data != src || ++ par->cursor_reset) { ++ par->cursor_state.image.data = src; ++ cursor.set |= FB_CUR_SETIMAGE; + } + + if (attribute) { +@@ -234,49 +234,49 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + dst = kmalloc_array(w, vc->vc_font.width, GFP_ATOMIC); + if (!dst) + return; +- kfree(ops->cursor_data); +- ops->cursor_data = dst; ++ kfree(par->cursor_data); ++ par->cursor_data = dst; + cw_update_attr(dst, src, attribute, vc); + src = dst; + } + +- if (ops->cursor_state.image.fg_color != fg || +- ops->cursor_state.image.bg_color != bg || +- ops->cursor_reset) { +- ops->cursor_state.image.fg_color = fg; +- ops->cursor_state.image.bg_color = bg; ++ if (par->cursor_state.image.fg_color != fg || ++ par->cursor_state.image.bg_color != bg || ++ par->cursor_reset) { ++ par->cursor_state.image.fg_color = fg; ++ par->cursor_state.image.bg_color = bg; + cursor.set |= FB_CUR_SETCMAP; + } + +- if (ops->cursor_state.image.height != vc->vc_font.width || +- ops->cursor_state.image.width != vc->vc_font.height || +- ops->cursor_reset) { +- ops->cursor_state.image.height = vc->vc_font.width; +- ops->cursor_state.image.width = vc->vc_font.height; ++ if (par->cursor_state.image.height != vc->vc_font.width || ++ par->cursor_state.image.width != vc->vc_font.height || ++ par->cursor_reset) { ++ par->cursor_state.image.height = vc->vc_font.width; ++ par->cursor_state.image.width = vc->vc_font.height; + cursor.set |= FB_CUR_SETSIZE; + } + + dx = vxres - ((y * vc->vc_font.height) + vc->vc_font.height); + dy = vc->state.x * vc->vc_font.width; + +- if (ops->cursor_state.image.dx != dx || +- ops->cursor_state.image.dy != dy || +- ops->cursor_reset) { +- ops->cursor_state.image.dx = dx; +- ops->cursor_state.image.dy = dy; ++ if (par->cursor_state.image.dx != dx || ++ par->cursor_state.image.dy != dy || ++ par->cursor_reset) { ++ par->cursor_state.image.dx = dx; ++ par->cursor_state.image.dy = dy; + cursor.set |= FB_CUR_SETPOS; + } + +- if (ops->cursor_state.hot.x || ops->cursor_state.hot.y || +- ops->cursor_reset) { +- ops->cursor_state.hot.x = cursor.hot.y = 0; ++ if (par->cursor_state.hot.x || par->cursor_state.hot.y || ++ par->cursor_reset) { ++ par->cursor_state.hot.x = cursor.hot.y = 0; + cursor.set |= FB_CUR_SETHOT; + } + + if (cursor.set & FB_CUR_SETSIZE || +- vc->vc_cursor_type != ops->p->cursor_shape || +- ops->cursor_state.mask == NULL || +- ops->cursor_reset) { ++ vc->vc_cursor_type != par->p->cursor_shape || ++ par->cursor_state.mask == NULL || ++ par->cursor_reset) { + char *tmp, *mask = kmalloc_array(w, vc->vc_font.width, + GFP_ATOMIC); + int cur_height, size, i = 0; +@@ -292,13 +292,13 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + return; + } + +- kfree(ops->cursor_state.mask); +- ops->cursor_state.mask = mask; ++ kfree(par->cursor_state.mask); ++ par->cursor_state.mask = mask; + +- ops->p->cursor_shape = vc->vc_cursor_type; ++ par->p->cursor_shape = vc->vc_cursor_type; + cursor.set |= FB_CUR_SETSHAPE; + +- switch (CUR_SIZE(ops->p->cursor_shape)) { ++ switch (CUR_SIZE(par->p->cursor_shape)) { + case CUR_NONE: + cur_height = 0; + break; +@@ -331,19 +331,19 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + kfree(tmp); + } + +- ops->cursor_state.enable = enable && !use_sw; ++ par->cursor_state.enable = enable && !use_sw; + + cursor.image.data = src; +- cursor.image.fg_color = ops->cursor_state.image.fg_color; +- cursor.image.bg_color = ops->cursor_state.image.bg_color; +- cursor.image.dx = ops->cursor_state.image.dx; +- cursor.image.dy = ops->cursor_state.image.dy; +- cursor.image.height = ops->cursor_state.image.height; +- cursor.image.width = ops->cursor_state.image.width; +- cursor.hot.x = ops->cursor_state.hot.x; +- cursor.hot.y = ops->cursor_state.hot.y; +- cursor.mask = ops->cursor_state.mask; +- cursor.enable = ops->cursor_state.enable; ++ cursor.image.fg_color = par->cursor_state.image.fg_color; ++ cursor.image.bg_color = par->cursor_state.image.bg_color; ++ cursor.image.dx = par->cursor_state.image.dx; ++ cursor.image.dy = par->cursor_state.image.dy; ++ cursor.image.height = par->cursor_state.image.height; ++ cursor.image.width = par->cursor_state.image.width; ++ cursor.hot.x = par->cursor_state.hot.x; ++ cursor.hot.y = par->cursor_state.hot.y; ++ cursor.mask = par->cursor_state.mask; ++ cursor.enable = par->cursor_state.enable; + cursor.image.depth = 1; + cursor.rop = ROP_XOR; + +@@ -353,32 +353,32 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + if (err) + soft_cursor(info, &cursor); + +- ops->cursor_reset = 0; ++ par->cursor_reset = 0; + } + + static int cw_update_start(struct fb_info *info) + { +- struct fbcon_ops *ops = info->fbcon_par; +- u32 vxres = GETVXRES(ops->p, info); ++ struct fbcon_par *par = info->fbcon_par; ++ u32 vxres = GETVXRES(par->p, info); + u32 xoffset; + int err; + +- xoffset = vxres - (info->var.xres + ops->var.yoffset); +- ops->var.yoffset = ops->var.xoffset; +- ops->var.xoffset = xoffset; +- err = fb_pan_display(info, &ops->var); +- ops->var.xoffset = info->var.xoffset; +- ops->var.yoffset = info->var.yoffset; +- ops->var.vmode = info->var.vmode; ++ xoffset = vxres - (info->var.xres + par->var.yoffset); ++ par->var.yoffset = par->var.xoffset; ++ par->var.xoffset = xoffset; ++ err = fb_pan_display(info, &par->var); ++ par->var.xoffset = info->var.xoffset; ++ par->var.yoffset = info->var.yoffset; ++ par->var.vmode = info->var.vmode; + return err; + } + +-void fbcon_rotate_cw(struct fbcon_ops *ops) ++void fbcon_rotate_cw(struct fbcon_par *par) + { +- ops->bmove = cw_bmove; +- ops->clear = cw_clear; +- ops->putcs = cw_putcs; +- ops->clear_margins = cw_clear_margins; +- ops->cursor = cw_cursor; +- ops->update_start = cw_update_start; ++ par->bmove = cw_bmove; ++ par->clear = cw_clear; ++ par->putcs = cw_putcs; ++ par->clear_margins = cw_clear_margins; ++ par->cursor = cw_cursor; ++ par->update_start = cw_update_start; + } +diff --git a/drivers/video/fbdev/core/fbcon_rotate.c b/drivers/video/fbdev/core/fbcon_rotate.c +index ec3c883400f7b..380b2746451a1 100644 +--- a/drivers/video/fbdev/core/fbcon_rotate.c ++++ b/drivers/video/fbdev/core/fbcon_rotate.c +@@ -20,32 +20,32 @@ + + static int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + int len, err = 0; + int s_cellsize, d_cellsize, i; + const u8 *src; + u8 *dst; + +- if (vc->vc_font.data == ops->fontdata && +- ops->p->con_rotate == ops->cur_rotate) ++ if (vc->vc_font.data == par->fontdata && ++ par->p->con_rotate == par->cur_rotate) + goto finished; + +- src = ops->fontdata = vc->vc_font.data; +- ops->cur_rotate = ops->p->con_rotate; ++ src = par->fontdata = vc->vc_font.data; ++ par->cur_rotate = par->p->con_rotate; + len = vc->vc_font.charcount; + s_cellsize = ((vc->vc_font.width + 7)/8) * + vc->vc_font.height; + d_cellsize = s_cellsize; + +- if (ops->rotate == FB_ROTATE_CW || +- ops->rotate == FB_ROTATE_CCW) ++ if (par->rotate == FB_ROTATE_CW || ++ par->rotate == FB_ROTATE_CCW) + d_cellsize = ((vc->vc_font.height + 7)/8) * + vc->vc_font.width; + + if (info->fbops->fb_sync) + info->fbops->fb_sync(info); + +- if (ops->fd_size < d_cellsize * len) { ++ if (par->fd_size < d_cellsize * len) { + dst = kmalloc_array(len, d_cellsize, GFP_KERNEL); + + if (dst == NULL) { +@@ -53,15 +53,15 @@ static int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc) + goto finished; + } + +- ops->fd_size = d_cellsize * len; +- kfree(ops->fontbuffer); +- ops->fontbuffer = dst; ++ par->fd_size = d_cellsize * len; ++ kfree(par->fontbuffer); ++ par->fontbuffer = dst; + } + +- dst = ops->fontbuffer; +- memset(dst, 0, ops->fd_size); ++ dst = par->fontbuffer; ++ memset(dst, 0, par->fd_size); + +- switch (ops->rotate) { ++ switch (par->rotate) { + case FB_ROTATE_UD: + for (i = len; i--; ) { + rotate_ud(src, dst, vc->vc_font.width, +@@ -93,19 +93,19 @@ static int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc) + return err; + } + +-void fbcon_set_rotate(struct fbcon_ops *ops) ++void fbcon_set_rotate(struct fbcon_par *par) + { +- ops->rotate_font = fbcon_rotate_font; ++ par->rotate_font = fbcon_rotate_font; + +- switch(ops->rotate) { ++ switch (par->rotate) { + case FB_ROTATE_CW: +- fbcon_rotate_cw(ops); ++ fbcon_rotate_cw(par); + break; + case FB_ROTATE_UD: +- fbcon_rotate_ud(ops); ++ fbcon_rotate_ud(par); + break; + case FB_ROTATE_CCW: +- fbcon_rotate_ccw(ops); ++ fbcon_rotate_ccw(par); + break; + } + } +diff --git a/drivers/video/fbdev/core/fbcon_rotate.h b/drivers/video/fbdev/core/fbcon_rotate.h +index 01cbe303b8a29..48305e1a07631 100644 +--- a/drivers/video/fbdev/core/fbcon_rotate.h ++++ b/drivers/video/fbdev/core/fbcon_rotate.h +@@ -90,7 +90,7 @@ static inline void rotate_ccw(const char *in, char *out, u32 width, u32 height) + } + } + +-extern void fbcon_rotate_cw(struct fbcon_ops *ops); +-extern void fbcon_rotate_ud(struct fbcon_ops *ops); +-extern void fbcon_rotate_ccw(struct fbcon_ops *ops); ++extern void fbcon_rotate_cw(struct fbcon_par *par); ++extern void fbcon_rotate_ud(struct fbcon_par *par); ++extern void fbcon_rotate_ccw(struct fbcon_par *par); + #endif +diff --git a/drivers/video/fbdev/core/fbcon_ud.c b/drivers/video/fbdev/core/fbcon_ud.c +index 0af7913a2abdc..14b40e2bf323f 100644 +--- a/drivers/video/fbdev/core/fbcon_ud.c ++++ b/drivers/video/fbdev/core/fbcon_ud.c +@@ -48,10 +48,10 @@ static void ud_update_attr(u8 *dst, u8 *src, int attribute, + static void ud_bmove(struct vc_data *vc, struct fb_info *info, int sy, + int sx, int dy, int dx, int height, int width) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + struct fb_copyarea area; +- u32 vyres = GETVYRES(ops->p, info); +- u32 vxres = GETVXRES(ops->p, info); ++ u32 vyres = GETVYRES(par->p, info); ++ u32 vxres = GETVXRES(par->p, info); + + area.sy = vyres - ((sy + height) * vc->vc_font.height); + area.sx = vxres - ((sx + width) * vc->vc_font.width); +@@ -66,10 +66,10 @@ static void ud_bmove(struct vc_data *vc, struct fb_info *info, int sy, + static void ud_clear(struct vc_data *vc, struct fb_info *info, int sy, + int sx, int height, int width, int fg, int bg) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + struct fb_fillrect region; +- u32 vyres = GETVYRES(ops->p, info); +- u32 vxres = GETVXRES(ops->p, info); ++ u32 vyres = GETVYRES(par->p, info); ++ u32 vxres = GETVXRES(par->p, info); + + region.color = bg; + region.dy = vyres - ((sy + height) * vc->vc_font.height); +@@ -86,13 +86,13 @@ static inline void ud_putcs_aligned(struct vc_data *vc, struct fb_info *info, + u32 d_pitch, u32 s_pitch, u32 cellsize, + struct fb_image *image, u8 *buf, u8 *dst) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; + u32 idx = vc->vc_font.width >> 3; + u8 *src; + + while (cnt--) { +- src = ops->fontbuffer + (scr_readw(s--) & charmask)*cellsize; ++ src = par->fontbuffer + (scr_readw(s--) & charmask) * cellsize; + + if (attr) { + ud_update_attr(buf, src, attr, vc); +@@ -119,7 +119,7 @@ static inline void ud_putcs_unaligned(struct vc_data *vc, + struct fb_image *image, u8 *buf, + u8 *dst) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; + u32 shift_low = 0, mod = vc->vc_font.width % 8; + u32 shift_high = 8; +@@ -127,7 +127,7 @@ static inline void ud_putcs_unaligned(struct vc_data *vc, + u8 *src; + + while (cnt--) { +- src = ops->fontbuffer + (scr_readw(s--) & charmask)*cellsize; ++ src = par->fontbuffer + (scr_readw(s--) & charmask) * cellsize; + + if (attr) { + ud_update_attr(buf, src, attr, vc); +@@ -152,7 +152,7 @@ static void ud_putcs(struct vc_data *vc, struct fb_info *info, + int fg, int bg) + { + struct fb_image image; +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + u32 width = (vc->vc_font.width + 7)/8; + u32 cellsize = width * vc->vc_font.height; + u32 maxcnt = info->pixmap.size/cellsize; +@@ -161,10 +161,10 @@ static void ud_putcs(struct vc_data *vc, struct fb_info *info, + u32 mod = vc->vc_font.width % 8, cnt, pitch, size; + u32 attribute = get_attribute(info, scr_readw(s)); + u8 *dst, *buf = NULL; +- u32 vyres = GETVYRES(ops->p, info); +- u32 vxres = GETVXRES(ops->p, info); ++ u32 vyres = GETVYRES(par->p, info); ++ u32 vxres = GETVXRES(par->p, info); + +- if (!ops->fontbuffer) ++ if (!par->fontbuffer) + return; + + image.fg_color = fg; +@@ -251,29 +251,29 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + int fg, int bg) + { + struct fb_cursor cursor; +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; + int w = (vc->vc_font.width + 7) >> 3, c; +- int y = real_y(ops->p, vc->state.y); ++ int y = real_y(par->p, vc->state.y); + int attribute, use_sw = vc->vc_cursor_type & CUR_SW; + int err = 1, dx, dy; + char *src; +- u32 vyres = GETVYRES(ops->p, info); +- u32 vxres = GETVXRES(ops->p, info); ++ u32 vyres = GETVYRES(par->p, info); ++ u32 vxres = GETVXRES(par->p, info); + +- if (!ops->fontbuffer) ++ if (!par->fontbuffer) + return; + + cursor.set = 0; + + c = scr_readw((u16 *) vc->vc_pos); + attribute = get_attribute(info, c); +- src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.height)); ++ src = par->fontbuffer + ((c & charmask) * (w * vc->vc_font.height)); + +- if (ops->cursor_state.image.data != src || +- ops->cursor_reset) { +- ops->cursor_state.image.data = src; +- cursor.set |= FB_CUR_SETIMAGE; ++ if (par->cursor_state.image.data != src || ++ par->cursor_reset) { ++ par->cursor_state.image.data = src; ++ cursor.set |= FB_CUR_SETIMAGE; + } + + if (attribute) { +@@ -282,49 +282,49 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + dst = kmalloc_array(w, vc->vc_font.height, GFP_ATOMIC); + if (!dst) + return; +- kfree(ops->cursor_data); +- ops->cursor_data = dst; ++ kfree(par->cursor_data); ++ par->cursor_data = dst; + ud_update_attr(dst, src, attribute, vc); + src = dst; + } + +- if (ops->cursor_state.image.fg_color != fg || +- ops->cursor_state.image.bg_color != bg || +- ops->cursor_reset) { +- ops->cursor_state.image.fg_color = fg; +- ops->cursor_state.image.bg_color = bg; ++ if (par->cursor_state.image.fg_color != fg || ++ par->cursor_state.image.bg_color != bg || ++ par->cursor_reset) { ++ par->cursor_state.image.fg_color = fg; ++ par->cursor_state.image.bg_color = bg; + cursor.set |= FB_CUR_SETCMAP; + } + +- if (ops->cursor_state.image.height != vc->vc_font.height || +- ops->cursor_state.image.width != vc->vc_font.width || +- ops->cursor_reset) { +- ops->cursor_state.image.height = vc->vc_font.height; +- ops->cursor_state.image.width = vc->vc_font.width; ++ if (par->cursor_state.image.height != vc->vc_font.height || ++ par->cursor_state.image.width != vc->vc_font.width || ++ par->cursor_reset) { ++ par->cursor_state.image.height = vc->vc_font.height; ++ par->cursor_state.image.width = vc->vc_font.width; + cursor.set |= FB_CUR_SETSIZE; + } + + dy = vyres - ((y * vc->vc_font.height) + vc->vc_font.height); + dx = vxres - ((vc->state.x * vc->vc_font.width) + vc->vc_font.width); + +- if (ops->cursor_state.image.dx != dx || +- ops->cursor_state.image.dy != dy || +- ops->cursor_reset) { +- ops->cursor_state.image.dx = dx; +- ops->cursor_state.image.dy = dy; ++ if (par->cursor_state.image.dx != dx || ++ par->cursor_state.image.dy != dy || ++ par->cursor_reset) { ++ par->cursor_state.image.dx = dx; ++ par->cursor_state.image.dy = dy; + cursor.set |= FB_CUR_SETPOS; + } + +- if (ops->cursor_state.hot.x || ops->cursor_state.hot.y || +- ops->cursor_reset) { +- ops->cursor_state.hot.x = cursor.hot.y = 0; ++ if (par->cursor_state.hot.x || par->cursor_state.hot.y || ++ par->cursor_reset) { ++ par->cursor_state.hot.x = cursor.hot.y = 0; + cursor.set |= FB_CUR_SETHOT; + } + + if (cursor.set & FB_CUR_SETSIZE || +- vc->vc_cursor_type != ops->p->cursor_shape || +- ops->cursor_state.mask == NULL || +- ops->cursor_reset) { ++ vc->vc_cursor_type != par->p->cursor_shape || ++ par->cursor_state.mask == NULL || ++ par->cursor_reset) { + char *mask = kmalloc_array(w, vc->vc_font.height, GFP_ATOMIC); + int cur_height, size, i = 0; + u8 msk = 0xff; +@@ -332,13 +332,13 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + if (!mask) + return; + +- kfree(ops->cursor_state.mask); +- ops->cursor_state.mask = mask; ++ kfree(par->cursor_state.mask); ++ par->cursor_state.mask = mask; + +- ops->p->cursor_shape = vc->vc_cursor_type; ++ par->p->cursor_shape = vc->vc_cursor_type; + cursor.set |= FB_CUR_SETSHAPE; + +- switch (CUR_SIZE(ops->p->cursor_shape)) { ++ switch (CUR_SIZE(par->p->cursor_shape)) { + case CUR_NONE: + cur_height = 0; + break; +@@ -371,19 +371,19 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + mask[i++] = ~msk; + } + +- ops->cursor_state.enable = enable && !use_sw; ++ par->cursor_state.enable = enable && !use_sw; + + cursor.image.data = src; +- cursor.image.fg_color = ops->cursor_state.image.fg_color; +- cursor.image.bg_color = ops->cursor_state.image.bg_color; +- cursor.image.dx = ops->cursor_state.image.dx; +- cursor.image.dy = ops->cursor_state.image.dy; +- cursor.image.height = ops->cursor_state.image.height; +- cursor.image.width = ops->cursor_state.image.width; +- cursor.hot.x = ops->cursor_state.hot.x; +- cursor.hot.y = ops->cursor_state.hot.y; +- cursor.mask = ops->cursor_state.mask; +- cursor.enable = ops->cursor_state.enable; ++ cursor.image.fg_color = par->cursor_state.image.fg_color; ++ cursor.image.bg_color = par->cursor_state.image.bg_color; ++ cursor.image.dx = par->cursor_state.image.dx; ++ cursor.image.dy = par->cursor_state.image.dy; ++ cursor.image.height = par->cursor_state.image.height; ++ cursor.image.width = par->cursor_state.image.width; ++ cursor.hot.x = par->cursor_state.hot.x; ++ cursor.hot.y = par->cursor_state.hot.y; ++ cursor.mask = par->cursor_state.mask; ++ cursor.enable = par->cursor_state.enable; + cursor.image.depth = 1; + cursor.rop = ROP_XOR; + +@@ -393,36 +393,36 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + if (err) + soft_cursor(info, &cursor); + +- ops->cursor_reset = 0; ++ par->cursor_reset = 0; + } + + static int ud_update_start(struct fb_info *info) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + int xoffset, yoffset; +- u32 vyres = GETVYRES(ops->p, info); +- u32 vxres = GETVXRES(ops->p, info); ++ u32 vyres = GETVYRES(par->p, info); ++ u32 vxres = GETVXRES(par->p, info); + int err; + +- xoffset = vxres - info->var.xres - ops->var.xoffset; +- yoffset = vyres - info->var.yres - ops->var.yoffset; ++ xoffset = vxres - info->var.xres - par->var.xoffset; ++ yoffset = vyres - info->var.yres - par->var.yoffset; + if (yoffset < 0) + yoffset += vyres; +- ops->var.xoffset = xoffset; +- ops->var.yoffset = yoffset; +- err = fb_pan_display(info, &ops->var); +- ops->var.xoffset = info->var.xoffset; +- ops->var.yoffset = info->var.yoffset; +- ops->var.vmode = info->var.vmode; ++ par->var.xoffset = xoffset; ++ par->var.yoffset = yoffset; ++ err = fb_pan_display(info, &par->var); ++ par->var.xoffset = info->var.xoffset; ++ par->var.yoffset = info->var.yoffset; ++ par->var.vmode = info->var.vmode; + return err; + } + +-void fbcon_rotate_ud(struct fbcon_ops *ops) ++void fbcon_rotate_ud(struct fbcon_par *par) + { +- ops->bmove = ud_bmove; +- ops->clear = ud_clear; +- ops->putcs = ud_putcs; +- ops->clear_margins = ud_clear_margins; +- ops->cursor = ud_cursor; +- ops->update_start = ud_update_start; ++ par->bmove = ud_bmove; ++ par->clear = ud_clear; ++ par->putcs = ud_putcs; ++ par->clear_margins = ud_clear_margins; ++ par->cursor = ud_cursor; ++ par->update_start = ud_update_start; + } +diff --git a/drivers/video/fbdev/core/softcursor.c b/drivers/video/fbdev/core/softcursor.c +index 29e5b21cf373e..900788c059153 100644 +--- a/drivers/video/fbdev/core/softcursor.c ++++ b/drivers/video/fbdev/core/softcursor.c +@@ -21,7 +21,7 @@ + + int soft_cursor(struct fb_info *info, struct fb_cursor *cursor) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + unsigned int scan_align = info->pixmap.scan_align - 1; + unsigned int buf_align = info->pixmap.buf_align - 1; + unsigned int i, size, dsize, s_pitch, d_pitch; +@@ -34,19 +34,19 @@ int soft_cursor(struct fb_info *info, struct fb_cursor *cursor) + s_pitch = (cursor->image.width + 7) >> 3; + dsize = s_pitch * cursor->image.height; + +- if (dsize + sizeof(struct fb_image) != ops->cursor_size) { +- kfree(ops->cursor_src); +- ops->cursor_size = dsize + sizeof(struct fb_image); ++ if (dsize + sizeof(struct fb_image) != par->cursor_size) { ++ kfree(par->cursor_src); ++ par->cursor_size = dsize + sizeof(struct fb_image); + +- ops->cursor_src = kmalloc(ops->cursor_size, GFP_ATOMIC); +- if (!ops->cursor_src) { +- ops->cursor_size = 0; ++ par->cursor_src = kmalloc(par->cursor_size, GFP_ATOMIC); ++ if (!par->cursor_src) { ++ par->cursor_size = 0; + return -ENOMEM; + } + } + +- src = ops->cursor_src + sizeof(struct fb_image); +- image = (struct fb_image *)ops->cursor_src; ++ src = par->cursor_src + sizeof(struct fb_image); ++ image = (struct fb_image *)par->cursor_src; + *image = cursor->image; + d_pitch = (s_pitch + scan_align) & ~scan_align; + +diff --git a/drivers/video/fbdev/core/tileblit.c b/drivers/video/fbdev/core/tileblit.c +index d342b90c42b7f..4428f2bcd3f8c 100644 +--- a/drivers/video/fbdev/core/tileblit.c ++++ b/drivers/video/fbdev/core/tileblit.c +@@ -151,34 +151,34 @@ static void tile_cursor(struct vc_data *vc, struct fb_info *info, bool enable, + + static int tile_update_start(struct fb_info *info) + { +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + int err; + +- err = fb_pan_display(info, &ops->var); +- ops->var.xoffset = info->var.xoffset; +- ops->var.yoffset = info->var.yoffset; +- ops->var.vmode = info->var.vmode; ++ err = fb_pan_display(info, &par->var); ++ par->var.xoffset = info->var.xoffset; ++ par->var.yoffset = info->var.yoffset; ++ par->var.vmode = info->var.vmode; + return err; + } + + void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info) + { + struct fb_tilemap map; +- struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_par *par = info->fbcon_par; + +- ops->bmove = tile_bmove; +- ops->clear = tile_clear; +- ops->putcs = tile_putcs; +- ops->clear_margins = tile_clear_margins; +- ops->cursor = tile_cursor; +- ops->update_start = tile_update_start; ++ par->bmove = tile_bmove; ++ par->clear = tile_clear; ++ par->putcs = tile_putcs; ++ par->clear_margins = tile_clear_margins; ++ par->cursor = tile_cursor; ++ par->update_start = tile_update_start; + +- if (ops->p) { ++ if (par->p) { + map.width = vc->vc_font.width; + map.height = vc->vc_font.height; + map.depth = 1; + map.length = vc->vc_font.charcount; +- map.data = ops->p->fontdata; ++ map.data = par->p->fontdata; + info->tileops->fb_settile(info, &map); + } + } +-- +2.51.0 + diff --git a/queue-6.18/fbcon-set-rotate_font-callback-with-related-callback.patch b/queue-6.18/fbcon-set-rotate_font-callback-with-related-callback.patch new file mode 100644 index 0000000000..3273c258c8 --- /dev/null +++ b/queue-6.18/fbcon-set-rotate_font-callback-with-related-callback.patch @@ -0,0 +1,99 @@ +From 53f6b5ab9bc90847781c94b71d1a86e526200d3e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Sep 2025 14:44:43 +0200 +Subject: fbcon: Set rotate_font callback with related callbacks + +From: Thomas Zimmermann + +[ Upstream commit 9cfd09402eb45f1b14b60668fd7c628445efdd8d ] + +The field struct fbcon_par.rotate_font points to fbcon_rotate_font() if +the console is rotated. Set the callback in the same place as the other +callbacks. Prepares for declaring all fbcon callbacks in a dedicated +struct type. + +If not rotated, fbcon_set_bitops() still clears the callback to NULL. + +Signed-off-by: Thomas Zimmermann +Reviewed-by: Sam Ravnborg +Link: https://lore.kernel.org/r/20250909124616.143365-4-tzimmermann@suse.de +Stable-dep-of: 8e9bf8b9e8c0 ("printk, vt, fbcon: Remove console_conditional_schedule()") +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/core/fbcon_ccw.c | 1 + + drivers/video/fbdev/core/fbcon_cw.c | 1 + + drivers/video/fbdev/core/fbcon_rotate.c | 4 +--- + drivers/video/fbdev/core/fbcon_rotate.h | 3 +++ + drivers/video/fbdev/core/fbcon_ud.c | 1 + + 5 files changed, 7 insertions(+), 3 deletions(-) + +diff --git a/drivers/video/fbdev/core/fbcon_ccw.c b/drivers/video/fbdev/core/fbcon_ccw.c +index 2ba8ec4c3e2bc..ba744b67a4fd9 100644 +--- a/drivers/video/fbdev/core/fbcon_ccw.c ++++ b/drivers/video/fbdev/core/fbcon_ccw.c +@@ -398,4 +398,5 @@ void fbcon_rotate_ccw(struct fbcon_par *par) + par->clear_margins = ccw_clear_margins; + par->cursor = ccw_cursor; + par->update_start = ccw_update_start; ++ par->rotate_font = fbcon_rotate_font; + } +diff --git a/drivers/video/fbdev/core/fbcon_cw.c b/drivers/video/fbdev/core/fbcon_cw.c +index 4bd22d5ee5f41..974bd9d9b7702 100644 +--- a/drivers/video/fbdev/core/fbcon_cw.c ++++ b/drivers/video/fbdev/core/fbcon_cw.c +@@ -381,4 +381,5 @@ void fbcon_rotate_cw(struct fbcon_par *par) + par->clear_margins = cw_clear_margins; + par->cursor = cw_cursor; + par->update_start = cw_update_start; ++ par->rotate_font = fbcon_rotate_font; + } +diff --git a/drivers/video/fbdev/core/fbcon_rotate.c b/drivers/video/fbdev/core/fbcon_rotate.c +index 380b2746451a1..0c7cac71a9c21 100644 +--- a/drivers/video/fbdev/core/fbcon_rotate.c ++++ b/drivers/video/fbdev/core/fbcon_rotate.c +@@ -18,7 +18,7 @@ + #include "fbcon.h" + #include "fbcon_rotate.h" + +-static int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc) ++int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc) + { + struct fbcon_par *par = info->fbcon_par; + int len, err = 0; +@@ -95,8 +95,6 @@ static int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc) + + void fbcon_set_rotate(struct fbcon_par *par) + { +- par->rotate_font = fbcon_rotate_font; +- + switch (par->rotate) { + case FB_ROTATE_CW: + fbcon_rotate_cw(par); +diff --git a/drivers/video/fbdev/core/fbcon_rotate.h b/drivers/video/fbdev/core/fbcon_rotate.h +index 48305e1a07631..784f3231a958f 100644 +--- a/drivers/video/fbdev/core/fbcon_rotate.h ++++ b/drivers/video/fbdev/core/fbcon_rotate.h +@@ -90,7 +90,10 @@ static inline void rotate_ccw(const char *in, char *out, u32 width, u32 height) + } + } + ++int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc); ++ + extern void fbcon_rotate_cw(struct fbcon_par *par); + extern void fbcon_rotate_ud(struct fbcon_par *par); + extern void fbcon_rotate_ccw(struct fbcon_par *par); ++ + #endif +diff --git a/drivers/video/fbdev/core/fbcon_ud.c b/drivers/video/fbdev/core/fbcon_ud.c +index 14b40e2bf323f..1a214a4d538fb 100644 +--- a/drivers/video/fbdev/core/fbcon_ud.c ++++ b/drivers/video/fbdev/core/fbcon_ud.c +@@ -425,4 +425,5 @@ void fbcon_rotate_ud(struct fbcon_par *par) + par->clear_margins = ud_clear_margins; + par->cursor = ud_cursor; + par->update_start = ud_update_start; ++ par->rotate_font = fbcon_rotate_font; + } +-- +2.51.0 + diff --git a/queue-6.18/fbdev-au1200fb-fix-a-memory-leak-in-au1200fb_drv_pro.patch b/queue-6.18/fbdev-au1200fb-fix-a-memory-leak-in-au1200fb_drv_pro.patch new file mode 100644 index 0000000000..20e646939b --- /dev/null +++ b/queue-6.18/fbdev-au1200fb-fix-a-memory-leak-in-au1200fb_drv_pro.patch @@ -0,0 +1,43 @@ +From dd4fabf2147befd706f059cd450b9e2700e01d0e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 20:14:58 +0800 +Subject: fbdev: au1200fb: Fix a memory leak in au1200fb_drv_probe() + +From: Felix Gu + +[ Upstream commit ce4e25198a6aaaaf36248edf8daf3d744ec8e309 ] + +In au1200fb_drv_probe(), when platform_get_irq fails(), it directly +returns from the function with an error code, which causes a memory +leak. + +Replace it with a goto label to ensure proper cleanup. + +Fixes: 4e88761f5f8c ("fbdev: au1200fb: Fix missing IRQ check in au1200fb_drv_probe") +Signed-off-by: Felix Gu +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/au1200fb.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/video/fbdev/au1200fb.c b/drivers/video/fbdev/au1200fb.c +index ed770222660b5..685e629e7e164 100644 +--- a/drivers/video/fbdev/au1200fb.c ++++ b/drivers/video/fbdev/au1200fb.c +@@ -1724,8 +1724,10 @@ static int au1200fb_drv_probe(struct platform_device *dev) + + /* Now hook interrupt too */ + irq = platform_get_irq(dev, 0); +- if (irq < 0) +- return irq; ++ if (irq < 0) { ++ ret = irq; ++ goto failed; ++ } + + ret = request_irq(irq, au1200fb_handle_irq, + IRQF_SHARED, "lcd", (void *)dev); +-- +2.51.0 + diff --git a/queue-6.18/fbdev-of_display_timing-fix-device-node-reference-le.patch b/queue-6.18/fbdev-of_display_timing-fix-device-node-reference-le.patch new file mode 100644 index 0000000000..9ade71f2c3 --- /dev/null +++ b/queue-6.18/fbdev-of_display_timing-fix-device-node-reference-le.patch @@ -0,0 +1,56 @@ +From 161b0b577424a995979a8e996015e1b79f875770 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Jan 2026 20:48:33 +0800 +Subject: fbdev: of_display_timing: Fix device node reference leak in + of_get_display_timings() + +From: Felix Gu + +[ Upstream commit c39ee2d264f98efa14aa46c9942114cb03c7baa6 ] + +Use for_each_child_of_node_scoped instead of for_each_child_of_node +to ensure automatic of_node_put on early exit paths, preventing +device node reference leak. + +Fixes: cc3f414cf2e4 ("video: add of helper for display timings/videomode") +Signed-off-by: Felix Gu +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/of_display_timing.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/video/of_display_timing.c b/drivers/video/of_display_timing.c +index bebd371c6b93e..a4cd446ac5a59 100644 +--- a/drivers/video/of_display_timing.c ++++ b/drivers/video/of_display_timing.c +@@ -195,7 +195,7 @@ struct display_timings *of_get_display_timings(const struct device_node *np) + disp->num_timings = 0; + disp->native_mode = 0; + +- for_each_child_of_node(timings_np, entry) { ++ for_each_child_of_node_scoped(timings_np, child) { + struct display_timing *dt; + int r; + +@@ -206,7 +206,7 @@ struct display_timings *of_get_display_timings(const struct device_node *np) + goto timingfail; + } + +- r = of_parse_display_timing(entry, dt); ++ r = of_parse_display_timing(child, dt); + if (r) { + /* + * to not encourage wrong devicetrees, fail in case of +@@ -218,7 +218,7 @@ struct display_timings *of_get_display_timings(const struct device_node *np) + goto timingfail; + } + +- if (native_mode == entry) ++ if (native_mode == child) + disp->native_mode = disp->num_timings; + + disp->timings[disp->num_timings] = dt; +-- +2.51.0 + diff --git a/queue-6.18/firmware-arm_ffa-correct-32-bit-response-handling-in.patch b/queue-6.18/firmware-arm_ffa-correct-32-bit-response-handling-in.patch new file mode 100644 index 0000000000..542837fc36 --- /dev/null +++ b/queue-6.18/firmware-arm_ffa-correct-32-bit-response-handling-in.patch @@ -0,0 +1,119 @@ +From 50821efb0568e17c9ed9f868a1e66cbd7ceeda16 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 14:20:01 +0000 +Subject: firmware: arm_ffa: Correct 32-bit response handling in + NOTIFICATION_INFO_GET + +From: Sudeep Holla + +[ Upstream commit be4d4543f78074fbebd530ba5109d39a2a34e668 ] + +The FF-A specification allows NOTIFICATION_INFO_GET to return either a +64-bit (FFA_FN64_SUCCESS) or a 32-bit (FFA_SUCCESS) response, depending on +whether the firmware chooses the SMC64 or SMC32 calling convention. + +The driver previously detected the response format by checking ret.a0, but +still interpreted the returned ID lists (x3..x17 or w3..w7) as if they always +followed the 64-bit SMC64 layout. In the SMC32 case, the upper 32 bits of +each argument register are undefined by the calling convention, meaning the +driver could read stale or garbage values when parsing notification IDs. + +This resulted in incorrectly decoded partition/VCPU IDs whenever the FF-A +firmware used an SMC32 return path. + +Fix the issue by: + +- Introducing logic to map list indices to the correct u16 offsets, + depending on whether the response width matches the kernel word size + or is a 32-bit response on a 64-bit kernel. +- Ensuring that the packed ID list is parsed using the proper layout, + avoiding reads from undefined upper halves in the SMC32 case. + +With this change, NOTIFICATION_INFO_GET now correctly interprets ID list +entries regardless of the response width, aligning the driver with the FF-A +specification. + +Fixes: 3522be48d82b ("firmware: arm_ffa: Implement the NOTIFICATION_INFO_GET interface") +Reported-by: Sourav Mohapatra +Message-Id: <20251218142001.2457111-1-sudeep.holla@arm.com> +Signed-off-by: Sudeep Holla +Signed-off-by: Sasha Levin +--- + drivers/firmware/arm_ffa/driver.c | 33 +++++++++++++++++++++++++++---- + 1 file changed, 29 insertions(+), 4 deletions(-) + +diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c +index c72ee47565856..c501c3104b3a4 100644 +--- a/drivers/firmware/arm_ffa/driver.c ++++ b/drivers/firmware/arm_ffa/driver.c +@@ -981,10 +981,27 @@ static void __do_sched_recv_cb(u16 part_id, u16 vcpu, bool is_per_vcpu) + } + } + ++/* ++ * Map logical ID index to the u16 index within the packed ID list. ++ * ++ * For native responses (FF-A width == kernel word size), IDs are ++ * tightly packed: idx -> idx. ++ * ++ * For 32-bit responses on a 64-bit kernel, each 64-bit register ++ * contributes 4 x u16 values but only the lower 2 are defined; the ++ * upper 2 are garbage. This mapping skips those upper halves: ++ * 0,1,2,3,4,5,... -> 0,1,4,5,8,9,... ++ */ ++static int list_idx_to_u16_idx(int idx, bool is_native_resp) ++{ ++ return is_native_resp ? idx : idx + 2 * (idx >> 1); ++} ++ + static void ffa_notification_info_get(void) + { +- int idx, list, max_ids, lists_cnt, ids_processed, ids_count[MAX_IDS_64]; +- bool is_64b_resp; ++ int ids_processed, ids_count[MAX_IDS_64]; ++ int idx, list, max_ids, lists_cnt; ++ bool is_64b_resp, is_native_resp; + ffa_value_t ret; + u64 id_list; + +@@ -1001,6 +1018,7 @@ static void ffa_notification_info_get(void) + } + + is_64b_resp = (ret.a0 == FFA_FN64_SUCCESS); ++ is_native_resp = (ret.a0 == FFA_FN_NATIVE(SUCCESS)); + + ids_processed = 0; + lists_cnt = FIELD_GET(NOTIFICATION_INFO_GET_ID_COUNT, ret.a2); +@@ -1017,12 +1035,16 @@ static void ffa_notification_info_get(void) + + /* Process IDs */ + for (list = 0; list < lists_cnt; list++) { ++ int u16_idx; + u16 vcpu_id, part_id, *packed_id_list = (u16 *)&ret.a3; + + if (ids_processed >= max_ids - 1) + break; + +- part_id = packed_id_list[ids_processed++]; ++ u16_idx = list_idx_to_u16_idx(ids_processed, ++ is_native_resp); ++ part_id = packed_id_list[u16_idx]; ++ ids_processed++; + + if (ids_count[list] == 1) { /* Global Notification */ + __do_sched_recv_cb(part_id, 0, false); +@@ -1034,7 +1056,10 @@ static void ffa_notification_info_get(void) + if (ids_processed >= max_ids - 1) + break; + +- vcpu_id = packed_id_list[ids_processed++]; ++ u16_idx = list_idx_to_u16_idx(ids_processed, ++ is_native_resp); ++ vcpu_id = packed_id_list[u16_idx]; ++ ids_processed++; + + __do_sched_recv_cb(part_id, vcpu_id, true); + } +-- +2.51.0 + diff --git a/queue-6.18/fs-add-linux-init_task.h-for-init_fs.patch b/queue-6.18/fs-add-linux-init_task.h-for-init_fs.patch new file mode 100644 index 0000000000..7b1460bee4 --- /dev/null +++ b/queue-6.18/fs-add-linux-init_task.h-for-init_fs.patch @@ -0,0 +1,40 @@ +From 42da8c6bbac27f288481243e83b0d35863fcdc46 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 11:58:56 +0000 +Subject: fs: add for 'init_fs' + +From: Ben Dooks + +[ Upstream commit 589cff4975afe1a4eaaa1d961652f50b1628d78d ] + +The init_fs symbol is defined in but was +not included in fs/fs_struct.c so fix by adding the include. + +Fixes the following sparse warning: +fs/fs_struct.c:150:18: warning: symbol 'init_fs' was not declared. Should it be static? + +Fixes: 3e93cd671813e ("Take fs_struct handling to new file") +Signed-off-by: Ben Dooks +Link: https://patch.msgid.link/20260108115856.238027-1-ben.dooks@codethink.co.uk +Reviewed-by: Jan Kara +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/fs_struct.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/fs_struct.c b/fs/fs_struct.c +index 28be762ac1c63..a0b40ad5e7423 100644 +--- a/fs/fs_struct.c ++++ b/fs/fs_struct.c +@@ -6,6 +6,7 @@ + #include + #include + #include ++#include + #include "internal.h" + + /* +-- +2.51.0 + diff --git a/queue-6.18/fs-move-initializing-f_mode-before-file_ref_init.patch b/queue-6.18/fs-move-initializing-f_mode-before-file_ref_init.patch new file mode 100644 index 0000000000..28f3f70ef6 --- /dev/null +++ b/queue-6.18/fs-move-initializing-f_mode-before-file_ref_init.patch @@ -0,0 +1,56 @@ +From cc5921346a63af7bd93828277c98db764f84377d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 22:15:36 +0100 +Subject: fs: move initializing f_mode before file_ref_init() + +From: Amir Goldstein + +[ Upstream commit 1219e0feaefc9697f738b223540e8e8906291cb3 ] + +The comment above file_ref_init() says: +"We're SLAB_TYPESAFE_BY_RCU so initialize f_ref last." +but file_set_fsnotify_mode() was added after file_ref_init(). + +Move it right after setting f_mode, where it makes more sense. + +Fixes: 711f9b8fbe4f4 ("fsnotify: disable pre-content and permission events by default") +Signed-off-by: Amir Goldstein +Link: https://patch.msgid.link/20260109211536.3565697-1-amir73il@gmail.com +Reviewed-by: Jan Kara +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/file_table.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/fs/file_table.c b/fs/file_table.c +index cd4a3db4659ac..34244fccf2edf 100644 +--- a/fs/file_table.c ++++ b/fs/file_table.c +@@ -176,6 +176,11 @@ static int init_file(struct file *f, int flags, const struct cred *cred) + + f->f_flags = flags; + f->f_mode = OPEN_FMODE(flags); ++ /* ++ * Disable permission and pre-content events for all files by default. ++ * They may be enabled later by fsnotify_open_perm_and_set_mode(). ++ */ ++ file_set_fsnotify_mode(f, FMODE_NONOTIFY_PERM); + + f->f_op = NULL; + f->f_mapping = NULL; +@@ -197,11 +202,6 @@ static int init_file(struct file *f, int flags, const struct cred *cred) + * refcount bumps we should reinitialize the reused file first. + */ + file_ref_init(&f->f_ref, 1); +- /* +- * Disable permission and pre-content events for all files by default. +- * They may be enabled later by fsnotify_open_perm_and_set_mode(). +- */ +- file_set_fsnotify_mode(f, FMODE_NONOTIFY_PERM); + return 0; + } + +-- +2.51.0 + diff --git a/queue-6.18/fs-nfs-fix-readdir-slow-start-regression.patch b/queue-6.18/fs-nfs-fix-readdir-slow-start-regression.patch new file mode 100644 index 0000000000..7f03a50b6e --- /dev/null +++ b/queue-6.18/fs-nfs-fix-readdir-slow-start-regression.patch @@ -0,0 +1,54 @@ +From 74c327cca39f30669314a12c233cc5b15adb469c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 27 Dec 2025 12:46:29 +0200 +Subject: fs/nfs: Fix readdir slow-start regression + +From: Sagi Grimberg + +[ Upstream commit 42e7c876b182da65723700f6bc507a8aecb10d3b ] + +Commit 580f236737d1 ("NFS: Adjust the amount of readahead +performed by NFS readdir") reduces the amount of readahead names +caching done by the client. + +The downside of this approach is READDIR now may suffer from +a slow-start issue, where initially it will fetch names that fit +in a single page, then in 2, 4, 8 until the maximum supported +transfer size (usually 1M). + +This patch tries to take a balanced approach between mitigating +the slow-start issue still maintaining some efficiency gains. + +Fixes: 580f236737d1 ("NFS: Adjust the amount of readahead performed by NFS readdir") +Signed-off-by: Sagi Grimberg +Signed-off-by: Anna Schumaker +Signed-off-by: Sasha Levin +--- + fs/nfs/dir.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c +index 3b8250ee01412..a653a401b7970 100644 +--- a/fs/nfs/dir.c ++++ b/fs/nfs/dir.c +@@ -72,7 +72,7 @@ const struct address_space_operations nfs_dir_aops = { + .free_folio = nfs_readdir_clear_array, + }; + +-#define NFS_INIT_DTSIZE PAGE_SIZE ++#define NFS_INIT_DTSIZE SZ_64K + + static struct nfs_open_dir_context * + alloc_nfs_open_dir_context(struct inode *dir) +@@ -83,7 +83,7 @@ alloc_nfs_open_dir_context(struct inode *dir) + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL_ACCOUNT); + if (ctx != NULL) { + ctx->attr_gencount = nfsi->attr_gencount; +- ctx->dtsize = NFS_INIT_DTSIZE; ++ ctx->dtsize = min(NFS_SERVER(dir)->dtsize, NFS_INIT_DTSIZE); + spin_lock(&dir->i_lock); + if (list_empty(&nfsi->open_files) && + (nfsi->cache_validity & NFS_INO_DATA_INVAL_DEFER)) +-- +2.51.0 + diff --git a/queue-6.18/fs-tests-exec-drop-duplicate-bprm_stack_limits-test-.patch b/queue-6.18/fs-tests-exec-drop-duplicate-bprm_stack_limits-test-.patch new file mode 100644 index 0000000000..8e41dcd2c1 --- /dev/null +++ b/queue-6.18/fs-tests-exec-drop-duplicate-bprm_stack_limits-test-.patch @@ -0,0 +1,48 @@ +From ecf661e153e84fddcc6c30b30f87483f91488dcf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 18:59:50 +0100 +Subject: fs/tests: exec: drop duplicate bprm_stack_limits test vectors + +From: Titouan Ameline de Cadeville + +[ Upstream commit 46a03ea50b5f380bdb99178b8f90b39c6ba1f528 ] + +Remove duplicate entries from the bprm_stack_limits KUnit test vector +table. The duplicates do not add coverage and only increase test size. + +Signed-off-by: Titouan Ameline de Cadeville +Fixes: 60371f43e56b ("exec: Add KUnit test for bprm_stack_limits()") +Link: https://patch.msgid.link/20260203175950.43710-1-titouan.ameline@gmail.com +Signed-off-by: Kees Cook +Signed-off-by: Sasha Levin +--- + fs/tests/exec_kunit.c | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/fs/tests/exec_kunit.c b/fs/tests/exec_kunit.c +index 7c77d039680bb..f412d1a0f6bba 100644 +--- a/fs/tests/exec_kunit.c ++++ b/fs/tests/exec_kunit.c +@@ -87,9 +87,6 @@ static const struct bprm_stack_limits_result bprm_stack_limits_results[] = { + .argc = 0, .envc = ARG_MAX / sizeof(void *) - 1 }, + .expected_argmin = ULONG_MAX - sizeof(void *) }, + /* Raising rlim_stack / 4 to _STK_LIM / 4 * 3 will see more space. */ +- { { .p = ULONG_MAX, .rlim_stack.rlim_cur = 4 * (_STK_LIM / 4 * 3), +- .argc = 0, .envc = 0 }, +- .expected_argmin = ULONG_MAX - (_STK_LIM / 4 * 3) + sizeof(void *) }, + { { .p = ULONG_MAX, .rlim_stack.rlim_cur = 4 * (_STK_LIM / 4 * 3), + .argc = 0, .envc = 0 }, + .expected_argmin = ULONG_MAX - (_STK_LIM / 4 * 3) + sizeof(void *) }, +@@ -103,9 +100,6 @@ static const struct bprm_stack_limits_result bprm_stack_limits_results[] = { + { { .p = ULONG_MAX, .rlim_stack.rlim_cur = 4 * _STK_LIM, + .argc = 0, .envc = 0 }, + .expected_argmin = ULONG_MAX - (_STK_LIM / 4 * 3) + sizeof(void *) }, +- { { .p = ULONG_MAX, .rlim_stack.rlim_cur = 4 * _STK_LIM, +- .argc = 0, .envc = 0 }, +- .expected_argmin = ULONG_MAX - (_STK_LIM / 4 * 3) + sizeof(void *) }, + }; + + static void exec_test_bprm_stack_limits(struct kunit *test) +-- +2.51.0 + diff --git a/queue-6.18/genirq-set-irqf_cond_oneshot-in-devm_request_irq.patch b/queue-6.18/genirq-set-irqf_cond_oneshot-in-devm_request_irq.patch new file mode 100644 index 0000000000..6da1da8ea6 --- /dev/null +++ b/queue-6.18/genirq-set-irqf_cond_oneshot-in-devm_request_irq.patch @@ -0,0 +1,43 @@ +From 98f245d098db2b02f82eb35ad9981c678721f06b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:55:21 +0100 +Subject: genirq: Set IRQF_COND_ONESHOT in devm_request_irq(). + +From: Sebastian Andrzej Siewior + +[ Upstream commit 943b052ded21feb84f293d40b06af3181cd0d0d7 ] + +The flag IRQF_COND_ONESHOT was already force-added to request_irq() because +the ACPI SCI interrupt handler is using the IRQF_ONESHOT flag which breaks +all shared handlers. + +devm_request_irq() needs the same change since some users, such as +int0002_vgpio, are using this function instead. + +Add IRQF_COND_ONESHOT to the flags passed to devm_request_irq(). + +Fixes: c37927a203fa2 ("genirq: Set IRQF_COND_ONESHOT in request_irq()") +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260128095540.863589-2-bigeasy@linutronix.de +Signed-off-by: Sasha Levin +--- + include/linux/interrupt.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h +index 51b6484c04934..8f1166bc3b1ce 100644 +--- a/include/linux/interrupt.h ++++ b/include/linux/interrupt.h +@@ -215,7 +215,7 @@ static inline int __must_check + devm_request_irq(struct device *dev, unsigned int irq, irq_handler_t handler, + unsigned long irqflags, const char *devname, void *dev_id) + { +- return devm_request_threaded_irq(dev, irq, handler, NULL, irqflags, ++ return devm_request_threaded_irq(dev, irq, handler, NULL, irqflags | IRQF_COND_ONESHOT, + devname, dev_id); + } + +-- +2.51.0 + diff --git a/queue-6.18/gfs2-fix-slab-use-after-free-in-qd_put.patch b/queue-6.18/gfs2-fix-slab-use-after-free-in-qd_put.patch new file mode 100644 index 0000000000..5153ebf39c --- /dev/null +++ b/queue-6.18/gfs2-fix-slab-use-after-free-in-qd_put.patch @@ -0,0 +1,45 @@ +From d31cc106241b4d014b4dc07c1decdcba8e0ab2cb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 14 Dec 2025 16:47:34 +0000 +Subject: gfs2: Fix slab-use-after-free in qd_put + +From: Andreas Gruenbacher + +[ Upstream commit 22150a7d401d9e9169b9b68e05bed95f7f49bf69 ] + +Commit a475c5dd16e5 ("gfs2: Free quota data objects synchronously") +started freeing quota data objects during filesystem shutdown instead of +putting them back onto the LRU list, but it failed to remove these +objects from the LRU list, causing LRU list corruption. This caused +use-after-free when the shrinker (gfs2_qd_shrink_scan) tried to access +already-freed objects on the LRU list. + +Fix this by removing qd objects from the LRU list before freeing them in +qd_put(). + +Initial fix from Deepanshu Kartikey . + +Fixes: a475c5dd16e5 ("gfs2: Free quota data objects synchronously") +Reported-by: syzbot+046b605f01802054bff0@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=046b605f01802054bff0 +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Sasha Levin +--- + fs/gfs2/quota.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c +index f2df01f801b81..898fc3937b449 100644 +--- a/fs/gfs2/quota.c ++++ b/fs/gfs2/quota.c +@@ -334,6 +334,7 @@ static void qd_put(struct gfs2_quota_data *qd) + lockref_mark_dead(&qd->qd_lockref); + spin_unlock(&qd->qd_lockref.lock); + ++ list_lru_del_obj(&gfs2_qd_lru, &qd->qd_lru); + gfs2_qd_dispose(qd); + return; + } +-- +2.51.0 + diff --git a/queue-6.18/gfs2-fix-use-after-free-in-iomap-inline-data-write-p.patch b/queue-6.18/gfs2-fix-use-after-free-in-iomap-inline-data-write-p.patch new file mode 100644 index 0000000000..0a85dd61e8 --- /dev/null +++ b/queue-6.18/gfs2-fix-use-after-free-in-iomap-inline-data-write-p.patch @@ -0,0 +1,84 @@ +From 2e6b11b8cd3be32ce43e3c56d5eb4f9ac17096b3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 14:51:34 +0530 +Subject: gfs2: Fix use-after-free in iomap inline data write path + +From: Deepanshu Kartikey + +[ Upstream commit faddeb848305e79db89ee0479bb0e33380656321 ] + +The inline data buffer head (dibh) is being released prematurely in +gfs2_iomap_begin() via release_metapath() while iomap->inline_data +still points to dibh->b_data. This causes a use-after-free when +iomap_write_end_inline() later attempts to write to the inline data +area. + +The bug sequence: +1. gfs2_iomap_begin() calls gfs2_meta_inode_buffer() to read inode + metadata into dibh +2. Sets iomap->inline_data = dibh->b_data + sizeof(struct gfs2_dinode) +3. Calls release_metapath() which calls brelse(dibh), dropping refcount + to 0 +4. kswapd reclaims the page (~39ms later in the syzbot report) +5. iomap_write_end_inline() tries to memcpy() to iomap->inline_data +6. KASAN detects use-after-free write to freed memory + +Fix by storing dibh in iomap->private and incrementing its refcount +with get_bh() in gfs2_iomap_begin(). The buffer is then properly +released in gfs2_iomap_end() after the inline write completes, +ensuring the page stays alive for the entire iomap operation. + +Note: A C reproducer is not available for this issue. The fix is based +on analysis of the KASAN report and code review showing the buffer head +is freed before use. + +[agruenba: Take buffer head reference in gfs2_iomap_begin() to avoid +leaks in gfs2_iomap_get() and gfs2_iomap_alloc().] + +Reported-by: syzbot+ea1cd4aa4d1e98458a55@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=ea1cd4aa4d1e98458a55 +Fixes: d0a22a4b03b8 ("gfs2: Fix iomap write page reclaim deadlock") +Signed-off-by: Deepanshu Kartikey +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Sasha Levin +--- + fs/gfs2/bmap.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c +index 131091520de6b..fdcac8e3f2ba2 100644 +--- a/fs/gfs2/bmap.c ++++ b/fs/gfs2/bmap.c +@@ -1127,10 +1127,18 @@ static int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length, + goto out_unlock; + break; + default: +- goto out_unlock; ++ goto out; + } + + ret = gfs2_iomap_begin_write(inode, pos, length, flags, iomap, &mp); ++ if (ret) ++ goto out_unlock; ++ ++out: ++ if (iomap->type == IOMAP_INLINE) { ++ iomap->private = metapath_dibh(&mp); ++ get_bh(iomap->private); ++ } + + out_unlock: + release_metapath(&mp); +@@ -1144,6 +1152,9 @@ static int gfs2_iomap_end(struct inode *inode, loff_t pos, loff_t length, + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); + ++ if (iomap->private) ++ brelse(iomap->private); ++ + switch (flags & (IOMAP_WRITE | IOMAP_ZERO)) { + case IOMAP_WRITE: + if (flags & IOMAP_DIRECT) +-- +2.51.0 + diff --git a/queue-6.18/gfs2-retries-missing-in-gfs2_-rename-exchange.patch b/queue-6.18/gfs2-retries-missing-in-gfs2_-rename-exchange.patch new file mode 100644 index 0000000000..a035465806 --- /dev/null +++ b/queue-6.18/gfs2-retries-missing-in-gfs2_-rename-exchange.patch @@ -0,0 +1,178 @@ +From 43d44f43fa093aa0961f6acefce7824f74e3899a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 22:59:12 +0000 +Subject: gfs2: Retries missing in gfs2_{rename,exchange} + +From: Andreas Gruenbacher + +[ Upstream commit 11d763f0b0afc2cf5f92f4adae5dbbbbef712f8f ] + +Fix a bug in gfs2's asynchronous glock handling for rename and exchange +operations. The original async implementation from commit ad26967b9afa +("gfs2: Use async glocks for rename") mentioned that retries were needed +but never implemented them, causing operations to fail with -ESTALE +instead of retrying on timeout. + +Also makes the waiting interruptible. + +In addition, the timeouts used were too high for situations in which +timing out is a rare but expected scenario. Switch to shorter timeouts +with randomization and exponentional backoff. + +Fixes: ad26967b9afa ("gfs2: Use async glocks for rename") +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Sasha Levin +--- + fs/gfs2/glock.c | 36 +++++++++++++++++++++++++++--------- + fs/gfs2/glock.h | 3 ++- + fs/gfs2/inode.c | 18 ++++++++++++++---- + 3 files changed, 43 insertions(+), 14 deletions(-) + +diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c +index 9f2eb7e385695..7aec6cfdfd91d 100644 +--- a/fs/gfs2/glock.c ++++ b/fs/gfs2/glock.c +@@ -1354,31 +1354,45 @@ static int glocks_pending(unsigned int num_gh, struct gfs2_holder *ghs) + * gfs2_glock_async_wait - wait on multiple asynchronous glock acquisitions + * @num_gh: the number of holders in the array + * @ghs: the glock holder array ++ * @retries: number of retries attempted so far + * + * Returns: 0 on success, meaning all glocks have been granted and are held. + * -ESTALE if the request timed out, meaning all glocks were released, + * and the caller should retry the operation. + */ + +-int gfs2_glock_async_wait(unsigned int num_gh, struct gfs2_holder *ghs) ++int gfs2_glock_async_wait(unsigned int num_gh, struct gfs2_holder *ghs, ++ unsigned int retries) + { + struct gfs2_sbd *sdp = ghs[0].gh_gl->gl_name.ln_sbd; +- int i, ret = 0, timeout = 0; + unsigned long start_time = jiffies; ++ int i, ret = 0; ++ long timeout; + + might_sleep(); +- /* +- * Total up the (minimum hold time * 2) of all glocks and use that to +- * determine the max amount of time we should wait. +- */ +- for (i = 0; i < num_gh; i++) +- timeout += ghs[i].gh_gl->gl_hold_time << 1; + +- if (!wait_event_timeout(sdp->sd_async_glock_wait, ++ timeout = GL_GLOCK_MIN_HOLD; ++ if (retries) { ++ unsigned int max_shift; ++ long incr; ++ ++ /* Add a random delay and increase the timeout exponentially. */ ++ max_shift = BITS_PER_LONG - 2 - __fls(GL_GLOCK_HOLD_INCR); ++ incr = min(GL_GLOCK_HOLD_INCR << min(retries - 1, max_shift), ++ 10 * HZ - GL_GLOCK_MIN_HOLD); ++ schedule_timeout_interruptible(get_random_long() % (incr / 3)); ++ if (signal_pending(current)) ++ goto interrupted; ++ timeout += (incr / 3) + get_random_long() % (incr / 3); ++ } ++ ++ if (!wait_event_interruptible_timeout(sdp->sd_async_glock_wait, + !glocks_pending(num_gh, ghs), timeout)) { + ret = -ESTALE; /* request timed out. */ + goto out; + } ++ if (signal_pending(current)) ++ goto interrupted; + + for (i = 0; i < num_gh; i++) { + struct gfs2_holder *gh = &ghs[i]; +@@ -1402,6 +1416,10 @@ int gfs2_glock_async_wait(unsigned int num_gh, struct gfs2_holder *ghs) + } + } + return ret; ++ ++interrupted: ++ ret = -EINTR; ++ goto out; + } + + /** +diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h +index d041b922b45e3..2d4fd1a2bbbb8 100644 +--- a/fs/gfs2/glock.h ++++ b/fs/gfs2/glock.h +@@ -204,7 +204,8 @@ int gfs2_glock_poll(struct gfs2_holder *gh); + int gfs2_instantiate(struct gfs2_holder *gh); + int gfs2_glock_holder_ready(struct gfs2_holder *gh); + int gfs2_glock_wait(struct gfs2_holder *gh); +-int gfs2_glock_async_wait(unsigned int num_gh, struct gfs2_holder *ghs); ++int gfs2_glock_async_wait(unsigned int num_gh, struct gfs2_holder *ghs, ++ unsigned int retries); + void gfs2_glock_dq(struct gfs2_holder *gh); + void gfs2_glock_dq_wait(struct gfs2_holder *gh); + void gfs2_glock_dq_uninit(struct gfs2_holder *gh); +diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c +index d7e35a05c1610..63d9fe7464344 100644 +--- a/fs/gfs2/inode.c ++++ b/fs/gfs2/inode.c +@@ -1495,7 +1495,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, + unsigned int num_gh; + int dir_rename = 0; + struct gfs2_diradd da = { .nr_blocks = 0, .save_loc = 0, }; +- unsigned int x; ++ unsigned int retries = 0, x; + int error; + + gfs2_holder_mark_uninitialized(&r_gh); +@@ -1545,12 +1545,17 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, + num_gh++; + } + ++again: + for (x = 0; x < num_gh; x++) { + error = gfs2_glock_nq(ghs + x); + if (error) + goto out_gunlock; + } +- error = gfs2_glock_async_wait(num_gh, ghs); ++ error = gfs2_glock_async_wait(num_gh, ghs, retries); ++ if (error == -ESTALE) { ++ retries++; ++ goto again; ++ } + if (error) + goto out_gunlock; + +@@ -1739,7 +1744,7 @@ static int gfs2_exchange(struct inode *odir, struct dentry *odentry, + struct gfs2_sbd *sdp = GFS2_SB(odir); + struct gfs2_holder ghs[4], r_gh; + unsigned int num_gh; +- unsigned int x; ++ unsigned int retries = 0, x; + umode_t old_mode = oip->i_inode.i_mode; + umode_t new_mode = nip->i_inode.i_mode; + int error; +@@ -1783,13 +1788,18 @@ static int gfs2_exchange(struct inode *odir, struct dentry *odentry, + gfs2_holder_init(nip->i_gl, LM_ST_EXCLUSIVE, GL_ASYNC, ghs + num_gh); + num_gh++; + ++again: + for (x = 0; x < num_gh; x++) { + error = gfs2_glock_nq(ghs + x); + if (error) + goto out_gunlock; + } + +- error = gfs2_glock_async_wait(num_gh, ghs); ++ error = gfs2_glock_async_wait(num_gh, ghs, retries); ++ if (error == -ESTALE) { ++ retries++; ++ goto again; ++ } + if (error) + goto out_gunlock; + +-- +2.51.0 + diff --git a/queue-6.18/gpib-fix-error-code-in-ibonline.patch b/queue-6.18/gpib-fix-error-code-in-ibonline.patch new file mode 100644 index 0000000000..3a8a1f14bb --- /dev/null +++ b/queue-6.18/gpib-fix-error-code-in-ibonline.patch @@ -0,0 +1,42 @@ +From 7cbbaec1c7fbe11f65ce6d3982feb54122a85a28 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 10:17:49 +0300 +Subject: gpib: Fix error code in ibonline() + +From: Dan Carpenter + +[ Upstream commit 96118565d24e7691e423d73be224b3a3fffc4680 ] + +This accidentally returns 1 on error, but it should return negative +error codes. + +Fixes: 9dde4559e939 ("staging: gpib: Add GPIB common core driver") +Signed-off-by: Dan Carpenter +Link: https://patch.msgid.link/aSlMnaT1M104NJb2@stanley.mountain +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/staging/gpib/common/iblib.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/staging/gpib/common/iblib.c b/drivers/staging/gpib/common/iblib.c +index 7cbb6a467177d..b672dd6aad25f 100644 +--- a/drivers/staging/gpib/common/iblib.c ++++ b/drivers/staging/gpib/common/iblib.c +@@ -227,11 +227,10 @@ int ibonline(struct gpib_board *board) + #ifndef CONFIG_NIOS2 + board->autospoll_task = kthread_run(&autospoll_thread, board, + "gpib%d_autospoll_kthread", board->minor); +- retval = IS_ERR(board->autospoll_task); +- if (retval) { ++ if (IS_ERR(board->autospoll_task)) { + dev_err(board->gpib_dev, "failed to create autospoll thread\n"); + board->interface->detach(board); +- return retval; ++ return PTR_ERR(board->autospoll_task); + } + #endif + board->online = 1; +-- +2.51.0 + diff --git a/queue-6.18/gpib-fix-error-code-in-ni_usb_write_registers.patch b/queue-6.18/gpib-fix-error-code-in-ni_usb_write_registers.patch new file mode 100644 index 0000000000..cec1d2a1c2 --- /dev/null +++ b/queue-6.18/gpib-fix-error-code-in-ni_usb_write_registers.patch @@ -0,0 +1,37 @@ +From 7f591231c8b3c954f6871e283460572534cf0cc5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 10:17:57 +0300 +Subject: gpib: Fix error code in ni_usb_write_registers() + +From: Dan Carpenter + +[ Upstream commit 484e62252212c5b5fc62eaee5e4977143cb159c6 ] + +If ni_usb_receive_bulk_msg() succeeds but without reading 16 bytes, then +the error code needs to be set. The current code returns success. + +Fixes: 4e127de14fa7 ("staging: gpib: Add National Instruments USB GPIB driver") +Signed-off-by: Dan Carpenter +Link: https://patch.msgid.link/aSlMpbE4IrQuBGFS@stanley.mountain +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/staging/gpib/ni_usb/ni_usb_gpib.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/staging/gpib/ni_usb/ni_usb_gpib.c b/drivers/staging/gpib/ni_usb/ni_usb_gpib.c +index 1f8412de9fa32..fdcaa6c00bfea 100644 +--- a/drivers/staging/gpib/ni_usb/ni_usb_gpib.c ++++ b/drivers/staging/gpib/ni_usb/ni_usb_gpib.c +@@ -566,7 +566,7 @@ static int ni_usb_write_registers(struct ni_usb_priv *ni_priv, + retval, bytes_read); + ni_usb_dump_raw_block(in_data, bytes_read); + kfree(in_data); +- return retval; ++ return retval ?: -EINVAL; + } + + mutex_unlock(&ni_priv->addressed_transfer_lock); +-- +2.51.0 + diff --git a/queue-6.18/gpib-fix-memory-leak-in-ni_usb_init.patch b/queue-6.18/gpib-fix-memory-leak-in-ni_usb_init.patch new file mode 100644 index 0000000000..e16765c842 --- /dev/null +++ b/queue-6.18/gpib-fix-memory-leak-in-ni_usb_init.patch @@ -0,0 +1,67 @@ +From d8dde3dcad98d4483328d8ef8dd7b1a4249c8ccf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Dec 2025 03:45:46 +0000 +Subject: gpib: Fix memory leak in ni_usb_init() + +From: Zilin Guan + +[ Upstream commit b89921eed8cf2d97250bac4be38dbcfbf048b586 ] + +In ni_usb_init(), if ni_usb_setup_init() fails, the function returns +-EFAULT without freeing the allocated writes buffer, leading to a +memory leak. + +Additionally, ni_usb_setup_init() returns 0 on failure, which causes +ni_usb_init() to return -EFAULT, an inappropriate error code for this +situation. + +Fix the leak by freeing writes in the error path. Modify +ni_usb_setup_init() to return -EINVAL on failure and propagate this +error code in ni_usb_init(). + +Fixes: 4e127de14fa7 ("staging: gpib: Add National Instruments USB GPIB driver") +Suggested-by: Greg KH +Suggested-by: Dave Penkler +Co-developed-by: Jianhao Xu +Signed-off-by: Jianhao Xu +Signed-off-by: Zilin Guan +Link: https://patch.msgid.link/20251230034546.929452-1-zilin@seu.edu.cn +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/staging/gpib/ni_usb/ni_usb_gpib.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/drivers/staging/gpib/ni_usb/ni_usb_gpib.c b/drivers/staging/gpib/ni_usb/ni_usb_gpib.c +index fdcaa6c00bfea..b6fddb437f552 100644 +--- a/drivers/staging/gpib/ni_usb/ni_usb_gpib.c ++++ b/drivers/staging/gpib/ni_usb/ni_usb_gpib.c +@@ -1780,7 +1780,7 @@ static int ni_usb_setup_init(struct gpib_board *board, struct ni_usb_register *w + i++; + if (i > NUM_INIT_WRITES) { + dev_err(&usb_dev->dev, "bug!, buffer overrun, i=%i\n", i); +- return 0; ++ return -EINVAL; + } + return i; + } +@@ -1799,10 +1799,12 @@ static int ni_usb_init(struct gpib_board *board) + return -ENOMEM; + + writes_len = ni_usb_setup_init(board, writes); +- if (writes_len) +- retval = ni_usb_write_registers(ni_priv, writes, writes_len, &ibsta); +- else +- return -EFAULT; ++ if (writes_len < 0) { ++ kfree(writes); ++ return writes_len; ++ } ++ ++ retval = ni_usb_write_registers(ni_priv, writes, writes_len, &ibsta); + kfree(writes); + if (retval) { + dev_err(&usb_dev->dev, "register write failed, retval=%i\n", retval); +-- +2.51.0 + diff --git a/queue-6.18/gpu-nova-core-apply-the-one-use-item-per-line-policy.patch b/queue-6.18/gpu-nova-core-apply-the-one-use-item-per-line-policy.patch new file mode 100644 index 0000000000..172af5dba2 --- /dev/null +++ b/queue-6.18/gpu-nova-core-apply-the-one-use-item-per-line-policy.patch @@ -0,0 +1,803 @@ +From 0b3d2d6050ac768e98f72b9c78fd453bd0638345 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Nov 2025 18:10:06 -0800 +Subject: gpu: nova-core: apply the one "use" item per line policy + +From: John Hubbard + +[ Upstream commit 173c99b85aa05387fcfb3231293124c5d611d167 ] + +As per [1], we need one "use" item per line, in order to reduce merge +conflicts. Furthermore, we need a trailing ", //" in order to tell +rustfmt(1) to leave it alone. + +This does that for the entire nova-core driver. + +[1] https://docs.kernel.org/rust/coding-guidelines.html#imports + +Acked-by: Danilo Krummrich +Signed-off-by: John Hubbard +[acourbot@nvidia.com: remove imports already in prelude as pointed out +by Danilo.] +[acourbot@nvidia.com: remove a few unneeded trailing `//`.] +Signed-off-by: Alexandre Courbot +Message-ID: <20251107021006.434109-1-jhubbard@nvidia.com> +Stable-dep-of: 5cf76277cdec ("gpu: nova-core: check for overflow to DMATRFBASE1") +Signed-off-by: Sasha Levin +--- + drivers/gpu/nova-core/dma.rs | 17 +++++--- + drivers/gpu/nova-core/driver.rs | 11 +++-- + drivers/gpu/nova-core/falcon.rs | 34 +++++++++------ + drivers/gpu/nova-core/falcon/gsp.rs | 12 +++++- + drivers/gpu/nova-core/falcon/hal.rs | 12 ++++-- + drivers/gpu/nova-core/falcon/hal/ga102.rs | 26 ++++++++---- + drivers/gpu/nova-core/falcon/sec2.rs | 10 ++++- + drivers/gpu/nova-core/fb.rs | 27 +++++++----- + drivers/gpu/nova-core/fb/hal.rs | 6 ++- + drivers/gpu/nova-core/fb/hal/ga100.rs | 12 +++--- + drivers/gpu/nova-core/fb/hal/ga102.rs | 8 ++-- + drivers/gpu/nova-core/fb/hal/tu102.rs | 9 ++-- + drivers/gpu/nova-core/firmware.rs | 23 +++++----- + drivers/gpu/nova-core/firmware/booter.rs | 45 ++++++++++++++------ + drivers/gpu/nova-core/firmware/fwsec.rs | 52 +++++++++++++++++------ + drivers/gpu/nova-core/firmware/gsp.rs | 33 +++++++++----- + drivers/gpu/nova-core/firmware/riscv.rs | 16 ++++--- + drivers/gpu/nova-core/gfw.rs | 14 +++--- + drivers/gpu/nova-core/gpu.rs | 29 +++++++++---- + drivers/gpu/nova-core/gsp/boot.rs | 44 ++++++++++++------- + drivers/gpu/nova-core/regs.rs | 24 ++++++++--- + drivers/gpu/nova-core/vbios.rs | 28 ++++++++---- + 22 files changed, 335 insertions(+), 157 deletions(-) + +diff --git a/drivers/gpu/nova-core/dma.rs b/drivers/gpu/nova-core/dma.rs +index 94f44bcfd748d..5b117aefdb15f 100644 +--- a/drivers/gpu/nova-core/dma.rs ++++ b/drivers/gpu/nova-core/dma.rs +@@ -2,12 +2,17 @@ + + //! Simple DMA object wrapper. + +-use core::ops::{Deref, DerefMut}; +- +-use kernel::device; +-use kernel::dma::CoherentAllocation; +-use kernel::page::PAGE_SIZE; +-use kernel::prelude::*; ++use core::ops::{ ++ Deref, ++ DerefMut, // ++}; ++ ++use kernel::{ ++ device, ++ dma::CoherentAllocation, ++ page::PAGE_SIZE, ++ prelude::*, // ++}; + + pub(crate) struct DmaObject { + dma: CoherentAllocation, +diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver.rs +index edc72052e27ae..2509f75eccb99 100644 +--- a/drivers/gpu/nova-core/driver.rs ++++ b/drivers/gpu/nova-core/driver.rs +@@ -1,13 +1,18 @@ + // SPDX-License-Identifier: GPL-2.0 + + use kernel::{ +- auxiliary, c_str, ++ auxiliary, ++ c_str, + device::Core, + pci, +- pci::{Class, ClassMask, Vendor}, ++ pci::{ ++ Class, ++ ClassMask, ++ Vendor, // ++ }, + prelude::*, + sizes::SZ_16M, +- sync::Arc, ++ sync::Arc, // + }; + + use crate::gpu::Gpu; +diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon.rs +index 05856b43b51c3..3fa2c9cfa2d7f 100644 +--- a/drivers/gpu/nova-core/falcon.rs ++++ b/drivers/gpu/nova-core/falcon.rs +@@ -3,20 +3,28 @@ + //! Falcon microprocessor base support + + use core::ops::Deref; ++ + use hal::FalconHal; +-use kernel::device; +-use kernel::dma::DmaAddress; +-use kernel::io::poll::read_poll_timeout; +-use kernel::prelude::*; +-use kernel::sync::aref::ARef; +-use kernel::time::delay::fsleep; +-use kernel::time::Delta; +- +-use crate::dma::DmaObject; +-use crate::driver::Bar0; +-use crate::gpu::Chipset; +-use crate::regs; +-use crate::regs::macros::RegisterBase; ++ ++use kernel::{ ++ device, ++ dma::DmaAddress, ++ io::poll::read_poll_timeout, ++ prelude::*, ++ sync::aref::ARef, ++ time::{ ++ delay::fsleep, ++ Delta, // ++ }, ++}; ++ ++use crate::{ ++ dma::DmaObject, ++ driver::Bar0, ++ gpu::Chipset, ++ regs, ++ regs::macros::RegisterBase, // ++}; + + pub(crate) mod gsp; + mod hal; +diff --git a/drivers/gpu/nova-core/falcon/gsp.rs b/drivers/gpu/nova-core/falcon/gsp.rs +index f17599cb49fa1..93d4eca65631e 100644 +--- a/drivers/gpu/nova-core/falcon/gsp.rs ++++ b/drivers/gpu/nova-core/falcon/gsp.rs +@@ -2,8 +2,16 @@ + + use crate::{ + driver::Bar0, +- falcon::{Falcon, FalconEngine, PFalcon2Base, PFalconBase}, +- regs::{self, macros::RegisterBase}, ++ falcon::{ ++ Falcon, ++ FalconEngine, ++ PFalcon2Base, ++ PFalconBase, // ++ }, ++ regs::{ ++ self, ++ macros::RegisterBase, // ++ }, + }; + + /// Type specifying the `Gsp` falcon engine. Cannot be instantiated. +diff --git a/drivers/gpu/nova-core/falcon/hal.rs b/drivers/gpu/nova-core/falcon/hal.rs +index bba2884556179..cde268e7411d9 100644 +--- a/drivers/gpu/nova-core/falcon/hal.rs ++++ b/drivers/gpu/nova-core/falcon/hal.rs +@@ -2,9 +2,15 @@ + + use kernel::prelude::*; + +-use crate::driver::Bar0; +-use crate::falcon::{Falcon, FalconBromParams, FalconEngine}; +-use crate::gpu::Chipset; ++use crate::{ ++ driver::Bar0, ++ falcon::{ ++ Falcon, ++ FalconBromParams, ++ FalconEngine, // ++ }, ++ gpu::Chipset, ++}; + + mod ga102; + +diff --git a/drivers/gpu/nova-core/falcon/hal/ga102.rs b/drivers/gpu/nova-core/falcon/hal/ga102.rs +index afed353b24d29..69a7a95cac163 100644 +--- a/drivers/gpu/nova-core/falcon/hal/ga102.rs ++++ b/drivers/gpu/nova-core/falcon/hal/ga102.rs +@@ -2,16 +2,24 @@ + + use core::marker::PhantomData; + +-use kernel::device; +-use kernel::io::poll::read_poll_timeout; +-use kernel::prelude::*; +-use kernel::time::Delta; +- +-use crate::driver::Bar0; +-use crate::falcon::{ +- Falcon, FalconBromParams, FalconEngine, FalconModSelAlgo, PeregrineCoreSelect, ++use kernel::{ ++ device, ++ io::poll::read_poll_timeout, ++ prelude::*, ++ time::Delta, // ++}; ++ ++use crate::{ ++ driver::Bar0, ++ falcon::{ ++ Falcon, ++ FalconBromParams, ++ FalconEngine, ++ FalconModSelAlgo, ++ PeregrineCoreSelect, // ++ }, ++ regs, + }; +-use crate::regs; + + use super::FalconHal; + +diff --git a/drivers/gpu/nova-core/falcon/sec2.rs b/drivers/gpu/nova-core/falcon/sec2.rs +index 815786c8480db..b57d362e576a4 100644 +--- a/drivers/gpu/nova-core/falcon/sec2.rs ++++ b/drivers/gpu/nova-core/falcon/sec2.rs +@@ -1,7 +1,13 @@ + // SPDX-License-Identifier: GPL-2.0 + +-use crate::falcon::{FalconEngine, PFalcon2Base, PFalconBase}; +-use crate::regs::macros::RegisterBase; ++use crate::{ ++ falcon::{ ++ FalconEngine, ++ PFalcon2Base, ++ PFalconBase, // ++ }, ++ regs::macros::RegisterBase, ++}; + + /// Type specifying the `Sec2` falcon engine. Cannot be instantiated. + pub(crate) struct Sec2(()); +diff --git a/drivers/gpu/nova-core/fb.rs b/drivers/gpu/nova-core/fb.rs +index 27d9edab8347c..989bbfd5bdeef 100644 +--- a/drivers/gpu/nova-core/fb.rs ++++ b/drivers/gpu/nova-core/fb.rs +@@ -2,16 +2,23 @@ + + use core::ops::Range; + +-use kernel::prelude::*; +-use kernel::ptr::{Alignable, Alignment}; +-use kernel::sizes::*; +-use kernel::sync::aref::ARef; +-use kernel::{dev_warn, device}; +- +-use crate::dma::DmaObject; +-use crate::driver::Bar0; +-use crate::gpu::Chipset; +-use crate::regs; ++use kernel::{ ++ device, ++ prelude::*, ++ ptr::{ ++ Alignable, ++ Alignment, // ++ }, ++ sizes::*, ++ sync::aref::ARef, // ++}; ++ ++use crate::{ ++ dma::DmaObject, ++ driver::Bar0, ++ gpu::Chipset, ++ regs, // ++}; + + mod hal; + +diff --git a/drivers/gpu/nova-core/fb/hal.rs b/drivers/gpu/nova-core/fb/hal.rs +index 2f914948bb9a9..aba0abd8ee005 100644 +--- a/drivers/gpu/nova-core/fb/hal.rs ++++ b/drivers/gpu/nova-core/fb/hal.rs +@@ -2,8 +2,10 @@ + + use kernel::prelude::*; + +-use crate::driver::Bar0; +-use crate::gpu::Chipset; ++use crate::{ ++ driver::Bar0, ++ gpu::Chipset, // ++}; + + mod ga100; + mod ga102; +diff --git a/drivers/gpu/nova-core/fb/hal/ga100.rs b/drivers/gpu/nova-core/fb/hal/ga100.rs +index 871c42bf033ac..dae392c38a1b5 100644 +--- a/drivers/gpu/nova-core/fb/hal/ga100.rs ++++ b/drivers/gpu/nova-core/fb/hal/ga100.rs +@@ -1,15 +1,17 @@ + // SPDX-License-Identifier: GPL-2.0 + +-struct Ga100; +- + use kernel::prelude::*; + +-use crate::driver::Bar0; +-use crate::fb::hal::FbHal; +-use crate::regs; ++use crate::{ ++ driver::Bar0, ++ fb::hal::FbHal, ++ regs, // ++}; + + use super::tu102::FLUSH_SYSMEM_ADDR_SHIFT; + ++struct Ga100; ++ + pub(super) fn read_sysmem_flush_page_ga100(bar: &Bar0) -> u64 { + u64::from(regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR::read(bar).adr_39_08()) << FLUSH_SYSMEM_ADDR_SHIFT + | u64::from(regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR_HI::read(bar).adr_63_40()) +diff --git a/drivers/gpu/nova-core/fb/hal/ga102.rs b/drivers/gpu/nova-core/fb/hal/ga102.rs +index a73b77e397151..734605905031b 100644 +--- a/drivers/gpu/nova-core/fb/hal/ga102.rs ++++ b/drivers/gpu/nova-core/fb/hal/ga102.rs +@@ -2,9 +2,11 @@ + + use kernel::prelude::*; + +-use crate::driver::Bar0; +-use crate::fb::hal::FbHal; +-use crate::regs; ++use crate::{ ++ driver::Bar0, ++ fb::hal::FbHal, ++ regs, // ++}; + + fn vidmem_size_ga102(bar: &Bar0) -> u64 { + regs::NV_USABLE_FB_SIZE_IN_MB::read(bar).usable_fb_size() +diff --git a/drivers/gpu/nova-core/fb/hal/tu102.rs b/drivers/gpu/nova-core/fb/hal/tu102.rs +index b022c781caf45..2faf95f0e1ad8 100644 +--- a/drivers/gpu/nova-core/fb/hal/tu102.rs ++++ b/drivers/gpu/nova-core/fb/hal/tu102.rs +@@ -1,10 +1,13 @@ + // SPDX-License-Identifier: GPL-2.0 + +-use crate::driver::Bar0; +-use crate::fb::hal::FbHal; +-use crate::regs; + use kernel::prelude::*; + ++use crate::{ ++ driver::Bar0, ++ fb::hal::FbHal, ++ regs, // ++}; ++ + /// Shift applied to the sysmem address before it is written into `NV_PFB_NISO_FLUSH_SYSMEM_ADDR`, + /// to be used by HALs. + pub(super) const FLUSH_SYSMEM_ADDR_SHIFT: u32 = 8; +diff --git a/drivers/gpu/nova-core/firmware.rs b/drivers/gpu/nova-core/firmware.rs +index 4179a74a23421..163b746f03ef3 100644 +--- a/drivers/gpu/nova-core/firmware.rs ++++ b/drivers/gpu/nova-core/firmware.rs +@@ -4,17 +4,20 @@ + //! to be loaded into a given execution unit. + + use core::marker::PhantomData; +-use core::mem::size_of; + +-use kernel::device; +-use kernel::firmware; +-use kernel::prelude::*; +-use kernel::str::CString; +-use kernel::transmute::FromBytes; +- +-use crate::dma::DmaObject; +-use crate::falcon::FalconFirmware; +-use crate::gpu; ++use kernel::{ ++ device, ++ firmware, ++ prelude::*, ++ str::CString, ++ transmute::FromBytes, // ++}; ++ ++use crate::{ ++ dma::DmaObject, ++ falcon::FalconFirmware, ++ gpu, // ++}; + + pub(crate) mod booter; + pub(crate) mod fwsec; +diff --git a/drivers/gpu/nova-core/firmware/booter.rs b/drivers/gpu/nova-core/firmware/booter.rs +index b4ff1b17e4a08..1e8f6c99fa2e1 100644 +--- a/drivers/gpu/nova-core/firmware/booter.rs ++++ b/drivers/gpu/nova-core/firmware/booter.rs +@@ -4,20 +4,37 @@ + //! running on [`Sec2`], that is used on Turing/Ampere to load the GSP firmware into the GSP falcon + //! (and optionally unload it through a separate firmware image). + +-use core::marker::PhantomData; +-use core::mem::size_of; +-use core::ops::Deref; +- +-use kernel::device; +-use kernel::prelude::*; +-use kernel::transmute::FromBytes; +- +-use crate::dma::DmaObject; +-use crate::driver::Bar0; +-use crate::falcon::sec2::Sec2; +-use crate::falcon::{Falcon, FalconBromParams, FalconFirmware, FalconLoadParams, FalconLoadTarget}; +-use crate::firmware::{BinFirmware, FirmwareDmaObject, FirmwareSignature, Signed, Unsigned}; +-use crate::gpu::Chipset; ++use core::{ ++ marker::PhantomData, ++ ops::Deref, // ++}; ++ ++use kernel::{ ++ device, ++ prelude::*, ++ transmute::FromBytes, // ++}; ++ ++use crate::{ ++ dma::DmaObject, ++ driver::Bar0, ++ falcon::{ ++ sec2::Sec2, ++ Falcon, ++ FalconBromParams, ++ FalconFirmware, ++ FalconLoadParams, ++ FalconLoadTarget, // ++ }, ++ firmware::{ ++ BinFirmware, ++ FirmwareDmaObject, ++ FirmwareSignature, ++ Signed, ++ Unsigned, // ++ }, ++ gpu::Chipset, ++}; + + /// Local convenience function to return a copy of `S` by reinterpreting the bytes starting at + /// `offset` in `slice`. +diff --git a/drivers/gpu/nova-core/firmware/fwsec.rs b/drivers/gpu/nova-core/firmware/fwsec.rs +index dd3420aaa2bf2..1e4dde0279d7f 100644 +--- a/drivers/gpu/nova-core/firmware/fwsec.rs ++++ b/drivers/gpu/nova-core/firmware/fwsec.rs +@@ -10,20 +10,44 @@ + //! - The command to be run, as this firmware can perform several tasks ; + //! - The ucode signature, so the GSP falcon can run FWSEC in HS mode. + +-use core::marker::PhantomData; +-use core::mem::{align_of, size_of}; +-use core::ops::Deref; +- +-use kernel::device::{self, Device}; +-use kernel::prelude::*; +-use kernel::transmute::FromBytes; +- +-use crate::dma::DmaObject; +-use crate::driver::Bar0; +-use crate::falcon::gsp::Gsp; +-use crate::falcon::{Falcon, FalconBromParams, FalconFirmware, FalconLoadParams, FalconLoadTarget}; +-use crate::firmware::{FalconUCodeDescV3, FirmwareDmaObject, FirmwareSignature, Signed, Unsigned}; +-use crate::vbios::Vbios; ++use core::{ ++ marker::PhantomData, ++ mem::{ ++ align_of, ++ size_of, // ++ }, ++ ops::Deref, ++}; ++ ++use kernel::{ ++ device::{ ++ self, ++ Device, // ++ }, ++ prelude::*, ++ transmute::FromBytes, ++}; ++ ++use crate::{ ++ dma::DmaObject, ++ driver::Bar0, ++ falcon::{ ++ gsp::Gsp, ++ Falcon, ++ FalconBromParams, ++ FalconFirmware, ++ FalconLoadParams, ++ FalconLoadTarget, // ++ }, ++ firmware::{ ++ FalconUCodeDescV3, ++ FirmwareDmaObject, ++ FirmwareSignature, ++ Signed, ++ Unsigned, // ++ }, ++ vbios::Vbios, ++}; + + const NVFW_FALCON_APPIF_ID_DMEMMAPPER: u32 = 0x4; + +diff --git a/drivers/gpu/nova-core/firmware/gsp.rs b/drivers/gpu/nova-core/firmware/gsp.rs +index 6b0761460a57d..f0f4756c315cd 100644 +--- a/drivers/gpu/nova-core/firmware/gsp.rs ++++ b/drivers/gpu/nova-core/firmware/gsp.rs +@@ -2,16 +2,29 @@ + + use core::mem::size_of_val; + +-use kernel::device; +-use kernel::dma::{DataDirection, DmaAddress}; +-use kernel::kvec; +-use kernel::prelude::*; +-use kernel::scatterlist::{Owned, SGTable}; +- +-use crate::dma::DmaObject; +-use crate::firmware::riscv::RiscvFirmware; +-use crate::gpu::{Architecture, Chipset}; +-use crate::gsp::GSP_PAGE_SIZE; ++use kernel::{ ++ device, ++ dma::{ ++ DataDirection, ++ DmaAddress, // ++ }, ++ kvec, ++ prelude::*, ++ scatterlist::{ ++ Owned, ++ SGTable, // ++ }, ++}; ++ ++use crate::{ ++ dma::DmaObject, ++ firmware::riscv::RiscvFirmware, ++ gpu::{ ++ Architecture, ++ Chipset, // ++ }, ++ gsp::GSP_PAGE_SIZE, ++}; + + /// Ad-hoc and temporary module to extract sections from ELF images. + /// +diff --git a/drivers/gpu/nova-core/firmware/riscv.rs b/drivers/gpu/nova-core/firmware/riscv.rs +index afb08f5bc4ba8..196dedb96aeb7 100644 +--- a/drivers/gpu/nova-core/firmware/riscv.rs ++++ b/drivers/gpu/nova-core/firmware/riscv.rs +@@ -5,13 +5,17 @@ + + use core::mem::size_of; + +-use kernel::device; +-use kernel::firmware::Firmware; +-use kernel::prelude::*; +-use kernel::transmute::FromBytes; ++use kernel::{ ++ device, ++ firmware::Firmware, ++ prelude::*, ++ transmute::FromBytes, // ++}; + +-use crate::dma::DmaObject; +-use crate::firmware::BinFirmware; ++use crate::{ ++ dma::DmaObject, ++ firmware::BinFirmware, // ++}; + + /// Descriptor for microcode running on a RISC-V core. + #[repr(C)] +diff --git a/drivers/gpu/nova-core/gfw.rs b/drivers/gpu/nova-core/gfw.rs +index 23c28c2a3793a..9121f400046d8 100644 +--- a/drivers/gpu/nova-core/gfw.rs ++++ b/drivers/gpu/nova-core/gfw.rs +@@ -18,12 +18,16 @@ + //! + //! Note that the devinit sequence also needs to run during suspend/resume. + +-use kernel::io::poll::read_poll_timeout; +-use kernel::prelude::*; +-use kernel::time::Delta; ++use kernel::{ ++ io::poll::read_poll_timeout, ++ prelude::*, ++ time::Delta, // ++}; + +-use crate::driver::Bar0; +-use crate::regs; ++use crate::{ ++ driver::Bar0, ++ regs, // ++}; + + /// Wait for the `GFW` (GPU firmware) boot completion signal (`GFW_BOOT`), or a 4 seconds timeout. + /// +diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs +index af20e2daea24f..bcc787b887953 100644 +--- a/drivers/gpu/nova-core/gpu.rs ++++ b/drivers/gpu/nova-core/gpu.rs +@@ -1,13 +1,26 @@ + // SPDX-License-Identifier: GPL-2.0 + +-use kernel::{device, devres::Devres, error::code::*, fmt, pci, prelude::*, sync::Arc}; +- +-use crate::driver::Bar0; +-use crate::falcon::{gsp::Gsp as GspFalcon, sec2::Sec2 as Sec2Falcon, Falcon}; +-use crate::fb::SysmemFlush; +-use crate::gfw; +-use crate::gsp::Gsp; +-use crate::regs; ++use kernel::{ ++ device, ++ devres::Devres, ++ fmt, ++ pci, ++ prelude::*, ++ sync::Arc, // ++}; ++ ++use crate::{ ++ driver::Bar0, ++ falcon::{ ++ gsp::Gsp as GspFalcon, ++ sec2::Sec2 as Sec2Falcon, ++ Falcon, // ++ }, ++ fb::SysmemFlush, ++ gfw, ++ gsp::Gsp, ++ regs, ++}; + + macro_rules! define_chipset { + ({ $($variant:ident = $value:expr),* $(,)* }) => +diff --git a/drivers/gpu/nova-core/gsp/boot.rs b/drivers/gpu/nova-core/gsp/boot.rs +index 2800f3aee37d0..19dddff929da4 100644 +--- a/drivers/gpu/nova-core/gsp/boot.rs ++++ b/drivers/gpu/nova-core/gsp/boot.rs +@@ -1,21 +1,35 @@ + // SPDX-License-Identifier: GPL-2.0 + +-use kernel::device; +-use kernel::pci; +-use kernel::prelude::*; +- +-use crate::driver::Bar0; +-use crate::falcon::{gsp::Gsp, sec2::Sec2, Falcon}; +-use crate::fb::FbLayout; +-use crate::firmware::{ +- booter::{BooterFirmware, BooterKind}, +- fwsec::{FwsecCommand, FwsecFirmware}, +- gsp::GspFirmware, +- FIRMWARE_VERSION, ++use kernel::{ ++ device, ++ pci, ++ prelude::*, // ++}; ++ ++use crate::{ ++ driver::Bar0, ++ falcon::{ ++ gsp::Gsp, ++ sec2::Sec2, ++ Falcon, // ++ }, ++ fb::FbLayout, ++ firmware::{ ++ booter::{ ++ BooterFirmware, ++ BooterKind, // ++ }, ++ fwsec::{ ++ FwsecCommand, ++ FwsecFirmware, // ++ }, ++ gsp::GspFirmware, ++ FIRMWARE_VERSION, // ++ }, ++ gpu::Chipset, ++ regs, ++ vbios::Vbios, + }; +-use crate::gpu::Chipset; +-use crate::regs; +-use crate::vbios::Vbios; + + impl super::Gsp { + /// Helper function to load and run the FWSEC-FRTS firmware and confirm that it has properly +diff --git a/drivers/gpu/nova-core/regs.rs b/drivers/gpu/nova-core/regs.rs +index 206dab2e13351..7cd2e8a4d4c6f 100644 +--- a/drivers/gpu/nova-core/regs.rs ++++ b/drivers/gpu/nova-core/regs.rs +@@ -7,13 +7,27 @@ + #[macro_use] + pub(crate) mod macros; + +-use crate::falcon::{ +- DmaTrfCmdSize, FalconCoreRev, FalconCoreRevSubversion, FalconFbifMemType, FalconFbifTarget, +- FalconModSelAlgo, FalconSecurityModel, PFalcon2Base, PFalconBase, PeregrineCoreSelect, +-}; +-use crate::gpu::{Architecture, Chipset}; + use kernel::prelude::*; + ++use crate::{ ++ falcon::{ ++ DmaTrfCmdSize, ++ FalconCoreRev, ++ FalconCoreRevSubversion, ++ FalconFbifMemType, ++ FalconFbifTarget, ++ FalconModSelAlgo, ++ FalconSecurityModel, ++ PFalcon2Base, ++ PFalconBase, ++ PeregrineCoreSelect, // ++ }, ++ gpu::{ ++ Architecture, ++ Chipset, // ++ }, ++}; ++ + // PMC + + register!(NV_PMC_BOOT_0 @ 0x00000000, "Basic revision information about the GPU" { +diff --git a/drivers/gpu/nova-core/vbios.rs b/drivers/gpu/nova-core/vbios.rs +index 0dfefad88cc6a..cc949e5ee2836 100644 +--- a/drivers/gpu/nova-core/vbios.rs ++++ b/drivers/gpu/nova-core/vbios.rs +@@ -2,16 +2,26 @@ + + //! VBIOS extraction and parsing. + +-use crate::driver::Bar0; +-use crate::firmware::fwsec::Bcrt30Rsa3kSignature; +-use crate::firmware::FalconUCodeDescV3; + use core::convert::TryFrom; +-use kernel::device; +-use kernel::error::Result; +-use kernel::prelude::*; +-use kernel::ptr::{Alignable, Alignment}; +-use kernel::transmute::FromBytes; +-use kernel::types::ARef; ++ ++use kernel::{ ++ device, ++ prelude::*, ++ ptr::{ ++ Alignable, ++ Alignment, // ++ }, ++ transmute::FromBytes, ++ types::ARef, ++}; ++ ++use crate::{ ++ driver::Bar0, ++ firmware::{ ++ fwsec::Bcrt30Rsa3kSignature, ++ FalconUCodeDescV3, // ++ }, ++}; + + /// The offset of the VBIOS ROM in the BAR0 space. + const ROM_OFFSET: usize = 0x300000; +-- +2.51.0 + diff --git a/queue-6.18/gpu-nova-core-check-for-overflow-to-dmatrfbase1.patch b/queue-6.18/gpu-nova-core-check-for-overflow-to-dmatrfbase1.patch new file mode 100644 index 0000000000..91c42236bc --- /dev/null +++ b/queue-6.18/gpu-nova-core-check-for-overflow-to-dmatrfbase1.patch @@ -0,0 +1,57 @@ +From 29e3db038507de6437b8ed000c8efc1116a909b8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 14:16:46 -0600 +Subject: gpu: nova-core: check for overflow to DMATRFBASE1 + +From: Timur Tabi + +[ Upstream commit 5cf76277cdec872aef9ff2e9008ae129bb303787 ] + +The NV_PFALCON_FALCON_DMATRFBASE/1 register pair supports DMA addresses +up to 49 bits only, but the write to DMATRFBASE1 could exceed that. +To mitigate, check first that the DMA address will fit. + +Reviewed-by: John Hubbard +Reviewed-by: Joel Fernandes +Fixes: 69f5cd67ce41 ("gpu: nova-core: add falcon register definitions and base code") +Signed-off-by: Timur Tabi +Link: https://patch.msgid.link/20260107201647.2490140-1-ttabi@nvidia.com +[ Import ::kernel::dma::DmaMask. - Danilo ] +Signed-off-by: Danilo Krummrich +Signed-off-by: Sasha Levin +--- + drivers/gpu/nova-core/falcon.rs | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon.rs +index 3fa2c9cfa2d7f..02a37a7e5ddab 100644 +--- a/drivers/gpu/nova-core/falcon.rs ++++ b/drivers/gpu/nova-core/falcon.rs +@@ -8,7 +8,10 @@ + + use kernel::{ + device, +- dma::DmaAddress, ++ dma::{ ++ DmaAddress, ++ DmaMask, // ++ }, + io::poll::read_poll_timeout, + prelude::*, + sync::aref::ARef, +@@ -470,6 +473,12 @@ fn dma_wr>( + return Err(EINVAL); + } + ++ // The DMATRFBASE/1 register pair only supports a 49-bit address. ++ if dma_start > DmaMask::new::<49>().value() { ++ dev_err!(self.dev, "DMA address {:#x} exceeds 49 bits\n", dma_start); ++ return Err(ERANGE); ++ } ++ + // DMA transfers can only be done in units of 256 bytes. Compute how many such transfers we + // need to perform. + let num_transfers = load_offsets.len.div_ceil(DMA_LEN); +-- +2.51.0 + diff --git a/queue-6.18/gpu-nova-core-replace-as-with-from-conversions-where.patch b/queue-6.18/gpu-nova-core-replace-as-with-from-conversions-where.patch new file mode 100644 index 0000000000..489ec14c89 --- /dev/null +++ b/queue-6.18/gpu-nova-core-replace-as-with-from-conversions-where.patch @@ -0,0 +1,197 @@ +From 9fed3df8a0ba9bb291cee42438a0887538f4c608 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Oct 2025 08:12:09 +0900 +Subject: gpu: nova-core: replace `as` with `from` conversions where possible + +From: Alexandre Courbot + +[ Upstream commit 9a3c2f8a4f84960a48c056d0da88de3d09e6d622 ] + +The `as` operator is best avoided as it silently drops bits if the +destination type is smaller that the source. + +For data types where this is clearly not the case, use `from` to +unambiguously signal that these conversions are lossless. + +Acked-by: Danilo Krummrich +Signed-off-by: Alexandre Courbot +Message-ID: <20251029-nova-as-v3-1-6a30c7333ad9@nvidia.com> +Stable-dep-of: 5cf76277cdec ("gpu: nova-core: check for overflow to DMATRFBASE1") +Signed-off-by: Sasha Levin +--- + drivers/gpu/nova-core/falcon/hal/ga102.rs | 6 ++-- + drivers/gpu/nova-core/firmware/fwsec.rs | 4 +-- + drivers/gpu/nova-core/vbios.rs | 42 +++++++++++------------ + 3 files changed, 25 insertions(+), 27 deletions(-) + +diff --git a/drivers/gpu/nova-core/falcon/hal/ga102.rs b/drivers/gpu/nova-core/falcon/hal/ga102.rs +index f2ae9537321d0..afed353b24d29 100644 +--- a/drivers/gpu/nova-core/falcon/hal/ga102.rs ++++ b/drivers/gpu/nova-core/falcon/hal/ga102.rs +@@ -40,11 +40,9 @@ fn signature_reg_fuse_version_ga102( + engine_id_mask: u16, + ucode_id: u8, + ) -> Result { +- const NV_FUSE_OPT_FPF_SIZE: u8 = regs::NV_FUSE_OPT_FPF_SIZE as u8; +- + // Each engine has 16 ucode version registers numbered from 1 to 16. +- let ucode_idx = match ucode_id { +- 1..=NV_FUSE_OPT_FPF_SIZE => (ucode_id - 1) as usize, ++ let ucode_idx = match usize::from(ucode_id) { ++ ucode_id @ 1..=regs::NV_FUSE_OPT_FPF_SIZE => ucode_id - 1, + _ => { + dev_err!(dev, "invalid ucode id {:#x}", ucode_id); + return Err(EINVAL); +diff --git a/drivers/gpu/nova-core/firmware/fwsec.rs b/drivers/gpu/nova-core/firmware/fwsec.rs +index 8edbb5c0572c9..dd3420aaa2bf2 100644 +--- a/drivers/gpu/nova-core/firmware/fwsec.rs ++++ b/drivers/gpu/nova-core/firmware/fwsec.rs +@@ -259,13 +259,13 @@ fn new_fwsec(dev: &Device, bios: &Vbios, cmd: FwsecCommand) -> Re + } + + // Find the DMEM mapper section in the firmware. +- for i in 0..hdr.entry_count as usize { ++ for i in 0..usize::from(hdr.entry_count) { + let app: &FalconAppifV1 = + // SAFETY: we have exclusive access to `dma_object`. + unsafe { + transmute( + &dma_object, +- hdr_offset + hdr.header_size as usize + i * hdr.entry_size as usize ++ hdr_offset + usize::from(hdr.header_size) + i * usize::from(hdr.entry_size) + ) + }?; + +diff --git a/drivers/gpu/nova-core/vbios.rs b/drivers/gpu/nova-core/vbios.rs +index 71fbe71b84db9..42ac83365e9b3 100644 +--- a/drivers/gpu/nova-core/vbios.rs ++++ b/drivers/gpu/nova-core/vbios.rs +@@ -328,7 +328,7 @@ fn is_last(&self) -> bool { + + /// Calculate image size in bytes from 512-byte blocks. + fn image_size_bytes(&self) -> usize { +- self.image_len as usize * 512 ++ usize::from(self.image_len) * 512 + } + } + +@@ -406,13 +406,13 @@ fn from_id(image: &PciAtBiosImage, token_id: u8) -> Result { + let header = &image.bit_header; + + // Offset to the first token entry +- let tokens_start = image.bit_offset + header.header_size as usize; ++ let tokens_start = image.bit_offset + usize::from(header.header_size); + +- for i in 0..header.token_entries as usize { +- let entry_offset = tokens_start + (i * header.token_size as usize); ++ for i in 0..usize::from(header.token_entries) { ++ let entry_offset = tokens_start + (i * usize::from(header.token_size)); + + // Make sure we don't go out of bounds +- if entry_offset + header.token_size as usize > image.base.data.len() { ++ if entry_offset + usize::from(header.token_size) > image.base.data.len() { + return Err(EINVAL); + } + +@@ -568,7 +568,7 @@ fn is_last(&self) -> bool { + + /// Calculate image size in bytes from 512-byte blocks. + fn image_size_bytes(&self) -> usize { +- self.subimage_len as usize * 512 ++ usize::from(self.subimage_len) * 512 + } + + /// Try to find NPDE in the data, the NPDE is right after the PCIR. +@@ -580,8 +580,8 @@ fn find_in_data( + ) -> Option { + // Calculate the offset where NPDE might be located + // NPDE should be right after the PCIR structure, aligned to 16 bytes +- let pcir_offset = rom_header.pci_data_struct_offset as usize; +- let npde_start = (pcir_offset + pcir.pci_data_struct_len as usize + 0x0F) & !0x0F; ++ let pcir_offset = usize::from(rom_header.pci_data_struct_offset); ++ let npde_start = (pcir_offset + usize::from(pcir.pci_data_struct_len) + 0x0F) & !0x0F; + + // Check if we have enough data + if npde_start + core::mem::size_of::() > data.len() { +@@ -775,7 +775,7 @@ fn new(dev: &device::Device, data: &[u8]) -> Result { + .inspect_err(|e| dev_err!(dev, "Failed to create PciRomHeader: {:?}\n", e))?; + + // Get the PCI Data Structure using the pointer from the ROM header. +- let pcir_offset = rom_header.pci_data_struct_offset as usize; ++ let pcir_offset = usize::from(rom_header.pci_data_struct_offset); + let pcir_data = data + .get(pcir_offset..pcir_offset + core::mem::size_of::()) + .ok_or(EINVAL) +@@ -843,12 +843,12 @@ fn falcon_data_ptr(&self) -> Result { + let token = self.get_bit_token(BIT_TOKEN_ID_FALCON_DATA)?; + + // Make sure we don't go out of bounds +- if token.data_offset as usize + 4 > self.base.data.len() { ++ if usize::from(token.data_offset) + 4 > self.base.data.len() { + return Err(EINVAL); + } + + // read the 4 bytes at the offset specified in the token +- let offset = token.data_offset as usize; ++ let offset = usize::from(token.data_offset); + let bytes: [u8; 4] = self.base.data[offset..offset + 4].try_into().map_err(|_| { + dev_err!(self.base.dev, "Failed to convert data slice to array"); + EINVAL +@@ -924,9 +924,9 @@ fn new(dev: &device::Device, data: &[u8]) -> Result { + return Err(EINVAL); + } + +- let header_len = data[1] as usize; +- let entry_len = data[2] as usize; +- let entry_count = data[3] as usize; ++ let header_len = usize::from(data[1]); ++ let entry_len = usize::from(data[2]); ++ let entry_count = usize::from(data[3]); + + let required_bytes = header_len + (entry_count * entry_len); + +@@ -949,9 +949,9 @@ fn new(dev: &device::Device, data: &[u8]) -> Result { + + Ok(PmuLookupTable { + version: data[0], +- header_len: header_len as u8, +- entry_len: entry_len as u8, +- entry_count: entry_count as u8, ++ header_len: data[1], ++ entry_len: data[2], ++ entry_count: data[3], + table_data, + }) + } +@@ -961,7 +961,7 @@ fn lookup_index(&self, idx: u8) -> Result { + return Err(EINVAL); + } + +- let index = (idx as usize) * self.entry_len as usize; ++ let index = (usize::from(idx)) * usize::from(self.entry_len); + PmuLookupTableEntry::new(&self.table_data[index..]) + } + +@@ -1130,8 +1130,8 @@ pub(crate) fn ucode(&self, desc: &FalconUCodeDescV3) -> Result<&[u8]> { + pub(crate) fn sigs(&self, desc: &FalconUCodeDescV3) -> Result<&[Bcrt30Rsa3kSignature]> { + // The signatures data follows the descriptor. + let sigs_data_offset = self.falcon_ucode_offset + core::mem::size_of::(); +- let sigs_size = +- desc.signature_count as usize * core::mem::size_of::(); ++ let sigs_count = usize::from(desc.signature_count); ++ let sigs_size = sigs_count * core::mem::size_of::(); + + // Make sure the data is within bounds. + if sigs_data_offset + sigs_size > self.base.data.len() { +@@ -1151,7 +1151,7 @@ pub(crate) fn sigs(&self, desc: &FalconUCodeDescV3) -> Result<&[Bcrt30Rsa3kSigna + .as_ptr() + .add(sigs_data_offset) + .cast::(), +- desc.signature_count as usize, ++ sigs_count, + ) + }) + } +-- +2.51.0 + diff --git a/queue-6.18/gpu-nova-core-replace-wait_on-with-kernel-equivalent.patch b/queue-6.18/gpu-nova-core-replace-wait_on-with-kernel-equivalent.patch new file mode 100644 index 0000000000..d51b66a1c5 --- /dev/null +++ b/queue-6.18/gpu-nova-core-replace-wait_on-with-kernel-equivalent.patch @@ -0,0 +1,312 @@ +From 6a682bb901f7f96c25552107df05683a7560629c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Oct 2025 15:09:25 +0900 +Subject: gpu: nova-core: replace wait_on with kernel equivalents + +From: Alexandre Courbot + +[ Upstream commit 76544ef6a01b2d8fa86f92ff17940b6ff534696e ] + +wait_on was a temporary helper function waiting for a kernel crate +equivalent. + +Now that read_poll_timeout and fsleep are available, use them and remove +wait_on. + +Acked-by: Danilo Krummrich +Signed-off-by: Alexandre Courbot +Message-ID: <20251020-nova_wait_on-v1-1-2eb87fb38d14@nvidia.com> +Stable-dep-of: 5cf76277cdec ("gpu: nova-core: check for overflow to DMATRFBASE1") +Signed-off-by: Sasha Levin +--- + Documentation/gpu/nova/core/todo.rst | 11 ---- + drivers/gpu/nova-core/falcon.rs | 62 ++++++++++------------- + drivers/gpu/nova-core/falcon/hal/ga102.rs | 16 +++--- + drivers/gpu/nova-core/gfw.rs | 36 ++++++------- + drivers/gpu/nova-core/nova_core.rs | 1 - + drivers/gpu/nova-core/util.rs | 27 ---------- + 6 files changed, 51 insertions(+), 102 deletions(-) + delete mode 100644 drivers/gpu/nova-core/util.rs + +diff --git a/Documentation/gpu/nova/core/todo.rst b/Documentation/gpu/nova/core/todo.rst +index 0972cb905f7ae..c55c7bedbfdfa 100644 +--- a/Documentation/gpu/nova/core/todo.rst ++++ b/Documentation/gpu/nova/core/todo.rst +@@ -153,17 +153,6 @@ A `num` core kernel module is being designed to provide these operations. + | Complexity: Intermediate + | Contact: Alexandre Courbot + +-Delay / Sleep abstractions [DLAY] +---------------------------------- +- +-Rust abstractions for the kernel's delay() and sleep() functions. +- +-FUJITA Tomonori plans to work on abstractions for read_poll_timeout_atomic() +-(and friends) [1]. +- +-| Complexity: Beginner +-| Link: https://lore.kernel.org/netdev/20250228.080550.354359820929821928.fujita.tomonori@gmail.com/ [1] +- + IRQ abstractions + ---------------- + +diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon.rs +index 37e6298195e49..05856b43b51c3 100644 +--- a/drivers/gpu/nova-core/falcon.rs ++++ b/drivers/gpu/nova-core/falcon.rs +@@ -6,8 +6,10 @@ + use hal::FalconHal; + use kernel::device; + use kernel::dma::DmaAddress; ++use kernel::io::poll::read_poll_timeout; + use kernel::prelude::*; + use kernel::sync::aref::ARef; ++use kernel::time::delay::fsleep; + use kernel::time::Delta; + + use crate::dma::DmaObject; +@@ -15,7 +17,6 @@ + use crate::gpu::Chipset; + use crate::regs; + use crate::regs::macros::RegisterBase; +-use crate::util; + + pub(crate) mod gsp; + mod hal; +@@ -380,13 +381,13 @@ pub(crate) fn new( + /// Wait for memory scrubbing to complete. + fn reset_wait_mem_scrubbing(&self, bar: &Bar0) -> Result { + // TIMEOUT: memory scrubbing should complete in less than 20ms. +- util::wait_on(Delta::from_millis(20), || { +- if regs::NV_PFALCON_FALCON_HWCFG2::read(bar, &E::ID).mem_scrubbing_done() { +- Some(()) +- } else { +- None +- } +- }) ++ read_poll_timeout( ++ || Ok(regs::NV_PFALCON_FALCON_HWCFG2::read(bar, &E::ID)), ++ |r| r.mem_scrubbing_done(), ++ Delta::ZERO, ++ Delta::from_millis(20), ++ ) ++ .map(|_| ()) + } + + /// Reset the falcon engine. +@@ -395,20 +396,17 @@ fn reset_eng(&self, bar: &Bar0) -> Result { + + // According to OpenRM's `kflcnPreResetWait_GA102` documentation, HW sometimes does not set + // RESET_READY so a non-failing timeout is used. +- let _ = util::wait_on(Delta::from_micros(150), || { +- let r = regs::NV_PFALCON_FALCON_HWCFG2::read(bar, &E::ID); +- if r.reset_ready() { +- Some(()) +- } else { +- None +- } +- }); ++ let _ = read_poll_timeout( ++ || Ok(regs::NV_PFALCON_FALCON_HWCFG2::read(bar, &E::ID)), ++ |r| r.reset_ready(), ++ Delta::ZERO, ++ Delta::from_micros(150), ++ ); + + regs::NV_PFALCON_FALCON_ENGINE::alter(bar, &E::ID, |v| v.set_reset(true)); + +- // TODO[DLAY]: replace with udelay() or equivalent once available. + // TIMEOUT: falcon engine should not take more than 10us to reset. +- let _: Result = util::wait_on(Delta::from_micros(10), || None); ++ fsleep(Delta::from_micros(10)); + + regs::NV_PFALCON_FALCON_ENGINE::alter(bar, &E::ID, |v| v.set_reset(false)); + +@@ -512,14 +510,12 @@ fn dma_wr>( + // Wait for the transfer to complete. + // TIMEOUT: arbitrarily large value, no DMA transfer to the falcon's small memories + // should ever take that long. +- util::wait_on(Delta::from_secs(2), || { +- let r = regs::NV_PFALCON_FALCON_DMATRFCMD::read(bar, &E::ID); +- if r.idle() { +- Some(()) +- } else { +- None +- } +- })?; ++ read_poll_timeout( ++ || Ok(regs::NV_PFALCON_FALCON_DMATRFCMD::read(bar, &E::ID)), ++ |r| r.idle(), ++ Delta::ZERO, ++ Delta::from_secs(2), ++ )?; + } + + Ok(()) +@@ -582,14 +578,12 @@ pub(crate) fn boot( + } + + // TIMEOUT: arbitrarily large value, firmwares should complete in less than 2 seconds. +- util::wait_on(Delta::from_secs(2), || { +- let r = regs::NV_PFALCON_FALCON_CPUCTL::read(bar, &E::ID); +- if r.halted() { +- Some(()) +- } else { +- None +- } +- })?; ++ read_poll_timeout( ++ || Ok(regs::NV_PFALCON_FALCON_CPUCTL::read(bar, &E::ID)), ++ |r| r.halted(), ++ Delta::ZERO, ++ Delta::from_secs(2), ++ )?; + + let (mbox0, mbox1) = ( + regs::NV_PFALCON_FALCON_MAILBOX0::read(bar, &E::ID).value(), +diff --git a/drivers/gpu/nova-core/falcon/hal/ga102.rs b/drivers/gpu/nova-core/falcon/hal/ga102.rs +index 0b1cbe7853b3e..f2ae9537321d0 100644 +--- a/drivers/gpu/nova-core/falcon/hal/ga102.rs ++++ b/drivers/gpu/nova-core/falcon/hal/ga102.rs +@@ -3,6 +3,7 @@ + use core::marker::PhantomData; + + use kernel::device; ++use kernel::io::poll::read_poll_timeout; + use kernel::prelude::*; + use kernel::time::Delta; + +@@ -11,7 +12,6 @@ + Falcon, FalconBromParams, FalconEngine, FalconModSelAlgo, PeregrineCoreSelect, + }; + use crate::regs; +-use crate::util; + + use super::FalconHal; + +@@ -23,14 +23,12 @@ fn select_core_ga102(bar: &Bar0) -> Result { + .write(bar, &E::ID); + + // TIMEOUT: falcon core should take less than 10ms to report being enabled. +- util::wait_on(Delta::from_millis(10), || { +- let r = regs::NV_PRISCV_RISCV_BCR_CTRL::read(bar, &E::ID); +- if r.valid() { +- Some(()) +- } else { +- None +- } +- })?; ++ read_poll_timeout( ++ || Ok(regs::NV_PRISCV_RISCV_BCR_CTRL::read(bar, &E::ID)), ++ |r| r.valid(), ++ Delta::ZERO, ++ Delta::from_millis(10), ++ )?; + } + + Ok(()) +diff --git a/drivers/gpu/nova-core/gfw.rs b/drivers/gpu/nova-core/gfw.rs +index 8ac1ed1871992..23c28c2a3793a 100644 +--- a/drivers/gpu/nova-core/gfw.rs ++++ b/drivers/gpu/nova-core/gfw.rs +@@ -18,13 +18,12 @@ + //! + //! Note that the devinit sequence also needs to run during suspend/resume. + +-use kernel::bindings; ++use kernel::io::poll::read_poll_timeout; + use kernel::prelude::*; + use kernel::time::Delta; + + use crate::driver::Bar0; + use crate::regs; +-use crate::util; + + /// Wait for the `GFW` (GPU firmware) boot completion signal (`GFW_BOOT`), or a 4 seconds timeout. + /// +@@ -50,22 +49,19 @@ pub(crate) fn wait_gfw_boot_completion(bar: &Bar0) -> Result { + // + // TIMEOUT: arbitrarily large value. GFW starts running immediately after the GPU is put out of + // reset, and should complete in less time than that. +- util::wait_on(Delta::from_secs(4), || { +- // Check that FWSEC has lowered its protection level before reading the GFW_BOOT status. +- let gfw_booted = regs::NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_PRIV_LEVEL_MASK::read(bar) +- .read_protection_level0() +- && regs::NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_0_GFW_BOOT::read(bar).completed(); +- +- if gfw_booted { +- Some(()) +- } else { +- // TODO[DLAY]: replace with [1] once it merges. +- // [1] https://lore.kernel.org/rust-for-linux/20250423192857.199712-6-fujita.tomonori@gmail.com/ +- // +- // SAFETY: `msleep()` is safe to call with any parameter. +- unsafe { bindings::msleep(1) }; +- +- None +- } +- }) ++ read_poll_timeout( ++ || { ++ Ok( ++ // Check that FWSEC has lowered its protection level before reading the GFW_BOOT ++ // status. ++ regs::NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_PRIV_LEVEL_MASK::read(bar) ++ .read_protection_level0() ++ && regs::NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_0_GFW_BOOT::read(bar).completed(), ++ ) ++ }, ++ |&gfw_booted| gfw_booted, ++ Delta::from_millis(1), ++ Delta::from_secs(4), ++ ) ++ .map(|_| ()) + } +diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nova_core.rs +index fffcaee2249fe..db062e31a5e23 100644 +--- a/drivers/gpu/nova-core/nova_core.rs ++++ b/drivers/gpu/nova-core/nova_core.rs +@@ -11,7 +11,6 @@ + mod gpu; + mod gsp; + mod regs; +-mod util; + mod vbios; + + pub(crate) const MODULE_NAME: &kernel::str::CStr = ::NAME; +diff --git a/drivers/gpu/nova-core/util.rs b/drivers/gpu/nova-core/util.rs +deleted file mode 100644 +index bf35f00cb732e..0000000000000 +--- a/drivers/gpu/nova-core/util.rs ++++ /dev/null +@@ -1,27 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0 +- +-use kernel::prelude::*; +-use kernel::time::{Delta, Instant, Monotonic}; +- +-/// Wait until `cond` is true or `timeout` elapsed. +-/// +-/// When `cond` evaluates to `Some`, its return value is returned. +-/// +-/// `Err(ETIMEDOUT)` is returned if `timeout` has been reached without `cond` evaluating to +-/// `Some`. +-/// +-/// TODO[DLAY]: replace with `read_poll_timeout` once it is available. +-/// (https://lore.kernel.org/lkml/20250220070611.214262-8-fujita.tomonori@gmail.com/) +-pub(crate) fn wait_on Option>(timeout: Delta, cond: F) -> Result { +- let start_time = Instant::::now(); +- +- loop { +- if let Some(ret) = cond() { +- return Ok(ret); +- } +- +- if start_time.elapsed().as_nanos() > timeout.as_nanos() { +- return Err(ETIMEDOUT); +- } +- } +-} +-- +2.51.0 + diff --git a/queue-6.18/gpu-nova-core-vbios-use-frombytes-for-pmulookuptable.patch b/queue-6.18/gpu-nova-core-vbios-use-frombytes-for-pmulookuptable.patch new file mode 100644 index 0000000000..0d5507857a --- /dev/null +++ b/queue-6.18/gpu-nova-core-vbios-use-frombytes-for-pmulookuptable.patch @@ -0,0 +1,115 @@ +From a0fedab2fb653e4b3c6a08fe660e93d65de418a5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Oct 2025 00:07:37 +0900 +Subject: gpu: nova-core: vbios: use FromBytes for PmuLookupTable header + +From: Alexandre Courbot + +[ Upstream commit 7f74842d95d1a24c68d23320de4f3eb27e6ba82b ] + +Use `from_bytes_copy_prefix` to create the `PmuLookupTable` header +instead of building it ourselves from the bytes stream. This lets us +remove a few `as` conversions and array accesses. + +Reviewed-by: Joel Fernandes +Signed-off-by: Alexandre Courbot +Message-ID: <20251029-nova-vbios-frombytes-v1-2-ac441ebc1de3@nvidia.com> +Stable-dep-of: 5cf76277cdec ("gpu: nova-core: check for overflow to DMATRFBASE1") +Signed-off-by: Sasha Levin +--- + drivers/gpu/nova-core/vbios.rs | 42 +++++++++++++++++----------------- + 1 file changed, 21 insertions(+), 21 deletions(-) + +diff --git a/drivers/gpu/nova-core/vbios.rs b/drivers/gpu/nova-core/vbios.rs +index 42ac83365e9b3..0dfefad88cc6a 100644 +--- a/drivers/gpu/nova-core/vbios.rs ++++ b/drivers/gpu/nova-core/vbios.rs +@@ -10,6 +10,7 @@ + use kernel::error::Result; + use kernel::prelude::*; + use kernel::ptr::{Alignable, Alignment}; ++use kernel::transmute::FromBytes; + use kernel::types::ARef; + + /// The offset of the VBIOS ROM in the BAR0 space. +@@ -904,29 +905,34 @@ fn new(data: &[u8]) -> Result { + } + } + ++#[repr(C)] ++struct PmuLookupTableHeader { ++ version: u8, ++ header_len: u8, ++ entry_len: u8, ++ entry_count: u8, ++} ++ ++// SAFETY: all bit patterns are valid for `PmuLookupTableHeader`. ++unsafe impl FromBytes for PmuLookupTableHeader {} ++ + /// The [`PmuLookupTableEntry`] structure is used to find the [`PmuLookupTableEntry`] for a given + /// application ID. + /// + /// The table of entries is pointed to by the falcon data pointer in the BIT table, and is used to + /// locate the Falcon Ucode. +-#[expect(dead_code)] + struct PmuLookupTable { +- version: u8, +- header_len: u8, +- entry_len: u8, +- entry_count: u8, ++ header: PmuLookupTableHeader, + table_data: KVec, + } + + impl PmuLookupTable { + fn new(dev: &device::Device, data: &[u8]) -> Result { +- if data.len() < 4 { +- return Err(EINVAL); +- } ++ let (header, _) = PmuLookupTableHeader::from_bytes_copy_prefix(data).ok_or(EINVAL)?; + +- let header_len = usize::from(data[1]); +- let entry_len = usize::from(data[2]); +- let entry_count = usize::from(data[3]); ++ let header_len = usize::from(header.header_len); ++ let entry_len = usize::from(header.entry_len); ++ let entry_count = usize::from(header.entry_count); + + let required_bytes = header_len + (entry_count * entry_len); + +@@ -947,27 +953,21 @@ fn new(dev: &device::Device, data: &[u8]) -> Result { + dev_dbg!(dev, "PMU entry: {:02x?}\n", &data[i..][..entry_len]); + } + +- Ok(PmuLookupTable { +- version: data[0], +- header_len: data[1], +- entry_len: data[2], +- entry_count: data[3], +- table_data, +- }) ++ Ok(PmuLookupTable { header, table_data }) + } + + fn lookup_index(&self, idx: u8) -> Result { +- if idx >= self.entry_count { ++ if idx >= self.header.entry_count { + return Err(EINVAL); + } + +- let index = (usize::from(idx)) * usize::from(self.entry_len); ++ let index = (usize::from(idx)) * usize::from(self.header.entry_len); + PmuLookupTableEntry::new(&self.table_data[index..]) + } + + // find entry by type value + fn find_entry_by_type(&self, entry_type: u8) -> Result { +- for i in 0..self.entry_count { ++ for i in 0..self.header.entry_count { + let entry = self.lookup_index(i)?; + if entry.application_id == entry_type { + return Ok(entry); +-- +2.51.0 + diff --git a/queue-6.18/hfsplus-return-error-when-node-already-exists-in-hfs.patch b/queue-6.18/hfsplus-return-error-when-node-already-exists-in-hfs.patch new file mode 100644 index 0000000000..1055826bc2 --- /dev/null +++ b/queue-6.18/hfsplus-return-error-when-node-already-exists-in-hfs.patch @@ -0,0 +1,58 @@ +From a387b59ee7cf9f2e5e82ce17d9eba07e8b37eba1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Dec 2025 02:19:38 +0530 +Subject: hfsplus: return error when node already exists in hfs_bnode_create + +From: Shardul Bankar + +[ Upstream commit d8a73cc46c8462a969a7516131feb3096f4c49d3 ] + +When hfs_bnode_create() finds that a node is already hashed (which should +not happen in normal operation), it currently returns the existing node +without incrementing its reference count. This causes a reference count +inconsistency that leads to a kernel panic when the node is later freed +in hfs_bnode_put(): + + kernel BUG at fs/hfsplus/bnode.c:676! + BUG_ON(!atomic_read(&node->refcnt)) + +This scenario can occur when hfs_bmap_alloc() attempts to allocate a node +that is already in use (e.g., when node 0's bitmap bit is incorrectly +unset), or due to filesystem corruption. + +Returning an existing node from a create path is not normal operation. + +Fix this by returning ERR_PTR(-EEXIST) instead of the node when it's +already hashed. This properly signals the error condition to callers, +which already check for IS_ERR() return values. + +Reported-by: syzbot+1c8ff72d0cd8a50dfeaa@syzkaller.appspotmail.com +Link: https://syzkaller.appspot.com/bug?extid=1c8ff72d0cd8a50dfeaa +Link: https://lore.kernel.org/all/784415834694f39902088fa8946850fc1779a318.camel@ibm.com/ +Fixes: 634725a92938 ("[PATCH] hfs: cleanup HFS+ prints") +Signed-off-by: Shardul Bankar +Reviewed-by: Viacheslav Dubeyko +Signed-off-by: Viacheslav Dubeyko +Link: https://lore.kernel.org/r/20251229204938.1907089-1-shardul.b@mpiricsoftware.com +Signed-off-by: Viacheslav Dubeyko +Signed-off-by: Sasha Levin +--- + fs/hfsplus/bnode.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/hfsplus/bnode.c b/fs/hfsplus/bnode.c +index 482a6c5faa197..8e60e04c427bd 100644 +--- a/fs/hfsplus/bnode.c ++++ b/fs/hfsplus/bnode.c +@@ -629,7 +629,7 @@ struct hfs_bnode *hfs_bnode_create(struct hfs_btree *tree, u32 num) + if (node) { + pr_crit("new node %u already hashed?\n", num); + WARN_ON(1); +- return node; ++ return ERR_PTR(-EEXIST); + } + node = __hfs_bnode_create(tree, num); + if (!node) +-- +2.51.0 + diff --git a/queue-6.18/hid-intel-ish-hid-fix-null-ptr-deref-in-ishtp_bus_re.patch b/queue-6.18/hid-intel-ish-hid-fix-null-ptr-deref-in-ishtp_bus_re.patch new file mode 100644 index 0000000000..98205d5b59 --- /dev/null +++ b/queue-6.18/hid-intel-ish-hid-fix-null-ptr-deref-in-ishtp_bus_re.patch @@ -0,0 +1,50 @@ +From b85a5c23dd5335bab5e47927eb666d0086c4ce12 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 13:34:56 +0800 +Subject: HID: intel-ish-hid: fix NULL-ptr-deref in + ishtp_bus_remove_all_clients + +From: Ryan Lin + +[ Upstream commit 56f7db581ee73af53cd512e00a6261a025bf1d58 ] + +During a warm reset flow, the cl->device pointer may be NULL if the +reset occurs while clients are still being enumerated. Accessing +cl->device->reference_count without a NULL check leads to a kernel panic. + +This issue was identified during multi-unit warm reboot stress clycles. +Add a defensive NULL check for cl->device to ensure stability under +such intensive testing conditions. + +KASAN: null-ptr-deref in range [0000000000000000-0000000000000007] +Workqueue: ish_fw_update_wq fw_reset_work_fn + +Call Trace: + ishtp_bus_remove_all_clients+0xbe/0x130 [intel_ishtp] + ishtp_reset_handler+0x85/0x1a0 [intel_ishtp] + fw_reset_work_fn+0x8a/0xc0 [intel_ish_ipc] + +Fixes: 3703f53b99e4a ("HID: intel_ish-hid: ISH Transport layer") +Signed-off-by: Ryan Lin +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/intel-ish-hid/ishtp/bus.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/hid/intel-ish-hid/ishtp/bus.c b/drivers/hid/intel-ish-hid/ishtp/bus.c +index c3915f3a060ea..b890fbf97a75c 100644 +--- a/drivers/hid/intel-ish-hid/ishtp/bus.c ++++ b/drivers/hid/intel-ish-hid/ishtp/bus.c +@@ -730,7 +730,7 @@ void ishtp_bus_remove_all_clients(struct ishtp_device *ishtp_dev, + spin_lock_irqsave(&ishtp_dev->cl_list_lock, flags); + list_for_each_entry(cl, &ishtp_dev->cl_list, link) { + cl->state = ISHTP_CL_DISCONNECTED; +- if (warm_reset && cl->device->reference_count) ++ if (warm_reset && cl->device && cl->device->reference_count) + continue; + + /* +-- +2.51.0 + diff --git a/queue-6.18/hid-playstation-add-missing-check-for-input_ff_creat.patch b/queue-6.18/hid-playstation-add-missing-check-for-input_ff_creat.patch new file mode 100644 index 0000000000..0f7e0cbdc9 --- /dev/null +++ b/queue-6.18/hid-playstation-add-missing-check-for-input_ff_creat.patch @@ -0,0 +1,41 @@ +From 1b548ebd5303e7dbc896ca6afcc91fa7e8fa9c70 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 17 Nov 2025 16:28:08 +0800 +Subject: HID: playstation: Add missing check for input_ff_create_memless + +From: Haotian Zhang + +[ Upstream commit e6807641ac94e832988655a1c0e60ccc806b76dc ] + +The ps_gamepad_create() function calls input_ff_create_memless() +without verifying its return value, which can lead to incorrect +behavior or potential crashes when FF effects are triggered. + +Add a check for the return value of input_ff_create_memless(). + +Fixes: 51151098d7ab ("HID: playstation: add DualSense classic rumble support.") +Signed-off-by: Haotian Zhang +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-playstation.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c +index e4dfcf26b04e7..2ec6d4445e84b 100644 +--- a/drivers/hid/hid-playstation.c ++++ b/drivers/hid/hid-playstation.c +@@ -774,7 +774,9 @@ ps_gamepad_create(struct hid_device *hdev, + #if IS_ENABLED(CONFIG_PLAYSTATION_FF) + if (play_effect) { + input_set_capability(gamepad, EV_FF, FF_RUMBLE); +- input_ff_create_memless(gamepad, NULL, play_effect); ++ ret = input_ff_create_memless(gamepad, NULL, play_effect); ++ if (ret) ++ return ERR_PTR(ret); + } + #endif + +-- +2.51.0 + diff --git a/queue-6.18/hisi_acc_vfio_pci-fix-vf-reset-timeout-issue.patch b/queue-6.18/hisi_acc_vfio_pci-fix-vf-reset-timeout-issue.patch new file mode 100644 index 0000000000..a0e25a41d9 --- /dev/null +++ b/queue-6.18/hisi_acc_vfio_pci-fix-vf-reset-timeout-issue.patch @@ -0,0 +1,93 @@ +From c58b563f0c8e5fafa2ec482f64db5452233b86ac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 10:02:02 +0800 +Subject: hisi_acc_vfio_pci: fix VF reset timeout issue + +From: Weili Qian + +[ Upstream commit a22099ed7936f8e8dabbdbadd97d56047797116b ] + +If device error occurs during live migration, qemu will +reset the VF. At this time, VF reset and device reset are performed +simultaneously. The VF reset will timeout. Therefore, the QM_RESETTING +flag is used to ensure that VF reset and device reset are performed +serially. + +Fixes: b0eed085903e ("hisi_acc_vfio_pci: Add support for VFIO live migration") +Signed-off-by: Weili Qian +Link: https://lore.kernel.org/r/20260122020205.2884497-2-liulongfang@huawei.com +Signed-off-by: Alex Williamson +Signed-off-by: Sasha Levin +--- + .../vfio/pci/hisilicon/hisi_acc_vfio_pci.c | 24 +++++++++++++++++++ + .../vfio/pci/hisilicon/hisi_acc_vfio_pci.h | 2 ++ + 2 files changed, 26 insertions(+) + +diff --git a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c +index d07093d7cc3f5..ed2ae035deb16 100644 +--- a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c ++++ b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c +@@ -1169,9 +1169,32 @@ hisi_acc_vfio_pci_get_device_state(struct vfio_device *vdev, + return 0; + } + ++static void hisi_acc_vf_pci_reset_prepare(struct pci_dev *pdev) ++{ ++ struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_drvdata(pdev); ++ struct hisi_qm *qm = hisi_acc_vdev->pf_qm; ++ struct device *dev = &qm->pdev->dev; ++ u32 delay = 0; ++ ++ /* All reset requests need to be queued for processing */ ++ while (test_and_set_bit(QM_RESETTING, &qm->misc_ctl)) { ++ msleep(1); ++ if (++delay > QM_RESET_WAIT_TIMEOUT) { ++ dev_err(dev, "reset prepare failed\n"); ++ return; ++ } ++ } ++ ++ hisi_acc_vdev->set_reset_flag = true; ++} ++ + static void hisi_acc_vf_pci_aer_reset_done(struct pci_dev *pdev) + { + struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_drvdata(pdev); ++ struct hisi_qm *qm = hisi_acc_vdev->pf_qm; ++ ++ if (hisi_acc_vdev->set_reset_flag) ++ clear_bit(QM_RESETTING, &qm->misc_ctl); + + if (hisi_acc_vdev->core_device.vdev.migration_flags != + VFIO_MIGRATION_STOP_COPY) +@@ -1690,6 +1713,7 @@ static const struct pci_device_id hisi_acc_vfio_pci_table[] = { + MODULE_DEVICE_TABLE(pci, hisi_acc_vfio_pci_table); + + static const struct pci_error_handlers hisi_acc_vf_err_handlers = { ++ .reset_prepare = hisi_acc_vf_pci_reset_prepare, + .reset_done = hisi_acc_vf_pci_aer_reset_done, + .error_detected = vfio_pci_core_aer_err_detected, + }; +diff --git a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h +index 91002ceeebc18..6253fa074003e 100644 +--- a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h ++++ b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h +@@ -27,6 +27,7 @@ + + #define ERROR_CHECK_TIMEOUT 100 + #define CHECK_DELAY_TIME 100 ++#define QM_RESET_WAIT_TIMEOUT 60000 + + #define QM_SQC_VFT_BASE_SHIFT_V2 28 + #define QM_SQC_VFT_BASE_MASK_V2 GENMASK(15, 0) +@@ -110,6 +111,7 @@ struct hisi_acc_vf_migration_file { + struct hisi_acc_vf_core_device { + struct vfio_pci_core_device core_device; + u8 match_done; ++ bool set_reset_flag; + /* + * io_base is only valid when dev_opened is true, + * which is protected by open_mutex. +-- +2.51.0 + diff --git a/queue-6.18/hrtimer-fix-trace-oddity.patch b/queue-6.18/hrtimer-fix-trace-oddity.patch new file mode 100644 index 0000000000..da199d738f --- /dev/null +++ b/queue-6.18/hrtimer-fix-trace-oddity.patch @@ -0,0 +1,43 @@ +From 5c0ed5d88d1dea6cbf571c1108a0bfa2d2798bf0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 11:38:34 +0100 +Subject: hrtimer: Fix trace oddity + +From: Thomas Gleixner + +[ Upstream commit 5d6446f409da00e5a389125ddb5ce09f5bc404c9 ] + +It turns out that __run_hrtimer() will trace like: + + -0 [032] d.h2. 20705.474563: hrtimer_cancel: hrtimer=0xff2db8f77f8226e8 + -0 [032] d.h1. 20705.474563: hrtimer_expire_entry: hrtimer=0xff2db8f77f8226e8 now=20699452001850 function=tick_nohz_handler/0x0 + +Which is a bit nonsensical, the timer doesn't get canceled on +expiration. The cause is the use of the incorrect debug helper. + +Fixes: c6a2a1770245 ("hrtimer: Add tracepoint for hrtimers") +Reported-by: Peter Zijlstra (Intel) +Signed-off-by: Thomas Gleixner +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260121143208.219595606@infradead.org +Signed-off-by: Sasha Levin +--- + kernel/time/hrtimer.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c +index e618addb58641..21b6d93401480 100644 +--- a/kernel/time/hrtimer.c ++++ b/kernel/time/hrtimer.c +@@ -1742,7 +1742,7 @@ static void __run_hrtimer(struct hrtimer_cpu_base *cpu_base, + + lockdep_assert_held(&cpu_base->lock); + +- debug_deactivate(timer); ++ debug_hrtimer_deactivate(timer); + base->running = timer; + + /* +-- +2.51.0 + diff --git a/queue-6.18/hwmon-pmbus-mpq8785-fix-vout_mode-mismatch-during-id.patch b/queue-6.18/hwmon-pmbus-mpq8785-fix-vout_mode-mismatch-during-id.patch new file mode 100644 index 0000000000..9048b91ae8 --- /dev/null +++ b/queue-6.18/hwmon-pmbus-mpq8785-fix-vout_mode-mismatch-during-id.patch @@ -0,0 +1,81 @@ +From 09d4b126e0cb8ae043ecf83f93996ec90e70e868 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Feb 2026 15:26:34 +0800 +Subject: hwmon: (pmbus/mpq8785) fix VOUT_MODE mismatch during identification + +From: Carl Lee + +[ Upstream commit 9e33c1dba22431bea9b2bf48adf56859e52fc7ec ] + +When MPQ8785 reports VOUT_MODE as VID mode, mpq8785_identify() +configures the driver for direct mode. The subsequent +pmbus_identify_common() check then fails due to a mismatch +between the reported mode and the configured mode, causing +device initialization to fail. + +Override the reported VOUT_MODE to direct mode to keep the +driver configuration consistent with the reported mode and +allow successful device initialization. + +This does not change how voltages are interpreted, but avoids +a false identification failure caused by mismatched mode +handling. + +Fixes: f20b4a931130c ("hwmon: Add driver for MPS MPQ8785 Synchronous Step-Down Converter") +Signed-off-by: Carl Lee +Link: https://lore.kernel.org/r/20260210-dt-bindings-hwmon-pmbus-mpq8785-add-mpq8786-support-v3-1-84636ccfe76f@amd.com +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + drivers/hwmon/pmbus/mpq8785.c | 28 ++++++++++++++++++++++++++++ + 1 file changed, 28 insertions(+) + +diff --git a/drivers/hwmon/pmbus/mpq8785.c b/drivers/hwmon/pmbus/mpq8785.c +index 1f56aaf4dde80..87bd039c77b9b 100644 +--- a/drivers/hwmon/pmbus/mpq8785.c ++++ b/drivers/hwmon/pmbus/mpq8785.c +@@ -47,6 +47,33 @@ static int mpq8785_identify(struct i2c_client *client, + return 0; + }; + ++static int mpq8785_read_byte_data(struct i2c_client *client, int page, int reg) ++{ ++ int ret; ++ ++ switch (reg) { ++ case PMBUS_VOUT_MODE: ++ ret = pmbus_read_byte_data(client, page, reg); ++ if (ret < 0) ++ return ret; ++ ++ if ((ret >> 5) == 1) { ++ /* ++ * The MPQ8785 chip reports VOUT_MODE as VID mode, but the driver ++ * treats VID as direct mode. Without this, identification would fail ++ * due to mode mismatch. ++ * This override ensures the reported mode matches the driver ++ * configuration, allowing successful initialization. ++ */ ++ return PB_VOUT_MODE_DIRECT; ++ } ++ ++ return ret; ++ default: ++ return -ENODATA; ++ } ++} ++ + static int mpm82504_read_word_data(struct i2c_client *client, int page, + int phase, int reg) + { +@@ -129,6 +156,7 @@ static int mpq8785_probe(struct i2c_client *client) + break; + case mpq8785: + info->identify = mpq8785_identify; ++ info->read_byte_data = mpq8785_read_byte_data; + break; + default: + return -ENODEV; +-- +2.51.0 + diff --git a/queue-6.18/hwrng-airoha-set-rng-quality-to-900.patch b/queue-6.18/hwrng-airoha-set-rng-quality-to-900.patch new file mode 100644 index 0000000000..5a72f30358 --- /dev/null +++ b/queue-6.18/hwrng-airoha-set-rng-quality-to-900.patch @@ -0,0 +1,67 @@ +From b2e55a16621964378ab04e5926887041fe3f8f2f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Jan 2026 21:41:49 +0100 +Subject: hwrng: airoha - set rng quality to 900 + +From: Aleksander Jan Bajkowski + +[ Upstream commit c0008a29a006091d7f9d288620c2456afa23ff27 ] + +Airoha uses RAW mode to collect noise from the TRNG. These appear to +be unprocessed oscillations from the tero loop. For this reason, they +do not have a perfect distribution and entropy. Simple noise compression +reduces its size by 9%, so setting the quality to 900 seems reasonable. +The same value is used by the downstream driver. + +Compare the size before and after compression: +$ ls -l random_airoha* +-rw-r--r-- 1 aleksander aleksander 76546048 Jan 3 23:43 random_airoha +-rw-rw-r-- 1 aleksander aleksander 69783562 Jan 5 20:23 random_airoha.zip + +FIPS test results: +$ cat random_airoha | rngtest -c 10000 +rngtest 2.6 +Copyright (c) 2004 by Henrique de Moraes Holschuh +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +rngtest: starting FIPS tests... +rngtest: bits received from input: 200000032 +rngtest: FIPS 140-2 successes: 0 +rngtest: FIPS 140-2 failures: 10000 +rngtest: FIPS 140-2(2001-10-10) Monobit: 9957 +rngtest: FIPS 140-2(2001-10-10) Poker: 10000 +rngtest: FIPS 140-2(2001-10-10) Runs: 10000 +rngtest: FIPS 140-2(2001-10-10) Long run: 4249 +rngtest: FIPS 140-2(2001-10-10) Continuous run: 0 +rngtest: input channel speed: (min=953.674; avg=27698.935; max=19073.486)Mibits/s +rngtest: FIPS tests speed: (min=59.791; avg=298.028; max=328.853)Mibits/s +rngtest: Program run time: 647638 microseconds + +In general, these data look like real noise, but with lower entropy +than expected. + +Fixes: e53ca8efcc5e ("hwrng: airoha - add support for Airoha EN7581 TRNG") +Suggested-by: Benjamin Larsson +Signed-off-by: Aleksander Jan Bajkowski +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/char/hw_random/airoha-trng.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/char/hw_random/airoha-trng.c b/drivers/char/hw_random/airoha-trng.c +index 1dbfa9505c214..9a648f6d9fd40 100644 +--- a/drivers/char/hw_random/airoha-trng.c ++++ b/drivers/char/hw_random/airoha-trng.c +@@ -212,6 +212,7 @@ static int airoha_trng_probe(struct platform_device *pdev) + trng->rng.init = airoha_trng_init; + trng->rng.cleanup = airoha_trng_cleanup; + trng->rng.read = airoha_trng_read; ++ trng->rng.quality = 900; + + ret = devm_hwrng_register(dev, &trng->rng); + if (ret) { +-- +2.51.0 + diff --git a/queue-6.18/hwrng-core-allow-runtime-disabling-of-the-hw-rng.patch b/queue-6.18/hwrng-core-allow-runtime-disabling-of-the-hw-rng.patch new file mode 100644 index 0000000000..6bbcddbfad --- /dev/null +++ b/queue-6.18/hwrng-core-allow-runtime-disabling-of-the-hw-rng.patch @@ -0,0 +1,95 @@ +From 1bc95f324da4c2f201d4158a5635884db1d656e9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 23 Sep 2025 14:33:05 +0100 +Subject: hwrng: core - Allow runtime disabling of the HW RNG + +From: Jonathan McDowell + +[ Upstream commit e74b96d77da9eb5ee1b603c937c2adab5134a04b ] + +The HW RNG core allows for manual selection of which RNG device to use, +but does not allow for no device to be enabled. It may be desirable to +do this on systems with only a single suitable hardware RNG, where we +need exclusive access to other functionality on this device. In +particular when performing TPM firmware upgrades this lets us ensure the +kernel does not try to access the device. + +Before: + +root@debian-qemu-efi:~# grep "" /sys/devices/virtual/misc/hw_random/rng_* +/sys/devices/virtual/misc/hw_random/rng_available:tpm-rng-0 +/sys/devices/virtual/misc/hw_random/rng_current:tpm-rng-0 +/sys/devices/virtual/misc/hw_random/rng_quality:1024 +/sys/devices/virtual/misc/hw_random/rng_selected:0 + +After: + +root@debian-qemu-efi:~# grep "" /sys/devices/virtual/misc/hw_random/rng_* +/sys/devices/virtual/misc/hw_random/rng_available:tpm-rng-0 none +/sys/devices/virtual/misc/hw_random/rng_current:tpm-rng-0 +/sys/devices/virtual/misc/hw_random/rng_quality:1024 +/sys/devices/virtual/misc/hw_random/rng_selected:0 + +root@debian-qemu-efi:~# echo none > /sys/devices/virtual/misc/hw_random/rng_current +root@debian-qemu-efi:~# grep "" /sys/devices/virtual/misc/hw_random/rng_* +/sys/devices/virtual/misc/hw_random/rng_available:tpm-rng-0 none +/sys/devices/virtual/misc/hw_random/rng_current:none +grep: /sys/devices/virtual/misc/hw_random/rng_quality: No such device +/sys/devices/virtual/misc/hw_random/rng_selected:1 + +(Observe using bpftrace no calls to TPM being made) + +root@debian-qemu-efi:~# echo "" > /sys/devices/virtual/misc/hw_random/rng_current +root@debian-qemu-efi:~# grep "" /sys/devices/virtual/misc/hw_random/rng_* +/sys/devices/virtual/misc/hw_random/rng_available:tpm-rng-0 none +/sys/devices/virtual/misc/hw_random/rng_current:tpm-rng-0 +/sys/devices/virtual/misc/hw_random/rng_quality:1024 +/sys/devices/virtual/misc/hw_random/rng_selected:0 + +(Observe using bpftrace that calls to the TPM resume) + +Signed-off-by: Jonathan McDowell +Signed-off-by: Herbert Xu +Stable-dep-of: cc2f39d6ac48 ("hwrng: core - use RCU and work_struct to fix race condition") +Signed-off-by: Sasha Levin +--- + drivers/char/hw_random/core.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c +index 018316f546215..56d888bebe0c0 100644 +--- a/drivers/char/hw_random/core.c ++++ b/drivers/char/hw_random/core.c +@@ -341,6 +341,9 @@ static ssize_t rng_current_store(struct device *dev, + + if (sysfs_streq(buf, "")) { + err = enable_best_rng(); ++ } else if (sysfs_streq(buf, "none")) { ++ cur_rng_set_by_user = 1; ++ drop_current_rng(); + } else { + list_for_each_entry(rng, &rng_list, list) { + if (sysfs_streq(rng->name, buf)) { +@@ -392,7 +395,7 @@ static ssize_t rng_available_show(struct device *dev, + strlcat(buf, rng->name, PAGE_SIZE); + strlcat(buf, " ", PAGE_SIZE); + } +- strlcat(buf, "\n", PAGE_SIZE); ++ strlcat(buf, "none\n", PAGE_SIZE); + mutex_unlock(&rng_mutex); + + return strlen(buf); +@@ -544,8 +547,8 @@ int hwrng_register(struct hwrng *rng) + /* Adjust quality field to always have a proper value */ + rng->quality = min_t(u16, min_t(u16, default_quality, 1024), rng->quality ?: 1024); + +- if (!current_rng || +- (!cur_rng_set_by_user && rng->quality > current_rng->quality)) { ++ if (!cur_rng_set_by_user && ++ (!current_rng || rng->quality > current_rng->quality)) { + /* + * Set new rng as current as the new rng source + * provides better entropy quality and was not +-- +2.51.0 + diff --git a/queue-6.18/hwrng-core-use-rcu-and-work_struct-to-fix-race-condi.patch b/queue-6.18/hwrng-core-use-rcu-and-work_struct-to-fix-race-condi.patch new file mode 100644 index 0000000000..22ed4a24a5 --- /dev/null +++ b/queue-6.18/hwrng-core-use-rcu-and-work_struct-to-fix-race-condi.patch @@ -0,0 +1,446 @@ +From 8d723d1d09d70b6ba6c4577f80fd746e5b98114b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 06:50:16 +0900 +Subject: hwrng: core - use RCU and work_struct to fix race condition + +From: Lianjie Wang + +[ Upstream commit cc2f39d6ac48e6e3cb2d6240bc0d6df839dd0828 ] + +Currently, hwrng_fill is not cleared until the hwrng_fillfn() thread +exits. Since hwrng_unregister() reads hwrng_fill outside the rng_mutex +lock, a concurrent hwrng_unregister() may call kthread_stop() again on +the same task. + +Additionally, if hwrng_unregister() is called immediately after +hwrng_register(), the stopped thread may have never been executed. Thus, +hwrng_fill remains dirty even after hwrng_unregister() returns. In this +case, subsequent calls to hwrng_register() will fail to start new +threads, and hwrng_unregister() will call kthread_stop() on the same +freed task. In both cases, a use-after-free occurs: + +refcount_t: addition on 0; use-after-free. +WARNING: ... at lib/refcount.c:25 refcount_warn_saturate+0xec/0x1c0 +Call Trace: + kthread_stop+0x181/0x360 + hwrng_unregister+0x288/0x380 + virtrng_remove+0xe3/0x200 + +This patch fixes the race by protecting the global hwrng_fill pointer +inside the rng_mutex lock, so that hwrng_fillfn() thread is stopped only +once, and calls to kthread_run() and kthread_stop() are serialized +with the lock held. + +To avoid deadlock in hwrng_fillfn() while being stopped with the lock +held, we convert current_rng to RCU, so that get_current_rng() can read +current_rng without holding the lock. To remove the lock from put_rng(), +we also delay the actual cleanup into a work_struct. + +Since get_current_rng() no longer returns ERR_PTR values, the IS_ERR() +checks are removed from its callers. + +With hwrng_fill protected by the rng_mutex lock, hwrng_fillfn() can no +longer clear hwrng_fill itself. Therefore, if hwrng_fillfn() returns +directly after current_rng is dropped, kthread_stop() would be called on +a freed task_struct later. To fix this, hwrng_fillfn() calls schedule() +now to keep the task alive until being stopped. The kthread_stop() call +is also moved from hwrng_unregister() to drop_current_rng(), ensuring +kthread_stop() is called on all possible paths where current_rng becomes +NULL, so that the thread would not wait forever. + +Fixes: be4000bc4644 ("hwrng: create filler thread") +Suggested-by: Herbert Xu +Signed-off-by: Lianjie Wang +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/char/hw_random/core.c | 168 +++++++++++++++++++++------------- + include/linux/hw_random.h | 2 + + 2 files changed, 107 insertions(+), 63 deletions(-) + +diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c +index 56d888bebe0c0..036de7294bbda 100644 +--- a/drivers/char/hw_random/core.c ++++ b/drivers/char/hw_random/core.c +@@ -20,23 +20,25 @@ + #include + #include + #include ++#include + #include + #include + #include + #include + #include ++#include + + #define RNG_MODULE_NAME "hw_random" + + #define RNG_BUFFER_SIZE (SMP_CACHE_BYTES < 32 ? 32 : SMP_CACHE_BYTES) + +-static struct hwrng *current_rng; ++static struct hwrng __rcu *current_rng; + /* the current rng has been explicitly chosen by user via sysfs */ + static int cur_rng_set_by_user; + static struct task_struct *hwrng_fill; + /* list of registered rngs */ + static LIST_HEAD(rng_list); +-/* Protects rng_list and current_rng */ ++/* Protects rng_list, hwrng_fill and updating on current_rng */ + static DEFINE_MUTEX(rng_mutex); + /* Protects rng read functions, data_avail, rng_buffer and rng_fillbuf */ + static DEFINE_MUTEX(reading_mutex); +@@ -64,18 +66,39 @@ static size_t rng_buffer_size(void) + return RNG_BUFFER_SIZE; + } + +-static inline void cleanup_rng(struct kref *kref) ++static void cleanup_rng_work(struct work_struct *work) + { +- struct hwrng *rng = container_of(kref, struct hwrng, ref); ++ struct hwrng *rng = container_of(work, struct hwrng, cleanup_work); ++ ++ /* ++ * Hold rng_mutex here so we serialize in case they set_current_rng ++ * on rng again immediately. ++ */ ++ mutex_lock(&rng_mutex); ++ ++ /* Skip if rng has been reinitialized. */ ++ if (kref_read(&rng->ref)) { ++ mutex_unlock(&rng_mutex); ++ return; ++ } + + if (rng->cleanup) + rng->cleanup(rng); + + complete(&rng->cleanup_done); ++ mutex_unlock(&rng_mutex); ++} ++ ++static inline void cleanup_rng(struct kref *kref) ++{ ++ struct hwrng *rng = container_of(kref, struct hwrng, ref); ++ ++ schedule_work(&rng->cleanup_work); + } + + static int set_current_rng(struct hwrng *rng) + { ++ struct hwrng *old_rng; + int err; + + BUG_ON(!mutex_is_locked(&rng_mutex)); +@@ -84,8 +107,14 @@ static int set_current_rng(struct hwrng *rng) + if (err) + return err; + +- drop_current_rng(); +- current_rng = rng; ++ old_rng = rcu_dereference_protected(current_rng, ++ lockdep_is_held(&rng_mutex)); ++ rcu_assign_pointer(current_rng, rng); ++ ++ if (old_rng) { ++ synchronize_rcu(); ++ kref_put(&old_rng->ref, cleanup_rng); ++ } + + /* if necessary, start hwrng thread */ + if (!hwrng_fill) { +@@ -101,47 +130,56 @@ static int set_current_rng(struct hwrng *rng) + + static void drop_current_rng(void) + { +- BUG_ON(!mutex_is_locked(&rng_mutex)); +- if (!current_rng) ++ struct hwrng *rng; ++ ++ rng = rcu_dereference_protected(current_rng, ++ lockdep_is_held(&rng_mutex)); ++ if (!rng) + return; + ++ RCU_INIT_POINTER(current_rng, NULL); ++ synchronize_rcu(); ++ ++ if (hwrng_fill) { ++ kthread_stop(hwrng_fill); ++ hwrng_fill = NULL; ++ } ++ + /* decrease last reference for triggering the cleanup */ +- kref_put(¤t_rng->ref, cleanup_rng); +- current_rng = NULL; ++ kref_put(&rng->ref, cleanup_rng); + } + +-/* Returns ERR_PTR(), NULL or refcounted hwrng */ ++/* Returns NULL or refcounted hwrng */ + static struct hwrng *get_current_rng_nolock(void) + { +- if (current_rng) +- kref_get(¤t_rng->ref); ++ struct hwrng *rng; ++ ++ rng = rcu_dereference_protected(current_rng, ++ lockdep_is_held(&rng_mutex)); ++ if (rng) ++ kref_get(&rng->ref); + +- return current_rng; ++ return rng; + } + + static struct hwrng *get_current_rng(void) + { + struct hwrng *rng; + +- if (mutex_lock_interruptible(&rng_mutex)) +- return ERR_PTR(-ERESTARTSYS); ++ rcu_read_lock(); ++ rng = rcu_dereference(current_rng); ++ if (rng) ++ kref_get(&rng->ref); + +- rng = get_current_rng_nolock(); ++ rcu_read_unlock(); + +- mutex_unlock(&rng_mutex); + return rng; + } + + static void put_rng(struct hwrng *rng) + { +- /* +- * Hold rng_mutex here so we serialize in case they set_current_rng +- * on rng again immediately. +- */ +- mutex_lock(&rng_mutex); + if (rng) + kref_put(&rng->ref, cleanup_rng); +- mutex_unlock(&rng_mutex); + } + + static int hwrng_init(struct hwrng *rng) +@@ -213,10 +251,6 @@ static ssize_t rng_dev_read(struct file *filp, char __user *buf, + + while (size) { + rng = get_current_rng(); +- if (IS_ERR(rng)) { +- err = PTR_ERR(rng); +- goto out; +- } + if (!rng) { + err = -ENODEV; + goto out; +@@ -303,7 +337,7 @@ static struct miscdevice rng_miscdev = { + + static int enable_best_rng(void) + { +- struct hwrng *rng, *new_rng = NULL; ++ struct hwrng *rng, *cur_rng, *new_rng = NULL; + int ret = -ENODEV; + + BUG_ON(!mutex_is_locked(&rng_mutex)); +@@ -321,7 +355,9 @@ static int enable_best_rng(void) + new_rng = rng; + } + +- ret = ((new_rng == current_rng) ? 0 : set_current_rng(new_rng)); ++ cur_rng = rcu_dereference_protected(current_rng, ++ lockdep_is_held(&rng_mutex)); ++ ret = ((new_rng == cur_rng) ? 0 : set_current_rng(new_rng)); + if (!ret) + cur_rng_set_by_user = 0; + +@@ -371,8 +407,6 @@ static ssize_t rng_current_show(struct device *dev, + struct hwrng *rng; + + rng = get_current_rng(); +- if (IS_ERR(rng)) +- return PTR_ERR(rng); + + ret = sysfs_emit(buf, "%s\n", rng ? rng->name : "none"); + put_rng(rng); +@@ -416,8 +450,6 @@ static ssize_t rng_quality_show(struct device *dev, + struct hwrng *rng; + + rng = get_current_rng(); +- if (IS_ERR(rng)) +- return PTR_ERR(rng); + + if (!rng) /* no need to put_rng */ + return -ENODEV; +@@ -432,6 +464,7 @@ static ssize_t rng_quality_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) + { ++ struct hwrng *rng; + u16 quality; + int ret = -EINVAL; + +@@ -448,12 +481,13 @@ static ssize_t rng_quality_store(struct device *dev, + goto out; + } + +- if (!current_rng) { ++ rng = rcu_dereference_protected(current_rng, lockdep_is_held(&rng_mutex)); ++ if (!rng) { + ret = -ENODEV; + goto out; + } + +- current_rng->quality = quality; ++ rng->quality = quality; + current_quality = quality; /* obsolete */ + + /* the best available RNG may have changed */ +@@ -489,8 +523,20 @@ static int hwrng_fillfn(void *unused) + struct hwrng *rng; + + rng = get_current_rng(); +- if (IS_ERR(rng) || !rng) ++ if (!rng) { ++ /* ++ * Keep the task_struct alive until kthread_stop() ++ * is called to avoid UAF in drop_current_rng(). ++ */ ++ while (!kthread_should_stop()) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ if (!kthread_should_stop()) ++ schedule(); ++ } ++ set_current_state(TASK_RUNNING); + break; ++ } ++ + mutex_lock(&reading_mutex); + rc = rng_get_data(rng, rng_fillbuf, + rng_buffer_size(), 1); +@@ -518,14 +564,13 @@ static int hwrng_fillfn(void *unused) + add_hwgenerator_randomness((void *)rng_fillbuf, rc, + entropy >> 10, true); + } +- hwrng_fill = NULL; + return 0; + } + + int hwrng_register(struct hwrng *rng) + { + int err = -EINVAL; +- struct hwrng *tmp; ++ struct hwrng *cur_rng, *tmp; + + if (!rng->name || (!rng->data_read && !rng->read)) + goto out; +@@ -540,6 +585,7 @@ int hwrng_register(struct hwrng *rng) + } + list_add_tail(&rng->list, &rng_list); + ++ INIT_WORK(&rng->cleanup_work, cleanup_rng_work); + init_completion(&rng->cleanup_done); + complete(&rng->cleanup_done); + init_completion(&rng->dying); +@@ -547,16 +593,19 @@ int hwrng_register(struct hwrng *rng) + /* Adjust quality field to always have a proper value */ + rng->quality = min_t(u16, min_t(u16, default_quality, 1024), rng->quality ?: 1024); + +- if (!cur_rng_set_by_user && +- (!current_rng || rng->quality > current_rng->quality)) { +- /* +- * Set new rng as current as the new rng source +- * provides better entropy quality and was not +- * chosen by userspace. +- */ +- err = set_current_rng(rng); +- if (err) +- goto out_unlock; ++ if (!cur_rng_set_by_user) { ++ cur_rng = rcu_dereference_protected(current_rng, ++ lockdep_is_held(&rng_mutex)); ++ if (!cur_rng || rng->quality > cur_rng->quality) { ++ /* ++ * Set new rng as current as the new rng source ++ * provides better entropy quality and was not ++ * chosen by userspace. ++ */ ++ err = set_current_rng(rng); ++ if (err) ++ goto out_unlock; ++ } + } + mutex_unlock(&rng_mutex); + return 0; +@@ -569,14 +618,17 @@ EXPORT_SYMBOL_GPL(hwrng_register); + + void hwrng_unregister(struct hwrng *rng) + { +- struct hwrng *new_rng; ++ struct hwrng *cur_rng; + int err; + + mutex_lock(&rng_mutex); + + list_del(&rng->list); + complete_all(&rng->dying); +- if (current_rng == rng) { ++ ++ cur_rng = rcu_dereference_protected(current_rng, ++ lockdep_is_held(&rng_mutex)); ++ if (cur_rng == rng) { + err = enable_best_rng(); + if (err) { + drop_current_rng(); +@@ -584,17 +636,7 @@ void hwrng_unregister(struct hwrng *rng) + } + } + +- new_rng = get_current_rng_nolock(); +- if (list_empty(&rng_list)) { +- mutex_unlock(&rng_mutex); +- if (hwrng_fill) +- kthread_stop(hwrng_fill); +- } else +- mutex_unlock(&rng_mutex); +- +- if (new_rng) +- put_rng(new_rng); +- ++ mutex_unlock(&rng_mutex); + wait_for_completion(&rng->cleanup_done); + } + EXPORT_SYMBOL_GPL(hwrng_unregister); +@@ -682,7 +724,7 @@ static int __init hwrng_modinit(void) + static void __exit hwrng_modexit(void) + { + mutex_lock(&rng_mutex); +- BUG_ON(current_rng); ++ WARN_ON(rcu_access_pointer(current_rng)); + kfree(rng_buffer); + kfree(rng_fillbuf); + mutex_unlock(&rng_mutex); +diff --git a/include/linux/hw_random.h b/include/linux/hw_random.h +index b424555753b11..b77bc55a4cf35 100644 +--- a/include/linux/hw_random.h ++++ b/include/linux/hw_random.h +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + + /** + * struct hwrng - Hardware Random Number Generator driver +@@ -48,6 +49,7 @@ struct hwrng { + /* internal. */ + struct list_head list; + struct kref ref; ++ struct work_struct cleanup_work; + struct completion cleanup_done; + struct completion dying; + }; +-- +2.51.0 + diff --git a/queue-6.18/hwspinlock-omap-handle-devm_pm_runtime_enable-errors.patch b/queue-6.18/hwspinlock-omap-handle-devm_pm_runtime_enable-errors.patch new file mode 100644 index 0000000000..7ad150b1d0 --- /dev/null +++ b/queue-6.18/hwspinlock-omap-handle-devm_pm_runtime_enable-errors.patch @@ -0,0 +1,44 @@ +From 856bb161805fce331cb3afe1545022ab7b443d2c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 24 Nov 2025 18:48:05 +0800 +Subject: hwspinlock: omap: Handle devm_pm_runtime_enable() errors + +From: Haotian Zhang + +[ Upstream commit 3bd4edd67b034f8e1f61c86e0eb098de6179e3f2 ] + +Although unlikely, devm_pm_runtime_enable() can fail due to memory +allocations. Without proper error handling, the subsequent +pm_runtime_resume_and_get() call may operate on incorrectly +initialized runtime PM state. + +Add error handling to check the return value of +devm_pm_runtime_enable() and return on failure. + +Fixes: 25f7d74d4514 ("hwspinlock: omap: Use devm_pm_runtime_enable() helper") +Signed-off-by: Haotian Zhang +Link: https://patch.msgid.link/20251124104805.135-1-vulab@iscas.ac.cn +Signed-off-by: Kevin Hilman +Signed-off-by: Sasha Levin +--- + drivers/hwspinlock/omap_hwspinlock.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/hwspinlock/omap_hwspinlock.c b/drivers/hwspinlock/omap_hwspinlock.c +index 27b47b8623c09..2d8de835bc242 100644 +--- a/drivers/hwspinlock/omap_hwspinlock.c ++++ b/drivers/hwspinlock/omap_hwspinlock.c +@@ -88,7 +88,9 @@ static int omap_hwspinlock_probe(struct platform_device *pdev) + * make sure the module is enabled and clocked before reading + * the module SYSSTATUS register + */ +- devm_pm_runtime_enable(&pdev->dev); ++ ret = devm_pm_runtime_enable(&pdev->dev); ++ if (ret) ++ return ret; + ret = pm_runtime_resume_and_get(&pdev->dev); + if (ret < 0) + return ret; +-- +2.51.0 + diff --git a/queue-6.18/i3c-dw-fix-memory-leak-in-dw_i3c_master_i2c_xfers.patch b/queue-6.18/i3c-dw-fix-memory-leak-in-dw_i3c_master_i2c_xfers.patch new file mode 100644 index 0000000000..47cfd2e262 --- /dev/null +++ b/queue-6.18/i3c-dw-fix-memory-leak-in-dw_i3c_master_i2c_xfers.patch @@ -0,0 +1,45 @@ +From 59b6412cb179b97f84f643c0c909b371771f03d3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 08:11:21 +0000 +Subject: i3c: dw: Fix memory leak in dw_i3c_master_i2c_xfers() + +From: Zilin Guan + +[ Upstream commit 2537089413514caaa9a5fdeeac3a34d45100f747 ] + +The dw_i3c_master_i2c_xfers() function allocates memory for the xfer +structure using dw_i3c_master_alloc_xfer(). If pm_runtime_resume_and_get() +fails, the function returns without freeing the allocated xfer, resulting +in a memory leak. + +Add a dw_i3c_master_free_xfer() call to the error path to ensure the +allocated memory is properly freed. + +Compile tested only. Issue found using a prototype static analysis tool +and code review. + +Fixes: 62fe9d06f570 ("i3c: dw: Add power management support") +Signed-off-by: Zilin Guan +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260126081121.644099-1-zilin@seu.edu.cn +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master/dw-i3c-master.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c +index 75f813d72f851..c06595cb74010 100644 +--- a/drivers/i3c/master/dw-i3c-master.c ++++ b/drivers/i3c/master/dw-i3c-master.c +@@ -1094,6 +1094,7 @@ static int dw_i3c_master_i2c_xfers(struct i2c_dev_desc *dev, + dev_err(master->dev, + "<%s> cannot resume i3c bus master, err: %d\n", + __func__, ret); ++ dw_i3c_master_free_xfer(xfer); + return ret; + } + +-- +2.51.0 + diff --git a/queue-6.18/i3c-dw-initialize-spinlock-to-avoid-upsetting-lockde.patch b/queue-6.18/i3c-dw-initialize-spinlock-to-avoid-upsetting-lockde.patch new file mode 100644 index 0000000000..6a4915574d --- /dev/null +++ b/queue-6.18/i3c-dw-initialize-spinlock-to-avoid-upsetting-lockde.patch @@ -0,0 +1,39 @@ +From caecd56786014fbc39e9bb22f7ec0b1e78b7c4cb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 15:29:42 +0100 +Subject: i3c: dw: Initialize spinlock to avoid upsetting lockdep + +From: Fredrik Markstrom + +[ Upstream commit b58eaa4761ab02fc38c39d674a6bcdd55e00f388 ] + +The devs_lock spinlock introduced when adding support for ibi:s was +never initialized. + +Fixes: e389b1d72a624 ("i3c: dw: Add support for in-band interrupts") +Suggested-by: Jani Nurminen +Signed-off-by: Fredrik Markstrom +Reviewed-by: Ivar Holmqvist +Link: https://patch.msgid.link/20260116-i3c_dw_initialize_spinlock-v3-1-cf707b6ed75f@est.tech +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master/dw-i3c-master.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c +index 9ceedf09c3b6a..75f813d72f851 100644 +--- a/drivers/i3c/master/dw-i3c-master.c ++++ b/drivers/i3c/master/dw-i3c-master.c +@@ -1563,6 +1563,8 @@ int dw_i3c_common_probe(struct dw_i3c_master *master, + spin_lock_init(&master->xferqueue.lock); + INIT_LIST_HEAD(&master->xferqueue.list); + ++ spin_lock_init(&master->devs_lock); ++ + writel(INTR_ALL, master->regs + INTR_STATUS); + irq = platform_get_irq(pdev, 0); + ret = devm_request_irq(&pdev->dev, irq, +-- +2.51.0 + diff --git a/queue-6.18/i3c-master-update-hot-join-flag-only-on-success.patch b/queue-6.18/i3c-master-update-hot-join-flag-only-on-success.patch new file mode 100644 index 0000000000..0515ae2f0c --- /dev/null +++ b/queue-6.18/i3c-master-update-hot-join-flag-only-on-success.patch @@ -0,0 +1,39 @@ +From bbb4c1d801088d24753360de02823165e3d3784c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Jan 2026 09:26:44 +0200 +Subject: i3c: master: Update hot-join flag only on success + +From: Adrian Hunter + +[ Upstream commit f0775157b9f9a28ae3eabc8d05b0bc52e8056c80 ] + +To prevent inconsistent state when an error occurs, ensure the hot-join +flag is updated only when enabling or disabling hot-join succeeds. + +Fixes: 317bacf960a48 ("i3c: master: add enable(disable) hot join in sys entry") +Signed-off-by: Adrian Hunter +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260113072702.16268-4-adrian.hunter@intel.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c +index bc68a5e7455be..425e36b36009b 100644 +--- a/drivers/i3c/master.c ++++ b/drivers/i3c/master.c +@@ -620,7 +620,8 @@ static int i3c_set_hotjoin(struct i3c_master_controller *master, bool enable) + else + ret = master->ops->disable_hotjoin(master); + +- master->hotjoin = enable; ++ if (!ret) ++ master->hotjoin = enable; + + i3c_bus_normaluse_unlock(&master->bus); + +-- +2.51.0 + diff --git a/queue-6.18/i3c-move-device-name-assignment-after-i3c_bus_init.patch b/queue-6.18/i3c-move-device-name-assignment-after-i3c_bus_init.patch new file mode 100644 index 0000000000..bf58ffa5c3 --- /dev/null +++ b/queue-6.18/i3c-move-device-name-assignment-after-i3c_bus_init.patch @@ -0,0 +1,46 @@ +From 5a517b3ce9310dee0187c22a508d0b33ad14bc52 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 14:07:22 +0800 +Subject: i3c: Move device name assignment after i3c_bus_init + +From: Billy Tsai + +[ Upstream commit 3502cea99c7ceb331458cbd34ef6792c83144687 ] + +Move device name initialization to occur after i3c_bus_init() +so that i3cbus->id is guaranteed to be assigned before it is used. + +Fixes: 9d4f219807d5 ("i3c: fix refcount inconsistency in i3c_master_register") +Signed-off-by: Billy Tsai +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260112-upstream_i3c_fix-v1-1-cbbf2cb71809@aspeedtech.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c +index 66513a27e6e77..bc68a5e7455be 100644 +--- a/drivers/i3c/master.c ++++ b/drivers/i3c/master.c +@@ -2884,7 +2884,6 @@ int i3c_master_register(struct i3c_master_controller *master, + INIT_LIST_HEAD(&master->boardinfo.i3c); + + device_initialize(&master->dev); +- dev_set_name(&master->dev, "i3c-%d", i3cbus->id); + + master->dev.dma_mask = parent->dma_mask; + master->dev.coherent_dma_mask = parent->coherent_dma_mask; +@@ -2894,6 +2893,8 @@ int i3c_master_register(struct i3c_master_controller *master, + if (ret) + goto err_put_dev; + ++ dev_set_name(&master->dev, "i3c-%d", i3cbus->id); ++ + ret = of_populate_i3c_bus(master); + if (ret) + goto err_put_dev; +-- +2.51.0 + diff --git a/queue-6.18/ib-cache-update-gid-cache-on-client-reregister-event.patch b/queue-6.18/ib-cache-update-gid-cache-on-client-reregister-event.patch new file mode 100644 index 0000000000..55c7f2f969 --- /dev/null +++ b/queue-6.18/ib-cache-update-gid-cache-on-client-reregister-event.patch @@ -0,0 +1,54 @@ +From 34c8f5b6fc5cc3fadd5b5439c1f3ce5721d956bd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 31 Dec 2025 14:07:45 +0100 +Subject: IB/cache: update gid cache on client reregister event +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Etienne AUJAMES + +[ Upstream commit ddd6c8c873e912cb1ead79def54de5e24ff71c80 ] + +Some HCAs (e.g: ConnectX4) do not trigger a IB_EVENT_GID_CHANGE on +subnet prefix update from SM (PortInfo). + +Since the commit d58c23c92548 ("IB/core: Only update PKEY and GID caches +on respective events"), the GID cache is updated exclusively on +IB_EVENT_GID_CHANGE. If this event is not emitted, the subnet prefix in the +IPoIB interface’s hardware address remains set to its default value +(0xfe80000000000000). + +Then rdma_bind_addr() failed because it relies on hardware address to +find the port GID (subnet_prefix + port GUID). + +This patch fixes this issue by updating the GID cache on +IB_EVENT_CLIENT_REREGISTER event (emitted on PortInfo::ClientReregister=1). + +Fixes: d58c23c92548 ("IB/core: Only update PKEY and GID caches on respective events") +Signed-off-by: Etienne AUJAMES +Link: https://patch.msgid.link/aVUfsO58QIDn5bGX@eaujamesFR0130 +Reviewed-by: Parav Pandit +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/cache.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c +index 81cf3c902e819..0fc1c5bce2f0d 100644 +--- a/drivers/infiniband/core/cache.c ++++ b/drivers/infiniband/core/cache.c +@@ -1537,7 +1537,8 @@ static void ib_cache_event_task(struct work_struct *_work) + * the cache. + */ + ret = ib_cache_update(work->event.device, work->event.element.port_num, +- work->event.event == IB_EVENT_GID_CHANGE, ++ work->event.event == IB_EVENT_GID_CHANGE || ++ work->event.event == IB_EVENT_CLIENT_REREGISTER, + work->event.event == IB_EVENT_PKEY_CHANGE, + work->enforce_security); + +-- +2.51.0 + diff --git a/queue-6.18/ib-mlx5-fix-port-speed-query-for-representors.patch b/queue-6.18/ib-mlx5-fix-port-speed-query-for-representors.patch new file mode 100644 index 0000000000..5deac2eb7a --- /dev/null +++ b/queue-6.18/ib-mlx5-fix-port-speed-query-for-representors.patch @@ -0,0 +1,63 @@ +From 5fe54026398c9b934f8ed9759956f5db5b17539c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 14:26:45 +0200 +Subject: IB/mlx5: Fix port speed query for representors + +From: Or Har-Toov + +[ Upstream commit 18ea78e2ae83d1d86a72d21d9511927e57e2c0e1 ] + +When querying speed information for a representor in switchdev mode, +the code previously used the first device in the eswitch, which may not +match the device that actually owns the representor. In setups such as +multi-port eswitch or LAG, this led to incorrect port attributes being +reported. + +Fix this by retrieving the correct core device from the representor's +eswitch before querying its port attributes. + +Fixes: 27f9e0ccb6da ("net/mlx5: Lag, Add single RDMA device in multiport mode") +Signed-off-by: Or Har-Toov +Reviewed-by: Mark Bloch +Signed-off-by: Edward Srouji +Link: https://patch.msgid.link/20260115-port-speed-query-fix-v2-1-3bde6a3c78e7@nvidia.com +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/hw/mlx5/main.c | 20 ++++++++++++++------ + 1 file changed, 14 insertions(+), 6 deletions(-) + +diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c +index b6096f9126858..5899bd5cb1623 100644 +--- a/drivers/infiniband/hw/mlx5/main.c ++++ b/drivers/infiniband/hw/mlx5/main.c +@@ -557,12 +557,20 @@ static int mlx5_query_port_roce(struct ib_device *device, u32 port_num, + * of an error it will still be zeroed out. + * Use native port in case of reps + */ +- if (dev->is_rep) +- err = mlx5_query_port_ptys(mdev, out, sizeof(out), MLX5_PTYS_EN, +- 1, 0); +- else +- err = mlx5_query_port_ptys(mdev, out, sizeof(out), MLX5_PTYS_EN, +- mdev_port_num, 0); ++ if (dev->is_rep) { ++ struct mlx5_eswitch_rep *rep; ++ ++ rep = dev->port[port_num - 1].rep; ++ if (rep) { ++ mdev = mlx5_eswitch_get_core_dev(rep->esw); ++ WARN_ON(!mdev); ++ } ++ mdev_port_num = 1; ++ } ++ ++ err = mlx5_query_port_ptys(mdev, out, sizeof(out), MLX5_PTYS_EN, ++ mdev_port_num, 0); ++ + if (err) + goto out; + ext = !!MLX5_GET_ETH_PROTO(ptys_reg, out, true, eth_proto_capability); +-- +2.51.0 + diff --git a/queue-6.18/iio-pressure-mprls0025pa-fix-interrupt-flag.patch b/queue-6.18/iio-pressure-mprls0025pa-fix-interrupt-flag.patch new file mode 100644 index 0000000000..8cb97fc9f9 --- /dev/null +++ b/queue-6.18/iio-pressure-mprls0025pa-fix-interrupt-flag.patch @@ -0,0 +1,40 @@ +From def131779cd242341985bc6d3dcd234c41582235 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:55:32 +0200 +Subject: iio: pressure: mprls0025pa: fix interrupt flag + +From: Petre Rodan + +[ Upstream commit fff3f1a7d805684e4701a70bfaeba39622b59dbc ] + +Interrupt falling/rising flags should only be defined in the device tree. + +Fixes: 713337d9143e ("iio: pressure: Honeywell mprls0025pa pressure sensor") +Signed-off-by: Petre Rodan +Reviewed-by: Andy Shevchenko +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/pressure/mprls0025pa.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/iio/pressure/mprls0025pa.c b/drivers/iio/pressure/mprls0025pa.c +index 2336f2760eaeb..4b23f87a822b1 100644 +--- a/drivers/iio/pressure/mprls0025pa.c ++++ b/drivers/iio/pressure/mprls0025pa.c +@@ -418,10 +418,8 @@ int mpr_common_probe(struct device *dev, const struct mpr_ops *ops, int irq) + data->offset = div_s64_rem(offset, NANO, &data->offset2); + + if (data->irq > 0) { +- ret = devm_request_irq(dev, data->irq, mpr_eoc_handler, +- IRQF_TRIGGER_RISING, +- dev_name(dev), +- data); ++ ret = devm_request_irq(dev, data->irq, mpr_eoc_handler, 0, ++ dev_name(dev), data); + if (ret) + return dev_err_probe(dev, ret, + "request irq %d failed\n", data->irq); +-- +2.51.0 + diff --git a/queue-6.18/iio-pressure-mprls0025pa-fix-pressure-calculation.patch b/queue-6.18/iio-pressure-mprls0025pa-fix-pressure-calculation.patch new file mode 100644 index 0000000000..a94509165a --- /dev/null +++ b/queue-6.18/iio-pressure-mprls0025pa-fix-pressure-calculation.patch @@ -0,0 +1,110 @@ +From 2abc29561ee940bfc75965ce4a867c06d72cc218 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:55:34 +0200 +Subject: iio: pressure: mprls0025pa: fix pressure calculation + +From: Petre Rodan + +[ Upstream commit d63403d4e31ae537fefc5c0ee9d90f29b4fc532b ] + +A sign change is needed for proper calculation of the pressure. + +This is a minor fix since it only affects users that might have custom +silicon from Honeywell that has honeywell,pmin-pascal != 0. + +Also due to the fact that raw pressure values can not be lower +than output_min (400k-3.3M) there is no need to calculate a decimal for +the offset. + +Fixes: 713337d9143e ("iio: pressure: Honeywell mprls0025pa pressure sensor") +Signed-off-by: Petre Rodan +Reviewed-by: Andy Shevchenko +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/pressure/mprls0025pa.c | 26 +++++++++++--------------- + drivers/iio/pressure/mprls0025pa.h | 2 -- + 2 files changed, 11 insertions(+), 17 deletions(-) + +diff --git a/drivers/iio/pressure/mprls0025pa.c b/drivers/iio/pressure/mprls0025pa.c +index 6ba45d4c16b30..d4133fef91fac 100644 +--- a/drivers/iio/pressure/mprls0025pa.c ++++ b/drivers/iio/pressure/mprls0025pa.c +@@ -59,7 +59,7 @@ + * + * Values given to the userspace in sysfs interface: + * * raw - press_cnt +- * * offset - (-1 * outputmin) - pmin / scale ++ * * offset - (-1 * outputmin) + pmin / scale + * note: With all sensors from the datasheet pmin = 0 + * which reduces the offset to (-1 * outputmin) + */ +@@ -313,8 +313,7 @@ static int mpr_read_raw(struct iio_dev *indio_dev, + return IIO_VAL_INT_PLUS_NANO; + case IIO_CHAN_INFO_OFFSET: + *val = data->offset; +- *val2 = data->offset2; +- return IIO_VAL_INT_PLUS_NANO; ++ return IIO_VAL_INT; + default: + return -EINVAL; + } +@@ -330,8 +329,9 @@ int mpr_common_probe(struct device *dev, const struct mpr_ops *ops, int irq) + struct mpr_data *data; + struct iio_dev *indio_dev; + const char *triplet; +- s64 scale, offset; ++ s64 odelta, pdelta; + u32 func; ++ s32 tmp; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) +@@ -405,17 +405,13 @@ int mpr_common_probe(struct device *dev, const struct mpr_ops *ops, int irq) + data->outmin = mpr_func_spec[data->function].output_min; + data->outmax = mpr_func_spec[data->function].output_max; + +- /* use 64 bit calculation for preserving a reasonable precision */ +- scale = div_s64(((s64)(data->pmax - data->pmin)) * NANO, +- data->outmax - data->outmin); +- data->scale = div_s64_rem(scale, NANO, &data->scale2); +- /* +- * multiply with NANO before dividing by scale and later divide by NANO +- * again. +- */ +- offset = ((-1LL) * (s64)data->outmin) * NANO - +- div_s64(div_s64((s64)data->pmin * NANO, scale), NANO); +- data->offset = div_s64_rem(offset, NANO, &data->offset2); ++ odelta = data->outmax - data->outmin; ++ pdelta = data->pmax - data->pmin; ++ ++ data->scale = div_s64_rem(div_s64(pdelta * NANO, odelta), NANO, &tmp); ++ data->scale2 = tmp; ++ ++ data->offset = div_s64(odelta * data->pmin, pdelta) - data->outmin; + + if (data->irq > 0) { + ret = devm_request_irq(dev, data->irq, mpr_eoc_handler, 0, +diff --git a/drivers/iio/pressure/mprls0025pa.h b/drivers/iio/pressure/mprls0025pa.h +index d62a018eaff32..b6944b3051267 100644 +--- a/drivers/iio/pressure/mprls0025pa.h ++++ b/drivers/iio/pressure/mprls0025pa.h +@@ -53,7 +53,6 @@ enum mpr_func_id { + * @scale: pressure scale + * @scale2: pressure scale, decimal number + * @offset: pressure offset +- * @offset2: pressure offset, decimal number + * @gpiod_reset: reset + * @irq: end of conversion irq. used to distinguish between irq mode and + * reading in a loop until data is ready +@@ -75,7 +74,6 @@ struct mpr_data { + int scale; + int scale2; + int offset; +- int offset2; + struct gpio_desc *gpiod_reset; + int irq; + struct completion completion; +-- +2.51.0 + diff --git a/queue-6.18/iio-pressure-mprls0025pa-fix-scan_type-struct.patch b/queue-6.18/iio-pressure-mprls0025pa-fix-scan_type-struct.patch new file mode 100644 index 0000000000..b76b4f3576 --- /dev/null +++ b/queue-6.18/iio-pressure-mprls0025pa-fix-scan_type-struct.patch @@ -0,0 +1,47 @@ +From 15989cbe9488052b14950392891a8ee31d8c1c32 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:55:33 +0200 +Subject: iio: pressure: mprls0025pa: fix scan_type struct + +From: Petre Rodan + +[ Upstream commit 8a228e036926f7e57421d750c3724e63f11b808a ] + +Fix the scan_type sign and realbits assignment. + +The pressure is a 24bit unsigned int between output_min and output_max. + + transfer function A: 10% to 90% of 2^24 + transfer function B: 2.5% to 22.5% of 2^24 + transfer function C: 20% to 80% of 2^24 +[MPR_FUNCTION_A] = { .output_min = 1677722, .output_max = 15099494 } +[MPR_FUNCTION_B] = { .output_min = 419430, .output_max = 3774874 } +[MPR_FUNCTION_C] = { .output_min = 3355443, .output_max = 13421773 } + +Fixes: 713337d9143e ("iio: pressure: Honeywell mprls0025pa pressure sensor") +Signed-off-by: Petre Rodan +Reviewed-by: Andy Shevchenko +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/pressure/mprls0025pa.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/iio/pressure/mprls0025pa.c b/drivers/iio/pressure/mprls0025pa.c +index 4b23f87a822b1..6ba45d4c16b30 100644 +--- a/drivers/iio/pressure/mprls0025pa.c ++++ b/drivers/iio/pressure/mprls0025pa.c +@@ -160,8 +160,8 @@ static const struct iio_chan_spec mpr_channels[] = { + BIT(IIO_CHAN_INFO_OFFSET), + .scan_index = 0, + .scan_type = { +- .sign = 's', +- .realbits = 32, ++ .sign = 'u', ++ .realbits = 24, + .storagebits = 32, + .endianness = IIO_CPU, + }, +-- +2.51.0 + diff --git a/queue-6.18/iio-pressure-mprls0025pa-fix-spi-cs-delay-violation.patch b/queue-6.18/iio-pressure-mprls0025pa-fix-spi-cs-delay-violation.patch new file mode 100644 index 0000000000..9b4638ef7c --- /dev/null +++ b/queue-6.18/iio-pressure-mprls0025pa-fix-spi-cs-delay-violation.patch @@ -0,0 +1,71 @@ +From d9307dd1e8ae0b6f7d93ff12bff677314404078f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:55:31 +0200 +Subject: iio: pressure: mprls0025pa: fix SPI CS delay violation + +From: Petre Rodan + +[ Upstream commit 583fa86ca581595b1f534a8de6d49ba8b3bf7196 ] + +Based on the sensor datasheet in chapter 7.6 SPI timing, Table 20, +during the SPI transfer there is a minimum time interval requirement +between the CS being asserted and the first clock edge (tHDSS). +This minimum interval of 2.5us is being violated if two consecutive SPI +transfers are queued up. + +Fixes: a0858f0cd28e ("iio: pressure: mprls0025pa add SPI driver") +Datasheet: https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/micropressure-mpr-series/documents/sps-siot-mpr-series-datasheet-32332628-ciid-172626.pdf?download=false +Signed-off-by: Petre Rodan +Reviewed-by: Andy Shevchenko +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/pressure/mprls0025pa_spi.c | 19 ++++++++++++++----- + 1 file changed, 14 insertions(+), 5 deletions(-) + +diff --git a/drivers/iio/pressure/mprls0025pa_spi.c b/drivers/iio/pressure/mprls0025pa_spi.c +index e6bb75de34119..cf17eb2e72083 100644 +--- a/drivers/iio/pressure/mprls0025pa_spi.c ++++ b/drivers/iio/pressure/mprls0025pa_spi.c +@@ -8,6 +8,7 @@ + * https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/micropressure-mpr-series/documents/sps-siot-mpr-series-datasheet-32332628-ciid-172626.pdf + */ + ++#include + #include + #include + #include +@@ -40,17 +41,25 @@ static int mpr_spi_xfer(struct mpr_data *data, const u8 cmd, const u8 pkt_len) + { + struct spi_device *spi = to_spi_device(data->dev); + struct mpr_spi_buf *buf = spi_get_drvdata(spi); +- struct spi_transfer xfer = { }; ++ struct spi_transfer xfers[2] = { }; + + if (pkt_len > MPR_MEASUREMENT_RD_SIZE) + return -EOVERFLOW; + + buf->tx[0] = cmd; +- xfer.tx_buf = buf->tx; +- xfer.rx_buf = data->buffer; +- xfer.len = pkt_len; + +- return spi_sync_transfer(spi, &xfer, 1); ++ /* ++ * Dummy transfer with no data, just cause a 2.5us+ delay between the CS assert ++ * and the first clock edge as per the datasheet tHDSS timing requirement. ++ */ ++ xfers[0].delay.value = 2500; ++ xfers[0].delay.unit = SPI_DELAY_UNIT_NSECS; ++ ++ xfers[1].tx_buf = buf->tx; ++ xfers[1].rx_buf = data->buffer; ++ xfers[1].len = pkt_len; ++ ++ return spi_sync_transfer(spi, xfers, ARRAY_SIZE(xfers)); + } + + static const struct mpr_ops mpr_spi_ops = { +-- +2.51.0 + diff --git a/queue-6.18/iio-pressure-mprls0025pa-fix-spi_transfer-struct-ini.patch b/queue-6.18/iio-pressure-mprls0025pa-fix-spi_transfer-struct-ini.patch new file mode 100644 index 0000000000..f097d0bedb --- /dev/null +++ b/queue-6.18/iio-pressure-mprls0025pa-fix-spi_transfer-struct-ini.patch @@ -0,0 +1,36 @@ +From e7b754909baa021b8571aca0e302131c59fa4ea0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:55:30 +0200 +Subject: iio: pressure: mprls0025pa: fix spi_transfer struct initialisation + +From: Petre Rodan + +[ Upstream commit 1e0ac56c92e26115cbc8cfc639843725cb3a7d6a ] + +Make sure that the spi_transfer struct is zeroed out before use. + +Fixes: a0858f0cd28e ("iio: pressure: mprls0025pa add SPI driver") +Signed-off-by: Petre Rodan +Reviewed-by: Andy Shevchenko +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/pressure/mprls0025pa_spi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/iio/pressure/mprls0025pa_spi.c b/drivers/iio/pressure/mprls0025pa_spi.c +index d04102f8a4a03..e6bb75de34119 100644 +--- a/drivers/iio/pressure/mprls0025pa_spi.c ++++ b/drivers/iio/pressure/mprls0025pa_spi.c +@@ -40,7 +40,7 @@ static int mpr_spi_xfer(struct mpr_data *data, const u8 cmd, const u8 pkt_len) + { + struct spi_device *spi = to_spi_device(data->dev); + struct mpr_spi_buf *buf = spi_get_drvdata(spi); +- struct spi_transfer xfer; ++ struct spi_transfer xfer = { }; + + if (pkt_len > MPR_MEASUREMENT_RD_SIZE) + return -EOVERFLOW; +-- +2.51.0 + diff --git a/queue-6.18/iio-sca3000-fix-a-resource-leak-in-sca3000_probe.patch b/queue-6.18/iio-sca3000-fix-a-resource-leak-in-sca3000_probe.patch new file mode 100644 index 0000000000..9239b2a7e1 --- /dev/null +++ b/queue-6.18/iio-sca3000-fix-a-resource-leak-in-sca3000_probe.patch @@ -0,0 +1,42 @@ +From 58ee64db4e7c355ef0b227f35fa3f1b7dad2f333 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 22:49:49 -0800 +Subject: iio: sca3000: Fix a resource leak in sca3000_probe() + +From: Harshit Mogalapalli + +[ Upstream commit 62b44ebc1f2c71db3ca2d4737c52e433f6f03038 ] + +spi->irq from request_threaded_irq() not released when +iio_device_register() fails. Add an return value check and jump to a +common error handler when iio_device_register() fails. + +Fixes: 9a4936dc89a3 ("staging:iio:accel:sca3000 Tidy up probe order to avoid a race.") +Signed-off-by: Harshit Mogalapalli +Reviewed-by: Andy Shevchenko +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/accel/sca3000.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/iio/accel/sca3000.c b/drivers/iio/accel/sca3000.c +index bfa8a3f5a92f4..9ef4d6e274669 100644 +--- a/drivers/iio/accel/sca3000.c ++++ b/drivers/iio/accel/sca3000.c +@@ -1489,7 +1489,11 @@ static int sca3000_probe(struct spi_device *spi) + if (ret) + goto error_free_irq; + +- return iio_device_register(indio_dev); ++ ret = iio_device_register(indio_dev); ++ if (ret) ++ goto error_free_irq; ++ ++ return 0; + + error_free_irq: + if (spi->irq) +-- +2.51.0 + diff --git a/queue-6.18/iio-test-drop-dangling-symbol-in-gain-time-scale-hel.patch b/queue-6.18/iio-test-drop-dangling-symbol-in-gain-time-scale-hel.patch new file mode 100644 index 0000000000..4baf83b006 --- /dev/null +++ b/queue-6.18/iio-test-drop-dangling-symbol-in-gain-time-scale-hel.patch @@ -0,0 +1,36 @@ +From e4190d5f447d0c1be3437506f463e9c961f7f397 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 27 Dec 2025 23:10:29 -0800 +Subject: iio: test: drop dangling symbol in gain-time-scale helpers + +From: Randy Dunlap + +[ Upstream commit d63d868b312478523670b76007dcc5eaedc3ee07 ] + +The code for this never went upstream. It was replaced by other code, +so this should be dropped. + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=216748 +Fixes: cf996f039679 ("iio: test: test gain-time-scale helpers") +Signed-off-by: Randy Dunlap +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/test/Kconfig | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/iio/test/Kconfig b/drivers/iio/test/Kconfig +index 6e65e929791ca..4fc17dd0dcd77 100644 +--- a/drivers/iio/test/Kconfig ++++ b/drivers/iio/test/Kconfig +@@ -8,7 +8,6 @@ config IIO_GTS_KUNIT_TEST + tristate "Test IIO gain-time-scale helpers" if !KUNIT_ALL_TESTS + depends on KUNIT + select IIO_GTS_HELPER +- select TEST_KUNIT_DEVICE_HELPERS + default KUNIT_ALL_TESTS + help + build unit tests for the IIO light sensor gain-time-scale helpers. +-- +2.51.0 + diff --git a/queue-6.18/inet-raw-sockets-using-ipproto_raw-must-drop-incomin.patch b/queue-6.18/inet-raw-sockets-using-ipproto_raw-must-drop-incomin.patch new file mode 100644 index 0000000000..06e0cc71fb --- /dev/null +++ b/queue-6.18/inet-raw-sockets-using-ipproto_raw-must-drop-incomin.patch @@ -0,0 +1,94 @@ +From fe20edbcc787e35d5a22af409f7979494a63c9ad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 19:25:09 +0000 +Subject: inet: RAW sockets using IPPROTO_RAW MUST drop incoming ICMP + +From: Eric Dumazet + +[ Upstream commit c89477ad79446867394360b29bb801010fc3ff22 ] + +Yizhou Zhao reported that simply having one RAW socket on protocol +IPPROTO_RAW (255) was dangerous. + + socket(AF_INET, SOCK_RAW, 255); + +A malicious incoming ICMP packet can set the protocol field to 255 +and match this socket, leading to FNHE cache changes. + +inner = IP(src="192.168.2.1", dst="8.8.8.8", proto=255)/Raw("TEST") +pkt = IP(src="192.168.1.1", dst="192.168.2.1")/ICMP(type=3, code=4, nexthopmtu=576)/inner + +"man 7 raw" states: + + A protocol of IPPROTO_RAW implies enabled IP_HDRINCL and is able + to send any IP protocol that is specified in the passed header. + Receiving of all IP protocols via IPPROTO_RAW is not possible + using raw sockets. + +Make sure we drop these malicious packets. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: Yizhou Zhao +Link: https://lore.kernel.org/netdev/20251109134600.292125-1-zhaoyz24@mails.tsinghua.edu.cn/ +Signed-off-by: Eric Dumazet +Reviewed-by: David Ahern +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260203192509.682208-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/icmp.c | 14 ++++++++++---- + net/ipv6/icmp.c | 6 ++++++ + 2 files changed, 16 insertions(+), 4 deletions(-) + +diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c +index 1b7fb5d935edf..8e10e9e7676c5 100644 +--- a/net/ipv4/icmp.c ++++ b/net/ipv4/icmp.c +@@ -843,16 +843,22 @@ static void icmp_socket_deliver(struct sk_buff *skb, u32 info) + /* Checkin full IP header plus 8 bytes of protocol to + * avoid additional coding at protocol handlers. + */ +- if (!pskb_may_pull(skb, iph->ihl * 4 + 8)) { +- __ICMP_INC_STATS(dev_net_rcu(skb->dev), ICMP_MIB_INERRORS); +- return; +- } ++ if (!pskb_may_pull(skb, iph->ihl * 4 + 8)) ++ goto out; ++ ++ /* IPPROTO_RAW sockets are not supposed to receive anything. */ ++ if (protocol == IPPROTO_RAW) ++ goto out; + + raw_icmp_error(skb, protocol, info); + + ipprot = rcu_dereference(inet_protos[protocol]); + if (ipprot && ipprot->err_handler) + ipprot->err_handler(skb, info); ++ return; ++ ++out: ++ __ICMP_INC_STATS(dev_net_rcu(skb->dev), ICMP_MIB_INERRORS); + } + + static bool icmp_tag_validation(int proto) +diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c +index cf6455cbe2cc9..306eec18e82c1 100644 +--- a/net/ipv6/icmp.c ++++ b/net/ipv6/icmp.c +@@ -870,6 +870,12 @@ enum skb_drop_reason icmpv6_notify(struct sk_buff *skb, u8 type, + if (reason != SKB_NOT_DROPPED_YET) + goto out; + ++ if (nexthdr == IPPROTO_RAW) { ++ /* Add a more specific reason later ? */ ++ reason = SKB_DROP_REASON_NOT_SPECIFIED; ++ goto out; ++ } ++ + /* BUGGG_FUTURE: we should try to parse exthdrs in this packet. + Without this we will not able f.e. to make source routed + pmtu discovery. +-- +2.51.0 + diff --git a/queue-6.18/input-adp5589-remove-a-leftover-header-file.patch b/queue-6.18/input-adp5589-remove-a-leftover-header-file.patch new file mode 100644 index 0000000000..a2a399704b --- /dev/null +++ b/queue-6.18/input-adp5589-remove-a-leftover-header-file.patch @@ -0,0 +1,217 @@ +From 019bd2cc9741266f611343f2d1b7325254e23d98 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Jan 2026 17:11:40 +0200 +Subject: Input: adp5589 - remove a leftover header file +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Vladimir Zapolskiy + +[ Upstream commit f8a6e5eac701369afb5d69aba875dc5fec93003d ] + +In commit 3bdbd0858df6 ("Input: adp5589: remove the driver") the last user +of include/linux/input/adp5589.h was removed along with the whole driver, +thus the header file can be also removed. + +Signed-off-by: Vladimir Zapolskiy +Reviewed-by: Laurent Pinchart +Reviewed-by: Nuno Sá +Fixes: 3bdbd0858df6 ("Input: adp5589: remove the driver") +Link: https://patch.msgid.link/20260113151140.3843753-1-vz@mleia.com +Signed-off-by: Dmitry Torokhov +Signed-off-by: Sasha Levin +--- + include/linux/input/adp5589.h | 180 ---------------------------------- + 1 file changed, 180 deletions(-) + delete mode 100644 include/linux/input/adp5589.h + +diff --git a/include/linux/input/adp5589.h b/include/linux/input/adp5589.h +deleted file mode 100644 +index 0e4742c8c81e3..0000000000000 +--- a/include/linux/input/adp5589.h ++++ /dev/null +@@ -1,180 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0-only */ +-/* +- * Analog Devices ADP5589/ADP5585 I/O Expander and QWERTY Keypad Controller +- * +- * Copyright 2010-2011 Analog Devices Inc. +- */ +- +-#ifndef _ADP5589_H +-#define _ADP5589_H +- +-/* +- * ADP5589 specific GPI and Keymap defines +- */ +- +-#define ADP5589_KEYMAPSIZE 88 +- +-#define ADP5589_GPI_PIN_ROW0 97 +-#define ADP5589_GPI_PIN_ROW1 98 +-#define ADP5589_GPI_PIN_ROW2 99 +-#define ADP5589_GPI_PIN_ROW3 100 +-#define ADP5589_GPI_PIN_ROW4 101 +-#define ADP5589_GPI_PIN_ROW5 102 +-#define ADP5589_GPI_PIN_ROW6 103 +-#define ADP5589_GPI_PIN_ROW7 104 +-#define ADP5589_GPI_PIN_COL0 105 +-#define ADP5589_GPI_PIN_COL1 106 +-#define ADP5589_GPI_PIN_COL2 107 +-#define ADP5589_GPI_PIN_COL3 108 +-#define ADP5589_GPI_PIN_COL4 109 +-#define ADP5589_GPI_PIN_COL5 110 +-#define ADP5589_GPI_PIN_COL6 111 +-#define ADP5589_GPI_PIN_COL7 112 +-#define ADP5589_GPI_PIN_COL8 113 +-#define ADP5589_GPI_PIN_COL9 114 +-#define ADP5589_GPI_PIN_COL10 115 +-#define GPI_LOGIC1 116 +-#define GPI_LOGIC2 117 +- +-#define ADP5589_GPI_PIN_ROW_BASE ADP5589_GPI_PIN_ROW0 +-#define ADP5589_GPI_PIN_ROW_END ADP5589_GPI_PIN_ROW7 +-#define ADP5589_GPI_PIN_COL_BASE ADP5589_GPI_PIN_COL0 +-#define ADP5589_GPI_PIN_COL_END ADP5589_GPI_PIN_COL10 +- +-#define ADP5589_GPI_PIN_BASE ADP5589_GPI_PIN_ROW_BASE +-#define ADP5589_GPI_PIN_END ADP5589_GPI_PIN_COL_END +- +-#define ADP5589_GPIMAPSIZE_MAX (ADP5589_GPI_PIN_END - ADP5589_GPI_PIN_BASE + 1) +- +-/* +- * ADP5585 specific GPI and Keymap defines +- */ +- +-#define ADP5585_KEYMAPSIZE 30 +- +-#define ADP5585_GPI_PIN_ROW0 37 +-#define ADP5585_GPI_PIN_ROW1 38 +-#define ADP5585_GPI_PIN_ROW2 39 +-#define ADP5585_GPI_PIN_ROW3 40 +-#define ADP5585_GPI_PIN_ROW4 41 +-#define ADP5585_GPI_PIN_ROW5 42 +-#define ADP5585_GPI_PIN_COL0 43 +-#define ADP5585_GPI_PIN_COL1 44 +-#define ADP5585_GPI_PIN_COL2 45 +-#define ADP5585_GPI_PIN_COL3 46 +-#define ADP5585_GPI_PIN_COL4 47 +-#define GPI_LOGIC 48 +- +-#define ADP5585_GPI_PIN_ROW_BASE ADP5585_GPI_PIN_ROW0 +-#define ADP5585_GPI_PIN_ROW_END ADP5585_GPI_PIN_ROW5 +-#define ADP5585_GPI_PIN_COL_BASE ADP5585_GPI_PIN_COL0 +-#define ADP5585_GPI_PIN_COL_END ADP5585_GPI_PIN_COL4 +- +-#define ADP5585_GPI_PIN_BASE ADP5585_GPI_PIN_ROW_BASE +-#define ADP5585_GPI_PIN_END ADP5585_GPI_PIN_COL_END +- +-#define ADP5585_GPIMAPSIZE_MAX (ADP5585_GPI_PIN_END - ADP5585_GPI_PIN_BASE + 1) +- +-struct adp5589_gpi_map { +- unsigned short pin; +- unsigned short sw_evt; +-}; +- +-/* scan_cycle_time */ +-#define ADP5589_SCAN_CYCLE_10ms 0 +-#define ADP5589_SCAN_CYCLE_20ms 1 +-#define ADP5589_SCAN_CYCLE_30ms 2 +-#define ADP5589_SCAN_CYCLE_40ms 3 +- +-/* RESET_CFG */ +-#define RESET_PULSE_WIDTH_500us 0 +-#define RESET_PULSE_WIDTH_1ms 1 +-#define RESET_PULSE_WIDTH_2ms 2 +-#define RESET_PULSE_WIDTH_10ms 3 +- +-#define RESET_TRIG_TIME_0ms (0 << 2) +-#define RESET_TRIG_TIME_1000ms (1 << 2) +-#define RESET_TRIG_TIME_1500ms (2 << 2) +-#define RESET_TRIG_TIME_2000ms (3 << 2) +-#define RESET_TRIG_TIME_2500ms (4 << 2) +-#define RESET_TRIG_TIME_3000ms (5 << 2) +-#define RESET_TRIG_TIME_3500ms (6 << 2) +-#define RESET_TRIG_TIME_4000ms (7 << 2) +- +-#define RESET_PASSTHRU_EN (1 << 5) +-#define RESET1_POL_HIGH (1 << 6) +-#define RESET1_POL_LOW (0 << 6) +-#define RESET2_POL_HIGH (1 << 7) +-#define RESET2_POL_LOW (0 << 7) +- +-/* ADP5589 Mask Bits: +- * C C C C C C C C C C C | R R R R R R R R +- * 1 9 8 7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0 +- * 0 +- * ---------------- BIT ------------------ +- * 1 1 1 1 1 1 1 1 1 0 0 | 0 0 0 0 0 0 0 0 +- * 8 7 6 5 4 3 2 1 0 9 8 | 7 6 5 4 3 2 1 0 +- */ +- +-#define ADP_ROW(x) (1 << (x)) +-#define ADP_COL(x) (1 << (x + 8)) +-#define ADP5589_ROW_MASK 0xFF +-#define ADP5589_COL_MASK 0xFF +-#define ADP5589_COL_SHIFT 8 +-#define ADP5589_MAX_ROW_NUM 7 +-#define ADP5589_MAX_COL_NUM 10 +- +-/* ADP5585 Mask Bits: +- * C C C C C | R R R R R R +- * 4 3 2 1 0 | 5 4 3 2 1 0 +- * +- * ---- BIT -- ----------- +- * 1 0 0 0 0 | 0 0 0 0 0 0 +- * 0 9 8 7 6 | 5 4 3 2 1 0 +- */ +- +-#define ADP5585_ROW_MASK 0x3F +-#define ADP5585_COL_MASK 0x1F +-#define ADP5585_ROW_SHIFT 0 +-#define ADP5585_COL_SHIFT 6 +-#define ADP5585_MAX_ROW_NUM 5 +-#define ADP5585_MAX_COL_NUM 4 +- +-#define ADP5585_ROW(x) (1 << ((x) & ADP5585_ROW_MASK)) +-#define ADP5585_COL(x) (1 << (((x) & ADP5585_COL_MASK) + ADP5585_COL_SHIFT)) +- +-/* Put one of these structures in i2c_board_info platform_data */ +- +-struct adp5589_kpad_platform_data { +- unsigned keypad_en_mask; /* Keypad (Rows/Columns) enable mask */ +- const unsigned short *keymap; /* Pointer to keymap */ +- unsigned short keymapsize; /* Keymap size */ +- bool repeat; /* Enable key repeat */ +- bool en_keylock; /* Enable key lock feature (ADP5589 only)*/ +- unsigned char unlock_key1; /* Unlock Key 1 (ADP5589 only) */ +- unsigned char unlock_key2; /* Unlock Key 2 (ADP5589 only) */ +- unsigned char unlock_timer; /* Time in seconds [0..7] between the two unlock keys 0=disable (ADP5589 only) */ +- unsigned char scan_cycle_time; /* Time between consecutive scan cycles */ +- unsigned char reset_cfg; /* Reset config */ +- unsigned short reset1_key_1; /* Reset Key 1 */ +- unsigned short reset1_key_2; /* Reset Key 2 */ +- unsigned short reset1_key_3; /* Reset Key 3 */ +- unsigned short reset2_key_1; /* Reset Key 1 */ +- unsigned short reset2_key_2; /* Reset Key 2 */ +- unsigned debounce_dis_mask; /* Disable debounce mask */ +- unsigned pull_dis_mask; /* Disable all pull resistors mask */ +- unsigned pullup_en_100k; /* Pull-Up 100k Enable Mask */ +- unsigned pullup_en_300k; /* Pull-Up 300k Enable Mask */ +- unsigned pulldown_en_300k; /* Pull-Down 300k Enable Mask */ +- const struct adp5589_gpi_map *gpimap; +- unsigned short gpimapsize; +- const struct adp5589_gpio_platform_data *gpio_data; +-}; +- +-struct i2c_client; /* forward declaration */ +- +-struct adp5589_gpio_platform_data { +- int gpio_start; /* GPIO Chip base # */ +-}; +- +-#endif +-- +2.51.0 + diff --git a/queue-6.18/interconnect-mediatek-aggregate-bandwidth-with-satur.patch b/queue-6.18/interconnect-mediatek-aggregate-bandwidth-with-satur.patch new file mode 100644 index 0000000000..5356aab3ac --- /dev/null +++ b/queue-6.18/interconnect-mediatek-aggregate-bandwidth-with-satur.patch @@ -0,0 +1,54 @@ +From 42c35c5b393d286ba4a1634928342ba837d68e82 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 24 Nov 2025 12:07:02 +0100 +Subject: interconnect: mediatek: Aggregate bandwidth with saturating add + +From: Nicolas Frattaroli + +[ Upstream commit 6ffd02b82243d9907b5f5d2c7a2fc6a62669eece ] + +By using a regular non-overflow-checking add, the MediaTek icc-emi +driver will happy wrap at U32_MAX + 1 to 0. As it's common for the +interconnect core to fill in INT_MAX values, this is not a hypothetical +situation, but something that actually happens in regular use. This +would be pretty disasterous if anything used this driver. + +Replace the addition with an overflow-checked addition from overflow.h, +and saturate to U32_MAX if an overflow is detected. + +Fixes: b45293799f75 ("interconnect: mediatek: Add MediaTek MT8183/8195 EMI Interconnect driver") +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Nicolas Frattaroli +Link: https://lore.kernel.org/r/20251124-mt8196-dvfsrc-v2-13-d9c1334db9f3@collabora.com +Signed-off-by: Georgi Djakov +Signed-off-by: Sasha Levin +--- + drivers/interconnect/mediatek/icc-emi.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/interconnect/mediatek/icc-emi.c b/drivers/interconnect/mediatek/icc-emi.c +index 182aa2b0623af..dfa3a9cd93998 100644 +--- a/drivers/interconnect/mediatek/icc-emi.c ++++ b/drivers/interconnect/mediatek/icc-emi.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -22,7 +23,9 @@ static int mtk_emi_icc_aggregate(struct icc_node *node, u32 tag, u32 avg_bw, + { + struct mtk_icc_node *in = node->data; + +- *agg_avg += avg_bw; ++ if (check_add_overflow(*agg_avg, avg_bw, agg_avg)) ++ *agg_avg = U32_MAX; ++ + *agg_peak = max_t(u32, *agg_peak, peak_bw); + + in->sum_avg = *agg_avg; +-- +2.51.0 + diff --git a/queue-6.18/interconnect-mediatek-don-t-hijack-parent-device.patch b/queue-6.18/interconnect-mediatek-don-t-hijack-parent-device.patch new file mode 100644 index 0000000000..8365d34dcb --- /dev/null +++ b/queue-6.18/interconnect-mediatek-don-t-hijack-parent-device.patch @@ -0,0 +1,53 @@ +From c758cdb03aa0067dfaed01a40ae8e12267054d0c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 24 Nov 2025 12:07:01 +0100 +Subject: interconnect: mediatek: Don't hijack parent device + +From: Nicolas Frattaroli + +[ Upstream commit 510f8214440c553e81774c5822437ccf154e9e38 ] + +If the intention is that users of the interconnect declare their +relationship to the child icc_emi node of the dvfsrc controller, then +this code never worked. That's because it uses the parent dvfsrc device +as the device it passes to the interconnect core framework, which means +all the OF parsing is broken. + +Use the actual device instead, and pass the dvfsrc parent into the +dvfsrc calls. + +Fixes: b45293799f75 ("interconnect: mediatek: Add MediaTek MT8183/8195 EMI Interconnect driver") +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Nicolas Frattaroli +Link: https://lore.kernel.org/r/20251124-mt8196-dvfsrc-v2-12-d9c1334db9f3@collabora.com +Signed-off-by: Georgi Djakov +Signed-off-by: Sasha Levin +--- + drivers/interconnect/mediatek/icc-emi.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/interconnect/mediatek/icc-emi.c b/drivers/interconnect/mediatek/icc-emi.c +index 7da740b5fa8d6..182aa2b0623af 100644 +--- a/drivers/interconnect/mediatek/icc-emi.c ++++ b/drivers/interconnect/mediatek/icc-emi.c +@@ -40,7 +40,7 @@ static int mtk_emi_icc_set(struct icc_node *src, struct icc_node *dst) + if (unlikely(!src->provider)) + return -EINVAL; + +- dev = src->provider->dev; ++ dev = src->provider->dev->parent; + + switch (node->ep) { + case 0: +@@ -97,7 +97,7 @@ int mtk_emi_icc_probe(struct platform_device *pdev) + if (!data) + return -ENOMEM; + +- provider->dev = pdev->dev.parent; ++ provider->dev = dev; + provider->set = mtk_emi_icc_set; + provider->aggregate = mtk_emi_icc_aggregate; + provider->xlate = of_icc_xlate_onecell; +-- +2.51.0 + diff --git a/queue-6.18/io_uring-cancel-de-unionize-file-and-user_data-in-st.patch b/queue-6.18/io_uring-cancel-de-unionize-file-and-user_data-in-st.patch new file mode 100644 index 0000000000..7c58c56c1e --- /dev/null +++ b/queue-6.18/io_uring-cancel-de-unionize-file-and-user_data-in-st.patch @@ -0,0 +1,45 @@ +From d8c63bdb9e0a61d80c6c0bb47290879565fd9955 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 14:16:27 -0700 +Subject: io_uring/cancel: de-unionize file and user_data in struct + io_cancel_data + +From: Jens Axboe + +[ Upstream commit 22dbb0987bd1e0ec3b1e4ad20756a98f99aa4a08 ] + +By having them share the same space in struct io_cancel_data, it ends up +disallowing IORING_ASYNC_CANCEL_FD|IORING_ASYNC_CANCEL_USERDATA from +working. Eg you cannot match on both a file and user_data for +cancelation purposes. This obviously isn't a common use case as nobody +has reported this, but it does result in -ENOENT potentially being +returned when trying to match on both, rather than actually doing what +the API says it would. + +Fixes: 4bf94615b888 ("io_uring: allow IORING_OP_ASYNC_CANCEL with 'fd' key") +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + io_uring/cancel.h | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/io_uring/cancel.h b/io_uring/cancel.h +index 43e9bb74e9d19..eaa4069e258c9 100644 +--- a/io_uring/cancel.h ++++ b/io_uring/cancel.h +@@ -6,10 +6,8 @@ + + struct io_cancel_data { + struct io_ring_ctx *ctx; +- union { +- u64 data; +- struct file *file; +- }; ++ u64 data; ++ struct file *file; + u8 opcode; + u32 flags; + int seq; +-- +2.51.0 + diff --git a/queue-6.18/io_uring-delay-sqarray-static-branch-disablement.patch b/queue-6.18/io_uring-delay-sqarray-static-branch-disablement.patch new file mode 100644 index 0000000000..bf86257b8f --- /dev/null +++ b/queue-6.18/io_uring-delay-sqarray-static-branch-disablement.patch @@ -0,0 +1,66 @@ +From b61199e7aceca201f98a5ac312475b3dbe91ffea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 15 Feb 2026 22:06:52 +0000 +Subject: io_uring: delay sqarray static branch disablement + +From: Pavel Begunkov + +[ Upstream commit 56112578c71213a10c995a56835bddb5e9ab1ed0 ] + +io_key_has_sqarray static branch can be easily switched on/off by the +user every time patching the kernel. That can be very disruptive as it +might require heavy synchronisation across all CPUs. Use deferred static +keys, which can rate-limit it by deferring, batching and potentially +effectively eliminating dec+inc pairs. + +Fixes: 9b296c625ac1d ("io_uring: static_key for !IORING_SETUP_NO_SQARRAY") +Signed-off-by: Pavel Begunkov +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + io_uring/io_uring.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c +index d8a35a49dd1ac..65af47b9135b8 100644 +--- a/io_uring/io_uring.c ++++ b/io_uring/io_uring.c +@@ -148,7 +148,7 @@ static bool io_uring_try_cancel_requests(struct io_ring_ctx *ctx, + static void io_queue_sqe(struct io_kiocb *req, unsigned int extra_flags); + static void __io_req_caches_free(struct io_ring_ctx *ctx); + +-static __read_mostly DEFINE_STATIC_KEY_FALSE(io_key_has_sqarray); ++static __read_mostly DEFINE_STATIC_KEY_DEFERRED_FALSE(io_key_has_sqarray, HZ); + + struct kmem_cache *req_cachep; + static struct workqueue_struct *iou_wq __ro_after_init; +@@ -2390,7 +2390,7 @@ static bool io_get_sqe(struct io_ring_ctx *ctx, const struct io_uring_sqe **sqe) + unsigned mask = ctx->sq_entries - 1; + unsigned head = ctx->cached_sq_head++ & mask; + +- if (static_branch_unlikely(&io_key_has_sqarray) && ++ if (static_branch_unlikely(&io_key_has_sqarray.key) && + (!(ctx->flags & IORING_SETUP_NO_SQARRAY))) { + head = READ_ONCE(ctx->sq_array[head]); + if (unlikely(head >= ctx->sq_entries)) { +@@ -2869,7 +2869,7 @@ static __cold void io_ring_ctx_free(struct io_ring_ctx *ctx) + io_rings_free(ctx); + + if (!(ctx->flags & IORING_SETUP_NO_SQARRAY)) +- static_branch_dec(&io_key_has_sqarray); ++ static_branch_slow_dec_deferred(&io_key_has_sqarray); + + percpu_ref_exit(&ctx->refs); + free_uid(ctx->user); +@@ -3817,7 +3817,7 @@ static __cold int io_uring_create(unsigned entries, struct io_uring_params *p, + ctx->clock_offset = 0; + + if (!(ctx->flags & IORING_SETUP_NO_SQARRAY)) +- static_branch_inc(&io_key_has_sqarray); ++ static_branch_deferred_inc(&io_key_has_sqarray); + + if ((ctx->flags & IORING_SETUP_DEFER_TASKRUN) && + !(ctx->flags & IORING_SETUP_IOPOLL) && +-- +2.51.0 + diff --git a/queue-6.18/io_uring-eventfd-remove-unused-ctx-evfd_last_cq_tail.patch b/queue-6.18/io_uring-eventfd-remove-unused-ctx-evfd_last_cq_tail.patch new file mode 100644 index 0000000000..5c6b10d607 --- /dev/null +++ b/queue-6.18/io_uring-eventfd-remove-unused-ctx-evfd_last_cq_tail.patch @@ -0,0 +1,47 @@ +From fcad8c23e08f2e79a1da4a5ae436bf83e19990a7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 11:21:32 -0700 +Subject: io_uring/eventfd: remove unused ctx->evfd_last_cq_tail member + +From: Jens Axboe + +[ Upstream commit 07f3c3a1cd56c2048a92dad0c11f15e4ac3888c1 ] + +A previous commit got rid of any use of this member, but forgot to +remove it. Kill it. + +Fixes: f4bb2f65bb81 ("io_uring/eventfd: move ctx->evfd_last_cq_tail into io_ev_fd") +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + include/linux/io_uring_types.h | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/include/linux/io_uring_types.h b/include/linux/io_uring_types.h +index c2ea6280901dc..b4d8aca3e7860 100644 +--- a/include/linux/io_uring_types.h ++++ b/include/linux/io_uring_types.h +@@ -439,6 +439,9 @@ struct io_ring_ctx { + struct list_head defer_list; + unsigned nr_drained; + ++ /* protected by ->completion_lock */ ++ unsigned nr_req_allocated; ++ + #ifdef CONFIG_NET_RX_BUSY_POLL + struct list_head napi_list; /* track busy poll napi_id */ + spinlock_t napi_lock; /* napi_list lock */ +@@ -451,10 +454,6 @@ struct io_ring_ctx { + DECLARE_HASHTABLE(napi_ht, 4); + #endif + +- /* protected by ->completion_lock */ +- unsigned evfd_last_cq_tail; +- unsigned nr_req_allocated; +- + /* + * Protection for resize vs mmap races - both the mmap and resize + * side will need to grab this lock, to prevent either side from +-- +2.51.0 + diff --git a/queue-6.18/io_uring-kbuf-fix-memory-leak-if-io_buffer_add_list-.patch b/queue-6.18/io_uring-kbuf-fix-memory-leak-if-io_buffer_add_list-.patch new file mode 100644 index 0000000000..6f21938486 --- /dev/null +++ b/queue-6.18/io_uring-kbuf-fix-memory-leak-if-io_buffer_add_list-.patch @@ -0,0 +1,43 @@ +From d8c242ca05788f313642a7427a368531dfc6fbb3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 08:38:20 -0700 +Subject: io_uring/kbuf: fix memory leak if io_buffer_add_list fails + +From: Jens Axboe + +[ Upstream commit 442ae406603a94f1a263654494f425302ceb0445 ] + +io_register_pbuf_ring() ignores the return value of io_buffer_add_list(), +which can fail if xa_store() returns an error (e.g., -ENOMEM). When this +happens, the function returns 0 (success) to the caller, but the +io_buffer_list structure is neither added to the xarray nor freed. + +In practice this requires failure injection to hit, hence not a real +issue. But it should get fixed up none the less. + +Fixes: c7fb19428d67 ("io_uring: add support for ring mapped supplied buffers") +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + io_uring/kbuf.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/io_uring/kbuf.c b/io_uring/kbuf.c +index d974381d93ff7..308ef71bcb286 100644 +--- a/io_uring/kbuf.c ++++ b/io_uring/kbuf.c +@@ -669,8 +669,9 @@ int io_register_pbuf_ring(struct io_ring_ctx *ctx, void __user *arg) + bl->buf_ring = br; + if (reg.flags & IOU_PBUF_RING_INC) + bl->flags |= IOBL_INC; +- io_buffer_add_list(ctx, bl, reg.bgid); +- return 0; ++ ret = io_buffer_add_list(ctx, bl, reg.bgid); ++ if (!ret) ++ return 0; + fail: + io_free_region(ctx, &bl->region); + kfree(bl); +-- +2.51.0 + diff --git a/queue-6.18/io_uring-sync-validate-passed-in-offset.patch b/queue-6.18/io_uring-sync-validate-passed-in-offset.patch new file mode 100644 index 0000000000..0b3876be41 --- /dev/null +++ b/queue-6.18/io_uring-sync-validate-passed-in-offset.patch @@ -0,0 +1,36 @@ +From 7878cffc353204c11aadd863c4a56cc42d519ffe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 11:48:56 -0700 +Subject: io_uring/sync: validate passed in offset + +From: Jens Axboe + +[ Upstream commit 649dd18f559891bdafc5532d737c7dfb56060a6d ] + +Check if the passed in offset is negative once cast to sync->off. This +ensures that -EINVAL is returned for that case, like it would be for +sync_file_range(2). + +Fixes: c992fe2925d7 ("io_uring: add fsync support") +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + io_uring/sync.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/io_uring/sync.c b/io_uring/sync.c +index cea2d381ffd2a..ab7fa1cd7dd63 100644 +--- a/io_uring/sync.c ++++ b/io_uring/sync.c +@@ -62,6 +62,8 @@ int io_fsync_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) + return -EINVAL; + + sync->off = READ_ONCE(sqe->off); ++ if (sync->off < 0) ++ return -EINVAL; + sync->len = READ_ONCE(sqe->len); + req->flags |= REQ_F_FORCE_ASYNC; + return 0; +-- +2.51.0 + diff --git a/queue-6.18/io_uring-use-release-acquire-ordering-for-ioring_set.patch b/queue-6.18/io_uring-use-release-acquire-ordering-for-ioring_set.patch new file mode 100644 index 0000000000..4da8983110 --- /dev/null +++ b/queue-6.18/io_uring-use-release-acquire-ordering-for-ioring_set.patch @@ -0,0 +1,93 @@ +From 709fb3b332235757610666b2008e28198eabc213 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Jan 2026 14:05:40 -0700 +Subject: io_uring: use release-acquire ordering for IORING_SETUP_R_DISABLED + +From: Caleb Sander Mateos + +[ Upstream commit 7a8737e1132ff07ca225aa7a4008f87319b5b1ca ] + +io_uring_enter(), __io_msg_ring_data(), and io_msg_send_fd() read +ctx->flags and ctx->submitter_task without holding the ctx's uring_lock. +This means they may race with the assignment to ctx->submitter_task and +the clearing of IORING_SETUP_R_DISABLED from ctx->flags in +io_register_enable_rings(). Ensure the correct ordering of the +ctx->flags and ctx->submitter_task memory accesses by storing to +ctx->flags using release ordering and loading it using acquire ordering. + +Signed-off-by: Caleb Sander Mateos +Fixes: 4add705e4eeb ("io_uring: remove io_register_submitter") +Reviewed-by: Joanne Koong +Reviewed-by: Gabriel Krisman Bertazi +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + io_uring/io_uring.c | 6 +++++- + io_uring/msg_ring.c | 12 ++++++++++-- + io_uring/register.c | 3 ++- + 3 files changed, 17 insertions(+), 4 deletions(-) + +diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c +index 104192bcc8e4b..d8a35a49dd1ac 100644 +--- a/io_uring/io_uring.c ++++ b/io_uring/io_uring.c +@@ -3490,7 +3490,11 @@ SYSCALL_DEFINE6(io_uring_enter, unsigned int, fd, u32, to_submit, + + ctx = file->private_data; + ret = -EBADFD; +- if (unlikely(ctx->flags & IORING_SETUP_R_DISABLED)) ++ /* ++ * Keep IORING_SETUP_R_DISABLED check before submitter_task load ++ * in io_uring_add_tctx_node() -> __io_uring_add_tctx_node_from_submit() ++ */ ++ if (unlikely(smp_load_acquire(&ctx->flags) & IORING_SETUP_R_DISABLED)) + goto out; + + /* +diff --git a/io_uring/msg_ring.c b/io_uring/msg_ring.c +index 5e5b94236d720..bce74a8b64c6e 100644 +--- a/io_uring/msg_ring.c ++++ b/io_uring/msg_ring.c +@@ -124,7 +124,11 @@ static int __io_msg_ring_data(struct io_ring_ctx *target_ctx, + return -EINVAL; + if (!(msg->flags & IORING_MSG_RING_FLAGS_PASS) && msg->dst_fd) + return -EINVAL; +- if (target_ctx->flags & IORING_SETUP_R_DISABLED) ++ /* ++ * Keep IORING_SETUP_R_DISABLED check before submitter_task load ++ * in io_msg_data_remote() -> io_msg_remote_post() ++ */ ++ if (smp_load_acquire(&target_ctx->flags) & IORING_SETUP_R_DISABLED) + return -EBADFD; + + if (io_msg_need_remote(target_ctx)) +@@ -244,7 +248,11 @@ static int io_msg_send_fd(struct io_kiocb *req, unsigned int issue_flags) + return -EINVAL; + if (target_ctx == ctx) + return -EINVAL; +- if (target_ctx->flags & IORING_SETUP_R_DISABLED) ++ /* ++ * Keep IORING_SETUP_R_DISABLED check before submitter_task load ++ * in io_msg_fd_remote() ++ */ ++ if (smp_load_acquire(&target_ctx->flags) & IORING_SETUP_R_DISABLED) + return -EBADFD; + if (!msg->src_file) { + int ret = io_msg_grab_file(req, issue_flags); +diff --git a/io_uring/register.c b/io_uring/register.c +index d189b266b8cce..db53e664348d7 100644 +--- a/io_uring/register.c ++++ b/io_uring/register.c +@@ -193,7 +193,8 @@ static int io_register_enable_rings(struct io_ring_ctx *ctx) + if (ctx->restrictions.registered) + ctx->restricted = 1; + +- ctx->flags &= ~IORING_SETUP_R_DISABLED; ++ /* Keep submitter_task store before clearing IORING_SETUP_R_DISABLED */ ++ smp_store_release(&ctx->flags, ctx->flags & ~IORING_SETUP_R_DISABLED); + if (ctx->sq_data && wq_has_sleeper(&ctx->sq_data->wait)) + wake_up(&ctx->sq_data->wait); + return 0; +-- +2.51.0 + diff --git a/queue-6.18/iomap-fix-submission-side-handling-of-completion-sid.patch b/queue-6.18/iomap-fix-submission-side-handling-of-completion-sid.patch new file mode 100644 index 0000000000..2df68bced7 --- /dev/null +++ b/queue-6.18/iomap-fix-submission-side-handling-of-completion-sid.patch @@ -0,0 +1,49 @@ +From f574cc1ab4d94937357672184b96c803f185b6c0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 06:53:38 +0100 +Subject: iomap: fix submission side handling of completion side errors + +From: Christoph Hellwig + +[ Upstream commit 4ad357e39b2ecd5da7bcc7e840ee24d179593cd5 ] + +The "if (dio->error)" in iomap_dio_bio_iter exists to stop submitting +more bios when a completion already return an error. Commit cfe057f7db1f +("iomap_dio_actor(): fix iov_iter bugs") made it revert the iov by +"copied", which is very wrong given that we've already consumed that +range and submitted a bio for it. + +Fixes: cfe057f7db1f ("iomap_dio_actor(): fix iov_iter bugs") +Signed-off-by: Christoph Hellwig +Reviewed-by: Damien Le Moal +Reviewed-by: Darrick J. Wong +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + fs/iomap/direct-io.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/fs/iomap/direct-io.c b/fs/iomap/direct-io.c +index 6317e4cd42517..e73c71f39bd45 100644 +--- a/fs/iomap/direct-io.c ++++ b/fs/iomap/direct-io.c +@@ -429,9 +429,13 @@ static int iomap_dio_bio_iter(struct iomap_iter *iter, struct iomap_dio *dio) + nr_pages = bio_iov_vecs_to_alloc(dio->submit.iter, BIO_MAX_VECS); + do { + size_t n; +- if (dio->error) { +- iov_iter_revert(dio->submit.iter, copied); +- copied = ret = 0; ++ ++ /* ++ * If completions already occurred and reported errors, give up now and ++ * don't bother submitting more bios. ++ */ ++ if (unlikely(data_race(dio->error))) { ++ ret = 0; + goto out; + } + +-- +2.51.0 + diff --git a/queue-6.18/iommu-amd-use-core-s-primary-handler-and-set-irqf_on.patch b/queue-6.18/iommu-amd-use-core-s-primary-handler-and-set-irqf_on.patch new file mode 100644 index 0000000000..90ee4695d6 --- /dev/null +++ b/queue-6.18/iommu-amd-use-core-s-primary-handler-and-set-irqf_on.patch @@ -0,0 +1,95 @@ +From 572814d784832e804ea3dd5d749aa27b912567af Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:55:23 +0100 +Subject: iommu/amd: Use core's primary handler and set IRQF_ONESHOT + +From: Sebastian Andrzej Siewior + +[ Upstream commit 5bfcdccb4d18d3909b7f87942be67fd6bdc00c1d ] + +request_threaded_irq() is invoked with a primary and a secondary handler +and no flags are passed. The primary handler is the same as +irq_default_primary_handler() so there is no need to have an identical +copy. + +The lack of the IRQF_ONESHOT can be dangerous because the interrupt +source is not masked while the threaded handler is active. This means, +especially on LEVEL typed interrupt lines, the interrupt can fire again +before the threaded handler had a chance to run. + +Use the default primary interrupt handler by specifying NULL and set +IRQF_ONESHOT so the interrupt source is masked until the secondary +handler is done. + +Fixes: 72fe00f01f9a3 ("x86/amd-iommu: Use threaded interupt handler") +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260128095540.863589-4-bigeasy@linutronix.de +Signed-off-by: Sasha Levin +--- + drivers/iommu/amd/amd_iommu.h | 1 - + drivers/iommu/amd/init.c | 12 ++++-------- + drivers/iommu/amd/iommu.c | 5 ----- + 3 files changed, 4 insertions(+), 14 deletions(-) + +diff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h +index 9b4b589a54b57..bf77fdf5529f4 100644 +--- a/drivers/iommu/amd/amd_iommu.h ++++ b/drivers/iommu/amd/amd_iommu.h +@@ -15,7 +15,6 @@ irqreturn_t amd_iommu_int_thread(int irq, void *data); + irqreturn_t amd_iommu_int_thread_evtlog(int irq, void *data); + irqreturn_t amd_iommu_int_thread_pprlog(int irq, void *data); + irqreturn_t amd_iommu_int_thread_galog(int irq, void *data); +-irqreturn_t amd_iommu_int_handler(int irq, void *data); + void amd_iommu_restart_log(struct amd_iommu *iommu, const char *evt_type, + u8 cntrl_intr, u8 cntrl_log, + u32 status_run_mask, u32 status_overflow_mask); +diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c +index 034edce816d01..53afb1cb0a6fc 100644 +--- a/drivers/iommu/amd/init.c ++++ b/drivers/iommu/amd/init.c +@@ -2355,12 +2355,8 @@ static int iommu_setup_msi(struct amd_iommu *iommu) + if (r) + return r; + +- r = request_threaded_irq(iommu->dev->irq, +- amd_iommu_int_handler, +- amd_iommu_int_thread, +- 0, "AMD-Vi", +- iommu); +- ++ r = request_threaded_irq(iommu->dev->irq, NULL, amd_iommu_int_thread, ++ IRQF_ONESHOT, "AMD-Vi", iommu); + if (r) { + pci_disable_msi(iommu->dev); + return r; +@@ -2534,8 +2530,8 @@ static int __iommu_setup_intcapxt(struct amd_iommu *iommu, const char *devname, + return irq; + } + +- ret = request_threaded_irq(irq, amd_iommu_int_handler, +- thread_fn, 0, devname, iommu); ++ ret = request_threaded_irq(irq, NULL, thread_fn, IRQF_ONESHOT, devname, ++ iommu); + if (ret) { + irq_domain_free_irqs(irq, 1); + irq_domain_remove(domain); +diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c +index 5914bef0c8c19..30dd482fe0953 100644 +--- a/drivers/iommu/amd/iommu.c ++++ b/drivers/iommu/amd/iommu.c +@@ -1146,11 +1146,6 @@ irqreturn_t amd_iommu_int_thread(int irq, void *data) + return IRQ_HANDLED; + } + +-irqreturn_t amd_iommu_int_handler(int irq, void *data) +-{ +- return IRQ_WAKE_THREAD; +-} +- + /**************************************************************************** + * + * IOMMU command queuing functions +-- +2.51.0 + diff --git a/queue-6.18/iommu-vt-d-clear-present-bit-before-tearing-down-con.patch b/queue-6.18/iommu-vt-d-clear-present-bit-before-tearing-down-con.patch new file mode 100644 index 0000000000..61a56353bf --- /dev/null +++ b/queue-6.18/iommu-vt-d-clear-present-bit-before-tearing-down-con.patch @@ -0,0 +1,128 @@ +From 6f495cc487be038240fadc7fa70cdfbf148a21eb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 09:48:55 +0800 +Subject: iommu/vt-d: Clear Present bit before tearing down context entry +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Lu Baolu + +[ Upstream commit c1e4f1dccbe9d7656d1c6872ebeadb5992d0aaa2 ] + +When tearing down a context entry, the current implementation zeros the +entire 128-bit entry using multiple 64-bit writes. This creates a window +where the hardware can fetch a "torn" entry — where some fields are +already zeroed while the 'Present' bit is still set — leading to +unpredictable behavior or spurious faults. + +While x86 provides strong write ordering, the compiler may reorder writes +to the two 64-bit halves of the context entry. Even without compiler +reordering, the hardware fetch is not guaranteed to be atomic with +respect to multiple CPU writes. + +Align with the "Guidance to Software for Invalidations" in the VT-d spec +(Section 6.5.3.3) by implementing the recommended ownership handshake: + +1. Clear only the 'Present' (P) bit of the context entry first to + signal the transition of ownership from hardware to software. +2. Use dma_wmb() to ensure the cleared bit is visible to the IOMMU. +3. Perform the required cache and context-cache invalidation to ensure + hardware no longer has cached references to the entry. +4. Fully zero out the entry only after the invalidation is complete. + +Also, add a dma_wmb() to context_set_present() to ensure the entry +is fully initialized before the 'Present' bit becomes visible. + +Fixes: ba39592764ed2 ("Intel IOMMU: Intel IOMMU driver") +Reported-by: Dmytro Maluka +Closes: https://lore.kernel.org/all/aTG7gc7I5wExai3S@google.com/ +Signed-off-by: Lu Baolu +Reviewed-by: Dmytro Maluka +Reviewed-by: Samiullah Khawaja +Reviewed-by: Kevin Tian +Link: https://lore.kernel.org/r/20260120061816.2132558-3-baolu.lu@linux.intel.com +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/intel/iommu.c | 4 +++- + drivers/iommu/intel/iommu.h | 21 ++++++++++++++++++++- + drivers/iommu/intel/pasid.c | 5 ++++- + 3 files changed, 27 insertions(+), 3 deletions(-) + +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index e236c7ec221f4..49e83c8566a32 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -1722,10 +1722,12 @@ static void domain_context_clear_one(struct device_domain_info *info, u8 bus, u8 + } + + did = context_domain_id(context); +- context_clear_entry(context); ++ context_clear_present(context); + __iommu_flush_cache(iommu, context, sizeof(*context)); + spin_unlock(&iommu->lock); + intel_context_flush_no_pasid(info, context, did); ++ context_clear_entry(context); ++ __iommu_flush_cache(iommu, context, sizeof(*context)); + } + + int __domain_setup_first_level(struct intel_iommu *iommu, struct device *dev, +diff --git a/drivers/iommu/intel/iommu.h b/drivers/iommu/intel/iommu.h +index dcc5466d35f93..9198ac7f6bbab 100644 +--- a/drivers/iommu/intel/iommu.h ++++ b/drivers/iommu/intel/iommu.h +@@ -969,7 +969,26 @@ static inline unsigned long lvl_to_nr_pages(unsigned int lvl) + + static inline void context_set_present(struct context_entry *context) + { +- context->lo |= 1; ++ u64 val; ++ ++ dma_wmb(); ++ val = READ_ONCE(context->lo) | 1; ++ WRITE_ONCE(context->lo, val); ++} ++ ++/* ++ * Clear the Present (P) bit (bit 0) of a context table entry. This initiates ++ * the transition of the entry's ownership from hardware to software. The ++ * caller is responsible for fulfilling the invalidation handshake recommended ++ * by the VT-d spec, Section 6.5.3.3 (Guidance to Software for Invalidations). ++ */ ++static inline void context_clear_present(struct context_entry *context) ++{ ++ u64 val; ++ ++ val = READ_ONCE(context->lo) & GENMASK_ULL(63, 1); ++ WRITE_ONCE(context->lo, val); ++ dma_wmb(); + } + + static inline void context_set_fault_enable(struct context_entry *context) +diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c +index f64b5ae306d0f..d13099a6cb9c3 100644 +--- a/drivers/iommu/intel/pasid.c ++++ b/drivers/iommu/intel/pasid.c +@@ -1028,7 +1028,7 @@ static int device_pasid_table_setup(struct device *dev, u8 bus, u8 devfn) + } + + if (context_copied(iommu, bus, devfn)) { +- context_clear_entry(context); ++ context_clear_present(context); + __iommu_flush_cache(iommu, context, sizeof(*context)); + + /* +@@ -1048,6 +1048,9 @@ static int device_pasid_table_setup(struct device *dev, u8 bus, u8 devfn) + iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH); + devtlb_invalidation_with_pasid(iommu, dev, IOMMU_NO_PASID); + ++ context_clear_entry(context); ++ __iommu_flush_cache(iommu, context, sizeof(*context)); ++ + /* + * At this point, the device is supposed to finish reset at + * its driver probe stage, so no in-flight DMA will exist, +-- +2.51.0 + diff --git a/queue-6.18/iommu-vt-d-clear-present-bit-before-tearing-down-pas.patch b/queue-6.18/iommu-vt-d-clear-present-bit-before-tearing-down-pas.patch new file mode 100644 index 0000000000..d069972782 --- /dev/null +++ b/queue-6.18/iommu-vt-d-clear-present-bit-before-tearing-down-pas.patch @@ -0,0 +1,104 @@ +From 9685e73ca7ac2458fd803b6c9af48cee465d6d28 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 09:48:54 +0800 +Subject: iommu/vt-d: Clear Present bit before tearing down PASID entry + +From: Lu Baolu + +[ Upstream commit 75ed00055c059dedc47b5daaaa2f8a7a019138ff ] + +The Intel VT-d Scalable Mode PASID table entry consists of 512 bits (64 +bytes). When tearing down an entry, the current implementation zeros the +entire 64-byte structure immediately using multiple 64-bit writes. + +Since the IOMMU hardware may fetch these 64 bytes using multiple +internal transactions (e.g., four 128-bit bursts), updating or zeroing +the entire entry while it is active (P=1) risks a "torn" read. If a +hardware fetch occurs simultaneously with the CPU zeroing the entry, the +hardware could observe an inconsistent state, leading to unpredictable +behavior or spurious faults. + +Follow the "Guidance to Software for Invalidations" in the VT-d spec +(Section 6.5.3.3) by implementing the recommended ownership handshake: + +1. Clear only the 'Present' (P) bit of the PASID entry. +2. Use a dma_wmb() to ensure the cleared bit is visible to hardware + before proceeding. +3. Execute the required invalidation sequence (PASID cache, IOTLB, and + Device-TLB flush) to ensure the hardware has released all cached + references. +4. Only after the flushes are complete, zero out the remaining fields + of the PASID entry. + +Also, add a dma_wmb() in pasid_set_present() to ensure that all other +fields of the PASID entry are visible to the hardware before the Present +bit is set. + +Fixes: 0bbeb01a4faf ("iommu/vt-d: Manage scalalble mode PASID tables") +Signed-off-by: Lu Baolu +Reviewed-by: Dmytro Maluka +Reviewed-by: Samiullah Khawaja +Reviewed-by: Kevin Tian +Link: https://lore.kernel.org/r/20260120061816.2132558-2-baolu.lu@linux.intel.com +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/intel/pasid.c | 6 +++++- + drivers/iommu/intel/pasid.h | 14 ++++++++++++++ + 2 files changed, 19 insertions(+), 1 deletion(-) + +diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c +index 67cbf53d18c8f..f64b5ae306d0f 100644 +--- a/drivers/iommu/intel/pasid.c ++++ b/drivers/iommu/intel/pasid.c +@@ -273,7 +273,7 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev, + + did = pasid_get_domain_id(pte); + pgtt = pasid_pte_get_pgtt(pte); +- intel_pasid_clear_entry(dev, pasid, fault_ignore); ++ pasid_clear_present(pte); + spin_unlock(&iommu->lock); + + if (!ecap_coherent(iommu->ecap)) +@@ -287,6 +287,10 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev, + iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH); + + devtlb_invalidation_with_pasid(iommu, dev, pasid); ++ intel_pasid_clear_entry(dev, pasid, fault_ignore); ++ if (!ecap_coherent(iommu->ecap)) ++ clflush_cache_range(pte, sizeof(*pte)); ++ + if (!fault_ignore) + intel_iommu_drain_pasid_prq(dev, pasid); + } +diff --git a/drivers/iommu/intel/pasid.h b/drivers/iommu/intel/pasid.h +index a771a77d4239c..637373995be80 100644 +--- a/drivers/iommu/intel/pasid.h ++++ b/drivers/iommu/intel/pasid.h +@@ -233,9 +233,23 @@ static inline void pasid_set_wpe(struct pasid_entry *pe) + */ + static inline void pasid_set_present(struct pasid_entry *pe) + { ++ dma_wmb(); + pasid_set_bits(&pe->val[0], 1 << 0, 1); + } + ++/* ++ * Clear the Present (P) bit (bit 0) of a scalable-mode PASID table entry. ++ * This initiates the transition of the entry's ownership from hardware ++ * to software. The caller is responsible for fulfilling the invalidation ++ * handshake recommended by the VT-d spec, Section 6.5.3.3 (Guidance to ++ * Software for Invalidations). ++ */ ++static inline void pasid_clear_present(struct pasid_entry *pe) ++{ ++ pasid_set_bits(&pe->val[0], 1 << 0, 0); ++ dma_wmb(); ++} ++ + /* + * Setup Page Walk Snoop bit (Bit 87) of a scalable mode PASID + * entry. +-- +2.51.0 + diff --git a/queue-6.18/iommu-vt-d-flush-cache-for-pasid-table-before-using-.patch b/queue-6.18/iommu-vt-d-flush-cache-for-pasid-table-before-using-.patch new file mode 100644 index 0000000000..adc8d9b3f6 --- /dev/null +++ b/queue-6.18/iommu-vt-d-flush-cache-for-pasid-table-before-using-.patch @@ -0,0 +1,55 @@ +From f9d85cd783131364d85fd3790901c56a906f59db Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 09:48:52 +0800 +Subject: iommu/vt-d: Flush cache for PASID table before using it + +From: Dmytro Maluka + +[ Upstream commit 22d169bdd2849fe6bd18c2643742e1c02be6451c ] + +When writing the address of a freshly allocated zero-initialized PASID +table to a PASID directory entry, do that after the CPU cache flush for +this PASID table, not before it, to avoid the time window when this +PASID table may be already used by non-coherent IOMMU hardware while +its contents in RAM is still some random old data, not zero-initialized. + +Fixes: 194b3348bdbb ("iommu/vt-d: Fix PASID directory pointer coherency") +Signed-off-by: Dmytro Maluka +Reviewed-by: Kevin Tian +Link: https://lore.kernel.org/r/20251221123508.37495-1-dmaluka@chromium.org +Signed-off-by: Lu Baolu +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/intel/pasid.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c +index 52f678975da74..67cbf53d18c8f 100644 +--- a/drivers/iommu/intel/pasid.c ++++ b/drivers/iommu/intel/pasid.c +@@ -153,6 +153,9 @@ static struct pasid_entry *intel_pasid_get_entry(struct device *dev, u32 pasid) + if (!entries) + return NULL; + ++ if (!ecap_coherent(info->iommu->ecap)) ++ clflush_cache_range(entries, VTD_PAGE_SIZE); ++ + /* + * The pasid directory table entry won't be freed after + * allocation. No worry about the race with free and +@@ -165,10 +168,8 @@ static struct pasid_entry *intel_pasid_get_entry(struct device *dev, u32 pasid) + iommu_free_pages(entries); + goto retry; + } +- if (!ecap_coherent(info->iommu->ecap)) { +- clflush_cache_range(entries, VTD_PAGE_SIZE); ++ if (!ecap_coherent(info->iommu->ecap)) + clflush_cache_range(&dir[dir_index].val, sizeof(*dir)); +- } + } + + return &entries[index]; +-- +2.51.0 + diff --git a/queue-6.18/ionic-rate-limit-unknown-xcvr-type-messages.patch b/queue-6.18/ionic-rate-limit-unknown-xcvr-type-messages.patch new file mode 100644 index 0000000000..703f9f5513 --- /dev/null +++ b/queue-6.18/ionic-rate-limit-unknown-xcvr-type-messages.patch @@ -0,0 +1,51 @@ +From a7a22c782c3a173b7ced1788d756c9dcae822377 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 14:46:51 -0800 +Subject: ionic: Rate limit unknown xcvr type messages + +From: Eric Joyner + +[ Upstream commit cdb1634de3bf197c0d86487d1fb84c128a79cc7c ] + +Running ethtool repeatedly with a transceiver unknown to the driver or +firmware will cause the driver to spam the kernel logs with "unknown +xcvr type" messages which can distract from real issues; and this isn't +interesting information outside of debugging. Fix this by rate limiting +the output so that there are still notifications but not so many that +they flood the log. + +Using dev_dbg_once() would reduce the number of messages further, but +this would miss the case where a different unknown transceiver type is +plugged in, and its status is requested. + +Fixes: 4d03e00a2140 ("ionic: Add initial ethtool support") +Signed-off-by: Eric Joyner +Reviewed-by: Brett Creeley +Link: https://patch.msgid.link/20260206224651.1491-1-eric.joyner@amd.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/pensando/ionic/ionic_ethtool.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c +index 2d9efadb5d2ae..347b0aff100b9 100644 +--- a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c ++++ b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c +@@ -263,9 +263,10 @@ static int ionic_get_link_ksettings(struct net_device *netdev, + /* This means there's no module plugged in */ + break; + default: +- dev_info(lif->ionic->dev, "unknown xcvr type pid=%d / 0x%x\n", +- idev->port_info->status.xcvr.pid, +- idev->port_info->status.xcvr.pid); ++ dev_dbg_ratelimited(lif->ionic->dev, ++ "unknown xcvr type pid=%d / 0x%x\n", ++ idev->port_info->status.xcvr.pid, ++ idev->port_info->status.xcvr.pid); + break; + } + +-- +2.51.0 + diff --git a/queue-6.18/ipc-don-t-audit-capability-check-in-ipc_permissions.patch b/queue-6.18/ipc-don-t-audit-capability-check-in-ipc_permissions.patch new file mode 100644 index 0000000000..bcb0ec444d --- /dev/null +++ b/queue-6.18/ipc-don-t-audit-capability-check-in-ipc_permissions.patch @@ -0,0 +1,66 @@ +From 83f72e4c373d68cdcdd9839f1ab6f6de89894b1a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 15:13:03 +0100 +Subject: ipc: don't audit capability check in ipc_permissions() + +From: Ondrej Mosnacek + +[ Upstream commit 071588136007482d70fd2667b827036bc60b1f8f ] + +The IPC sysctls implement the ctl_table_root::permissions hook and +they override the file access mode based on the CAP_CHECKPOINT_RESTORE +capability, which is being checked regardless of whether any access is +actually denied or not, so if an LSM denies the capability, an audit +record may be logged even when access is in fact granted. + +It wouldn't be viable to restructure the sysctl permission logic to only +check the capability when the access would be actually denied if it's +not granted. Thus, do the same as in net_ctl_permissions() +(net/sysctl_net.c) - switch from ns_capable() to ns_capable_noaudit(), +so that the check never emits an audit record. + +Fixes: 0889f44e2810 ("ipc: Check permissions for checkpoint_restart sysctls at open time") +Signed-off-by: Ondrej Mosnacek +Acked-by: Alexey Gladkov +Acked-by: Serge Hallyn +Signed-off-by: Serge Hallyn +Stable-dep-of: 8924336531e2 ("ipc: don't audit capability check in ipc_permissions()") +Signed-off-by: Sasha Levin +--- + include/linux/capability.h | 6 ++++++ + ipc/ipc_sysctl.c | 2 +- + 2 files changed, 7 insertions(+), 1 deletion(-) + +diff --git a/include/linux/capability.h b/include/linux/capability.h +index 1fb08922552c7..37db92b3d6f89 100644 +--- a/include/linux/capability.h ++++ b/include/linux/capability.h +@@ -203,6 +203,12 @@ static inline bool checkpoint_restore_ns_capable(struct user_namespace *ns) + ns_capable(ns, CAP_SYS_ADMIN); + } + ++static inline bool checkpoint_restore_ns_capable_noaudit(struct user_namespace *ns) ++{ ++ return ns_capable_noaudit(ns, CAP_CHECKPOINT_RESTORE) || ++ ns_capable_noaudit(ns, CAP_SYS_ADMIN); ++} ++ + /* audit system wants to get cap info from files as well */ + int get_vfs_caps_from_disk(struct mnt_idmap *idmap, + const struct dentry *dentry, +diff --git a/ipc/ipc_sysctl.c b/ipc/ipc_sysctl.c +index 15b17e86e198c..9b087ebeb643b 100644 +--- a/ipc/ipc_sysctl.c ++++ b/ipc/ipc_sysctl.c +@@ -214,7 +214,7 @@ static int ipc_permissions(struct ctl_table_header *head, const struct ctl_table + if (((table->data == &ns->ids[IPC_SEM_IDS].next_id) || + (table->data == &ns->ids[IPC_MSG_IDS].next_id) || + (table->data == &ns->ids[IPC_SHM_IDS].next_id)) && +- checkpoint_restore_ns_capable(ns->user_ns)) ++ checkpoint_restore_ns_capable_noaudit(ns->user_ns)) + mode = 0666; + else + #endif +-- +2.51.0 + diff --git a/queue-6.18/jfs-avoid-wtautological-constant-out-of-range-compar.patch b/queue-6.18/jfs-avoid-wtautological-constant-out-of-range-compar.patch new file mode 100644 index 0000000000..9629632807 --- /dev/null +++ b/queue-6.18/jfs-avoid-wtautological-constant-out-of-range-compar.patch @@ -0,0 +1,56 @@ +From 491c55548cf1142def5dfa9fdf7671b0141130d3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 21:43:45 +0100 +Subject: jfs: avoid -Wtautological-constant-out-of-range-compare warning + +From: Arnd Bergmann + +[ Upstream commit 7833570dae833028337bb53b7f389825b910c100 ] + +A recent change for the range check started triggering a clang warning: + +fs/jfs/jfs_dtree.c:2906:31: error: result of comparison of constant 128 with expression of type 's8' (aka 'signed char') is always false [-Werror,-Wtautological-constant-out-of-range-compare] + 2906 | if (stbl[i] < 0 || stbl[i] >= DTPAGEMAXSLOT) { + | ~~~~~~~ ^ ~~~~~~~~~~~~~ +fs/jfs/jfs_dtree.c:3111:30: error: result of comparison of constant 128 with expression of type 's8' (aka 'signed char') is always false [-Werror,-Wtautological-constant-out-of-range-compare] + 3111 | if (stbl[0] < 0 || stbl[0] >= DTPAGEMAXSLOT) { + | ~~~~~~~ ^ ~~~~~~~~~~~~~ + +Both the old and the new check were useless, but the previous version +apparently did not lead to the warning. + +Remove the extraneous range check for simplicity. + +Fixes: cafc6679824a ("jfs: replace hardcoded magic number with DTPAGEMAXSLOT constant") +Signed-off-by: Arnd Bergmann +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_dtree.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c +index 0ab83bb7bbdf9..9ab3f2fc61d17 100644 +--- a/fs/jfs/jfs_dtree.c ++++ b/fs/jfs/jfs_dtree.c +@@ -2903,7 +2903,7 @@ int jfs_readdir(struct file *file, struct dir_context *ctx) + stbl = DT_GETSTBL(p); + + for (i = index; i < p->header.nextindex; i++) { +- if (stbl[i] < 0 || stbl[i] >= DTPAGEMAXSLOT) { ++ if (stbl[i] < 0) { + jfs_err("JFS: Invalid stbl[%d] = %d for inode %ld, block = %lld", + i, stbl[i], (long)ip->i_ino, (long long)bn); + free_page(dirent_buf); +@@ -3108,7 +3108,7 @@ static int dtReadFirst(struct inode *ip, struct btstack * btstack) + /* get the leftmost entry */ + stbl = DT_GETSTBL(p); + +- if (stbl[0] < 0 || stbl[0] >= DTPAGEMAXSLOT) { ++ if (stbl[0] < 0) { + DT_PUTPAGE(mp); + jfs_error(ip->i_sb, "stbl[0] out of bound\n"); + return -EIO; +-- +2.51.0 + diff --git a/queue-6.18/kallsyms-bpf-rename-__bpf_address_lookup-to-bpf_addr.patch b/queue-6.18/kallsyms-bpf-rename-__bpf_address_lookup-to-bpf_addr.patch new file mode 100644 index 0000000000..6adeac589f --- /dev/null +++ b/queue-6.18/kallsyms-bpf-rename-__bpf_address_lookup-to-bpf_addr.patch @@ -0,0 +1,186 @@ +From 0bb3404e35cc0d92e9012e2d071137c4efc1c968 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 14:59:18 +0100 +Subject: kallsyms/bpf: rename __bpf_address_lookup() to bpf_address_lookup() + +From: Petr Mladek + +[ Upstream commit cd6735896d0343942cf3dafb48ce32eb79341990 ] + +bpf_address_lookup() has been used only in kallsyms_lookup_buildid(). It +was supposed to set @modname and @modbuildid when the symbol was in a +module. + +But it always just cleared @modname because BPF symbols were never in a +module. And it did not clear @modbuildid because the pointer was not +passed. + +The wrapper is no longer needed. Both @modname and @modbuildid are now +always initialized to NULL in kallsyms_lookup_buildid(). + +Remove the wrapper and rename __bpf_address_lookup() to +bpf_address_lookup() because this variant is used everywhere. + +[akpm@linux-foundation.org: fix loongarch] +Link: https://lkml.kernel.org/r/20251128135920.217303-6-pmladek@suse.com +Fixes: 9294523e3768 ("module: add printk formats to add module build ID to stacktraces") +Signed-off-by: Petr Mladek +Acked-by: Alexei Starovoitov +Cc: Aaron Tomlin +Cc: Daniel Borkman +Cc: Daniel Gomez +Cc: John Fastabend +Cc: Kees Cook +Cc: Luis Chamberalin +Cc: Marc Rutland +Cc: "Masami Hiramatsu (Google)" +Cc: Petr Pavlu +Cc: Sami Tolvanen +Cc: Steven Rostedt (Google) +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + arch/arm64/net/bpf_jit_comp.c | 2 +- + arch/loongarch/net/bpf_jit.c | 2 +- + arch/powerpc/net/bpf_jit_comp.c | 2 +- + include/linux/filter.h | 26 ++++---------------------- + kernel/bpf/core.c | 4 ++-- + kernel/kallsyms.c | 5 ++--- + 6 files changed, 11 insertions(+), 30 deletions(-) + +diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c +index 0dfefeedfe56c..83a6ca613f9c2 100644 +--- a/arch/arm64/net/bpf_jit_comp.c ++++ b/arch/arm64/net/bpf_jit_comp.c +@@ -2939,7 +2939,7 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type poke_type, + u64 plt_target = 0ULL; + bool poking_bpf_entry; + +- if (!__bpf_address_lookup((unsigned long)ip, &size, &offset, namebuf)) ++ if (!bpf_address_lookup((unsigned long)ip, &size, &offset, namebuf)) + /* Only poking bpf text is supported. Since kernel function + * entry is set up by ftrace, we reply on ftrace to poke kernel + * functions. +diff --git a/arch/loongarch/net/bpf_jit.c b/arch/loongarch/net/bpf_jit.c +index 87ff025137873..e9d666508ae28 100644 +--- a/arch/loongarch/net/bpf_jit.c ++++ b/arch/loongarch/net/bpf_jit.c +@@ -1318,7 +1318,7 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type poke_type, + /* Only poking bpf text is supported. Since kernel function entry + * is set up by ftrace, we rely on ftrace to poke kernel functions. + */ +- if (!__bpf_address_lookup((unsigned long)ip, &size, &offset, namebuf)) ++ if (!bpf_address_lookup((unsigned long)ip, &size, &offset, namebuf)) + return -ENOTSUPP; + + image = ip - offset; +diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c +index 88ad5ba7b87fd..21f7f26a5e2f3 100644 +--- a/arch/powerpc/net/bpf_jit_comp.c ++++ b/arch/powerpc/net/bpf_jit_comp.c +@@ -1122,7 +1122,7 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type poke_type, + branch_flags = poke_type == BPF_MOD_CALL ? BRANCH_SET_LINK : 0; + + /* We currently only support poking bpf programs */ +- if (!__bpf_address_lookup(bpf_func, &size, &offset, name)) { ++ if (!bpf_address_lookup(bpf_func, &size, &offset, name)) { + pr_err("%s (0x%lx): kernel/modules are not supported\n", __func__, bpf_func); + return -EOPNOTSUPP; + } +diff --git a/include/linux/filter.h b/include/linux/filter.h +index 569de3b14279a..cf7a0bce1bb6d 100644 +--- a/include/linux/filter.h ++++ b/include/linux/filter.h +@@ -1375,24 +1375,13 @@ static inline bool bpf_jit_kallsyms_enabled(void) + return false; + } + +-int __bpf_address_lookup(unsigned long addr, unsigned long *size, +- unsigned long *off, char *sym); ++int bpf_address_lookup(unsigned long addr, unsigned long *size, ++ unsigned long *off, char *sym); + bool is_bpf_text_address(unsigned long addr); + int bpf_get_kallsym(unsigned int symnum, unsigned long *value, char *type, + char *sym); + struct bpf_prog *bpf_prog_ksym_find(unsigned long addr); + +-static inline int +-bpf_address_lookup(unsigned long addr, unsigned long *size, +- unsigned long *off, char **modname, char *sym) +-{ +- int ret = __bpf_address_lookup(addr, size, off, sym); +- +- if (ret && modname) +- *modname = NULL; +- return ret; +-} +- + void bpf_prog_kallsyms_add(struct bpf_prog *fp); + void bpf_prog_kallsyms_del(struct bpf_prog *fp); + +@@ -1431,8 +1420,8 @@ static inline bool bpf_jit_kallsyms_enabled(void) + } + + static inline int +-__bpf_address_lookup(unsigned long addr, unsigned long *size, +- unsigned long *off, char *sym) ++bpf_address_lookup(unsigned long addr, unsigned long *size, ++ unsigned long *off, char *sym) + { + return 0; + } +@@ -1453,13 +1442,6 @@ static inline struct bpf_prog *bpf_prog_ksym_find(unsigned long addr) + return NULL; + } + +-static inline int +-bpf_address_lookup(unsigned long addr, unsigned long *size, +- unsigned long *off, char **modname, char *sym) +-{ +- return 0; +-} +- + static inline void bpf_prog_kallsyms_add(struct bpf_prog *fp) + { + } +diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c +index d595fe512498c..c2278f392e932 100644 +--- a/kernel/bpf/core.c ++++ b/kernel/bpf/core.c +@@ -713,8 +713,8 @@ static struct bpf_ksym *bpf_ksym_find(unsigned long addr) + return n ? container_of(n, struct bpf_ksym, tnode) : NULL; + } + +-int __bpf_address_lookup(unsigned long addr, unsigned long *size, +- unsigned long *off, char *sym) ++int bpf_address_lookup(unsigned long addr, unsigned long *size, ++ unsigned long *off, char *sym) + { + struct bpf_ksym *ksym; + int ret = 0; +diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c +index 049e296f586cc..7417dd5f8a796 100644 +--- a/kernel/kallsyms.c ++++ b/kernel/kallsyms.c +@@ -345,7 +345,7 @@ int kallsyms_lookup_size_offset(unsigned long addr, unsigned long *symbolsize, + return 1; + } + return !!module_address_lookup(addr, symbolsize, offset, NULL, NULL, namebuf) || +- !!__bpf_address_lookup(addr, symbolsize, offset, namebuf); ++ !!bpf_address_lookup(addr, symbolsize, offset, namebuf); + } + + static int kallsyms_lookup_buildid(unsigned long addr, +@@ -377,8 +377,7 @@ static int kallsyms_lookup_buildid(unsigned long addr, + ret = module_address_lookup(addr, symbolsize, offset, + modname, modbuildid, namebuf); + if (!ret) +- ret = bpf_address_lookup(addr, symbolsize, +- offset, modname, namebuf); ++ ret = bpf_address_lookup(addr, symbolsize, offset, namebuf); + + if (!ret) + ret = ftrace_mod_address_lookup(addr, symbolsize, +-- +2.51.0 + diff --git a/queue-6.18/kallsyms-ftrace-set-module-buildid-in-ftrace_mod_add.patch b/queue-6.18/kallsyms-ftrace-set-module-buildid-in-ftrace_mod_add.patch new file mode 100644 index 0000000000..d32b686207 --- /dev/null +++ b/queue-6.18/kallsyms-ftrace-set-module-buildid-in-ftrace_mod_add.patch @@ -0,0 +1,100 @@ +From 60e81eb1eed89cee681366c718562480c2bba850 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 14:59:19 +0100 +Subject: kallsyms/ftrace: set module buildid in ftrace_mod_address_lookup() + +From: Petr Mladek + +[ Upstream commit e8a1e7eaa19d0b757b06a2f913e3eeb4b1c002c6 ] + +__sprint_symbol() might access an invalid pointer when +kallsyms_lookup_buildid() returns a symbol found by +ftrace_mod_address_lookup(). + +The ftrace lookup function must set both @modname and @modbuildid the same +way as module_address_lookup(). + +Link: https://lkml.kernel.org/r/20251128135920.217303-7-pmladek@suse.com +Fixes: 9294523e3768 ("module: add printk formats to add module build ID to stacktraces") +Signed-off-by: Petr Mladek +Reviewed-by: Aaron Tomlin +Acked-by: Steven Rostedt (Google) +Cc: Alexei Starovoitov +Cc: Daniel Borkman +Cc: Daniel Gomez +Cc: John Fastabend +Cc: Kees Cook +Cc: Luis Chamberalin +Cc: Marc Rutland +Cc: "Masami Hiramatsu (Google)" +Cc: Petr Pavlu +Cc: Sami Tolvanen +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + include/linux/ftrace.h | 6 ++++-- + kernel/kallsyms.c | 4 ++-- + kernel/trace/ftrace.c | 5 ++++- + 3 files changed, 10 insertions(+), 5 deletions(-) + +diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h +index 07f8c309e4327..9cc60e2506af1 100644 +--- a/include/linux/ftrace.h ++++ b/include/linux/ftrace.h +@@ -87,11 +87,13 @@ struct ftrace_hash; + defined(CONFIG_DYNAMIC_FTRACE) + int + ftrace_mod_address_lookup(unsigned long addr, unsigned long *size, +- unsigned long *off, char **modname, char *sym); ++ unsigned long *off, char **modname, ++ const unsigned char **modbuildid, char *sym); + #else + static inline int + ftrace_mod_address_lookup(unsigned long addr, unsigned long *size, +- unsigned long *off, char **modname, char *sym) ++ unsigned long *off, char **modname, ++ const unsigned char **modbuildid, char *sym) + { + return 0; + } +diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c +index 7417dd5f8a796..cdd6e025935d3 100644 +--- a/kernel/kallsyms.c ++++ b/kernel/kallsyms.c +@@ -380,8 +380,8 @@ static int kallsyms_lookup_buildid(unsigned long addr, + ret = bpf_address_lookup(addr, symbolsize, offset, namebuf); + + if (!ret) +- ret = ftrace_mod_address_lookup(addr, symbolsize, +- offset, modname, namebuf); ++ ret = ftrace_mod_address_lookup(addr, symbolsize, offset, ++ modname, modbuildid, namebuf); + + return ret; + } +diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c +index e95408a47c1d0..905f4d1679559 100644 +--- a/kernel/trace/ftrace.c ++++ b/kernel/trace/ftrace.c +@@ -7709,7 +7709,8 @@ ftrace_func_address_lookup(struct ftrace_mod_map *mod_map, + + int + ftrace_mod_address_lookup(unsigned long addr, unsigned long *size, +- unsigned long *off, char **modname, char *sym) ++ unsigned long *off, char **modname, ++ const unsigned char **modbuildid, char *sym) + { + struct ftrace_mod_map *mod_map; + int ret = 0; +@@ -7721,6 +7722,8 @@ ftrace_mod_address_lookup(unsigned long addr, unsigned long *size, + if (ret) { + if (modname) + *modname = mod_map->mod->name; ++ if (modbuildid) ++ *modbuildid = module_buildid(mod_map->mod); + break; + } + } +-- +2.51.0 + diff --git a/queue-6.18/leds-expresswire-fix-chip-state-breakage.patch b/queue-6.18/leds-expresswire-fix-chip-state-breakage.patch new file mode 100644 index 0000000000..6f04f6406c --- /dev/null +++ b/queue-6.18/leds-expresswire-fix-chip-state-breakage.patch @@ -0,0 +1,129 @@ +From ff652dffa9fac798189197612a57ae90f7202665 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 17 Dec 2025 19:14:23 +0100 +Subject: leds: expresswire: Fix chip state breakage +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Duje Mihanović + +[ Upstream commit f4b830a5371914239756b0599e5dc9d4c328e387 ] + +It is possible to put the KTD2801 chip in an unknown/undefined state by +changing the brightness very rapidly (for example, with a brightness +slider). When this happens, the brightness is stuck on max and cannot be +changed until the chip is power cycled. + +Fix this by disabling interrupts while talking to the chip. While at it, +make expresswire_power_off() use fsleep() and also unexport some +functions meant to be internal. + +Fixes: 1368d06dd2c9 ("leds: Introduce ExpressWire library") +Tested-by: Karel Balej +Signed-off-by: Duje Mihanović +Link: https://patch.msgid.link/20251217-expresswire-fix-v2-1-4a02b10acd96@dujemihanovic.xyz +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/leds/leds-expresswire.c | 24 +++++++++++++++++------- + include/linux/leds-expresswire.h | 3 --- + 2 files changed, 17 insertions(+), 10 deletions(-) + +diff --git a/drivers/leds/leds-expresswire.c b/drivers/leds/leds-expresswire.c +index bb69be228a6d3..25c6b159a6ee9 100644 +--- a/drivers/leds/leds-expresswire.c ++++ b/drivers/leds/leds-expresswire.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -16,37 +17,41 @@ + void expresswire_power_off(struct expresswire_common_props *props) + { + gpiod_set_value_cansleep(props->ctrl_gpio, 0); +- usleep_range(props->timing.poweroff_us, props->timing.poweroff_us * 2); ++ fsleep(props->timing.poweroff_us); + } + EXPORT_SYMBOL_NS_GPL(expresswire_power_off, "EXPRESSWIRE"); + + void expresswire_enable(struct expresswire_common_props *props) + { ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ + gpiod_set_value(props->ctrl_gpio, 1); + udelay(props->timing.detect_delay_us); + gpiod_set_value(props->ctrl_gpio, 0); + udelay(props->timing.detect_us); + gpiod_set_value(props->ctrl_gpio, 1); ++ ++ local_irq_restore(flags); + } + EXPORT_SYMBOL_NS_GPL(expresswire_enable, "EXPRESSWIRE"); + +-void expresswire_start(struct expresswire_common_props *props) ++static void expresswire_start(struct expresswire_common_props *props) + { + gpiod_set_value(props->ctrl_gpio, 1); + udelay(props->timing.data_start_us); + } +-EXPORT_SYMBOL_NS_GPL(expresswire_start, "EXPRESSWIRE"); + +-void expresswire_end(struct expresswire_common_props *props) ++static void expresswire_end(struct expresswire_common_props *props) + { + gpiod_set_value(props->ctrl_gpio, 0); + udelay(props->timing.end_of_data_low_us); + gpiod_set_value(props->ctrl_gpio, 1); + udelay(props->timing.end_of_data_high_us); + } +-EXPORT_SYMBOL_NS_GPL(expresswire_end, "EXPRESSWIRE"); + +-void expresswire_set_bit(struct expresswire_common_props *props, bool bit) ++static void expresswire_set_bit(struct expresswire_common_props *props, bool bit) + { + if (bit) { + gpiod_set_value(props->ctrl_gpio, 0); +@@ -60,13 +65,18 @@ void expresswire_set_bit(struct expresswire_common_props *props, bool bit) + udelay(props->timing.short_bitset_us); + } + } +-EXPORT_SYMBOL_NS_GPL(expresswire_set_bit, "EXPRESSWIRE"); + + void expresswire_write_u8(struct expresswire_common_props *props, u8 val) + { ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ + expresswire_start(props); + for (int i = 7; i >= 0; i--) + expresswire_set_bit(props, val & BIT(i)); + expresswire_end(props); ++ ++ local_irq_restore(flags); + } + EXPORT_SYMBOL_NS_GPL(expresswire_write_u8, "EXPRESSWIRE"); +diff --git a/include/linux/leds-expresswire.h b/include/linux/leds-expresswire.h +index a422921f4159f..7f8c4795f69fa 100644 +--- a/include/linux/leds-expresswire.h ++++ b/include/linux/leds-expresswire.h +@@ -30,9 +30,6 @@ struct expresswire_common_props { + + void expresswire_power_off(struct expresswire_common_props *props); + void expresswire_enable(struct expresswire_common_props *props); +-void expresswire_start(struct expresswire_common_props *props); +-void expresswire_end(struct expresswire_common_props *props); +-void expresswire_set_bit(struct expresswire_common_props *props, bool bit); + void expresswire_write_u8(struct expresswire_common_props *props, u8 val); + + #endif /* _LEDS_EXPRESSWIRE_H */ +-- +2.51.0 + diff --git a/queue-6.18/leds-qcom-lpg-check-the-return-value-of-regmap_bulk_.patch b/queue-6.18/leds-qcom-lpg-check-the-return-value-of-regmap_bulk_.patch new file mode 100644 index 0000000000..3d92ca1fa9 --- /dev/null +++ b/queue-6.18/leds-qcom-lpg-check-the-return-value-of-regmap_bulk_.patch @@ -0,0 +1,55 @@ +From e8b4ac4d7154150734b1497d251a0f5abcd2f168 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 01:51:33 +0800 +Subject: leds: qcom-lpg: Check the return value of regmap_bulk_write() + +From: Haotian Zhang + +[ Upstream commit f42033b5ce8c79c5db645916c9a72ee3e10cecfa ] + +The lpg_lut_store() function currently ignores the return value of +regmap_bulk_write() and always returns 0. This can cause hardware write +failures to go undetected, leading the caller to believe LUT programming +succeeded when it may have failed. + +Check the return value of regmap_bulk_write() in lpg_lut_store and return +the error to the caller on failure. + +Fixes: 24e2d05d1b68 ("leds: Add driver for Qualcomm LPG") +Signed-off-by: Haotian Zhang +Link: https://patch.msgid.link/20260108175133.638-1-vulab@iscas.ac.cn +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/leds/rgb/leds-qcom-lpg.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/leds/rgb/leds-qcom-lpg.c b/drivers/leds/rgb/leds-qcom-lpg.c +index e197f548cddb0..a460782dadca4 100644 +--- a/drivers/leds/rgb/leds-qcom-lpg.c ++++ b/drivers/leds/rgb/leds-qcom-lpg.c +@@ -369,7 +369,7 @@ static int lpg_lut_store(struct lpg *lpg, struct led_pattern *pattern, + { + unsigned int idx; + u16 val; +- int i; ++ int i, ret; + + idx = bitmap_find_next_zero_area(lpg->lut_bitmap, lpg->lut_size, + 0, len, 0); +@@ -379,8 +379,10 @@ static int lpg_lut_store(struct lpg *lpg, struct led_pattern *pattern, + for (i = 0; i < len; i++) { + val = pattern[i].brightness; + +- regmap_bulk_write(lpg->map, lpg->lut_base + LPG_LUT_REG(idx + i), +- &val, sizeof(val)); ++ ret = regmap_bulk_write(lpg->map, lpg->lut_base + LPG_LUT_REG(idx + i), ++ &val, sizeof(val)); ++ if (ret) ++ return ret; + } + + bitmap_set(lpg->lut_bitmap, idx, len); +-- +2.51.0 + diff --git a/queue-6.18/lib-kstrtox-fix-kstrtobool-docstring-to-mention-enab.patch b/queue-6.18/lib-kstrtox-fix-kstrtobool-docstring-to-mention-enab.patch new file mode 100644 index 0000000000..754477848c --- /dev/null +++ b/queue-6.18/lib-kstrtox-fix-kstrtobool-docstring-to-mention-enab.patch @@ -0,0 +1,44 @@ +From 8f8198c848821ec0b8fe4caa70a4f8d8f0cba044 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 27 Dec 2025 14:52:29 +0530 +Subject: lib/kstrtox: fix kstrtobool() docstring to mention enabled/disabled + +From: Chaitanya Mishra + +[ Upstream commit 1921044eebf1d6861a6de1a76e3f63729a45e712 ] + +Commit ae5b3500856f ("kstrtox: add support for enabled and disabled in +kstrtobool()") added support for 'e'/'E' (enabled) and 'd'/'D' (disabled) +inputs, but did not update the docstring accordingly. + +Update the docstring to include 'Ee' (for true) and 'Dd' (for false) in +the list of accepted first characters. + +Link: https://lkml.kernel.org/r/20251227092229.57330-1-chaitanyamishra.ai@gmail.com +Fixes: ae5b3500856f ("kstrtox: add support for enabled and disabled in kstrtobool()") +Signed-off-by: Chaitanya Mishra +Cc: Mario Limonciello +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + lib/kstrtox.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/lib/kstrtox.c b/lib/kstrtox.c +index bdde40cd69d78..97be2a39f5371 100644 +--- a/lib/kstrtox.c ++++ b/lib/kstrtox.c +@@ -340,8 +340,8 @@ EXPORT_SYMBOL(kstrtos8); + * @s: input string + * @res: result + * +- * This routine returns 0 iff the first character is one of 'YyTt1NnFf0', or +- * [oO][NnFf] for "on" and "off". Otherwise it will return -EINVAL. Value ++ * This routine returns 0 iff the first character is one of 'EeYyTt1DdNnFf0', ++ * or [oO][NnFf] for "on" and "off". Otherwise it will return -EINVAL. Value + * pointed to by res is updated upon finding a match. + */ + noinline +-- +2.51.0 + diff --git a/queue-6.18/libbpf-fix-oob-read-in-btf_dump_get_bitfield_value.patch b/queue-6.18/libbpf-fix-oob-read-in-btf_dump_get_bitfield_value.patch new file mode 100644 index 0000000000..9ae72e0191 --- /dev/null +++ b/queue-6.18/libbpf-fix-oob-read-in-btf_dump_get_bitfield_value.patch @@ -0,0 +1,59 @@ +From 4d64f48ed9aeddfb3ca08d08c8c034da70f38d85 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 05:05:27 +0530 +Subject: libbpf: Fix OOB read in btf_dump_get_bitfield_value + +From: Varun R Mallya + +[ Upstream commit 5714ca8cba5ed736f3733663c446cbee63a10a64 ] + +When dumping bitfield data, btf_dump_get_bitfield_value() reads data +based on the underlying type's size (t->size). However, it does not +verify that the provided data buffer (data_sz) is large enough to +contain these bytes. + +If btf_dump__dump_type_data() is called with a buffer smaller than +the type's size, this leads to an out-of-bounds read. This was +confirmed by AddressSanitizer in the linked issue. + +Fix this by ensuring we do not read past the provided data_sz limit. + +Fixes: a1d3cc3c5eca ("libbpf: Avoid use of __int128 in typed dump display") +Reported-by: Harrison Green +Suggested-by: Alan Maguire +Signed-off-by: Varun R Mallya +Signed-off-by: Andrii Nakryiko +Link: https://lore.kernel.org/bpf/20260106233527.163487-1-varunrmallya@gmail.com + +Closes: https://github.com/libbpf/libbpf/issues/928 +Signed-off-by: Sasha Levin +--- + tools/lib/bpf/btf_dump.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/tools/lib/bpf/btf_dump.c b/tools/lib/bpf/btf_dump.c +index 6388392f49a0b..53c6624161d79 100644 +--- a/tools/lib/bpf/btf_dump.c ++++ b/tools/lib/bpf/btf_dump.c +@@ -1762,9 +1762,18 @@ static int btf_dump_get_bitfield_value(struct btf_dump *d, + __u16 left_shift_bits, right_shift_bits; + const __u8 *bytes = data; + __u8 nr_copy_bits; ++ __u8 start_bit, nr_bytes; + __u64 num = 0; + int i; + ++ /* Calculate how many bytes cover the bitfield */ ++ start_bit = bits_offset % 8; ++ nr_bytes = (start_bit + bit_sz + 7) / 8; ++ ++ /* Bound check */ ++ if (data + nr_bytes > d->typed_dump->data_end) ++ return -E2BIG; ++ + /* Maximum supported bitfield size is 64 bits */ + if (t->size > 8) { + pr_warn("unexpected bitfield size %d\n", t->size); +-- +2.51.0 + diff --git a/queue-6.18/mcb-fix-incorrect-sanity-check.patch b/queue-6.18/mcb-fix-incorrect-sanity-check.patch new file mode 100644 index 0000000000..e210971612 --- /dev/null +++ b/queue-6.18/mcb-fix-incorrect-sanity-check.patch @@ -0,0 +1,62 @@ +From 203332885fe564e9f7d87e35c35107f3ae5d13ba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 12:21:41 +0100 +Subject: mcb: fix incorrect sanity check + +From: Jose Javier Rodriguez Barbarin + +[ Upstream commit bc2e4bc952e26dd93b978588219044bd8b24237b ] + +__mcb_register_driver() makes some sanity checks over mcb_driver +to check if .probe and .remove callbacks are set. However, since commit +3bd13ae04ccc ("gpio: menz127: simplify error path and remove remove()") +removed the .remove callback from menz127-gpio.c, not all mcb device +drivers implement .remove callback. + +Remove .remove check to ensure all mcb device drivers can be loaded. + +Signed-off-by: Jose Javier Rodriguez Barbarin +Fixes: 3bd13ae04ccc ("gpio: menz127: simplify error path and remove remove()") +[ jth: added statement about menz127-gpio.c ] +Signed-off-by: Johannes Thumshirn +Link: https://patch.msgid.link/16fb55bd59d9c1d2ce2443f41d4dec2048f9a8ec.1768562302.git.jth@kernel.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/mcb/mcb-core.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/drivers/mcb/mcb-core.c b/drivers/mcb/mcb-core.c +index c1367223e71a0..3d487d75c483d 100644 +--- a/drivers/mcb/mcb-core.c ++++ b/drivers/mcb/mcb-core.c +@@ -85,7 +85,8 @@ static void mcb_remove(struct device *dev) + struct mcb_device *mdev = to_mcb_device(dev); + struct module *carrier_mod; + +- mdrv->remove(mdev); ++ if (mdrv->remove) ++ mdrv->remove(mdev); + + carrier_mod = mdev->dev.parent->driver->owner; + module_put(carrier_mod); +@@ -176,13 +177,13 @@ static const struct device_type mcb_carrier_device_type = { + * @owner: The @mcb_driver's module + * @mod_name: The name of the @mcb_driver's module + * +- * Register a @mcb_driver at the system. Perform some sanity checks, if +- * the .probe and .remove methods are provided by the driver. ++ * Register a @mcb_driver at the system. Perform a sanity check, if ++ * .probe method is provided by the driver. + */ + int __mcb_register_driver(struct mcb_driver *drv, struct module *owner, + const char *mod_name) + { +- if (!drv->probe || !drv->remove) ++ if (!drv->probe) + return -EINVAL; + + drv->driver.owner = owner; +-- +2.51.0 + diff --git a/queue-6.18/mctp-i2c-initialise-event-handler-read-bytes.patch b/queue-6.18/mctp-i2c-initialise-event-handler-read-bytes.patch new file mode 100644 index 0000000000..9a3f739855 --- /dev/null +++ b/queue-6.18/mctp-i2c-initialise-event-handler-read-bytes.patch @@ -0,0 +1,43 @@ +From 40cba6c4c223f91699517166402fb5c71bda3458 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Jan 2026 17:01:16 +0800 +Subject: mctp i2c: initialise event handler read bytes + +From: Matt Johnston + +[ Upstream commit 2a14e91b6d76639dac70ea170f4384c1ee3cb48d ] + +Set a 0xff value for i2c reads of an mctp-i2c device. Otherwise reads +will return "val" from the i2c bus driver. For i2c-aspeed and +i2c-npcm7xx that is a stack uninitialised u8. + +Tested with "i2ctransfer -y 1 r10@0x34" where 0x34 is a mctp-i2c +instance, now it returns all 0xff. + +Fixes: f5b8abf9fc3d ("mctp i2c: MCTP I2C binding driver") +Signed-off-by: Matt Johnston +Link: https://patch.msgid.link/20260113-mctp-read-fix-v1-1-70c4b59c741c@codeconstruct.com.au +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/mctp/mctp-i2c.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/mctp/mctp-i2c.c b/drivers/net/mctp/mctp-i2c.c +index ecda1cc36391c..8043b57bdf250 100644 +--- a/drivers/net/mctp/mctp-i2c.c ++++ b/drivers/net/mctp/mctp-i2c.c +@@ -243,7 +243,10 @@ static int mctp_i2c_slave_cb(struct i2c_client *client, + + switch (event) { + case I2C_SLAVE_READ_REQUESTED: ++ case I2C_SLAVE_READ_PROCESSED: ++ /* MCTP I2C transport only uses writes */ + midev->rx_pos = 0; ++ *val = 0xff; + break; + case I2C_SLAVE_WRITE_RECEIVED: + if (midev->rx_pos < MCTP_I2C_BUFSZ) { +-- +2.51.0 + diff --git a/queue-6.18/md-fix-return-value-of-mddev_trylock.patch b/queue-6.18/md-fix-return-value-of-mddev_trylock.patch new file mode 100644 index 0000000000..08fd6b4b91 --- /dev/null +++ b/queue-6.18/md-fix-return-value-of-mddev_trylock.patch @@ -0,0 +1,43 @@ +From 24922a3abf73d8adfd79f8713f735a5a8eaa33fa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 15:39:27 +0800 +Subject: md: fix return value of mddev_trylock + +From: Xiao Ni + +[ Upstream commit 05c8de4f09b08e97c6ecb190dcec0e68b167cb03 ] + +A return value of 0 is treaded as successful lock acquisition. In fact, a +return value of 1 means getting the lock successfully. + +Link: https://lore.kernel.org/linux-raid/20260127073951.17248-1-xni@redhat.com +Fixes: 9e59d609763f ("md: call del_gendisk in control path") +Reported-by: Bart Van Assche +Closes: https://lore.kernel.org/linux-raid/20250611073108.25463-1-xni@redhat.com/T/#mfa369ef5faa4aa58e13e6d9fdb88aecd862b8f2f +Signed-off-by: Xiao Ni +Reviewed-by: Bart Van Assche +Reviewed-by: Li Nan +Signed-off-by: Yu Kuai +Signed-off-by: Sasha Levin +--- + drivers/md/md.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/md/md.h b/drivers/md/md.h +index fd6e001c1d38f..9d66afb8cc6e6 100644 +--- a/drivers/md/md.h ++++ b/drivers/md/md.h +@@ -736,8 +736,8 @@ static inline int mddev_trylock(struct mddev *mddev) + int ret; + + ret = mutex_trylock(&mddev->reconfig_mutex); +- if (!ret && test_bit(MD_DELETED, &mddev->flags)) { +- ret = -ENODEV; ++ if (ret && test_bit(MD_DELETED, &mddev->flags)) { ++ ret = 0; + mutex_unlock(&mddev->reconfig_mutex); + } + return ret; +-- +2.51.0 + diff --git a/queue-6.18/md-md-llbitmap-fix-percpu_ref-not-resurrected-on-sus.patch b/queue-6.18/md-md-llbitmap-fix-percpu_ref-not-resurrected-on-sus.patch new file mode 100644 index 0000000000..8a7e06138e --- /dev/null +++ b/queue-6.18/md-md-llbitmap-fix-percpu_ref-not-resurrected-on-sus.patch @@ -0,0 +1,47 @@ +From d744472fb9eaec527397370444f60eeaddc5b0e9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 24 Jan 2026 02:26:23 +0800 +Subject: md/md-llbitmap: fix percpu_ref not resurrected on suspend timeout + +From: Yu Kuai + +[ Upstream commit d119bd2e1643cc023210ff3c6f0657e4f914e71d ] + +When llbitmap_suspend_timeout() times out waiting for percpu_ref to +become zero, it returns -ETIMEDOUT without resurrecting the percpu_ref. +The caller (md_llbitmap_daemon_fn) then continues to the next page +without calling llbitmap_resume(), leaving the percpu_ref in a killed +state permanently. + +Fix this by resurrecting the percpu_ref before returning the error, +ensuring the page control structure remains usable for subsequent +operations. + +Link: https://lore.kernel.org/linux-raid/20260123182623.3718551-3-yukuai@fnnas.com +Fixes: 5ab829f1971d ("md/md-llbitmap: introduce new lockless bitmap") +Signed-off-by: Yu Kuai +Reviewed-by: Li Nan +Signed-off-by: Sasha Levin +--- + drivers/md/md-llbitmap.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/md-llbitmap.c b/drivers/md/md-llbitmap.c +index 1eb434306162a..bcb6eae1c711f 100644 +--- a/drivers/md/md-llbitmap.c ++++ b/drivers/md/md-llbitmap.c +@@ -712,8 +712,10 @@ static int llbitmap_suspend_timeout(struct llbitmap *llbitmap, int page_idx) + percpu_ref_kill(&pctl->active); + + if (!wait_event_timeout(pctl->wait, percpu_ref_is_zero(&pctl->active), +- llbitmap->mddev->bitmap_info.daemon_sleep * HZ)) ++ llbitmap->mddev->bitmap_info.daemon_sleep * HZ)) { ++ percpu_ref_resurrect(&pctl->active); + return -ETIMEDOUT; ++ } + + return 0; + } +-- +2.51.0 + diff --git a/queue-6.18/md-raid1-fix-memory-leak-in-raid1_run.patch b/queue-6.18/md-raid1-fix-memory-leak-in-raid1_run.patch new file mode 100644 index 0000000000..4862bc1832 --- /dev/null +++ b/queue-6.18/md-raid1-fix-memory-leak-in-raid1_run.patch @@ -0,0 +1,46 @@ +From fafa23a03142c2d801172e8d92326f12b928630b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 07:15:33 +0000 +Subject: md/raid1: fix memory leak in raid1_run() + +From: Zilin Guan + +[ Upstream commit 6abc7d5dcf0ee0f85e16e41c87fbd06231f28753 ] + +raid1_run() calls setup_conf() which registers a thread via +md_register_thread(). If raid1_set_limits() fails, the previously +registered thread is not unregistered, resulting in a memory leak +of the md_thread structure and the thread resource itself. + +Add md_unregister_thread() to the error path to properly cleanup +the thread, which aligns with the error handling logic of other paths +in this function. + +Compile tested only. Issue found using a prototype static analysis tool +and code review. + +Link: https://lore.kernel.org/linux-raid/20260126071533.606263-1-zilin@seu.edu.cn +Fixes: 97894f7d3c29 ("md/raid1: use the atomic queue limit update APIs") +Signed-off-by: Zilin Guan +Reviewed-by: Li Nan +Signed-off-by: Yu Kuai +Signed-off-by: Sasha Levin +--- + drivers/md/raid1.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c +index 592a402330047..ce7fd68869566 100644 +--- a/drivers/md/raid1.c ++++ b/drivers/md/raid1.c +@@ -3253,6 +3253,7 @@ static int raid1_run(struct mddev *mddev) + if (!mddev_is_dm(mddev)) { + ret = raid1_set_limits(mddev); + if (ret) { ++ md_unregister_thread(mddev, &conf->thread); + if (!mddev->private) + raid1_free(mddev, conf); + return ret; +-- +2.51.0 + diff --git a/queue-6.18/md-raid10-fix-any_working-flag-handling-in-raid10_sy.patch b/queue-6.18/md-raid10-fix-any_working-flag-handling-in-raid10_sy.patch new file mode 100644 index 0000000000..73a93ff1ef --- /dev/null +++ b/queue-6.18/md-raid10-fix-any_working-flag-handling-in-raid10_sy.patch @@ -0,0 +1,47 @@ +From 79398d470eddc930d22b0ba444bfc9ad4f18d887 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Jan 2026 19:02:58 +0800 +Subject: md/raid10: fix any_working flag handling in raid10_sync_request + +From: Li Nan + +[ Upstream commit 99582edb3f62e8ee6c34512021368f53f9b091f2 ] + +In raid10_sync_request(), 'any_working' indicates if any IO will +be submitted. When there's only one In_sync disk with badblocks, +'any_working' might be set to 1 but no IO is submitted. Fix it by +setting 'any_working' after badblock checks. + +Link: https://lore.kernel.org/linux-raid/20260105110300.1442509-11-linan666@huaweicloud.com +Fixes: e875ecea266a ("md/raid10 record bad blocks as needed during recovery.") +Signed-off-by: Li Nan +Reviewed-by: Yu Kuai +Signed-off-by: Yu Kuai +Signed-off-by: Sasha Levin +--- + drivers/md/raid10.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c +index 14dcd5142eb47..d58ae150b4502 100644 +--- a/drivers/md/raid10.c ++++ b/drivers/md/raid10.c +@@ -3402,7 +3402,6 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr, + !test_bit(In_sync, &rdev->flags)) + continue; + /* This is where we read from */ +- any_working = 1; + sector = r10_bio->devs[j].addr; + + if (is_badblock(rdev, sector, max_sync, +@@ -3417,6 +3416,7 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr, + continue; + } + } ++ any_working = 1; + bio = r10_bio->devs[0].bio; + bio->bi_next = biolist; + biolist = bio; +-- +2.51.0 + diff --git a/queue-6.18/md-raid5-fix-io-hang-with-degraded-array-with-llbitm.patch b/queue-6.18/md-raid5-fix-io-hang-with-degraded-array-with-llbitm.patch new file mode 100644 index 0000000000..fb6517f3f2 --- /dev/null +++ b/queue-6.18/md-raid5-fix-io-hang-with-degraded-array-with-llbitm.patch @@ -0,0 +1,48 @@ +From cdd6ca209d6191cdb3b128f9a80c61da3f030c6a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 24 Jan 2026 02:26:22 +0800 +Subject: md/raid5: fix IO hang with degraded array with llbitmap + +From: Yu Kuai + +[ Upstream commit cd1635d844d26471c56c0a432abdee12fc9ad735 ] + +When llbitmap bit state is still unwritten, any new write should force +rcw, as bitmap_ops->blocks_synced() is checked in handle_stripe_dirtying(). +However, later the same check is missing in need_this_block(), causing +stripe to deadloop during handling because handle_stripe() will decide +to go to handle_stripe_fill(), meanwhile need_this_block() always return +0 and nothing is handled. + +Link: https://lore.kernel.org/linux-raid/20260123182623.3718551-2-yukuai@fnnas.com +Fixes: 5ab829f1971d ("md/md-llbitmap: introduce new lockless bitmap") +Signed-off-by: Yu Kuai +Reviewed-by: Li Nan +Signed-off-by: Sasha Levin +--- + drivers/md/raid5.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c +index 1041788a54c20..3b711a1198adb 100644 +--- a/drivers/md/raid5.c ++++ b/drivers/md/raid5.c +@@ -3751,9 +3751,14 @@ static int need_this_block(struct stripe_head *sh, struct stripe_head_state *s, + struct r5dev *dev = &sh->dev[disk_idx]; + struct r5dev *fdev[2] = { &sh->dev[s->failed_num[0]], + &sh->dev[s->failed_num[1]] }; ++ struct mddev *mddev = sh->raid_conf->mddev; ++ bool force_rcw = false; + int i; +- bool force_rcw = (sh->raid_conf->rmw_level == PARITY_DISABLE_RMW); + ++ if (sh->raid_conf->rmw_level == PARITY_DISABLE_RMW || ++ (mddev->bitmap_ops && mddev->bitmap_ops->blocks_synced && ++ !mddev->bitmap_ops->blocks_synced(mddev, sh->sector))) ++ force_rcw = true; + + if (test_bit(R5_LOCKED, &dev->flags) || + test_bit(R5_UPTODATE, &dev->flags)) +-- +2.51.0 + diff --git a/queue-6.18/md-raid5-fix-raid5_run-to-return-error-when-log_init.patch b/queue-6.18/md-raid5-fix-raid5_run-to-return-error-when-log_init.patch new file mode 100644 index 0000000000..e48b65a4b4 --- /dev/null +++ b/queue-6.18/md-raid5-fix-raid5_run-to-return-error-when-log_init.patch @@ -0,0 +1,47 @@ +From 913d1f0b37159abe59a8b5cc0c586e7d8e19d109 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 01:12:29 +0800 +Subject: md/raid5: fix raid5_run() to return error when log_init() fails + +From: Yu Kuai + +[ Upstream commit 2d9f7150ac197ce79c9c917a004d4cf0b26ad7e0 ] + +Since commit f63f17350e53 ("md/raid5: use the atomic queue limit +update APIs"), the abort path in raid5_run() returns 'ret' instead of +-EIO. However, if log_init() fails, 'ret' is still 0 from the previous +successful call, causing raid5_run() to return success despite the +failure. + +Fix this by capturing the return value from log_init(). + +Link: https://lore.kernel.org/linux-raid/20260114171241.3043364-2-yukuai@fnnas.com +Fixes: f63f17350e53 ("md/raid5: use the atomic queue limit update APIs") +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/r/202601130531.LGfcZsa4-lkp@intel.com/ +Signed-off-by: Yu Kuai +Reviewed-by: Li Nan +Reviewed-by: Xiao Ni +Reviewed-by: Christoph Hellwig +Signed-off-by: Sasha Levin +--- + drivers/md/raid5.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c +index 41de29206402a..1041788a54c20 100644 +--- a/drivers/md/raid5.c ++++ b/drivers/md/raid5.c +@@ -8056,7 +8056,8 @@ static int raid5_run(struct mddev *mddev) + goto abort; + } + +- if (log_init(conf, journal_dev, raid5_has_ppl(conf))) ++ ret = log_init(conf, journal_dev, raid5_has_ppl(conf)); ++ if (ret) + goto abort; + + return 0; +-- +2.51.0 + diff --git a/queue-6.18/media-ccs-accommodate-c-phy-into-the-calculation.patch b/queue-6.18/media-ccs-accommodate-c-phy-into-the-calculation.patch new file mode 100644 index 0000000000..bff28f6c00 --- /dev/null +++ b/queue-6.18/media-ccs-accommodate-c-phy-into-the-calculation.patch @@ -0,0 +1,53 @@ +From 209c3ad39b3dcdf4c95bd4f1ae8ae5c60df1f3b8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 18:57:07 +0100 +Subject: media: ccs: Accommodate C-PHY into the calculation + +From: David Heidelberg + +[ Upstream commit 3085977e734dab74adebb1dda195befce25addff ] + +We need to set correct mode for PLL to calculate correct frequency. +Signalling mode is known at this point, so use it for that. + +Fixes: 47b6eaf36eba ("media: ccs-pll: Differentiate between CSI-2 D-PHY and C-PHY") +Reviewed-by: Mehdi Djait +Signed-off-by: David Heidelberg +[Sakari Ailus: Drop extra newline.] +Signed-off-by: Sakari Ailus +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/i2c/ccs/ccs-core.c | 16 +++++++++++++++- + 1 file changed, 15 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c +index 1c889c878abd3..08e78f0bf2528 100644 +--- a/drivers/media/i2c/ccs/ccs-core.c ++++ b/drivers/media/i2c/ccs/ccs-core.c +@@ -3425,7 +3425,21 @@ static int ccs_probe(struct i2c_client *client) + sensor->scale_m = CCS_LIM(sensor, SCALER_N_MIN); + + /* prepare PLL configuration input values */ +- sensor->pll.bus_type = CCS_PLL_BUS_TYPE_CSI2_DPHY; ++ switch (sensor->hwcfg.csi_signalling_mode) { ++ case CCS_CSI_SIGNALING_MODE_CSI_2_CPHY: ++ sensor->pll.bus_type = CCS_PLL_BUS_TYPE_CSI2_CPHY; ++ break; ++ case CCS_CSI_SIGNALING_MODE_CSI_2_DPHY: ++ case SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK: ++ case SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_STROBE: ++ sensor->pll.bus_type = CCS_PLL_BUS_TYPE_CSI2_DPHY; ++ break; ++ default: ++ dev_err(&client->dev, "unsupported signalling mode %u\n", ++ sensor->hwcfg.csi_signalling_mode); ++ rval = -EINVAL; ++ goto out_cleanup; ++ } + sensor->pll.csi2.lanes = sensor->hwcfg.lanes; + if (CCS_LIM(sensor, CLOCK_CALCULATION) & + CCS_CLOCK_CALCULATION_LANE_SPEED) { +-- +2.51.0 + diff --git a/queue-6.18/media-chips-media-wave5-fix-memory-leak-on-codec_inf.patch b/queue-6.18/media-chips-media-wave5-fix-memory-leak-on-codec_inf.patch new file mode 100644 index 0000000000..6491a6b022 --- /dev/null +++ b/queue-6.18/media-chips-media-wave5-fix-memory-leak-on-codec_inf.patch @@ -0,0 +1,63 @@ +From 0531fc1d56827ebf4ce01194cc5fb4786ec692bf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 11 Nov 2025 14:57:06 +0000 +Subject: media: chips-media: wave5: Fix memory leak on codec_info allocation + failure + +From: Zilin Guan + +[ Upstream commit a519e21e32398459ba357e67b541402f7295ee1b ] + +In wave5_vpu_open_enc() and wave5_vpu_open_dec(), a vpu instance is +allocated via kzalloc(). If the subsequent allocation for inst->codec_info +fails, the functions return -ENOMEM without freeing the previously +allocated instance, causing a memory leak. + +Fix this by calling kfree() on the instance in this error path to ensure +it is properly released. + +Fixes: 9707a6254a8a6 ("media: chips-media: wave5: Add the v4l2 layer") +Signed-off-by: Zilin Guan +Signed-off-by: Nicolas Dufresne +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c | 4 +++- + drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c | 4 +++- + 2 files changed, 6 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c +index e3038c18ca362..a4387ed58cac3 100644 +--- a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c ++++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c +@@ -1753,8 +1753,10 @@ static int wave5_vpu_open_dec(struct file *filp) + spin_lock_init(&inst->state_spinlock); + + inst->codec_info = kzalloc(sizeof(*inst->codec_info), GFP_KERNEL); +- if (!inst->codec_info) ++ if (!inst->codec_info) { ++ kfree(inst); + return -ENOMEM; ++ } + + v4l2_fh_init(&inst->v4l2_fh, vdev); + v4l2_fh_add(&inst->v4l2_fh, filp); +diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c +index 9bfaa9fb3ceb3..94fb5d7c87021 100644 +--- a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c ++++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c +@@ -1578,8 +1578,10 @@ static int wave5_vpu_open_enc(struct file *filp) + inst->ops = &wave5_vpu_enc_inst_ops; + + inst->codec_info = kzalloc(sizeof(*inst->codec_info), GFP_KERNEL); +- if (!inst->codec_info) ++ if (!inst->codec_info) { ++ kfree(inst); + return -ENOMEM; ++ } + + v4l2_fh_init(&inst->v4l2_fh, vdev); + v4l2_fh_add(&inst->v4l2_fh, filp); +-- +2.51.0 + diff --git a/queue-6.18/media-pci-mg4b-use-irqf_no_thread.patch b/queue-6.18/media-pci-mg4b-use-irqf_no_thread.patch new file mode 100644 index 0000000000..71643cd63a --- /dev/null +++ b/queue-6.18/media-pci-mg4b-use-irqf_no_thread.patch @@ -0,0 +1,39 @@ +From 90b16d62b9b8f8ee5deb4b82af79be29c5de8132 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:55:40 +0100 +Subject: media: pci: mg4b: Use IRQF_NO_THREAD + +From: Sebastian Andrzej Siewior + +[ Upstream commit ef92b98f5f6758a049898b53aa30476010db04fa ] + +The interrupt handler iio_trigger_generic_data_rdy_poll() will invoke other +interrupt handlers and this supposed to happen from hard interrupt context. + +Use IRQF_NO_THREAD to forbid forced-threading. + +Fixes: 0ab13674a9bd1 ("media: pci: mgb4: Added Digiteq Automotive MGB4 driver") +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260128095540.863589-21-bigeasy@linutronix.de +Signed-off-by: Sasha Levin +--- + drivers/media/pci/mgb4/mgb4_trigger.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/media/pci/mgb4/mgb4_trigger.c b/drivers/media/pci/mgb4/mgb4_trigger.c +index d7dddc5c8728e..10c23f0c833d5 100644 +--- a/drivers/media/pci/mgb4/mgb4_trigger.c ++++ b/drivers/media/pci/mgb4/mgb4_trigger.c +@@ -114,7 +114,7 @@ static int probe_trigger(struct iio_dev *indio_dev, int irq) + if (!st->trig) + return -ENOMEM; + +- ret = request_irq(irq, &iio_trigger_generic_data_rdy_poll, 0, ++ ret = request_irq(irq, &iio_trigger_generic_data_rdy_poll, IRQF_NO_THREAD, + "mgb4-trigger", st->trig); + if (ret) + goto error_free_trig; +-- +2.51.0 + diff --git a/queue-6.18/media-uvcvideo-fix-allocation-for-small-frame-sizes.patch b/queue-6.18/media-uvcvideo-fix-allocation-for-small-frame-sizes.patch new file mode 100644 index 0000000000..c1578d84d4 --- /dev/null +++ b/queue-6.18/media-uvcvideo-fix-allocation-for-small-frame-sizes.patch @@ -0,0 +1,57 @@ +From c3a66d85bacf8ee034ebe2cbbfda1dd8535a604e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 10:32:13 +0000 +Subject: media: uvcvideo: Fix allocation for small frame sizes + +From: Ricardo Ribalda + +[ Upstream commit 40d3ac25c11310bfaa50ed7614846ef75cb69a1e ] + +If a frame has size of less or equal than one packet size +uvc_alloc_urb_buffers() is unable to allocate memory for it due to a +off-by-one error. + +Fix the off-by-one-error and now that we are at it, make sure that +stream->urb_size has always a valid value when we return from the +function, even when an error happens. + +Fixes: efdc8a9585ce ("V4L/DVB (10295): uvcvideo: Retry URB buffers allocation when the system is low on memory.") +Reported-by: Itay Chamiel +Closes: https://lore.kernel.org/linux-media/CANiDSCsSoZf2LsCCoWAUbCg6tJT-ypXR1B85aa6rAdMVYr2iBQ@mail.gmail.com/T/#t +Co-developed-by: Itay Chamiel +Signed-off-by: Itay Chamiel +Signed-off-by: Ricardo Ribalda +Reviewed-by: Laurent Pinchart +Tested-by: Itay Chamiel +Link: https://patch.msgid.link/20260114-uvc-alloc-urb-v1-1-cedf3fb66711@chromium.org +Signed-off-by: Laurent Pinchart +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/usb/uvc/uvc_video.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c +index 2094e059d7d39..ec76595f3c4be 100644 +--- a/drivers/media/usb/uvc/uvc_video.c ++++ b/drivers/media/usb/uvc/uvc_video.c +@@ -1812,7 +1812,7 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream, + npackets = UVC_MAX_PACKETS; + + /* Retry allocations until one succeed. */ +- for (; npackets > 1; npackets /= 2) { ++ for (; npackets > 0; npackets /= 2) { + stream->urb_size = psize * npackets; + + for (i = 0; i < UVC_URBS; ++i) { +@@ -1837,6 +1837,7 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream, + uvc_dbg(stream->dev, VIDEO, + "Failed to allocate URB buffers (%u bytes per packet)\n", + psize); ++ stream->urb_size = 0; + return 0; + } + +-- +2.51.0 + diff --git a/queue-6.18/mei-late_bind-fix-struct-intel_lb_component_ops-kern.patch b/queue-6.18/mei-late_bind-fix-struct-intel_lb_component_ops-kern.patch new file mode 100644 index 0000000000..3ec97e1449 --- /dev/null +++ b/queue-6.18/mei-late_bind-fix-struct-intel_lb_component_ops-kern.patch @@ -0,0 +1,46 @@ +From 8e800d3daab6d5e13ac603c0b54585a01a9734c9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 18:02:26 +0200 +Subject: mei: late_bind: fix struct intel_lb_component_ops kernel-doc + +From: Jani Nikula + +[ Upstream commit 936cae9254e55a39aeaa0c156a764d22f319338b ] + +Fix kernel-doc warnings on struct intel_lb_component_ops: + +Warning: include/drm/intel/intel_lb_mei_interface.h:55 Incorrect use of + kernel-doc format: * push_payload - Sends a payload to the + authentication firmware + +And a bunch more. There isn't really support for documenting function +pointer struct members in kernel-doc, but at least reference the member +properly. + +Fixes: 741eeabb7c78 ("mei: late_bind: add late binding component driver") +Cc: Alexander Usyskin +Reviewed-by: Nitin Gote +Link: https://patch.msgid.link/20260107160226.2381388-1-jani.nikula@intel.com +Signed-off-by: Jani Nikula +Signed-off-by: Sasha Levin +--- + include/drm/intel/intel_lb_mei_interface.h | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/include/drm/intel/intel_lb_mei_interface.h b/include/drm/intel/intel_lb_mei_interface.h +index d65be2cba2ab9..0850738a30fc7 100644 +--- a/include/drm/intel/intel_lb_mei_interface.h ++++ b/include/drm/intel/intel_lb_mei_interface.h +@@ -53,7 +53,8 @@ enum intel_lb_status { + */ + struct intel_lb_component_ops { + /** +- * push_payload - Sends a payload to the authentication firmware ++ * @push_payload: Sends a payload to the authentication firmware ++ * + * @dev: Device struct corresponding to the mei device + * @type: Payload type (see &enum intel_lb_type) + * @flags: Payload flags bitmap (e.g. %INTEL_LB_FLAGS_IS_PERSISTENT) +-- +2.51.0 + diff --git a/queue-6.18/mfd-arizona-fix-regulator-resource-leak-on-wm5102_cl.patch b/queue-6.18/mfd-arizona-fix-regulator-resource-leak-on-wm5102_cl.patch new file mode 100644 index 0000000000..d4144bcd60 --- /dev/null +++ b/queue-6.18/mfd-arizona-fix-regulator-resource-leak-on-wm5102_cl.patch @@ -0,0 +1,43 @@ +From a220b0df10cb4d4f4e88da907b8b03c88f8a279b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 14 Dec 2025 22:58:03 +0800 +Subject: mfd: arizona: Fix regulator resource leak on + wm5102_clear_write_sequencer() failure + +From: Haotian Zhang + +[ Upstream commit 4feb753ba6e5e5bbaba868b841a2db41c21e56fa ] + +The wm5102_clear_write_sequencer() helper may return an error +and just return, bypassing the cleanup sequence and causing +regulators to remain enabled, leading to a resource leak. + +Change the direct return to jump to the err_reset label to +properly free the resources. + +Fixes: 1c1c6bba57f5 ("mfd: wm5102: Ensure we always boot the device fully") +Signed-off-by: Haotian Zhang +Reviewed-by: Charles Keepax +Link: https://patch.msgid.link/20251214145804.2037-1-vulab@iscas.ac.cn +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/mfd/arizona-core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c +index 85ff8717d8504..91975536d14d2 100644 +--- a/drivers/mfd/arizona-core.c ++++ b/drivers/mfd/arizona-core.c +@@ -1100,7 +1100,7 @@ int arizona_dev_init(struct arizona *arizona) + } else if (val & 0x01) { + ret = wm5102_clear_write_sequencer(arizona); + if (ret) +- return ret; ++ goto err_reset; + } + break; + default: +-- +2.51.0 + diff --git a/queue-6.18/mfd-simple-mfd-i2c-add-delta-tn48m-cpld-support.patch b/queue-6.18/mfd-simple-mfd-i2c-add-delta-tn48m-cpld-support.patch new file mode 100644 index 0000000000..c277684dc6 --- /dev/null +++ b/queue-6.18/mfd-simple-mfd-i2c-add-delta-tn48m-cpld-support.patch @@ -0,0 +1,67 @@ +From effa79f19e5b50a8186bdb0ce91f238c0064451b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 17:14:52 +0100 +Subject: mfd: simple-mfd-i2c: Add Delta TN48M CPLD support + +From: Robert Marko + +[ Upstream commit 8f34c1a64c5394d2b51d3fba197947dc4b0b48a0 ] + +Delta TN48M switches have a Lattice CPLD that serves +multiple purposes including being a GPIO expander. + +So, lets use the simple I2C MFD driver to provide the MFD core. + +Also add a virtual symbol which pulls in the simple-mfd-i2c driver and +provide a common symbol on which the subdevice drivers can depend on. + +Fixes: b3dcb5de6209 ("gpio: Add Delta TN48M CPLD GPIO driver") +Signed-off-by: Robert Marko +Link: https://lore.kernel.org/20220131133049.77780-2-robert.marko@sartura.hr +Link: https://lore.kernel.org/linux-gpio/20260112064950.3837737-1-rdunlap@infradead.org/ +Signed-off-by: Linus Walleij +Link: https://patch.msgid.link/20260112-mfd-tn48m-v11-1-00c798d8cd2a@kernel.org +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/mfd/Kconfig | 11 +++++++++++ + drivers/mfd/simple-mfd-i2c.c | 1 + + 2 files changed, 12 insertions(+) + +diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig +index 6cec1858947bf..55a9fea95195b 100644 +--- a/drivers/mfd/Kconfig ++++ b/drivers/mfd/Kconfig +@@ -406,6 +406,17 @@ config MFD_CS47L92 + help + Support for Cirrus Logic CS42L92, CS47L92 and CS47L93 Smart Codecs + ++config MFD_TN48M_CPLD ++ tristate "Delta Networks TN48M switch CPLD driver" ++ depends on I2C ++ depends on ARCH_MVEBU || COMPILE_TEST ++ select MFD_SIMPLE_MFD_I2C ++ help ++ Select this option to enable support for Delta Networks TN48M switch ++ CPLD. It consists of reset and GPIO drivers. CPLD provides GPIOS-s ++ for the SFP slots as well as power supply related information. ++ SFP support depends on the GPIO driver being selected. ++ + config PMIC_DA903X + bool "Dialog Semiconductor DA9030/DA9034 PMIC Support" + depends on I2C=y +diff --git a/drivers/mfd/simple-mfd-i2c.c b/drivers/mfd/simple-mfd-i2c.c +index 0a607a1e3ca1d..9f911afafc25e 100644 +--- a/drivers/mfd/simple-mfd-i2c.c ++++ b/drivers/mfd/simple-mfd-i2c.c +@@ -110,6 +110,7 @@ static const struct simple_mfd_data spacemit_p1 = { + }; + + static const struct of_device_id simple_mfd_i2c_of_match[] = { ++ { .compatible = "delta,tn48m-cpld" }, + { .compatible = "fsl,ls1028aqds-fpga" }, + { .compatible = "fsl,lx2160aqds-fpga" }, + { .compatible = "fsl,lx2160ardb-fpga" }, +-- +2.51.0 + diff --git a/queue-6.18/mfd-wm8350-core-use-irqf_oneshot.patch b/queue-6.18/mfd-wm8350-core-use-irqf_oneshot.patch new file mode 100644 index 0000000000..6a7190da01 --- /dev/null +++ b/queue-6.18/mfd-wm8350-core-use-irqf_oneshot.patch @@ -0,0 +1,48 @@ +From 626eddfa2f6c45e647b978ed54d55ce8deebfa7e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:55:35 +0100 +Subject: mfd: wm8350-core: Use IRQF_ONESHOT + +From: Sebastian Andrzej Siewior + +[ Upstream commit 553b4999cbe231b5011cb8db05a3092dec168aca ] + +Using a threaded interrupt without a dedicated primary handler mandates +the IRQF_ONESHOT flag to mask the interrupt source while the threaded +handler is active. Otherwise the interrupt can fire again before the +threaded handler had a chance to run. + +Mark explained that this should not happen with this hardware since it +is a slow irqchip which is behind an I2C/ SPI bus but the IRQ-core will +refuse to accept such a handler. + +Set IRQF_ONESHOT so the interrupt source is masked until the secondary +handler is done. + +Fixes: 1c6c69525b40e ("genirq: Reject bogus threaded irq requests") +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Reviewed-by: Charles Keepax +Reviewed-by: Andy Shevchenko +Link: https://patch.msgid.link/20260128095540.863589-16-bigeasy@linutronix.de +Signed-off-by: Sasha Levin +--- + include/linux/mfd/wm8350/core.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/linux/mfd/wm8350/core.h b/include/linux/mfd/wm8350/core.h +index 5f70d3b5d1b1a..097ef4dfcdac8 100644 +--- a/include/linux/mfd/wm8350/core.h ++++ b/include/linux/mfd/wm8350/core.h +@@ -667,7 +667,7 @@ static inline int wm8350_register_irq(struct wm8350 *wm8350, int irq, + return -ENODEV; + + return request_threaded_irq(irq + wm8350->irq_base, NULL, +- handler, flags, name, data); ++ handler, flags | IRQF_ONESHOT, name, data); + } + + static inline void wm8350_free_irq(struct wm8350 *wm8350, int irq, void *data) +-- +2.51.0 + diff --git a/queue-6.18/mips-loongson32-drop-a-dangling-kconfig-symbol.patch b/queue-6.18/mips-loongson32-drop-a-dangling-kconfig-symbol.patch new file mode 100644 index 0000000000..b6ee9f719b --- /dev/null +++ b/queue-6.18/mips-loongson32-drop-a-dangling-kconfig-symbol.patch @@ -0,0 +1,36 @@ +From b9bac5ed2ab1b715ececb27ee087c271c7900a7b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 28 Dec 2025 11:04:43 -0800 +Subject: mips: LOONGSON32: drop a dangling Kconfig symbol + +From: Randy Dunlap + +[ Upstream commit d463fc5ca1ace0b2e8bb764df04fc12ecd6f8e2b ] + +CPU_HAS_LOAD_STORE_LR is not used anywhere in the kernel sources, +so drop it. + +Fixes: 85c4354076ca ("MIPS: loongson32: Switch to generic core") +Signed-off-by: Randy Dunlap +Reviewed-by: Keguang Zhang +Signed-off-by: Thomas Bogendoerfer +Signed-off-by: Sasha Levin +--- + arch/mips/Kconfig | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig +index e8683f58fd3e2..83a6b68d8a39a 100644 +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -1408,7 +1408,6 @@ config CPU_LOONGSON32 + select CPU_MIPS32 + select CPU_MIPSR2 + select CPU_HAS_PREFETCH +- select CPU_HAS_LOAD_STORE_LR + select CPU_SUPPORTS_32BIT_KERNEL + select CPU_SUPPORTS_HIGHMEM + select CPU_SUPPORTS_CPUFREQ +-- +2.51.0 + diff --git a/queue-6.18/mm-slab-fix-false-lockdep-warning-in-__kfree_rcu_she.patch b/queue-6.18/mm-slab-fix-false-lockdep-warning-in-__kfree_rcu_she.patch new file mode 100644 index 0000000000..cfdb2ad9d8 --- /dev/null +++ b/queue-6.18/mm-slab-fix-false-lockdep-warning-in-__kfree_rcu_she.patch @@ -0,0 +1,130 @@ +From b4f37e9194ed38787121b6ea6cf8f72ca0798171 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 07:52:40 +0100 +Subject: mm/slab: fix false lockdep warning in __kfree_rcu_sheaf() + +From: Harry Yoo + +[ Upstream commit f8b4cd2dad097e4ea5aed3511f42b9eb771e7b19 ] + +kvfree_call_rcu() can be called while holding a raw_spinlock_t. +Since __kfree_rcu_sheaf() may acquire a spinlock_t (which becomes a +sleeping lock on PREEMPT_RT) and violate lock nesting rules, +kvfree_call_rcu() bypasses the sheaves layer entirely on PREEMPT_RT. + +However, lockdep still complains about acquiring spinlock_t while holding +raw_spinlock_t, even on !PREEMPT_RT where spinlock_t is a spinning lock. +This causes a false lockdep warning [1]: + + ============================= + [ BUG: Invalid wait context ] + 6.19.0-rc6-next-20260120 #21508 Not tainted + ----------------------------- + migration/1/23 is trying to lock: + ffff8afd01054e98 (&barn->lock){..-.}-{3:3}, at: barn_get_empty_sheaf+0x1d/0xb0 + other info that might help us debug this: + context-{5:5} + 3 locks held by migration/1/23: + #0: ffff8afd01fd89a8 (&p->pi_lock){-.-.}-{2:2}, at: __balance_push_cpu_stop+0x3f/0x200 + #1: ffffffff9f15c5c8 (rcu_read_lock){....}-{1:3}, at: cpuset_cpus_allowed_fallback+0x27/0x250 + #2: ffff8afd1f470be0 ((local_lock_t *)&pcs->lock){+.+.}-{3:3}, at: __kfree_rcu_sheaf+0x52/0x3d0 + stack backtrace: + CPU: 1 UID: 0 PID: 23 Comm: migration/1 Not tainted 6.19.0-rc6-next-20260120 #21508 PREEMPTLAZY + Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.14.0-0-g155821a1990b-prebuilt.qemu.org 04/01/2014 + Stopper: __balance_push_cpu_stop+0x0/0x200 <- balance_push+0x118/0x170 + Call Trace: + + __dump_stack+0x22/0x30 + dump_stack_lvl+0x60/0x80 + dump_stack+0x19/0x24 + __lock_acquire+0xd3a/0x28e0 + ? __lock_acquire+0x5a9/0x28e0 + ? __lock_acquire+0x5a9/0x28e0 + ? barn_get_empty_sheaf+0x1d/0xb0 + lock_acquire+0xc3/0x270 + ? barn_get_empty_sheaf+0x1d/0xb0 + ? __kfree_rcu_sheaf+0x52/0x3d0 + _raw_spin_lock_irqsave+0x47/0x70 + ? barn_get_empty_sheaf+0x1d/0xb0 + barn_get_empty_sheaf+0x1d/0xb0 + ? __kfree_rcu_sheaf+0x52/0x3d0 + __kfree_rcu_sheaf+0x19f/0x3d0 + kvfree_call_rcu+0xaf/0x390 + set_cpus_allowed_force+0xc8/0xf0 + [...] + + +This wasn't triggered until sheaves were enabled for all slab caches, +since kfree_rcu() wasn't being called with a raw spinlock held for +caches with sheaves (vma, maple node). + +As suggested by Vlastimil Babka, fix this by using a lockdep map with +LD_WAIT_CONFIG wait type to tell lockdep that acquiring spinlock_t is valid +in this case, as those spinlocks won't be used on PREEMPT_RT. + +Note that kfree_rcu_sheaf_map should be acquired using _try() variant, +otherwise the acquisition of the lockdep map itself will trigger an invalid +wait context warning. + +Reported-by: Paul E. McKenney +Closes: https://lore.kernel.org/linux-mm/c858b9af-2510-448b-9ab3-058f7b80dd42@paulmck-laptop [1] +Fixes: ec66e0d59952 ("slab: add sheaf support for batching kfree_rcu() operations") +Suggested-by: Vlastimil Babka +Signed-off-by: Harry Yoo +Reviewed-by: Sebastian Andrzej Siewior +Signed-off-by: Vlastimil Babka +Signed-off-by: Sasha Levin +--- + mm/slub.c | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +diff --git a/mm/slub.c b/mm/slub.c +index e01641cea143b..896421a555573 100644 +--- a/mm/slub.c ++++ b/mm/slub.c +@@ -6232,11 +6232,29 @@ static void rcu_free_sheaf(struct rcu_head *head) + free_empty_sheaf(s, sheaf); + } + ++/* ++ * kvfree_call_rcu() can be called while holding a raw_spinlock_t. Since ++ * __kfree_rcu_sheaf() may acquire a spinlock_t (sleeping lock on PREEMPT_RT), ++ * this would violate lock nesting rules. Therefore, kvfree_call_rcu() avoids ++ * this problem by bypassing the sheaves layer entirely on PREEMPT_RT. ++ * ++ * However, lockdep still complains that it is invalid to acquire spinlock_t ++ * while holding raw_spinlock_t, even on !PREEMPT_RT where spinlock_t is a ++ * spinning lock. Tell lockdep that acquiring spinlock_t is valid here ++ * by temporarily raising the wait-type to LD_WAIT_CONFIG. ++ */ ++static DEFINE_WAIT_OVERRIDE_MAP(kfree_rcu_sheaf_map, LD_WAIT_CONFIG); ++ + bool __kfree_rcu_sheaf(struct kmem_cache *s, void *obj) + { + struct slub_percpu_sheaves *pcs; + struct slab_sheaf *rcu_sheaf; + ++ if (WARN_ON_ONCE(IS_ENABLED(CONFIG_PREEMPT_RT))) ++ return false; ++ ++ lock_map_acquire_try(&kfree_rcu_sheaf_map); ++ + if (!local_trylock(&s->cpu_sheaves->lock)) + goto fail; + +@@ -6313,10 +6331,12 @@ bool __kfree_rcu_sheaf(struct kmem_cache *s, void *obj) + local_unlock(&s->cpu_sheaves->lock); + + stat(s, FREE_RCU_SHEAF); ++ lock_map_release(&kfree_rcu_sheaf_map); + return true; + + fail: + stat(s, FREE_RCU_SHEAF_FAIL); ++ lock_map_release(&kfree_rcu_sheaf_map); + return false; + } + +-- +2.51.0 + diff --git a/queue-6.18/mmc-rtsx_pci_sdmmc-increase-power-on-settling-delay-.patch b/queue-6.18/mmc-rtsx_pci_sdmmc-increase-power-on-settling-delay-.patch new file mode 100644 index 0000000000..8f134260f8 --- /dev/null +++ b/queue-6.18/mmc-rtsx_pci_sdmmc-increase-power-on-settling-delay-.patch @@ -0,0 +1,40 @@ +From 711fc457a41e1edaf73c024deba51988540dee1e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 4 Jan 2026 22:02:36 -0800 +Subject: mmc: rtsx_pci_sdmmc: increase power-on settling delay to 5ms + +From: Matthew Schwartz + +[ Upstream commit aced969e9bf3701dc75cfca57c78c031b7875b9d ] + +The existing 1ms delay in sd_power_on is insufficient and causes resume +errors around 4% of the time. + +Increasing the delay to 5ms resolves this issue after testing 300 +s2idle cycles. + +Fixes: 1f311c94aabd ("mmc: rtsx: add 74 Clocks in power on flow") +Signed-off-by: Matthew Schwartz +Link: https://patch.msgid.link/20260105060236.400366-3-matthew.schwartz@linux.dev +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/mmc/host/rtsx_pci_sdmmc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c +index 4db3328f46dfb..b6cf1803c7d27 100644 +--- a/drivers/mmc/host/rtsx_pci_sdmmc.c ++++ b/drivers/mmc/host/rtsx_pci_sdmmc.c +@@ -937,7 +937,7 @@ static int sd_power_on(struct realtek_pci_sdmmc *host, unsigned char power_mode) + if (err < 0) + return err; + +- mdelay(1); ++ mdelay(5); + + err = rtsx_pci_write_register(pcr, CARD_OE, SD_OUTPUT_EN, SD_OUTPUT_EN); + if (err < 0) +-- +2.51.0 + diff --git a/queue-6.18/module-add-helper-function-for-reading-module_buildi.patch b/queue-6.18/module-add-helper-function-for-reading-module_buildi.patch new file mode 100644 index 0000000000..ee768abd3a --- /dev/null +++ b/queue-6.18/module-add-helper-function-for-reading-module_buildi.patch @@ -0,0 +1,80 @@ +From df596c1da1bfb45f39014c465ffd14ef36f61512 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 14:59:16 +0100 +Subject: module: add helper function for reading module_buildid() + +From: Petr Mladek + +[ Upstream commit acfdbb4ab2910ff6f03becb569c23ac7b2223913 ] + +Add a helper function for reading the optional "build_id" member of struct +module. It is going to be used also in ftrace_mod_address_lookup(). + +Use "#ifdef" instead of "#if IS_ENABLED()" to match the declaration of the +optional field in struct module. + +Link: https://lkml.kernel.org/r/20251128135920.217303-4-pmladek@suse.com +Signed-off-by: Petr Mladek +Reviewed-by: Daniel Gomez +Reviewed-by: Petr Pavlu +Cc: Aaron Tomlin +Cc: Alexei Starovoitov +Cc: Daniel Borkman +Cc: John Fastabend +Cc: Kees Cook +Cc: Luis Chamberalin +Cc: Marc Rutland +Cc: "Masami Hiramatsu (Google)" +Cc: Sami Tolvanen +Cc: Steven Rostedt (Google) +Signed-off-by: Andrew Morton +Stable-dep-of: e8a1e7eaa19d ("kallsyms/ftrace: set module buildid in ftrace_mod_address_lookup()") +Signed-off-by: Sasha Levin +--- + include/linux/module.h | 9 +++++++++ + kernel/module/kallsyms.c | 9 ++------- + 2 files changed, 11 insertions(+), 7 deletions(-) + +diff --git a/include/linux/module.h b/include/linux/module.h +index e135cc79aceea..4decae2b16755 100644 +--- a/include/linux/module.h ++++ b/include/linux/module.h +@@ -747,6 +747,15 @@ static inline void __module_get(struct module *module) + __mod ? __mod->name : "kernel"; \ + }) + ++static inline const unsigned char *module_buildid(struct module *mod) ++{ ++#ifdef CONFIG_STACKTRACE_BUILD_ID ++ return mod->build_id; ++#else ++ return NULL; ++#endif ++} ++ + /* Dereference module function descriptor */ + void *dereference_module_function_descriptor(struct module *mod, void *ptr); + +diff --git a/kernel/module/kallsyms.c b/kernel/module/kallsyms.c +index 00a60796327c0..0fc11e45df9b9 100644 +--- a/kernel/module/kallsyms.c ++++ b/kernel/module/kallsyms.c +@@ -334,13 +334,8 @@ int module_address_lookup(unsigned long addr, + if (mod) { + if (modname) + *modname = mod->name; +- if (modbuildid) { +-#if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID) +- *modbuildid = mod->build_id; +-#else +- *modbuildid = NULL; +-#endif +- } ++ if (modbuildid) ++ *modbuildid = module_buildid(mod); + + sym = find_kallsyms_symbol(mod, addr, size, offset); + +-- +2.51.0 + diff --git a/queue-6.18/mptcp-do-not-account-for-ooo-in-mptcp_rcvbuf_grow.patch b/queue-6.18/mptcp-do-not-account-for-ooo-in-mptcp_rcvbuf_grow.patch new file mode 100644 index 0000000000..b2132f7a00 --- /dev/null +++ b/queue-6.18/mptcp-do-not-account-for-ooo-in-mptcp_rcvbuf_grow.patch @@ -0,0 +1,63 @@ +From 102cf4dc1b5358d1ecf35c2390b17d14a7142857 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 19:41:17 +0100 +Subject: mptcp: do not account for OoO in mptcp_rcvbuf_grow() + +From: Paolo Abeni + +[ Upstream commit 6b329393502e5857662b851a13f947209c588587 ] + +MPTCP-level OoOs are physiological when multiple subflows are active +concurrently and will not cause retransmissions nor are caused by +drops. + +Accounting for them in mptcp_rcvbuf_grow() causes the rcvbuf slowly +drifting towards tcp_rmem[2]. + +Remove such accounting. Note that subflows will still account for TCP-level +OoO when the MPTCP-level rcvbuf is propagated. + +This also closes a subtle and very unlikely race condition with rcvspace +init; active sockets with user-space holding the msk-level socket lock, +could complete such initialization in the receive callback, after that the +first OoO data reaches the rcvbuf and potentially triggering a divide by +zero Oops. + +Fixes: e118cdc34dd1 ("mptcp: rcvbuf auto-tuning improvement") +Signed-off-by: Paolo Abeni +Reviewed-by: Mat Martineau +Signed-off-by: Matthieu Baerts (NGI0) +Link: https://patch.msgid.link/20260203-net-next-mptcp-misc-feat-6-20-v1-1-31ec8bfc56d1@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/mptcp/protocol.c | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c +index e4bb7e2d7b19a..15a70af7b776d 100644 +--- a/net/mptcp/protocol.c ++++ b/net/mptcp/protocol.c +@@ -224,9 +224,6 @@ static bool mptcp_rcvbuf_grow(struct sock *sk, u32 newval) + do_div(grow, oldval); + rcvwin += grow << 1; + +- if (!RB_EMPTY_ROOT(&msk->out_of_order_queue)) +- rcvwin += MPTCP_SKB_CB(msk->ooo_last_skb)->end_seq - msk->ack_seq; +- + cap = READ_ONCE(net->ipv4.sysctl_tcp_rmem[2]); + + rcvbuf = min_t(u32, mptcp_space_from_win(sk, rcvwin), cap); +@@ -350,9 +347,6 @@ static void mptcp_data_queue_ofo(struct mptcp_sock *msk, struct sk_buff *skb) + end: + skb_condense(skb); + skb_set_owner_r(skb, sk); +- /* do not grow rcvbuf for not-yet-accepted or orphaned sockets. */ +- if (sk->sk_socket) +- mptcp_rcvbuf_grow(sk, msk->rcvq_space.space); + } + + static void mptcp_init_skb(struct sock *ssk, struct sk_buff *skb, int offset, +-- +2.51.0 + diff --git a/queue-6.18/mptcp-fix-receive-space-timestamp-initialization.patch b/queue-6.18/mptcp-fix-receive-space-timestamp-initialization.patch new file mode 100644 index 0000000000..3d39308904 --- /dev/null +++ b/queue-6.18/mptcp-fix-receive-space-timestamp-initialization.patch @@ -0,0 +1,92 @@ +From e19b9f504cd909cc9f538c58ad03e9641549935a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 19:41:18 +0100 +Subject: mptcp: fix receive space timestamp initialization + +From: Paolo Abeni + +[ Upstream commit 70274765fef555af92a1532d5bd5450c691fca9d ] + +MPTCP initialize the receive buffer stamp in mptcp_rcv_space_init(), +using the provided subflow stamp. Such helper is invoked in several +places; for passive sockets, space init happened at clone time. + +In such scenario, MPTCP ends-up accesses the subflow stamp before +its initialization, leading to quite randomic timing for the first +receive buffer auto-tune event, as the timestamp for newly created +subflow is not refreshed there. + +Fix the issue moving the stamp initialization out of the mentioned helper, +at the data transfer start, and always using a fresh timestamp. + +Fixes: 013e3179dbd2 ("mptcp: fix rcv space initialization") +Reviewed-by: Mat Martineau +Signed-off-by: Paolo Abeni +Signed-off-by: Matthieu Baerts (NGI0) +Link: https://patch.msgid.link/20260203-net-next-mptcp-misc-feat-6-20-v1-2-31ec8bfc56d1@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/mptcp/protocol.c | 8 ++++---- + net/mptcp/protocol.h | 5 +++++ + 2 files changed, 9 insertions(+), 4 deletions(-) + +diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c +index 15a70af7b776d..8f18509204b67 100644 +--- a/net/mptcp/protocol.c ++++ b/net/mptcp/protocol.c +@@ -2056,8 +2056,8 @@ static void mptcp_rcv_space_adjust(struct mptcp_sock *msk, int copied) + + msk->rcvq_space.copied += copied; + +- mstamp = div_u64(tcp_clock_ns(), NSEC_PER_USEC); +- time = tcp_stamp_us_delta(mstamp, msk->rcvq_space.time); ++ mstamp = mptcp_stamp(); ++ time = tcp_stamp_us_delta(mstamp, READ_ONCE(msk->rcvq_space.time)); + + rtt_us = msk->rcvq_space.rtt_us; + if (rtt_us && time < (rtt_us >> 3)) +@@ -3421,6 +3421,7 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk, + __mptcp_propagate_sndbuf(nsk, ssk); + + mptcp_rcv_space_init(msk, ssk); ++ msk->rcvq_space.time = mptcp_stamp(); + + if (mp_opt->suboptions & OPTION_MPTCP_MPC_ACK) + __mptcp_subflow_fully_established(msk, subflow, mp_opt); +@@ -3438,8 +3439,6 @@ void mptcp_rcv_space_init(struct mptcp_sock *msk, const struct sock *ssk) + msk->rcvq_space.copied = 0; + msk->rcvq_space.rtt_us = 0; + +- msk->rcvq_space.time = tp->tcp_mstamp; +- + /* initial rcv_space offering made to peer */ + msk->rcvq_space.space = min_t(u32, tp->rcv_wnd, + TCP_INIT_CWND * tp->advmss); +@@ -3652,6 +3651,7 @@ void mptcp_finish_connect(struct sock *ssk) + * accessing the field below + */ + WRITE_ONCE(msk->local_key, subflow->local_key); ++ WRITE_ONCE(msk->rcvq_space.time, mptcp_stamp()); + + mptcp_pm_new_connection(msk, ssk, 0); + } +diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h +index 30d5e57197936..27b1698c5aa2d 100644 +--- a/net/mptcp/protocol.h ++++ b/net/mptcp/protocol.h +@@ -870,6 +870,11 @@ static inline bool mptcp_is_fully_established(struct sock *sk) + READ_ONCE(mptcp_sk(sk)->fully_established); + } + ++static inline u64 mptcp_stamp(void) ++{ ++ return div_u64(tcp_clock_ns(), NSEC_PER_USEC); ++} ++ + void mptcp_rcv_space_init(struct mptcp_sock *msk, const struct sock *ssk); + void mptcp_data_ready(struct sock *sk, struct sock *ssk); + bool mptcp_finish_join(struct sock *sk); +-- +2.51.0 + diff --git a/queue-6.18/mtd-intel-dg-fix-accessing-regions-before-setting-nr.patch b/queue-6.18/mtd-intel-dg-fix-accessing-regions-before-setting-nr.patch new file mode 100644 index 0000000000..c73f456b57 --- /dev/null +++ b/queue-6.18/mtd-intel-dg-fix-accessing-regions-before-setting-nr.patch @@ -0,0 +1,66 @@ +From 7b1551b8ab3c1733b78435855634201f7d916500 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 07:22:37 +0200 +Subject: mtd: intel-dg: Fix accessing regions before setting nregions + +From: Alexander Usyskin + +[ Upstream commit 779c59274d03cc5c07237a2c845dfb71cff77705 ] + +The regions array is counted by nregions, but it's set only after +accessing it: + +[] UBSAN: array-index-out-of-bounds in drivers/mtd/devices/mtd_intel_dg.c:750:15 +[] index 0 is out of range for type ' [*]' + +Fix it by also fixing an undesired behavior: the loop silently ignores +ENOMEM and continues setting the other entries. + +CC: Gustavo A. R. Silva +CC: Raag Jadav +Reported-by: Jani Partanen +Closes: https://lore.kernel.org/all/caca6c67-4f1d-49f1-948f-e63b6b937b29@sotapeli.fi +Fixes: ceb5ab3cb646 ("mtd: add driver for intel graphics non-volatile memory device") +Signed-off-by: Lucas De Marchi +Signed-off-by: Alexander Usyskin +Reviewed-by: Raag Jadav +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/devices/mtd_intel_dg.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/drivers/mtd/devices/mtd_intel_dg.c b/drivers/mtd/devices/mtd_intel_dg.c +index b438ee5aacc34..114e69135b8d9 100644 +--- a/drivers/mtd/devices/mtd_intel_dg.c ++++ b/drivers/mtd/devices/mtd_intel_dg.c +@@ -738,6 +738,7 @@ static int intel_dg_mtd_probe(struct auxiliary_device *aux_dev, + + kref_init(&nvm->refcnt); + mutex_init(&nvm->lock); ++ nvm->nregions = nregions; + + for (n = 0, i = 0; i < INTEL_DG_NVM_REGIONS; i++) { + if (!invm->regions[i].name) +@@ -745,13 +746,15 @@ static int intel_dg_mtd_probe(struct auxiliary_device *aux_dev, + + char *name = kasprintf(GFP_KERNEL, "%s.%s", + dev_name(&aux_dev->dev), invm->regions[i].name); +- if (!name) +- continue; ++ if (!name) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ + nvm->regions[n].name = name; + nvm->regions[n].id = i; + n++; + } +- nvm->nregions = n; /* in case where kasprintf fail */ + + nvm->base = devm_ioremap_resource(device, &invm->bar); + if (IS_ERR(nvm->base)) { +-- +2.51.0 + diff --git a/queue-6.18/mtd-parsers-fix-memory-leak-in-mtd_parser_tplink_saf.patch b/queue-6.18/mtd-parsers-fix-memory-leak-in-mtd_parser_tplink_saf.patch new file mode 100644 index 0000000000..6abb3f19c7 --- /dev/null +++ b/queue-6.18/mtd-parsers-fix-memory-leak-in-mtd_parser_tplink_saf.patch @@ -0,0 +1,42 @@ +From a1422c707212691f5214a18d79f39aa477c79e6e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 13:09:50 +0000 +Subject: mtd: parsers: Fix memory leak in mtd_parser_tplink_safeloader_parse() + +From: Zilin Guan + +[ Upstream commit 980ce2b02dd06a4fdf5fee38b2e14becf9cf7b8b ] + +The function mtd_parser_tplink_safeloader_parse() allocates buf via +mtd_parser_tplink_safeloader_read_table(). If the allocation for +parts[idx].name fails inside the loop, the code jumps to the err_free +label without freeing buf, leading to a memory leak. + +Fix this by freeing the temporary buffer buf in the err_free label. + +Compile tested only. Issue found using a prototype static analysis tool +and code review. + +Fixes: 00a3588084be ("mtd: parsers: add TP-Link SafeLoader partitions table parser") +Signed-off-by: Zilin Guan +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/parsers/tplink_safeloader.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/mtd/parsers/tplink_safeloader.c b/drivers/mtd/parsers/tplink_safeloader.c +index e358a029dc70c..4fcaf92d22e4f 100644 +--- a/drivers/mtd/parsers/tplink_safeloader.c ++++ b/drivers/mtd/parsers/tplink_safeloader.c +@@ -116,6 +116,7 @@ static int mtd_parser_tplink_safeloader_parse(struct mtd_info *mtd, + return idx; + + err_free: ++ kfree(buf); + for (idx -= 1; idx >= 0; idx--) + kfree(parts[idx].name); + err_free_parts: +-- +2.51.0 + diff --git a/queue-6.18/mtd-parsers-ofpart-fix-of-node-refcount-leak-in-pars.patch b/queue-6.18/mtd-parsers-ofpart-fix-of-node-refcount-leak-in-pars.patch new file mode 100644 index 0000000000..5532f11bfb --- /dev/null +++ b/queue-6.18/mtd-parsers-ofpart-fix-of-node-refcount-leak-in-pars.patch @@ -0,0 +1,84 @@ +From 51586f7a022f371fc7a7eadfc5337fd316f1a62c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 05:26:08 +0000 +Subject: mtd: parsers: ofpart: fix OF node refcount leak in + parse_fixed_partitions() + +From: Weigang He + +[ Upstream commit 7cce81df7d26d44123bd7620715c8349d96793d7 ] + +of_get_child_by_name() returns a node pointer with refcount incremented, +which must be released with of_node_put() when done. However, in +parse_fixed_partitions(), when dedicated is true (i.e., a "partitions" +subnode was found), the ofpart_node obtained from of_get_child_by_name() +is never released on any code path. + +Add of_node_put(ofpart_node) calls on all exit paths when dedicated is +true to fix the reference count leak. + +This bug was detected by our static analysis tool. + +Fixes: 562b4e91d3b2 ("mtd: parsers: ofpart: fix parsing subpartitions") +Signed-off-by: Weigang He +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/parsers/ofpart_core.c | 16 ++++++++++++++-- + 1 file changed, 14 insertions(+), 2 deletions(-) + +diff --git a/drivers/mtd/parsers/ofpart_core.c b/drivers/mtd/parsers/ofpart_core.c +index abfa687989182..09961c6f39496 100644 +--- a/drivers/mtd/parsers/ofpart_core.c ++++ b/drivers/mtd/parsers/ofpart_core.c +@@ -77,6 +77,7 @@ static int parse_fixed_partitions(struct mtd_info *master, + of_id = of_match_node(parse_ofpart_match_table, ofpart_node); + if (dedicated && !of_id) { + /* The 'partitions' subnode might be used by another parser */ ++ of_node_put(ofpart_node); + return 0; + } + +@@ -91,12 +92,18 @@ static int parse_fixed_partitions(struct mtd_info *master, + nr_parts++; + } + +- if (nr_parts == 0) ++ if (nr_parts == 0) { ++ if (dedicated) ++ of_node_put(ofpart_node); + return 0; ++ } + + parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL); +- if (!parts) ++ if (!parts) { ++ if (dedicated) ++ of_node_put(ofpart_node); + return -ENOMEM; ++ } + + i = 0; + for_each_child_of_node(ofpart_node, pp) { +@@ -175,6 +182,9 @@ static int parse_fixed_partitions(struct mtd_info *master, + if (quirks && quirks->post_parse) + quirks->post_parse(master, parts, nr_parts); + ++ if (dedicated) ++ of_node_put(ofpart_node); ++ + *pparts = parts; + return nr_parts; + +@@ -183,6 +193,8 @@ static int parse_fixed_partitions(struct mtd_info *master, + master->name, pp, mtd_node); + ret = -EINVAL; + ofpart_none: ++ if (dedicated) ++ of_node_put(ofpart_node); + of_node_put(pp); + kfree(parts); + return ret; +-- +2.51.0 + diff --git a/queue-6.18/mtd-rawnand-cadence-fix-return-type-of-cdma-send-and.patch b/queue-6.18/mtd-rawnand-cadence-fix-return-type-of-cdma-send-and.patch new file mode 100644 index 0000000000..88e1f86ca1 --- /dev/null +++ b/queue-6.18/mtd-rawnand-cadence-fix-return-type-of-cdma-send-and.patch @@ -0,0 +1,40 @@ +From 778983c2eea5388fcae419f28a4c8cf1978e301b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 19 Dec 2025 03:09:30 -0800 +Subject: mtd: rawnand: cadence: Fix return type of CDMA send-and-wait helper + +From: Alok Tiwari + +[ Upstream commit 6d8226cbbf124bb5613b532216b74c886a4361b7 ] + +cadence_nand_cdma_send_and_wait() propagates negative errno values +from cadence_nand_cdma_send(), returns -ETIMEDOUT on failure and -EIO +when the CDMA engine reports a command failure. + +However, it is declared as u32, causing error codes to wrap. +Change the return type to int to correctly propagate errors. + +Fixes: ec4ba01e894d ("mtd: rawnand: Add new Cadence NAND driver to MTD subsystem") +Signed-off-by: Alok Tiwari +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/nand/raw/cadence-nand-controller.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/nand/raw/cadence-nand-controller.c b/drivers/mtd/nand/raw/cadence-nand-controller.c +index 32ed38b893947..21eabedc2ed1c 100644 +--- a/drivers/mtd/nand/raw/cadence-nand-controller.c ++++ b/drivers/mtd/nand/raw/cadence-nand-controller.c +@@ -1015,7 +1015,7 @@ static int cadence_nand_cdma_send(struct cdns_nand_ctrl *cdns_ctrl, + } + + /* Send SDMA command and wait for finish. */ +-static u32 ++static int + cadence_nand_cdma_send_and_wait(struct cdns_nand_ctrl *cdns_ctrl, + u8 thread) + { +-- +2.51.0 + diff --git a/queue-6.18/mtd-spinand-fix-kernel-doc.patch b/queue-6.18/mtd-spinand-fix-kernel-doc.patch new file mode 100644 index 0000000000..6e533c8a94 --- /dev/null +++ b/queue-6.18/mtd-spinand-fix-kernel-doc.patch @@ -0,0 +1,36 @@ +From 949edff5f2dc12f2a15d84a14f9a80b7f11f351c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 18:18:02 +0100 +Subject: mtd: spinand: Fix kernel doc + +From: Miquel Raynal + +[ Upstream commit a57b1f07d2d35843a7ada30c8cf9a215c0931868 ] + +The @data buffer is 5 bytes, not 4, it has been extended for the need of +devices with an extra ID bytes. + +Fixes: 34a956739d29 ("mtd: spinand: Add support for 5-byte IDs") +Reviewed-by: Tudor Ambarus +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + include/linux/mtd/spinand.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h +index 927c10d787695..1c741145e4971 100644 +--- a/include/linux/mtd/spinand.h ++++ b/include/linux/mtd/spinand.h +@@ -287,7 +287,7 @@ struct spinand_device; + + /** + * struct spinand_id - SPI NAND id structure +- * @data: buffer containing the id bytes. Currently 4 bytes large, but can ++ * @data: buffer containing the id bytes. Currently 5 bytes large, but can + * be extended if required + * @len: ID length + */ +-- +2.51.0 + diff --git a/queue-6.18/net-atm-fix-crash-due-to-unvalidated-vcc-pointer-in-.patch b/queue-6.18/net-atm-fix-crash-due-to-unvalidated-vcc-pointer-in-.patch new file mode 100644 index 0000000000..80eec8a0a5 --- /dev/null +++ b/queue-6.18/net-atm-fix-crash-due-to-unvalidated-vcc-pointer-in-.patch @@ -0,0 +1,154 @@ +From 4de4eba5c5c92cfd3c7ff15a852ac1f2d61e3157 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 17:54:51 +0800 +Subject: net: atm: fix crash due to unvalidated vcc pointer in sigd_send() + +From: Jiayuan Chen + +[ Upstream commit ae88a5d2f29b69819dc7b04086734439d074a643 ] + +Reproducer available at [1]. + +The ATM send path (sendmsg -> vcc_sendmsg -> sigd_send) reads the vcc +pointer from msg->vcc and uses it directly without any validation. This +pointer comes from userspace via sendmsg() and can be arbitrarily forged: + + int fd = socket(AF_ATMSVC, SOCK_DGRAM, 0); + ioctl(fd, ATMSIGD_CTRL); // become ATM signaling daemon + struct msghdr msg = { .msg_iov = &iov, ... }; + *(unsigned long *)(buf + 4) = 0xdeadbeef; // fake vcc pointer + sendmsg(fd, &msg, 0); // kernel dereferences 0xdeadbeef + +In normal operation, the kernel sends the vcc pointer to the signaling +daemon via sigd_enq() when processing operations like connect(), bind(), +or listen(). The daemon is expected to return the same pointer when +responding. However, a malicious daemon can send arbitrary pointer values. + +Fix this by introducing find_get_vcc() which validates the pointer by +searching through vcc_hash (similar to how sigd_close() iterates over +all VCCs), and acquires a reference via sock_hold() if found. + +Since struct atm_vcc embeds struct sock as its first member, they share +the same lifetime. Therefore using sock_hold/sock_put is sufficient to +keep the vcc alive while it is being used. + +Note that there may be a race with sigd_close() which could mark the vcc +with various flags (e.g., ATM_VF_RELEASED) after find_get_vcc() returns. +However, sock_hold() guarantees the memory remains valid, so this race +only affects the logical state, not memory safety. + +[1]: https://gist.github.com/mrpre/1ba5949c45529c511152e2f4c755b0f3 +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: syzbot+1f22cb1769f249df9fa0@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/69039850.a70a0220.5b2ed.005d.GAE@google.com/T/ +Signed-off-by: Jiayuan Chen +Link: https://patch.msgid.link/20260205095501.131890-1-jiayuan.chen@linux.dev +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/atm/signaling.c | 56 +++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 54 insertions(+), 2 deletions(-) + +diff --git a/net/atm/signaling.c b/net/atm/signaling.c +index e70ae2c113f95..358fbe5e4d1d0 100644 +--- a/net/atm/signaling.c ++++ b/net/atm/signaling.c +@@ -22,6 +22,36 @@ + + struct atm_vcc *sigd = NULL; + ++/* ++ * find_get_vcc - validate and get a reference to a vcc pointer ++ * @vcc: the vcc pointer to validate ++ * ++ * This function validates that @vcc points to a registered VCC in vcc_hash. ++ * If found, it increments the socket reference count and returns the vcc. ++ * The caller must call sock_put(sk_atm(vcc)) when done. ++ * ++ * Returns the vcc pointer if valid, NULL otherwise. ++ */ ++static struct atm_vcc *find_get_vcc(struct atm_vcc *vcc) ++{ ++ int i; ++ ++ read_lock(&vcc_sklist_lock); ++ for (i = 0; i < VCC_HTABLE_SIZE; i++) { ++ struct sock *s; ++ ++ sk_for_each(s, &vcc_hash[i]) { ++ if (atm_sk(s) == vcc) { ++ sock_hold(s); ++ read_unlock(&vcc_sklist_lock); ++ return vcc; ++ } ++ } ++ } ++ read_unlock(&vcc_sklist_lock); ++ return NULL; ++} ++ + static void sigd_put_skb(struct sk_buff *skb) + { + if (!sigd) { +@@ -69,7 +99,14 @@ static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb) + + msg = (struct atmsvc_msg *) skb->data; + WARN_ON(refcount_sub_and_test(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc)); +- vcc = *(struct atm_vcc **) &msg->vcc; ++ ++ vcc = find_get_vcc(*(struct atm_vcc **)&msg->vcc); ++ if (!vcc) { ++ pr_debug("invalid vcc pointer in msg\n"); ++ dev_kfree_skb(skb); ++ return -EINVAL; ++ } ++ + pr_debug("%d (0x%lx)\n", (int)msg->type, (unsigned long)vcc); + sk = sk_atm(vcc); + +@@ -100,7 +137,16 @@ static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb) + clear_bit(ATM_VF_WAITING, &vcc->flags); + break; + case as_indicate: +- vcc = *(struct atm_vcc **)&msg->listen_vcc; ++ /* Release the reference from msg->vcc, we'll use msg->listen_vcc instead */ ++ sock_put(sk); ++ ++ vcc = find_get_vcc(*(struct atm_vcc **)&msg->listen_vcc); ++ if (!vcc) { ++ pr_debug("invalid listen_vcc pointer in msg\n"); ++ dev_kfree_skb(skb); ++ return -EINVAL; ++ } ++ + sk = sk_atm(vcc); + pr_debug("as_indicate!!!\n"); + lock_sock(sk); +@@ -115,6 +161,8 @@ static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb) + sk->sk_state_change(sk); + as_indicate_complete: + release_sock(sk); ++ /* Paired with find_get_vcc(msg->listen_vcc) above */ ++ sock_put(sk); + return 0; + case as_close: + set_bit(ATM_VF_RELEASED, &vcc->flags); +@@ -131,11 +179,15 @@ static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb) + break; + default: + pr_alert("bad message type %d\n", (int)msg->type); ++ /* Paired with find_get_vcc(msg->vcc) above */ ++ sock_put(sk); + return -EINVAL; + } + sk->sk_state_change(sk); + out: + dev_kfree_skb(skb); ++ /* Paired with find_get_vcc(msg->vcc) above */ ++ sock_put(sk); + return 0; + } + +-- +2.51.0 + diff --git a/queue-6.18/net-hns3-fix-double-free-issue-for-tx-spare-buffer.patch b/queue-6.18/net-hns3-fix-double-free-issue-for-tx-spare-buffer.patch new file mode 100644 index 0000000000..5049a03ebe --- /dev/null +++ b/queue-6.18/net-hns3-fix-double-free-issue-for-tx-spare-buffer.patch @@ -0,0 +1,74 @@ +From 2b405a0a71642bde6aab8584887dfed1664b582c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 20:17:19 +0800 +Subject: net: hns3: fix double free issue for tx spare buffer + +From: Jian Shen + +[ Upstream commit 6d2f142b1e4b203387a92519d9d2e34752a79dbb ] + +In hns3_set_ringparam(), a temporary copy (tmp_rings) of the ring structure +is created for rollback. However, the tx_spare pointer in the original +ring handle is incorrectly left pointing to the old backup memory. + +Later, if memory allocation fails in hns3_init_all_ring() during the setup, +the error path attempts to free all newly allocated rings. Since tx_spare +contains a stale (non-NULL) pointer from the backup, it is mistaken for +a newly allocated buffer and is erroneously freed, leading to a double-free +of the backup memory. + +The root cause is that the tx_spare field was not cleared after its value +was saved in tmp_rings, leaving a dangling pointer. + +Fix this by setting tx_spare to NULL in the original ring structure +when the creation of the new `tx_spare` fails. This ensures the +error cleanup path only frees genuinely newly allocated buffers. + +Fixes: 907676b130711 ("net: hns3: use tx bounce buffer for small packets") +Signed-off-by: Jian Shen +Signed-off-by: Jijie Shao +Reviewed-by: Jacob Keller +Link: https://patch.msgid.link/20260205121719.3285730-1-shaojijie@huawei.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +index e976a88b952f0..c8eba180250e7 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +@@ -1048,13 +1048,13 @@ static void hns3_init_tx_spare_buffer(struct hns3_enet_ring *ring) + int order; + + if (!alloc_size) +- return; ++ goto not_init; + + order = get_order(alloc_size); + if (order > MAX_PAGE_ORDER) { + if (net_ratelimit()) + dev_warn(ring_to_dev(ring), "failed to allocate tx spare buffer, exceed to max order\n"); +- return; ++ goto not_init; + } + + tx_spare = devm_kzalloc(ring_to_dev(ring), sizeof(*tx_spare), +@@ -1092,6 +1092,13 @@ static void hns3_init_tx_spare_buffer(struct hns3_enet_ring *ring) + devm_kfree(ring_to_dev(ring), tx_spare); + devm_kzalloc_error: + ring->tqp->handle->kinfo.tx_spare_buf_size = 0; ++not_init: ++ /* When driver init or reset_init, the ring->tx_spare is always NULL; ++ * but when called from hns3_set_ringparam, it's usually not NULL, and ++ * will be restored if hns3_init_all_ring() failed. So it's safe to set ++ * ring->tx_spare to NULL here. ++ */ ++ ring->tx_spare = NULL; + } + + /* Use hns3_tx_spare_space() to make sure there is enough buffer +-- +2.51.0 + diff --git a/queue-6.18/net-mctp-i2c-fix-duplicate-reception-of-old-data.patch b/queue-6.18/net-mctp-i2c-fix-duplicate-reception-of-old-data.patch new file mode 100644 index 0000000000..22b2b796a5 --- /dev/null +++ b/queue-6.18/net-mctp-i2c-fix-duplicate-reception-of-old-data.patch @@ -0,0 +1,49 @@ +From 2fc490db7a93bba46b564df0ae0f36937f9650a7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 18:18:29 +0800 +Subject: net: mctp-i2c: fix duplicate reception of old data + +From: Jian Zhang + +[ Upstream commit ae4744e173fadd092c43eda4ca92dcb74645225a ] + +The MCTP I2C slave callback did not handle I2C_SLAVE_READ_REQUESTED +events. As a result, i2c read event will trigger repeated reception of +old data, reset rx_pos when a read request is received. + +Signed-off-by: Jian Zhang +Link: https://patch.msgid.link/20260108101829.1140448-1-zhangjian.3032@bytedance.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 2a14e91b6d76 ("mctp i2c: initialise event handler read bytes") +Signed-off-by: Sasha Levin +--- + drivers/net/mctp/mctp-i2c.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/mctp/mctp-i2c.c b/drivers/net/mctp/mctp-i2c.c +index f782d93f826ef..ecda1cc36391c 100644 +--- a/drivers/net/mctp/mctp-i2c.c ++++ b/drivers/net/mctp/mctp-i2c.c +@@ -242,6 +242,9 @@ static int mctp_i2c_slave_cb(struct i2c_client *client, + return 0; + + switch (event) { ++ case I2C_SLAVE_READ_REQUESTED: ++ midev->rx_pos = 0; ++ break; + case I2C_SLAVE_WRITE_RECEIVED: + if (midev->rx_pos < MCTP_I2C_BUFSZ) { + midev->rx_buffer[midev->rx_pos] = *val; +@@ -279,6 +282,9 @@ static int mctp_i2c_recv(struct mctp_i2c_dev *midev) + size_t recvlen; + int status; + ++ if (midev->rx_pos == 0) ++ return 0; ++ + /* + 1 for the PEC */ + if (midev->rx_pos < MCTP_I2C_MINLEN + 1) { + ndev->stats.rx_length_errors++; +-- +2.51.0 + diff --git a/queue-6.18/net-renesas-rswitch-fix-forwarding-offload-statemach.patch b/queue-6.18/net-renesas-rswitch-fix-forwarding-offload-statemach.patch new file mode 100644 index 0000000000..ac5fb411ea --- /dev/null +++ b/queue-6.18/net-renesas-rswitch-fix-forwarding-offload-statemach.patch @@ -0,0 +1,73 @@ +From 947ac10e214e73a838c293505ddb7560aa418616 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 14:41:53 +0100 +Subject: net: renesas: rswitch: fix forwarding offload statemachine + +From: Michael Dege + +[ Upstream commit e9a5073a98d940837cbb95e71eed1f28f48e7b30 ] + +A change of the port state of one port, caused the state of another +port to change. This behvior was unintended. + +Fixes: b7502b1043de ("net: renesas: rswitch: add offloading for L2 switching") +Signed-off-by: Michael Dege +Link: https://patch.msgid.link/20260206-fix-offloading-statemachine-v3-1-07bfba07d03e@renesas.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/renesas/rswitch_l2.c | 15 +++++++-------- + 1 file changed, 7 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/ethernet/renesas/rswitch_l2.c b/drivers/net/ethernet/renesas/rswitch_l2.c +index 4a69ec77d69c6..9433cd8adced9 100644 +--- a/drivers/net/ethernet/renesas/rswitch_l2.c ++++ b/drivers/net/ethernet/renesas/rswitch_l2.c +@@ -1,7 +1,7 @@ + // SPDX-License-Identifier: GPL-2.0 + /* Renesas Ethernet Switch device driver + * +- * Copyright (C) 2025 Renesas Electronics Corporation ++ * Copyright (C) 2025 - 2026 Renesas Electronics Corporation + */ + + #include +@@ -60,6 +60,7 @@ static void rswitch_update_l2_hw_learning(struct rswitch_private *priv) + static void rswitch_update_l2_hw_forwarding(struct rswitch_private *priv) + { + struct rswitch_device *rdev; ++ bool new_forwarding_offload; + unsigned int fwd_mask; + + /* calculate fwd_mask with zeroes in bits corresponding to ports that +@@ -73,8 +74,9 @@ static void rswitch_update_l2_hw_forwarding(struct rswitch_private *priv) + } + + rswitch_for_all_ports(priv, rdev) { +- if ((rdev_for_l2_offload(rdev) && rdev->forwarding_requested) || +- rdev->forwarding_offloaded) { ++ new_forwarding_offload = (rdev_for_l2_offload(rdev) && rdev->forwarding_requested); ++ ++ if (new_forwarding_offload || rdev->forwarding_offloaded) { + /* Update allowed offload destinations even for ports + * with L2 offload enabled earlier. + * +@@ -84,13 +86,10 @@ static void rswitch_update_l2_hw_forwarding(struct rswitch_private *priv) + priv->addr + FWPC2(rdev->port)); + } + +- if (rdev_for_l2_offload(rdev) && +- rdev->forwarding_requested && +- !rdev->forwarding_offloaded) { ++ if (new_forwarding_offload && !rdev->forwarding_offloaded) + rswitch_change_l2_hw_offloading(rdev, true, false); +- } else if (rdev->forwarding_offloaded) { ++ else if (!new_forwarding_offload && rdev->forwarding_offloaded) + rswitch_change_l2_hw_offloading(rdev, false, false); +- } + } + } + +-- +2.51.0 + diff --git a/queue-6.18/net-sunhme-fix-sbus-regression.patch b/queue-6.18/net-sunhme-fix-sbus-regression.patch new file mode 100644 index 0000000000..6e890aaa3b --- /dev/null +++ b/queue-6.18/net-sunhme-fix-sbus-regression.patch @@ -0,0 +1,73 @@ +From c63c6e71be51be5c32552213b5cd18ca007dd801 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 17:09:59 +0100 +Subject: net: sunhme: Fix sbus regression +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: René Rebe + +[ Upstream commit 8c5d17834ec104d0abd1bda52fbc04e647fab274 ] + +Commit cc216e4b44ce ("net: sunhme: Switch SBUS to devres") changed +explicit sized of_ioremap with BMAC_REG_SIZEs to +devm_platform_ioremap_resource mapping all the resource. However, +this does not work on my Sun Ultra 2 with SBUS HMEs: + +hme f0072f38: error -EBUSY: can't request region for resource [mem 0x1ffe8c07000-0x1ffe8c0701f] +hme f0072f38: Cannot map TCVR registers. +hme f0072f38: probe with driver hme failed with error -16 +hme f007ab44: error -EBUSY: can't request region for resource [mem 0x1ff28c07000-0x1ff28c0701f] +hme f007ab44: Cannot map TCVR registers. +hme f007ab44: probe with driver hme failed with error -16 + +Turns out the open-firmware resources overlap, at least on this +machines and PROM version: + +hexdump /proc/device-tree/sbus@1f,0/SUNW,hme@2,8c00000/reg: +00 00 00 02 08 c0 00 00 00 00 01 08 +00 00 00 02 08 c0 20 00 00 00 20 00 +00 00 00 02 08 c0 40 00 00 00 20 00 +00 00 00 02 08 c0 60 00 00 00 20 00 +00 00 00 02 08 c0 70 00 00 00 00 20 + +And the driver previously explicitly mapped way smaller mmio regions: + +/proc/iomem: +1ff28c00000-1ff28c00107 : HME Global Regs +1ff28c02000-1ff28c02033 : HME TX Regs +1ff28c04000-1ff28c0401f : HME RX Regs +1ff28c06000-1ff28c0635f : HME BIGMAC Regs +1ff28c07000-1ff28c0701f : HME Tranceiver Regs + +Quirk this specific issue by truncating the previous resource to not +overlap into the TCVR registers. + +Fixes: cc216e4b44ce ("net: sunhme: Switch SBUS to devres") +Signed-off-by: René Rebe +Reviewed-by: Sean Anderson +Link: https://patch.msgid.link/20260205.170959.89574674688839340.rene@exactco.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/sun/sunhme.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/ethernet/sun/sunhme.c b/drivers/net/ethernet/sun/sunhme.c +index 48f0a96c0e9e3..6669980829980 100644 +--- a/drivers/net/ethernet/sun/sunhme.c ++++ b/drivers/net/ethernet/sun/sunhme.c +@@ -2551,6 +2551,9 @@ static int happy_meal_sbus_probe_one(struct platform_device *op, int is_qfe) + goto err_out_clear_quattro; + } + ++ /* BIGMAC may have bogus sizes */ ++ if ((op->resource[3].end - op->resource[3].start) >= BMAC_REG_SIZE) ++ op->resource[3].end = op->resource[3].start + BMAC_REG_SIZE - 1; + hp->bigmacregs = devm_platform_ioremap_resource(op, 3); + if (IS_ERR(hp->bigmacregs)) { + dev_err(&op->dev, "Cannot map BIGMAC registers.\n"); +-- +2.51.0 + diff --git a/queue-6.18/netfilter-nf_conncount-fix-tracking-of-connections-f.patch b/queue-6.18/netfilter-nf_conncount-fix-tracking-of-connections-f.patch new file mode 100644 index 0000000000..584cdd9ddb --- /dev/null +++ b/queue-6.18/netfilter-nf_conncount-fix-tracking-of-connections-f.patch @@ -0,0 +1,69 @@ +From 8a8d4d27f32fdb2210f0fb448de717fc36c9fb04 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 21:35:46 +0100 +Subject: netfilter: nf_conncount: fix tracking of connections from localhost + +From: Fernando Fernandez Mancera + +[ Upstream commit de8a70cefcb26cdceaafdc5ac144712681419c29 ] + +Since commit be102eb6a0e7 ("netfilter: nf_conncount: rework API to use +sk_buff directly"), we skip the adding and trigger a GC when the ct is +confirmed. For connections originated from local to local it doesn't +work because the connection is confirmed on POSTROUTING, therefore +tracking on the INPUT hook is always skipped. + +In order to fix this, we check whether skb input ifindex is set to +loopback ifindex. If it is then we fallback on a GC plus track operation +skipping the optimization. This fallback is necessary to avoid +duplicated tracking of a packet train e.g 10 UDP datagrams sent on a +burst when initiating the connection. + +Tested with xt_connlimit/nft_connlimit and OVS limit and with a HTTP +server and iperf3 on UDP mode. + +Fixes: be102eb6a0e7 ("netfilter: nf_conncount: rework API to use sk_buff directly") +Reported-by: Michal Slabihoudek +Closes: https://lore.kernel.org/netfilter/6989BD9F-8C24-4397-9AD7-4613B28BF0DB@gooddata.com/ +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_conncount.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +diff --git a/net/netfilter/nf_conncount.c b/net/netfilter/nf_conncount.c +index 288936f5c1bf9..14e62b3263cd9 100644 +--- a/net/netfilter/nf_conncount.c ++++ b/net/netfilter/nf_conncount.c +@@ -179,14 +179,25 @@ static int __nf_conncount_add(struct net *net, + return -ENOENT; + + if (ct && nf_ct_is_confirmed(ct)) { +- err = -EEXIST; +- goto out_put; ++ /* local connections are confirmed in postrouting so confirmation ++ * might have happened before hitting connlimit ++ */ ++ if (skb->skb_iif != LOOPBACK_IFINDEX) { ++ err = -EEXIST; ++ goto out_put; ++ } ++ ++ /* this is likely a local connection, skip optimization to avoid ++ * adding duplicates from a 'packet train' ++ */ ++ goto check_connections; + } + + if ((u32)jiffies == list->last_gc && + (list->count - list->last_gc_count) < CONNCOUNT_GC_MAX_COLLECT) + goto add_new_node; + ++check_connections: + /* check the saved connections */ + list_for_each_entry_safe(conn, conn_n, &list->head, node) { + if (collect > CONNCOUNT_GC_MAX_COLLECT) +-- +2.51.0 + diff --git a/queue-6.18/netfilter-nf_conncount-increase-the-connection-clean.patch b/queue-6.18/netfilter-nf_conncount-increase-the-connection-clean.patch new file mode 100644 index 0000000000..3cc1fa143e --- /dev/null +++ b/queue-6.18/netfilter-nf_conncount-increase-the-connection-clean.patch @@ -0,0 +1,123 @@ +From 64b59e5b74acc4ccfe03b9fe9991ccdc1566ab34 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 17 Dec 2025 15:46:41 +0100 +Subject: netfilter: nf_conncount: increase the connection clean up limit to 64 + +From: Fernando Fernandez Mancera + +[ Upstream commit 21d033e472735ecec677f1ae46d6740b5e47a4f3 ] + +After the optimization to only perform one GC per jiffy, a new problem +was introduced. If more than 8 new connections are tracked per jiffy the +list won't be cleaned up fast enough possibly reaching the limit +wrongly. + +In order to prevent this issue, only skip the GC if it was already +triggered during the same jiffy and the increment is lower than the +clean up limit. In addition, increase the clean up limit to 64 +connections to avoid triggering GC too often and do more effective GCs. + +This has been tested using a HTTP server and several +performance tools while having nft_connlimit/xt_connlimit or OVS limit +configured. + +Output of slowhttptest + OVS limit at 52000 connections: + + slow HTTP test status on 340th second: + initializing: 0 + pending: 432 + connected: 51998 + error: 0 + closed: 0 + service available: YES + +Fixes: d265929930e2 ("netfilter: nf_conncount: reduce unnecessary GC") +Reported-by: Aleksandra Rukomoinikova +Closes: https://lore.kernel.org/netfilter/b2064e7b-0776-4e14-adb6-c68080987471@k2.cloud/ +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + include/net/netfilter/nf_conntrack_count.h | 1 + + net/netfilter/nf_conncount.c | 15 ++++++++++----- + 2 files changed, 11 insertions(+), 5 deletions(-) + +diff --git a/include/net/netfilter/nf_conntrack_count.h b/include/net/netfilter/nf_conntrack_count.h +index 52a06de41aa0f..cf0166520cf33 100644 +--- a/include/net/netfilter/nf_conntrack_count.h ++++ b/include/net/netfilter/nf_conntrack_count.h +@@ -13,6 +13,7 @@ struct nf_conncount_list { + u32 last_gc; /* jiffies at most recent gc */ + struct list_head head; /* connections with the same filtering key */ + unsigned int count; /* length of list */ ++ unsigned int last_gc_count; /* length of list at most recent gc */ + }; + + struct nf_conncount_data *nf_conncount_init(struct net *net, unsigned int keylen); +diff --git a/net/netfilter/nf_conncount.c b/net/netfilter/nf_conncount.c +index 8487808c87614..288936f5c1bf9 100644 +--- a/net/netfilter/nf_conncount.c ++++ b/net/netfilter/nf_conncount.c +@@ -34,8 +34,9 @@ + + #define CONNCOUNT_SLOTS 256U + +-#define CONNCOUNT_GC_MAX_NODES 8 +-#define MAX_KEYLEN 5 ++#define CONNCOUNT_GC_MAX_NODES 8 ++#define CONNCOUNT_GC_MAX_COLLECT 64 ++#define MAX_KEYLEN 5 + + /* we will save the tuples of all connections we care about */ + struct nf_conncount_tuple { +@@ -182,12 +183,13 @@ static int __nf_conncount_add(struct net *net, + goto out_put; + } + +- if ((u32)jiffies == list->last_gc) ++ if ((u32)jiffies == list->last_gc && ++ (list->count - list->last_gc_count) < CONNCOUNT_GC_MAX_COLLECT) + goto add_new_node; + + /* check the saved connections */ + list_for_each_entry_safe(conn, conn_n, &list->head, node) { +- if (collect > CONNCOUNT_GC_MAX_NODES) ++ if (collect > CONNCOUNT_GC_MAX_COLLECT) + break; + + found = find_or_evict(net, list, conn); +@@ -230,6 +232,7 @@ static int __nf_conncount_add(struct net *net, + nf_ct_put(found_ct); + } + list->last_gc = (u32)jiffies; ++ list->last_gc_count = list->count; + + add_new_node: + if (WARN_ON_ONCE(list->count > INT_MAX)) { +@@ -277,6 +280,7 @@ void nf_conncount_list_init(struct nf_conncount_list *list) + spin_lock_init(&list->list_lock); + INIT_LIST_HEAD(&list->head); + list->count = 0; ++ list->last_gc_count = 0; + list->last_gc = (u32)jiffies; + } + EXPORT_SYMBOL_GPL(nf_conncount_list_init); +@@ -316,13 +320,14 @@ static bool __nf_conncount_gc_list(struct net *net, + } + + nf_ct_put(found_ct); +- if (collected > CONNCOUNT_GC_MAX_NODES) ++ if (collected > CONNCOUNT_GC_MAX_COLLECT) + break; + } + + if (!list->count) + ret = true; + list->last_gc = (u32)jiffies; ++ list->last_gc_count = list->count; + + return ret; + } +-- +2.51.0 + diff --git a/queue-6.18/netfilter-nf_conncount-make-nf_conncount_gc_list-to-.patch b/queue-6.18/netfilter-nf_conncount-make-nf_conncount_gc_list-to-.patch new file mode 100644 index 0000000000..d42da36351 --- /dev/null +++ b/queue-6.18/netfilter-nf_conncount-make-nf_conncount_gc_list-to-.patch @@ -0,0 +1,93 @@ +From 511467d3d66ccb3bfe6db38e7a4c171bba5850a9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 21 Nov 2025 01:14:31 +0100 +Subject: netfilter: nf_conncount: make nf_conncount_gc_list() to disable BH + +From: Fernando Fernandez Mancera + +[ Upstream commit c0362b5748282e22fa1592a8d3474f726ad964c2 ] + +For convenience when performing GC over the connection list, make +nf_conncount_gc_list() to disable BH. This unifies the behavior with +nf_conncount_add() and nf_conncount_count(). + +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: 21d033e47273 ("netfilter: nf_conncount: increase the connection clean up limit to 64") +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_conncount.c | 24 +++++++++++++++++------- + net/netfilter/nft_connlimit.c | 7 +------ + 2 files changed, 18 insertions(+), 13 deletions(-) + +diff --git a/net/netfilter/nf_conncount.c b/net/netfilter/nf_conncount.c +index 828d5c64c68a3..8487808c87614 100644 +--- a/net/netfilter/nf_conncount.c ++++ b/net/netfilter/nf_conncount.c +@@ -282,8 +282,8 @@ void nf_conncount_list_init(struct nf_conncount_list *list) + EXPORT_SYMBOL_GPL(nf_conncount_list_init); + + /* Return true if the list is empty. Must be called with BH disabled. */ +-bool nf_conncount_gc_list(struct net *net, +- struct nf_conncount_list *list) ++static bool __nf_conncount_gc_list(struct net *net, ++ struct nf_conncount_list *list) + { + const struct nf_conntrack_tuple_hash *found; + struct nf_conncount_tuple *conn, *conn_n; +@@ -295,10 +295,6 @@ bool nf_conncount_gc_list(struct net *net, + if ((u32)jiffies == READ_ONCE(list->last_gc)) + return false; + +- /* don't bother if other cpu is already doing GC */ +- if (!spin_trylock(&list->list_lock)) +- return false; +- + list_for_each_entry_safe(conn, conn_n, &list->head, node) { + found = find_or_evict(net, list, conn); + if (IS_ERR(found)) { +@@ -327,7 +323,21 @@ bool nf_conncount_gc_list(struct net *net, + if (!list->count) + ret = true; + list->last_gc = (u32)jiffies; +- spin_unlock(&list->list_lock); ++ ++ return ret; ++} ++ ++bool nf_conncount_gc_list(struct net *net, ++ struct nf_conncount_list *list) ++{ ++ bool ret; ++ ++ /* don't bother if other cpu is already doing GC */ ++ if (!spin_trylock_bh(&list->list_lock)) ++ return false; ++ ++ ret = __nf_conncount_gc_list(net, list); ++ spin_unlock_bh(&list->list_lock); + + return ret; + } +diff --git a/net/netfilter/nft_connlimit.c b/net/netfilter/nft_connlimit.c +index d4964087bbc5e..714a594859357 100644 +--- a/net/netfilter/nft_connlimit.c ++++ b/net/netfilter/nft_connlimit.c +@@ -232,13 +232,8 @@ static void nft_connlimit_destroy_clone(const struct nft_ctx *ctx, + static bool nft_connlimit_gc(struct net *net, const struct nft_expr *expr) + { + struct nft_connlimit *priv = nft_expr_priv(expr); +- bool ret; + +- local_bh_disable(); +- ret = nf_conncount_gc_list(net, priv->list); +- local_bh_enable(); +- +- return ret; ++ return nf_conncount_gc_list(net, priv->list); + } + + static struct nft_expr_type nft_connlimit_type; +-- +2.51.0 + diff --git a/queue-6.18/netfilter-nf_tables-reset-table-validation-state-on-.patch b/queue-6.18/netfilter-nf_tables-reset-table-validation-state-on-.patch new file mode 100644 index 0000000000..7a57baf732 --- /dev/null +++ b/queue-6.18/netfilter-nf_tables-reset-table-validation-state-on-.patch @@ -0,0 +1,59 @@ +From 39047c724f4c80a45d63e0e664c92d8db4c84dc2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 12:26:54 +0100 +Subject: netfilter: nf_tables: reset table validation state on abort + +From: Florian Westphal + +[ Upstream commit 6f93616a7323d646d18db9c09f147e453b40fdd7 ] + +If a transaction fails the final validation in the commit hook, the table +validation state is changed to NFT_VALIDATE_DO and a replay of the batch is +performed. Every rule insert will then do a graph validation. + +This is much slower, but provides better error reporting to the user +because we can point at the rule that introduces the validation issue. + +Without this reset the affected table(s) remain in full validation mode, +i.e. on next transaction we start with slow-mode. + +This makes the next transaction after a failed incremental update very slow: + + # time iptables-restore < /tmp/ruleset + real 0m0.496s [..] + # time iptables -A CALLEE -j CALLER + iptables v1.8.11 (nf_tables): RULE_APPEND failed (Too many links): rule in chain CALLEE + real 0m0.022s [..] + # time iptables-restore < /tmp/ruleset + real 1m22.355s [..] + +After this patch, 2nd iptables-restore is back to ~0.5s. + +Fixes: 9a32e9850686 ("netfilter: nf_tables: don't write table validation state without mutex") +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_tables_api.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c +index 6059a299004d4..df18dfd5a8271 100644 +--- a/net/netfilter/nf_tables_api.c ++++ b/net/netfilter/nf_tables_api.c +@@ -11538,6 +11538,13 @@ static int nf_tables_abort(struct net *net, struct sk_buff *skb, + ret = __nf_tables_abort(net, action); + nft_gc_seq_end(nft_net, gc_seq); + ++ if (action == NFNL_ABORT_NONE) { ++ struct nft_table *table; ++ ++ list_for_each_entry(table, &nft_net->tables, list) ++ table->validate_state = NFT_VALIDATE_SKIP; ++ } ++ + WARN_ON_ONCE(!list_empty(&nft_net->commit_list)); + + /* module autoload needs to happen after GC sequence update because it +-- +2.51.0 + diff --git a/queue-6.18/netfilter-nfnetlink_queue-do-shared-unconfirmed-chec.patch b/queue-6.18/netfilter-nfnetlink_queue-do-shared-unconfirmed-chec.patch new file mode 100644 index 0000000000..36cc3f636e --- /dev/null +++ b/queue-6.18/netfilter-nfnetlink_queue-do-shared-unconfirmed-chec.patch @@ -0,0 +1,246 @@ +From 6e42c7a4e4b37192a7cf89a73083abf26fdc7417 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 20 Nov 2025 17:17:06 +0100 +Subject: netfilter: nfnetlink_queue: do shared-unconfirmed check before + segmentation + +From: Florian Westphal + +[ Upstream commit 207b3ebacb6113acaaec0d171d5307032c690004 ] + +Ulrich reports a regression with nfqueue: + +If an application did not set the 'F_GSO' capability flag and a gso +packet with an unconfirmed nf_conn entry is received all packets are +now dropped instead of queued, because the check happens after +skb_gso_segment(). In that case, we did have exclusive ownership +of the skb and its associated conntrack entry. The elevated use +count is due to skb_clone happening via skb_gso_segment(). + +Move the check so that its peformed vs. the aggregated packet. + +Then, annotate the individual segments except the first one so we +can do a 2nd check at reinject time. + +For the normal case, where userspace does in-order reinjects, this avoids +packet drops: first reinjected segment continues traversal and confirms +entry, remaining segments observe the confirmed entry. + +While at it, simplify nf_ct_drop_unconfirmed(): We only care about +unconfirmed entries with a refcnt > 1, there is no need to special-case +dying entries. + +This only happens with UDP. With TCP, the only unconfirmed packet will +be the TCP SYN, those aren't aggregated by GRO. + +Next patch adds a udpgro test case to cover this scenario. + +Reported-by: Ulrich Weber +Fixes: 7d8dc1c7be8d ("netfilter: nf_queue: drop packets with cloned unconfirmed conntracks") +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + include/net/netfilter/nf_queue.h | 1 + + net/netfilter/nfnetlink_queue.c | 123 +++++++++++++++++++------------ + 2 files changed, 75 insertions(+), 49 deletions(-) + +diff --git a/include/net/netfilter/nf_queue.h b/include/net/netfilter/nf_queue.h +index e6803831d6af5..45eb26b2e95b3 100644 +--- a/include/net/netfilter/nf_queue.h ++++ b/include/net/netfilter/nf_queue.h +@@ -21,6 +21,7 @@ struct nf_queue_entry { + struct net_device *physout; + #endif + struct nf_hook_state state; ++ bool nf_ct_is_unconfirmed; + u16 size; /* sizeof(entry) + saved route keys */ + u16 queue_num; + +diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c +index 336e3ad18e72d..34548213f2f14 100644 +--- a/net/netfilter/nfnetlink_queue.c ++++ b/net/netfilter/nfnetlink_queue.c +@@ -438,6 +438,34 @@ static void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict) + nf_queue_entry_free(entry); + } + ++/* return true if the entry has an unconfirmed conntrack attached that isn't owned by us ++ * exclusively. ++ */ ++static bool nf_ct_drop_unconfirmed(const struct nf_queue_entry *entry, bool *is_unconfirmed) ++{ ++#if IS_ENABLED(CONFIG_NF_CONNTRACK) ++ struct nf_conn *ct = (void *)skb_nfct(entry->skb); ++ ++ if (!ct || nf_ct_is_confirmed(ct)) ++ return false; ++ ++ if (is_unconfirmed) ++ *is_unconfirmed = true; ++ ++ /* in some cases skb_clone() can occur after initial conntrack ++ * pickup, but conntrack assumes exclusive skb->_nfct ownership for ++ * unconfirmed entries. ++ * ++ * This happens for br_netfilter and with ip multicast routing. ++ * This can't be solved with serialization here because one clone ++ * could have been queued for local delivery or could be transmitted ++ * in parallel on another CPU. ++ */ ++ return refcount_read(&ct->ct_general.use) > 1; ++#endif ++ return false; ++} ++ + static void nfqnl_reinject(struct nf_queue_entry *entry, unsigned int verdict) + { + const struct nf_ct_hook *ct_hook; +@@ -465,6 +493,24 @@ static void nfqnl_reinject(struct nf_queue_entry *entry, unsigned int verdict) + break; + } + } ++ ++ if (verdict != NF_DROP && entry->nf_ct_is_unconfirmed) { ++ /* If first queued segment was already reinjected then ++ * there is a good chance the ct entry is now confirmed. ++ * ++ * Handle the rare cases: ++ * - out-of-order verdict ++ * - threaded userspace reinjecting in parallel ++ * - first segment was dropped ++ * ++ * In all of those cases we can't handle this packet ++ * because we can't be sure that another CPU won't modify ++ * nf_conn->ext in parallel which isn't allowed. ++ */ ++ if (nf_ct_drop_unconfirmed(entry, NULL)) ++ verdict = NF_DROP; ++ } ++ + nf_reinject(entry, verdict); + } + +@@ -894,49 +940,6 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue, + return NULL; + } + +-static bool nf_ct_drop_unconfirmed(const struct nf_queue_entry *entry) +-{ +-#if IS_ENABLED(CONFIG_NF_CONNTRACK) +- static const unsigned long flags = IPS_CONFIRMED | IPS_DYING; +- struct nf_conn *ct = (void *)skb_nfct(entry->skb); +- unsigned long status; +- unsigned int use; +- +- if (!ct) +- return false; +- +- status = READ_ONCE(ct->status); +- if ((status & flags) == IPS_DYING) +- return true; +- +- if (status & IPS_CONFIRMED) +- return false; +- +- /* in some cases skb_clone() can occur after initial conntrack +- * pickup, but conntrack assumes exclusive skb->_nfct ownership for +- * unconfirmed entries. +- * +- * This happens for br_netfilter and with ip multicast routing. +- * We can't be solved with serialization here because one clone could +- * have been queued for local delivery. +- */ +- use = refcount_read(&ct->ct_general.use); +- if (likely(use == 1)) +- return false; +- +- /* Can't decrement further? Exclusive ownership. */ +- if (!refcount_dec_not_one(&ct->ct_general.use)) +- return false; +- +- skb_set_nfct(entry->skb, 0); +- /* No nf_ct_put(): we already decremented .use and it cannot +- * drop down to 0. +- */ +- return true; +-#endif +- return false; +-} +- + static int + __nfqnl_enqueue_packet(struct net *net, struct nfqnl_instance *queue, + struct nf_queue_entry *entry) +@@ -953,9 +956,6 @@ __nfqnl_enqueue_packet(struct net *net, struct nfqnl_instance *queue, + } + spin_lock_bh(&queue->lock); + +- if (nf_ct_drop_unconfirmed(entry)) +- goto err_out_free_nskb; +- + if (queue->queue_total >= queue->queue_maxlen) + goto err_out_queue_drop; + +@@ -998,7 +998,6 @@ __nfqnl_enqueue_packet(struct net *net, struct nfqnl_instance *queue, + else + net_warn_ratelimited("nf_queue: hash insert failed: %d\n", err); + } +-err_out_free_nskb: + kfree_skb(nskb); + err_out_unlock: + spin_unlock_bh(&queue->lock); +@@ -1077,9 +1076,10 @@ __nfqnl_enqueue_packet_gso(struct net *net, struct nfqnl_instance *queue, + static int + nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) + { +- unsigned int queued; +- struct nfqnl_instance *queue; + struct sk_buff *skb, *segs, *nskb; ++ bool ct_is_unconfirmed = false; ++ struct nfqnl_instance *queue; ++ unsigned int queued; + int err = -ENOBUFS; + struct net *net = entry->state.net; + struct nfnl_queue_net *q = nfnl_queue_pernet(net); +@@ -1103,6 +1103,15 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) + break; + } + ++ /* Check if someone already holds another reference to ++ * unconfirmed ct. If so, we cannot queue the skb: ++ * concurrent modifications of nf_conn->ext are not ++ * allowed and we can't know if another CPU isn't ++ * processing the same nf_conn entry in parallel. ++ */ ++ if (nf_ct_drop_unconfirmed(entry, &ct_is_unconfirmed)) ++ return -EINVAL; ++ + if (!skb_is_gso(skb) || ((queue->flags & NFQA_CFG_F_GSO) && !skb_is_gso_sctp(skb))) + return __nfqnl_enqueue_packet(net, queue, entry); + +@@ -1116,7 +1125,23 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) + goto out_err; + queued = 0; + err = 0; ++ + skb_list_walk_safe(segs, segs, nskb) { ++ if (ct_is_unconfirmed && queued > 0) { ++ /* skb_gso_segment() increments the ct refcount. ++ * This is a problem for unconfirmed (not in hash) ++ * entries, those can race when reinjections happen ++ * in parallel. ++ * ++ * Annotate this for all queued entries except the ++ * first one. ++ * ++ * As long as the first one is reinjected first it ++ * will do the confirmation for us. ++ */ ++ entry->nf_ct_is_unconfirmed = ct_is_unconfirmed; ++ } ++ + if (err == 0) + err = __nfqnl_enqueue_packet_gso(net, queue, + segs, entry); +-- +2.51.0 + diff --git a/queue-6.18/netfilter-nfnetlink_queue-optimize-verdict-lookup-wi.patch b/queue-6.18/netfilter-nfnetlink_queue-optimize-verdict-lookup-wi.patch new file mode 100644 index 0000000000..eefecfa91b --- /dev/null +++ b/queue-6.18/netfilter-nfnetlink_queue-optimize-verdict-lookup-wi.patch @@ -0,0 +1,318 @@ +From 901f9ef8c7f481de4f37358957f14d2f5e894d6b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 14:09:30 -0800 +Subject: netfilter: nfnetlink_queue: optimize verdict lookup with hash table + +From: Scott Mitchell + +[ Upstream commit e19079adcd26a25d7d3e586b1837493361fdf8b6 ] + +The current implementation uses a linear list to find queued packets by +ID when processing verdicts from userspace. With large queue depths and +out-of-order verdicting, this O(n) lookup becomes a significant +bottleneck, causing userspace verdict processing to dominate CPU time. + +Replace the linear search with a hash table for O(1) average-case +packet lookup by ID. A global rhashtable spanning all network +namespaces attributes hash bucket memory to kernel but is subject to +fixed upper bound. + +Signed-off-by: Scott Mitchell +Signed-off-by: Florian Westphal +Stable-dep-of: 207b3ebacb61 ("netfilter: nfnetlink_queue: do shared-unconfirmed check before segmentation") +Signed-off-by: Sasha Levin +--- + include/net/netfilter/nf_queue.h | 3 + + net/netfilter/nfnetlink_queue.c | 146 ++++++++++++++++++++++++------- + 2 files changed, 119 insertions(+), 30 deletions(-) + +diff --git a/include/net/netfilter/nf_queue.h b/include/net/netfilter/nf_queue.h +index 4aeffddb75861..e6803831d6af5 100644 +--- a/include/net/netfilter/nf_queue.h ++++ b/include/net/netfilter/nf_queue.h +@@ -6,11 +6,13 @@ + #include + #include + #include ++#include + #include + + /* Each queued (to userspace) skbuff has one of these. */ + struct nf_queue_entry { + struct list_head list; ++ struct rhash_head hash_node; + struct sk_buff *skb; + unsigned int id; + unsigned int hook_index; /* index in hook_entries->hook[] */ +@@ -20,6 +22,7 @@ struct nf_queue_entry { + #endif + struct nf_hook_state state; + u16 size; /* sizeof(entry) + saved route keys */ ++ u16 queue_num; + + /* extra space to store route keys */ + }; +diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c +index 8b7b39d8a1091..336e3ad18e72d 100644 +--- a/net/netfilter/nfnetlink_queue.c ++++ b/net/netfilter/nfnetlink_queue.c +@@ -30,6 +30,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -47,6 +49,8 @@ + #endif + + #define NFQNL_QMAX_DEFAULT 1024 ++#define NFQNL_HASH_MIN 1024 ++#define NFQNL_HASH_MAX 1048576 + + /* We're using struct nlattr which has 16bit nla_len. Note that nla_len + * includes the header length. Thus, the maximum packet length that we +@@ -56,6 +60,26 @@ + */ + #define NFQNL_MAX_COPY_RANGE (0xffff - NLA_HDRLEN) + ++/* Composite key for packet lookup: (net, queue_num, packet_id) */ ++struct nfqnl_packet_key { ++ possible_net_t net; ++ u32 packet_id; ++ u16 queue_num; ++} __aligned(sizeof(u32)); /* jhash2 requires 32-bit alignment */ ++ ++/* Global rhashtable - one for entire system, all netns */ ++static struct rhashtable nfqnl_packet_map __read_mostly; ++ ++/* Helper to initialize composite key */ ++static inline void nfqnl_init_key(struct nfqnl_packet_key *key, ++ struct net *net, u32 packet_id, u16 queue_num) ++{ ++ memset(key, 0, sizeof(*key)); ++ write_pnet(&key->net, net); ++ key->packet_id = packet_id; ++ key->queue_num = queue_num; ++} ++ + struct nfqnl_instance { + struct hlist_node hlist; /* global list of queues */ + struct rcu_head rcu; +@@ -100,6 +124,39 @@ static inline u_int8_t instance_hashfn(u_int16_t queue_num) + return ((queue_num >> 8) ^ queue_num) % INSTANCE_BUCKETS; + } + ++/* Extract composite key from nf_queue_entry for hashing */ ++static u32 nfqnl_packet_obj_hashfn(const void *data, u32 len, u32 seed) ++{ ++ const struct nf_queue_entry *entry = data; ++ struct nfqnl_packet_key key; ++ ++ nfqnl_init_key(&key, entry->state.net, entry->id, entry->queue_num); ++ ++ return jhash2((u32 *)&key, sizeof(key) / sizeof(u32), seed); ++} ++ ++/* Compare stack-allocated key against entry */ ++static int nfqnl_packet_obj_cmpfn(struct rhashtable_compare_arg *arg, ++ const void *obj) ++{ ++ const struct nfqnl_packet_key *key = arg->key; ++ const struct nf_queue_entry *entry = obj; ++ ++ return !net_eq(entry->state.net, read_pnet(&key->net)) || ++ entry->queue_num != key->queue_num || ++ entry->id != key->packet_id; ++} ++ ++static const struct rhashtable_params nfqnl_rhashtable_params = { ++ .head_offset = offsetof(struct nf_queue_entry, hash_node), ++ .key_len = sizeof(struct nfqnl_packet_key), ++ .obj_hashfn = nfqnl_packet_obj_hashfn, ++ .obj_cmpfn = nfqnl_packet_obj_cmpfn, ++ .automatic_shrinking = true, ++ .min_size = NFQNL_HASH_MIN, ++ .max_size = NFQNL_HASH_MAX, ++}; ++ + static struct nfqnl_instance * + instance_lookup(struct nfnl_queue_net *q, u_int16_t queue_num) + { +@@ -191,33 +248,45 @@ instance_destroy(struct nfnl_queue_net *q, struct nfqnl_instance *inst) + spin_unlock(&q->instances_lock); + } + +-static inline void ++static int + __enqueue_entry(struct nfqnl_instance *queue, struct nf_queue_entry *entry) + { +- list_add_tail(&entry->list, &queue->queue_list); +- queue->queue_total++; ++ int err; ++ ++ entry->queue_num = queue->queue_num; ++ ++ err = rhashtable_insert_fast(&nfqnl_packet_map, &entry->hash_node, ++ nfqnl_rhashtable_params); ++ if (unlikely(err)) ++ return err; ++ ++ list_add_tail(&entry->list, &queue->queue_list); ++ queue->queue_total++; ++ ++ return 0; + } + + static void + __dequeue_entry(struct nfqnl_instance *queue, struct nf_queue_entry *entry) + { ++ rhashtable_remove_fast(&nfqnl_packet_map, &entry->hash_node, ++ nfqnl_rhashtable_params); + list_del(&entry->list); + queue->queue_total--; + } + + static struct nf_queue_entry * +-find_dequeue_entry(struct nfqnl_instance *queue, unsigned int id) ++find_dequeue_entry(struct nfqnl_instance *queue, unsigned int id, ++ struct net *net) + { +- struct nf_queue_entry *entry = NULL, *i; ++ struct nfqnl_packet_key key; ++ struct nf_queue_entry *entry; + +- spin_lock_bh(&queue->lock); ++ nfqnl_init_key(&key, net, id, queue->queue_num); + +- list_for_each_entry(i, &queue->queue_list, list) { +- if (i->id == id) { +- entry = i; +- break; +- } +- } ++ spin_lock_bh(&queue->lock); ++ entry = rhashtable_lookup_fast(&nfqnl_packet_map, &key, ++ nfqnl_rhashtable_params); + + if (entry) + __dequeue_entry(queue, entry); +@@ -407,8 +476,7 @@ nfqnl_flush(struct nfqnl_instance *queue, nfqnl_cmpfn cmpfn, unsigned long data) + spin_lock_bh(&queue->lock); + list_for_each_entry_safe(entry, next, &queue->queue_list, list) { + if (!cmpfn || cmpfn(entry, data)) { +- list_del(&entry->list); +- queue->queue_total--; ++ __dequeue_entry(queue, entry); + nfqnl_reinject(entry, NF_DROP); + } + } +@@ -888,23 +956,23 @@ __nfqnl_enqueue_packet(struct net *net, struct nfqnl_instance *queue, + if (nf_ct_drop_unconfirmed(entry)) + goto err_out_free_nskb; + +- if (queue->queue_total >= queue->queue_maxlen) { +- if (queue->flags & NFQA_CFG_F_FAIL_OPEN) { +- failopen = 1; +- err = 0; +- } else { +- queue->queue_dropped++; +- net_warn_ratelimited("nf_queue: full at %d entries, dropping packets(s)\n", +- queue->queue_total); +- } +- goto err_out_free_nskb; +- } ++ if (queue->queue_total >= queue->queue_maxlen) ++ goto err_out_queue_drop; ++ + entry->id = ++queue->id_sequence; + *packet_id_ptr = htonl(entry->id); + ++ /* Insert into hash BEFORE unicast. If failure don't send to userspace. */ ++ err = __enqueue_entry(queue, entry); ++ if (unlikely(err)) ++ goto err_out_queue_drop; ++ + /* nfnetlink_unicast will either free the nskb or add it to a socket */ + err = nfnetlink_unicast(nskb, net, queue->peer_portid); + if (err < 0) { ++ /* Unicast failed - remove entry we just inserted */ ++ __dequeue_entry(queue, entry); ++ + if (queue->flags & NFQA_CFG_F_FAIL_OPEN) { + failopen = 1; + err = 0; +@@ -914,11 +982,22 @@ __nfqnl_enqueue_packet(struct net *net, struct nfqnl_instance *queue, + goto err_out_unlock; + } + +- __enqueue_entry(queue, entry); +- + spin_unlock_bh(&queue->lock); + return 0; + ++err_out_queue_drop: ++ if (queue->flags & NFQA_CFG_F_FAIL_OPEN) { ++ failopen = 1; ++ err = 0; ++ } else { ++ queue->queue_dropped++; ++ ++ if (queue->queue_total >= queue->queue_maxlen) ++ net_warn_ratelimited("nf_queue: full at %d entries, dropping packets(s)\n", ++ queue->queue_total); ++ else ++ net_warn_ratelimited("nf_queue: hash insert failed: %d\n", err); ++ } + err_out_free_nskb: + kfree_skb(nskb); + err_out_unlock: +@@ -1430,7 +1509,7 @@ static int nfqnl_recv_verdict(struct sk_buff *skb, const struct nfnl_info *info, + + verdict = ntohl(vhdr->verdict); + +- entry = find_dequeue_entry(queue, ntohl(vhdr->id)); ++ entry = find_dequeue_entry(queue, ntohl(vhdr->id), info->net); + if (entry == NULL) + return -ENOENT; + +@@ -1781,10 +1860,14 @@ static int __init nfnetlink_queue_init(void) + { + int status; + ++ status = rhashtable_init(&nfqnl_packet_map, &nfqnl_rhashtable_params); ++ if (status < 0) ++ return status; ++ + status = register_pernet_subsys(&nfnl_queue_net_ops); + if (status < 0) { + pr_err("failed to register pernet ops\n"); +- goto out; ++ goto cleanup_rhashtable; + } + + netlink_register_notifier(&nfqnl_rtnl_notifier); +@@ -1809,7 +1892,8 @@ static int __init nfnetlink_queue_init(void) + cleanup_netlink_notifier: + netlink_unregister_notifier(&nfqnl_rtnl_notifier); + unregister_pernet_subsys(&nfnl_queue_net_ops); +-out: ++cleanup_rhashtable: ++ rhashtable_destroy(&nfqnl_packet_map); + return status; + } + +@@ -1821,6 +1905,8 @@ static void __exit nfnetlink_queue_fini(void) + netlink_unregister_notifier(&nfqnl_rtnl_notifier); + unregister_pernet_subsys(&nfnl_queue_net_ops); + ++ rhashtable_destroy(&nfqnl_packet_map); ++ + rcu_barrier(); /* Wait for completion of call_rcu()'s */ + } + +-- +2.51.0 + diff --git a/queue-6.18/netfilter-nft_compat-add-more-restrictions-on-netlin.patch b/queue-6.18/netfilter-nft_compat-add-more-restrictions-on-netlin.patch new file mode 100644 index 0000000000..addba4a99d --- /dev/null +++ b/queue-6.18/netfilter-nft_compat-add-more-restrictions-on-netlin.patch @@ -0,0 +1,71 @@ +From 106038d9c1e659fdbf19fdabd3f40f7f06d4e149 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 19 Aug 2022 16:16:07 +0200 +Subject: netfilter: nft_compat: add more restrictions on netlink attributes + +From: Florian Westphal + +[ Upstream commit cda26c645946b08f070f20c166d4736767e4a805 ] + +As far as I can see nothing bad can happen when NFTA_TARGET/MATCH_NAME +are too large because this calls x_tables helpers which check for the +length, but it seems better to already reject it during netlink parsing. + +Rest of the changes avoid silent u8/u16 truncations. + +For _TYPE, its expected to be only 1 or 0. In x_tables world, this +variable is set by kernel, for IPT_SO_GET_REVISION_TARGET its 1, for +all others its set to 0. + +As older versions of nf_tables permitted any value except 1 to mean 'match', +keep this as-is but sanitize the value for consistency. + +Fixes: 0ca743a55991 ("netfilter: nf_tables: add compatibility layer for x_tables") +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_compat.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/net/netfilter/nft_compat.c b/net/netfilter/nft_compat.c +index 72711d62fddfa..08f620311b03f 100644 +--- a/net/netfilter/nft_compat.c ++++ b/net/netfilter/nft_compat.c +@@ -134,7 +134,8 @@ static void nft_target_eval_bridge(const struct nft_expr *expr, + } + + static const struct nla_policy nft_target_policy[NFTA_TARGET_MAX + 1] = { +- [NFTA_TARGET_NAME] = { .type = NLA_NUL_STRING }, ++ [NFTA_TARGET_NAME] = { .type = NLA_NUL_STRING, ++ .len = XT_EXTENSION_MAXNAMELEN, }, + [NFTA_TARGET_REV] = NLA_POLICY_MAX(NLA_BE32, 255), + [NFTA_TARGET_INFO] = { .type = NLA_BINARY }, + }; +@@ -434,7 +435,8 @@ static void nft_match_eval(const struct nft_expr *expr, + } + + static const struct nla_policy nft_match_policy[NFTA_MATCH_MAX + 1] = { +- [NFTA_MATCH_NAME] = { .type = NLA_NUL_STRING }, ++ [NFTA_MATCH_NAME] = { .type = NLA_NUL_STRING, ++ .len = XT_EXTENSION_MAXNAMELEN }, + [NFTA_MATCH_REV] = NLA_POLICY_MAX(NLA_BE32, 255), + [NFTA_MATCH_INFO] = { .type = NLA_BINARY }, + }; +@@ -693,7 +695,12 @@ static int nfnl_compat_get_rcu(struct sk_buff *skb, + + name = nla_data(tb[NFTA_COMPAT_NAME]); + rev = ntohl(nla_get_be32(tb[NFTA_COMPAT_REV])); +- target = ntohl(nla_get_be32(tb[NFTA_COMPAT_TYPE])); ++ /* x_tables api checks for 'target == 1' to mean target, ++ * everything else means 'match'. ++ * In x_tables world, the number is set by kernel, not ++ * userspace. ++ */ ++ target = nla_get_be32(tb[NFTA_COMPAT_TYPE]) == htonl(1); + + switch(family) { + case AF_INET: +-- +2.51.0 + diff --git a/queue-6.18/netfilter-nft_counter-fix-reset-of-counters-on-32bit.patch b/queue-6.18/netfilter-nft_counter-fix-reset-of-counters-on-32bit.patch new file mode 100644 index 0000000000..6d7ebe1e89 --- /dev/null +++ b/queue-6.18/netfilter-nft_counter-fix-reset-of-counters-on-32bit.patch @@ -0,0 +1,75 @@ +From 6e180ace74e9570d275a426ed4b69a8c79ec6079 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 14:48:30 +0100 +Subject: netfilter: nft_counter: fix reset of counters on 32bit archs + +From: Anders Grahn + +[ Upstream commit 1e13f27e0675552161ab1778be9a23a636dde8a7 ] + +nft_counter_reset() calls u64_stats_add() with a negative value to reset +the counter. This will work on 64bit archs, hence the negative value +added will wrap as a 64bit value which then can wrap the stat counter as +well. + +On 32bit archs, the added negative value will wrap as a 32bit value and +_not_ wrapping the stat counter properly. In most cases, this would just +lead to a very large 32bit value being added to the stat counter. + +Fix by introducing u64_stats_sub(). + +Fixes: 4a1d3acd6ea8 ("netfilter: nft_counter: Use u64_stats_t for statistic.") +Signed-off-by: Anders Grahn +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + include/linux/u64_stats_sync.h | 10 ++++++++++ + net/netfilter/nft_counter.c | 4 ++-- + 2 files changed, 12 insertions(+), 2 deletions(-) + +diff --git a/include/linux/u64_stats_sync.h b/include/linux/u64_stats_sync.h +index 457879938fc19..3366090a86bd2 100644 +--- a/include/linux/u64_stats_sync.h ++++ b/include/linux/u64_stats_sync.h +@@ -89,6 +89,11 @@ static inline void u64_stats_add(u64_stats_t *p, unsigned long val) + local64_add(val, &p->v); + } + ++static inline void u64_stats_sub(u64_stats_t *p, s64 val) ++{ ++ local64_sub(val, &p->v); ++} ++ + static inline void u64_stats_inc(u64_stats_t *p) + { + local64_inc(&p->v); +@@ -130,6 +135,11 @@ static inline void u64_stats_add(u64_stats_t *p, unsigned long val) + p->v += val; + } + ++static inline void u64_stats_sub(u64_stats_t *p, s64 val) ++{ ++ p->v -= val; ++} ++ + static inline void u64_stats_inc(u64_stats_t *p) + { + p->v++; +diff --git a/net/netfilter/nft_counter.c b/net/netfilter/nft_counter.c +index cc73253294963..0d70325280cc5 100644 +--- a/net/netfilter/nft_counter.c ++++ b/net/netfilter/nft_counter.c +@@ -117,8 +117,8 @@ static void nft_counter_reset(struct nft_counter_percpu_priv *priv, + nft_sync = this_cpu_ptr(&nft_counter_sync); + + u64_stats_update_begin(nft_sync); +- u64_stats_add(&this_cpu->packets, -total->packets); +- u64_stats_add(&this_cpu->bytes, -total->bytes); ++ u64_stats_sub(&this_cpu->packets, total->packets); ++ u64_stats_sub(&this_cpu->bytes, total->bytes); + u64_stats_update_end(nft_sync); + + local_bh_enable(); +-- +2.51.0 + diff --git a/queue-6.18/netfilter-nft_set_hash-fix-get-operation-on-big-endi.patch b/queue-6.18/netfilter-nft_set_hash-fix-get-operation-on-big-endi.patch new file mode 100644 index 0000000000..6ae1b73208 --- /dev/null +++ b/queue-6.18/netfilter-nft_set_hash-fix-get-operation-on-big-endi.patch @@ -0,0 +1,57 @@ +From 61f14566691978c6d65e4d33de0c00caa08cf61d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 20:13:45 +0100 +Subject: netfilter: nft_set_hash: fix get operation on big endian + +From: Florian Westphal + +[ Upstream commit 2f635adbe2642d398a0be3ab245accd2987be0c3 ] + +tests/shell/testcases/packetpath/set_match_nomatch_hash_fast +fails on big endian with: + +Error: Could not process rule: No such file or directory +reset element ip test s { 244.147.90.126 } +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Fatal: Cannot fetch element "244.147.90.126" + +... because the wrong bucket is searched, jhash() and jhash1_word are +not interchangeable on big endian. + +Fixes: 3b02b0adc242 ("netfilter: nft_set_hash: fix lookups with fixed size hash on big endian") +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_set_hash.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/net/netfilter/nft_set_hash.c b/net/netfilter/nft_set_hash.c +index ba01ce75d6dea..739b992bde591 100644 +--- a/net/netfilter/nft_set_hash.c ++++ b/net/netfilter/nft_set_hash.c +@@ -619,15 +619,20 @@ static struct nft_elem_priv * + nft_hash_get(const struct net *net, const struct nft_set *set, + const struct nft_set_elem *elem, unsigned int flags) + { ++ const u32 *key = (const u32 *)&elem->key.val; + struct nft_hash *priv = nft_set_priv(set); + u8 genmask = nft_genmask_cur(net); + struct nft_hash_elem *he; + u32 hash; + +- hash = jhash(elem->key.val.data, set->klen, priv->seed); ++ if (set->klen == 4) ++ hash = jhash_1word(*key, priv->seed); ++ else ++ hash = jhash(key, set->klen, priv->seed); ++ + hash = reciprocal_scale(hash, priv->buckets); + hlist_for_each_entry_rcu(he, &priv->table[hash], node) { +- if (!memcmp(nft_set_ext_key(&he->ext), elem->key.val.data, set->klen) && ++ if (!memcmp(nft_set_ext_key(&he->ext), key, set->klen) && + nft_set_elem_active(&he->ext, genmask)) + return &he->priv; + } +-- +2.51.0 + diff --git a/queue-6.18/netfilter-nft_set_rbtree-check-for-partial-overlaps-.patch b/queue-6.18/netfilter-nft_set_rbtree-check-for-partial-overlaps-.patch new file mode 100644 index 0000000000..36498ad18c --- /dev/null +++ b/queue-6.18/netfilter-nft_set_rbtree-check-for-partial-overlaps-.patch @@ -0,0 +1,90 @@ +From 66ec79945c2b27dcc677b4f210ddfbfaf0990e90 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 13:33:44 +0100 +Subject: netfilter: nft_set_rbtree: check for partial overlaps in anonymous + sets + +From: Pablo Neira Ayuso + +[ Upstream commit 4780ec142cbb24b794129d3080eee5cac2943ffc ] + +Userspace provides an optimized representation in case intervals are +adjacent, where the end element is omitted. + +The existing partial overlap detection logic skips anonymous set checks +on start elements for this reason. + +However, it is possible to add intervals that overlap to this anonymous +where two start elements with the same, eg. A-B, A-C where C < B. + + start end + A B + start end + A C + +Restore the check on overlapping start elements to report an overlap. + +Fixes: c9e6978e2725 ("netfilter: nft_set_rbtree: Switch to node list walk for overlap detection") +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_set_rbtree.c | 30 +++++++++++++++++++++++++----- + 1 file changed, 25 insertions(+), 5 deletions(-) + +diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c +index eacb3acc2b957..f2a1aa8860184 100644 +--- a/net/netfilter/nft_set_rbtree.c ++++ b/net/netfilter/nft_set_rbtree.c +@@ -309,11 +309,23 @@ static bool nft_rbtree_update_first(const struct nft_set *set, + return false; + } + ++/* Only for anonymous sets which do not allow updates, all element are active. */ ++static struct nft_rbtree_elem *nft_rbtree_prev_active(struct nft_rbtree_elem *rbe) ++{ ++ struct rb_node *node; ++ ++ node = rb_prev(&rbe->node); ++ if (!node) ++ return NULL; ++ ++ return rb_entry(node, struct nft_rbtree_elem, node); ++} ++ + static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set, + struct nft_rbtree_elem *new, + struct nft_elem_priv **elem_priv) + { +- struct nft_rbtree_elem *rbe, *rbe_le = NULL, *rbe_ge = NULL; ++ struct nft_rbtree_elem *rbe, *rbe_le = NULL, *rbe_ge = NULL, *rbe_prev; + struct rb_node *node, *next, *parent, **p, *first = NULL; + struct nft_rbtree *priv = nft_set_priv(set); + u8 cur_genmask = nft_genmask_cur(net); +@@ -451,11 +463,19 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set, + /* - new start element with existing closest, less or equal key value + * being a start element: partial overlap, reported as -ENOTEMPTY. + * Anonymous sets allow for two consecutive start element since they +- * are constant, skip them to avoid bogus overlap reports. ++ * are constant, but validate that this new start element does not ++ * sit in between an existing start and end elements: partial overlap, ++ * reported as -ENOTEMPTY. + */ +- if (!nft_set_is_anonymous(set) && rbe_le && +- nft_rbtree_interval_start(rbe_le) && nft_rbtree_interval_start(new)) +- return -ENOTEMPTY; ++ if (rbe_le && ++ nft_rbtree_interval_start(rbe_le) && nft_rbtree_interval_start(new)) { ++ if (!nft_set_is_anonymous(set)) ++ return -ENOTEMPTY; ++ ++ rbe_prev = nft_rbtree_prev_active(rbe_le); ++ if (rbe_prev && nft_rbtree_interval_end(rbe_prev)) ++ return -ENOTEMPTY; ++ } + + /* - new end element with existing closest, less or equal key value + * being a end element: partial overlap, reported as -ENOTEMPTY. +-- +2.51.0 + diff --git a/queue-6.18/netfilter-nft_set_rbtree-don-t-gc-elements-on-insert.patch b/queue-6.18/netfilter-nft_set_rbtree-don-t-gc-elements-on-insert.patch new file mode 100644 index 0000000000..fd4292ace3 --- /dev/null +++ b/queue-6.18/netfilter-nft_set_rbtree-don-t-gc-elements-on-insert.patch @@ -0,0 +1,301 @@ +From 34027f96065bf25f00758d7361ed3819bb89129b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 15:06:21 +0100 +Subject: netfilter: nft_set_rbtree: don't gc elements on insert + +From: Florian Westphal + +[ Upstream commit 35f83a75529a829b0939708b003652f7b4f3df9a ] + +During insertion we can queue up expired elements for garbage +collection. + +In case of later abort, the commit hook will never be called. +Packet path and 'get' requests will find free'd elements in the +binary search blob: + + nft_set_ext_key include/net/netfilter/nf_tables.h:800 [inline] + nft_array_get_cmp+0x1f6/0x2a0 net/netfilter/nft_set_rbtree.c:133 + __inline_bsearch include/linux/bsearch.h:15 [inline] + bsearch+0x50/0xc0 lib/bsearch.c:33 + nft_rbtree_get+0x16b/0x400 net/netfilter/nft_set_rbtree.c:169 + nft_setelem_get net/netfilter/nf_tables_api.c:6495 [inline] + nft_get_set_elem+0x420/0xaa0 net/netfilter/nf_tables_api.c:6543 + nf_tables_getsetelem+0x448/0x5e0 net/netfilter/nf_tables_api.c:6632 + nfnetlink_rcv_msg+0x8ae/0x12c0 net/netfilter/nfnetlink.c:290 + +Also, when we insert an element that triggers -EEXIST, and that insertion +happens to also zap a timed-out entry, we end up with same issue: +Neither commit nor abort hook is called. + +Fix this by removing gc api usage during insertion. + +The blamed commit also removes concurrency of the rbtree with the +packet path, so we can now safely rb_erase() the element and move +it to a new expired list that can be reaped in the commit hook +before building the next blob iteration. + +This also avoids the need to rebuild the blob in the abort path: +Expired elements seen during insertion attempts are kept around +until a transaction passes. + +Reported-by: syzbot+d417922a3e7935517ef6@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=d417922a3e7935517ef6 +Fixes: 7e43e0a1141d ("netfilter: nft_set_rbtree: translate rbtree to array for binary search") +Signed-off-by: Florian Westphal +Stable-dep-of: 782f2688128e ("netfilter: nft_set_rbtree: validate element belonging to interval") +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_set_rbtree.c | 136 ++++++++++++++++----------------- + 1 file changed, 68 insertions(+), 68 deletions(-) + +diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c +index 6470bc5d38749..14b4256bb00d0 100644 +--- a/net/netfilter/nft_set_rbtree.c ++++ b/net/netfilter/nft_set_rbtree.c +@@ -34,11 +34,15 @@ struct nft_rbtree { + struct nft_array __rcu *array; + struct nft_array *array_next; + unsigned long last_gc; ++ struct list_head expired; + }; + + struct nft_rbtree_elem { + struct nft_elem_priv priv; +- struct rb_node node; ++ union { ++ struct rb_node node; ++ struct list_head list; ++ }; + struct nft_set_ext ext; + }; + +@@ -186,13 +190,16 @@ nft_rbtree_get(const struct net *net, const struct nft_set *set, + return &rbe->priv; + } + +-static void nft_rbtree_gc_elem_remove(struct net *net, struct nft_set *set, +- struct nft_rbtree *priv, +- struct nft_rbtree_elem *rbe) ++static void nft_rbtree_gc_elem_move(struct net *net, struct nft_set *set, ++ struct nft_rbtree *priv, ++ struct nft_rbtree_elem *rbe) + { + lockdep_assert_held_write(&priv->lock); + nft_setelem_data_deactivate(net, set, &rbe->priv); + rb_erase(&rbe->node, &priv->root); ++ ++ /* collected later on in commit callback */ ++ list_add(&rbe->list, &priv->expired); + } + + static const struct nft_rbtree_elem * +@@ -203,11 +210,6 @@ nft_rbtree_gc_elem(const struct nft_set *__set, struct nft_rbtree *priv, + struct rb_node *prev = rb_prev(&rbe->node); + struct net *net = read_pnet(&set->net); + struct nft_rbtree_elem *rbe_prev; +- struct nft_trans_gc *gc; +- +- gc = nft_trans_gc_alloc(set, 0, GFP_ATOMIC); +- if (!gc) +- return ERR_PTR(-ENOMEM); + + /* search for end interval coming before this element. + * end intervals don't carry a timeout extension, they +@@ -225,28 +227,10 @@ nft_rbtree_gc_elem(const struct nft_set *__set, struct nft_rbtree *priv, + rbe_prev = NULL; + if (prev) { + rbe_prev = rb_entry(prev, struct nft_rbtree_elem, node); +- nft_rbtree_gc_elem_remove(net, set, priv, rbe_prev); +- +- /* There is always room in this trans gc for this element, +- * memory allocation never actually happens, hence, the warning +- * splat in such case. No need to set NFT_SET_ELEM_DEAD_BIT, +- * this is synchronous gc which never fails. +- */ +- gc = nft_trans_gc_queue_sync(gc, GFP_ATOMIC); +- if (WARN_ON_ONCE(!gc)) +- return ERR_PTR(-ENOMEM); +- +- nft_trans_gc_elem_add(gc, rbe_prev); ++ nft_rbtree_gc_elem_move(net, set, priv, rbe_prev); + } + +- nft_rbtree_gc_elem_remove(net, set, priv, rbe); +- gc = nft_trans_gc_queue_sync(gc, GFP_ATOMIC); +- if (WARN_ON_ONCE(!gc)) +- return ERR_PTR(-ENOMEM); +- +- nft_trans_gc_elem_add(gc, rbe); +- +- nft_trans_gc_queue_sync_done(gc); ++ nft_rbtree_gc_elem_move(net, set, priv, rbe); + + return rbe_prev; + } +@@ -708,29 +692,13 @@ static void nft_rbtree_walk(const struct nft_ctx *ctx, + } + } + +-static void nft_rbtree_gc_remove(struct net *net, struct nft_set *set, +- struct nft_rbtree *priv, +- struct nft_rbtree_elem *rbe) +-{ +- nft_setelem_data_deactivate(net, set, &rbe->priv); +- nft_rbtree_erase(priv, rbe); +-} +- +-static void nft_rbtree_gc(struct nft_set *set) ++static void nft_rbtree_gc_scan(struct nft_set *set) + { + struct nft_rbtree *priv = nft_set_priv(set); + struct nft_rbtree_elem *rbe, *rbe_end = NULL; + struct net *net = read_pnet(&set->net); + u64 tstamp = nft_net_tstamp(net); + struct rb_node *node, *next; +- struct nft_trans_gc *gc; +- +- set = nft_set_container_of(priv); +- net = read_pnet(&set->net); +- +- gc = nft_trans_gc_alloc(set, 0, GFP_KERNEL); +- if (!gc) +- return; + + for (node = rb_first(&priv->root); node ; node = next) { + next = rb_next(node); +@@ -748,34 +716,46 @@ static void nft_rbtree_gc(struct nft_set *set) + if (!__nft_set_elem_expired(&rbe->ext, tstamp)) + continue; + +- gc = nft_trans_gc_queue_sync(gc, GFP_KERNEL); +- if (!gc) +- goto try_later; +- + /* end element needs to be removed first, it has + * no timeout extension. + */ ++ write_lock_bh(&priv->lock); + if (rbe_end) { +- nft_rbtree_gc_remove(net, set, priv, rbe_end); +- nft_trans_gc_elem_add(gc, rbe_end); ++ nft_rbtree_gc_elem_move(net, set, priv, rbe_end); + rbe_end = NULL; + } + +- gc = nft_trans_gc_queue_sync(gc, GFP_KERNEL); +- if (!gc) +- goto try_later; +- +- nft_rbtree_gc_remove(net, set, priv, rbe); +- nft_trans_gc_elem_add(gc, rbe); ++ nft_rbtree_gc_elem_move(net, set, priv, rbe); ++ write_unlock_bh(&priv->lock); + } + +-try_later: ++ priv->last_gc = jiffies; ++} ++ ++static void nft_rbtree_gc_queue(struct nft_set *set) ++{ ++ struct nft_rbtree *priv = nft_set_priv(set); ++ struct nft_rbtree_elem *rbe, *rbe_end; ++ struct nft_trans_gc *gc; ++ ++ if (list_empty(&priv->expired)) ++ return; + +- if (gc) { +- gc = nft_trans_gc_catchall_sync(gc); +- nft_trans_gc_queue_sync_done(gc); +- priv->last_gc = jiffies; ++ gc = nft_trans_gc_alloc(set, 0, GFP_KERNEL); ++ if (!gc) ++ return; ++ ++ list_for_each_entry_safe(rbe, rbe_end, &priv->expired, list) { ++ list_del(&rbe->list); ++ nft_trans_gc_elem_add(gc, rbe); ++ ++ gc = nft_trans_gc_queue_sync(gc, GFP_KERNEL); ++ if (!gc) ++ return; + } ++ ++ gc = nft_trans_gc_catchall_sync(gc); ++ nft_trans_gc_queue_sync_done(gc); + } + + static u64 nft_rbtree_privsize(const struct nlattr * const nla[], +@@ -794,6 +774,7 @@ static int nft_rbtree_init(const struct nft_set *set, + + rwlock_init(&priv->lock); + priv->root = RB_ROOT; ++ INIT_LIST_HEAD(&priv->expired); + + priv->array = NULL; + priv->array_next = NULL; +@@ -811,10 +792,15 @@ static void nft_rbtree_destroy(const struct nft_ctx *ctx, + const struct nft_set *set) + { + struct nft_rbtree *priv = nft_set_priv(set); +- struct nft_rbtree_elem *rbe; ++ struct nft_rbtree_elem *rbe, *next; + struct nft_array *array; + struct rb_node *node; + ++ list_for_each_entry_safe(rbe, next, &priv->expired, list) { ++ list_del(&rbe->list); ++ nf_tables_set_elem_destroy(ctx, set, &rbe->priv); ++ } ++ + while ((node = priv->root.rb_node) != NULL) { + rb_erase(node, &priv->root); + rbe = rb_entry(node, struct nft_rbtree_elem, node); +@@ -861,13 +847,21 @@ static void nft_rbtree_commit(struct nft_set *set) + u32 num_intervals = 0; + struct rb_node *node; + +- if (time_after_eq(jiffies, priv->last_gc + nft_set_gc_interval(set))) +- nft_rbtree_gc(set); +- + /* No changes, skip, eg. elements updates only. */ + if (!priv->array_next) + return; + ++ /* GC can be performed if the binary search blob is going ++ * to be rebuilt. It has to be done in two phases: first ++ * scan tree and move all expired elements to the expired ++ * list. ++ * ++ * Then, after blob has been re-built and published to other ++ * CPUs, queue collected entries for freeing. ++ */ ++ if (time_after_eq(jiffies, priv->last_gc + nft_set_gc_interval(set))) ++ nft_rbtree_gc_scan(set); ++ + /* Reverse walk to create an array from smaller to largest interval. */ + node = rb_last(&priv->root); + if (node) +@@ -914,10 +908,16 @@ static void nft_rbtree_commit(struct nft_set *set) + num_intervals++; + err_out: + priv->array_next->num_intervals = num_intervals; +- old = rcu_replace_pointer(priv->array, priv->array_next, true); ++ old = rcu_replace_pointer(priv->array, priv->array_next, ++ lockdep_is_held(&nft_pernet(read_pnet(&set->net))->commit_mutex)); + priv->array_next = NULL; + if (old) + call_rcu(&old->rcu_head, nft_array_free_rcu); ++ ++ /* New blob is public, queue collected entries for freeing. ++ * call_rcu ensures elements stay around until readers are done. ++ */ ++ nft_rbtree_gc_queue(set); + } + + static void nft_rbtree_abort(const struct nft_set *set) +-- +2.51.0 + diff --git a/queue-6.18/netfilter-nft_set_rbtree-fix-bogus-eexist-with-nlm_f.patch b/queue-6.18/netfilter-nft_set_rbtree-fix-bogus-eexist-with-nlm_f.patch new file mode 100644 index 0000000000..ec9f6227ed --- /dev/null +++ b/queue-6.18/netfilter-nft_set_rbtree-fix-bogus-eexist-with-nlm_f.patch @@ -0,0 +1,80 @@ +From c3ac83123298c4ace4012a325ac39467e5945420 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 13:33:43 +0100 +Subject: netfilter: nft_set_rbtree: fix bogus EEXIST with NLM_F_CREATE with + null interval + +From: Pablo Neira Ayuso + +[ Upstream commit 7f9203f41aae8eea74fba6a3370da41332eabcda ] + +Userspace adds a non-matching null element to the kernel for historical +reasons. This null element is added when the set is populated with +elements. Inclusion of this element is conditional, therefore, +userspace needs to dump the set content to check for its presence. + +If the NLM_F_CREATE flag is turned on, this becomes an issue because +kernel bogusly reports EEXIST. + +Add special case to ignore NLM_F_CREATE in this case, therefore, +re-adding the nul-element never fails. + +Fixes: c016c7e45ddf ("netfilter: nf_tables: honor NLM_F_EXCL flag in set element insertion") +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_tables_api.c | 5 +++++ + net/netfilter/nft_set_rbtree.c | 13 +++++++++++++ + 2 files changed, 18 insertions(+) + +diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c +index df18dfd5a8271..e3279179cd305 100644 +--- a/net/netfilter/nf_tables_api.c ++++ b/net/netfilter/nf_tables_api.c +@@ -7637,6 +7637,11 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, + * and an existing one. + */ + err = -EEXIST; ++ } else if (err == -ECANCELED) { ++ /* ECANCELED reports an existing nul-element in ++ * interval sets. ++ */ ++ err = 0; + } + goto err_element_clash; + } +diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c +index ca594161b8402..eacb3acc2b957 100644 +--- a/net/netfilter/nft_set_rbtree.c ++++ b/net/netfilter/nft_set_rbtree.c +@@ -39,6 +39,13 @@ static bool nft_rbtree_interval_start(const struct nft_rbtree_elem *rbe) + return !nft_rbtree_interval_end(rbe); + } + ++static bool nft_rbtree_interval_null(const struct nft_set *set, ++ const struct nft_rbtree_elem *rbe) ++{ ++ return (!memchr_inv(nft_set_ext_key(&rbe->ext), 0, set->klen) && ++ nft_rbtree_interval_end(rbe)); ++} ++ + static int nft_rbtree_cmp(const struct nft_set *set, + const struct nft_rbtree_elem *e1, + const struct nft_rbtree_elem *e2) +@@ -431,6 +438,12 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set, + */ + if (rbe_le && !nft_rbtree_cmp(set, new, rbe_le) && + nft_rbtree_interval_end(rbe_le) == nft_rbtree_interval_end(new)) { ++ /* - ignore null interval, otherwise NLM_F_CREATE bogusly ++ * reports EEXIST. ++ */ ++ if (nft_rbtree_interval_null(set, new)) ++ return -ECANCELED; ++ + *elem_priv = &rbe_le->priv; + return -EEXIST; + } +-- +2.51.0 + diff --git a/queue-6.18/netfilter-nft_set_rbtree-remove-seqcount_rwlock_t.patch b/queue-6.18/netfilter-nft_set_rbtree-remove-seqcount_rwlock_t.patch new file mode 100644 index 0000000000..92fdf1cd1c --- /dev/null +++ b/queue-6.18/netfilter-nft_set_rbtree-remove-seqcount_rwlock_t.patch @@ -0,0 +1,63 @@ +From 5c2c8105b2c89b3bd3456f775fe72b4d177201b9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 01:08:47 +0100 +Subject: netfilter: nft_set_rbtree: remove seqcount_rwlock_t + +From: Pablo Neira Ayuso + +[ Upstream commit 5599fa810b503eafc2bd8cd15bd45f35fc8ff6b9 ] + +After the conversion to binary search array, this is not required anymore. +Remove it. + +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Florian Westphal +Stable-dep-of: 782f2688128e ("netfilter: nft_set_rbtree: validate element belonging to interval") +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_set_rbtree.c | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c +index 1b0502cc87301..6470bc5d38749 100644 +--- a/net/netfilter/nft_set_rbtree.c ++++ b/net/netfilter/nft_set_rbtree.c +@@ -33,7 +33,6 @@ struct nft_rbtree { + rwlock_t lock; + struct nft_array __rcu *array; + struct nft_array *array_next; +- seqcount_rwlock_t count; + unsigned long last_gc; + }; + +@@ -572,9 +571,7 @@ static int nft_rbtree_insert(const struct net *net, const struct nft_set *set, + cond_resched(); + + write_lock_bh(&priv->lock); +- write_seqcount_begin(&priv->count); + err = __nft_rbtree_insert(net, set, rbe, elem_priv); +- write_seqcount_end(&priv->count); + write_unlock_bh(&priv->lock); + } while (err == -EAGAIN); + +@@ -584,9 +581,7 @@ static int nft_rbtree_insert(const struct net *net, const struct nft_set *set, + static void nft_rbtree_erase(struct nft_rbtree *priv, struct nft_rbtree_elem *rbe) + { + write_lock_bh(&priv->lock); +- write_seqcount_begin(&priv->count); + rb_erase(&rbe->node, &priv->root); +- write_seqcount_end(&priv->count); + write_unlock_bh(&priv->lock); + } + +@@ -798,7 +793,6 @@ static int nft_rbtree_init(const struct nft_set *set, + BUILD_BUG_ON(offsetof(struct nft_rbtree_elem, priv) != 0); + + rwlock_init(&priv->lock); +- seqcount_rwlock_init(&priv->count, &priv->lock); + priv->root = RB_ROOT; + + priv->array = NULL; +-- +2.51.0 + diff --git a/queue-6.18/netfilter-nft_set_rbtree-translate-rbtree-to-array-f.patch b/queue-6.18/netfilter-nft_set_rbtree-translate-rbtree-to-array-f.patch new file mode 100644 index 0000000000..68690f8497 --- /dev/null +++ b/queue-6.18/netfilter-nft_set_rbtree-translate-rbtree-to-array-f.patch @@ -0,0 +1,508 @@ +From 92ae01371c1919eed7247591c7c5b2ed610efd26 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 01:08:45 +0100 +Subject: netfilter: nft_set_rbtree: translate rbtree to array for binary + search + +From: Pablo Neira Ayuso + +[ Upstream commit 7e43e0a1141deec651a60109dab3690854107298 ] + +The rbtree can temporarily store overlapping inactive elements during +the transaction processing, leading to false negative lookups. + +To address this issue, this patch adds a .commit function that walks the +the rbtree to build a array of intervals of ordered elements. This +conversion compacts the two singleton elements that represent the start +and the end of the interval into a single interval object for space +efficient. + +Binary search is O(log n), similar to rbtree lookup time, therefore, +performance number should be similar, and there is an implementation +available under lib/bsearch.c and include/linux/bsearch.h that is used +for this purpose. + +This slightly increases memory consumption for this new array that +stores pointers to the start and the end of the interval. + +With this patch: + + # time nft -f 100k-intervals-set.nft + + real 0m4.218s + user 0m3.544s + sys 0m0.400s + +Without this patch: + + # time nft -f 100k-intervals-set.nft + + real 0m3.920s + user 0m3.547s + sys 0m0.276s + +With this patch, with IPv4 intervals: + + baseline rbtree (match on first field only): 15254954pps + +Without this patch: + + baseline rbtree (match on first field only): 10256119pps + +This provides a ~50% improvement in matching intervals from packet path. + +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Florian Westphal +Stable-dep-of: 782f2688128e ("netfilter: nft_set_rbtree: validate element belonging to interval") +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_set_rbtree.c | 341 +++++++++++++++++++++++++-------- + 1 file changed, 257 insertions(+), 84 deletions(-) + +diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c +index f2a1aa8860184..04e696c87f4a0 100644 +--- a/net/netfilter/nft_set_rbtree.c ++++ b/net/netfilter/nft_set_rbtree.c +@@ -10,14 +10,29 @@ + #include + #include + #include ++#include + #include + #include + #include + #include + ++struct nft_array_interval { ++ struct nft_set_ext *from; ++ struct nft_set_ext *to; ++}; ++ ++struct nft_array { ++ u32 max_intervals; ++ u32 num_intervals; ++ struct nft_array_interval *intervals; ++ struct rcu_head rcu_head; ++}; ++ + struct nft_rbtree { + struct rb_root root; + rwlock_t lock; ++ struct nft_array __rcu *array; ++ struct nft_array *array_next; + seqcount_rwlock_t count; + unsigned long last_gc; + }; +@@ -54,90 +69,6 @@ static int nft_rbtree_cmp(const struct nft_set *set, + set->klen); + } + +-static bool nft_rbtree_elem_expired(const struct nft_rbtree_elem *rbe) +-{ +- return nft_set_elem_expired(&rbe->ext); +-} +- +-static const struct nft_set_ext * +-__nft_rbtree_lookup(const struct net *net, const struct nft_set *set, +- const u32 *key, unsigned int seq) +-{ +- struct nft_rbtree *priv = nft_set_priv(set); +- const struct nft_rbtree_elem *rbe, *interval = NULL; +- u8 genmask = nft_genmask_cur(net); +- const struct rb_node *parent; +- int d; +- +- parent = rcu_dereference_raw(priv->root.rb_node); +- while (parent != NULL) { +- if (read_seqcount_retry(&priv->count, seq)) +- return NULL; +- +- rbe = rb_entry(parent, struct nft_rbtree_elem, node); +- +- d = memcmp(nft_set_ext_key(&rbe->ext), key, set->klen); +- if (d < 0) { +- parent = rcu_dereference_raw(parent->rb_left); +- if (interval && +- !nft_rbtree_cmp(set, rbe, interval) && +- nft_rbtree_interval_end(rbe) && +- nft_rbtree_interval_start(interval)) +- continue; +- if (nft_set_elem_active(&rbe->ext, genmask) && +- !nft_rbtree_elem_expired(rbe)) +- interval = rbe; +- } else if (d > 0) +- parent = rcu_dereference_raw(parent->rb_right); +- else { +- if (!nft_set_elem_active(&rbe->ext, genmask)) { +- parent = rcu_dereference_raw(parent->rb_left); +- continue; +- } +- +- if (nft_rbtree_elem_expired(rbe)) +- return NULL; +- +- if (nft_rbtree_interval_end(rbe)) { +- if (nft_set_is_anonymous(set)) +- return NULL; +- parent = rcu_dereference_raw(parent->rb_left); +- interval = NULL; +- continue; +- } +- +- return &rbe->ext; +- } +- } +- +- if (set->flags & NFT_SET_INTERVAL && interval != NULL && +- nft_rbtree_interval_start(interval)) +- return &interval->ext; +- +- return NULL; +-} +- +-INDIRECT_CALLABLE_SCOPE +-const struct nft_set_ext * +-nft_rbtree_lookup(const struct net *net, const struct nft_set *set, +- const u32 *key) +-{ +- struct nft_rbtree *priv = nft_set_priv(set); +- unsigned int seq = read_seqcount_begin(&priv->count); +- const struct nft_set_ext *ext; +- +- ext = __nft_rbtree_lookup(net, set, key, seq); +- if (ext || !read_seqcount_retry(&priv->count, seq)) +- return ext; +- +- read_lock_bh(&priv->lock); +- seq = read_seqcount_begin(&priv->count); +- ext = __nft_rbtree_lookup(net, set, key, seq); +- read_unlock_bh(&priv->lock); +- +- return ext; +-} +- + static bool __nft_rbtree_get(const struct net *net, const struct nft_set *set, + const u32 *key, struct nft_rbtree_elem **elem, + unsigned int seq, unsigned int flags, u8 genmask) +@@ -228,6 +159,60 @@ nft_rbtree_get(const struct net *net, const struct nft_set *set, + return &rbe->priv; + } + ++struct nft_array_lookup_ctx { ++ const u32 *key; ++ u32 klen; ++}; ++ ++static int nft_array_lookup_cmp(const void *pkey, const void *entry) ++{ ++ const struct nft_array_interval *interval = entry; ++ const struct nft_array_lookup_ctx *ctx = pkey; ++ int a, b; ++ ++ if (!interval->from) ++ return 1; ++ ++ a = memcmp(ctx->key, nft_set_ext_key(interval->from), ctx->klen); ++ if (!interval->to) ++ b = -1; ++ else ++ b = memcmp(ctx->key, nft_set_ext_key(interval->to), ctx->klen); ++ ++ if (a >= 0 && b < 0) ++ return 0; ++ ++ if (a < 0) ++ return -1; ++ ++ return 1; ++} ++ ++INDIRECT_CALLABLE_SCOPE ++const struct nft_set_ext * ++nft_rbtree_lookup(const struct net *net, const struct nft_set *set, ++ const u32 *key) ++{ ++ struct nft_rbtree *priv = nft_set_priv(set); ++ struct nft_array *array = rcu_dereference(priv->array); ++ const struct nft_array_interval *interval; ++ struct nft_array_lookup_ctx ctx = { ++ .key = key, ++ .klen = set->klen, ++ }; ++ ++ if (!array) ++ return NULL; ++ ++ interval = bsearch(&ctx, array->intervals, array->num_intervals, ++ sizeof(struct nft_array_interval), ++ nft_array_lookup_cmp); ++ if (!interval || nft_set_elem_expired(interval->from)) ++ return NULL; ++ ++ return interval->from; ++} ++ + static void nft_rbtree_gc_elem_remove(struct net *net, struct nft_set *set, + struct nft_rbtree *priv, + struct nft_rbtree_elem *rbe) +@@ -514,6 +499,87 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set, + return 0; + } + ++static int nft_array_intervals_alloc(struct nft_array *array, u32 max_intervals) ++{ ++ struct nft_array_interval *intervals; ++ ++ intervals = kvcalloc(max_intervals, sizeof(struct nft_array_interval), ++ GFP_KERNEL_ACCOUNT); ++ if (!intervals) ++ return -ENOMEM; ++ ++ if (array->intervals) ++ kvfree(array->intervals); ++ ++ array->intervals = intervals; ++ array->max_intervals = max_intervals; ++ ++ return 0; ++} ++ ++static struct nft_array *nft_array_alloc(u32 max_intervals) ++{ ++ struct nft_array *array; ++ ++ array = kzalloc(sizeof(*array), GFP_KERNEL_ACCOUNT); ++ if (!array) ++ return NULL; ++ ++ if (nft_array_intervals_alloc(array, max_intervals) < 0) { ++ kfree(array); ++ return NULL; ++ } ++ ++ return array; ++} ++ ++#define NFT_ARRAY_EXTRA_SIZE 10240 ++ ++/* Similar to nft_rbtree_{u,k}size to hide details to userspace, but consider ++ * packed representation coming from userspace for anonymous sets too. ++ */ ++static u32 nft_array_elems(const struct nft_set *set) ++{ ++ u32 nelems = atomic_read(&set->nelems); ++ ++ /* Adjacent intervals are represented with a single start element in ++ * anonymous sets, use the current element counter as is. ++ */ ++ if (nft_set_is_anonymous(set)) ++ return nelems; ++ ++ /* Add extra room for never matching interval at the beginning and open ++ * interval at the end which only use a single element to represent it. ++ * The conversion to array will compact intervals, this allows reduce ++ * memory consumption. ++ */ ++ return (nelems / 2) + 2; ++} ++ ++static int nft_array_may_resize(const struct nft_set *set) ++{ ++ u32 nelems = nft_array_elems(set), new_max_intervals; ++ struct nft_rbtree *priv = nft_set_priv(set); ++ struct nft_array *array; ++ ++ if (!priv->array_next) { ++ array = nft_array_alloc(nelems + NFT_ARRAY_EXTRA_SIZE); ++ if (!array) ++ return -ENOMEM; ++ ++ priv->array_next = array; ++ } ++ ++ if (nelems < priv->array_next->max_intervals) ++ return 0; ++ ++ new_max_intervals = priv->array_next->max_intervals + NFT_ARRAY_EXTRA_SIZE; ++ if (nft_array_intervals_alloc(priv->array_next, new_max_intervals) < 0) ++ return -ENOMEM; ++ ++ return 0; ++} ++ + static int nft_rbtree_insert(const struct net *net, const struct nft_set *set, + const struct nft_set_elem *elem, + struct nft_elem_priv **elem_priv) +@@ -522,6 +588,9 @@ static int nft_rbtree_insert(const struct net *net, const struct nft_set *set, + struct nft_rbtree *priv = nft_set_priv(set); + int err; + ++ if (nft_array_may_resize(set) < 0) ++ return -ENOMEM; ++ + do { + if (fatal_signal_pending(current)) + return -EINTR; +@@ -586,6 +655,9 @@ nft_rbtree_deactivate(const struct net *net, const struct nft_set *set, + u64 tstamp = nft_net_tstamp(net); + int d; + ++ if (nft_array_may_resize(set) < 0) ++ return NULL; ++ + while (parent != NULL) { + rbe = rb_entry(parent, struct nft_rbtree_elem, node); + +@@ -648,6 +720,11 @@ static void nft_rbtree_walk(const struct nft_ctx *ctx, + switch (iter->type) { + case NFT_ITER_UPDATE: + lockdep_assert_held(&nft_pernet(ctx->net)->commit_mutex); ++ ++ if (nft_array_may_resize(set) < 0) { ++ iter->err = -ENOMEM; ++ break; ++ } + nft_rbtree_do_walk(ctx, set, iter); + break; + case NFT_ITER_READ: +@@ -750,14 +827,24 @@ static int nft_rbtree_init(const struct nft_set *set, + seqcount_rwlock_init(&priv->count, &priv->lock); + priv->root = RB_ROOT; + ++ priv->array = NULL; ++ priv->array_next = NULL; ++ + return 0; + } + ++static void __nft_array_free(struct nft_array *array) ++{ ++ kvfree(array->intervals); ++ kfree(array); ++} ++ + static void nft_rbtree_destroy(const struct nft_ctx *ctx, + const struct nft_set *set) + { + struct nft_rbtree *priv = nft_set_priv(set); + struct nft_rbtree_elem *rbe; ++ struct nft_array *array; + struct rb_node *node; + + while ((node = priv->root.rb_node) != NULL) { +@@ -765,6 +852,12 @@ static void nft_rbtree_destroy(const struct nft_ctx *ctx, + rbe = rb_entry(node, struct nft_rbtree_elem, node); + nf_tables_set_elem_destroy(ctx, set, &rbe->priv); + } ++ ++ array = rcu_dereference_protected(priv->array, true); ++ if (array) ++ __nft_array_free(array); ++ if (priv->array_next) ++ __nft_array_free(priv->array_next); + } + + static bool nft_rbtree_estimate(const struct nft_set_desc *desc, u32 features, +@@ -785,12 +878,91 @@ static bool nft_rbtree_estimate(const struct nft_set_desc *desc, u32 features, + return true; + } + ++static void nft_array_free_rcu(struct rcu_head *rcu_head) ++{ ++ struct nft_array *array = container_of(rcu_head, struct nft_array, rcu_head); ++ ++ __nft_array_free(array); ++} ++ + static void nft_rbtree_commit(struct nft_set *set) + { + struct nft_rbtree *priv = nft_set_priv(set); ++ struct nft_rbtree_elem *rbe, *prev_rbe; ++ struct nft_array *old; ++ u32 num_intervals = 0; ++ struct rb_node *node; + + if (time_after_eq(jiffies, priv->last_gc + nft_set_gc_interval(set))) + nft_rbtree_gc(set); ++ ++ /* No changes, skip, eg. elements updates only. */ ++ if (!priv->array_next) ++ return; ++ ++ /* Reverse walk to create an array from smaller to largest interval. */ ++ node = rb_last(&priv->root); ++ if (node) ++ prev_rbe = rb_entry(node, struct nft_rbtree_elem, node); ++ else ++ prev_rbe = NULL; ++ ++ while (prev_rbe) { ++ rbe = prev_rbe; ++ ++ if (nft_rbtree_interval_start(rbe)) ++ priv->array_next->intervals[num_intervals].from = &rbe->ext; ++ else if (nft_rbtree_interval_end(rbe)) ++ priv->array_next->intervals[num_intervals++].to = &rbe->ext; ++ ++ if (num_intervals >= priv->array_next->max_intervals) { ++ pr_warn_once("malformed interval set from userspace?"); ++ goto err_out; ++ } ++ ++ node = rb_prev(node); ++ if (!node) ++ break; ++ ++ prev_rbe = rb_entry(node, struct nft_rbtree_elem, node); ++ ++ /* For anonymous sets, when adjacent ranges are found, ++ * the end element is not added to the set to pack the set ++ * representation. Use next start element to complete this ++ * interval. ++ */ ++ if (nft_rbtree_interval_start(rbe) && ++ nft_rbtree_interval_start(prev_rbe) && ++ priv->array_next->intervals[num_intervals].from) ++ priv->array_next->intervals[num_intervals++].to = &prev_rbe->ext; ++ ++ if (num_intervals >= priv->array_next->max_intervals) { ++ pr_warn_once("malformed interval set from userspace?"); ++ goto err_out; ++ } ++ } ++ ++ if (priv->array_next->intervals[num_intervals].from) ++ num_intervals++; ++err_out: ++ priv->array_next->num_intervals = num_intervals; ++ old = rcu_replace_pointer(priv->array, priv->array_next, true); ++ priv->array_next = NULL; ++ if (old) ++ call_rcu(&old->rcu_head, nft_array_free_rcu); ++} ++ ++static void nft_rbtree_abort(const struct nft_set *set) ++{ ++ struct nft_rbtree *priv = nft_set_priv(set); ++ struct nft_array *array_next; ++ ++ if (!priv->array_next) ++ return; ++ ++ array_next = priv->array_next; ++ priv->array_next = NULL; ++ __nft_array_free(array_next); + } + + static void nft_rbtree_gc_init(const struct nft_set *set) +@@ -854,6 +1026,7 @@ const struct nft_set_type nft_set_rbtree_type = { + .flush = nft_rbtree_flush, + .activate = nft_rbtree_activate, + .commit = nft_rbtree_commit, ++ .abort = nft_rbtree_abort, + .gc_init = nft_rbtree_gc_init, + .lookup = nft_rbtree_lookup, + .walk = nft_rbtree_walk, +-- +2.51.0 + diff --git a/queue-6.18/netfilter-nft_set_rbtree-use-binary-search-array-in-.patch b/queue-6.18/netfilter-nft_set_rbtree-use-binary-search-array-in-.patch new file mode 100644 index 0000000000..1e9cc05bac --- /dev/null +++ b/queue-6.18/netfilter-nft_set_rbtree-use-binary-search-array-in-.patch @@ -0,0 +1,198 @@ +From e7070456f47f7f89876541c56071a8be5d9b55fe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 01:08:46 +0100 +Subject: netfilter: nft_set_rbtree: use binary search array in get command + +From: Pablo Neira Ayuso + +[ Upstream commit 2aa34191f06fc5af4f70241518a8554370d86054 ] + +Rework .get interface to use the binary search array, this needs a specific +lookup function to match on end intervals (<=). Packet path lookup is slight +different because match is on lesser value, not equal (ie. <). + +After this patch, seqcount can be removed in a follow up patch. + +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Florian Westphal +Stable-dep-of: 782f2688128e ("netfilter: nft_set_rbtree: validate element belonging to interval") +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_set_rbtree.c | 154 ++++++++++++++------------------- + 1 file changed, 64 insertions(+), 90 deletions(-) + +diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c +index 04e696c87f4a0..1b0502cc87301 100644 +--- a/net/netfilter/nft_set_rbtree.c ++++ b/net/netfilter/nft_set_rbtree.c +@@ -69,96 +69,6 @@ static int nft_rbtree_cmp(const struct nft_set *set, + set->klen); + } + +-static bool __nft_rbtree_get(const struct net *net, const struct nft_set *set, +- const u32 *key, struct nft_rbtree_elem **elem, +- unsigned int seq, unsigned int flags, u8 genmask) +-{ +- struct nft_rbtree_elem *rbe, *interval = NULL; +- struct nft_rbtree *priv = nft_set_priv(set); +- const struct rb_node *parent; +- const void *this; +- int d; +- +- parent = rcu_dereference_raw(priv->root.rb_node); +- while (parent != NULL) { +- if (read_seqcount_retry(&priv->count, seq)) +- return false; +- +- rbe = rb_entry(parent, struct nft_rbtree_elem, node); +- +- this = nft_set_ext_key(&rbe->ext); +- d = memcmp(this, key, set->klen); +- if (d < 0) { +- parent = rcu_dereference_raw(parent->rb_left); +- if (!(flags & NFT_SET_ELEM_INTERVAL_END)) +- interval = rbe; +- } else if (d > 0) { +- parent = rcu_dereference_raw(parent->rb_right); +- if (flags & NFT_SET_ELEM_INTERVAL_END) +- interval = rbe; +- } else { +- if (!nft_set_elem_active(&rbe->ext, genmask)) { +- parent = rcu_dereference_raw(parent->rb_left); +- continue; +- } +- +- if (nft_set_elem_expired(&rbe->ext)) +- return false; +- +- if (!nft_set_ext_exists(&rbe->ext, NFT_SET_EXT_FLAGS) || +- (*nft_set_ext_flags(&rbe->ext) & NFT_SET_ELEM_INTERVAL_END) == +- (flags & NFT_SET_ELEM_INTERVAL_END)) { +- *elem = rbe; +- return true; +- } +- +- if (nft_rbtree_interval_end(rbe)) +- interval = NULL; +- +- parent = rcu_dereference_raw(parent->rb_left); +- } +- } +- +- if (set->flags & NFT_SET_INTERVAL && interval != NULL && +- nft_set_elem_active(&interval->ext, genmask) && +- !nft_set_elem_expired(&interval->ext) && +- ((!nft_rbtree_interval_end(interval) && +- !(flags & NFT_SET_ELEM_INTERVAL_END)) || +- (nft_rbtree_interval_end(interval) && +- (flags & NFT_SET_ELEM_INTERVAL_END)))) { +- *elem = interval; +- return true; +- } +- +- return false; +-} +- +-static struct nft_elem_priv * +-nft_rbtree_get(const struct net *net, const struct nft_set *set, +- const struct nft_set_elem *elem, unsigned int flags) +-{ +- struct nft_rbtree *priv = nft_set_priv(set); +- unsigned int seq = read_seqcount_begin(&priv->count); +- struct nft_rbtree_elem *rbe = ERR_PTR(-ENOENT); +- const u32 *key = (const u32 *)&elem->key.val; +- u8 genmask = nft_genmask_cur(net); +- bool ret; +- +- ret = __nft_rbtree_get(net, set, key, &rbe, seq, flags, genmask); +- if (ret || !read_seqcount_retry(&priv->count, seq)) +- return &rbe->priv; +- +- read_lock_bh(&priv->lock); +- seq = read_seqcount_begin(&priv->count); +- ret = __nft_rbtree_get(net, set, key, &rbe, seq, flags, genmask); +- read_unlock_bh(&priv->lock); +- +- if (!ret) +- return ERR_PTR(-ENOENT); +- +- return &rbe->priv; +-} +- + struct nft_array_lookup_ctx { + const u32 *key; + u32 klen; +@@ -213,6 +123,70 @@ nft_rbtree_lookup(const struct net *net, const struct nft_set *set, + return interval->from; + } + ++struct nft_array_get_ctx { ++ const u32 *key; ++ unsigned int flags; ++ u32 klen; ++}; ++ ++static int nft_array_get_cmp(const void *pkey, const void *entry) ++{ ++ const struct nft_array_interval *interval = entry; ++ const struct nft_array_get_ctx *ctx = pkey; ++ int a, b; ++ ++ if (!interval->from) ++ return 1; ++ ++ a = memcmp(ctx->key, nft_set_ext_key(interval->from), ctx->klen); ++ if (!interval->to) ++ b = -1; ++ else ++ b = memcmp(ctx->key, nft_set_ext_key(interval->to), ctx->klen); ++ ++ if (a >= 0) { ++ if (ctx->flags & NFT_SET_ELEM_INTERVAL_END && b <= 0) ++ return 0; ++ else if (b < 0) ++ return 0; ++ } ++ ++ if (a < 0) ++ return -1; ++ ++ return 1; ++} ++ ++static struct nft_elem_priv * ++nft_rbtree_get(const struct net *net, const struct nft_set *set, ++ const struct nft_set_elem *elem, unsigned int flags) ++{ ++ struct nft_rbtree *priv = nft_set_priv(set); ++ struct nft_array *array = rcu_dereference(priv->array); ++ const struct nft_array_interval *interval; ++ struct nft_array_get_ctx ctx = { ++ .key = (const u32 *)&elem->key.val, ++ .flags = flags, ++ .klen = set->klen, ++ }; ++ struct nft_rbtree_elem *rbe; ++ ++ if (!array) ++ return ERR_PTR(-ENOENT); ++ ++ interval = bsearch(&ctx, array->intervals, array->num_intervals, ++ sizeof(struct nft_array_interval), nft_array_get_cmp); ++ if (!interval || nft_set_elem_expired(interval->from)) ++ return ERR_PTR(-ENOENT); ++ ++ if (flags & NFT_SET_ELEM_INTERVAL_END) ++ rbe = container_of(interval->to, struct nft_rbtree_elem, ext); ++ else ++ rbe = container_of(interval->from, struct nft_rbtree_elem, ext); ++ ++ return &rbe->priv; ++} ++ + static void nft_rbtree_gc_elem_remove(struct net *net, struct nft_set *set, + struct nft_rbtree *priv, + struct nft_rbtree_elem *rbe) +-- +2.51.0 + diff --git a/queue-6.18/netfilter-nft_set_rbtree-validate-element-belonging-.patch b/queue-6.18/netfilter-nft_set_rbtree-validate-element-belonging-.patch new file mode 100644 index 0000000000..1ddf648768 --- /dev/null +++ b/queue-6.18/netfilter-nft_set_rbtree-validate-element-belonging-.patch @@ -0,0 +1,294 @@ +From 5bd8a354163dc93167ac062db137e8daae8b485c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 13:33:45 +0100 +Subject: netfilter: nft_set_rbtree: validate element belonging to interval + +From: Pablo Neira Ayuso + +[ Upstream commit 782f2688128eca6d05a48be1c247f68d86afc168 ] + +The existing partial overlap detection does not check if the elements +belong to the interval, eg. + + add element inet x y { 1.1.1.1-2.2.2.2, 4.4.4.4-5.5.5.5 } + add element inet x y { 1.1.1.1-5.5.5.5 } => this should fail: ENOENT + +Similar situation occurs with deletions: + + add element inet x y { 1.1.1.1-2.2.2.2, 4.4.4.4-5.5.5.5} + delete element inet x y { 1.1.1.1-5.5.5.5 } => this should fail: ENOENT + +This currently works via mitigation by nft in userspace, which is +performing the overlap detection before sending the elements to the +kernel. This requires a previous netlink dump of the set content which +slows down incremental updates on interval sets, because a netlink set +content dump is needed. + +This patch extends the existing overlap detection to track the most +recent start element that already exists. The pointer to the existing +start element is stored as a cookie (no pointer dereference is ever +possible). If the end element is added and it already exists, then +check that the existing end element is adjacent to the already existing +start element. Similar logic applies to element deactivation. + +This patch also annotates the timestamp to identify if start cookie +comes from an older batch, in such case reset it. Otherwise, a failing +create element command leaves the start cookie in place, resulting in +bogus error reporting. + +There is still a few more corner cases of overlap detection related to +the open interval that are addressed in follow up patches. + +This is address an early design mistake where an interval is expressed +as two elements, using the NFT_SET_ELEM_INTERVAL_END flag, instead of +the more recent NFTA_SET_ELEM_KEY_END attribute that pipapo already +uses. + +Fixes: 7c84d41416d8 ("netfilter: nft_set_rbtree: Detect partial overlaps on insertion") +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_set_rbtree.c | 147 ++++++++++++++++++++++++++++++++- + 1 file changed, 143 insertions(+), 4 deletions(-) + +diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c +index 14b4256bb00d0..a4fb5b517d9de 100644 +--- a/net/netfilter/nft_set_rbtree.c ++++ b/net/netfilter/nft_set_rbtree.c +@@ -33,8 +33,10 @@ struct nft_rbtree { + rwlock_t lock; + struct nft_array __rcu *array; + struct nft_array *array_next; ++ unsigned long start_rbe_cookie; + unsigned long last_gc; + struct list_head expired; ++ u64 last_tstamp; + }; + + struct nft_rbtree_elem { +@@ -263,16 +265,85 @@ static struct nft_rbtree_elem *nft_rbtree_prev_active(struct nft_rbtree_elem *rb + return rb_entry(node, struct nft_rbtree_elem, node); + } + ++static struct nft_rbtree_elem * ++__nft_rbtree_next_active(struct rb_node *node, u8 genmask) ++{ ++ struct nft_rbtree_elem *next_rbe; ++ ++ while (node) { ++ next_rbe = rb_entry(node, struct nft_rbtree_elem, node); ++ if (!nft_set_elem_active(&next_rbe->ext, genmask)) { ++ node = rb_next(node); ++ continue; ++ } ++ ++ return next_rbe; ++ } ++ ++ return NULL; ++} ++ ++static struct nft_rbtree_elem * ++nft_rbtree_next_active(struct nft_rbtree_elem *rbe, u8 genmask) ++{ ++ return __nft_rbtree_next_active(rb_next(&rbe->node), genmask); ++} ++ ++static void nft_rbtree_maybe_reset_start_cookie(struct nft_rbtree *priv, ++ u64 tstamp) ++{ ++ if (priv->last_tstamp != tstamp) { ++ priv->start_rbe_cookie = 0; ++ priv->last_tstamp = tstamp; ++ } ++} ++ ++static void nft_rbtree_set_start_cookie(struct nft_rbtree *priv, ++ const struct nft_rbtree_elem *rbe) ++{ ++ priv->start_rbe_cookie = (unsigned long)rbe; ++} ++ ++static bool nft_rbtree_cmp_start_cookie(struct nft_rbtree *priv, ++ const struct nft_rbtree_elem *rbe) ++{ ++ return priv->start_rbe_cookie == (unsigned long)rbe; ++} ++ ++static bool nft_rbtree_insert_same_interval(const struct net *net, ++ struct nft_rbtree *priv, ++ struct nft_rbtree_elem *rbe) ++{ ++ u8 genmask = nft_genmask_next(net); ++ struct nft_rbtree_elem *next_rbe; ++ ++ if (!priv->start_rbe_cookie) ++ return true; ++ ++ next_rbe = nft_rbtree_next_active(rbe, genmask); ++ if (next_rbe) { ++ /* Closest start element differs from last element added. */ ++ if (nft_rbtree_interval_start(next_rbe) && ++ nft_rbtree_cmp_start_cookie(priv, next_rbe)) { ++ priv->start_rbe_cookie = 0; ++ return true; ++ } ++ } ++ ++ priv->start_rbe_cookie = 0; ++ ++ return false; ++} ++ + static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set, + struct nft_rbtree_elem *new, +- struct nft_elem_priv **elem_priv) ++ struct nft_elem_priv **elem_priv, u64 tstamp) + { + struct nft_rbtree_elem *rbe, *rbe_le = NULL, *rbe_ge = NULL, *rbe_prev; + struct rb_node *node, *next, *parent, **p, *first = NULL; + struct nft_rbtree *priv = nft_set_priv(set); + u8 cur_genmask = nft_genmask_cur(net); + u8 genmask = nft_genmask_next(net); +- u64 tstamp = nft_net_tstamp(net); + int d; + + /* Descend the tree to search for an existing element greater than the +@@ -378,12 +449,18 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set, + } + } + ++ if (nft_rbtree_interval_null(set, new)) ++ priv->start_rbe_cookie = 0; ++ else if (nft_rbtree_interval_start(new) && priv->start_rbe_cookie) ++ priv->start_rbe_cookie = 0; ++ + /* - new start element matching existing start element: full overlap + * reported as -EEXIST, cleared by caller if NLM_F_EXCL is not given. + */ + if (rbe_ge && !nft_rbtree_cmp(set, new, rbe_ge) && + nft_rbtree_interval_start(rbe_ge) == nft_rbtree_interval_start(new)) { + *elem_priv = &rbe_ge->priv; ++ nft_rbtree_set_start_cookie(priv, rbe_ge); + return -EEXIST; + } + +@@ -399,6 +476,11 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set, + return -ECANCELED; + + *elem_priv = &rbe_le->priv; ++ ++ /* - start and end element belong to the same interval. */ ++ if (!nft_rbtree_insert_same_interval(net, priv, rbe_le)) ++ return -ENOTEMPTY; ++ + return -EEXIST; + } + +@@ -543,8 +625,11 @@ static int nft_rbtree_insert(const struct net *net, const struct nft_set *set, + { + struct nft_rbtree_elem *rbe = nft_elem_priv_cast(elem->priv); + struct nft_rbtree *priv = nft_set_priv(set); ++ u64 tstamp = nft_net_tstamp(net); + int err; + ++ nft_rbtree_maybe_reset_start_cookie(priv, tstamp); ++ + if (nft_array_may_resize(set) < 0) + return -ENOMEM; + +@@ -555,7 +640,7 @@ static int nft_rbtree_insert(const struct net *net, const struct nft_set *set, + cond_resched(); + + write_lock_bh(&priv->lock); +- err = __nft_rbtree_insert(net, set, rbe, elem_priv); ++ err = __nft_rbtree_insert(net, set, rbe, elem_priv, tstamp); + write_unlock_bh(&priv->lock); + } while (err == -EAGAIN); + +@@ -588,6 +673,48 @@ static void nft_rbtree_activate(const struct net *net, + nft_clear(net, &rbe->ext); + } + ++static struct nft_rbtree_elem * ++nft_rbtree_next_inactive(struct nft_rbtree_elem *rbe, u8 genmask) ++{ ++ struct nft_rbtree_elem *next_rbe; ++ struct rb_node *node; ++ ++ node = rb_next(&rbe->node); ++ if (node) { ++ next_rbe = rb_entry(node, struct nft_rbtree_elem, node); ++ if (nft_rbtree_interval_start(next_rbe) && ++ !nft_set_elem_active(&next_rbe->ext, genmask)) ++ return next_rbe; ++ } ++ ++ return NULL; ++} ++ ++static bool nft_rbtree_deactivate_same_interval(const struct net *net, ++ struct nft_rbtree *priv, ++ struct nft_rbtree_elem *rbe) ++{ ++ u8 genmask = nft_genmask_next(net); ++ struct nft_rbtree_elem *next_rbe; ++ ++ if (!priv->start_rbe_cookie) ++ return true; ++ ++ next_rbe = nft_rbtree_next_inactive(rbe, genmask); ++ if (next_rbe) { ++ /* Closest start element differs from last element added. */ ++ if (nft_rbtree_interval_start(next_rbe) && ++ nft_rbtree_cmp_start_cookie(priv, next_rbe)) { ++ priv->start_rbe_cookie = 0; ++ return true; ++ } ++ } ++ ++ priv->start_rbe_cookie = 0; ++ ++ return false; ++} ++ + static void nft_rbtree_flush(const struct net *net, + const struct nft_set *set, + struct nft_elem_priv *elem_priv) +@@ -602,12 +729,18 @@ nft_rbtree_deactivate(const struct net *net, const struct nft_set *set, + const struct nft_set_elem *elem) + { + struct nft_rbtree_elem *rbe, *this = nft_elem_priv_cast(elem->priv); +- const struct nft_rbtree *priv = nft_set_priv(set); ++ struct nft_rbtree *priv = nft_set_priv(set); + const struct rb_node *parent = priv->root.rb_node; + u8 genmask = nft_genmask_next(net); + u64 tstamp = nft_net_tstamp(net); + int d; + ++ nft_rbtree_maybe_reset_start_cookie(priv, tstamp); ++ ++ if (nft_rbtree_interval_start(this) || ++ nft_rbtree_interval_null(set, this)) ++ priv->start_rbe_cookie = 0; ++ + if (nft_array_may_resize(set) < 0) + return NULL; + +@@ -635,6 +768,12 @@ nft_rbtree_deactivate(const struct net *net, const struct nft_set *set, + parent = parent->rb_left; + continue; + } ++ ++ if (nft_rbtree_interval_start(rbe)) ++ nft_rbtree_set_start_cookie(priv, rbe); ++ else if (!nft_rbtree_deactivate_same_interval(net, priv, rbe)) ++ return NULL; ++ + nft_rbtree_flush(net, set, &rbe->priv); + return &rbe->priv; + } +-- +2.51.0 + diff --git a/queue-6.18/netfilter-nft_set_rbtree-validate-open-interval-over.patch b/queue-6.18/netfilter-nft_set_rbtree-validate-open-interval-over.patch new file mode 100644 index 0000000000..2c9184853a --- /dev/null +++ b/queue-6.18/netfilter-nft_set_rbtree-validate-open-interval-over.patch @@ -0,0 +1,308 @@ +From 4a04d1c90a57eac71a674b6beaa14f838dfacfee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 13:33:46 +0100 +Subject: netfilter: nft_set_rbtree: validate open interval overlap + +From: Pablo Neira Ayuso + +[ Upstream commit 648946966a08e4cb1a71619e3d1b12bd7642de7b ] + +Open intervals do not have an end element, in particular an open +interval at the end of the set is hard to validate because of it is +lacking the end element, and interval validation relies on such end +element to perform the checks. + +This patch adds a new flag field to struct nft_set_elem, this is not an +issue because this is a temporary object that is allocated in the stack +from the insert/deactivate path. This flag field is used to specify that +this is the last element in this add/delete command. + +The last flag is used, in combination with the start element cookie, to +check if there is a partial overlap, eg. + + Already exists: 255.255.255.0-255.255.255.254 + Add interval: 255.255.255.0-255.255.255.255 + ~~~~~~~~~~~~~ + start element overlap + +Basically, the idea is to check for an existing end element in the set +if there is an overlap with an existing start element. + +However, the last open interval can come in any position in the add +command, the corner case can get a bit more complicated: + + Already exists: 255.255.255.0-255.255.255.254 + Add intervals: 255.255.255.0-255.255.255.255,255.255.255.0-255.255.255.254 + ~~~~~~~~~~~~~ + start element overlap + +To catch this overlap, annotate that the new start element is a possible +overlap, then report the overlap if the next element is another start +element that confirms that previous element in an open interval at the +end of the set. + +For deletions, do not update the start cookie when deleting an open +interval, otherwise this can trigger spurious EEXIST when adding new +elements. + +Unfortunately, there is no NFT_SET_ELEM_INTERVAL_OPEN flag which would +make easier to detect open interval overlaps. + +Fixes: 7c84d41416d8 ("netfilter: nft_set_rbtree: Detect partial overlaps on insertion") +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + include/net/netfilter/nf_tables.h | 4 ++ + net/netfilter/nf_tables_api.c | 21 +++++++-- + net/netfilter/nft_set_rbtree.c | 71 ++++++++++++++++++++++++++----- + 3 files changed, 82 insertions(+), 14 deletions(-) + +diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h +index 0e266c2d0e7f0..7eac73f9b4ce3 100644 +--- a/include/net/netfilter/nf_tables.h ++++ b/include/net/netfilter/nf_tables.h +@@ -278,6 +278,8 @@ struct nft_userdata { + unsigned char data[]; + }; + ++#define NFT_SET_ELEM_INTERNAL_LAST 0x1 ++ + /* placeholder structure for opaque set element backend representation. */ + struct nft_elem_priv { }; + +@@ -287,6 +289,7 @@ struct nft_elem_priv { }; + * @key: element key + * @key_end: closing element key + * @data: element data ++ * @flags: flags + * @priv: element private data and extensions + */ + struct nft_set_elem { +@@ -302,6 +305,7 @@ struct nft_set_elem { + u32 buf[NFT_DATA_VALUE_MAXLEN / sizeof(u32)]; + struct nft_data val; + } data; ++ u32 flags; + struct nft_elem_priv *priv; + }; + +diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c +index e3279179cd305..9051f2c3595a2 100644 +--- a/net/netfilter/nf_tables_api.c ++++ b/net/netfilter/nf_tables_api.c +@@ -7271,7 +7271,8 @@ static u32 nft_set_maxsize(const struct nft_set *set) + } + + static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, +- const struct nlattr *attr, u32 nlmsg_flags) ++ const struct nlattr *attr, u32 nlmsg_flags, ++ bool last) + { + struct nft_expr *expr_array[NFT_SET_EXPR_MAX] = {}; + struct nlattr *nla[NFTA_SET_ELEM_MAX + 1]; +@@ -7557,6 +7558,11 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, + if (flags) + *nft_set_ext_flags(ext) = flags; + ++ if (last) ++ elem.flags = NFT_SET_ELEM_INTERNAL_LAST; ++ else ++ elem.flags = 0; ++ + if (obj) + *nft_set_ext_obj(ext) = obj; + +@@ -7720,7 +7726,8 @@ static int nf_tables_newsetelem(struct sk_buff *skb, + nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla); + + nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) { +- err = nft_add_set_elem(&ctx, set, attr, info->nlh->nlmsg_flags); ++ err = nft_add_set_elem(&ctx, set, attr, info->nlh->nlmsg_flags, ++ nla_is_last(attr, rem)); + if (err < 0) { + NL_SET_BAD_ATTR(extack, attr); + return err; +@@ -7843,7 +7850,7 @@ static void nft_trans_elems_destroy_abort(const struct nft_ctx *ctx, + } + + static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set, +- const struct nlattr *attr) ++ const struct nlattr *attr, bool last) + { + struct nlattr *nla[NFTA_SET_ELEM_MAX + 1]; + struct nft_set_ext_tmpl tmpl; +@@ -7911,6 +7918,11 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set, + if (flags) + *nft_set_ext_flags(ext) = flags; + ++ if (last) ++ elem.flags = NFT_SET_ELEM_INTERNAL_LAST; ++ else ++ elem.flags = 0; ++ + trans = nft_trans_elem_alloc(ctx, NFT_MSG_DELSETELEM, set); + if (trans == NULL) + goto fail_trans; +@@ -8058,7 +8070,8 @@ static int nf_tables_delsetelem(struct sk_buff *skb, + return nft_set_flush(&ctx, set, genmask); + + nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) { +- err = nft_del_setelem(&ctx, set, attr); ++ err = nft_del_setelem(&ctx, set, attr, ++ nla_is_last(attr, rem)); + if (err == -ENOENT && + NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYSETELEM) + continue; +diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c +index a4fb5b517d9de..644d4b9167057 100644 +--- a/net/netfilter/nft_set_rbtree.c ++++ b/net/netfilter/nft_set_rbtree.c +@@ -304,10 +304,19 @@ static void nft_rbtree_set_start_cookie(struct nft_rbtree *priv, + priv->start_rbe_cookie = (unsigned long)rbe; + } + ++static void nft_rbtree_set_start_cookie_open(struct nft_rbtree *priv, ++ const struct nft_rbtree_elem *rbe, ++ unsigned long open_interval) ++{ ++ priv->start_rbe_cookie = (unsigned long)rbe | open_interval; ++} ++ ++#define NFT_RBTREE_OPEN_INTERVAL 1UL ++ + static bool nft_rbtree_cmp_start_cookie(struct nft_rbtree *priv, + const struct nft_rbtree_elem *rbe) + { +- return priv->start_rbe_cookie == (unsigned long)rbe; ++ return (priv->start_rbe_cookie & ~NFT_RBTREE_OPEN_INTERVAL) == (unsigned long)rbe; + } + + static bool nft_rbtree_insert_same_interval(const struct net *net, +@@ -337,13 +346,14 @@ static bool nft_rbtree_insert_same_interval(const struct net *net, + + static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set, + struct nft_rbtree_elem *new, +- struct nft_elem_priv **elem_priv, u64 tstamp) ++ struct nft_elem_priv **elem_priv, u64 tstamp, bool last) + { + struct nft_rbtree_elem *rbe, *rbe_le = NULL, *rbe_ge = NULL, *rbe_prev; + struct rb_node *node, *next, *parent, **p, *first = NULL; + struct nft_rbtree *priv = nft_set_priv(set); + u8 cur_genmask = nft_genmask_cur(net); + u8 genmask = nft_genmask_next(net); ++ unsigned long open_interval = 0; + int d; + + /* Descend the tree to search for an existing element greater than the +@@ -449,10 +459,18 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set, + } + } + +- if (nft_rbtree_interval_null(set, new)) +- priv->start_rbe_cookie = 0; +- else if (nft_rbtree_interval_start(new) && priv->start_rbe_cookie) ++ if (nft_rbtree_interval_null(set, new)) { + priv->start_rbe_cookie = 0; ++ } else if (nft_rbtree_interval_start(new) && priv->start_rbe_cookie) { ++ if (nft_set_is_anonymous(set)) { ++ priv->start_rbe_cookie = 0; ++ } else if (priv->start_rbe_cookie & NFT_RBTREE_OPEN_INTERVAL) { ++ /* Previous element is an open interval that partially ++ * overlaps with an existing non-open interval. ++ */ ++ return -ENOTEMPTY; ++ } ++ } + + /* - new start element matching existing start element: full overlap + * reported as -EEXIST, cleared by caller if NLM_F_EXCL is not given. +@@ -460,7 +478,27 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set, + if (rbe_ge && !nft_rbtree_cmp(set, new, rbe_ge) && + nft_rbtree_interval_start(rbe_ge) == nft_rbtree_interval_start(new)) { + *elem_priv = &rbe_ge->priv; +- nft_rbtree_set_start_cookie(priv, rbe_ge); ++ ++ /* - Corner case: new start element of open interval (which ++ * comes as last element in the batch) overlaps the start of ++ * an existing interval with an end element: partial overlap. ++ */ ++ node = rb_first(&priv->root); ++ rbe = __nft_rbtree_next_active(node, genmask); ++ if (rbe && nft_rbtree_interval_end(rbe)) { ++ rbe = nft_rbtree_next_active(rbe, genmask); ++ if (rbe && ++ nft_rbtree_interval_start(rbe) && ++ !nft_rbtree_cmp(set, new, rbe)) { ++ if (last) ++ return -ENOTEMPTY; ++ ++ /* Maybe open interval? */ ++ open_interval = NFT_RBTREE_OPEN_INTERVAL; ++ } ++ } ++ nft_rbtree_set_start_cookie_open(priv, rbe_ge, open_interval); ++ + return -EEXIST; + } + +@@ -515,6 +553,12 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set, + nft_rbtree_interval_end(rbe_ge) && nft_rbtree_interval_end(new)) + return -ENOTEMPTY; + ++ /* - start element overlaps an open interval but end element is new: ++ * partial overlap, reported as -ENOEMPTY. ++ */ ++ if (!rbe_ge && priv->start_rbe_cookie && nft_rbtree_interval_end(new)) ++ return -ENOTEMPTY; ++ + /* Accepted element: pick insertion point depending on key value */ + parent = NULL; + p = &priv->root.rb_node; +@@ -624,6 +668,7 @@ static int nft_rbtree_insert(const struct net *net, const struct nft_set *set, + struct nft_elem_priv **elem_priv) + { + struct nft_rbtree_elem *rbe = nft_elem_priv_cast(elem->priv); ++ bool last = !!(elem->flags & NFT_SET_ELEM_INTERNAL_LAST); + struct nft_rbtree *priv = nft_set_priv(set); + u64 tstamp = nft_net_tstamp(net); + int err; +@@ -640,8 +685,12 @@ static int nft_rbtree_insert(const struct net *net, const struct nft_set *set, + cond_resched(); + + write_lock_bh(&priv->lock); +- err = __nft_rbtree_insert(net, set, rbe, elem_priv, tstamp); ++ err = __nft_rbtree_insert(net, set, rbe, elem_priv, tstamp, last); + write_unlock_bh(&priv->lock); ++ ++ if (nft_rbtree_interval_end(rbe)) ++ priv->start_rbe_cookie = 0; ++ + } while (err == -EAGAIN); + + return err; +@@ -729,6 +778,7 @@ nft_rbtree_deactivate(const struct net *net, const struct nft_set *set, + const struct nft_set_elem *elem) + { + struct nft_rbtree_elem *rbe, *this = nft_elem_priv_cast(elem->priv); ++ bool last = !!(elem->flags & NFT_SET_ELEM_INTERNAL_LAST); + struct nft_rbtree *priv = nft_set_priv(set); + const struct rb_node *parent = priv->root.rb_node; + u8 genmask = nft_genmask_next(net); +@@ -769,9 +819,10 @@ nft_rbtree_deactivate(const struct net *net, const struct nft_set *set, + continue; + } + +- if (nft_rbtree_interval_start(rbe)) +- nft_rbtree_set_start_cookie(priv, rbe); +- else if (!nft_rbtree_deactivate_same_interval(net, priv, rbe)) ++ if (nft_rbtree_interval_start(rbe)) { ++ if (!last) ++ nft_rbtree_set_start_cookie(priv, rbe); ++ } else if (!nft_rbtree_deactivate_same_interval(net, priv, rbe)) + return NULL; + + nft_rbtree_flush(net, set, &rbe->priv); +-- +2.51.0 + diff --git a/queue-6.18/netfs-avoid-double-increment-of-retry_count-in-subre.patch b/queue-6.18/netfs-avoid-double-increment-of-retry_count-in-subre.patch new file mode 100644 index 0000000000..2e13e34ffe --- /dev/null +++ b/queue-6.18/netfs-avoid-double-increment-of-retry_count-in-subre.patch @@ -0,0 +1,38 @@ +From 6639be2970cab643a5bd6a253f865d40b567a635 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Jan 2026 14:03:05 +0530 +Subject: netfs: avoid double increment of retry_count in subreq + +From: Shyam Prasad N + +[ Upstream commit a5ca32d031bbba5160e1f555aabb75a3f40f918d ] + +This change fixes the instance of double incrementing of +retry_count. The increment of this count already happens +when netfs_reissue_write gets called. Incrementing this +value before is not necessary. + +Fixes: 4acb665cf4f3 ("netfs: Work around recursion by abandoning retry if nothing read") +Acked-by: David Howells +Signed-off-by: Shyam Prasad N +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/netfs/write_retry.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/fs/netfs/write_retry.c b/fs/netfs/write_retry.c +index fc9c3e0d34d81..29489a23a2209 100644 +--- a/fs/netfs/write_retry.c ++++ b/fs/netfs/write_retry.c +@@ -98,7 +98,6 @@ static void netfs_retry_write_stream(struct netfs_io_request *wreq, + subreq->start = start; + subreq->len = len; + __clear_bit(NETFS_SREQ_NEED_RETRY, &subreq->flags); +- subreq->retry_count++; + trace_netfs_sreq(subreq, netfs_sreq_trace_retry); + + /* Renegotiate max_len (wsize) */ +-- +2.51.0 + diff --git a/queue-6.18/nfc-hci-shdlc-stop-timers-and-work-before-freeing-co.patch b/queue-6.18/nfc-hci-shdlc-stop-timers-and-work-before-freeing-co.patch new file mode 100644 index 0000000000..7a35f91cac --- /dev/null +++ b/queue-6.18/nfc-hci-shdlc-stop-timers-and-work-before-freeing-co.patch @@ -0,0 +1,52 @@ +From d64e1e7b1bac3827cb97f55e7b021d4e03ecb7a7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 14:31:57 +0300 +Subject: nfc: hci: shdlc: Stop timers and work before freeing context + +From: Votokina Victoria + +[ Upstream commit c9efde1e537baed7648a94022b43836a348a074f ] + +llc_shdlc_deinit() purges SHDLC skb queues and frees the llc_shdlc +structure while its timers and state machine work may still be active. + +Timer callbacks can schedule sm_work, and sm_work accesses SHDLC state +and the skb queues. If teardown happens in parallel with a queued/running +work item, it can lead to UAF and other shutdown races. + +Stop all SHDLC timers and cancel sm_work synchronously before purging the +queues and freeing the context. + +Found by Linux Verification Center (linuxtesting.org) with SVACE. + +Fixes: 4a61cd6687fc ("NFC: Add an shdlc llc module to llc core") +Signed-off-by: Votokina Victoria +Link: https://patch.msgid.link/20260203113158.2008723-1-Victoria.Votokina@kaspersky.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/nfc/hci/llc_shdlc.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/net/nfc/hci/llc_shdlc.c b/net/nfc/hci/llc_shdlc.c +index 4fc37894860c9..08c8aa1530d8a 100644 +--- a/net/nfc/hci/llc_shdlc.c ++++ b/net/nfc/hci/llc_shdlc.c +@@ -762,6 +762,14 @@ static void llc_shdlc_deinit(struct nfc_llc *llc) + { + struct llc_shdlc *shdlc = nfc_llc_get_data(llc); + ++ timer_shutdown_sync(&shdlc->connect_timer); ++ timer_shutdown_sync(&shdlc->t1_timer); ++ timer_shutdown_sync(&shdlc->t2_timer); ++ shdlc->t1_active = false; ++ shdlc->t2_active = false; ++ ++ cancel_work_sync(&shdlc->sm_work); ++ + skb_queue_purge(&shdlc->rcv_q); + skb_queue_purge(&shdlc->send_q); + skb_queue_purge(&shdlc->ack_pending_q); +-- +2.51.0 + diff --git a/queue-6.18/nfs-localio-handle-short-writes-by-retrying.patch b/queue-6.18/nfs-localio-handle-short-writes-by-retrying.patch new file mode 100644 index 0000000000..ace7cda2c8 --- /dev/null +++ b/queue-6.18/nfs-localio-handle-short-writes-by-retrying.patch @@ -0,0 +1,121 @@ +From fe9c74bcf12b82211031725eac0a92186eb46886 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 3 Jan 2026 12:14:59 -0500 +Subject: NFS/localio: Handle short writes by retrying + +From: Trond Myklebust + +[ Upstream commit 615762059d284b863f9163b53679d95b3dcdd495 ] + +The current code for handling short writes in localio just truncates the +I/O and then sets an error. While that is close to how the ordinary NFS +code behaves, it does mean there is a chance the data that got written +is lost because it isn't persisted. +To fix this, change localio so that the upper layers can direct the +behaviour to persist any unstable data by rewriting it, and then +continuing writing until an ENOSPC is hit. + +Fixes: 70ba381e1a43 ("nfs: add LOCALIO support") +Signed-off-by: Trond Myklebust +Reviewed-by: Mike Snitzer +Signed-off-by: Anna Schumaker +Signed-off-by: Sasha Levin +--- + fs/nfs/localio.c | 64 +++++++++++++++++++++++++++++++++++------------- + 1 file changed, 47 insertions(+), 17 deletions(-) + +diff --git a/fs/nfs/localio.c b/fs/nfs/localio.c +index f537bc3386bf2..ea7b35191d0af 100644 +--- a/fs/nfs/localio.c ++++ b/fs/nfs/localio.c +@@ -58,6 +58,11 @@ struct nfs_local_fsync_ctx { + static bool localio_enabled __read_mostly = true; + module_param(localio_enabled, bool, 0644); + ++static int nfs_local_do_read(struct nfs_local_kiocb *iocb, ++ const struct rpc_call_ops *call_ops); ++static int nfs_local_do_write(struct nfs_local_kiocb *iocb, ++ const struct rpc_call_ops *call_ops); ++ + static inline bool nfs_client_is_local(const struct nfs_client *clp) + { + return !!rcu_access_pointer(clp->cl_uuid.net); +@@ -542,13 +547,50 @@ nfs_local_iocb_release(struct nfs_local_kiocb *iocb) + nfs_local_iocb_free(iocb); + } + +-static void +-nfs_local_pgio_release(struct nfs_local_kiocb *iocb) ++static void nfs_local_pgio_restart(struct nfs_local_kiocb *iocb, ++ struct nfs_pgio_header *hdr) ++{ ++ int status = 0; ++ ++ iocb->kiocb.ki_pos = hdr->args.offset; ++ iocb->kiocb.ki_flags &= ~(IOCB_DSYNC | IOCB_SYNC | IOCB_DIRECT); ++ iocb->kiocb.ki_complete = NULL; ++ iocb->aio_complete_work = NULL; ++ iocb->end_iter_index = -1; ++ ++ switch (hdr->rw_mode) { ++ case FMODE_READ: ++ nfs_local_iters_init(iocb, ITER_DEST); ++ status = nfs_local_do_read(iocb, hdr->task.tk_ops); ++ break; ++ case FMODE_WRITE: ++ nfs_local_iters_init(iocb, ITER_SOURCE); ++ status = nfs_local_do_write(iocb, hdr->task.tk_ops); ++ break; ++ default: ++ status = -EOPNOTSUPP; ++ } ++ ++ if (status != 0) { ++ nfs_local_iocb_release(iocb); ++ hdr->task.tk_status = status; ++ nfs_local_hdr_release(hdr, hdr->task.tk_ops); ++ } ++} ++ ++static void nfs_local_pgio_release(struct nfs_local_kiocb *iocb) + { + struct nfs_pgio_header *hdr = iocb->hdr; ++ struct rpc_task *task = &hdr->task; ++ ++ task->tk_action = NULL; ++ task->tk_ops->rpc_call_done(task, hdr); + +- nfs_local_iocb_release(iocb); +- nfs_local_hdr_release(hdr, hdr->task.tk_ops); ++ if (task->tk_action == NULL) { ++ nfs_local_iocb_release(iocb); ++ task->tk_ops->rpc_release(hdr); ++ } else ++ nfs_local_pgio_restart(iocb, hdr); + } + + /* +@@ -776,19 +818,7 @@ static void nfs_local_write_done(struct nfs_local_kiocb *iocb) + pr_info_ratelimited("nfs: Unexpected direct I/O write alignment failure\n"); + } + +- /* Handle short writes as if they are ENOSPC */ +- status = hdr->res.count; +- if (status > 0 && status < hdr->args.count) { +- hdr->mds_offset += status; +- hdr->args.offset += status; +- hdr->args.pgbase += status; +- hdr->args.count -= status; +- nfs_set_pgio_error(hdr, -ENOSPC, hdr->args.offset); +- status = -ENOSPC; +- /* record -ENOSPC in terms of nfs_local_pgio_done */ +- (void) nfs_local_pgio_done(iocb, status, true); +- } +- if (hdr->task.tk_status < 0) ++ if (status < 0) + nfs_reset_boot_verifier(hdr->inode); + } + +-- +2.51.0 + diff --git a/queue-6.18/nfs-localio-prevent-direct-reclaim-recursion-into-nf.patch b/queue-6.18/nfs-localio-prevent-direct-reclaim-recursion-into-nf.patch new file mode 100644 index 0000000000..9113e68055 --- /dev/null +++ b/queue-6.18/nfs-localio-prevent-direct-reclaim-recursion-into-nf.patch @@ -0,0 +1,77 @@ +From 0d58cd515221eef3ed5d6dc189a23402a42ec231 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 11:08:55 -0500 +Subject: NFS/localio: prevent direct reclaim recursion into NFS via + nfs_writepages + +From: Mike Snitzer + +[ Upstream commit 67435d2d8a33a75f9647724952cb1b18279d2e95 ] + +LOCALIO is an NFS loopback mount optimization that avoids using the +network for READ, WRITE and COMMIT if the NFS client and server are +determined to be on the same system. But because LOCALIO is still +fundamentally "just NFS loopback mount" it is susceptible to recursion +deadlock via direct reclaim, e.g.: NFS LOCALIO down to XFS and then +back into NFS via nfs_writepages. + +Fix LOCALIO's potential for direct reclaim deadlock by ensuring that +all its page cache allocations are done from GFP_NOFS context. + +Thanks to Ben Coddington for pointing out commit ad22c7a043c2 ("xfs: +prevent stack overflows from page cache allocation"). + +Reported-by: John Cagle +Tested-by: Allen Lu +Suggested-by: Benjamin Coddington +Fixes: 70ba381e1a43 ("nfs: add LOCALIO support") +Signed-off-by: Mike Snitzer +Signed-off-by: Anna Schumaker +Signed-off-by: Sasha Levin +--- + fs/nfs/localio.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/fs/nfs/localio.c b/fs/nfs/localio.c +index ea7b35191d0af..ff430e6b773a5 100644 +--- a/fs/nfs/localio.c ++++ b/fs/nfs/localio.c +@@ -291,6 +291,18 @@ nfs_local_open_fh(struct nfs_client *clp, const struct cred *cred, + } + EXPORT_SYMBOL_GPL(nfs_local_open_fh); + ++/* ++ * Ensure all page cache allocations are done from GFP_NOFS context to ++ * prevent direct reclaim recursion back into NFS via nfs_writepages. ++ */ ++static void ++nfs_local_mapping_set_gfp_nofs_context(struct address_space *m) ++{ ++ gfp_t gfp_mask = mapping_gfp_mask(m); ++ ++ mapping_set_gfp_mask(m, (gfp_mask & ~(__GFP_FS))); ++} ++ + static void + nfs_local_iocb_free(struct nfs_local_kiocb *iocb) + { +@@ -315,6 +327,7 @@ nfs_local_iocb_alloc(struct nfs_pgio_header *hdr, + return NULL; + } + ++ nfs_local_mapping_set_gfp_nofs_context(file->f_mapping); + init_sync_kiocb(&iocb->kiocb, file); + + iocb->hdr = hdr; +@@ -1010,6 +1023,8 @@ nfs_local_run_commit(struct file *filp, struct nfs_commit_data *data) + end = LLONG_MAX; + } + ++ nfs_local_mapping_set_gfp_nofs_context(filp->f_mapping); ++ + dprintk("%s: commit %llu - %llu\n", __func__, start, end); + return vfs_fsync_range(filp, start, end, 0); + } +-- +2.51.0 + diff --git a/queue-6.18/nfs-localio-remove-eagain-handling-in-nfs_local_doio.patch b/queue-6.18/nfs-localio-remove-eagain-handling-in-nfs_local_doio.patch new file mode 100644 index 0000000000..e075e31d3a --- /dev/null +++ b/queue-6.18/nfs-localio-remove-eagain-handling-in-nfs_local_doio.patch @@ -0,0 +1,43 @@ +From 3f2cc06e2aab041a5eb9b7cfc539a05fd7272ce7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 11:08:57 -0500 +Subject: NFS/localio: remove -EAGAIN handling in nfs_local_doio() + +From: Mike Snitzer + +[ Upstream commit e72a73957613653f50375db1f3a3fbb907a9c40b ] + +Handling -EAGAIN in nfs_local_doio() was introduced with commit +0978e5b85fc08 (nfs_do_local_{read,write} were made to have negative +checks for correspoding iter method) but commit e43e9a3a3d66 +since eliminated the possibility for this -EAGAIN early return. + +So remove nfs_local_doio()'s -EAGAIN handling that calls +nfs_localio_disable_client() -- while it should never happen from +nfs_do_local_{read,write} this particular -EAGAIN handling is now +"dead" and so it has become a liability. + +Fixes: e43e9a3a3d66 ("nfs/localio: refactor iocb initialization") +Signed-off-by: Mike Snitzer +Signed-off-by: Anna Schumaker +Signed-off-by: Sasha Levin +--- + fs/nfs/localio.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/fs/nfs/localio.c b/fs/nfs/localio.c +index d1a8f6fa9d74e..358d686d2ae33 100644 +--- a/fs/nfs/localio.c ++++ b/fs/nfs/localio.c +@@ -995,8 +995,6 @@ int nfs_local_doio(struct nfs_client *clp, struct nfsd_file *localio, + } + + if (status != 0) { +- if (status == -EAGAIN) +- nfs_localio_disable_client(clp); + nfs_local_iocb_release(iocb); + hdr->task.tk_status = status; + nfs_local_hdr_release(hdr, call_ops); +-- +2.51.0 + diff --git a/queue-6.18/nfs-localio-use-gfp_noio-and-non-memreclaim-workqueu.patch b/queue-6.18/nfs-localio-use-gfp_noio-and-non-memreclaim-workqueu.patch new file mode 100644 index 0000000000..6ea5c69a21 --- /dev/null +++ b/queue-6.18/nfs-localio-use-gfp_noio-and-non-memreclaim-workqueu.patch @@ -0,0 +1,80 @@ +From 1d2992cbd220aa4bcfc005208584604b18026fa7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 11:08:56 -0500 +Subject: NFS/localio: use GFP_NOIO and non-memreclaim workqueue in + nfs_local_commit + +From: Mike Snitzer + +[ Upstream commit 9bb0060f7860aa4561c5b21163dd45ceb66946a9 ] + +nfslocaliod_workqueue is a non-memreclaim workqueue (it isn't +initialized with WQ_MEM_RECLAIM), see commit b9f5dd57f4a5 +("nfs/localio: use dedicated workqueues for filesystem read and +write"). + +Use nfslocaliod_workqueue for LOCALIO's SYNC work. + +Also, set PF_LOCAL_THROTTLE | PF_MEMALLOC_NOIO in +nfs_local_fsync_work. + +Fixes: b9f5dd57f4a5 ("nfs/localio: use dedicated workqueues for filesystem read and write") +Signed-off-by: Mike Snitzer +Signed-off-by: Anna Schumaker +Signed-off-by: Sasha Levin +--- + fs/nfs/localio.c | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +diff --git a/fs/nfs/localio.c b/fs/nfs/localio.c +index ff430e6b773a5..d1a8f6fa9d74e 100644 +--- a/fs/nfs/localio.c ++++ b/fs/nfs/localio.c +@@ -1066,17 +1066,22 @@ nfs_local_fsync_ctx_free(struct nfs_local_fsync_ctx *ctx) + static void + nfs_local_fsync_work(struct work_struct *work) + { ++ unsigned long old_flags = current->flags; + struct nfs_local_fsync_ctx *ctx; + int status; + + ctx = container_of(work, struct nfs_local_fsync_ctx, work); + ++ current->flags |= PF_LOCAL_THROTTLE | PF_MEMALLOC_NOIO; ++ + status = nfs_local_run_commit(nfs_to->nfsd_file_file(ctx->localio), + ctx->data); + nfs_local_commit_done(ctx->data, status); + if (ctx->done != NULL) + complete(ctx->done); + nfs_local_fsync_ctx_free(ctx); ++ ++ current->flags = old_flags; + } + + static struct nfs_local_fsync_ctx * +@@ -1100,7 +1105,7 @@ int nfs_local_commit(struct nfsd_file *localio, + { + struct nfs_local_fsync_ctx *ctx; + +- ctx = nfs_local_fsync_ctx_alloc(data, localio, GFP_KERNEL); ++ ctx = nfs_local_fsync_ctx_alloc(data, localio, GFP_NOIO); + if (!ctx) { + nfs_local_commit_done(data, -ENOMEM); + nfs_local_release_commit_data(localio, data, call_ops); +@@ -1112,10 +1117,10 @@ int nfs_local_commit(struct nfsd_file *localio, + if (how & FLUSH_SYNC) { + DECLARE_COMPLETION_ONSTACK(done); + ctx->done = &done; +- queue_work(nfsiod_workqueue, &ctx->work); ++ queue_work(nfslocaliod_workqueue, &ctx->work); + wait_for_completion(&done); + } else +- queue_work(nfsiod_workqueue, &ctx->work); ++ queue_work(nfslocaliod_workqueue, &ctx->work); + + return 0; + } +-- +2.51.0 + diff --git a/queue-6.18/nfs-nfserr_inval-is-not-defined-by-nfsv2.patch b/queue-6.18/nfs-nfserr_inval-is-not-defined-by-nfsv2.patch new file mode 100644 index 0000000000..bb754b8376 --- /dev/null +++ b/queue-6.18/nfs-nfserr_inval-is-not-defined-by-nfsv2.patch @@ -0,0 +1,78 @@ +From d24a2d195fe832952766f17998284209600bf913 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 19:28:50 -0500 +Subject: NFS: NFSERR_INVAL is not defined by NFSv2 + +From: Chuck Lever + +[ Upstream commit 0ac903d1bfdce8ff40657c2b7d996947b72b6645 ] + +A documenting comment in include/uapi/linux/nfs.h claims incorrectly +that NFSv2 defines NFSERR_INVAL. There is no such definition in either +RFC 1094 or https://pubs.opengroup.org/onlinepubs/9629799/chap7.htm + +NFS3ERR_INVAL is introduced in RFC 1813. + +NFSD returns NFSERR_INVAL for PROC_GETACL, which has no +specification (yet). + +However, nfsd_map_status() maps nfserr_symlink and nfserr_wrong_type +to nfserr_inval, which does not align with RFC 1094. This logic was +introduced only recently by commit 438f81e0e92a ("nfsd: move error +choice for incorrect object types to version-specific code."). Given +that we have no INVAL or SERVERFAULT status in NFSv2, probably the +only choice is NFSERR_IO. + +Fixes: 438f81e0e92a ("nfsd: move error choice for incorrect object types to version-specific code.") +Reviewed-by: NeilBrown +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs2acl.c | 2 +- + fs/nfsd/nfsproc.c | 2 +- + include/uapi/linux/nfs.h | 2 +- + 3 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c +index 5fb202acb0fd0..0ac538c761800 100644 +--- a/fs/nfsd/nfs2acl.c ++++ b/fs/nfsd/nfs2acl.c +@@ -45,7 +45,7 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst *rqstp) + inode = d_inode(fh->fh_dentry); + + if (argp->mask & ~NFS_ACL_MASK) { +- resp->status = nfserr_inval; ++ resp->status = nfserr_io; + goto out; + } + resp->mask = argp->mask; +diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c +index 8f71f5748c75b..906a672578900 100644 +--- a/fs/nfsd/nfsproc.c ++++ b/fs/nfsd/nfsproc.c +@@ -33,7 +33,7 @@ static __be32 nfsd_map_status(__be32 status) + break; + case nfserr_symlink: + case nfserr_wrong_type: +- status = nfserr_inval; ++ status = nfserr_io; + break; + } + return status; +diff --git a/include/uapi/linux/nfs.h b/include/uapi/linux/nfs.h +index 71c7196d32817..e629c49535345 100644 +--- a/include/uapi/linux/nfs.h ++++ b/include/uapi/linux/nfs.h +@@ -55,7 +55,7 @@ + NFSERR_NODEV = 19, /* v2 v3 v4 */ + NFSERR_NOTDIR = 20, /* v2 v3 v4 */ + NFSERR_ISDIR = 21, /* v2 v3 v4 */ +- NFSERR_INVAL = 22, /* v2 v3 v4 */ ++ NFSERR_INVAL = 22, /* v3 v4 */ + NFSERR_FBIG = 27, /* v2 v3 v4 */ + NFSERR_NOSPC = 28, /* v2 v3 v4 */ + NFSERR_ROFS = 30, /* v2 v3 v4 */ +-- +2.51.0 + diff --git a/queue-6.18/nfsd-never-defer-requests-during-idmap-lookup.patch b/queue-6.18/nfsd-never-defer-requests-during-idmap-lookup.patch new file mode 100644 index 0000000000..dbdccd2914 --- /dev/null +++ b/queue-6.18/nfsd-never-defer-requests-during-idmap-lookup.patch @@ -0,0 +1,152 @@ +From 9d590103491a50dbe40bfdb18ac2585fa31937b3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 22 Dec 2025 14:30:04 -0500 +Subject: nfsd: never defer requests during idmap lookup + +From: Anthony Iliopoulos + +[ Upstream commit f9c206cdc4266caad6a9a7f46341420a10f03ccb ] + +During v4 request compound arg decoding, some ops (e.g. SETATTR) +can trigger idmap lookup upcalls. When those upcall responses get +delayed beyond the allowed time limit, cache_check() will mark the +request for deferral and cause it to be dropped. + +This prevents nfs4svc_encode_compoundres from being executed, and +thus the session slot flag NFSD4_SLOT_INUSE never gets cleared. +Subsequent client requests will fail with NFSERR_JUKEBOX, given +that the slot will be marked as in-use, making the SEQUENCE op +fail. + +Fix this by making sure that the RQ_USEDEFERRAL flag is always +clear during nfs4svc_decode_compoundargs(), since no v4 request +should ever be deferred. + +Fixes: 2f425878b6a7 ("nfsd: don't use the deferral service, return NFS4ERR_DELAY") +Signed-off-by: Anthony Iliopoulos +Reviewed-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4idmap.c | 48 +++++++++++++++++++++++++++++++++++++++------ + fs/nfsd/nfs4proc.c | 2 -- + fs/nfsd/nfs4xdr.c | 16 +++++++++++++++ + 3 files changed, 58 insertions(+), 8 deletions(-) + +diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c +index 8cca1329f3485..b5b3d45979c9b 100644 +--- a/fs/nfsd/nfs4idmap.c ++++ b/fs/nfsd/nfs4idmap.c +@@ -643,13 +643,31 @@ static __be32 encode_name_from_id(struct xdr_stream *xdr, + return idmap_id_to_name(xdr, rqstp, type, id); + } + +-__be32 +-nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen, +- kuid_t *uid) ++/** ++ * nfsd_map_name_to_uid - Map user@domain to local UID ++ * @rqstp: RPC execution context ++ * @name: user@domain name to be mapped ++ * @namelen: length of name, in bytes ++ * @uid: OUT: mapped local UID value ++ * ++ * Returns nfs_ok on success or an NFSv4 status code on failure. ++ */ ++__be32 nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, ++ size_t namelen, kuid_t *uid) + { + __be32 status; + u32 id = -1; + ++ /* ++ * The idmap lookup below triggers an upcall that invokes ++ * cache_check(). RQ_USEDEFERRAL must be clear to prevent ++ * cache_check() from setting RQ_DROPME via svc_defer(). ++ * NFSv4 servers are not permitted to drop requests. Also ++ * RQ_DROPME will force NFSv4.1 session slot processing to ++ * be skipped. ++ */ ++ WARN_ON_ONCE(test_bit(RQ_USEDEFERRAL, &rqstp->rq_flags)); ++ + if (name == NULL || namelen == 0) + return nfserr_inval; + +@@ -660,13 +678,31 @@ nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen, + return status; + } + +-__be32 +-nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, size_t namelen, +- kgid_t *gid) ++/** ++ * nfsd_map_name_to_gid - Map user@domain to local GID ++ * @rqstp: RPC execution context ++ * @name: user@domain name to be mapped ++ * @namelen: length of name, in bytes ++ * @gid: OUT: mapped local GID value ++ * ++ * Returns nfs_ok on success or an NFSv4 status code on failure. ++ */ ++__be32 nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, ++ size_t namelen, kgid_t *gid) + { + __be32 status; + u32 id = -1; + ++ /* ++ * The idmap lookup below triggers an upcall that invokes ++ * cache_check(). RQ_USEDEFERRAL must be clear to prevent ++ * cache_check() from setting RQ_DROPME via svc_defer(). ++ * NFSv4 servers are not permitted to drop requests. Also ++ * RQ_DROPME will force NFSv4.1 session slot processing to ++ * be skipped. ++ */ ++ WARN_ON_ONCE(test_bit(RQ_USEDEFERRAL, &rqstp->rq_flags)); ++ + if (name == NULL || namelen == 0) + return nfserr_inval; + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 42a6b914c0fe6..8dada7ef97cb1 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -2995,8 +2995,6 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) + BUG_ON(cstate->replay_owner); + out: + cstate->status = status; +- /* Reset deferral mechanism for RPC deferrals */ +- set_bit(RQ_USEDEFERRAL, &rqstp->rq_flags); + return rpc_success; + } + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 4a403ce4fd468..5f046d5be4a6e 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -6001,6 +6001,22 @@ nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + args->ops = args->iops; + args->rqstp = rqstp; + ++ /* ++ * NFSv4 operation decoders can invoke svc cache lookups ++ * that trigger svc_defer() when RQ_USEDEFERRAL is set, ++ * setting RQ_DROPME. This creates two problems: ++ * ++ * 1. Non-idempotency: Compounds make it too hard to avoid ++ * problems if a request is deferred and replayed. ++ * ++ * 2. Session slot leakage (NFSv4.1+): If RQ_DROPME is set ++ * during decode but SEQUENCE executes successfully, the ++ * session slot will be marked INUSE. The request is then ++ * dropped before encoding, so the slot is never released, ++ * rendering it permanently unusable by the client. ++ */ ++ clear_bit(RQ_USEDEFERRAL, &rqstp->rq_flags); ++ + return nfsd4_decode_compound(args); + } + +-- +2.51.0 + diff --git a/queue-6.18/nvdimm-virtio_pmem-serialize-flush-requests.patch b/queue-6.18/nvdimm-virtio_pmem-serialize-flush-requests.patch new file mode 100644 index 0000000000..68839ed888 --- /dev/null +++ b/queue-6.18/nvdimm-virtio_pmem-serialize-flush-requests.patch @@ -0,0 +1,98 @@ +From 76277ed9970cd80bda31f1312cb66719a1c9b841 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 10:13:51 +0800 +Subject: nvdimm: virtio_pmem: serialize flush requests + +From: Li Chen + +[ Upstream commit a9ba6733c7f1096c4506bf4e34a546e07242df74 ] + +Under heavy concurrent flush traffic, virtio-pmem can overflow its request +virtqueue (req_vq): virtqueue_add_sgs() starts returning -ENOSPC and the +driver logs "no free slots in the virtqueue". Shortly after that the +device enters VIRTIO_CONFIG_S_NEEDS_RESET and flush requests fail with +"virtio pmem device needs a reset". + +Serialize virtio_pmem_flush() with a per-device mutex so only one flush +request is in-flight at a time. This prevents req_vq descriptor overflow +under high concurrency. + +Reproducer (guest with virtio-pmem): + - mkfs.ext4 -F /dev/pmem0 + - mount -t ext4 -o dax,noatime /dev/pmem0 /mnt/bench + - fio: ioengine=io_uring rw=randwrite bs=4k iodepth=64 numjobs=64 + direct=1 fsync=1 runtime=30s time_based=1 + - dmesg: "no free slots in the virtqueue" + "virtio pmem device needs a reset" + +Fixes: 6e84200c0a29 ("virtio-pmem: Add virtio pmem driver") +Signed-off-by: Li Chen +Acked-by: Pankaj Gupta +Acked-by: Michael S. Tsirkin +Link: https://patch.msgid.link/20260203021353.121091-1-me@linux.beauty +Signed-off-by: Ira Weiny +Signed-off-by: Sasha Levin +--- + drivers/nvdimm/nd_virtio.c | 3 ++- + drivers/nvdimm/virtio_pmem.c | 1 + + drivers/nvdimm/virtio_pmem.h | 4 ++++ + 3 files changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/nvdimm/nd_virtio.c b/drivers/nvdimm/nd_virtio.c +index c3f07be4aa22a..af82385be7c6a 100644 +--- a/drivers/nvdimm/nd_virtio.c ++++ b/drivers/nvdimm/nd_virtio.c +@@ -44,6 +44,8 @@ static int virtio_pmem_flush(struct nd_region *nd_region) + unsigned long flags; + int err, err1; + ++ guard(mutex)(&vpmem->flush_lock); ++ + /* + * Don't bother to submit the request to the device if the device is + * not activated. +@@ -53,7 +55,6 @@ static int virtio_pmem_flush(struct nd_region *nd_region) + return -EIO; + } + +- might_sleep(); + req_data = kmalloc(sizeof(*req_data), GFP_KERNEL); + if (!req_data) + return -ENOMEM; +diff --git a/drivers/nvdimm/virtio_pmem.c b/drivers/nvdimm/virtio_pmem.c +index 2396d19ce5496..77b1966619059 100644 +--- a/drivers/nvdimm/virtio_pmem.c ++++ b/drivers/nvdimm/virtio_pmem.c +@@ -64,6 +64,7 @@ static int virtio_pmem_probe(struct virtio_device *vdev) + goto out_err; + } + ++ mutex_init(&vpmem->flush_lock); + vpmem->vdev = vdev; + vdev->priv = vpmem; + err = init_vq(vpmem); +diff --git a/drivers/nvdimm/virtio_pmem.h b/drivers/nvdimm/virtio_pmem.h +index 0dddefe594c46..f72cf17f9518f 100644 +--- a/drivers/nvdimm/virtio_pmem.h ++++ b/drivers/nvdimm/virtio_pmem.h +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + #include + + struct virtio_pmem_request { +@@ -35,6 +36,9 @@ struct virtio_pmem { + /* Virtio pmem request queue */ + struct virtqueue *req_vq; + ++ /* Serialize flush requests to the device. */ ++ struct mutex flush_lock; ++ + /* nvdimm bus registers virtio pmem device */ + struct nvdimm_bus *nvdimm_bus; + struct nvdimm_bus_descriptor nd_desc; +-- +2.51.0 + diff --git a/queue-6.18/nvmem-an8855-drop-an-unused-kconfig-symbol.patch b/queue-6.18/nvmem-an8855-drop-an-unused-kconfig-symbol.patch new file mode 100644 index 0000000000..ebcf499e15 --- /dev/null +++ b/queue-6.18/nvmem-an8855-drop-an-unused-kconfig-symbol.patch @@ -0,0 +1,38 @@ +From 726aa679fc40e2878dc9ac167820257c47f4a961 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 17:08:45 +0000 +Subject: nvmem: an8855: drop an unused Kconfig symbol + +From: Randy Dunlap + +[ Upstream commit 4796eaafd6a170db012395a40385d2baf4f4d118 ] + +MFD_AIROHA_AN8855 is referenced here but never defined, so drop it +from the Kconfig file. + +Fixes: e2258cfd9b98 ("nvmem: an8855: Add support for Airoha AN8855 Switch EFUSE") +Signed-off-by: Randy Dunlap +Signed-off-by: Srinivas Kandagatla +Link: https://patch.msgid.link/20260116170846.733558-4-srini@kernel.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/nvmem/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig +index e0d88d3199c11..11b098705ec62 100644 +--- a/drivers/nvmem/Kconfig ++++ b/drivers/nvmem/Kconfig +@@ -30,7 +30,7 @@ source "drivers/nvmem/layouts/Kconfig" + + config NVMEM_AN8855_EFUSE + tristate "Airoha AN8855 eFuse support" +- depends on MFD_AIROHA_AN8855 || COMPILE_TEST ++ depends on COMPILE_TEST + help + Say y here to enable support for reading eFuses on Airoha AN8855 + Switch. These are e.g. used to store factory programmed +-- +2.51.0 + diff --git a/queue-6.18/octeon_ep-disable-per-ring-interrupts.patch b/queue-6.18/octeon_ep-disable-per-ring-interrupts.patch new file mode 100644 index 0000000000..70e18520e4 --- /dev/null +++ b/queue-6.18/octeon_ep-disable-per-ring-interrupts.patch @@ -0,0 +1,119 @@ +From 0e5ce890cade2063cb8407391514ea365dc8d34e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 11:15:06 +0000 +Subject: octeon_ep: disable per ring interrupts + +From: Vimlesh Kumar + +[ Upstream commit 73e6ffa37cebee152c07c5f2b8bc70fd2899ea6e ] + +Disable the MSI-X per ring interrupt for every PF ring when PF +netdev goes down. + +Fixes: 1f2c2d0cee023 ("octeon_ep: add hardware configuration APIs") +Signed-off-by: Sathesh Edara +Signed-off-by: Shinas Rasheed +Signed-off-by: Vimlesh Kumar +Link: https://patch.msgid.link/20260206111510.1045092-2-vimleshk@marvell.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + .../ethernet/marvell/octeon_ep/octep_cn9k_pf.c | 18 +++++++++++++++--- + .../ethernet/marvell/octeon_ep/octep_cnxk_pf.c | 18 +++++++++++++++--- + .../marvell/octeon_ep/octep_regs_cn9k_pf.h | 1 + + .../marvell/octeon_ep/octep_regs_cnxk_pf.h | 1 + + 4 files changed, 32 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c b/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c +index b5805969404fa..f0bcb5f3c1474 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c +@@ -696,14 +696,26 @@ static void octep_enable_interrupts_cn93_pf(struct octep_device *oct) + /* Disable all interrupts */ + static void octep_disable_interrupts_cn93_pf(struct octep_device *oct) + { +- u64 intr_mask = 0ULL; ++ u64 reg_val, intr_mask = 0ULL; + int srn, num_rings, i; + + srn = CFG_GET_PORTS_PF_SRN(oct->conf); + num_rings = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); + +- for (i = 0; i < num_rings; i++) +- intr_mask |= (0x1ULL << (srn + i)); ++ for (i = 0; i < num_rings; i++) { ++ intr_mask |= BIT_ULL(srn + i); ++ reg_val = octep_read_csr64(oct, ++ CN93_SDP_R_IN_INT_LEVELS(srn + i)); ++ reg_val &= ~CN93_INT_ENA_BIT; ++ octep_write_csr64(oct, ++ CN93_SDP_R_IN_INT_LEVELS(srn + i), reg_val); ++ ++ reg_val = octep_read_csr64(oct, ++ CN93_SDP_R_OUT_INT_LEVELS(srn + i)); ++ reg_val &= ~CN93_INT_ENA_BIT; ++ octep_write_csr64(oct, ++ CN93_SDP_R_OUT_INT_LEVELS(srn + i), reg_val); ++ } + + octep_write_csr64(oct, CN93_SDP_EPF_IRERR_RINT_ENA_W1C, intr_mask); + octep_write_csr64(oct, CN93_SDP_EPF_ORERR_RINT_ENA_W1C, intr_mask); +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c b/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c +index 5de0b5ecbc5fd..07e00887c6940 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c +@@ -720,14 +720,26 @@ static void octep_enable_interrupts_cnxk_pf(struct octep_device *oct) + /* Disable all interrupts */ + static void octep_disable_interrupts_cnxk_pf(struct octep_device *oct) + { +- u64 intr_mask = 0ULL; ++ u64 reg_val, intr_mask = 0ULL; + int srn, num_rings, i; + + srn = CFG_GET_PORTS_PF_SRN(oct->conf); + num_rings = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); + +- for (i = 0; i < num_rings; i++) +- intr_mask |= (0x1ULL << (srn + i)); ++ for (i = 0; i < num_rings; i++) { ++ intr_mask |= BIT_ULL(srn + i); ++ reg_val = octep_read_csr64(oct, ++ CNXK_SDP_R_IN_INT_LEVELS(srn + i)); ++ reg_val &= ~CNXK_INT_ENA_BIT; ++ octep_write_csr64(oct, ++ CNXK_SDP_R_IN_INT_LEVELS(srn + i), reg_val); ++ ++ reg_val = octep_read_csr64(oct, ++ CNXK_SDP_R_OUT_INT_LEVELS(srn + i)); ++ reg_val &= ~CNXK_INT_ENA_BIT; ++ octep_write_csr64(oct, ++ CNXK_SDP_R_OUT_INT_LEVELS(srn + i), reg_val); ++ } + + octep_write_csr64(oct, CNXK_SDP_EPF_IRERR_RINT_ENA_W1C, intr_mask); + octep_write_csr64(oct, CNXK_SDP_EPF_ORERR_RINT_ENA_W1C, intr_mask); +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cn9k_pf.h b/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cn9k_pf.h +index ca473502d7a02..95f1dfff90cce 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cn9k_pf.h ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cn9k_pf.h +@@ -386,5 +386,6 @@ + #define CN93_PEM_BAR4_INDEX 7 + #define CN93_PEM_BAR4_INDEX_SIZE 0x400000ULL + #define CN93_PEM_BAR4_INDEX_OFFSET (CN93_PEM_BAR4_INDEX * CN93_PEM_BAR4_INDEX_SIZE) ++#define CN93_INT_ENA_BIT BIT_ULL(62) + + #endif /* _OCTEP_REGS_CN9K_PF_H_ */ +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h b/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h +index e637d7c8224d4..4d172a552f80c 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h +@@ -412,5 +412,6 @@ + #define CNXK_PEM_BAR4_INDEX 7 + #define CNXK_PEM_BAR4_INDEX_SIZE 0x400000ULL + #define CNXK_PEM_BAR4_INDEX_OFFSET (CNXK_PEM_BAR4_INDEX * CNXK_PEM_BAR4_INDEX_SIZE) ++#define CNXK_INT_ENA_BIT BIT_ULL(62) + + #endif /* _OCTEP_REGS_CNXK_PF_H_ */ +-- +2.51.0 + diff --git a/queue-6.18/octeon_ep-ensure-dbell-baddr-updation.patch b/queue-6.18/octeon_ep-ensure-dbell-baddr-updation.patch new file mode 100644 index 0000000000..423cf3653d --- /dev/null +++ b/queue-6.18/octeon_ep-ensure-dbell-baddr-updation.patch @@ -0,0 +1,186 @@ +From 489c162965b9360da3588282459f23769d03d2dd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 11:15:07 +0000 +Subject: octeon_ep: ensure dbell BADDR updation + +From: Vimlesh Kumar + +[ Upstream commit ce8fe3fc4f99efd872120301c0f72f2e90ab9769 ] + +Make sure the OUT DBELL base address reflects the +latest values written to it. + +Fix: +Add a wait until the OUT DBELL base address register +is updated with the DMA ring descriptor address, +and modify the setup_oq function to properly +handle failures. + +Fixes: 0807dc76f3bf5 ("octeon_ep: support Octeon CN10K devices") +Signed-off-by: Sathesh Edara +Signed-off-by: Shinas Rasheed +Signed-off-by: Vimlesh Kumar +Link: https://patch.msgid.link/20260206111510.1045092-3-vimleshk@marvell.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + .../marvell/octeon_ep/octep_cn9k_pf.c | 3 +- + .../marvell/octeon_ep/octep_cnxk_pf.c | 46 +++++++++++++++---- + .../ethernet/marvell/octeon_ep/octep_main.h | 2 +- + .../net/ethernet/marvell/octeon_ep/octep_rx.c | 8 +++- + 4 files changed, 48 insertions(+), 11 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c b/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c +index f0bcb5f3c1474..01e82d0b6b2cd 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c +@@ -307,7 +307,7 @@ static void octep_setup_iq_regs_cn93_pf(struct octep_device *oct, int iq_no) + } + + /* Setup registers for a hardware Rx Queue */ +-static void octep_setup_oq_regs_cn93_pf(struct octep_device *oct, int oq_no) ++static int octep_setup_oq_regs_cn93_pf(struct octep_device *oct, int oq_no) + { + u64 reg_val; + u64 oq_ctl = 0ULL; +@@ -355,6 +355,7 @@ static void octep_setup_oq_regs_cn93_pf(struct octep_device *oct, int oq_no) + reg_val = ((u64)time_threshold << 32) | + CFG_GET_OQ_INTR_PKT(oct->conf); + octep_write_csr64(oct, CN93_SDP_R_OUT_INT_LEVELS(oq_no), reg_val); ++ return 0; + } + + /* Setup registers for a PF mailbox */ +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c b/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c +index 07e00887c6940..09a3f1d0645b8 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + + #include "octep_config.h" + #include "octep_main.h" +@@ -327,12 +328,14 @@ static void octep_setup_iq_regs_cnxk_pf(struct octep_device *oct, int iq_no) + } + + /* Setup registers for a hardware Rx Queue */ +-static void octep_setup_oq_regs_cnxk_pf(struct octep_device *oct, int oq_no) ++static int octep_setup_oq_regs_cnxk_pf(struct octep_device *oct, int oq_no) + { +- u64 reg_val; +- u64 oq_ctl = 0ULL; +- u32 time_threshold = 0; + struct octep_oq *oq = oct->oq[oq_no]; ++ unsigned long t_out_jiffies; ++ u32 time_threshold = 0; ++ u64 oq_ctl = 0ULL; ++ u64 reg_ba_val; ++ u64 reg_val; + + oq_no += CFG_GET_PORTS_PF_SRN(oct->conf); + reg_val = octep_read_csr64(oct, CNXK_SDP_R_OUT_CONTROL(oq_no)); +@@ -343,6 +346,36 @@ static void octep_setup_oq_regs_cnxk_pf(struct octep_device *oct, int oq_no) + reg_val = octep_read_csr64(oct, CNXK_SDP_R_OUT_CONTROL(oq_no)); + } while (!(reg_val & CNXK_R_OUT_CTL_IDLE)); + } ++ octep_write_csr64(oct, CNXK_SDP_R_OUT_WMARK(oq_no), oq->max_count); ++ /* Wait for WMARK to get applied */ ++ usleep_range(10, 15); ++ ++ octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_BADDR(oq_no), ++ oq->desc_ring_dma); ++ octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_RSIZE(oq_no), ++ oq->max_count); ++ reg_ba_val = octep_read_csr64(oct, CNXK_SDP_R_OUT_SLIST_BADDR(oq_no)); ++ ++ if (reg_ba_val != oq->desc_ring_dma) { ++ t_out_jiffies = jiffies + 10 * HZ; ++ do { ++ if (reg_ba_val == ULLONG_MAX) ++ return -EFAULT; ++ octep_write_csr64(oct, ++ CNXK_SDP_R_OUT_SLIST_BADDR(oq_no), ++ oq->desc_ring_dma); ++ octep_write_csr64(oct, ++ CNXK_SDP_R_OUT_SLIST_RSIZE(oq_no), ++ oq->max_count); ++ reg_ba_val = ++ octep_read_csr64(oct, ++ CNXK_SDP_R_OUT_SLIST_BADDR(oq_no)); ++ } while ((reg_ba_val != oq->desc_ring_dma) && ++ time_before(jiffies, t_out_jiffies)); ++ ++ if (reg_ba_val != oq->desc_ring_dma) ++ return -EAGAIN; ++ } + + reg_val &= ~(CNXK_R_OUT_CTL_IMODE); + reg_val &= ~(CNXK_R_OUT_CTL_ROR_P); +@@ -356,10 +389,6 @@ static void octep_setup_oq_regs_cnxk_pf(struct octep_device *oct, int oq_no) + reg_val |= (CNXK_R_OUT_CTL_ES_P); + + octep_write_csr64(oct, CNXK_SDP_R_OUT_CONTROL(oq_no), reg_val); +- octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_BADDR(oq_no), +- oq->desc_ring_dma); +- octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_RSIZE(oq_no), +- oq->max_count); + + oq_ctl = octep_read_csr64(oct, CNXK_SDP_R_OUT_CONTROL(oq_no)); + +@@ -385,6 +414,7 @@ static void octep_setup_oq_regs_cnxk_pf(struct octep_device *oct, int oq_no) + reg_val &= ~0xFFFFFFFFULL; + reg_val |= CFG_GET_OQ_WMARK(oct->conf); + octep_write_csr64(oct, CNXK_SDP_R_OUT_WMARK(oq_no), reg_val); ++ return 0; + } + + /* Setup registers for a PF mailbox */ +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_main.h b/drivers/net/ethernet/marvell/octeon_ep/octep_main.h +index 81ac4267811c8..35d0ff289a70d 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_main.h ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_main.h +@@ -77,7 +77,7 @@ struct octep_pci_win_regs { + + struct octep_hw_ops { + void (*setup_iq_regs)(struct octep_device *oct, int q); +- void (*setup_oq_regs)(struct octep_device *oct, int q); ++ int (*setup_oq_regs)(struct octep_device *oct, int q); + void (*setup_mbox_regs)(struct octep_device *oct, int mbox); + + irqreturn_t (*mbox_intr_handler)(void *ioq_vector); +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c b/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c +index 82b6b19e76b47..f2a7c6a76c742 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c +@@ -12,6 +12,8 @@ + #include "octep_config.h" + #include "octep_main.h" + ++static void octep_oq_free_ring_buffers(struct octep_oq *oq); ++ + static void octep_oq_reset_indices(struct octep_oq *oq) + { + oq->host_read_idx = 0; +@@ -170,11 +172,15 @@ static int octep_setup_oq(struct octep_device *oct, int q_no) + goto oq_fill_buff_err; + + octep_oq_reset_indices(oq); +- oct->hw_ops.setup_oq_regs(oct, q_no); ++ if (oct->hw_ops.setup_oq_regs(oct, q_no)) ++ goto oq_setup_err; ++ + oct->num_oqs++; + + return 0; + ++oq_setup_err: ++ octep_oq_free_ring_buffers(oq); + oq_fill_buff_err: + vfree(oq->buff_info); + oq->buff_info = NULL; +-- +2.51.0 + diff --git a/queue-6.18/octeon_ep_vf-ensure-dbell-baddr-updation.patch b/queue-6.18/octeon_ep_vf-ensure-dbell-baddr-updation.patch new file mode 100644 index 0000000000..a51954c3dc --- /dev/null +++ b/queue-6.18/octeon_ep_vf-ensure-dbell-baddr-updation.patch @@ -0,0 +1,174 @@ +From a3ffcefcfdb1507f34c673cb23c96006456e68f4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 11:15:08 +0000 +Subject: octeon_ep_vf: ensure dbell BADDR updation + +From: Vimlesh Kumar + +[ Upstream commit 484e834d53cffa91c311631271f83130cf6e9e7c ] + +Make sure the OUT DBELL base address reflects the +latest values written to it. + +Fix: +Add a wait until the OUT DBELL base address register +is updated with the DMA ring descriptor address, +and modify the setup_oq function to properly +handle failures. + +Fixes: 2c0c32c72be29 ("octeon_ep_vf: add hardware configuration APIs") +Signed-off-by: Sathesh Edara +Signed-off-by: Shinas Rasheed +Signed-off-by: Vimlesh Kumar +Link: https://patch.msgid.link/20260206111510.1045092-4-vimleshk@marvell.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + .../marvell/octeon_ep_vf/octep_vf_cn9k.c | 3 +- + .../marvell/octeon_ep_vf/octep_vf_cnxk.c | 39 +++++++++++++++++-- + .../marvell/octeon_ep_vf/octep_vf_main.h | 2 +- + .../marvell/octeon_ep_vf/octep_vf_rx.c | 8 +++- + 4 files changed, 46 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cn9k.c b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cn9k.c +index 88937fce75f14..4c769b27c2789 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cn9k.c ++++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cn9k.c +@@ -196,7 +196,7 @@ static void octep_vf_setup_iq_regs_cn93(struct octep_vf_device *oct, int iq_no) + } + + /* Setup registers for a hardware Rx Queue */ +-static void octep_vf_setup_oq_regs_cn93(struct octep_vf_device *oct, int oq_no) ++static int octep_vf_setup_oq_regs_cn93(struct octep_vf_device *oct, int oq_no) + { + struct octep_vf_oq *oq = oct->oq[oq_no]; + u32 time_threshold = 0; +@@ -239,6 +239,7 @@ static void octep_vf_setup_oq_regs_cn93(struct octep_vf_device *oct, int oq_no) + time_threshold = CFG_GET_OQ_INTR_TIME(oct->conf); + reg_val = ((u64)time_threshold << 32) | CFG_GET_OQ_INTR_PKT(oct->conf); + octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_INT_LEVELS(oq_no), reg_val); ++ return 0; + } + + /* Setup registers for a VF mailbox */ +diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cnxk.c b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cnxk.c +index 1f79dfad42c62..a968b93a67943 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cnxk.c ++++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cnxk.c +@@ -199,11 +199,13 @@ static void octep_vf_setup_iq_regs_cnxk(struct octep_vf_device *oct, int iq_no) + } + + /* Setup registers for a hardware Rx Queue */ +-static void octep_vf_setup_oq_regs_cnxk(struct octep_vf_device *oct, int oq_no) ++static int octep_vf_setup_oq_regs_cnxk(struct octep_vf_device *oct, int oq_no) + { + struct octep_vf_oq *oq = oct->oq[oq_no]; ++ unsigned long t_out_jiffies; + u32 time_threshold = 0; + u64 oq_ctl = ULL(0); ++ u64 reg_ba_val; + u64 reg_val; + + reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_CONTROL(oq_no)); +@@ -214,6 +216,38 @@ static void octep_vf_setup_oq_regs_cnxk(struct octep_vf_device *oct, int oq_no) + reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_CONTROL(oq_no)); + } while (!(reg_val & CNXK_VF_R_OUT_CTL_IDLE)); + } ++ octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_WMARK(oq_no), ++ oq->max_count); ++ /* Wait for WMARK to get applied */ ++ usleep_range(10, 15); ++ ++ octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_SLIST_BADDR(oq_no), ++ oq->desc_ring_dma); ++ octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_SLIST_RSIZE(oq_no), ++ oq->max_count); ++ reg_ba_val = octep_vf_read_csr64(oct, ++ CNXK_VF_SDP_R_OUT_SLIST_BADDR(oq_no)); ++ if (reg_ba_val != oq->desc_ring_dma) { ++ t_out_jiffies = jiffies + 10 * HZ; ++ do { ++ if (reg_ba_val == ULLONG_MAX) ++ return -EFAULT; ++ octep_vf_write_csr64(oct, ++ CNXK_VF_SDP_R_OUT_SLIST_BADDR ++ (oq_no), oq->desc_ring_dma); ++ octep_vf_write_csr64(oct, ++ CNXK_VF_SDP_R_OUT_SLIST_RSIZE ++ (oq_no), oq->max_count); ++ reg_ba_val = ++ octep_vf_read_csr64(oct, ++ CNXK_VF_SDP_R_OUT_SLIST_BADDR ++ (oq_no)); ++ } while ((reg_ba_val != oq->desc_ring_dma) && ++ time_before(jiffies, t_out_jiffies)); ++ ++ if (reg_ba_val != oq->desc_ring_dma) ++ return -EAGAIN; ++ } + + reg_val &= ~(CNXK_VF_R_OUT_CTL_IMODE); + reg_val &= ~(CNXK_VF_R_OUT_CTL_ROR_P); +@@ -227,8 +261,6 @@ static void octep_vf_setup_oq_regs_cnxk(struct octep_vf_device *oct, int oq_no) + reg_val |= (CNXK_VF_R_OUT_CTL_ES_P); + + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_CONTROL(oq_no), reg_val); +- octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_SLIST_BADDR(oq_no), oq->desc_ring_dma); +- octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_SLIST_RSIZE(oq_no), oq->max_count); + + oq_ctl = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_CONTROL(oq_no)); + /* Clear the ISIZE and BSIZE (22-0) */ +@@ -250,6 +282,7 @@ static void octep_vf_setup_oq_regs_cnxk(struct octep_vf_device *oct, int oq_no) + reg_val &= ~GENMASK_ULL(31, 0); + reg_val |= CFG_GET_OQ_WMARK(oct->conf); + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_WMARK(oq_no), reg_val); ++ return 0; + } + + /* Setup registers for a VF mailbox */ +diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.h b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.h +index b9f13506f4620..c74cd2369e90d 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.h ++++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.h +@@ -55,7 +55,7 @@ struct octep_vf_mmio { + + struct octep_vf_hw_ops { + void (*setup_iq_regs)(struct octep_vf_device *oct, int q); +- void (*setup_oq_regs)(struct octep_vf_device *oct, int q); ++ int (*setup_oq_regs)(struct octep_vf_device *oct, int q); + void (*setup_mbox_regs)(struct octep_vf_device *oct, int mbox); + + irqreturn_t (*non_ioq_intr_handler)(void *ioq_vector); +diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c +index d70c8be3cfc40..6f865dbbba6c6 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c ++++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c +@@ -12,6 +12,8 @@ + #include "octep_vf_config.h" + #include "octep_vf_main.h" + ++static void octep_vf_oq_free_ring_buffers(struct octep_vf_oq *oq); ++ + static void octep_vf_oq_reset_indices(struct octep_vf_oq *oq) + { + oq->host_read_idx = 0; +@@ -171,11 +173,15 @@ static int octep_vf_setup_oq(struct octep_vf_device *oct, int q_no) + goto oq_fill_buff_err; + + octep_vf_oq_reset_indices(oq); +- oct->hw_ops.setup_oq_regs(oct, q_no); ++ if (oct->hw_ops.setup_oq_regs(oct, q_no)) ++ goto oq_setup_err; ++ + oct->num_oqs++; + + return 0; + ++oq_setup_err: ++ octep_vf_oq_free_ring_buffers(oq); + oq_fill_buff_err: + vfree(oq->buff_info); + oq->buff_info = NULL; +-- +2.51.0 + diff --git a/queue-6.18/octeontx2-af-fix-pf-driver-crash-with-kexec-kernel-b.patch b/queue-6.18/octeontx2-af-fix-pf-driver-crash-with-kexec-kernel-b.patch new file mode 100644 index 0000000000..890f82109b --- /dev/null +++ b/queue-6.18/octeontx2-af-fix-pf-driver-crash-with-kexec-kernel-b.patch @@ -0,0 +1,62 @@ +From fad03216ac74fb87c725337e4fa9f56e1a9b7dbb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 10:37:01 +0530 +Subject: octeontx2-af: Fix PF driver crash with kexec kernel booting + +From: Anshumali Gaur + +[ Upstream commit 2d2d574309e3ae84ee794869a5da8b4c38753a94 ] + +During a kexec reboot the hardware is not power-cycled, so AF state from +the old kernel can persist into the new kernel. When AF and PF drivers +are built as modules, the PF driver may probe before AF reinitializes +the hardware. + +The PF driver treats the RVUM block revision as an indication that AF +initialization is complete. If this value is left uncleared at shutdown, +PF may incorrectly assume AF is ready and access stale hardware state, +leading to a crash. + +Clear the RVUM block revision during AF shutdown to avoid PF +mis-detecting AF readiness after kexec. + +Fixes: 54494aa5d1e6 ("octeontx2-af: Add Marvell OcteonTX2 RVU AF driver") +Signed-off-by: Anshumali Gaur +Reviewed-by: Jacob Keller +Link: https://patch.msgid.link/20260203050701.2616685-1-agaur@marvell.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/octeontx2/af/rvu.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +index 747fbdf2a908f..8530df8b3fdaf 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +@@ -3632,11 +3632,22 @@ static void rvu_remove(struct pci_dev *pdev) + devm_kfree(&pdev->dev, rvu); + } + ++static void rvu_shutdown(struct pci_dev *pdev) ++{ ++ struct rvu *rvu = pci_get_drvdata(pdev); ++ ++ if (!rvu) ++ return; ++ ++ rvu_clear_rvum_blk_revid(rvu); ++} ++ + static struct pci_driver rvu_driver = { + .name = DRV_NAME, + .id_table = rvu_id_table, + .probe = rvu_probe, + .remove = rvu_remove, ++ .shutdown = rvu_shutdown, + }; + + static int __init rvu_init_module(void) +-- +2.51.0 + diff --git a/queue-6.18/octeontx2-pf-unregister-devlink-on-probe-failure.patch b/queue-6.18/octeontx2-pf-unregister-devlink-on-probe-failure.patch new file mode 100644 index 0000000000..38c763fa10 --- /dev/null +++ b/queue-6.18/octeontx2-pf-unregister-devlink-on-probe-failure.patch @@ -0,0 +1,36 @@ +From ac7b3bd2d516421ad07c7f05a0ede465af7cb85d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 23:56:45 +0530 +Subject: octeontx2-pf: Unregister devlink on probe failure + +From: Hariprasad Kelam + +[ Upstream commit 943f3b8bfbf297cf74392b50a7108ce1fe4cbd8c ] + +When probe fails after devlink registration, the missing devlink unregister +call causing a memory leak. + +Fixes: 2da489432747 ("octeontx2-pf: devlink params support to set mcam entry count") +Signed-off-by: Hariprasad Kelam +Link: https://patch.msgid.link/20260206182645.4032737-1-hkelam@marvell.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +index a7a7bc0e1b675..bbf25769f4994 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c ++++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +@@ -3321,6 +3321,7 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id) + err_sriov_cleannup: + otx2_sriov_vfcfg_cleanup(pf); + err_pf_sriov_init: ++ otx2_unregister_dl(pf); + otx2_shutdown_tc(pf); + err_mcam_flow_del: + otx2_mcam_flow_del(pf); +-- +2.51.0 + diff --git a/queue-6.18/of-unittest-fix-possible-null-pointer-dereferences-i.patch b/queue-6.18/of-unittest-fix-possible-null-pointer-dereferences-i.patch new file mode 100644 index 0000000000..046148048a --- /dev/null +++ b/queue-6.18/of-unittest-fix-possible-null-pointer-dereferences-i.patch @@ -0,0 +1,49 @@ +From d9d6b1a409a7cdf08c1163857e96b73668bcc3c0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Jan 2026 15:14:38 +0800 +Subject: of: unittest: fix possible null-pointer dereferences in + of_unittest_property_copy() + +From: Tuo Li + +[ Upstream commit d289cb7fcefe41a54d8f9c6d0e0947f5f82b15c6 ] + +This function first duplicates p1 and p2 into new, and then checks whether +the duplication succeeds. However, if the duplication fails (e.g., +kzalloc() returns NULL in __of_prop_dup()), new will be NULL but is still +dereferenced in __of_prop_free(). To ensure that the unit test continues to +run even when duplication fails, add a NULL check before calling +__of_prop_free(). + +Fixes: 1c5e3d9bf33b ("of: Add a helper to free property struct") +Signed-off-by: Tuo Li +Link: https://patch.msgid.link/20260105071438.156186-1-islituo@gmail.com +Signed-off-by: Rob Herring (Arm) +Signed-off-by: Sasha Levin +--- + drivers/of/unittest.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c +index 3b773aaf9d050..9c184e93f50c6 100644 +--- a/drivers/of/unittest.c ++++ b/drivers/of/unittest.c +@@ -804,11 +804,13 @@ static void __init of_unittest_property_copy(void) + + new = __of_prop_dup(&p1, GFP_KERNEL); + unittest(new && propcmp(&p1, new), "empty property didn't copy correctly\n"); +- __of_prop_free(new); ++ if (new) ++ __of_prop_free(new); + + new = __of_prop_dup(&p2, GFP_KERNEL); + unittest(new && propcmp(&p2, new), "non-empty property didn't copy correctly\n"); +- __of_prop_free(new); ++ if (new) ++ __of_prop_free(new); + #endif + } + +-- +2.51.0 + diff --git a/queue-6.18/opp-return-correct-value-in-dev_pm_opp_get_level.patch b/queue-6.18/opp-return-correct-value-in-dev_pm_opp_get_level.patch new file mode 100644 index 0000000000..75c43a8dda --- /dev/null +++ b/queue-6.18/opp-return-correct-value-in-dev_pm_opp_get_level.patch @@ -0,0 +1,40 @@ +From 9e9edf861d319a178b3170b0f16ea6644d697822 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 14:03:44 +0000 +Subject: OPP: Return correct value in dev_pm_opp_get_level + +From: Aleks Todorov + +[ Upstream commit 0b7277e02dabba2a9921a7f4761ae6e627e7297a ] + +Commit 073d3d2ca7d4 ("OPP: Level zero is valid") modified the +documentation for this function to indicate that errors should return a +non-zero value to avoid colliding with the OPP level zero, however +forgot to actually update the return. + +No in-tree kernel code depends on the error value being 0. + +Fixes: 073d3d2ca7d4 ("OPP: Level zero is valid") +Signed-off-by: Aleks Todorov +Signed-off-by: Viresh Kumar +Signed-off-by: Sasha Levin +--- + drivers/opp/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/opp/core.c b/drivers/opp/core.c +index bba4f7daff8cb..775d4a36f2f54 100644 +--- a/drivers/opp/core.c ++++ b/drivers/opp/core.c +@@ -241,7 +241,7 @@ unsigned int dev_pm_opp_get_level(struct dev_pm_opp *opp) + { + if (IS_ERR_OR_NULL(opp) || !opp->available) { + pr_err("%s: Invalid parameters\n", __func__); +- return 0; ++ return U32_MAX; + } + + return opp->level; +-- +2.51.0 + diff --git a/queue-6.18/ovl-fix-uninit-value-in-ovl_fill_real.patch b/queue-6.18/ovl-fix-uninit-value-in-ovl_fill_real.patch new file mode 100644 index 0000000000..136730aff9 --- /dev/null +++ b/queue-6.18/ovl-fix-uninit-value-in-ovl_fill_real.patch @@ -0,0 +1,58 @@ +From e1e46bc35e5a7d018dd2efca6b13be6e207948b1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 14:24:04 +0100 +Subject: ovl: Fix uninit-value in ovl_fill_real + +From: Qing Wang + +[ Upstream commit 1992330d90dd766fcf1730fd7bf2d6af65370ac4 ] + +Syzbot reported a KMSAN uninit-value issue in ovl_fill_real. + +This iusse's call chain is: +__do_sys_getdents64() + -> iterate_dir() + ... + -> ext4_readdir() + -> fscrypt_fname_alloc_buffer() // alloc + -> fscrypt_fname_disk_to_usr // write without tail '\0' + -> dir_emit() + -> ovl_fill_real() // read by strcmp() + +The string is used to store the decrypted directory entry name for an +encrypted inode. As shown in the call chain, fscrypt_fname_disk_to_usr() +write it without null-terminate. However, ovl_fill_real() uses strcmp() to +compare the name against "..", which assumes a null-terminated string and +may trigger a KMSAN uninit-value warning when the buffer tail contains +uninit data. + +Reported-by: syzbot+d130f98b2c265fae5297@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=d130f98b2c265fae5297 +Fixes: 4edb83bb1041 ("ovl: constant d_ino for non-merge dirs") +Signed-off-by: Qing Wang +Signed-off-by: Amir Goldstein +Link: https://patch.msgid.link/20260128132406.23768-2-amir73il@gmail.com +Acked-by: Miklos Szeredi +Reviewed-by: Eric Biggers +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/overlayfs/readdir.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c +index 1e9792cc557b8..3c27e7a16f94b 100644 +--- a/fs/overlayfs/readdir.c ++++ b/fs/overlayfs/readdir.c +@@ -761,7 +761,7 @@ static bool ovl_fill_real(struct dir_context *ctx, const char *name, + struct dir_context *orig_ctx = rdt->orig_ctx; + bool res; + +- if (rdt->parent_ino && strcmp(name, "..") == 0) { ++ if (rdt->parent_ino && namelen == 2 && !strncmp(name, "..", 2)) { + ino = rdt->parent_ino; + } else if (rdt->cache) { + struct ovl_cache_entry *p; +-- +2.51.0 + diff --git a/queue-6.18/partial-revert-x86-xen-fix-balloon-target-initializa.patch b/queue-6.18/partial-revert-x86-xen-fix-balloon-target-initializa.patch new file mode 100644 index 0000000000..5cfac7b42b --- /dev/null +++ b/queue-6.18/partial-revert-x86-xen-fix-balloon-target-initializa.patch @@ -0,0 +1,140 @@ +From 50562186a17d0d0f00e1fec4ad4c5b9fedb21f1d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 12:05:08 +0100 +Subject: Partial revert "x86/xen: fix balloon target initialization for PVH + dom0" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Roger Pau Monne + +[ Upstream commit 0949c646d64697428ff6257d52efa5093566868d ] + +This partially reverts commit 87af633689ce16ddb166c80f32b120e50b1295de so +the current memory target for PV guests is still fetched from +start_info->nr_pages, which matches exactly what the toolstack sets the +initial memory target to. + +Using get_num_physpages() is possible on PV also, but needs adjusting to +take into account the ISA hole and the PFN at 0 not considered usable +memory despite being populated, and hence would need extra adjustments. +Instead of carrying those extra adjustments switch back to the previous +code. That leaves Linux with a difference in how current memory target is +obtained for HVM vs PV, but that's better than adding extra logic just for +PV. + +However if switching to start_info->nr_pages for PV domains we need to +differentiate between released pages (freed back to the hypervisor) as +opposed to pages in the physmap which are not populated to start with. +Introduce a new xen_unpopulated_pages to account for papges that have +never been populated, and hence in the PV case don't need subtracting. + +Fixes: 87af633689ce ("x86/xen: fix balloon target initialization for PVH dom0") +Reported-by: James Dingwall +Signed-off-by: Roger Pau Monné +Reviewed-by: Juergen Gross +Signed-off-by: Juergen Gross +Message-ID: <20260128110510.46425-2-roger.pau@citrix.com> +Signed-off-by: Sasha Levin +--- + arch/x86/xen/enlighten.c | 2 +- + drivers/xen/balloon.c | 19 +++++++++++++++---- + drivers/xen/unpopulated-alloc.c | 3 +++ + include/xen/xen.h | 2 ++ + 4 files changed, 21 insertions(+), 5 deletions(-) + +diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c +index 53282dc7d5ac5..23b91bf9b6630 100644 +--- a/arch/x86/xen/enlighten.c ++++ b/arch/x86/xen/enlighten.c +@@ -470,7 +470,7 @@ int __init arch_xen_unpopulated_init(struct resource **res) + * driver to know how much of the physmap is unpopulated and + * set an accurate initial memory target. + */ +- xen_released_pages += xen_extra_mem[i].n_pfns; ++ xen_unpopulated_pages += xen_extra_mem[i].n_pfns; + /* Zero so region is not also added to the balloon driver. */ + xen_extra_mem[i].n_pfns = 0; + } +diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c +index 49c3f99263943..8c44a25a7d2b9 100644 +--- a/drivers/xen/balloon.c ++++ b/drivers/xen/balloon.c +@@ -724,6 +724,7 @@ static int __init balloon_add_regions(void) + static int __init balloon_init(void) + { + struct task_struct *task; ++ unsigned long current_pages; + int rc; + + if (!xen_domain()) +@@ -731,12 +732,18 @@ static int __init balloon_init(void) + + pr_info("Initialising balloon driver\n"); + +- if (xen_released_pages >= get_num_physpages()) { +- WARN(1, "Released pages underflow current target"); +- return -ERANGE; ++ if (xen_pv_domain()) { ++ if (xen_released_pages >= xen_start_info->nr_pages) ++ goto underflow; ++ current_pages = min(xen_start_info->nr_pages - ++ xen_released_pages, max_pfn); ++ } else { ++ if (xen_unpopulated_pages >= get_num_physpages()) ++ goto underflow; ++ current_pages = get_num_physpages() - xen_unpopulated_pages; + } + +- balloon_stats.current_pages = get_num_physpages() - xen_released_pages; ++ balloon_stats.current_pages = current_pages; + balloon_stats.target_pages = balloon_stats.current_pages; + balloon_stats.balloon_low = 0; + balloon_stats.balloon_high = 0; +@@ -767,6 +774,10 @@ static int __init balloon_init(void) + xen_balloon_init(); + + return 0; ++ ++ underflow: ++ WARN(1, "Released pages underflow current target"); ++ return -ERANGE; + } + subsys_initcall(balloon_init); + +diff --git a/drivers/xen/unpopulated-alloc.c b/drivers/xen/unpopulated-alloc.c +index d6fc2aefe2646..1dc0b495c8e59 100644 +--- a/drivers/xen/unpopulated-alloc.c ++++ b/drivers/xen/unpopulated-alloc.c +@@ -18,6 +18,9 @@ static unsigned int list_count; + + static struct resource *target_resource; + ++/* Pages to subtract from the memory count when setting balloon target. */ ++unsigned long xen_unpopulated_pages __initdata; ++ + /* + * If arch is not happy with system "iomem_resource" being used for + * the region allocation it can provide it's own view by creating specific +diff --git a/include/xen/xen.h b/include/xen/xen.h +index 61854e3f28377..f280c5dcf9236 100644 +--- a/include/xen/xen.h ++++ b/include/xen/xen.h +@@ -69,11 +69,13 @@ extern u64 xen_saved_max_mem_size; + #endif + + #ifdef CONFIG_XEN_UNPOPULATED_ALLOC ++extern unsigned long xen_unpopulated_pages; + int xen_alloc_unpopulated_pages(unsigned int nr_pages, struct page **pages); + void xen_free_unpopulated_pages(unsigned int nr_pages, struct page **pages); + #include + int arch_xen_unpopulated_init(struct resource **res); + #else ++#define xen_unpopulated_pages 0UL + #include + static inline int xen_alloc_unpopulated_pages(unsigned int nr_pages, + struct page **pages) +-- +2.51.0 + diff --git a/queue-6.18/pci-acpi-restrict-program_hpx_type2-to-aer-bits.patch b/queue-6.18/pci-acpi-restrict-program_hpx_type2-to-aer-bits.patch new file mode 100644 index 0000000000..842f5ad521 --- /dev/null +++ b/queue-6.18/pci-acpi-restrict-program_hpx_type2-to-aer-bits.patch @@ -0,0 +1,200 @@ +From b28c63122c3061f3d31e6c6447cb0c91ee9fb5c2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 18:52:33 +0100 +Subject: PCI/ACPI: Restrict program_hpx_type2() to AER bits +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: HÃ¥kon Bugge + +[ Upstream commit 9abf79c8d7b40db0e5a34aa8c744ea60ff9a3fcf ] + +Previously program_hpx_type2() applied PCIe settings unconditionally, +which could incorrectly change bits like Extended Tag Field Enable and +Enable Relaxed Ordering. + +When _HPX was added to ACPI r3.0, the intent of the PCIe Setting +Record (Type 2) in sec 6.2.7.3 was to configure AER registers when the +OS does not own the AER Capability: + + The PCI Express setting record contains ... [the AER] Uncorrectable + Error Mask, Uncorrectable Error Severity, Correctable Error Mask + ... to be used when configuring registers in the Advanced Error + Reporting Extended Capability Structure ... + + OSPM [1] will only evaluate _HPX with Setting Record – Type 2 if + OSPM is not controlling the PCI Express Advanced Error Reporting + capability. + +ACPI r3.0b, sec 6.2.7.3, added more AER registers, including registers +in the PCIe Capability with AER-related bits, and the restriction that +the OS use this only when it owns PCIe native hotplug: + + ... when configuring PCI Express registers in the Advanced Error + Reporting Extended Capability Structure *or PCI Express Capability + Structure* ... + + An OS that has assumed ownership of native hot plug but does not + ... have ownership of the AER register set must use ... the Type 2 + record to program the AER registers ... + + However, since the Type 2 record also includes register bits that + have functions other than AER, the OS must ignore values ... that + are not applicable. + +Restrict program_hpx_type2() to only the intended purpose: + + - Apply settings only when OS owns PCIe native hotplug but not AER, + + - Only touch the AER-related bits (Error Reporting Enables) in Device + Control + + - Don't touch Link Control at all, since nothing there seems AER-related, + but log _HPX settings for debugging purposes + +Note that Read Completion Boundary is now configured elsewhere, since it is +unrelated to _HPX. + +[1] Operating System-directed configuration and Power Management + +Fixes: 40abb96c51bb ("[PATCH] pciehp: Fix programming hotplug parameters") +Signed-off-by: HÃ¥kon Bugge +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260129175237.727059-3-haakon.bugge@oracle.com +Signed-off-by: Sasha Levin +--- + drivers/pci/pci-acpi.c | 59 +++++++++++++++++------------------------- + drivers/pci/pci.h | 3 +++ + drivers/pci/pcie/aer.c | 3 --- + 3 files changed, 27 insertions(+), 38 deletions(-) + +diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c +index 9369377725fa0..0162acfb57896 100644 +--- a/drivers/pci/pci-acpi.c ++++ b/drivers/pci/pci-acpi.c +@@ -271,21 +271,6 @@ static acpi_status decode_type1_hpx_record(union acpi_object *record, + return AE_OK; + } + +-static bool pcie_root_rcb_set(struct pci_dev *dev) +-{ +- struct pci_dev *rp = pcie_find_root_port(dev); +- u16 lnkctl; +- +- if (!rp) +- return false; +- +- pcie_capability_read_word(rp, PCI_EXP_LNKCTL, &lnkctl); +- if (lnkctl & PCI_EXP_LNKCTL_RCB) +- return true; +- +- return false; +-} +- + /* _HPX PCI Express Setting Record (Type 2) */ + struct hpx_type2 { + u32 revision; +@@ -311,6 +296,7 @@ static void program_hpx_type2(struct pci_dev *dev, struct hpx_type2 *hpx) + { + int pos; + u32 reg32; ++ const struct pci_host_bridge *host; + + if (!hpx) + return; +@@ -318,6 +304,15 @@ static void program_hpx_type2(struct pci_dev *dev, struct hpx_type2 *hpx) + if (!pci_is_pcie(dev)) + return; + ++ host = pci_find_host_bridge(dev->bus); ++ ++ /* ++ * Only do the _HPX Type 2 programming if OS owns PCIe native ++ * hotplug but not AER. ++ */ ++ if (!host->native_pcie_hotplug || host->native_aer) ++ return; ++ + if (hpx->revision > 1) { + pci_warn(dev, "PCIe settings rev %d not supported\n", + hpx->revision); +@@ -325,33 +320,27 @@ static void program_hpx_type2(struct pci_dev *dev, struct hpx_type2 *hpx) + } + + /* +- * Don't allow _HPX to change MPS or MRRS settings. We manage +- * those to make sure they're consistent with the rest of the +- * platform. ++ * We only allow _HPX to program DEVCTL bits related to AER, namely ++ * PCI_EXP_DEVCTL_CERE, PCI_EXP_DEVCTL_NFERE, PCI_EXP_DEVCTL_FERE, ++ * and PCI_EXP_DEVCTL_URRE. ++ * ++ * The rest of DEVCTL is managed by the OS to make sure it's ++ * consistent with the rest of the platform. + */ +- hpx->pci_exp_devctl_and |= PCI_EXP_DEVCTL_PAYLOAD | +- PCI_EXP_DEVCTL_READRQ; +- hpx->pci_exp_devctl_or &= ~(PCI_EXP_DEVCTL_PAYLOAD | +- PCI_EXP_DEVCTL_READRQ); ++ hpx->pci_exp_devctl_and |= ~PCI_EXP_AER_FLAGS; ++ hpx->pci_exp_devctl_or &= PCI_EXP_AER_FLAGS; + + /* Initialize Device Control Register */ + pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL, + ~hpx->pci_exp_devctl_and, hpx->pci_exp_devctl_or); + +- /* Initialize Link Control Register */ ++ /* Log if _HPX attempts to modify Link Control Register */ + if (pcie_cap_has_lnkctl(dev)) { +- +- /* +- * If the Root Port supports Read Completion Boundary of +- * 128, set RCB to 128. Otherwise, clear it. +- */ +- hpx->pci_exp_lnkctl_and |= PCI_EXP_LNKCTL_RCB; +- hpx->pci_exp_lnkctl_or &= ~PCI_EXP_LNKCTL_RCB; +- if (pcie_root_rcb_set(dev)) +- hpx->pci_exp_lnkctl_or |= PCI_EXP_LNKCTL_RCB; +- +- pcie_capability_clear_and_set_word(dev, PCI_EXP_LNKCTL, +- ~hpx->pci_exp_lnkctl_and, hpx->pci_exp_lnkctl_or); ++ if (hpx->pci_exp_lnkctl_and != 0xffff || ++ hpx->pci_exp_lnkctl_or != 0) ++ pci_info(dev, "_HPX attempts Link Control setting (AND %#06x OR %#06x)\n", ++ hpx->pci_exp_lnkctl_and, ++ hpx->pci_exp_lnkctl_or); + } + + /* Find Advanced Error Reporting Enhanced Capability */ +diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h +index 36f8c0985430a..565acfcd7cdb1 100644 +--- a/drivers/pci/pci.h ++++ b/drivers/pci/pci.h +@@ -88,6 +88,9 @@ struct pcie_tlp_log; + #define PCI_BUS_BRIDGE_MEM_WINDOW 1 + #define PCI_BUS_BRIDGE_PREF_MEM_WINDOW 2 + ++#define PCI_EXP_AER_FLAGS (PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE | \ ++ PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE) ++ + extern const unsigned char pcie_link_speed[]; + extern bool pci_early_dump; + +diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c +index 0b5ed4722ac32..23bead9415fcd 100644 +--- a/drivers/pci/pcie/aer.c ++++ b/drivers/pci/pcie/aer.c +@@ -238,9 +238,6 @@ void pcie_ecrc_get_policy(char *str) + } + #endif /* CONFIG_PCIE_ECRC */ + +-#define PCI_EXP_AER_FLAGS (PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE | \ +- PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE) +- + int pcie_aer_is_native(struct pci_dev *dev) + { + struct pci_host_bridge *host = pci_find_host_bridge(dev->bus); +-- +2.51.0 + diff --git a/queue-6.18/pci-add-acs-quirk-for-pericom-pi7c9x2g404-switches-1.patch b/queue-6.18/pci-add-acs-quirk-for-pericom-pi7c9x2g404-switches-1.patch new file mode 100644 index 0000000000..37d4265d7a --- /dev/null +++ b/queue-6.18/pci-add-acs-quirk-for-pericom-pi7c9x2g404-switches-1.patch @@ -0,0 +1,46 @@ +From 4f5959db727c4e3fe899eca9fc42ea6723b6134d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 17:08:33 +0100 +Subject: PCI: Add ACS quirk for Pericom PI7C9X2G404 switches [12d8:b404] + +From: Nicolas Cavallari + +[ Upstream commit 5907a90551e9f7968781f3a6ab8684458959beb3 ] + +12d8:b404 is apparently another PCI ID for Pericom PI7C9X2G404 (as +identified by the chip silkscreen and lspci). + +It is also affected by the PI7C9X2G errata (e.g. a network card attached +to it fails under load when P2P Redirect Request is enabled), so apply +the same quirk to this PCI ID too. + +PCI bridge [0604]: Pericom Semiconductor PI7C9X2G404 EV/SV PCIe2 4-Port/4-Lane Packet Switch [12d8:b404] (rev 01) + +Fixes: acd61ffb2f16 ("PCI: Add ACS quirk for Pericom PI7C9X2G switches") +Closes: https://lore.kernel.org/all/a1d926f0-4cb5-4877-a4df-617902648d80@green-communications.fr/ +Signed-off-by: Nicolas Cavallari +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260119160915.26456-1-nicolas.cavallari@green-communications.fr +Signed-off-by: Sasha Levin +--- + drivers/pci/quirks.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index c7e733beaab03..9e073321b2dd2 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -6189,6 +6189,10 @@ DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_PERICOM, 0x2303, + pci_fixup_pericom_acs_store_forward); + DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_PERICOM, 0x2303, + pci_fixup_pericom_acs_store_forward); ++DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_PERICOM, 0xb404, ++ pci_fixup_pericom_acs_store_forward); ++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_PERICOM, 0xb404, ++ pci_fixup_pericom_acs_store_forward); + + static void nvidia_ion_ahci_fixup(struct pci_dev *pdev) + { +-- +2.51.0 + diff --git a/queue-6.18/pci-check-parent-for-null-in-of_pci_bus_release_doma.patch b/queue-6.18/pci-check-parent-for-null-in-of_pci_bus_release_doma.patch new file mode 100644 index 0000000000..0b51d74e83 --- /dev/null +++ b/queue-6.18/pci-check-parent-for-null-in-of_pci_bus_release_doma.patch @@ -0,0 +1,42 @@ +From fcf45bb5d710961b4a9db7e5b9101723b0087bb9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 23:39:42 +0300 +Subject: PCI: Check parent for NULL in of_pci_bus_release_domain_nr() + +From: Sergey Shtylyov + +[ Upstream commit f7245901de8978d829f80b3d8e36ed9a8fd18049 ] + +of_pci_bus_find_domain_nr() allows its parent parameter to be NULL but +of_pci_bus_release_domain_nr() (that undoes its effect) doesn't -- that +means it's going to blow up while calling of_get_pci_domain_nr() if the +parent parameter indeed happens to be NULL. Add the missing NULL check. + +Found by Linux Verification Center (linuxtesting.org) with the Svace static +analysis tool. + +Fixes: c14f7ccc9f5d ("PCI: Assign PCI domain IDs by ida_alloc()") +Signed-off-by: Sergey Shtylyov +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260127203944.28588-1-s.shtylyov@auroraos.dev +Signed-off-by: Sasha Levin +--- + drivers/pci/pci.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c +index 08a8c17ba4b12..82e323b5aaa25 100644 +--- a/drivers/pci/pci.c ++++ b/drivers/pci/pci.c +@@ -6717,7 +6717,7 @@ static void of_pci_bus_release_domain_nr(struct device *parent, int domain_nr) + return; + + /* Release domain from IDA where it was allocated. */ +- if (of_get_pci_domain_nr(parent->of_node) == domain_nr) ++ if (parent && of_get_pci_domain_nr(parent->of_node) == domain_nr) + ida_free(&pci_domain_nr_static_ida, domain_nr); + else + ida_free(&pci_domain_nr_dynamic_ida, domain_nr); +-- +2.51.0 + diff --git a/queue-6.18/pci-do-not-attempt-to-set-exttag-for-vfs.patch b/queue-6.18/pci-do-not-attempt-to-set-exttag-for-vfs.patch new file mode 100644 index 0000000000..863fa1a842 --- /dev/null +++ b/queue-6.18/pci-do-not-attempt-to-set-exttag-for-vfs.patch @@ -0,0 +1,49 @@ +From 9ccfdf28fa6450f21add5cadf900166d3484e4d9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 12 Nov 2025 10:54:40 +0100 +Subject: PCI: Do not attempt to set ExtTag for VFs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: HÃ¥kon Bugge + +[ Upstream commit 73711730a1128d91ebca1a6994ceeb18f36cb0cd ] + +The bit for enabling extended tags is Reserved and Preserved (RsvdP) for +VFs, according to PCIe r7.0 section 7.5.3.4 table 7.21. Hence, bail out +early from pci_configure_extended_tags() if the device is a VF. + +Otherwise, we may see incorrect log messages such as: + + kernel: pci 0000:af:00.2: enabling Extended Tags + +(af:00.2 is a VF) + +Fixes: 60db3a4d8cc9 ("PCI: Enable PCIe Extended Tags if supported") +Signed-off-by: HÃ¥kon Bugge +Signed-off-by: Bjorn Helgaas +Reviewed-by: Zhu Yanjun +Link: https://patch.msgid.link/20251112095442.1913258-1-haakon.bugge@oracle.com +Signed-off-by: Sasha Levin +--- + drivers/pci/probe.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c +index 9cd032dff31e5..8cf573fca3078 100644 +--- a/drivers/pci/probe.c ++++ b/drivers/pci/probe.c +@@ -2251,7 +2251,8 @@ int pci_configure_extended_tags(struct pci_dev *dev, void *ign) + u16 ctl; + int ret; + +- if (!pci_is_pcie(dev)) ++ /* PCI_EXP_DEVCTL_EXT_TAG is RsvdP in VFs */ ++ if (!pci_is_pcie(dev) || dev->is_virtfn) + return 0; + + ret = pcie_capability_read_dword(dev, PCI_EXP_DEVCAP, &cap); +-- +2.51.0 + diff --git a/queue-6.18/pci-initialize-rcb-from-pci_configure_device.patch b/queue-6.18/pci-initialize-rcb-from-pci_configure_device.patch new file mode 100644 index 0000000000..70580d575e --- /dev/null +++ b/queue-6.18/pci-initialize-rcb-from-pci_configure_device.patch @@ -0,0 +1,90 @@ +From 2a2fd043b82fb4804a15b19347bbd30a40015b0a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 18:52:32 +0100 +Subject: PCI: Initialize RCB from pci_configure_device() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: HÃ¥kon Bugge + +[ Upstream commit 1a6845aaa6de81f95959b380b45de8f10d6a8502 ] + +Commit e42010d8207f ("PCI: Set Read Completion Boundary to 128 iff Root +Port supports it (_HPX)") worked around a bogus _HPX type 2 record, which +caused program_hpx_type2() to set the RCB in an endpoint even though the +Root Port did not have the RCB bit set. + +e42010d8207f fixed that by setting the RCB in the endpoint only when it was +set in the Root Port. + +In retrospect, program_hpx_type2() is intended for AER-related settings, +and the RCB should be configured elsewhere so it doesn't depend on the +presence or contents of an _HPX record. + +Explicitly program the RCB from pci_configure_device() so it matches the +Root Port's RCB. The Root Port may not be visible to virtualized guests; +in that case, leave RCB alone. + +Fixes: e42010d8207f ("PCI: Set Read Completion Boundary to 128 iff Root Port supports it (_HPX)") +Signed-off-by: HÃ¥kon Bugge +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260129175237.727059-2-haakon.bugge@oracle.com +Signed-off-by: Sasha Levin +--- + drivers/pci/probe.c | 32 ++++++++++++++++++++++++++++++++ + 1 file changed, 32 insertions(+) + +diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c +index 8cf573fca3078..7d4f0db5ac265 100644 +--- a/drivers/pci/probe.c ++++ b/drivers/pci/probe.c +@@ -2381,6 +2381,37 @@ static void pci_configure_serr(struct pci_dev *dev) + } + } + ++static void pci_configure_rcb(struct pci_dev *dev) ++{ ++ struct pci_dev *rp; ++ u16 rp_lnkctl; ++ ++ /* ++ * Per PCIe r7.0, sec 7.5.3.7, RCB is only meaningful in Root Ports ++ * (where it is read-only), Endpoints, and Bridges. It may only be ++ * set for Endpoints and Bridges if it is set in the Root Port. For ++ * Endpoints, it is 'RsvdP' for Virtual Functions. ++ */ ++ if (!pci_is_pcie(dev) || ++ pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT || ++ pci_pcie_type(dev) == PCI_EXP_TYPE_UPSTREAM || ++ pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM || ++ pci_pcie_type(dev) == PCI_EXP_TYPE_RC_EC || ++ dev->is_virtfn) ++ return; ++ ++ /* Root Port often not visible to virtualized guests */ ++ rp = pcie_find_root_port(dev); ++ if (!rp) ++ return; ++ ++ pcie_capability_read_word(rp, PCI_EXP_LNKCTL, &rp_lnkctl); ++ pcie_capability_clear_and_set_word(dev, PCI_EXP_LNKCTL, ++ PCI_EXP_LNKCTL_RCB, ++ (rp_lnkctl & PCI_EXP_LNKCTL_RCB) ? ++ PCI_EXP_LNKCTL_RCB : 0); ++} ++ + static void pci_configure_device(struct pci_dev *dev) + { + pci_configure_mps(dev); +@@ -2390,6 +2421,7 @@ static void pci_configure_device(struct pci_dev *dev) + pci_configure_aspm_l1ss(dev); + pci_configure_eetlp_prefix(dev); + pci_configure_serr(dev); ++ pci_configure_rcb(dev); + + pci_acpi_program_hp_params(dev); + } +-- +2.51.0 + diff --git a/queue-6.18/pci-mark-3ware-9650sa-root-port-extended-tags-as-bro.patch b/queue-6.18/pci-mark-3ware-9650sa-root-port-extended-tags-as-bro.patch new file mode 100644 index 0000000000..1db85d7d6a --- /dev/null +++ b/queue-6.18/pci-mark-3ware-9650sa-root-port-extended-tags-as-bro.patch @@ -0,0 +1,56 @@ +From 248aeae8af54d29cefa4540e8f31060a4e4fffe7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 15:31:10 +0100 +Subject: PCI: Mark 3ware-9650SA Root Port Extended Tags as broken +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jörg Wedekind + +[ Upstream commit 959ac08a2c2811305be8c2779779e8b0932e5a99 ] + +Per PCIe r7.0, sec 2.2.6.2.1 and 7.5.3.4, a Requester may not use 8-bit Tags +unless its Extended Tag Field Enable is set, but all Receivers/Completers +must handle 8-bit Tags correctly regardless of their Extended Tag Field +Enable. + +Some devices do not handle 8-bit Tags as Completers, so add a quirk for +them. If we find such a device, we disable Extended Tags for the entire +hierarchy to make peer-to-peer DMA possible. + +The 3ware 9650SA seems to have issues with handling 8-bit tags. Mark it as +broken. + +This fixes PCI Parity Errors like : + + 3w-9xxx: scsi0: ERROR: (0x06:0x000C): PCI Parity Error: clearing. + 3w-9xxx: scsi0: ERROR: (0x06:0x000D): PCI Abort: clearing. + 3w-9xxx: scsi0: ERROR: (0x06:0x000E): Controller Queue Error: clearing. + 3w-9xxx: scsi0: ERROR: (0x06:0x0010): Microcontroller Error: clearing. + +Fixes: 60db3a4d8cc9 ("PCI: Enable PCIe Extended Tags if supported") +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=202425 +Signed-off-by: Jörg Wedekind +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260119143114.21948-1-joerg@wedekind.de +Signed-off-by: Sasha Levin +--- + drivers/pci/quirks.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index b9c252aa6fe08..c7e733beaab03 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -5581,6 +5581,7 @@ static void quirk_no_ext_tags(struct pci_dev *pdev) + pci_walk_bus(bridge->bus, pci_configure_extended_tags, NULL); + } + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_3WARE, 0x1004, quirk_no_ext_tags); ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_3WARE, 0x1005, quirk_no_ext_tags); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0132, quirk_no_ext_tags); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0140, quirk_no_ext_tags); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0141, quirk_no_ext_tags); +-- +2.51.0 + diff --git a/queue-6.18/pci-mediatek-fix-irq-domain-leak-when-msi-allocation.patch b/queue-6.18/pci-mediatek-fix-irq-domain-leak-when-msi-allocation.patch new file mode 100644 index 0000000000..d5d5b7ae37 --- /dev/null +++ b/queue-6.18/pci-mediatek-fix-irq-domain-leak-when-msi-allocation.patch @@ -0,0 +1,45 @@ +From 4fbf096a2dc550818112d54395542230641a56ea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 19 Nov 2025 10:33:08 +0800 +Subject: PCI: mediatek: Fix IRQ domain leak when MSI allocation fails + +From: Haotian Zhang + +[ Upstream commit 7f0cdcddf8bef1c8c18f9be6708073fd3790a20f ] + +In mtk_pcie_init_irq_domain(), if mtk_pcie_allocate_msi_domains() +fails after port->irq_domain has been successfully created via +irq_domain_create_linear(), the function returns directly without +cleaning up the allocated IRQ domain, resulting in a resource leak. + +Add irq_domain_remove() call in the error path to properly release the +INTx IRQ domain before returning the error. + +Fixes: 43e6409db64d ("PCI: mediatek: Add MSI support for MT2712 and MT7622") +Signed-off-by: Haotian Zhang +Signed-off-by: Manivannan Sadhasivam +Link: https://patch.msgid.link/20251119023308.476-1-vulab@iscas.ac.cn +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/pcie-mediatek.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c +index 24cc30a2ab6c6..e0bf667c2b4c6 100644 +--- a/drivers/pci/controller/pcie-mediatek.c ++++ b/drivers/pci/controller/pcie-mediatek.c +@@ -575,8 +575,10 @@ static int mtk_pcie_init_irq_domain(struct mtk_pcie_port *port, + + if (IS_ENABLED(CONFIG_PCI_MSI)) { + ret = mtk_pcie_allocate_msi_domains(port); +- if (ret) ++ if (ret) { ++ irq_domain_remove(port->irq_domain); + return ret; ++ } + } + + return 0; +-- +2.51.0 + diff --git a/queue-6.18/pci-p2pdma-fix-p2pmem_alloc_mmap-warning-condition.patch b/queue-6.18/pci-p2pdma-fix-p2pmem_alloc_mmap-warning-condition.patch new file mode 100644 index 0000000000..de14808450 --- /dev/null +++ b/queue-6.18/pci-p2pdma-fix-p2pmem_alloc_mmap-warning-condition.patch @@ -0,0 +1,52 @@ +From d5153d0dc68638a8464e630dbc0d8022b6df235b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 12:04:35 +0800 +Subject: PCI/P2PDMA: Fix p2pmem_alloc_mmap() warning condition + +From: Hou Tao + +[ Upstream commit cb500023a75246f60b79af9f7321d6e75330c5b5 ] + +Commit b7e282378773 has already changed the initial page refcount of +p2pdma page from one to zero, however, in p2pmem_alloc_mmap() it uses +"VM_WARN_ON_ONCE_PAGE(!page_ref_count(page))" to assert the initial page +refcount should not be zero and the following will be reported when +CONFIG_DEBUG_VM is enabled: + + page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x380400000 + flags: 0x20000000002000(reserved|node=0|zone=4) + raw: 0020000000002000 ff1100015e3ab440 0000000000000000 0000000000000000 + raw: 0000000000000000 0000000000000000 00000000ffffffff 0000000000000000 + page dumped because: VM_WARN_ON_ONCE_PAGE(!page_ref_count(page)) + ------------[ cut here ]------------ + WARNING: CPU: 5 PID: 449 at drivers/pci/p2pdma.c:240 p2pmem_alloc_mmap+0x83a/0xa60 + +Fix by using "page_ref_count(page)" as the assertion condition. + +Fixes: b7e282378773 ("mm/mm_init: move p2pdma page refcount initialisation to p2pdma") +Signed-off-by: Hou Tao +Signed-off-by: Bjorn Helgaas +Reviewed-by: Logan Gunthorpe +Reviewed-by: Alistair Popple +Link: https://patch.msgid.link/20251220040446.274991-3-houtao@huaweicloud.com +Signed-off-by: Sasha Levin +--- + drivers/pci/p2pdma.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c +index 5497ce0be7c5c..12c69bb2b2326 100644 +--- a/drivers/pci/p2pdma.c ++++ b/drivers/pci/p2pdma.c +@@ -147,7 +147,7 @@ static int p2pmem_alloc_mmap(struct file *filp, struct kobject *kobj, + * we have just allocated the page no one else should be + * using it. + */ +- VM_WARN_ON_ONCE_PAGE(!page_ref_count(page), page); ++ VM_WARN_ON_ONCE_PAGE(page_ref_count(page), page); + set_page_count(page, 1); + ret = vm_insert_page(vma, vaddr, page); + if (ret) { +-- +2.51.0 + diff --git a/queue-6.18/pci-p2pdma-release-per-cpu-pgmap-ref-when-vm_insert_.patch b/queue-6.18/pci-p2pdma-release-per-cpu-pgmap-ref-when-vm_insert_.patch new file mode 100644 index 0000000000..0215f0fce7 --- /dev/null +++ b/queue-6.18/pci-p2pdma-release-per-cpu-pgmap-ref-when-vm_insert_.patch @@ -0,0 +1,42 @@ +From 66efcee6687168bb3694101ab65eea841f819d27 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 12:04:34 +0800 +Subject: PCI/P2PDMA: Release per-CPU pgmap ref when vm_insert_page() fails + +From: Hou Tao + +[ Upstream commit 6220694c52a5a04102b48109e4f24e958b559bd3 ] + +When vm_insert_page() fails in p2pmem_alloc_mmap(), p2pmem_alloc_mmap() +doesn't invoke percpu_ref_put() to free the per-CPU ref of pgmap acquired +after gen_pool_alloc_owner(), and memunmap_pages() will hang forever when +trying to remove the PCI device. + +Fix it by adding the missed percpu_ref_put(). + +Fixes: 7e9c7ef83d78 ("PCI/P2PDMA: Allow userspace VMA allocations through sysfs") +Signed-off-by: Hou Tao +Signed-off-by: Bjorn Helgaas +Reviewed-by: Logan Gunthorpe +Reviewed-by: Alistair Popple +Link: https://patch.msgid.link/20251220040446.274991-2-houtao@huaweicloud.com +Signed-off-by: Sasha Levin +--- + drivers/pci/p2pdma.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c +index 78e108e47254a..5497ce0be7c5c 100644 +--- a/drivers/pci/p2pdma.c ++++ b/drivers/pci/p2pdma.c +@@ -152,6 +152,7 @@ static int p2pmem_alloc_mmap(struct file *filp, struct kobject *kobj, + ret = vm_insert_page(vma, vaddr, page); + if (ret) { + gen_pool_free(p2pdma->pool, (uintptr_t)kaddr, len); ++ percpu_ref_put(ref); + return ret; + } + percpu_ref_get(ref); +-- +2.51.0 + diff --git a/queue-6.18/pci-p2pdma-reset-page-reference-count-when-page-mapp.patch b/queue-6.18/pci-p2pdma-reset-page-reference-count-when-page-mapp.patch new file mode 100644 index 0000000000..6032f9e28b --- /dev/null +++ b/queue-6.18/pci-p2pdma-reset-page-reference-count-when-page-mapp.patch @@ -0,0 +1,57 @@ +From 2974531503b0f7e33cd7578c851e1ce22aff1e81 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 11:54:40 +1100 +Subject: PCI/P2PDMA: Reset page reference count when page mapping fails + +From: Alistair Popple + +[ Upstream commit 83014d82a1100abc89f7712ad67c3e5accaddc43 ] + +When mapping a p2pdma page the page reference count is initialised to 1 +prior to calling vm_insert_page(). This is to avoid vm_insert_page() +warning if the page refcount is zero. Prior to setting the page count there +is a check to ensure the page is currently free (ie. has a zero reference +count). + +However vm_insert_page() can fail. In this case the pages are freed back to +the genalloc pool, but that does not reset the page refcount. So a future +allocation of the same page will see the elevated page refcount from the +previous set_page_count() call triggering the VM_WARN_ON_ONCE_PAGE checking +that the page is free. + +Fix this by resetting the page refcount to zero using set_page_count(). +Note that put_page() is not used because that would result in freeing the +page twice due to implicitly calling p2pdma_folio_free(). + +Fixes: b7e282378773 ("mm/mm_init: move p2pdma page refcount initialisation to p2pdma") +Signed-off-by: Alistair Popple +Signed-off-by: Bjorn Helgaas +Reviewed-by: Logan Gunthorpe +Acked-by: Balbir Singh +Link: https://patch.msgid.link/20260112005440.998543-1-apopple@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/p2pdma.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c +index 12c69bb2b2326..49e395eb013d3 100644 +--- a/drivers/pci/p2pdma.c ++++ b/drivers/pci/p2pdma.c +@@ -152,6 +152,13 @@ static int p2pmem_alloc_mmap(struct file *filp, struct kobject *kobj, + ret = vm_insert_page(vma, vaddr, page); + if (ret) { + gen_pool_free(p2pdma->pool, (uintptr_t)kaddr, len); ++ ++ /* ++ * Reset the page count. We don't use put_page() ++ * because we don't want to trigger the ++ * p2pdma_folio_free() path. ++ */ ++ set_page_count(page, 0); + percpu_ref_put(ref); + return ret; + } +-- +2.51.0 + diff --git a/queue-6.18/pci-pm-avoid-redundant-delays-on-d3hot-d3cold.patch b/queue-6.18/pci-pm-avoid-redundant-delays-on-d3hot-d3cold.patch new file mode 100644 index 0000000000..99cd964ad7 --- /dev/null +++ b/queue-6.18/pci-pm-avoid-redundant-delays-on-d3hot-d3cold.patch @@ -0,0 +1,56 @@ +From 4b47852d79be0524d037a5af5e9653f29c77c250 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Oct 2025 15:40:09 -0700 +Subject: PCI/PM: Avoid redundant delays on D3hot->D3cold + +From: Brian Norris + +[ Upstream commit 4d982084507d663df160546c4c48066a8887ed89 ] + +When transitioning to D3cold, __pci_set_power_state() first transitions to +D3hot. If the device was already in D3hot, this adds excess work: + + (a) read/modify/write PMCSR; and + (b) excess delay (pci_dev_d3_sleep()). + +For (b), we already performed the necessary delay on the previous D3hot +entry; this was extra noticeable when evaluating runtime PM transition +latency. + +Check whether we're already in the target state before continuing. + +Note that __pci_set_power_state() already does this same check for other +state transitions, but D3cold is special because __pci_set_power_state() +converts it to D3hot for the purposes of PMCSR. + +This seems to be an oversight in commit 0aacdc957401 ("PCI/PM: Clean up +pci_set_low_power_state()"). + +Fixes: 0aacdc957401 ("PCI/PM: Clean up pci_set_low_power_state()") +Signed-off-by: Brian Norris +Signed-off-by: Brian Norris +[bhelgaas: reverse test to match other "dev->current_state == state" cases] +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20251003154008.1.I7a21c240b30062c66471329567a96dceb6274358@changeid +Signed-off-by: Sasha Levin +--- + drivers/pci/pci.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c +index 2f0da5dbbba40..08a8c17ba4b12 100644 +--- a/drivers/pci/pci.c ++++ b/drivers/pci/pci.c +@@ -1488,6 +1488,9 @@ static int pci_set_low_power_state(struct pci_dev *dev, pci_power_t state, bool + || (state == PCI_D2 && !dev->d2_support)) + return -EIO; + ++ if (dev->current_state == state) ++ return 0; ++ + pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr); + if (PCI_POSSIBLE_ERROR(pmcsr)) { + pci_err(dev, "Unable to change power state from %s to %s, device inaccessible\n", +-- +2.51.0 + diff --git a/queue-6.18/pci-portdrv-fix-potential-resource-leak.patch b/queue-6.18/pci-portdrv-fix-potential-resource-leak.patch new file mode 100644 index 0000000000..6e8ff20380 --- /dev/null +++ b/queue-6.18/pci-portdrv-fix-potential-resource-leak.patch @@ -0,0 +1,48 @@ +From a749a863d6c827016d84f2e9988817f08383fbae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Dec 2025 16:13:49 +0100 +Subject: PCI/portdrv: Fix potential resource leak +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Uwe Kleine-König + +[ Upstream commit 01464a3fdf91c041a381d93a1b6fefbdb819a46f ] + +pcie_port_probe_service() unconditionally calls get_device() (unless it +fails). So drop that reference also unconditionally as it's fine for a +PCIe driver to not have a remove callback. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Uwe Kleine-König +Signed-off-by: Bjorn Helgaas +Reviewed-by: Ilpo Järvinen +Reviewed-by: Jonathan Cameron +Link: https://patch.msgid.link/e1c68c3b3f1af8427e98ca5e2c79f8bf0ebe2ce4.1764688034.git.u.kleine-koenig@baylibre.com +Signed-off-by: Sasha Levin +--- + drivers/pci/pcie/portdrv.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/pci/pcie/portdrv.c b/drivers/pci/pcie/portdrv.c +index 38a41ccf79b9a..a0991da482136 100644 +--- a/drivers/pci/pcie/portdrv.c ++++ b/drivers/pci/pcie/portdrv.c +@@ -557,10 +557,10 @@ static int pcie_port_remove_service(struct device *dev) + + pciedev = to_pcie_device(dev); + driver = to_service_driver(dev->driver); +- if (driver && driver->remove) { ++ if (driver && driver->remove) + driver->remove(pciedev); +- put_device(dev); +- } ++ ++ put_device(dev); + return 0; + } + +-- +2.51.0 + diff --git a/queue-6.18/pci-ptm-fix-pcie_ptm_create_debugfs-memory-leak.patch b/queue-6.18/pci-ptm-fix-pcie_ptm_create_debugfs-memory-leak.patch new file mode 100644 index 0000000000..25c6c29056 --- /dev/null +++ b/queue-6.18/pci-ptm-fix-pcie_ptm_create_debugfs-memory-leak.patch @@ -0,0 +1,55 @@ +From cc6d63dc50fc695b0e0f6b4dd01517fd53e981c1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 11 Jan 2026 22:06:50 +0530 +Subject: PCI/PTM: Fix pcie_ptm_create_debugfs() memory leak + +From: Aadityarangan Shridhar Iyengar + +[ Upstream commit 62171369cf17794ddd88f602c2c84d008ecafcff ] + +In pcie_ptm_create_debugfs(), if devm_kasprintf() fails after successfully +allocating ptm_debugfs with kzalloc(), the function returns without freeing +the allocated memory, resulting in a memory leak. + +Free ptm_debugfs before returning in the devm_kasprintf() error path and in +pcie_ptm_destroy_debugfs(). + +Fixes: 132833405e61 ("PCI: Add debugfs support for exposing PTM context") +Signed-off-by: Aadityarangan Shridhar Iyengar +[bhelgaas: squash additional fix from Mani: +https://lore.kernel.org/r/pdp4xc4d5ee3e547mmdro5riui3mclduqdl7j6iclfbozo2a4c@7m3qdm6yrhuv] +Signed-off-by: Bjorn Helgaas +Reviewed-by: Manivannan Sadhasivam +Link: https://patch.msgid.link/20260111163650.33168-1-adiyenga@cisco.com +Signed-off-by: Sasha Levin +--- + drivers/pci/pcie/ptm.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/pci/pcie/ptm.c b/drivers/pci/pcie/ptm.c +index 65e4b008be00d..41d370f082ee4 100644 +--- a/drivers/pci/pcie/ptm.c ++++ b/drivers/pci/pcie/ptm.c +@@ -519,8 +519,10 @@ struct pci_ptm_debugfs *pcie_ptm_create_debugfs(struct device *dev, void *pdata, + return NULL; + + dirname = devm_kasprintf(dev, GFP_KERNEL, "pcie_ptm_%s", dev_name(dev)); +- if (!dirname) ++ if (!dirname) { ++ kfree(ptm_debugfs); + return NULL; ++ } + + ptm_debugfs->debugfs = debugfs_create_dir(dirname, NULL); + ptm_debugfs->pdata = pdata; +@@ -551,6 +553,7 @@ void pcie_ptm_destroy_debugfs(struct pci_ptm_debugfs *ptm_debugfs) + + mutex_destroy(&ptm_debugfs->lock); + debugfs_remove_recursive(ptm_debugfs->debugfs); ++ kfree(ptm_debugfs); + } + EXPORT_SYMBOL_GPL(pcie_ptm_destroy_debugfs); + #endif +-- +2.51.0 + diff --git a/queue-6.18/pci-remove-old_size-limit-from-bridge-window-sizing.patch b/queue-6.18/pci-remove-old_size-limit-from-bridge-window-sizing.patch new file mode 100644 index 0000000000..c85dc5b037 --- /dev/null +++ b/queue-6.18/pci-remove-old_size-limit-from-bridge-window-sizing.patch @@ -0,0 +1,117 @@ +From be54e24925f8ddaea301d2fe250c5a34180f7dbe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 19 Dec 2025 19:40:18 +0200 +Subject: PCI: Remove old_size limit from bridge window sizing +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ilpo Järvinen + +[ Upstream commit f909e3ee3ed1a44202f09ac7e637a0f9ec372225 ] + +calculate_memsize() applies lower bound to the resource size before +aligning the resource size making it impossible to shrink bridge window +resources. I've not found any justification for this lower bound and +nothing indicated it was to work around some HW issue. + +Prior to the commit 3baeae36039a ("PCI: Use pci_release_resource() instead +of release_resource()"), releasing a bridge window during BAR resize +resulted in clearing start and end address of the resource. Clearing +addresses destroys the resource size as a side-effect, therefore nullifying +the effect of the old size lower bound. + +After the commit 3baeae36039a ("PCI: Use pci_release_resource() instead of +release_resource()"), BAR resize uses the aligned old size, which results +in exceeding what fits into the parent window in some cases: + + xe 0030:03:00.0: [drm] Attempting to resize bar from 256MiB -> 16384MiB + xe 0030:03:00.0: BAR 0 [mem 0x620c000000000-0x620c000ffffff 64bit]: releasing + xe 0030:03:00.0: BAR 2 [mem 0x6200000000000-0x620000fffffff 64bit pref]: releasing + pci 0030:02:01.0: bridge window [mem 0x6200000000000-0x620001fffffff 64bit pref]: releasing + pci 0030:01:00.0: bridge window [mem 0x6200000000000-0x6203fbff0ffff 64bit pref]: releasing + pci 0030:00:00.0: bridge window [mem 0x6200000000000-0x6203fbff0ffff 64bit pref]: was not released (still contains assigned resources) + pci 0030:00:00.0: Assigned bridge window [mem 0x6200000000000-0x6203fbff0ffff 64bit pref] to [bus 01-04] free space at [mem 0x6200400000000-0x62007ffffffff 64bit pref] + pci 0030:00:00.0: Assigned bridge window [mem 0x6200000000000-0x6203fbff0ffff 64bit pref] to [bus 01-04] cannot fit 0x4000000000 required for 0030:01:00.0 bridging to [bus 02-04] + +The old size of 0x6200000000000-0x6203fbff0ffff resource was used as the +lower bound which results in 0x4000000000 size request due to alignment. +That exceeds what can fit into the parent window. + +Since the lower bound never even was enforced fully because the resource +addresses were cleared when the bridge window is released, remove the +old_size lower bound entirely and trust the calculated bridge window size +is enough. + +This same problem may occur on io window side but seems less likely to +cause issues due to general difference in alignment. Removing the lower +bound may have other unforeseen consequences in case of io window so it's +better to leave it as -next material if no problem is reported related to +io window sizing (BAR resize shouldn't touch io windows anyway). + +Fixes: 3baeae36039a ("PCI: Use pci_release_resource() instead of release_resource()") +Reported-by: Simon Richter +Link: https://lore.kernel.org/r/f9a8c975-f5d3-4dd2-988e-4371a1433a60@hogyros.de/ +Signed-off-by: Ilpo Järvinen +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20251219174036.16738-6-ilpo.jarvinen@linux.intel.com +Signed-off-by: Sasha Levin +--- + drivers/pci/setup-bus.c | 11 +++-------- + 1 file changed, 3 insertions(+), 8 deletions(-) + +diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c +index 25d6d4d3afc14..4f4890196e63e 100644 +--- a/drivers/pci/setup-bus.c ++++ b/drivers/pci/setup-bus.c +@@ -1066,16 +1066,13 @@ static resource_size_t calculate_memsize(resource_size_t size, + resource_size_t min_size, + resource_size_t add_size, + resource_size_t children_add_size, +- resource_size_t old_size, + resource_size_t align) + { + if (size < min_size) + size = min_size; +- if (old_size == 1) +- old_size = 0; + + size = max(size, add_size) + children_add_size; +- return ALIGN(max(size, old_size), align); ++ return ALIGN(size, align); + } + + resource_size_t __weak pcibios_window_alignment(struct pci_bus *bus, +@@ -1293,7 +1290,6 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type, + resource_size_t children_add_size = 0; + resource_size_t children_add_align = 0; + resource_size_t add_align = 0; +- resource_size_t old_size; + + if (!b_res) + return; +@@ -1359,11 +1355,10 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type, + } + } + +- old_size = resource_size(b_res); + win_align = window_alignment(bus, b_res->flags); + min_align = calculate_head_align(aligns, max_order); + min_align = max(min_align, win_align); +- size0 = calculate_memsize(size, min_size, 0, 0, old_size, win_align); ++ size0 = calculate_memsize(size, min_size, 0, 0, win_align); + + if (size0) { + resource_set_range(b_res, min_align, size0); +@@ -1373,7 +1368,7 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type, + if (realloc_head && (add_size > 0 || children_add_size > 0)) { + add_align = max(min_align, add_align); + size1 = calculate_memsize(size, min_size, add_size, children_add_size, +- old_size, win_align); ++ win_align); + } + + if (!size0 && !size1) { +-- +2.51.0 + diff --git a/queue-6.18/pci-rewrite-bridge-window-head-alignment-function.patch b/queue-6.18/pci-rewrite-bridge-window-head-alignment-function.patch new file mode 100644 index 0000000000..444e9ec599 --- /dev/null +++ b/queue-6.18/pci-rewrite-bridge-window-head-alignment-function.patch @@ -0,0 +1,174 @@ +From 437303b7b629d6c720828f8d0e96dcbd661a2691 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 19 Dec 2025 19:40:15 +0200 +Subject: PCI: Rewrite bridge window head alignment function +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ilpo Järvinen + +[ Upstream commit bc75c8e5071120e919beb39e69f0979cccfdf219 ] + +The calculation of bridge window head alignment is done by +calculate_mem_align() [*]. With the default bridge window alignment, it +is used for both head and tail alignment. + +The selected head alignment does not always result in tight-fitting +resources (gap at d4f00000-d4ffffff): + + d4800000-dbffffff : PCI Bus 0000:06 + d4800000-d48fffff : PCI Bus 0000:07 + d4800000-d4803fff : 0000:07:00.0 + d4800000-d4803fff : nvme + d4900000-d49fffff : PCI Bus 0000:0a + d4900000-d490ffff : 0000:0a:00.0 + d4900000-d490ffff : r8169 + d4910000-d4913fff : 0000:0a:00.0 + d4a00000-d4cfffff : PCI Bus 0000:0b + d4a00000-d4bfffff : 0000:0b:00.0 + d4a00000-d4bfffff : 0000:0b:00.0 + d4c00000-d4c07fff : 0000:0b:00.0 + d4d00000-d4dfffff : PCI Bus 0000:15 + d4d00000-d4d07fff : 0000:15:00.0 + d4d00000-d4d07fff : xhci-hcd + d4e00000-d4efffff : PCI Bus 0000:16 + d4e00000-d4e7ffff : 0000:16:00.0 + d4e80000-d4e803ff : 0000:16:00.0 + d4e80000-d4e803ff : ahci + d5000000-dbffffff : PCI Bus 0000:0c + +This has not caused problems (for years) with the default bridge window +tail alignment that grossly over-estimates the required tail alignment +leaving more tail room than necessary. With the introduction of relaxed +tail alignment that leaves no extra tail room whatsoever, any gaps will +immediately turn into assignment failures. + +Introduce head alignment calculation that ensures no gaps are left and +apply the new approach when using relaxed alignment. We may want to +consider using it for the normal alignment eventually, but as the first +step, solve only the problem with the relaxed tail alignment. + +([*] I don't understand the algorithm in calculate_mem_align().) + +Link: https://git.kernel.org/history/history/c/5d0a8965aea9 ("[PATCH] 2.5.14: New PCI allocation code (alpha, arm, parisc) [2/2]") +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220775 +Reported-by: Malte Schröder +Signed-off-by: Ilpo Järvinen +Signed-off-by: Bjorn Helgaas +Tested-by: Malte Schröder +Cc: stable@vger.kernel.org +Link: https://patch.msgid.link/20251219174036.16738-3-ilpo.jarvinen@linux.intel.com +Stable-dep-of: f909e3ee3ed1 ("PCI: Remove old_size limit from bridge window sizing") +Signed-off-by: Sasha Levin +--- + drivers/pci/setup-bus.c | 53 ++++++++++++++++++++++++++++++++++------- + 1 file changed, 44 insertions(+), 9 deletions(-) + +diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c +index 5ba878f15db35..cd12926a72af7 100644 +--- a/drivers/pci/setup-bus.c ++++ b/drivers/pci/setup-bus.c +@@ -1223,6 +1223,45 @@ static inline resource_size_t calculate_mem_align(resource_size_t *aligns, + return min_align; + } + ++/* ++ * Calculate bridge window head alignment that leaves no gaps in between ++ * resources. ++ */ ++static resource_size_t calculate_head_align(resource_size_t *aligns, ++ int max_order) ++{ ++ resource_size_t head_align = 1; ++ resource_size_t remainder = 0; ++ int order; ++ ++ /* Take the largest alignment as the starting point. */ ++ head_align <<= max_order + __ffs(SZ_1M); ++ ++ for (order = max_order - 1; order >= 0; order--) { ++ resource_size_t align1 = 1; ++ ++ align1 <<= order + __ffs(SZ_1M); ++ ++ /* ++ * Account smaller resources with alignment < max_order that ++ * could be used to fill head room if alignment less than ++ * max_order is used. ++ */ ++ remainder += aligns[order]; ++ ++ /* ++ * Test if head fill is enough to satisfy the alignment of ++ * the larger resources after reducing the alignment. ++ */ ++ while ((head_align > align1) && (remainder >= head_align / 2)) { ++ head_align /= 2; ++ remainder -= head_align; ++ } ++ } ++ ++ return head_align; ++} ++ + /** + * pbus_upstream_space_available - Check no upstream resource limits allocation + * @bus: The bus +@@ -1310,13 +1349,13 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type, + { + struct pci_dev *dev; + resource_size_t min_align, win_align, align, size, size0, size1 = 0; +- resource_size_t aligns[28]; /* Alignments from 1MB to 128TB */ ++ resource_size_t aligns[28] = {}; /* Alignments from 1MB to 128TB */ ++ resource_size_t aligns2[28] = {};/* Alignments from 1MB to 128TB */ + int order, max_order; + struct resource *b_res = pbus_select_window_for_type(bus, type); + resource_size_t children_add_size = 0; + resource_size_t children_add_align = 0; + resource_size_t add_align = 0; +- resource_size_t relaxed_align; + resource_size_t old_size; + + if (!b_res) +@@ -1326,7 +1365,6 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type, + if (b_res->parent) + return; + +- memset(aligns, 0, sizeof(aligns)); + max_order = 0; + size = 0; + +@@ -1377,6 +1415,7 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type, + */ + if (r_size <= align) + aligns[order] += align; ++ aligns2[order] += align; + if (order > max_order) + max_order = order; + +@@ -1401,9 +1440,7 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type, + + if (bus->self && size0 && + !pbus_upstream_space_available(bus, b_res, size0, min_align)) { +- relaxed_align = 1ULL << (max_order + __ffs(SZ_1M)); +- relaxed_align = max(relaxed_align, win_align); +- min_align = min(min_align, relaxed_align); ++ min_align = calculate_head_align(aligns2, max_order); + size0 = calculate_memsize(size, min_size, 0, 0, old_size, win_align); + resource_set_range(b_res, min_align, size0); + pci_info(bus->self, "bridge window %pR to %pR requires relaxed alignment rules\n", +@@ -1417,9 +1454,7 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type, + + if (bus->self && size1 && + !pbus_upstream_space_available(bus, b_res, size1, add_align)) { +- relaxed_align = 1ULL << (max_order + __ffs(SZ_1M)); +- relaxed_align = max(relaxed_align, win_align); +- min_align = min(min_align, relaxed_align); ++ min_align = calculate_head_align(aligns2, max_order); + size1 = calculate_memsize(size, min_size, add_size, children_add_size, + old_size, win_align); + pci_info(bus->self, +-- +2.51.0 + diff --git a/queue-6.18/pci-sophgo-disable-l0s-and-l1-on-sophgo-2044-pcie-ro.patch b/queue-6.18/pci-sophgo-disable-l0s-and-l1-on-sophgo-2044-pcie-ro.patch new file mode 100644 index 0000000000..d0a732cf23 --- /dev/null +++ b/queue-6.18/pci-sophgo-disable-l0s-and-l1-on-sophgo-2044-pcie-ro.patch @@ -0,0 +1,68 @@ +From e7214025778898d5facbd70b6bdb08daa0162842 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 12:07:53 +0800 +Subject: PCI: sophgo: Disable L0s and L1 on Sophgo 2044 PCIe Root Ports + +From: Inochi Amaoto + +[ Upstream commit 613f3255a35a95f52575dd8c60b7ac9d711639ce ] + +Sophgo 2044 Root Ports advertise L0 and L1 capabilities without supporting +them. Since commit f3ac2ff14834 ("PCI/ASPM: Enable all ClockPM and ASPM +states for devicetree platforms") force enabled ASPM on all device tree +platforms, the issue became evident and the SG2044 Root Port started +breaking. + +Hence, disable the L0s and L1 capabilities in the LINKCAP register for the +SG2044 Root Ports, so that these states won't get enabled. + +Fixes: 467d9c0348d6 ("PCI: dwc: Add Sophgo SG2044 PCIe controller driver in Root Complex mode") +Signed-off-by: Inochi Amaoto +[mani: reworded description and corrected fixes tag] +Signed-off-by: Manivannan Sadhasivam +Tested-by: Han Gao +Link: https://patch.msgid.link/20260109040756.731169-1-inochiama@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-sophgo.c | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/drivers/pci/controller/dwc/pcie-sophgo.c b/drivers/pci/controller/dwc/pcie-sophgo.c +index ad4baaa34ffa1..044088898819e 100644 +--- a/drivers/pci/controller/dwc/pcie-sophgo.c ++++ b/drivers/pci/controller/dwc/pcie-sophgo.c +@@ -161,6 +161,22 @@ static void sophgo_pcie_msi_enable(struct dw_pcie_rp *pp) + raw_spin_unlock_irqrestore(&pp->lock, flags); + } + ++static void sophgo_pcie_disable_l0s_l1(struct dw_pcie_rp *pp) ++{ ++ struct dw_pcie *pci = to_dw_pcie_from_pp(pp); ++ u32 offset, val; ++ ++ offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); ++ ++ dw_pcie_dbi_ro_wr_en(pci); ++ ++ val = dw_pcie_readl_dbi(pci, PCI_EXP_LNKCAP + offset); ++ val &= ~(PCI_EXP_LNKCAP_ASPM_L0S | PCI_EXP_LNKCAP_ASPM_L1); ++ dw_pcie_writel_dbi(pci, PCI_EXP_LNKCAP + offset, val); ++ ++ dw_pcie_dbi_ro_wr_dis(pci); ++} ++ + static int sophgo_pcie_host_init(struct dw_pcie_rp *pp) + { + int irq; +@@ -171,6 +187,8 @@ static int sophgo_pcie_host_init(struct dw_pcie_rp *pp) + + irq_set_chained_handler_and_data(irq, sophgo_pcie_intx_handler, pp); + ++ sophgo_pcie_disable_l0s_l1(pp); ++ + sophgo_pcie_msi_enable(pp); + + return 0; +-- +2.51.0 + diff --git a/queue-6.18/pci-stop-over-estimating-bridge-window-size.patch b/queue-6.18/pci-stop-over-estimating-bridge-window-size.patch new file mode 100644 index 0000000000..47497a64fd --- /dev/null +++ b/queue-6.18/pci-stop-over-estimating-bridge-window-size.patch @@ -0,0 +1,173 @@ +From 309a3189955a334d9a51145338734b83ab64539e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 19 Dec 2025 19:40:16 +0200 +Subject: PCI: Stop over-estimating bridge window size +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ilpo Järvinen + +[ Upstream commit 3958bf16e2fe1b1c95467e58694102122c951a31 ] + +New way to calculate the bridge window head alignment produces tight-fit, +that is, it does not leave any gaps between the resources. Similarly, +relaxed tail alignment does not leave extra tail room. + +Start to use bridge window calculation that does not over-estimate the size +of the required window. + +pbus_upstream_space_available() can be removed. + +Signed-off-by: Ilpo Järvinen +Signed-off-by: Bjorn Helgaas +Tested-by: Malte Schröder +Link: https://patch.msgid.link/20251219174036.16738-4-ilpo.jarvinen@linux.intel.com +Stable-dep-of: f909e3ee3ed1 ("PCI: Remove old_size limit from bridge window sizing") +Signed-off-by: Sasha Levin +--- + drivers/pci/setup-bus.c | 97 +++-------------------------------------- + 1 file changed, 5 insertions(+), 92 deletions(-) + +diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c +index cd12926a72af7..25d6d4d3afc14 100644 +--- a/drivers/pci/setup-bus.c ++++ b/drivers/pci/setup-bus.c +@@ -1262,68 +1262,6 @@ static resource_size_t calculate_head_align(resource_size_t *aligns, + return head_align; + } + +-/** +- * pbus_upstream_space_available - Check no upstream resource limits allocation +- * @bus: The bus +- * @res: The resource to help select the correct bridge window +- * @size: The size required from the bridge window +- * @align: Required alignment for the resource +- * +- * Check that @size can fit inside the upstream bridge resources that are +- * already assigned. Select the upstream bridge window based on the type of +- * @res. +- * +- * Return: %true if enough space is available on all assigned upstream +- * resources. +- */ +-static bool pbus_upstream_space_available(struct pci_bus *bus, +- struct resource *res, +- resource_size_t size, +- resource_size_t align) +-{ +- struct resource_constraint constraint = { +- .max = RESOURCE_SIZE_MAX, +- .align = align, +- }; +- struct pci_bus *downstream = bus; +- +- while ((bus = bus->parent)) { +- if (pci_is_root_bus(bus)) +- break; +- +- res = pbus_select_window(bus, res); +- if (!res) +- return false; +- if (!res->parent) +- continue; +- +- if (resource_size(res) >= size) { +- struct resource gap = {}; +- +- if (find_resource_space(res, &gap, size, &constraint) == 0) { +- gap.flags = res->flags; +- pci_dbg(bus->self, +- "Assigned bridge window %pR to %pR free space at %pR\n", +- res, &bus->busn_res, &gap); +- return true; +- } +- } +- +- if (bus->self) { +- pci_info(bus->self, +- "Assigned bridge window %pR to %pR cannot fit 0x%llx required for %s bridging to %pR\n", +- res, &bus->busn_res, +- (unsigned long long)size, +- pci_name(downstream->self), +- &downstream->busn_res); +- } +- +- return false; +- } +- +- return true; +-} +- + /** + * pbus_size_mem() - Size the memory window of a given bus + * +@@ -1350,7 +1288,6 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type, + struct pci_dev *dev; + resource_size_t min_align, win_align, align, size, size0, size1 = 0; + resource_size_t aligns[28] = {}; /* Alignments from 1MB to 128TB */ +- resource_size_t aligns2[28] = {};/* Alignments from 1MB to 128TB */ + int order, max_order; + struct resource *b_res = pbus_select_window_for_type(bus, type); + resource_size_t children_add_size = 0; +@@ -1409,13 +1346,8 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type, + continue; + } + size += max(r_size, align); +- /* +- * Exclude ranges with size > align from calculation of +- * the alignment. +- */ +- if (r_size <= align) +- aligns[order] += align; +- aligns2[order] += align; ++ ++ aligns[order] += align; + if (order > max_order) + max_order = order; + +@@ -1429,38 +1361,19 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type, + + old_size = resource_size(b_res); + win_align = window_alignment(bus, b_res->flags); +- min_align = calculate_mem_align(aligns, max_order); ++ min_align = calculate_head_align(aligns, max_order); + min_align = max(min_align, win_align); +- size0 = calculate_memsize(size, min_size, 0, 0, old_size, min_align); ++ size0 = calculate_memsize(size, min_size, 0, 0, old_size, win_align); + + if (size0) { + resource_set_range(b_res, min_align, size0); + b_res->flags &= ~IORESOURCE_DISABLED; + } + +- if (bus->self && size0 && +- !pbus_upstream_space_available(bus, b_res, size0, min_align)) { +- min_align = calculate_head_align(aligns2, max_order); +- size0 = calculate_memsize(size, min_size, 0, 0, old_size, win_align); +- resource_set_range(b_res, min_align, size0); +- pci_info(bus->self, "bridge window %pR to %pR requires relaxed alignment rules\n", +- b_res, &bus->busn_res); +- } +- + if (realloc_head && (add_size > 0 || children_add_size > 0)) { + add_align = max(min_align, add_align); + size1 = calculate_memsize(size, min_size, add_size, children_add_size, +- old_size, add_align); +- +- if (bus->self && size1 && +- !pbus_upstream_space_available(bus, b_res, size1, add_align)) { +- min_align = calculate_head_align(aligns2, max_order); +- size1 = calculate_memsize(size, min_size, add_size, children_add_size, +- old_size, win_align); +- pci_info(bus->self, +- "bridge window %pR to %pR requires relaxed alignment rules\n", +- b_res, &bus->busn_res); +- } ++ old_size, win_align); + } + + if (!size0 && !size1) { +-- +2.51.0 + diff --git a/queue-6.18/pci-xilinx-fix-intx-irq-domain-leak-in-error-paths.patch b/queue-6.18/pci-xilinx-fix-intx-irq-domain-leak-in-error-paths.patch new file mode 100644 index 0000000000..8fe1eb8a59 --- /dev/null +++ b/queue-6.18/pci-xilinx-fix-intx-irq-domain-leak-in-error-paths.patch @@ -0,0 +1,70 @@ +From 9d74adbb5af66b72e4a38abb06498cbdf34d5da7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 19 Dec 2025 10:16:15 +0800 +Subject: PCI: xilinx: Fix INTx IRQ domain leak in error paths + +From: Haotian Zhang + +[ Upstream commit f42b3c053b1554d66af6fe45bb1ef357464c0456 ] + +In xilinx_pcie_init_irq_domain(), if xilinx_allocate_msi_domains() fails +after pcie->leg_domain has been successfully created via +irq_domain_create_linear(), the function returns directly without cleaning +up the allocated IRQ domain, resulting in a resource leak. In +xilinx_free_msi_domains(), pcie->leg_domain is also neglected. + +Add irq_domain_remove() call in the error path to properly release the +IRQ domain before returning the error. Also rename +xilinx_free_msi_domains() to xilinx_free_irq_domains() and add the release +of pcie->leg_domain to it. + +Fixes: 313b64c3ae52 ("PCI: xilinx: Convert to MSI domains") +Suggested-by: Manivannan Sadhasivam +Signed-off-by: Haotian Zhang +Signed-off-by: Manivannan Sadhasivam +Link: https://patch.msgid.link/20251219021615.965-1-vulab@iscas.ac.cn +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/pcie-xilinx.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/drivers/pci/controller/pcie-xilinx.c b/drivers/pci/controller/pcie-xilinx.c +index 937ea6ae1ac48..4aa139abac16e 100644 +--- a/drivers/pci/controller/pcie-xilinx.c ++++ b/drivers/pci/controller/pcie-xilinx.c +@@ -302,9 +302,10 @@ static int xilinx_allocate_msi_domains(struct xilinx_pcie *pcie) + return 0; + } + +-static void xilinx_free_msi_domains(struct xilinx_pcie *pcie) ++static void xilinx_free_irq_domains(struct xilinx_pcie *pcie) + { + irq_domain_remove(pcie->msi_domain); ++ irq_domain_remove(pcie->leg_domain); + } + + /* INTx Functions */ +@@ -480,8 +481,10 @@ static int xilinx_pcie_init_irq_domain(struct xilinx_pcie *pcie) + phys_addr_t pa = ALIGN_DOWN(virt_to_phys(pcie), SZ_4K); + + ret = xilinx_allocate_msi_domains(pcie); +- if (ret) ++ if (ret) { ++ irq_domain_remove(pcie->leg_domain); + return ret; ++ } + + pcie_write(pcie, upper_32_bits(pa), XILINX_PCIE_REG_MSIBASE1); + pcie_write(pcie, lower_32_bits(pa), XILINX_PCIE_REG_MSIBASE2); +@@ -600,7 +603,7 @@ static int xilinx_pcie_probe(struct platform_device *pdev) + + err = pci_host_probe(bridge); + if (err) +- xilinx_free_msi_domains(pcie); ++ xilinx_free_irq_domains(pcie); + + return err; + } +-- +2.51.0 + diff --git a/queue-6.18/perf-arm_spe-properly-set-hw.state-on-failures.patch b/queue-6.18/perf-arm_spe-properly-set-hw.state-on-failures.patch new file mode 100644 index 0000000000..9b13e1b9e8 --- /dev/null +++ b/queue-6.18/perf-arm_spe-properly-set-hw.state-on-failures.patch @@ -0,0 +1,108 @@ +From 49cfa6baab155667378ffab63fb718f7432bc501 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 14:40:43 +0000 +Subject: perf: arm_spe: Properly set hw.state on failures + +From: Leo Yan + +[ Upstream commit 283182c1c239f6873d1a50e9e710c1a699f2256b ] + +When arm_spe_pmu_next_off() fails to calculate a valid limit, it returns +zero to indicate that tracing should not start. However, the caller +arm_spe_perf_aux_output_begin() does not propagate this failure by +updating hwc->state, cause the error to be silently ignored by upper +layers. + +Because hwc->state remains zero after a failure, arm_spe_pmu_start() +continues to programs filter registers unnecessarily. The driver +still reports success to the perf core, so the core assumes the SPE +event was enabled and proceeds to enable other events. This breaks +event group semantics: SPE is already stopped while other events in the +same group are enabled. + +Fix this by updating arm_spe_perf_aux_output_begin() to return a status +code indicating success (0) or failure (-EIO). Both the interrupt +handler and arm_spe_pmu_start() check the return value and call +arm_spe_pmu_stop() to set PERF_HES_STOPPED in hwc->state. + +In the interrupt handler, the period (e.g., period_left) needs to be +updated, so PERF_EF_UPDATE is passed to arm_spe_pmu_stop(). When the +error occurs during event start, the trace unit is not yet enabled, so +a flag '0' is used to drain buffer and update state only. + +Fixes: d5d9696b0380 ("drivers/perf: Add support for ARMv8.2 Statistical Profiling Extension") +Signed-off-by: Leo Yan +Signed-off-by: Will Deacon +Signed-off-by: Sasha Levin +--- + drivers/perf/arm_spe_pmu.c | 18 ++++++++++++------ + 1 file changed, 12 insertions(+), 6 deletions(-) + +diff --git a/drivers/perf/arm_spe_pmu.c b/drivers/perf/arm_spe_pmu.c +index fa50645feddad..e4e4e63c64c42 100644 +--- a/drivers/perf/arm_spe_pmu.c ++++ b/drivers/perf/arm_spe_pmu.c +@@ -105,6 +105,8 @@ struct arm_spe_pmu { + /* Keep track of our dynamic hotplug state */ + static enum cpuhp_state arm_spe_pmu_online; + ++static void arm_spe_pmu_stop(struct perf_event *event, int flags); ++ + enum arm_spe_pmu_buf_fault_action { + SPE_PMU_BUF_FAULT_ACT_SPURIOUS, + SPE_PMU_BUF_FAULT_ACT_FATAL, +@@ -582,8 +584,8 @@ static u64 arm_spe_pmu_next_off(struct perf_output_handle *handle) + return limit; + } + +-static void arm_spe_perf_aux_output_begin(struct perf_output_handle *handle, +- struct perf_event *event) ++static int arm_spe_perf_aux_output_begin(struct perf_output_handle *handle, ++ struct perf_event *event) + { + u64 base, limit; + struct arm_spe_pmu_buf *buf; +@@ -597,7 +599,6 @@ static void arm_spe_perf_aux_output_begin(struct perf_output_handle *handle, + /* Start a new aux session */ + buf = perf_aux_output_begin(handle, event); + if (!buf) { +- event->hw.state |= PERF_HES_STOPPED; + /* + * We still need to clear the limit pointer, since the + * profiler might only be disabled by virtue of a fault. +@@ -617,6 +618,7 @@ static void arm_spe_perf_aux_output_begin(struct perf_output_handle *handle, + + out_write_limit: + write_sysreg_s(limit, SYS_PMBLIMITR_EL1); ++ return (limit & PMBLIMITR_EL1_E) ? 0 : -EIO; + } + + static void arm_spe_perf_aux_output_end(struct perf_output_handle *handle) +@@ -756,7 +758,10 @@ static irqreturn_t arm_spe_pmu_irq_handler(int irq, void *dev) + * when we get to it. + */ + if (!(handle->aux_flags & PERF_AUX_FLAG_TRUNCATED)) { +- arm_spe_perf_aux_output_begin(handle, event); ++ if (arm_spe_perf_aux_output_begin(handle, event)) { ++ arm_spe_pmu_stop(event, PERF_EF_UPDATE); ++ break; ++ } + isb(); + } + break; +@@ -851,9 +856,10 @@ static void arm_spe_pmu_start(struct perf_event *event, int flags) + struct perf_output_handle *handle = this_cpu_ptr(spe_pmu->handle); + + hwc->state = 0; +- arm_spe_perf_aux_output_begin(handle, event); +- if (hwc->state) ++ if (arm_spe_perf_aux_output_begin(handle, event)) { ++ arm_spe_pmu_stop(event, 0); + return; ++ } + + reg = arm_spe_event_to_pmsfcr(event); + write_sysreg_s(reg, SYS_PMSFCR_EL1); +-- +2.51.0 + diff --git a/queue-6.18/perf-x86-core-do-not-set-bit-width-for-unavailable-c.patch b/queue-6.18/perf-x86-core-do-not-set-bit-width-for-unavailable-c.patch new file mode 100644 index 0000000000..81b6c10da2 --- /dev/null +++ b/queue-6.18/perf-x86-core-do-not-set-bit-width-for-unavailable-c.patch @@ -0,0 +1,46 @@ +From 3856659f76b719182ddcfd536ba3d476dd56e1dd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Dec 2025 16:16:46 -0800 +Subject: perf/x86/core: Do not set bit width for unavailable counters + +From: Sandipan Das + +[ Upstream commit b456a6ba5756b6fb7e651775343e713bd08418e7 ] + +Not all x86 processors have fixed counters. It may also be the case that +a processor has only fixed counters and no general-purpose counters. Set +the bit widths corresponding to each counter type only if such counters +are available. + +Fixes: b3d9468a8bd2 ("perf, x86: Expose perf capability to other modules") +Signed-off-by: Sandipan Das +Co-developed-by: Dapeng Mi +Signed-off-by: Dapeng Mi +Signed-off-by: Mingwei Zhang +Signed-off-by: Sean Christopherson +Signed-off-by: Peter Zijlstra (Intel) +Tested-by: Xudong Hao +Link: https://patch.msgid.link/20251206001720.468579-11-seanjc@google.com +Signed-off-by: Sasha Levin +--- + arch/x86/events/core.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c +index dd9ff120ad437..56df4855f38e9 100644 +--- a/arch/x86/events/core.c ++++ b/arch/x86/events/core.c +@@ -3101,8 +3101,8 @@ void perf_get_x86_pmu_capability(struct x86_pmu_capability *cap) + cap->version = x86_pmu.version; + cap->num_counters_gp = x86_pmu_num_counters(NULL); + cap->num_counters_fixed = x86_pmu_num_counters_fixed(NULL); +- cap->bit_width_gp = x86_pmu.cntval_bits; +- cap->bit_width_fixed = x86_pmu.cntval_bits; ++ cap->bit_width_gp = cap->num_counters_gp ? x86_pmu.cntval_bits : 0; ++ cap->bit_width_fixed = cap->num_counters_fixed ? x86_pmu.cntval_bits : 0; + cap->events_mask = (unsigned int)x86_pmu.events_maskl; + cap->events_mask_len = x86_pmu.events_mask_len; + cap->pebs_ept = x86_pmu.pebs_ept; +-- +2.51.0 + diff --git a/queue-6.18/phy-freescale-imx8qm-hsio-fix-null-pointer-dereferen.patch b/queue-6.18/phy-freescale-imx8qm-hsio-fix-null-pointer-dereferen.patch new file mode 100644 index 0000000000..b8b6116985 --- /dev/null +++ b/queue-6.18/phy-freescale-imx8qm-hsio-fix-null-pointer-dereferen.patch @@ -0,0 +1,41 @@ +From 33d23ac0650bf77bc04da5a7402ac260de8d524e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 17:50:23 +0100 +Subject: phy: freescale: imx8qm-hsio: fix NULL pointer dereference + +From: Thomas Richard + +[ Upstream commit 4dd5d4c0361af0a3fd24f45c815996abf4429770 ] + +During the probe the refclk_pad pointer is set to NULL if the +'fsl,refclk-pad-mode' property is not defined in the devicetree node. But +in imx_hsio_configure_clk_pad() this pointer is unconditionally used which +could result in a NULL pointer dereference. So check the pointer before to +use it. + +Fixes: 82c56b6dd24f ("phy: freescale: imx8qm-hsio: Add i.MX8QM HSIO PHY driver support") +Signed-off-by: Thomas Richard +Reviewed-by: Richard Zhu +Link: https://patch.msgid.link/20260114-phy-fsl-imx8qm-hsio-fix-null-pointer-dereference-v1-1-730e941be464@bootlin.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/phy/freescale/phy-fsl-imx8qm-hsio.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/phy/freescale/phy-fsl-imx8qm-hsio.c b/drivers/phy/freescale/phy-fsl-imx8qm-hsio.c +index 977d21d753a59..279b8ac7822df 100644 +--- a/drivers/phy/freescale/phy-fsl-imx8qm-hsio.c ++++ b/drivers/phy/freescale/phy-fsl-imx8qm-hsio.c +@@ -251,7 +251,7 @@ static void imx_hsio_configure_clk_pad(struct phy *phy) + struct imx_hsio_lane *lane = phy_get_drvdata(phy); + struct imx_hsio_priv *priv = lane->priv; + +- if (strncmp(priv->refclk_pad, "output", 6) == 0) { ++ if (priv->refclk_pad && strncmp(priv->refclk_pad, "output", 6) == 0) { + pll = true; + regmap_update_bits(priv->misc, HSIO_CTRL0, + HSIO_IOB_A_0_TXOE | HSIO_IOB_A_0_M1M0_MASK, +-- +2.51.0 + diff --git a/queue-6.18/phy-rockchip-samsung-hdptx-pre-compute-hdmi-pll-conf.patch b/queue-6.18/phy-rockchip-samsung-hdptx-pre-compute-hdmi-pll-conf.patch new file mode 100644 index 0000000000..c636c6b1d8 --- /dev/null +++ b/queue-6.18/phy-rockchip-samsung-hdptx-pre-compute-hdmi-pll-conf.patch @@ -0,0 +1,62 @@ +From b32e7694f37dbc3c6f22d9645168ca48998fb053 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 21 Dec 2025 12:36:23 +0200 +Subject: phy: rockchip: samsung-hdptx: Pre-compute HDMI PLL config for + 461.10125 MHz output + +From: Cristian Ciocaltea + +[ Upstream commit f2daf0c67a1767ff6536aa3e96599afb42ca42e7 ] + +Attempting to make use of a 1080p@120Hz display mode with 10 bpc RGB on +my Acer XV275K P3 monitor results in a blank image. A similar behavior +has been reported on Philips 279M1RV. + +The faulty modeline is created by drm_gtf_mode_complex() based on the +following EDID entry from the Standard Timings block: + + GTF: 1920x1080 119.999987 Hz 16:9 138.840 kHz 368.759000 MHz + +It's worth noting the computed pixel clock ends up being slightly higher +at 368.881000 MHz. Nevertheless, this seems to work consistently fine +with 8 bpc RGB. + +After switching to 10 bpc, the TMDS character rate expected for the mode +increases to 461.101250 MHz, as per drm_hdmi_compute_mode_clock(). + +Since there is no entry for this rate in the ropll_tmds_cfg table, the +necessary HDMI PLL configuration parameters are calculated dynamically +by rk_hdptx_phy_clk_pll_calc(). However, the resulting output rate is +not quite a perfect match, i.e. 461.100000 MHz. That proved to be the +actual root cause of the problem. + +Add a new entry to the TMDS configuration table and provide the +necessary frequency division coefficients for the PHY PLL to generate +the expected 461.101250 MHz output. + +Fixes: 9d0ec51d7c22 ("phy: rockchip: samsung-hdptx: Add high color depth management") +Tested-by: Derek Foreman +Signed-off-by: Cristian Ciocaltea +Link: https://patch.msgid.link/20251221-phy-hdptx-pll-fix-v2-1-ae4abf7f75a1@collabora.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c +index 29de2f7bdae8a..cafa618d70fdc 100644 +--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c ++++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c +@@ -414,6 +414,8 @@ struct rk_hdptx_phy { + static const struct ropll_config ropll_tmds_cfg[] = { + { 594000000ULL, 124, 124, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, ++ { 461101250ULL, 97, 97, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 71, 1, 53, 2, 6, ++ 35, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 371250000ULL, 155, 155, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 297000000ULL, 124, 124, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, +-- +2.51.0 + diff --git a/queue-6.18/pidfs-return-eremote-when-pidfd_get_info-is-called-o.patch b/queue-6.18/pidfs-return-eremote-when-pidfd_get_info-is-called-o.patch new file mode 100644 index 0000000000..5e536556b7 --- /dev/null +++ b/queue-6.18/pidfs-return-eremote-when-pidfd_get_info-is-called-o.patch @@ -0,0 +1,47 @@ +From d2181eaed02aeba184c2cdd246116702d3ba45be Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 22:51:37 +0000 +Subject: pidfs: return -EREMOTE when PIDFD_GET_INFO is called on another ns + +From: Luca Boccassi + +[ Upstream commit ab89060fbc92edd6e852bf0f533f29140afabe0e ] + +Currently it is not possible to distinguish between the case where a +process has already exited and the case where a process is in a +different namespace, as both return -ESRCH. +glibc's pidfd_getpid() procfs-based implementation returns -EREMOTE +in the latter, so that distinguishing the two is possible, as the +fdinfo in procfs will list '0' as the PID in that case: + +https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/pidfd_getpid.c;h=860829cf07da2267484299ccb02861822c0d07b4;hb=HEAD#l121 + +Change the error code so that the kernel also returns -EREMOTE in +that case. + +Fixes: 7477d7dce48a ("pidfs: allow to retrieve exit information") + +Signed-off-by: Luca Boccassi +Link: https://patch.msgid.link/20260127225209.2293342-1-luca.boccassi@gmail.com +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/pidfs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/pidfs.c b/fs/pidfs.c +index f4d7dac1b4494..34987fcdd9a87 100644 +--- a/fs/pidfs.c ++++ b/fs/pidfs.c +@@ -321,7 +321,7 @@ static long pidfd_info(struct file *file, unsigned int cmd, unsigned long arg) + * namespace hierarchy. + */ + if (!pid_in_current_pidns(pid)) +- return -ESRCH; ++ return -EREMOTE; + + attr = READ_ONCE(pid->attr); + if (mask & PIDFD_INFO_EXIT) { +-- +2.51.0 + diff --git a/queue-6.18/pinctrl-canaan-k230-fix-null-pointer-dereference-whe.patch b/queue-6.18/pinctrl-canaan-k230-fix-null-pointer-dereference-whe.patch new file mode 100644 index 0000000000..1e56262705 --- /dev/null +++ b/queue-6.18/pinctrl-canaan-k230-fix-null-pointer-dereference-whe.patch @@ -0,0 +1,76 @@ +From 38b2f1a7a563d08e024c1cb126cf1ec1d866b940 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 28 Dec 2025 23:49:47 +0800 +Subject: pinctrl: canaan: k230: Fix NULL pointer dereference when parsing + devicetree + +From: Jiayu Du + +[ Upstream commit d8c128fb6c2277d95f3f6a4ce28b82c8370031f6 ] + +When probing the k230 pinctrl driver, the kernel triggers a NULL pointer +dereference. The crash trace showed: +[ 0.732084] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000068 +[ 0.740737] ... +[ 0.776296] epc : k230_pinctrl_probe+0x1be/0x4fc + +In k230_pinctrl_parse_functions(), we attempt to retrieve the device +pointer via info->pctl_dev->dev, but info->pctl_dev is only initialized +after k230_pinctrl_parse_dt() completes. + +At the time of DT parsing, info->pctl_dev is still NULL, leading to +the invalid dereference of info->pctl_dev->dev. + +Use the already available device pointer from platform_device +instead of accessing through uninitialized pctl_dev. + +Fixes: d94a32ac688f ("pinctrl: canaan: k230: Fix order of DT parse and pinctrl register") +Signed-off-by: Jiayu Du +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-k230.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/pinctrl/pinctrl-k230.c b/drivers/pinctrl/pinctrl-k230.c +index d716f23d837f7..20f7c0f70eb77 100644 +--- a/drivers/pinctrl/pinctrl-k230.c ++++ b/drivers/pinctrl/pinctrl-k230.c +@@ -65,6 +65,7 @@ struct k230_pmx_func { + }; + + struct k230_pinctrl { ++ struct device *dev; + struct pinctrl_desc pctl; + struct pinctrl_dev *pctl_dev; + struct regmap *regmap_base; +@@ -470,7 +471,7 @@ static int k230_pinctrl_parse_groups(struct device_node *np, + struct k230_pinctrl *info, + unsigned int index) + { +- struct device *dev = info->pctl_dev->dev; ++ struct device *dev = info->dev; + const __be32 *list; + int size, i, ret; + +@@ -511,7 +512,7 @@ static int k230_pinctrl_parse_functions(struct device_node *np, + struct k230_pinctrl *info, + unsigned int index) + { +- struct device *dev = info->pctl_dev->dev; ++ struct device *dev = info->dev; + struct k230_pmx_func *func; + struct k230_pin_group *grp; + static unsigned int idx, i; +@@ -596,6 +597,8 @@ static int k230_pinctrl_probe(struct platform_device *pdev) + if (!info) + return -ENOMEM; + ++ info->dev = dev; ++ + pctl = &info->pctl; + + pctl->name = "k230-pinctrl"; +-- +2.51.0 + diff --git a/queue-6.18/pinctrl-equilibrium-fix-device-node-reference-leak-i.patch b/queue-6.18/pinctrl-equilibrium-fix-device-node-reference-leak-i.patch new file mode 100644 index 0000000000..9d3c0f52a7 --- /dev/null +++ b/queue-6.18/pinctrl-equilibrium-fix-device-node-reference-leak-i.patch @@ -0,0 +1,44 @@ +From 44ab18d3a371d5e31d63f7231b7bc003d9e67bd7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 01:30:07 +0800 +Subject: pinctrl: equilibrium: Fix device node reference leak in + pinbank_init() + +From: Felix Gu + +[ Upstream commit c0b4a4feeb43305a754893d8d9c6b2b5a52d45ac ] + +When calling of_parse_phandle_with_fixed_args(), the caller is +responsible to call of_node_put() to release the reference of device +node. + +In pinbank_init(), the reference of the node obtained from the +"gpio-ranges" property is never released, resulting in a reference +count leak. + +Add the missing of_node_put() call to fix the leak. + +Fixes: 1948d5c51dba ("pinctrl: Add pinmux & GPIO controller driver for a new SoC") +Signed-off-by: Felix Gu +Acked-by: Andy Shevchenko +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-equilibrium.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/pinctrl/pinctrl-equilibrium.c b/drivers/pinctrl/pinctrl-equilibrium.c +index 2d04829b29c99..48b55c5bf8d4f 100644 +--- a/drivers/pinctrl/pinctrl-equilibrium.c ++++ b/drivers/pinctrl/pinctrl-equilibrium.c +@@ -846,6 +846,7 @@ static int pinbank_init(struct device_node *np, + + bank->pin_base = spec.args[1]; + bank->nr_pins = spec.args[2]; ++ of_node_put(spec.np); + + bank->aval_pinmap = readl(bank->membase + REG_AVAIL); + bank->id = id; +-- +2.51.0 + diff --git a/queue-6.18/pinctrl-meson-amlogic-a4-fix-device-node-reference-l.patch b/queue-6.18/pinctrl-meson-amlogic-a4-fix-device-node-reference-l.patch new file mode 100644 index 0000000000..143791d666 --- /dev/null +++ b/queue-6.18/pinctrl-meson-amlogic-a4-fix-device-node-reference-l.patch @@ -0,0 +1,57 @@ +From a748d0815cb9b44bea433cab24ac8466ae3876e9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 02:23:12 +0800 +Subject: pinctrl: meson: amlogic-a4: Fix device node reference leak in bank + helpers + +From: Felix Gu + +[ Upstream commit e56aa18eba32fb68ac5e19e44670010095bb189c ] + +of_parse_phandle_with_fixed_args() increments the reference count of the +returned device node, so it must be explicitly released using +of_node_put() after use. + +Fix the reference leak in aml_bank_pins() and aml_bank_number() by +adding the missing of_node_put() calls. + +Fixes: 6e9be3abb78c ("pinctrl: Add driver support for Amlogic SoCs") +Signed-off-by: Felix Gu +Reviewed-by: Xianwei Zhao +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/meson/pinctrl-amlogic-a4.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/drivers/pinctrl/meson/pinctrl-amlogic-a4.c b/drivers/pinctrl/meson/pinctrl-amlogic-a4.c +index d9e3a8d5932a8..f05d8261624a4 100644 +--- a/drivers/pinctrl/meson/pinctrl-amlogic-a4.c ++++ b/drivers/pinctrl/meson/pinctrl-amlogic-a4.c +@@ -725,8 +725,9 @@ static u32 aml_bank_pins(struct device_node *np) + if (of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, + 0, &of_args)) + return 0; +- else +- return of_args.args[2]; ++ ++ of_node_put(of_args.np); ++ return of_args.args[2]; + } + + static int aml_bank_number(struct device_node *np) +@@ -736,8 +737,9 @@ static int aml_bank_number(struct device_node *np) + if (of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, + 0, &of_args)) + return -EINVAL; +- else +- return of_args.args[1] >> 8; ++ ++ of_node_put(of_args.np); ++ return of_args.args[1] >> 8; + } + + static unsigned int aml_count_pins(struct device_node *np) +-- +2.51.0 + diff --git a/queue-6.18/pinctrl-qcom-sm8250-lpass-lpi-fix-i2s2_data_groups-d.patch b/queue-6.18/pinctrl-qcom-sm8250-lpass-lpi-fix-i2s2_data_groups-d.patch new file mode 100644 index 0000000000..b9ba6d5b47 --- /dev/null +++ b/queue-6.18/pinctrl-qcom-sm8250-lpass-lpi-fix-i2s2_data_groups-d.patch @@ -0,0 +1,38 @@ +From 4a7a26dfb24b8b6324c84a68be3f78451fd82579 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 12:22:28 +0100 +Subject: pinctrl: qcom: sm8250-lpass-lpi: Fix i2s2_data_groups definition + +From: Luca Weiss + +[ Upstream commit eabf273c8466af3f033473c2d2267a6ea7946d57 ] + +The i2s2_data function is available on both gpio12 and gpio13. Fix the +groups definition. + +Fixes: 6e261d1090d6 ("pinctrl: qcom: Add sm8250 lpass lpi pinctrl driver") +Signed-off-by: Luca Weiss +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c +index 64494a86490e2..c27452eece3e6 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c ++++ b/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c +@@ -73,7 +73,7 @@ static const char * const i2s1_ws_groups[] = { "gpio7" }; + static const char * const i2s1_data_groups[] = { "gpio8", "gpio9" }; + static const char * const wsa_swr_clk_groups[] = { "gpio10" }; + static const char * const wsa_swr_data_groups[] = { "gpio11" }; +-static const char * const i2s2_data_groups[] = { "gpio12", "gpio12" }; ++static const char * const i2s2_data_groups[] = { "gpio12", "gpio13" }; + + static const struct lpi_pingroup sm8250_groups[] = { + LPI_PINGROUP(0, 0, swr_tx_clk, qua_mi2s_sclk, _, _), +-- +2.51.0 + diff --git a/queue-6.18/pinctrl-single-fix-refcount-leak-in-pcs_add_gpio_fun.patch b/queue-6.18/pinctrl-single-fix-refcount-leak-in-pcs_add_gpio_fun.patch new file mode 100644 index 0000000000..515e347ce8 --- /dev/null +++ b/queue-6.18/pinctrl-single-fix-refcount-leak-in-pcs_add_gpio_fun.patch @@ -0,0 +1,50 @@ +From 3454766c8e869321b28a958083dbf430d83bf0c1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 08:07:35 +0000 +Subject: pinctrl: single: fix refcount leak in pcs_add_gpio_func() + +From: Wei Li + +[ Upstream commit 353353309b0f7afa407df29e455f9d15b5acc296 ] + +of_parse_phandle_with_args() returns a device_node pointer with refcount +incremented in gpiospec.np. The loop iterates through all phandles but +never releases the reference, causing a refcount leak on each iteration. + +Add of_node_put() calls to release the reference after extracting the +needed arguments and on the error path when devm_kzalloc() fails. + +This bug was detected by our static analysis tool and verified by my +code review. + +Fixes: a1a277eb76b3 ("pinctrl: single: create new gpio function range") +Signed-off-by: Wei Li +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-single.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c +index 998f23d6c3179..d85e6c1f63218 100644 +--- a/drivers/pinctrl/pinctrl-single.c ++++ b/drivers/pinctrl/pinctrl-single.c +@@ -1359,6 +1359,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) + } + range = devm_kzalloc(pcs->dev, sizeof(*range), GFP_KERNEL); + if (!range) { ++ of_node_put(gpiospec.np); + ret = -ENOMEM; + break; + } +@@ -1368,6 +1369,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) + mutex_lock(&pcs->mutex); + list_add_tail(&range->node, &pcs->gpiofuncs); + mutex_unlock(&pcs->mutex); ++ of_node_put(gpiospec.np); + } + return ret; + } +-- +2.51.0 + diff --git a/queue-6.18/platform-chrome-cros_ec_lightbar-fix-response-size-i.patch b/queue-6.18/platform-chrome-cros_ec_lightbar-fix-response-size-i.patch new file mode 100644 index 0000000000..5c21ce200b --- /dev/null +++ b/queue-6.18/platform-chrome-cros_ec_lightbar-fix-response-size-i.patch @@ -0,0 +1,43 @@ +From 1dcc3b10bae6508dbe138c12e8eb5392a554f525 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 04:03:35 +0000 +Subject: platform/chrome: cros_ec_lightbar: Fix response size initialization + +From: Tzung-Bi Shih + +[ Upstream commit ec0dd36dbf8b0b209e63d0cd795451fa2203c736 ] + +Commit 1e7913ff5f9f ("platform/chrome: cros_ec_lightbar: Reduce +ligthbar get version command") meant to set smaller values for both +request and response sizes. + +However, it incorrectly assigned the response size to the `result` field +instead of `insize`. Fix it. + +Reported-by: Gwendal Grignou +Closes: https://lore.kernel.org/chrome-platform/CAMHSBOVrrYaB=1nEqZk09VkczCrj=6B-P8Fe29TpPdSDgT2CCQ@mail.gmail.com +Fixes: 1e7913ff5f9f ("platform/chrome: cros_ec_lightbar: Reduce ligthbar get version command") +Link: https://lore.kernel.org/r/20260130040335.361997-1-tzungbi@kernel.org +Reviewed-by: Gwendal Grignou +Signed-off-by: Tzung-Bi Shih +Signed-off-by: Sasha Levin +--- + drivers/platform/chrome/cros_ec_lightbar.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/platform/chrome/cros_ec_lightbar.c b/drivers/platform/chrome/cros_ec_lightbar.c +index 87634f6921b78..6b028615ee245 100644 +--- a/drivers/platform/chrome/cros_ec_lightbar.c ++++ b/drivers/platform/chrome/cros_ec_lightbar.c +@@ -119,7 +119,7 @@ static int get_lightbar_version(struct cros_ec_dev *ec, + param = (struct ec_params_lightbar *)msg->data; + param->cmd = LIGHTBAR_CMD_VERSION; + msg->outsize = sizeof(param->cmd); +- msg->result = sizeof(resp->version); ++ msg->insize = sizeof(resp->version); + ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg); + if (ret < 0 && ret != -EINVAL) { + ret = 0; +-- +2.51.0 + diff --git a/queue-6.18/platform-chrome-cros_typec_switch-don-t-touch-struct.patch b/queue-6.18/platform-chrome-cros_typec_switch-don-t-touch-struct.patch new file mode 100644 index 0000000000..91954cd804 --- /dev/null +++ b/queue-6.18/platform-chrome-cros_typec_switch-don-t-touch-struct.patch @@ -0,0 +1,54 @@ +From af052b99ae661cc313e71e1e791934753975cb63 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 14:12:30 +0100 +Subject: platform/chrome: cros_typec_switch: Don't touch struct + fwnode_handle::dev + +From: Andy Shevchenko + +[ Upstream commit e1adf48853bc715f4deea074932aa1c44eb7abea ] + +The 'dev' field in struct fwnode is special and related to device links, +There no driver should use it for printing messages. Fix incorrect use +of private field. + +Fixes: affc804c44c8 ("platform/chrome: cros_typec_switch: Add switch driver") +Signed-off-by: Andy Shevchenko +Link: https://lore.kernel.org/r/20260120131413.1697891-2-andriy.shevchenko@linux.intel.com +Signed-off-by: Tzung-Bi Shih +Signed-off-by: Sasha Levin +--- + drivers/platform/chrome/cros_typec_switch.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/platform/chrome/cros_typec_switch.c b/drivers/platform/chrome/cros_typec_switch.c +index 8d7c34abb0a12..d8a28d4e51a85 100644 +--- a/drivers/platform/chrome/cros_typec_switch.c ++++ b/drivers/platform/chrome/cros_typec_switch.c +@@ -230,20 +230,20 @@ static int cros_typec_register_switches(struct cros_typec_switch_data *sdata) + + adev = to_acpi_device_node(fwnode); + if (!adev) { +- dev_err(fwnode->dev, "Couldn't get ACPI device handle\n"); ++ dev_err(dev, "Couldn't get ACPI device handle for %pfwP\n", fwnode); + ret = -ENODEV; + goto err_switch; + } + + ret = acpi_evaluate_integer(adev->handle, "_ADR", NULL, &index); + if (ACPI_FAILURE(ret)) { +- dev_err(fwnode->dev, "_ADR wasn't evaluated\n"); ++ dev_err(dev, "_ADR wasn't evaluated for %pfwP\n", fwnode); + ret = -ENODATA; + goto err_switch; + } + + if (index >= EC_USB_PD_MAX_PORTS) { +- dev_err(fwnode->dev, "Invalid port index number: %llu\n", index); ++ dev_err(dev, "%pfwP: Invalid port index number: %llu\n", fwnode, index); + ret = -EINVAL; + goto err_switch; + } +-- +2.51.0 + diff --git a/queue-6.18/platform-x86-amd-pmf-prevent-tee-errors-after-hibern.patch b/queue-6.18/platform-x86-amd-pmf-prevent-tee-errors-after-hibern.patch new file mode 100644 index 0000000000..9f6e8bd813 --- /dev/null +++ b/queue-6.18/platform-x86-amd-pmf-prevent-tee-errors-after-hibern.patch @@ -0,0 +1,193 @@ +From c9e4e6da1617b2fa019d965b09c22e0276527994 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 22:11:28 -0600 +Subject: platform/x86/amd/pmf: Prevent TEE errors after hibernate +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Shyam Sundar S K + +[ Upstream commit 48d229c7047128dd52eaf863881bb3e62b5896e5 ] + +After resuming from hibernate, TEE commands can time out and cause PSP +disables. Fix this by reinitializing the Trusted Application (TA) and +cancelling the pb workqueue in the hibernate callbacks to avoid these +errors. + +ccp 0000:c4:00.2: tee: command 0x5 timed out, disabling PSP +amd-pmf AMDI0107:00: TEE enact cmd failed. err: ffff000e, ret:0 +amd-pmf AMDI0107:00: TEE enact cmd failed. err: ffff000e, ret:0 +amd-pmf AMDI0107:00: TEE enact cmd failed. err: ffff000e, ret:0 + +Fixes: ae82cef7d9c5 ("platform/x86/amd/pmf: Add support for PMF-TA interaction") +Reported-by: Lars Francke +Closes: https://lore.kernel.org/platform-driver-x86/CAD-Ua_gfJnQSo8ucS_7ZwzuhoBRJ14zXP7s8b-zX3ZcxcyWePw@mail.gmail.com/ +Tested-by: Yijun Shen +Co-developed-by: Patil Rajesh Reddy +Signed-off-by: Patil Rajesh Reddy +Signed-off-by: Shyam Sundar S K +[ML: Add more tags] +Signed-off-by: Mario Limonciello (AMD) +Link: https://patch.msgid.link/20260116041132.153674-2-superm1@kernel.org +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/amd/pmf/core.c | 62 ++++++++++++++++++++++++++- + drivers/platform/x86/amd/pmf/pmf.h | 10 +++++ + drivers/platform/x86/amd/pmf/tee-if.c | 12 ++---- + 3 files changed, 74 insertions(+), 10 deletions(-) + +diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c +index bc544a4a5266e..e787480f4df26 100644 +--- a/drivers/platform/x86/amd/pmf/core.c ++++ b/drivers/platform/x86/amd/pmf/core.c +@@ -314,6 +314,61 @@ int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev) + return 0; + } + ++static int amd_pmf_reinit_ta(struct amd_pmf_dev *pdev) ++{ ++ bool status; ++ int ret, i; ++ ++ for (i = 0; i < ARRAY_SIZE(amd_pmf_ta_uuid); i++) { ++ ret = amd_pmf_tee_init(pdev, &amd_pmf_ta_uuid[i]); ++ if (ret) { ++ dev_err(pdev->dev, "TEE init failed for UUID[%d] ret: %d\n", i, ret); ++ return ret; ++ } ++ ++ ret = amd_pmf_start_policy_engine(pdev); ++ dev_dbg(pdev->dev, "start policy engine ret: %d (UUID idx: %d)\n", ret, i); ++ status = ret == TA_PMF_TYPE_SUCCESS; ++ if (status) ++ break; ++ amd_pmf_tee_deinit(pdev); ++ } ++ ++ return 0; ++} ++ ++static int amd_pmf_restore_handler(struct device *dev) ++{ ++ struct amd_pmf_dev *pdev = dev_get_drvdata(dev); ++ int ret; ++ ++ if (pdev->buf) { ++ ret = amd_pmf_set_dram_addr(pdev, false); ++ if (ret) ++ return ret; ++ } ++ ++ if (pdev->smart_pc_enabled) ++ amd_pmf_reinit_ta(pdev); ++ ++ return 0; ++} ++ ++static int amd_pmf_freeze_handler(struct device *dev) ++{ ++ struct amd_pmf_dev *pdev = dev_get_drvdata(dev); ++ ++ if (!pdev->smart_pc_enabled) ++ return 0; ++ ++ cancel_delayed_work_sync(&pdev->pb_work); ++ /* Clear all TEE resources */ ++ amd_pmf_tee_deinit(pdev); ++ pdev->session_id = 0; ++ ++ return 0; ++} ++ + static int amd_pmf_suspend_handler(struct device *dev) + { + struct amd_pmf_dev *pdev = dev_get_drvdata(dev); +@@ -347,7 +402,12 @@ static int amd_pmf_resume_handler(struct device *dev) + return 0; + } + +-static DEFINE_SIMPLE_DEV_PM_OPS(amd_pmf_pm, amd_pmf_suspend_handler, amd_pmf_resume_handler); ++static const struct dev_pm_ops amd_pmf_pm = { ++ .suspend = amd_pmf_suspend_handler, ++ .resume = amd_pmf_resume_handler, ++ .freeze = amd_pmf_freeze_handler, ++ .restore = amd_pmf_restore_handler, ++}; + + static void amd_pmf_init_features(struct amd_pmf_dev *dev) + { +diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h +index bd19f2a6bc786..2da1885d87915 100644 +--- a/drivers/platform/x86/amd/pmf/pmf.h ++++ b/drivers/platform/x86/amd/pmf/pmf.h +@@ -122,6 +122,12 @@ struct cookie_header { + + typedef void (*apmf_event_handler_t)(acpi_handle handle, u32 event, void *data); + ++static const uuid_t amd_pmf_ta_uuid[] __used = { UUID_INIT(0xd9b39bf2, 0x66bd, 0x4154, 0xaf, 0xb8, ++ 0x8a, 0xcc, 0x2b, 0x2b, 0x60, 0xd6), ++ UUID_INIT(0x6fd93b77, 0x3fb8, 0x524d, 0xb1, 0x2d, ++ 0xc5, 0x29, 0xb1, 0x3d, 0x85, 0x43), ++ }; ++ + /* APTS PMF BIOS Interface */ + struct amd_pmf_apts_output { + u16 table_version; +@@ -888,4 +894,8 @@ void amd_pmf_populate_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_tab + void amd_pmf_dump_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in); + int amd_pmf_invoke_cmd_enact(struct amd_pmf_dev *dev); + ++int amd_pmf_tee_init(struct amd_pmf_dev *dev, const uuid_t *uuid); ++void amd_pmf_tee_deinit(struct amd_pmf_dev *dev); ++int amd_pmf_start_policy_engine(struct amd_pmf_dev *dev); ++ + #endif /* PMF_H */ +diff --git a/drivers/platform/x86/amd/pmf/tee-if.c b/drivers/platform/x86/amd/pmf/tee-if.c +index 6e8116bef4f6a..9030459352375 100644 +--- a/drivers/platform/x86/amd/pmf/tee-if.c ++++ b/drivers/platform/x86/amd/pmf/tee-if.c +@@ -27,12 +27,6 @@ module_param(pb_side_load, bool, 0444); + MODULE_PARM_DESC(pb_side_load, "Sideload policy binaries debug policy failures"); + #endif + +-static const uuid_t amd_pmf_ta_uuid[] = { UUID_INIT(0xd9b39bf2, 0x66bd, 0x4154, 0xaf, 0xb8, 0x8a, +- 0xcc, 0x2b, 0x2b, 0x60, 0xd6), +- UUID_INIT(0x6fd93b77, 0x3fb8, 0x524d, 0xb1, 0x2d, 0xc5, +- 0x29, 0xb1, 0x3d, 0x85, 0x43), +- }; +- + static const char *amd_pmf_uevent_as_str(unsigned int state) + { + switch (state) { +@@ -312,7 +306,7 @@ static void amd_pmf_invoke_cmd(struct work_struct *work) + schedule_delayed_work(&dev->pb_work, msecs_to_jiffies(pb_actions_ms)); + } + +-static int amd_pmf_start_policy_engine(struct amd_pmf_dev *dev) ++int amd_pmf_start_policy_engine(struct amd_pmf_dev *dev) + { + struct cookie_header *header; + int res; +@@ -468,7 +462,7 @@ static int amd_pmf_register_input_device(struct amd_pmf_dev *dev) + return 0; + } + +-static int amd_pmf_tee_init(struct amd_pmf_dev *dev, const uuid_t *uuid) ++int amd_pmf_tee_init(struct amd_pmf_dev *dev, const uuid_t *uuid) + { + u32 size; + int ret; +@@ -516,7 +510,7 @@ static int amd_pmf_tee_init(struct amd_pmf_dev *dev, const uuid_t *uuid) + return ret; + } + +-static void amd_pmf_tee_deinit(struct amd_pmf_dev *dev) ++void amd_pmf_tee_deinit(struct amd_pmf_dev *dev) + { + if (!dev->tee_ctx) + return; +-- +2.51.0 + diff --git a/queue-6.18/platform-x86-hp-wmi-fix-platform-profile-values-for-.patch b/queue-6.18/platform-x86-hp-wmi-fix-platform-profile-values-for-.patch new file mode 100644 index 0000000000..549a56e05a --- /dev/null +++ b/queue-6.18/platform-x86-hp-wmi-fix-platform-profile-values-for-.patch @@ -0,0 +1,306 @@ +From 8b30139c9c61146d6cd1ca5517a0b1cbc70677df Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Jan 2026 23:56:03 +0530 +Subject: platform/x86: hp-wmi: fix platform profile values for Omen 16-wf1xxx +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Krishna Chomal + +[ Upstream commit 8ca7515d3c76a8b629f703ff8301a75f503bcc50 ] + +HP Omen 16-wf1xxx (board ID 8C78) currently sends the incorrect +Victus-specific thermal profile values via WMI, leading to a logical +inconsistency when switching between platform profiles. + +The driver currently uses Victus S values: +0x00 => Balanced / Low-Power +0x01 => Performance + +However, Omen Gaming Hub logs / EC register inspection on Windows shows +that this board is intended to use: +0x30 => Balanced / Low-Power +0x31 => Performance + +This patch corrects the thermal profile command values to match the +values observed from Omen Gaming Hub logs. The performance benchmarks +and peak power draw (from both CPU and GPU) show no observable change +with this correction (suggesting that the firmware is currently tolerant +of the incorrect values). However sending the correct values prevents +potential regressions after future firmware updates. + +Refactor victus_s_thermal_profile_boards from a list of strings to a +dmi_system_id table and move the lookup to module init. The new struct +thermal_profile_params is used to store board-specific WMI parameters, +allowing the driver to cache these values in a static pointer. This +avoids repeated DMI string comparisons and allows marking of DMI table as +__initconst. + +Testing on HP Omen 16-wf1xxx (board 8C78) confirmed WMI codes 0x30/0x31 +are now sent, resolving the logical inconsistency and ensuring the value +visible in EC registers match the Windows state for this profile. + +Fixes: fb146a38cb11 ("platform/x86: hp-wmi: Add Omen 16-wf1xxx fan support") +Signed-off-by: Krishna Chomal +Link: https://patch.msgid.link/20260113182604.115211-2-krishna.chomal108@gmail.com +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/hp/hp-wmi.c | 179 ++++++++++++++++++++++--------- + 1 file changed, 127 insertions(+), 52 deletions(-) + +diff --git a/drivers/platform/x86/hp/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c +index ad9d9f97960f2..dfe45692c956a 100644 +--- a/drivers/platform/x86/hp/hp-wmi.c ++++ b/drivers/platform/x86/hp/hp-wmi.c +@@ -53,6 +53,66 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45E9-BE91-3D44E2C707E4"); + + #define zero_if_sup(tmp) (zero_insize_support?0:sizeof(tmp)) // use when zero insize is required + ++enum hp_thermal_profile_omen_v0 { ++ HP_OMEN_V0_THERMAL_PROFILE_DEFAULT = 0x00, ++ HP_OMEN_V0_THERMAL_PROFILE_PERFORMANCE = 0x01, ++ HP_OMEN_V0_THERMAL_PROFILE_COOL = 0x02, ++}; ++ ++enum hp_thermal_profile_omen_v1 { ++ HP_OMEN_V1_THERMAL_PROFILE_DEFAULT = 0x30, ++ HP_OMEN_V1_THERMAL_PROFILE_PERFORMANCE = 0x31, ++ HP_OMEN_V1_THERMAL_PROFILE_COOL = 0x50, ++}; ++ ++enum hp_thermal_profile_omen_flags { ++ HP_OMEN_EC_FLAGS_TURBO = 0x04, ++ HP_OMEN_EC_FLAGS_NOTIMER = 0x02, ++ HP_OMEN_EC_FLAGS_JUSTSET = 0x01, ++}; ++ ++enum hp_thermal_profile_victus { ++ HP_VICTUS_THERMAL_PROFILE_DEFAULT = 0x00, ++ HP_VICTUS_THERMAL_PROFILE_PERFORMANCE = 0x01, ++ HP_VICTUS_THERMAL_PROFILE_QUIET = 0x03, ++}; ++ ++enum hp_thermal_profile_victus_s { ++ HP_VICTUS_S_THERMAL_PROFILE_DEFAULT = 0x00, ++ HP_VICTUS_S_THERMAL_PROFILE_PERFORMANCE = 0x01, ++}; ++ ++enum hp_thermal_profile { ++ HP_THERMAL_PROFILE_PERFORMANCE = 0x00, ++ HP_THERMAL_PROFILE_DEFAULT = 0x01, ++ HP_THERMAL_PROFILE_COOL = 0x02, ++ HP_THERMAL_PROFILE_QUIET = 0x03, ++}; ++ ++struct thermal_profile_params { ++ u8 performance; ++ u8 balanced; ++ u8 low_power; ++}; ++ ++static const struct thermal_profile_params victus_s_thermal_params = { ++ .performance = HP_VICTUS_S_THERMAL_PROFILE_PERFORMANCE, ++ .balanced = HP_VICTUS_S_THERMAL_PROFILE_DEFAULT, ++ .low_power = HP_VICTUS_S_THERMAL_PROFILE_DEFAULT, ++}; ++ ++static const struct thermal_profile_params omen_v1_thermal_params = { ++ .performance = HP_OMEN_V1_THERMAL_PROFILE_PERFORMANCE, ++ .balanced = HP_OMEN_V1_THERMAL_PROFILE_DEFAULT, ++ .low_power = HP_OMEN_V1_THERMAL_PROFILE_DEFAULT, ++}; ++ ++/* ++ * A generic pointer for the currently-active board's thermal profile ++ * parameters. ++ */ ++static struct thermal_profile_params *active_thermal_profile_params; ++ + /* DMI board names of devices that should use the omen specific path for + * thermal profiles. + * This was obtained by taking a look in the windows omen command center +@@ -93,12 +153,40 @@ static const char * const victus_thermal_profile_boards[] = { + }; + + /* DMI Board names of Victus 16-r and Victus 16-s laptops */ +-static const char * const victus_s_thermal_profile_boards[] = { +- "8BBE", "8BD4", "8BD5", +- "8C78", "8C99", "8C9C", +- "8D41", ++static const struct dmi_system_id victus_s_thermal_profile_boards[] __initconst = { ++ { ++ .matches = { DMI_MATCH(DMI_BOARD_NAME, "8BBE") }, ++ .driver_data = (void *)&victus_s_thermal_params, ++ }, ++ { ++ .matches = { DMI_MATCH(DMI_BOARD_NAME, "8BD4") }, ++ .driver_data = (void *)&victus_s_thermal_params, ++ }, ++ { ++ .matches = { DMI_MATCH(DMI_BOARD_NAME, "8BD5") }, ++ .driver_data = (void *)&victus_s_thermal_params, ++ }, ++ { ++ .matches = { DMI_MATCH(DMI_BOARD_NAME, "8C78") }, ++ .driver_data = (void *)&omen_v1_thermal_params, ++ }, ++ { ++ .matches = { DMI_MATCH(DMI_BOARD_NAME, "8C99") }, ++ .driver_data = (void *)&victus_s_thermal_params, ++ }, ++ { ++ .matches = { DMI_MATCH(DMI_BOARD_NAME, "8C9C") }, ++ .driver_data = (void *)&victus_s_thermal_params, ++ }, ++ { ++ .matches = { DMI_MATCH(DMI_BOARD_NAME, "8D41") }, ++ .driver_data = (void *)&victus_s_thermal_params, ++ }, ++ {}, + }; + ++static bool is_victus_s_board; ++ + enum hp_wmi_radio { + HPWMI_WIFI = 0x0, + HPWMI_BLUETOOTH = 0x1, +@@ -219,42 +307,6 @@ enum hp_wireless2_bits { + HPWMI_POWER_FW_OR_HW = HPWMI_POWER_BIOS | HPWMI_POWER_HARD, + }; + +-enum hp_thermal_profile_omen_v0 { +- HP_OMEN_V0_THERMAL_PROFILE_DEFAULT = 0x00, +- HP_OMEN_V0_THERMAL_PROFILE_PERFORMANCE = 0x01, +- HP_OMEN_V0_THERMAL_PROFILE_COOL = 0x02, +-}; +- +-enum hp_thermal_profile_omen_v1 { +- HP_OMEN_V1_THERMAL_PROFILE_DEFAULT = 0x30, +- HP_OMEN_V1_THERMAL_PROFILE_PERFORMANCE = 0x31, +- HP_OMEN_V1_THERMAL_PROFILE_COOL = 0x50, +-}; +- +-enum hp_thermal_profile_omen_flags { +- HP_OMEN_EC_FLAGS_TURBO = 0x04, +- HP_OMEN_EC_FLAGS_NOTIMER = 0x02, +- HP_OMEN_EC_FLAGS_JUSTSET = 0x01, +-}; +- +-enum hp_thermal_profile_victus { +- HP_VICTUS_THERMAL_PROFILE_DEFAULT = 0x00, +- HP_VICTUS_THERMAL_PROFILE_PERFORMANCE = 0x01, +- HP_VICTUS_THERMAL_PROFILE_QUIET = 0x03, +-}; +- +-enum hp_thermal_profile_victus_s { +- HP_VICTUS_S_THERMAL_PROFILE_DEFAULT = 0x00, +- HP_VICTUS_S_THERMAL_PROFILE_PERFORMANCE = 0x01, +-}; +- +-enum hp_thermal_profile { +- HP_THERMAL_PROFILE_PERFORMANCE = 0x00, +- HP_THERMAL_PROFILE_DEFAULT = 0x01, +- HP_THERMAL_PROFILE_COOL = 0x02, +- HP_THERMAL_PROFILE_QUIET = 0x03, +-}; +- + #define IS_HWBLOCKED(x) ((x & HPWMI_POWER_FW_OR_HW) != HPWMI_POWER_FW_OR_HW) + #define IS_SWBLOCKED(x) !(x & HPWMI_POWER_SOFT) + +@@ -1575,15 +1627,8 @@ static int platform_profile_victus_set_ec(enum platform_profile_option profile) + + static bool is_victus_s_thermal_profile(void) + { +- const char *board_name; +- +- board_name = dmi_get_system_info(DMI_BOARD_NAME); +- if (!board_name) +- return false; +- +- return match_string(victus_s_thermal_profile_boards, +- ARRAY_SIZE(victus_s_thermal_profile_boards), +- board_name) >= 0; ++ /* Initialised in driver init, hence safe to use here */ ++ return is_victus_s_board; + } + + static int victus_s_gpu_thermal_profile_get(bool *ctgp_enable, +@@ -1666,25 +1711,30 @@ static int victus_s_set_cpu_pl1_pl2(u8 pl1, u8 pl2) + + static int platform_profile_victus_s_set_ec(enum platform_profile_option profile) + { ++ struct thermal_profile_params *params; + bool gpu_ctgp_enable, gpu_ppab_enable; + u8 gpu_dstate; /* Test shows 1 = 100%, 2 = 50%, 3 = 25%, 4 = 12.5% */ + int err, tp; + ++ params = active_thermal_profile_params; ++ if (!params) ++ return -ENODEV; ++ + switch (profile) { + case PLATFORM_PROFILE_PERFORMANCE: +- tp = HP_VICTUS_S_THERMAL_PROFILE_PERFORMANCE; ++ tp = params->performance; + gpu_ctgp_enable = true; + gpu_ppab_enable = true; + gpu_dstate = 1; + break; + case PLATFORM_PROFILE_BALANCED: +- tp = HP_VICTUS_S_THERMAL_PROFILE_DEFAULT; ++ tp = params->balanced; + gpu_ctgp_enable = false; + gpu_ppab_enable = true; + gpu_dstate = 1; + break; + case PLATFORM_PROFILE_LOW_POWER: +- tp = HP_VICTUS_S_THERMAL_PROFILE_DEFAULT; ++ tp = params->low_power; + gpu_ctgp_enable = false; + gpu_ppab_enable = false; + gpu_dstate = 1; +@@ -2221,6 +2271,26 @@ static int hp_wmi_hwmon_init(void) + return 0; + } + ++static void __init setup_active_thermal_profile_params(void) ++{ ++ const struct dmi_system_id *id; ++ ++ /* ++ * Currently only victus_s devices use the ++ * active_thermal_profile_params ++ */ ++ id = dmi_first_match(victus_s_thermal_profile_boards); ++ if (id) { ++ /* ++ * Marking this boolean is required to ensure that ++ * is_victus_s_thermal_profile() behaves like a valid ++ * wrapper. ++ */ ++ is_victus_s_board = true; ++ active_thermal_profile_params = id->driver_data; ++ } ++} ++ + static int __init hp_wmi_init(void) + { + int event_capable = wmi_has_guid(HPWMI_EVENT_GUID); +@@ -2248,6 +2318,11 @@ static int __init hp_wmi_init(void) + goto err_destroy_input; + } + ++ /* ++ * Setup active board's thermal profile parameters before ++ * starting platform driver probe. ++ */ ++ setup_active_thermal_profile_params(); + err = platform_driver_probe(&hp_wmi_driver, hp_wmi_bios_setup); + if (err) + goto err_unregister_device; +-- +2.51.0 + diff --git a/queue-6.18/platform-x86-int0002-remove-irqf_oneshot-from-reques.patch b/queue-6.18/platform-x86-int0002-remove-irqf_oneshot-from-reques.patch new file mode 100644 index 0000000000..d71f8a6fa6 --- /dev/null +++ b/queue-6.18/platform-x86-int0002-remove-irqf_oneshot-from-reques.patch @@ -0,0 +1,57 @@ +From 64ff3efb7034ced7d66b834299ba7b26f34974ea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:55:22 +0100 +Subject: platform/x86: int0002: Remove IRQF_ONESHOT from request_irq() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Sebastian Andrzej Siewior + +[ Upstream commit f6bc712877f24dc89bdfd7bdbf1a32f3b9960b34 ] + +Passing IRQF_ONESHOT ensures that the interrupt source is masked until the +secondary (threaded) handler is done. If only a primary handler is used +then the flag makes no sense because the interrupt cannot fire (again) +while its handler is running. + +The flag also prevents force-threading of the primary handler and the +irq-core will warn about this. + +The flag was added to match the flag on the shared handler which uses a +threaded handler and therefore IRQF_ONESHOT. This is no longer needed +because devm_request_irq() now passes IRQF_COND_ONESHOT for this case. + +Revert adding IRQF_ONESHOT to irqflags. + +Fixes: 8f812373d1958 ("platform/x86: intel: int0002_vgpio: Pass IRQF_ONESHOT to request_irq()") +Reported-by: Borah, Chaitanya Kumar +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Reviewed-by: Hans de Goede +Acked-by: Ilpo Järvinen +Link: https://patch.msgid.link/20260128095540.863589-3-bigeasy@linutronix.de +Closes: https://lore.kernel.org/all/555f1c56-0f74-41bf-8bd2-6217e0aab0c6@intel.com +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/intel/int0002_vgpio.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/platform/x86/intel/int0002_vgpio.c b/drivers/platform/x86/intel/int0002_vgpio.c +index 6f5629dc3f8db..562e880256436 100644 +--- a/drivers/platform/x86/intel/int0002_vgpio.c ++++ b/drivers/platform/x86/intel/int0002_vgpio.c +@@ -206,8 +206,8 @@ static int int0002_probe(struct platform_device *pdev) + * FIXME: augment this if we managed to pull handling of shared + * IRQs into gpiolib. + */ +- ret = devm_request_irq(dev, irq, int0002_irq, +- IRQF_ONESHOT | IRQF_SHARED, "INT0002", chip); ++ ret = devm_request_irq(dev, irq, int0002_irq, IRQF_SHARED, "INT0002", ++ chip); + if (ret) { + dev_err(dev, "Error requesting IRQ %d: %d\n", irq, ret); + return ret; +-- +2.51.0 + diff --git a/queue-6.18/pm-sleep-wakeirq-harden-dev_pm_clear_wake_irq-agains.patch b/queue-6.18/pm-sleep-wakeirq-harden-dev_pm_clear_wake_irq-agains.patch new file mode 100644 index 0000000000..5f4cbc2955 --- /dev/null +++ b/queue-6.18/pm-sleep-wakeirq-harden-dev_pm_clear_wake_irq-agains.patch @@ -0,0 +1,65 @@ +From 77eb1ab4c5b053cb4126d58bd25c611a688b4977 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 11:19:43 +0800 +Subject: PM: sleep: wakeirq: harden dev_pm_clear_wake_irq() against races + +From: Gui-Dong Han + +[ Upstream commit 5c9ecd8e6437cd55a38ea4f1e1d19cee8e226cb8 ] + +dev_pm_clear_wake_irq() currently uses a dangerous pattern where +dev->power.wakeirq is read and checked for NULL outside the lock. +If two callers invoke this function concurrently, both might see +a valid pointer and proceed. This could result in a double-free +when the second caller acquires the lock and tries to release the +same object. + +Address this by removing the lockless check of dev->power.wakeirq. +Instead, acquire dev->power.lock immediately to ensure the check and +the subsequent operations are atomic. If dev->power.wakeirq is NULL +under the lock, simply unlock and return. This guarantees that +concurrent calls cannot race to free the same object. + +Based on a quick scan of current users, I did not find an actual bug as +drivers seem to rely on their own synchronization. However, since +asynchronous usage patterns exist (e.g., in +drivers/net/wireless/ti/wlcore), I believe a race is theoretically +possible if the API is used less carefully in the future. This change +hardens the API to be robust against such cases. + +Fixes: 4990d4fe327b ("PM / Wakeirq: Add automated device wake IRQ handling") +Signed-off-by: Gui-Dong Han +Link: https://patch.msgid.link/20260203031943.1924-1-hanguidong02@gmail.com +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/base/power/wakeirq.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/drivers/base/power/wakeirq.c b/drivers/base/power/wakeirq.c +index 8aa28c08b2891..c0809d18fc540 100644 +--- a/drivers/base/power/wakeirq.c ++++ b/drivers/base/power/wakeirq.c +@@ -83,13 +83,16 @@ EXPORT_SYMBOL_GPL(dev_pm_set_wake_irq); + */ + void dev_pm_clear_wake_irq(struct device *dev) + { +- struct wake_irq *wirq = dev->power.wakeirq; ++ struct wake_irq *wirq; + unsigned long flags; + +- if (!wirq) ++ spin_lock_irqsave(&dev->power.lock, flags); ++ wirq = dev->power.wakeirq; ++ if (!wirq) { ++ spin_unlock_irqrestore(&dev->power.lock, flags); + return; ++ } + +- spin_lock_irqsave(&dev->power.lock, flags); + device_wakeup_detach_irq(dev); + dev->power.wakeirq = NULL; + spin_unlock_irqrestore(&dev->power.lock, flags); +-- +2.51.0 + diff --git a/queue-6.18/pm-wakeup-handle-empty-list-in-wakeup_sources_walk_s.patch b/queue-6.18/pm-wakeup-handle-empty-list-in-wakeup_sources_walk_s.patch new file mode 100644 index 0000000000..38fc00b03c --- /dev/null +++ b/queue-6.18/pm-wakeup-handle-empty-list-in-wakeup_sources_walk_s.patch @@ -0,0 +1,44 @@ +From 5f85e6a7e0d07b7141d5d429ac39879ca13c9c6c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 17:21:29 -0800 +Subject: PM: wakeup: Handle empty list in wakeup_sources_walk_start() + +From: Samuel Wu + +[ Upstream commit 75ce02f4bc9a8b8350b6b1b01872467b0cc960cc ] + +In the case of an empty wakeup_sources list, wakeup_sources_walk_start() +will return an invalid but non-NULL address. This also affects wrappers +of the aforementioned function, like for_each_wakeup_source(). + +Update wakeup_sources_walk_start() to return NULL in case of an empty +list. + +Fixes: b4941adb24c0 ("PM: wakeup: Add routine to help fetch wakeup source object.") +Signed-off-by: Samuel Wu +[ rjw: Subject and changelog edits ] +Link: https://patch.msgid.link/20260124012133.2451708-2-wusamuel@google.com +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/base/power/wakeup.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c +index d1283ff1080bb..2f630df16bfe1 100644 +--- a/drivers/base/power/wakeup.c ++++ b/drivers/base/power/wakeup.c +@@ -276,9 +276,7 @@ EXPORT_SYMBOL_GPL(wakeup_sources_read_unlock); + */ + struct wakeup_source *wakeup_sources_walk_start(void) + { +- struct list_head *ws_head = &wakeup_sources; +- +- return list_entry_rcu(ws_head->next, struct wakeup_source, entry); ++ return list_first_or_null_rcu(&wakeup_sources, struct wakeup_source, entry); + } + EXPORT_SYMBOL_GPL(wakeup_sources_walk_start); + +-- +2.51.0 + diff --git a/queue-6.18/pnfs-fix-a-missing-wake-up-while-waiting-on-nfs_layo.patch b/queue-6.18/pnfs-fix-a-missing-wake-up-while-waiting-on-nfs_layo.patch new file mode 100644 index 0000000000..da435e2ca0 --- /dev/null +++ b/queue-6.18/pnfs-fix-a-missing-wake-up-while-waiting-on-nfs_layo.patch @@ -0,0 +1,61 @@ +From 62cb861e71c80d8788fa17a0da2314d0a3666279 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 14:15:39 -0500 +Subject: pNFS: fix a missing wake up while waiting on NFS_LAYOUT_DRAIN + +From: Olga Kornievskaia + +[ Upstream commit 5248d8474e594d156bee1ed10339cc16e207a28b ] + +It is possible to have a task get stuck on waiting on the +NFS_LAYOUT_DRAIN in the following scenario + +1. cpu a: waiter test NFS_LAYOUT_DRAIN (1) and plh_outstanding (1) +2. cpu b: atomic_dec_and_test() -> clear bit -> wake up +3. cpu c: sets NFS_LAYOUT_DRAIN again +4. cpu a: calls wait_on_bit() sleeps forever. + +To expand on this we have say 2 outstanding pnfs write IO that get +ESTALE which causes both to call pnfs_destroy_layout() and set the +NFS_LAYOUT_DRAIN bit but the 1st one doesn't call the +pnfs_put_layout_hdr() yet (as that would prevent the 2nd ESTALE write +from trying to call pnfs_destroy_layout()). If the 1st ESTALE write +is the one that initially sets the NFS_LAYOUT_DRAIN so that new IO +on this file initiates new LAYOUTGET. Another new write would find +NFS_LAYOUT_DRAIN set and phl_outstanding>0 (step 1) and would +wait_on_bit(). LAYOUTGET completes doing step 2. Now, the 2nd of +ESTALE writes is calling pnfs_destory_layout() and set the +NFS_LAYOUT_DRAIN bit (step 3). Finally, the waiting write wakes up +to check the bit and goes back to sleep. + +The problem revolves around the fact that if NFS_LAYOUT_INVALID_STID +was already set, it should not do the work of +pnfs_mark_layout_stateid_invalid(), thus NFS_LAYOUT_DRAIN will not +be set more than once for an invalid layout. + +Suggested-by: Trond Myklebust +Fixes: 880265c77ac4 ("pNFS: Avoid a live lock condition in pnfs_update_layout()") +Signed-off-by: Olga Kornievskaia +Signed-off-by: Anna Schumaker +Signed-off-by: Sasha Levin +--- + fs/nfs/pnfs.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c +index 33bc6db0dc92f..b3cb5ee9d821e 100644 +--- a/fs/nfs/pnfs.c ++++ b/fs/nfs/pnfs.c +@@ -463,7 +463,8 @@ pnfs_mark_layout_stateid_invalid(struct pnfs_layout_hdr *lo, + }; + struct pnfs_layout_segment *lseg, *next; + +- set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags); ++ if (test_and_set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags)) ++ return !list_empty(&lo->plh_segs); + clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(lo->plh_inode)->flags); + list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list) + pnfs_clear_lseg_state(lseg, lseg_list); +-- +2.51.0 + diff --git a/queue-6.18/power-reset-nvmem-reboot-mode-respect-cell-size-for-.patch b/queue-6.18/power-reset-nvmem-reboot-mode-respect-cell-size-for-.patch new file mode 100644 index 0000000000..318cfb928c --- /dev/null +++ b/queue-6.18/power-reset-nvmem-reboot-mode-respect-cell-size-for-.patch @@ -0,0 +1,64 @@ +From 25503e04392474fbc07096d4810099029ee37754 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 14 Dec 2025 19:16:18 +0000 +Subject: power: reset: nvmem-reboot-mode: respect cell size for + nvmem_cell_write + +From: Alexander Koskovich + +[ Upstream commit 36b05629226413836cfbb3fbe6689cd188bca156 ] + +Some platforms expose reboot mode cells that are smaller than an +unsigned int, in which cases lead to write failures. Read the cell +first to determine actual size and only write the number of bytes the +cell can hold. + +Fixes: 7a78a7f7695b ("power: reset: nvmem-reboot-mode: use NVMEM as reboot mode write interface") +Signed-off-by: Alexander Koskovich +Link: https://patch.msgid.link/20251214191529.2470580-1-akoskovich@pm.me +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/reset/nvmem-reboot-mode.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +diff --git a/drivers/power/reset/nvmem-reboot-mode.c b/drivers/power/reset/nvmem-reboot-mode.c +index 41530b70cfc48..d260715fccf67 100644 +--- a/drivers/power/reset/nvmem-reboot-mode.c ++++ b/drivers/power/reset/nvmem-reboot-mode.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + + struct nvmem_reboot_mode { + struct reboot_mode_driver reboot; +@@ -19,12 +20,22 @@ struct nvmem_reboot_mode { + static int nvmem_reboot_mode_write(struct reboot_mode_driver *reboot, + unsigned int magic) + { +- int ret; + struct nvmem_reboot_mode *nvmem_rbm; ++ size_t buf_len; ++ void *buf; ++ int ret; + + nvmem_rbm = container_of(reboot, struct nvmem_reboot_mode, reboot); + +- ret = nvmem_cell_write(nvmem_rbm->cell, &magic, sizeof(magic)); ++ buf = nvmem_cell_read(nvmem_rbm->cell, &buf_len); ++ if (IS_ERR(buf)) ++ return PTR_ERR(buf); ++ kfree(buf); ++ ++ if (buf_len > sizeof(magic)) ++ return -EINVAL; ++ ++ ret = nvmem_cell_write(nvmem_rbm->cell, &magic, buf_len); + if (ret < 0) + dev_err(reboot->dev, "update reboot mode bits failed\n"); + +-- +2.51.0 + diff --git a/queue-6.18/power-supply-ab8500-fix-use-after-free-in-power_supp.patch b/queue-6.18/power-supply-ab8500-fix-use-after-free-in-power_supp.patch new file mode 100644 index 0000000000..613cb619da --- /dev/null +++ b/queue-6.18/power-supply-ab8500-fix-use-after-free-in-power_supp.patch @@ -0,0 +1,104 @@ +From 3e80a6026f5fe38e56606daa8a4cd64446d25430 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:35:58 +0100 +Subject: power: supply: ab8500: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit c4af8a98bb52825a5331ae1d0604c0ea6956ba4b ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Commit 1c1f13a006ed ("power: supply: ab8500: Move to componentized +binding") introduced this issue during a refactorization. Fix this racy +use-after-free by making sure the IRQ is requested _after_ the +registration of the `power_supply` handle. + +Fixes: 1c1f13a006ed ("power: supply: ab8500: Move to componentized binding") +Signed-off-by: Waqar Hameed +Reviewed-by: Linus Walleij +Link: https://patch.msgid.link/ccf83a09942cb8dda3dff70b2682f2c2e9cb97f2.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/ab8500_charger.c | 40 +++++++++++++-------------- + 1 file changed, 20 insertions(+), 20 deletions(-) + +diff --git a/drivers/power/supply/ab8500_charger.c b/drivers/power/supply/ab8500_charger.c +index 5f4537766e5b9..1813fbdfa1c1f 100644 +--- a/drivers/power/supply/ab8500_charger.c ++++ b/drivers/power/supply/ab8500_charger.c +@@ -3466,26 +3466,6 @@ static int ab8500_charger_probe(struct platform_device *pdev) + return ret; + } + +- /* Request interrupts */ +- for (i = 0; i < ARRAY_SIZE(ab8500_charger_irq); i++) { +- irq = platform_get_irq_byname(pdev, ab8500_charger_irq[i].name); +- if (irq < 0) +- return irq; +- +- ret = devm_request_threaded_irq(dev, +- irq, NULL, ab8500_charger_irq[i].isr, +- IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT, +- ab8500_charger_irq[i].name, di); +- +- if (ret != 0) { +- dev_err(dev, "failed to request %s IRQ %d: %d\n" +- , ab8500_charger_irq[i].name, irq, ret); +- return ret; +- } +- dev_dbg(dev, "Requested %s IRQ %d: %d\n", +- ab8500_charger_irq[i].name, irq, ret); +- } +- + /* initialize lock */ + spin_lock_init(&di->usb_state.usb_lock); + mutex_init(&di->usb_ipt_crnt_lock); +@@ -3614,6 +3594,26 @@ static int ab8500_charger_probe(struct platform_device *pdev) + return PTR_ERR(di->usb_chg.psy); + } + ++ /* Request interrupts */ ++ for (i = 0; i < ARRAY_SIZE(ab8500_charger_irq); i++) { ++ irq = platform_get_irq_byname(pdev, ab8500_charger_irq[i].name); ++ if (irq < 0) ++ return irq; ++ ++ ret = devm_request_threaded_irq(dev, ++ irq, NULL, ab8500_charger_irq[i].isr, ++ IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT, ++ ab8500_charger_irq[i].name, di); ++ ++ if (ret != 0) { ++ dev_err(dev, "failed to request %s IRQ %d: %d\n" ++ , ab8500_charger_irq[i].name, irq, ret); ++ return ret; ++ } ++ dev_dbg(dev, "Requested %s IRQ %d: %d\n", ++ ab8500_charger_irq[i].name, irq, ret); ++ } ++ + /* + * Check what battery we have, since we always have the USB + * psy, use that as a handle. +-- +2.51.0 + diff --git a/queue-6.18/power-supply-act8945a-fix-use-after-free-in-power_su.patch b/queue-6.18/power-supply-act8945a-fix-use-after-free-in-power_su.patch new file mode 100644 index 0000000000..92a68805f6 --- /dev/null +++ b/queue-6.18/power-supply-act8945a-fix-use-after-free-in-power_su.patch @@ -0,0 +1,77 @@ +From f6f813b7a59a048614a71a408b281d4562dec13c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:35:59 +0100 +Subject: power: supply: act8945a: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 3291c51d4684d048dd2eb91b5b65fcfdaf72141f ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: a09209acd6a8 ("power: supply: act8945a_charger: Add status change update support") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/bcf3a23b5187df0bba54a8c8fe09f8b8a0031dee.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/act8945a_charger.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/drivers/power/supply/act8945a_charger.c b/drivers/power/supply/act8945a_charger.c +index 3901a02f326a5..9dec4486b1439 100644 +--- a/drivers/power/supply/act8945a_charger.c ++++ b/drivers/power/supply/act8945a_charger.c +@@ -597,14 +597,6 @@ static int act8945a_charger_probe(struct platform_device *pdev) + return irq ?: -ENXIO; + } + +- ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, +- IRQF_TRIGGER_FALLING, "act8945a_interrupt", +- charger); +- if (ret) { +- dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); +- return ret; +- } +- + charger->desc.name = "act8945a-charger"; + charger->desc.get_property = act8945a_charger_get_property; + charger->desc.properties = act8945a_charger_props; +@@ -625,6 +617,14 @@ static int act8945a_charger_probe(struct platform_device *pdev) + return PTR_ERR(charger->psy); + } + ++ ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, ++ IRQF_TRIGGER_FALLING, "act8945a_interrupt", ++ charger); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); ++ return ret; ++ } ++ + platform_set_drvdata(pdev, charger); + + INIT_WORK(&charger->work, act8945a_work); +-- +2.51.0 + diff --git a/queue-6.18/power-supply-bq256xx-fix-use-after-free-in-power_sup.patch b/queue-6.18/power-supply-bq256xx-fix-use-after-free-in-power_sup.patch new file mode 100644 index 0000000000..4377313b3a --- /dev/null +++ b/queue-6.18/power-supply-bq256xx-fix-use-after-free-in-power_sup.patch @@ -0,0 +1,73 @@ +From 658515ea9551d3e8c3358ae234747694b82ff3f9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:35:59 +0100 +Subject: power: supply: bq256xx: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 8005843369723d9c8975b7c4202d1b85d6125302 ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: 32e4978bb920 ("power: supply: bq256xx: Introduce the BQ256XX charger driver") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/39da6da8cc060fa0382ca859f65071e791cb6119.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/bq256xx_charger.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/power/supply/bq256xx_charger.c b/drivers/power/supply/bq256xx_charger.c +index ae14162f017a9..d3de4f8b80db1 100644 +--- a/drivers/power/supply/bq256xx_charger.c ++++ b/drivers/power/supply/bq256xx_charger.c +@@ -1741,6 +1741,12 @@ static int bq256xx_probe(struct i2c_client *client) + usb_register_notifier(bq->usb3_phy, &bq->usb_nb); + } + ++ ret = bq256xx_power_supply_init(bq, &psy_cfg, dev); ++ if (ret) { ++ dev_err(dev, "Failed to register power supply\n"); ++ return ret; ++ } ++ + if (client->irq) { + ret = devm_request_threaded_irq(dev, client->irq, NULL, + bq256xx_irq_handler_thread, +@@ -1753,12 +1759,6 @@ static int bq256xx_probe(struct i2c_client *client) + } + } + +- ret = bq256xx_power_supply_init(bq, &psy_cfg, dev); +- if (ret) { +- dev_err(dev, "Failed to register power supply\n"); +- return ret; +- } +- + ret = bq256xx_hw_init(bq); + if (ret) { + dev_err(dev, "Cannot initialize the chip.\n"); +-- +2.51.0 + diff --git a/queue-6.18/power-supply-bq25980-fix-use-after-free-in-power_sup.patch b/queue-6.18/power-supply-bq25980-fix-use-after-free-in-power_sup.patch new file mode 100644 index 0000000000..134ef409ea --- /dev/null +++ b/queue-6.18/power-supply-bq25980-fix-use-after-free-in-power_sup.patch @@ -0,0 +1,73 @@ +From 08b55c045ac385ab30a0bc0c7c8555a7c9dc36d7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:35:59 +0100 +Subject: power: supply: bq25980: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 5f0b1cb41906e86b64bf69f5ededb83b0d757c27 ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: 5069185fc18e ("power: supply: bq25980: Add support for the BQ259xx family") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/8763035cadb959e14787b3837f2d3db61f6e1c34.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/bq25980_charger.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/power/supply/bq25980_charger.c b/drivers/power/supply/bq25980_charger.c +index 723858d62d141..73f06f09f134c 100644 +--- a/drivers/power/supply/bq25980_charger.c ++++ b/drivers/power/supply/bq25980_charger.c +@@ -1241,6 +1241,12 @@ static int bq25980_probe(struct i2c_client *client) + return ret; + } + ++ ret = bq25980_power_supply_init(bq, dev); ++ if (ret) { ++ dev_err(dev, "Failed to register power supply\n"); ++ return ret; ++ } ++ + if (client->irq) { + ret = devm_request_threaded_irq(dev, client->irq, NULL, + bq25980_irq_handler_thread, +@@ -1251,12 +1257,6 @@ static int bq25980_probe(struct i2c_client *client) + return ret; + } + +- ret = bq25980_power_supply_init(bq, dev); +- if (ret) { +- dev_err(dev, "Failed to register power supply\n"); +- return ret; +- } +- + ret = bq25980_hw_init(bq); + if (ret) { + dev_err(dev, "Cannot initialize the chip.\n"); +-- +2.51.0 + diff --git a/queue-6.18/power-supply-bq27xxx-fix-wrong-errno-when-bus-ops-ar.patch b/queue-6.18/power-supply-bq27xxx-fix-wrong-errno-when-bus-ops-ar.patch new file mode 100644 index 0000000000..ec97feb26c --- /dev/null +++ b/queue-6.18/power-supply-bq27xxx-fix-wrong-errno-when-bus-ops-ar.patch @@ -0,0 +1,61 @@ +From f36c32efebdeac572664d6053ca776cd8dc50370 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Dec 2025 16:34:36 +0800 +Subject: power: supply: bq27xxx: fix wrong errno when bus ops are unsupported + +From: Haotian Zhang + +[ Upstream commit 688364a11647dc09ba1e4429313e0008066ec790 ] + +bq27xxx_write(), bq27xxx_read_block(), and bq27xxx_write_block() +return -EPERM when the bus callback pointer is NULL. A NULL callback +indicates the operation is not supported by the bus/driver, +not that permission is denied. + +Return -EOPNOTSUPP instead of -EPERM when di->bus.write/ +read_bulk/write_bulk is NULL. + +Fixes: 14073f6614f6 ("power: supply: bq27xxx: Add bulk transfer bus methods") +Signed-off-by: Haotian Zhang +Reviewed-by: Matt Ranostay +Link: https://patch.msgid.link/20251204083436.1367-1-vulab@iscas.ac.cn +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/bq27xxx_battery.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c +index 19445e39651c7..45f0e39b8c2dd 100644 +--- a/drivers/power/supply/bq27xxx_battery.c ++++ b/drivers/power/supply/bq27xxx_battery.c +@@ -1172,7 +1172,7 @@ static inline int bq27xxx_write(struct bq27xxx_device_info *di, int reg_index, + return -EINVAL; + + if (!di->bus.write) +- return -EPERM; ++ return -EOPNOTSUPP; + + ret = di->bus.write(di, di->regs[reg_index], value, single); + if (ret < 0) +@@ -1191,7 +1191,7 @@ static inline int bq27xxx_read_block(struct bq27xxx_device_info *di, int reg_ind + return -EINVAL; + + if (!di->bus.read_bulk) +- return -EPERM; ++ return -EOPNOTSUPP; + + ret = di->bus.read_bulk(di, di->regs[reg_index], data, len); + if (ret < 0) +@@ -1210,7 +1210,7 @@ static inline int bq27xxx_write_block(struct bq27xxx_device_info *di, int reg_in + return -EINVAL; + + if (!di->bus.write_bulk) +- return -EPERM; ++ return -EOPNOTSUPP; + + ret = di->bus.write_bulk(di, di->regs[reg_index], data, len); + if (ret < 0) +-- +2.51.0 + diff --git a/queue-6.18/power-supply-cpcap-battery-fix-use-after-free-in-pow.patch b/queue-6.18/power-supply-cpcap-battery-fix-use-after-free-in-pow.patch new file mode 100644 index 0000000000..c9133d2fa3 --- /dev/null +++ b/queue-6.18/power-supply-cpcap-battery-fix-use-after-free-in-pow.patch @@ -0,0 +1,70 @@ +From 0046a2801444a2d0cce0ff5b821c3ca925155788 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:36:00 +0100 +Subject: power: supply: cpcap-battery: Fix use-after-free in + power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 642f33e34b969eedec334738fd5df95d2dc42742 ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: 874b2adbed12 ("power: supply: cpcap-battery: Add a battery driver") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/81db58d610c9a51a68184f856cd431a934cccee2.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/cpcap-battery.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/power/supply/cpcap-battery.c b/drivers/power/supply/cpcap-battery.c +index 8106d1edcbc26..507fdc1c866d5 100644 +--- a/drivers/power/supply/cpcap-battery.c ++++ b/drivers/power/supply/cpcap-battery.c +@@ -1122,10 +1122,6 @@ static int cpcap_battery_probe(struct platform_device *pdev) + + platform_set_drvdata(pdev, ddata); + +- error = cpcap_battery_init_interrupts(pdev, ddata); +- if (error) +- return error; +- + error = cpcap_battery_init_iio(ddata); + if (error) + return error; +@@ -1142,6 +1138,10 @@ static int cpcap_battery_probe(struct platform_device *pdev) + return error; + } + ++ error = cpcap_battery_init_interrupts(pdev, ddata); ++ if (error) ++ return error; ++ + atomic_set(&ddata->active, 1); + + error = cpcap_battery_calibrate(ddata); +-- +2.51.0 + diff --git a/queue-6.18/power-supply-goldfish-fix-use-after-free-in-power_su.patch b/queue-6.18/power-supply-goldfish-fix-use-after-free-in-power_su.patch new file mode 100644 index 0000000000..349acf1ca8 --- /dev/null +++ b/queue-6.18/power-supply-goldfish-fix-use-after-free-in-power_su.patch @@ -0,0 +1,73 @@ +From 791e9988e5110e3bd6dfc1f5f65c050fdeed1a4e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:36:00 +0100 +Subject: power: supply: goldfish: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit b2ce982e2e0c888dc55c888ad0e20ea04daf2e6b ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: 84d7b7687489 ("power: Add battery driver for goldfish emulator") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/500a606bb6fb6f2bb8d797e19a00cea9dd7b03c1.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/goldfish_battery.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/power/supply/goldfish_battery.c b/drivers/power/supply/goldfish_battery.c +index 479195e35d734..5aa24e4dc4455 100644 +--- a/drivers/power/supply/goldfish_battery.c ++++ b/drivers/power/supply/goldfish_battery.c +@@ -224,12 +224,6 @@ static int goldfish_battery_probe(struct platform_device *pdev) + if (data->irq < 0) + return -ENODEV; + +- ret = devm_request_irq(&pdev->dev, data->irq, +- goldfish_battery_interrupt, +- IRQF_SHARED, pdev->name, data); +- if (ret) +- return ret; +- + psy_cfg.drv_data = data; + + data->ac = devm_power_supply_register(&pdev->dev, +@@ -244,6 +238,12 @@ static int goldfish_battery_probe(struct platform_device *pdev) + if (IS_ERR(data->battery)) + return PTR_ERR(data->battery); + ++ ret = devm_request_irq(&pdev->dev, data->irq, ++ goldfish_battery_interrupt, ++ IRQF_SHARED, pdev->name, data); ++ if (ret) ++ return ret; ++ + GOLDFISH_BATTERY_WRITE(data, BATTERY_INT_ENABLE, BATTERY_INT_MASK); + return 0; + } +-- +2.51.0 + diff --git a/queue-6.18/power-supply-pm8916_bms_vm-fix-use-after-free-in-pow.patch b/queue-6.18/power-supply-pm8916_bms_vm-fix-use-after-free-in-pow.patch new file mode 100644 index 0000000000..a6345572c9 --- /dev/null +++ b/queue-6.18/power-supply-pm8916_bms_vm-fix-use-after-free-in-pow.patch @@ -0,0 +1,81 @@ +From 1d188a9848c2ccc52ed5dc035e60a64d170c0710 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:36:01 +0100 +Subject: power: supply: pm8916_bms_vm: Fix use-after-free in + power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 62914959b35e9a1e29cc0f64cb8cfc5075a5366f ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: 098bce1838e0 ("power: supply: Add pm8916 VM-BMS support") +Signed-off-by: Waqar Hameed +Reviewed-by: Nikita Travkin +Link: https://patch.msgid.link/2749c09ff81fcac87ae48147e216135450d8c067.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/pm8916_bms_vm.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/drivers/power/supply/pm8916_bms_vm.c b/drivers/power/supply/pm8916_bms_vm.c +index 5120be086e6ff..de5d571c03e21 100644 +--- a/drivers/power/supply/pm8916_bms_vm.c ++++ b/drivers/power/supply/pm8916_bms_vm.c +@@ -167,15 +167,6 @@ static int pm8916_bms_vm_battery_probe(struct platform_device *pdev) + if (ret < 0) + return -EINVAL; + +- irq = platform_get_irq_byname(pdev, "fifo"); +- if (irq < 0) +- return irq; +- +- ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_bms_vm_fifo_update_done_irq, +- IRQF_ONESHOT, "pm8916_vm_bms", bat); +- if (ret) +- return ret; +- + ret = regmap_bulk_read(bat->regmap, bat->reg + PM8916_PERPH_TYPE, &tmp, 2); + if (ret) + goto comm_error; +@@ -220,6 +211,15 @@ static int pm8916_bms_vm_battery_probe(struct platform_device *pdev) + if (ret) + return dev_err_probe(dev, ret, "Unable to get battery info\n"); + ++ irq = platform_get_irq_byname(pdev, "fifo"); ++ if (irq < 0) ++ return irq; ++ ++ ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_bms_vm_fifo_update_done_irq, ++ IRQF_ONESHOT, "pm8916_vm_bms", bat); ++ if (ret) ++ return ret; ++ + platform_set_drvdata(pdev, bat); + + return 0; +-- +2.51.0 + diff --git a/queue-6.18/power-supply-pm8916_lbc-fix-use-after-free-for-extco.patch b/queue-6.18/power-supply-pm8916_lbc-fix-use-after-free-for-extco.patch new file mode 100644 index 0000000000..8a3014599f --- /dev/null +++ b/queue-6.18/power-supply-pm8916_lbc-fix-use-after-free-for-extco.patch @@ -0,0 +1,67 @@ +From 755279dfdec586fd6beb9c545f6594bfd3687f00 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 11:24:20 +0100 +Subject: power: supply: pm8916_lbc: Fix use-after-free for extcon in IRQ + handler + +From: Waqar Hameed + +[ Upstream commit 23067259919663580c6f81801847cfc7bd54fd1f ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `extcon` handle, means that the +`extcon` handle will be deallocated/unregistered _before_ the interrupt +handler (since `devm_` naturally deallocates in reverse allocation +order). This means that during removal, there is a race condition where +an interrupt can fire just _after_ the `extcon` handle has been +freed, *but* just _before_ the corresponding unregistration of the IRQ +handler has run. + +This will lead to the IRQ handler calling `extcon_set_state_sync()` with +a freed `extcon` handle. Which usually crashes the system or otherwise +silently corrupts the memory... + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `extcon` handle. + +Fixes: f8d7a3d21160 ("power: supply: Add driver for pm8916 lbc") +Signed-off-by: Waqar Hameed +Reviewed-by: Nikita Travkin +Link: https://patch.msgid.link/e2a4cd2fcd42b6cd97d856c17c097289a2aed393.1769163273.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/pm8916_lbc.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/power/supply/pm8916_lbc.c b/drivers/power/supply/pm8916_lbc.c +index 3ca717d84aade..6b631012a7959 100644 +--- a/drivers/power/supply/pm8916_lbc.c ++++ b/drivers/power/supply/pm8916_lbc.c +@@ -327,11 +327,6 @@ static int pm8916_lbc_charger_probe(struct platform_device *pdev) + if (irq < 0) + return irq; + +- ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_lbc_charger_state_changed_irq, +- IRQF_ONESHOT, "pm8916_lbc", chg); +- if (ret) +- return ret; +- + chg->edev = devm_extcon_dev_allocate(dev, pm8916_lbc_charger_cable); + if (IS_ERR(chg->edev)) + return PTR_ERR(chg->edev); +@@ -340,6 +335,11 @@ static int pm8916_lbc_charger_probe(struct platform_device *pdev) + if (ret < 0) + return dev_err_probe(dev, ret, "failed to register extcon device\n"); + ++ ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_lbc_charger_state_changed_irq, ++ IRQF_ONESHOT, "pm8916_lbc", chg); ++ if (ret) ++ return ret; ++ + ret = regmap_read(chg->regmap, chg->reg[LBC_USB] + PM8916_INT_RT_STS, &tmp); + if (ret) + goto comm_error; +-- +2.51.0 + diff --git a/queue-6.18/power-supply-pm8916_lbc-fix-use-after-free-in-power_.patch b/queue-6.18/power-supply-pm8916_lbc-fix-use-after-free-in-power_.patch new file mode 100644 index 0000000000..2458921835 --- /dev/null +++ b/queue-6.18/power-supply-pm8916_lbc-fix-use-after-free-in-power_.patch @@ -0,0 +1,81 @@ +From f4ce1e6a5773b38e1a87dcfd29e08a2631c1a08b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:36:01 +0100 +Subject: power: supply: pm8916_lbc: Fix use-after-free in + power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit b7508129978ae1e2ed9b0410396abc05def9c4eb ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: f8d7a3d21160 ("power: supply: Add driver for pm8916 lbc") +Signed-off-by: Waqar Hameed +Reviewed-by: Nikita Travkin +Link: https://patch.msgid.link/64d8dd3675a4e59fa32c3e0ef451f12d1f7ed18f.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/pm8916_lbc.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/drivers/power/supply/pm8916_lbc.c b/drivers/power/supply/pm8916_lbc.c +index c74b75b1b2676..3ca717d84aade 100644 +--- a/drivers/power/supply/pm8916_lbc.c ++++ b/drivers/power/supply/pm8916_lbc.c +@@ -274,15 +274,6 @@ static int pm8916_lbc_charger_probe(struct platform_device *pdev) + return dev_err_probe(dev, -EINVAL, + "Wrong amount of reg values: %d (4 expected)\n", len); + +- irq = platform_get_irq_byname(pdev, "usb_vbus"); +- if (irq < 0) +- return irq; +- +- ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_lbc_charger_state_changed_irq, +- IRQF_ONESHOT, "pm8916_lbc", chg); +- if (ret) +- return ret; +- + ret = device_property_read_u32_array(dev, "reg", chg->reg, len); + if (ret) + return ret; +@@ -332,6 +323,15 @@ static int pm8916_lbc_charger_probe(struct platform_device *pdev) + if (ret) + return dev_err_probe(dev, ret, "Unable to get battery info\n"); + ++ irq = platform_get_irq_byname(pdev, "usb_vbus"); ++ if (irq < 0) ++ return irq; ++ ++ ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_lbc_charger_state_changed_irq, ++ IRQF_ONESHOT, "pm8916_lbc", chg); ++ if (ret) ++ return ret; ++ + chg->edev = devm_extcon_dev_allocate(dev, pm8916_lbc_charger_cable); + if (IS_ERR(chg->edev)) + return PTR_ERR(chg->edev); +-- +2.51.0 + diff --git a/queue-6.18/power-supply-qcom_battmgr-recognize-lip-as-lithium-p.patch b/queue-6.18/power-supply-qcom_battmgr-recognize-lip-as-lithium-p.patch new file mode 100644 index 0000000000..edca19637a --- /dev/null +++ b/queue-6.18/power-supply-qcom_battmgr-recognize-lip-as-lithium-p.patch @@ -0,0 +1,42 @@ +From 96f0d854590f2429bf35decec27c713d335400cd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 20:57:58 -0300 +Subject: power: supply: qcom_battmgr: Recognize "LiP" as lithium-polymer + +From: Val Packett + +[ Upstream commit c655f45480637aee326b5bd96488d35ab90db2b0 ] + +On the Dell Latitude 7455, the firmware uses "LiP" with a lowercase 'i' +for the battery chemistry type, but only all-uppercase "LIP" was being +recognized. Add the CamelCase variant to the check to fix the "Unknown +battery technology" warning. + +Fixes: 202ac22b8e2e ("power: supply: qcom_battmgr: Add lithium-polymer entry") +Signed-off-by: Val Packett +Reviewed-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Link: https://patch.msgid.link/20260120235831.479038-1-val@packett.cool +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/qcom_battmgr.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/power/supply/qcom_battmgr.c b/drivers/power/supply/qcom_battmgr.c +index e6f01e0122e1c..ff77dba29a3ef 100644 +--- a/drivers/power/supply/qcom_battmgr.c ++++ b/drivers/power/supply/qcom_battmgr.c +@@ -1244,7 +1244,8 @@ static unsigned int qcom_battmgr_sc8280xp_parse_technology(const char *chemistry + if ((!strncmp(chemistry, "LIO", BATTMGR_CHEMISTRY_LEN)) || + (!strncmp(chemistry, "OOI", BATTMGR_CHEMISTRY_LEN))) + return POWER_SUPPLY_TECHNOLOGY_LION; +- if (!strncmp(chemistry, "LIP", BATTMGR_CHEMISTRY_LEN)) ++ if (!strncmp(chemistry, "LIP", BATTMGR_CHEMISTRY_LEN) || ++ !strncmp(chemistry, "LiP", BATTMGR_CHEMISTRY_LEN)) + return POWER_SUPPLY_TECHNOLOGY_LIPO; + + pr_err("Unknown battery technology '%s'\n", chemistry); +-- +2.51.0 + diff --git a/queue-6.18/power-supply-rt9455-fix-use-after-free-in-power_supp.patch b/queue-6.18/power-supply-rt9455-fix-use-after-free-in-power_supp.patch new file mode 100644 index 0000000000..2a5dcc5768 --- /dev/null +++ b/queue-6.18/power-supply-rt9455-fix-use-after-free-in-power_supp.patch @@ -0,0 +1,78 @@ +From 7b6e3762474f51b7f07ec761428a1100e0de3c53 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:36:02 +0100 +Subject: power: supply: rt9455: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit e2febe375e5ea5afed92f4cd9711bde8f24ee6d2 ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: e86d69dd786e ("power_supply: Add support for Richtek RT9455 battery charger") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/1567d831e04c3e2fcb9e18dd36b7bcba4634581a.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/rt9455_charger.c | 17 +++++++++-------- + 1 file changed, 9 insertions(+), 8 deletions(-) + +diff --git a/drivers/power/supply/rt9455_charger.c b/drivers/power/supply/rt9455_charger.c +index 1ffe7f02932f6..5130d2395e88f 100644 +--- a/drivers/power/supply/rt9455_charger.c ++++ b/drivers/power/supply/rt9455_charger.c +@@ -1663,6 +1663,15 @@ static int rt9455_probe(struct i2c_client *client) + rt9455_charger_config.supplied_to = rt9455_charger_supplied_to; + rt9455_charger_config.num_supplicants = + ARRAY_SIZE(rt9455_charger_supplied_to); ++ ++ info->charger = devm_power_supply_register(dev, &rt9455_charger_desc, ++ &rt9455_charger_config); ++ if (IS_ERR(info->charger)) { ++ dev_err(dev, "Failed to register charger\n"); ++ ret = PTR_ERR(info->charger); ++ goto put_usb_notifier; ++ } ++ + ret = devm_request_threaded_irq(dev, client->irq, NULL, + rt9455_irq_handler_thread, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, +@@ -1678,14 +1687,6 @@ static int rt9455_probe(struct i2c_client *client) + goto put_usb_notifier; + } + +- info->charger = devm_power_supply_register(dev, &rt9455_charger_desc, +- &rt9455_charger_config); +- if (IS_ERR(info->charger)) { +- dev_err(dev, "Failed to register charger\n"); +- ret = PTR_ERR(info->charger); +- goto put_usb_notifier; +- } +- + return 0; + + put_usb_notifier: +-- +2.51.0 + diff --git a/queue-6.18/power-supply-sbs-battery-fix-use-after-free-in-power.patch b/queue-6.18/power-supply-sbs-battery-fix-use-after-free-in-power.patch new file mode 100644 index 0000000000..8bc7e653e9 --- /dev/null +++ b/queue-6.18/power-supply-sbs-battery-fix-use-after-free-in-power.patch @@ -0,0 +1,101 @@ +From bac220b6fcd9ce36581273cfcb7987c779dc7a11 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:36:02 +0100 +Subject: power: supply: sbs-battery: Fix use-after-free in + power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 8d59cf3887fbabacef53bfba473e33e8a8d9d07b ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. Keep the old behavior of +just printing a warning in case of any failures during the IRQ request +and finishing the probe successfully. + +Fixes: d2cec82c2880 ("power: sbs-battery: Request threaded irq and fix dev callback cookie") +Signed-off-by: Waqar Hameed +Reviewed-by: Phil Reid +Link: https://patch.msgid.link/0ef896e002495e615157b482d18a437af19ddcd0.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/sbs-battery.c | 36 +++++++++++++++--------------- + 1 file changed, 18 insertions(+), 18 deletions(-) + +diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c +index 943c82ee978f4..43c48196c1674 100644 +--- a/drivers/power/supply/sbs-battery.c ++++ b/drivers/power/supply/sbs-battery.c +@@ -1174,24 +1174,6 @@ static int sbs_probe(struct i2c_client *client) + + i2c_set_clientdata(client, chip); + +- if (!chip->gpio_detect) +- goto skip_gpio; +- +- irq = gpiod_to_irq(chip->gpio_detect); +- if (irq <= 0) { +- dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq); +- goto skip_gpio; +- } +- +- rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq, +- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, +- dev_name(&client->dev), chip); +- if (rc) { +- dev_warn(&client->dev, "Failed to request irq: %d\n", rc); +- goto skip_gpio; +- } +- +-skip_gpio: + /* + * Before we register, we might need to make sure we can actually talk + * to the battery. +@@ -1217,6 +1199,24 @@ static int sbs_probe(struct i2c_client *client) + return dev_err_probe(&client->dev, PTR_ERR(chip->power_supply), + "Failed to register power supply\n"); + ++ if (!chip->gpio_detect) ++ goto out; ++ ++ irq = gpiod_to_irq(chip->gpio_detect); ++ if (irq <= 0) { ++ dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq); ++ goto out; ++ } ++ ++ rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq, ++ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, ++ dev_name(&client->dev), chip); ++ if (rc) { ++ dev_warn(&client->dev, "Failed to request irq: %d\n", rc); ++ goto out; ++ } ++ ++out: + dev_info(&client->dev, + "%s: battery gas gauge device registered\n", client->name); + +-- +2.51.0 + diff --git a/queue-6.18/power-supply-wm97xx-fix-null-pointer-dereference-in-.patch b/queue-6.18/power-supply-wm97xx-fix-null-pointer-dereference-in-.patch new file mode 100644 index 0000000000..6d5fabc2c7 --- /dev/null +++ b/queue-6.18/power-supply-wm97xx-fix-null-pointer-dereference-in-.patch @@ -0,0 +1,98 @@ +From fe4a68485a393781dd38cceeb403478533b8d729 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:46:24 +0100 +Subject: power: supply: wm97xx: Fix NULL pointer dereference in + power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 39fe0eac6d755ef215026518985fcf8de9360e9e ] + +In `probe()`, `request_irq()` is called before allocating/registering a +`power_supply` handle. If an interrupt is fired between the call to +`request_irq()` and `power_supply_register()`, the `power_supply` handle +will be used uninitialized in `power_supply_changed()` in +`wm97xx_bat_update()` (triggered from the interrupt handler). This will +lead to a `NULL` pointer dereference since + +Fix this racy `NULL` pointer dereference by making sure the IRQ is +requested _after_ the registration of the `power_supply` handle. Since +the IRQ is the last thing requests in the `probe()` now, remove the +error path for freeing it. Instead add one for unregistering the +`power_supply` handle when IRQ request fails. + +Fixes: 7c87942aef52 ("wm97xx_battery: Use irq to detect charger state") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/97b55f0479a932eea7213844bf66f28a974e27a2.1766270196.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/wm97xx_battery.c | 34 +++++++++++++++------------ + 1 file changed, 19 insertions(+), 15 deletions(-) + +diff --git a/drivers/power/supply/wm97xx_battery.c b/drivers/power/supply/wm97xx_battery.c +index b3b0c37a9dd2d..f00722c88c6fe 100644 +--- a/drivers/power/supply/wm97xx_battery.c ++++ b/drivers/power/supply/wm97xx_battery.c +@@ -178,12 +178,6 @@ static int wm97xx_bat_probe(struct platform_device *dev) + "failed to get charge GPIO\n"); + if (charge_gpiod) { + gpiod_set_consumer_name(charge_gpiod, "BATT CHRG"); +- ret = request_irq(gpiod_to_irq(charge_gpiod), +- wm97xx_chrg_irq, 0, +- "AC Detect", dev); +- if (ret) +- return dev_err_probe(&dev->dev, ret, +- "failed to request GPIO irq\n"); + props++; /* POWER_SUPPLY_PROP_STATUS */ + } + +@@ -199,10 +193,8 @@ static int wm97xx_bat_probe(struct platform_device *dev) + props++; /* POWER_SUPPLY_PROP_VOLTAGE_MIN */ + + prop = kcalloc(props, sizeof(*prop), GFP_KERNEL); +- if (!prop) { +- ret = -ENOMEM; +- goto err3; +- } ++ if (!prop) ++ return -ENOMEM; + + prop[i++] = POWER_SUPPLY_PROP_PRESENT; + if (charge_gpiod) +@@ -236,15 +228,27 @@ static int wm97xx_bat_probe(struct platform_device *dev) + schedule_work(&bat_work); + } else { + ret = PTR_ERR(bat_psy); +- goto err4; ++ goto free; ++ } ++ ++ if (charge_gpiod) { ++ ret = request_irq(gpiod_to_irq(charge_gpiod), wm97xx_chrg_irq, ++ 0, "AC Detect", dev); ++ if (ret) { ++ dev_err_probe(&dev->dev, ret, ++ "failed to request GPIO irq\n"); ++ goto unregister; ++ } + } + + return 0; +-err4: ++ ++unregister: ++ power_supply_unregister(bat_psy); ++ ++free: + kfree(prop); +-err3: +- if (charge_gpiod) +- free_irq(gpiod_to_irq(charge_gpiod), dev); ++ + return ret; + } + +-- +2.51.0 + diff --git a/queue-6.18/powerpc-eeh-fix-recursive-pci_lock_rescan_remove-loc.patch b/queue-6.18/powerpc-eeh-fix-recursive-pci_lock_rescan_remove-loc.patch new file mode 100644 index 0000000000..fba45a583a --- /dev/null +++ b/queue-6.18/powerpc-eeh-fix-recursive-pci_lock_rescan_remove-loc.patch @@ -0,0 +1,275 @@ +From 2ec217523bd638140b8938868a85b8fbf4d047c8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 10 Dec 2025 08:25:59 -0600 +Subject: powerpc/eeh: fix recursive pci_lock_rescan_remove locking in EEH + event handling +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Narayana Murty N + +[ Upstream commit 815a8d2feb5615ae7f0b5befd206af0b0160614c ] + +The recent commit 1010b4c012b0 ("powerpc/eeh: Make EEH driver device +hotplug safe") restructured the EEH driver to improve synchronization +with the PCI hotplug layer. + +However, it inadvertently moved pci_lock_rescan_remove() outside its +intended scope in eeh_handle_normal_event(), leading to broken PCI +error reporting and improper EEH event triggering. Specifically, +eeh_handle_normal_event() acquired pci_lock_rescan_remove() before +calling eeh_pe_bus_get(), but eeh_pe_bus_get() itself attempts to +acquire the same lock internally, causing nested locking and disrupting +normal EEH event handling paths. + +This patch adds a boolean parameter do_lock to _eeh_pe_bus_get(), +with two public wrappers: + eeh_pe_bus_get() with locking enabled. + eeh_pe_bus_get_nolock() that skips locking. + +Callers that already hold pci_lock_rescan_remove() now use +eeh_pe_bus_get_nolock() to avoid recursive lock acquisition. + +Additionally, pci_lock_rescan_remove() calls are restored to the correct +position—after eeh_pe_bus_get() and immediately before iterating affected +PEs and devices. This ensures EEH-triggered PCI removes occur under proper +bus rescan locking without recursive lock contention. + +The eeh_pe_loc_get() function has been split into two functions: + eeh_pe_loc_get(struct eeh_pe *pe) which retrieves the loc for given PE. + eeh_pe_loc_get_bus(struct pci_bus *bus) which retrieves the location + code for given bus. + +This resolves lockdep warnings such as: + +[ 84.964298] [ T928] ============================================ +[ 84.964304] [ T928] WARNING: possible recursive locking detected +[ 84.964311] [ T928] 6.18.0-rc3 #51 Not tainted +[ 84.964315] [ T928] -------------------------------------------- +[ 84.964320] [ T928] eehd/928 is trying to acquire lock: +[ 84.964324] [ T928] c000000003b29d58 (pci_rescan_remove_lock){+.+.}-{3:3}, at: pci_lock_rescan_remove+0x28/0x40 +[ 84.964342] [ T928] + but task is already holding lock: +[ 84.964347] [ T928] c000000003b29d58 (pci_rescan_remove_lock){+.+.}-{3:3}, at: pci_lock_rescan_remove+0x28/0x40 +[ 84.964357] [ T928] + other info that might help us debug this: +[ 84.964363] [ T928] Possible unsafe locking scenario: + +[ 84.964367] [ T928] CPU0 +[ 84.964370] [ T928] ---- +[ 84.964373] [ T928] lock(pci_rescan_remove_lock); +[ 84.964378] [ T928] lock(pci_rescan_remove_lock); +[ 84.964383] [ T928] + *** DEADLOCK *** + +[ 84.964388] [ T928] May be due to missing lock nesting notation + +[ 84.964393] [ T928] 1 lock held by eehd/928: +[ 84.964397] [ T928] #0: c000000003b29d58 (pci_rescan_remove_lock){+.+.}-{3:3}, at: pci_lock_rescan_remove+0x28/0x40 +[ 84.964408] [ T928] + stack backtrace: +[ 84.964414] [ T928] CPU: 2 UID: 0 PID: 928 Comm: eehd Not tainted 6.18.0-rc3 #51 VOLUNTARY +[ 84.964417] [ T928] Hardware name: IBM,9080-HEX POWER10 (architected) 0x800200 0xf000006 of:IBM,FW1060.00 (NH1060_022) hv:phyp pSeries +[ 84.964419] [ T928] Call Trace: +[ 84.964420] [ T928] [c0000011a7157990] [c000000001705de4] dump_stack_lvl+0xc8/0x130 (unreliable) +[ 84.964424] [ T928] [c0000011a71579d0] [c0000000002f66e0] print_deadlock_bug+0x430/0x440 +[ 84.964428] [ T928] [c0000011a7157a70] [c0000000002fd0c0] __lock_acquire+0x1530/0x2d80 +[ 84.964431] [ T928] [c0000011a7157ba0] [c0000000002fea54] lock_acquire+0x144/0x410 +[ 84.964433] [ T928] [c0000011a7157cb0] [c0000011a7157cb0] __mutex_lock+0xf4/0x1050 +[ 84.964436] [ T928] [c0000011a7157e00] [c000000000de21d8] pci_lock_rescan_remove+0x28/0x40 +[ 84.964439] [ T928] [c0000011a7157e20] [c00000000004ed98] eeh_pe_bus_get+0x48/0xc0 +[ 84.964442] [ T928] [c0000011a7157e50] [c000000000050434] eeh_handle_normal_event+0x64/0xa60 +[ 84.964446] [ T928] [c0000011a7157f30] [c000000000051de8] eeh_event_handler+0xf8/0x190 +[ 84.964450] [ T928] [c0000011a7157f90] [c0000000002747ac] kthread+0x16c/0x180 +[ 84.964453] [ T928] [c0000011a7157fe0] [c00000000000ded8] start_kernel_thread+0x14/0x18 + + +Fixes: 1010b4c012b0 ("powerpc/eeh: Make EEH driver device hotplug safe") +Signed-off-by: Narayana Murty N +Reviewed-by: Sourabh Jain +Reviewed-by: Mahesh Salgaonkar +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/20251210142559.8874-1-nnmlinux@linux.ibm.com +Signed-off-by: Sasha Levin +--- + arch/powerpc/include/asm/eeh.h | 2 + + arch/powerpc/kernel/eeh_driver.c | 11 ++--- + arch/powerpc/kernel/eeh_pe.c | 74 ++++++++++++++++++++++++++++++-- + 3 files changed, 78 insertions(+), 9 deletions(-) + +diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h +index 5e34611de9ef4..b7ebb4ac2c710 100644 +--- a/arch/powerpc/include/asm/eeh.h ++++ b/arch/powerpc/include/asm/eeh.h +@@ -289,6 +289,8 @@ void eeh_pe_dev_traverse(struct eeh_pe *root, + void eeh_pe_restore_bars(struct eeh_pe *pe); + const char *eeh_pe_loc_get(struct eeh_pe *pe); + struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe); ++const char *eeh_pe_loc_get_bus(struct pci_bus *bus); ++struct pci_bus *eeh_pe_bus_get_nolock(struct eeh_pe *pe); + + void eeh_show_enabled(void); + int __init eeh_init(struct eeh_ops *ops); +diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c +index ef78ff77cf8f2..028f691585323 100644 +--- a/arch/powerpc/kernel/eeh_driver.c ++++ b/arch/powerpc/kernel/eeh_driver.c +@@ -846,7 +846,7 @@ void eeh_handle_normal_event(struct eeh_pe *pe) + + pci_lock_rescan_remove(); + +- bus = eeh_pe_bus_get(pe); ++ bus = eeh_pe_bus_get_nolock(pe); + if (!bus) { + pr_err("%s: Cannot find PCI bus for PHB#%x-PE#%x\n", + __func__, pe->phb->global_number, pe->addr); +@@ -886,14 +886,15 @@ void eeh_handle_normal_event(struct eeh_pe *pe) + /* Log the event */ + if (pe->type & EEH_PE_PHB) { + pr_err("EEH: Recovering PHB#%x, location: %s\n", +- pe->phb->global_number, eeh_pe_loc_get(pe)); ++ pe->phb->global_number, eeh_pe_loc_get_bus(bus)); + } else { + struct eeh_pe *phb_pe = eeh_phb_pe_get(pe->phb); + + pr_err("EEH: Recovering PHB#%x-PE#%x\n", + pe->phb->global_number, pe->addr); + pr_err("EEH: PE location: %s, PHB location: %s\n", +- eeh_pe_loc_get(pe), eeh_pe_loc_get(phb_pe)); ++ eeh_pe_loc_get_bus(bus), ++ eeh_pe_loc_get_bus(eeh_pe_bus_get_nolock(phb_pe))); + } + + #ifdef CONFIG_STACKTRACE +@@ -1098,7 +1099,7 @@ void eeh_handle_normal_event(struct eeh_pe *pe) + eeh_pe_state_clear(pe, EEH_PE_PRI_BUS, true); + eeh_pe_dev_mode_mark(pe, EEH_DEV_REMOVED); + +- bus = eeh_pe_bus_get(pe); ++ bus = eeh_pe_bus_get_nolock(pe); + if (bus) + pci_hp_remove_devices(bus); + else +@@ -1222,7 +1223,7 @@ void eeh_handle_special_event(void) + (phb_pe->state & EEH_PE_RECOVERING)) + continue; + +- bus = eeh_pe_bus_get(phb_pe); ++ bus = eeh_pe_bus_get_nolock(phb_pe); + if (!bus) { + pr_err("%s: Cannot find PCI bus for " + "PHB#%x-PE#%x\n", +diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c +index e740101fadf3b..040e8f69a4aa8 100644 +--- a/arch/powerpc/kernel/eeh_pe.c ++++ b/arch/powerpc/kernel/eeh_pe.c +@@ -812,6 +812,24 @@ void eeh_pe_restore_bars(struct eeh_pe *pe) + const char *eeh_pe_loc_get(struct eeh_pe *pe) + { + struct pci_bus *bus = eeh_pe_bus_get(pe); ++ return eeh_pe_loc_get_bus(bus); ++} ++ ++/** ++ * eeh_pe_loc_get_bus - Retrieve location code binding to the given PCI bus ++ * @bus: PCI bus ++ * ++ * Retrieve the location code associated with the given PCI bus. If the bus ++ * is a root bus, the location code is fetched from the PHB device tree node ++ * or root port. Otherwise, the location code is obtained from the device ++ * tree node of the upstream bridge of the bus. The function walks up the ++ * bus hierarchy if necessary, checking each node for the appropriate ++ * location code property ("ibm,io-base-loc-code" for root buses, ++ * "ibm,slot-location-code" for others). If no location code is found, ++ * returns "N/A". ++ */ ++const char *eeh_pe_loc_get_bus(struct pci_bus *bus) ++{ + struct device_node *dn; + const char *loc = NULL; + +@@ -838,8 +856,9 @@ const char *eeh_pe_loc_get(struct eeh_pe *pe) + } + + /** +- * eeh_pe_bus_get - Retrieve PCI bus according to the given PE ++ * _eeh_pe_bus_get - Retrieve PCI bus according to the given PE + * @pe: EEH PE ++ * @do_lock: Is the caller already held the pci_lock_rescan_remove? + * + * Retrieve the PCI bus according to the given PE. Basically, + * there're 3 types of PEs: PHB/Bus/Device. For PHB PE, the +@@ -847,7 +866,7 @@ const char *eeh_pe_loc_get(struct eeh_pe *pe) + * returned for BUS PE. However, we don't have associated PCI + * bus for DEVICE PE. + */ +-struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe) ++static struct pci_bus *_eeh_pe_bus_get(struct eeh_pe *pe, bool do_lock) + { + struct eeh_dev *edev; + struct pci_dev *pdev; +@@ -862,11 +881,58 @@ struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe) + + /* Retrieve the parent PCI bus of first (top) PCI device */ + edev = list_first_entry_or_null(&pe->edevs, struct eeh_dev, entry); +- pci_lock_rescan_remove(); ++ if (do_lock) ++ pci_lock_rescan_remove(); + pdev = eeh_dev_to_pci_dev(edev); + if (pdev) + bus = pdev->bus; +- pci_unlock_rescan_remove(); ++ if (do_lock) ++ pci_unlock_rescan_remove(); + + return bus; + } ++ ++/** ++ * eeh_pe_bus_get - Retrieve PCI bus associated with the given EEH PE, locking ++ * if needed ++ * @pe: Pointer to the EEH PE ++ * ++ * This function is a wrapper around _eeh_pe_bus_get(), which retrieves the PCI ++ * bus associated with the provided EEH PE structure. It acquires the PCI ++ * rescans lock to ensure safe access to shared data during the retrieval ++ * process. This function should be used when the caller requires the PCI bus ++ * while holding the rescan/remove lock, typically during operations that modify ++ * or inspect PCIe device state in a safe manner. ++ * ++ * RETURNS: ++ * A pointer to the PCI bus associated with the EEH PE, or NULL if none found. ++ */ ++ ++struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe) ++{ ++ return _eeh_pe_bus_get(pe, true); ++} ++ ++/** ++ * eeh_pe_bus_get_nolock - Retrieve PCI bus associated with the given EEH PE ++ * without locking ++ * @pe: Pointer to the EEH PE ++ * ++ * This function is a variant of _eeh_pe_bus_get() that retrieves the PCI bus ++ * associated with the specified EEH PE without acquiring the ++ * pci_lock_rescan_remove lock. It should only be used when the caller can ++ * guarantee safe access to PE structures without the need for that lock, ++ * typically in contexts where the lock is already held locking is otherwise ++ * managed. ++ * ++ * RETURNS: ++ * pointer to the PCI bus associated with the EEH PE, or NULL if none is found. ++ * ++ * NOTE: ++ * Use this function carefully to avoid race conditions and data corruption. ++ */ ++ ++struct pci_bus *eeh_pe_bus_get_nolock(struct eeh_pe *pe) ++{ ++ return _eeh_pe_bus_get(pe, false); ++} +-- +2.51.0 + diff --git a/queue-6.18/powerpc-uaccess-move-barrier_nospec-out-of-allow_rea.patch b/queue-6.18/powerpc-uaccess-move-barrier_nospec-out-of-allow_rea.patch new file mode 100644 index 0000000000..79ad50b025 --- /dev/null +++ b/queue-6.18/powerpc-uaccess-move-barrier_nospec-out-of-allow_rea.patch @@ -0,0 +1,98 @@ +From cbbd9171e86be90913b3b0f4c6a5724637efac17 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Dec 2025 12:20:49 +0100 +Subject: powerpc/uaccess: Move barrier_nospec() out of + allow_read_{from/write}_user() + +From: Christophe Leroy + +[ Upstream commit 5fbc09eb0b4f4b1a4b33abebacbeee0d29f195e9 ] + +Commit 74e19ef0ff80 ("uaccess: Add speculation barrier to +copy_from_user()") added a redundant barrier_nospec() in +copy_from_user(), because powerpc is already calling +barrier_nospec() in allow_read_from_user() and +allow_read_write_user(). But on other architectures that +call to barrier_nospec() was missing. So change powerpc +instead of reverting the above commit and having to fix +other architectures one by one. This is now possible +because barrier_nospec() has also been added in +copy_from_user_iter(). + +Move barrier_nospec() out of allow_read_from_user() and +allow_read_write_user(). This will also allow reuse of those +functions when implementing masked user access which doesn't +require barrier_nospec(). + +Don't add it back in raw_copy_from_user() as it is already called +by copy_from_user() and copy_from_user_iter(). + +Fixes: 74e19ef0ff80 ("uaccess: Add speculation barrier to copy_from_user()") +Signed-off-by: Christophe Leroy +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/f29612105c5fcbc8ceb7303808ddc1a781f0f6b5.1766574657.git.chleroy@kernel.org +Signed-off-by: Sasha Levin +--- + arch/powerpc/include/asm/kup.h | 2 -- + arch/powerpc/include/asm/uaccess.h | 4 ++++ + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/arch/powerpc/include/asm/kup.h b/arch/powerpc/include/asm/kup.h +index dab63b82a8d4f..f2009d7c8cfa7 100644 +--- a/arch/powerpc/include/asm/kup.h ++++ b/arch/powerpc/include/asm/kup.h +@@ -134,7 +134,6 @@ static __always_inline void kuap_assert_locked(void) + + static __always_inline void allow_read_from_user(const void __user *from, unsigned long size) + { +- barrier_nospec(); + allow_user_access(NULL, from, size, KUAP_READ); + } + +@@ -146,7 +145,6 @@ static __always_inline void allow_write_to_user(void __user *to, unsigned long s + static __always_inline void allow_read_write_user(void __user *to, const void __user *from, + unsigned long size) + { +- barrier_nospec(); + allow_user_access(to, from, size, KUAP_READ_WRITE); + } + +diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h +index 4f5a46a77fa2b..3987a5c33558b 100644 +--- a/arch/powerpc/include/asm/uaccess.h ++++ b/arch/powerpc/include/asm/uaccess.h +@@ -301,6 +301,7 @@ do { \ + __typeof__(sizeof(*(ptr))) __gu_size = sizeof(*(ptr)); \ + \ + might_fault(); \ ++ barrier_nospec(); \ + allow_read_from_user(__gu_addr, __gu_size); \ + __get_user_size_allowed(__gu_val, __gu_addr, __gu_size, __gu_err); \ + prevent_read_from_user(__gu_addr, __gu_size); \ +@@ -329,6 +330,7 @@ raw_copy_in_user(void __user *to, const void __user *from, unsigned long n) + { + unsigned long ret; + ++ barrier_nospec(); + allow_read_write_user(to, from, n); + ret = __copy_tofrom_user(to, from, n); + prevent_read_write_user(to, from, n); +@@ -415,6 +417,7 @@ static __must_check __always_inline bool user_access_begin(const void __user *pt + + might_fault(); + ++ barrier_nospec(); + allow_read_write_user((void __user *)ptr, ptr, len); + return true; + } +@@ -431,6 +434,7 @@ user_read_access_begin(const void __user *ptr, size_t len) + + might_fault(); + ++ barrier_nospec(); + allow_read_from_user(ptr, len); + return true; + } +-- +2.51.0 + diff --git a/queue-6.18/printk-vt-fbcon-remove-console_conditional_schedule.patch b/queue-6.18/printk-vt-fbcon-remove-console_conditional_schedule.patch new file mode 100644 index 0000000000..d07055a4a2 --- /dev/null +++ b/queue-6.18/printk-vt-fbcon-remove-console_conditional_schedule.patch @@ -0,0 +1,176 @@ +From 8582538229755cef300ddccabe133abdb11aca9a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 19:08:36 +0100 +Subject: printk, vt, fbcon: Remove console_conditional_schedule() + +From: Sebastian Andrzej Siewior + +[ Upstream commit 8e9bf8b9e8c0a3e1ef16dd48260a113f65ed01d2 ] + +do_con_write(), fbcon_redraw.*() invoke console_conditional_schedule() +which is a conditional scheduling point based on printk's internal +variables console_may_schedule. It may only be used if the console lock +is acquired for instance via console_lock() or console_trylock(). + +Prinkt sets the internal variable to 1 (and allows to schedule) +if the console lock has been acquired via console_lock(). The trylock +does not allow it. + +The console_conditional_schedule() invocation in do_con_write() is +invoked shortly before console_unlock(). +The console_conditional_schedule() invocation in fbcon_redraw.*() +original from fbcon_scroll() / vt's con_scroll() which originate from a +line feed. + +In console_unlock() the variable is set to 0 (forbids to schedule) and +it tries to schedule while making progress printing. This is brand new +compared to when console_conditional_schedule() was added in v2.4.9.11. + +In v2.6.38-rc3, console_unlock() (started its existence) iterated over +all consoles and flushed them with disabled interrupts. A scheduling +attempt here was not possible, it relied that a long print scheduled +before console_unlock(). + +Since commit 8d91f8b15361d ("printk: do cond_resched() between lines +while outputting to consoles"), which appeared in v4.5-rc1, +console_unlock() attempts to schedule if it was allowed to schedule +while during console_lock(). Each record is idealy one line so after +every line feed. + +This console_conditional_schedule() is also only relevant on +PREEMPT_NONE and PREEMPT_VOLUNTARY builds. In other configurations +cond_resched() becomes a nop and has no impact. + +I'm bringing this all up just proof that it is not required anymore. It +becomes a problem on a PREEMPT_RT build with debug code enabled because +that might_sleep() in cond_resched() remains and triggers a warnings. +This is due to + + legacy_kthread_func-> console_flush_one_record -> vt_console_print-> lf + -> con_scroll -> fbcon_scroll + +and vt_console_print() acquires a spinlock_t which does not allow a +voluntary schedule. There is no need to fb_scroll() to schedule since +console_flush_one_record() attempts to schedule after each line. +!PREEMPT_RT is not affected because the legacy printing thread is only +enabled on PREEMPT_RT builds. + +Therefore I suggest to remove console_conditional_schedule(). + +Cc: Simona Vetter +Cc: Helge Deller +Cc: linux-fbdev@vger.kernel.org +Cc: dri-devel@lists.freedesktop.org +Fixes: 5f53ca3ff83b4 ("printk: Implement legacy printer kthread for PREEMPT_RT") +Signed-off-by: Sebastian Andrzej Siewior +Acked-by: Greg Kroah-Hartman +Acked-by: Petr Mladek # from printk() POV +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/tty/vt/vt.c | 1 - + drivers/video/fbdev/core/fbcon.c | 6 ------ + include/linux/console.h | 1 - + kernel/printk/printk.c | 16 ---------------- + 4 files changed, 24 deletions(-) + +diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c +index 6e0089b85c270..53dffb6e00a91 100644 +--- a/drivers/tty/vt/vt.c ++++ b/drivers/tty/vt/vt.c +@@ -3236,7 +3236,6 @@ static int do_con_write(struct tty_struct *tty, const u8 *buf, int count) + goto rescan_last_byte; + } + con_flush(vc, &draw); +- console_conditional_schedule(); + notify_update(vc); + + return n; +diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c +index 413aa46228549..19469c60ce45f 100644 +--- a/drivers/video/fbdev/core/fbcon.c ++++ b/drivers/video/fbdev/core/fbcon.c +@@ -1586,12 +1586,10 @@ static void fbcon_redraw_move(struct vc_data *vc, struct fbcon_display *p, + start = s; + } + } +- console_conditional_schedule(); + s++; + } while (s < le); + if (s > start) + fbcon_putcs(vc, start, s - start, dy, x); +- console_conditional_schedule(); + dy++; + } + } +@@ -1627,14 +1625,12 @@ static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info, + } + + scr_writew(c, d); +- console_conditional_schedule(); + s++; + d++; + } while (s < le); + if (s > start) + par->bitops->bmove(vc, info, line + ycount, x, line, x, 1, + s - start); +- console_conditional_schedule(); + if (ycount > 0) + line++; + else { +@@ -1682,13 +1678,11 @@ static void fbcon_redraw(struct vc_data *vc, int line, int count, int offset) + } + } + scr_writew(c, d); +- console_conditional_schedule(); + s++; + d++; + } while (s < le); + if (s > start) + fbcon_putcs(vc, start, s - start, line, x); +- console_conditional_schedule(); + if (offset > 0) + line++; + else { +diff --git a/include/linux/console.h b/include/linux/console.h +index 031a58dc2b911..a307f89c5e687 100644 +--- a/include/linux/console.h ++++ b/include/linux/console.h +@@ -629,7 +629,6 @@ extern int unregister_console(struct console *); + extern void console_lock(void); + extern int console_trylock(void); + extern void console_unlock(void); +-extern void console_conditional_schedule(void); + extern void console_unblank(void); + extern void console_flush_on_panic(enum con_flush_mode mode); + extern struct tty_driver *console_device(int *); +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index c27fc7fc64eb5..0c26491f732c2 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -3322,22 +3322,6 @@ void console_unlock(void) + } + EXPORT_SYMBOL(console_unlock); + +-/** +- * console_conditional_schedule - yield the CPU if required +- * +- * If the console code is currently allowed to sleep, and +- * if this CPU should yield the CPU to another task, do +- * so here. +- * +- * Must be called within console_lock();. +- */ +-void __sched console_conditional_schedule(void) +-{ +- if (console_may_schedule) +- cond_resched(); +-} +-EXPORT_SYMBOL(console_conditional_schedule); +- + void console_unblank(void) + { + bool found_unblank = false; +-- +2.51.0 + diff --git a/queue-6.18/procfs-fix-missing-rcu-protection-when-reading-real_.patch b/queue-6.18/procfs-fix-missing-rcu-protection-when-reading-real_.patch new file mode 100644 index 0000000000..546426467c --- /dev/null +++ b/queue-6.18/procfs-fix-missing-rcu-protection-when-reading-real_.patch @@ -0,0 +1,59 @@ +From 728ce3b10a023199aaba6190d52a2d576d8f1585 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 16:30:07 +0800 +Subject: procfs: fix missing RCU protection when reading real_parent in + do_task_stat() + +From: Jinliang Zheng + +[ Upstream commit 76149d53502cf17ef3ae454ff384551236fba867 ] + +When reading /proc/[pid]/stat, do_task_stat() accesses task->real_parent +without proper RCU protection, which leads to: + + cpu 0 cpu 1 + ----- ----- + do_task_stat + var = task->real_parent + release_task + call_rcu(delayed_put_task_struct) + task_tgid_nr_ns(var) + rcu_read_lock <--- Too late to protect task->real_parent! + task_pid_ptr <--- UAF! + rcu_read_unlock + +This patch uses task_ppid_nr_ns() instead of task_tgid_nr_ns() to add +proper RCU protection for accessing task->real_parent. + +Link: https://lkml.kernel.org/r/20260128083007.3173016-1-alexjlzheng@tencent.com +Fixes: 06fffb1267c9 ("do_task_stat: don't take rcu_read_lock()") +Signed-off-by: Jinliang Zheng +Acked-by: Oleg Nesterov +Cc: David Hildenbrand +Cc: Ingo Molnar +Cc: Lorenzo Stoakes +Cc: Mateusz Guzik +Cc: ruippan +Cc: Usama Arif +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/proc/array.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/proc/array.c b/fs/proc/array.c +index 2ae63189091e0..038d4b57127fe 100644 +--- a/fs/proc/array.c ++++ b/fs/proc/array.c +@@ -529,7 +529,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, + } + + sid = task_session_nr_ns(task, ns); +- ppid = task_tgid_nr_ns(task->real_parent, ns); ++ ppid = task_ppid_nr_ns(task, ns); + pgid = task_pgrp_nr_ns(task, ns); + + unlock_task_sighand(task, &flags); +-- +2.51.0 + diff --git a/queue-6.18/pstore-ram-fix-buffer-overflow-in-persistent_ram_sav.patch b/queue-6.18/pstore-ram-fix-buffer-overflow-in-persistent_ram_sav.patch new file mode 100644 index 0000000000..4dcb13dcd1 --- /dev/null +++ b/queue-6.18/pstore-ram-fix-buffer-overflow-in-persistent_ram_sav.patch @@ -0,0 +1,92 @@ +From 7a461ccaf8def0c2852683de22a1d7060f00c898 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 1 Feb 2026 13:22:40 +0000 +Subject: pstore/ram: fix buffer overflow in persistent_ram_save_old() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Sai Ritvik Tanksalkar + +[ Upstream commit 5669645c052f235726a85f443769b6fc02f66762 ] + +persistent_ram_save_old() can be called multiple times for the same +persistent_ram_zone (e.g., via ramoops_pstore_read -> ramoops_get_next_prz +for PSTORE_TYPE_DMESG records). + +Currently, the function only allocates prz->old_log when it is NULL, +but it unconditionally updates prz->old_log_size to the current buffer +size and then performs memcpy_fromio() using this new size. If the +buffer size has grown since the first allocation (which can happen +across different kernel boot cycles), this leads to: + +1. A heap buffer overflow (OOB write) in the memcpy_fromio() calls +2. A subsequent OOB read when ramoops_pstore_read() accesses the buffer + using the incorrect (larger) old_log_size + +The KASAN splat would look similar to: + BUG: KASAN: slab-out-of-bounds in ramoops_pstore_read+0x... + Read of size N at addr ... by task ... + +The conditions are likely extremely hard to hit: + + 0. Crash with a ramoops write of less-than-record-max-size bytes. + 1. Reboot: ramoops registers, pstore_get_records(0) reads old crash, + allocates old_log with size X + 2. Crash handler registered, timer started (if pstore_update_ms >= 0) + 3. Oops happens (non-fatal, system continues) + 4. pstore_dump() writes oops via ramoops_pstore_write() size Y (>X) + 5. pstore_new_entry = 1, pstore_timer_kick() called + 6. System continues running (not a panic oops) + 7. Timer fires after pstore_update_ms milliseconds + 8. pstore_timefunc() → schedule_work() → pstore_dowork() → pstore_get_records(1) + 9. ramoops_get_next_prz() → persistent_ram_save_old() + 10. buffer_size() returns Y, but old_log is X bytes + 11. Y > X: memcpy_fromio() overflows heap + + Requirements: + - a prior crash record exists that did not fill the record size + (almost impossible since the crash handler writes as much as it + can possibly fit into the record, capped by max record size and + the kmsg buffer almost always exceeds the max record size) + - pstore_update_ms >= 0 (disabled by default) + - Non-fatal oops (system survives) + +Free and reallocate the buffer when the new size differs from the +previously allocated size. This ensures old_log always has sufficient +space for the data being copied. + +Fixes: 201e4aca5aa1 ("pstore/ram: Should update old dmesg buffer before reading") +Signed-off-by: Sai Ritvik Tanksalkar +Link: https://patch.msgid.link/20260201132240.2948732-1-stanksal@purdue.edu +Signed-off-by: Kees Cook +Signed-off-by: Sasha Levin +--- + fs/pstore/ram_core.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c +index f1848cdd6d348..c9eaacdec37e4 100644 +--- a/fs/pstore/ram_core.c ++++ b/fs/pstore/ram_core.c +@@ -298,6 +298,17 @@ void persistent_ram_save_old(struct persistent_ram_zone *prz) + if (!size) + return; + ++ /* ++ * If the existing buffer is differently sized, free it so a new ++ * one is allocated. This can happen when persistent_ram_save_old() ++ * is called early in boot and later for a timer-triggered ++ * survivable crash when the crash dumps don't match in size ++ * (which would be extremely unlikely given kmsg buffers usually ++ * exceed prz buffer sizes). ++ */ ++ if (prz->old_log && prz->old_log_size != size) ++ persistent_ram_free_old(prz); ++ + if (!prz->old_log) { + persistent_ram_ecc_old(prz); + prz->old_log = kvzalloc(size, GFP_KERNEL); +-- +2.51.0 + diff --git a/queue-6.18/pwm-tiehrpwm-enable-pwmchip-s-parent-device-before-s.patch b/queue-6.18/pwm-tiehrpwm-enable-pwmchip-s-parent-device-before-s.patch new file mode 100644 index 0000000000..c5c9cbd62c --- /dev/null +++ b/queue-6.18/pwm-tiehrpwm-enable-pwmchip-s-parent-device-before-s.patch @@ -0,0 +1,69 @@ +From 0dcf3a01fb51266166e0b91080762502e8f53e50 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 11:41:34 +0530 +Subject: pwm: tiehrpwm: Enable pwmchip's parent device before setting + configuration +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Gokul Praveen + +[ Upstream commit 75e7ed52ac7c1da90f304dcda2906636404df921 ] + +The period and duty cycle configurations on J7200 and J784S4 SoCs +does not get reflected after setting them using sysfs nodes. +This is because at the end of ehrpwm_pwm_config function, +the put_sync function is called which resets the hardware. + +Hold the PWM controller out of low-power mode during .apply() to +make sure it accepts the writes to its registers. + +This renders the calls to pm_runtime_get_sync() and +pm_runtime_put_sync() in ehrpwm_pwm_config() into no-ops, so +these can be dropped. + +Fixes: 5f027d9b83db ("pwm: tiehrpwm: Implement .apply() callback") +Signed-off-by: Gokul Praveen +Suggested-by: Uwe Kleine-König +Link: https://patch.msgid.link/20260121061134.15466-1-g-praveen@ti.com +Signed-off-by: Uwe Kleine-König +Signed-off-by: Sasha Levin +--- + drivers/pwm/pwm-tiehrpwm.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c +index 7a86cb090f76f..2533c95b0ba9d 100644 +--- a/drivers/pwm/pwm-tiehrpwm.c ++++ b/drivers/pwm/pwm-tiehrpwm.c +@@ -237,8 +237,6 @@ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, + if (period_cycles < 1) + period_cycles = 1; + +- pm_runtime_get_sync(pwmchip_parent(chip)); +- + /* Update clock prescaler values */ + ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_CLKDIV_MASK, tb_divval); + +@@ -290,8 +288,6 @@ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, + if (!(duty_cycles > period_cycles)) + ehrpwm_write(pc->mmio_base, cmp_reg, duty_cycles); + +- pm_runtime_put_sync(pwmchip_parent(chip)); +- + return 0; + } + +@@ -378,6 +374,8 @@ static int ehrpwm_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + int err; + bool enabled = pwm->state.enabled; + ++ guard(pm_runtime_active)(pwmchip_parent(chip)); ++ + if (state->polarity != pwm->state.polarity) { + if (enabled) { + ehrpwm_pwm_disable(chip, pwm); +-- +2.51.0 + diff --git a/queue-6.18/quota-fix-livelock-between-quotactl-and-freeze_super.patch b/queue-6.18/quota-fix-livelock-between-quotactl-and-freeze_super.patch new file mode 100644 index 0000000000..4eb6209795 --- /dev/null +++ b/queue-6.18/quota-fix-livelock-between-quotactl-and-freeze_super.patch @@ -0,0 +1,73 @@ +From 08f11ed9304f8a63dbafe7c312fff0aa75e12ecb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 21:31:03 +0000 +Subject: quota: fix livelock between quotactl and freeze_super + +From: Abhishek Bapat + +[ Upstream commit 77449e453dfc006ad738dec55374c4cbc056fd39 ] + +When a filesystem is frozen, quotactl_block() enters a retry loop +waiting for the filesystem to thaw. It acquires s_umount, checks the +freeze state, drops s_umount and uses sb_start_write() - sb_end_write() +pair to wait for the unfreeze. + +However, this retry loop can trigger a livelock issue, specifically on +kernels with preemption disabled. + +The mechanism is as follows: +1. freeze_super() sets SB_FREEZE_WRITE and calls sb_wait_write(). +2. sb_wait_write() calls percpu_down_write(), which initiates + synchronize_rcu(). +3. Simultaneously, quotactl_block() spins in its retry loop, immediately + executing the sb_start_write() - sb_end_write() pair. +4. Because the kernel is non-preemptible and the loop contains no + scheduling points, quotactl_block() never yields the CPU. This + prevents that CPU from reaching an RCU quiescent state. +5. synchronize_rcu() in the freezer thread waits indefinitely for the + quotactl_block() CPU to report a quiescent state. +6. quotactl_block() spins indefinitely waiting for the freezer to + advance, which it cannot do as it is blocked on the RCU sync. + +This results in a hang of the freezer process and 100% CPU usage by the +quota process. + +While this can occur intermittently on multi-core systems, it is +reliably reproducing on a node with the following script, running both +the freezer and the quota toggle on the same CPU: + + # mkfs.ext4 -O quota /dev/sda 2g && mkdir a_mount + # mount /dev/sda -o quota,usrquota,grpquota a_mount + # taskset -c 3 bash -c "while true; do xfs_freeze -f a_mount; \ + xfs_freeze -u a_mount; done" & + # taskset -c 3 bash -c "while true; do quotaon a_mount; \ + quotaoff a_mount; done" & + +Adding cond_resched() to the retry loop fixes the issue. It acts as an +RCU quiescent state, allowing synchronize_rcu() in percpu_down_write() +to complete. + +Fixes: 576215cffdef ("fs: Drop wait_unfrozen wait queue") +Signed-off-by: Abhishek Bapat +Link: https://patch.msgid.link/20260115213103.1089129-1-abhishekbapat@google.com +Signed-off-by: Jan Kara +Signed-off-by: Sasha Levin +--- + fs/quota/quota.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/quota/quota.c b/fs/quota/quota.c +index 7c2b75a444852..de4379a9c7920 100644 +--- a/fs/quota/quota.c ++++ b/fs/quota/quota.c +@@ -899,6 +899,7 @@ static struct super_block *quotactl_block(const char __user *special, int cmd) + sb_start_write(sb); + sb_end_write(sb); + put_super(sb); ++ cond_resched(); + goto retry; + } + return sb; +-- +2.51.0 + diff --git a/queue-6.18/rcu-fix-rcu_read_unlock-deadloop-due-to-softirq.patch b/queue-6.18/rcu-fix-rcu_read_unlock-deadloop-due-to-softirq.patch new file mode 100644 index 0000000000..6b35973110 --- /dev/null +++ b/queue-6.18/rcu-fix-rcu_read_unlock-deadloop-due-to-softirq.patch @@ -0,0 +1,168 @@ +From 7812aed90643995f9a958e502bdd204303b138ff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 1 Jan 2026 11:34:10 -0500 +Subject: rcu: Fix rcu_read_unlock() deadloop due to softirq + +From: Yao Kai + +[ Upstream commit d41e37f26b3157b3f1d10223863519a943aa239b ] + +Commit 5f5fa7ea89dc ("rcu: Don't use negative nesting depth in +__rcu_read_unlock()") removes the recursion-protection code from +__rcu_read_unlock(). Therefore, we could invoke the deadloop in +raise_softirq_irqoff() with ftrace enabled as follows: + +WARNING: CPU: 0 PID: 0 at kernel/trace/trace.c:3021 __ftrace_trace_stack.constprop.0+0x172/0x180 +Modules linked in: my_irq_work(O) +CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Tainted: G O 6.18.0-rc7-dirty #23 PREEMPT(full) +Tainted: [O]=OOT_MODULE +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014 +RIP: 0010:__ftrace_trace_stack.constprop.0+0x172/0x180 +RSP: 0018:ffffc900000034a8 EFLAGS: 00010002 +RAX: 0000000000000000 RBX: 0000000000000004 RCX: 0000000000000000 +RDX: 0000000000000003 RSI: ffffffff826d7b87 RDI: ffffffff826e9329 +RBP: 0000000000090009 R08: 0000000000000005 R09: ffffffff82afbc4c +R10: 0000000000000008 R11: 0000000000011d7a R12: 0000000000000000 +R13: ffff888003874100 R14: 0000000000000003 R15: ffff8880038c1054 +FS: 0000000000000000(0000) GS:ffff8880fa8ea000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 000055b31fa7f540 CR3: 00000000078f4005 CR4: 0000000000770ef0 +PKRU: 55555554 +Call Trace: + + trace_buffer_unlock_commit_regs+0x6d/0x220 + trace_event_buffer_commit+0x5c/0x260 + trace_event_raw_event_softirq+0x47/0x80 + raise_softirq_irqoff+0x6e/0xa0 + rcu_read_unlock_special+0xb1/0x160 + unwind_next_frame+0x203/0x9b0 + __unwind_start+0x15d/0x1c0 + arch_stack_walk+0x62/0xf0 + stack_trace_save+0x48/0x70 + __ftrace_trace_stack.constprop.0+0x144/0x180 + trace_buffer_unlock_commit_regs+0x6d/0x220 + trace_event_buffer_commit+0x5c/0x260 + trace_event_raw_event_softirq+0x47/0x80 + raise_softirq_irqoff+0x6e/0xa0 + rcu_read_unlock_special+0xb1/0x160 + unwind_next_frame+0x203/0x9b0 + __unwind_start+0x15d/0x1c0 + arch_stack_walk+0x62/0xf0 + stack_trace_save+0x48/0x70 + __ftrace_trace_stack.constprop.0+0x144/0x180 + trace_buffer_unlock_commit_regs+0x6d/0x220 + trace_event_buffer_commit+0x5c/0x260 + trace_event_raw_event_softirq+0x47/0x80 + raise_softirq_irqoff+0x6e/0xa0 + rcu_read_unlock_special+0xb1/0x160 + unwind_next_frame+0x203/0x9b0 + __unwind_start+0x15d/0x1c0 + arch_stack_walk+0x62/0xf0 + stack_trace_save+0x48/0x70 + __ftrace_trace_stack.constprop.0+0x144/0x180 + trace_buffer_unlock_commit_regs+0x6d/0x220 + trace_event_buffer_commit+0x5c/0x260 + trace_event_raw_event_softirq+0x47/0x80 + raise_softirq_irqoff+0x6e/0xa0 + rcu_read_unlock_special+0xb1/0x160 + __is_insn_slot_addr+0x54/0x70 + kernel_text_address+0x48/0xc0 + __kernel_text_address+0xd/0x40 + unwind_get_return_address+0x1e/0x40 + arch_stack_walk+0x9c/0xf0 + stack_trace_save+0x48/0x70 + __ftrace_trace_stack.constprop.0+0x144/0x180 + trace_buffer_unlock_commit_regs+0x6d/0x220 + trace_event_buffer_commit+0x5c/0x260 + trace_event_raw_event_softirq+0x47/0x80 + __raise_softirq_irqoff+0x61/0x80 + __flush_smp_call_function_queue+0x115/0x420 + __sysvec_call_function_single+0x17/0xb0 + sysvec_call_function_single+0x8c/0xc0 + + +Commit b41642c87716 ("rcu: Fix rcu_read_unlock() deadloop due to IRQ work") +fixed the infinite loop in rcu_read_unlock_special() for IRQ work by +setting a flag before calling irq_work_queue_on(). We fix this issue by +setting the same flag before calling raise_softirq_irqoff() and rename the +flag to defer_qs_pending for more common. + +Fixes: 5f5fa7ea89dc ("rcu: Don't use negative nesting depth in __rcu_read_unlock()") +Reported-by: Tengda Wu +Signed-off-by: Yao Kai +Reviewed-by: Joel Fernandes +Tested-by: Paul E. McKenney +Signed-off-by: Joel Fernandes +Signed-off-by: Boqun Feng +Signed-off-by: Sasha Levin +--- + kernel/rcu/tree.h | 2 +- + kernel/rcu/tree_plugin.h | 15 +++++++++------ + 2 files changed, 10 insertions(+), 7 deletions(-) + +diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h +index b8bbe7960cda7..2265b9c2906e1 100644 +--- a/kernel/rcu/tree.h ++++ b/kernel/rcu/tree.h +@@ -203,7 +203,7 @@ struct rcu_data { + /* during and after the last grace */ + /* period it is aware of. */ + struct irq_work defer_qs_iw; /* Obtain later scheduler attention. */ +- int defer_qs_iw_pending; /* Scheduler attention pending? */ ++ int defer_qs_pending; /* irqwork or softirq pending? */ + struct work_struct strict_work; /* Schedule readers for strict GPs. */ + + /* 2) batch handling */ +diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h +index d85763336b3c0..cafb1cc8eff84 100644 +--- a/kernel/rcu/tree_plugin.h ++++ b/kernel/rcu/tree_plugin.h +@@ -487,8 +487,8 @@ rcu_preempt_deferred_qs_irqrestore(struct task_struct *t, unsigned long flags) + union rcu_special special; + + rdp = this_cpu_ptr(&rcu_data); +- if (rdp->defer_qs_iw_pending == DEFER_QS_PENDING) +- rdp->defer_qs_iw_pending = DEFER_QS_IDLE; ++ if (rdp->defer_qs_pending == DEFER_QS_PENDING) ++ rdp->defer_qs_pending = DEFER_QS_IDLE; + + /* + * If RCU core is waiting for this CPU to exit its critical section, +@@ -645,7 +645,7 @@ static void rcu_preempt_deferred_qs_handler(struct irq_work *iwp) + * 5. Deferred QS reporting does not happen. + */ + if (rcu_preempt_depth() > 0) +- WRITE_ONCE(rdp->defer_qs_iw_pending, DEFER_QS_IDLE); ++ WRITE_ONCE(rdp->defer_qs_pending, DEFER_QS_IDLE); + } + + /* +@@ -747,7 +747,10 @@ static void rcu_read_unlock_special(struct task_struct *t) + // Using softirq, safe to awaken, and either the + // wakeup is free or there is either an expedited + // GP in flight or a potential need to deboost. +- raise_softirq_irqoff(RCU_SOFTIRQ); ++ if (rdp->defer_qs_pending != DEFER_QS_PENDING) { ++ rdp->defer_qs_pending = DEFER_QS_PENDING; ++ raise_softirq_irqoff(RCU_SOFTIRQ); ++ } + } else { + // Enabling BH or preempt does reschedule, so... + // Also if no expediting and no possible deboosting, +@@ -756,11 +759,11 @@ static void rcu_read_unlock_special(struct task_struct *t) + set_tsk_need_resched(current); + set_preempt_need_resched(); + if (IS_ENABLED(CONFIG_IRQ_WORK) && irqs_were_disabled && +- needs_exp && rdp->defer_qs_iw_pending != DEFER_QS_PENDING && ++ needs_exp && rdp->defer_qs_pending != DEFER_QS_PENDING && + cpu_online(rdp->cpu)) { + // Get scheduler to re-evaluate and call hooks. + // If !IRQ_WORK, FQS scan will eventually IPI. +- rdp->defer_qs_iw_pending = DEFER_QS_PENDING; ++ rdp->defer_qs_pending = DEFER_QS_PENDING; + irq_work_queue_on(&rdp->defer_qs_iw, rdp->cpu); + } + } +-- +2.51.0 + diff --git a/queue-6.18/rdma-core-add-rdma_rw_max_sge-helper-for-sq-sizing.patch b/queue-6.18/rdma-core-add-rdma_rw_max_sge-helper-for-sq-sizing.patch new file mode 100644 index 0000000000..5312e137e9 --- /dev/null +++ b/queue-6.18/rdma-core-add-rdma_rw_max_sge-helper-for-sq-sizing.patch @@ -0,0 +1,159 @@ +From 713ca265d28f92ae8df36a939e058ffab88179df Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 19:53:59 -0500 +Subject: RDMA/core: add rdma_rw_max_sge() helper for SQ sizing + +From: Chuck Lever + +[ Upstream commit afcae7d7b8a278a6c29e064f99e5bafd4ac1fb37 ] + +svc_rdma_accept() computes sc_sq_depth as the sum of rq_depth and the +number of rdma_rw contexts (ctxts). This value is used to allocate the +Send CQ and to initialize the sc_sq_avail credit pool. + +However, when the device uses memory registration for RDMA operations, +rdma_rw_init_qp() inflates the QP's max_send_wr by a factor of three +per context to account for REG and INV work requests. The Send CQ and +credit pool remain sized for only one work request per context, +causing Send Queue exhaustion under heavy NFS WRITE workloads. + +Introduce rdma_rw_max_sge() to compute the actual number of Send Queue +entries required for a given number of rdma_rw contexts. Upper layer +protocols call this helper before creating a Queue Pair so that their +Send CQs and credit accounting match the QP's true capacity. + +Update svc_rdma_accept() to use rdma_rw_max_sge() when computing +sc_sq_depth, ensuring the credit pool reflects the work requests +that rdma_rw_init_qp() will reserve. + +Reviewed-by: Christoph Hellwig +Fixes: 00bd1439f464 ("RDMA/rw: Support threshold for registration vs scattering to local pages") +Signed-off-by: Chuck Lever +Link: https://patch.msgid.link/20260128005400.25147-5-cel@kernel.org +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/rw.c | 53 +++++++++++++++++------- + include/rdma/rw.h | 2 + + net/sunrpc/xprtrdma/svc_rdma_transport.c | 8 +++- + 3 files changed, 46 insertions(+), 17 deletions(-) + +diff --git a/drivers/infiniband/core/rw.c b/drivers/infiniband/core/rw.c +index 6354ddf2a274c..2522ff1cc462c 100644 +--- a/drivers/infiniband/core/rw.c ++++ b/drivers/infiniband/core/rw.c +@@ -651,34 +651,57 @@ unsigned int rdma_rw_mr_factor(struct ib_device *device, u32 port_num, + } + EXPORT_SYMBOL(rdma_rw_mr_factor); + ++/** ++ * rdma_rw_max_send_wr - compute max Send WRs needed for RDMA R/W contexts ++ * @dev: RDMA device ++ * @port_num: port number ++ * @max_rdma_ctxs: number of rdma_rw_ctx structures ++ * @create_flags: QP create flags (pass IB_QP_CREATE_INTEGRITY_EN if ++ * data integrity will be enabled on the QP) ++ * ++ * Returns the total number of Send Queue entries needed for ++ * @max_rdma_ctxs. The result accounts for memory registration and ++ * invalidation work requests when the device requires them. ++ * ++ * ULPs use this to size Send Queues and Send CQs before creating a ++ * Queue Pair. ++ */ ++unsigned int rdma_rw_max_send_wr(struct ib_device *dev, u32 port_num, ++ unsigned int max_rdma_ctxs, u32 create_flags) ++{ ++ unsigned int factor = 1; ++ unsigned int result; ++ ++ if (create_flags & IB_QP_CREATE_INTEGRITY_EN || ++ rdma_rw_can_use_mr(dev, port_num)) ++ factor += 2; /* reg + inv */ ++ ++ if (check_mul_overflow(factor, max_rdma_ctxs, &result)) ++ return UINT_MAX; ++ return result; ++} ++EXPORT_SYMBOL(rdma_rw_max_send_wr); ++ + void rdma_rw_init_qp(struct ib_device *dev, struct ib_qp_init_attr *attr) + { +- u32 factor; ++ unsigned int factor = 1; + + WARN_ON_ONCE(attr->port_num == 0); + + /* +- * Each context needs at least one RDMA READ or WRITE WR. +- * +- * For some hardware we might need more, eventually we should ask the +- * HCA driver for a multiplier here. +- */ +- factor = 1; +- +- /* +- * If the device needs MRs to perform RDMA READ or WRITE operations, +- * we'll need two additional MRs for the registrations and the +- * invalidation. ++ * If the device uses MRs to perform RDMA READ or WRITE operations, ++ * or if data integrity is enabled, account for registration and ++ * invalidation work requests. + */ + if (attr->create_flags & IB_QP_CREATE_INTEGRITY_EN || + rdma_rw_can_use_mr(dev, attr->port_num)) +- factor += 2; /* inv + reg */ ++ factor += 2; /* reg + inv */ + + attr->cap.max_send_wr += factor * attr->cap.max_rdma_ctxs; + + /* +- * But maybe we were just too high in the sky and the device doesn't +- * even support all we need, and we'll have to live with what we get.. ++ * The device might not support all we need, and we'll have to ++ * live with what we get. + */ + attr->cap.max_send_wr = + min_t(u32, attr->cap.max_send_wr, dev->attrs.max_qp_wr); +diff --git a/include/rdma/rw.h b/include/rdma/rw.h +index d606cac482338..9a8f4b76ce588 100644 +--- a/include/rdma/rw.h ++++ b/include/rdma/rw.h +@@ -66,6 +66,8 @@ int rdma_rw_ctx_post(struct rdma_rw_ctx *ctx, struct ib_qp *qp, u32 port_num, + + unsigned int rdma_rw_mr_factor(struct ib_device *device, u32 port_num, + unsigned int maxpages); ++unsigned int rdma_rw_max_send_wr(struct ib_device *dev, u32 port_num, ++ unsigned int max_rdma_ctxs, u32 create_flags); + void rdma_rw_init_qp(struct ib_device *dev, struct ib_qp_init_attr *attr); + int rdma_rw_init_mrs(struct ib_qp *qp, struct ib_qp_init_attr *attr); + void rdma_rw_cleanup_mrs(struct ib_qp *qp); +diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c +index 3d7f1413df023..12857381e8610 100644 +--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c ++++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c +@@ -462,7 +462,10 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + newxprt->sc_max_bc_requests = 2; + } + +- /* Arbitrary estimate of the needed number of rdma_rw contexts. ++ /* Estimate the needed number of rdma_rw contexts. The maximum ++ * Read and Write chunks have one segment each. Each request ++ * can involve one Read chunk and either a Write chunk or Reply ++ * chunk; thus a factor of three. + */ + maxpayload = min(xprt->xpt_server->sv_max_payload, + RPCSVC_MAXPAYLOAD_RDMA); +@@ -470,7 +473,8 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + rdma_rw_mr_factor(dev, newxprt->sc_port_num, + maxpayload >> PAGE_SHIFT); + +- newxprt->sc_sq_depth = rq_depth + ctxts; ++ newxprt->sc_sq_depth = rq_depth + ++ rdma_rw_max_send_wr(dev, newxprt->sc_port_num, ctxts, 0); + if (newxprt->sc_sq_depth > dev->attrs.max_qp_wr) + newxprt->sc_sq_depth = dev->attrs.max_qp_wr; + atomic_set(&newxprt->sc_sq_avail, newxprt->sc_sq_depth); +-- +2.51.0 + diff --git a/queue-6.18/rdma-hns-fix-rocev1-failure-due-to-dscp.patch b/queue-6.18/rdma-hns-fix-rocev1-failure-due-to-dscp.patch new file mode 100644 index 0000000000..7a49b5e078 --- /dev/null +++ b/queue-6.18/rdma-hns-fix-rocev1-failure-due-to-dscp.patch @@ -0,0 +1,112 @@ +From ba9e5cbd6e3d698f99c77f8ea037685115e975bf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 4 Jan 2026 14:40:56 +0800 +Subject: RDMA/hns: Fix RoCEv1 failure due to DSCP + +From: Junxian Huang + +[ Upstream commit 84bd5d60f0a2b9c763c5e6d0b3d8f4f61f6c5470 ] + +DSCP is not supported in RoCEv1, but get_dscp() is still called. If +get_dscp() returns an error, it'll eventually cause create_ah to fail +even when using RoCEv1. + +Correct the return value and avoid calling get_dscp() when using +RoCEv1. + +Fixes: ee20cc17e9d8 ("RDMA/hns: Support DSCP") +Signed-off-by: Junxian Huang +Link: https://patch.msgid.link/20260104064057.1582216-4-huangjunxian6@hisilicon.com +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/hw/hns/hns_roce_ah.c | 23 +++++++++--------- + drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 28 ++++++++++++---------- + 2 files changed, 26 insertions(+), 25 deletions(-) + +diff --git a/drivers/infiniband/hw/hns/hns_roce_ah.c b/drivers/infiniband/hw/hns/hns_roce_ah.c +index 307c35888b300..3b6c6a6e9f977 100644 +--- a/drivers/infiniband/hw/hns/hns_roce_ah.c ++++ b/drivers/infiniband/hw/hns/hns_roce_ah.c +@@ -61,7 +61,7 @@ int hns_roce_create_ah(struct ib_ah *ibah, struct rdma_ah_init_attr *init_attr, + u8 tclass = get_tclass(grh); + u8 priority = 0; + u8 tc_mode = 0; +- int ret; ++ int ret = 0; + + if (hr_dev->pci_dev->revision == PCI_REVISION_ID_HIP08 && udata) { + ret = -EOPNOTSUPP; +@@ -78,19 +78,18 @@ int hns_roce_create_ah(struct ib_ah *ibah, struct rdma_ah_init_attr *init_attr, + ah->av.flowlabel = grh->flow_label; + ah->av.udp_sport = get_ah_udp_sport(ah_attr); + ah->av.tclass = tclass; ++ ah->av.sl = rdma_ah_get_sl(ah_attr); + +- ret = hr_dev->hw->get_dscp(hr_dev, tclass, &tc_mode, &priority); +- if (ret == -EOPNOTSUPP) +- ret = 0; +- +- if (ret && grh->sgid_attr->gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) +- goto err_out; ++ if (grh->sgid_attr->gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) { ++ ret = hr_dev->hw->get_dscp(hr_dev, tclass, &tc_mode, &priority); ++ if (ret == -EOPNOTSUPP) ++ ret = 0; ++ else if (ret) ++ goto err_out; + +- if (tc_mode == HNAE3_TC_MAP_MODE_DSCP && +- grh->sgid_attr->gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) +- ah->av.sl = priority; +- else +- ah->av.sl = rdma_ah_get_sl(ah_attr); ++ if (tc_mode == HNAE3_TC_MAP_MODE_DSCP) ++ ah->av.sl = priority; ++ } + + if (!check_sl_valid(hr_dev, ah->av.sl)) { + ret = -EINVAL; +diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +index cb0bbc4167b0d..b0e7c5c6e2ff5 100644 +--- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c ++++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +@@ -4975,20 +4975,22 @@ static int hns_roce_set_sl(struct ib_qp *ibqp, + struct ib_device *ibdev = &hr_dev->ib_dev; + int ret; + +- ret = hns_roce_hw_v2_get_dscp(hr_dev, get_tclass(&attr->ah_attr.grh), +- &hr_qp->tc_mode, &hr_qp->priority); +- if (ret && ret != -EOPNOTSUPP && +- grh->sgid_attr->gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) { +- ibdev_err_ratelimited(ibdev, +- "failed to get dscp, ret = %d.\n", ret); +- return ret; +- } ++ hr_qp->sl = rdma_ah_get_sl(&attr->ah_attr); + +- if (hr_qp->tc_mode == HNAE3_TC_MAP_MODE_DSCP && +- grh->sgid_attr->gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) +- hr_qp->sl = hr_qp->priority; +- else +- hr_qp->sl = rdma_ah_get_sl(&attr->ah_attr); ++ if (grh->sgid_attr->gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) { ++ ret = hns_roce_hw_v2_get_dscp(hr_dev, ++ get_tclass(&attr->ah_attr.grh), ++ &hr_qp->tc_mode, &hr_qp->priority); ++ if (ret && ret != -EOPNOTSUPP) { ++ ibdev_err_ratelimited(ibdev, ++ "failed to get dscp, ret = %d.\n", ++ ret); ++ return ret; ++ } ++ ++ if (hr_qp->tc_mode == HNAE3_TC_MAP_MODE_DSCP) ++ hr_qp->sl = hr_qp->priority; ++ } + + if (!check_sl_valid(hr_dev, hr_qp->sl)) + return -EINVAL; +-- +2.51.0 + diff --git a/queue-6.18/rdma-hns-fix-wq_mem_reclaim-warning.patch b/queue-6.18/rdma-hns-fix-wq_mem_reclaim-warning.patch new file mode 100644 index 0000000000..248afacccd --- /dev/null +++ b/queue-6.18/rdma-hns-fix-wq_mem_reclaim-warning.patch @@ -0,0 +1,62 @@ +From 098cce3906bd6018ce6e5d7416a17fd8191e4167 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 4 Jan 2026 14:40:54 +0800 +Subject: RDMA/hns: Fix WQ_MEM_RECLAIM warning + +From: Chengchang Tang + +[ Upstream commit c0a26bbd3f99b7b03f072e3409aff4e6ec8af6f6 ] + +When sunrpc is used, if a reset triggered, our wq may lead the +following trace: + +workqueue: WQ_MEM_RECLAIM xprtiod:xprt_rdma_connect_worker [rpcrdma] +is flushing !WQ_MEM_RECLAIM hns_roce_irq_workq:flush_work_handle +[hns_roce_hw_v2] +WARNING: CPU: 0 PID: 8250 at kernel/workqueue.c:2644 check_flush_dependency+0xe0/0x144 +Call trace: + check_flush_dependency+0xe0/0x144 + start_flush_work.constprop.0+0x1d0/0x2f0 + __flush_work.isra.0+0x40/0xb0 + flush_work+0x14/0x30 + hns_roce_v2_destroy_qp+0xac/0x1e0 [hns_roce_hw_v2] + ib_destroy_qp_user+0x9c/0x2b4 + rdma_destroy_qp+0x34/0xb0 + rpcrdma_ep_destroy+0x28/0xcc [rpcrdma] + rpcrdma_ep_put+0x74/0xb4 [rpcrdma] + rpcrdma_xprt_disconnect+0x1d8/0x260 [rpcrdma] + xprt_rdma_connect_worker+0xc0/0x120 [rpcrdma] + process_one_work+0x1cc/0x4d0 + worker_thread+0x154/0x414 + kthread+0x104/0x144 + ret_from_fork+0x10/0x18 + +Since QP destruction frees memory, this wq should have the WQ_MEM_RECLAIM. + +Fixes: ffd541d45726 ("RDMA/hns: Add the workqueue framework for flush cqe handler") +Signed-off-by: Chengchang Tang +Signed-off-by: Junxian Huang +Link: https://patch.msgid.link/20260104064057.1582216-2-huangjunxian6@hisilicon.com +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +index 63052c0e76133..cb0bbc4167b0d 100644 +--- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c ++++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +@@ -6878,7 +6878,8 @@ static int hns_roce_v2_init_eq_table(struct hns_roce_dev *hr_dev) + + INIT_WORK(&hr_dev->ecc_work, fmea_ram_ecc_work); + +- hr_dev->irq_workq = alloc_ordered_workqueue("hns_roce_irq_workq", 0); ++ hr_dev->irq_workq = alloc_ordered_workqueue("hns_roce_irq_workq", ++ WQ_MEM_RECLAIM); + if (!hr_dev->irq_workq) { + dev_err(dev, "failed to create irq workqueue.\n"); + ret = -ENOMEM; +-- +2.51.0 + diff --git a/queue-6.18/rdma-hns-notify-ulp-of-remaining-soft-wcs-during-res.patch b/queue-6.18/rdma-hns-notify-ulp-of-remaining-soft-wcs-during-res.patch new file mode 100644 index 0000000000..0d338bb811 --- /dev/null +++ b/queue-6.18/rdma-hns-notify-ulp-of-remaining-soft-wcs-during-res.patch @@ -0,0 +1,70 @@ +From 8eb46428ae33d5efb5d1598b9018ac9f5d428faa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 4 Jan 2026 14:40:57 +0800 +Subject: RDMA/hns: Notify ULP of remaining soft-WCs during reset + +From: Chengchang Tang + +[ Upstream commit 0789f929900d85b80b343c5f04f8b9444e991384 ] + +During a reset, software-generated WCs cannot be reported via +interrupts. This may cause the ULP to miss some WCs. + +To avoid this, add check in the CQ arm process: if a hardware reset +has occurred and there are still unreported soft-WCs, notify the ULP +to handle the remaining WCs, thereby preventing any loss of completions. + +Fixes: 626903e9355b ("RDMA/hns: Add support for reporting wc as software mode") +Signed-off-by: Chengchang Tang +Signed-off-by: Junxian Huang +Link: https://patch.msgid.link/20260104064057.1582216-5-huangjunxian6@hisilicon.com +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 23 ++++++++++++++++++++++ + 1 file changed, 23 insertions(+) + +diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +index b0e7c5c6e2ff5..f895731ad74a0 100644 +--- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c ++++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +@@ -3661,6 +3661,23 @@ static void hns_roce_v2_write_cqc(struct hns_roce_dev *hr_dev, + HNS_ROCE_V2_CQ_DEFAULT_INTERVAL); + } + ++static bool left_sw_wc(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq) ++{ ++ struct hns_roce_qp *hr_qp; ++ ++ list_for_each_entry(hr_qp, &hr_cq->sq_list, sq_node) { ++ if (hr_qp->sq.head != hr_qp->sq.tail) ++ return true; ++ } ++ ++ list_for_each_entry(hr_qp, &hr_cq->rq_list, rq_node) { ++ if (hr_qp->rq.head != hr_qp->rq.tail) ++ return true; ++ } ++ ++ return false; ++} ++ + static int hns_roce_v2_req_notify_cq(struct ib_cq *ibcq, + enum ib_cq_notify_flags flags) + { +@@ -3669,6 +3686,12 @@ static int hns_roce_v2_req_notify_cq(struct ib_cq *ibcq, + struct hns_roce_v2_db cq_db = {}; + u32 notify_flag; + ++ if (hr_dev->state >= HNS_ROCE_DEVICE_STATE_RST_DOWN) { ++ if ((flags & IB_CQ_REPORT_MISSED_EVENTS) && ++ left_sw_wc(hr_dev, hr_cq)) ++ return 1; ++ return 0; ++ } + /* + * flags = 0, then notify_flag : next + * flags = 1, then notify flag : solocited +-- +2.51.0 + diff --git a/queue-6.18/rdma-iwcm-fix-workqueue-list-corruption-by-removing-.patch b/queue-6.18/rdma-iwcm-fix-workqueue-list-corruption-by-removing-.patch new file mode 100644 index 0000000000..7df29464ae --- /dev/null +++ b/queue-6.18/rdma-iwcm-fix-workqueue-list-corruption-by-removing-.patch @@ -0,0 +1,206 @@ +From a5f845bf67fe730915a1ebb198ada1877d4ca03e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 02:00:06 +0000 +Subject: RDMA/iwcm: Fix workqueue list corruption by removing work_list + +From: Jacob Moroni + +[ Upstream commit 7874eeacfa42177565c01d5198726671acf7adf2 ] + +The commit e1168f0 ("RDMA/iwcm: Simplify cm_event_handler()") +changed the work submission logic to unconditionally call +queue_work() with the expectation that queue_work() would +have no effect if work was already pending. The problem is +that a free list of struct iwcm_work is used (for which +struct work_struct is embedded), so each call to queue_work() +is basically unique and therefore does indeed queue the work. + +This causes a problem in the work handler which walks the work_list +until it's empty to process entries. This means that a single +run of the work handler could process item N+1 and release it +back to the free list while the actual workqueue entry is still +queued. It could then get reused (INIT_WORK...) and lead to +list corruption in the workqueue logic. + +Fix this by just removing the work_list. The workqueue already +does this for us. + +This fixes the following error that was observed when stress +testing with ucmatose on an Intel E830 in iWARP mode: + +[ 151.465780] list_del corruption. next->prev should be ffff9f0915c69c08, but was ffff9f0a1116be08. (next=ffff9f0a15b11c08) +[ 151.466639] ------------[ cut here ]------------ +[ 151.466986] kernel BUG at lib/list_debug.c:67! +[ 151.467349] Oops: invalid opcode: 0000 [#1] SMP NOPTI +[ 151.467753] CPU: 14 UID: 0 PID: 2306 Comm: kworker/u64:18 Not tainted 6.19.0-rc4+ #1 PREEMPT(voluntary) +[ 151.468466] Hardware name: QEMU Ubuntu 24.04 PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 +[ 151.469192] Workqueue: 0x0 (iw_cm_wq) +[ 151.469478] RIP: 0010:__list_del_entry_valid_or_report+0xf0/0x100 +[ 151.469942] Code: c7 58 5f 4c b2 e8 10 50 aa ff 0f 0b 48 89 ef e8 36 57 cb ff 48 8b 55 08 48 89 e9 48 89 de 48 c7 c7 a8 5f 4c b2 e8 f0 4f aa ff <0f> 0b 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 90 90 90 90 90 90 +[ 151.471323] RSP: 0000:ffffb15644e7bd68 EFLAGS: 00010046 +[ 151.471712] RAX: 000000000000006d RBX: ffff9f0915c69c08 RCX: 0000000000000027 +[ 151.472243] RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff9f0a37d9c600 +[ 151.472768] RBP: ffff9f0a15b11c08 R08: 0000000000000000 R09: c0000000ffff7fff +[ 151.473294] R10: 0000000000000001 R11: ffffb15644e7bba8 R12: ffff9f092339ee68 +[ 151.473817] R13: ffff9f0900059c28 R14: ffff9f092339ee78 R15: 0000000000000000 +[ 151.474344] FS: 0000000000000000(0000) GS:ffff9f0a847b5000(0000) knlGS:0000000000000000 +[ 151.474934] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 151.475362] CR2: 0000559e233a9088 CR3: 000000020296b004 CR4: 0000000000770ef0 +[ 151.475895] PKRU: 55555554 +[ 151.476118] Call Trace: +[ 151.476331] +[ 151.476497] move_linked_works+0x49/0xa0 +[ 151.476792] __pwq_activate_work.isra.46+0x2f/0xa0 +[ 151.477151] pwq_dec_nr_in_flight+0x1e0/0x2f0 +[ 151.477479] process_scheduled_works+0x1c8/0x410 +[ 151.477823] worker_thread+0x125/0x260 +[ 151.478108] ? __pfx_worker_thread+0x10/0x10 +[ 151.478430] kthread+0xfe/0x240 +[ 151.478671] ? __pfx_kthread+0x10/0x10 +[ 151.478955] ? __pfx_kthread+0x10/0x10 +[ 151.479240] ret_from_fork+0x208/0x270 +[ 151.479523] ? __pfx_kthread+0x10/0x10 +[ 151.479806] ret_from_fork_asm+0x1a/0x30 +[ 151.480103] + +Fixes: e1168f09b331 ("RDMA/iwcm: Simplify cm_event_handler()") +Signed-off-by: Jacob Moroni +Link: https://patch.msgid.link/20260112020006.1352438-1-jmoroni@google.com +Reviewed-by: Bart Van Assche +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/iwcm.c | 56 +++++++++++++--------------------- + drivers/infiniband/core/iwcm.h | 1 - + 2 files changed, 21 insertions(+), 36 deletions(-) + +diff --git a/drivers/infiniband/core/iwcm.c b/drivers/infiniband/core/iwcm.c +index 62410578dec37..eb942ab9c4055 100644 +--- a/drivers/infiniband/core/iwcm.c ++++ b/drivers/infiniband/core/iwcm.c +@@ -95,7 +95,6 @@ static struct workqueue_struct *iwcm_wq; + struct iwcm_work { + struct work_struct work; + struct iwcm_id_private *cm_id; +- struct list_head list; + struct iw_cm_event event; + struct list_head free_list; + }; +@@ -178,7 +177,6 @@ static int alloc_work_entries(struct iwcm_id_private *cm_id_priv, int count) + return -ENOMEM; + } + work->cm_id = cm_id_priv; +- INIT_LIST_HEAD(&work->list); + put_work(work); + } + return 0; +@@ -213,7 +211,6 @@ static void free_cm_id(struct iwcm_id_private *cm_id_priv) + static bool iwcm_deref_id(struct iwcm_id_private *cm_id_priv) + { + if (refcount_dec_and_test(&cm_id_priv->refcount)) { +- BUG_ON(!list_empty(&cm_id_priv->work_list)); + free_cm_id(cm_id_priv); + return true; + } +@@ -260,7 +257,6 @@ struct iw_cm_id *iw_create_cm_id(struct ib_device *device, + refcount_set(&cm_id_priv->refcount, 1); + init_waitqueue_head(&cm_id_priv->connect_wait); + init_completion(&cm_id_priv->destroy_comp); +- INIT_LIST_HEAD(&cm_id_priv->work_list); + INIT_LIST_HEAD(&cm_id_priv->work_free_list); + + return &cm_id_priv->id; +@@ -1007,13 +1003,13 @@ static int process_event(struct iwcm_id_private *cm_id_priv, + } + + /* +- * Process events on the work_list for the cm_id. If the callback +- * function requests that the cm_id be deleted, a flag is set in the +- * cm_id flags to indicate that when the last reference is +- * removed, the cm_id is to be destroyed. This is necessary to +- * distinguish between an object that will be destroyed by the app +- * thread asleep on the destroy_comp list vs. an object destroyed +- * here synchronously when the last reference is removed. ++ * Process events for the cm_id. If the callback function requests ++ * that the cm_id be deleted, a flag is set in the cm_id flags to ++ * indicate that when the last reference is removed, the cm_id is ++ * to be destroyed. This is necessary to distinguish between an ++ * object that will be destroyed by the app thread asleep on the ++ * destroy_comp list vs. an object destroyed here synchronously ++ * when the last reference is removed. + */ + static void cm_work_handler(struct work_struct *_work) + { +@@ -1024,35 +1020,26 @@ static void cm_work_handler(struct work_struct *_work) + int ret = 0; + + spin_lock_irqsave(&cm_id_priv->lock, flags); +- while (!list_empty(&cm_id_priv->work_list)) { +- work = list_first_entry(&cm_id_priv->work_list, +- struct iwcm_work, list); +- list_del_init(&work->list); +- levent = work->event; +- put_work(work); +- spin_unlock_irqrestore(&cm_id_priv->lock, flags); +- +- if (!test_bit(IWCM_F_DROP_EVENTS, &cm_id_priv->flags)) { +- ret = process_event(cm_id_priv, &levent); +- if (ret) { +- destroy_cm_id(&cm_id_priv->id); +- WARN_ON_ONCE(iwcm_deref_id(cm_id_priv)); +- } +- } else +- pr_debug("dropping event %d\n", levent.event); +- if (iwcm_deref_id(cm_id_priv)) +- return; +- spin_lock_irqsave(&cm_id_priv->lock, flags); +- } ++ levent = work->event; ++ put_work(work); + spin_unlock_irqrestore(&cm_id_priv->lock, flags); ++ ++ if (!test_bit(IWCM_F_DROP_EVENTS, &cm_id_priv->flags)) { ++ ret = process_event(cm_id_priv, &levent); ++ if (ret) { ++ destroy_cm_id(&cm_id_priv->id); ++ WARN_ON_ONCE(iwcm_deref_id(cm_id_priv)); ++ } ++ } else ++ pr_debug("dropping event %d\n", levent.event); ++ if (iwcm_deref_id(cm_id_priv)) ++ return; + } + + /* + * This function is called on interrupt context. Schedule events on + * the iwcm_wq thread to allow callback functions to downcall into +- * the CM and/or block. Events are queued to a per-CM_ID +- * work_list. If this is the first event on the work_list, the work +- * element is also queued on the iwcm_wq thread. ++ * the CM and/or block. + * + * Each event holds a reference on the cm_id. Until the last posted + * event has been delivered and processed, the cm_id cannot be +@@ -1094,7 +1081,6 @@ static int cm_event_handler(struct iw_cm_id *cm_id, + } + + refcount_inc(&cm_id_priv->refcount); +- list_add_tail(&work->list, &cm_id_priv->work_list); + queue_work(iwcm_wq, &work->work); + out: + spin_unlock_irqrestore(&cm_id_priv->lock, flags); +diff --git a/drivers/infiniband/core/iwcm.h b/drivers/infiniband/core/iwcm.h +index bf74639be1287..b56fb12edece4 100644 +--- a/drivers/infiniband/core/iwcm.h ++++ b/drivers/infiniband/core/iwcm.h +@@ -50,7 +50,6 @@ struct iwcm_id_private { + struct ib_qp *qp; + struct completion destroy_comp; + wait_queue_head_t connect_wait; +- struct list_head work_list; + spinlock_t lock; + refcount_t refcount; + struct list_head work_free_list; +-- +2.51.0 + diff --git a/queue-6.18/rdma-mlx5-fix-memory-leak-in-get_data_direct_sysfs_p.patch b/queue-6.18/rdma-mlx5-fix-memory-leak-in-get_data_direct_sysfs_p.patch new file mode 100644 index 0000000000..27ae969e95 --- /dev/null +++ b/queue-6.18/rdma-mlx5-fix-memory-leak-in-get_data_direct_sysfs_p.patch @@ -0,0 +1,57 @@ +From bedee5911337644ad2579473d786b222bbf880e5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 07:48:01 +0000 +Subject: RDMA/mlx5: Fix memory leak in GET_DATA_DIRECT_SYSFS_PATH handler + +From: Zilin Guan + +[ Upstream commit 9b9d253908478f504297ac283c514e5953ddafa6 ] + +The UVERBS_HANDLER(MLX5_IB_METHOD_GET_DATA_DIRECT_SYSFS_PATH) function +allocates memory for the device path using kobject_get_path(). If the +length of the device path exceeds the output buffer length, the function +returns -ENOSPC but does not free the allocated memory, resulting in a +memory leak. + +Add a kfree() call to the error path to ensure the allocated memory is +properly freed. + +Compile tested only. Issue found using a prototype static analysis tool +and code review. + +Fixes: ec7ad6530909 ("RDMA/mlx5: Introduce GET_DATA_DIRECT_SYSFS_PATH ioctl") +Signed-off-by: Zilin Guan +Link: https://patch.msgid.link/20260126074801.627898-1-zilin@seu.edu.cn +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/hw/mlx5/std_types.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/infiniband/hw/mlx5/std_types.c b/drivers/infiniband/hw/mlx5/std_types.c +index 2fcf553044e15..1ee31611b4b3f 100644 +--- a/drivers/infiniband/hw/mlx5/std_types.c ++++ b/drivers/infiniband/hw/mlx5/std_types.c +@@ -195,7 +195,7 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_GET_DATA_DIRECT_SYSFS_PATH)( + int out_len = uverbs_attr_get_len(attrs, + MLX5_IB_ATTR_GET_DATA_DIRECT_SYSFS_PATH); + u32 dev_path_len; +- char *dev_path; ++ char *dev_path = NULL; + int ret; + + c = to_mucontext(ib_uverbs_get_ucontext(attrs)); +@@ -223,9 +223,9 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_GET_DATA_DIRECT_SYSFS_PATH)( + + ret = uverbs_copy_to(attrs, MLX5_IB_ATTR_GET_DATA_DIRECT_SYSFS_PATH, dev_path, + dev_path_len); +- kfree(dev_path); + + end: ++ kfree(dev_path); + mutex_unlock(&dev->data_direct_lock); + return ret; + } +-- +2.51.0 + diff --git a/queue-6.18/rdma-mlx5-fix-ucaps-init-error-flow.patch b/queue-6.18/rdma-mlx5-fix-ucaps-init-error-flow.patch new file mode 100644 index 0000000000..673a1267ae --- /dev/null +++ b/queue-6.18/rdma-mlx5-fix-ucaps-init-error-flow.patch @@ -0,0 +1,52 @@ +From 42a15c6d1bbeab0eb80baac446d7db88d7397efe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 4 Jan 2026 15:51:35 +0200 +Subject: RDMA/mlx5: Fix ucaps init error flow + +From: Maher Sanalla + +[ Upstream commit 6dc78c53de99e4ed9868d4f0fc6da6e46f52fe4d ] + +In mlx5_ib_stage_caps_init(), if mlx5_ib_init_ucaps() fails after +mlx5_ib_init_var_table() succeeds, the VAR bitmap is leaked since +the function returns without cleanup. + +Thus, cleanup the var table bitmap in case of error of initializing +ucaps before exiting, preventing the leak above. + +Fixes: cf7174e8982f ("RDMA/mlx5: Create UCAP char devices for supported device capabilities") +Signed-off-by: Maher Sanalla +Reviewed-by: Yishai Hadas +Link: https://patch.msgid.link/20260104-ib-core-misc-v1-3-00367f77f3a8@nvidia.com +Reviewed-by: Kalesh AP +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/hw/mlx5/main.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c +index fc1e86f6c4097..8f69c8c1ba54d 100644 +--- a/drivers/infiniband/hw/mlx5/main.c ++++ b/drivers/infiniband/hw/mlx5/main.c +@@ -4462,12 +4462,16 @@ static int mlx5_ib_stage_caps_init(struct mlx5_ib_dev *dev) + MLX5_HCA_CAP_2_GENERAL_OBJECT_TYPES_RDMA_CTRL) { + err = mlx5_ib_init_ucaps(dev); + if (err) +- return err; ++ goto err_ucaps; + } + + dev->ib_dev.use_cq_dim = true; + + return 0; ++ ++err_ucaps: ++ bitmap_free(dev->var_table.bitmap); ++ return err; + } + + static const struct ib_device_ops mlx5_ib_dev_port_ops = { +-- +2.51.0 + diff --git a/queue-6.18/rdma-mlx5-fix-umr-hang-in-lag-error-state-unload.patch b/queue-6.18/rdma-mlx5-fix-umr-hang-in-lag-error-state-unload.patch new file mode 100644 index 0000000000..2ca358b4a4 --- /dev/null +++ b/queue-6.18/rdma-mlx5-fix-umr-hang-in-lag-error-state-unload.patch @@ -0,0 +1,220 @@ +From ed84e8478179e1b8580fa205e6537a1cbb61a6bb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Jan 2026 15:37:10 +0200 +Subject: RDMA/mlx5: Fix UMR hang in LAG error state unload + +From: Chiara Meiohas + +[ Upstream commit ebc2164a4cd4314503f1a0c8e7aaf76d7e5fa211 ] + +During firmware reset in LAG mode, a race condition causes the driver +to hang indefinitely while waiting for UMR completion during device +unload. See [1]. + +In LAG mode the bond device is only registered on the master, so it +never sees sys_error events from the slave. +During firmware reset this causes UMR waits to hang forever on unload +as the slave is dead but the master hasn't entered error state yet, so +UMR posts succeed but completions never arrive. + +Fix this by adding a sys_error notifier that gets registered before +MLX5_IB_STAGE_IB_REG and stays alive until after ib_unregister_device(). +This ensures error events reach the bond device throughout teardown. + +[1] +Call Trace: + __schedule+0x2bd/0x760 + schedule+0x37/0xa0 + schedule_preempt_disabled+0xa/0x10 + __mutex_lock.isra.6+0x2b5/0x4a0 + __mlx5_ib_dereg_mr+0x606/0x870 [mlx5_ib] + ? __xa_erase+0x4a/0xa0 + ? _cond_resched+0x15/0x30 + ? wait_for_completion+0x31/0x100 + ib_dereg_mr_user+0x48/0xc0 [ib_core] + ? rdmacg_uncharge_hierarchy+0xa0/0x100 + destroy_hw_idr_uobject+0x20/0x50 [ib_uverbs] + uverbs_destroy_uobject+0x37/0x150 [ib_uverbs] + __uverbs_cleanup_ufile+0xda/0x140 [ib_uverbs] + uverbs_destroy_ufile_hw+0x3a/0xf0 [ib_uverbs] + ib_uverbs_remove_one+0xc3/0x140 [ib_uverbs] + remove_client_context+0x8b/0xd0 [ib_core] + disable_device+0x8c/0x130 [ib_core] + __ib_unregister_device+0x10d/0x180 [ib_core] + ib_unregister_device+0x21/0x30 [ib_core] + __mlx5_ib_remove+0x1e4/0x1f0 [mlx5_ib] + auxiliary_bus_remove+0x1e/0x30 + device_release_driver_internal+0x103/0x1f0 + bus_remove_device+0xf7/0x170 + device_del+0x181/0x410 + mlx5_rescan_drivers_locked.part.10+0xa9/0x1d0 [mlx5_core] + mlx5_disable_lag+0x253/0x260 [mlx5_core] + mlx5_lag_disable_change+0x89/0xc0 [mlx5_core] + mlx5_eswitch_disable+0x67/0xa0 [mlx5_core] + mlx5_unload+0x15/0xd0 [mlx5_core] + mlx5_unload_one+0x71/0xc0 [mlx5_core] + mlx5_sync_reset_reload_work+0x83/0x100 [mlx5_core] + process_one_work+0x1a7/0x360 + worker_thread+0x30/0x390 + ? create_worker+0x1a0/0x1a0 + kthread+0x116/0x130 + ? kthread_flush_work_fn+0x10/0x10 + ret_from_fork+0x22/0x40 + +Fixes: ede132a5cf55 ("RDMA/mlx5: Move events notifier registration to be after device registration") +Signed-off-by: Chiara Meiohas +Signed-off-by: Maher Sanalla +Reviewed-by: Mark Bloch +Signed-off-by: Edward Srouji +Link: https://patch.msgid.link/20260113-umr-hand-lag-fix-v1-1-3dc476e00cd9@nvidia.com +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/hw/mlx5/main.c | 75 ++++++++++++++++++++++++---- + drivers/infiniband/hw/mlx5/mlx5_ib.h | 2 + + 2 files changed, 68 insertions(+), 9 deletions(-) + +diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c +index 8f69c8c1ba54d..b6096f9126858 100644 +--- a/drivers/infiniband/hw/mlx5/main.c ++++ b/drivers/infiniband/hw/mlx5/main.c +@@ -2874,7 +2874,6 @@ static void mlx5_ib_handle_event(struct work_struct *_work) + container_of(_work, struct mlx5_ib_event_work, work); + struct mlx5_ib_dev *ibdev; + struct ib_event ibev; +- bool fatal = false; + + if (work->is_slave) { + ibdev = mlx5_ib_get_ibdev_from_mpi(work->mpi); +@@ -2885,12 +2884,6 @@ static void mlx5_ib_handle_event(struct work_struct *_work) + } + + switch (work->event) { +- case MLX5_DEV_EVENT_SYS_ERROR: +- ibev.event = IB_EVENT_DEVICE_FATAL; +- mlx5_ib_handle_internal_error(ibdev); +- ibev.element.port_num = (u8)(unsigned long)work->param; +- fatal = true; +- break; + case MLX5_EVENT_TYPE_PORT_CHANGE: + if (handle_port_change(ibdev, work->param, &ibev)) + goto out; +@@ -2912,8 +2905,6 @@ static void mlx5_ib_handle_event(struct work_struct *_work) + if (ibdev->ib_active) + ib_dispatch_event(&ibev); + +- if (fatal) +- ibdev->ib_active = false; + out: + kfree(work); + } +@@ -2957,6 +2948,66 @@ static int mlx5_ib_event_slave_port(struct notifier_block *nb, + return NOTIFY_OK; + } + ++static void mlx5_ib_handle_sys_error_event(struct work_struct *_work) ++{ ++ struct mlx5_ib_event_work *work = ++ container_of(_work, struct mlx5_ib_event_work, work); ++ struct mlx5_ib_dev *ibdev = work->dev; ++ struct ib_event ibev; ++ ++ ibev.event = IB_EVENT_DEVICE_FATAL; ++ mlx5_ib_handle_internal_error(ibdev); ++ ibev.element.port_num = (u8)(unsigned long)work->param; ++ ibev.device = &ibdev->ib_dev; ++ ++ if (!rdma_is_port_valid(&ibdev->ib_dev, ibev.element.port_num)) { ++ mlx5_ib_warn(ibdev, "warning: event on port %d\n", ibev.element.port_num); ++ goto out; ++ } ++ ++ if (ibdev->ib_active) ++ ib_dispatch_event(&ibev); ++ ++ ibdev->ib_active = false; ++out: ++ kfree(work); ++} ++ ++static int mlx5_ib_sys_error_event(struct notifier_block *nb, ++ unsigned long event, void *param) ++{ ++ struct mlx5_ib_event_work *work; ++ ++ if (event != MLX5_DEV_EVENT_SYS_ERROR) ++ return NOTIFY_DONE; ++ ++ work = kmalloc(sizeof(*work), GFP_ATOMIC); ++ if (!work) ++ return NOTIFY_DONE; ++ ++ INIT_WORK(&work->work, mlx5_ib_handle_sys_error_event); ++ work->dev = container_of(nb, struct mlx5_ib_dev, sys_error_events); ++ work->is_slave = false; ++ work->param = param; ++ work->event = event; ++ ++ queue_work(mlx5_ib_event_wq, &work->work); ++ ++ return NOTIFY_OK; ++} ++ ++static int mlx5_ib_stage_sys_error_notifier_init(struct mlx5_ib_dev *dev) ++{ ++ dev->sys_error_events.notifier_call = mlx5_ib_sys_error_event; ++ mlx5_notifier_register(dev->mdev, &dev->sys_error_events); ++ return 0; ++} ++ ++static void mlx5_ib_stage_sys_error_notifier_cleanup(struct mlx5_ib_dev *dev) ++{ ++ mlx5_notifier_unregister(dev->mdev, &dev->sys_error_events); ++} ++ + static int mlx5_ib_get_plane_num(struct mlx5_core_dev *mdev, u8 *num_plane) + { + struct mlx5_hca_vport_context vport_ctx; +@@ -4807,6 +4858,9 @@ static const struct mlx5_ib_profile pf_profile = { + STAGE_CREATE(MLX5_IB_STAGE_WHITELIST_UID, + mlx5_ib_devx_init, + mlx5_ib_devx_cleanup), ++ STAGE_CREATE(MLX5_IB_STAGE_SYS_ERROR_NOTIFIER, ++ mlx5_ib_stage_sys_error_notifier_init, ++ mlx5_ib_stage_sys_error_notifier_cleanup), + STAGE_CREATE(MLX5_IB_STAGE_IB_REG, + mlx5_ib_stage_ib_reg_init, + mlx5_ib_stage_ib_reg_cleanup), +@@ -4864,6 +4918,9 @@ const struct mlx5_ib_profile raw_eth_profile = { + STAGE_CREATE(MLX5_IB_STAGE_WHITELIST_UID, + mlx5_ib_devx_init, + mlx5_ib_devx_cleanup), ++ STAGE_CREATE(MLX5_IB_STAGE_SYS_ERROR_NOTIFIER, ++ mlx5_ib_stage_sys_error_notifier_init, ++ mlx5_ib_stage_sys_error_notifier_cleanup), + STAGE_CREATE(MLX5_IB_STAGE_IB_REG, + mlx5_ib_stage_ib_reg_init, + mlx5_ib_stage_ib_reg_cleanup), +diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h +index 09d82d5f95e35..fbccb0362590b 100644 +--- a/drivers/infiniband/hw/mlx5/mlx5_ib.h ++++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h +@@ -1007,6 +1007,7 @@ enum mlx5_ib_stages { + MLX5_IB_STAGE_BFREG, + MLX5_IB_STAGE_PRE_IB_REG_UMR, + MLX5_IB_STAGE_WHITELIST_UID, ++ MLX5_IB_STAGE_SYS_ERROR_NOTIFIER, + MLX5_IB_STAGE_IB_REG, + MLX5_IB_STAGE_DEVICE_NOTIFIER, + MLX5_IB_STAGE_POST_IB_REG_UMR, +@@ -1165,6 +1166,7 @@ struct mlx5_ib_dev { + /* protect accessing data_direct_dev */ + struct mutex data_direct_lock; + struct notifier_block mdev_events; ++ struct notifier_block sys_error_events; + struct notifier_block lag_events; + int num_ports; + /* serialize update of capability mask +-- +2.51.0 + diff --git a/queue-6.18/rdma-rtrs-server-remove-dead-code.patch b/queue-6.18/rdma-rtrs-server-remove-dead-code.patch new file mode 100644 index 0000000000..5365f41fbb --- /dev/null +++ b/queue-6.18/rdma-rtrs-server-remove-dead-code.patch @@ -0,0 +1,57 @@ +From c94c5ce56d640763da18ed8cde71525990d0c0ec Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Dec 2025 10:38:19 +0800 +Subject: RDMA/rtrs: server: remove dead code + +From: Honggang LI + +[ Upstream commit a3572bdc3a028ca47f77d7166ac95b719cf77d50 ] + +As rkey had been initialized to zero, the WARN_ON_ONCE should never been +triggered. Remove it. + +Fixes: 9cb837480424 ("RDMA/rtrs: server: main functionality") +Signed-off-by: Honggang LI +Link: https://patch.msgid.link/20251224023819.138846-1-honggangli@163.com +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/ulp/rtrs/rtrs-srv.c | 8 +------- + 1 file changed, 1 insertion(+), 7 deletions(-) + +diff --git a/drivers/infiniband/ulp/rtrs/rtrs-srv.c b/drivers/infiniband/ulp/rtrs/rtrs-srv.c +index 9ecc6343455d6..7a402eb8e0bf0 100644 +--- a/drivers/infiniband/ulp/rtrs/rtrs-srv.c ++++ b/drivers/infiniband/ulp/rtrs/rtrs-srv.c +@@ -208,7 +208,6 @@ static int rdma_write_sg(struct rtrs_srv_op *id) + size_t sg_cnt; + int err, offset; + bool need_inval; +- u32 rkey = 0; + struct ib_reg_wr rwr; + struct ib_sge *plist; + struct ib_sge list; +@@ -240,11 +239,6 @@ static int rdma_write_sg(struct rtrs_srv_op *id) + wr->wr.num_sge = 1; + wr->remote_addr = le64_to_cpu(id->rd_msg->desc[0].addr); + wr->rkey = le32_to_cpu(id->rd_msg->desc[0].key); +- if (rkey == 0) +- rkey = wr->rkey; +- else +- /* Only one key is actually used */ +- WARN_ON_ONCE(rkey != wr->rkey); + + wr->wr.opcode = IB_WR_RDMA_WRITE; + wr->wr.wr_cqe = &io_comp_cqe; +@@ -277,7 +271,7 @@ static int rdma_write_sg(struct rtrs_srv_op *id) + inv_wr.opcode = IB_WR_SEND_WITH_INV; + inv_wr.wr_cqe = &io_comp_cqe; + inv_wr.send_flags = 0; +- inv_wr.ex.invalidate_rkey = rkey; ++ inv_wr.ex.invalidate_rkey = wr->rkey; + } + + imm_wr.wr.next = NULL; +-- +2.51.0 + diff --git a/queue-6.18/rdma-rtrs-srv-fix-sg-mapping.patch b/queue-6.18/rdma-rtrs-srv-fix-sg-mapping.patch new file mode 100644 index 0000000000..c337783285 --- /dev/null +++ b/queue-6.18/rdma-rtrs-srv-fix-sg-mapping.patch @@ -0,0 +1,85 @@ +From f4c917678ee2602815f6afba3543b01b412ad57e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 17:15:08 +0100 +Subject: RDMA/rtrs-srv: fix SG mapping + +From: Roman Penyaev + +[ Upstream commit 83835f7c07b523c7ca2a5ad0a511670b5810539e ] + +This fixes the following error on the server side: + + RTRS server session allocation failed: -EINVAL + +caused by the caller of the `ib_dma_map_sg()`, which does not expect +less mapped entries, than requested, which is in the order of things +and can be easily reproduced on the machine with enabled IOMMU. + +The fix is to treat any positive number of mapped sg entries as a +successful mapping and cache DMA addresses by traversing modified +SG table. + +Fixes: 9cb837480424 ("RDMA/rtrs: server: main functionality") +Signed-off-by: Roman Penyaev +Signed-off-by: Jack Wang +Signed-off-by: Grzegorz Prajsner +Link: https://patch.msgid.link/20260107161517.56357-2-haris.iqbal@ionos.com +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/ulp/rtrs/rtrs-srv.c | 25 ++++++++++++++++++++----- + 1 file changed, 20 insertions(+), 5 deletions(-) + +diff --git a/drivers/infiniband/ulp/rtrs/rtrs-srv.c b/drivers/infiniband/ulp/rtrs/rtrs-srv.c +index 7a402eb8e0bf0..adb798e2a54ae 100644 +--- a/drivers/infiniband/ulp/rtrs/rtrs-srv.c ++++ b/drivers/infiniband/ulp/rtrs/rtrs-srv.c +@@ -595,7 +595,7 @@ static int map_cont_bufs(struct rtrs_srv_path *srv_path) + srv_path->mrs_num++) { + struct rtrs_srv_mr *srv_mr = &srv_path->mrs[srv_path->mrs_num]; + struct scatterlist *s; +- int nr, nr_sgt, chunks; ++ int nr, nr_sgt, chunks, ind; + + sgt = &srv_mr->sgt; + chunks = chunks_per_mr * srv_path->mrs_num; +@@ -625,7 +625,7 @@ static int map_cont_bufs(struct rtrs_srv_path *srv_path) + } + nr = ib_map_mr_sg(mr, sgt->sgl, nr_sgt, + NULL, max_chunk_size); +- if (nr != nr_sgt) { ++ if (nr < nr_sgt) { + err = nr < 0 ? nr : -EINVAL; + goto dereg_mr; + } +@@ -641,9 +641,24 @@ static int map_cont_bufs(struct rtrs_srv_path *srv_path) + goto dereg_mr; + } + } +- /* Eventually dma addr for each chunk can be cached */ +- for_each_sg(sgt->sgl, s, nr_sgt, i) +- srv_path->dma_addr[chunks + i] = sg_dma_address(s); ++ ++ /* ++ * Cache DMA addresses by traversing sg entries. If ++ * regions were merged, an inner loop is required to ++ * populate the DMA address array by traversing larger ++ * regions. ++ */ ++ ind = chunks; ++ for_each_sg(sgt->sgl, s, nr_sgt, i) { ++ unsigned int dma_len = sg_dma_len(s); ++ u64 dma_addr = sg_dma_address(s); ++ u64 dma_addr_end = dma_addr + dma_len; ++ ++ do { ++ srv_path->dma_addr[ind++] = dma_addr; ++ dma_addr += max_chunk_size; ++ } while (dma_addr < dma_addr_end); ++ } + + ib_update_fast_reg_key(mr, ib_inc_rkey(mr->rkey)); + srv_mr->mr = mr; +-- +2.51.0 + diff --git a/queue-6.18/rdma-rxe-fix-double-free-in-rxe_srq_from_init.patch b/queue-6.18/rdma-rxe-fix-double-free-in-rxe_srq_from_init.patch new file mode 100644 index 0000000000..103cf23d87 --- /dev/null +++ b/queue-6.18/rdma-rxe-fix-double-free-in-rxe_srq_from_init.patch @@ -0,0 +1,67 @@ +From 522a92c2dd531629ce9ecece72eff3eff17a063f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 01:54:12 +0000 +Subject: RDMA/rxe: Fix double free in rxe_srq_from_init + +From: Jiasheng Jiang + +[ Upstream commit 0beefd0e15d962f497aad750b2d5e9c3570b66d1 ] + +In rxe_srq_from_init(), the queue pointer 'q' is assigned to +'srq->rq.queue' before copying the SRQ number to user space. +If copy_to_user() fails, the function calls rxe_queue_cleanup() +to free the queue, but leaves the now-invalid pointer in +'srq->rq.queue'. + +The caller of rxe_srq_from_init() (rxe_create_srq) eventually +calls rxe_srq_cleanup() upon receiving the error, which triggers +a second rxe_queue_cleanup() on the same memory, leading to a +double free. + +The call trace looks like this: + kmem_cache_free+0x.../0x... + rxe_queue_cleanup+0x1a/0x30 [rdma_rxe] + rxe_srq_cleanup+0x42/0x60 [rdma_rxe] + rxe_elem_release+0x31/0x70 [rdma_rxe] + rxe_create_srq+0x12b/0x1a0 [rdma_rxe] + ib_create_srq_user+0x9a/0x150 [ib_core] + +Fix this by moving 'srq->rq.queue = q' after copy_to_user. + +Fixes: aae0484e15f0 ("IB/rxe: avoid srq memory leak") +Signed-off-by: Jiasheng Jiang +Link: https://patch.msgid.link/20260112015412.29458-1-jiashengjiangcool@gmail.com +Reviewed-by: Zhu Yanjun +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/sw/rxe/rxe_srq.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/infiniband/sw/rxe/rxe_srq.c b/drivers/infiniband/sw/rxe/rxe_srq.c +index 2a234f26ac104..c9a7cd38953d3 100644 +--- a/drivers/infiniband/sw/rxe/rxe_srq.c ++++ b/drivers/infiniband/sw/rxe/rxe_srq.c +@@ -77,9 +77,6 @@ int rxe_srq_from_init(struct rxe_dev *rxe, struct rxe_srq *srq, + goto err_free; + } + +- srq->rq.queue = q; +- init->attr.max_wr = srq->rq.max_wr; +- + if (uresp) { + if (copy_to_user(&uresp->srq_num, &srq->srq_num, + sizeof(uresp->srq_num))) { +@@ -88,6 +85,9 @@ int rxe_srq_from_init(struct rxe_dev *rxe, struct rxe_srq *srq, + } + } + ++ srq->rq.queue = q; ++ init->attr.max_wr = srq->rq.max_wr; ++ + return 0; + + err_free: +-- +2.51.0 + diff --git a/queue-6.18/rdma-rxe-fix-iova-to-va-conversion-for-mr-page-sizes.patch b/queue-6.18/rdma-rxe-fix-iova-to-va-conversion-for-mr-page-sizes.patch new file mode 100644 index 0000000000..c433bb67a9 --- /dev/null +++ b/queue-6.18/rdma-rxe-fix-iova-to-va-conversion-for-mr-page-sizes.patch @@ -0,0 +1,553 @@ +From 3d082929f19da06bcd7ebdcdcb1081e1f00fc79f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 11:27:53 +0800 +Subject: RDMA/rxe: Fix iova-to-va conversion for MR page sizes != PAGE_SIZE + +From: Li Zhijian + +[ Upstream commit 12985e5915a0b8354796efadaaeb201eed115377 ] + +The current implementation incorrectly handles memory regions (MRs) with +page sizes different from the system PAGE_SIZE. The core issue is that +rxe_set_page() is called with mr->page_size step increments, but the +page_list stores individual struct page pointers, each representing +PAGE_SIZE of memory. + +ib_sg_to_page() has ensured that when i>=1 either +a) SG[i-1].dma_end and SG[i].dma_addr are contiguous +or +b) SG[i-1].dma_end and SG[i].dma_addr are mr->page_size aligned. + +This leads to incorrect iova-to-va conversion in scenarios: + +1) page_size < PAGE_SIZE (e.g., MR: 4K, system: 64K): + ibmr->iova = 0x181800 + sg[0]: dma_addr=0x181800, len=0x800 + sg[1]: dma_addr=0x173000, len=0x1000 + + Access iova = 0x181800 + 0x810 = 0x182010 + Expected VA: 0x173010 (second SG, offset 0x10) + Before fix: + - index = (0x182010 >> 12) - (0x181800 >> 12) = 1 + - page_offset = 0x182010 & 0xFFF = 0x10 + - xarray[1] stores system page base 0x170000 + - Resulting VA: 0x170000 + 0x10 = 0x170010 (wrong) + +2) page_size > PAGE_SIZE (e.g., MR: 64K, system: 4K): + ibmr->iova = 0x18f800 + sg[0]: dma_addr=0x18f800, len=0x800 + sg[1]: dma_addr=0x170000, len=0x1000 + + Access iova = 0x18f800 + 0x810 = 0x190010 + Expected VA: 0x170010 (second SG, offset 0x10) + Before fix: + - index = (0x190010 >> 16) - (0x18f800 >> 16) = 1 + - page_offset = 0x190010 & 0xFFFF = 0x10 + - xarray[1] stores system page for dma_addr 0x170000 + - Resulting VA: system page of 0x170000 + 0x10 = 0x170010 (wrong) + +Yi Zhang reported a kernel panic[1] years ago related to this defect. + +Solution: +1. Replace xarray with pre-allocated rxe_mr_page array for sequential + indexing (all MR page indices are contiguous) +2. Each rxe_mr_page stores both struct page* and offset within the + system page +3. Handle MR page_size != PAGE_SIZE relationships: + - page_size > PAGE_SIZE: Split MR pages into multiple system pages + - page_size <= PAGE_SIZE: Store offset within system page +4. Add boundary checks and compatibility validation + +This ensures correct iova-to-va conversion regardless of MR page size +and system PAGE_SIZE relationship, while improving performance through +array-based sequential access. + +Tests on 4K and 64K PAGE_SIZE hosts: +- rdma-core/pytests + $ ./build/bin/run_tests.py --dev eth0_rxe +- blktest: + $ TIMEOUT=30 QUICK_RUN=1 USE_RXE=1 NVMET_TRTYPES=rdma ./check nvme srp rnbd + +[1] https://lore.kernel.org/all/CAHj4cs9XRqE25jyVw9rj9YugffLn5+f=1znaBEnu1usLOciD+g@mail.gmail.com/T/ + +Fixes: 592627ccbdff ("RDMA/rxe: Replace rxe_map and rxe_phys_buf by xarray") +Signed-off-by: Li Zhijian +Link: https://patch.msgid.link/20260116032753.2574363-1-lizhijian@fujitsu.com +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/sw/rxe/rxe_mr.c | 281 +++++++++++++++++--------- + drivers/infiniband/sw/rxe/rxe_verbs.h | 10 +- + 2 files changed, 194 insertions(+), 97 deletions(-) + +diff --git a/drivers/infiniband/sw/rxe/rxe_mr.c b/drivers/infiniband/sw/rxe/rxe_mr.c +index bcb97b3ea58ac..2c486bb616a7c 100644 +--- a/drivers/infiniband/sw/rxe/rxe_mr.c ++++ b/drivers/infiniband/sw/rxe/rxe_mr.c +@@ -72,14 +72,46 @@ void rxe_mr_init_dma(int access, struct rxe_mr *mr) + mr->ibmr.type = IB_MR_TYPE_DMA; + } + ++/* ++ * Convert iova to page_info index. The page_info stores pages of size ++ * PAGE_SIZE, but MRs can have different page sizes. This function ++ * handles the conversion for all cases: ++ * ++ * 1. mr->page_size > PAGE_SIZE: ++ * The MR's iova may not be aligned to mr->page_size. We use the ++ * aligned base (iova & page_mask) as reference, then calculate ++ * which PAGE_SIZE sub-page the iova falls into. ++ * ++ * 2. mr->page_size <= PAGE_SIZE: ++ * Use simple shift arithmetic since each page_info entry corresponds ++ * to one or more MR pages. ++ */ + static unsigned long rxe_mr_iova_to_index(struct rxe_mr *mr, u64 iova) + { +- return (iova >> mr->page_shift) - (mr->ibmr.iova >> mr->page_shift); ++ int idx; ++ ++ if (mr_page_size(mr) > PAGE_SIZE) ++ idx = (iova - (mr->ibmr.iova & mr->page_mask)) >> PAGE_SHIFT; ++ else ++ idx = (iova >> mr->page_shift) - ++ (mr->ibmr.iova >> mr->page_shift); ++ ++ WARN_ON(idx >= mr->nbuf); ++ return idx; + } + ++/* ++ * Convert iova to offset within the page_info entry. ++ * ++ * For mr_page_size > PAGE_SIZE, the offset is within the system page. ++ * For mr_page_size <= PAGE_SIZE, the offset is within the MR page size. ++ */ + static unsigned long rxe_mr_iova_to_page_offset(struct rxe_mr *mr, u64 iova) + { +- return iova & (mr_page_size(mr) - 1); ++ if (mr_page_size(mr) > PAGE_SIZE) ++ return iova & (PAGE_SIZE - 1); ++ else ++ return iova & (mr_page_size(mr) - 1); + } + + static bool is_pmem_page(struct page *pg) +@@ -93,37 +125,69 @@ static bool is_pmem_page(struct page *pg) + + static int rxe_mr_fill_pages_from_sgt(struct rxe_mr *mr, struct sg_table *sgt) + { +- XA_STATE(xas, &mr->page_list, 0); + struct sg_page_iter sg_iter; + struct page *page; + bool persistent = !!(mr->access & IB_ACCESS_FLUSH_PERSISTENT); + ++ WARN_ON(mr_page_size(mr) != PAGE_SIZE); ++ + __sg_page_iter_start(&sg_iter, sgt->sgl, sgt->orig_nents, 0); + if (!__sg_page_iter_next(&sg_iter)) + return 0; + +- do { +- xas_lock(&xas); +- while (true) { +- page = sg_page_iter_page(&sg_iter); +- +- if (persistent && !is_pmem_page(page)) { +- rxe_dbg_mr(mr, "Page can't be persistent\n"); +- xas_set_err(&xas, -EINVAL); +- break; +- } ++ while (true) { ++ page = sg_page_iter_page(&sg_iter); + +- xas_store(&xas, page); +- if (xas_error(&xas)) +- break; +- xas_next(&xas); +- if (!__sg_page_iter_next(&sg_iter)) +- break; ++ if (persistent && !is_pmem_page(page)) { ++ rxe_dbg_mr(mr, "Page can't be persistent\n"); ++ return -EINVAL; + } +- xas_unlock(&xas); +- } while (xas_nomem(&xas, GFP_KERNEL)); + +- return xas_error(&xas); ++ mr->page_info[mr->nbuf].page = page; ++ mr->page_info[mr->nbuf].offset = 0; ++ mr->nbuf++; ++ ++ if (!__sg_page_iter_next(&sg_iter)) ++ break; ++ } ++ ++ return 0; ++} ++ ++static int __alloc_mr_page_info(struct rxe_mr *mr, int num_pages) ++{ ++ mr->page_info = kcalloc(num_pages, sizeof(struct rxe_mr_page), ++ GFP_KERNEL); ++ if (!mr->page_info) ++ return -ENOMEM; ++ ++ mr->max_allowed_buf = num_pages; ++ mr->nbuf = 0; ++ ++ return 0; ++} ++ ++static int alloc_mr_page_info(struct rxe_mr *mr, int num_pages) ++{ ++ int ret; ++ ++ WARN_ON(mr->num_buf); ++ ret = __alloc_mr_page_info(mr, num_pages); ++ if (ret) ++ return ret; ++ ++ mr->num_buf = num_pages; ++ ++ return 0; ++} ++ ++static void free_mr_page_info(struct rxe_mr *mr) ++{ ++ if (!mr->page_info) ++ return; ++ ++ kfree(mr->page_info); ++ mr->page_info = NULL; + } + + int rxe_mr_init_user(struct rxe_dev *rxe, u64 start, u64 length, +@@ -134,8 +198,6 @@ int rxe_mr_init_user(struct rxe_dev *rxe, u64 start, u64 length, + + rxe_mr_init(access, mr); + +- xa_init(&mr->page_list); +- + umem = ib_umem_get(&rxe->ib_dev, start, length, access); + if (IS_ERR(umem)) { + rxe_dbg_mr(mr, "Unable to pin memory region err = %d\n", +@@ -143,46 +205,24 @@ int rxe_mr_init_user(struct rxe_dev *rxe, u64 start, u64 length, + return PTR_ERR(umem); + } + ++ err = alloc_mr_page_info(mr, ib_umem_num_pages(umem)); ++ if (err) ++ goto err2; ++ + err = rxe_mr_fill_pages_from_sgt(mr, &umem->sgt_append.sgt); +- if (err) { +- ib_umem_release(umem); +- return err; +- } ++ if (err) ++ goto err1; + + mr->umem = umem; + mr->ibmr.type = IB_MR_TYPE_USER; + mr->state = RXE_MR_STATE_VALID; + + return 0; +-} +- +-static int rxe_mr_alloc(struct rxe_mr *mr, int num_buf) +-{ +- XA_STATE(xas, &mr->page_list, 0); +- int i = 0; +- int err; +- +- xa_init(&mr->page_list); +- +- do { +- xas_lock(&xas); +- while (i != num_buf) { +- xas_store(&xas, XA_ZERO_ENTRY); +- if (xas_error(&xas)) +- break; +- xas_next(&xas); +- i++; +- } +- xas_unlock(&xas); +- } while (xas_nomem(&xas, GFP_KERNEL)); +- +- err = xas_error(&xas); +- if (err) +- return err; +- +- mr->num_buf = num_buf; +- +- return 0; ++err1: ++ free_mr_page_info(mr); ++err2: ++ ib_umem_release(umem); ++ return err; + } + + int rxe_mr_init_fast(int max_pages, struct rxe_mr *mr) +@@ -192,7 +232,7 @@ int rxe_mr_init_fast(int max_pages, struct rxe_mr *mr) + /* always allow remote access for FMRs */ + rxe_mr_init(RXE_ACCESS_REMOTE, mr); + +- err = rxe_mr_alloc(mr, max_pages); ++ err = alloc_mr_page_info(mr, max_pages); + if (err) + goto err1; + +@@ -205,26 +245,43 @@ int rxe_mr_init_fast(int max_pages, struct rxe_mr *mr) + return err; + } + ++/* ++ * I) MRs with page_size >= PAGE_SIZE, ++ * Split a large MR page (mr->page_size) into multiple PAGE_SIZE ++ * sub-pages and store them in page_info, offset is always 0. ++ * ++ * Called when mr->page_size > PAGE_SIZE. Each call to rxe_set_page() ++ * represents one mr->page_size region, which we must split into ++ * (mr->page_size >> PAGE_SHIFT) individual pages. ++ * ++ * II) MRs with page_size < PAGE_SIZE, ++ * Save each PAGE_SIZE page and its offset within the system page in page_info. ++ */ + static int rxe_set_page(struct ib_mr *ibmr, u64 dma_addr) + { + struct rxe_mr *mr = to_rmr(ibmr); +- struct page *page = ib_virt_dma_to_page(dma_addr); + bool persistent = !!(mr->access & IB_ACCESS_FLUSH_PERSISTENT); +- int err; ++ u32 i, pages_per_mr = mr_page_size(mr) >> PAGE_SHIFT; + +- if (persistent && !is_pmem_page(page)) { +- rxe_dbg_mr(mr, "Page cannot be persistent\n"); +- return -EINVAL; +- } ++ pages_per_mr = MAX(1, pages_per_mr); + +- if (unlikely(mr->nbuf == mr->num_buf)) +- return -ENOMEM; ++ for (i = 0; i < pages_per_mr; i++) { ++ u64 addr = dma_addr + i * PAGE_SIZE; ++ struct page *sub_page = ib_virt_dma_to_page(addr); + +- err = xa_err(xa_store(&mr->page_list, mr->nbuf, page, GFP_KERNEL)); +- if (err) +- return err; ++ if (unlikely(mr->nbuf >= mr->max_allowed_buf)) ++ return -ENOMEM; ++ ++ if (persistent && !is_pmem_page(sub_page)) { ++ rxe_dbg_mr(mr, "Page cannot be persistent\n"); ++ return -EINVAL; ++ } ++ ++ mr->page_info[mr->nbuf].page = sub_page; ++ mr->page_info[mr->nbuf].offset = addr & (PAGE_SIZE - 1); ++ mr->nbuf++; ++ } + +- mr->nbuf++; + return 0; + } + +@@ -234,6 +291,31 @@ int rxe_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sgl, + struct rxe_mr *mr = to_rmr(ibmr); + unsigned int page_size = mr_page_size(mr); + ++ /* ++ * Ensure page_size and PAGE_SIZE are compatible for mapping. ++ * We require one to be a multiple of the other for correct ++ * iova-to-page conversion. ++ */ ++ if (!IS_ALIGNED(page_size, PAGE_SIZE) && ++ !IS_ALIGNED(PAGE_SIZE, page_size)) { ++ rxe_dbg_mr(mr, "MR page size %u must be compatible with PAGE_SIZE %lu\n", ++ page_size, PAGE_SIZE); ++ return -EINVAL; ++ } ++ ++ if (mr_page_size(mr) > PAGE_SIZE) { ++ /* resize page_info if needed */ ++ u32 map_mr_pages = (page_size >> PAGE_SHIFT) * mr->num_buf; ++ ++ if (map_mr_pages > mr->max_allowed_buf) { ++ rxe_dbg_mr(mr, "requested pages %u exceed max %u\n", ++ map_mr_pages, mr->max_allowed_buf); ++ free_mr_page_info(mr); ++ if (__alloc_mr_page_info(mr, map_mr_pages)) ++ return -ENOMEM; ++ } ++ } ++ + mr->nbuf = 0; + mr->page_shift = ilog2(page_size); + mr->page_mask = ~((u64)page_size - 1); +@@ -245,30 +327,30 @@ int rxe_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sgl, + static int rxe_mr_copy_xarray(struct rxe_mr *mr, u64 iova, void *addr, + unsigned int length, enum rxe_mr_copy_dir dir) + { +- unsigned int page_offset = rxe_mr_iova_to_page_offset(mr, iova); +- unsigned long index = rxe_mr_iova_to_index(mr, iova); + unsigned int bytes; +- struct page *page; +- void *va; ++ u8 *va; + + while (length) { +- page = xa_load(&mr->page_list, index); +- if (!page) ++ unsigned long index = rxe_mr_iova_to_index(mr, iova); ++ struct rxe_mr_page *info = &mr->page_info[index]; ++ unsigned int page_offset = rxe_mr_iova_to_page_offset(mr, iova); ++ ++ if (!info->page) + return -EFAULT; + +- bytes = min_t(unsigned int, length, +- mr_page_size(mr) - page_offset); +- va = kmap_local_page(page); ++ page_offset += info->offset; ++ bytes = min_t(unsigned int, length, PAGE_SIZE - page_offset); ++ va = kmap_local_page(info->page); ++ + if (dir == RXE_FROM_MR_OBJ) + memcpy(addr, va + page_offset, bytes); + else + memcpy(va + page_offset, addr, bytes); + kunmap_local(va); + +- page_offset = 0; + addr += bytes; ++ iova += bytes; + length -= bytes; +- index++; + } + + return 0; +@@ -426,9 +508,6 @@ int copy_data( + + static int rxe_mr_flush_pmem_iova(struct rxe_mr *mr, u64 iova, unsigned int length) + { +- unsigned int page_offset; +- unsigned long index; +- struct page *page; + unsigned int bytes; + int err; + u8 *va; +@@ -438,15 +517,17 @@ static int rxe_mr_flush_pmem_iova(struct rxe_mr *mr, u64 iova, unsigned int leng + return err; + + while (length > 0) { +- index = rxe_mr_iova_to_index(mr, iova); +- page = xa_load(&mr->page_list, index); +- page_offset = rxe_mr_iova_to_page_offset(mr, iova); +- if (!page) ++ unsigned long index = rxe_mr_iova_to_index(mr, iova); ++ struct rxe_mr_page *info = &mr->page_info[index]; ++ unsigned int page_offset = rxe_mr_iova_to_page_offset(mr, iova); ++ ++ if (!info->page) + return -EFAULT; +- bytes = min_t(unsigned int, length, +- mr_page_size(mr) - page_offset); + +- va = kmap_local_page(page); ++ page_offset += info->offset; ++ bytes = min_t(unsigned int, length, PAGE_SIZE - page_offset); ++ ++ va = kmap_local_page(info->page); + arch_wb_cache_pmem(va + page_offset, bytes); + kunmap_local(va); + +@@ -502,6 +583,7 @@ enum resp_states rxe_mr_do_atomic_op(struct rxe_mr *mr, u64 iova, int opcode, + } else { + unsigned long index; + int err; ++ struct rxe_mr_page *info; + + err = mr_check_range(mr, iova, sizeof(value)); + if (err) { +@@ -510,9 +592,12 @@ enum resp_states rxe_mr_do_atomic_op(struct rxe_mr *mr, u64 iova, int opcode, + } + page_offset = rxe_mr_iova_to_page_offset(mr, iova); + index = rxe_mr_iova_to_index(mr, iova); +- page = xa_load(&mr->page_list, index); +- if (!page) ++ info = &mr->page_info[index]; ++ if (!info->page) + return RESPST_ERR_RKEY_VIOLATION; ++ ++ page_offset += info->offset; ++ page = info->page; + } + + if (unlikely(page_offset & 0x7)) { +@@ -551,6 +636,7 @@ enum resp_states rxe_mr_do_atomic_write(struct rxe_mr *mr, u64 iova, u64 value) + } else { + unsigned long index; + int err; ++ struct rxe_mr_page *info; + + /* See IBA oA19-28 */ + err = mr_check_range(mr, iova, sizeof(value)); +@@ -560,9 +646,12 @@ enum resp_states rxe_mr_do_atomic_write(struct rxe_mr *mr, u64 iova, u64 value) + } + page_offset = rxe_mr_iova_to_page_offset(mr, iova); + index = rxe_mr_iova_to_index(mr, iova); +- page = xa_load(&mr->page_list, index); +- if (!page) ++ info = &mr->page_info[index]; ++ if (!info->page) + return RESPST_ERR_RKEY_VIOLATION; ++ ++ page_offset += info->offset; ++ page = info->page; + } + + /* See IBA A19.4.2 */ +@@ -726,5 +815,5 @@ void rxe_mr_cleanup(struct rxe_pool_elem *elem) + ib_umem_release(mr->umem); + + if (mr->ibmr.type != IB_MR_TYPE_DMA) +- xa_destroy(&mr->page_list); ++ free_mr_page_info(mr); + } +diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.h b/drivers/infiniband/sw/rxe/rxe_verbs.h +index fd48075810dd1..1b8ed1031bd57 100644 +--- a/drivers/infiniband/sw/rxe/rxe_verbs.h ++++ b/drivers/infiniband/sw/rxe/rxe_verbs.h +@@ -335,6 +335,11 @@ static inline int rkey_is_mw(u32 rkey) + return (index >= RXE_MIN_MW_INDEX) && (index <= RXE_MAX_MW_INDEX); + } + ++struct rxe_mr_page { ++ struct page *page; ++ unsigned int offset; /* offset in system page */ ++}; ++ + struct rxe_mr { + struct rxe_pool_elem elem; + struct ib_mr ibmr; +@@ -351,10 +356,13 @@ struct rxe_mr { + unsigned int page_shift; + u64 page_mask; + ++ /* size of page_info when mr allocated */ + u32 num_buf; ++ /* real size of page_info */ ++ u32 max_allowed_buf; + u32 nbuf; + +- struct xarray page_list; ++ struct rxe_mr_page *page_info; + }; + + static inline unsigned int mr_page_size(struct rxe_mr *mr) +-- +2.51.0 + diff --git a/queue-6.18/rdma-rxe-fix-race-condition-in-qp-timer-handlers.patch b/queue-6.18/rdma-rxe-fix-race-condition-in-qp-timer-handlers.patch new file mode 100644 index 0000000000..76454c500f --- /dev/null +++ b/queue-6.18/rdma-rxe-fix-race-condition-in-qp-timer-handlers.patch @@ -0,0 +1,116 @@ +From 4c62a9e93a7eae68278e34ab62f031e463da0a3a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 15:44:37 +0800 +Subject: RDMA/rxe: Fix race condition in QP timer handlers + +From: Li Zhijian + +[ Upstream commit 87bf646921430e303176edc4eb07c30160361b73 ] + +I encontered the following warning: + WARNING: drivers/infiniband/sw/rxe/rxe_task.c:249 at rxe_sched_task+0x1c8/0x238 [rdma_rxe], CPU#0: swapper/0/0 +... + libsha1 [last unloaded: ip6_udp_tunnel] + CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Tainted: G C 6.19.0-rc5-64k-v8+ #37 PREEMPT + Tainted: [C]=CRAP + Hardware name: Raspberry Pi 4 Model B Rev 1.2 + Call trace: + rxe_sched_task+0x1c8/0x238 [rdma_rxe] (P) + retransmit_timer+0x130/0x188 [rdma_rxe] + call_timer_fn+0x68/0x4d0 + __run_timers+0x630/0x888 +... + WARNING: drivers/infiniband/sw/rxe/rxe_task.c:38 at rxe_sched_task+0x1c0/0x238 [rdma_rxe], CPU#0: swapper/0/0 +... + WARNING: drivers/infiniband/sw/rxe/rxe_task.c:111 at do_work+0x488/0x5c8 [rdma_rxe], CPU#3: kworker/u17:4/93400 +... + refcount_t: underflow; use-after-free. + WARNING: lib/refcount.c:28 at refcount_warn_saturate+0x138/0x1a0, CPU#3: kworker/u17:4/93400 + +The issue is caused by a race condition between retransmit_timer() and +rxe_destroy_qp, leading to the Queue Pair's (QP) reference count dropping +to zero during timer handler execution. + +It seems this warning is harmless because rxe_qp_do_cleanup() will flush +all pending timers and requests. + +Example of flow causing the issue: + +CPU0 CPU1 +retransmit_timer() { + spin_lock_irqsave + rxe_destroy_qp() + __rxe_cleanup() + __rxe_put() // qp->ref_count decrease to 0 + rxe_qp_do_cleanup() { + if (qp->valid) { + rxe_sched_task() { + WARN_ON(rxe_read(task->qp) <= 0); + } + } + spin_unlock_irqrestore +} + spin_lock_irqsave + qp->valid = 0 + spin_unlock_irqrestore + } + +Ensure the QP's reference count is maintained and its validity is checked +within the timer callbacks by adding calls to rxe_get(qp) and corresponding +rxe_put(qp) after use. + +Signed-off-by: Li Zhijian +Fixes: d94671632572 ("RDMA/rxe: Rewrite rxe_task.c") +Link: https://patch.msgid.link/20260120074437.623018-1-lizhijian@fujitsu.com +Reviewed-by: Zhu Yanjun +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/sw/rxe/rxe_comp.c | 3 +++ + drivers/infiniband/sw/rxe/rxe_req.c | 3 +++ + 2 files changed, 6 insertions(+) + +diff --git a/drivers/infiniband/sw/rxe/rxe_comp.c b/drivers/infiniband/sw/rxe/rxe_comp.c +index a5b2b62f596b0..1390e861bd1d7 100644 +--- a/drivers/infiniband/sw/rxe/rxe_comp.c ++++ b/drivers/infiniband/sw/rxe/rxe_comp.c +@@ -119,12 +119,15 @@ void retransmit_timer(struct timer_list *t) + + rxe_dbg_qp(qp, "retransmit timer fired\n"); + ++ if (!rxe_get(qp)) ++ return; + spin_lock_irqsave(&qp->state_lock, flags); + if (qp->valid) { + qp->comp.timeout = 1; + rxe_sched_task(&qp->send_task); + } + spin_unlock_irqrestore(&qp->state_lock, flags); ++ rxe_put(qp); + } + + void rxe_comp_queue_pkt(struct rxe_qp *qp, struct sk_buff *skb) +diff --git a/drivers/infiniband/sw/rxe/rxe_req.c b/drivers/infiniband/sw/rxe/rxe_req.c +index 373b03f223beb..12d03f390b097 100644 +--- a/drivers/infiniband/sw/rxe/rxe_req.c ++++ b/drivers/infiniband/sw/rxe/rxe_req.c +@@ -102,6 +102,8 @@ void rnr_nak_timer(struct timer_list *t) + + rxe_dbg_qp(qp, "nak timer fired\n"); + ++ if (!rxe_get(qp)) ++ return; + spin_lock_irqsave(&qp->state_lock, flags); + if (qp->valid) { + /* request a send queue retry */ +@@ -110,6 +112,7 @@ void rnr_nak_timer(struct timer_list *t) + rxe_sched_task(&qp->send_task); + } + spin_unlock_irqrestore(&qp->state_lock, flags); ++ rxe_put(qp); + } + + static void req_check_sq_drain_done(struct rxe_qp *qp) +-- +2.51.0 + diff --git a/queue-6.18/rdma-uverbs-add-__gfp_nowarn-to-ib_uverbs_unmarshall.patch b/queue-6.18/rdma-uverbs-add-__gfp_nowarn-to-ib_uverbs_unmarshall.patch new file mode 100644 index 0000000000..bd5980fca2 --- /dev/null +++ b/queue-6.18/rdma-uverbs-add-__gfp_nowarn-to-ib_uverbs_unmarshall.patch @@ -0,0 +1,39 @@ +From 5305247da174bf940b13eab8e3cf3b0cc07ec6f5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 17:49:00 +0800 +Subject: RDMA/uverbs: Add __GFP_NOWARN to ib_uverbs_unmarshall_recv() kmalloc + +From: Yi Liu + +[ Upstream commit 58b604dfc7bb753f91bc0ccd3fa705e14e6edfb4 ] + +Since wqe_size in ib_uverbs_unmarshall_recv() is user-provided and already +validated, but can still be large, add __GFP_NOWARN to suppress memory +allocation warnings for large sizes, consistent with the similar fix in +ib_uverbs_post_send(). + +Fixes: 67cdb40ca444 ("[IB] uverbs: Implement more commands") +Signed-off-by: Yi Liu +Link: https://patch.msgid.link/20260129094900.3517706-1-liuy22@mails.tsinghua.edu.cn +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/uverbs_cmd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c +index 3259e9848cc79..f4616deeca545 100644 +--- a/drivers/infiniband/core/uverbs_cmd.c ++++ b/drivers/infiniband/core/uverbs_cmd.c +@@ -2242,7 +2242,7 @@ ib_uverbs_unmarshall_recv(struct uverbs_req_iter *iter, u32 wr_count, + if (ret) + return ERR_PTR(ret); + +- user_wr = kmalloc(wqe_size, GFP_KERNEL); ++ user_wr = kmalloc(wqe_size, GFP_KERNEL | __GFP_NOWARN); + if (!user_wr) + return ERR_PTR(-ENOMEM); + +-- +2.51.0 + diff --git a/queue-6.18/rdma-uverbs-validate-wqe_size-before-using-it-in-ib_.patch b/queue-6.18/rdma-uverbs-validate-wqe_size-before-using-it-in-ib_.patch new file mode 100644 index 0000000000..6ff04a09d7 --- /dev/null +++ b/queue-6.18/rdma-uverbs-validate-wqe_size-before-using-it-in-ib_.patch @@ -0,0 +1,57 @@ +From 76c4fc3e51dff6a36a7f086f67b052e8d8b05427 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 22:29:00 +0800 +Subject: RDMA/uverbs: Validate wqe_size before using it in ib_uverbs_post_send + +From: Yi Liu + +[ Upstream commit 1956f0a74ccf5dc9c3ef717f2985c3ed3400aab0 ] + +ib_uverbs_post_send() uses cmd.wqe_size from userspace without any +validation before passing it to kmalloc() and using the allocated +buffer as struct ib_uverbs_send_wr. + +If a user provides a small wqe_size value (e.g., 1), kmalloc() will +succeed, but subsequent accesses to user_wr->opcode, user_wr->num_sge, +and other fields will read beyond the allocated buffer, resulting in +an out-of-bounds read from kernel heap memory. This could potentially +leak sensitive kernel information to userspace. + +Additionally, providing an excessively large wqe_size can trigger a +WARNING in the memory allocation path, as reported by syzkaller. + +This is inconsistent with ib_uverbs_unmarshall_recv() which properly +validates that wqe_size >= sizeof(struct ib_uverbs_recv_wr) before +proceeding. + +Add the same validation for ib_uverbs_post_send() to ensure wqe_size +is at least sizeof(struct ib_uverbs_send_wr). + +Fixes: c3bea3d2dc53 ("RDMA/uverbs: Use the iterator for ib_uverbs_unmarshall_recv()") +Signed-off-by: Yi Liu +Link: https://patch.msgid.link/20260122142900.2356276-2-liuy22@mails.tsinghua.edu.cn +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/uverbs_cmd.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c +index ce16404cdfb8c..3259e9848cc79 100644 +--- a/drivers/infiniband/core/uverbs_cmd.c ++++ b/drivers/infiniband/core/uverbs_cmd.c +@@ -2049,7 +2049,10 @@ static int ib_uverbs_post_send(struct uverbs_attr_bundle *attrs) + if (ret) + return ret; + +- user_wr = kmalloc(cmd.wqe_size, GFP_KERNEL); ++ if (cmd.wqe_size < sizeof(struct ib_uverbs_send_wr)) ++ return -EINVAL; ++ ++ user_wr = kmalloc(cmd.wqe_size, GFP_KERNEL | __GFP_NOWARN); + if (!user_wr) + return -ENOMEM; + +-- +2.51.0 + diff --git a/queue-6.18/regulator-core-move-supply-check-earlier-in-set_mach.patch b/queue-6.18/regulator-core-move-supply-check-earlier-in-set_mach.patch new file mode 100644 index 0000000000..5038021a85 --- /dev/null +++ b/queue-6.18/regulator-core-move-supply-check-earlier-in-set_mach.patch @@ -0,0 +1,121 @@ +From e7ef315ca64092566bfa4bc31f97796a1ed6438e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 08:38:39 +0000 +Subject: regulator: core: move supply check earlier in + set_machine_constraints() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: André Draszik + +[ Upstream commit 86a8eeb0e913f4b6a55dabba5122098d4e805e55 ] + +Since commit 98e48cd9283d ("regulator: core: resolve supply for +boot-on/always-on regulators"), set_machine_constraints() can return +-EPROBE_DEFER very late, after it has done a lot of work and +configuration of the regulator. + +This means that configuration will happen multiple times for no +benefit in that case. Furthermore, this can lead to timing-dependent +voltage glitches as mentioned e.g. in commit 8a866d527ac0 ("regulator: +core: Resolve supply name earlier to prevent double-init"). + +We can know that it's going to fail very early, in particular before +going through the complete regulator configuration by moving some code +around a little. + +Do so to avoid re-configuring the regulator multiple times, also +avoiding the voltage glitches if we can. + +Fixes: 98e48cd9283d ("regulator: core: resolve supply for boot-on/always-on regulators") +Signed-off-by: André Draszik +Link: https://patch.msgid.link/20260109-regulators-defer-v2-3-1a25dc968e60@linaro.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/regulator/core.c | 55 ++++++++++++++++++++++------------------ + 1 file changed, 30 insertions(+), 25 deletions(-) + +diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c +index b38b087eccfd7..17c60d9547dc5 100644 +--- a/drivers/regulator/core.c ++++ b/drivers/regulator/core.c +@@ -1431,6 +1431,33 @@ static int set_machine_constraints(struct regulator_dev *rdev) + int ret = 0; + const struct regulator_ops *ops = rdev->desc->ops; + ++ /* ++ * If there is no mechanism for controlling the regulator then ++ * flag it as always_on so we don't end up duplicating checks ++ * for this so much. Note that we could control the state of ++ * a supply to control the output on a regulator that has no ++ * direct control. ++ */ ++ if (!rdev->ena_pin && !ops->enable) { ++ if (rdev->supply_name && !rdev->supply) ++ return -EPROBE_DEFER; ++ ++ if (rdev->supply) ++ rdev->constraints->always_on = ++ rdev->supply->rdev->constraints->always_on; ++ else ++ rdev->constraints->always_on = true; ++ } ++ ++ /* ++ * If we want to enable this regulator, make sure that we know the ++ * supplying regulator. ++ */ ++ if (rdev->constraints->always_on || rdev->constraints->boot_on) { ++ if (rdev->supply_name && !rdev->supply) ++ return -EPROBE_DEFER; ++ } ++ + ret = machine_constraints_voltage(rdev, rdev->constraints); + if (ret != 0) + return ret; +@@ -1596,37 +1623,15 @@ static int set_machine_constraints(struct regulator_dev *rdev) + } + } + +- /* +- * If there is no mechanism for controlling the regulator then +- * flag it as always_on so we don't end up duplicating checks +- * for this so much. Note that we could control the state of +- * a supply to control the output on a regulator that has no +- * direct control. +- */ +- if (!rdev->ena_pin && !ops->enable) { +- if (rdev->supply_name && !rdev->supply) +- return -EPROBE_DEFER; +- +- if (rdev->supply) +- rdev->constraints->always_on = +- rdev->supply->rdev->constraints->always_on; +- else +- rdev->constraints->always_on = true; +- } +- + /* If the constraints say the regulator should be on at this point + * and we have control then make sure it is enabled. + */ + if (rdev->constraints->always_on || rdev->constraints->boot_on) { + bool supply_enabled = false; + +- /* If we want to enable this regulator, make sure that we know +- * the supplying regulator. +- */ +- if (rdev->supply_name && !rdev->supply) +- return -EPROBE_DEFER; +- +- /* If supplying regulator has already been enabled, ++ /* We have ensured a potential supply has been resolved above. ++ * ++ * If supplying regulator has already been enabled, + * it's not intended to have use_count increment + * when rdev is only boot-on. + */ +-- +2.51.0 + diff --git a/queue-6.18/remoteproc-imx_dsp_rproc-only-reset-carveout-memory-.patch b/queue-6.18/remoteproc-imx_dsp_rproc-only-reset-carveout-memory-.patch new file mode 100644 index 0000000000..f6f1b29332 --- /dev/null +++ b/queue-6.18/remoteproc-imx_dsp_rproc-only-reset-carveout-memory-.patch @@ -0,0 +1,47 @@ +From d953140a4e7be0f7c7cd7f423b0f7835e9136aa5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 15:17:50 +0800 +Subject: remoteproc: imx_dsp_rproc: Only reset carveout memory at + RPROC_OFFLINE state + +From: Shengjiu Wang + +[ Upstream commit b490ddf27be28e64a39c08ae643d7b22561beaf6 ] + +Do not reset memory at suspend and resume stage, because some +memory is used to save the software state for resume, if it is cleared, +the resume operation can fail. + +Fixes: c4c432dfb00f ("remoteproc: imx_dsp_rproc: Add support of recovery and coredump process") +Signed-off-by: Shengjiu Wang +Reviewed-by: Daniel Baluta +Reviewed-by: Iuliana Prodan +Link: https://lore.kernel.org/r/20251218071750.2692132-1-shengjiu.wang@nxp.com +Signed-off-by: Mathieu Poirier +Signed-off-by: Sasha Levin +--- + drivers/remoteproc/imx_dsp_rproc.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/remoteproc/imx_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c +index 6e78a01755c7b..e61a08df113e4 100644 +--- a/drivers/remoteproc/imx_dsp_rproc.c ++++ b/drivers/remoteproc/imx_dsp_rproc.c +@@ -1026,9 +1026,11 @@ static int imx_dsp_rproc_load(struct rproc *rproc, const struct firmware *fw) + * Clear buffers after pm rumtime for internal ocram is not + * accessible if power and clock are not enabled. + */ +- list_for_each_entry(carveout, &rproc->carveouts, node) { +- if (carveout->va) +- memset(carveout->va, 0, carveout->len); ++ if (rproc->state == RPROC_OFFLINE) { ++ list_for_each_entry(carveout, &rproc->carveouts, node) { ++ if (carveout->va) ++ memset(carveout->va, 0, carveout->len); ++ } + } + + ret = imx_dsp_rproc_elf_load_segments(rproc, fw); +-- +2.51.0 + diff --git a/queue-6.18/reset-canaan-k230-drop-of-dependency-and-enable-by-d.patch b/queue-6.18/reset-canaan-k230-drop-of-dependency-and-enable-by-d.patch new file mode 100644 index 0000000000..68c9aacf76 --- /dev/null +++ b/queue-6.18/reset-canaan-k230-drop-of-dependency-and-enable-by-d.patch @@ -0,0 +1,36 @@ +From b39b488362600e584b11cc00ac5daaf12f541ac6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 17 Jan 2026 18:06:22 +0800 +Subject: reset: canaan: k230: drop OF dependency and enable by default + +From: Junhui Liu + +[ Upstream commit c7a5e01e229d21e0560d78bd645b4f7398667ce4 ] + +The driver doesn't use any symbols depending on CONFIG_OF, so drop the +dependency. Also, enable it by default when ARCH_CANAAN is selected. + +Fixes: 360a7a647759 ("reset: canaan: add reset driver for Kendryte K230") +Signed-off-by: Junhui Liu +Signed-off-by: Philipp Zabel +Signed-off-by: Sasha Levin +--- + drivers/reset/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig +index 78b7078478d46..b3b9e0f9d8c48 100644 +--- a/drivers/reset/Kconfig ++++ b/drivers/reset/Kconfig +@@ -150,7 +150,7 @@ config RESET_K210 + config RESET_K230 + tristate "Reset controller driver for Canaan Kendryte K230 SoC" + depends on ARCH_CANAAN || COMPILE_TEST +- depends on OF ++ default ARCH_CANAAN + help + Support for the Canaan Kendryte K230 RISC-V SoC reset controller. + Say Y if you want to control reset signals provided by this +-- +2.51.0 + diff --git a/queue-6.18/revert-hwmon-ibmpex-fix-use-after-free-in-high-low-s.patch b/queue-6.18/revert-hwmon-ibmpex-fix-use-after-free-in-high-low-s.patch new file mode 100644 index 0000000000..4e420b0687 --- /dev/null +++ b/queue-6.18/revert-hwmon-ibmpex-fix-use-after-free-in-high-low-s.patch @@ -0,0 +1,89 @@ +From b4b5fc8d1cea7db2078d3987b1e90c757ab9cf1a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Feb 2026 08:12:25 -0800 +Subject: Revert "hwmon: (ibmpex) fix use-after-free in high/low store" + +From: Guenter Roeck + +[ Upstream commit 8bde3e395a85017f12af2b0ba5c3684f5af9c006 ] + +This reverts commit 6946c726c3f4c36f0f049e6f97e88c510b15f65d. + +Jean Delvare points out that the patch does not completely +fix the reported problem, that it in fact introduces a +(new) race condition, and that it may actually not be needed in +the first place. + +Various AI reviews agree. Specific and relevant AI feedback: + +" +This reordering sets the driver data to NULL before removing the sensor +attributes in the loop below. + +ibmpex_show_sensor() retrieves this driver data via dev_get_drvdata() but +does not check if it is NULL before dereferencing it to access +data->sensors[]. + +If a userspace process reads a sensor file (like temp1_input) while this +delete function is running, could it race with the dev_set_drvdata(..., +NULL) call here and crash in ibmpex_show_sensor()? + +Would it be safer to keep the original order where device_remove_file() is +called before clearing the driver data? device_remove_file() should wait +for any active sysfs callbacks to complete, which might already prevent the +use-after-free this patch intends to fix. +" + +Revert the offending patch. If it can be shown that the originally reported +alleged race condition does indeed exist, it can always be re-introduced +with a complete fix. + +Reported-by: Jean Delvare +Closes: https://lore.kernel.org/linux-hwmon/20260121095342.73e723cb@endymion/ +Cc: Jean Delvare +Cc: Junrui Luo +Fixes: 6946c726c3f4 ("hwmon: (ibmpex) fix use-after-free in high/low store") +Reviewed-by: Jean Delvare +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + drivers/hwmon/ibmpex.c | 9 ++------- + 1 file changed, 2 insertions(+), 7 deletions(-) + +diff --git a/drivers/hwmon/ibmpex.c b/drivers/hwmon/ibmpex.c +index 129f3a9e8fe96..228c5f6c6f383 100644 +--- a/drivers/hwmon/ibmpex.c ++++ b/drivers/hwmon/ibmpex.c +@@ -277,9 +277,6 @@ static ssize_t ibmpex_high_low_store(struct device *dev, + { + struct ibmpex_bmc_data *data = dev_get_drvdata(dev); + +- if (!data) +- return -ENODEV; +- + ibmpex_reset_high_low_data(data); + + return count; +@@ -511,9 +508,6 @@ static void ibmpex_bmc_delete(struct ibmpex_bmc_data *data) + { + int i, j; + +- hwmon_device_unregister(data->hwmon_dev); +- dev_set_drvdata(data->bmc_device, NULL); +- + device_remove_file(data->bmc_device, + &sensor_dev_attr_reset_high_low.dev_attr); + device_remove_file(data->bmc_device, &dev_attr_name.attr); +@@ -527,7 +521,8 @@ static void ibmpex_bmc_delete(struct ibmpex_bmc_data *data) + } + + list_del(&data->list); +- ++ dev_set_drvdata(data->bmc_device, NULL); ++ hwmon_device_unregister(data->hwmon_dev); + ipmi_destroy_user(data->user); + kfree(data->sensors); + kfree(data); +-- +2.51.0 + diff --git a/queue-6.18/revert-mailbox-pcc-support-mailbox-management-of-the.patch b/queue-6.18/revert-mailbox-pcc-support-mailbox-management-of-the.patch new file mode 100644 index 0000000000..178a45ff29 --- /dev/null +++ b/queue-6.18/revert-mailbox-pcc-support-mailbox-management-of-the.patch @@ -0,0 +1,254 @@ +From d100a87419323ca57c2a97db53b59344b86de23f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Oct 2025 20:08:15 +0100 +Subject: Revert "mailbox/pcc: support mailbox management of the shared buffer" + +From: Sudeep Holla + +[ Upstream commit f82c3e62b6b8c31d8c56415bf38658f306fda4cb ] + +This reverts commit 5378bdf6a611a32500fccf13d14156f219bb0c85. + +Commit 5378bdf6a611 ("mailbox/pcc: support mailbox management of the shared buffer") +attempted to introduce generic helpers for managing the PCC shared memory, +but it largely duplicates functionality already provided by the mailbox +core and leaves gaps: + +1. TX preparation: The mailbox framework already supports this via + ->tx_prepare callback for mailbox clients. The patch adds + pcc_write_to_buffer() and expects clients to toggle pchan->chan.manage_writes, + but no drivers set manage_writes, so pcc_write_to_buffer() has no users. + +2. RX handling: Data reception is already delivered through + mbox_chan_received_data() and client ->rx_callback. The patch adds an + optional pchan->chan.rx_alloc, which again has no users and duplicates + the existing path. + +3. Completion handling: While adding last_tx_done is directionally useful, + the implementation only covers Type 3/4 and fails to handle the absence + of a command_complete register, so it is incomplete for other types. + +Given the duplication and incomplete coverage, revert this change. Any new +requirements should be addressed in focused follow-ups rather than bundling +multiple behavioral changes together. + +Fixes: 5378bdf6a611 ("mailbox/pcc: support mailbox management of the shared buffer") +Signed-off-by: Sudeep Holla +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/pcc.c | 102 ++---------------------------------------- + include/acpi/pcc.h | 29 ------------ + 2 files changed, 4 insertions(+), 127 deletions(-) + +diff --git a/drivers/mailbox/pcc.c b/drivers/mailbox/pcc.c +index ff292b9e0be9e..0e0a66359d4c3 100644 +--- a/drivers/mailbox/pcc.c ++++ b/drivers/mailbox/pcc.c +@@ -305,22 +305,6 @@ static void pcc_chan_acknowledge(struct pcc_chan_info *pchan) + pcc_chan_reg_read_modify_write(&pchan->db); + } + +-static void *write_response(struct pcc_chan_info *pchan) +-{ +- struct pcc_header pcc_header; +- void *buffer; +- int data_len; +- +- memcpy_fromio(&pcc_header, pchan->chan.shmem, +- sizeof(pcc_header)); +- data_len = pcc_header.length - sizeof(u32) + sizeof(struct pcc_header); +- +- buffer = pchan->chan.rx_alloc(pchan->chan.mchan->cl, data_len); +- if (buffer != NULL) +- memcpy_fromio(buffer, pchan->chan.shmem, data_len); +- return buffer; +-} +- + /** + * pcc_mbox_irq - PCC mailbox interrupt handler + * @irq: interrupt number +@@ -332,8 +316,6 @@ static irqreturn_t pcc_mbox_irq(int irq, void *p) + { + struct pcc_chan_info *pchan; + struct mbox_chan *chan = p; +- struct pcc_header *pcc_header = chan->active_req; +- void *handle = NULL; + + pchan = chan->con_priv; + +@@ -357,17 +339,7 @@ static irqreturn_t pcc_mbox_irq(int irq, void *p) + * required to avoid any possible race in updatation of this flag. + */ + pchan->chan_in_use = false; +- +- if (pchan->chan.rx_alloc) +- handle = write_response(pchan); +- +- if (chan->active_req) { +- pcc_header = chan->active_req; +- if (pcc_header->flags & PCC_CMD_COMPLETION_NOTIFY) +- mbox_chan_txdone(chan, 0); +- } +- +- mbox_chan_received_data(chan, handle); ++ mbox_chan_received_data(chan, NULL); + + pcc_chan_acknowledge(pchan); + +@@ -411,24 +383,9 @@ pcc_mbox_request_channel(struct mbox_client *cl, int subspace_id) + pcc_mchan = &pchan->chan; + pcc_mchan->shmem = acpi_os_ioremap(pcc_mchan->shmem_base_addr, + pcc_mchan->shmem_size); +- if (!pcc_mchan->shmem) +- goto err; +- +- pcc_mchan->manage_writes = false; +- +- /* This indicates that the channel is ready to accept messages. +- * This needs to happen after the channel has registered +- * its callback. There is no access point to do that in +- * the mailbox API. That implies that the mailbox client must +- * have set the allocate callback function prior to +- * sending any messages. +- */ +- if (pchan->type == ACPI_PCCT_TYPE_EXT_PCC_SLAVE_SUBSPACE) +- pcc_chan_reg_read_modify_write(&pchan->cmd_update); +- +- return pcc_mchan; ++ if (pcc_mchan->shmem) ++ return pcc_mchan; + +-err: + mbox_free_channel(chan); + return ERR_PTR(-ENXIO); + } +@@ -459,38 +416,8 @@ void pcc_mbox_free_channel(struct pcc_mbox_chan *pchan) + } + EXPORT_SYMBOL_GPL(pcc_mbox_free_channel); + +-static int pcc_write_to_buffer(struct mbox_chan *chan, void *data) +-{ +- struct pcc_chan_info *pchan = chan->con_priv; +- struct pcc_mbox_chan *pcc_mbox_chan = &pchan->chan; +- struct pcc_header *pcc_header = data; +- +- if (!pchan->chan.manage_writes) +- return 0; +- +- /* The PCC header length includes the command field +- * but not the other values from the header. +- */ +- int len = pcc_header->length - sizeof(u32) + sizeof(struct pcc_header); +- u64 val; +- +- pcc_chan_reg_read(&pchan->cmd_complete, &val); +- if (!val) { +- pr_info("%s pchan->cmd_complete not set", __func__); +- return -1; +- } +- memcpy_toio(pcc_mbox_chan->shmem, data, len); +- return 0; +-} +- +- + /** +- * pcc_send_data - Called from Mailbox Controller code. If +- * pchan->chan.rx_alloc is set, then the command complete +- * flag is checked and the data is written to the shared +- * buffer io memory. +- * +- * If pchan->chan.rx_alloc is not set, then it is used ++ * pcc_send_data - Called from Mailbox Controller code. Used + * here only to ring the channel doorbell. The PCC client + * specific read/write is done in the client driver in + * order to maintain atomicity over PCC channel once +@@ -506,37 +433,17 @@ static int pcc_send_data(struct mbox_chan *chan, void *data) + int ret; + struct pcc_chan_info *pchan = chan->con_priv; + +- ret = pcc_write_to_buffer(chan, data); +- if (ret) +- return ret; +- + ret = pcc_chan_reg_read_modify_write(&pchan->cmd_update); + if (ret) + return ret; + + ret = pcc_chan_reg_read_modify_write(&pchan->db); +- + if (!ret && pchan->plat_irq > 0) + pchan->chan_in_use = true; + + return ret; + } + +- +-static bool pcc_last_tx_done(struct mbox_chan *chan) +-{ +- struct pcc_chan_info *pchan = chan->con_priv; +- u64 val; +- +- pcc_chan_reg_read(&pchan->cmd_complete, &val); +- if (!val) +- return false; +- else +- return true; +-} +- +- +- + /** + * pcc_startup - Called from Mailbox Controller code. Used here + * to request the interrupt. +@@ -582,7 +489,6 @@ static const struct mbox_chan_ops pcc_chan_ops = { + .send_data = pcc_send_data, + .startup = pcc_startup, + .shutdown = pcc_shutdown, +- .last_tx_done = pcc_last_tx_done, + }; + + /** +diff --git a/include/acpi/pcc.h b/include/acpi/pcc.h +index 9af3b502f8395..840bfc95bae33 100644 +--- a/include/acpi/pcc.h ++++ b/include/acpi/pcc.h +@@ -17,35 +17,6 @@ struct pcc_mbox_chan { + u32 latency; + u32 max_access_rate; + u16 min_turnaround_time; +- +- /* Set to true to indicate that the mailbox should manage +- * writing the dat to the shared buffer. This differs from +- * the case where the drivesr are writing to the buffer and +- * using send_data only to ring the doorbell. If this flag +- * is set, then the void * data parameter of send_data must +- * point to a kernel-memory buffer formatted in accordance with +- * the PCC specification. +- * +- * The active buffer management will include reading the +- * notify_on_completion flag, and will then +- * call mbox_chan_txdone when the acknowledgment interrupt is +- * received. +- */ +- bool manage_writes; +- +- /* Optional callback that allows the driver +- * to allocate the memory used for receiving +- * messages. The return value is the location +- * inside the buffer where the mailbox should write the data. +- */ +- void *(*rx_alloc)(struct mbox_client *cl, int size); +-}; +- +-struct pcc_header { +- u32 signature; +- u32 flags; +- u32 length; +- u32 command; + }; + + /* Generic Communications Channel Shared Memory Region */ +-- +2.51.0 + diff --git a/queue-6.18/revert-mmc-rtsx_pci_sdmmc-increase-power-on-settling.patch b/queue-6.18/revert-mmc-rtsx_pci_sdmmc-increase-power-on-settling.patch new file mode 100644 index 0000000000..ddf083ef99 --- /dev/null +++ b/queue-6.18/revert-mmc-rtsx_pci_sdmmc-increase-power-on-settling.patch @@ -0,0 +1,39 @@ +From 5793a572bbb0695f1a562bf286d0bfebf821c123 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 15:49:31 +0100 +Subject: Revert "mmc: rtsx_pci_sdmmc: increase power-on settling delay to 5ms" + +From: Greg Kroah-Hartman + +[ Upstream commit ff112f1ecd10b72004eac05bae395e1c65f0c63c ] + +This reverts commit aced969e9bf3701dc75cfca57c78c031b7875b9d. + +It was determined that this was not the correct "fix", so should be +reverted. + +Fixes: aced969e9bf3 ("mmc: rtsx_pci_sdmmc: increase power-on settling delay to 5ms") +Cc: Matthew Schwartz +Cc: Ulf Hansson +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/mmc/host/rtsx_pci_sdmmc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c +index b6cf1803c7d27..4db3328f46dfb 100644 +--- a/drivers/mmc/host/rtsx_pci_sdmmc.c ++++ b/drivers/mmc/host/rtsx_pci_sdmmc.c +@@ -937,7 +937,7 @@ static int sd_power_on(struct realtek_pci_sdmmc *host, unsigned char power_mode) + if (err < 0) + return err; + +- mdelay(5); ++ mdelay(1); + + err = rtsx_pci_write_register(pcr, CARD_OE, SD_OUTPUT_EN, SD_OUTPUT_EN); + if (err < 0) +-- +2.51.0 + diff --git a/queue-6.18/rnbd-srv-fix-server-side-setting-of-bi_size-for-spec.patch b/queue-6.18/rnbd-srv-fix-server-side-setting-of-bi_size-for-spec.patch new file mode 100644 index 0000000000..f9bcc16fbc --- /dev/null +++ b/queue-6.18/rnbd-srv-fix-server-side-setting-of-bi_size-for-spec.patch @@ -0,0 +1,80 @@ +From ba1d3b2bf01bb7b7dce9b813d9091ee593d4225a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Dec 2025 13:47:32 +0100 +Subject: rnbd-srv: Fix server side setting of bi_size for special IOs + +From: Florian-Ewald Mueller + +[ Upstream commit 4ac9690d4b9456ca1d5276d86547fa2e7cd47684 ] + +On rnbd-srv, the bi_size of the bio is set during the bio_add_page +function, to which datalen is passed. But for special IOs like DISCARD +and WRITE_ZEROES, datalen is 0, since there is no data to write. For +these special IOs, use the bi_size of the rnbd_msg_io. + +Fixes: f6f84be089c9 ("block/rnbd-srv: Add sanity check and remove redundant assignment") +Signed-off-by: Florian-Ewald Mueller +Signed-off-by: Md Haris Iqbal +Signed-off-by: Grzegorz Prajsner +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/block/rnbd/rnbd-srv.c | 33 +++++++++++++++++++++++---------- + 1 file changed, 23 insertions(+), 10 deletions(-) + +diff --git a/drivers/block/rnbd/rnbd-srv.c b/drivers/block/rnbd/rnbd-srv.c +index 2df8941a6b146..9b3fdc202e152 100644 +--- a/drivers/block/rnbd/rnbd-srv.c ++++ b/drivers/block/rnbd/rnbd-srv.c +@@ -145,18 +145,30 @@ static int process_rdma(struct rnbd_srv_session *srv_sess, + priv->sess_dev = sess_dev; + priv->id = id; + +- bio = bio_alloc(file_bdev(sess_dev->bdev_file), 1, ++ bio = bio_alloc(file_bdev(sess_dev->bdev_file), !!datalen, + rnbd_to_bio_flags(le32_to_cpu(msg->rw)), GFP_KERNEL); +- bio_add_virt_nofail(bio, data, datalen); +- +- bio->bi_opf = rnbd_to_bio_flags(le32_to_cpu(msg->rw)); +- if (bio_has_data(bio) && +- bio->bi_iter.bi_size != le32_to_cpu(msg->bi_size)) { +- rnbd_srv_err_rl(sess_dev, "Datalen mismatch: bio bi_size (%u), bi_size (%u)\n", +- bio->bi_iter.bi_size, msg->bi_size); +- err = -EINVAL; +- goto bio_put; ++ if (unlikely(!bio)) { ++ err = -ENOMEM; ++ goto put_sess_dev; + } ++ ++ if (!datalen) { ++ /* ++ * For special requests like DISCARD and WRITE_ZEROES, the datalen is zero. ++ */ ++ bio->bi_iter.bi_size = le32_to_cpu(msg->bi_size); ++ } else { ++ bio_add_virt_nofail(bio, data, datalen); ++ bio->bi_opf = rnbd_to_bio_flags(le32_to_cpu(msg->rw)); ++ if (bio->bi_iter.bi_size != le32_to_cpu(msg->bi_size)) { ++ rnbd_srv_err_rl(sess_dev, ++ "Datalen mismatch: bio bi_size (%u), bi_size (%u)\n", ++ bio->bi_iter.bi_size, msg->bi_size); ++ err = -EINVAL; ++ goto bio_put; ++ } ++ } ++ + bio->bi_end_io = rnbd_dev_bi_end_io; + bio->bi_private = priv; + bio->bi_iter.bi_sector = le64_to_cpu(msg->sector); +@@ -170,6 +182,7 @@ static int process_rdma(struct rnbd_srv_session *srv_sess, + + bio_put: + bio_put(bio); ++put_sess_dev: + rnbd_put_sess_dev(sess_dev); + err: + kfree(priv); +-- +2.51.0 + diff --git a/queue-6.18/rqspinlock-fix-tas-fallback-lock-entry-creation.patch b/queue-6.18/rqspinlock-fix-tas-fallback-lock-entry-creation.patch new file mode 100644 index 0000000000..a6b43e4aa3 --- /dev/null +++ b/queue-6.18/rqspinlock-fix-tas-fallback-lock-entry-creation.patch @@ -0,0 +1,67 @@ +From 732ac2ac20098089391a7f8872fa0261c695a228 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 03:59:11 -0800 +Subject: rqspinlock: Fix TAS fallback lock entry creation + +From: Kumar Kartikeya Dwivedi + +[ Upstream commit 82f3b142c99cf44c7b1e70b7720169c646b9760f ] + +The TAS fallback can be invoked directly when queued spin locks are +disabled, and through the slow path when paravirt is enabled for queued +spin locks. In the latter case, the res_spin_lock macro will attempt the +fast path and already hold the entry when entering the slow path. This +will lead to creation of extraneous entries that are not released, which +may cause false positives for deadlock detection. + +Fix this by always preceding invocation of the TAS fallback in every +case with the grabbing of the held lock entry, and add a comment to make +note of this. + +Fixes: c9102a68c070 ("rqspinlock: Add a test-and-set fallback") +Reported-by: Amery Hung +Signed-off-by: Kumar Kartikeya Dwivedi +Tested-by: Amery Hung +Link: https://lore.kernel.org/r/20260122115911.3668985-1-memxor@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + include/asm-generic/rqspinlock.h | 2 +- + kernel/bpf/rqspinlock.c | 7 ++++--- + 2 files changed, 5 insertions(+), 4 deletions(-) + +diff --git a/include/asm-generic/rqspinlock.h b/include/asm-generic/rqspinlock.h +index 0f2dcbbfee2f0..5c5cf2f7fc395 100644 +--- a/include/asm-generic/rqspinlock.h ++++ b/include/asm-generic/rqspinlock.h +@@ -191,7 +191,7 @@ static __always_inline int res_spin_lock(rqspinlock_t *lock) + + #else + +-#define res_spin_lock(lock) resilient_tas_spin_lock(lock) ++#define res_spin_lock(lock) ({ grab_held_lock_entry(lock); resilient_tas_spin_lock(lock); }) + + #endif /* CONFIG_QUEUED_SPINLOCKS */ + +diff --git a/kernel/bpf/rqspinlock.c b/kernel/bpf/rqspinlock.c +index 3faf9cbd6c753..c0c93a0f5af63 100644 +--- a/kernel/bpf/rqspinlock.c ++++ b/kernel/bpf/rqspinlock.c +@@ -276,10 +276,11 @@ int __lockfunc resilient_tas_spin_lock(rqspinlock_t *lock) + + RES_INIT_TIMEOUT(ts); + /* +- * The fast path is not invoked for the TAS fallback, so we must grab +- * the deadlock detection entry here. ++ * We are either called directly from res_spin_lock after grabbing the ++ * deadlock detection entry when queued spinlocks are disabled, or from ++ * resilient_queued_spin_lock_slowpath after grabbing the deadlock ++ * detection entry. No need to obtain it here. + */ +- grab_held_lock_entry(lock); + + /* + * Since the waiting loop's time is dependent on the amount of +-- +2.51.0 + diff --git a/queue-6.18/rtc-amlogic-a4-remove-irqf_oneshot.patch b/queue-6.18/rtc-amlogic-a4-remove-irqf_oneshot.patch new file mode 100644 index 0000000000..0d7daee21c --- /dev/null +++ b/queue-6.18/rtc-amlogic-a4-remove-irqf_oneshot.patch @@ -0,0 +1,45 @@ +From 012f79ae0cd3f3058f360cf504c1da271736484e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:55:32 +0100 +Subject: rtc: amlogic-a4: Remove IRQF_ONESHOT + +From: Sebastian Andrzej Siewior + +[ Upstream commit 18d28446231390e4ea3634fb16200865df2c6506 ] + +Passing IRQF_ONESHOT ensures that the interrupt source is masked until +the secondary (threaded) handler is done. If only a primary handler is +used then the flag makes no sense because the interrupt can not fire +(again) while its handler is running. + +The flag also prevents force-threading of the primary handler and the +irq-core will warn about this. + +Remove IRQF_ONESHOT from irqflags. + +Fixes: c89ac9182ee29 ("rtc: support for the Amlogic on-chip RTC") +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Reviewed-by: Xianwei Zhao +Link: https://patch.msgid.link/20260128095540.863589-13-bigeasy@linutronix.de +Signed-off-by: Sasha Levin +--- + drivers/rtc/rtc-amlogic-a4.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/rtc/rtc-amlogic-a4.c b/drivers/rtc/rtc-amlogic-a4.c +index a993d35e1d6b0..d766055d95848 100644 +--- a/drivers/rtc/rtc-amlogic-a4.c ++++ b/drivers/rtc/rtc-amlogic-a4.c +@@ -371,7 +371,7 @@ static int aml_rtc_probe(struct platform_device *pdev) + } + + ret = devm_request_irq(dev, rtc->irq, aml_rtc_handler, +- IRQF_ONESHOT, "aml-rtc alarm", rtc); ++ 0, "aml-rtc alarm", rtc); + if (ret) { + dev_err_probe(dev, ret, "IRQ%d request failed, ret = %d\n", + rtc->irq, ret); +-- +2.51.0 + diff --git a/queue-6.18/rust-task-restrict-task-group_leader-to-current.patch b/queue-6.18/rust-task-restrict-task-group_leader-to-current.patch new file mode 100644 index 0000000000..ce29c8a1cd --- /dev/null +++ b/queue-6.18/rust-task-restrict-task-group_leader-to-current.patch @@ -0,0 +1,102 @@ +From afd4cb72fea7e256c378bc90efc19e140da35e00 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 08:28:46 +0000 +Subject: rust: task: restrict Task::group_leader() to current +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Alice Ryhl + +[ Upstream commit 105ddfb2d2b3acec7a7d9695463df48733d91e6c ] + +The Task::group_leader() method currently allows you to access the +group_leader() of any task, for example one you hold a refcount to. But +this is not safe in general since the group leader could change when a +task exits. See for example commit a15f37a40145c ("kernel/sys.c: fix the +racy usage of task_lock(tsk->group_leader) in sys_prlimit64() paths"). + +All existing users of Task::group_leader() call this method on current, +which is guaranteed running, so there's not an actual issue in Rust code +today. But to prevent code in the future from making this mistake, +restrict Task::group_leader() so that it can only be called on current. + +There are some other cases where accessing task->group_leader is okay. +For example it can be safe if you hold tasklist_lock or rcu_read_lock(). +However, only supporting current->group_leader is sufficient for all +in-tree Rust users of group_leader right now. Safe Rust functionality for +accessing it under rcu or while holding tasklist_lock may be added in the +future if required by any future Rust module. + +This patch is a bugfix in that it prevents users of this API from writing +incorrect code. It doesn't change behavior of correct code. + +Link: https://lkml.kernel.org/r/20260107-task-group-leader-v2-1-8fbf816f2a2f@google.com +Signed-off-by: Alice Ryhl +Fixes: 313c4281bc9d ("rust: add basic `Task`") +Reported-by: Oleg Nesterov +Closes: https://lore.kernel.org/all/aTLnV-5jlgfk1aRK@redhat.com/ +Reviewed-by: Boqun Feng +Reviewed-by: Gary Guo +Cc: Andreas Hindborg +Cc: Benno Lossin +Cc: "Björn Roy Baron" +Cc: Björn Roy Baron +Cc: Christian Brauner +Cc: Danilo Krummrich +Cc: FUJITA Tomonori +Cc: Miguel Ojeda +Cc: Panagiotis Foliadis +Cc: Shankari Anand +Cc: Trevor Gross +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + rust/kernel/task.rs | 24 ++++++++++++------------ + 1 file changed, 12 insertions(+), 12 deletions(-) + +diff --git a/rust/kernel/task.rs b/rust/kernel/task.rs +index 49fad6de06740..cc907fb531bce 100644 +--- a/rust/kernel/task.rs ++++ b/rust/kernel/task.rs +@@ -204,18 +204,6 @@ pub fn as_ptr(&self) -> *mut bindings::task_struct { + self.0.get() + } + +- /// Returns the group leader of the given task. +- pub fn group_leader(&self) -> &Task { +- // SAFETY: The group leader of a task never changes after initialization, so reading this +- // field is not a data race. +- let ptr = unsafe { *ptr::addr_of!((*self.as_ptr()).group_leader) }; +- +- // SAFETY: The lifetime of the returned task reference is tied to the lifetime of `self`, +- // and given that a task has a reference to its group leader, we know it must be valid for +- // the lifetime of the returned task reference. +- unsafe { &*ptr.cast() } +- } +- + /// Returns the PID of the given task. + pub fn pid(&self) -> Pid { + // SAFETY: The pid of a task never changes after initialization, so reading this field is +@@ -345,6 +333,18 @@ pub fn active_pid_ns(&self) -> Option<&PidNamespace> { + // `release_task()` call. + Some(unsafe { PidNamespace::from_ptr(active_ns) }) + } ++ ++ /// Returns the group leader of the current task. ++ pub fn group_leader(&self) -> &Task { ++ // SAFETY: The group leader of a task never changes while the task is running, and `self` ++ // is the current task, which is guaranteed running. ++ let ptr = unsafe { (*self.as_ptr()).group_leader }; ++ ++ // SAFETY: `current->group_leader` stays valid for at least the duration in which `current` ++ // is running, and the signature of this function ensures that the returned `&Task` can ++ // only be used while `current` is still valid, thus still running. ++ unsafe { &*ptr.cast() } ++ } + } + + // SAFETY: The type invariants guarantee that `Task` is always refcounted. +-- +2.51.0 + diff --git a/queue-6.18/s390-cio-fix-device-lifecycle-handling-in-css_alloc_.patch b/queue-6.18/s390-cio-fix-device-lifecycle-handling-in-css_alloc_.patch new file mode 100644 index 0000000000..bf6feb4cef --- /dev/null +++ b/queue-6.18/s390-cio-fix-device-lifecycle-handling-in-css_alloc_.patch @@ -0,0 +1,49 @@ +From 098a0c41f4bbf9503be5079861e33e7f0df40013 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 21:47:59 +0100 +Subject: s390/cio: Fix device lifecycle handling in css_alloc_subchannel() + +From: Salah Triki + +[ Upstream commit f65c75b0b9b5a390bc3beadcde0a6fbc3ad118f7 ] + +`css_alloc_subchannel()` calls `device_initialize()` before setting up +the DMA masks. If `dma_set_coherent_mask()` or `dma_set_mask()` fails, +the error path frees the subchannel structure directly, bypassing +the device model reference counting. + +Once `device_initialize()` has been called, the embedded struct device +must be released via `put_device()`, allowing the release callback to +free the container structure. + +Fix the error path by dropping the initial device reference with +`put_device()` instead of calling `kfree()` directly. + +This ensures correct device lifetime handling and avoids potential +use-after-free or double-free issues. + +Fixes: e5dcf0025d7af ("s390/css: move subchannel lock allocation") +Signed-off-by: Salah Triki +Reviewed-by: Vineeth Vijayan +Signed-off-by: Heiko Carstens +Signed-off-by: Sasha Levin +--- + drivers/s390/cio/css.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c +index be78a57f9bfde..8a70596a55447 100644 +--- a/drivers/s390/cio/css.c ++++ b/drivers/s390/cio/css.c +@@ -236,7 +236,7 @@ struct subchannel *css_alloc_subchannel(struct subchannel_id schid, + return sch; + + err: +- kfree(sch); ++ put_device(&sch->dev); + return ERR_PTR(ret); + } + +-- +2.51.0 + diff --git a/queue-6.18/sched-deadline-clear-the-defer-params.patch b/queue-6.18/sched-deadline-clear-the-defer-params.patch new file mode 100644 index 0000000000..d5e7643514 --- /dev/null +++ b/queue-6.18/sched-deadline-clear-the-defer-params.patch @@ -0,0 +1,43 @@ +From 54ef03dcc2fe64b423ec6bc136c6532ec933d77d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 10:58:59 +0100 +Subject: sched/deadline: Clear the defer params + +From: Joel Fernandes + +[ Upstream commit 3cb3b27693bf30defb16aa096158a3b24583b8d2 ] + +The defer params were not cleared in __dl_clear_params. Clear them. + +Without this is some of my test cases are flaking and the DL timer is +not starting correctly AFAICS. + +Fixes: a110a81c52a9 ("sched/deadline: Deferrable dl server") +Signed-off-by: Joel Fernandes +Signed-off-by: Peter Zijlstra (Intel) +Reviewed-by: Andrea Righi +Acked-by: Juri Lelli +Tested-by: Christian Loehle +Link: https://patch.msgid.link/20260126100050.3854740-2-arighi@nvidia.com +Signed-off-by: Sasha Levin +--- + kernel/sched/deadline.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c +index c7a8717e837dd..72499cf2a1db5 100644 +--- a/kernel/sched/deadline.c ++++ b/kernel/sched/deadline.c +@@ -3591,6 +3591,9 @@ static void __dl_clear_params(struct sched_dl_entity *dl_se) + dl_se->dl_non_contending = 0; + dl_se->dl_overrun = 0; + dl_se->dl_server = 0; ++ dl_se->dl_defer = 0; ++ dl_se->dl_defer_running = 0; ++ dl_se->dl_defer_armed = 0; + + #ifdef CONFIG_RT_MUTEXES + dl_se->pi_se = dl_se; +-- +2.51.0 + diff --git a/queue-6.18/sched-export-hidden-tracepoints-to-modules.patch b/queue-6.18/sched-export-hidden-tracepoints-to-modules.patch new file mode 100644 index 0000000000..0d578678a8 --- /dev/null +++ b/queue-6.18/sched-export-hidden-tracepoints-to-modules.patch @@ -0,0 +1,48 @@ +From de0fd182af8bfeec19a34122b78ca27443a8bd37 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Dec 2025 14:16:16 +0100 +Subject: sched: Export hidden tracepoints to modules + +From: Gabriele Monaco + +[ Upstream commit 6c125b85f3c87b4bf7dba91af6f27d9600b9dba0 ] + +The tracepoints sched_entry, sched_exit and sched_set_need_resched +are not exported to tracefs as trace events, this allows only kernel +code to access them. Helper modules like [1] can be used to still have +the tracepoints available to ftrace for debugging purposes, but they do +rely on the tracepoints being exported. + +Export the 3 not exported tracepoints. +Note that sched_set_state is already exported as the macro is called +from modules. + +[1] - https://github.com/qais-yousef/sched_tp.git + +Fixes: adcc3bfa8806 ("sched: Adapt sched tracepoints for RV task model") +Signed-off-by: Gabriele Monaco +Signed-off-by: Peter Zijlstra (Intel) +Reviewed-by: Phil Auld +Link: https://patch.msgid.link/20251205131621.135513-9-gmonaco@redhat.com +Signed-off-by: Sasha Levin +--- + kernel/sched/core.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/kernel/sched/core.c b/kernel/sched/core.c +index e460c22de8ad4..c1e4d8a5947cf 100644 +--- a/kernel/sched/core.c ++++ b/kernel/sched/core.c +@@ -119,6 +119,9 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(sched_util_est_cfs_tp); + EXPORT_TRACEPOINT_SYMBOL_GPL(sched_util_est_se_tp); + EXPORT_TRACEPOINT_SYMBOL_GPL(sched_update_nr_running_tp); + EXPORT_TRACEPOINT_SYMBOL_GPL(sched_compute_energy_tp); ++EXPORT_TRACEPOINT_SYMBOL_GPL(sched_entry_tp); ++EXPORT_TRACEPOINT_SYMBOL_GPL(sched_exit_tp); ++EXPORT_TRACEPOINT_SYMBOL_GPL(sched_set_need_resched_tp); + + DEFINE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues); + DEFINE_PER_CPU(struct rnd_state, sched_rnd_state); +-- +2.51.0 + diff --git a/queue-6.18/sched-fix-build-for-modules-using-set_tsk_need_resch.patch b/queue-6.18/sched-fix-build-for-modules-using-set_tsk_need_resch.patch new file mode 100644 index 0000000000..731a1fede8 --- /dev/null +++ b/queue-6.18/sched-fix-build-for-modules-using-set_tsk_need_resch.patch @@ -0,0 +1,44 @@ +From 4a56dfe21381062013aa350ead14d7b7716c7307 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 15:04:13 +0100 +Subject: sched: Fix build for modules using set_tsk_need_resched() + +From: Gabriele Monaco + +[ Upstream commit 8d737320166bd145af70a3133a9964b00ca81cba ] + +Commit adcc3bfa8806 ("sched: Adapt sched tracepoints for RV task model") +added a tracepoint to the need_resched action that can be triggered also +by set_tsk_need_resched. +This function was previously accessible from out-of-tree modules but +it's no longer available because the __trace_set_need_resched() symbol +is not exported (together with the tracepoint itself, which was exported +in a separate patch) and building such modules fails. + +Export __trace_set_need_resched to modules to fix those build issues. + +Fixes: adcc3bfa8806 ("sched: Adapt sched tracepoints for RV task model") +Signed-off-by: Gabriele Monaco +Signed-off-by: Peter Zijlstra (Intel) +Reviewed-by: Phil Auld +Link: https://patch.msgid.link/20260112140413.362202-1-gmonaco@redhat.com +Signed-off-by: Sasha Levin +--- + kernel/sched/core.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/kernel/sched/core.c b/kernel/sched/core.c +index c1e4d8a5947cf..582c3847f483a 100644 +--- a/kernel/sched/core.c ++++ b/kernel/sched/core.c +@@ -1139,6 +1139,7 @@ void __trace_set_need_resched(struct task_struct *curr, int tif) + { + trace_sched_set_need_resched_tp(curr, smp_processor_id(), tif); + } ++EXPORT_SYMBOL_GPL(__trace_set_need_resched); + + void resched_curr(struct rq *rq) + { +-- +2.51.0 + diff --git a/queue-6.18/sched-rt-skip-currently-executing-cpu-in-rto_next_cp.patch b/queue-6.18/sched-rt-skip-currently-executing-cpu-in-rto_next_cp.patch new file mode 100644 index 0000000000..b46faaef67 --- /dev/null +++ b/queue-6.18/sched-rt-skip-currently-executing-cpu-in-rto_next_cp.patch @@ -0,0 +1,87 @@ +From 6297de2a82aed32dfe7285f86ebcdb93ef312109 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 01:25:33 +0000 +Subject: sched/rt: Skip currently executing CPU in rto_next_cpu() + +From: Chen Jinghuang + +[ Upstream commit 94894c9c477e53bcea052e075c53f89df3d2a33e ] + +CPU0 becomes overloaded when hosting a CPU-bound RT task, a non-CPU-bound +RT task, and a CFS task stuck in kernel space. When other CPUs switch from +RT to non-RT tasks, RT load balancing (LB) is triggered; with +HAVE_RT_PUSH_IPI enabled, they send IPIs to CPU0 to drive the execution +of rto_push_irq_work_func. During push_rt_task on CPU0, +if next_task->prio < rq->donor->prio, resched_curr() sets NEED_RESCHED +and after the push operation completes, CPU0 calls rto_next_cpu(). +Since only CPU0 is overloaded in this scenario, rto_next_cpu() should +ideally return -1 (no further IPI needed). + +However, multiple CPUs invoking tell_cpu_to_push() during LB increments +rd->rto_loop_next. Even when rd->rto_cpu is set to -1, the mismatch between +rd->rto_loop and rd->rto_loop_next forces rto_next_cpu() to restart its +search from -1. With CPU0 remaining overloaded (satisfying rt_nr_migratory +&& rt_nr_total > 1), it gets reselected, causing CPU0 to queue irq_work to +itself and send self-IPIs repeatedly. As long as CPU0 stays overloaded and +other CPUs run pull_rt_tasks(), it falls into an infinite self-IPI loop, +which triggers a CPU hardlockup due to continuous self-interrupts. + +The trigging scenario is as follows: + + cpu0 cpu1 cpu2 + pull_rt_task + tell_cpu_to_push + <------------irq_work_queue_on +rto_push_irq_work_func + push_rt_task + resched_curr(rq) pull_rt_task + rto_next_cpu tell_cpu_to_push + <-------------------------- atomic_inc(rto_loop_next) +rd->rto_loop != next + rto_next_cpu + irq_work_queue_on +rto_push_irq_work_func + +Fix redundant self-IPI by filtering the initiating CPU in rto_next_cpu(). +This solution has been verified to effectively eliminate spurious self-IPIs +and prevent CPU hardlockup scenarios. + +Fixes: 4bdced5c9a29 ("sched/rt: Simplify the IPI based RT balancing logic") +Suggested-by: Steven Rostedt (Google) +Suggested-by: K Prateek Nayak +Signed-off-by: Chen Jinghuang +Signed-off-by: Peter Zijlstra (Intel) +Reviewed-by: Steven Rostedt (Google) +Reviewed-by: Valentin Schneider +Link: https://patch.msgid.link/20260122012533.673768-1-chenjinghuang2@huawei.com +Signed-off-by: Sasha Levin +--- + kernel/sched/rt.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c +index fb07dcfc60a24..d4d994fb8999a 100644 +--- a/kernel/sched/rt.c ++++ b/kernel/sched/rt.c +@@ -2100,6 +2100,7 @@ static void push_rt_tasks(struct rq *rq) + */ + static int rto_next_cpu(struct root_domain *rd) + { ++ int this_cpu = smp_processor_id(); + int next; + int cpu; + +@@ -2123,6 +2124,10 @@ static int rto_next_cpu(struct root_domain *rd) + + rd->rto_cpu = cpu; + ++ /* Do not send IPI to self */ ++ if (cpu == this_cpu) ++ continue; ++ + if (cpu < nr_cpu_ids) + return cpu; + +-- +2.51.0 + diff --git a/queue-6.18/scsi-csiostor-fix-dereference-of-null-pointer-rn.patch b/queue-6.18/scsi-csiostor-fix-dereference-of-null-pointer-rn.patch new file mode 100644 index 0000000000..f3fdb6b72c --- /dev/null +++ b/queue-6.18/scsi-csiostor-fix-dereference-of-null-pointer-rn.patch @@ -0,0 +1,46 @@ +From 6816c68a4d88a27603b01683e79756768eb753b4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 15:53:32 +0000 +Subject: scsi: csiostor: Fix dereference of null pointer rn + +From: Colin Ian King + +[ Upstream commit 1982257570b84dc33753d536dd969fd357a014e9 ] + +The error exit path when rn is NULL ends up deferencing the null pointer rn +via the use of the macro CSIO_INC_STATS. Fix this by adding a new error +return path label after the use of the macro to avoid the deference. + +Fixes: a3667aaed569 ("[SCSI] csiostor: Chelsio FCoE offload driver") +Signed-off-by: Colin Ian King +Link: https://patch.msgid.link/20260129155332.196338-1-colin.i.king@gmail.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/csiostor/csio_scsi.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/scsi/csiostor/csio_scsi.c b/drivers/scsi/csiostor/csio_scsi.c +index 34bde6650fae0..356a7c577ec3e 100644 +--- a/drivers/scsi/csiostor/csio_scsi.c ++++ b/drivers/scsi/csiostor/csio_scsi.c +@@ -2074,7 +2074,7 @@ csio_eh_lun_reset_handler(struct scsi_cmnd *cmnd) + struct csio_scsi_level_data sld; + + if (!rn) +- goto fail; ++ goto fail_ret; + + csio_dbg(hw, "Request to reset LUN:%llu (ssni:0x%x tgtid:%d)\n", + cmnd->device->lun, rn->flowid, rn->scsi_id); +@@ -2220,6 +2220,7 @@ csio_eh_lun_reset_handler(struct scsi_cmnd *cmnd) + csio_put_scsi_ioreq_lock(hw, scsim, ioreq); + fail: + CSIO_INC_STATS(rn, n_lun_rst_fail); ++fail_ret: + return FAILED; + } + +-- +2.51.0 + diff --git a/queue-6.18/scsi-efct-use-irqf_oneshot-and-default-primary-handl.patch b/queue-6.18/scsi-efct-use-irqf_oneshot-and-default-primary-handl.patch new file mode 100644 index 0000000000..fecdd18db6 --- /dev/null +++ b/queue-6.18/scsi-efct-use-irqf_oneshot-and-default-primary-handl.patch @@ -0,0 +1,59 @@ +From 8f60468347ca8d081ac222861fc926cc0f6967c3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:55:27 +0100 +Subject: scsi: efct: Use IRQF_ONESHOT and default primary handler + +From: Sebastian Andrzej Siewior + +[ Upstream commit bd81f07e9a27c341cd7e72be95eb0b7cf3910926 ] + +There is no added value in efct_intr_msix() compared to +irq_default_primary_handler(). + +Using a threaded interrupt without a dedicated primary handler mandates +the IRQF_ONESHOT flag to mask the interrupt source while the threaded +handler is active. Otherwise the interrupt can fire again before the +threaded handler had a chance to run. + +Use the default primary interrupt handler by specifying NULL and set +IRQF_ONESHOT so the interrupt source is masked until the secondary +handler is done. + +Fixes: 4df84e8466242 ("scsi: elx: efct: Driver initialization routines") +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260128095540.863589-8-bigeasy@linutronix.de +Signed-off-by: Sasha Levin +--- + drivers/scsi/elx/efct/efct_driver.c | 8 +------- + 1 file changed, 1 insertion(+), 7 deletions(-) + +diff --git a/drivers/scsi/elx/efct/efct_driver.c b/drivers/scsi/elx/efct/efct_driver.c +index 1bd42f7db1773..528399f725d42 100644 +--- a/drivers/scsi/elx/efct/efct_driver.c ++++ b/drivers/scsi/elx/efct/efct_driver.c +@@ -415,12 +415,6 @@ efct_intr_thread(int irq, void *handle) + return IRQ_HANDLED; + } + +-static irqreturn_t +-efct_intr_msix(int irq, void *handle) +-{ +- return IRQ_WAKE_THREAD; +-} +- + static int + efct_setup_msix(struct efct *efct, u32 num_intrs) + { +@@ -450,7 +444,7 @@ efct_setup_msix(struct efct *efct, u32 num_intrs) + intr_ctx->index = i; + + rc = request_threaded_irq(pci_irq_vector(efct->pci, i), +- efct_intr_msix, efct_intr_thread, 0, ++ NULL, efct_intr_thread, IRQF_ONESHOT, + EFCT_DRIVER_NAME, intr_ctx); + if (rc) { + dev_err(&efct->pci->dev, +-- +2.51.0 + diff --git a/queue-6.18/scsi-smartpqi-fix-memory-leak-in-pqi_report_phys_lun.patch b/queue-6.18/scsi-smartpqi-fix-memory-leak-in-pqi_report_phys_lun.patch new file mode 100644 index 0000000000..f843788e6a --- /dev/null +++ b/queue-6.18/scsi-smartpqi-fix-memory-leak-in-pqi_report_phys_lun.patch @@ -0,0 +1,72 @@ +From 1a84a3468cce3b67af60e11b58e2c7363908050a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Jan 2026 09:36:41 +0000 +Subject: scsi: smartpqi: Fix memory leak in pqi_report_phys_luns() + +From: Zilin Guan + +[ Upstream commit 41b37312bd9722af77ec7817ccf22d7a4880c289 ] + +pqi_report_phys_luns() fails to release the rpl_list buffer when +encountering an unsupported data format or when the allocation for +rpl_16byte_wwid_list fails. These early returns bypass the cleanup logic, +leading to memory leaks. + +Consolidate the error handling by adding an out_free_rpl_list label and use +goto statements to ensure rpl_list is consistently freed on failure. + +Compile tested only. Issue found using a prototype static analysis tool and +code review. + +Fixes: 28ca6d876c5a ("scsi: smartpqi: Add extended report physical LUNs") +Signed-off-by: Zilin Guan +Tested-by: Don Brace +Acked-by: Don Brace +Link: https://patch.msgid.link/20260131093641.1008117-1-zilin@seu.edu.cn +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/smartpqi/smartpqi_init.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c +index 98e93900254cb..5a6e1bb57e7c8 100644 +--- a/drivers/scsi/smartpqi/smartpqi_init.c ++++ b/drivers/scsi/smartpqi/smartpqi_init.c +@@ -1241,7 +1241,8 @@ static inline int pqi_report_phys_luns(struct pqi_ctrl_info *ctrl_info, void **b + dev_err(&ctrl_info->pci_dev->dev, + "RPL returned unsupported data format %u\n", + rpl_response_format); +- return -EINVAL; ++ rc = -EINVAL; ++ goto out_free_rpl_list; + } else { + dev_warn(&ctrl_info->pci_dev->dev, + "RPL returned extended format 2 instead of 4\n"); +@@ -1253,8 +1254,10 @@ static inline int pqi_report_phys_luns(struct pqi_ctrl_info *ctrl_info, void **b + + rpl_16byte_wwid_list = kmalloc(struct_size(rpl_16byte_wwid_list, lun_entries, + num_physicals), GFP_KERNEL); +- if (!rpl_16byte_wwid_list) +- return -ENOMEM; ++ if (!rpl_16byte_wwid_list) { ++ rc = -ENOMEM; ++ goto out_free_rpl_list; ++ } + + put_unaligned_be32(num_physicals * sizeof(struct report_phys_lun_16byte_wwid), + &rpl_16byte_wwid_list->header.list_length); +@@ -1275,6 +1278,10 @@ static inline int pqi_report_phys_luns(struct pqi_ctrl_info *ctrl_info, void **b + *buffer = rpl_16byte_wwid_list; + + return 0; ++ ++out_free_rpl_list: ++ kfree(rpl_list); ++ return rc; + } + + static inline int pqi_report_logical_luns(struct pqi_ctrl_info *ctrl_info, void **buffer) +-- +2.51.0 + diff --git a/queue-6.18/scsi-ufs-host-mediatek-require-config_pm.patch b/queue-6.18/scsi-ufs-host-mediatek-require-config_pm.patch new file mode 100644 index 0000000000..e2f82a599c --- /dev/null +++ b/queue-6.18/scsi-ufs-host-mediatek-require-config_pm.patch @@ -0,0 +1,116 @@ +From 5a6dcecbbc8a02fc575ce99176ef80038eb207a8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 10:50:18 +0100 +Subject: scsi: ufs: host: mediatek: Require CONFIG_PM + +From: Arnd Bergmann + +[ Upstream commit bbb8d98fb4536594cb104fd630ea0f7dce3771d6 ] + +The added print statement from a recent fix causes the driver to fail +building when CONFIG_PM is disabled: + +drivers/ufs/host/ufs-mediatek.c: In function 'ufs_mtk_resume': +drivers/ufs/host/ufs-mediatek.c:1890:40: error: 'struct dev_pm_info' has no member named 'request' + 1890 | hba->dev->power.request, + +It seems unlikely that the driver can work at all without CONFIG_PM, so +just add a dependency and remove the existing ifdef checks, rather than +adding another ifdef. + +Fixes: 15ef3f5aa822 ("scsi: ufs: host: mediatek: Enhance recovery on resume failure") +Signed-off-by: Arnd Bergmann +Reviewed-by: AngeloGioacchino Del Regno +Link: https://patch.msgid.link/20260202095052.1232703-1-arnd@kernel.org +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/ufs/host/Kconfig | 1 + + drivers/ufs/host/ufs-mediatek.c | 12 +++--------- + include/ufs/ufshcd.h | 4 ---- + 3 files changed, 4 insertions(+), 13 deletions(-) + +diff --git a/drivers/ufs/host/Kconfig b/drivers/ufs/host/Kconfig +index 191fbd799ec5b..48ee7e9b665ef 100644 +--- a/drivers/ufs/host/Kconfig ++++ b/drivers/ufs/host/Kconfig +@@ -72,6 +72,7 @@ config SCSI_UFS_QCOM + config SCSI_UFS_MEDIATEK + tristate "Mediatek specific hooks to UFS controller platform driver" + depends on SCSI_UFSHCD_PLATFORM && ARCH_MEDIATEK ++ depends on PM + depends on RESET_CONTROLLER + select PHY_MTK_UFS + select RESET_TI_SYSCON +diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c +index d0cbd96ad29dc..3c63adca561d2 100644 +--- a/drivers/ufs/host/ufs-mediatek.c ++++ b/drivers/ufs/host/ufs-mediatek.c +@@ -2366,7 +2366,6 @@ static void ufs_mtk_remove(struct platform_device *pdev) + ufshcd_pltfrm_remove(pdev); + } + +-#ifdef CONFIG_PM_SLEEP + static int ufs_mtk_system_suspend(struct device *dev) + { + struct ufs_hba *hba = dev_get_drvdata(dev); +@@ -2413,9 +2412,7 @@ static int ufs_mtk_system_resume(struct device *dev) + + return ret; + } +-#endif + +-#ifdef CONFIG_PM + static int ufs_mtk_runtime_suspend(struct device *dev) + { + struct ufs_hba *hba = dev_get_drvdata(dev); +@@ -2454,13 +2451,10 @@ static int ufs_mtk_runtime_resume(struct device *dev) + + return ufshcd_runtime_resume(dev); + } +-#endif + + static const struct dev_pm_ops ufs_mtk_pm_ops = { +- SET_SYSTEM_SLEEP_PM_OPS(ufs_mtk_system_suspend, +- ufs_mtk_system_resume) +- SET_RUNTIME_PM_OPS(ufs_mtk_runtime_suspend, +- ufs_mtk_runtime_resume, NULL) ++ SYSTEM_SLEEP_PM_OPS(ufs_mtk_system_suspend, ufs_mtk_system_resume) ++ RUNTIME_PM_OPS(ufs_mtk_runtime_suspend, ufs_mtk_runtime_resume, NULL) + .prepare = ufshcd_suspend_prepare, + .complete = ufshcd_resume_complete, + }; +@@ -2470,7 +2464,7 @@ static struct platform_driver ufs_mtk_pltform = { + .remove = ufs_mtk_remove, + .driver = { + .name = "ufshcd-mtk", +- .pm = &ufs_mtk_pm_ops, ++ .pm = pm_ptr(&ufs_mtk_pm_ops), + .of_match_table = ufs_mtk_of_match, + }, + }; +diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h +index d949db3a46759..17fe07dac6a7e 100644 +--- a/include/ufs/ufshcd.h ++++ b/include/ufs/ufshcd.h +@@ -1350,17 +1350,13 @@ static inline void *ufshcd_get_variant(struct ufs_hba *hba) + return hba->priv; + } + +-#ifdef CONFIG_PM + extern int ufshcd_runtime_suspend(struct device *dev); + extern int ufshcd_runtime_resume(struct device *dev); +-#endif +-#ifdef CONFIG_PM_SLEEP + extern int ufshcd_system_suspend(struct device *dev); + extern int ufshcd_system_resume(struct device *dev); + extern int ufshcd_system_freeze(struct device *dev); + extern int ufshcd_system_thaw(struct device *dev); + extern int ufshcd_system_restore(struct device *dev); +-#endif + + extern int ufshcd_dme_reset(struct ufs_hba *hba); + extern int ufshcd_dme_enable(struct ufs_hba *hba); +-- +2.51.0 + diff --git a/queue-6.18/selftests-bpf-fix-kprobe-multi-stacktrace_ips-test.patch b/queue-6.18/selftests-bpf-fix-kprobe-multi-stacktrace_ips-test.patch new file mode 100644 index 0000000000..d656e7b347 --- /dev/null +++ b/queue-6.18/selftests-bpf-fix-kprobe-multi-stacktrace_ips-test.patch @@ -0,0 +1,54 @@ +From 1678160cee2903386e13acee33868b4d2de5154e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 22:18:34 +0100 +Subject: selftests/bpf: Fix kprobe multi stacktrace_ips test + +From: Jiri Olsa + +[ Upstream commit 0207f94971e72a13380e28022c86da147e8e090f ] + +We now include the attached function in the stack trace, +fixing the test accordingly. + +Fixes: c9e208fa93cd ("selftests/bpf: Add stacktrace ips test for kprobe_multi/kretprobe_multi") +Signed-off-by: Jiri Olsa +Signed-off-by: Andrii Nakryiko +Link: https://lore.kernel.org/bpf/20260126211837.472802-4-jolsa@kernel.org +Signed-off-by: Sasha Levin +--- + .../selftests/bpf/prog_tests/stacktrace_ips.c | 19 ++++++++++++++----- + 1 file changed, 14 insertions(+), 5 deletions(-) + +diff --git a/tools/testing/selftests/bpf/prog_tests/stacktrace_ips.c b/tools/testing/selftests/bpf/prog_tests/stacktrace_ips.c +index c9efdd2a5b18a..c93718dafd9b6 100644 +--- a/tools/testing/selftests/bpf/prog_tests/stacktrace_ips.c ++++ b/tools/testing/selftests/bpf/prog_tests/stacktrace_ips.c +@@ -74,11 +74,20 @@ static void test_stacktrace_ips_kprobe_multi(bool retprobe) + + load_kallsyms(); + +- check_stacktrace_ips(bpf_map__fd(skel->maps.stackmap), skel->bss->stack_key, 4, +- ksym_get_addr("bpf_testmod_stacktrace_test_3"), +- ksym_get_addr("bpf_testmod_stacktrace_test_2"), +- ksym_get_addr("bpf_testmod_stacktrace_test_1"), +- ksym_get_addr("bpf_testmod_test_read")); ++ if (retprobe) { ++ check_stacktrace_ips(bpf_map__fd(skel->maps.stackmap), skel->bss->stack_key, 4, ++ ksym_get_addr("bpf_testmod_stacktrace_test_3"), ++ ksym_get_addr("bpf_testmod_stacktrace_test_2"), ++ ksym_get_addr("bpf_testmod_stacktrace_test_1"), ++ ksym_get_addr("bpf_testmod_test_read")); ++ } else { ++ check_stacktrace_ips(bpf_map__fd(skel->maps.stackmap), skel->bss->stack_key, 5, ++ ksym_get_addr("bpf_testmod_stacktrace_test"), ++ ksym_get_addr("bpf_testmod_stacktrace_test_3"), ++ ksym_get_addr("bpf_testmod_stacktrace_test_2"), ++ ksym_get_addr("bpf_testmod_stacktrace_test_1"), ++ ksym_get_addr("bpf_testmod_test_read")); ++ } + + cleanup: + stacktrace_ips__destroy(skel); +-- +2.51.0 + diff --git a/queue-6.18/selftests-bpf-fix-resource-leak-in-serial_test_wq-on.patch b/queue-6.18/selftests-bpf-fix-resource-leak-in-serial_test_wq-on.patch new file mode 100644 index 0000000000..c5f6e40055 --- /dev/null +++ b/queue-6.18/selftests-bpf-fix-resource-leak-in-serial_test_wq-on.patch @@ -0,0 +1,60 @@ +From fbf632b99a50c8a7b83ad1afb87624994fa681b4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 17:41:16 +0800 +Subject: selftests/bpf: Fix resource leak in serial_test_wq on attach failure + +From: Kery Qi + +[ Upstream commit a32ae2658471dd87a2f7a438388ed7d9a5767212 ] + +When wq__attach() fails, serial_test_wq() returns early without calling +wq__destroy(), leaking the skeleton resources allocated by +wq__open_and_load(). This causes ASAN leak reports in selftests runs. + +Fix this by jumping to a common clean_up label that calls wq__destroy() +on all exit paths after successful open_and_load. + +Note that the early return after wq__open_and_load() failure is correct +and doesn't need fixing, since that function returns NULL on failure +(after internally cleaning up any partial allocations). + +Fixes: 8290dba51910 ("selftests/bpf: wq: add bpf_wq_start() checks") +Signed-off-by: Kery Qi +Signed-off-by: Andrii Nakryiko +Acked-by: Yonghong Song +Link: https://lore.kernel.org/bpf/20260121094114.1801-3-qikeyu2017@gmail.com +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/bpf/prog_tests/wq.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/tools/testing/selftests/bpf/prog_tests/wq.c b/tools/testing/selftests/bpf/prog_tests/wq.c +index 99e438fe12acd..15ac8e6d17450 100644 +--- a/tools/testing/selftests/bpf/prog_tests/wq.c ++++ b/tools/testing/selftests/bpf/prog_tests/wq.c +@@ -16,12 +16,12 @@ void serial_test_wq(void) + /* re-run the success test to check if the timer was actually executed */ + + wq_skel = wq__open_and_load(); +- if (!ASSERT_OK_PTR(wq_skel, "wq_skel_load")) ++ if (!ASSERT_OK_PTR(wq_skel, "wq__open_and_load")) + return; + + err = wq__attach(wq_skel); + if (!ASSERT_OK(err, "wq_attach")) +- return; ++ goto clean_up; + + prog_fd = bpf_program__fd(wq_skel->progs.test_syscall_array_sleepable); + err = bpf_prog_test_run_opts(prog_fd, &topts); +@@ -31,6 +31,7 @@ void serial_test_wq(void) + usleep(50); /* 10 usecs should be enough, but give it extra */ + + ASSERT_EQ(wq_skel->bss->ok_sleepable, (1 << 1), "ok_sleepable"); ++clean_up: + wq__destroy(wq_skel); + } + +-- +2.51.0 + diff --git a/queue-6.18/selftests-bpf-test_xsk-split-xskxceiver.patch b/queue-6.18/selftests-bpf-test_xsk-split-xskxceiver.patch new file mode 100644 index 0000000000..f6a20deded --- /dev/null +++ b/queue-6.18/selftests-bpf-test_xsk-split-xskxceiver.patch @@ -0,0 +1,5596 @@ +From f804bb6687266f96701ce0e714ee5c6a07645baa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 Oct 2025 09:04:37 +0100 +Subject: selftests/bpf: test_xsk: Split xskxceiver + +From: Bastien Curutchet (eBPF Foundation) + +[ Upstream commit 3ab77f35a75eb236956c1e8ba8494ef18a75eae0 ] + +AF_XDP features are tested by the test_xsk.sh script but not by the +test_progs framework. The tests used by the script are defined in +xksxceiver.c which can't be integrated in the test_progs framework as is. + +Extract these test definitions from xskxceiver{.c/.h} to put them in new +test_xsk{.c/.h} files. +Keep the main() function and its unshared dependencies in xksxceiver to +avoid impacting the test_xsk.sh script which is often used to test real +hardware. +Move ksft_test_result_*() calls to xskxceiver.c to keep the kselftest's +report valid + +Reviewed-by: Maciej Fijalkowski +Signed-off-by: Bastien Curutchet (eBPF Foundation) +Link: https://lore.kernel.org/r/20251031-xsk-v7-1-39fe486593a3@bootlin.com +Signed-off-by: Alexei Starovoitov +Stable-dep-of: 42e41b2a0afa ("selftests/xsk: properly handle batch ending in the middle of a packet") +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/bpf/Makefile | 2 +- + tools/testing/selftests/bpf/test_xsk.c | 2420 ++++++++++++++++++++ + tools/testing/selftests/bpf/test_xsk.h | 297 +++ + tools/testing/selftests/bpf/xskxceiver.c | 2545 +--------------------- + tools/testing/selftests/bpf/xskxceiver.h | 156 -- + 5 files changed, 2762 insertions(+), 2658 deletions(-) + create mode 100644 tools/testing/selftests/bpf/test_xsk.c + create mode 100644 tools/testing/selftests/bpf/test_xsk.h + +diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile +index e59b2bbf8d920..591e7e77f89ba 100644 +--- a/tools/testing/selftests/bpf/Makefile ++++ b/tools/testing/selftests/bpf/Makefile +@@ -805,7 +805,7 @@ $(OUTPUT)/test_verifier: test_verifier.c verifier/tests.h $(BPFOBJ) | $(OUTPUT) + + # Include find_bit.c to compile xskxceiver. + EXTRA_SRC := $(TOOLSDIR)/lib/find_bit.c +-$(OUTPUT)/xskxceiver: $(EXTRA_SRC) xskxceiver.c xskxceiver.h $(OUTPUT)/network_helpers.o $(OUTPUT)/xsk.o $(OUTPUT)/xsk_xdp_progs.skel.h $(BPFOBJ) | $(OUTPUT) ++$(OUTPUT)/xskxceiver: $(EXTRA_SRC) test_xsk.c test_xsk.h xskxceiver.c xskxceiver.h $(OUTPUT)/network_helpers.o $(OUTPUT)/xsk.o $(OUTPUT)/xsk_xdp_progs.skel.h $(BPFOBJ) | $(OUTPUT) + $(call msg,BINARY,,$@) + $(Q)$(CC) $(CFLAGS) $(filter %.a %.o %.c,$^) $(LDLIBS) -o $@ + +diff --git a/tools/testing/selftests/bpf/test_xsk.c b/tools/testing/selftests/bpf/test_xsk.c +new file mode 100644 +index 0000000000000..02250f29f9946 +--- /dev/null ++++ b/tools/testing/selftests/bpf/test_xsk.c +@@ -0,0 +1,2420 @@ ++// SPDX-License-Identifier: GPL-2.0 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "network_helpers.h" ++#include "test_xsk.h" ++#include "xsk_xdp_common.h" ++#include "xsk_xdp_progs.skel.h" ++ ++#define DEFAULT_BATCH_SIZE 64 ++#define MIN_PKT_SIZE 64 ++#define MAX_ETH_JUMBO_SIZE 9000 ++#define MAX_INTERFACES 2 ++#define MAX_TEARDOWN_ITER 10 ++#define MAX_TX_BUDGET_DEFAULT 32 ++#define PKT_DUMP_NB_TO_PRINT 16 ++/* Just to align the data in the packet */ ++#define PKT_HDR_SIZE (sizeof(struct ethhdr) + 2) ++#define POLL_TMOUT 1000 ++#define THREAD_TMOUT 3 ++#define UMEM_HEADROOM_TEST_SIZE 128 ++#define XSK_DESC__INVALID_OPTION (0xffff) ++#define XSK_UMEM__INVALID_FRAME_SIZE (MAX_ETH_JUMBO_SIZE + 1) ++#define XSK_UMEM__LARGE_FRAME_SIZE (3 * 1024) ++#define XSK_UMEM__MAX_FRAME_SIZE (4 * 1024) ++ ++static const u8 g_mac[ETH_ALEN] = {0x55, 0x44, 0x33, 0x22, 0x11, 0x00}; ++ ++bool opt_verbose; ++pthread_barrier_t barr; ++pthread_mutex_t pacing_mutex = PTHREAD_MUTEX_INITIALIZER; ++ ++int pkts_in_flight; ++ ++/* The payload is a word consisting of a packet sequence number in the upper ++ * 16-bits and a intra packet data sequence number in the lower 16 bits. So the 3rd packet's ++ * 5th word of data will contain the number (2<<16) | 4 as they are numbered from 0. ++ */ ++static void write_payload(void *dest, u32 pkt_nb, u32 start, u32 size) ++{ ++ u32 *ptr = (u32 *)dest, i; ++ ++ start /= sizeof(*ptr); ++ size /= sizeof(*ptr); ++ for (i = 0; i < size; i++) ++ ptr[i] = htonl(pkt_nb << 16 | (i + start)); ++} ++ ++static void gen_eth_hdr(struct xsk_socket_info *xsk, struct ethhdr *eth_hdr) ++{ ++ memcpy(eth_hdr->h_dest, xsk->dst_mac, ETH_ALEN); ++ memcpy(eth_hdr->h_source, xsk->src_mac, ETH_ALEN); ++ eth_hdr->h_proto = htons(ETH_P_LOOPBACK); ++} ++ ++static bool is_umem_valid(struct ifobject *ifobj) ++{ ++ return !!ifobj->umem->umem; ++} ++ ++static u32 mode_to_xdp_flags(enum test_mode mode) ++{ ++ return (mode == TEST_MODE_SKB) ? XDP_FLAGS_SKB_MODE : XDP_FLAGS_DRV_MODE; ++} ++ ++static u64 umem_size(struct xsk_umem_info *umem) ++{ ++ return umem->num_frames * umem->frame_size; ++} ++ ++int xsk_configure_umem(struct ifobject *ifobj, struct xsk_umem_info *umem, void *buffer, ++ u64 size) ++{ ++ struct xsk_umem_config cfg = { ++ .fill_size = XSK_RING_PROD__DEFAULT_NUM_DESCS, ++ .comp_size = XSK_RING_CONS__DEFAULT_NUM_DESCS, ++ .frame_size = umem->frame_size, ++ .frame_headroom = umem->frame_headroom, ++ .flags = XSK_UMEM__DEFAULT_FLAGS ++ }; ++ int ret; ++ ++ if (umem->fill_size) ++ cfg.fill_size = umem->fill_size; ++ ++ if (umem->comp_size) ++ cfg.comp_size = umem->comp_size; ++ ++ if (umem->unaligned_mode) ++ cfg.flags |= XDP_UMEM_UNALIGNED_CHUNK_FLAG; ++ ++ ret = xsk_umem__create(&umem->umem, buffer, size, ++ &umem->fq, &umem->cq, &cfg); ++ if (ret) ++ return ret; ++ ++ umem->buffer = buffer; ++ if (ifobj->shared_umem && ifobj->rx_on) { ++ umem->base_addr = umem_size(umem); ++ umem->next_buffer = umem_size(umem); ++ } ++ ++ return 0; ++} ++ ++static u64 umem_alloc_buffer(struct xsk_umem_info *umem) ++{ ++ u64 addr; ++ ++ addr = umem->next_buffer; ++ umem->next_buffer += umem->frame_size; ++ if (umem->next_buffer >= umem->base_addr + umem_size(umem)) ++ umem->next_buffer = umem->base_addr; ++ ++ return addr; ++} ++ ++static void umem_reset_alloc(struct xsk_umem_info *umem) ++{ ++ umem->next_buffer = 0; ++} ++ ++static void enable_busy_poll(struct xsk_socket_info *xsk) ++{ ++ int sock_opt; ++ ++ sock_opt = 1; ++ if (setsockopt(xsk_socket__fd(xsk->xsk), SOL_SOCKET, SO_PREFER_BUSY_POLL, ++ (void *)&sock_opt, sizeof(sock_opt)) < 0) ++ exit_with_error(errno); ++ ++ sock_opt = 20; ++ if (setsockopt(xsk_socket__fd(xsk->xsk), SOL_SOCKET, SO_BUSY_POLL, ++ (void *)&sock_opt, sizeof(sock_opt)) < 0) ++ exit_with_error(errno); ++ ++ sock_opt = xsk->batch_size; ++ if (setsockopt(xsk_socket__fd(xsk->xsk), SOL_SOCKET, SO_BUSY_POLL_BUDGET, ++ (void *)&sock_opt, sizeof(sock_opt)) < 0) ++ exit_with_error(errno); ++} ++ ++int xsk_configure_socket(struct xsk_socket_info *xsk, struct xsk_umem_info *umem, ++ struct ifobject *ifobject, bool shared) ++{ ++ struct xsk_socket_config cfg = {}; ++ struct xsk_ring_cons *rxr; ++ struct xsk_ring_prod *txr; ++ ++ xsk->umem = umem; ++ cfg.rx_size = xsk->rxqsize; ++ cfg.tx_size = XSK_RING_PROD__DEFAULT_NUM_DESCS; ++ cfg.bind_flags = ifobject->bind_flags; ++ if (shared) ++ cfg.bind_flags |= XDP_SHARED_UMEM; ++ if (ifobject->mtu > MAX_ETH_PKT_SIZE) ++ cfg.bind_flags |= XDP_USE_SG; ++ if (umem->comp_size) ++ cfg.tx_size = umem->comp_size; ++ if (umem->fill_size) ++ cfg.rx_size = umem->fill_size; ++ ++ txr = ifobject->tx_on ? &xsk->tx : NULL; ++ rxr = ifobject->rx_on ? &xsk->rx : NULL; ++ return xsk_socket__create(&xsk->xsk, ifobject->ifindex, 0, umem->umem, rxr, txr, &cfg); ++} ++ ++#define MAX_SKB_FRAGS_PATH "/proc/sys/net/core/max_skb_frags" ++static unsigned int get_max_skb_frags(void) ++{ ++ unsigned int max_skb_frags = 0; ++ FILE *file; ++ ++ file = fopen(MAX_SKB_FRAGS_PATH, "r"); ++ if (!file) { ++ ksft_print_msg("Error opening %s\n", MAX_SKB_FRAGS_PATH); ++ return 0; ++ } ++ ++ if (fscanf(file, "%u", &max_skb_frags) != 1) ++ ksft_print_msg("Error reading %s\n", MAX_SKB_FRAGS_PATH); ++ ++ fclose(file); ++ return max_skb_frags; ++} ++ ++static int set_ring_size(struct ifobject *ifobj) ++{ ++ int ret; ++ u32 ctr = 0; ++ ++ while (ctr++ < SOCK_RECONF_CTR) { ++ ret = set_hw_ring_size(ifobj->ifname, &ifobj->ring); ++ if (!ret) ++ break; ++ ++ /* Retry if it fails */ ++ if (ctr >= SOCK_RECONF_CTR || errno != EBUSY) ++ return -errno; ++ ++ usleep(USLEEP_MAX); ++ } ++ ++ return ret; ++} ++ ++int hw_ring_size_reset(struct ifobject *ifobj) ++{ ++ ifobj->ring.tx_pending = ifobj->set_ring.default_tx; ++ ifobj->ring.rx_pending = ifobj->set_ring.default_rx; ++ return set_ring_size(ifobj); ++} ++ ++static void __test_spec_init(struct test_spec *test, struct ifobject *ifobj_tx, ++ struct ifobject *ifobj_rx) ++{ ++ u32 i, j; ++ ++ for (i = 0; i < MAX_INTERFACES; i++) { ++ struct ifobject *ifobj = i ? ifobj_rx : ifobj_tx; ++ ++ ifobj->xsk = &ifobj->xsk_arr[0]; ++ ifobj->use_poll = false; ++ ifobj->use_fill_ring = true; ++ ifobj->release_rx = true; ++ ifobj->validation_func = NULL; ++ ifobj->use_metadata = false; ++ ++ if (i == 0) { ++ ifobj->rx_on = false; ++ ifobj->tx_on = true; ++ } else { ++ ifobj->rx_on = true; ++ ifobj->tx_on = false; ++ } ++ ++ memset(ifobj->umem, 0, sizeof(*ifobj->umem)); ++ ifobj->umem->num_frames = DEFAULT_UMEM_BUFFERS; ++ ifobj->umem->frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE; ++ ++ for (j = 0; j < MAX_SOCKETS; j++) { ++ memset(&ifobj->xsk_arr[j], 0, sizeof(ifobj->xsk_arr[j])); ++ ifobj->xsk_arr[j].rxqsize = XSK_RING_CONS__DEFAULT_NUM_DESCS; ++ ifobj->xsk_arr[j].batch_size = DEFAULT_BATCH_SIZE; ++ if (i == 0) ++ ifobj->xsk_arr[j].pkt_stream = test->tx_pkt_stream_default; ++ else ++ ifobj->xsk_arr[j].pkt_stream = test->rx_pkt_stream_default; ++ ++ memcpy(ifobj->xsk_arr[j].src_mac, g_mac, ETH_ALEN); ++ memcpy(ifobj->xsk_arr[j].dst_mac, g_mac, ETH_ALEN); ++ ifobj->xsk_arr[j].src_mac[5] += ((j * 2) + 0); ++ ifobj->xsk_arr[j].dst_mac[5] += ((j * 2) + 1); ++ } ++ } ++ ++ if (ifobj_tx->hw_ring_size_supp) ++ hw_ring_size_reset(ifobj_tx); ++ ++ test->ifobj_tx = ifobj_tx; ++ test->ifobj_rx = ifobj_rx; ++ test->current_step = 0; ++ test->total_steps = 1; ++ test->nb_sockets = 1; ++ test->fail = false; ++ test->set_ring = false; ++ test->adjust_tail = false; ++ test->adjust_tail_support = false; ++ test->mtu = MAX_ETH_PKT_SIZE; ++ test->xdp_prog_rx = ifobj_rx->xdp_progs->progs.xsk_def_prog; ++ test->xskmap_rx = ifobj_rx->xdp_progs->maps.xsk; ++ test->xdp_prog_tx = ifobj_tx->xdp_progs->progs.xsk_def_prog; ++ test->xskmap_tx = ifobj_tx->xdp_progs->maps.xsk; ++} ++ ++void test_init(struct test_spec *test, struct ifobject *ifobj_tx, ++ struct ifobject *ifobj_rx, enum test_mode mode, ++ const struct test_spec *test_to_run) ++{ ++ struct pkt_stream *tx_pkt_stream; ++ struct pkt_stream *rx_pkt_stream; ++ u32 i; ++ ++ tx_pkt_stream = test->tx_pkt_stream_default; ++ rx_pkt_stream = test->rx_pkt_stream_default; ++ memset(test, 0, sizeof(*test)); ++ test->tx_pkt_stream_default = tx_pkt_stream; ++ test->rx_pkt_stream_default = rx_pkt_stream; ++ ++ for (i = 0; i < MAX_INTERFACES; i++) { ++ struct ifobject *ifobj = i ? ifobj_rx : ifobj_tx; ++ ++ ifobj->bind_flags = XDP_USE_NEED_WAKEUP; ++ if (mode == TEST_MODE_ZC) ++ ifobj->bind_flags |= XDP_ZEROCOPY; ++ else ++ ifobj->bind_flags |= XDP_COPY; ++ } ++ ++ memcpy(test->name, test_to_run->name, MAX_TEST_NAME_SIZE); ++ test->test_func = test_to_run->test_func; ++ test->mode = mode; ++ __test_spec_init(test, ifobj_tx, ifobj_rx); ++} ++ ++static void test_spec_reset(struct test_spec *test) ++{ ++ __test_spec_init(test, test->ifobj_tx, test->ifobj_rx); ++} ++ ++static void test_spec_set_xdp_prog(struct test_spec *test, struct bpf_program *xdp_prog_rx, ++ struct bpf_program *xdp_prog_tx, struct bpf_map *xskmap_rx, ++ struct bpf_map *xskmap_tx) ++{ ++ test->xdp_prog_rx = xdp_prog_rx; ++ test->xdp_prog_tx = xdp_prog_tx; ++ test->xskmap_rx = xskmap_rx; ++ test->xskmap_tx = xskmap_tx; ++} ++ ++static int test_spec_set_mtu(struct test_spec *test, int mtu) ++{ ++ int err; ++ ++ if (test->ifobj_rx->mtu != mtu) { ++ err = xsk_set_mtu(test->ifobj_rx->ifindex, mtu); ++ if (err) ++ return err; ++ test->ifobj_rx->mtu = mtu; ++ } ++ if (test->ifobj_tx->mtu != mtu) { ++ err = xsk_set_mtu(test->ifobj_tx->ifindex, mtu); ++ if (err) ++ return err; ++ test->ifobj_tx->mtu = mtu; ++ } ++ ++ return 0; ++} ++ ++void pkt_stream_reset(struct pkt_stream *pkt_stream) ++{ ++ if (pkt_stream) { ++ pkt_stream->current_pkt_nb = 0; ++ pkt_stream->nb_rx_pkts = 0; ++ } ++} ++ ++static struct pkt *pkt_stream_get_next_tx_pkt(struct pkt_stream *pkt_stream) ++{ ++ if (pkt_stream->current_pkt_nb >= pkt_stream->nb_pkts) ++ return NULL; ++ ++ return &pkt_stream->pkts[pkt_stream->current_pkt_nb++]; ++} ++ ++static struct pkt *pkt_stream_get_next_rx_pkt(struct pkt_stream *pkt_stream, u32 *pkts_sent) ++{ ++ while (pkt_stream->current_pkt_nb < pkt_stream->nb_pkts) { ++ (*pkts_sent)++; ++ if (pkt_stream->pkts[pkt_stream->current_pkt_nb].valid) ++ return &pkt_stream->pkts[pkt_stream->current_pkt_nb++]; ++ pkt_stream->current_pkt_nb++; ++ } ++ return NULL; ++} ++ ++void pkt_stream_delete(struct pkt_stream *pkt_stream) ++{ ++ free(pkt_stream->pkts); ++ free(pkt_stream); ++} ++ ++void pkt_stream_restore_default(struct test_spec *test) ++{ ++ struct pkt_stream *tx_pkt_stream = test->ifobj_tx->xsk->pkt_stream; ++ struct pkt_stream *rx_pkt_stream = test->ifobj_rx->xsk->pkt_stream; ++ ++ if (tx_pkt_stream != test->tx_pkt_stream_default) { ++ pkt_stream_delete(test->ifobj_tx->xsk->pkt_stream); ++ test->ifobj_tx->xsk->pkt_stream = test->tx_pkt_stream_default; ++ } ++ ++ if (rx_pkt_stream != test->rx_pkt_stream_default) { ++ pkt_stream_delete(test->ifobj_rx->xsk->pkt_stream); ++ test->ifobj_rx->xsk->pkt_stream = test->rx_pkt_stream_default; ++ } ++} ++ ++static struct pkt_stream *__pkt_stream_alloc(u32 nb_pkts) ++{ ++ struct pkt_stream *pkt_stream; ++ ++ pkt_stream = calloc(1, sizeof(*pkt_stream)); ++ if (!pkt_stream) ++ return NULL; ++ ++ pkt_stream->pkts = calloc(nb_pkts, sizeof(*pkt_stream->pkts)); ++ if (!pkt_stream->pkts) { ++ free(pkt_stream); ++ return NULL; ++ } ++ ++ pkt_stream->nb_pkts = nb_pkts; ++ return pkt_stream; ++} ++ ++static u32 pkt_nb_frags(u32 frame_size, struct pkt_stream *pkt_stream, struct pkt *pkt) ++{ ++ u32 nb_frags = 1, next_frag; ++ ++ if (!pkt) ++ return 1; ++ ++ if (!pkt_stream->verbatim) { ++ if (!pkt->valid || !pkt->len) ++ return 1; ++ return ceil_u32(pkt->len, frame_size); ++ } ++ ++ /* Search for the end of the packet in verbatim mode */ ++ if (!pkt_continues(pkt->options)) ++ return nb_frags; ++ ++ next_frag = pkt_stream->current_pkt_nb; ++ pkt++; ++ while (next_frag++ < pkt_stream->nb_pkts) { ++ nb_frags++; ++ if (!pkt_continues(pkt->options) || !pkt->valid) ++ break; ++ pkt++; ++ } ++ return nb_frags; ++} ++ ++static bool set_pkt_valid(int offset, u32 len) ++{ ++ return len <= MAX_ETH_JUMBO_SIZE; ++} ++ ++static void pkt_set(struct pkt_stream *pkt_stream, struct pkt *pkt, int offset, u32 len) ++{ ++ pkt->offset = offset; ++ pkt->len = len; ++ pkt->valid = set_pkt_valid(offset, len); ++} ++ ++static void pkt_stream_pkt_set(struct pkt_stream *pkt_stream, struct pkt *pkt, int offset, u32 len) ++{ ++ bool prev_pkt_valid = pkt->valid; ++ ++ pkt_set(pkt_stream, pkt, offset, len); ++ pkt_stream->nb_valid_entries += pkt->valid - prev_pkt_valid; ++} ++ ++static u32 pkt_get_buffer_len(struct xsk_umem_info *umem, u32 len) ++{ ++ return ceil_u32(len, umem->frame_size) * umem->frame_size; ++} ++ ++static struct pkt_stream *__pkt_stream_generate(u32 nb_pkts, u32 pkt_len, u32 nb_start, u32 nb_off) ++{ ++ struct pkt_stream *pkt_stream; ++ u32 i; ++ ++ pkt_stream = __pkt_stream_alloc(nb_pkts); ++ if (!pkt_stream) ++ exit_with_error(ENOMEM); ++ ++ pkt_stream->nb_pkts = nb_pkts; ++ pkt_stream->max_pkt_len = pkt_len; ++ for (i = 0; i < nb_pkts; i++) { ++ struct pkt *pkt = &pkt_stream->pkts[i]; ++ ++ pkt_stream_pkt_set(pkt_stream, pkt, 0, pkt_len); ++ pkt->pkt_nb = nb_start + i * nb_off; ++ } ++ ++ return pkt_stream; ++} ++ ++struct pkt_stream *pkt_stream_generate(u32 nb_pkts, u32 pkt_len) ++{ ++ return __pkt_stream_generate(nb_pkts, pkt_len, 0, 1); ++} ++ ++static struct pkt_stream *pkt_stream_clone(struct pkt_stream *pkt_stream) ++{ ++ return pkt_stream_generate(pkt_stream->nb_pkts, pkt_stream->pkts[0].len); ++} ++ ++static void pkt_stream_replace_ifobject(struct ifobject *ifobj, u32 nb_pkts, u32 pkt_len) ++{ ++ ifobj->xsk->pkt_stream = pkt_stream_generate(nb_pkts, pkt_len); ++} ++ ++static void pkt_stream_replace(struct test_spec *test, u32 nb_pkts, u32 pkt_len) ++{ ++ pkt_stream_replace_ifobject(test->ifobj_tx, nb_pkts, pkt_len); ++ pkt_stream_replace_ifobject(test->ifobj_rx, nb_pkts, pkt_len); ++} ++ ++static void __pkt_stream_replace_half(struct ifobject *ifobj, u32 pkt_len, ++ int offset) ++{ ++ struct pkt_stream *pkt_stream; ++ u32 i; ++ ++ pkt_stream = pkt_stream_clone(ifobj->xsk->pkt_stream); ++ for (i = 1; i < ifobj->xsk->pkt_stream->nb_pkts; i += 2) ++ pkt_stream_pkt_set(pkt_stream, &pkt_stream->pkts[i], offset, pkt_len); ++ ++ ifobj->xsk->pkt_stream = pkt_stream; ++} ++ ++static void pkt_stream_replace_half(struct test_spec *test, u32 pkt_len, int offset) ++{ ++ __pkt_stream_replace_half(test->ifobj_tx, pkt_len, offset); ++ __pkt_stream_replace_half(test->ifobj_rx, pkt_len, offset); ++} ++ ++static void pkt_stream_receive_half(struct test_spec *test) ++{ ++ struct pkt_stream *pkt_stream = test->ifobj_tx->xsk->pkt_stream; ++ u32 i; ++ ++ test->ifobj_rx->xsk->pkt_stream = pkt_stream_generate(pkt_stream->nb_pkts, ++ pkt_stream->pkts[0].len); ++ pkt_stream = test->ifobj_rx->xsk->pkt_stream; ++ for (i = 1; i < pkt_stream->nb_pkts; i += 2) ++ pkt_stream->pkts[i].valid = false; ++ ++ pkt_stream->nb_valid_entries /= 2; ++} ++ ++static void pkt_stream_even_odd_sequence(struct test_spec *test) ++{ ++ struct pkt_stream *pkt_stream; ++ u32 i; ++ ++ for (i = 0; i < test->nb_sockets; i++) { ++ pkt_stream = test->ifobj_tx->xsk_arr[i].pkt_stream; ++ pkt_stream = __pkt_stream_generate(pkt_stream->nb_pkts / 2, ++ pkt_stream->pkts[0].len, i, 2); ++ test->ifobj_tx->xsk_arr[i].pkt_stream = pkt_stream; ++ ++ pkt_stream = test->ifobj_rx->xsk_arr[i].pkt_stream; ++ pkt_stream = __pkt_stream_generate(pkt_stream->nb_pkts / 2, ++ pkt_stream->pkts[0].len, i, 2); ++ test->ifobj_rx->xsk_arr[i].pkt_stream = pkt_stream; ++ } ++} ++ ++static u64 pkt_get_addr(struct pkt *pkt, struct xsk_umem_info *umem) ++{ ++ if (!pkt->valid) ++ return pkt->offset; ++ return pkt->offset + umem_alloc_buffer(umem); ++} ++ ++static void pkt_stream_cancel(struct pkt_stream *pkt_stream) ++{ ++ pkt_stream->current_pkt_nb--; ++} ++ ++static void pkt_generate(struct xsk_socket_info *xsk, struct xsk_umem_info *umem, u64 addr, u32 len, ++ u32 pkt_nb, u32 bytes_written) ++{ ++ void *data = xsk_umem__get_data(umem->buffer, addr); ++ ++ if (len < MIN_PKT_SIZE) ++ return; ++ ++ if (!bytes_written) { ++ gen_eth_hdr(xsk, data); ++ ++ len -= PKT_HDR_SIZE; ++ data += PKT_HDR_SIZE; ++ } else { ++ bytes_written -= PKT_HDR_SIZE; ++ } ++ ++ write_payload(data, pkt_nb, bytes_written, len); ++} ++ ++static struct pkt_stream *__pkt_stream_generate_custom(struct ifobject *ifobj, struct pkt *frames, ++ u32 nb_frames, bool verbatim) ++{ ++ u32 i, len = 0, pkt_nb = 0, payload = 0; ++ struct pkt_stream *pkt_stream; ++ ++ pkt_stream = __pkt_stream_alloc(nb_frames); ++ if (!pkt_stream) ++ exit_with_error(ENOMEM); ++ ++ for (i = 0; i < nb_frames; i++) { ++ struct pkt *pkt = &pkt_stream->pkts[pkt_nb]; ++ struct pkt *frame = &frames[i]; ++ ++ pkt->offset = frame->offset; ++ if (verbatim) { ++ *pkt = *frame; ++ pkt->pkt_nb = payload; ++ if (!frame->valid || !pkt_continues(frame->options)) ++ payload++; ++ } else { ++ if (frame->valid) ++ len += frame->len; ++ if (frame->valid && pkt_continues(frame->options)) ++ continue; ++ ++ pkt->pkt_nb = pkt_nb; ++ pkt->len = len; ++ pkt->valid = frame->valid; ++ pkt->options = 0; ++ ++ len = 0; ++ } ++ ++ print_verbose("offset: %d len: %u valid: %u options: %u pkt_nb: %u\n", ++ pkt->offset, pkt->len, pkt->valid, pkt->options, pkt->pkt_nb); ++ ++ if (pkt->valid && pkt->len > pkt_stream->max_pkt_len) ++ pkt_stream->max_pkt_len = pkt->len; ++ ++ if (pkt->valid) ++ pkt_stream->nb_valid_entries++; ++ ++ pkt_nb++; ++ } ++ ++ pkt_stream->nb_pkts = pkt_nb; ++ pkt_stream->verbatim = verbatim; ++ return pkt_stream; ++} ++ ++static void pkt_stream_generate_custom(struct test_spec *test, struct pkt *pkts, u32 nb_pkts) ++{ ++ struct pkt_stream *pkt_stream; ++ ++ pkt_stream = __pkt_stream_generate_custom(test->ifobj_tx, pkts, nb_pkts, true); ++ test->ifobj_tx->xsk->pkt_stream = pkt_stream; ++ ++ pkt_stream = __pkt_stream_generate_custom(test->ifobj_rx, pkts, nb_pkts, false); ++ test->ifobj_rx->xsk->pkt_stream = pkt_stream; ++} ++ ++static void pkt_print_data(u32 *data, u32 cnt) ++{ ++ u32 i; ++ ++ for (i = 0; i < cnt; i++) { ++ u32 seqnum, pkt_nb; ++ ++ seqnum = ntohl(*data) & 0xffff; ++ pkt_nb = ntohl(*data) >> 16; ++ ksft_print_msg("%u:%u ", pkt_nb, seqnum); ++ data++; ++ } ++} ++ ++static void pkt_dump(void *pkt, u32 len, bool eth_header) ++{ ++ struct ethhdr *ethhdr = pkt; ++ u32 i, *data; ++ ++ if (eth_header) { ++ /*extract L2 frame */ ++ ksft_print_msg("DEBUG>> L2: dst mac: "); ++ for (i = 0; i < ETH_ALEN; i++) ++ ksft_print_msg("%02X", ethhdr->h_dest[i]); ++ ++ ksft_print_msg("\nDEBUG>> L2: src mac: "); ++ for (i = 0; i < ETH_ALEN; i++) ++ ksft_print_msg("%02X", ethhdr->h_source[i]); ++ ++ data = pkt + PKT_HDR_SIZE; ++ } else { ++ data = pkt; ++ } ++ ++ /*extract L5 frame */ ++ ksft_print_msg("\nDEBUG>> L5: seqnum: "); ++ pkt_print_data(data, PKT_DUMP_NB_TO_PRINT); ++ ksft_print_msg("...."); ++ if (len > PKT_DUMP_NB_TO_PRINT * sizeof(u32)) { ++ ksft_print_msg("\n.... "); ++ pkt_print_data(data + len / sizeof(u32) - PKT_DUMP_NB_TO_PRINT, ++ PKT_DUMP_NB_TO_PRINT); ++ } ++ ksft_print_msg("\n---------------------------------------\n"); ++} ++ ++static bool is_offset_correct(struct xsk_umem_info *umem, struct pkt *pkt, u64 addr) ++{ ++ u32 headroom = umem->unaligned_mode ? 0 : umem->frame_headroom; ++ u32 offset = addr % umem->frame_size, expected_offset; ++ int pkt_offset = pkt->valid ? pkt->offset : 0; ++ ++ if (!umem->unaligned_mode) ++ pkt_offset = 0; ++ ++ expected_offset = (pkt_offset + headroom + XDP_PACKET_HEADROOM) % umem->frame_size; ++ ++ if (offset == expected_offset) ++ return true; ++ ++ ksft_print_msg("[%s] expected [%u], got [%u]\n", __func__, expected_offset, offset); ++ return false; ++} ++ ++static bool is_metadata_correct(struct pkt *pkt, void *buffer, u64 addr) ++{ ++ void *data = xsk_umem__get_data(buffer, addr); ++ struct xdp_info *meta = data - sizeof(struct xdp_info); ++ ++ if (meta->count != pkt->pkt_nb) { ++ ksft_print_msg("[%s] expected meta_count [%d], got meta_count [%llu]\n", ++ __func__, pkt->pkt_nb, ++ (unsigned long long)meta->count); ++ return false; ++ } ++ ++ return true; ++} ++ ++static bool is_adjust_tail_supported(struct xsk_xdp_progs *skel_rx) ++{ ++ struct bpf_map *data_map; ++ int adjust_value = 0; ++ int key = 0; ++ int ret; ++ ++ data_map = bpf_object__find_map_by_name(skel_rx->obj, "xsk_xdp_.bss"); ++ if (!data_map || !bpf_map__is_internal(data_map)) { ++ ksft_print_msg("Error: could not find bss section of XDP program\n"); ++ exit_with_error(errno); ++ } ++ ++ ret = bpf_map_lookup_elem(bpf_map__fd(data_map), &key, &adjust_value); ++ if (ret) { ++ ksft_print_msg("Error: bpf_map_lookup_elem failed with error %d\n", ret); ++ exit_with_error(errno); ++ } ++ ++ /* Set the 'adjust_value' variable to -EOPNOTSUPP in the XDP program if the adjust_tail ++ * helper is not supported. Skip the adjust_tail test case in this scenario. ++ */ ++ return adjust_value != -EOPNOTSUPP; ++} ++ ++static bool is_frag_valid(struct xsk_umem_info *umem, u64 addr, u32 len, u32 expected_pkt_nb, ++ u32 bytes_processed) ++{ ++ u32 seqnum, pkt_nb, *pkt_data, words_to_end, expected_seqnum; ++ void *data = xsk_umem__get_data(umem->buffer, addr); ++ ++ addr -= umem->base_addr; ++ ++ if (addr >= umem->num_frames * umem->frame_size || ++ addr + len > umem->num_frames * umem->frame_size) { ++ ksft_print_msg("Frag invalid addr: %llx len: %u\n", ++ (unsigned long long)addr, len); ++ return false; ++ } ++ if (!umem->unaligned_mode && addr % umem->frame_size + len > umem->frame_size) { ++ ksft_print_msg("Frag crosses frame boundary addr: %llx len: %u\n", ++ (unsigned long long)addr, len); ++ return false; ++ } ++ ++ pkt_data = data; ++ if (!bytes_processed) { ++ pkt_data += PKT_HDR_SIZE / sizeof(*pkt_data); ++ len -= PKT_HDR_SIZE; ++ } else { ++ bytes_processed -= PKT_HDR_SIZE; ++ } ++ ++ expected_seqnum = bytes_processed / sizeof(*pkt_data); ++ seqnum = ntohl(*pkt_data) & 0xffff; ++ pkt_nb = ntohl(*pkt_data) >> 16; ++ ++ if (expected_pkt_nb != pkt_nb) { ++ ksft_print_msg("[%s] expected pkt_nb [%u], got pkt_nb [%u]\n", ++ __func__, expected_pkt_nb, pkt_nb); ++ goto error; ++ } ++ if (expected_seqnum != seqnum) { ++ ksft_print_msg("[%s] expected seqnum at start [%u], got seqnum [%u]\n", ++ __func__, expected_seqnum, seqnum); ++ goto error; ++ } ++ ++ words_to_end = len / sizeof(*pkt_data) - 1; ++ pkt_data += words_to_end; ++ seqnum = ntohl(*pkt_data) & 0xffff; ++ expected_seqnum += words_to_end; ++ if (expected_seqnum != seqnum) { ++ ksft_print_msg("[%s] expected seqnum at end [%u], got seqnum [%u]\n", ++ __func__, expected_seqnum, seqnum); ++ goto error; ++ } ++ ++ return true; ++ ++error: ++ pkt_dump(data, len, !bytes_processed); ++ return false; ++} ++ ++static bool is_pkt_valid(struct pkt *pkt, void *buffer, u64 addr, u32 len) ++{ ++ if (pkt->len != len) { ++ ksft_print_msg("[%s] expected packet length [%d], got length [%d]\n", ++ __func__, pkt->len, len); ++ pkt_dump(xsk_umem__get_data(buffer, addr), len, true); ++ return false; ++ } ++ ++ return true; ++} ++ ++static u32 load_value(u32 *counter) ++{ ++ return __atomic_load_n(counter, __ATOMIC_ACQUIRE); ++} ++ ++static bool kick_tx_with_check(struct xsk_socket_info *xsk, int *ret) ++{ ++ u32 max_budget = MAX_TX_BUDGET_DEFAULT; ++ u32 cons, ready_to_send; ++ int delta; ++ ++ cons = load_value(xsk->tx.consumer); ++ ready_to_send = load_value(xsk->tx.producer) - cons; ++ *ret = sendto(xsk_socket__fd(xsk->xsk), NULL, 0, MSG_DONTWAIT, NULL, 0); ++ ++ delta = load_value(xsk->tx.consumer) - cons; ++ /* By default, xsk should consume exact @max_budget descs at one ++ * send in this case where hitting the max budget limit in while ++ * loop is triggered in __xsk_generic_xmit(). Please make sure that ++ * the number of descs to be sent is larger than @max_budget, or ++ * else the tx.consumer will be updated in xskq_cons_peek_desc() ++ * in time which hides the issue we try to verify. ++ */ ++ if (ready_to_send > max_budget && delta != max_budget) ++ return false; ++ ++ return true; ++} ++ ++int kick_tx(struct xsk_socket_info *xsk) ++{ ++ int ret; ++ ++ if (xsk->check_consumer) { ++ if (!kick_tx_with_check(xsk, &ret)) ++ return TEST_FAILURE; ++ } else { ++ ret = sendto(xsk_socket__fd(xsk->xsk), NULL, 0, MSG_DONTWAIT, NULL, 0); ++ } ++ if (ret >= 0) ++ return TEST_PASS; ++ if (errno == ENOBUFS || errno == EAGAIN || errno == EBUSY || errno == ENETDOWN) { ++ usleep(100); ++ return TEST_PASS; ++ } ++ return TEST_FAILURE; ++} ++ ++int kick_rx(struct xsk_socket_info *xsk) ++{ ++ int ret; ++ ++ ret = recvfrom(xsk_socket__fd(xsk->xsk), NULL, 0, MSG_DONTWAIT, NULL, NULL); ++ if (ret < 0) ++ return TEST_FAILURE; ++ ++ return TEST_PASS; ++} ++ ++static int complete_pkts(struct xsk_socket_info *xsk, int batch_size) ++{ ++ unsigned int rcvd; ++ u32 idx; ++ int ret; ++ ++ if (xsk_ring_prod__needs_wakeup(&xsk->tx)) { ++ ret = kick_tx(xsk); ++ if (ret) ++ return TEST_FAILURE; ++ } ++ ++ rcvd = xsk_ring_cons__peek(&xsk->umem->cq, batch_size, &idx); ++ if (rcvd) { ++ if (rcvd > xsk->outstanding_tx) { ++ u64 addr = *xsk_ring_cons__comp_addr(&xsk->umem->cq, idx + rcvd - 1); ++ ++ ksft_print_msg("[%s] Too many packets completed\n", __func__); ++ ksft_print_msg("Last completion address: %llx\n", ++ (unsigned long long)addr); ++ return TEST_FAILURE; ++ } ++ ++ xsk_ring_cons__release(&xsk->umem->cq, rcvd); ++ xsk->outstanding_tx -= rcvd; ++ } ++ ++ return TEST_PASS; ++} ++ ++static int __receive_pkts(struct test_spec *test, struct xsk_socket_info *xsk) ++{ ++ u32 frags_processed = 0, nb_frags = 0, pkt_len = 0; ++ u32 idx_rx = 0, idx_fq = 0, rcvd, pkts_sent = 0; ++ struct pkt_stream *pkt_stream = xsk->pkt_stream; ++ struct ifobject *ifobj = test->ifobj_rx; ++ struct xsk_umem_info *umem = xsk->umem; ++ struct pollfd fds = { }; ++ struct pkt *pkt; ++ u64 first_addr = 0; ++ int ret; ++ ++ fds.fd = xsk_socket__fd(xsk->xsk); ++ fds.events = POLLIN; ++ ++ ret = kick_rx(xsk); ++ if (ret) ++ return TEST_FAILURE; ++ ++ if (ifobj->use_poll) { ++ ret = poll(&fds, 1, POLL_TMOUT); ++ if (ret < 0) ++ return TEST_FAILURE; ++ ++ if (!ret) { ++ if (!is_umem_valid(test->ifobj_tx)) ++ return TEST_PASS; ++ ++ ksft_print_msg("ERROR: [%s] Poll timed out\n", __func__); ++ return TEST_CONTINUE; ++ } ++ ++ if (!(fds.revents & POLLIN)) ++ return TEST_CONTINUE; ++ } ++ ++ rcvd = xsk_ring_cons__peek(&xsk->rx, xsk->batch_size, &idx_rx); ++ if (!rcvd) ++ return TEST_CONTINUE; ++ ++ if (ifobj->use_fill_ring) { ++ ret = xsk_ring_prod__reserve(&umem->fq, rcvd, &idx_fq); ++ while (ret != rcvd) { ++ if (xsk_ring_prod__needs_wakeup(&umem->fq)) { ++ ret = poll(&fds, 1, POLL_TMOUT); ++ if (ret < 0) ++ return TEST_FAILURE; ++ } ++ ret = xsk_ring_prod__reserve(&umem->fq, rcvd, &idx_fq); ++ } ++ } ++ ++ while (frags_processed < rcvd) { ++ const struct xdp_desc *desc = xsk_ring_cons__rx_desc(&xsk->rx, idx_rx++); ++ u64 addr = desc->addr, orig; ++ ++ orig = xsk_umem__extract_addr(addr); ++ addr = xsk_umem__add_offset_to_addr(addr); ++ ++ if (!nb_frags) { ++ pkt = pkt_stream_get_next_rx_pkt(pkt_stream, &pkts_sent); ++ if (!pkt) { ++ ksft_print_msg("[%s] received too many packets addr: %lx len %u\n", ++ __func__, addr, desc->len); ++ return TEST_FAILURE; ++ } ++ } ++ ++ print_verbose("Rx: addr: %lx len: %u options: %u pkt_nb: %u valid: %u\n", ++ addr, desc->len, desc->options, pkt->pkt_nb, pkt->valid); ++ ++ if (!is_frag_valid(umem, addr, desc->len, pkt->pkt_nb, pkt_len) || ++ !is_offset_correct(umem, pkt, addr) || (ifobj->use_metadata && ++ !is_metadata_correct(pkt, umem->buffer, addr))) ++ return TEST_FAILURE; ++ ++ if (!nb_frags++) ++ first_addr = addr; ++ frags_processed++; ++ pkt_len += desc->len; ++ if (ifobj->use_fill_ring) ++ *xsk_ring_prod__fill_addr(&umem->fq, idx_fq++) = orig; ++ ++ if (pkt_continues(desc->options)) ++ continue; ++ ++ /* The complete packet has been received */ ++ if (!is_pkt_valid(pkt, umem->buffer, first_addr, pkt_len) || ++ !is_offset_correct(umem, pkt, addr)) ++ return TEST_FAILURE; ++ ++ pkt_stream->nb_rx_pkts++; ++ nb_frags = 0; ++ pkt_len = 0; ++ } ++ ++ if (nb_frags) { ++ /* In the middle of a packet. Start over from beginning of packet. */ ++ idx_rx -= nb_frags; ++ xsk_ring_cons__cancel(&xsk->rx, nb_frags); ++ if (ifobj->use_fill_ring) { ++ idx_fq -= nb_frags; ++ xsk_ring_prod__cancel(&umem->fq, nb_frags); ++ } ++ frags_processed -= nb_frags; ++ } ++ ++ if (ifobj->use_fill_ring) ++ xsk_ring_prod__submit(&umem->fq, frags_processed); ++ if (ifobj->release_rx) ++ xsk_ring_cons__release(&xsk->rx, frags_processed); ++ ++ pthread_mutex_lock(&pacing_mutex); ++ pkts_in_flight -= pkts_sent; ++ pthread_mutex_unlock(&pacing_mutex); ++ pkts_sent = 0; ++ ++ return TEST_CONTINUE; ++} ++ ++bool all_packets_received(struct test_spec *test, struct xsk_socket_info *xsk, u32 sock_num, ++ unsigned long *bitmap) ++{ ++ struct pkt_stream *pkt_stream = xsk->pkt_stream; ++ ++ if (!pkt_stream) { ++ __set_bit(sock_num, bitmap); ++ return false; ++ } ++ ++ if (pkt_stream->nb_rx_pkts == pkt_stream->nb_valid_entries) { ++ __set_bit(sock_num, bitmap); ++ if (bitmap_full(bitmap, test->nb_sockets)) ++ return true; ++ } ++ ++ return false; ++} ++ ++static int receive_pkts(struct test_spec *test) ++{ ++ struct timeval tv_end, tv_now, tv_timeout = {THREAD_TMOUT, 0}; ++ DECLARE_BITMAP(bitmap, test->nb_sockets); ++ struct xsk_socket_info *xsk; ++ u32 sock_num = 0; ++ int res, ret; ++ ++ ret = gettimeofday(&tv_now, NULL); ++ if (ret) ++ exit_with_error(errno); ++ ++ timeradd(&tv_now, &tv_timeout, &tv_end); ++ ++ while (1) { ++ xsk = &test->ifobj_rx->xsk_arr[sock_num]; ++ ++ if ((all_packets_received(test, xsk, sock_num, bitmap))) ++ break; ++ ++ res = __receive_pkts(test, xsk); ++ if (!(res == TEST_PASS || res == TEST_CONTINUE)) ++ return res; ++ ++ ret = gettimeofday(&tv_now, NULL); ++ if (ret) ++ exit_with_error(errno); ++ ++ if (timercmp(&tv_now, &tv_end, >)) { ++ ksft_print_msg("ERROR: [%s] Receive loop timed out\n", __func__); ++ return TEST_FAILURE; ++ } ++ sock_num = (sock_num + 1) % test->nb_sockets; ++ } ++ ++ return TEST_PASS; ++} ++ ++static int __send_pkts(struct ifobject *ifobject, struct xsk_socket_info *xsk, bool timeout) ++{ ++ u32 i, idx = 0, valid_pkts = 0, valid_frags = 0, buffer_len; ++ struct pkt_stream *pkt_stream = xsk->pkt_stream; ++ struct xsk_umem_info *umem = ifobject->umem; ++ bool use_poll = ifobject->use_poll; ++ struct pollfd fds = { }; ++ int ret; ++ ++ buffer_len = pkt_get_buffer_len(umem, pkt_stream->max_pkt_len); ++ /* pkts_in_flight might be negative if many invalid packets are sent */ ++ if (pkts_in_flight >= (int)((umem_size(umem) - xsk->batch_size * buffer_len) / ++ buffer_len)) { ++ ret = kick_tx(xsk); ++ if (ret) ++ return TEST_FAILURE; ++ return TEST_CONTINUE; ++ } ++ ++ fds.fd = xsk_socket__fd(xsk->xsk); ++ fds.events = POLLOUT; ++ ++ while (xsk_ring_prod__reserve(&xsk->tx, xsk->batch_size, &idx) < xsk->batch_size) { ++ if (use_poll) { ++ ret = poll(&fds, 1, POLL_TMOUT); ++ if (timeout) { ++ if (ret < 0) { ++ ksft_print_msg("ERROR: [%s] Poll error %d\n", ++ __func__, errno); ++ return TEST_FAILURE; ++ } ++ if (ret == 0) ++ return TEST_PASS; ++ break; ++ } ++ if (ret <= 0) { ++ ksft_print_msg("ERROR: [%s] Poll error %d\n", ++ __func__, errno); ++ return TEST_FAILURE; ++ } ++ } ++ ++ complete_pkts(xsk, xsk->batch_size); ++ } ++ ++ for (i = 0; i < xsk->batch_size; i++) { ++ struct pkt *pkt = pkt_stream_get_next_tx_pkt(pkt_stream); ++ u32 nb_frags_left, nb_frags, bytes_written = 0; ++ ++ if (!pkt) ++ break; ++ ++ nb_frags = pkt_nb_frags(umem->frame_size, pkt_stream, pkt); ++ if (nb_frags > xsk->batch_size - i) { ++ pkt_stream_cancel(pkt_stream); ++ xsk_ring_prod__cancel(&xsk->tx, xsk->batch_size - i); ++ break; ++ } ++ nb_frags_left = nb_frags; ++ ++ while (nb_frags_left--) { ++ struct xdp_desc *tx_desc = xsk_ring_prod__tx_desc(&xsk->tx, idx + i); ++ ++ tx_desc->addr = pkt_get_addr(pkt, ifobject->umem); ++ if (pkt_stream->verbatim) { ++ tx_desc->len = pkt->len; ++ tx_desc->options = pkt->options; ++ } else if (nb_frags_left) { ++ tx_desc->len = umem->frame_size; ++ tx_desc->options = XDP_PKT_CONTD; ++ } else { ++ tx_desc->len = pkt->len - bytes_written; ++ tx_desc->options = 0; ++ } ++ if (pkt->valid) ++ pkt_generate(xsk, umem, tx_desc->addr, tx_desc->len, pkt->pkt_nb, ++ bytes_written); ++ bytes_written += tx_desc->len; ++ ++ print_verbose("Tx addr: %llx len: %u options: %u pkt_nb: %u\n", ++ tx_desc->addr, tx_desc->len, tx_desc->options, pkt->pkt_nb); ++ ++ if (nb_frags_left) { ++ i++; ++ if (pkt_stream->verbatim) ++ pkt = pkt_stream_get_next_tx_pkt(pkt_stream); ++ } ++ } ++ ++ if (pkt && pkt->valid) { ++ valid_pkts++; ++ valid_frags += nb_frags; ++ } ++ } ++ ++ pthread_mutex_lock(&pacing_mutex); ++ pkts_in_flight += valid_pkts; ++ pthread_mutex_unlock(&pacing_mutex); ++ ++ xsk_ring_prod__submit(&xsk->tx, i); ++ xsk->outstanding_tx += valid_frags; ++ ++ if (use_poll) { ++ ret = poll(&fds, 1, POLL_TMOUT); ++ if (ret <= 0) { ++ if (ret == 0 && timeout) ++ return TEST_PASS; ++ ++ ksft_print_msg("ERROR: [%s] Poll error %d\n", __func__, ret); ++ return TEST_FAILURE; ++ } ++ } ++ ++ if (!timeout) { ++ if (complete_pkts(xsk, i)) ++ return TEST_FAILURE; ++ ++ usleep(10); ++ return TEST_PASS; ++ } ++ ++ return TEST_CONTINUE; ++} ++ ++static int wait_for_tx_completion(struct xsk_socket_info *xsk) ++{ ++ struct timeval tv_end, tv_now, tv_timeout = {THREAD_TMOUT, 0}; ++ int ret; ++ ++ ret = gettimeofday(&tv_now, NULL); ++ if (ret) ++ exit_with_error(errno); ++ timeradd(&tv_now, &tv_timeout, &tv_end); ++ ++ while (xsk->outstanding_tx) { ++ ret = gettimeofday(&tv_now, NULL); ++ if (ret) ++ exit_with_error(errno); ++ if (timercmp(&tv_now, &tv_end, >)) { ++ ksft_print_msg("ERROR: [%s] Transmission loop timed out\n", __func__); ++ return TEST_FAILURE; ++ } ++ ++ complete_pkts(xsk, xsk->batch_size); ++ } ++ ++ return TEST_PASS; ++} ++ ++bool all_packets_sent(struct test_spec *test, unsigned long *bitmap) ++{ ++ return bitmap_full(bitmap, test->nb_sockets); ++} ++ ++static int send_pkts(struct test_spec *test, struct ifobject *ifobject) ++{ ++ bool timeout = !is_umem_valid(test->ifobj_rx); ++ DECLARE_BITMAP(bitmap, test->nb_sockets); ++ u32 i, ret; ++ ++ while (!(all_packets_sent(test, bitmap))) { ++ for (i = 0; i < test->nb_sockets; i++) { ++ struct pkt_stream *pkt_stream; ++ ++ pkt_stream = ifobject->xsk_arr[i].pkt_stream; ++ if (!pkt_stream || pkt_stream->current_pkt_nb >= pkt_stream->nb_pkts) { ++ __set_bit(i, bitmap); ++ continue; ++ } ++ ret = __send_pkts(ifobject, &ifobject->xsk_arr[i], timeout); ++ if (ret == TEST_CONTINUE && !test->fail) ++ continue; ++ ++ if ((ret || test->fail) && !timeout) ++ return TEST_FAILURE; ++ ++ if (ret == TEST_PASS && timeout) ++ return ret; ++ ++ ret = wait_for_tx_completion(&ifobject->xsk_arr[i]); ++ if (ret) ++ return TEST_FAILURE; ++ } ++ } ++ ++ return TEST_PASS; ++} ++ ++static int get_xsk_stats(struct xsk_socket *xsk, struct xdp_statistics *stats) ++{ ++ int fd = xsk_socket__fd(xsk), err; ++ socklen_t optlen, expected_len; ++ ++ optlen = sizeof(*stats); ++ err = getsockopt(fd, SOL_XDP, XDP_STATISTICS, stats, &optlen); ++ if (err) { ++ ksft_print_msg("[%s] getsockopt(XDP_STATISTICS) error %u %s\n", ++ __func__, -err, strerror(-err)); ++ return TEST_FAILURE; ++ } ++ ++ expected_len = sizeof(struct xdp_statistics); ++ if (optlen != expected_len) { ++ ksft_print_msg("[%s] getsockopt optlen error. Expected: %u got: %u\n", ++ __func__, expected_len, optlen); ++ return TEST_FAILURE; ++ } ++ ++ return TEST_PASS; ++} ++ ++static int validate_rx_dropped(struct ifobject *ifobject) ++{ ++ struct xsk_socket *xsk = ifobject->xsk->xsk; ++ struct xdp_statistics stats; ++ int err; ++ ++ err = kick_rx(ifobject->xsk); ++ if (err) ++ return TEST_FAILURE; ++ ++ err = get_xsk_stats(xsk, &stats); ++ if (err) ++ return TEST_FAILURE; ++ ++ /* The receiver calls getsockopt after receiving the last (valid) ++ * packet which is not the final packet sent in this test (valid and ++ * invalid packets are sent in alternating fashion with the final ++ * packet being invalid). Since the last packet may or may not have ++ * been dropped already, both outcomes must be allowed. ++ */ ++ if (stats.rx_dropped == ifobject->xsk->pkt_stream->nb_pkts / 2 || ++ stats.rx_dropped == ifobject->xsk->pkt_stream->nb_pkts / 2 - 1) ++ return TEST_PASS; ++ ++ return TEST_FAILURE; ++} ++ ++static int validate_rx_full(struct ifobject *ifobject) ++{ ++ struct xsk_socket *xsk = ifobject->xsk->xsk; ++ struct xdp_statistics stats; ++ int err; ++ ++ usleep(1000); ++ err = kick_rx(ifobject->xsk); ++ if (err) ++ return TEST_FAILURE; ++ ++ err = get_xsk_stats(xsk, &stats); ++ if (err) ++ return TEST_FAILURE; ++ ++ if (stats.rx_ring_full) ++ return TEST_PASS; ++ ++ return TEST_FAILURE; ++} ++ ++static int validate_fill_empty(struct ifobject *ifobject) ++{ ++ struct xsk_socket *xsk = ifobject->xsk->xsk; ++ struct xdp_statistics stats; ++ int err; ++ ++ usleep(1000); ++ err = kick_rx(ifobject->xsk); ++ if (err) ++ return TEST_FAILURE; ++ ++ err = get_xsk_stats(xsk, &stats); ++ if (err) ++ return TEST_FAILURE; ++ ++ if (stats.rx_fill_ring_empty_descs) ++ return TEST_PASS; ++ ++ return TEST_FAILURE; ++} ++ ++static int validate_tx_invalid_descs(struct ifobject *ifobject) ++{ ++ struct xsk_socket *xsk = ifobject->xsk->xsk; ++ int fd = xsk_socket__fd(xsk); ++ struct xdp_statistics stats; ++ socklen_t optlen; ++ int err; ++ ++ optlen = sizeof(stats); ++ err = getsockopt(fd, SOL_XDP, XDP_STATISTICS, &stats, &optlen); ++ if (err) { ++ ksft_print_msg("[%s] getsockopt(XDP_STATISTICS) error %u %s\n", ++ __func__, -err, strerror(-err)); ++ return TEST_FAILURE; ++ } ++ ++ if (stats.tx_invalid_descs != ifobject->xsk->pkt_stream->nb_pkts / 2) { ++ ksft_print_msg("[%s] tx_invalid_descs incorrect. Got [%llu] expected [%u]\n", ++ __func__, ++ (unsigned long long)stats.tx_invalid_descs, ++ ifobject->xsk->pkt_stream->nb_pkts); ++ return TEST_FAILURE; ++ } ++ ++ return TEST_PASS; ++} ++ ++static void xsk_configure(struct test_spec *test, struct ifobject *ifobject, ++ struct xsk_umem_info *umem, bool tx) ++{ ++ int i, ret; ++ ++ for (i = 0; i < test->nb_sockets; i++) { ++ bool shared = (ifobject->shared_umem && tx) ? true : !!i; ++ u32 ctr = 0; ++ ++ while (ctr++ < SOCK_RECONF_CTR) { ++ ret = xsk_configure_socket(&ifobject->xsk_arr[i], umem, ++ ifobject, shared); ++ if (!ret) ++ break; ++ ++ /* Retry if it fails as xsk_socket__create() is asynchronous */ ++ if (ctr >= SOCK_RECONF_CTR) ++ exit_with_error(-ret); ++ usleep(USLEEP_MAX); ++ } ++ if (ifobject->busy_poll) ++ enable_busy_poll(&ifobject->xsk_arr[i]); ++ } ++} ++ ++static void thread_common_ops_tx(struct test_spec *test, struct ifobject *ifobject) ++{ ++ xsk_configure(test, ifobject, test->ifobj_rx->umem, true); ++ ifobject->xsk = &ifobject->xsk_arr[0]; ++ ifobject->xskmap = test->ifobj_rx->xskmap; ++ memcpy(ifobject->umem, test->ifobj_rx->umem, sizeof(struct xsk_umem_info)); ++ ifobject->umem->base_addr = 0; ++} ++ ++static void xsk_populate_fill_ring(struct xsk_umem_info *umem, struct pkt_stream *pkt_stream, ++ bool fill_up) ++{ ++ u32 rx_frame_size = umem->frame_size - XDP_PACKET_HEADROOM; ++ u32 idx = 0, filled = 0, buffers_to_fill, nb_pkts; ++ int ret; ++ ++ if (umem->num_frames < XSK_RING_PROD__DEFAULT_NUM_DESCS) ++ buffers_to_fill = umem->num_frames; ++ else ++ buffers_to_fill = umem->fill_size; ++ ++ ret = xsk_ring_prod__reserve(&umem->fq, buffers_to_fill, &idx); ++ if (ret != buffers_to_fill) ++ exit_with_error(ENOSPC); ++ ++ while (filled < buffers_to_fill) { ++ struct pkt *pkt = pkt_stream_get_next_rx_pkt(pkt_stream, &nb_pkts); ++ u64 addr; ++ u32 i; ++ ++ for (i = 0; i < pkt_nb_frags(rx_frame_size, pkt_stream, pkt); i++) { ++ if (!pkt) { ++ if (!fill_up) ++ break; ++ addr = filled * umem->frame_size + umem->base_addr; ++ } else if (pkt->offset >= 0) { ++ addr = pkt->offset % umem->frame_size + umem_alloc_buffer(umem); ++ } else { ++ addr = pkt->offset + umem_alloc_buffer(umem); ++ } ++ ++ *xsk_ring_prod__fill_addr(&umem->fq, idx++) = addr; ++ if (++filled >= buffers_to_fill) ++ break; ++ } ++ } ++ xsk_ring_prod__submit(&umem->fq, filled); ++ xsk_ring_prod__cancel(&umem->fq, buffers_to_fill - filled); ++ ++ pkt_stream_reset(pkt_stream); ++ umem_reset_alloc(umem); ++} ++ ++static void thread_common_ops(struct test_spec *test, struct ifobject *ifobject) ++{ ++ LIBBPF_OPTS(bpf_xdp_query_opts, opts); ++ int mmap_flags; ++ u64 umem_sz; ++ void *bufs; ++ int ret; ++ u32 i; ++ ++ umem_sz = ifobject->umem->num_frames * ifobject->umem->frame_size; ++ mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE; ++ ++ if (ifobject->umem->unaligned_mode) ++ mmap_flags |= MAP_HUGETLB | MAP_HUGE_2MB; ++ ++ if (ifobject->shared_umem) ++ umem_sz *= 2; ++ ++ bufs = mmap(NULL, umem_sz, PROT_READ | PROT_WRITE, mmap_flags, -1, 0); ++ if (bufs == MAP_FAILED) ++ exit_with_error(errno); ++ ++ ret = xsk_configure_umem(ifobject, ifobject->umem, bufs, umem_sz); ++ if (ret) ++ exit_with_error(-ret); ++ ++ xsk_configure(test, ifobject, ifobject->umem, false); ++ ++ ifobject->xsk = &ifobject->xsk_arr[0]; ++ ++ if (!ifobject->rx_on) ++ return; ++ ++ xsk_populate_fill_ring(ifobject->umem, ifobject->xsk->pkt_stream, ifobject->use_fill_ring); ++ ++ for (i = 0; i < test->nb_sockets; i++) { ++ ifobject->xsk = &ifobject->xsk_arr[i]; ++ ret = xsk_update_xskmap(ifobject->xskmap, ifobject->xsk->xsk, i); ++ if (ret) ++ exit_with_error(errno); ++ } ++} ++ ++void *worker_testapp_validate_tx(void *arg) ++{ ++ struct test_spec *test = (struct test_spec *)arg; ++ struct ifobject *ifobject = test->ifobj_tx; ++ int err; ++ ++ if (test->current_step == 1) { ++ if (!ifobject->shared_umem) ++ thread_common_ops(test, ifobject); ++ else ++ thread_common_ops_tx(test, ifobject); ++ } ++ ++ err = send_pkts(test, ifobject); ++ ++ if (!err && ifobject->validation_func) ++ err = ifobject->validation_func(ifobject); ++ if (err) ++ test->fail = true; ++ ++ pthread_exit(NULL); ++} ++ ++void *worker_testapp_validate_rx(void *arg) ++{ ++ struct test_spec *test = (struct test_spec *)arg; ++ struct ifobject *ifobject = test->ifobj_rx; ++ int err; ++ ++ if (test->current_step == 1) { ++ thread_common_ops(test, ifobject); ++ } else { ++ xsk_clear_xskmap(ifobject->xskmap); ++ err = xsk_update_xskmap(ifobject->xskmap, ifobject->xsk->xsk, 0); ++ if (err) { ++ ksft_print_msg("Error: Failed to update xskmap, error %s\n", ++ strerror(-err)); ++ exit_with_error(-err); ++ } ++ } ++ ++ pthread_barrier_wait(&barr); ++ ++ err = receive_pkts(test); ++ ++ if (!err && ifobject->validation_func) ++ err = ifobject->validation_func(ifobject); ++ ++ if (err) { ++ if (test->adjust_tail && !is_adjust_tail_supported(ifobject->xdp_progs)) ++ test->adjust_tail_support = false; ++ else ++ test->fail = true; ++ } ++ ++ pthread_exit(NULL); ++} ++ ++static void testapp_clean_xsk_umem(struct ifobject *ifobj) ++{ ++ u64 umem_sz = ifobj->umem->num_frames * ifobj->umem->frame_size; ++ ++ if (ifobj->shared_umem) ++ umem_sz *= 2; ++ ++ umem_sz = ceil_u64(umem_sz, HUGEPAGE_SIZE) * HUGEPAGE_SIZE; ++ xsk_umem__delete(ifobj->umem->umem); ++ munmap(ifobj->umem->buffer, umem_sz); ++} ++ ++static void handler(int signum) ++{ ++ pthread_exit(NULL); ++} ++ ++static bool xdp_prog_changed_rx(struct test_spec *test) ++{ ++ struct ifobject *ifobj = test->ifobj_rx; ++ ++ return ifobj->xdp_prog != test->xdp_prog_rx || ifobj->mode != test->mode; ++} ++ ++static bool xdp_prog_changed_tx(struct test_spec *test) ++{ ++ struct ifobject *ifobj = test->ifobj_tx; ++ ++ return ifobj->xdp_prog != test->xdp_prog_tx || ifobj->mode != test->mode; ++} ++ ++static void xsk_reattach_xdp(struct ifobject *ifobj, struct bpf_program *xdp_prog, ++ struct bpf_map *xskmap, enum test_mode mode) ++{ ++ int err; ++ ++ xsk_detach_xdp_program(ifobj->ifindex, mode_to_xdp_flags(ifobj->mode)); ++ err = xsk_attach_xdp_program(xdp_prog, ifobj->ifindex, mode_to_xdp_flags(mode)); ++ if (err) { ++ ksft_print_msg("Error attaching XDP program\n"); ++ exit_with_error(-err); ++ } ++ ++ if (ifobj->mode != mode && (mode == TEST_MODE_DRV || mode == TEST_MODE_ZC)) ++ if (!xsk_is_in_mode(ifobj->ifindex, XDP_FLAGS_DRV_MODE)) { ++ ksft_print_msg("ERROR: XDP prog not in DRV mode\n"); ++ exit_with_error(EINVAL); ++ } ++ ++ ifobj->xdp_prog = xdp_prog; ++ ifobj->xskmap = xskmap; ++ ifobj->mode = mode; ++} ++ ++static void xsk_attach_xdp_progs(struct test_spec *test, struct ifobject *ifobj_rx, ++ struct ifobject *ifobj_tx) ++{ ++ if (xdp_prog_changed_rx(test)) ++ xsk_reattach_xdp(ifobj_rx, test->xdp_prog_rx, test->xskmap_rx, test->mode); ++ ++ if (!ifobj_tx || ifobj_tx->shared_umem) ++ return; ++ ++ if (xdp_prog_changed_tx(test)) ++ xsk_reattach_xdp(ifobj_tx, test->xdp_prog_tx, test->xskmap_tx, test->mode); ++} ++ ++static int __testapp_validate_traffic(struct test_spec *test, struct ifobject *ifobj1, ++ struct ifobject *ifobj2) ++{ ++ pthread_t t0, t1; ++ int err; ++ ++ if (test->mtu > MAX_ETH_PKT_SIZE) { ++ if (test->mode == TEST_MODE_ZC && (!ifobj1->multi_buff_zc_supp || ++ (ifobj2 && !ifobj2->multi_buff_zc_supp))) { ++ ksft_print_msg("Multi buffer for zero-copy not supported.\n"); ++ return TEST_SKIP; ++ } ++ if (test->mode != TEST_MODE_ZC && (!ifobj1->multi_buff_supp || ++ (ifobj2 && !ifobj2->multi_buff_supp))) { ++ ksft_print_msg("Multi buffer not supported.\n"); ++ return TEST_SKIP; ++ } ++ } ++ err = test_spec_set_mtu(test, test->mtu); ++ if (err) { ++ ksft_print_msg("Error, could not set mtu.\n"); ++ exit_with_error(err); ++ } ++ ++ if (ifobj2) { ++ if (pthread_barrier_init(&barr, NULL, 2)) ++ exit_with_error(errno); ++ pkt_stream_reset(ifobj2->xsk->pkt_stream); ++ } ++ ++ test->current_step++; ++ pkt_stream_reset(ifobj1->xsk->pkt_stream); ++ pkts_in_flight = 0; ++ ++ signal(SIGUSR1, handler); ++ /*Spawn RX thread */ ++ pthread_create(&t0, NULL, ifobj1->func_ptr, test); ++ ++ if (ifobj2) { ++ pthread_barrier_wait(&barr); ++ if (pthread_barrier_destroy(&barr)) ++ exit_with_error(errno); ++ ++ /*Spawn TX thread */ ++ pthread_create(&t1, NULL, ifobj2->func_ptr, test); ++ ++ pthread_join(t1, NULL); ++ } ++ ++ if (!ifobj2) ++ pthread_kill(t0, SIGUSR1); ++ else ++ pthread_join(t0, NULL); ++ ++ if (test->total_steps == test->current_step || test->fail) { ++ u32 i; ++ ++ if (ifobj2) ++ for (i = 0; i < test->nb_sockets; i++) ++ xsk_socket__delete(ifobj2->xsk_arr[i].xsk); ++ ++ for (i = 0; i < test->nb_sockets; i++) ++ xsk_socket__delete(ifobj1->xsk_arr[i].xsk); ++ ++ testapp_clean_xsk_umem(ifobj1); ++ if (ifobj2 && !ifobj2->shared_umem) ++ testapp_clean_xsk_umem(ifobj2); ++ } ++ ++ return !!test->fail; ++} ++ ++static int testapp_validate_traffic(struct test_spec *test) ++{ ++ struct ifobject *ifobj_rx = test->ifobj_rx; ++ struct ifobject *ifobj_tx = test->ifobj_tx; ++ ++ if ((ifobj_rx->umem->unaligned_mode && !ifobj_rx->unaligned_supp) || ++ (ifobj_tx->umem->unaligned_mode && !ifobj_tx->unaligned_supp)) { ++ ksft_print_msg("No huge pages present.\n"); ++ return TEST_SKIP; ++ } ++ ++ if (test->set_ring) { ++ if (ifobj_tx->hw_ring_size_supp) { ++ if (set_ring_size(ifobj_tx)) { ++ ksft_print_msg("Failed to change HW ring size.\n"); ++ return TEST_FAILURE; ++ } ++ } else { ++ ksft_print_msg("Changing HW ring size not supported.\n"); ++ return TEST_SKIP; ++ } ++ } ++ ++ xsk_attach_xdp_progs(test, ifobj_rx, ifobj_tx); ++ return __testapp_validate_traffic(test, ifobj_rx, ifobj_tx); ++} ++ ++static int testapp_validate_traffic_single_thread(struct test_spec *test, struct ifobject *ifobj) ++{ ++ return __testapp_validate_traffic(test, ifobj, NULL); ++} ++ ++int testapp_teardown(struct test_spec *test) ++{ ++ int i; ++ ++ for (i = 0; i < MAX_TEARDOWN_ITER; i++) { ++ if (testapp_validate_traffic(test)) ++ return TEST_FAILURE; ++ test_spec_reset(test); ++ } ++ ++ return TEST_PASS; ++} ++ ++static void swap_directions(struct ifobject **ifobj1, struct ifobject **ifobj2) ++{ ++ thread_func_t tmp_func_ptr = (*ifobj1)->func_ptr; ++ struct ifobject *tmp_ifobj = (*ifobj1); ++ ++ (*ifobj1)->func_ptr = (*ifobj2)->func_ptr; ++ (*ifobj2)->func_ptr = tmp_func_ptr; ++ ++ *ifobj1 = *ifobj2; ++ *ifobj2 = tmp_ifobj; ++} ++ ++int testapp_bidirectional(struct test_spec *test) ++{ ++ int res; ++ ++ test->ifobj_tx->rx_on = true; ++ test->ifobj_rx->tx_on = true; ++ test->total_steps = 2; ++ if (testapp_validate_traffic(test)) ++ return TEST_FAILURE; ++ ++ print_verbose("Switching Tx/Rx direction\n"); ++ swap_directions(&test->ifobj_rx, &test->ifobj_tx); ++ res = __testapp_validate_traffic(test, test->ifobj_rx, test->ifobj_tx); ++ ++ swap_directions(&test->ifobj_rx, &test->ifobj_tx); ++ return res; ++} ++ ++static int swap_xsk_resources(struct test_spec *test) ++{ ++ int ret; ++ ++ test->ifobj_tx->xsk_arr[0].pkt_stream = NULL; ++ test->ifobj_rx->xsk_arr[0].pkt_stream = NULL; ++ test->ifobj_tx->xsk_arr[1].pkt_stream = test->tx_pkt_stream_default; ++ test->ifobj_rx->xsk_arr[1].pkt_stream = test->rx_pkt_stream_default; ++ test->ifobj_tx->xsk = &test->ifobj_tx->xsk_arr[1]; ++ test->ifobj_rx->xsk = &test->ifobj_rx->xsk_arr[1]; ++ ++ ret = xsk_update_xskmap(test->ifobj_rx->xskmap, test->ifobj_rx->xsk->xsk, 0); ++ if (ret) ++ return TEST_FAILURE; ++ ++ return TEST_PASS; ++} ++ ++int testapp_xdp_prog_cleanup(struct test_spec *test) ++{ ++ test->total_steps = 2; ++ test->nb_sockets = 2; ++ if (testapp_validate_traffic(test)) ++ return TEST_FAILURE; ++ ++ if (swap_xsk_resources(test)) ++ return TEST_FAILURE; ++ return testapp_validate_traffic(test); ++} ++ ++int testapp_headroom(struct test_spec *test) ++{ ++ test->ifobj_rx->umem->frame_headroom = UMEM_HEADROOM_TEST_SIZE; ++ return testapp_validate_traffic(test); ++} ++ ++int testapp_stats_rx_dropped(struct test_spec *test) ++{ ++ if (test->mode == TEST_MODE_ZC) { ++ ksft_print_msg("Can not run RX_DROPPED test for ZC mode\n"); ++ return TEST_SKIP; ++ } ++ ++ pkt_stream_replace_half(test, MIN_PKT_SIZE * 4, 0); ++ test->ifobj_rx->umem->frame_headroom = test->ifobj_rx->umem->frame_size - ++ XDP_PACKET_HEADROOM - MIN_PKT_SIZE * 3; ++ pkt_stream_receive_half(test); ++ test->ifobj_rx->validation_func = validate_rx_dropped; ++ return testapp_validate_traffic(test); ++} ++ ++int testapp_stats_tx_invalid_descs(struct test_spec *test) ++{ ++ pkt_stream_replace_half(test, XSK_UMEM__INVALID_FRAME_SIZE, 0); ++ test->ifobj_tx->validation_func = validate_tx_invalid_descs; ++ return testapp_validate_traffic(test); ++} ++ ++int testapp_stats_rx_full(struct test_spec *test) ++{ ++ pkt_stream_replace(test, DEFAULT_UMEM_BUFFERS + DEFAULT_UMEM_BUFFERS / 2, MIN_PKT_SIZE); ++ test->ifobj_rx->xsk->pkt_stream = pkt_stream_generate(DEFAULT_UMEM_BUFFERS, MIN_PKT_SIZE); ++ ++ test->ifobj_rx->xsk->rxqsize = DEFAULT_UMEM_BUFFERS; ++ test->ifobj_rx->release_rx = false; ++ test->ifobj_rx->validation_func = validate_rx_full; ++ return testapp_validate_traffic(test); ++} ++ ++int testapp_stats_fill_empty(struct test_spec *test) ++{ ++ pkt_stream_replace(test, DEFAULT_UMEM_BUFFERS + DEFAULT_UMEM_BUFFERS / 2, MIN_PKT_SIZE); ++ test->ifobj_rx->xsk->pkt_stream = pkt_stream_generate(DEFAULT_UMEM_BUFFERS, MIN_PKT_SIZE); ++ ++ test->ifobj_rx->use_fill_ring = false; ++ test->ifobj_rx->validation_func = validate_fill_empty; ++ return testapp_validate_traffic(test); ++} ++ ++int testapp_send_receive_unaligned(struct test_spec *test) ++{ ++ test->ifobj_tx->umem->unaligned_mode = true; ++ test->ifobj_rx->umem->unaligned_mode = true; ++ /* Let half of the packets straddle a 4K buffer boundary */ ++ pkt_stream_replace_half(test, MIN_PKT_SIZE, -MIN_PKT_SIZE / 2); ++ ++ return testapp_validate_traffic(test); ++} ++ ++int testapp_send_receive_unaligned_mb(struct test_spec *test) ++{ ++ test->mtu = MAX_ETH_JUMBO_SIZE; ++ test->ifobj_tx->umem->unaligned_mode = true; ++ test->ifobj_rx->umem->unaligned_mode = true; ++ pkt_stream_replace(test, DEFAULT_PKT_CNT, MAX_ETH_JUMBO_SIZE); ++ return testapp_validate_traffic(test); ++} ++ ++int testapp_single_pkt(struct test_spec *test) ++{ ++ struct pkt pkts[] = {{0, MIN_PKT_SIZE, 0, true}}; ++ ++ pkt_stream_generate_custom(test, pkts, ARRAY_SIZE(pkts)); ++ return testapp_validate_traffic(test); ++} ++ ++int testapp_send_receive_mb(struct test_spec *test) ++{ ++ test->mtu = MAX_ETH_JUMBO_SIZE; ++ pkt_stream_replace(test, DEFAULT_PKT_CNT, MAX_ETH_JUMBO_SIZE); ++ ++ return testapp_validate_traffic(test); ++} ++ ++int testapp_invalid_desc_mb(struct test_spec *test) ++{ ++ struct xsk_umem_info *umem = test->ifobj_tx->umem; ++ u64 umem_size = umem->num_frames * umem->frame_size; ++ struct pkt pkts[] = { ++ /* Valid packet for synch to start with */ ++ {0, MIN_PKT_SIZE, 0, true, 0}, ++ /* Zero frame len is not legal */ ++ {0, XSK_UMEM__LARGE_FRAME_SIZE, 0, false, XDP_PKT_CONTD}, ++ {0, XSK_UMEM__LARGE_FRAME_SIZE, 0, false, XDP_PKT_CONTD}, ++ {0, 0, 0, false, 0}, ++ /* Invalid address in the second frame */ ++ {0, XSK_UMEM__LARGE_FRAME_SIZE, 0, false, XDP_PKT_CONTD}, ++ {umem_size, XSK_UMEM__LARGE_FRAME_SIZE, 0, false, XDP_PKT_CONTD}, ++ /* Invalid len in the middle */ ++ {0, XSK_UMEM__LARGE_FRAME_SIZE, 0, false, XDP_PKT_CONTD}, ++ {0, XSK_UMEM__INVALID_FRAME_SIZE, 0, false, XDP_PKT_CONTD}, ++ /* Invalid options in the middle */ ++ {0, XSK_UMEM__LARGE_FRAME_SIZE, 0, false, XDP_PKT_CONTD}, ++ {0, XSK_UMEM__LARGE_FRAME_SIZE, 0, false, XSK_DESC__INVALID_OPTION}, ++ /* Transmit 2 frags, receive 3 */ ++ {0, XSK_UMEM__MAX_FRAME_SIZE, 0, true, XDP_PKT_CONTD}, ++ {0, XSK_UMEM__MAX_FRAME_SIZE, 0, true, 0}, ++ /* Middle frame crosses chunk boundary with small length */ ++ {0, XSK_UMEM__LARGE_FRAME_SIZE, 0, false, XDP_PKT_CONTD}, ++ {-MIN_PKT_SIZE / 2, MIN_PKT_SIZE, 0, false, 0}, ++ /* Valid packet for synch so that something is received */ ++ {0, MIN_PKT_SIZE, 0, true, 0}}; ++ ++ if (umem->unaligned_mode) { ++ /* Crossing a chunk boundary allowed */ ++ pkts[12].valid = true; ++ pkts[13].valid = true; ++ } ++ ++ test->mtu = MAX_ETH_JUMBO_SIZE; ++ pkt_stream_generate_custom(test, pkts, ARRAY_SIZE(pkts)); ++ return testapp_validate_traffic(test); ++} ++ ++int testapp_invalid_desc(struct test_spec *test) ++{ ++ struct xsk_umem_info *umem = test->ifobj_tx->umem; ++ u64 umem_size = umem->num_frames * umem->frame_size; ++ struct pkt pkts[] = { ++ /* Zero packet address allowed */ ++ {0, MIN_PKT_SIZE, 0, true}, ++ /* Allowed packet */ ++ {0, MIN_PKT_SIZE, 0, true}, ++ /* Straddling the start of umem */ ++ {-2, MIN_PKT_SIZE, 0, false}, ++ /* Packet too large */ ++ {0, XSK_UMEM__INVALID_FRAME_SIZE, 0, false}, ++ /* Up to end of umem allowed */ ++ {umem_size - MIN_PKT_SIZE - 2 * umem->frame_size, MIN_PKT_SIZE, 0, true}, ++ /* After umem ends */ ++ {umem_size, MIN_PKT_SIZE, 0, false}, ++ /* Straddle the end of umem */ ++ {umem_size - MIN_PKT_SIZE / 2, MIN_PKT_SIZE, 0, false}, ++ /* Straddle a 4K boundary */ ++ {0x1000 - MIN_PKT_SIZE / 2, MIN_PKT_SIZE, 0, false}, ++ /* Straddle a 2K boundary */ ++ {0x800 - MIN_PKT_SIZE / 2, MIN_PKT_SIZE, 0, true}, ++ /* Valid packet for synch so that something is received */ ++ {0, MIN_PKT_SIZE, 0, true}}; ++ ++ if (umem->unaligned_mode) { ++ /* Crossing a page boundary allowed */ ++ pkts[7].valid = true; ++ } ++ if (umem->frame_size == XSK_UMEM__DEFAULT_FRAME_SIZE / 2) { ++ /* Crossing a 2K frame size boundary not allowed */ ++ pkts[8].valid = false; ++ } ++ ++ if (test->ifobj_tx->shared_umem) { ++ pkts[4].offset += umem_size; ++ pkts[5].offset += umem_size; ++ pkts[6].offset += umem_size; ++ } ++ ++ pkt_stream_generate_custom(test, pkts, ARRAY_SIZE(pkts)); ++ return testapp_validate_traffic(test); ++} ++ ++int testapp_xdp_drop(struct test_spec *test) ++{ ++ struct xsk_xdp_progs *skel_rx = test->ifobj_rx->xdp_progs; ++ struct xsk_xdp_progs *skel_tx = test->ifobj_tx->xdp_progs; ++ ++ test_spec_set_xdp_prog(test, skel_rx->progs.xsk_xdp_drop, skel_tx->progs.xsk_xdp_drop, ++ skel_rx->maps.xsk, skel_tx->maps.xsk); ++ ++ pkt_stream_receive_half(test); ++ return testapp_validate_traffic(test); ++} ++ ++int testapp_xdp_metadata_copy(struct test_spec *test) ++{ ++ struct xsk_xdp_progs *skel_rx = test->ifobj_rx->xdp_progs; ++ struct xsk_xdp_progs *skel_tx = test->ifobj_tx->xdp_progs; ++ ++ test_spec_set_xdp_prog(test, skel_rx->progs.xsk_xdp_populate_metadata, ++ skel_tx->progs.xsk_xdp_populate_metadata, ++ skel_rx->maps.xsk, skel_tx->maps.xsk); ++ test->ifobj_rx->use_metadata = true; ++ ++ skel_rx->bss->count = 0; ++ ++ return testapp_validate_traffic(test); ++} ++ ++int testapp_xdp_shared_umem(struct test_spec *test) ++{ ++ struct xsk_xdp_progs *skel_rx = test->ifobj_rx->xdp_progs; ++ struct xsk_xdp_progs *skel_tx = test->ifobj_tx->xdp_progs; ++ ++ test->total_steps = 1; ++ test->nb_sockets = 2; ++ ++ test_spec_set_xdp_prog(test, skel_rx->progs.xsk_xdp_shared_umem, ++ skel_tx->progs.xsk_xdp_shared_umem, ++ skel_rx->maps.xsk, skel_tx->maps.xsk); ++ ++ pkt_stream_even_odd_sequence(test); ++ ++ return testapp_validate_traffic(test); ++} ++ ++int testapp_poll_txq_tmout(struct test_spec *test) ++{ ++ test->ifobj_tx->use_poll = true; ++ /* create invalid frame by set umem frame_size and pkt length equal to 2048 */ ++ test->ifobj_tx->umem->frame_size = 2048; ++ pkt_stream_replace(test, 2 * DEFAULT_PKT_CNT, 2048); ++ return testapp_validate_traffic_single_thread(test, test->ifobj_tx); ++} ++ ++int testapp_poll_rxq_tmout(struct test_spec *test) ++{ ++ test->ifobj_rx->use_poll = true; ++ return testapp_validate_traffic_single_thread(test, test->ifobj_rx); ++} ++ ++int testapp_too_many_frags(struct test_spec *test) ++{ ++ struct pkt *pkts; ++ u32 max_frags, i; ++ int ret; ++ ++ if (test->mode == TEST_MODE_ZC) { ++ max_frags = test->ifobj_tx->xdp_zc_max_segs; ++ } else { ++ max_frags = get_max_skb_frags(); ++ if (!max_frags) { ++ ksft_print_msg("Can't get MAX_SKB_FRAGS from system, using default (17)\n"); ++ max_frags = 17; ++ } ++ max_frags += 1; ++ } ++ ++ pkts = calloc(2 * max_frags + 2, sizeof(struct pkt)); ++ if (!pkts) ++ return TEST_FAILURE; ++ ++ test->mtu = MAX_ETH_JUMBO_SIZE; ++ ++ /* Valid packet for synch */ ++ pkts[0].len = MIN_PKT_SIZE; ++ pkts[0].valid = true; ++ ++ /* One valid packet with the max amount of frags */ ++ for (i = 1; i < max_frags + 1; i++) { ++ pkts[i].len = MIN_PKT_SIZE; ++ pkts[i].options = XDP_PKT_CONTD; ++ pkts[i].valid = true; ++ } ++ pkts[max_frags].options = 0; ++ ++ /* An invalid packet with the max amount of frags but signals packet ++ * continues on the last frag ++ */ ++ for (i = max_frags + 1; i < 2 * max_frags + 1; i++) { ++ pkts[i].len = MIN_PKT_SIZE; ++ pkts[i].options = XDP_PKT_CONTD; ++ pkts[i].valid = false; ++ } ++ ++ /* Valid packet for synch */ ++ pkts[2 * max_frags + 1].len = MIN_PKT_SIZE; ++ pkts[2 * max_frags + 1].valid = true; ++ ++ pkt_stream_generate_custom(test, pkts, 2 * max_frags + 2); ++ ret = testapp_validate_traffic(test); ++ ++ free(pkts); ++ return ret; ++} ++ ++static int xsk_load_xdp_programs(struct ifobject *ifobj) ++{ ++ ifobj->xdp_progs = xsk_xdp_progs__open_and_load(); ++ if (libbpf_get_error(ifobj->xdp_progs)) ++ return libbpf_get_error(ifobj->xdp_progs); ++ ++ return 0; ++} ++ ++/* Simple test */ ++static bool hugepages_present(void) ++{ ++ size_t mmap_sz = 2 * DEFAULT_UMEM_BUFFERS * XSK_UMEM__DEFAULT_FRAME_SIZE; ++ void *bufs; ++ ++ bufs = mmap(NULL, mmap_sz, PROT_READ | PROT_WRITE, ++ MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB, -1, MAP_HUGE_2MB); ++ if (bufs == MAP_FAILED) ++ return false; ++ ++ mmap_sz = ceil_u64(mmap_sz, HUGEPAGE_SIZE) * HUGEPAGE_SIZE; ++ munmap(bufs, mmap_sz); ++ return true; ++} ++ ++void init_iface(struct ifobject *ifobj, thread_func_t func_ptr) ++{ ++ LIBBPF_OPTS(bpf_xdp_query_opts, query_opts); ++ int err; ++ ++ ifobj->func_ptr = func_ptr; ++ ++ err = xsk_load_xdp_programs(ifobj); ++ if (err) { ++ ksft_print_msg("Error loading XDP program\n"); ++ exit_with_error(err); ++ } ++ ++ if (hugepages_present()) ++ ifobj->unaligned_supp = true; ++ ++ err = bpf_xdp_query(ifobj->ifindex, XDP_FLAGS_DRV_MODE, &query_opts); ++ if (err) { ++ ksft_print_msg("Error querying XDP capabilities\n"); ++ exit_with_error(-err); ++ } ++ if (query_opts.feature_flags & NETDEV_XDP_ACT_RX_SG) ++ ifobj->multi_buff_supp = true; ++ if (query_opts.feature_flags & NETDEV_XDP_ACT_XSK_ZEROCOPY) { ++ if (query_opts.xdp_zc_max_segs > 1) { ++ ifobj->multi_buff_zc_supp = true; ++ ifobj->xdp_zc_max_segs = query_opts.xdp_zc_max_segs; ++ } else { ++ ifobj->xdp_zc_max_segs = 0; ++ } ++ } ++} ++ ++int testapp_send_receive(struct test_spec *test) ++{ ++ return testapp_validate_traffic(test); ++} ++ ++int testapp_send_receive_2k_frame(struct test_spec *test) ++{ ++ test->ifobj_tx->umem->frame_size = 2048; ++ test->ifobj_rx->umem->frame_size = 2048; ++ pkt_stream_replace(test, DEFAULT_PKT_CNT, MIN_PKT_SIZE); ++ return testapp_validate_traffic(test); ++} ++ ++int testapp_poll_rx(struct test_spec *test) ++{ ++ test->ifobj_rx->use_poll = true; ++ return testapp_validate_traffic(test); ++} ++ ++int testapp_poll_tx(struct test_spec *test) ++{ ++ test->ifobj_tx->use_poll = true; ++ return testapp_validate_traffic(test); ++} ++ ++int testapp_aligned_inv_desc(struct test_spec *test) ++{ ++ return testapp_invalid_desc(test); ++} ++ ++int testapp_aligned_inv_desc_2k_frame(struct test_spec *test) ++{ ++ test->ifobj_tx->umem->frame_size = 2048; ++ test->ifobj_rx->umem->frame_size = 2048; ++ return testapp_invalid_desc(test); ++} ++ ++int testapp_unaligned_inv_desc(struct test_spec *test) ++{ ++ test->ifobj_tx->umem->unaligned_mode = true; ++ test->ifobj_rx->umem->unaligned_mode = true; ++ return testapp_invalid_desc(test); ++} ++ ++int testapp_unaligned_inv_desc_4001_frame(struct test_spec *test) ++{ ++ u64 page_size, umem_size; ++ ++ /* Odd frame size so the UMEM doesn't end near a page boundary. */ ++ test->ifobj_tx->umem->frame_size = 4001; ++ test->ifobj_rx->umem->frame_size = 4001; ++ test->ifobj_tx->umem->unaligned_mode = true; ++ test->ifobj_rx->umem->unaligned_mode = true; ++ /* This test exists to test descriptors that staddle the end of ++ * the UMEM but not a page. ++ */ ++ page_size = sysconf(_SC_PAGESIZE); ++ umem_size = test->ifobj_tx->umem->num_frames * test->ifobj_tx->umem->frame_size; ++ assert(umem_size % page_size > MIN_PKT_SIZE); ++ assert(umem_size % page_size < page_size - MIN_PKT_SIZE); ++ ++ return testapp_invalid_desc(test); ++} ++ ++int testapp_aligned_inv_desc_mb(struct test_spec *test) ++{ ++ return testapp_invalid_desc_mb(test); ++} ++ ++int testapp_unaligned_inv_desc_mb(struct test_spec *test) ++{ ++ test->ifobj_tx->umem->unaligned_mode = true; ++ test->ifobj_rx->umem->unaligned_mode = true; ++ return testapp_invalid_desc_mb(test); ++} ++ ++int testapp_xdp_metadata(struct test_spec *test) ++{ ++ return testapp_xdp_metadata_copy(test); ++} ++ ++int testapp_xdp_metadata_mb(struct test_spec *test) ++{ ++ test->mtu = MAX_ETH_JUMBO_SIZE; ++ return testapp_xdp_metadata_copy(test); ++} ++ ++int testapp_hw_sw_min_ring_size(struct test_spec *test) ++{ ++ int ret; ++ ++ test->set_ring = true; ++ test->total_steps = 2; ++ test->ifobj_tx->ring.tx_pending = DEFAULT_BATCH_SIZE; ++ test->ifobj_tx->ring.rx_pending = DEFAULT_BATCH_SIZE * 2; ++ test->ifobj_tx->xsk->batch_size = 1; ++ test->ifobj_rx->xsk->batch_size = 1; ++ ret = testapp_validate_traffic(test); ++ if (ret) ++ return ret; ++ ++ /* Set batch size to hw_ring_size - 1 */ ++ test->ifobj_tx->xsk->batch_size = DEFAULT_BATCH_SIZE - 1; ++ test->ifobj_rx->xsk->batch_size = DEFAULT_BATCH_SIZE - 1; ++ return testapp_validate_traffic(test); ++} ++ ++int testapp_hw_sw_max_ring_size(struct test_spec *test) ++{ ++ u32 max_descs = XSK_RING_PROD__DEFAULT_NUM_DESCS * 4; ++ int ret; ++ ++ test->set_ring = true; ++ test->total_steps = 2; ++ test->ifobj_tx->ring.tx_pending = test->ifobj_tx->ring.tx_max_pending; ++ test->ifobj_tx->ring.rx_pending = test->ifobj_tx->ring.rx_max_pending; ++ test->ifobj_rx->umem->num_frames = max_descs; ++ test->ifobj_rx->umem->fill_size = max_descs; ++ test->ifobj_rx->umem->comp_size = max_descs; ++ test->ifobj_tx->xsk->batch_size = XSK_RING_PROD__DEFAULT_NUM_DESCS; ++ test->ifobj_rx->xsk->batch_size = XSK_RING_PROD__DEFAULT_NUM_DESCS; ++ ++ ret = testapp_validate_traffic(test); ++ if (ret) ++ return ret; ++ ++ /* Set batch_size to 8152 for testing, as the ice HW ignores the 3 lowest bits when ++ * updating the Rx HW tail register. ++ */ ++ test->ifobj_tx->xsk->batch_size = test->ifobj_tx->ring.tx_max_pending - 8; ++ test->ifobj_rx->xsk->batch_size = test->ifobj_tx->ring.tx_max_pending - 8; ++ pkt_stream_replace(test, max_descs, MIN_PKT_SIZE); ++ return testapp_validate_traffic(test); ++} ++ ++static int testapp_xdp_adjust_tail(struct test_spec *test, int adjust_value) ++{ ++ struct xsk_xdp_progs *skel_rx = test->ifobj_rx->xdp_progs; ++ struct xsk_xdp_progs *skel_tx = test->ifobj_tx->xdp_progs; ++ ++ test_spec_set_xdp_prog(test, skel_rx->progs.xsk_xdp_adjust_tail, ++ skel_tx->progs.xsk_xdp_adjust_tail, ++ skel_rx->maps.xsk, skel_tx->maps.xsk); ++ ++ skel_rx->bss->adjust_value = adjust_value; ++ ++ return testapp_validate_traffic(test); ++} ++ ++static int testapp_adjust_tail(struct test_spec *test, u32 value, u32 pkt_len) ++{ ++ int ret; ++ ++ test->adjust_tail_support = true; ++ test->adjust_tail = true; ++ test->total_steps = 1; ++ ++ pkt_stream_replace_ifobject(test->ifobj_tx, DEFAULT_BATCH_SIZE, pkt_len); ++ pkt_stream_replace_ifobject(test->ifobj_rx, DEFAULT_BATCH_SIZE, pkt_len + value); ++ ++ ret = testapp_xdp_adjust_tail(test, value); ++ if (ret) ++ return ret; ++ ++ if (!test->adjust_tail_support) { ++ ksft_print_msg("%s %sResize pkt with bpf_xdp_adjust_tail() not supported\n", ++ mode_string(test), busy_poll_string(test)); ++ return TEST_SKIP; ++ } ++ ++ return 0; ++} ++ ++int testapp_adjust_tail_shrink(struct test_spec *test) ++{ ++ /* Shrink by 4 bytes for testing purpose */ ++ return testapp_adjust_tail(test, -4, MIN_PKT_SIZE * 2); ++} ++ ++int testapp_adjust_tail_shrink_mb(struct test_spec *test) ++{ ++ test->mtu = MAX_ETH_JUMBO_SIZE; ++ /* Shrink by the frag size */ ++ return testapp_adjust_tail(test, -XSK_UMEM__MAX_FRAME_SIZE, XSK_UMEM__LARGE_FRAME_SIZE * 2); ++} ++ ++int testapp_adjust_tail_grow(struct test_spec *test) ++{ ++ /* Grow by 4 bytes for testing purpose */ ++ return testapp_adjust_tail(test, 4, MIN_PKT_SIZE * 2); ++} ++ ++int testapp_adjust_tail_grow_mb(struct test_spec *test) ++{ ++ test->mtu = MAX_ETH_JUMBO_SIZE; ++ /* Grow by (frag_size - last_frag_Size) - 1 to stay inside the last fragment */ ++ return testapp_adjust_tail(test, (XSK_UMEM__MAX_FRAME_SIZE / 2) - 1, ++ XSK_UMEM__LARGE_FRAME_SIZE * 2); ++} ++ ++int testapp_tx_queue_consumer(struct test_spec *test) ++{ ++ int nr_packets; ++ ++ if (test->mode == TEST_MODE_ZC) { ++ ksft_print_msg("Can not run TX_QUEUE_CONSUMER test for ZC mode\n"); ++ return TEST_SKIP; ++ } ++ ++ nr_packets = MAX_TX_BUDGET_DEFAULT + 1; ++ pkt_stream_replace(test, nr_packets, MIN_PKT_SIZE); ++ test->ifobj_tx->xsk->batch_size = nr_packets; ++ test->ifobj_tx->xsk->check_consumer = true; ++ ++ return testapp_validate_traffic(test); ++} ++ ++struct ifobject *ifobject_create(void) ++{ ++ struct ifobject *ifobj; ++ ++ ifobj = calloc(1, sizeof(struct ifobject)); ++ if (!ifobj) ++ return NULL; ++ ++ ifobj->xsk_arr = calloc(MAX_SOCKETS, sizeof(*ifobj->xsk_arr)); ++ if (!ifobj->xsk_arr) ++ goto out_xsk_arr; ++ ++ ifobj->umem = calloc(1, sizeof(*ifobj->umem)); ++ if (!ifobj->umem) ++ goto out_umem; ++ ++ return ifobj; ++ ++out_umem: ++ free(ifobj->xsk_arr); ++out_xsk_arr: ++ free(ifobj); ++ return NULL; ++} ++ ++void ifobject_delete(struct ifobject *ifobj) ++{ ++ free(ifobj->umem); ++ free(ifobj->xsk_arr); ++ free(ifobj); ++} +diff --git a/tools/testing/selftests/bpf/test_xsk.h b/tools/testing/selftests/bpf/test_xsk.h +new file mode 100644 +index 0000000000000..fb546cab39fdf +--- /dev/null ++++ b/tools/testing/selftests/bpf/test_xsk.h +@@ -0,0 +1,297 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef TEST_XSK_H_ ++#define TEST_XSK_H_ ++ ++#include ++#include ++ ++#include "../kselftest.h" ++#include "xsk.h" ++ ++#ifndef SO_PREFER_BUSY_POLL ++#define SO_PREFER_BUSY_POLL 69 ++#endif ++ ++#ifndef SO_BUSY_POLL_BUDGET ++#define SO_BUSY_POLL_BUDGET 70 ++#endif ++ ++#define TEST_PASS 0 ++#define TEST_FAILURE -1 ++#define TEST_CONTINUE 1 ++#define TEST_SKIP 2 ++ ++#define DEFAULT_PKT_CNT (4 * 1024) ++#define DEFAULT_UMEM_BUFFERS (DEFAULT_PKT_CNT / 4) ++#define HUGEPAGE_SIZE (2 * 1024 * 1024) ++#define MIN_PKT_SIZE 64 ++#define MAX_ETH_PKT_SIZE 1518 ++#define MAX_INTERFACE_NAME_CHARS 16 ++#define MAX_TEST_NAME_SIZE 48 ++#define SOCK_RECONF_CTR 10 ++#define USLEEP_MAX 10000 ++ ++extern bool opt_verbose; ++#define print_verbose(x...) do { if (opt_verbose) ksft_print_msg(x); } while (0) ++ ++static void __exit_with_error(int error, const char *file, const char *func, int line) ++{ ++ ksft_test_result_fail("[%s:%s:%i]: ERROR: %d/\"%s\"\n", file, func, line, error, ++ strerror(error)); ++ ksft_exit_xfail(); ++} ++#define exit_with_error(error) __exit_with_error(error, __FILE__, __func__, __LINE__) ++ ++static inline u32 ceil_u32(u32 a, u32 b) ++{ ++ return (a + b - 1) / b; ++} ++ ++static inline u64 ceil_u64(u64 a, u64 b) ++{ ++ return (a + b - 1) / b; ++} ++ ++/* Simple test */ ++enum test_mode { ++ TEST_MODE_SKB, ++ TEST_MODE_DRV, ++ TEST_MODE_ZC, ++ TEST_MODE_ALL ++}; ++ ++struct ifobject; ++struct test_spec; ++typedef int (*validation_func_t)(struct ifobject *ifobj); ++typedef void *(*thread_func_t)(void *arg); ++typedef int (*test_func_t)(struct test_spec *test); ++ ++struct xsk_socket_info { ++ struct xsk_ring_cons rx; ++ struct xsk_ring_prod tx; ++ struct xsk_umem_info *umem; ++ struct xsk_socket *xsk; ++ struct pkt_stream *pkt_stream; ++ u32 outstanding_tx; ++ u32 rxqsize; ++ u32 batch_size; ++ u8 dst_mac[ETH_ALEN]; ++ u8 src_mac[ETH_ALEN]; ++ bool check_consumer; ++}; ++ ++int kick_rx(struct xsk_socket_info *xsk); ++int kick_tx(struct xsk_socket_info *xsk); ++ ++struct xsk_umem_info { ++ struct xsk_ring_prod fq; ++ struct xsk_ring_cons cq; ++ struct xsk_umem *umem; ++ u64 next_buffer; ++ u32 num_frames; ++ u32 frame_headroom; ++ void *buffer; ++ u32 frame_size; ++ u32 base_addr; ++ u32 fill_size; ++ u32 comp_size; ++ bool unaligned_mode; ++}; ++ ++struct set_hw_ring { ++ u32 default_tx; ++ u32 default_rx; ++}; ++ ++int hw_ring_size_reset(struct ifobject *ifobj); ++ ++struct ifobject { ++ char ifname[MAX_INTERFACE_NAME_CHARS]; ++ struct xsk_socket_info *xsk; ++ struct xsk_socket_info *xsk_arr; ++ struct xsk_umem_info *umem; ++ thread_func_t func_ptr; ++ validation_func_t validation_func; ++ struct xsk_xdp_progs *xdp_progs; ++ struct bpf_map *xskmap; ++ struct bpf_program *xdp_prog; ++ struct ethtool_ringparam ring; ++ struct set_hw_ring set_ring; ++ enum test_mode mode; ++ int ifindex; ++ int mtu; ++ u32 bind_flags; ++ u32 xdp_zc_max_segs; ++ bool tx_on; ++ bool rx_on; ++ bool use_poll; ++ bool busy_poll; ++ bool use_fill_ring; ++ bool release_rx; ++ bool shared_umem; ++ bool use_metadata; ++ bool unaligned_supp; ++ bool multi_buff_supp; ++ bool multi_buff_zc_supp; ++ bool hw_ring_size_supp; ++}; ++struct ifobject *ifobject_create(void); ++void ifobject_delete(struct ifobject *ifobj); ++void init_iface(struct ifobject *ifobj, thread_func_t func_ptr); ++ ++int xsk_configure_umem(struct ifobject *ifobj, struct xsk_umem_info *umem, void *buffer, u64 size); ++int xsk_configure_socket(struct xsk_socket_info *xsk, struct xsk_umem_info *umem, ++ struct ifobject *ifobject, bool shared); ++ ++ ++struct pkt { ++ int offset; ++ u32 len; ++ u32 pkt_nb; ++ bool valid; ++ u16 options; ++}; ++ ++struct pkt_stream { ++ u32 nb_pkts; ++ u32 current_pkt_nb; ++ struct pkt *pkts; ++ u32 max_pkt_len; ++ u32 nb_rx_pkts; ++ u32 nb_valid_entries; ++ bool verbatim; ++}; ++ ++static inline bool pkt_continues(u32 options) ++{ ++ return options & XDP_PKT_CONTD; ++} ++ ++struct pkt_stream *pkt_stream_generate(u32 nb_pkts, u32 pkt_len); ++void pkt_stream_delete(struct pkt_stream *pkt_stream); ++void pkt_stream_reset(struct pkt_stream *pkt_stream); ++void pkt_stream_restore_default(struct test_spec *test); ++ ++struct test_spec { ++ struct ifobject *ifobj_tx; ++ struct ifobject *ifobj_rx; ++ struct pkt_stream *tx_pkt_stream_default; ++ struct pkt_stream *rx_pkt_stream_default; ++ struct bpf_program *xdp_prog_rx; ++ struct bpf_program *xdp_prog_tx; ++ struct bpf_map *xskmap_rx; ++ struct bpf_map *xskmap_tx; ++ test_func_t test_func; ++ int mtu; ++ u16 total_steps; ++ u16 current_step; ++ u16 nb_sockets; ++ bool fail; ++ bool set_ring; ++ bool adjust_tail; ++ bool adjust_tail_support; ++ enum test_mode mode; ++ char name[MAX_TEST_NAME_SIZE]; ++}; ++ ++#define busy_poll_string(test) (test)->ifobj_tx->busy_poll ? "BUSY-POLL " : "" ++static inline char *mode_string(struct test_spec *test) ++{ ++ switch (test->mode) { ++ case TEST_MODE_SKB: ++ return "SKB"; ++ case TEST_MODE_DRV: ++ return "DRV"; ++ case TEST_MODE_ZC: ++ return "ZC"; ++ default: ++ return "BOGUS"; ++ } ++} ++ ++void test_init(struct test_spec *test, struct ifobject *ifobj_tx, ++ struct ifobject *ifobj_rx, enum test_mode mode, ++ const struct test_spec *test_to_run); ++ ++int testapp_adjust_tail_grow(struct test_spec *test); ++int testapp_adjust_tail_grow_mb(struct test_spec *test); ++int testapp_adjust_tail_shrink(struct test_spec *test); ++int testapp_adjust_tail_shrink_mb(struct test_spec *test); ++int testapp_aligned_inv_desc(struct test_spec *test); ++int testapp_aligned_inv_desc_2k_frame(struct test_spec *test); ++int testapp_aligned_inv_desc_mb(struct test_spec *test); ++int testapp_bidirectional(struct test_spec *test); ++int testapp_headroom(struct test_spec *test); ++int testapp_hw_sw_max_ring_size(struct test_spec *test); ++int testapp_hw_sw_min_ring_size(struct test_spec *test); ++int testapp_poll_rx(struct test_spec *test); ++int testapp_poll_rxq_tmout(struct test_spec *test); ++int testapp_poll_tx(struct test_spec *test); ++int testapp_poll_txq_tmout(struct test_spec *test); ++int testapp_send_receive(struct test_spec *test); ++int testapp_send_receive_2k_frame(struct test_spec *test); ++int testapp_send_receive_mb(struct test_spec *test); ++int testapp_send_receive_unaligned(struct test_spec *test); ++int testapp_send_receive_unaligned_mb(struct test_spec *test); ++int testapp_single_pkt(struct test_spec *test); ++int testapp_stats_fill_empty(struct test_spec *test); ++int testapp_stats_rx_dropped(struct test_spec *test); ++int testapp_stats_tx_invalid_descs(struct test_spec *test); ++int testapp_stats_rx_full(struct test_spec *test); ++int testapp_teardown(struct test_spec *test); ++int testapp_too_many_frags(struct test_spec *test); ++int testapp_tx_queue_consumer(struct test_spec *test); ++int testapp_unaligned_inv_desc(struct test_spec *test); ++int testapp_unaligned_inv_desc_4001_frame(struct test_spec *test); ++int testapp_unaligned_inv_desc_mb(struct test_spec *test); ++int testapp_xdp_drop(struct test_spec *test); ++int testapp_xdp_metadata(struct test_spec *test); ++int testapp_xdp_metadata_mb(struct test_spec *test); ++int testapp_xdp_prog_cleanup(struct test_spec *test); ++int testapp_xdp_shared_umem(struct test_spec *test); ++ ++void *worker_testapp_validate_rx(void *arg); ++void *worker_testapp_validate_tx(void *arg); ++ ++static const struct test_spec tests[] = { ++ {.name = "SEND_RECEIVE", .test_func = testapp_send_receive}, ++ {.name = "SEND_RECEIVE_2K_FRAME", .test_func = testapp_send_receive_2k_frame}, ++ {.name = "SEND_RECEIVE_SINGLE_PKT", .test_func = testapp_single_pkt}, ++ {.name = "POLL_RX", .test_func = testapp_poll_rx}, ++ {.name = "POLL_TX", .test_func = testapp_poll_tx}, ++ {.name = "POLL_RXQ_FULL", .test_func = testapp_poll_rxq_tmout}, ++ {.name = "POLL_TXQ_FULL", .test_func = testapp_poll_txq_tmout}, ++ {.name = "SEND_RECEIVE_UNALIGNED", .test_func = testapp_send_receive_unaligned}, ++ {.name = "ALIGNED_INV_DESC", .test_func = testapp_aligned_inv_desc}, ++ {.name = "ALIGNED_INV_DESC_2K_FRAME_SIZE", .test_func = testapp_aligned_inv_desc_2k_frame}, ++ {.name = "UNALIGNED_INV_DESC", .test_func = testapp_unaligned_inv_desc}, ++ {.name = "UNALIGNED_INV_DESC_4001_FRAME_SIZE", ++ .test_func = testapp_unaligned_inv_desc_4001_frame}, ++ {.name = "UMEM_HEADROOM", .test_func = testapp_headroom}, ++ {.name = "TEARDOWN", .test_func = testapp_teardown}, ++ {.name = "BIDIRECTIONAL", .test_func = testapp_bidirectional}, ++ {.name = "STAT_RX_DROPPED", .test_func = testapp_stats_rx_dropped}, ++ {.name = "STAT_TX_INVALID", .test_func = testapp_stats_tx_invalid_descs}, ++ {.name = "STAT_RX_FULL", .test_func = testapp_stats_rx_full}, ++ {.name = "STAT_FILL_EMPTY", .test_func = testapp_stats_fill_empty}, ++ {.name = "XDP_PROG_CLEANUP", .test_func = testapp_xdp_prog_cleanup}, ++ {.name = "XDP_DROP_HALF", .test_func = testapp_xdp_drop}, ++ {.name = "XDP_SHARED_UMEM", .test_func = testapp_xdp_shared_umem}, ++ {.name = "XDP_METADATA_COPY", .test_func = testapp_xdp_metadata}, ++ {.name = "XDP_METADATA_COPY_MULTI_BUFF", .test_func = testapp_xdp_metadata_mb}, ++ {.name = "SEND_RECEIVE_9K_PACKETS", .test_func = testapp_send_receive_mb}, ++ {.name = "SEND_RECEIVE_UNALIGNED_9K_PACKETS", ++ .test_func = testapp_send_receive_unaligned_mb}, ++ {.name = "ALIGNED_INV_DESC_MULTI_BUFF", .test_func = testapp_aligned_inv_desc_mb}, ++ {.name = "UNALIGNED_INV_DESC_MULTI_BUFF", .test_func = testapp_unaligned_inv_desc_mb}, ++ {.name = "TOO_MANY_FRAGS", .test_func = testapp_too_many_frags}, ++ {.name = "HW_SW_MIN_RING_SIZE", .test_func = testapp_hw_sw_min_ring_size}, ++ {.name = "HW_SW_MAX_RING_SIZE", .test_func = testapp_hw_sw_max_ring_size}, ++ {.name = "XDP_ADJUST_TAIL_SHRINK", .test_func = testapp_adjust_tail_shrink}, ++ {.name = "XDP_ADJUST_TAIL_SHRINK_MULTI_BUFF", .test_func = testapp_adjust_tail_shrink_mb}, ++ {.name = "XDP_ADJUST_TAIL_GROW", .test_func = testapp_adjust_tail_grow}, ++ {.name = "XDP_ADJUST_TAIL_GROW_MULTI_BUFF", .test_func = testapp_adjust_tail_grow_mb}, ++ {.name = "TX_QUEUE_CONSUMER", .test_func = testapp_tx_queue_consumer}, ++ }; ++ ++#endif /* TEST_XSK_H_ */ +diff --git a/tools/testing/selftests/bpf/xskxceiver.c b/tools/testing/selftests/bpf/xskxceiver.c +index 352adc8df2d1c..8e108e3162695 100644 +--- a/tools/testing/selftests/bpf/xskxceiver.c ++++ b/tools/testing/selftests/bpf/xskxceiver.c +@@ -74,31 +74,23 @@ + #define _GNU_SOURCE + #include + #include +-#include + #include + #include + #include + #include + #include +-#include + #include + #include + #include + #include +-#include +-#include +-#include + #include + #include + #include +-#include + #include + #include +-#include +-#include + #include +-#include + ++#include "test_xsk.h" + #include "xsk_xdp_progs.skel.h" + #include "xsk.h" + #include "xskxceiver.h" +@@ -109,181 +101,12 @@ + + #include + +-#define MAX_TX_BUDGET_DEFAULT 32 +- +-static bool opt_verbose; + static bool opt_print_tests; + static enum test_mode opt_mode = TEST_MODE_ALL; + static u32 opt_run_test = RUN_ALL_TESTS; + + void test__fail(void) { /* for network_helpers.c */ } + +-static void __exit_with_error(int error, const char *file, const char *func, int line) +-{ +- ksft_test_result_fail("[%s:%s:%i]: ERROR: %d/\"%s\"\n", file, func, line, error, +- strerror(error)); +- ksft_exit_xfail(); +-} +- +-#define exit_with_error(error) __exit_with_error(error, __FILE__, __func__, __LINE__) +-#define busy_poll_string(test) (test)->ifobj_tx->busy_poll ? "BUSY-POLL " : "" +-static char *mode_string(struct test_spec *test) +-{ +- switch (test->mode) { +- case TEST_MODE_SKB: +- return "SKB"; +- case TEST_MODE_DRV: +- return "DRV"; +- case TEST_MODE_ZC: +- return "ZC"; +- default: +- return "BOGUS"; +- } +-} +- +-static void report_failure(struct test_spec *test) +-{ +- if (test->fail) +- return; +- +- ksft_test_result_fail("FAIL: %s %s%s\n", mode_string(test), busy_poll_string(test), +- test->name); +- test->fail = true; +-} +- +-/* The payload is a word consisting of a packet sequence number in the upper +- * 16-bits and a intra packet data sequence number in the lower 16 bits. So the 3rd packet's +- * 5th word of data will contain the number (2<<16) | 4 as they are numbered from 0. +- */ +-static void write_payload(void *dest, u32 pkt_nb, u32 start, u32 size) +-{ +- u32 *ptr = (u32 *)dest, i; +- +- start /= sizeof(*ptr); +- size /= sizeof(*ptr); +- for (i = 0; i < size; i++) +- ptr[i] = htonl(pkt_nb << 16 | (i + start)); +-} +- +-static void gen_eth_hdr(struct xsk_socket_info *xsk, struct ethhdr *eth_hdr) +-{ +- memcpy(eth_hdr->h_dest, xsk->dst_mac, ETH_ALEN); +- memcpy(eth_hdr->h_source, xsk->src_mac, ETH_ALEN); +- eth_hdr->h_proto = htons(ETH_P_LOOPBACK); +-} +- +-static bool is_umem_valid(struct ifobject *ifobj) +-{ +- return !!ifobj->umem->umem; +-} +- +-static u32 mode_to_xdp_flags(enum test_mode mode) +-{ +- return (mode == TEST_MODE_SKB) ? XDP_FLAGS_SKB_MODE : XDP_FLAGS_DRV_MODE; +-} +- +-static u64 umem_size(struct xsk_umem_info *umem) +-{ +- return umem->num_frames * umem->frame_size; +-} +- +-static int xsk_configure_umem(struct ifobject *ifobj, struct xsk_umem_info *umem, void *buffer, +- u64 size) +-{ +- struct xsk_umem_config cfg = { +- .fill_size = XSK_RING_PROD__DEFAULT_NUM_DESCS, +- .comp_size = XSK_RING_CONS__DEFAULT_NUM_DESCS, +- .frame_size = umem->frame_size, +- .frame_headroom = umem->frame_headroom, +- .flags = XSK_UMEM__DEFAULT_FLAGS +- }; +- int ret; +- +- if (umem->fill_size) +- cfg.fill_size = umem->fill_size; +- +- if (umem->comp_size) +- cfg.comp_size = umem->comp_size; +- +- if (umem->unaligned_mode) +- cfg.flags |= XDP_UMEM_UNALIGNED_CHUNK_FLAG; +- +- ret = xsk_umem__create(&umem->umem, buffer, size, +- &umem->fq, &umem->cq, &cfg); +- if (ret) +- return ret; +- +- umem->buffer = buffer; +- if (ifobj->shared_umem && ifobj->rx_on) { +- umem->base_addr = umem_size(umem); +- umem->next_buffer = umem_size(umem); +- } +- +- return 0; +-} +- +-static u64 umem_alloc_buffer(struct xsk_umem_info *umem) +-{ +- u64 addr; +- +- addr = umem->next_buffer; +- umem->next_buffer += umem->frame_size; +- if (umem->next_buffer >= umem->base_addr + umem_size(umem)) +- umem->next_buffer = umem->base_addr; +- +- return addr; +-} +- +-static void umem_reset_alloc(struct xsk_umem_info *umem) +-{ +- umem->next_buffer = 0; +-} +- +-static void enable_busy_poll(struct xsk_socket_info *xsk) +-{ +- int sock_opt; +- +- sock_opt = 1; +- if (setsockopt(xsk_socket__fd(xsk->xsk), SOL_SOCKET, SO_PREFER_BUSY_POLL, +- (void *)&sock_opt, sizeof(sock_opt)) < 0) +- exit_with_error(errno); +- +- sock_opt = 20; +- if (setsockopt(xsk_socket__fd(xsk->xsk), SOL_SOCKET, SO_BUSY_POLL, +- (void *)&sock_opt, sizeof(sock_opt)) < 0) +- exit_with_error(errno); +- +- sock_opt = xsk->batch_size; +- if (setsockopt(xsk_socket__fd(xsk->xsk), SOL_SOCKET, SO_BUSY_POLL_BUDGET, +- (void *)&sock_opt, sizeof(sock_opt)) < 0) +- exit_with_error(errno); +-} +- +-static int __xsk_configure_socket(struct xsk_socket_info *xsk, struct xsk_umem_info *umem, +- struct ifobject *ifobject, bool shared) +-{ +- struct xsk_socket_config cfg = {}; +- struct xsk_ring_cons *rxr; +- struct xsk_ring_prod *txr; +- +- xsk->umem = umem; +- cfg.rx_size = xsk->rxqsize; +- cfg.tx_size = XSK_RING_PROD__DEFAULT_NUM_DESCS; +- cfg.bind_flags = ifobject->bind_flags; +- if (shared) +- cfg.bind_flags |= XDP_SHARED_UMEM; +- if (ifobject->mtu > MAX_ETH_PKT_SIZE) +- cfg.bind_flags |= XDP_USE_SG; +- if (umem->comp_size) +- cfg.tx_size = umem->comp_size; +- if (umem->fill_size) +- cfg.rx_size = umem->fill_size; +- +- txr = ifobject->tx_on ? &xsk->tx : NULL; +- rxr = ifobject->rx_on ? &xsk->rx : NULL; +- return xsk_socket__create(&xsk->xsk, ifobject->ifindex, 0, umem->umem, rxr, txr, &cfg); +-} +- + static bool ifobj_zc_avail(struct ifobject *ifobject) + { + size_t umem_sz = DEFAULT_UMEM_BUFFERS * XSK_UMEM__DEFAULT_FRAME_SIZE; +@@ -314,7 +137,7 @@ static bool ifobj_zc_avail(struct ifobject *ifobject) + ifobject->bind_flags = XDP_USE_NEED_WAKEUP | XDP_ZEROCOPY; + ifobject->rx_on = true; + xsk->rxqsize = XSK_RING_CONS__DEFAULT_NUM_DESCS; +- ret = __xsk_configure_socket(xsk, umem, ifobject, false); ++ ret = xsk_configure_socket(xsk, umem, ifobject, false); + if (!ret) + zc_avail = true; + +@@ -327,25 +150,6 @@ static bool ifobj_zc_avail(struct ifobject *ifobject) + return zc_avail; + } + +-#define MAX_SKB_FRAGS_PATH "/proc/sys/net/core/max_skb_frags" +-static unsigned int get_max_skb_frags(void) +-{ +- unsigned int max_skb_frags = 0; +- FILE *file; +- +- file = fopen(MAX_SKB_FRAGS_PATH, "r"); +- if (!file) { +- ksft_print_msg("Error opening %s\n", MAX_SKB_FRAGS_PATH); +- return 0; +- } +- +- if (fscanf(file, "%u", &max_skb_frags) != 1) +- ksft_print_msg("Error reading %s\n", MAX_SKB_FRAGS_PATH); +- +- fclose(file); +- return max_skb_frags; +-} +- + static struct option long_options[] = { + {"interface", required_argument, 0, 'i'}, + {"busy-poll", no_argument, 0, 'b'}, +@@ -446,2327 +250,66 @@ static void parse_command_line(struct ifobject *ifobj_tx, struct ifobject *ifobj + } + } + +-static int set_ring_size(struct ifobject *ifobj) +-{ +- int ret; +- u32 ctr = 0; +- +- while (ctr++ < SOCK_RECONF_CTR) { +- ret = set_hw_ring_size(ifobj->ifname, &ifobj->ring); +- if (!ret) +- break; +- +- /* Retry if it fails */ +- if (ctr >= SOCK_RECONF_CTR || errno != EBUSY) +- return -errno; +- +- usleep(USLEEP_MAX); +- } +- +- return ret; +-} +- +-static int hw_ring_size_reset(struct ifobject *ifobj) +-{ +- ifobj->ring.tx_pending = ifobj->set_ring.default_tx; +- ifobj->ring.rx_pending = ifobj->set_ring.default_rx; +- return set_ring_size(ifobj); +-} +- +-static void __test_spec_init(struct test_spec *test, struct ifobject *ifobj_tx, +- struct ifobject *ifobj_rx) ++static void xsk_unload_xdp_programs(struct ifobject *ifobj) + { +- u32 i, j; +- +- for (i = 0; i < MAX_INTERFACES; i++) { +- struct ifobject *ifobj = i ? ifobj_rx : ifobj_tx; +- +- ifobj->xsk = &ifobj->xsk_arr[0]; +- ifobj->use_poll = false; +- ifobj->use_fill_ring = true; +- ifobj->release_rx = true; +- ifobj->validation_func = NULL; +- ifobj->use_metadata = false; +- +- if (i == 0) { +- ifobj->rx_on = false; +- ifobj->tx_on = true; +- } else { +- ifobj->rx_on = true; +- ifobj->tx_on = false; +- } +- +- memset(ifobj->umem, 0, sizeof(*ifobj->umem)); +- ifobj->umem->num_frames = DEFAULT_UMEM_BUFFERS; +- ifobj->umem->frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE; +- +- for (j = 0; j < MAX_SOCKETS; j++) { +- memset(&ifobj->xsk_arr[j], 0, sizeof(ifobj->xsk_arr[j])); +- ifobj->xsk_arr[j].rxqsize = XSK_RING_CONS__DEFAULT_NUM_DESCS; +- ifobj->xsk_arr[j].batch_size = DEFAULT_BATCH_SIZE; +- if (i == 0) +- ifobj->xsk_arr[j].pkt_stream = test->tx_pkt_stream_default; +- else +- ifobj->xsk_arr[j].pkt_stream = test->rx_pkt_stream_default; +- +- memcpy(ifobj->xsk_arr[j].src_mac, g_mac, ETH_ALEN); +- memcpy(ifobj->xsk_arr[j].dst_mac, g_mac, ETH_ALEN); +- ifobj->xsk_arr[j].src_mac[5] += ((j * 2) + 0); +- ifobj->xsk_arr[j].dst_mac[5] += ((j * 2) + 1); +- } +- } +- +- if (ifobj_tx->hw_ring_size_supp) +- hw_ring_size_reset(ifobj_tx); +- +- test->ifobj_tx = ifobj_tx; +- test->ifobj_rx = ifobj_rx; +- test->current_step = 0; +- test->total_steps = 1; +- test->nb_sockets = 1; +- test->fail = false; +- test->set_ring = false; +- test->adjust_tail = false; +- test->adjust_tail_support = false; +- test->mtu = MAX_ETH_PKT_SIZE; +- test->xdp_prog_rx = ifobj_rx->xdp_progs->progs.xsk_def_prog; +- test->xskmap_rx = ifobj_rx->xdp_progs->maps.xsk; +- test->xdp_prog_tx = ifobj_tx->xdp_progs->progs.xsk_def_prog; +- test->xskmap_tx = ifobj_tx->xdp_progs->maps.xsk; ++ xsk_xdp_progs__destroy(ifobj->xdp_progs); + } + +-static void test_spec_init(struct test_spec *test, struct ifobject *ifobj_tx, +- struct ifobject *ifobj_rx, enum test_mode mode, +- const struct test_spec *test_to_run) ++static void run_pkt_test(struct test_spec *test) + { +- struct pkt_stream *tx_pkt_stream; +- struct pkt_stream *rx_pkt_stream; +- u32 i; +- +- tx_pkt_stream = test->tx_pkt_stream_default; +- rx_pkt_stream = test->rx_pkt_stream_default; +- memset(test, 0, sizeof(*test)); +- test->tx_pkt_stream_default = tx_pkt_stream; +- test->rx_pkt_stream_default = rx_pkt_stream; ++ int ret; + +- for (i = 0; i < MAX_INTERFACES; i++) { +- struct ifobject *ifobj = i ? ifobj_rx : ifobj_tx; ++ ret = test->test_func(test); + +- ifobj->bind_flags = XDP_USE_NEED_WAKEUP; +- if (mode == TEST_MODE_ZC) +- ifobj->bind_flags |= XDP_ZEROCOPY; +- else +- ifobj->bind_flags |= XDP_COPY; ++ switch (ret) { ++ case TEST_PASS: ++ ksft_test_result_pass("PASS: %s %s%s\n", mode_string(test), busy_poll_string(test), ++ test->name); ++ break; ++ case TEST_SKIP: ++ ksft_test_result_skip("SKIP: %s %s%s\n", mode_string(test), busy_poll_string(test), ++ test->name); ++ break; ++ case TEST_FAILURE: ++ ksft_test_result_fail("FAIL: %s %s%s\n", mode_string(test), busy_poll_string(test), ++ test->name); ++ break; ++ default: ++ ksft_test_result_fail("FAIL: %s %s%s -- Unexpected returned value (%d)\n", ++ mode_string(test), busy_poll_string(test), test->name, ret); + } + +- strncpy(test->name, test_to_run->name, MAX_TEST_NAME_SIZE); +- test->test_func = test_to_run->test_func; +- test->mode = mode; +- __test_spec_init(test, ifobj_tx, ifobj_rx); +-} +- +-static void test_spec_reset(struct test_spec *test) +-{ +- __test_spec_init(test, test->ifobj_tx, test->ifobj_rx); ++ pkt_stream_restore_default(test); + } + +-static void test_spec_set_xdp_prog(struct test_spec *test, struct bpf_program *xdp_prog_rx, +- struct bpf_program *xdp_prog_tx, struct bpf_map *xskmap_rx, +- struct bpf_map *xskmap_tx) ++static bool is_xdp_supported(int ifindex) + { +- test->xdp_prog_rx = xdp_prog_rx; +- test->xdp_prog_tx = xdp_prog_tx; +- test->xskmap_rx = xskmap_rx; +- test->xskmap_tx = xskmap_tx; +-} ++ int flags = XDP_FLAGS_DRV_MODE; + +-static int test_spec_set_mtu(struct test_spec *test, int mtu) +-{ ++ LIBBPF_OPTS(bpf_link_create_opts, opts, .flags = flags); ++ struct bpf_insn insns[2] = { ++ BPF_MOV64_IMM(BPF_REG_0, XDP_PASS), ++ BPF_EXIT_INSN() ++ }; ++ int prog_fd, insn_cnt = ARRAY_SIZE(insns); + int err; + +- if (test->ifobj_rx->mtu != mtu) { +- err = xsk_set_mtu(test->ifobj_rx->ifindex, mtu); +- if (err) +- return err; +- test->ifobj_rx->mtu = mtu; +- } +- if (test->ifobj_tx->mtu != mtu) { +- err = xsk_set_mtu(test->ifobj_tx->ifindex, mtu); +- if (err) +- return err; +- test->ifobj_tx->mtu = mtu; +- } +- +- return 0; +-} +- +-static void pkt_stream_reset(struct pkt_stream *pkt_stream) +-{ +- if (pkt_stream) { +- pkt_stream->current_pkt_nb = 0; +- pkt_stream->nb_rx_pkts = 0; +- } +-} +- +-static struct pkt *pkt_stream_get_next_tx_pkt(struct pkt_stream *pkt_stream) +-{ +- if (pkt_stream->current_pkt_nb >= pkt_stream->nb_pkts) +- return NULL; +- +- return &pkt_stream->pkts[pkt_stream->current_pkt_nb++]; +-} +- +-static struct pkt *pkt_stream_get_next_rx_pkt(struct pkt_stream *pkt_stream, u32 *pkts_sent) +-{ +- while (pkt_stream->current_pkt_nb < pkt_stream->nb_pkts) { +- (*pkts_sent)++; +- if (pkt_stream->pkts[pkt_stream->current_pkt_nb].valid) +- return &pkt_stream->pkts[pkt_stream->current_pkt_nb++]; +- pkt_stream->current_pkt_nb++; +- } +- return NULL; +-} +- +-static void pkt_stream_delete(struct pkt_stream *pkt_stream) +-{ +- free(pkt_stream->pkts); +- free(pkt_stream); +-} +- +-static void pkt_stream_restore_default(struct test_spec *test) +-{ +- struct pkt_stream *tx_pkt_stream = test->ifobj_tx->xsk->pkt_stream; +- struct pkt_stream *rx_pkt_stream = test->ifobj_rx->xsk->pkt_stream; +- +- if (tx_pkt_stream != test->tx_pkt_stream_default) { +- pkt_stream_delete(test->ifobj_tx->xsk->pkt_stream); +- test->ifobj_tx->xsk->pkt_stream = test->tx_pkt_stream_default; +- } +- +- if (rx_pkt_stream != test->rx_pkt_stream_default) { +- pkt_stream_delete(test->ifobj_rx->xsk->pkt_stream); +- test->ifobj_rx->xsk->pkt_stream = test->rx_pkt_stream_default; +- } +-} +- +-static struct pkt_stream *__pkt_stream_alloc(u32 nb_pkts) +-{ +- struct pkt_stream *pkt_stream; +- +- pkt_stream = calloc(1, sizeof(*pkt_stream)); +- if (!pkt_stream) +- return NULL; +- +- pkt_stream->pkts = calloc(nb_pkts, sizeof(*pkt_stream->pkts)); +- if (!pkt_stream->pkts) { +- free(pkt_stream); +- return NULL; +- } +- +- pkt_stream->nb_pkts = nb_pkts; +- return pkt_stream; +-} +- +-static bool pkt_continues(u32 options) +-{ +- return options & XDP_PKT_CONTD; +-} +- +-static u32 ceil_u32(u32 a, u32 b) +-{ +- return (a + b - 1) / b; +-} +- +-static u32 pkt_nb_frags(u32 frame_size, struct pkt_stream *pkt_stream, struct pkt *pkt) +-{ +- u32 nb_frags = 1, next_frag; +- +- if (!pkt) +- return 1; +- +- if (!pkt_stream->verbatim) { +- if (!pkt->valid || !pkt->len) +- return 1; +- return ceil_u32(pkt->len, frame_size); +- } +- +- /* Search for the end of the packet in verbatim mode */ +- if (!pkt_continues(pkt->options)) +- return nb_frags; +- +- next_frag = pkt_stream->current_pkt_nb; +- pkt++; +- while (next_frag++ < pkt_stream->nb_pkts) { +- nb_frags++; +- if (!pkt_continues(pkt->options) || !pkt->valid) +- break; +- pkt++; +- } +- return nb_frags; +-} +- +-static bool set_pkt_valid(int offset, u32 len) +-{ +- return len <= MAX_ETH_JUMBO_SIZE; +-} +- +-static void pkt_set(struct pkt_stream *pkt_stream, struct pkt *pkt, int offset, u32 len) +-{ +- pkt->offset = offset; +- pkt->len = len; +- pkt->valid = set_pkt_valid(offset, len); +-} +- +-static void pkt_stream_pkt_set(struct pkt_stream *pkt_stream, struct pkt *pkt, int offset, u32 len) +-{ +- bool prev_pkt_valid = pkt->valid; +- +- pkt_set(pkt_stream, pkt, offset, len); +- pkt_stream->nb_valid_entries += pkt->valid - prev_pkt_valid; +-} +- +-static u32 pkt_get_buffer_len(struct xsk_umem_info *umem, u32 len) +-{ +- return ceil_u32(len, umem->frame_size) * umem->frame_size; +-} +- +-static struct pkt_stream *__pkt_stream_generate(u32 nb_pkts, u32 pkt_len, u32 nb_start, u32 nb_off) +-{ +- struct pkt_stream *pkt_stream; +- u32 i; +- +- pkt_stream = __pkt_stream_alloc(nb_pkts); +- if (!pkt_stream) +- exit_with_error(ENOMEM); +- +- pkt_stream->nb_pkts = nb_pkts; +- pkt_stream->max_pkt_len = pkt_len; +- for (i = 0; i < nb_pkts; i++) { +- struct pkt *pkt = &pkt_stream->pkts[i]; +- +- pkt_stream_pkt_set(pkt_stream, pkt, 0, pkt_len); +- pkt->pkt_nb = nb_start + i * nb_off; +- } +- +- return pkt_stream; +-} +- +-static struct pkt_stream *pkt_stream_generate(u32 nb_pkts, u32 pkt_len) +-{ +- return __pkt_stream_generate(nb_pkts, pkt_len, 0, 1); +-} +- +-static struct pkt_stream *pkt_stream_clone(struct pkt_stream *pkt_stream) +-{ +- return pkt_stream_generate(pkt_stream->nb_pkts, pkt_stream->pkts[0].len); +-} +- +-static void pkt_stream_replace_ifobject(struct ifobject *ifobj, u32 nb_pkts, u32 pkt_len) +-{ +- ifobj->xsk->pkt_stream = pkt_stream_generate(nb_pkts, pkt_len); +-} +- +-static void pkt_stream_replace(struct test_spec *test, u32 nb_pkts, u32 pkt_len) +-{ +- pkt_stream_replace_ifobject(test->ifobj_tx, nb_pkts, pkt_len); +- pkt_stream_replace_ifobject(test->ifobj_rx, nb_pkts, pkt_len); +-} +- +-static void __pkt_stream_replace_half(struct ifobject *ifobj, u32 pkt_len, +- int offset) +-{ +- struct pkt_stream *pkt_stream; +- u32 i; +- +- pkt_stream = pkt_stream_clone(ifobj->xsk->pkt_stream); +- for (i = 1; i < ifobj->xsk->pkt_stream->nb_pkts; i += 2) +- pkt_stream_pkt_set(pkt_stream, &pkt_stream->pkts[i], offset, pkt_len); +- +- ifobj->xsk->pkt_stream = pkt_stream; +-} +- +-static void pkt_stream_replace_half(struct test_spec *test, u32 pkt_len, int offset) +-{ +- __pkt_stream_replace_half(test->ifobj_tx, pkt_len, offset); +- __pkt_stream_replace_half(test->ifobj_rx, pkt_len, offset); +-} +- +-static void pkt_stream_receive_half(struct test_spec *test) +-{ +- struct pkt_stream *pkt_stream = test->ifobj_tx->xsk->pkt_stream; +- u32 i; +- +- test->ifobj_rx->xsk->pkt_stream = pkt_stream_generate(pkt_stream->nb_pkts, +- pkt_stream->pkts[0].len); +- pkt_stream = test->ifobj_rx->xsk->pkt_stream; +- for (i = 1; i < pkt_stream->nb_pkts; i += 2) +- pkt_stream->pkts[i].valid = false; +- +- pkt_stream->nb_valid_entries /= 2; +-} +- +-static void pkt_stream_even_odd_sequence(struct test_spec *test) +-{ +- struct pkt_stream *pkt_stream; +- u32 i; +- +- for (i = 0; i < test->nb_sockets; i++) { +- pkt_stream = test->ifobj_tx->xsk_arr[i].pkt_stream; +- pkt_stream = __pkt_stream_generate(pkt_stream->nb_pkts / 2, +- pkt_stream->pkts[0].len, i, 2); +- test->ifobj_tx->xsk_arr[i].pkt_stream = pkt_stream; ++ prog_fd = bpf_prog_load(BPF_PROG_TYPE_XDP, NULL, "GPL", insns, insn_cnt, NULL); ++ if (prog_fd < 0) ++ return false; + +- pkt_stream = test->ifobj_rx->xsk_arr[i].pkt_stream; +- pkt_stream = __pkt_stream_generate(pkt_stream->nb_pkts / 2, +- pkt_stream->pkts[0].len, i, 2); +- test->ifobj_rx->xsk_arr[i].pkt_stream = pkt_stream; ++ err = bpf_xdp_attach(ifindex, prog_fd, flags, NULL); ++ if (err) { ++ close(prog_fd); ++ return false; + } +-} +- +-static u64 pkt_get_addr(struct pkt *pkt, struct xsk_umem_info *umem) +-{ +- if (!pkt->valid) +- return pkt->offset; +- return pkt->offset + umem_alloc_buffer(umem); +-} + +-static void pkt_stream_cancel(struct pkt_stream *pkt_stream) +-{ +- pkt_stream->current_pkt_nb--; +-} +- +-static void pkt_generate(struct xsk_socket_info *xsk, struct xsk_umem_info *umem, u64 addr, u32 len, +- u32 pkt_nb, u32 bytes_written) +-{ +- void *data = xsk_umem__get_data(umem->buffer, addr); +- +- if (len < MIN_PKT_SIZE) +- return; +- +- if (!bytes_written) { +- gen_eth_hdr(xsk, data); +- +- len -= PKT_HDR_SIZE; +- data += PKT_HDR_SIZE; +- } else { +- bytes_written -= PKT_HDR_SIZE; +- } ++ bpf_xdp_detach(ifindex, flags, NULL); ++ close(prog_fd); + +- write_payload(data, pkt_nb, bytes_written, len); ++ return true; + } + +-static struct pkt_stream *__pkt_stream_generate_custom(struct ifobject *ifobj, struct pkt *frames, +- u32 nb_frames, bool verbatim) +-{ +- u32 i, len = 0, pkt_nb = 0, payload = 0; +- struct pkt_stream *pkt_stream; +- +- pkt_stream = __pkt_stream_alloc(nb_frames); +- if (!pkt_stream) +- exit_with_error(ENOMEM); +- +- for (i = 0; i < nb_frames; i++) { +- struct pkt *pkt = &pkt_stream->pkts[pkt_nb]; +- struct pkt *frame = &frames[i]; +- +- pkt->offset = frame->offset; +- if (verbatim) { +- *pkt = *frame; +- pkt->pkt_nb = payload; +- if (!frame->valid || !pkt_continues(frame->options)) +- payload++; +- } else { +- if (frame->valid) +- len += frame->len; +- if (frame->valid && pkt_continues(frame->options)) +- continue; +- +- pkt->pkt_nb = pkt_nb; +- pkt->len = len; +- pkt->valid = frame->valid; +- pkt->options = 0; +- +- len = 0; +- } +- +- print_verbose("offset: %d len: %u valid: %u options: %u pkt_nb: %u\n", +- pkt->offset, pkt->len, pkt->valid, pkt->options, pkt->pkt_nb); +- +- if (pkt->valid && pkt->len > pkt_stream->max_pkt_len) +- pkt_stream->max_pkt_len = pkt->len; +- +- if (pkt->valid) +- pkt_stream->nb_valid_entries++; +- +- pkt_nb++; +- } +- +- pkt_stream->nb_pkts = pkt_nb; +- pkt_stream->verbatim = verbatim; +- return pkt_stream; +-} +- +-static void pkt_stream_generate_custom(struct test_spec *test, struct pkt *pkts, u32 nb_pkts) +-{ +- struct pkt_stream *pkt_stream; +- +- pkt_stream = __pkt_stream_generate_custom(test->ifobj_tx, pkts, nb_pkts, true); +- test->ifobj_tx->xsk->pkt_stream = pkt_stream; +- +- pkt_stream = __pkt_stream_generate_custom(test->ifobj_rx, pkts, nb_pkts, false); +- test->ifobj_rx->xsk->pkt_stream = pkt_stream; +-} +- +-static void pkt_print_data(u32 *data, u32 cnt) +-{ +- u32 i; +- +- for (i = 0; i < cnt; i++) { +- u32 seqnum, pkt_nb; +- +- seqnum = ntohl(*data) & 0xffff; +- pkt_nb = ntohl(*data) >> 16; +- ksft_print_msg("%u:%u ", pkt_nb, seqnum); +- data++; +- } +-} +- +-static void pkt_dump(void *pkt, u32 len, bool eth_header) +-{ +- struct ethhdr *ethhdr = pkt; +- u32 i, *data; +- +- if (eth_header) { +- /*extract L2 frame */ +- ksft_print_msg("DEBUG>> L2: dst mac: "); +- for (i = 0; i < ETH_ALEN; i++) +- ksft_print_msg("%02X", ethhdr->h_dest[i]); +- +- ksft_print_msg("\nDEBUG>> L2: src mac: "); +- for (i = 0; i < ETH_ALEN; i++) +- ksft_print_msg("%02X", ethhdr->h_source[i]); +- +- data = pkt + PKT_HDR_SIZE; +- } else { +- data = pkt; +- } +- +- /*extract L5 frame */ +- ksft_print_msg("\nDEBUG>> L5: seqnum: "); +- pkt_print_data(data, PKT_DUMP_NB_TO_PRINT); +- ksft_print_msg("...."); +- if (len > PKT_DUMP_NB_TO_PRINT * sizeof(u32)) { +- ksft_print_msg("\n.... "); +- pkt_print_data(data + len / sizeof(u32) - PKT_DUMP_NB_TO_PRINT, +- PKT_DUMP_NB_TO_PRINT); +- } +- ksft_print_msg("\n---------------------------------------\n"); +-} +- +-static bool is_offset_correct(struct xsk_umem_info *umem, struct pkt *pkt, u64 addr) +-{ +- u32 headroom = umem->unaligned_mode ? 0 : umem->frame_headroom; +- u32 offset = addr % umem->frame_size, expected_offset; +- int pkt_offset = pkt->valid ? pkt->offset : 0; +- +- if (!umem->unaligned_mode) +- pkt_offset = 0; +- +- expected_offset = (pkt_offset + headroom + XDP_PACKET_HEADROOM) % umem->frame_size; +- +- if (offset == expected_offset) +- return true; +- +- ksft_print_msg("[%s] expected [%u], got [%u]\n", __func__, expected_offset, offset); +- return false; +-} +- +-static bool is_metadata_correct(struct pkt *pkt, void *buffer, u64 addr) +-{ +- void *data = xsk_umem__get_data(buffer, addr); +- struct xdp_info *meta = data - sizeof(struct xdp_info); +- +- if (meta->count != pkt->pkt_nb) { +- ksft_print_msg("[%s] expected meta_count [%d], got meta_count [%llu]\n", +- __func__, pkt->pkt_nb, +- (unsigned long long)meta->count); +- return false; +- } +- +- return true; +-} +- +-static bool is_adjust_tail_supported(struct xsk_xdp_progs *skel_rx) +-{ +- struct bpf_map *data_map; +- int adjust_value = 0; +- int key = 0; +- int ret; +- +- data_map = bpf_object__find_map_by_name(skel_rx->obj, "xsk_xdp_.bss"); +- if (!data_map || !bpf_map__is_internal(data_map)) { +- ksft_print_msg("Error: could not find bss section of XDP program\n"); +- exit_with_error(errno); +- } +- +- ret = bpf_map_lookup_elem(bpf_map__fd(data_map), &key, &adjust_value); +- if (ret) { +- ksft_print_msg("Error: bpf_map_lookup_elem failed with error %d\n", ret); +- exit_with_error(errno); +- } +- +- /* Set the 'adjust_value' variable to -EOPNOTSUPP in the XDP program if the adjust_tail +- * helper is not supported. Skip the adjust_tail test case in this scenario. +- */ +- return adjust_value != -EOPNOTSUPP; +-} +- +-static bool is_frag_valid(struct xsk_umem_info *umem, u64 addr, u32 len, u32 expected_pkt_nb, +- u32 bytes_processed) +-{ +- u32 seqnum, pkt_nb, *pkt_data, words_to_end, expected_seqnum; +- void *data = xsk_umem__get_data(umem->buffer, addr); +- +- addr -= umem->base_addr; +- +- if (addr >= umem->num_frames * umem->frame_size || +- addr + len > umem->num_frames * umem->frame_size) { +- ksft_print_msg("Frag invalid addr: %llx len: %u\n", +- (unsigned long long)addr, len); +- return false; +- } +- if (!umem->unaligned_mode && addr % umem->frame_size + len > umem->frame_size) { +- ksft_print_msg("Frag crosses frame boundary addr: %llx len: %u\n", +- (unsigned long long)addr, len); +- return false; +- } +- +- pkt_data = data; +- if (!bytes_processed) { +- pkt_data += PKT_HDR_SIZE / sizeof(*pkt_data); +- len -= PKT_HDR_SIZE; +- } else { +- bytes_processed -= PKT_HDR_SIZE; +- } +- +- expected_seqnum = bytes_processed / sizeof(*pkt_data); +- seqnum = ntohl(*pkt_data) & 0xffff; +- pkt_nb = ntohl(*pkt_data) >> 16; +- +- if (expected_pkt_nb != pkt_nb) { +- ksft_print_msg("[%s] expected pkt_nb [%u], got pkt_nb [%u]\n", +- __func__, expected_pkt_nb, pkt_nb); +- goto error; +- } +- if (expected_seqnum != seqnum) { +- ksft_print_msg("[%s] expected seqnum at start [%u], got seqnum [%u]\n", +- __func__, expected_seqnum, seqnum); +- goto error; +- } +- +- words_to_end = len / sizeof(*pkt_data) - 1; +- pkt_data += words_to_end; +- seqnum = ntohl(*pkt_data) & 0xffff; +- expected_seqnum += words_to_end; +- if (expected_seqnum != seqnum) { +- ksft_print_msg("[%s] expected seqnum at end [%u], got seqnum [%u]\n", +- __func__, expected_seqnum, seqnum); +- goto error; +- } +- +- return true; +- +-error: +- pkt_dump(data, len, !bytes_processed); +- return false; +-} +- +-static bool is_pkt_valid(struct pkt *pkt, void *buffer, u64 addr, u32 len) +-{ +- if (pkt->len != len) { +- ksft_print_msg("[%s] expected packet length [%d], got length [%d]\n", +- __func__, pkt->len, len); +- pkt_dump(xsk_umem__get_data(buffer, addr), len, true); +- return false; +- } +- +- return true; +-} +- +-static u32 load_value(u32 *counter) +-{ +- return __atomic_load_n(counter, __ATOMIC_ACQUIRE); +-} +- +-static bool kick_tx_with_check(struct xsk_socket_info *xsk, int *ret) +-{ +- u32 max_budget = MAX_TX_BUDGET_DEFAULT; +- u32 cons, ready_to_send; +- int delta; +- +- cons = load_value(xsk->tx.consumer); +- ready_to_send = load_value(xsk->tx.producer) - cons; +- *ret = sendto(xsk_socket__fd(xsk->xsk), NULL, 0, MSG_DONTWAIT, NULL, 0); +- +- delta = load_value(xsk->tx.consumer) - cons; +- /* By default, xsk should consume exact @max_budget descs at one +- * send in this case where hitting the max budget limit in while +- * loop is triggered in __xsk_generic_xmit(). Please make sure that +- * the number of descs to be sent is larger than @max_budget, or +- * else the tx.consumer will be updated in xskq_cons_peek_desc() +- * in time which hides the issue we try to verify. +- */ +- if (ready_to_send > max_budget && delta != max_budget) +- return false; +- +- return true; +-} +- +-static int kick_tx(struct xsk_socket_info *xsk) +-{ +- int ret; +- +- if (xsk->check_consumer) { +- if (!kick_tx_with_check(xsk, &ret)) +- return TEST_FAILURE; +- } else { +- ret = sendto(xsk_socket__fd(xsk->xsk), NULL, 0, MSG_DONTWAIT, NULL, 0); +- } +- if (ret >= 0) +- return TEST_PASS; +- if (errno == ENOBUFS || errno == EAGAIN || errno == EBUSY || errno == ENETDOWN) { +- usleep(100); +- return TEST_PASS; +- } +- return TEST_FAILURE; +-} +- +-static int kick_rx(struct xsk_socket_info *xsk) +-{ +- int ret; +- +- ret = recvfrom(xsk_socket__fd(xsk->xsk), NULL, 0, MSG_DONTWAIT, NULL, NULL); +- if (ret < 0) +- return TEST_FAILURE; +- +- return TEST_PASS; +-} +- +-static int complete_pkts(struct xsk_socket_info *xsk, int batch_size) +-{ +- unsigned int rcvd; +- u32 idx; +- int ret; +- +- if (xsk_ring_prod__needs_wakeup(&xsk->tx)) { +- ret = kick_tx(xsk); +- if (ret) +- return TEST_FAILURE; +- } +- +- rcvd = xsk_ring_cons__peek(&xsk->umem->cq, batch_size, &idx); +- if (rcvd) { +- if (rcvd > xsk->outstanding_tx) { +- u64 addr = *xsk_ring_cons__comp_addr(&xsk->umem->cq, idx + rcvd - 1); +- +- ksft_print_msg("[%s] Too many packets completed\n", __func__); +- ksft_print_msg("Last completion address: %llx\n", +- (unsigned long long)addr); +- return TEST_FAILURE; +- } +- +- xsk_ring_cons__release(&xsk->umem->cq, rcvd); +- xsk->outstanding_tx -= rcvd; +- } +- +- return TEST_PASS; +-} +- +-static int __receive_pkts(struct test_spec *test, struct xsk_socket_info *xsk) +-{ +- u32 frags_processed = 0, nb_frags = 0, pkt_len = 0; +- u32 idx_rx = 0, idx_fq = 0, rcvd, pkts_sent = 0; +- struct pkt_stream *pkt_stream = xsk->pkt_stream; +- struct ifobject *ifobj = test->ifobj_rx; +- struct xsk_umem_info *umem = xsk->umem; +- struct pollfd fds = { }; +- struct pkt *pkt; +- u64 first_addr = 0; +- int ret; +- +- fds.fd = xsk_socket__fd(xsk->xsk); +- fds.events = POLLIN; +- +- ret = kick_rx(xsk); +- if (ret) +- return TEST_FAILURE; +- +- if (ifobj->use_poll) { +- ret = poll(&fds, 1, POLL_TMOUT); +- if (ret < 0) +- return TEST_FAILURE; +- +- if (!ret) { +- if (!is_umem_valid(test->ifobj_tx)) +- return TEST_PASS; +- +- ksft_print_msg("ERROR: [%s] Poll timed out\n", __func__); +- return TEST_CONTINUE; +- } +- +- if (!(fds.revents & POLLIN)) +- return TEST_CONTINUE; +- } +- +- rcvd = xsk_ring_cons__peek(&xsk->rx, xsk->batch_size, &idx_rx); +- if (!rcvd) +- return TEST_CONTINUE; +- +- if (ifobj->use_fill_ring) { +- ret = xsk_ring_prod__reserve(&umem->fq, rcvd, &idx_fq); +- while (ret != rcvd) { +- if (xsk_ring_prod__needs_wakeup(&umem->fq)) { +- ret = poll(&fds, 1, POLL_TMOUT); +- if (ret < 0) +- return TEST_FAILURE; +- } +- ret = xsk_ring_prod__reserve(&umem->fq, rcvd, &idx_fq); +- } +- } +- +- while (frags_processed < rcvd) { +- const struct xdp_desc *desc = xsk_ring_cons__rx_desc(&xsk->rx, idx_rx++); +- u64 addr = desc->addr, orig; +- +- orig = xsk_umem__extract_addr(addr); +- addr = xsk_umem__add_offset_to_addr(addr); +- +- if (!nb_frags) { +- pkt = pkt_stream_get_next_rx_pkt(pkt_stream, &pkts_sent); +- if (!pkt) { +- ksft_print_msg("[%s] received too many packets addr: %lx len %u\n", +- __func__, addr, desc->len); +- return TEST_FAILURE; +- } +- } +- +- print_verbose("Rx: addr: %lx len: %u options: %u pkt_nb: %u valid: %u\n", +- addr, desc->len, desc->options, pkt->pkt_nb, pkt->valid); +- +- if (!is_frag_valid(umem, addr, desc->len, pkt->pkt_nb, pkt_len) || +- !is_offset_correct(umem, pkt, addr) || (ifobj->use_metadata && +- !is_metadata_correct(pkt, umem->buffer, addr))) +- return TEST_FAILURE; +- +- if (!nb_frags++) +- first_addr = addr; +- frags_processed++; +- pkt_len += desc->len; +- if (ifobj->use_fill_ring) +- *xsk_ring_prod__fill_addr(&umem->fq, idx_fq++) = orig; +- +- if (pkt_continues(desc->options)) +- continue; +- +- /* The complete packet has been received */ +- if (!is_pkt_valid(pkt, umem->buffer, first_addr, pkt_len) || +- !is_offset_correct(umem, pkt, addr)) +- return TEST_FAILURE; +- +- pkt_stream->nb_rx_pkts++; +- nb_frags = 0; +- pkt_len = 0; +- } +- +- if (nb_frags) { +- /* In the middle of a packet. Start over from beginning of packet. */ +- idx_rx -= nb_frags; +- xsk_ring_cons__cancel(&xsk->rx, nb_frags); +- if (ifobj->use_fill_ring) { +- idx_fq -= nb_frags; +- xsk_ring_prod__cancel(&umem->fq, nb_frags); +- } +- frags_processed -= nb_frags; +- } +- +- if (ifobj->use_fill_ring) +- xsk_ring_prod__submit(&umem->fq, frags_processed); +- if (ifobj->release_rx) +- xsk_ring_cons__release(&xsk->rx, frags_processed); +- +- pthread_mutex_lock(&pacing_mutex); +- pkts_in_flight -= pkts_sent; +- pthread_mutex_unlock(&pacing_mutex); +- pkts_sent = 0; +- +-return TEST_CONTINUE; +-} +- +-bool all_packets_received(struct test_spec *test, struct xsk_socket_info *xsk, u32 sock_num, +- unsigned long *bitmap) +-{ +- struct pkt_stream *pkt_stream = xsk->pkt_stream; +- +- if (!pkt_stream) { +- __set_bit(sock_num, bitmap); +- return false; +- } +- +- if (pkt_stream->nb_rx_pkts == pkt_stream->nb_valid_entries) { +- __set_bit(sock_num, bitmap); +- if (bitmap_full(bitmap, test->nb_sockets)) +- return true; +- } +- +- return false; +-} +- +-static int receive_pkts(struct test_spec *test) +-{ +- struct timeval tv_end, tv_now, tv_timeout = {THREAD_TMOUT, 0}; +- DECLARE_BITMAP(bitmap, test->nb_sockets); +- struct xsk_socket_info *xsk; +- u32 sock_num = 0; +- int res, ret; +- +- ret = gettimeofday(&tv_now, NULL); +- if (ret) +- exit_with_error(errno); +- +- timeradd(&tv_now, &tv_timeout, &tv_end); +- +- while (1) { +- xsk = &test->ifobj_rx->xsk_arr[sock_num]; +- +- if ((all_packets_received(test, xsk, sock_num, bitmap))) +- break; +- +- res = __receive_pkts(test, xsk); +- if (!(res == TEST_PASS || res == TEST_CONTINUE)) +- return res; +- +- ret = gettimeofday(&tv_now, NULL); +- if (ret) +- exit_with_error(errno); +- +- if (timercmp(&tv_now, &tv_end, >)) { +- ksft_print_msg("ERROR: [%s] Receive loop timed out\n", __func__); +- return TEST_FAILURE; +- } +- sock_num = (sock_num + 1) % test->nb_sockets; +- } +- +- return TEST_PASS; +-} +- +-static int __send_pkts(struct ifobject *ifobject, struct xsk_socket_info *xsk, bool timeout) +-{ +- u32 i, idx = 0, valid_pkts = 0, valid_frags = 0, buffer_len; +- struct pkt_stream *pkt_stream = xsk->pkt_stream; +- struct xsk_umem_info *umem = ifobject->umem; +- bool use_poll = ifobject->use_poll; +- struct pollfd fds = { }; +- int ret; +- +- buffer_len = pkt_get_buffer_len(umem, pkt_stream->max_pkt_len); +- /* pkts_in_flight might be negative if many invalid packets are sent */ +- if (pkts_in_flight >= (int)((umem_size(umem) - xsk->batch_size * buffer_len) / +- buffer_len)) { +- ret = kick_tx(xsk); +- if (ret) +- return TEST_FAILURE; +- return TEST_CONTINUE; +- } +- +- fds.fd = xsk_socket__fd(xsk->xsk); +- fds.events = POLLOUT; +- +- while (xsk_ring_prod__reserve(&xsk->tx, xsk->batch_size, &idx) < xsk->batch_size) { +- if (use_poll) { +- ret = poll(&fds, 1, POLL_TMOUT); +- if (timeout) { +- if (ret < 0) { +- ksft_print_msg("ERROR: [%s] Poll error %d\n", +- __func__, errno); +- return TEST_FAILURE; +- } +- if (ret == 0) +- return TEST_PASS; +- break; +- } +- if (ret <= 0) { +- ksft_print_msg("ERROR: [%s] Poll error %d\n", +- __func__, errno); +- return TEST_FAILURE; +- } +- } +- +- complete_pkts(xsk, xsk->batch_size); +- } +- +- for (i = 0; i < xsk->batch_size; i++) { +- struct pkt *pkt = pkt_stream_get_next_tx_pkt(pkt_stream); +- u32 nb_frags_left, nb_frags, bytes_written = 0; +- +- if (!pkt) +- break; +- +- nb_frags = pkt_nb_frags(umem->frame_size, pkt_stream, pkt); +- if (nb_frags > xsk->batch_size - i) { +- pkt_stream_cancel(pkt_stream); +- xsk_ring_prod__cancel(&xsk->tx, xsk->batch_size - i); +- break; +- } +- nb_frags_left = nb_frags; +- +- while (nb_frags_left--) { +- struct xdp_desc *tx_desc = xsk_ring_prod__tx_desc(&xsk->tx, idx + i); +- +- tx_desc->addr = pkt_get_addr(pkt, ifobject->umem); +- if (pkt_stream->verbatim) { +- tx_desc->len = pkt->len; +- tx_desc->options = pkt->options; +- } else if (nb_frags_left) { +- tx_desc->len = umem->frame_size; +- tx_desc->options = XDP_PKT_CONTD; +- } else { +- tx_desc->len = pkt->len - bytes_written; +- tx_desc->options = 0; +- } +- if (pkt->valid) +- pkt_generate(xsk, umem, tx_desc->addr, tx_desc->len, pkt->pkt_nb, +- bytes_written); +- bytes_written += tx_desc->len; +- +- print_verbose("Tx addr: %llx len: %u options: %u pkt_nb: %u\n", +- tx_desc->addr, tx_desc->len, tx_desc->options, pkt->pkt_nb); +- +- if (nb_frags_left) { +- i++; +- if (pkt_stream->verbatim) +- pkt = pkt_stream_get_next_tx_pkt(pkt_stream); +- } +- } +- +- if (pkt && pkt->valid) { +- valid_pkts++; +- valid_frags += nb_frags; +- } +- } +- +- pthread_mutex_lock(&pacing_mutex); +- pkts_in_flight += valid_pkts; +- pthread_mutex_unlock(&pacing_mutex); +- +- xsk_ring_prod__submit(&xsk->tx, i); +- xsk->outstanding_tx += valid_frags; +- +- if (use_poll) { +- ret = poll(&fds, 1, POLL_TMOUT); +- if (ret <= 0) { +- if (ret == 0 && timeout) +- return TEST_PASS; +- +- ksft_print_msg("ERROR: [%s] Poll error %d\n", __func__, ret); +- return TEST_FAILURE; +- } +- } +- +- if (!timeout) { +- if (complete_pkts(xsk, i)) +- return TEST_FAILURE; +- +- usleep(10); +- return TEST_PASS; +- } +- +- return TEST_CONTINUE; +-} +- +-static int wait_for_tx_completion(struct xsk_socket_info *xsk) +-{ +- struct timeval tv_end, tv_now, tv_timeout = {THREAD_TMOUT, 0}; +- int ret; +- +- ret = gettimeofday(&tv_now, NULL); +- if (ret) +- exit_with_error(errno); +- timeradd(&tv_now, &tv_timeout, &tv_end); +- +- while (xsk->outstanding_tx) { +- ret = gettimeofday(&tv_now, NULL); +- if (ret) +- exit_with_error(errno); +- if (timercmp(&tv_now, &tv_end, >)) { +- ksft_print_msg("ERROR: [%s] Transmission loop timed out\n", __func__); +- return TEST_FAILURE; +- } +- +- complete_pkts(xsk, xsk->batch_size); +- } +- +- return TEST_PASS; +-} +- +-bool all_packets_sent(struct test_spec *test, unsigned long *bitmap) +-{ +- return bitmap_full(bitmap, test->nb_sockets); +-} +- +-static int send_pkts(struct test_spec *test, struct ifobject *ifobject) +-{ +- bool timeout = !is_umem_valid(test->ifobj_rx); +- DECLARE_BITMAP(bitmap, test->nb_sockets); +- u32 i, ret; +- +- while (!(all_packets_sent(test, bitmap))) { +- for (i = 0; i < test->nb_sockets; i++) { +- struct pkt_stream *pkt_stream; +- +- pkt_stream = ifobject->xsk_arr[i].pkt_stream; +- if (!pkt_stream || pkt_stream->current_pkt_nb >= pkt_stream->nb_pkts) { +- __set_bit(i, bitmap); +- continue; +- } +- ret = __send_pkts(ifobject, &ifobject->xsk_arr[i], timeout); +- if (ret == TEST_CONTINUE && !test->fail) +- continue; +- +- if ((ret || test->fail) && !timeout) +- return TEST_FAILURE; +- +- if (ret == TEST_PASS && timeout) +- return ret; +- +- ret = wait_for_tx_completion(&ifobject->xsk_arr[i]); +- if (ret) +- return TEST_FAILURE; +- } +- } +- +- return TEST_PASS; +-} +- +-static int get_xsk_stats(struct xsk_socket *xsk, struct xdp_statistics *stats) +-{ +- int fd = xsk_socket__fd(xsk), err; +- socklen_t optlen, expected_len; +- +- optlen = sizeof(*stats); +- err = getsockopt(fd, SOL_XDP, XDP_STATISTICS, stats, &optlen); +- if (err) { +- ksft_print_msg("[%s] getsockopt(XDP_STATISTICS) error %u %s\n", +- __func__, -err, strerror(-err)); +- return TEST_FAILURE; +- } +- +- expected_len = sizeof(struct xdp_statistics); +- if (optlen != expected_len) { +- ksft_print_msg("[%s] getsockopt optlen error. Expected: %u got: %u\n", +- __func__, expected_len, optlen); +- return TEST_FAILURE; +- } +- +- return TEST_PASS; +-} +- +-static int validate_rx_dropped(struct ifobject *ifobject) +-{ +- struct xsk_socket *xsk = ifobject->xsk->xsk; +- struct xdp_statistics stats; +- int err; +- +- err = kick_rx(ifobject->xsk); +- if (err) +- return TEST_FAILURE; +- +- err = get_xsk_stats(xsk, &stats); +- if (err) +- return TEST_FAILURE; +- +- /* The receiver calls getsockopt after receiving the last (valid) +- * packet which is not the final packet sent in this test (valid and +- * invalid packets are sent in alternating fashion with the final +- * packet being invalid). Since the last packet may or may not have +- * been dropped already, both outcomes must be allowed. +- */ +- if (stats.rx_dropped == ifobject->xsk->pkt_stream->nb_pkts / 2 || +- stats.rx_dropped == ifobject->xsk->pkt_stream->nb_pkts / 2 - 1) +- return TEST_PASS; +- +- return TEST_FAILURE; +-} +- +-static int validate_rx_full(struct ifobject *ifobject) +-{ +- struct xsk_socket *xsk = ifobject->xsk->xsk; +- struct xdp_statistics stats; +- int err; +- +- usleep(1000); +- err = kick_rx(ifobject->xsk); +- if (err) +- return TEST_FAILURE; +- +- err = get_xsk_stats(xsk, &stats); +- if (err) +- return TEST_FAILURE; +- +- if (stats.rx_ring_full) +- return TEST_PASS; +- +- return TEST_FAILURE; +-} +- +-static int validate_fill_empty(struct ifobject *ifobject) +-{ +- struct xsk_socket *xsk = ifobject->xsk->xsk; +- struct xdp_statistics stats; +- int err; +- +- usleep(1000); +- err = kick_rx(ifobject->xsk); +- if (err) +- return TEST_FAILURE; +- +- err = get_xsk_stats(xsk, &stats); +- if (err) +- return TEST_FAILURE; +- +- if (stats.rx_fill_ring_empty_descs) +- return TEST_PASS; +- +- return TEST_FAILURE; +-} +- +-static int validate_tx_invalid_descs(struct ifobject *ifobject) +-{ +- struct xsk_socket *xsk = ifobject->xsk->xsk; +- int fd = xsk_socket__fd(xsk); +- struct xdp_statistics stats; +- socklen_t optlen; +- int err; +- +- optlen = sizeof(stats); +- err = getsockopt(fd, SOL_XDP, XDP_STATISTICS, &stats, &optlen); +- if (err) { +- ksft_print_msg("[%s] getsockopt(XDP_STATISTICS) error %u %s\n", +- __func__, -err, strerror(-err)); +- return TEST_FAILURE; +- } +- +- if (stats.tx_invalid_descs != ifobject->xsk->pkt_stream->nb_pkts / 2) { +- ksft_print_msg("[%s] tx_invalid_descs incorrect. Got [%llu] expected [%u]\n", +- __func__, +- (unsigned long long)stats.tx_invalid_descs, +- ifobject->xsk->pkt_stream->nb_pkts); +- return TEST_FAILURE; +- } +- +- return TEST_PASS; +-} +- +-static void xsk_configure_socket(struct test_spec *test, struct ifobject *ifobject, +- struct xsk_umem_info *umem, bool tx) +-{ +- int i, ret; +- +- for (i = 0; i < test->nb_sockets; i++) { +- bool shared = (ifobject->shared_umem && tx) ? true : !!i; +- u32 ctr = 0; +- +- while (ctr++ < SOCK_RECONF_CTR) { +- ret = __xsk_configure_socket(&ifobject->xsk_arr[i], umem, +- ifobject, shared); +- if (!ret) +- break; +- +- /* Retry if it fails as xsk_socket__create() is asynchronous */ +- if (ctr >= SOCK_RECONF_CTR) +- exit_with_error(-ret); +- usleep(USLEEP_MAX); +- } +- if (ifobject->busy_poll) +- enable_busy_poll(&ifobject->xsk_arr[i]); +- } +-} +- +-static void thread_common_ops_tx(struct test_spec *test, struct ifobject *ifobject) +-{ +- xsk_configure_socket(test, ifobject, test->ifobj_rx->umem, true); +- ifobject->xsk = &ifobject->xsk_arr[0]; +- ifobject->xskmap = test->ifobj_rx->xskmap; +- memcpy(ifobject->umem, test->ifobj_rx->umem, sizeof(struct xsk_umem_info)); +- ifobject->umem->base_addr = 0; +-} +- +-static void xsk_populate_fill_ring(struct xsk_umem_info *umem, struct pkt_stream *pkt_stream, +- bool fill_up) +-{ +- u32 rx_frame_size = umem->frame_size - XDP_PACKET_HEADROOM; +- u32 idx = 0, filled = 0, buffers_to_fill, nb_pkts; +- int ret; +- +- if (umem->num_frames < XSK_RING_PROD__DEFAULT_NUM_DESCS) +- buffers_to_fill = umem->num_frames; +- else +- buffers_to_fill = umem->fill_size; +- +- ret = xsk_ring_prod__reserve(&umem->fq, buffers_to_fill, &idx); +- if (ret != buffers_to_fill) +- exit_with_error(ENOSPC); +- +- while (filled < buffers_to_fill) { +- struct pkt *pkt = pkt_stream_get_next_rx_pkt(pkt_stream, &nb_pkts); +- u64 addr; +- u32 i; +- +- for (i = 0; i < pkt_nb_frags(rx_frame_size, pkt_stream, pkt); i++) { +- if (!pkt) { +- if (!fill_up) +- break; +- addr = filled * umem->frame_size + umem->base_addr; +- } else if (pkt->offset >= 0) { +- addr = pkt->offset % umem->frame_size + umem_alloc_buffer(umem); +- } else { +- addr = pkt->offset + umem_alloc_buffer(umem); +- } +- +- *xsk_ring_prod__fill_addr(&umem->fq, idx++) = addr; +- if (++filled >= buffers_to_fill) +- break; +- } +- } +- xsk_ring_prod__submit(&umem->fq, filled); +- xsk_ring_prod__cancel(&umem->fq, buffers_to_fill - filled); +- +- pkt_stream_reset(pkt_stream); +- umem_reset_alloc(umem); +-} +- +-static void thread_common_ops(struct test_spec *test, struct ifobject *ifobject) +-{ +- u64 umem_sz = ifobject->umem->num_frames * ifobject->umem->frame_size; +- int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE; +- LIBBPF_OPTS(bpf_xdp_query_opts, opts); +- void *bufs; +- int ret; +- u32 i; +- +- if (ifobject->umem->unaligned_mode) +- mmap_flags |= MAP_HUGETLB | MAP_HUGE_2MB; +- +- if (ifobject->shared_umem) +- umem_sz *= 2; +- +- bufs = mmap(NULL, umem_sz, PROT_READ | PROT_WRITE, mmap_flags, -1, 0); +- if (bufs == MAP_FAILED) +- exit_with_error(errno); +- +- ret = xsk_configure_umem(ifobject, ifobject->umem, bufs, umem_sz); +- if (ret) +- exit_with_error(-ret); +- +- xsk_configure_socket(test, ifobject, ifobject->umem, false); +- +- ifobject->xsk = &ifobject->xsk_arr[0]; +- +- if (!ifobject->rx_on) +- return; +- +- xsk_populate_fill_ring(ifobject->umem, ifobject->xsk->pkt_stream, ifobject->use_fill_ring); +- +- for (i = 0; i < test->nb_sockets; i++) { +- ifobject->xsk = &ifobject->xsk_arr[i]; +- ret = xsk_update_xskmap(ifobject->xskmap, ifobject->xsk->xsk, i); +- if (ret) +- exit_with_error(errno); +- } +-} +- +-static void *worker_testapp_validate_tx(void *arg) +-{ +- struct test_spec *test = (struct test_spec *)arg; +- struct ifobject *ifobject = test->ifobj_tx; +- int err; +- +- if (test->current_step == 1) { +- if (!ifobject->shared_umem) +- thread_common_ops(test, ifobject); +- else +- thread_common_ops_tx(test, ifobject); +- } +- +- err = send_pkts(test, ifobject); +- +- if (!err && ifobject->validation_func) +- err = ifobject->validation_func(ifobject); +- if (err) +- report_failure(test); +- +- pthread_exit(NULL); +-} +- +-static void *worker_testapp_validate_rx(void *arg) +-{ +- struct test_spec *test = (struct test_spec *)arg; +- struct ifobject *ifobject = test->ifobj_rx; +- int err; +- +- if (test->current_step == 1) { +- thread_common_ops(test, ifobject); +- } else { +- xsk_clear_xskmap(ifobject->xskmap); +- err = xsk_update_xskmap(ifobject->xskmap, ifobject->xsk->xsk, 0); +- if (err) { +- ksft_print_msg("Error: Failed to update xskmap, error %s\n", +- strerror(-err)); +- exit_with_error(-err); +- } +- } +- +- pthread_barrier_wait(&barr); +- +- err = receive_pkts(test); +- +- if (!err && ifobject->validation_func) +- err = ifobject->validation_func(ifobject); +- +- if (err) { +- if (test->adjust_tail && !is_adjust_tail_supported(ifobject->xdp_progs)) +- test->adjust_tail_support = false; +- else +- report_failure(test); +- } +- +- pthread_exit(NULL); +-} +- +-static u64 ceil_u64(u64 a, u64 b) +-{ +- return (a + b - 1) / b; +-} +- +-static void testapp_clean_xsk_umem(struct ifobject *ifobj) +-{ +- u64 umem_sz = ifobj->umem->num_frames * ifobj->umem->frame_size; +- +- if (ifobj->shared_umem) +- umem_sz *= 2; +- +- umem_sz = ceil_u64(umem_sz, HUGEPAGE_SIZE) * HUGEPAGE_SIZE; +- xsk_umem__delete(ifobj->umem->umem); +- munmap(ifobj->umem->buffer, umem_sz); +-} +- +-static void handler(int signum) +-{ +- pthread_exit(NULL); +-} +- +-static bool xdp_prog_changed_rx(struct test_spec *test) +-{ +- struct ifobject *ifobj = test->ifobj_rx; +- +- return ifobj->xdp_prog != test->xdp_prog_rx || ifobj->mode != test->mode; +-} +- +-static bool xdp_prog_changed_tx(struct test_spec *test) +-{ +- struct ifobject *ifobj = test->ifobj_tx; +- +- return ifobj->xdp_prog != test->xdp_prog_tx || ifobj->mode != test->mode; +-} +- +-static void xsk_reattach_xdp(struct ifobject *ifobj, struct bpf_program *xdp_prog, +- struct bpf_map *xskmap, enum test_mode mode) +-{ +- int err; +- +- xsk_detach_xdp_program(ifobj->ifindex, mode_to_xdp_flags(ifobj->mode)); +- err = xsk_attach_xdp_program(xdp_prog, ifobj->ifindex, mode_to_xdp_flags(mode)); +- if (err) { +- ksft_print_msg("Error attaching XDP program\n"); +- exit_with_error(-err); +- } +- +- if (ifobj->mode != mode && (mode == TEST_MODE_DRV || mode == TEST_MODE_ZC)) +- if (!xsk_is_in_mode(ifobj->ifindex, XDP_FLAGS_DRV_MODE)) { +- ksft_print_msg("ERROR: XDP prog not in DRV mode\n"); +- exit_with_error(EINVAL); +- } +- +- ifobj->xdp_prog = xdp_prog; +- ifobj->xskmap = xskmap; +- ifobj->mode = mode; +-} +- +-static void xsk_attach_xdp_progs(struct test_spec *test, struct ifobject *ifobj_rx, +- struct ifobject *ifobj_tx) +-{ +- if (xdp_prog_changed_rx(test)) +- xsk_reattach_xdp(ifobj_rx, test->xdp_prog_rx, test->xskmap_rx, test->mode); +- +- if (!ifobj_tx || ifobj_tx->shared_umem) +- return; +- +- if (xdp_prog_changed_tx(test)) +- xsk_reattach_xdp(ifobj_tx, test->xdp_prog_tx, test->xskmap_tx, test->mode); +-} +- +-static int __testapp_validate_traffic(struct test_spec *test, struct ifobject *ifobj1, +- struct ifobject *ifobj2) +-{ +- pthread_t t0, t1; +- int err; +- +- if (test->mtu > MAX_ETH_PKT_SIZE) { +- if (test->mode == TEST_MODE_ZC && (!ifobj1->multi_buff_zc_supp || +- (ifobj2 && !ifobj2->multi_buff_zc_supp))) { +- ksft_test_result_skip("Multi buffer for zero-copy not supported.\n"); +- return TEST_SKIP; +- } +- if (test->mode != TEST_MODE_ZC && (!ifobj1->multi_buff_supp || +- (ifobj2 && !ifobj2->multi_buff_supp))) { +- ksft_test_result_skip("Multi buffer not supported.\n"); +- return TEST_SKIP; +- } +- } +- err = test_spec_set_mtu(test, test->mtu); +- if (err) { +- ksft_print_msg("Error, could not set mtu.\n"); +- exit_with_error(err); +- } +- +- if (ifobj2) { +- if (pthread_barrier_init(&barr, NULL, 2)) +- exit_with_error(errno); +- pkt_stream_reset(ifobj2->xsk->pkt_stream); +- } +- +- test->current_step++; +- pkt_stream_reset(ifobj1->xsk->pkt_stream); +- pkts_in_flight = 0; +- +- signal(SIGUSR1, handler); +- /*Spawn RX thread */ +- pthread_create(&t0, NULL, ifobj1->func_ptr, test); +- +- if (ifobj2) { +- pthread_barrier_wait(&barr); +- if (pthread_barrier_destroy(&barr)) +- exit_with_error(errno); +- +- /*Spawn TX thread */ +- pthread_create(&t1, NULL, ifobj2->func_ptr, test); +- +- pthread_join(t1, NULL); +- } +- +- if (!ifobj2) +- pthread_kill(t0, SIGUSR1); +- else +- pthread_join(t0, NULL); +- +- if (test->total_steps == test->current_step || test->fail) { +- u32 i; +- +- if (ifobj2) +- for (i = 0; i < test->nb_sockets; i++) +- xsk_socket__delete(ifobj2->xsk_arr[i].xsk); +- +- for (i = 0; i < test->nb_sockets; i++) +- xsk_socket__delete(ifobj1->xsk_arr[i].xsk); +- +- testapp_clean_xsk_umem(ifobj1); +- if (ifobj2 && !ifobj2->shared_umem) +- testapp_clean_xsk_umem(ifobj2); +- } +- +- return !!test->fail; +-} +- +-static int testapp_validate_traffic(struct test_spec *test) +-{ +- struct ifobject *ifobj_rx = test->ifobj_rx; +- struct ifobject *ifobj_tx = test->ifobj_tx; +- +- if ((ifobj_rx->umem->unaligned_mode && !ifobj_rx->unaligned_supp) || +- (ifobj_tx->umem->unaligned_mode && !ifobj_tx->unaligned_supp)) { +- ksft_test_result_skip("No huge pages present.\n"); +- return TEST_SKIP; +- } +- +- if (test->set_ring) { +- if (ifobj_tx->hw_ring_size_supp) { +- if (set_ring_size(ifobj_tx)) { +- ksft_test_result_skip("Failed to change HW ring size.\n"); +- return TEST_FAILURE; +- } +- } else { +- ksft_test_result_skip("Changing HW ring size not supported.\n"); +- return TEST_SKIP; +- } +- } +- +- xsk_attach_xdp_progs(test, ifobj_rx, ifobj_tx); +- return __testapp_validate_traffic(test, ifobj_rx, ifobj_tx); +-} +- +-static int testapp_validate_traffic_single_thread(struct test_spec *test, struct ifobject *ifobj) +-{ +- return __testapp_validate_traffic(test, ifobj, NULL); +-} +- +-static int testapp_teardown(struct test_spec *test) +-{ +- int i; +- +- for (i = 0; i < MAX_TEARDOWN_ITER; i++) { +- if (testapp_validate_traffic(test)) +- return TEST_FAILURE; +- test_spec_reset(test); +- } +- +- return TEST_PASS; +-} +- +-static void swap_directions(struct ifobject **ifobj1, struct ifobject **ifobj2) +-{ +- thread_func_t tmp_func_ptr = (*ifobj1)->func_ptr; +- struct ifobject *tmp_ifobj = (*ifobj1); +- +- (*ifobj1)->func_ptr = (*ifobj2)->func_ptr; +- (*ifobj2)->func_ptr = tmp_func_ptr; +- +- *ifobj1 = *ifobj2; +- *ifobj2 = tmp_ifobj; +-} +- +-static int testapp_bidirectional(struct test_spec *test) +-{ +- int res; +- +- test->ifobj_tx->rx_on = true; +- test->ifobj_rx->tx_on = true; +- test->total_steps = 2; +- if (testapp_validate_traffic(test)) +- return TEST_FAILURE; +- +- print_verbose("Switching Tx/Rx direction\n"); +- swap_directions(&test->ifobj_rx, &test->ifobj_tx); +- res = __testapp_validate_traffic(test, test->ifobj_rx, test->ifobj_tx); +- +- swap_directions(&test->ifobj_rx, &test->ifobj_tx); +- return res; +-} +- +-static int swap_xsk_resources(struct test_spec *test) +-{ +- int ret; +- +- test->ifobj_tx->xsk_arr[0].pkt_stream = NULL; +- test->ifobj_rx->xsk_arr[0].pkt_stream = NULL; +- test->ifobj_tx->xsk_arr[1].pkt_stream = test->tx_pkt_stream_default; +- test->ifobj_rx->xsk_arr[1].pkt_stream = test->rx_pkt_stream_default; +- test->ifobj_tx->xsk = &test->ifobj_tx->xsk_arr[1]; +- test->ifobj_rx->xsk = &test->ifobj_rx->xsk_arr[1]; +- +- ret = xsk_update_xskmap(test->ifobj_rx->xskmap, test->ifobj_rx->xsk->xsk, 0); +- if (ret) +- return TEST_FAILURE; +- +- return TEST_PASS; +-} +- +-static int testapp_xdp_prog_cleanup(struct test_spec *test) +-{ +- test->total_steps = 2; +- test->nb_sockets = 2; +- if (testapp_validate_traffic(test)) +- return TEST_FAILURE; +- +- if (swap_xsk_resources(test)) +- return TEST_FAILURE; +- return testapp_validate_traffic(test); +-} +- +-static int testapp_headroom(struct test_spec *test) +-{ +- test->ifobj_rx->umem->frame_headroom = UMEM_HEADROOM_TEST_SIZE; +- return testapp_validate_traffic(test); +-} +- +-static int testapp_stats_rx_dropped(struct test_spec *test) +-{ +- if (test->mode == TEST_MODE_ZC) { +- ksft_test_result_skip("Can not run RX_DROPPED test for ZC mode\n"); +- return TEST_SKIP; +- } +- +- pkt_stream_replace_half(test, MIN_PKT_SIZE * 4, 0); +- test->ifobj_rx->umem->frame_headroom = test->ifobj_rx->umem->frame_size - +- XDP_PACKET_HEADROOM - MIN_PKT_SIZE * 3; +- pkt_stream_receive_half(test); +- test->ifobj_rx->validation_func = validate_rx_dropped; +- return testapp_validate_traffic(test); +-} +- +-static int testapp_stats_tx_invalid_descs(struct test_spec *test) +-{ +- pkt_stream_replace_half(test, XSK_UMEM__INVALID_FRAME_SIZE, 0); +- test->ifobj_tx->validation_func = validate_tx_invalid_descs; +- return testapp_validate_traffic(test); +-} +- +-static int testapp_stats_rx_full(struct test_spec *test) +-{ +- pkt_stream_replace(test, DEFAULT_UMEM_BUFFERS + DEFAULT_UMEM_BUFFERS / 2, MIN_PKT_SIZE); +- test->ifobj_rx->xsk->pkt_stream = pkt_stream_generate(DEFAULT_UMEM_BUFFERS, MIN_PKT_SIZE); +- +- test->ifobj_rx->xsk->rxqsize = DEFAULT_UMEM_BUFFERS; +- test->ifobj_rx->release_rx = false; +- test->ifobj_rx->validation_func = validate_rx_full; +- return testapp_validate_traffic(test); +-} +- +-static int testapp_stats_fill_empty(struct test_spec *test) +-{ +- pkt_stream_replace(test, DEFAULT_UMEM_BUFFERS + DEFAULT_UMEM_BUFFERS / 2, MIN_PKT_SIZE); +- test->ifobj_rx->xsk->pkt_stream = pkt_stream_generate(DEFAULT_UMEM_BUFFERS, MIN_PKT_SIZE); +- +- test->ifobj_rx->use_fill_ring = false; +- test->ifobj_rx->validation_func = validate_fill_empty; +- return testapp_validate_traffic(test); +-} +- +-static int testapp_send_receive_unaligned(struct test_spec *test) +-{ +- test->ifobj_tx->umem->unaligned_mode = true; +- test->ifobj_rx->umem->unaligned_mode = true; +- /* Let half of the packets straddle a 4K buffer boundary */ +- pkt_stream_replace_half(test, MIN_PKT_SIZE, -MIN_PKT_SIZE / 2); +- +- return testapp_validate_traffic(test); +-} +- +-static int testapp_send_receive_unaligned_mb(struct test_spec *test) +-{ +- test->mtu = MAX_ETH_JUMBO_SIZE; +- test->ifobj_tx->umem->unaligned_mode = true; +- test->ifobj_rx->umem->unaligned_mode = true; +- pkt_stream_replace(test, DEFAULT_PKT_CNT, MAX_ETH_JUMBO_SIZE); +- return testapp_validate_traffic(test); +-} +- +-static int testapp_single_pkt(struct test_spec *test) +-{ +- struct pkt pkts[] = {{0, MIN_PKT_SIZE, 0, true}}; +- +- pkt_stream_generate_custom(test, pkts, ARRAY_SIZE(pkts)); +- return testapp_validate_traffic(test); +-} +- +-static int testapp_send_receive_mb(struct test_spec *test) +-{ +- test->mtu = MAX_ETH_JUMBO_SIZE; +- pkt_stream_replace(test, DEFAULT_PKT_CNT, MAX_ETH_JUMBO_SIZE); +- +- return testapp_validate_traffic(test); +-} +- +-static int testapp_invalid_desc_mb(struct test_spec *test) +-{ +- struct xsk_umem_info *umem = test->ifobj_tx->umem; +- u64 umem_size = umem->num_frames * umem->frame_size; +- struct pkt pkts[] = { +- /* Valid packet for synch to start with */ +- {0, MIN_PKT_SIZE, 0, true, 0}, +- /* Zero frame len is not legal */ +- {0, XSK_UMEM__LARGE_FRAME_SIZE, 0, false, XDP_PKT_CONTD}, +- {0, XSK_UMEM__LARGE_FRAME_SIZE, 0, false, XDP_PKT_CONTD}, +- {0, 0, 0, false, 0}, +- /* Invalid address in the second frame */ +- {0, XSK_UMEM__LARGE_FRAME_SIZE, 0, false, XDP_PKT_CONTD}, +- {umem_size, XSK_UMEM__LARGE_FRAME_SIZE, 0, false, XDP_PKT_CONTD}, +- /* Invalid len in the middle */ +- {0, XSK_UMEM__LARGE_FRAME_SIZE, 0, false, XDP_PKT_CONTD}, +- {0, XSK_UMEM__INVALID_FRAME_SIZE, 0, false, XDP_PKT_CONTD}, +- /* Invalid options in the middle */ +- {0, XSK_UMEM__LARGE_FRAME_SIZE, 0, false, XDP_PKT_CONTD}, +- {0, XSK_UMEM__LARGE_FRAME_SIZE, 0, false, XSK_DESC__INVALID_OPTION}, +- /* Transmit 2 frags, receive 3 */ +- {0, XSK_UMEM__MAX_FRAME_SIZE, 0, true, XDP_PKT_CONTD}, +- {0, XSK_UMEM__MAX_FRAME_SIZE, 0, true, 0}, +- /* Middle frame crosses chunk boundary with small length */ +- {0, XSK_UMEM__LARGE_FRAME_SIZE, 0, false, XDP_PKT_CONTD}, +- {-MIN_PKT_SIZE / 2, MIN_PKT_SIZE, 0, false, 0}, +- /* Valid packet for synch so that something is received */ +- {0, MIN_PKT_SIZE, 0, true, 0}}; +- +- if (umem->unaligned_mode) { +- /* Crossing a chunk boundary allowed */ +- pkts[12].valid = true; +- pkts[13].valid = true; +- } +- +- test->mtu = MAX_ETH_JUMBO_SIZE; +- pkt_stream_generate_custom(test, pkts, ARRAY_SIZE(pkts)); +- return testapp_validate_traffic(test); +-} +- +-static int testapp_invalid_desc(struct test_spec *test) +-{ +- struct xsk_umem_info *umem = test->ifobj_tx->umem; +- u64 umem_size = umem->num_frames * umem->frame_size; +- struct pkt pkts[] = { +- /* Zero packet address allowed */ +- {0, MIN_PKT_SIZE, 0, true}, +- /* Allowed packet */ +- {0, MIN_PKT_SIZE, 0, true}, +- /* Straddling the start of umem */ +- {-2, MIN_PKT_SIZE, 0, false}, +- /* Packet too large */ +- {0, XSK_UMEM__INVALID_FRAME_SIZE, 0, false}, +- /* Up to end of umem allowed */ +- {umem_size - MIN_PKT_SIZE - 2 * umem->frame_size, MIN_PKT_SIZE, 0, true}, +- /* After umem ends */ +- {umem_size, MIN_PKT_SIZE, 0, false}, +- /* Straddle the end of umem */ +- {umem_size - MIN_PKT_SIZE / 2, MIN_PKT_SIZE, 0, false}, +- /* Straddle a 4K boundary */ +- {0x1000 - MIN_PKT_SIZE / 2, MIN_PKT_SIZE, 0, false}, +- /* Straddle a 2K boundary */ +- {0x800 - MIN_PKT_SIZE / 2, MIN_PKT_SIZE, 0, true}, +- /* Valid packet for synch so that something is received */ +- {0, MIN_PKT_SIZE, 0, true}}; +- +- if (umem->unaligned_mode) { +- /* Crossing a page boundary allowed */ +- pkts[7].valid = true; +- } +- if (umem->frame_size == XSK_UMEM__DEFAULT_FRAME_SIZE / 2) { +- /* Crossing a 2K frame size boundary not allowed */ +- pkts[8].valid = false; +- } +- +- if (test->ifobj_tx->shared_umem) { +- pkts[4].offset += umem_size; +- pkts[5].offset += umem_size; +- pkts[6].offset += umem_size; +- } +- +- pkt_stream_generate_custom(test, pkts, ARRAY_SIZE(pkts)); +- return testapp_validate_traffic(test); +-} +- +-static int testapp_xdp_drop(struct test_spec *test) +-{ +- struct xsk_xdp_progs *skel_rx = test->ifobj_rx->xdp_progs; +- struct xsk_xdp_progs *skel_tx = test->ifobj_tx->xdp_progs; +- +- test_spec_set_xdp_prog(test, skel_rx->progs.xsk_xdp_drop, skel_tx->progs.xsk_xdp_drop, +- skel_rx->maps.xsk, skel_tx->maps.xsk); +- +- pkt_stream_receive_half(test); +- return testapp_validate_traffic(test); +-} +- +-static int testapp_xdp_metadata_copy(struct test_spec *test) +-{ +- struct xsk_xdp_progs *skel_rx = test->ifobj_rx->xdp_progs; +- struct xsk_xdp_progs *skel_tx = test->ifobj_tx->xdp_progs; +- +- test_spec_set_xdp_prog(test, skel_rx->progs.xsk_xdp_populate_metadata, +- skel_tx->progs.xsk_xdp_populate_metadata, +- skel_rx->maps.xsk, skel_tx->maps.xsk); +- test->ifobj_rx->use_metadata = true; +- +- skel_rx->bss->count = 0; +- +- return testapp_validate_traffic(test); +-} +- +-static int testapp_xdp_shared_umem(struct test_spec *test) +-{ +- struct xsk_xdp_progs *skel_rx = test->ifobj_rx->xdp_progs; +- struct xsk_xdp_progs *skel_tx = test->ifobj_tx->xdp_progs; +- +- test->total_steps = 1; +- test->nb_sockets = 2; +- +- test_spec_set_xdp_prog(test, skel_rx->progs.xsk_xdp_shared_umem, +- skel_tx->progs.xsk_xdp_shared_umem, +- skel_rx->maps.xsk, skel_tx->maps.xsk); +- +- pkt_stream_even_odd_sequence(test); +- +- return testapp_validate_traffic(test); +-} +- +-static int testapp_poll_txq_tmout(struct test_spec *test) +-{ +- test->ifobj_tx->use_poll = true; +- /* create invalid frame by set umem frame_size and pkt length equal to 2048 */ +- test->ifobj_tx->umem->frame_size = 2048; +- pkt_stream_replace(test, 2 * DEFAULT_PKT_CNT, 2048); +- return testapp_validate_traffic_single_thread(test, test->ifobj_tx); +-} +- +-static int testapp_poll_rxq_tmout(struct test_spec *test) +-{ +- test->ifobj_rx->use_poll = true; +- return testapp_validate_traffic_single_thread(test, test->ifobj_rx); +-} +- +-static int testapp_too_many_frags(struct test_spec *test) +-{ +- struct pkt *pkts; +- u32 max_frags, i; +- int ret; +- +- if (test->mode == TEST_MODE_ZC) { +- max_frags = test->ifobj_tx->xdp_zc_max_segs; +- } else { +- max_frags = get_max_skb_frags(); +- if (!max_frags) { +- ksft_print_msg("Couldn't retrieve MAX_SKB_FRAGS from system, using default (17) value\n"); +- max_frags = 17; +- } +- max_frags += 1; +- } +- +- pkts = calloc(2 * max_frags + 2, sizeof(struct pkt)); +- if (!pkts) +- return TEST_FAILURE; +- +- test->mtu = MAX_ETH_JUMBO_SIZE; +- +- /* Valid packet for synch */ +- pkts[0].len = MIN_PKT_SIZE; +- pkts[0].valid = true; +- +- /* One valid packet with the max amount of frags */ +- for (i = 1; i < max_frags + 1; i++) { +- pkts[i].len = MIN_PKT_SIZE; +- pkts[i].options = XDP_PKT_CONTD; +- pkts[i].valid = true; +- } +- pkts[max_frags].options = 0; +- +- /* An invalid packet with the max amount of frags but signals packet +- * continues on the last frag +- */ +- for (i = max_frags + 1; i < 2 * max_frags + 1; i++) { +- pkts[i].len = MIN_PKT_SIZE; +- pkts[i].options = XDP_PKT_CONTD; +- pkts[i].valid = false; +- } +- +- /* Valid packet for synch */ +- pkts[2 * max_frags + 1].len = MIN_PKT_SIZE; +- pkts[2 * max_frags + 1].valid = true; +- +- pkt_stream_generate_custom(test, pkts, 2 * max_frags + 2); +- ret = testapp_validate_traffic(test); +- +- free(pkts); +- return ret; +-} +- +-static int xsk_load_xdp_programs(struct ifobject *ifobj) +-{ +- ifobj->xdp_progs = xsk_xdp_progs__open_and_load(); +- if (libbpf_get_error(ifobj->xdp_progs)) +- return libbpf_get_error(ifobj->xdp_progs); +- +- return 0; +-} +- +-static void xsk_unload_xdp_programs(struct ifobject *ifobj) +-{ +- xsk_xdp_progs__destroy(ifobj->xdp_progs); +-} +- +-/* Simple test */ +-static bool hugepages_present(void) +-{ +- size_t mmap_sz = 2 * DEFAULT_UMEM_BUFFERS * XSK_UMEM__DEFAULT_FRAME_SIZE; +- void *bufs; +- +- bufs = mmap(NULL, mmap_sz, PROT_READ | PROT_WRITE, +- MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB, -1, MAP_HUGE_2MB); +- if (bufs == MAP_FAILED) +- return false; +- +- mmap_sz = ceil_u64(mmap_sz, HUGEPAGE_SIZE) * HUGEPAGE_SIZE; +- munmap(bufs, mmap_sz); +- return true; +-} +- +-static void init_iface(struct ifobject *ifobj, thread_func_t func_ptr) +-{ +- LIBBPF_OPTS(bpf_xdp_query_opts, query_opts); +- int err; +- +- ifobj->func_ptr = func_ptr; +- +- err = xsk_load_xdp_programs(ifobj); +- if (err) { +- ksft_print_msg("Error loading XDP program\n"); +- exit_with_error(err); +- } +- +- if (hugepages_present()) +- ifobj->unaligned_supp = true; +- +- err = bpf_xdp_query(ifobj->ifindex, XDP_FLAGS_DRV_MODE, &query_opts); +- if (err) { +- ksft_print_msg("Error querying XDP capabilities\n"); +- exit_with_error(-err); +- } +- if (query_opts.feature_flags & NETDEV_XDP_ACT_RX_SG) +- ifobj->multi_buff_supp = true; +- if (query_opts.feature_flags & NETDEV_XDP_ACT_XSK_ZEROCOPY) { +- if (query_opts.xdp_zc_max_segs > 1) { +- ifobj->multi_buff_zc_supp = true; +- ifobj->xdp_zc_max_segs = query_opts.xdp_zc_max_segs; +- } else { +- ifobj->xdp_zc_max_segs = 0; +- } +- } +-} +- +-static int testapp_send_receive(struct test_spec *test) +-{ +- return testapp_validate_traffic(test); +-} +- +-static int testapp_send_receive_2k_frame(struct test_spec *test) +-{ +- test->ifobj_tx->umem->frame_size = 2048; +- test->ifobj_rx->umem->frame_size = 2048; +- pkt_stream_replace(test, DEFAULT_PKT_CNT, MIN_PKT_SIZE); +- return testapp_validate_traffic(test); +-} +- +-static int testapp_poll_rx(struct test_spec *test) +-{ +- test->ifobj_rx->use_poll = true; +- return testapp_validate_traffic(test); +-} +- +-static int testapp_poll_tx(struct test_spec *test) +-{ +- test->ifobj_tx->use_poll = true; +- return testapp_validate_traffic(test); +-} +- +-static int testapp_aligned_inv_desc(struct test_spec *test) +-{ +- return testapp_invalid_desc(test); +-} +- +-static int testapp_aligned_inv_desc_2k_frame(struct test_spec *test) +-{ +- test->ifobj_tx->umem->frame_size = 2048; +- test->ifobj_rx->umem->frame_size = 2048; +- return testapp_invalid_desc(test); +-} +- +-static int testapp_unaligned_inv_desc(struct test_spec *test) +-{ +- test->ifobj_tx->umem->unaligned_mode = true; +- test->ifobj_rx->umem->unaligned_mode = true; +- return testapp_invalid_desc(test); +-} +- +-static int testapp_unaligned_inv_desc_4001_frame(struct test_spec *test) +-{ +- u64 page_size, umem_size; +- +- /* Odd frame size so the UMEM doesn't end near a page boundary. */ +- test->ifobj_tx->umem->frame_size = 4001; +- test->ifobj_rx->umem->frame_size = 4001; +- test->ifobj_tx->umem->unaligned_mode = true; +- test->ifobj_rx->umem->unaligned_mode = true; +- /* This test exists to test descriptors that staddle the end of +- * the UMEM but not a page. +- */ +- page_size = sysconf(_SC_PAGESIZE); +- umem_size = test->ifobj_tx->umem->num_frames * test->ifobj_tx->umem->frame_size; +- assert(umem_size % page_size > MIN_PKT_SIZE); +- assert(umem_size % page_size < page_size - MIN_PKT_SIZE); +- +- return testapp_invalid_desc(test); +-} +- +-static int testapp_aligned_inv_desc_mb(struct test_spec *test) +-{ +- return testapp_invalid_desc_mb(test); +-} +- +-static int testapp_unaligned_inv_desc_mb(struct test_spec *test) +-{ +- test->ifobj_tx->umem->unaligned_mode = true; +- test->ifobj_rx->umem->unaligned_mode = true; +- return testapp_invalid_desc_mb(test); +-} +- +-static int testapp_xdp_metadata(struct test_spec *test) +-{ +- return testapp_xdp_metadata_copy(test); +-} +- +-static int testapp_xdp_metadata_mb(struct test_spec *test) +-{ +- test->mtu = MAX_ETH_JUMBO_SIZE; +- return testapp_xdp_metadata_copy(test); +-} +- +-static int testapp_hw_sw_min_ring_size(struct test_spec *test) +-{ +- int ret; +- +- test->set_ring = true; +- test->total_steps = 2; +- test->ifobj_tx->ring.tx_pending = DEFAULT_BATCH_SIZE; +- test->ifobj_tx->ring.rx_pending = DEFAULT_BATCH_SIZE * 2; +- test->ifobj_tx->xsk->batch_size = 1; +- test->ifobj_rx->xsk->batch_size = 1; +- ret = testapp_validate_traffic(test); +- if (ret) +- return ret; +- +- /* Set batch size to hw_ring_size - 1 */ +- test->ifobj_tx->xsk->batch_size = DEFAULT_BATCH_SIZE - 1; +- test->ifobj_rx->xsk->batch_size = DEFAULT_BATCH_SIZE - 1; +- return testapp_validate_traffic(test); +-} +- +-static int testapp_hw_sw_max_ring_size(struct test_spec *test) +-{ +- u32 max_descs = XSK_RING_PROD__DEFAULT_NUM_DESCS * 4; +- int ret; +- +- test->set_ring = true; +- test->total_steps = 2; +- test->ifobj_tx->ring.tx_pending = test->ifobj_tx->ring.tx_max_pending; +- test->ifobj_tx->ring.rx_pending = test->ifobj_tx->ring.rx_max_pending; +- test->ifobj_rx->umem->num_frames = max_descs; +- test->ifobj_rx->umem->fill_size = max_descs; +- test->ifobj_rx->umem->comp_size = max_descs; +- test->ifobj_tx->xsk->batch_size = XSK_RING_PROD__DEFAULT_NUM_DESCS; +- test->ifobj_rx->xsk->batch_size = XSK_RING_PROD__DEFAULT_NUM_DESCS; +- +- ret = testapp_validate_traffic(test); +- if (ret) +- return ret; +- +- /* Set batch_size to 8152 for testing, as the ice HW ignores the 3 lowest bits when +- * updating the Rx HW tail register. +- */ +- test->ifobj_tx->xsk->batch_size = test->ifobj_tx->ring.tx_max_pending - 8; +- test->ifobj_rx->xsk->batch_size = test->ifobj_tx->ring.tx_max_pending - 8; +- pkt_stream_replace(test, max_descs, MIN_PKT_SIZE); +- return testapp_validate_traffic(test); +-} +- +-static int testapp_xdp_adjust_tail(struct test_spec *test, int adjust_value) +-{ +- struct xsk_xdp_progs *skel_rx = test->ifobj_rx->xdp_progs; +- struct xsk_xdp_progs *skel_tx = test->ifobj_tx->xdp_progs; +- +- test_spec_set_xdp_prog(test, skel_rx->progs.xsk_xdp_adjust_tail, +- skel_tx->progs.xsk_xdp_adjust_tail, +- skel_rx->maps.xsk, skel_tx->maps.xsk); +- +- skel_rx->bss->adjust_value = adjust_value; +- +- return testapp_validate_traffic(test); +-} +- +-static int testapp_adjust_tail(struct test_spec *test, u32 value, u32 pkt_len) +-{ +- int ret; +- +- test->adjust_tail_support = true; +- test->adjust_tail = true; +- test->total_steps = 1; +- +- pkt_stream_replace_ifobject(test->ifobj_tx, DEFAULT_BATCH_SIZE, pkt_len); +- pkt_stream_replace_ifobject(test->ifobj_rx, DEFAULT_BATCH_SIZE, pkt_len + value); +- +- ret = testapp_xdp_adjust_tail(test, value); +- if (ret) +- return ret; +- +- if (!test->adjust_tail_support) { +- ksft_test_result_skip("%s %sResize pkt with bpf_xdp_adjust_tail() not supported\n", +- mode_string(test), busy_poll_string(test)); +- return TEST_SKIP; +- } +- +- return 0; +-} +- +-static int testapp_adjust_tail_shrink(struct test_spec *test) +-{ +- /* Shrink by 4 bytes for testing purpose */ +- return testapp_adjust_tail(test, -4, MIN_PKT_SIZE * 2); +-} +- +-static int testapp_adjust_tail_shrink_mb(struct test_spec *test) +-{ +- test->mtu = MAX_ETH_JUMBO_SIZE; +- /* Shrink by the frag size */ +- return testapp_adjust_tail(test, -XSK_UMEM__MAX_FRAME_SIZE, XSK_UMEM__LARGE_FRAME_SIZE * 2); +-} +- +-static int testapp_adjust_tail_grow(struct test_spec *test) +-{ +- /* Grow by 4 bytes for testing purpose */ +- return testapp_adjust_tail(test, 4, MIN_PKT_SIZE * 2); +-} +- +-static int testapp_adjust_tail_grow_mb(struct test_spec *test) +-{ +- test->mtu = MAX_ETH_JUMBO_SIZE; +- /* Grow by (frag_size - last_frag_Size) - 1 to stay inside the last fragment */ +- return testapp_adjust_tail(test, (XSK_UMEM__MAX_FRAME_SIZE / 2) - 1, +- XSK_UMEM__LARGE_FRAME_SIZE * 2); +-} +- +-static int testapp_tx_queue_consumer(struct test_spec *test) +-{ +- int nr_packets; +- +- if (test->mode == TEST_MODE_ZC) { +- ksft_test_result_skip("Can not run TX_QUEUE_CONSUMER test for ZC mode\n"); +- return TEST_SKIP; +- } +- +- nr_packets = MAX_TX_BUDGET_DEFAULT + 1; +- pkt_stream_replace(test, nr_packets, MIN_PKT_SIZE); +- test->ifobj_tx->xsk->batch_size = nr_packets; +- test->ifobj_tx->xsk->check_consumer = true; +- +- return testapp_validate_traffic(test); +-} +- +-static void run_pkt_test(struct test_spec *test) +-{ +- int ret; +- +- ret = test->test_func(test); +- +- if (ret == TEST_PASS) +- ksft_test_result_pass("PASS: %s %s%s\n", mode_string(test), busy_poll_string(test), +- test->name); +- pkt_stream_restore_default(test); +-} +- +-static struct ifobject *ifobject_create(void) +-{ +- struct ifobject *ifobj; +- +- ifobj = calloc(1, sizeof(struct ifobject)); +- if (!ifobj) +- return NULL; +- +- ifobj->xsk_arr = calloc(MAX_SOCKETS, sizeof(*ifobj->xsk_arr)); +- if (!ifobj->xsk_arr) +- goto out_xsk_arr; +- +- ifobj->umem = calloc(1, sizeof(*ifobj->umem)); +- if (!ifobj->umem) +- goto out_umem; +- +- return ifobj; +- +-out_umem: +- free(ifobj->xsk_arr); +-out_xsk_arr: +- free(ifobj); +- return NULL; +-} +- +-static void ifobject_delete(struct ifobject *ifobj) +-{ +- free(ifobj->umem); +- free(ifobj->xsk_arr); +- free(ifobj); +-} +- +-static bool is_xdp_supported(int ifindex) +-{ +- int flags = XDP_FLAGS_DRV_MODE; +- +- LIBBPF_OPTS(bpf_link_create_opts, opts, .flags = flags); +- struct bpf_insn insns[2] = { +- BPF_MOV64_IMM(BPF_REG_0, XDP_PASS), +- BPF_EXIT_INSN() +- }; +- int prog_fd, insn_cnt = ARRAY_SIZE(insns); +- int err; +- +- prog_fd = bpf_prog_load(BPF_PROG_TYPE_XDP, NULL, "GPL", insns, insn_cnt, NULL); +- if (prog_fd < 0) +- return false; +- +- err = bpf_xdp_attach(ifindex, prog_fd, flags, NULL); +- if (err) { +- close(prog_fd); +- return false; +- } +- +- bpf_xdp_detach(ifindex, flags, NULL); +- close(prog_fd); +- +- return true; +-} +- +-static const struct test_spec tests[] = { +- {.name = "SEND_RECEIVE", .test_func = testapp_send_receive}, +- {.name = "SEND_RECEIVE_2K_FRAME", .test_func = testapp_send_receive_2k_frame}, +- {.name = "SEND_RECEIVE_SINGLE_PKT", .test_func = testapp_single_pkt}, +- {.name = "POLL_RX", .test_func = testapp_poll_rx}, +- {.name = "POLL_TX", .test_func = testapp_poll_tx}, +- {.name = "POLL_RXQ_FULL", .test_func = testapp_poll_rxq_tmout}, +- {.name = "POLL_TXQ_FULL", .test_func = testapp_poll_txq_tmout}, +- {.name = "SEND_RECEIVE_UNALIGNED", .test_func = testapp_send_receive_unaligned}, +- {.name = "ALIGNED_INV_DESC", .test_func = testapp_aligned_inv_desc}, +- {.name = "ALIGNED_INV_DESC_2K_FRAME_SIZE", .test_func = testapp_aligned_inv_desc_2k_frame}, +- {.name = "UNALIGNED_INV_DESC", .test_func = testapp_unaligned_inv_desc}, +- {.name = "UNALIGNED_INV_DESC_4001_FRAME_SIZE", +- .test_func = testapp_unaligned_inv_desc_4001_frame}, +- {.name = "UMEM_HEADROOM", .test_func = testapp_headroom}, +- {.name = "TEARDOWN", .test_func = testapp_teardown}, +- {.name = "BIDIRECTIONAL", .test_func = testapp_bidirectional}, +- {.name = "STAT_RX_DROPPED", .test_func = testapp_stats_rx_dropped}, +- {.name = "STAT_TX_INVALID", .test_func = testapp_stats_tx_invalid_descs}, +- {.name = "STAT_RX_FULL", .test_func = testapp_stats_rx_full}, +- {.name = "STAT_FILL_EMPTY", .test_func = testapp_stats_fill_empty}, +- {.name = "XDP_PROG_CLEANUP", .test_func = testapp_xdp_prog_cleanup}, +- {.name = "XDP_DROP_HALF", .test_func = testapp_xdp_drop}, +- {.name = "XDP_SHARED_UMEM", .test_func = testapp_xdp_shared_umem}, +- {.name = "XDP_METADATA_COPY", .test_func = testapp_xdp_metadata}, +- {.name = "XDP_METADATA_COPY_MULTI_BUFF", .test_func = testapp_xdp_metadata_mb}, +- {.name = "SEND_RECEIVE_9K_PACKETS", .test_func = testapp_send_receive_mb}, +- {.name = "SEND_RECEIVE_UNALIGNED_9K_PACKETS", +- .test_func = testapp_send_receive_unaligned_mb}, +- {.name = "ALIGNED_INV_DESC_MULTI_BUFF", .test_func = testapp_aligned_inv_desc_mb}, +- {.name = "UNALIGNED_INV_DESC_MULTI_BUFF", .test_func = testapp_unaligned_inv_desc_mb}, +- {.name = "TOO_MANY_FRAGS", .test_func = testapp_too_many_frags}, +- {.name = "HW_SW_MIN_RING_SIZE", .test_func = testapp_hw_sw_min_ring_size}, +- {.name = "HW_SW_MAX_RING_SIZE", .test_func = testapp_hw_sw_max_ring_size}, +- {.name = "XDP_ADJUST_TAIL_SHRINK", .test_func = testapp_adjust_tail_shrink}, +- {.name = "XDP_ADJUST_TAIL_SHRINK_MULTI_BUFF", .test_func = testapp_adjust_tail_shrink_mb}, +- {.name = "XDP_ADJUST_TAIL_GROW", .test_func = testapp_adjust_tail_grow}, +- {.name = "XDP_ADJUST_TAIL_GROW_MULTI_BUFF", .test_func = testapp_adjust_tail_grow_mb}, +- {.name = "TX_QUEUE_CONSUMER", .test_func = testapp_tx_queue_consumer}, +- }; +- + static void print_tests(void) + { + u32 i; +@@ -2833,7 +376,7 @@ int main(int argc, char **argv) + init_iface(ifobj_rx, worker_testapp_validate_rx); + init_iface(ifobj_tx, worker_testapp_validate_tx); + +- test_spec_init(&test, ifobj_tx, ifobj_rx, 0, &tests[0]); ++ test_init(&test, ifobj_tx, ifobj_rx, 0, &tests[0]); + tx_pkt_stream_default = pkt_stream_generate(DEFAULT_PKT_CNT, MIN_PKT_SIZE); + rx_pkt_stream_default = pkt_stream_generate(DEFAULT_PKT_CNT, MIN_PKT_SIZE); + if (!tx_pkt_stream_default || !rx_pkt_stream_default) +@@ -2868,7 +411,7 @@ int main(int argc, char **argv) + if (opt_run_test != RUN_ALL_TESTS && j != opt_run_test) + continue; + +- test_spec_init(&test, ifobj_tx, ifobj_rx, i, &tests[j]); ++ test_init(&test, ifobj_tx, ifobj_rx, i, &tests[j]); + run_pkt_test(&test); + usleep(USLEEP_MAX); + +diff --git a/tools/testing/selftests/bpf/xskxceiver.h b/tools/testing/selftests/bpf/xskxceiver.h +index 4df3a5d329acf..3ca518df23ada 100644 +--- a/tools/testing/selftests/bpf/xskxceiver.h ++++ b/tools/testing/selftests/bpf/xskxceiver.h +@@ -22,169 +22,13 @@ + #define PF_XDP AF_XDP + #endif + +-#ifndef SO_BUSY_POLL_BUDGET +-#define SO_BUSY_POLL_BUDGET 70 +-#endif +- +-#ifndef SO_PREFER_BUSY_POLL +-#define SO_PREFER_BUSY_POLL 69 +-#endif +- +-#define TEST_PASS 0 +-#define TEST_FAILURE -1 +-#define TEST_CONTINUE 1 +-#define TEST_SKIP 2 +-#define MAX_INTERFACES 2 +-#define MAX_INTERFACE_NAME_CHARS 16 +-#define MAX_TEST_NAME_SIZE 48 + #define MAX_TEARDOWN_ITER 10 +-#define PKT_HDR_SIZE (sizeof(struct ethhdr) + 2) /* Just to align the data in the packet */ +-#define MIN_PKT_SIZE 64 +-#define MAX_ETH_PKT_SIZE 1518 + #define MAX_ETH_JUMBO_SIZE 9000 +-#define USLEEP_MAX 10000 + #define SOCK_RECONF_CTR 10 +-#define DEFAULT_BATCH_SIZE 64 +-#define POLL_TMOUT 1000 +-#define THREAD_TMOUT 3 +-#define DEFAULT_PKT_CNT (4 * 1024) +-#define DEFAULT_UMEM_BUFFERS (DEFAULT_PKT_CNT / 4) + #define RX_FULL_RXQSIZE 32 + #define UMEM_HEADROOM_TEST_SIZE 128 + #define XSK_UMEM__INVALID_FRAME_SIZE (MAX_ETH_JUMBO_SIZE + 1) +-#define XSK_UMEM__LARGE_FRAME_SIZE (3 * 1024) +-#define XSK_UMEM__MAX_FRAME_SIZE (4 * 1024) +-#define XSK_DESC__INVALID_OPTION (0xffff) +-#define HUGEPAGE_SIZE (2 * 1024 * 1024) +-#define PKT_DUMP_NB_TO_PRINT 16 + #define RUN_ALL_TESTS UINT_MAX + #define NUM_MAC_ADDRESSES 4 + +-#define print_verbose(x...) do { if (opt_verbose) ksft_print_msg(x); } while (0) +- +-enum test_mode { +- TEST_MODE_SKB, +- TEST_MODE_DRV, +- TEST_MODE_ZC, +- TEST_MODE_ALL +-}; +- +-struct xsk_umem_info { +- struct xsk_ring_prod fq; +- struct xsk_ring_cons cq; +- struct xsk_umem *umem; +- u64 next_buffer; +- u32 num_frames; +- u32 frame_headroom; +- void *buffer; +- u32 frame_size; +- u32 base_addr; +- u32 fill_size; +- u32 comp_size; +- bool unaligned_mode; +-}; +- +-struct xsk_socket_info { +- struct xsk_ring_cons rx; +- struct xsk_ring_prod tx; +- struct xsk_umem_info *umem; +- struct xsk_socket *xsk; +- struct pkt_stream *pkt_stream; +- u32 outstanding_tx; +- u32 rxqsize; +- u32 batch_size; +- u8 dst_mac[ETH_ALEN]; +- u8 src_mac[ETH_ALEN]; +- bool check_consumer; +-}; +- +-struct pkt { +- int offset; +- u32 len; +- u32 pkt_nb; +- bool valid; +- u16 options; +-}; +- +-struct pkt_stream { +- u32 nb_pkts; +- u32 current_pkt_nb; +- struct pkt *pkts; +- u32 max_pkt_len; +- u32 nb_rx_pkts; +- u32 nb_valid_entries; +- bool verbatim; +-}; +- +-struct set_hw_ring { +- u32 default_tx; +- u32 default_rx; +-}; +- +-struct ifobject; +-struct test_spec; +-typedef int (*validation_func_t)(struct ifobject *ifobj); +-typedef void *(*thread_func_t)(void *arg); +-typedef int (*test_func_t)(struct test_spec *test); +- +-struct ifobject { +- char ifname[MAX_INTERFACE_NAME_CHARS]; +- struct xsk_socket_info *xsk; +- struct xsk_socket_info *xsk_arr; +- struct xsk_umem_info *umem; +- thread_func_t func_ptr; +- validation_func_t validation_func; +- struct xsk_xdp_progs *xdp_progs; +- struct bpf_map *xskmap; +- struct bpf_program *xdp_prog; +- struct ethtool_ringparam ring; +- struct set_hw_ring set_ring; +- enum test_mode mode; +- int ifindex; +- int mtu; +- u32 bind_flags; +- u32 xdp_zc_max_segs; +- bool tx_on; +- bool rx_on; +- bool use_poll; +- bool busy_poll; +- bool use_fill_ring; +- bool release_rx; +- bool shared_umem; +- bool use_metadata; +- bool unaligned_supp; +- bool multi_buff_supp; +- bool multi_buff_zc_supp; +- bool hw_ring_size_supp; +-}; +- +-struct test_spec { +- struct ifobject *ifobj_tx; +- struct ifobject *ifobj_rx; +- struct pkt_stream *tx_pkt_stream_default; +- struct pkt_stream *rx_pkt_stream_default; +- struct bpf_program *xdp_prog_rx; +- struct bpf_program *xdp_prog_tx; +- struct bpf_map *xskmap_rx; +- struct bpf_map *xskmap_tx; +- test_func_t test_func; +- int mtu; +- u16 total_steps; +- u16 current_step; +- u16 nb_sockets; +- bool fail; +- bool set_ring; +- bool adjust_tail; +- bool adjust_tail_support; +- enum test_mode mode; +- char name[MAX_TEST_NAME_SIZE]; +-}; +- +-pthread_barrier_t barr; +-pthread_mutex_t pacing_mutex = PTHREAD_MUTEX_INITIALIZER; +- +-int pkts_in_flight; +- +-static const u8 g_mac[ETH_ALEN] = {0x55, 0x44, 0x33, 0x22, 0x11, 0x00}; +- + #endif /* XSKXCEIVER_H_ */ +-- +2.51.0 + diff --git a/queue-6.18/selftests-bpf-veristat-fix-printing-order-in-output_.patch b/queue-6.18/selftests-bpf-veristat-fix-printing-order-in-output_.patch new file mode 100644 index 0000000000..f1b84d995b --- /dev/null +++ b/queue-6.18/selftests-bpf-veristat-fix-printing-order-in-output_.patch @@ -0,0 +1,46 @@ +From c03a1db655878ae282d476afea24913ae44444df Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 31 Dec 2025 14:10:50 -0800 +Subject: selftests/bpf: veristat: fix printing order in output_stats() + +From: Puranjay Mohan + +[ Upstream commit c286e7e9d1f1f3d90ad11c37e896f582b02d19c4 ] + +The order of the variables in the printf() doesn't match the text and +therefore veristat prints something like this: + +Done. Processed 24 files, 0 programs. Skipped 62 files, 0 programs. + +When it should print: + +Done. Processed 24 files, 62 programs. Skipped 0 files, 0 programs. + +Fix the order of variables in the printf() call. + +Fixes: 518fee8bfaf2 ("selftests/bpf: make veristat skip non-BPF and failing-to-open BPF objects") +Tested-by: Eduard Zingerman +Signed-off-by: Puranjay Mohan +Link: https://lore.kernel.org/r/20251231221052.759396-1-puranjay@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/bpf/veristat.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/testing/selftests/bpf/veristat.c b/tools/testing/selftests/bpf/veristat.c +index e962f133250c7..1be1e353d40a7 100644 +--- a/tools/testing/selftests/bpf/veristat.c ++++ b/tools/testing/selftests/bpf/veristat.c +@@ -2580,7 +2580,7 @@ static void output_stats(const struct verif_stats *s, enum resfmt fmt, bool last + if (last && fmt == RESFMT_TABLE) { + output_header_underlines(); + printf("Done. Processed %d files, %d programs. Skipped %d files, %d programs.\n", +- env.files_processed, env.files_skipped, env.progs_processed, env.progs_skipped); ++ env.files_processed, env.progs_processed, env.files_skipped, env.progs_skipped); + } + } + +-- +2.51.0 + diff --git a/queue-6.18/selftests-mm-fix-faulting-in-code-in-pagemap_ioctl-t.patch b/queue-6.18/selftests-mm-fix-faulting-in-code-in-pagemap_ioctl-t.patch new file mode 100644 index 0000000000..40b2c5073c --- /dev/null +++ b/queue-6.18/selftests-mm-fix-faulting-in-code-in-pagemap_ioctl-t.patch @@ -0,0 +1,80 @@ +From cf3c9df2152c243b7a0ca14a5be3fb58ae08ae64 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 17:02:22 +0000 +Subject: selftests/mm: fix faulting-in code in pagemap_ioctl test + +From: Kevin Brodsky + +[ Upstream commit 7e938f00b00319510ae097e20b7487dfa578d53f ] + +One of the pagemap_ioctl tests attempts to fault in pages by memcpy()'ing +them to an unused buffer. This probably worked originally, but since +commit 46036188ea1f ("selftests/mm: build with -O2") the compiler is free +to optimise away that unused buffer and the memcpy() with it. As a result +there might not be any resident page in the mapping and the test may fail. + +We don't need to copy all that memory anyway. Just fault in every page. + +While at it also make sure to compute the number of pages once using +simple integer arithmetic instead of ceilf() and implicit conversions. + +Link: https://lkml.kernel.org/r/20260122170224.4056513-8-kevin.brodsky@arm.com +Fixes: 46036188ea1f ("selftests/mm: build with -O2") +Signed-off-by: Kevin Brodsky +Acked-by: David Hildenbrand (Red Hat) +Reviewed-by: Dev Jain +Reviewed-by: Muhammad Usama Anjum +Cc: Jason Gunthorpe +Cc: John Hubbard +Cc: Lorenzo Stoakes +Cc: Mark Brown +Cc: Paolo Abeni +Cc: Ryan Roberts +Cc: SeongJae Park +Cc: Shuah Khan +Cc: wang lian +Cc: Yunsheng Lin +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/mm/pagemap_ioctl.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/tools/testing/selftests/mm/pagemap_ioctl.c b/tools/testing/selftests/mm/pagemap_ioctl.c +index 4fc8e578ec7c3..8978ab0b45a7a 100644 +--- a/tools/testing/selftests/mm/pagemap_ioctl.c ++++ b/tools/testing/selftests/mm/pagemap_ioctl.c +@@ -1052,11 +1052,10 @@ static void test_simple(void) + int sanity_tests(void) + { + unsigned long long mem_size, vec_size; +- long ret, fd, i, buf_size; ++ long ret, fd, i, buf_size, nr_pages; + struct page_region *vec; + char *mem, *fmem; + struct stat sbuf; +- char *tmp_buf; + + /* 1. wrong operation */ + mem_size = 10 * page_size; +@@ -1167,14 +1166,14 @@ int sanity_tests(void) + if (fmem == MAP_FAILED) + ksft_exit_fail_msg("error nomem %d %s\n", errno, strerror(errno)); + +- tmp_buf = malloc(sbuf.st_size); +- memcpy(tmp_buf, fmem, sbuf.st_size); ++ nr_pages = (sbuf.st_size + page_size - 1) / page_size; ++ force_read_pages(fmem, nr_pages, page_size); + + ret = pagemap_ioctl(fmem, sbuf.st_size, vec, vec_size, 0, 0, + 0, PAGEMAP_NON_WRITTEN_BITS, 0, PAGEMAP_NON_WRITTEN_BITS); + + ksft_test_result(ret >= 0 && vec[0].start == (uintptr_t)fmem && +- LEN(vec[0]) == ceilf((float)sbuf.st_size/page_size) && ++ LEN(vec[0]) == nr_pages && + (vec[0].categories & PAGE_IS_FILE), + "%s Memory mapped file\n", __func__); + +-- +2.51.0 + diff --git a/queue-6.18/selftests-mm-fix-usage-of-force_read-in-cow-tests.patch b/queue-6.18/selftests-mm-fix-usage-of-force_read-in-cow-tests.patch new file mode 100644 index 0000000000..43d72d5599 --- /dev/null +++ b/queue-6.18/selftests-mm-fix-usage-of-force_read-in-cow-tests.patch @@ -0,0 +1,96 @@ +From 841bb05d7ae2a68961bb6c6b81b40ef7cb6081b0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 17:02:19 +0000 +Subject: selftests/mm: fix usage of FORCE_READ() in cow tests + +From: Kevin Brodsky + +[ Upstream commit bce1dabd310e87fefe0645fec9ba98b84d37e418 ] + +Commit 5bbc2b785e63 ("selftests/mm: fix FORCE_READ to read input value +correctly") modified FORCE_READ() to take a value instead of a pointer. +It also changed most of the call sites accordingly, but missed many of +them in cow.c. In those cases, we ended up with the pointer itself being +read, not the memory it points to. + +No failure occurred as a result, so it looks like the tests work just fine +without faulting in. However, the huge_zeropage tests explicitly check +that pages are populated, so those became skipped. + +Convert all the remaining FORCE_READ() to fault in the mapped page, as was +originally intended. This allows the huge_zeropage tests to run again (3 +tests in total). + +Link: https://lkml.kernel.org/r/20260122170224.4056513-5-kevin.brodsky@arm.com +Fixes: 5bbc2b785e63 ("selftests/mm: fix FORCE_READ to read input value correctly") +Signed-off-by: Kevin Brodsky +Acked-by: SeongJae Park +Reviewed-by: wang lian +Acked-by: David Hildenbrand (Red Hat) +Reviewed-by: Dev Jain +Cc: Jason Gunthorpe +Cc: John Hubbard +Cc: Lorenzo Stoakes +Cc: Mark Brown +Cc: Paolo Abeni +Cc: Ryan Roberts +Cc: Shuah Khan +Cc: Usama Anjum +Cc: Yunsheng Lin +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/mm/cow.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/tools/testing/selftests/mm/cow.c b/tools/testing/selftests/mm/cow.c +index 6560c26f47d1f..0df61422467da 100644 +--- a/tools/testing/selftests/mm/cow.c ++++ b/tools/testing/selftests/mm/cow.c +@@ -1612,8 +1612,8 @@ static void run_with_huge_zeropage(non_anon_test_fn fn, const char *desc) + * the first sub-page and test if we get another sub-page populated + * automatically. + */ +- FORCE_READ(mem); +- FORCE_READ(smem); ++ FORCE_READ(*mem); ++ FORCE_READ(*smem); + if (!pagemap_is_populated(pagemap_fd, mem + pagesize) || + !pagemap_is_populated(pagemap_fd, smem + pagesize)) { + ksft_test_result_skip("Did not get THPs populated\n"); +@@ -1663,8 +1663,8 @@ static void run_with_memfd(non_anon_test_fn fn, const char *desc) + } + + /* Fault the page in. */ +- FORCE_READ(mem); +- FORCE_READ(smem); ++ FORCE_READ(*mem); ++ FORCE_READ(*smem); + + fn(mem, smem, pagesize); + munmap: +@@ -1719,8 +1719,8 @@ static void run_with_tmpfile(non_anon_test_fn fn, const char *desc) + } + + /* Fault the page in. */ +- FORCE_READ(mem); +- FORCE_READ(smem); ++ FORCE_READ(*mem); ++ FORCE_READ(*smem); + + fn(mem, smem, pagesize); + munmap: +@@ -1773,8 +1773,8 @@ static void run_with_memfd_hugetlb(non_anon_test_fn fn, const char *desc, + } + + /* Fault the page in. */ +- FORCE_READ(mem); +- FORCE_READ(smem); ++ FORCE_READ(*mem); ++ FORCE_READ(*smem); + + fn(mem, smem, hugetlbsize); + munmap: +-- +2.51.0 + diff --git a/queue-6.18/selftests-resctrl-fix-a-division-by-zero-error-on-hy.patch b/queue-6.18/selftests-resctrl-fix-a-division-by-zero-error-on-hy.patch new file mode 100644 index 0000000000..6b046a4d1e --- /dev/null +++ b/queue-6.18/selftests-resctrl-fix-a-division-by-zero-error-on-hy.patch @@ -0,0 +1,67 @@ +From ba2b5d29afde43ceb14d8642905e55e10c09a489 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 17 Dec 2025 11:04:53 +0800 +Subject: selftests/resctrl: Fix a division by zero error on Hygon + +From: Xiaochen Shen + +[ Upstream commit 671ef08d9455f5754d1fc96f5a14e357d6b80936 ] + +Change to adjust effective L3 cache size with SNC enabled change +introduced the snc_nodes_per_l3_cache() function to detect the Intel +Sub-NUMA Clustering (SNC) feature by comparing #CPUs in node0 with #CPUs +sharing LLC with CPU0. The function was designed to return: + (1) >1: SNC mode is enabled. + (2) 1: SNC mode is not enabled or not supported. + +However, on certain Hygon CPUs, #CPUs sharing LLC with CPU0 is actually +less than #CPUs in node0. This results in snc_nodes_per_l3_cache() +returning 0 (calculated as cache_cpus / node_cpus). + +This leads to a division by zero error in get_cache_size(): + *cache_size /= snc_nodes_per_l3_cache(); + +Causing the resctrl selftest to fail with: + "Floating point exception (core dumped)" + +Fix the issue by ensuring snc_nodes_per_l3_cache() returns 1 when SNC +mode is not supported on the platform. + +Updated commit log to fix commit has issues: +Shuah Khan + +Link: https://lore.kernel.org/r/20251217030456.3834956-2-shenxiaochen@open-hieco.net +Fixes: a1cd99e700ec ("selftests/resctrl: Adjust effective L3 cache size with SNC enabled") +Signed-off-by: Xiaochen Shen +Reviewed-by: Reinette Chatre +Reviewed-by: Fenghua Yu +Signed-off-by: Shuah Khan +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/resctrl/resctrlfs.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/tools/testing/selftests/resctrl/resctrlfs.c b/tools/testing/selftests/resctrl/resctrlfs.c +index 195f04c4d1586..b9c1bfb6cc029 100644 +--- a/tools/testing/selftests/resctrl/resctrlfs.c ++++ b/tools/testing/selftests/resctrl/resctrlfs.c +@@ -243,6 +243,16 @@ int snc_nodes_per_l3_cache(void) + } + snc_mode = cache_cpus / node_cpus; + ++ /* ++ * On some platforms (e.g. Hygon), ++ * cache_cpus < node_cpus, the calculated snc_mode is 0. ++ * ++ * Set snc_mode = 1 to indicate that SNC mode is not ++ * supported on the platform. ++ */ ++ if (!snc_mode) ++ snc_mode = 1; ++ + if (snc_mode > 1) + ksft_print_msg("SNC-%d mode discovered.\n", snc_mode); + } +-- +2.51.0 + diff --git a/queue-6.18/selftests-xsk-fix-number-of-tx-frags-in-invalid-pack.patch b/queue-6.18/selftests-xsk-fix-number-of-tx-frags-in-invalid-pack.patch new file mode 100644 index 0000000000..2a8bdfb51d --- /dev/null +++ b/queue-6.18/selftests-xsk-fix-number-of-tx-frags-in-invalid-pack.patch @@ -0,0 +1,59 @@ +From ee3c64b4211da2ea6acee10639f13e67b6ca2fb7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 16:50:58 +0100 +Subject: selftests/xsk: fix number of Tx frags in invalid packet + +From: Larysa Zaremba + +[ Upstream commit 88af9fefed412e4bea9a1a771cbe6fe347fa3507 ] + +The issue occurs in TOO_MANY_FRAGS test case when xdp_zc_max_segs is set to +an odd number. + +TOO_MANY_FRAGS test case contains an invalid packet consisting of +(xdp_zc_max_segs) frags. Every frag, even the last one has XDP_PKT_CONTD +flag set. This packet is expected to be dropped. After that, there is a +valid linear packet, which is expected to be received back. + +Once (xdp_zc_max_segs) is an odd number, the last packet cannot be +received, if packet forwarding between Rx and Tx interfaces relies on +the ethernet header, e.g. checks for ETH_P_LOOPBACK. Packet is malformed, +if all traffic is looped. + +Turns out, sending function processes multiple invalid frags as if they +were in 2-frag packets. So once the invalid mbuf packet contains an odd +number of those, the valid packet after gets paired with the previous +invalid descriptor, and hence does not get an ethernet header generated, so +it is either dropped or malformed. + +Make invalid packets in verbatim mode always have only a single frag. For +such packets, number of frags is otherwise meaningless, as descriptor flags +are pre-configured in verbatim mode and packet data is not generated for +invalid descriptors. + +Fixes: 697604492b64 ("selftests/xsk: add invalid descriptor test for multi-buffer") +Reviewed-by: Aleksandr Loktionov +Signed-off-by: Larysa Zaremba +Link: https://lore.kernel.org/r/20260203155103.2305816-3-larysa.zaremba@intel.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/bpf/test_xsk.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/testing/selftests/bpf/test_xsk.c b/tools/testing/selftests/bpf/test_xsk.c +index b52f597ea9bd2..55d318c5c5e59 100644 +--- a/tools/testing/selftests/bpf/test_xsk.c ++++ b/tools/testing/selftests/bpf/test_xsk.c +@@ -431,7 +431,7 @@ static u32 pkt_nb_frags(u32 frame_size, struct pkt_stream *pkt_stream, struct pk + } + + /* Search for the end of the packet in verbatim mode */ +- if (!pkt_continues(pkt->options)) ++ if (!pkt_continues(pkt->options) || !pkt->valid) + return nb_frags; + + next_frag = pkt_stream->current_pkt_nb; +-- +2.51.0 + diff --git a/queue-6.18/selftests-xsk-properly-handle-batch-ending-in-the-mi.patch b/queue-6.18/selftests-xsk-properly-handle-batch-ending-in-the-mi.patch new file mode 100644 index 0000000000..fd0d3d1f53 --- /dev/null +++ b/queue-6.18/selftests-xsk-properly-handle-batch-ending-in-the-mi.patch @@ -0,0 +1,43 @@ +From 535dd4a7ea60a27f03551eff59f64488ce539834 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 16:50:57 +0100 +Subject: selftests/xsk: properly handle batch ending in the middle of a packet + +From: Larysa Zaremba + +[ Upstream commit 42e41b2a0afa04ca49ee2725aadf90ccb058ed28 ] + +Referenced commit reduced the scope of the variable pkt, so now it has to +be reinitialized via pkt_stream_get_next_rx_pkt(), which also increments +some counters. When the packet is interrupted by the batch ending, pkt +stream therefore proceeds to the next packet, while xsk ring still contains +the previous one, this results in a pkt_nb mismatch. + +Decrement the affected counters when packet is interrupted. + +Fixes: 8913e653e9b8 ("selftests/xsk: Iterate over all the sockets in the receive pkts function") +Reviewed-by: Aleksandr Loktionov +Signed-off-by: Larysa Zaremba +Link: https://lore.kernel.org/r/20260203155103.2305816-2-larysa.zaremba@intel.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/bpf/test_xsk.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/tools/testing/selftests/bpf/test_xsk.c b/tools/testing/selftests/bpf/test_xsk.c +index 02250f29f9946..b52f597ea9bd2 100644 +--- a/tools/testing/selftests/bpf/test_xsk.c ++++ b/tools/testing/selftests/bpf/test_xsk.c +@@ -1027,6 +1027,8 @@ static int __receive_pkts(struct test_spec *test, struct xsk_socket_info *xsk) + xsk_ring_prod__cancel(&umem->fq, nb_frags); + } + frags_processed -= nb_frags; ++ pkt_stream_cancel(pkt_stream); ++ pkts_sent--; + } + + if (ifobj->use_fill_ring) +-- +2.51.0 + diff --git a/queue-6.18/serial-caif-fix-use-after-free-in-caif_serial-ldisc_.patch b/queue-6.18/serial-caif-fix-use-after-free-in-caif_serial-ldisc_.patch new file mode 100644 index 0000000000..0c79238c55 --- /dev/null +++ b/queue-6.18/serial-caif-fix-use-after-free-in-caif_serial-ldisc_.patch @@ -0,0 +1,152 @@ +From 665db2b9c36ecc234096fee8c3a728ffaafa672f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 15:44:44 +0800 +Subject: serial: caif: fix use-after-free in caif_serial ldisc_close() + +From: Jiayuan Chen + +[ Upstream commit 308e7e4d0a846359685f40aade023aee7b27284c ] + +There is a use-after-free bug in caif_serial where handle_tx() may +access ser->tty after the tty has been freed. + +The race condition occurs between ldisc_close() and packet transmission: + + CPU 0 (close) CPU 1 (xmit) + ------------- ------------ + ldisc_close() + tty_kref_put(ser->tty) + [tty may be freed here] + <-- race window --> + caif_xmit() + handle_tx() + tty = ser->tty // dangling ptr + tty->ops->write() // UAF! + schedule_work() + ser_release() + unregister_netdevice() + +The root cause is that tty_kref_put() is called in ldisc_close() while +the network device is still active and can receive packets. + +Since ser and tty have a 1:1 binding relationship with consistent +lifecycles (ser is allocated in ldisc_open and freed in ser_release +via unregister_netdevice, and each ser binds exactly one tty), we can +safely defer the tty reference release to ser_release() where the +network device is unregistered. + +Fix this by moving tty_kref_put() from ldisc_close() to ser_release(), +after unregister_netdevice(). This ensures the tty reference is held +as long as the network device exists, preventing the UAF. + +Note: We save ser->tty before unregister_netdevice() because ser is +embedded in netdev's private data and will be freed along with netdev +(needs_free_netdev = true). + +How to reproduce: Add mdelay(500) at the beginning of ldisc_close() +to widen the race window, then run the reproducer program [1]. + +Note: There is a separate deadloop issue in handle_tx() when using +PORT_UNKNOWN serial ports (e.g., /dev/ttyS3 in QEMU without proper +serial backend). This deadloop exists even without this patch, +and is likely caused by inconsistency between uart_write_room() and +uart_write() in serial core. It has been addressed in a separate +patch [2]. + +KASAN report: + +================================================================== +BUG: KASAN: slab-use-after-free in handle_tx+0x5d1/0x620 +Read of size 1 at addr ffff8881131e1490 by task caif_uaf_trigge/9929 + +Call Trace: + + dump_stack_lvl+0x10e/0x1f0 + print_report+0xd0/0x630 + kasan_report+0xe4/0x120 + handle_tx+0x5d1/0x620 + dev_hard_start_xmit+0x9d/0x6c0 + __dev_queue_xmit+0x6e2/0x4410 + packet_xmit+0x243/0x360 + packet_sendmsg+0x26cf/0x5500 + __sys_sendto+0x4a3/0x520 + __x64_sys_sendto+0xe0/0x1c0 + do_syscall_64+0xc9/0xf80 + entry_SYSCALL_64_after_hwframe+0x77/0x7f +RIP: 0033:0x7f615df2c0d7 + +Allocated by task 9930: + +Freed by task 64: + +Last potentially related work creation: + +The buggy address belongs to the object at ffff8881131e1000 + which belongs to the cache kmalloc-cg-2k of size 2048 +The buggy address is located 1168 bytes inside of + freed 2048-byte region [ffff8881131e1000, ffff8881131e1800) + +The buggy address belongs to the physical page: +page_owner tracks the page as allocated +page last free pid 9778 tgid 9778 stack trace: + +Memory state around the buggy address: + ffff8881131e1380: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb + ffff8881131e1400: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb +>ffff8881131e1480: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb + ^ + ffff8881131e1500: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb + ffff8881131e1580: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb +================================================================== +[1]: https://gist.github.com/mrpre/f683f244544f7b11e7fa87df9e6c2eeb +[2]: https://lore.kernel.org/linux-serial/20260204074327.226165-1-jiayuan.chen@linux.dev/T/#u + +Reported-by: syzbot+827272712bd6d12c79a4@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/000000000000a4a7550611e234f5@google.com/T/ +Fixes: 56e0ef527b18 ("drivers/net: caif: fix wrong rtnl_is_locked() usage") +Reviewed-by: Greg Kroah-Hartman +Signed-off-by: Jiayuan Chen +Reviewed-by: Jijie Shao +Link: https://patch.msgid.link/20260206074450.154267-1-jiayuan.chen@linux.dev +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/caif/caif_serial.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c +index c398ac42eae90..b90890030751f 100644 +--- a/drivers/net/caif/caif_serial.c ++++ b/drivers/net/caif/caif_serial.c +@@ -284,6 +284,7 @@ static void ser_release(struct work_struct *work) + { + struct list_head list; + struct ser_device *ser, *tmp; ++ struct tty_struct *tty; + + spin_lock(&ser_lock); + list_replace_init(&ser_release_list, &list); +@@ -292,9 +293,11 @@ static void ser_release(struct work_struct *work) + if (!list_empty(&list)) { + rtnl_lock(); + list_for_each_entry_safe(ser, tmp, &list, node) { ++ tty = ser->tty; + dev_close(ser->dev); + unregister_netdevice(ser->dev); + debugfs_deinit(ser); ++ tty_kref_put(tty); + } + rtnl_unlock(); + } +@@ -355,8 +358,6 @@ static void ldisc_close(struct tty_struct *tty) + { + struct ser_device *ser = tty->disc_data; + +- tty_kref_put(ser->tty); +- + spin_lock(&ser_lock); + list_move(&ser->node, &ser_release_list); + spin_unlock(&ser_lock); +-- +2.51.0 + diff --git a/queue-6.18/serial-imx-change-serial_imx_console-to-bool.patch b/queue-6.18/serial-imx-change-serial_imx_console-to-bool.patch new file mode 100644 index 0000000000..e9ff2504f6 --- /dev/null +++ b/queue-6.18/serial-imx-change-serial_imx_console-to-bool.patch @@ -0,0 +1,50 @@ +From 04c0b1be2cacee83c91987f8d52aff59d9d86681 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 10 Jan 2026 15:26:40 -0800 +Subject: serial: imx: change SERIAL_IMX_CONSOLE to bool + +From: Randy Dunlap + +[ Upstream commit 79527d86ba91c2d9354832d19fd12b3baa66bd10 ] + +SERIAL_IMX_CONSOLE is a build option for the imx driver (SERIAL_IMX). +It does not build a separate console driver file, so it can't be built +as a module since it isn't built at all. + +Change the Kconfig symbol from tristate to bool and update the help +text accordingly. + +Fixes: 0db4f9b91c86 ("tty: serial: imx: enable imx serial console port as module") +Signed-off-by: Randy Dunlap +Link: https://patch.msgid.link/20260110232643.3533351-2-rdunlap@infradead.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/Kconfig | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig +index 282116765e648..0981288d19c2c 100644 +--- a/drivers/tty/serial/Kconfig ++++ b/drivers/tty/serial/Kconfig +@@ -486,14 +486,14 @@ config SERIAL_IMX + can enable its onboard serial port by enabling this option. + + config SERIAL_IMX_CONSOLE +- tristate "Console on IMX serial port" ++ bool "Console on IMX serial port" + depends on SERIAL_IMX + select SERIAL_CORE_CONSOLE + help + If you have enabled the serial port on the Freescale IMX +- CPU you can make it the console by answering Y/M to this option. ++ CPU you can make it the console by answering Y to this option. + +- Even if you say Y/M here, the currently visible virtual console ++ Even if you say Y here, the currently visible virtual console + (/dev/tty0) will still be used as the system console by default, but + you can alter that using a kernel command line option such as + "console=ttymxc0". (Try "man bootparam" or see the documentation of +-- +2.51.0 + diff --git a/queue-6.18/serial-sh_sci-improve-dma-support-prompt.patch b/queue-6.18/serial-sh_sci-improve-dma-support-prompt.patch new file mode 100644 index 0000000000..23c6f9caf5 --- /dev/null +++ b/queue-6.18/serial-sh_sci-improve-dma-support-prompt.patch @@ -0,0 +1,39 @@ +From 001c649051af5ea68d9f2ded1c848a59b9ad23c0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 10 Jan 2026 15:26:43 -0800 +Subject: serial: SH_SCI: improve "DMA support" prompt + +From: Randy Dunlap + +[ Upstream commit 93bb95a11238d66a4c9aa6eabf9774b073a5895c ] + +Having a prompt of "DMA support" suddenly appear during a +"make oldconfig" can be confusing. Add a little helpful text to +the prompt message. + +Fixes: 73a19e4c0301 ("serial: sh-sci: Add DMA support.") +Signed-off-by: Randy Dunlap +Reviewed-by: Geert Uytterhoeven +Link: https://patch.msgid.link/20260110232643.3533351-5-rdunlap@infradead.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig +index 0981288d19c2c..2b9c8b39d68f5 100644 +--- a/drivers/tty/serial/Kconfig ++++ b/drivers/tty/serial/Kconfig +@@ -671,7 +671,7 @@ config SERIAL_SH_SCI_EARLYCON + default ARCH_RENESAS + + config SERIAL_SH_SCI_DMA +- bool "DMA support" if EXPERT ++ bool "Support for DMA on SuperH SCI(F)" if EXPERT + depends on SERIAL_SH_SCI && DMA_ENGINE + default ARCH_RENESAS + +-- +2.51.0 + diff --git a/queue-6.18/series b/queue-6.18/series index 0b63edc9fd..fa8fd2f03a 100644 --- a/queue-6.18/series +++ b/queue-6.18/series @@ -1,2 +1,509 @@ rdma-siw-fix-potential-null-pointer-dereference-in-header-processing.patch rdma-umad-reject-negative-data_len-in-ib_umad_write.patch +auxdisplay-arm-charlcd-fix-release_mem_region-size.patch +hfsplus-return-error-when-node-already-exists-in-hfs.patch +rcu-fix-rcu_read_unlock-deadloop-due-to-softirq.patch +audit-move-the-compat_xxx_class-extern-declarations-.patch +selftests-resctrl-fix-a-division-by-zero-error-on-hy.patch +i3c-move-device-name-assignment-after-i3c_bus_init.patch +device_cgroup-remove-branch-hint-after-code-refactor.patch +fs-move-initializing-f_mode-before-file_ref_init.patch +fs-add-linux-init_task.h-for-init_fs.patch +i3c-master-update-hot-join-flag-only-on-success.patch +gfs2-retries-missing-in-gfs2_-rename-exchange.patch +gfs2-fix-slab-use-after-free-in-qd_put.patch +gfs2-fix-use-after-free-in-iomap-inline-data-write-p.patch +i3c-dw-initialize-spinlock-to-avoid-upsetting-lockde.patch +i3c-dw-fix-memory-leak-in-dw_i3c_master_i2c_xfers.patch +tpm-tpm_i2c_infineon-fix-locality-leak-on-get_burstc.patch +tpm-st33zp24-fix-missing-cleanup-on-get_burstcount-e.patch +erofs-get-rid-of-raw-bi_end_io-usage.patch +erofs-handle-end-of-filesystem-properly-for-file-bac.patch +btrfs-headers-cleanup-to-remove-unnecessary-local-in.patch +btrfs-remove-btrfs_bio-fs_info-by-extracting-it-from.patch +btrfs-make-sure-all-btrfs_bio-end_io-are-called-in-t.patch +btrfs-introduce-btrfs_bio-async_csum.patch +btrfs-add-orig_logical-to-btrfs_bio-for-encryption.patch +btrfs-zoned-don-t-zone-append-to-conventional-zone.patch +btrfs-qgroup-return-correct-error-when-deleting-qgro.patch +btrfs-fix-block_group_tree-dirty_list-corruption.patch +btrfs-fix-eexist-abort-due-to-non-consecutive-gaps-i.patch +erofs-fix-inline-data-read-failure-for-ztailpacking-.patch +smb-client-fix-potential-uaf-and-double-free-in-smb2.patch +netfs-avoid-double-increment-of-retry_count-in-subre.patch +rnbd-srv-fix-server-side-setting-of-bi_size-for-spec.patch +acpi-processor-update-cpuidle-driver-check-in-__acpi.patch +xen-virtio-don-t-use-grant-dma-ops-when-running-as-d.patch +io_uring-use-release-acquire-ordering-for-ioring_set.patch +acpica-fix-null-pointer-dereference-in-acpi_ev_addre.patch +io_uring-eventfd-remove-unused-ctx-evfd_last_cq_tail.patch +io_uring-sync-validate-passed-in-offset.patch +cpuidle-governors-menu-always-check-timers-with-tick.patch +thermal-intel-x86_pkg_temp_thermal-handle-invalid-te.patch +md-raid5-fix-raid5_run-to-return-error-when-log_init.patch +md-raid10-fix-any_working-flag-handling-in-raid10_sy.patch +md-raid5-fix-io-hang-with-degraded-array-with-llbitm.patch +md-md-llbitmap-fix-percpu_ref-not-resurrected-on-sus.patch +opp-return-correct-value-in-dev_pm_opp_get_level.patch +cpufreq-scmi-correct-scmi-explanation.patch +cpufreq-scmi-fix-device_node-reference-leak-in-scmi_.patch +iomap-fix-submission-side-handling-of-completion-sid.patch +thermal-of-fix-reference-leak-in-thermal_of_cm_looku.patch +ublk-restore-auto-buf-unregister-refcount-optimizati.patch +ublk-validate-sqe128-flag-before-accessing-the-cmd.patch +partial-revert-x86-xen-fix-balloon-target-initializa.patch +md-raid1-fix-memory-leak-in-raid1_run.patch +md-fix-return-value-of-mddev_trylock.patch +pm-wakeup-handle-empty-list-in-wakeup_sources_walk_s.patch +arm64-gcs-fix-error-handling-in-arch_set_shadow_stac.patch +perf-arm_spe-properly-set-hw.state-on-failures.patch +cpufreq-intel_pstate-enable-asym-capacity-only-when-.patch +pm-sleep-wakeirq-harden-dev_pm_clear_wake_irq-agains.patch +s390-cio-fix-device-lifecycle-handling-in-css_alloc_.patch +io_uring-kbuf-fix-memory-leak-if-io_buffer_add_list-.patch +x86-cpu-amd-correct-the-microcode-table-for-zenbleed.patch +perf-x86-core-do-not-set-bit-width-for-unavailable-c.patch +crypto-qat-fix-warning-on-adf_pfvf_pf_proto.c.patch +selftests-bpf-veristat-fix-printing-order-in-output_.patch +libbpf-fix-oob-read-in-btf_dump_get_bitfield_value.patch +sched-export-hidden-tracepoints-to-modules.patch +arm-vdso-patch-out-__vdso_clock_getres-if-unavailabl.patch +time-sched_clock-use-access_private-to-evaluate-hrti.patch +sched-fix-build-for-modules-using-set_tsk_need_resch.patch +crypto-cavium-fix-dma_free_coherent-size.patch +crypto-octeontx-fix-dma_free_coherent-size.patch +crypto-hisilicon-zip-adjust-the-way-to-obtain-the-re.patch +crypto-hisilicon-sec-move-backlog-management-to-qp-a.patch +crypto-hisilicon-hpre-extend-tag-field-to-64-bits-fo.patch +crypto-hisilicon-qm-enhance-the-configuration-of-req.patch +crypto-hisilicon-qm-centralize-the-sending-locks-of-.patch +crypto-hisilicon-zip-support-fallback-for-zip.patch +crypto-hisilicon-consolidate-qp-creation-and-start-i.patch +crypto-hisilicon-hpre-support-the-hpre-algorithm-fal.patch +crypto-hisilicon-sec2-support-skcipher-aead-fallback.patch +crypto-hisilicon-sgl-fix-inconsistent-map-unmap-dire.patch +bpf-preserve-id-of-register-in-sync_linked_regs.patch +bpf-fix-memory-access-flags-in-helper-prototypes.patch +selftests-bpf-fix-resource-leak-in-serial_test_wq-on.patch +hrtimer-fix-trace-oddity.patch +crypto-inside-secure-eip93-fix-kernel-panic-in-drive.patch +crypto-ccp-fix-a-case-where-snp_shutdown-is-missed.patch +crypto-ccp-narrow-scope-of-snp_range_list.patch +hwrng-airoha-set-rng-quality-to-900.patch +rqspinlock-fix-tas-fallback-lock-entry-creation.patch +bpf-sockmap-fix-incorrect-copied_seq-calculation.patch +bpf-sockmap-fix-fionread-for-sockmap.patch +bpf-fix-tcx-netkit-detach-permissions-when-prog-fd-i.patch +bpf-fix-verifier_bug_if-to-account-for-bpf_call.patch +crypto-ccp-fix-a-crash-due-to-incorrect-cleanup-usag.patch +crypto-inside-secure-eip93-unregister-only-available.patch +x86-fgraph-fix-return_to_handler-regs.rsp-value.patch +x86-fgraph-bpf-switch-kprobe_multi-program-stack-unw.patch +selftests-bpf-fix-kprobe-multi-stacktrace_ips-test.patch +crypto-hisilicon-trng-support-tfms-sharing-the-devic.patch +crypto-caam-fix-netdev-memory-leak-in-dpaa2_caam_pro.patch +bpf-fix-bpf_xdp_store_bytes-proto-for-read-only-arg.patch +genirq-set-irqf_cond_oneshot-in-devm_request_irq.patch +platform-x86-int0002-remove-irqf_oneshot-from-reques.patch +iommu-amd-use-core-s-primary-handler-and-set-irqf_on.patch +bluetooth-btintel_pcie-use-irqf_oneshot-and-default-.patch +scsi-efct-use-irqf_oneshot-and-default-primary-handl.patch +edac-altera-remove-irqf_oneshot.patch +usb-typec-fusb302-remove-irqf_oneshot.patch +rtc-amlogic-a4-remove-irqf_oneshot.patch +mfd-wm8350-core-use-irqf_oneshot.patch +media-pci-mg4b-use-irqf_no_thread.patch +sched-deadline-clear-the-defer-params.patch +sched-rt-skip-currently-executing-cpu-in-rto_next_cp.patch +fs-tests-exec-drop-duplicate-bprm_stack_limits-test-.patch +bpf-limit-bpf-program-signature-size.patch +bpf-require-frozen-map-for-calculating-map-hash.patch +crypto-starfive-fix-memory-leak-in-starfive_aes_aead.patch +hwrng-core-allow-runtime-disabling-of-the-hw-rng.patch +hwrng-core-use-rcu-and-work_struct-to-fix-race-condi.patch +selftests-bpf-test_xsk-split-xskxceiver.patch +selftests-xsk-properly-handle-batch-ending-in-the-mi.patch +selftests-xsk-fix-number-of-tx-frags-in-invalid-pack.patch +pstore-ram-fix-buffer-overflow-in-persistent_ram_sav.patch +soc-qcom-smem-handle-enomem-error-during-probe.patch +edac-i5000-fix-snprintf-size-calculation-in-calculat.patch +edac-i5400-fix-snprintf-limit-calculation-in-calcula.patch +firmware-arm_ffa-correct-32-bit-response-handling-in.patch +arm64-dts-tqma8mpql-mba8mpxl-fix-hdmi-cec-pad-contro.patch +arm64-dts-tqma8mpql-mba8mp-ras314-fix-hdmi-cec-pad-c.patch +clk-qcom-return-correct-error-code-in-qcom_cc_probe_.patch +arm64-dts-qcom-sdm630-fix-gpu_speed_bin-size.patch +arm64-dts-qcom-sdm845-oneplus-don-t-mark-ts-supply-b.patch +arm64-dts-qcom-sdm845-oneplus-don-t-keep-panel-regul.patch +arm64-dts-qcom-sdm845-oneplus-mark-l14a-regulator-as.patch +arm64-dts-qcom-x1e80100-fix-usb-combo-phys-ss1-and-s.patch +arm64-dts-renesas-r9a09g047e57-smarc-remove-duplicat.patch +arm64-dts-qcom-msm8994-octagon-fix-analog-devices-ve.patch +arm-dts-allwinner-sun5i-a13-utoo-p66-delete-power-gp.patch +powerpc-uaccess-move-barrier_nospec-out-of-allow_rea.patch +soc-qcom-cmd-db-use-devm_memremap-to-fix-memory-leak.patch +soc-mediatek-svs-fix-memory-leak-in-svs_enable_debug.patch +powerpc-eeh-fix-recursive-pci_lock_rescan_remove-loc.patch +arm64-dts-renesas-rzt2h-n2h-evk-common-use-gpio-for-.patch +arm-dts-lpc32xx-add-clocks-property-to-motor-control.patch +arm64-dts-mediatek-mt8183-jacuzzi-pico6-fix-typo-in-.patch +arm64-dts-amlogic-s4-assign-mmc-b-clock-to-24mhz.patch +arm64-dts-amlogic-s4-fix-mmc-clock-assignment.patch +arm64-dts-ti-k3-j784s4-main.dtsi-move-c71_3-node-to-.patch +arm64-dts-ti-k3-j784s4-j742s2-main-common.dtsi-refac.patch +soc-qcom-ubwc-add-missing-include.patch +hwspinlock-omap-handle-devm_pm_runtime_enable-errors.patch +arm64-dts-amlogic-c3-assign-the-mmc-signal-clocks.patch +arm64-dts-amlogic-axg-assign-the-mmc-signal-clocks.patch +arm64-dts-amlogic-gx-assign-the-mmc-signal-clocks.patch +arm64-dts-amlogic-g12-assign-the-mmc-b-and-c-signal-.patch +arm64-dts-amlogic-g12-assign-the-mmc-a-signal-clock.patch +arm64-dts-qcom-qrb4210-rb2-fix-uart3-wakeup-irq-stor.patch +arm64-dts-qcom-sdm845-db845c-drop-cs-from-spio0.patch +arm64-dts-qcom-sdm845-db845c-specify-power-for-wifi-.patch +arm64-dts-qcom-x1e-bus-is-40-bits-fix-64gb-models.patch +arm64-dts-qcom-talos-drop-opp-shared-from-qup-opp-ta.patch +arm64-dts-qcom-agatti-add-cx_mem-dbgc-gpu-regions.patch +arm64-dts-qcom-sm6115-add-cx_mem-dbgc-gpu-regions.patch +reset-canaan-k230-drop-of-dependency-and-enable-by-d.patch +drm-panthor-recover-from-panthor_gpu_flush_caches-fa.patch +drm-panthor-fix-the-full_tick-check.patch +drm-panthor-fix-the-group-priority-rotation-logic.patch +drm-panthor-fix-immediate-ticking-on-a-disabled-tick.patch +drm-panthor-fix-the-logic-that-decides-when-to-stop-.patch +drm-panthor-make-sure-we-resume-the-tick-when-new-jo.patch +workqueue-factor-out-assign_rescuer_work.patch +workqueue-only-assign-rescuer-work-when-really-neede.patch +workqueue-process-rescuer-work-items-one-by-one-usin.patch +drm-panthor-fix-panthor_gpu_coherency_set.patch +accel-amdxdna-fix-race-where-send-ring-appears-full-.patch +drm-panel-sw43408-remove-manual-invocation-of-unprep.patch +alsa-pcm-relax-__free-variable-declarations.patch +alsa-vmaster-relax-__free-variable-declarations.patch +asoc-sdca-allow-sample-width-wild-cards-in-set_usage.patch +drm-panthor-evict-groups-before-vm-termination.patch +smack-smack-doi-must-be-0.patch +smack-smack-doi-accept-previously-used-values.patch +asoc-nau8821-fixup-nau8821_enable_jack_detect.patch +media-chips-media-wave5-fix-memory-leak-on-codec_inf.patch +drm-amd-drop-amdgpu-kernel-modesetting-enabled-messa.patch +drm-amdkfd-fix-signal_eviction_fence-bool-return-val.patch +drm-amdgpu-use-explicit-vcn-instance-0-in-sr-iov-ini.patch +drm-msm-disp-dpu-add-merge3d-support-for-sc7280.patch +drm-msm-dpu-set-vsync-source-irrespective-of-mdp-top.patch +drm-msm-dpu-fix-wd-timer-handling-on-dpu-8.x.patch +drm-msm-dp-update-msm_dp_controller-ids-for-sa8775p.patch +mei-late_bind-fix-struct-intel_lb_component_ops-kern.patch +regulator-core-move-supply-check-earlier-in-set_mach.patch +hid-playstation-add-missing-check-for-input_ff_creat.patch +gpu-nova-core-replace-wait_on-with-kernel-equivalent.patch +gpu-nova-core-replace-as-with-from-conversions-where.patch +gpu-nova-core-vbios-use-frombytes-for-pmulookuptable.patch +gpu-nova-core-apply-the-one-use-item-per-line-policy.patch +gpu-nova-core-check-for-overflow-to-dmatrfbase1.patch +drm-msm-disp-set-num_planes-to-1-for-interleaved-yuv.patch +drm-msm-dpu-fix-cmd-panels-on-dpu-1.x-3.x.patch +drm-msm-dsi_phy_14nm-convert-from-divider_round_rate.patch +accel-amdxdna-fix-notifier_wq-flushing-warning.patch +media-ccs-accommodate-c-phy-into-the-calculation.patch +drm-msm-a2xx-fix-pixel-shader-start-on-a225.patch +drm-buddy-release-free_trees-array-on-buddy-mm-teard.patch +drm-hisilicon-hibmc-fix-dp-probabilistical-detect-er.patch +drm-hisilicon-hibmc-add-dp-mode-valid-check.patch +drm-hisilicon-hibmc-fix-no-showing-problem-with-load.patch +drm-hisilicon-hibmc-adding-reset-colorbar-cfg-in-dp-.patch +drm-rockchip-dw_hdmi_qp-fix-rk3576-hpd-interrupt-han.patch +drm-msm-mdss-correct-hbb-programmed-on-ubwc-5.x-and-.patch +drm-msm-dpu-offset-hbb-values-written-to-dpu-by-13.patch +drm-msm-dpu-program-correct-register-for-ubwc-config.patch +drm-msm-dp-avoid-division-by-zero-in-msm_dp_ctrl_con.patch +platform-chrome-cros_typec_switch-don-t-touch-struct.patch +pwm-tiehrpwm-enable-pwmchip-s-parent-device-before-s.patch +media-uvcvideo-fix-allocation-for-small-frame-sizes.patch +evm-use-ordered-xattrs-list-to-calculate-hmac-in-evm.patch +drm-xe-ptl-disable-dcc-on-ptl.patch +drm-xe-unregister-drm-device-on-probe-error.patch +mm-slab-fix-false-lockdep-warning-in-__kfree_rcu_she.patch +asoc-tegra-add-ahub-writeable_reg-for-rx-holes.patch +platform-chrome-cros_ec_lightbar-fix-response-size-i.patch +accel-amdxdna-hold-mm-structure-across-iommu_sva_unb.patch +accel-amdxdna-stop-job-scheduling-across-aie2_releas.patch +accel-amdxdna-fix-memory-leak-in-amdxdna_ubuf_map.patch +hid-intel-ish-hid-fix-null-ptr-deref-in-ishtp_bus_re.patch +accel-amdxdna-fix-incorrect-error-code-returned-for-.patch +asoc-sdca-remove-outdated-todo-comment.patch +asoc-sdca-force-some-sdca-controls-to-be-volatile.patch +asoc-sdca-handle-volatile-controls-correctly.patch +spi-tools-add-include-folder-to-.gitignore.patch +revert-hwmon-ibmpex-fix-use-after-free-in-high-low-s.patch +hwmon-pmbus-mpq8785-fix-vout_mode-mismatch-during-id.patch +pci-mediatek-fix-irq-domain-leak-when-msi-allocation.patch +pci-xilinx-fix-intx-irq-domain-leak-in-error-paths.patch +documentation-pci-endpoint-fix-ntb-vntb-copy-paste-e.patch +pci-pm-avoid-redundant-delays-on-d3hot-d3cold.patch +wifi-cfg80211-fix-use_for-flag-update-on-bss-refresh.patch +pci-p2pdma-release-per-cpu-pgmap-ref-when-vm_insert_.patch +pci-p2pdma-fix-p2pmem_alloc_mmap-warning-condition.patch +documentation-tracing-add-pci-tracepoint-documentati.patch +pci-do-not-attempt-to-set-exttag-for-vfs.patch +pci-sophgo-disable-l0s-and-l1-on-sophgo-2044-pcie-ro.patch +pci-portdrv-fix-potential-resource-leak.patch +dm-fix-unlocked-test-for-dm_suspended_md.patch +dm-use-read_once-in-dm_blk_report_zones.patch +pci-ptm-fix-pcie_ptm_create_debugfs-memory-leak.patch +pci-p2pdma-reset-page-reference-count-when-page-mapp.patch +wifi-ath9k-add-of-dependency-to-ahb.patch +wifi-ath12k-do-wow-offloads-only-on-primary-link.patch +quota-fix-livelock-between-quotactl-and-freeze_super.patch +net-mctp-i2c-fix-duplicate-reception-of-old-data.patch +mctp-i2c-initialise-event-handler-read-bytes.patch +wifi-cfg80211-stop-nan-and-p2p-in-cfg80211_leave.patch +ext4-fast-commit-make-s_fc_lock-reclaim-safe.patch +netfilter-nf_tables-reset-table-validation-state-on-.patch +netfilter-nf_conncount-make-nf_conncount_gc_list-to-.patch +netfilter-nf_conncount-increase-the-connection-clean.patch +netfilter-nft_compat-add-more-restrictions-on-netlin.patch +netfilter-nf_conncount-fix-tracking-of-connections-f.patch +kallsyms-bpf-rename-__bpf_address_lookup-to-bpf_addr.patch +module-add-helper-function-for-reading-module_buildi.patch +kallsyms-ftrace-set-module-buildid-in-ftrace_mod_add.patch +pci-mark-3ware-9650sa-root-port-extended-tags-as-bro.patch +wifi-rtw89-debug-fix-memory-leak-in-__print_txpwr_ma.patch +iommu-vt-d-flush-cache-for-pasid-table-before-using-.patch +iommu-vt-d-clear-present-bit-before-tearing-down-pas.patch +iommu-vt-d-clear-present-bit-before-tearing-down-con.patch +dm-use-bio_clone_blkg_association.patch +xdrgen-fix-struct-prefix-for-typedef-types-in-progra.patch +nfs-nfserr_inval-is-not-defined-by-nfsv2.patch +xdrgen-initialize-data-pointer-for-zero-length-items.patch +xdrgen-remove-inclusion-of-nlm4.h-header.patch +nfsd-never-defer-requests-during-idmap-lookup.patch +lib-kstrtox-fix-kstrtobool-docstring-to-mention-enab.patch +rust-task-restrict-task-group_leader-to-current.patch +fat-avoid-parent-link-count-underflow-in-rmdir.patch +pci-rewrite-bridge-window-head-alignment-function.patch +pci-stop-over-estimating-bridge-window-size.patch +pci-remove-old_size-limit-from-bridge-window-sizing.patch +tcp-tcp_tx_timestamp-must-look-at-the-rtx-queue.patch +pci-check-parent-for-null-in-of_pci_bus_release_doma.patch +wifi-ath10k-sdio-add-missing-lock-protection-in-ath1.patch +wifi-ath11k-add-usecase-firmware-handling-based-on-d.patch +wifi-ath12k-fix-index-decrement-when-array_len-is-ze.patch +wifi-ath12k-clear-stale-link-mapping-of-ahvif-links_.patch +pci-initialize-rcb-from-pci_configure_device.patch +pci-acpi-restrict-program_hpx_type2-to-aer-bits.patch +selftests-mm-fix-usage-of-force_read-in-cow-tests.patch +selftests-mm-fix-faulting-in-code-in-pagemap_ioctl-t.patch +ipc-don-t-audit-capability-check-in-ipc_permissions.patch +ucount-check-for-cap_sys_resource-using-ns_capable_n.patch +jfs-avoid-wtautological-constant-out-of-range-compar.patch +tcp-ect_1_negotiation-and-needs_accecn-identifiers.patch +tcp-disable-rfc3168-fallback-identifier-for-cc-modul.patch +tcp-accecn-handle-unexpected-accecn-negotiation-feed.patch +of-unittest-fix-possible-null-pointer-dereferences-i.patch +mptcp-do-not-account-for-ooo-in-mptcp_rcvbuf_grow.patch +mptcp-fix-receive-space-timestamp-initialization.patch +octeontx2-af-fix-pf-driver-crash-with-kexec-kernel-b.patch +bonding-only-set-speed-duplex-to-unknown-if-getting-.patch +inet-raw-sockets-using-ipproto_raw-must-drop-incomin.patch +nfc-hci-shdlc-stop-timers-and-work-before-freeing-co.patch +netfilter-nfnetlink_queue-optimize-verdict-lookup-wi.patch +netfilter-nfnetlink_queue-do-shared-unconfirmed-chec.patch +netfilter-nft_set_hash-fix-get-operation-on-big-endi.patch +netfilter-nft_counter-fix-reset-of-counters-on-32bit.patch +netfilter-nft_set_rbtree-fix-bogus-eexist-with-nlm_f.patch +netfilter-nft_set_rbtree-check-for-partial-overlaps-.patch +netfilter-nft_set_rbtree-translate-rbtree-to-array-f.patch +netfilter-nft_set_rbtree-use-binary-search-array-in-.patch +netfilter-nft_set_rbtree-remove-seqcount_rwlock_t.patch +netfilter-nft_set_rbtree-don-t-gc-elements-on-insert.patch +netfilter-nft_set_rbtree-validate-element-belonging-.patch +netfilter-nft_set_rbtree-validate-open-interval-over.patch +pci-add-acs-quirk-for-pericom-pi7c9x2g404-switches-1.patch +dpll-add-phase-adjust-gran-pin-attribute.patch +dpll-zl3073x-specify-phase-adjustment-granularity-fo.patch +dpll-zl3073x-store-raw-register-values-instead-of-pa.patch +dpll-zl3073x-split-ref-out-and-synth-logic-from-core.patch +dpll-zl3073x-cache-all-output-properties-in-zl3073x_.patch +dpll-zl3073x-fix-output-pin-phase-adjustment-sign.patch +net-hns3-fix-double-free-issue-for-tx-spare-buffer.patch +procfs-fix-missing-rcu-protection-when-reading-real_.patch +smb-client-correct-value-for-smbd_max_fragmented_rec.patch +net-atm-fix-crash-due-to-unvalidated-vcc-pointer-in-.patch +net-sunhme-fix-sbus-regression.patch +xfrm-fix-ip_rt_bug-race-in-icmp_route_lookup-reverse.patch +serial-caif-fix-use-after-free-in-caif_serial-ldisc_.patch +octeon_ep-disable-per-ring-interrupts.patch +octeon_ep-ensure-dbell-baddr-updation.patch +octeon_ep_vf-ensure-dbell-baddr-updation.patch +ionic-rate-limit-unknown-xcvr-type-messages.patch +net-renesas-rswitch-fix-forwarding-offload-statemach.patch +octeontx2-pf-unregister-devlink-on-probe-failure.patch +af_unix-fix-memleak-of-newsk-in-unix_stream_connect.patch +rdma-rtrs-server-remove-dead-code.patch +ib-cache-update-gid-cache-on-client-reregister-event.patch +rdma-hns-fix-wq_mem_reclaim-warning.patch +rdma-hns-fix-rocev1-failure-due-to-dscp.patch +rdma-hns-notify-ulp-of-remaining-soft-wcs-during-res.patch +rdma-mlx5-fix-ucaps-init-error-flow.patch +cxl-mem-fix-devm_cxl_memdev_edac_release-confusion.patch +power-supply-ab8500-fix-use-after-free-in-power_supp.patch +power-supply-act8945a-fix-use-after-free-in-power_su.patch +power-supply-bq256xx-fix-use-after-free-in-power_sup.patch +power-supply-bq25980-fix-use-after-free-in-power_sup.patch +power-supply-cpcap-battery-fix-use-after-free-in-pow.patch +power-supply-goldfish-fix-use-after-free-in-power_su.patch +power-supply-pm8916_bms_vm-fix-use-after-free-in-pow.patch +power-supply-pm8916_lbc-fix-use-after-free-in-power_.patch +power-supply-rt9455-fix-use-after-free-in-power_supp.patch +power-supply-sbs-battery-fix-use-after-free-in-power.patch +power-reset-nvmem-reboot-mode-respect-cell-size-for-.patch +power-supply-bq27xxx-fix-wrong-errno-when-bus-ops-ar.patch +power-supply-wm97xx-fix-null-pointer-dereference-in-.patch +rdma-rtrs-srv-fix-sg-mapping.patch +rdma-rxe-fix-double-free-in-rxe_srq_from_init.patch +rdma-iwcm-fix-workqueue-list-corruption-by-removing-.patch +platform-x86-hp-wmi-fix-platform-profile-values-for-.patch +tools-power-x86-intel-speed-select-fix-file-descript.patch +rdma-mlx5-fix-umr-hang-in-lag-error-state-unload.patch +ib-mlx5-fix-port-speed-query-for-representors.patch +mtd-rawnand-cadence-fix-return-type-of-cdma-send-and.patch +mtd-intel-dg-fix-accessing-regions-before-setting-nr.patch +vfio-pci-lock-upstream-bridge-for-vfio_pci_core_disa.patch +platform-x86-amd-pmf-prevent-tee-errors-after-hibern.patch +crypto-ccp-declare-psp-dead-if-psp_cmd_tee_ring_init.patch +crypto-ccp-add-an-s4-restore-flow.patch +crypto-ccp-factor-out-ring-destroy-handling-to-a-hel.patch +crypto-ccp-send-psp_cmd_tee_ring_destroy-when-psp_cm.patch +mtd-parsers-fix-memory-leak-in-mtd_parser_tplink_saf.patch +nfs-localio-handle-short-writes-by-retrying.patch +nfs-localio-prevent-direct-reclaim-recursion-into-nf.patch +nfs-localio-use-gfp_noio-and-non-memreclaim-workqueu.patch +nfs-localio-remove-eagain-handling-in-nfs_local_doio.patch +cxl-core-fix-cxl_dport-debugfs-einj-entries.patch +rdma-rxe-fix-iova-to-va-conversion-for-mr-page-sizes.patch +rdma-uverbs-validate-wqe_size-before-using-it-in-ib_.patch +rdma-mlx5-fix-memory-leak-in-get_data_direct_sysfs_p.patch +rdma-rxe-fix-race-condition-in-qp-timer-handlers.patch +rdma-core-add-rdma_rw_max_sge-helper-for-sq-sizing.patch +cxl-fix-premature-commit_end-increment-on-decoder-co.patch +mtd-parsers-ofpart-fix-of-node-refcount-leak-in-pars.patch +mtd-spinand-fix-kernel-doc.patch +hisi_acc_vfio_pci-fix-vf-reset-timeout-issue.patch +power-supply-pm8916_lbc-fix-use-after-free-for-extco.patch +power-supply-qcom_battmgr-recognize-lip-as-lithium-p.patch +rdma-uverbs-add-__gfp_nowarn-to-ib_uverbs_unmarshall.patch +pnfs-fix-a-missing-wake-up-while-waiting-on-nfs_layo.patch +scsi-smartpqi-fix-memory-leak-in-pqi_report_phys_lun.patch +scsi-ufs-host-mediatek-require-config_pm.patch +scsi-csiostor-fix-dereference-of-null-pointer-rn.patch +nvdimm-virtio_pmem-serialize-flush-requests.patch +fs-nfs-fix-readdir-slow-start-regression.patch +tracing-properly-process-error-handling-in-event_his.patch +tracing-remove-duplicate-enable_event_str-and-disabl.patch +remoteproc-imx_dsp_rproc-only-reset-carveout-memory-.patch +revert-mailbox-pcc-support-mailbox-management-of-the.patch +fbcon-rename-struct-fbcon_ops-to-struct-fbcon_par.patch +fbcon-set-rotate_font-callback-with-related-callback.patch +fbcon-move-fbcon-callbacks-into-struct-fbcon_bitops.patch +printk-vt-fbcon-remove-console_conditional_schedule.patch +fbdev-of_display_timing-fix-device-node-reference-le.patch +fbdev-au1200fb-fix-a-memory-leak-in-au1200fb_drv_pro.patch +clk-thead-th1520-ap-poll-for-pll-lock-and-wait-for-s.patch +clk-spacemit-respect-kconfig-setting-when-building-m.patch +clk-qcom-gcc-sm8550-use-floor-ops-for-sdcc-rcgs.patch +clk-qcom-gcc-sm8650-use-floor-ops-for-sdcc-rcgs.patch +clk-qcom-rcg2-compute-2d-using-duty-fraction-directl.patch +clk-meson-gxbb-limit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch +clk-meson-g12a-limit-the-hdmi-pll-od-to-4.patch +clk-qcom-gcc-sm8450-update-the-sdcc-rcgs-to-use-shar.patch +clk-qcom-gcc-sm8750-update-the-sdcc-rcgs-to-use-shar.patch +clk-qcom-gcc-sm4450-update-the-sdcc-rcgs-to-use-shar.patch +clk-qcom-gcc-sdx75-update-the-sdcc-rcgs-to-use-share.patch +clk-qcom-gcc-milos-update-the-sdcc-rcgs-to-use-share.patch +clk-qcom-gcc-x1e80100-update-the-sdcc-rcgs-to-use-sh.patch +clk-qcom-gcc-qdu1000-update-the-sdcc-rcgs-to-use-sha.patch +clk-qcom-gcc-glymur-update-the-sdcc-rcgs-to-use-shar.patch +clk-qcom-gcc-msm8953-remove-always_on-flag-from-cpp_.patch +clk-qcom-gcc-msm8917-remove-always_on-flag-from-cpp_.patch +clk-qcom-gcc-ipq5018-flag-sleep-clock-as-critical.patch +clk-qcom-alpha-pll-convert-from-divider_round_rate-t.patch +clk-rockchip-fix-error-pointer-check-after-rockchip_.patch +clk-microchip-core-remove-duplicate-determine_rate-o.patch +input-adp5589-remove-a-leftover-header-file.patch +clk-move-clk_-save-restore-_context-to-common_clk-se.patch +clk-qcom-regmap-divider-convert-from-divider_ro_roun.patch +clk-qcom-regmap-divider-convert-from-divider_round_r.patch +clk-qcom-dispcc-sdm845-enable-parents-for-pixel-cloc.patch +clk-qcom-dispcc-sm7150-fix-dispcc_mdss_pclk1_clk_src.patch +clk-qcom-gfx3d-add-parent-to-parent-request-map.patch +clk-actions-owl-composite-convert-from-owl_divider_h.patch +clk-actions-owl-divider-convert-from-divider_round_r.patch +clk-bm1880-convert-from-divider_round_rate-to-divide.patch +clk-hisilicon-clkdivider-hi6220-convert-from-divider.patch +clk-loongson1-convert-from-divider_round_rate-to-div.patch +clk-milbeaut-convert-from-divider_round_rate-to-divi.patch +clk-nuvoton-ma35d1-divider-convert-from-divider_roun.patch +clk-nxp-lpc32xx-convert-from-divider_round_rate-to-d.patch +clk-sophgo-sg2042-clkgen-convert-from-divider_round_.patch +clk-sprd-div-convert-from-divider_round_rate-to-divi.patch +clk-stm32-stm32-core-convert-from-divider_ro_round_r.patch +clk-stm32-stm32-core-convert-from-divider_round_rate.patch +clk-versaclock3-convert-from-divider_round_rate-to-d.patch +clk-x86-cgu-convert-from-divider_round_rate-to-divid.patch +clk-zynqmp-divider-convert-from-divider_round_rate-t.patch +clk-mediatek-drop-__initconst-from-gates.patch +clk-mediatek-add-mfg_eb-as-parent-to-mt8196-mfgpll-c.patch +clk-mediatek-fix-error-handling-in-runtime-pm-setup.patch +clk-zynqmp-divider-fix-zynqmp_clk_divider_determine_.patch +clk-zynqmp-pll-fix-zynqmp_clk_divider_determine_rate.patch +interconnect-mediatek-don-t-hijack-parent-device.patch +interconnect-mediatek-aggregate-bandwidth-with-satur.patch +dmaengine-mediatek-uart-apdma-fix-above-4g-addressin.patch +dma-dma-axi-dmac-fix-sw-cyclic-transfers.patch +dma-dma-axi-dmac-fix-hw-scatter-gather-not-looking-a.patch +phy-rockchip-samsung-hdptx-pre-compute-hdmi-pll-conf.patch +char-misc-use-is_err-for-filp_open-return-value.patch +soundwire-intel_ace2x-add-snd_hda_core-dependency.patch +iio-test-drop-dangling-symbol-in-gain-time-scale-hel.patch +usb-typec-ucsi-drop-an-unused-kconfig-symbol.patch +staging-greybus-lights-avoid-null-deref.patch +serial-imx-change-serial_imx_console-to-bool.patch +serial-sh_sci-improve-dma-support-prompt.patch +gpib-fix-error-code-in-ibonline.patch +gpib-fix-error-code-in-ni_usb_write_registers.patch +gpib-fix-memory-leak-in-ni_usb_init.patch +mmc-rtsx_pci_sdmmc-increase-power-on-settling-delay-.patch +iio-pressure-mprls0025pa-fix-spi_transfer-struct-ini.patch +iio-pressure-mprls0025pa-fix-spi-cs-delay-violation.patch +iio-pressure-mprls0025pa-fix-interrupt-flag.patch +iio-pressure-mprls0025pa-fix-scan_type-struct.patch +iio-pressure-mprls0025pa-fix-pressure-calculation.patch +watchdog-starfive-wdt-fix-pm-reference-leak-in-probe.patch +coresight-etm3x-fix-cpulocked-warning-on-cpuhp.patch +phy-freescale-imx8qm-hsio-fix-null-pointer-dereferen.patch +coresight-tmc-etr-fix-race-condition-between-sysfs-a.patch +revert-mmc-rtsx_pci_sdmmc-increase-power-on-settling.patch +mfd-arizona-fix-regulator-resource-leak-on-wm5102_cl.patch +mfd-simple-mfd-i2c-add-delta-tn48m-cpld-support.patch +drivers-iio-mpu3050-use-dev_err_probe-for-regulator-.patch +usb-bdc-fix-sleep-during-atomic.patch +nvmem-an8855-drop-an-unused-kconfig-symbol.patch +mcb-fix-incorrect-sanity-check.patch +pinctrl-equilibrium-fix-device-node-reference-leak-i.patch +ovl-fix-uninit-value-in-ovl_fill_real.patch +iio-sca3000-fix-a-resource-leak-in-sca3000_probe.patch +mips-loongson32-drop-a-dangling-kconfig-symbol.patch +pidfs-return-eremote-when-pidfd_get_info-is-called-o.patch +pinctrl-qcom-sm8250-lpass-lpi-fix-i2s2_data_groups-d.patch +pinctrl-meson-amlogic-a4-fix-device-node-reference-l.patch +pinctrl-single-fix-refcount-leak-in-pcs_add_gpio_fun.patch +pinctrl-canaan-k230-fix-null-pointer-dereference-whe.patch +leds-expresswire-fix-chip-state-breakage.patch +leds-qcom-lpg-check-the-return-value-of-regmap_bulk_.patch +backlight-qcom-wled-support-ovp-values-for-pmi8994.patch +backlight-qcom-wled-change-pm8950-wled-configuration.patch +dmaengine-fsl-edma-don-t-explicitly-disable-clocks-i.patch +drbd-always-set-blk_feat_stable_writes.patch +io_uring-delay-sqarray-static-branch-disablement.patch +io_uring-cancel-de-unionize-file-and-user_data-in-st.patch diff --git a/queue-6.18/smack-smack-doi-accept-previously-used-values.patch b/queue-6.18/smack-smack-doi-accept-previously-used-values.patch new file mode 100644 index 0000000000..f0cb23d225 --- /dev/null +++ b/queue-6.18/smack-smack-doi-accept-previously-used-values.patch @@ -0,0 +1,233 @@ +From 3d521c622b2eb784c953e247b32fc3f93e2e7cd7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Sep 2025 15:31:53 +0300 +Subject: smack: /smack/doi: accept previously used values +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Konstantin Andreev + +[ Upstream commit 33d589ed60ae433b483761987b85e0d24e54584e ] + +Writing to /smack/doi a value that has ever been +written there in the past disables networking for +non-ambient labels. +E.g. + + # cat /smack/doi + 3 + # netlabelctl -p cipso list + Configured CIPSO mappings (1) + DOI value : 3 + mapping type : PASS_THROUGH + # netlabelctl -p map list + Configured NetLabel domain mappings (3) + domain: "_" (IPv4) + protocol: UNLABELED + domain: DEFAULT (IPv4) + protocol: CIPSO, DOI = 3 + domain: DEFAULT (IPv6) + protocol: UNLABELED + + # cat /smack/ambient + _ + # cat /proc/$$/attr/smack/current + _ + # ping -c1 10.1.95.12 + 64 bytes from 10.1.95.12: icmp_seq=1 ttl=64 time=0.964 ms + # echo foo >/proc/$$/attr/smack/current + # ping -c1 10.1.95.12 + 64 bytes from 10.1.95.12: icmp_seq=1 ttl=64 time=0.956 ms + unknown option 86 + + # echo 4 >/smack/doi + # echo 3 >/smack/doi +!> [ 214.050395] smk_cipso_doi:691 cipso add rc = -17 + # echo 3 >/smack/doi +!> [ 249.402261] smk_cipso_doi:678 remove rc = -2 +!> [ 249.402261] smk_cipso_doi:691 cipso add rc = -17 + + # ping -c1 10.1.95.12 +!!> ping: 10.1.95.12: Address family for hostname not supported + + # echo _ >/proc/$$/attr/smack/current + # ping -c1 10.1.95.12 + 64 bytes from 10.1.95.12: icmp_seq=1 ttl=64 time=0.617 ms + +This happens because Smack keeps decommissioned DOIs, +fails to re-add them, and consequently refuses to add +the “default” domain map: + + # netlabelctl -p cipso list + Configured CIPSO mappings (2) + DOI value : 3 + mapping type : PASS_THROUGH + DOI value : 4 + mapping type : PASS_THROUGH + # netlabelctl -p map list + Configured NetLabel domain mappings (2) + domain: "_" (IPv4) + protocol: UNLABELED +!> (no ipv4 map for default domain here) + domain: DEFAULT (IPv6) + protocol: UNLABELED + +Fix by clearing decommissioned DOI definitions and +serializing concurrent DOI updates with a new lock. + +Also: +- allow /smack/doi to live unconfigured, since + adding a map (netlbl_cfg_cipsov4_map_add) may fail. + CIPSO_V4_DOI_UNKNOWN(0) indicates the unconfigured DOI +- add new DOI before removing the old default map, + so the old map remains if the add fails + +(2008-02-04, Casey Schaufler) +Fixes: e114e473771c ("Smack: Simplified Mandatory Access Control Kernel") + +Signed-off-by: Konstantin Andreev +Signed-off-by: Casey Schaufler +Signed-off-by: Sasha Levin +--- + security/smack/smackfs.c | 71 +++++++++++++++++++++++++--------------- + 1 file changed, 45 insertions(+), 26 deletions(-) + +diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c +index 316c2ea401e8a..d27d9140dda2f 100644 +--- a/security/smack/smackfs.c ++++ b/security/smack/smackfs.c +@@ -70,6 +70,7 @@ enum smk_inos { + static DEFINE_MUTEX(smack_cipso_lock); + static DEFINE_MUTEX(smack_ambient_lock); + static DEFINE_MUTEX(smk_net4addr_lock); ++static DEFINE_MUTEX(smk_cipso_doi_lock); + #if IS_ENABLED(CONFIG_IPV6) + static DEFINE_MUTEX(smk_net6addr_lock); + #endif /* CONFIG_IPV6 */ +@@ -141,7 +142,7 @@ struct smack_parsed_rule { + int smk_access2; + }; + +-static u32 smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; ++static u32 smk_cipso_doi_value = CIPSO_V4_DOI_UNKNOWN; + + /* + * Values for parsing cipso rules +@@ -663,43 +664,60 @@ static const struct file_operations smk_load_ops = { + }; + + /** +- * smk_cipso_doi - initialize the CIPSO domain ++ * smk_cipso_doi - set netlabel maps ++ * @ndoi: new value for our CIPSO DOI ++ * @gfp_flags: kmalloc allocation context + */ +-static void smk_cipso_doi(void) ++static int ++smk_cipso_doi(u32 ndoi, gfp_t gfp_flags) + { +- int rc; ++ int rc = 0; + struct cipso_v4_doi *doip; + struct netlbl_audit nai; + +- smk_netlabel_audit_set(&nai); ++ mutex_lock(&smk_cipso_doi_lock); + +- rc = netlbl_cfg_map_del(NULL, PF_INET, NULL, NULL, &nai); +- if (rc != 0) +- printk(KERN_WARNING "%s:%d remove rc = %d\n", +- __func__, __LINE__, rc); ++ if (smk_cipso_doi_value == ndoi) ++ goto clr_doi_lock; ++ ++ smk_netlabel_audit_set(&nai); + +- doip = kmalloc(sizeof(struct cipso_v4_doi), GFP_KERNEL | __GFP_NOFAIL); ++ doip = kmalloc(sizeof(struct cipso_v4_doi), gfp_flags); ++ if (!doip) { ++ rc = -ENOMEM; ++ goto clr_doi_lock; ++ } + doip->map.std = NULL; +- doip->doi = smk_cipso_doi_value; ++ doip->doi = ndoi; + doip->type = CIPSO_V4_MAP_PASS; + doip->tags[0] = CIPSO_V4_TAG_RBITMAP; + for (rc = 1; rc < CIPSO_V4_TAG_MAXCNT; rc++) + doip->tags[rc] = CIPSO_V4_TAG_INVALID; + + rc = netlbl_cfg_cipsov4_add(doip, &nai); +- if (rc != 0) { +- printk(KERN_WARNING "%s:%d cipso add rc = %d\n", +- __func__, __LINE__, rc); ++ if (rc) { + kfree(doip); +- return; ++ goto clr_doi_lock; + } +- rc = netlbl_cfg_cipsov4_map_add(doip->doi, NULL, NULL, NULL, &nai); +- if (rc != 0) { +- printk(KERN_WARNING "%s:%d map add rc = %d\n", +- __func__, __LINE__, rc); +- netlbl_cfg_cipsov4_del(doip->doi, &nai); +- return; ++ ++ if (smk_cipso_doi_value != CIPSO_V4_DOI_UNKNOWN) { ++ rc = netlbl_cfg_map_del(NULL, PF_INET, NULL, NULL, &nai); ++ if (rc && rc != -ENOENT) ++ goto clr_ndoi_def; ++ ++ netlbl_cfg_cipsov4_del(smk_cipso_doi_value, &nai); + } ++ ++ rc = netlbl_cfg_cipsov4_map_add(ndoi, NULL, NULL, NULL, &nai); ++ if (rc) { ++ smk_cipso_doi_value = CIPSO_V4_DOI_UNKNOWN; // no default map ++clr_ndoi_def: netlbl_cfg_cipsov4_del(ndoi, &nai); ++ } else ++ smk_cipso_doi_value = ndoi; ++ ++clr_doi_lock: ++ mutex_unlock(&smk_cipso_doi_lock); ++ return rc; + } + + /** +@@ -1599,11 +1617,8 @@ static ssize_t smk_write_doi(struct file *file, const char __user *buf, + + if (u == CIPSO_V4_DOI_UNKNOWN || u > U32_MAX) + return -EINVAL; +- smk_cipso_doi_value = u; +- +- smk_cipso_doi(); + +- return count; ++ return smk_cipso_doi(u, GFP_KERNEL) ? : count; + } + + static const struct file_operations smk_doi_ops = { +@@ -2984,6 +2999,7 @@ static int __init init_smk_fs(void) + { + int err; + int rc; ++ struct netlbl_audit nai; + + if (smack_enabled == 0) + return 0; +@@ -3002,7 +3018,10 @@ static int __init init_smk_fs(void) + } + } + +- smk_cipso_doi(); ++ smk_netlabel_audit_set(&nai); ++ (void) netlbl_cfg_map_del(NULL, PF_INET, NULL, NULL, &nai); ++ (void) smk_cipso_doi(SMACK_CIPSO_DOI_DEFAULT, ++ GFP_KERNEL | __GFP_NOFAIL); + smk_unlbl_ambient(NULL); + + rc = smack_populate_secattr(&smack_known_floor); +-- +2.51.0 + diff --git a/queue-6.18/smack-smack-doi-must-be-0.patch b/queue-6.18/smack-smack-doi-must-be-0.patch new file mode 100644 index 0000000000..52d641c99e --- /dev/null +++ b/queue-6.18/smack-smack-doi-must-be-0.patch @@ -0,0 +1,71 @@ +From 16be5a1d5efbeb13f67e79b4558a9e771c302c3b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Sep 2025 15:16:02 +0300 +Subject: smack: /smack/doi must be > 0 + +From: Konstantin Andreev + +[ Upstream commit 19c013e1551bf51e1493da1270841d60e4fd3f15 ] + +/smack/doi allows writing and keeping negative doi values. +Correct values are 0 < doi <= (max 32-bit positive integer) + +(2008-02-04, Casey Schaufler) +Fixes: e114e473771c ("Smack: Simplified Mandatory Access Control Kernel") + +Signed-off-by: Konstantin Andreev +Signed-off-by: Casey Schaufler +Signed-off-by: Sasha Levin +--- + security/smack/smackfs.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c +index b1e5e62f5cbd1..316c2ea401e8a 100644 +--- a/security/smack/smackfs.c ++++ b/security/smack/smackfs.c +@@ -141,7 +141,7 @@ struct smack_parsed_rule { + int smk_access2; + }; + +-static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; ++static u32 smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; + + /* + * Values for parsing cipso rules +@@ -1562,7 +1562,7 @@ static ssize_t smk_read_doi(struct file *filp, char __user *buf, + if (*ppos != 0) + return 0; + +- sprintf(temp, "%d", smk_cipso_doi_value); ++ sprintf(temp, "%lu", (unsigned long)smk_cipso_doi_value); + rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp)); + + return rc; +@@ -1581,7 +1581,7 @@ static ssize_t smk_write_doi(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) + { + char temp[80]; +- int i; ++ unsigned long u; + + if (!smack_privileged(CAP_MAC_ADMIN)) + return -EPERM; +@@ -1594,10 +1594,12 @@ static ssize_t smk_write_doi(struct file *file, const char __user *buf, + + temp[count] = '\0'; + +- if (sscanf(temp, "%d", &i) != 1) ++ if (kstrtoul(temp, 10, &u)) + return -EINVAL; + +- smk_cipso_doi_value = i; ++ if (u == CIPSO_V4_DOI_UNKNOWN || u > U32_MAX) ++ return -EINVAL; ++ smk_cipso_doi_value = u; + + smk_cipso_doi(); + +-- +2.51.0 + diff --git a/queue-6.18/smb-client-correct-value-for-smbd_max_fragmented_rec.patch b/queue-6.18/smb-client-correct-value-for-smbd_max_fragmented_rec.patch new file mode 100644 index 0000000000..29eca133fd --- /dev/null +++ b/queue-6.18/smb-client-correct-value-for-smbd_max_fragmented_rec.patch @@ -0,0 +1,78 @@ +From 0f7de76e4df7960075c14e5cba2907291be3f8cc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 17:14:14 +0100 +Subject: smb: client: correct value for smbd_max_fragmented_recv_size + +From: Stefan Metzmacher + +[ Upstream commit 4a93d1ee2d0206970b6eb13fbffe07938cd95948 ] + +When we download a file without rdma offload or get +a large directly enumeration from the server, +the server might want to send up to smbd_max_fragmented_recv_size +bytes, but if it is too large all our recv buffers +might already be moved to the recv_io.reassembly.list +and we're no longer able to grant recv credits. + +The maximum fragmented upper-layer payload receive size supported + +Assume max_payload_per_credit is +smbd_max_receive_size - 24 = 1340 + +The maximum number would be +smbd_receive_credit_max * max_payload_per_credit + + 1340 * 255 = 341700 (0x536C4) + +The minimum value from the spec is 131072 (0x20000) + +For now we use the logic we used in ksmbd before: + (1364 * 255) / 2 = 173910 (0x2A756) + +Fixes: 03bee01d6215 ("CIFS: SMBD: Add SMB Direct protocol initial values and constants") +Cc: Steve French +Cc: Tom Talpey +Cc: Long Li +Cc: Namjae Jeon +Cc: linux-cifs@vger.kernel.org +Cc: samba-technical@lists.samba.org +Signed-off-by: Stefan Metzmacher +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/client/smbdirect.c | 19 +++++++++++++++++-- + 1 file changed, 17 insertions(+), 2 deletions(-) + +diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c +index 01d55bcc6d0f9..c8cef098d4806 100644 +--- a/fs/smb/client/smbdirect.c ++++ b/fs/smb/client/smbdirect.c +@@ -101,8 +101,23 @@ int smbd_send_credit_target = 255; + /* The maximum single message size can be sent to remote peer */ + int smbd_max_send_size = 1364; + +-/* The maximum fragmented upper-layer payload receive size supported */ +-int smbd_max_fragmented_recv_size = 1024 * 1024; ++/* ++ * The maximum fragmented upper-layer payload receive size supported ++ * ++ * Assume max_payload_per_credit is ++ * smbd_max_receive_size - 24 = 1340 ++ * ++ * The maximum number would be ++ * smbd_receive_credit_max * max_payload_per_credit ++ * ++ * 1340 * 255 = 341700 (0x536C4) ++ * ++ * The minimum value from the spec is 131072 (0x20000) ++ * ++ * For now we use the logic we used in ksmbd before: ++ * (1364 * 255) / 2 = 173910 (0x2A756) ++ */ ++int smbd_max_fragmented_recv_size = (1364 * 255) / 2; + + /* The maximum single-message size which can be received */ + int smbd_max_receive_size = 1364; +-- +2.51.0 + diff --git a/queue-6.18/smb-client-fix-potential-uaf-and-double-free-in-smb2.patch b/queue-6.18/smb-client-fix-potential-uaf-and-double-free-in-smb2.patch new file mode 100644 index 0000000000..3c259cd338 --- /dev/null +++ b/queue-6.18/smb-client-fix-potential-uaf-and-double-free-in-smb2.patch @@ -0,0 +1,41 @@ +From 83db1e83f4cfec1b622d9fbe8f166e028ea09c86 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 13:19:52 -0300 +Subject: smb: client: fix potential UAF and double free in smb2_open_file() + +From: Paulo Alcantara + +[ Upstream commit ebbbc4bfad4cb355d17c671223d0814ee3ef4eda ] + +Zero out @err_iov and @err_buftype before retrying SMB2_open() to +prevent an UAF bug if @data != NULL, otherwise a double free. + +Fixes: e3a43633023e ("smb/client: fix memory leak in smb2_open_file()") +Reported-by: David Howells +Closes: https://lore.kernel.org/r/2892312.1770306653@warthog.procyon.org.uk +Signed-off-by: Paulo Alcantara (Red Hat) +Reviewed-by: David Howells +Reviewed-by: ChenXiaoSong +Cc: linux-cifs@vger.kernel.org +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/client/smb2file.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/fs/smb/client/smb2file.c b/fs/smb/client/smb2file.c +index 03f90553d8319..e6cdf2efc7f4f 100644 +--- a/fs/smb/client/smb2file.c ++++ b/fs/smb/client/smb2file.c +@@ -178,6 +178,8 @@ int smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, __u32 + &err_buftype); + if (rc == -EACCES && retry_without_read_attributes) { + free_rsp_buf(err_buftype, err_iov.iov_base); ++ memset(&err_iov, 0, sizeof(err_iov)); ++ err_buftype = CIFS_NO_BUFFER; + oparms->desired_access &= ~FILE_READ_ATTRIBUTES; + rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, smb2_data, NULL, &err_iov, + &err_buftype); +-- +2.51.0 + diff --git a/queue-6.18/soc-mediatek-svs-fix-memory-leak-in-svs_enable_debug.patch b/queue-6.18/soc-mediatek-svs-fix-memory-leak-in-svs_enable_debug.patch new file mode 100644 index 0000000000..bb2adb12df --- /dev/null +++ b/queue-6.18/soc-mediatek-svs-fix-memory-leak-in-svs_enable_debug.patch @@ -0,0 +1,59 @@ +From e3558d92aea94cc7a5e958255b547d9518fa0c98 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 28 Dec 2025 16:26:36 +0000 +Subject: soc: mediatek: svs: Fix memory leak in svs_enable_debug_write() + +From: Zilin Guan + +[ Upstream commit 6259094ee806fb813ca95894c65fb80e2ec98bf1 ] + +In svs_enable_debug_write(), the buf allocated by memdup_user_nul() +is leaked if kstrtoint() fails. + +Fix this by using __free(kfree) to automatically free buf, eliminating +the need for explicit kfree() calls and preventing leaks. + +Fixes: 13f1bbcfb582 ("soc: mediatek: SVS: add debug commands") +Co-developed-by: Jianhao Xu +Signed-off-by: Jianhao Xu +Signed-off-by: Zilin Guan +[Angelo: Added missing cleanup.h inclusion] +Signed-off-by: AngeloGioacchino Del Regno +Signed-off-by: Sasha Levin +--- + drivers/soc/mediatek/mtk-svs.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/soc/mediatek/mtk-svs.c b/drivers/soc/mediatek/mtk-svs.c +index f45537546553e..99edecb204f25 100644 +--- a/drivers/soc/mediatek/mtk-svs.c ++++ b/drivers/soc/mediatek/mtk-svs.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -789,7 +790,7 @@ static ssize_t svs_enable_debug_write(struct file *filp, + struct svs_bank *svsb = file_inode(filp)->i_private; + struct svs_platform *svsp = dev_get_drvdata(svsb->dev); + int enabled, ret; +- char *buf = NULL; ++ char *buf __free(kfree) = NULL; + + if (count >= PAGE_SIZE) + return -EINVAL; +@@ -807,8 +808,6 @@ static ssize_t svs_enable_debug_write(struct file *filp, + svsb->mode_support = SVSB_MODE_ALL_DISABLE; + } + +- kfree(buf); +- + return count; + } + +-- +2.51.0 + diff --git a/queue-6.18/soc-qcom-cmd-db-use-devm_memremap-to-fix-memory-leak.patch b/queue-6.18/soc-qcom-cmd-db-use-devm_memremap-to-fix-memory-leak.patch new file mode 100644 index 0000000000..2369104c64 --- /dev/null +++ b/queue-6.18/soc-qcom-cmd-db-use-devm_memremap-to-fix-memory-leak.patch @@ -0,0 +1,53 @@ +From 43b9c12c19acf9863c27a6ace77f606c60998b23 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Dec 2025 09:39:32 +0800 +Subject: soc: qcom: cmd-db: Use devm_memremap() to fix memory leak in + cmd_db_dev_probe + +From: Haotian Zhang + +[ Upstream commit 0da7824734d8d83e6a844dd0207f071cb0c50cf4 ] + +If cmd_db_magic_matches() fails after memremap() succeeds, the function +returns -EINVAL without unmapping the memory region, causing a +potential resource leak. + +Switch to devm_memremap to automatically manage the map resource. + +Fixes: 312416d9171a ("drivers: qcom: add command DB driver") +Suggested-by: Dmitry Baryshkov +Signed-off-by: Haotian Zhang +Link: https://lore.kernel.org/r/20251216013933.773-1-vulab@iscas.ac.cn +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/cmd-db.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/soc/qcom/cmd-db.c b/drivers/soc/qcom/cmd-db.c +index ae66c2623d250..84a75d8c4b702 100644 +--- a/drivers/soc/qcom/cmd-db.c ++++ b/drivers/soc/qcom/cmd-db.c +@@ -349,15 +349,16 @@ static int cmd_db_dev_probe(struct platform_device *pdev) + return -EINVAL; + } + +- cmd_db_header = memremap(rmem->base, rmem->size, MEMREMAP_WC); +- if (!cmd_db_header) { +- ret = -ENOMEM; ++ cmd_db_header = devm_memremap(&pdev->dev, rmem->base, rmem->size, MEMREMAP_WC); ++ if (IS_ERR(cmd_db_header)) { ++ ret = PTR_ERR(cmd_db_header); + cmd_db_header = NULL; + return ret; + } + + if (!cmd_db_magic_matches(cmd_db_header)) { + dev_err(&pdev->dev, "Invalid Command DB Magic\n"); ++ cmd_db_header = NULL; + return -EINVAL; + } + +-- +2.51.0 + diff --git a/queue-6.18/soc-qcom-smem-handle-enomem-error-during-probe.patch b/queue-6.18/soc-qcom-smem-handle-enomem-error-during-probe.patch new file mode 100644 index 0000000000..b726e75695 --- /dev/null +++ b/queue-6.18/soc-qcom-smem-handle-enomem-error-during-probe.patch @@ -0,0 +1,39 @@ +From 454e955586f228a2a33353a5489150c47e1ff737 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 08:45:37 +0100 +Subject: soc: qcom: smem: handle ENOMEM error during probe + +From: Jorge Ramirez-Ortiz + +[ Upstream commit 0fe01a7955f4fef97e7cc6d14bfc5931c660402b ] + +Fail the driver probe if the region can't be mapped + +Signed-off-by: Jorge Ramirez-Ortiz +Fixes: 20bb6c9de1b7 ("soc: qcom: smem: map only partitions used by local HOST") +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20251209074610.3751781-1-jorge.ramirez@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/smem.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c +index f1d1b5aa5e4db..39177aa5793ad 100644 +--- a/drivers/soc/qcom/smem.c ++++ b/drivers/soc/qcom/smem.c +@@ -1215,7 +1215,9 @@ static int qcom_smem_probe(struct platform_device *pdev) + smem->item_count = qcom_smem_get_item_count(smem); + break; + case SMEM_GLOBAL_HEAP_VERSION: +- qcom_smem_map_global(smem, size); ++ ret = qcom_smem_map_global(smem, size); ++ if (ret < 0) ++ return ret; + smem->item_count = SMEM_ITEM_COUNT; + break; + default: +-- +2.51.0 + diff --git a/queue-6.18/soc-qcom-ubwc-add-missing-include.patch b/queue-6.18/soc-qcom-ubwc-add-missing-include.patch new file mode 100644 index 0000000000..4554d5b3d4 --- /dev/null +++ b/queue-6.18/soc-qcom-ubwc-add-missing-include.patch @@ -0,0 +1,37 @@ +From 4bbfd2fd27589836eafdae331531df55ceef4366 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 10 Jan 2026 21:37:53 +0200 +Subject: soc: qcom: ubwc: add missing include + +From: Dmitry Baryshkov + +[ Upstream commit ccef4b2703ff5b0de0b1bda30a0de3026d52eb19 ] + +The header has a function which calls pr_err(). Don't require users of +the header to include and include it here. + +Fixes: 87cfc79dcd60 ("drm/msm/a6xx: Resolve the meaning of UBWC_MODE") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Bryan O'Donoghue +Link: https://lore.kernel.org/r/20260110-iris-ubwc-v1-1-dd70494dcd7b@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + include/linux/soc/qcom/ubwc.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/include/linux/soc/qcom/ubwc.h b/include/linux/soc/qcom/ubwc.h +index 1ed8b1b16bc90..d9dfc9edc1b2f 100644 +--- a/include/linux/soc/qcom/ubwc.h ++++ b/include/linux/soc/qcom/ubwc.h +@@ -8,6 +8,7 @@ + #define __QCOM_UBWC_H__ + + #include ++#include + #include + + struct qcom_ubwc_cfg_data { +-- +2.51.0 + diff --git a/queue-6.18/soundwire-intel_ace2x-add-snd_hda_core-dependency.patch b/queue-6.18/soundwire-intel_ace2x-add-snd_hda_core-dependency.patch new file mode 100644 index 0000000000..40f3ec5dd9 --- /dev/null +++ b/queue-6.18/soundwire-intel_ace2x-add-snd_hda_core-dependency.patch @@ -0,0 +1,45 @@ +From 36876452bda7c93694ba6aa2a49308de53720f35 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 23 Dec 2025 22:50:01 +0100 +Subject: soundwire: intel_ace2x: add SND_HDA_CORE dependency + +From: Arnd Bergmann + +[ Upstream commit dc3a6a942e9ee3f18560bfcb16c06bb94f37fabf ] + +The ace2x driver can optionally use the HDA infrastructure, but can still +build without that. However, with SND_HDA_CORE=m and SND_HDA_ALIGNED_MMIO=y, +it fails to link as built-in: + +aarch64-linux-ld: drivers/soundwire/intel_ace2x.o: in function `intel_shim_wake': +intel_ace2x.c:(.text+0x2518): undefined reference to `snd_hdac_aligned_read' +aarch64-linux-ld: intel_ace2x.c:(.text+0x25d4): undefined reference to `snd_hdac_aligned_read' +aarch64-linux-ld: intel_ace2x.c:(.text+0x268c): undefined reference to `snd_hdac_aligned_write' + +Add a Kconfig dependency that forces the soundwire driver to be a loadable +module if necessary. + +Fixes: 79e7123c078d ("soundwire: intel_ace2x: fix wakeup handling") +Signed-off-by: Arnd Bergmann +Link: https://patch.msgid.link/20251223215014.534756-1-arnd@kernel.org +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/soundwire/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/soundwire/Kconfig b/drivers/soundwire/Kconfig +index ad56393e4c93b..196a7daaabdb8 100644 +--- a/drivers/soundwire/Kconfig ++++ b/drivers/soundwire/Kconfig +@@ -40,6 +40,7 @@ config SOUNDWIRE_INTEL + select AUXILIARY_BUS + depends on ACPI && SND_SOC + depends on SND_SOC_SOF_HDA_MLINK || !SND_SOC_SOF_HDA_MLINK ++ depends on SND_HDA_CORE || !SND_HDA_ALIGNED_MMIO + help + SoundWire Intel Master driver. + If you have an Intel platform which has a SoundWire Master then +-- +2.51.0 + diff --git a/queue-6.18/spi-tools-add-include-folder-to-.gitignore.patch b/queue-6.18/spi-tools-add-include-folder-to-.gitignore.patch new file mode 100644 index 0000000000..26d9dbd05c --- /dev/null +++ b/queue-6.18/spi-tools-add-include-folder-to-.gitignore.patch @@ -0,0 +1,35 @@ +From 82e0a155341bc0ade9ec7fb94b03ca3daf3aade9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 10:50:01 +0100 +Subject: spi: tools: Add include folder to .gitignore + +From: Francesco Lavra + +[ Upstream commit 5af56f30c4fcbade4a92f94dadfea517d1db9703 ] + +The Makefile for the SPI tools creates an include/linux/spi folder and some +symlinks inside it. After running `make -C spi/tools`, this folder shows up +as untracked in the git status. +Add the above folder to the .gitignore file. + +Fixes: f325b73dc4db ("spi: tools: move to tools buildsystem") +Signed-off-by: Francesco Lavra +Link: https://patch.msgid.link/20260209095001.556495-1-flavra@baylibre.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + tools/spi/.gitignore | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/tools/spi/.gitignore b/tools/spi/.gitignore +index 14ddba3d21957..038261b34ed83 100644 +--- a/tools/spi/.gitignore ++++ b/tools/spi/.gitignore +@@ -1,3 +1,4 @@ + # SPDX-License-Identifier: GPL-2.0-only + spidev_fdx + spidev_test ++include/ +-- +2.51.0 + diff --git a/queue-6.18/staging-greybus-lights-avoid-null-deref.patch b/queue-6.18/staging-greybus-lights-avoid-null-deref.patch new file mode 100644 index 0000000000..09654ebfa5 --- /dev/null +++ b/queue-6.18/staging-greybus-lights-avoid-null-deref.patch @@ -0,0 +1,55 @@ +From b516148e4c6ed6a9707968a3f8e9edcf487e00a6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 20:42:54 +0530 +Subject: staging: greybus: lights: avoid NULL deref + +From: Chaitanya Mishra + +[ Upstream commit efcffd9a6ad8d190651498d5eda53bfc7cf683a7 ] + +gb_lights_light_config() stores channel_count before allocating the +channels array. If kcalloc() fails, gb_lights_release() iterates the +non-zero count and dereferences light->channels, which is NULL. + +Allocate channels first and only then publish channels_count so the +cleanup path can't walk a NULL pointer. + +Fixes: 2870b52bae4c ("greybus: lights: add lights implementation") +Link: https://lore.kernel.org/all/20260108103700.15384-1-chaitanyamishra.ai@gmail.com/ +Reviewed-by: Rui Miguel Silva +Signed-off-by: Chaitanya Mishra +Link: https://patch.msgid.link/20260108151254.81553-1-chaitanyamishra.ai@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/staging/greybus/light.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/drivers/staging/greybus/light.c b/drivers/staging/greybus/light.c +index e509fdc715dbb..38c233a706c48 100644 +--- a/drivers/staging/greybus/light.c ++++ b/drivers/staging/greybus/light.c +@@ -1008,14 +1008,18 @@ static int gb_lights_light_config(struct gb_lights *glights, u8 id) + if (!strlen(conf.name)) + return -EINVAL; + +- light->channels_count = conf.channel_count; + light->name = kstrndup(conf.name, NAMES_MAX, GFP_KERNEL); + if (!light->name) + return -ENOMEM; +- light->channels = kcalloc(light->channels_count, ++ light->channels = kcalloc(conf.channel_count, + sizeof(struct gb_channel), GFP_KERNEL); + if (!light->channels) + return -ENOMEM; ++ /* ++ * Publish channels_count only after channels allocation so cleanup ++ * doesn't walk a NULL channels pointer on allocation failure. ++ */ ++ light->channels_count = conf.channel_count; + + /* First we collect all the configurations for all channels */ + for (i = 0; i < light->channels_count; i++) { +-- +2.51.0 + diff --git a/queue-6.18/tcp-accecn-handle-unexpected-accecn-negotiation-feed.patch b/queue-6.18/tcp-accecn-handle-unexpected-accecn-negotiation-feed.patch new file mode 100644 index 0000000000..e0fbeeb5e6 --- /dev/null +++ b/queue-6.18/tcp-accecn-handle-unexpected-accecn-negotiation-feed.patch @@ -0,0 +1,117 @@ +From 2eb71721247fa8c9b9eb2d6c6b1880a58436bb76 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Jan 2026 23:25:06 +0100 +Subject: tcp: accecn: handle unexpected AccECN negotiation feedback + +From: Chia-Yu Chang + +[ Upstream commit c5ff6b83715919767f181f13e992b5055812a194 ] + +According to Sections 3.1.2 and 3.1.3 of AccECN spec (RFC9768). + +In Section 3.1.2, it says an AccECN implementation has no need to +recognize or support the Server response labelled 'Nonce' or ECN-nonce +feedback more generally, as RFC 3540 has been reclassified as Historic. +AccECN is compatible with alternative ECN feedback integrity approaches +to the nonce. The SYN/ACK labelled 'Nonce' with (AE,CWR,ECE) = (1,0,1) +is reserved for future use. A TCP Client (A) that receives such a SYN/ACK +follows the procedure for forward compatibility given in Section 3.1.3. + +Then in Section 3.1.3, it says if a TCP Client has sent a SYN requesting +AccECN feedback with (AE,CWR,ECE) = (1,1,1) then receives a SYN/ACK with +the currently reserved combination (AE,CWR,ECE) = (1,0,1) but it does not +have logic specific to such a combination, the Client MUST enable AccECN +mode as if the SYN/ACK onfirmed that the Server supported AccECN and as +if it fed back that the IP-ECN field on the SYN had arrived unchanged. + +Fixes: 3cae34274c79 ("tcp: accecn: AccECN negotiation"). +Signed-off-by: Chia-Yu Chang +Acked-by: Paolo Abeni +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260131222515.8485-7-chia-yu.chang@nokia-bell-labs.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + include/net/tcp_ecn.h | 44 ++++++++++++++++++++++++++++++------------- + 1 file changed, 31 insertions(+), 13 deletions(-) + +diff --git a/include/net/tcp_ecn.h b/include/net/tcp_ecn.h +index 2e1637edf1d3c..a709fb1756eb7 100644 +--- a/include/net/tcp_ecn.h ++++ b/include/net/tcp_ecn.h +@@ -473,6 +473,26 @@ static inline u8 tcp_accecn_option_init(const struct sk_buff *skb, + return TCP_ACCECN_OPT_COUNTER_SEEN; + } + ++static inline void tcp_ecn_rcv_synack_accecn(struct sock *sk, ++ const struct sk_buff *skb, u8 dsf) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ tcp_ecn_mode_set(tp, TCP_ECN_MODE_ACCECN); ++ tp->syn_ect_rcv = dsf & INET_ECN_MASK; ++ /* Demand Accurate ECN option in response to the SYN on the SYN/ACK ++ * and the TCP server will try to send one more packet with an AccECN ++ * Option at a later point during the connection. ++ */ ++ if (tp->rx_opt.accecn && ++ tp->saw_accecn_opt < TCP_ACCECN_OPT_COUNTER_SEEN) { ++ u8 saw_opt = tcp_accecn_option_init(skb, tp->rx_opt.accecn); ++ ++ tcp_accecn_saw_opt_fail_recv(tp, saw_opt); ++ tp->accecn_opt_demand = 2; ++ } ++} ++ + /* See Table 2 of the AccECN draft */ + static inline void tcp_ecn_rcv_synack(struct sock *sk, const struct sk_buff *skb, + const struct tcphdr *th, u8 ip_dsfield) +@@ -495,13 +515,11 @@ static inline void tcp_ecn_rcv_synack(struct sock *sk, const struct sk_buff *skb + tcp_ecn_mode_set(tp, TCP_ECN_DISABLED); + break; + case 0x1: +- case 0x5: + /* +========+========+============+=============+ + * | A | B | SYN/ACK | Feedback | + * | | | B->A | Mode of A | + * | | | AE CWR ECE | | + * +========+========+============+=============+ +- * | AccECN | Nonce | 1 0 1 | (Reserved) | + * | AccECN | ECN | 0 0 1 | Classic ECN | + * | Nonce | AccECN | 0 0 1 | Classic ECN | + * | ECN | AccECN | 0 0 1 | Classic ECN | +@@ -509,20 +527,20 @@ static inline void tcp_ecn_rcv_synack(struct sock *sk, const struct sk_buff *skb + */ + if (tcp_ca_no_fallback_rfc3168(sk)) + tcp_ecn_mode_set(tp, TCP_ECN_DISABLED); +- else if (tcp_ecn_mode_pending(tp)) +- /* Downgrade from AccECN, or requested initially */ ++ else + tcp_ecn_mode_set(tp, TCP_ECN_MODE_RFC3168); + break; +- default: +- tcp_ecn_mode_set(tp, TCP_ECN_MODE_ACCECN); +- tp->syn_ect_rcv = ip_dsfield & INET_ECN_MASK; +- if (tp->rx_opt.accecn && +- tp->saw_accecn_opt < TCP_ACCECN_OPT_COUNTER_SEEN) { +- u8 saw_opt = tcp_accecn_option_init(skb, tp->rx_opt.accecn); +- +- tcp_accecn_saw_opt_fail_recv(tp, saw_opt); +- tp->accecn_opt_demand = 2; ++ case 0x5: ++ if (tcp_ecn_mode_pending(tp)) { ++ tcp_ecn_rcv_synack_accecn(sk, skb, ip_dsfield); ++ if (INET_ECN_is_ce(ip_dsfield)) { ++ tp->received_ce++; ++ tp->received_ce_pending++; ++ } + } ++ break; ++ default: ++ tcp_ecn_rcv_synack_accecn(sk, skb, ip_dsfield); + if (INET_ECN_is_ce(ip_dsfield) && + tcp_accecn_validate_syn_feedback(sk, ace, + tp->syn_ect_snt)) { +-- +2.51.0 + diff --git a/queue-6.18/tcp-disable-rfc3168-fallback-identifier-for-cc-modul.patch b/queue-6.18/tcp-disable-rfc3168-fallback-identifier-for-cc-modul.patch new file mode 100644 index 0000000000..d4e777776a --- /dev/null +++ b/queue-6.18/tcp-disable-rfc3168-fallback-identifier-for-cc-modul.patch @@ -0,0 +1,135 @@ +From 3e2ad738421293802511eefc29ac6012b38486ac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Jan 2026 23:25:05 +0100 +Subject: tcp: disable RFC3168 fallback identifier for CC modules + +From: Chia-Yu Chang + +[ Upstream commit e68c28f22f46ecfdec3656ae785dd8ccbb4d557d ] + +When AccECN is not successfully negociated for a TCP flow, it defaults +fallback to classic ECN (RFC3168). However, L4S service will fallback +to non-ECN. + +This patch enables congestion control module to control whether it +should not fallback to classic ECN after unsuccessful AccECN negotiation. +A new CA module flag (TCP_CONG_NO_FALLBACK_RFC3168) identifies this +behavior expected by the CA. + +Signed-off-by: Chia-Yu Chang +Acked-by: Paolo Abeni +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260131222515.8485-6-chia-yu.chang@nokia-bell-labs.com +Signed-off-by: Paolo Abeni +Stable-dep-of: c5ff6b837159 ("tcp: accecn: handle unexpected AccECN negotiation feedback") +Signed-off-by: Sasha Levin +--- + include/net/tcp.h | 12 +++++++++++- + include/net/tcp_ecn.h | 11 ++++++++--- + net/ipv4/tcp_input.c | 2 +- + net/ipv4/tcp_minisocks.c | 7 ++++--- + 4 files changed, 24 insertions(+), 8 deletions(-) + +diff --git a/include/net/tcp.h b/include/net/tcp.h +index c1db8a851243d..3c84d95cdba81 100644 +--- a/include/net/tcp.h ++++ b/include/net/tcp.h +@@ -1194,8 +1194,11 @@ enum tcp_ca_ack_event_flags { + #define TCP_CONG_NEEDS_ACCECN BIT(2) + /* Use ECT(1) instead of ECT(0) while the CA is uninitialized */ + #define TCP_CONG_ECT_1_NEGOTIATION BIT(3) ++/* Cannot fallback to RFC3168 during AccECN negotiation */ ++#define TCP_CONG_NO_FALLBACK_RFC3168 BIT(4) + #define TCP_CONG_MASK (TCP_CONG_NON_RESTRICTED | TCP_CONG_NEEDS_ECN | \ +- TCP_CONG_NEEDS_ACCECN | TCP_CONG_ECT_1_NEGOTIATION) ++ TCP_CONG_NEEDS_ACCECN | TCP_CONG_ECT_1_NEGOTIATION | \ ++ TCP_CONG_NO_FALLBACK_RFC3168) + + union tcp_cc_info; + +@@ -1341,6 +1344,13 @@ static inline bool tcp_ca_ect_1_negotiation(const struct sock *sk) + return icsk->icsk_ca_ops->flags & TCP_CONG_ECT_1_NEGOTIATION; + } + ++static inline bool tcp_ca_no_fallback_rfc3168(const struct sock *sk) ++{ ++ const struct inet_connection_sock *icsk = inet_csk(sk); ++ ++ return icsk->icsk_ca_ops->flags & TCP_CONG_NO_FALLBACK_RFC3168; ++} ++ + static inline void tcp_ca_event(struct sock *sk, const enum tcp_ca_event event) + { + const struct inet_connection_sock *icsk = inet_csk(sk); +diff --git a/include/net/tcp_ecn.h b/include/net/tcp_ecn.h +index fdde1c342b35c..2e1637edf1d3c 100644 +--- a/include/net/tcp_ecn.h ++++ b/include/net/tcp_ecn.h +@@ -507,7 +507,9 @@ static inline void tcp_ecn_rcv_synack(struct sock *sk, const struct sk_buff *skb + * | ECN | AccECN | 0 0 1 | Classic ECN | + * +========+========+============+=============+ + */ +- if (tcp_ecn_mode_pending(tp)) ++ if (tcp_ca_no_fallback_rfc3168(sk)) ++ tcp_ecn_mode_set(tp, TCP_ECN_DISABLED); ++ else if (tcp_ecn_mode_pending(tp)) + /* Downgrade from AccECN, or requested initially */ + tcp_ecn_mode_set(tp, TCP_ECN_MODE_RFC3168); + break; +@@ -531,9 +533,11 @@ static inline void tcp_ecn_rcv_synack(struct sock *sk, const struct sk_buff *skb + } + } + +-static inline void tcp_ecn_rcv_syn(struct tcp_sock *tp, const struct tcphdr *th, ++static inline void tcp_ecn_rcv_syn(struct sock *sk, const struct tcphdr *th, + const struct sk_buff *skb) + { ++ struct tcp_sock *tp = tcp_sk(sk); ++ + if (tcp_ecn_mode_pending(tp)) { + if (!tcp_accecn_syn_requested(th)) { + /* Downgrade to classic ECN feedback */ +@@ -545,7 +549,8 @@ static inline void tcp_ecn_rcv_syn(struct tcp_sock *tp, const struct tcphdr *th, + tcp_ecn_mode_set(tp, TCP_ECN_MODE_ACCECN); + } + } +- if (tcp_ecn_mode_rfc3168(tp) && (!th->ece || !th->cwr)) ++ if (tcp_ecn_mode_rfc3168(tp) && ++ (!th->ece || !th->cwr || tcp_ca_no_fallback_rfc3168(sk))) + tcp_ecn_mode_set(tp, TCP_ECN_DISABLED); + } + +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index f920fa44c3d39..ede266463d5d1 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -6817,7 +6817,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, + tp->snd_wl1 = TCP_SKB_CB(skb)->seq; + tp->max_window = tp->snd_wnd; + +- tcp_ecn_rcv_syn(tp, th, skb); ++ tcp_ecn_rcv_syn(sk, th, skb); + + tcp_mtup_init(sk); + tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); +diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c +index 2ec8c6f1cdccc..1fade94813c62 100644 +--- a/net/ipv4/tcp_minisocks.c ++++ b/net/ipv4/tcp_minisocks.c +@@ -488,9 +488,10 @@ static void tcp_ecn_openreq_child(struct sock *sk, + tp->accecn_opt_demand = 1; + tcp_ecn_received_counters_payload(sk, skb); + } else { +- tcp_ecn_mode_set(tp, inet_rsk(req)->ecn_ok ? +- TCP_ECN_MODE_RFC3168 : +- TCP_ECN_DISABLED); ++ if (inet_rsk(req)->ecn_ok && !tcp_ca_no_fallback_rfc3168(sk)) ++ tcp_ecn_mode_set(tp, TCP_ECN_MODE_RFC3168); ++ else ++ tcp_ecn_mode_set(tp, TCP_ECN_DISABLED); + } + } + +-- +2.51.0 + diff --git a/queue-6.18/tcp-ect_1_negotiation-and-needs_accecn-identifiers.patch b/queue-6.18/tcp-ect_1_negotiation-and-needs_accecn-identifiers.patch new file mode 100644 index 0000000000..ebce470f5e --- /dev/null +++ b/queue-6.18/tcp-ect_1_negotiation-and-needs_accecn-identifiers.patch @@ -0,0 +1,207 @@ +From 8bd8fbd0cddae5be9bb646fa3e5d91321aa16aae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Jan 2026 23:25:04 +0100 +Subject: tcp: ECT_1_NEGOTIATION and NEEDS_ACCECN identifiers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Chia-Yu Chang + +[ Upstream commit 100f946b8d44b64bc0b8a8c30d283105031c0a77 ] + +Two flags for congestion control (CC) module are added in this patch +related to AccECN negotiation. First, a new flag (TCP_CONG_NEEDS_ACCECN) +defines that the CC expects to negotiate AccECN functionality using the +ECE, CWR and AE flags in the TCP header. + +Second, during ECN negotiation, ECT(0) in the IP header is used. This +patch enables CC to control whether ECT(0) or ECT(1) should be used on +a per-segment basis. A new flag (TCP_CONG_ECT_1_NEGOTIATION) defines the +expected ECT value in the IP header by the CA when not-yet initialized +for the connection. + +The detailed AccECN negotiaotn can be found in IETF RFC9768. + +Co-developed-by: Olivier Tilmans +Signed-off-by: Olivier Tilmans +Signed-off-by: Ilpo Järvinen +Signed-off-by: Chia-Yu Chang +Acked-by: Paolo Abeni +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260131222515.8485-5-chia-yu.chang@nokia-bell-labs.com +Signed-off-by: Paolo Abeni +Stable-dep-of: c5ff6b837159 ("tcp: accecn: handle unexpected AccECN negotiation feedback") +Signed-off-by: Sasha Levin +--- + include/net/inet_ecn.h | 20 +++++++++++++++++--- + include/net/tcp.h | 21 ++++++++++++++++++++- + include/net/tcp_ecn.h | 13 ++++++++++--- + net/ipv4/tcp_cong.c | 5 +++-- + net/ipv4/tcp_input.c | 3 ++- + 5 files changed, 52 insertions(+), 10 deletions(-) + +diff --git a/include/net/inet_ecn.h b/include/net/inet_ecn.h +index ea32393464a29..827b87a95dab3 100644 +--- a/include/net/inet_ecn.h ++++ b/include/net/inet_ecn.h +@@ -51,11 +51,25 @@ static inline __u8 INET_ECN_encapsulate(__u8 outer, __u8 inner) + return outer; + } + ++/* Apply either ECT(0) or ECT(1) */ ++static inline void __INET_ECN_xmit(struct sock *sk, bool use_ect_1) ++{ ++ __u8 ect = use_ect_1 ? INET_ECN_ECT_1 : INET_ECN_ECT_0; ++ ++ /* Mask the complete byte in case the connection alternates between ++ * ECT(0) and ECT(1). ++ */ ++ inet_sk(sk)->tos &= ~INET_ECN_MASK; ++ inet_sk(sk)->tos |= ect; ++ if (inet6_sk(sk)) { ++ inet6_sk(sk)->tclass &= ~INET_ECN_MASK; ++ inet6_sk(sk)->tclass |= ect; ++ } ++} ++ + static inline void INET_ECN_xmit(struct sock *sk) + { +- inet_sk(sk)->tos |= INET_ECN_ECT_0; +- if (inet6_sk(sk) != NULL) +- inet6_sk(sk)->tclass |= INET_ECN_ECT_0; ++ __INET_ECN_xmit(sk, false); + } + + static inline void INET_ECN_dontxmit(struct sock *sk) +diff --git a/include/net/tcp.h b/include/net/tcp.h +index ab20f549b8f91..c1db8a851243d 100644 +--- a/include/net/tcp.h ++++ b/include/net/tcp.h +@@ -1190,7 +1190,12 @@ enum tcp_ca_ack_event_flags { + #define TCP_CONG_NON_RESTRICTED BIT(0) + /* Requires ECN/ECT set on all packets */ + #define TCP_CONG_NEEDS_ECN BIT(1) +-#define TCP_CONG_MASK (TCP_CONG_NON_RESTRICTED | TCP_CONG_NEEDS_ECN) ++/* Require successfully negotiated AccECN capability */ ++#define TCP_CONG_NEEDS_ACCECN BIT(2) ++/* Use ECT(1) instead of ECT(0) while the CA is uninitialized */ ++#define TCP_CONG_ECT_1_NEGOTIATION BIT(3) ++#define TCP_CONG_MASK (TCP_CONG_NON_RESTRICTED | TCP_CONG_NEEDS_ECN | \ ++ TCP_CONG_NEEDS_ACCECN | TCP_CONG_ECT_1_NEGOTIATION) + + union tcp_cc_info; + +@@ -1322,6 +1327,20 @@ static inline bool tcp_ca_needs_ecn(const struct sock *sk) + return icsk->icsk_ca_ops->flags & TCP_CONG_NEEDS_ECN; + } + ++static inline bool tcp_ca_needs_accecn(const struct sock *sk) ++{ ++ const struct inet_connection_sock *icsk = inet_csk(sk); ++ ++ return icsk->icsk_ca_ops->flags & TCP_CONG_NEEDS_ACCECN; ++} ++ ++static inline bool tcp_ca_ect_1_negotiation(const struct sock *sk) ++{ ++ const struct inet_connection_sock *icsk = inet_csk(sk); ++ ++ return icsk->icsk_ca_ops->flags & TCP_CONG_ECT_1_NEGOTIATION; ++} ++ + static inline void tcp_ca_event(struct sock *sk, const enum tcp_ca_event event) + { + const struct inet_connection_sock *icsk = inet_csk(sk); +diff --git a/include/net/tcp_ecn.h b/include/net/tcp_ecn.h +index f13e5cd2b1ac3..fdde1c342b35c 100644 +--- a/include/net/tcp_ecn.h ++++ b/include/net/tcp_ecn.h +@@ -31,6 +31,12 @@ enum tcp_accecn_option { + TCP_ACCECN_OPTION_FULL = 2, + }; + ++/* Apply either ECT(0) or ECT(1) based on TCP_CONG_ECT_1_NEGOTIATION flag */ ++static inline void INET_ECN_xmit_ect_1_negotiation(struct sock *sk) ++{ ++ __INET_ECN_xmit(sk, tcp_ca_ect_1_negotiation(sk)); ++} ++ + static inline void tcp_ecn_queue_cwr(struct tcp_sock *tp) + { + /* Do not set CWR if in AccECN mode! */ +@@ -561,7 +567,7 @@ static inline void tcp_ecn_send_synack(struct sock *sk, struct sk_buff *skb) + TCP_SKB_CB(skb)->tcp_flags &= ~TCPHDR_ECE; + else if (tcp_ca_needs_ecn(sk) || + tcp_bpf_ca_needs_ecn(sk)) +- INET_ECN_xmit(sk); ++ INET_ECN_xmit_ect_1_negotiation(sk); + + if (tp->ecn_flags & TCP_ECN_MODE_ACCECN) { + TCP_SKB_CB(skb)->tcp_flags &= ~TCPHDR_ACE; +@@ -579,7 +585,8 @@ static inline void tcp_ecn_send_syn(struct sock *sk, struct sk_buff *skb) + bool use_ecn, use_accecn; + u8 tcp_ecn = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_ecn); + +- use_accecn = tcp_ecn == TCP_ECN_IN_ACCECN_OUT_ACCECN; ++ use_accecn = tcp_ecn == TCP_ECN_IN_ACCECN_OUT_ACCECN || ++ tcp_ca_needs_accecn(sk); + use_ecn = tcp_ecn == TCP_ECN_IN_ECN_OUT_ECN || + tcp_ecn == TCP_ECN_IN_ACCECN_OUT_ECN || + tcp_ca_needs_ecn(sk) || bpf_needs_ecn || use_accecn; +@@ -595,7 +602,7 @@ static inline void tcp_ecn_send_syn(struct sock *sk, struct sk_buff *skb) + + if (use_ecn) { + if (tcp_ca_needs_ecn(sk) || bpf_needs_ecn) +- INET_ECN_xmit(sk); ++ INET_ECN_xmit_ect_1_negotiation(sk); + + TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_ECE | TCPHDR_CWR; + if (use_accecn) { +diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c +index df758adbb445f..e9f6c77e06316 100644 +--- a/net/ipv4/tcp_cong.c ++++ b/net/ipv4/tcp_cong.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + #include + + static DEFINE_SPINLOCK(tcp_cong_list_lock); +@@ -227,7 +228,7 @@ void tcp_assign_congestion_control(struct sock *sk) + + memset(icsk->icsk_ca_priv, 0, sizeof(icsk->icsk_ca_priv)); + if (ca->flags & TCP_CONG_NEEDS_ECN) +- INET_ECN_xmit(sk); ++ INET_ECN_xmit_ect_1_negotiation(sk); + else + INET_ECN_dontxmit(sk); + } +@@ -257,7 +258,7 @@ static void tcp_reinit_congestion_control(struct sock *sk, + memset(icsk->icsk_ca_priv, 0, sizeof(icsk->icsk_ca_priv)); + + if (ca->flags & TCP_CONG_NEEDS_ECN) +- INET_ECN_xmit(sk); ++ INET_ECN_xmit_ect_1_negotiation(sk); + else + INET_ECN_dontxmit(sk); + +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index e4a979b75cc66..f920fa44c3d39 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -7222,7 +7222,8 @@ static void tcp_ecn_create_request(struct request_sock *req, + u32 ecn_ok_dst; + + if (tcp_accecn_syn_requested(th) && +- READ_ONCE(net->ipv4.sysctl_tcp_ecn) >= 3) { ++ (READ_ONCE(net->ipv4.sysctl_tcp_ecn) >= 3 || ++ tcp_ca_needs_accecn(listen_sk))) { + inet_rsk(req)->ecn_ok = 1; + tcp_rsk(req)->accecn_ok = 1; + tcp_rsk(req)->syn_ect_rcv = TCP_SKB_CB(skb)->ip_dsfield & +-- +2.51.0 + diff --git a/queue-6.18/tcp-tcp_tx_timestamp-must-look-at-the-rtx-queue.patch b/queue-6.18/tcp-tcp_tx_timestamp-must-look-at-the-rtx-queue.patch new file mode 100644 index 0000000000..1d6e67f482 --- /dev/null +++ b/queue-6.18/tcp-tcp_tx_timestamp-must-look-at-the-rtx-queue.patch @@ -0,0 +1,44 @@ +From 7cfb869a892b0bb53fe55b0e21984dc044fc72c2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 12:38:27 +0000 +Subject: tcp: tcp_tx_timestamp() must look at the rtx queue + +From: Eric Dumazet + +[ Upstream commit 838eb9687691d29915797a885b861fd09353386e ] + +tcp_tx_timestamp() is only called at the end of tcp_sendmsg_locked() +before the final tcp_push(). + +By the time it is called, it is possible all the copied data +has been sent already (transmit queue is empty). + +If this is the case, use the last skb in the rtx queue. + +Fixes: 75c119afe14f ("tcp: implement rb-tree based retransmit queue") +Signed-off-by: Eric Dumazet +Reviewed-by: Jason Xing +Link: https://patch.msgid.link/20260127123828.4098577-2-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 74079eab89804..e35825656e6ea 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -503,6 +503,9 @@ static void tcp_tx_timestamp(struct sock *sk, struct sockcm_cookie *sockc) + struct sk_buff *skb = tcp_write_queue_tail(sk); + u32 tsflags = sockc->tsflags; + ++ if (unlikely(!skb)) ++ skb = skb_rb_last(&sk->tcp_rtx_queue); ++ + if (tsflags && skb) { + struct skb_shared_info *shinfo = skb_shinfo(skb); + struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); +-- +2.51.0 + diff --git a/queue-6.18/thermal-intel-x86_pkg_temp_thermal-handle-invalid-te.patch b/queue-6.18/thermal-intel-x86_pkg_temp_thermal-handle-invalid-te.patch new file mode 100644 index 0000000000..d8b254ea14 --- /dev/null +++ b/queue-6.18/thermal-intel-x86_pkg_temp_thermal-handle-invalid-te.patch @@ -0,0 +1,43 @@ +From 74e8c41e50c4dacb29ed76277865d0eb64e2516c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 16:23:41 +0100 +Subject: thermal: intel: x86_pkg_temp_thermal: Handle invalid temperature + +From: Rafael J. Wysocki + +[ Upstream commit 9635c586a559ba0e45b2bfbff79c937ddbaf1a62 ] + +After commit be0a3600aa1e ("thermal: sysfs: Rework the handling of trip +point updates"), THERMAL_TEMP_INVALID can be passed to sys_set_trip_temp() +and it is treated as a regular temperature value there, so the sysfs +write fails even though it is expected to succeed and disable the given +trip point. + +Address this by making sys_set_trip_temp() clear its temp variable when +it is equal to THERMAL_TEMP_INVALID. + +Fixes: be0a3600aa1e ("thermal: sysfs: Rework the handling of trip point updates") +Signed-off-by: Rafael J. Wysocki +Link: https://patch.msgid.link/2815400.mvXUDI8C0e@rafael.j.wysocki +Signed-off-by: Sasha Levin +--- + drivers/thermal/intel/x86_pkg_temp_thermal.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/thermal/intel/x86_pkg_temp_thermal.c b/drivers/thermal/intel/x86_pkg_temp_thermal.c +index 3fc679b6f11b1..aab5f9fca9c33 100644 +--- a/drivers/thermal/intel/x86_pkg_temp_thermal.c ++++ b/drivers/thermal/intel/x86_pkg_temp_thermal.c +@@ -128,6 +128,9 @@ sys_set_trip_temp(struct thermal_zone_device *tzd, + u32 l, h, mask, shift, intr; + int tj_max, val, ret; + ++ if (temp == THERMAL_TEMP_INVALID) ++ temp = 0; ++ + tj_max = intel_tcc_get_tjmax(zonedev->cpu); + if (tj_max < 0) + return tj_max; +-- +2.51.0 + diff --git a/queue-6.18/thermal-of-fix-reference-leak-in-thermal_of_cm_looku.patch b/queue-6.18/thermal-of-fix-reference-leak-in-thermal_of_cm_looku.patch new file mode 100644 index 0000000000..60817690b4 --- /dev/null +++ b/queue-6.18/thermal-of-fix-reference-leak-in-thermal_of_cm_looku.patch @@ -0,0 +1,46 @@ +From c00d771882dd6946d825ea8013672ed9699053ed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 24 Jan 2026 03:06:40 +0800 +Subject: thermal/of: Fix reference leak in thermal_of_cm_lookup() + +From: Felix Gu + +[ Upstream commit a1fe789a96fe47733c133134fd264cb7ca832395 ] + +In thermal_of_cm_lookup(), tr_np is obtained via of_parse_phandle(), but +never released. + +Use the __free(device_node) cleanup attribute to automatically release +the node and fix the leak. + +Fixes: 423de5b5bc5b ("thermal/of: Fix cdev lookup in thermal_of_should_bind()") +Signed-off-by: Felix Gu +Reviewed-by: Lukasz Luba +[ rjw: Changelog edits ] +Link: https://patch.msgid.link/20260124-thermal_of-v1-1-54d3416948cf@gmail.com +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/thermal/thermal_of.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/thermal/thermal_of.c b/drivers/thermal/thermal_of.c +index 1a51a4d240ff6..b6d0c92f5522b 100644 +--- a/drivers/thermal/thermal_of.c ++++ b/drivers/thermal/thermal_of.c +@@ -280,10 +280,10 @@ static bool thermal_of_cm_lookup(struct device_node *cm_np, + struct cooling_spec *c) + { + for_each_child_of_node_scoped(cm_np, child) { +- struct device_node *tr_np; + int count, i; + +- tr_np = of_parse_phandle(child, "trip", 0); ++ struct device_node *tr_np __free(device_node) = ++ of_parse_phandle(child, "trip", 0); + if (tr_np != trip->priv) + continue; + +-- +2.51.0 + diff --git a/queue-6.18/time-sched_clock-use-access_private-to-evaluate-hrti.patch b/queue-6.18/time-sched_clock-use-access_private-to-evaluate-hrti.patch new file mode 100644 index 0000000000..e93363e812 --- /dev/null +++ b/queue-6.18/time-sched_clock-use-access_private-to-evaluate-hrti.patch @@ -0,0 +1,38 @@ +From e2ffb701c6092dcaf66144cda173ed76f5aae25b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Jan 2026 17:47:37 +0100 +Subject: time/sched_clock: Use ACCESS_PRIVATE() to evaluate hrtimer::function + +From: Thomas Gleixner + +[ Upstream commit 3db5306b0bd562ac0fe7eddad26c60ebb6f5fdd4 ] + +This dereference of sched_clock_timer::function was missed when the +hrtimer callback function pointer was marked private. + +Fixes: 04257da0c99c ("hrtimers: Make callback function pointer private") +Reported-by: kernel test robot +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/875x95jw7q.ffs@tglx +Closes: https://lore.kernel.org/oe-kbuild-all/202601131713.KsxhXQ0M-lkp@intel.com/ +Signed-off-by: Sasha Levin +--- + kernel/time/sched_clock.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/time/sched_clock.c b/kernel/time/sched_clock.c +index cc1afec306b3f..425d429906d0d 100644 +--- a/kernel/time/sched_clock.c ++++ b/kernel/time/sched_clock.c +@@ -215,7 +215,7 @@ void sched_clock_register(u64 (*read)(void), int bits, unsigned long rate) + + update_clock_read_data(&rd); + +- if (sched_clock_timer.function != NULL) { ++ if (ACCESS_PRIVATE(&sched_clock_timer, function) != NULL) { + /* update timeout for clock wrap */ + hrtimer_start(&sched_clock_timer, cd.wrap_kt, + HRTIMER_MODE_REL_HARD); +-- +2.51.0 + diff --git a/queue-6.18/tools-power-x86-intel-speed-select-fix-file-descript.patch b/queue-6.18/tools-power-x86-intel-speed-select-fix-file-descript.patch new file mode 100644 index 0000000000..f168829fd9 --- /dev/null +++ b/queue-6.18/tools-power-x86-intel-speed-select-fix-file-descript.patch @@ -0,0 +1,50 @@ +From c67493ff22cec8459d0c4fe0b6b0c48b32063341 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 15:33:33 +0530 +Subject: tools/power/x86/intel-speed-select: Fix file descriptor leak in + isolate_cpus() + +From: Malaya Kumar Rout + +[ Upstream commit 56c17ee151c6e1a73d77e15b82a8e2130cd8dd16 ] + +The file descriptor opened in isolate_cpus() when (!level) is true was +not being closed before returning, causing a file descriptor leak in +both the error path and the success path. + +When write() fails at line 950, the function returns at line 953 without +closing the file descriptor. Similarly, on success, the function returns +at line 956 without closing the file descriptor. + +Add close(fd) calls before both return statements to fix the resource +leak. This follows the same pattern used elsewhere in the same function +where file descriptors are properly closed before returning (see lines +1005 and 1027). + +Fixes: 997074df658e ("tools/power/x86/intel-speed-select: Use cgroup v2 isolation") +Signed-off-by: Malaya Kumar Rout +Signed-off-by: Srinivas Pandruvada +Signed-off-by: Sasha Levin +--- + tools/power/x86/intel-speed-select/isst-config.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/tools/power/x86/intel-speed-select/isst-config.c b/tools/power/x86/intel-speed-select/isst-config.c +index 0ce251b8d4665..a7d54dfd3c68b 100644 +--- a/tools/power/x86/intel-speed-select/isst-config.c ++++ b/tools/power/x86/intel-speed-select/isst-config.c +@@ -950,9 +950,11 @@ int isolate_cpus(struct isst_id *id, int mask_size, cpu_set_t *cpu_mask, int lev + ret = write(fd, "member", strlen("member")); + if (ret == -1) { + printf("Can't update to member\n"); ++ close(fd); + return ret; + } + ++ close(fd); + return 0; + } + +-- +2.51.0 + diff --git a/queue-6.18/tpm-st33zp24-fix-missing-cleanup-on-get_burstcount-e.patch b/queue-6.18/tpm-st33zp24-fix-missing-cleanup-on-get_burstcount-e.patch new file mode 100644 index 0000000000..686a4344a3 --- /dev/null +++ b/queue-6.18/tpm-st33zp24-fix-missing-cleanup-on-get_burstcount-e.patch @@ -0,0 +1,43 @@ +From a2620f88039ef4a265fe10d49debc066d9711030 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Dec 2025 15:09:27 +0300 +Subject: tpm: st33zp24: Fix missing cleanup on get_burstcount() error + +From: Alper Ak + +[ Upstream commit 3e91b44c93ad2871f89fc2a98c5e4fe6ca5db3d9 ] + +get_burstcount() can return -EBUSY on timeout. When this happens, +st33zp24_send() returns directly without releasing the locality +acquired earlier. + +Use goto out_err to ensure proper cleanup when get_burstcount() fails. + +Fixes: bf38b8710892 ("tpm/tpm_i2c_stm_st33: Split tpm_i2c_tpm_st33 in 2 layers (core + phy)") +Signed-off-by: Alper Ak +Signed-off-by: Jarkko Sakkinen +Signed-off-by: Sasha Levin +--- + drivers/char/tpm/st33zp24/st33zp24.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/char/tpm/st33zp24/st33zp24.c b/drivers/char/tpm/st33zp24/st33zp24.c +index 2ed7815e4899b..e2b7451ea7ccd 100644 +--- a/drivers/char/tpm/st33zp24/st33zp24.c ++++ b/drivers/char/tpm/st33zp24/st33zp24.c +@@ -328,8 +328,10 @@ static int st33zp24_send(struct tpm_chip *chip, unsigned char *buf, + + for (i = 0; i < len - 1;) { + burstcnt = get_burstcount(chip); +- if (burstcnt < 0) +- return burstcnt; ++ if (burstcnt < 0) { ++ ret = burstcnt; ++ goto out_err; ++ } + size = min_t(int, len - i - 1, burstcnt); + ret = tpm_dev->ops->send(tpm_dev->phy_id, TPM_DATA_FIFO, + buf + i, size); +-- +2.51.0 + diff --git a/queue-6.18/tpm-tpm_i2c_infineon-fix-locality-leak-on-get_burstc.patch b/queue-6.18/tpm-tpm_i2c_infineon-fix-locality-leak-on-get_burstc.patch new file mode 100644 index 0000000000..1ec7bf1696 --- /dev/null +++ b/queue-6.18/tpm-tpm_i2c_infineon-fix-locality-leak-on-get_burstc.patch @@ -0,0 +1,44 @@ +From 625462b0a69ec7ac3612b6f639ef2b4bebd67b3a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Dec 2025 13:23:38 +0300 +Subject: tpm: tpm_i2c_infineon: Fix locality leak on get_burstcount() failure + +From: Alper Ak + +[ Upstream commit bbd6e97c836cbeb9606d7b7e5dcf8a1d89525713 ] + +get_burstcount() can return -EBUSY on timeout. When this happens, the +function returns directly without releasing the locality that was +acquired at the beginning of tpm_tis_i2c_send(). + +Use goto out_err to ensure proper cleanup when get_burstcount() fails. + +Fixes: aad628c1d91a ("char/tpm: Add new driver for Infineon I2C TIS TPM") +Signed-off-by: Alper Ak +Reviewed-by: Jarkko Sakkinen +Signed-off-by: Jarkko Sakkinen +Signed-off-by: Sasha Levin +--- + drivers/char/tpm/tpm_i2c_infineon.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c +index bdf1f329a6794..8b7d32de0b2ef 100644 +--- a/drivers/char/tpm/tpm_i2c_infineon.c ++++ b/drivers/char/tpm/tpm_i2c_infineon.c +@@ -544,8 +544,10 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t bufsiz, + burstcnt = get_burstcount(chip); + + /* burstcnt < 0 = TPM is busy */ +- if (burstcnt < 0) +- return burstcnt; ++ if (burstcnt < 0) { ++ rc = burstcnt; ++ goto out_err; ++ } + + if (burstcnt > (len - 1 - count)) + burstcnt = len - 1 - count; +-- +2.51.0 + diff --git a/queue-6.18/tracing-properly-process-error-handling-in-event_his.patch b/queue-6.18/tracing-properly-process-error-handling-in-event_his.patch new file mode 100644 index 0000000000..5a9ceac89b --- /dev/null +++ b/queue-6.18/tracing-properly-process-error-handling-in-event_his.patch @@ -0,0 +1,51 @@ +From 9fa213c7096e2cb32acfef78fda100ce7a414083 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 11 Dec 2025 14:00:58 +0400 +Subject: tracing: Properly process error handling in + event_hist_trigger_parse() + +From: Miaoqian Lin + +[ Upstream commit 0550069cc25f513ce1f109c88f7c1f01d63297db ] + +Memory allocated with trigger_data_alloc() requires trigger_data_free() +for proper cleanup. + +Replace kfree() with trigger_data_free() to fix this. + +Found via static analysis and code review. + +This isn't a real bug due to the current code basically being an open +coded version of trigger_data_free() without the synchronization. The +synchronization isn't needed as this is the error path of creation and +there's nothing to synchronize against yet. Replace the kfree() to be +consistent with the allocation. + +Cc: Masami Hiramatsu +Cc: Mathieu Desnoyers +Cc: Tom Zanussi +Link: https://patch.msgid.link/20251211100058.2381268-1-linmq006@gmail.com +Fixes: e1f187d09e11 ("tracing: Have existing event_command.parse() implementations use helpers") +Signed-off-by: Miaoqian Lin +Signed-off-by: Steven Rostedt (Google) +Signed-off-by: Sasha Levin +--- + kernel/trace/trace_events_hist.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c +index 425ae26064bab..45727c4cf9545 100644 +--- a/kernel/trace/trace_events_hist.c ++++ b/kernel/trace/trace_events_hist.c +@@ -6909,7 +6909,7 @@ static int event_hist_trigger_parse(struct event_command *cmd_ops, + + remove_hist_vars(hist_data); + +- kfree(trigger_data); ++ trigger_data_free(trigger_data); + + destroy_hist_data(hist_data); + goto out; +-- +2.51.0 + diff --git a/queue-6.18/tracing-remove-duplicate-enable_event_str-and-disabl.patch b/queue-6.18/tracing-remove-duplicate-enable_event_str-and-disabl.patch new file mode 100644 index 0000000000..050c704654 --- /dev/null +++ b/queue-6.18/tracing-remove-duplicate-enable_event_str-and-disabl.patch @@ -0,0 +1,44 @@ +From b83f52168fecd1644e59bd491f319fa4fe7eddee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 13:00:37 -0500 +Subject: tracing: Remove duplicate ENABLE_EVENT_STR and DISABLE_EVENT_STR + macros + +From: Steven Rostedt + +[ Upstream commit 9df0e49c5b9b8d051529be9994e4f92f2d20be6f ] + +The macros ENABLE_EVENT_STR and DISABLE_EVENT_STR were added to trace.h so +that more than one file can have access to them, but was never removed +from their original location. Remove the duplicates. + +Cc: Masami Hiramatsu +Cc: Mathieu Desnoyers +Cc: Tom Zanussi +Link: https://patch.msgid.link/20260126130037.4ba201f9@gandalf.local.home +Fixes: d0bad49bb0a09 ("tracing: Add enable_hist/disable_hist triggers") +Signed-off-by: Steven Rostedt (Google) +Signed-off-by: Sasha Levin +--- + kernel/trace/trace_events.c | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c +index 099f081329021..5cf55a9c6fad4 100644 +--- a/kernel/trace/trace_events.c ++++ b/kernel/trace/trace_events.c +@@ -3964,11 +3964,6 @@ void trace_put_event_file(struct trace_event_file *file) + EXPORT_SYMBOL_GPL(trace_put_event_file); + + #ifdef CONFIG_DYNAMIC_FTRACE +- +-/* Avoid typos */ +-#define ENABLE_EVENT_STR "enable_event" +-#define DISABLE_EVENT_STR "disable_event" +- + struct event_probe_data { + struct trace_event_file *file; + unsigned long count; +-- +2.51.0 + diff --git a/queue-6.18/ublk-restore-auto-buf-unregister-refcount-optimizati.patch b/queue-6.18/ublk-restore-auto-buf-unregister-refcount-optimizati.patch new file mode 100644 index 0000000000..53c955b92d --- /dev/null +++ b/queue-6.18/ublk-restore-auto-buf-unregister-refcount-optimizati.patch @@ -0,0 +1,52 @@ +From bb023a788fb3ded53d7a6207e6b9075f0ff68f09 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 13:56:34 -0700 +Subject: ublk: restore auto buf unregister refcount optimization + +From: Caleb Sander Mateos + +[ Upstream commit ad5f2e2908c9b79a86529281a48e94d644d43dc7 ] + +Commit 1ceeedb59749 ("ublk: optimize UBLK_IO_UNREGISTER_IO_BUF on daemon +task") optimized ublk request buffer unregistration to use a non-atomic +reference count decrement when performed on the ublk_io's daemon task. +The optimization applied to auto buffer unregistration, which happens as +part of handling UBLK_IO_COMMIT_AND_FETCH_REQ on the daemon task. +However, commit b749965edda8 ("ublk: remove ublk_commit_and_fetch()") +reordered the ublk_sub_req_ref() for the completed request before the +io_buffer_unregister_bvec() call. As a result, task_registered_buffers +is already 0 when io_buffer_unregister_bvec() calls ublk_io_release() +and the non-atomic refcount optimization doesn't apply. +Move the io_buffer_unregister_bvec() call back to before +ublk_need_complete_req() to restore the reference counting optimization. + +Signed-off-by: Caleb Sander Mateos +Fixes: b749965edda8 ("ublk: remove ublk_commit_and_fetch()") +Reviewed-by: Ming Lei +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/block/ublk_drv.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c +index 4b6d7b785d7b3..56058090d223e 100644 +--- a/drivers/block/ublk_drv.c ++++ b/drivers/block/ublk_drv.c +@@ -2526,11 +2526,11 @@ static int ublk_ch_uring_cmd_local(struct io_uring_cmd *cmd, + io->res = result; + req = ublk_fill_io_cmd(io, cmd); + ret = ublk_config_io_buf(ub, io, cmd, addr, &buf_idx); ++ if (buf_idx != UBLK_INVALID_BUF_IDX) ++ io_buffer_unregister_bvec(cmd, buf_idx, issue_flags); + compl = ublk_need_complete_req(ub, io); + + /* can't touch 'ublk_io' any more */ +- if (buf_idx != UBLK_INVALID_BUF_IDX) +- io_buffer_unregister_bvec(cmd, buf_idx, issue_flags); + if (req_op(req) == REQ_OP_ZONE_APPEND) + req->__sector = addr; + if (compl) +-- +2.51.0 + diff --git a/queue-6.18/ublk-validate-sqe128-flag-before-accessing-the-cmd.patch b/queue-6.18/ublk-validate-sqe128-flag-before-accessing-the-cmd.patch new file mode 100644 index 0000000000..1472fcff87 --- /dev/null +++ b/queue-6.18/ublk-validate-sqe128-flag-before-accessing-the-cmd.patch @@ -0,0 +1,47 @@ +From e159ddcbca34a4ee3f33349a87880e0bb8f274b0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 10:14:12 -0700 +Subject: ublk: Validate SQE128 flag before accessing the cmd + +From: Govindarajulu Varadarajan + +[ Upstream commit da7e4b75e50c087d2031a92f6646eb90f7045a67 ] + +ublk_ctrl_cmd_dump() accesses (header *)sqe->cmd before +IO_URING_F_SQE128 flag check. This could cause out of boundary memory +access. + +Move the SQE128 flag check earlier in ublk_ctrl_uring_cmd() to return +-EINVAL immediately if the flag is not set. + +Fixes: 71f28f3136af ("ublk_drv: add io_uring based userspace block driver") +Signed-off-by: Govindarajulu Varadarajan +Reviewed-by: Caleb Sander Mateos +Reviewed-by: Ming Lei +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/block/ublk_drv.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c +index 56058090d223e..965460d4fc76e 100644 +--- a/drivers/block/ublk_drv.c ++++ b/drivers/block/ublk_drv.c +@@ -3841,10 +3841,10 @@ static int ublk_ctrl_uring_cmd(struct io_uring_cmd *cmd, + if (issue_flags & IO_URING_F_NONBLOCK) + return -EAGAIN; + +- ublk_ctrl_cmd_dump(cmd); +- + if (!(issue_flags & IO_URING_F_SQE128)) +- goto out; ++ return -EINVAL; ++ ++ ublk_ctrl_cmd_dump(cmd); + + ret = ublk_check_cmd_op(cmd_op); + if (ret) +-- +2.51.0 + diff --git a/queue-6.18/ucount-check-for-cap_sys_resource-using-ns_capable_n.patch b/queue-6.18/ucount-check-for-cap_sys_resource-using-ns_capable_n.patch new file mode 100644 index 0000000000..f22cd677d7 --- /dev/null +++ b/queue-6.18/ucount-check-for-cap_sys_resource-using-ns_capable_n.patch @@ -0,0 +1,51 @@ +From bd083f5463ad790a9f0be5a8e0a3a3eded7ac632 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 15:07:45 +0100 +Subject: ucount: check for CAP_SYS_RESOURCE using ns_capable_noaudit() + +From: Ondrej Mosnacek + +[ Upstream commit 0895a000e4fff9e950a7894210db45973e485c35 ] + +The user.* sysctls implement the ctl_table_root::permissions hook and they +override the file access mode based on the CAP_SYS_RESOURCE capability (at +most rwx if capable, at most r-- if not). The capability is being checked +unconditionally, so if an LSM denies the capability, an audit record may +be logged even when access is in fact granted. + +Given the logic in the set_permissions() function in kernel/ucount.c and +the unfortunate way the permission checking is implemented, it doesn't +seem viable to avoid false positive denials by deferring the capability +check. Thus, do the same as in net_ctl_permissions() (net/sysctl_net.c) - +switch from ns_capable() to ns_capable_noaudit(), so that the check never +logs an audit record. + +Link: https://lkml.kernel.org/r/20260122140745.239428-1-omosnace@redhat.com +Fixes: dbec28460a89 ("userns: Add per user namespace sysctls.") +Signed-off-by: Ondrej Mosnacek +Reviewed-by: Paul Moore +Acked-by: Serge Hallyn +Cc: Eric Biederman +Cc: Alexey Gladkov +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + kernel/ucount.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/ucount.c b/kernel/ucount.c +index 586af49fc03e4..fc4a8f2d30965 100644 +--- a/kernel/ucount.c ++++ b/kernel/ucount.c +@@ -47,7 +47,7 @@ static int set_permissions(struct ctl_table_header *head, + int mode; + + /* Allow users with CAP_SYS_RESOURCE unrestrained access */ +- if (ns_capable(user_ns, CAP_SYS_RESOURCE)) ++ if (ns_capable_noaudit(user_ns, CAP_SYS_RESOURCE)) + mode = (table->mode & S_IRWXU) >> 6; + else + /* Allow all others at most read-only access */ +-- +2.51.0 + diff --git a/queue-6.18/usb-bdc-fix-sleep-during-atomic.patch b/queue-6.18/usb-bdc-fix-sleep-during-atomic.patch new file mode 100644 index 0000000000..7b5795c63b --- /dev/null +++ b/queue-6.18/usb-bdc-fix-sleep-during-atomic.patch @@ -0,0 +1,41 @@ +From a5a0eecf2c519e103dac73e79f988dd2c2b54657 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 12:07:54 -0800 +Subject: usb: bdc: fix sleep during atomic + +From: Justin Chen + +[ Upstream commit f1195ca3b4bbd001d3f1264dce91f83dec7777f5 ] + +bdc_run() can be ran during atomic context leading to a sleep during +atomic warning. Fix this by replacing read_poll_timeout() with +read_poll_timeout_atomic(). + +Fixes: 75ae051efc9b ("usb: gadget: bdc: use readl_poll_timeout() to simplify code") +Signed-off-by: Justin Chen +Reviewed-by: Florian Fainelli +Link: https://patch.msgid.link/20260120200754.2488765-1-justin.chen@broadcom.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/gadget/udc/bdc/bdc_core.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/usb/gadget/udc/bdc/bdc_core.c b/drivers/usb/gadget/udc/bdc/bdc_core.c +index 5c3d8b64c0e76..f47aac078f6be 100644 +--- a/drivers/usb/gadget/udc/bdc/bdc_core.c ++++ b/drivers/usb/gadget/udc/bdc/bdc_core.c +@@ -35,8 +35,8 @@ static int poll_oip(struct bdc *bdc, u32 usec) + u32 status; + int ret; + +- ret = readl_poll_timeout(bdc->regs + BDC_BDCSC, status, +- (BDC_CSTS(status) != BDC_OIP), 10, usec); ++ ret = readl_poll_timeout_atomic(bdc->regs + BDC_BDCSC, status, ++ (BDC_CSTS(status) != BDC_OIP), 10, usec); + if (ret) + dev_err(bdc->dev, "operation timedout BDCSC: 0x%08x\n", status); + else +-- +2.51.0 + diff --git a/queue-6.18/usb-typec-fusb302-remove-irqf_oneshot.patch b/queue-6.18/usb-typec-fusb302-remove-irqf_oneshot.patch new file mode 100644 index 0000000000..c73a28c46f --- /dev/null +++ b/queue-6.18/usb-typec-fusb302-remove-irqf_oneshot.patch @@ -0,0 +1,47 @@ +From e9322bdd9d75dc48f524c38de4a7344ce6b185c5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:55:31 +0100 +Subject: usb: typec: fusb302: Remove IRQF_ONESHOT + +From: Sebastian Andrzej Siewior + +[ Upstream commit a7fb84ea70aae9a92a842932206e70ed1b3c7007 ] + +Passing IRQF_ONESHOT ensures that the interrupt source is masked until +the secondary (threaded) handler is done. If only a primary handler is +used then the flag makes no sense because the interrupt can not fire +(again) while its handler is running. + +The flag also prevents force-threading of the primary handler and the +irq-core will warn about this. + +Remove IRQF_ONESHOT from irqflags. + +Fixes: 309b6341d5570 ("usb: typec: fusb302: Revert incorrect threaded irq fix") +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Acked-by: Greg Kroah-Hartman +Acked-by: Heikki Krogerus +Link: https://patch.msgid.link/20260128095540.863589-12-bigeasy@linutronix.de +Signed-off-by: Sasha Levin +--- + drivers/usb/typec/tcpm/fusb302.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c +index 870a71f953f6c..19ff8217818e7 100644 +--- a/drivers/usb/typec/tcpm/fusb302.c ++++ b/drivers/usb/typec/tcpm/fusb302.c +@@ -1756,8 +1756,7 @@ static int fusb302_probe(struct i2c_client *client) + } + + ret = request_irq(chip->gpio_int_n_irq, fusb302_irq_intn, +- IRQF_ONESHOT | IRQF_TRIGGER_LOW, +- "fsc_interrupt_int_n", chip); ++ IRQF_TRIGGER_LOW, "fsc_interrupt_int_n", chip); + if (ret < 0) { + dev_err(dev, "cannot request IRQ for GPIO Int_N, ret=%d", ret); + goto tcpm_unregister_port; +-- +2.51.0 + diff --git a/queue-6.18/usb-typec-ucsi-drop-an-unused-kconfig-symbol.patch b/queue-6.18/usb-typec-ucsi-drop-an-unused-kconfig-symbol.patch new file mode 100644 index 0000000000..87f2f211e2 --- /dev/null +++ b/queue-6.18/usb-typec-ucsi-drop-an-unused-kconfig-symbol.patch @@ -0,0 +1,40 @@ +From f074bb43b8ee80f18411537a579304e074eb75f1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 28 Dec 2025 11:06:03 -0800 +Subject: usb: typec: ucsi: drop an unused Kconfig symbol + +From: Randy Dunlap + +[ Upstream commit c5177144b561dd4037a6a225d444b3604afbfbf2 ] + +EXTCON_TCSS_CROS_EC isn't used anywhere else in the kernel tree, +so drop it from this Kconfig file. + +(unless it should be EXTCON_USBC_CROS_EC ?) + +Fixes: f1a2241778d9 ("usb: typec: ucsi: Implement ChromeOS UCSI driver") +Signed-off-by: Randy Dunlap +Reviewed-by: Abhishek Pandit-Subedi +Reviewed-by: Benson Leung +Link: https://patch.msgid.link/20251228190604.2484082-1-rdunlap@infradead.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/typec/ucsi/Kconfig | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/usb/typec/ucsi/Kconfig b/drivers/usb/typec/ucsi/Kconfig +index b812be4d0e674..87dd992a4b9e9 100644 +--- a/drivers/usb/typec/ucsi/Kconfig ++++ b/drivers/usb/typec/ucsi/Kconfig +@@ -73,7 +73,6 @@ config CROS_EC_UCSI + tristate "UCSI Driver for ChromeOS EC" + depends on MFD_CROS_EC_DEV + depends on CROS_USBPD_NOTIFY +- depends on !EXTCON_TCSS_CROS_EC + default MFD_CROS_EC_DEV + help + This driver enables UCSI support for a ChromeOS EC. The EC is +-- +2.51.0 + diff --git a/queue-6.18/vfio-pci-lock-upstream-bridge-for-vfio_pci_core_disa.patch b/queue-6.18/vfio-pci-lock-upstream-bridge-for-vfio_pci_core_disa.patch new file mode 100644 index 0000000000..9603f216b5 --- /dev/null +++ b/queue-6.18/vfio-pci-lock-upstream-bridge-for-vfio_pci_core_disa.patch @@ -0,0 +1,74 @@ +From 4c6016d4a046158358c0a2c101335849059946d5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 15:31:26 +0000 +Subject: vfio/pci: Lock upstream bridge for vfio_pci_core_disable() + +From: Anthony Pighin (Nokia) + +[ Upstream commit 962ae6892d8bd208b2d1e2b358f07551ddc8d32f ] + +The commit 7e89efc6e9e4 ("Lock upstream bridge for pci_reset_function()") +added locking of the upstream bridge to the reset function. To catch +paths that are not properly locked, the commit 920f6468924f ("Warn on +missing cfg_access_lock during secondary bus reset") added a warning +if the PCI configuration space was not locked during a secondary bus reset +request. + +When a VFIO PCI device is released from userspace ownership, an attempt +to reset the PCI device function may be made. If so, and the upstream bridge +is not locked, the release request results in a warning: + + pcieport 0000:00:00.0: unlocked secondary bus reset via: + pci_reset_bus_function+0x188/0x1b8 + +Add missing upstream bridge locking to vfio_pci_core_disable(). + +Fixes: 7e89efc6e9e4 ("PCI: Lock upstream bridge for pci_reset_function()") +Signed-off-by: Anthony Pighin +Link: https://lore.kernel.org/r/BN0PR08MB695171D3AB759C65B6438B5D838DA@BN0PR08MB6951.namprd08.prod.outlook.com +Signed-off-by: Alex Williamson +Signed-off-by: Sasha Levin +--- + drivers/vfio/pci/vfio_pci_core.c | 17 +++++++++++++---- + 1 file changed, 13 insertions(+), 4 deletions(-) + +diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c +index 5efe7535f41ed..085373d71e9c2 100644 +--- a/drivers/vfio/pci/vfio_pci_core.c ++++ b/drivers/vfio/pci/vfio_pci_core.c +@@ -589,6 +589,7 @@ EXPORT_SYMBOL_GPL(vfio_pci_core_enable); + + void vfio_pci_core_disable(struct vfio_pci_core_device *vdev) + { ++ struct pci_dev *bridge; + struct pci_dev *pdev = vdev->pdev; + struct vfio_pci_dummy_resource *dummy_res, *tmp; + struct vfio_pci_ioeventfd *ioeventfd, *ioeventfd_tmp; +@@ -695,12 +696,20 @@ void vfio_pci_core_disable(struct vfio_pci_core_device *vdev) + * We can not use the "try" reset interface here, which will + * overwrite the previously restored configuration information. + */ +- if (vdev->reset_works && pci_dev_trylock(pdev)) { +- if (!__pci_reset_function_locked(pdev)) +- vdev->needs_reset = false; +- pci_dev_unlock(pdev); ++ if (vdev->reset_works) { ++ bridge = pci_upstream_bridge(pdev); ++ if (bridge && !pci_dev_trylock(bridge)) ++ goto out_restore_state; ++ if (pci_dev_trylock(pdev)) { ++ if (!__pci_reset_function_locked(pdev)) ++ vdev->needs_reset = false; ++ pci_dev_unlock(pdev); ++ } ++ if (bridge) ++ pci_dev_unlock(bridge); + } + ++out_restore_state: + pci_restore_state(pdev); + out: + pci_disable_device(pdev); +-- +2.51.0 + diff --git a/queue-6.18/watchdog-starfive-wdt-fix-pm-reference-leak-in-probe.patch b/queue-6.18/watchdog-starfive-wdt-fix-pm-reference-leak-in-probe.patch new file mode 100644 index 0000000000..0a5ab86ae9 --- /dev/null +++ b/queue-6.18/watchdog-starfive-wdt-fix-pm-reference-leak-in-probe.patch @@ -0,0 +1,45 @@ +From 42e58fde8cada5e0400e3b3ef1bc1f5e32acc7c4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 01:29:15 +0800 +Subject: watchdog: starfive-wdt: Fix PM reference leak in probe error path + +From: Kery Qi + +[ Upstream commit 3f2d8d79cceb05a8b8dd200fa81c0dffc59ec46f ] + +The PM reference count is not expected to be incremented on return in +functions starfive_wdt_probe. + +However, pm_runtime_get_sync will increment pm usage counter +even failed. Forgetting to putting operation will result in a +reference leak here. + +Replace it with pm_runtime_resume_and_get to keep usage +counter balanced. + +Fixes: db728ea9c7be ("drivers: watchdog: Add StarFive Watchdog driver") +Signed-off-by: Kery Qi +Reviewed-by: Guenter Roeck +Signed-off-by: Guenter Roeck +Signed-off-by: Wim Van Sebroeck +Signed-off-by: Sasha Levin +--- + drivers/watchdog/starfive-wdt.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/watchdog/starfive-wdt.c b/drivers/watchdog/starfive-wdt.c +index ed71d3960a0f2..af55adc4a3c69 100644 +--- a/drivers/watchdog/starfive-wdt.c ++++ b/drivers/watchdog/starfive-wdt.c +@@ -446,7 +446,7 @@ static int starfive_wdt_probe(struct platform_device *pdev) + platform_set_drvdata(pdev, wdt); + pm_runtime_enable(&pdev->dev); + if (pm_runtime_enabled(&pdev->dev)) { +- ret = pm_runtime_get_sync(&pdev->dev); ++ ret = pm_runtime_resume_and_get(&pdev->dev); + if (ret < 0) + return ret; + } else { +-- +2.51.0 + diff --git a/queue-6.18/wifi-ath10k-sdio-add-missing-lock-protection-in-ath1.patch b/queue-6.18/wifi-ath10k-sdio-add-missing-lock-protection-in-ath1.patch new file mode 100644 index 0000000000..be25e77ebb --- /dev/null +++ b/queue-6.18/wifi-ath10k-sdio-add-missing-lock-protection-in-ath1.patch @@ -0,0 +1,62 @@ +From 61475b4c8417139857e97896801976eeff59e450 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 04:58:22 +0000 +Subject: wifi: ath10k: sdio: add missing lock protection in + ath10k_sdio_fw_crashed_dump() + +From: Ziyi Guo + +[ Upstream commit e55ac348089e579fc224569c7bd90340bf2439f9 ] + +ath10k_sdio_fw_crashed_dump() calls ath10k_coredump_new() which requires +ar->dump_mutex to be held, as indicated by lockdep_assert_held() in that +function. However, the SDIO implementation does not acquire this lock, +unlike the PCI and SNOC implementations which properly hold the mutex. + +Additionally, ar->stats.fw_crash_counter is documented as protected by +ar->data_lock in core.h, but the SDIO implementation modifies it without +holding this spinlock. + +Add the missing mutex_lock()/mutex_unlock() around the coredump +operations, and add spin_lock_bh()/spin_unlock_bh() around the +fw_crash_counter increment, following the pattern used in +ath10k_pci_fw_dump_work() and ath10k_snoc_fw_crashed_dump(). + +Fixes: 3c45f21af84e ("ath10k: sdio: add firmware coredump support") +Signed-off-by: Ziyi Guo +Reviewed-by: Baochen Qiang +Link: https://patch.msgid.link/20260123045822.2221549-1-n7l8m4@u.northwestern.edu +Signed-off-by: Jeff Johnson +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/ath/ath10k/sdio.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c +index c06d50db40b81..00d0556dafefd 100644 +--- a/drivers/net/wireless/ath/ath10k/sdio.c ++++ b/drivers/net/wireless/ath/ath10k/sdio.c +@@ -2487,7 +2487,11 @@ void ath10k_sdio_fw_crashed_dump(struct ath10k *ar) + if (fast_dump) + ath10k_bmi_start(ar); + ++ mutex_lock(&ar->dump_mutex); ++ ++ spin_lock_bh(&ar->data_lock); + ar->stats.fw_crash_counter++; ++ spin_unlock_bh(&ar->data_lock); + + ath10k_sdio_disable_intrs(ar); + +@@ -2505,6 +2509,8 @@ void ath10k_sdio_fw_crashed_dump(struct ath10k *ar) + + ath10k_sdio_enable_intrs(ar); + ++ mutex_unlock(&ar->dump_mutex); ++ + ath10k_core_start_recovery(ar); + } + +-- +2.51.0 + diff --git a/queue-6.18/wifi-ath11k-add-usecase-firmware-handling-based-on-d.patch b/queue-6.18/wifi-ath11k-add-usecase-firmware-handling-based-on-d.patch new file mode 100644 index 0000000000..b2e452e2f6 --- /dev/null +++ b/queue-6.18/wifi-ath11k-add-usecase-firmware-handling-based-on-d.patch @@ -0,0 +1,101 @@ +From 39299664f39476665e3c26ddd053f2ff0ed6526f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 17:50:54 +0800 +Subject: wifi: ath11k: add usecase firmware handling based on device + compatible + +From: Miaoqing Pan + +[ Upstream commit c386a2b1068910538e87ef1cf2fc938ebf7e218f ] + +For M.2 WLAN chips, there is no suitable DTS node to specify the +firmware-name property. In addition, assigning firmware for the +M.2 PCIe interface causes chips that do not use usecase specific +firmware to fail. Therefore, abandoning the approach of specifying +firmware in DTS. As an alternative, propose a static lookup table +mapping device compatible to firmware names. Currently, only WCN6855 +HW2.1 requires this. + +However, support for the firmware-name property is retained to keep +the ABI backwards compatible. + +For details on usecase specific firmware, see: +https://lore.kernel.org/all/20250522013444.1301330-3-miaoqing.pan@oss.qualcomm.com/. + +Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-04685-QCAHSPSWPL_V1_V2_SILICONZ_IOE-1 + +Fixes: edbbc647c4f3 ("wifi: ath11k: support usercase-specific firmware overrides") +Signed-off-by: Miaoqing Pan +Reviewed-by: Vasanthakumar Thiagarajan +Reviewed-by: Baochen Qiang +Link: https://patch.msgid.link/20260121095055.3683957-2-miaoqing.pan@oss.qualcomm.com +Signed-off-by: Jeff Johnson +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/ath/ath11k/core.c | 27 ++++++++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/core.h | 4 ++++ + 2 files changed, 31 insertions(+) + +diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c +index 812686173ac8a..06b4df2370e95 100644 +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -997,6 +997,33 @@ static const struct dmi_system_id ath11k_pm_quirk_table[] = { + {} + }; + ++static const struct __ath11k_core_usecase_firmware_table { ++ u32 hw_rev; ++ const char *compatible; ++ const char *firmware_name; ++} ath11k_core_usecase_firmware_table[] = { ++ { ATH11K_HW_WCN6855_HW21, "qcom,lemans-evk", "nfa765"}, ++ { ATH11K_HW_WCN6855_HW21, "qcom,monaco-evk", "nfa765"}, ++ { ATH11K_HW_WCN6855_HW21, "qcom,hamoa-iot-evk", "nfa765"}, ++ { /* Sentinel */ } ++}; ++ ++const char *ath11k_core_get_usecase_firmware(struct ath11k_base *ab) ++{ ++ const struct __ath11k_core_usecase_firmware_table *entry = NULL; ++ ++ entry = ath11k_core_usecase_firmware_table; ++ while (entry->compatible) { ++ if (ab->hw_rev == entry->hw_rev && ++ of_machine_is_compatible(entry->compatible)) ++ return entry->firmware_name; ++ entry++; ++ } ++ ++ return NULL; ++} ++EXPORT_SYMBOL(ath11k_core_get_usecase_firmware); ++ + void ath11k_fw_stats_pdevs_free(struct list_head *head) + { + struct ath11k_fw_stats_pdev *i, *tmp; +diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h +index e8780b05ce11e..834988dad591c 100644 +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -1275,6 +1275,7 @@ bool ath11k_core_coldboot_cal_support(struct ath11k_base *ab); + + const struct firmware *ath11k_core_firmware_request(struct ath11k_base *ab, + const char *filename); ++const char *ath11k_core_get_usecase_firmware(struct ath11k_base *ab); + + static inline const char *ath11k_scan_state_str(enum ath11k_scan_state state) + { +@@ -1329,6 +1330,9 @@ static inline void ath11k_core_create_firmware_path(struct ath11k_base *ab, + + of_property_read_string(ab->dev->of_node, "firmware-name", &fw_name); + ++ if (!fw_name) ++ fw_name = ath11k_core_get_usecase_firmware(ab); ++ + if (fw_name && strncmp(filename, "board", 5)) + snprintf(buf, buf_len, "%s/%s/%s/%s", ATH11K_FW_DIR, + ab->hw_params.fw.dir, fw_name, filename); +-- +2.51.0 + diff --git a/queue-6.18/wifi-ath12k-clear-stale-link-mapping-of-ahvif-links_.patch b/queue-6.18/wifi-ath12k-clear-stale-link-mapping-of-ahvif-links_.patch new file mode 100644 index 0000000000..c4127fb6ff --- /dev/null +++ b/queue-6.18/wifi-ath12k-clear-stale-link-mapping-of-ahvif-links_.patch @@ -0,0 +1,68 @@ +From 57d234df498556d2285fe74f95c660a628f1d9ac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 09:04:00 +0530 +Subject: wifi: ath12k: clear stale link mapping of ahvif->links_map + +From: Aaradhana Sahu + +[ Upstream commit 2c1ba9c2adf0fda96eaaebd8799268a7506a8fc9 ] + +When an arvif is initialized in non-AP STA mode but MLO connection +preparation fails before the arvif is created +(arvif->is_created remains false), the error path attempts to delete all +links. However, link deletion only executes when arvif->is_created is true. +As a result, ahvif retains a stale entry of arvif that is initialized but +not created. + +When a new arvif is initialized with the same link id, this stale mapping +triggers the following WARN_ON. + +WARNING: drivers/net/wireless/ath/ath12k/mac.c:4271 at ath12k_mac_op_change_vif_links+0x140/0x180 [ath12k], CPU#3: wpa_supplicant/275 + +Call trace: + ath12k_mac_op_change_vif_links+0x140/0x180 [ath12k] (P) + drv_change_vif_links+0xbc/0x1a4 [mac80211] + ieee80211_vif_update_links+0x54c/0x6a0 [mac80211] + ieee80211_vif_set_links+0x40/0x70 [mac80211] + ieee80211_prep_connection+0x84/0x450 [mac80211] + ieee80211_mgd_auth+0x200/0x480 [mac80211] + ieee80211_auth+0x14/0x20 [mac80211] + cfg80211_mlme_auth+0x90/0xf0 [cfg80211] + nl80211_authenticate+0x32c/0x380 [cfg80211] + genl_family_rcv_msg_doit+0xc8/0x134 + +Fix this issue by unassigning the link vif and clearing ahvif->links_map +if arvif is only initialized but not created. + +Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.5-01651-QCAHKSWPL_SILICONZ-1 + +Fixes: 81e4be30544e ("wifi: ath12k: handle link removal in change_vif_links()") +Signed-off-by: Aaradhana Sahu +Reviewed-by: Vasanthakumar Thiagarajan +Reviewed-by: Baochen Qiang +Link: https://patch.msgid.link/20260127033400.1721220-1-aaradhana.sahu@oss.qualcomm.com +Signed-off-by: Jeff Johnson +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/ath/ath12k/mac.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c +index 256ffae4d7f7d..b97469dca0467 100644 +--- a/drivers/net/wireless/ath/ath12k/mac.c ++++ b/drivers/net/wireless/ath/ath12k/mac.c +@@ -4004,8 +4004,10 @@ ath12k_mac_op_change_vif_links(struct ieee80211_hw *hw, + if (WARN_ON(!arvif)) + return -EINVAL; + +- if (!arvif->is_created) ++ if (!arvif->is_created) { ++ ath12k_mac_unassign_link_vif(arvif); + continue; ++ } + + if (WARN_ON(!arvif->ar)) + return -EINVAL; +-- +2.51.0 + diff --git a/queue-6.18/wifi-ath12k-do-wow-offloads-only-on-primary-link.patch b/queue-6.18/wifi-ath12k-do-wow-offloads-only-on-primary-link.patch new file mode 100644 index 0000000000..6d0c319056 --- /dev/null +++ b/queue-6.18/wifi-ath12k-do-wow-offloads-only-on-primary-link.patch @@ -0,0 +1,86 @@ +From 633622471eb81f3bf806b803cf717483b66de1de Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 3 Nov 2025 10:44:49 +0800 +Subject: wifi: ath12k: do WoW offloads only on primary link + +From: Baochen Qiang + +[ Upstream commit e62102ac9b773bdb08475aa9ca24dea61ae98708 ] + +In case of multi-link connection, WCN7850 firmware crashes due to WoW +offloads enabled on both primary and secondary links. + +Change to do it only on primary link to fix it. + +Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00284-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1 + +Fixes: 32f7b19668bd ("wifi: ath12k: support MLO as well if single_chip_mlo_support flag is set") +Signed-off-by: Baochen Qiang +Reviewed-by: Vasanthakumar Thiagarajan +Link: https://patch.msgid.link/20251103-ath12-primary-link-wow-v1-1-3cf523dc09f0@oss.qualcomm.com +Signed-off-by: Jeff Johnson +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/ath/ath12k/wow.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/drivers/net/wireless/ath/ath12k/wow.c b/drivers/net/wireless/ath/ath12k/wow.c +index e8481626f1940..c78aa95d49791 100644 +--- a/drivers/net/wireless/ath/ath12k/wow.c ++++ b/drivers/net/wireless/ath/ath12k/wow.c +@@ -135,6 +135,9 @@ static int ath12k_wow_cleanup(struct ath12k *ar) + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); + + list_for_each_entry(arvif, &ar->arvifs, list) { ++ if (arvif != &arvif->ahvif->deflink) ++ continue; ++ + ret = ath12k_wow_vif_cleanup(arvif); + if (ret) { + ath12k_warn(ar->ab, "failed to clean wow wakeups on vdev %i: %d\n", +@@ -479,8 +482,12 @@ static int ath12k_wow_set_wakeups(struct ath12k *ar, + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); + + list_for_each_entry(arvif, &ar->arvifs, list) { ++ if (arvif != &arvif->ahvif->deflink) ++ continue; ++ + if (ath12k_wow_is_p2p_vdev(arvif->ahvif)) + continue; ++ + ret = ath12k_wow_vif_set_wakeups(arvif, wowlan); + if (ret) { + ath12k_warn(ar->ab, "failed to set wow wakeups on vdev %i: %d\n", +@@ -538,6 +545,9 @@ static int ath12k_wow_nlo_cleanup(struct ath12k *ar) + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); + + list_for_each_entry(arvif, &ar->arvifs, list) { ++ if (arvif != &arvif->ahvif->deflink) ++ continue; ++ + if (ath12k_wow_is_p2p_vdev(arvif->ahvif)) + continue; + +@@ -745,6 +755,9 @@ static int ath12k_wow_arp_ns_offload(struct ath12k *ar, bool enable) + list_for_each_entry(arvif, &ar->arvifs, list) { + ahvif = arvif->ahvif; + ++ if (arvif != &ahvif->deflink) ++ continue; ++ + if (ahvif->vdev_type != WMI_VDEV_TYPE_STA) + continue; + +@@ -776,6 +789,9 @@ static int ath12k_gtk_rekey_offload(struct ath12k *ar, bool enable) + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); + + list_for_each_entry(arvif, &ar->arvifs, list) { ++ if (arvif != &arvif->ahvif->deflink) ++ continue; ++ + if (arvif->ahvif->vdev_type != WMI_VDEV_TYPE_STA || + !arvif->is_up || + !arvif->rekey_data.enable_offload) +-- +2.51.0 + diff --git a/queue-6.18/wifi-ath12k-fix-index-decrement-when-array_len-is-ze.patch b/queue-6.18/wifi-ath12k-fix-index-decrement-when-array_len-is-ze.patch new file mode 100644 index 0000000000..9355042609 --- /dev/null +++ b/queue-6.18/wifi-ath12k-fix-index-decrement-when-array_len-is-ze.patch @@ -0,0 +1,56 @@ +From cfab3ac0459fab87a0fbf8e55934f34c3808aef5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 12:42:51 +0530 +Subject: wifi: ath12k: Fix index decrement when array_len is zero + +From: Aaradhana Sahu + +[ Upstream commit e4763898bb1325dbb3792961b6d607b5c6452d64 ] + +Currently, print_array_to_buf_index() decrements index unconditionally. +This may lead to invalid buffer access when array_len is zero. + +Fix this by decrementing index only when array_len is non-zero. + +Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.5-01651-QCAHKSWPL_SILICONZ-1 +Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00302-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.115823.3 + +Fixes: adf6df963c03 ("wifi: ath12k: Add support to parse requested stats_type") +Signed-off-by: Aaradhana Sahu +Reviewed-by: Baochen Qiang +Link: https://patch.msgid.link/20260123071253.2202644-2-aaradhana.sahu@oss.qualcomm.com +Signed-off-by: Jeff Johnson +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c +index 48b010a1b7566..4f749d473d0e1 100644 +--- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c ++++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c +@@ -1,7 +1,7 @@ + // SPDX-License-Identifier: BSD-3-Clause-Clear + /* + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. +- * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved. ++ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + + #include +@@ -29,8 +29,10 @@ print_array_to_buf_index(u8 *buf, u32 offset, const char *header, u32 stats_inde + " %u:%u,", stats_index++, le32_to_cpu(array[i])); + } + /* To overwrite the last trailing comma */ +- index--; +- *(buf + offset + index) = '\0'; ++ if (array_len > 0) { ++ index--; ++ *(buf + offset + index) = '\0'; ++ } + + if (footer) { + index += scnprintf(buf + offset + index, +-- +2.51.0 + diff --git a/queue-6.18/wifi-ath9k-add-of-dependency-to-ahb.patch b/queue-6.18/wifi-ath9k-add-of-dependency-to-ahb.patch new file mode 100644 index 0000000000..22908702ed --- /dev/null +++ b/queue-6.18/wifi-ath9k-add-of-dependency-to-ahb.patch @@ -0,0 +1,40 @@ +From 9ce3a5c0c4d3898a2735586b0ddaa8a09cfd6a42 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 1 Aug 2025 17:04:32 -0700 +Subject: wifi: ath9k: add OF dependency to AHB +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Rosen Penev + +[ Upstream commit 125e7b31f041cc0a4ede1e42bef69915f0a63a35 ] + +The conversion to OF missed adding a Kconfig dependency. + +Fixes: 2fa490c0d759 ("wifi: ath9k: ahb: replace id_table with of") +Signed-off-by: Rosen Penev +Acked-by: Toke Høiland-Jørgensen +Link: https://patch.msgid.link/20250802000432.3079550-1-rosenp@gmail.com +Signed-off-by: Jeff Johnson +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/ath/ath9k/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig +index 0c47be06c153b..47d570a5ca6a1 100644 +--- a/drivers/net/wireless/ath/ath9k/Kconfig ++++ b/drivers/net/wireless/ath/ath9k/Kconfig +@@ -47,7 +47,7 @@ config ATH9K_PCI + + config ATH9K_AHB + bool "Atheros ath9k AHB bus support" +- depends on ATH9K ++ depends on ATH9K && OF + default n + help + This option enables the AHB bus support in ath9k. +-- +2.51.0 + diff --git a/queue-6.18/wifi-cfg80211-fix-use_for-flag-update-on-bss-refresh.patch b/queue-6.18/wifi-cfg80211-fix-use_for-flag-update-on-bss-refresh.patch new file mode 100644 index 0000000000..178f3c26a1 --- /dev/null +++ b/queue-6.18/wifi-cfg80211-fix-use_for-flag-update-on-bss-refresh.patch @@ -0,0 +1,54 @@ +From ad7dfa52d978f33c028df64b19c197ba308bf7cf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 08:27:33 +0530 +Subject: wifi: cfg80211: Fix use_for flag update on BSS refresh +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Huang Chenming + +[ Upstream commit 4073ea516106e5f98ed0476f89cdede8baa98d37 ] + +Userspace may fail to connect to certain BSS that were initially +marked as unusable due to regulatory restrictions (use_for = 0, +e.g., 6 GHz power type mismatch). Even after these restrictions +are removed and the BSS becomes usable, connection attempts still +fail. + +The issue occurs in cfg80211_update_known_bss() where the use_for +flag is updated using bitwise AND (&=) instead of direct assignment. +Once a BSS is marked with use_for = 0, the AND operation masks out +any subsequent non-zero values, permanently keeping the flag at 0. +This causes __cfg80211_get_bss(), invoked by nl80211_assoc_bss(), to +fail the check "(bss->pub.use_for & use_for) != use_for", thereby +blocking association. + +Replace the bitwise AND operation with direct assignment so the use_for +flag accurately reflects the current BSS state. + +Fixes: d02a12b8e4bb ("wifi: cfg80211: add BSS usage reporting") +Signed-off-by: Huang Chenming +Link: https://patch.msgid.link/20251209025733.2098456-1-chenming.huang@oss.qualcomm.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/wireless/scan.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/wireless/scan.c b/net/wireless/scan.c +index 90a9187a6b135..9a0c02c23dc56 100644 +--- a/net/wireless/scan.c ++++ b/net/wireless/scan.c +@@ -1959,7 +1959,7 @@ cfg80211_update_known_bss(struct cfg80211_registered_device *rdev, + ether_addr_copy(known->parent_bssid, new->parent_bssid); + known->pub.max_bssid_indicator = new->pub.max_bssid_indicator; + known->pub.bssid_index = new->pub.bssid_index; +- known->pub.use_for &= new->pub.use_for; ++ known->pub.use_for = new->pub.use_for; + known->pub.cannot_use_reasons = new->pub.cannot_use_reasons; + known->bss_source = new->bss_source; + +-- +2.51.0 + diff --git a/queue-6.18/wifi-cfg80211-stop-nan-and-p2p-in-cfg80211_leave.patch b/queue-6.18/wifi-cfg80211-stop-nan-and-p2p-in-cfg80211_leave.patch new file mode 100644 index 0000000000..58a50799c5 --- /dev/null +++ b/queue-6.18/wifi-cfg80211-stop-nan-and-p2p-in-cfg80211_leave.patch @@ -0,0 +1,47 @@ +From 644da9cbf7f655a9a535374a9fb7b24f557c51aa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 14:04:51 +0200 +Subject: wifi: cfg80211: stop NAN and P2P in cfg80211_leave + +From: Miri Korenblit + +[ Upstream commit e1696c8bd0056bc1a5f7766f58ac333adc203e8a ] + +Seems that there is an assumption that this function should be called +only for netdev interfaces, but it can also be called in suspend, or +from nl80211_netlink_notify (indirectly). +Note that the documentation of NL80211_ATTR_SOCKET_OWNER explicitly +says that NAN interfaces would be destroyed as well in the +nl80211_netlink_notify case. + +Fix this by also stopping P2P and NAN. + +Fixes: cb3b7d87652a ("cfg80211: add start / stop NAN commands") +Reviewed-by: Johannes Berg +Signed-off-by: Miri Korenblit +Link: https://patch.msgid.link/20260107140430.dab142cbef0b.I290cc47836d56dd7e35012ce06bec36c6da688cd@changeid +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/wireless/core.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/net/wireless/core.c b/net/wireless/core.c +index 5e5c1bc380a89..87f083d9247a4 100644 +--- a/net/wireless/core.c ++++ b/net/wireless/core.c +@@ -1400,8 +1400,10 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev, + cfg80211_leave_ocb(rdev, dev); + break; + case NL80211_IFTYPE_P2P_DEVICE: ++ cfg80211_stop_p2p_device(rdev, wdev); ++ break; + case NL80211_IFTYPE_NAN: +- /* cannot happen, has no netdev */ ++ cfg80211_stop_nan(rdev, wdev); + break; + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_MONITOR: +-- +2.51.0 + diff --git a/queue-6.18/wifi-rtw89-debug-fix-memory-leak-in-__print_txpwr_ma.patch b/queue-6.18/wifi-rtw89-debug-fix-memory-leak-in-__print_txpwr_ma.patch new file mode 100644 index 0000000000..d7a3331577 --- /dev/null +++ b/queue-6.18/wifi-rtw89-debug-fix-memory-leak-in-__print_txpwr_ma.patch @@ -0,0 +1,59 @@ +From d74332ea12323cd6a1b783a1d1e82fbec5d1119f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 13:08:34 +0000 +Subject: wifi: rtw89: debug: Fix memory leak in __print_txpwr_map() + +From: Zilin Guan + +[ Upstream commit 6070a44051b1c35714fa130de7726cfe91ca5559 ] + +In __print_txpwr_map(), memory is allocated to bufp via vzalloc(). +If max_valid_addr is 0, the function returns -EOPNOTSUPP immediately +without freeing bufp, leading to a memory leak. + +Since the validation of max_valid_addr does not depend on the allocated +memory, fix this by moving the vzalloc() call after the check. + +Compile tested only. Issue found using a prototype static analysis tool +and code review. + +Fixes: 036042e15770 ("wifi: rtw89: debug: txpwr table supports Wi-Fi 7 chips") +Suggested-by: Zong-Zhe Yang +Signed-off-by: Zilin Guan +Reviewed-by: Zong-Zhe Yang +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/20260116130834.1413924-1-zilin@seu.edu.cn +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtw89/debug.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/wireless/realtek/rtw89/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c +index 3dc7981c510fd..a82df3814069c 100644 +--- a/drivers/net/wireless/realtek/rtw89/debug.c ++++ b/drivers/net/wireless/realtek/rtw89/debug.c +@@ -824,10 +824,6 @@ static ssize_t __print_txpwr_map(struct rtw89_dev *rtwdev, char *buf, size_t buf + s8 *bufp, tmp; + int ret; + +- bufp = vzalloc(map->addr_to - map->addr_from + 4); +- if (!bufp) +- return -ENOMEM; +- + if (path_num == 1) + max_valid_addr = map->addr_to_1ss; + else +@@ -836,6 +832,10 @@ static ssize_t __print_txpwr_map(struct rtw89_dev *rtwdev, char *buf, size_t buf + if (max_valid_addr == 0) + return -EOPNOTSUPP; + ++ bufp = vzalloc(map->addr_to - map->addr_from + 4); ++ if (!bufp) ++ return -ENOMEM; ++ + for (addr = map->addr_from; addr <= max_valid_addr; addr += 4) { + ret = rtw89_mac_txpwr_read32(rtwdev, RTW89_PHY_0, addr, &val); + if (ret) +-- +2.51.0 + diff --git a/queue-6.18/workqueue-factor-out-assign_rescuer_work.patch b/queue-6.18/workqueue-factor-out-assign_rescuer_work.patch new file mode 100644 index 0000000000..97e048c30e --- /dev/null +++ b/queue-6.18/workqueue-factor-out-assign_rescuer_work.patch @@ -0,0 +1,78 @@ +From 8bdb14587c202c5cd998df7ac34f9209b4485fb1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 21 Nov 2025 22:57:14 +0800 +Subject: workqueue: Factor out assign_rescuer_work() + +From: Lai Jiangshan + +[ Upstream commit 99ed6f62a46e91dc796b785618d646eeded1b230 ] + +Move the code to assign work to rescuer and assign_rescuer_work(). + +Signed-off-by: Lai Jiangshan +Signed-off-by: Tejun Heo +Stable-dep-of: e5a30c303b07 ("workqueue: Process rescuer work items one-by-one using a cursor") +Signed-off-by: Sasha Levin +--- + kernel/workqueue.c | 29 ++++++++++++++++++----------- + 1 file changed, 18 insertions(+), 11 deletions(-) + +diff --git a/kernel/workqueue.c b/kernel/workqueue.c +index 45320e27a16c4..2fa3187101725 100644 +--- a/kernel/workqueue.c ++++ b/kernel/workqueue.c +@@ -3443,6 +3443,23 @@ static int worker_thread(void *__worker) + goto woke_up; + } + ++static bool assign_rescuer_work(struct pool_workqueue *pwq, struct worker *rescuer) ++{ ++ struct worker_pool *pool = pwq->pool; ++ struct work_struct *work, *n; ++ ++ /* ++ * Slurp in all works issued via this workqueue and ++ * process'em. ++ */ ++ list_for_each_entry_safe(work, n, &pool->worklist, entry) { ++ if (get_work_pwq(work) == pwq && assign_work(work, rescuer, &n)) ++ pwq->stats[PWQ_STAT_RESCUED]++; ++ } ++ ++ return !list_empty(&rescuer->scheduled); ++} ++ + /** + * rescuer_thread - the rescuer thread function + * @__rescuer: self +@@ -3497,7 +3514,6 @@ static int rescuer_thread(void *__rescuer) + struct pool_workqueue *pwq = list_first_entry(&wq->maydays, + struct pool_workqueue, mayday_node); + struct worker_pool *pool = pwq->pool; +- struct work_struct *work, *n; + + __set_current_state(TASK_RUNNING); + list_del_init(&pwq->mayday_node); +@@ -3508,18 +3524,9 @@ static int rescuer_thread(void *__rescuer) + + raw_spin_lock_irq(&pool->lock); + +- /* +- * Slurp in all works issued via this workqueue and +- * process'em. +- */ + WARN_ON_ONCE(!list_empty(&rescuer->scheduled)); +- list_for_each_entry_safe(work, n, &pool->worklist, entry) { +- if (get_work_pwq(work) == pwq && +- assign_work(work, rescuer, &n)) +- pwq->stats[PWQ_STAT_RESCUED]++; +- } + +- if (!list_empty(&rescuer->scheduled)) { ++ if (assign_rescuer_work(pwq, rescuer)) { + process_scheduled_works(rescuer); + + /* +-- +2.51.0 + diff --git a/queue-6.18/workqueue-only-assign-rescuer-work-when-really-neede.patch b/queue-6.18/workqueue-only-assign-rescuer-work-when-really-neede.patch new file mode 100644 index 0000000000..977485efc4 --- /dev/null +++ b/queue-6.18/workqueue-only-assign-rescuer-work-when-really-neede.patch @@ -0,0 +1,39 @@ +From e0f632a935ecd8a8450537fddd79c39ef285b66e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 21 Nov 2025 22:57:15 +0800 +Subject: workqueue: Only assign rescuer work when really needed + +From: Lai Jiangshan + +[ Upstream commit 7b05c90b3302cf3d830dfa6f8961376bcaf43b94 ] + +If the pwq does not need rescue (normal workers have been created or +become available), the rescuer can immediately move on to other stalled +pwqs. + +Signed-off-by: Lai Jiangshan +Signed-off-by: Tejun Heo +Stable-dep-of: e5a30c303b07 ("workqueue: Process rescuer work items one-by-one using a cursor") +Signed-off-by: Sasha Levin +--- + kernel/workqueue.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/kernel/workqueue.c b/kernel/workqueue.c +index 2fa3187101725..f678200ce8692 100644 +--- a/kernel/workqueue.c ++++ b/kernel/workqueue.c +@@ -3448,6 +3448,10 @@ static bool assign_rescuer_work(struct pool_workqueue *pwq, struct worker *rescu + struct worker_pool *pool = pwq->pool; + struct work_struct *work, *n; + ++ /* need rescue? */ ++ if (!pwq->nr_active || !need_to_create_worker(pool)) ++ return false; ++ + /* + * Slurp in all works issued via this workqueue and + * process'em. +-- +2.51.0 + diff --git a/queue-6.18/workqueue-process-rescuer-work-items-one-by-one-usin.patch b/queue-6.18/workqueue-process-rescuer-work-items-one-by-one-usin.patch new file mode 100644 index 0000000000..89b4d4f1ff --- /dev/null +++ b/queue-6.18/workqueue-process-rescuer-work-items-one-by-one-usin.patch @@ -0,0 +1,202 @@ +From 3eeadcbe049e84cbe52bcadbd0b7c22006cac28b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Dec 2025 21:25:18 +0800 +Subject: workqueue: Process rescuer work items one-by-one using a cursor + +From: Lai Jiangshan + +[ Upstream commit e5a30c303b07a4d6083e0f7f051b53add6d93c5d ] + +Previously, the rescuer scanned for all matching work items at once and +processed them within a single rescuer thread, which could cause one +blocking work item to stall all others. + +Make the rescuer process work items one-by-one instead of slurping all +matches in a single pass. + +Break the rescuer loop after finding and processing the first matching +work item, then restart the search to pick up the next. This gives +normal worker threads a chance to process other items which gives them +the opportunity to be processed instead of waiting on the rescuer's +queue and prevents a blocking work item from stalling the rest once +memory pressure is relieved. + +Introduce a dummy cursor work item to avoid potentially O(N^2) +rescans of the work list. The marker records the resume position for +the next scan, eliminating redundant traversals. + +Also introduce RESCUER_BATCH to control the maximum number of work items +the rescuer processes in each turn, and move on to other PWQs when the +limit is reached. + +Cc: ying chen +Reported-by: ying chen +Fixes: e22bee782b3b ("workqueue: implement concurrency managed dynamic worker pool") +Signed-off-by: Lai Jiangshan +Signed-off-by: Tejun Heo +Signed-off-by: Sasha Levin +--- + kernel/workqueue.c | 75 ++++++++++++++++++++++++++++++++++++---------- + 1 file changed, 59 insertions(+), 16 deletions(-) + +diff --git a/kernel/workqueue.c b/kernel/workqueue.c +index f678200ce8692..885a8b31f855b 100644 +--- a/kernel/workqueue.c ++++ b/kernel/workqueue.c +@@ -117,6 +117,8 @@ enum wq_internal_consts { + MAYDAY_INTERVAL = HZ / 10, /* and then every 100ms */ + CREATE_COOLDOWN = HZ, /* time to breath after fail */ + ++ RESCUER_BATCH = 16, /* process items per turn */ ++ + /* + * Rescue workers are used only on emergencies and shared by + * all cpus. Give MIN_NICE. +@@ -286,6 +288,7 @@ struct pool_workqueue { + struct list_head pending_node; /* LN: node on wq_node_nr_active->pending_pwqs */ + struct list_head pwqs_node; /* WR: node on wq->pwqs */ + struct list_head mayday_node; /* MD: node on wq->maydays */ ++ struct work_struct mayday_cursor; /* L: cursor on pool->worklist */ + + u64 stats[PWQ_NR_STATS]; + +@@ -1126,6 +1129,12 @@ static struct worker *find_worker_executing_work(struct worker_pool *pool, + return NULL; + } + ++static void mayday_cursor_func(struct work_struct *work) ++{ ++ /* should not be processed, only for marking position */ ++ BUG(); ++} ++ + /** + * move_linked_works - move linked works to a list + * @work: start of series of works to be scheduled +@@ -1188,6 +1197,16 @@ static bool assign_work(struct work_struct *work, struct worker *worker, + + lockdep_assert_held(&pool->lock); + ++ /* The cursor work should not be processed */ ++ if (unlikely(work->func == mayday_cursor_func)) { ++ /* only worker_thread() can possibly take this branch */ ++ WARN_ON_ONCE(worker->rescue_wq); ++ if (nextp) ++ *nextp = list_next_entry(work, entry); ++ list_del_init(&work->entry); ++ return false; ++ } ++ + /* + * A single work shouldn't be executed concurrently by multiple workers. + * __queue_work() ensures that @work doesn't jump to a different pool +@@ -3446,22 +3465,30 @@ static int worker_thread(void *__worker) + static bool assign_rescuer_work(struct pool_workqueue *pwq, struct worker *rescuer) + { + struct worker_pool *pool = pwq->pool; ++ struct work_struct *cursor = &pwq->mayday_cursor; + struct work_struct *work, *n; + + /* need rescue? */ + if (!pwq->nr_active || !need_to_create_worker(pool)) + return false; + +- /* +- * Slurp in all works issued via this workqueue and +- * process'em. +- */ +- list_for_each_entry_safe(work, n, &pool->worklist, entry) { +- if (get_work_pwq(work) == pwq && assign_work(work, rescuer, &n)) ++ /* search from the start or cursor if available */ ++ if (list_empty(&cursor->entry)) ++ work = list_first_entry(&pool->worklist, struct work_struct, entry); ++ else ++ work = list_next_entry(cursor, entry); ++ ++ /* find the next work item to rescue */ ++ list_for_each_entry_safe_from(work, n, &pool->worklist, entry) { ++ if (get_work_pwq(work) == pwq && assign_work(work, rescuer, &n)) { + pwq->stats[PWQ_STAT_RESCUED]++; ++ /* put the cursor for next search */ ++ list_move_tail(&cursor->entry, &n->entry); ++ return true; ++ } + } + +- return !list_empty(&rescuer->scheduled); ++ return false; + } + + /** +@@ -3518,6 +3545,7 @@ static int rescuer_thread(void *__rescuer) + struct pool_workqueue *pwq = list_first_entry(&wq->maydays, + struct pool_workqueue, mayday_node); + struct worker_pool *pool = pwq->pool; ++ unsigned int count = 0; + + __set_current_state(TASK_RUNNING); + list_del_init(&pwq->mayday_node); +@@ -3530,19 +3558,16 @@ static int rescuer_thread(void *__rescuer) + + WARN_ON_ONCE(!list_empty(&rescuer->scheduled)); + +- if (assign_rescuer_work(pwq, rescuer)) { ++ while (assign_rescuer_work(pwq, rescuer)) { + process_scheduled_works(rescuer); + + /* +- * The above execution of rescued work items could +- * have created more to rescue through +- * pwq_activate_first_inactive() or chained +- * queueing. Let's put @pwq back on mayday list so +- * that such back-to-back work items, which may be +- * being used to relieve memory pressure, don't +- * incur MAYDAY_INTERVAL delay inbetween. ++ * If the per-turn work item limit is reached and other ++ * PWQs are in mayday, requeue mayday for this PWQ and ++ * let the rescuer handle the other PWQs first. + */ +- if (pwq->nr_active && need_to_create_worker(pool)) { ++ if (++count > RESCUER_BATCH && !list_empty(&pwq->wq->maydays) && ++ pwq->nr_active && need_to_create_worker(pool)) { + raw_spin_lock(&wq_mayday_lock); + /* + * Queue iff we aren't racing destruction +@@ -3553,9 +3578,14 @@ static int rescuer_thread(void *__rescuer) + list_add_tail(&pwq->mayday_node, &wq->maydays); + } + raw_spin_unlock(&wq_mayday_lock); ++ break; + } + } + ++ /* The cursor can not be left behind without the rescuer watching it. */ ++ if (!list_empty(&pwq->mayday_cursor.entry) && list_empty(&pwq->mayday_node)) ++ list_del_init(&pwq->mayday_cursor.entry); ++ + /* + * Leave this pool. Notify regular workers; otherwise, we end up + * with 0 concurrency and stalling the execution. +@@ -5174,6 +5204,19 @@ static void init_pwq(struct pool_workqueue *pwq, struct workqueue_struct *wq, + INIT_LIST_HEAD(&pwq->pwqs_node); + INIT_LIST_HEAD(&pwq->mayday_node); + kthread_init_work(&pwq->release_work, pwq_release_workfn); ++ ++ /* ++ * Set the dummy cursor work with valid function and get_work_pwq(). ++ * ++ * The cursor work should only be in the pwq->pool->worklist, and ++ * should not be treated as a processable work item. ++ * ++ * WORK_STRUCT_PENDING and WORK_STRUCT_INACTIVE just make it less ++ * surprise for kernel debugging tools and reviewers. ++ */ ++ INIT_WORK(&pwq->mayday_cursor, mayday_cursor_func); ++ atomic_long_set(&pwq->mayday_cursor.data, (unsigned long)pwq | ++ WORK_STRUCT_PENDING | WORK_STRUCT_PWQ | WORK_STRUCT_INACTIVE); + } + + /* sync @pwq with the current state of its associated wq and link it */ +-- +2.51.0 + diff --git a/queue-6.18/x86-cpu-amd-correct-the-microcode-table-for-zenbleed.patch b/queue-6.18/x86-cpu-amd-correct-the-microcode-table-for-zenbleed.patch new file mode 100644 index 0000000000..7b6458afb0 --- /dev/null +++ b/queue-6.18/x86-cpu-amd-correct-the-microcode-table-for-zenbleed.patch @@ -0,0 +1,84 @@ +From c8353babae06d87f6b24ea3374da03c80c0eadac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 26 Nov 2025 13:03:52 +0000 +Subject: x86/cpu/amd: Correct the microcode table for Zenbleed + +From: Andrew Cooper + +[ Upstream commit fb7bfa31b8e8569f154f2fe0ea6c2f03c0f087aa ] + +The good revisions are tied to exact steppings, meaning it's not valid to +match on model number alone, let alone a range. + +This is probably only a latent issue. From public microcode archives, the +following CPUs exist 17-30-00, 17-60-00, 17-70-00 and would be captured by the +model ranges. They're likely pre-production steppings, and likely didn't get +Zenbleed microcode, but it's still incorrect to compare them to a different +steppings revision. + +Either way, convert the logic to use x86_match_min_microcode_rev(), which is +the preferred mechanism. + +Fixes: 522b1d69219d ("x86/cpu/amd: Add a Zenbleed fix") +Signed-off-by: Andrew Cooper +Signed-off-by: Ingo Molnar +Cc: Borislav Petkov +Cc: Mario Limonciello +Cc: x86@kernel.org +Link: https://patch.msgid.link/20251126130352.880424-1-andrew.cooper3@citrix.com +Signed-off-by: Sasha Levin +--- + arch/x86/kernel/cpu/amd.c | 30 +++++++++--------------------- + 1 file changed, 9 insertions(+), 21 deletions(-) + +diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c +index 5d46709c58d0b..a92750f3079af 100644 +--- a/arch/x86/kernel/cpu/amd.c ++++ b/arch/x86/kernel/cpu/amd.c +@@ -951,26 +951,14 @@ static void init_amd_zen1(struct cpuinfo_x86 *c) + } + } + +-static bool cpu_has_zenbleed_microcode(void) +-{ +- u32 good_rev = 0; +- +- switch (boot_cpu_data.x86_model) { +- case 0x30 ... 0x3f: good_rev = 0x0830107b; break; +- case 0x60 ... 0x67: good_rev = 0x0860010c; break; +- case 0x68 ... 0x6f: good_rev = 0x08608107; break; +- case 0x70 ... 0x7f: good_rev = 0x08701033; break; +- case 0xa0 ... 0xaf: good_rev = 0x08a00009; break; +- +- default: +- return false; +- } +- +- if (boot_cpu_data.microcode < good_rev) +- return false; +- +- return true; +-} ++static const struct x86_cpu_id amd_zenbleed_microcode[] = { ++ ZEN_MODEL_STEP_UCODE(0x17, 0x31, 0x0, 0x0830107b), ++ ZEN_MODEL_STEP_UCODE(0x17, 0x60, 0x1, 0x0860010c), ++ ZEN_MODEL_STEP_UCODE(0x17, 0x68, 0x1, 0x08608107), ++ ZEN_MODEL_STEP_UCODE(0x17, 0x71, 0x0, 0x08701033), ++ ZEN_MODEL_STEP_UCODE(0x17, 0xa0, 0x0, 0x08a00009), ++ {} ++}; + + static void zen2_zenbleed_check(struct cpuinfo_x86 *c) + { +@@ -980,7 +968,7 @@ static void zen2_zenbleed_check(struct cpuinfo_x86 *c) + if (!cpu_has(c, X86_FEATURE_AVX)) + return; + +- if (!cpu_has_zenbleed_microcode()) { ++ if (!x86_match_min_microcode_rev(amd_zenbleed_microcode)) { + pr_notice_once("Zenbleed: please update your microcode for the most optimal fix\n"); + msr_set_bit(MSR_AMD64_DE_CFG, MSR_AMD64_DE_CFG_ZEN2_FP_BACKUP_FIX_BIT); + } else { +-- +2.51.0 + diff --git a/queue-6.18/x86-fgraph-bpf-switch-kprobe_multi-program-stack-unw.patch b/queue-6.18/x86-fgraph-bpf-switch-kprobe_multi-program-stack-unw.patch new file mode 100644 index 0000000000..7d03cc2723 --- /dev/null +++ b/queue-6.18/x86-fgraph-bpf-switch-kprobe_multi-program-stack-unw.patch @@ -0,0 +1,111 @@ +From aa9b9d658b8e45e8ec2514a8f619a18960e9895f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 22:18:33 +0100 +Subject: x86/fgraph,bpf: Switch kprobe_multi program stack unwind to hw_regs + path +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jiri Olsa + +[ Upstream commit aea251799998aa1b78eacdfb308f18ea114ea5b3 ] + +Mahe reported missing function from stack trace on top of kprobe +multi program. The missing function is the very first one in the +stacktrace, the one that the bpf program is attached to. + + # bpftrace -e 'kprobe:__x64_sys_newuname* { print(kstack)}' + Attaching 1 probe... + + do_syscall_64+134 + entry_SYSCALL_64_after_hwframe+118 + + ('*' is used for kprobe_multi attachment) + +The reason is that the previous change (the Fixes commit) fixed +stack unwind for tracepoint, but removed attached function address +from the stack trace on top of kprobe multi programs, which I also +overlooked in the related test (check following patch). + +The tracepoint and kprobe_multi have different stack setup, but use +same unwind path. I think it's better to keep the previous change, +which fixed tracepoint unwind and instead change the kprobe multi +unwind as explained below. + +The bpf program stack unwind calls perf_callchain_kernel for kernel +portion and it follows two unwind paths based on X86_EFLAGS_FIXED +bit in pt_regs.flags. + +When the bit set we unwind from stack represented by pt_regs argument, +otherwise we unwind currently executed stack up to 'first_frame' +boundary. + +The 'first_frame' value is taken from regs.rsp value, but ftrace_caller +and ftrace_regs_caller (ftrace trampoline) functions set the regs.rsp +to the previous stack frame, so we skip the attached function entry. + +If we switch kprobe_multi unwind to use the X86_EFLAGS_FIXED bit, +we set the start of the unwind to the attached function address. +As another benefit we also cut extra unwind cycles needed to reach +the 'first_frame' boundary. + +The speedup can be measured with trigger bench for kprobe_multi +program and stacktrace support. + +- trigger bench with stacktrace on current code: + + kprobe-multi : 0.810 ± 0.001M/s + kretprobe-multi: 0.808 ± 0.001M/s + +- and with the fix: + + kprobe-multi : 1.264 ± 0.001M/s + kretprobe-multi: 1.401 ± 0.002M/s + +With the fix, the entry probe stacktrace: + + # bpftrace -e 'kprobe:__x64_sys_newuname* { print(kstack)}' + Attaching 1 probe... + + __x64_sys_newuname+9 + do_syscall_64+134 + entry_SYSCALL_64_after_hwframe+118 + +The return probe skips the attached function, because it's no longer +on the stack at the point of the unwind and this way is the same how +standard kretprobe works. + + # bpftrace -e 'kretprobe:__x64_sys_newuname* { print(kstack)}' + Attaching 1 probe... + + do_syscall_64+134 + entry_SYSCALL_64_after_hwframe+118 + +Fixes: 6d08340d1e35 ("Revert "perf/x86: Always store regs->ip in perf_callchain_kernel()"") +Reported-by: Mahe Tardy +Signed-off-by: Jiri Olsa +Signed-off-by: Andrii Nakryiko +Acked-by: Steven Rostedt (Google) +Link: https://lore.kernel.org/bpf/20260126211837.472802-3-jolsa@kernel.org +Signed-off-by: Sasha Levin +--- + arch/x86/include/asm/ftrace.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h +index b08c95872eed9..c56e1e63b8932 100644 +--- a/arch/x86/include/asm/ftrace.h ++++ b/arch/x86/include/asm/ftrace.h +@@ -57,7 +57,7 @@ arch_ftrace_get_regs(struct ftrace_regs *fregs) + } + + #define arch_ftrace_partial_regs(regs) do { \ +- regs->flags &= ~X86_EFLAGS_FIXED; \ ++ regs->flags |= X86_EFLAGS_FIXED; \ + regs->cs = __KERNEL_CS; \ + } while (0) + +-- +2.51.0 + diff --git a/queue-6.18/x86-fgraph-fix-return_to_handler-regs.rsp-value.patch b/queue-6.18/x86-fgraph-fix-return_to_handler-regs.rsp-value.patch new file mode 100644 index 0000000000..5a7de3a06c --- /dev/null +++ b/queue-6.18/x86-fgraph-fix-return_to_handler-regs.rsp-value.patch @@ -0,0 +1,66 @@ +From 0437ad7f84b09b9b937df33a946ff41a90c23ec8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 22:18:32 +0100 +Subject: x86/fgraph: Fix return_to_handler regs.rsp value + +From: Jiri Olsa + +[ Upstream commit 8bc11700e0d23d4fdb7d8d5a73b2e95de427cabc ] + +The previous change (Fixes commit) messed up the rsp register value, +which is wrong because it's already adjusted with FRAME_SIZE, we need +the original rsp value. + +This change does not affect fprobe current kernel unwind, the !perf_hw_regs +path perf_callchain_kernel: + + if (perf_hw_regs(regs)) { + if (perf_callchain_store(entry, regs->ip)) + return; + unwind_start(&state, current, regs, NULL); + } else { + unwind_start(&state, current, NULL, (void *)regs->sp); + } + +which uses pt_regs.sp as first_frame boundary (FRAME_SIZE shift makes +no difference, unwind stil stops at the right frame). + +This change fixes the other path when we want to unwind directly from +pt_regs sp/fp/ip state, which is coming in following change. + +Fixes: 20a0bc10272f ("x86/fgraph,bpf: Fix stack ORC unwind from kprobe_multi return probe") +Signed-off-by: Jiri Olsa +Signed-off-by: Andrii Nakryiko +Reviewed-by: Steven Rostedt (Google) +Link: https://lore.kernel.org/bpf/20260126211837.472802-2-jolsa@kernel.org +Signed-off-by: Sasha Levin +--- + arch/x86/kernel/ftrace_64.S | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/arch/x86/kernel/ftrace_64.S b/arch/x86/kernel/ftrace_64.S +index 823dbdd0eb410..ae94f7b0fdf16 100644 +--- a/arch/x86/kernel/ftrace_64.S ++++ b/arch/x86/kernel/ftrace_64.S +@@ -354,6 +354,9 @@ SYM_CODE_START(return_to_handler) + UNWIND_HINT_UNDEFINED + ANNOTATE_NOENDBR + ++ /* Store original rsp for pt_regs.sp value. */ ++ movq %rsp, %rdi ++ + /* Restore return_to_handler value that got eaten by previous ret instruction. */ + subq $8, %rsp + UNWIND_HINT_FUNC +@@ -364,7 +367,7 @@ SYM_CODE_START(return_to_handler) + movq %rax, RAX(%rsp) + movq %rdx, RDX(%rsp) + movq %rbp, RBP(%rsp) +- movq %rsp, RSP(%rsp) ++ movq %rdi, RSP(%rsp) + movq %rsp, %rdi + + call ftrace_return_to_handler +-- +2.51.0 + diff --git a/queue-6.18/xdrgen-fix-struct-prefix-for-typedef-types-in-progra.patch b/queue-6.18/xdrgen-fix-struct-prefix-for-typedef-types-in-progra.patch new file mode 100644 index 0000000000..3c0773c379 --- /dev/null +++ b/queue-6.18/xdrgen-fix-struct-prefix-for-typedef-types-in-progra.patch @@ -0,0 +1,83 @@ +From fe2ec6127ff6c5695597ec959e5fcff63ccae61d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Dec 2025 11:15:32 -0500 +Subject: xdrgen: Fix struct prefix for typedef types in program wrappers + +From: Chuck Lever + +[ Upstream commit bf0fe9ad3d597d8e1378dc9953ca96dfc3addb2b ] + +The program templates for decoder/argument.j2 and encoder/result.j2 +unconditionally add 'struct' prefix to all types. This is incorrect +when an RPC protocol specification lists a typedef'd basic type or +an enum as a procedure argument or result (e.g., NFSv2's fhandle or +stat), resulting in compiler errors when building generated C code. + +Fixes: 4b132aacb076 ("tools: Add xdrgen") +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + tools/net/sunrpc/xdrgen/generators/__init__.py | 3 ++- + .../sunrpc/xdrgen/templates/C/program/decoder/argument.j2 | 4 ++++ + .../net/sunrpc/xdrgen/templates/C/program/encoder/result.j2 | 6 ++++++ + 3 files changed, 12 insertions(+), 1 deletion(-) + +diff --git a/tools/net/sunrpc/xdrgen/generators/__init__.py b/tools/net/sunrpc/xdrgen/generators/__init__.py +index b98574a36a4ac..a2eb6652ac900 100644 +--- a/tools/net/sunrpc/xdrgen/generators/__init__.py ++++ b/tools/net/sunrpc/xdrgen/generators/__init__.py +@@ -6,7 +6,7 @@ import sys + from jinja2 import Environment, FileSystemLoader, Template + + from xdr_ast import _XdrAst, Specification, _RpcProgram, _XdrTypeSpecifier +-from xdr_ast import public_apis, pass_by_reference, get_header_name ++from xdr_ast import public_apis, pass_by_reference, structs, get_header_name + from xdr_parse import get_xdr_annotate + + +@@ -22,6 +22,7 @@ def create_jinja2_environment(language: str, xdr_type: str) -> Environment: + environment.globals["annotate"] = get_xdr_annotate() + environment.globals["public_apis"] = public_apis + environment.globals["pass_by_reference"] = pass_by_reference ++ environment.globals["structs"] = structs + return environment + case _: + raise NotImplementedError("Language not supported") +diff --git a/tools/net/sunrpc/xdrgen/templates/C/program/decoder/argument.j2 b/tools/net/sunrpc/xdrgen/templates/C/program/decoder/argument.j2 +index 0b1709cca0d4a..19b219dd276d3 100644 +--- a/tools/net/sunrpc/xdrgen/templates/C/program/decoder/argument.j2 ++++ b/tools/net/sunrpc/xdrgen/templates/C/program/decoder/argument.j2 +@@ -14,7 +14,11 @@ bool {{ program }}_svc_decode_{{ argument }}(struct svc_rqst *rqstp, struct xdr_ + {% if argument == 'void' %} + return xdrgen_decode_void(xdr); + {% else %} ++{% if argument in structs %} + struct {{ argument }} *argp = rqstp->rq_argp; ++{% else %} ++ {{ argument }} *argp = rqstp->rq_argp; ++{% endif %} + + return xdrgen_decode_{{ argument }}(xdr, argp); + {% endif %} +diff --git a/tools/net/sunrpc/xdrgen/templates/C/program/encoder/result.j2 b/tools/net/sunrpc/xdrgen/templates/C/program/encoder/result.j2 +index 6fc61a5d47b7f..746592cfda562 100644 +--- a/tools/net/sunrpc/xdrgen/templates/C/program/encoder/result.j2 ++++ b/tools/net/sunrpc/xdrgen/templates/C/program/encoder/result.j2 +@@ -14,8 +14,14 @@ bool {{ program }}_svc_encode_{{ result }}(struct svc_rqst *rqstp, struct xdr_st + {% if result == 'void' %} + return xdrgen_encode_void(xdr); + {% else %} ++{% if result in structs %} + struct {{ result }} *resp = rqstp->rq_resp; + + return xdrgen_encode_{{ result }}(xdr, resp); ++{% else %} ++ {{ result }} *resp = rqstp->rq_resp; ++ ++ return xdrgen_encode_{{ result }}(xdr, *resp); ++{% endif %} + {% endif %} + } +-- +2.51.0 + diff --git a/queue-6.18/xdrgen-initialize-data-pointer-for-zero-length-items.patch b/queue-6.18/xdrgen-initialize-data-pointer-for-zero-length-items.patch new file mode 100644 index 0000000000..dbad232ba8 --- /dev/null +++ b/queue-6.18/xdrgen-initialize-data-pointer-for-zero-length-items.patch @@ -0,0 +1,70 @@ +From 8bf6920b81bfaed6aeda250c35d7ced7331e597a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 10:41:09 -0500 +Subject: xdrgen: Initialize data pointer for zero-length items + +From: Chuck Lever + +[ Upstream commit 27b0fcae8f535fb882b1876227a935dcfdf576aa ] + +The xdrgen decoders for strings and opaque data had an +optimization that skipped calling xdr_inline_decode() when the +item length was zero. This left the data pointer uninitialized, +which could lead to unpredictable behavior when callers access +it. + +Remove the zero-length check and always call xdr_inline_decode(). +When passed a length of zero, xdr_inline_decode() returns the +current buffer position, which is valid and matches the behavior +of hand-coded XDR decoders throughout the kernel. + +Fixes: 4b132aacb076 ("tools: Add xdrgen") +Reviewed-by: Jeff Layton +Reviewed-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + include/linux/sunrpc/xdrgen/_builtins.h | 20 ++++++++------------ + 1 file changed, 8 insertions(+), 12 deletions(-) + +diff --git a/include/linux/sunrpc/xdrgen/_builtins.h b/include/linux/sunrpc/xdrgen/_builtins.h +index 66ca3ece951ab..a5ab75d2db044 100644 +--- a/include/linux/sunrpc/xdrgen/_builtins.h ++++ b/include/linux/sunrpc/xdrgen/_builtins.h +@@ -188,12 +188,10 @@ xdrgen_decode_string(struct xdr_stream *xdr, string *ptr, u32 maxlen) + return false; + if (unlikely(maxlen && len > maxlen)) + return false; +- if (len != 0) { +- p = xdr_inline_decode(xdr, len); +- if (unlikely(!p)) +- return false; +- ptr->data = (unsigned char *)p; +- } ++ p = xdr_inline_decode(xdr, len); ++ if (unlikely(!p)) ++ return false; ++ ptr->data = (unsigned char *)p; + ptr->len = len; + return true; + } +@@ -219,12 +217,10 @@ xdrgen_decode_opaque(struct xdr_stream *xdr, opaque *ptr, u32 maxlen) + return false; + if (unlikely(maxlen && len > maxlen)) + return false; +- if (len != 0) { +- p = xdr_inline_decode(xdr, len); +- if (unlikely(!p)) +- return false; +- ptr->data = (u8 *)p; +- } ++ p = xdr_inline_decode(xdr, len); ++ if (unlikely(!p)) ++ return false; ++ ptr->data = (u8 *)p; + ptr->len = len; + return true; + } +-- +2.51.0 + diff --git a/queue-6.18/xdrgen-remove-inclusion-of-nlm4.h-header.patch b/queue-6.18/xdrgen-remove-inclusion-of-nlm4.h-header.patch new file mode 100644 index 0000000000..733a415df4 --- /dev/null +++ b/queue-6.18/xdrgen-remove-inclusion-of-nlm4.h-header.patch @@ -0,0 +1,35 @@ +From 62f3d8d311654b8312fae8f46bef54044838598a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 22 Dec 2025 09:44:29 -0500 +Subject: xdrgen: Remove inclusion of nlm4.h header + +From: Chuck Lever + +[ Upstream commit eb1f3b55ac6202a013daf14ed508066947cdafa8 ] + +The client-side source code template mistakenly includes the +nlm4.h header file, which is specific to the NLM protocol and +should not be present in the generic template that generates +client stubs for all XDR-based protocols. + +Fixes: 903a7d37d9ea ("xdrgen: Update the files included in client-side source code") +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + tools/net/sunrpc/xdrgen/templates/C/source_top/client.j2 | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/tools/net/sunrpc/xdrgen/templates/C/source_top/client.j2 b/tools/net/sunrpc/xdrgen/templates/C/source_top/client.j2 +index c5518c519854a..df3598c38b2c2 100644 +--- a/tools/net/sunrpc/xdrgen/templates/C/source_top/client.j2 ++++ b/tools/net/sunrpc/xdrgen/templates/C/source_top/client.j2 +@@ -8,6 +8,5 @@ + #include + #include + #include +-#include + + #include +-- +2.51.0 + diff --git a/queue-6.18/xen-virtio-don-t-use-grant-dma-ops-when-running-as-d.patch b/queue-6.18/xen-virtio-don-t-use-grant-dma-ops-when-running-as-d.patch new file mode 100644 index 0000000000..0689e4f6ae --- /dev/null +++ b/queue-6.18/xen-virtio-don-t-use-grant-dma-ops-when-running-as-d.patch @@ -0,0 +1,45 @@ +From 8fe6a1441cd9552307e3f50c5d9d829471acad4a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Jan 2026 17:36:50 +0000 +Subject: xen/virtio: Don't use grant-dma-ops when running as Dom0 + +From: Teddy Astie + +[ Upstream commit dc8ea8714311e549ee93a2b0bdd5487d20bfadbf ] + +Dom0 inherit devices from the machine and is usually in PV mode. +If we are running in a virtual that has virtio devices, these devices +would be considered as using grants with Dom0 as backend, while being +the said Dom0 itself, while we want to use these devices like regular +PCI devices. + +Fix this by preventing grant-dma-ops from being used when running as Dom0 +(initial domain). We still keep the device-tree logic as-is. + +Signed-off-by: Teddy Astie +Fixes: 61367688f1fb0 ("xen/virtio: enable grant based virtio on x86") +Reviewed-by: Juergen Gross +Signed-off-by: Juergen Gross +Message-ID: <6698564dd2270a9f7377b78ebfb20cb425cabbe8.1767720955.git.teddy.astie@vates.tech> +Signed-off-by: Sasha Levin +--- + drivers/xen/grant-dma-ops.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/xen/grant-dma-ops.c b/drivers/xen/grant-dma-ops.c +index 29257d2639dbf..43a918c498c6c 100644 +--- a/drivers/xen/grant-dma-ops.c ++++ b/drivers/xen/grant-dma-ops.c +@@ -362,7 +362,8 @@ static int xen_grant_init_backend_domid(struct device *dev, + if (np) { + ret = xen_dt_grant_init_backend_domid(dev, np, backend_domid); + of_node_put(np); +- } else if (IS_ENABLED(CONFIG_XEN_VIRTIO_FORCE_GRANT) || xen_pv_domain()) { ++ } else if (!xen_initial_domain() && ++ (IS_ENABLED(CONFIG_XEN_VIRTIO_FORCE_GRANT) || xen_pv_domain())) { + dev_info(dev, "Using dom0 as backend\n"); + *backend_domid = 0; + ret = 0; +-- +2.51.0 + diff --git a/queue-6.18/xfrm-fix-ip_rt_bug-race-in-icmp_route_lookup-reverse.patch b/queue-6.18/xfrm-fix-ip_rt_bug-race-in-icmp_route_lookup-reverse.patch new file mode 100644 index 0000000000..7d5ade4f31 --- /dev/null +++ b/queue-6.18/xfrm-fix-ip_rt_bug-race-in-icmp_route_lookup-reverse.patch @@ -0,0 +1,100 @@ +From 3f10cb9903e57b02aa1c1f7df8c021e94783fc19 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 13:02:19 +0800 +Subject: xfrm: fix ip_rt_bug race in icmp_route_lookup reverse path + +From: Jiayuan Chen + +[ Upstream commit 81b84de32bb27ae1ae2eb9acf0420e9d0d14bf00 ] + +icmp_route_lookup() performs multiple route lookups to find a suitable +route for sending ICMP error messages, with special handling for XFRM +(IPsec) policies. + +The lookup sequence is: +1. First, lookup output route for ICMP reply (dst = original src) +2. Pass through xfrm_lookup() for policy check +3. If blocked (-EPERM) or dst is not local, enter "reverse path" +4. In reverse path, call xfrm_decode_session_reverse() to get fl4_dec + which reverses the original packet's flow (saddr<->daddr swapped) +5. If fl4_dec.saddr is local (we are the original destination), use + __ip_route_output_key() for output route lookup +6. If fl4_dec.saddr is NOT local (we are a forwarding node), use + ip_route_input() to simulate the reverse packet's input path +7. Finally, pass rt2 through xfrm_lookup() with XFRM_LOOKUP_ICMP flag + +The bug occurs in step 6: ip_route_input() is called with fl4_dec.daddr +(original packet's source) as destination. If this address becomes local +between the initial check and ip_route_input() call (e.g., due to +concurrent "ip addr add"), ip_route_input() returns a LOCAL route with +dst.output set to ip_rt_bug. + +This route is then used for ICMP output, causing dst_output() to call +ip_rt_bug(), triggering a WARN_ON: + + ------------[ cut here ]------------ + WARNING: net/ipv4/route.c:1275 at ip_rt_bug+0x21/0x30, CPU#1 + Call Trace: + + ip_push_pending_frames+0x202/0x240 + icmp_push_reply+0x30d/0x430 + __icmp_send+0x1149/0x24f0 + ip_options_compile+0xa2/0xd0 + ip_rcv_finish_core+0x829/0x1950 + ip_rcv+0x2d7/0x420 + __netif_receive_skb_one_core+0x185/0x1f0 + netif_receive_skb+0x90/0x450 + tun_get_user+0x3413/0x3fb0 + tun_chr_write_iter+0xe4/0x220 + ... + +Fix this by checking rt2->rt_type after ip_route_input(). If it's +RTN_LOCAL, the route cannot be used for output, so treat it as an error. + +The reproducer requires kernel modification to widen the race window, +making it unsuitable as a selftest. It is available at: + + https://gist.github.com/mrpre/eae853b72ac6a750f5d45d64ddac1e81 + +Reported-by: syzbot+e738404dcd14b620923c@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/000000000000b1060905eada8881@google.com/T/ +Closes: https://lore.kernel.org/r/20260128090523.356953-1-jiayuan.chen@linux.dev +Fixes: 8b7817f3a959 ("[IPSEC]: Add ICMP host relookup support") +Signed-off-by: Jiayuan Chen +Signed-off-by: Jiayuan Chen +Link: https://patch.msgid.link/20260206050220.59642-1-jiayuan.chen@linux.dev +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/ipv4/icmp.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c +index 8e10e9e7676c5..9323ee0a6ac48 100644 +--- a/net/ipv4/icmp.c ++++ b/net/ipv4/icmp.c +@@ -554,6 +554,21 @@ static struct rtable *icmp_route_lookup(struct net *net, struct flowi4 *fl4, + /* steal dst entry from skb_in, don't drop refcnt */ + skb_dstref_steal(skb_in); + skb_dstref_restore(skb_in, orefdst); ++ ++ /* ++ * At this point, fl4_dec.daddr should NOT be local (we ++ * checked fl4_dec.saddr above). However, a race condition ++ * may occur if the address is added to the interface ++ * concurrently. In that case, ip_route_input() returns a ++ * LOCAL route with dst.output=ip_rt_bug, which must not ++ * be used for output. ++ */ ++ if (!err && rt2 && rt2->rt_type == RTN_LOCAL) { ++ net_warn_ratelimited("detected local route for %pI4 during ICMP sending, src %pI4\n", ++ &fl4_dec.daddr, &fl4_dec.saddr); ++ dst_release(&rt2->dst); ++ err = -EINVAL; ++ } + } + + if (err) +-- +2.51.0 + diff --git a/queue-6.19/accel-amdxdna-enable-temporal-sharing-only-mode.patch b/queue-6.19/accel-amdxdna-enable-temporal-sharing-only-mode.patch new file mode 100644 index 0000000000..05db119328 --- /dev/null +++ b/queue-6.19/accel-amdxdna-enable-temporal-sharing-only-mode.patch @@ -0,0 +1,130 @@ +From af6236b1a4cdcf7c1c2e88caba10b73504d36c69 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 17 Dec 2025 11:11:50 -0800 +Subject: accel/amdxdna: Enable temporal sharing only mode + +From: Lizhi Hou + +[ Upstream commit 7818618a09a06320f409571bf28801ccfe7e0a30 ] + +Newer firmware versions prefer temporal sharing only mode. In this mode, +the driver no longer needs to manage AIE array column allocation. Instead, +a new field, num_unused_col, is added to the hardware context creation +request to specify how many columns will not be used by this hardware +context. + +Reviewed-by: Mario Limonciello (AMD) +Signed-off-by: Lizhi Hou +Link: https://patch.msgid.link/20251217191150.2145937-1-lizhi.hou@amd.com +Stable-dep-of: b853007fdcdd ("accel/amdxdna: Remove hardware context status") +Signed-off-by: Sasha Levin +--- + drivers/accel/amdxdna/aie2_ctx.c | 18 +++++++++++++++--- + drivers/accel/amdxdna/aie2_message.c | 1 + + drivers/accel/amdxdna/aie2_msg_priv.h | 3 ++- + drivers/accel/amdxdna/aie2_pci.h | 1 + + drivers/accel/amdxdna/amdxdna_ctx.h | 1 + + drivers/accel/amdxdna/npu4_regs.c | 1 + + 6 files changed, 21 insertions(+), 4 deletions(-) + +diff --git a/drivers/accel/amdxdna/aie2_ctx.c b/drivers/accel/amdxdna/aie2_ctx.c +index 2c36ed7e9639c..c4a58c00e442a 100644 +--- a/drivers/accel/amdxdna/aie2_ctx.c ++++ b/drivers/accel/amdxdna/aie2_ctx.c +@@ -471,6 +471,12 @@ static int aie2_alloc_resource(struct amdxdna_hwctx *hwctx) + struct alloc_requests *xrs_req; + int ret; + ++ if (AIE2_FEATURE_ON(xdna->dev_handle, AIE2_TEMPORAL_ONLY)) { ++ hwctx->num_unused_col = xdna->dev_handle->total_col - hwctx->num_col; ++ hwctx->num_col = xdna->dev_handle->total_col; ++ return aie2_create_context(xdna->dev_handle, hwctx); ++ } ++ + xrs_req = kzalloc(sizeof(*xrs_req), GFP_KERNEL); + if (!xrs_req) + return -ENOMEM; +@@ -502,9 +508,15 @@ static void aie2_release_resource(struct amdxdna_hwctx *hwctx) + struct amdxdna_dev *xdna = hwctx->client->xdna; + int ret; + +- ret = xrs_release_resource(xdna->xrs_hdl, (uintptr_t)hwctx); +- if (ret) +- XDNA_ERR(xdna, "Release AIE resource failed, ret %d", ret); ++ if (AIE2_FEATURE_ON(xdna->dev_handle, AIE2_TEMPORAL_ONLY)) { ++ ret = aie2_destroy_context(xdna->dev_handle, hwctx); ++ if (ret) ++ XDNA_ERR(xdna, "Destroy temporal only context failed, ret %d", ret); ++ } else { ++ ret = xrs_release_resource(xdna->xrs_hdl, (uintptr_t)hwctx); ++ if (ret) ++ XDNA_ERR(xdna, "Release AIE resource failed, ret %d", ret); ++ } + } + + static int aie2_ctx_syncobj_create(struct amdxdna_hwctx *hwctx) +diff --git a/drivers/accel/amdxdna/aie2_message.c b/drivers/accel/amdxdna/aie2_message.c +index 9e55e66830ead..273d6af9f6f52 100644 +--- a/drivers/accel/amdxdna/aie2_message.c ++++ b/drivers/accel/amdxdna/aie2_message.c +@@ -211,6 +211,7 @@ int aie2_create_context(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwct + req.aie_type = 1; + req.start_col = hwctx->start_col; + req.num_col = hwctx->num_col; ++ req.num_unused_col = hwctx->num_unused_col; + req.num_cq_pairs_requested = 1; + req.pasid = hwctx->client->pasid; + req.context_priority = 2; +diff --git a/drivers/accel/amdxdna/aie2_msg_priv.h b/drivers/accel/amdxdna/aie2_msg_priv.h +index 1c957a6298d39..cc912b7899ce5 100644 +--- a/drivers/accel/amdxdna/aie2_msg_priv.h ++++ b/drivers/accel/amdxdna/aie2_msg_priv.h +@@ -112,7 +112,8 @@ struct create_ctx_req { + __u32 aie_type; + __u8 start_col; + __u8 num_col; +- __u16 reserved; ++ __u8 num_unused_col; ++ __u8 reserved; + __u8 num_cq_pairs_requested; + __u8 reserved1; + __u16 pasid; +diff --git a/drivers/accel/amdxdna/aie2_pci.h b/drivers/accel/amdxdna/aie2_pci.h +index e08ec2fd44daa..4fdc032bc171b 100644 +--- a/drivers/accel/amdxdna/aie2_pci.h ++++ b/drivers/accel/amdxdna/aie2_pci.h +@@ -231,6 +231,7 @@ struct aie2_hw_ops { + enum aie2_fw_feature { + AIE2_NPU_COMMAND, + AIE2_PREEMPT, ++ AIE2_TEMPORAL_ONLY, + AIE2_FEATURE_MAX + }; + +diff --git a/drivers/accel/amdxdna/amdxdna_ctx.h b/drivers/accel/amdxdna/amdxdna_ctx.h +index b6151244d64fe..b29449a92f607 100644 +--- a/drivers/accel/amdxdna/amdxdna_ctx.h ++++ b/drivers/accel/amdxdna/amdxdna_ctx.h +@@ -98,6 +98,7 @@ struct amdxdna_hwctx { + u32 *col_list; + u32 start_col; + u32 num_col; ++ u32 num_unused_col; + #define HWCTX_STAT_INIT 0 + #define HWCTX_STAT_READY 1 + #define HWCTX_STAT_STOP 2 +diff --git a/drivers/accel/amdxdna/npu4_regs.c b/drivers/accel/amdxdna/npu4_regs.c +index 986a5f28ba245..2ceedfe583a8c 100644 +--- a/drivers/accel/amdxdna/npu4_regs.c ++++ b/drivers/accel/amdxdna/npu4_regs.c +@@ -89,6 +89,7 @@ const struct dpm_clk_freq npu4_dpm_clk_table[] = { + const struct aie2_fw_feature_tbl npu4_fw_feature_table[] = { + { .feature = AIE2_NPU_COMMAND, .min_minor = 15 }, + { .feature = AIE2_PREEMPT, .min_minor = 12 }, ++ { .feature = AIE2_TEMPORAL_ONLY, .min_minor = 12 }, + { 0 } + }; + +-- +2.51.0 + diff --git a/queue-6.19/accel-amdxdna-fix-cu_idx-being-cleared-by-memset-dur.patch b/queue-6.19/accel-amdxdna-fix-cu_idx-being-cleared-by-memset-dur.patch new file mode 100644 index 0000000000..4c3990a8f5 --- /dev/null +++ b/queue-6.19/accel-amdxdna-fix-cu_idx-being-cleared-by-memset-dur.patch @@ -0,0 +1,98 @@ +From ae3c125a19aec318921746c84b402abf015fd6f3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 13:16:39 -0800 +Subject: accel/amdxdna: Fix cu_idx being cleared by memset() during command + setup + +From: Lizhi Hou + +[ Upstream commit 3d32eb7a5ecff92d83a5fd34c45c171c17d3d5d0 ] + +For one command type, cu_idx is assigned before calling memset() on the +command structure. This results in cu_idx being overwritten, causing the +firmware to receive an incomplete or invalid command and leading to +unexpected command failures. + +Fix this by moving the memset() call before initializing cu_idx so that +all fields are populated in the correct order. + +Fixes: 71829d7f2f70 ("accel/amdxdna: Use MSG_OP_CHAIN_EXEC_NPU when supported") +Reviewed-by: Mario Limonciello (AMD) +Signed-off-by: Lizhi Hou +Link: https://patch.msgid.link/20251209211639.1636888-1-lizhi.hou@amd.com +Signed-off-by: Sasha Levin +--- + drivers/accel/amdxdna/aie2_message.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/accel/amdxdna/aie2_message.c b/drivers/accel/amdxdna/aie2_message.c +index 18cf8e49ea94d..e64dc3152c884 100644 +--- a/drivers/accel/amdxdna/aie2_message.c ++++ b/drivers/accel/amdxdna/aie2_message.c +@@ -645,6 +645,7 @@ aie2_cmdlist_fill_npu_cf(struct amdxdna_gem_obj *cmd_bo, void *slot, size_t *siz + u32 cmd_len; + void *cmd; + ++ memset(npu_slot, 0, sizeof(*npu_slot)); + cmd = amdxdna_cmd_get_payload(cmd_bo, &cmd_len); + if (*size < sizeof(*npu_slot) + cmd_len) + return -EINVAL; +@@ -653,7 +654,6 @@ aie2_cmdlist_fill_npu_cf(struct amdxdna_gem_obj *cmd_bo, void *slot, size_t *siz + if (npu_slot->cu_idx == INVALID_CU_IDX) + return -EINVAL; + +- memset(npu_slot, 0, sizeof(*npu_slot)); + npu_slot->type = EXEC_NPU_TYPE_NON_ELF; + npu_slot->arg_cnt = cmd_len / sizeof(u32); + memcpy(npu_slot->args, cmd, cmd_len); +@@ -670,6 +670,7 @@ aie2_cmdlist_fill_npu_dpu(struct amdxdna_gem_obj *cmd_bo, void *slot, size_t *si + u32 cmd_len; + u32 arg_sz; + ++ memset(npu_slot, 0, sizeof(*npu_slot)); + sn = amdxdna_cmd_get_payload(cmd_bo, &cmd_len); + arg_sz = cmd_len - sizeof(*sn); + if (cmd_len < sizeof(*sn) || arg_sz > MAX_NPU_ARGS_SIZE) +@@ -682,7 +683,6 @@ aie2_cmdlist_fill_npu_dpu(struct amdxdna_gem_obj *cmd_bo, void *slot, size_t *si + if (npu_slot->cu_idx == INVALID_CU_IDX) + return -EINVAL; + +- memset(npu_slot, 0, sizeof(*npu_slot)); + npu_slot->type = EXEC_NPU_TYPE_PARTIAL_ELF; + npu_slot->inst_buf_addr = sn->buffer; + npu_slot->inst_size = sn->buffer_size; +@@ -702,6 +702,7 @@ aie2_cmdlist_fill_npu_preempt(struct amdxdna_gem_obj *cmd_bo, void *slot, size_t + u32 cmd_len; + u32 arg_sz; + ++ memset(npu_slot, 0, sizeof(*npu_slot)); + pd = amdxdna_cmd_get_payload(cmd_bo, &cmd_len); + arg_sz = cmd_len - sizeof(*pd); + if (cmd_len < sizeof(*pd) || arg_sz > MAX_NPU_ARGS_SIZE) +@@ -714,7 +715,6 @@ aie2_cmdlist_fill_npu_preempt(struct amdxdna_gem_obj *cmd_bo, void *slot, size_t + if (npu_slot->cu_idx == INVALID_CU_IDX) + return -EINVAL; + +- memset(npu_slot, 0, sizeof(*npu_slot)); + npu_slot->type = EXEC_NPU_TYPE_PREEMPT; + npu_slot->inst_buf_addr = pd->inst_buf; + npu_slot->save_buf_addr = pd->save_buf; +@@ -738,6 +738,7 @@ aie2_cmdlist_fill_npu_elf(struct amdxdna_gem_obj *cmd_bo, void *slot, size_t *si + u32 cmd_len; + u32 arg_sz; + ++ memset(npu_slot, 0, sizeof(*npu_slot)); + pd = amdxdna_cmd_get_payload(cmd_bo, &cmd_len); + arg_sz = cmd_len - sizeof(*pd); + if (cmd_len < sizeof(*pd) || arg_sz > MAX_NPU_ARGS_SIZE) +@@ -746,7 +747,6 @@ aie2_cmdlist_fill_npu_elf(struct amdxdna_gem_obj *cmd_bo, void *slot, size_t *si + if (*size < sizeof(*npu_slot) + arg_sz) + return -EINVAL; + +- memset(npu_slot, 0, sizeof(*npu_slot)); + npu_slot->type = EXEC_NPU_TYPE_ELF; + npu_slot->inst_buf_addr = pd->inst_buf; + npu_slot->save_buf_addr = pd->save_buf; +-- +2.51.0 + diff --git a/queue-6.19/accel-amdxdna-fix-incorrect-dpm-level-after-suspend-.patch b/queue-6.19/accel-amdxdna-fix-incorrect-dpm-level-after-suspend-.patch new file mode 100644 index 0000000000..43940f4b8f --- /dev/null +++ b/queue-6.19/accel-amdxdna-fix-incorrect-dpm-level-after-suspend-.patch @@ -0,0 +1,70 @@ +From 7a20fe323aeb31e5114d51dadda6168310468cd1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 09:10:48 -0800 +Subject: accel/amdxdna: Fix incorrect DPM level after suspend/resume + +From: Lizhi Hou + +[ Upstream commit d19d963d2a4acb5bbf03e25733ba565a7f6e1422 ] + +The suspend routine sets the DPM level to 0, which unintentionally +overwrites the previously saved DPM level. As a result, the device always +resumes with DPM level 0 instead of restoring the original value. + +Fix this by ensuring the suspend path does not overwrite the saved DPM +level, allowing the correct DPM level to be restored during resume. + +Fixes: f4d7b8a6bc8c ("accel/amdxdna: Enhance power management settings") +Reviewed-by: Mario Limonciello (AMD) +Signed-off-by: Lizhi Hou +Link: https://patch.msgid.link/20260204171048.3165580-1-lizhi.hou@amd.com +Signed-off-by: Sasha Levin +--- + drivers/accel/amdxdna/aie2_pm.c | 3 +++ + drivers/accel/amdxdna/aie2_smu.c | 2 -- + 2 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/accel/amdxdna/aie2_pm.c b/drivers/accel/amdxdna/aie2_pm.c +index afcd6d4683e56..579b8be13b180 100644 +--- a/drivers/accel/amdxdna/aie2_pm.c ++++ b/drivers/accel/amdxdna/aie2_pm.c +@@ -36,6 +36,8 @@ int aie2_pm_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level) + return ret; + + ret = ndev->priv->hw_ops.set_dpm(ndev, dpm_level); ++ if (!ret) ++ ndev->dpm_level = dpm_level; + amdxdna_pm_suspend_put(ndev->xdna); + + return ret; +@@ -65,6 +67,7 @@ int aie2_pm_init(struct amdxdna_dev_hdl *ndev) + ret = ndev->priv->hw_ops.set_dpm(ndev, ndev->max_dpm_level); + if (ret) + return ret; ++ ndev->dpm_level = ndev->max_dpm_level; + + ret = aie2_pm_set_clk_gating(ndev, AIE2_CLK_GATING_ENABLE); + if (ret) +diff --git a/drivers/accel/amdxdna/aie2_smu.c b/drivers/accel/amdxdna/aie2_smu.c +index 2d195e41f83dd..d8c31924e501b 100644 +--- a/drivers/accel/amdxdna/aie2_smu.c ++++ b/drivers/accel/amdxdna/aie2_smu.c +@@ -84,7 +84,6 @@ int npu1_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level) + } + + ndev->hclk_freq = freq; +- ndev->dpm_level = dpm_level; + ndev->max_tops = 2 * ndev->total_col; + ndev->curr_tops = ndev->max_tops * freq / 1028; + +@@ -114,7 +113,6 @@ int npu4_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level) + + ndev->npuclk_freq = ndev->priv->dpm_clk_tbl[dpm_level].npuclk; + ndev->hclk_freq = ndev->priv->dpm_clk_tbl[dpm_level].hclk; +- ndev->dpm_level = dpm_level; + ndev->max_tops = NPU4_DPM_TOPS(ndev, ndev->max_dpm_level); + ndev->curr_tops = NPU4_DPM_TOPS(ndev, dpm_level); + +-- +2.51.0 + diff --git a/queue-6.19/accel-amdxdna-fix-incorrect-error-code-returned-for-.patch b/queue-6.19/accel-amdxdna-fix-incorrect-error-code-returned-for-.patch new file mode 100644 index 0000000000..7860fa4c26 --- /dev/null +++ b/queue-6.19/accel-amdxdna-fix-incorrect-error-code-returned-for-.patch @@ -0,0 +1,40 @@ +From 1f06c5d4b9adbc7a6f68361a2e21d13fb2b44546 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 10:40:37 -0800 +Subject: accel/amdxdna: Fix incorrect error code returned for failed chain + command + +From: Lizhi Hou + +[ Upstream commit 750817a7c41de083ca5d73052e97bb7b67d7c394 ] + +The driver currently returns an incorrect error code when a chain command +fails. In this case, ERT_CMD_STATE_ERROR is expected to be reported for +failed chain commands. + +Fixes: aac243092b70 ("accel/amdxdna: Add command execution") +Reviewed-by: Mario Limonciello (AMD) +Reviewed-by: Maciej Falkowski +Signed-off-by: Lizhi Hou +Link: https://patch.msgid.link/20260203184037.2751889-1-lizhi.hou@amd.com +Signed-off-by: Sasha Levin +--- + drivers/accel/amdxdna/aie2_ctx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/accel/amdxdna/aie2_ctx.c b/drivers/accel/amdxdna/aie2_ctx.c +index ad5b5cd0bc81f..fe8f9783a73c7 100644 +--- a/drivers/accel/amdxdna/aie2_ctx.c ++++ b/drivers/accel/amdxdna/aie2_ctx.c +@@ -274,7 +274,7 @@ aie2_sched_cmdlist_resp_handler(void *handle, void __iomem *data, size_t size) + ret = -EINVAL; + goto out; + } +- amdxdna_cmd_set_state(cmd_abo, fail_cmd_status); ++ amdxdna_cmd_set_state(cmd_abo, ERT_CMD_STATE_ERROR); + + if (amdxdna_cmd_get_op(cmd_abo) == ERT_CMD_CHAIN) { + struct amdxdna_cmd_chain *cc = amdxdna_cmd_get_payload(cmd_abo, NULL); +-- +2.51.0 + diff --git a/queue-6.19/accel-amdxdna-fix-memory-leak-in-amdxdna_ubuf_map.patch b/queue-6.19/accel-amdxdna-fix-memory-leak-in-amdxdna_ubuf_map.patch new file mode 100644 index 0000000000..5441647ade --- /dev/null +++ b/queue-6.19/accel-amdxdna-fix-memory-leak-in-amdxdna_ubuf_map.patch @@ -0,0 +1,55 @@ +From aa18429580a664544e6ebf72ede1a83b82b026bc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 01:10:22 +0800 +Subject: accel/amdxdna: Fix memory leak in amdxdna_ubuf_map + +From: Zishun Yi + +[ Upstream commit 84dd57fb0359500092f1101409ca32091731490d ] + +The amdxdna_ubuf_map() function allocates memory for sg and +internal sg table structures, but it fails to free them if subsequent +operations (sg_alloc_table_from_pages or dma_map_sgtable) fail. + +Fixes: bd72d4acda10 ("accel/amdxdna: Support user space allocated buffer") +Signed-off-by: Zishun Yi +Reviewed-by: Lizhi Hou +Reviewed-by: Min Ma +Signed-off-by: Lizhi Hou +Link: https://patch.msgid.link/20260129171022.68578-1-zishun.yi.dev@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/accel/amdxdna/amdxdna_ubuf.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/drivers/accel/amdxdna/amdxdna_ubuf.c b/drivers/accel/amdxdna/amdxdna_ubuf.c +index 077b2261cf2a0..9e3b3b055caa8 100644 +--- a/drivers/accel/amdxdna/amdxdna_ubuf.c ++++ b/drivers/accel/amdxdna/amdxdna_ubuf.c +@@ -34,15 +34,21 @@ static struct sg_table *amdxdna_ubuf_map(struct dma_buf_attachment *attach, + ret = sg_alloc_table_from_pages(sg, ubuf->pages, ubuf->nr_pages, 0, + ubuf->nr_pages << PAGE_SHIFT, GFP_KERNEL); + if (ret) +- return ERR_PTR(ret); ++ goto err_free_sg; + + if (ubuf->flags & AMDXDNA_UBUF_FLAG_MAP_DMA) { + ret = dma_map_sgtable(attach->dev, sg, direction, 0); + if (ret) +- return ERR_PTR(ret); ++ goto err_free_table; + } + + return sg; ++ ++err_free_table: ++ sg_free_table(sg); ++err_free_sg: ++ kfree(sg); ++ return ERR_PTR(ret); + } + + static void amdxdna_ubuf_unmap(struct dma_buf_attachment *attach, +-- +2.51.0 + diff --git a/queue-6.19/accel-amdxdna-fix-notifier_wq-flushing-warning.patch b/queue-6.19/accel-amdxdna-fix-notifier_wq-flushing-warning.patch new file mode 100644 index 0000000000..0256beb9a1 --- /dev/null +++ b/queue-6.19/accel-amdxdna-fix-notifier_wq-flushing-warning.patch @@ -0,0 +1,39 @@ +From 9089a242fd0e2385e3fef111bc396d9ad6924296 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Jan 2026 09:36:24 -0800 +Subject: accel/amdxdna: Fix notifier_wq flushing warning + +From: Lizhi Hou + +[ Upstream commit b36178488d479e9a53bbef2b01280378b5586e60 ] + +Create notifier_wq with WQ_MEM_RECLAIM flag to fix the possible warning. + + workqueue: WQ_MEM_RECLAIM amdxdna_js:drm_sched_free_job_work [gpu_sched] is flushing !WQ_MEM_RECLAIM notifier_wq:0x0 + +Fixes: e486147c912f ("accel/amdxdna: Add BO import and export") +Reviewed-by: Mario Limonciello (AMD) +Reviewed-by: Maciej Falkowski +Signed-off-by: Lizhi Hou +Link: https://patch.msgid.link/20260113173624.256053-1-lizhi.hou@amd.com +Signed-off-by: Sasha Levin +--- + drivers/accel/amdxdna/amdxdna_pci_drv.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/accel/amdxdna/amdxdna_pci_drv.c b/drivers/accel/amdxdna/amdxdna_pci_drv.c +index 1973ab67721be..fcc9be23b3de5 100644 +--- a/drivers/accel/amdxdna/amdxdna_pci_drv.c ++++ b/drivers/accel/amdxdna/amdxdna_pci_drv.c +@@ -282,7 +282,7 @@ static int amdxdna_probe(struct pci_dev *pdev, const struct pci_device_id *id) + fs_reclaim_release(GFP_KERNEL); + } + +- xdna->notifier_wq = alloc_ordered_workqueue("notifier_wq", 0); ++ xdna->notifier_wq = alloc_ordered_workqueue("notifier_wq", WQ_MEM_RECLAIM); + if (!xdna->notifier_wq) + return -ENOMEM; + +-- +2.51.0 + diff --git a/queue-6.19/accel-amdxdna-fix-potential-null-pointer-dereference.patch b/queue-6.19/accel-amdxdna-fix-potential-null-pointer-dereference.patch new file mode 100644 index 0000000000..514a823fb6 --- /dev/null +++ b/queue-6.19/accel-amdxdna-fix-potential-null-pointer-dereference.patch @@ -0,0 +1,134 @@ +From 0650d02ea9f39a20c22ea59c2785706989e63465 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 12 Dec 2025 10:32:44 -0800 +Subject: accel/amdxdna: Fix potential NULL pointer dereference in context + cleanup + +From: Lizhi Hou + +[ Upstream commit 97f27573837ef96b4ba42af463cc800cab615c0e ] + +aie_destroy_context() is invoked during error handling in +aie2_create_context(). However, aie_destroy_context() assumes that the +context's mailbox channel pointer is non-NULL. If mailbox channel +creation fails, the pointer remains NULL and calling aie_destroy_context() +can lead to a NULL pointer dereference. + +In aie2_create_context(), replace aie_destroy_context() with a function +which request firmware to remove the context created previously. + +Fixes: be462c97b7df ("accel/amdxdna: Add hardware context") +Reviewed-by: Mario Limonciello (AMD) +Signed-off-by: Lizhi Hou +Link: https://patch.msgid.link/20251212183244.1826318-1-lizhi.hou@amd.com +Signed-off-by: Sasha Levin +--- + drivers/accel/amdxdna/aie2_message.c | 50 +++++++++++++++------------- + 1 file changed, 26 insertions(+), 24 deletions(-) + +diff --git a/drivers/accel/amdxdna/aie2_message.c b/drivers/accel/amdxdna/aie2_message.c +index e64dc3152c884..9e55e66830ead 100644 +--- a/drivers/accel/amdxdna/aie2_message.c ++++ b/drivers/accel/amdxdna/aie2_message.c +@@ -185,6 +185,19 @@ int aie2_query_firmware_version(struct amdxdna_dev_hdl *ndev, + return 0; + } + ++static int aie2_destroy_context_req(struct amdxdna_dev_hdl *ndev, u32 id) ++{ ++ DECLARE_AIE2_MSG(destroy_ctx, MSG_OP_DESTROY_CONTEXT); ++ struct amdxdna_dev *xdna = ndev->xdna; ++ int ret; ++ ++ req.context_id = id; ++ ret = aie2_send_mgmt_msg_wait(ndev, &msg); ++ if (ret) ++ XDNA_WARN(xdna, "Destroy context failed, ret %d", ret); ++ ++ return ret; ++} + int aie2_create_context(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwctx) + { + DECLARE_AIE2_MSG(create_ctx, MSG_OP_CREATE_CONTEXT); +@@ -207,13 +220,14 @@ int aie2_create_context(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwct + return ret; + + hwctx->fw_ctx_id = resp.context_id; +- WARN_ONCE(hwctx->fw_ctx_id == -1, "Unexpected context id"); ++ if (WARN_ON_ONCE(hwctx->fw_ctx_id == -1)) ++ return -EINVAL; + + if (ndev->force_preempt_enabled) { + ret = aie2_runtime_cfg(ndev, AIE2_RT_CFG_FORCE_PREEMPT, &hwctx->fw_ctx_id); + if (ret) { + XDNA_ERR(xdna, "failed to enable force preempt %d", ret); +- return ret; ++ goto del_ctx_req; + } + } + +@@ -230,51 +244,39 @@ int aie2_create_context(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwct + + ret = pci_irq_vector(to_pci_dev(xdna->ddev.dev), resp.msix_id); + if (ret == -EINVAL) { +- XDNA_ERR(xdna, "not able to create channel"); +- goto out_destroy_context; ++ XDNA_ERR(xdna, "Alloc IRQ failed %d", ret); ++ goto del_ctx_req; + } + + intr_reg = i2x.mb_head_ptr_reg + 4; + hwctx->priv->mbox_chann = xdna_mailbox_create_channel(ndev->mbox, &x2i, &i2x, + intr_reg, ret); + if (!hwctx->priv->mbox_chann) { +- XDNA_ERR(xdna, "not able to create channel"); ++ XDNA_ERR(xdna, "Not able to create channel"); + ret = -EINVAL; +- goto out_destroy_context; ++ goto del_ctx_req; + } + ndev->hwctx_num++; + +- XDNA_DBG(xdna, "%s mailbox channel irq: %d, msix_id: %d", +- hwctx->name, ret, resp.msix_id); +- XDNA_DBG(xdna, "%s created fw ctx %d pasid %d", hwctx->name, +- hwctx->fw_ctx_id, hwctx->client->pasid); ++ XDNA_DBG(xdna, "Mailbox channel irq: %d, msix_id: %d", ret, resp.msix_id); ++ XDNA_DBG(xdna, "Created fw ctx %d pasid %d", hwctx->fw_ctx_id, hwctx->client->pasid); + + return 0; + +-out_destroy_context: +- aie2_destroy_context(ndev, hwctx); ++del_ctx_req: ++ aie2_destroy_context_req(ndev, hwctx->fw_ctx_id); + return ret; + } + + int aie2_destroy_context(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwctx) + { +- DECLARE_AIE2_MSG(destroy_ctx, MSG_OP_DESTROY_CONTEXT); + struct amdxdna_dev *xdna = ndev->xdna; + int ret; + +- if (hwctx->fw_ctx_id == -1) +- return 0; +- + xdna_mailbox_stop_channel(hwctx->priv->mbox_chann); +- +- req.context_id = hwctx->fw_ctx_id; +- ret = aie2_send_mgmt_msg_wait(ndev, &msg); +- if (ret) +- XDNA_WARN(xdna, "%s destroy context failed, ret %d", hwctx->name, ret); +- ++ ret = aie2_destroy_context_req(ndev, hwctx->fw_ctx_id); + xdna_mailbox_destroy_channel(hwctx->priv->mbox_chann); +- XDNA_DBG(xdna, "%s destroyed fw ctx %d", hwctx->name, +- hwctx->fw_ctx_id); ++ XDNA_DBG(xdna, "Destroyed fw ctx %d", hwctx->fw_ctx_id); + hwctx->priv->mbox_chann = NULL; + hwctx->fw_ctx_id = -1; + ndev->hwctx_num--; +-- +2.51.0 + diff --git a/queue-6.19/accel-amdxdna-fix-race-condition-when-checking-rpm_o.patch b/queue-6.19/accel-amdxdna-fix-race-condition-when-checking-rpm_o.patch new file mode 100644 index 0000000000..b5e6446070 --- /dev/null +++ b/queue-6.19/accel-amdxdna-fix-race-condition-when-checking-rpm_o.patch @@ -0,0 +1,295 @@ +From e55612bfa11af811e892523800ae5cace19f2ce5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Dec 2025 08:53:56 -0800 +Subject: accel/amdxdna: Fix race condition when checking rpm_on + +From: Lizhi Hou + +[ Upstream commit 00ffe45ece80160aef446d74ded906352f21dd72 ] + +When autosuspend is triggered, driver rpm_on flag is set to indicate that +a suspend/resume is already in progress. However, when a userspace +application submits a command during this narrow window, +amdxdna_pm_resume_get() may incorrectly skip the resume operation because +the rpm_on flag is still set. This results in commands being submitted +while the device has not actually resumed, causing unexpected behavior. + +The set_dpm() is called by suspend/resume, it relied on rpm_on flag to +avoid calling into rpm suspend/resume recursivly. So to fix this, remove +the use of the rpm_on flag entirely. Instead, introduce aie2_pm_set_dpm() +which explicitly resumes the device before invoking set_dpm(). With this +change, set_dpm() is called directly inside the suspend or resume execution +path. Otherwise, aie2_pm_set_dpm() is called. + +Fixes: 063db451832b ("accel/amdxdna: Enhance runtime power management") +Reviewed-by: Mario Limonciello (AMD) +Reviewed-by: Maciej Falkowski +Signed-off-by: Lizhi Hou +Link: https://patch.msgid.link/20251208165356.1549237-1-lizhi.hou@amd.com +Signed-off-by: Sasha Levin +--- + drivers/accel/amdxdna/aie2_message.c | 1 - + drivers/accel/amdxdna/aie2_pci.c | 2 +- + drivers/accel/amdxdna/aie2_pci.h | 1 + + drivers/accel/amdxdna/aie2_pm.c | 17 +++++++++++++++- + drivers/accel/amdxdna/aie2_smu.c | 27 ++++--------------------- + drivers/accel/amdxdna/amdxdna_pci_drv.h | 1 - + drivers/accel/amdxdna/amdxdna_pm.c | 22 ++------------------ + 7 files changed, 24 insertions(+), 47 deletions(-) + +diff --git a/drivers/accel/amdxdna/aie2_message.c b/drivers/accel/amdxdna/aie2_message.c +index d493bb1c33606..18cf8e49ea94d 100644 +--- a/drivers/accel/amdxdna/aie2_message.c ++++ b/drivers/accel/amdxdna/aie2_message.c +@@ -39,7 +39,6 @@ static int aie2_send_mgmt_msg_wait(struct amdxdna_dev_hdl *ndev, + if (!ndev->mgmt_chann) + return -ENODEV; + +- drm_WARN_ON(&xdna->ddev, xdna->rpm_on && !mutex_is_locked(&xdna->dev_lock)); + ret = xdna_send_msg_wait(xdna, ndev->mgmt_chann, msg); + if (ret == -ETIME) { + xdna_mailbox_stop_channel(ndev->mgmt_chann); +diff --git a/drivers/accel/amdxdna/aie2_pci.c b/drivers/accel/amdxdna/aie2_pci.c +index 8141d8e516360..ec1c3ad57d490 100644 +--- a/drivers/accel/amdxdna/aie2_pci.c ++++ b/drivers/accel/amdxdna/aie2_pci.c +@@ -322,7 +322,7 @@ static int aie2_xrs_set_dft_dpm_level(struct drm_device *ddev, u32 dpm_level) + if (ndev->pw_mode != POWER_MODE_DEFAULT || ndev->dpm_level == dpm_level) + return 0; + +- return ndev->priv->hw_ops.set_dpm(ndev, dpm_level); ++ return aie2_pm_set_dpm(ndev, dpm_level); + } + + static struct xrs_action_ops aie2_xrs_actions = { +diff --git a/drivers/accel/amdxdna/aie2_pci.h b/drivers/accel/amdxdna/aie2_pci.h +index a5f9c42155d17..e08ec2fd44daa 100644 +--- a/drivers/accel/amdxdna/aie2_pci.h ++++ b/drivers/accel/amdxdna/aie2_pci.h +@@ -285,6 +285,7 @@ int npu4_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level); + /* aie2_pm.c */ + int aie2_pm_init(struct amdxdna_dev_hdl *ndev); + int aie2_pm_set_mode(struct amdxdna_dev_hdl *ndev, enum amdxdna_power_mode_type target); ++int aie2_pm_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level); + + /* aie2_psp.c */ + struct psp_device *aie2m_psp_create(struct drm_device *ddev, struct psp_config *conf); +diff --git a/drivers/accel/amdxdna/aie2_pm.c b/drivers/accel/amdxdna/aie2_pm.c +index 426c38fce8482..afcd6d4683e56 100644 +--- a/drivers/accel/amdxdna/aie2_pm.c ++++ b/drivers/accel/amdxdna/aie2_pm.c +@@ -10,6 +10,7 @@ + + #include "aie2_pci.h" + #include "amdxdna_pci_drv.h" ++#include "amdxdna_pm.h" + + #define AIE2_CLK_GATING_ENABLE 1 + #define AIE2_CLK_GATING_DISABLE 0 +@@ -26,6 +27,20 @@ static int aie2_pm_set_clk_gating(struct amdxdna_dev_hdl *ndev, u32 val) + return 0; + } + ++int aie2_pm_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level) ++{ ++ int ret; ++ ++ ret = amdxdna_pm_resume_get(ndev->xdna); ++ if (ret) ++ return ret; ++ ++ ret = ndev->priv->hw_ops.set_dpm(ndev, dpm_level); ++ amdxdna_pm_suspend_put(ndev->xdna); ++ ++ return ret; ++} ++ + int aie2_pm_init(struct amdxdna_dev_hdl *ndev) + { + int ret; +@@ -94,7 +109,7 @@ int aie2_pm_set_mode(struct amdxdna_dev_hdl *ndev, enum amdxdna_power_mode_type + return -EOPNOTSUPP; + } + +- ret = ndev->priv->hw_ops.set_dpm(ndev, dpm_level); ++ ret = aie2_pm_set_dpm(ndev, dpm_level); + if (ret) + return ret; + +diff --git a/drivers/accel/amdxdna/aie2_smu.c b/drivers/accel/amdxdna/aie2_smu.c +index bd94ee96c2bc0..2d195e41f83dd 100644 +--- a/drivers/accel/amdxdna/aie2_smu.c ++++ b/drivers/accel/amdxdna/aie2_smu.c +@@ -11,7 +11,6 @@ + + #include "aie2_pci.h" + #include "amdxdna_pci_drv.h" +-#include "amdxdna_pm.h" + + #define SMU_RESULT_OK 1 + +@@ -67,16 +66,12 @@ int npu1_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level) + u32 freq; + int ret; + +- ret = amdxdna_pm_resume_get(ndev->xdna); +- if (ret) +- return ret; +- + ret = aie2_smu_exec(ndev, AIE2_SMU_SET_MPNPUCLK_FREQ, + ndev->priv->dpm_clk_tbl[dpm_level].npuclk, &freq); + if (ret) { + XDNA_ERR(ndev->xdna, "Set npu clock to %d failed, ret %d\n", + ndev->priv->dpm_clk_tbl[dpm_level].npuclk, ret); +- goto suspend_put; ++ return ret; + } + ndev->npuclk_freq = freq; + +@@ -85,10 +80,9 @@ int npu1_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level) + if (ret) { + XDNA_ERR(ndev->xdna, "Set h clock to %d failed, ret %d\n", + ndev->priv->dpm_clk_tbl[dpm_level].hclk, ret); +- goto suspend_put; ++ return ret; + } + +- amdxdna_pm_suspend_put(ndev->xdna); + ndev->hclk_freq = freq; + ndev->dpm_level = dpm_level; + ndev->max_tops = 2 * ndev->total_col; +@@ -98,35 +92,26 @@ int npu1_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level) + ndev->npuclk_freq, ndev->hclk_freq); + + return 0; +- +-suspend_put: +- amdxdna_pm_suspend_put(ndev->xdna); +- return ret; + } + + int npu4_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level) + { + int ret; + +- ret = amdxdna_pm_resume_get(ndev->xdna); +- if (ret) +- return ret; +- + ret = aie2_smu_exec(ndev, AIE2_SMU_SET_HARD_DPMLEVEL, dpm_level, NULL); + if (ret) { + XDNA_ERR(ndev->xdna, "Set hard dpm level %d failed, ret %d ", + dpm_level, ret); +- goto suspend_put; ++ return ret; + } + + ret = aie2_smu_exec(ndev, AIE2_SMU_SET_SOFT_DPMLEVEL, dpm_level, NULL); + if (ret) { + XDNA_ERR(ndev->xdna, "Set soft dpm level %d failed, ret %d", + dpm_level, ret); +- goto suspend_put; ++ return ret; + } + +- amdxdna_pm_suspend_put(ndev->xdna); + ndev->npuclk_freq = ndev->priv->dpm_clk_tbl[dpm_level].npuclk; + ndev->hclk_freq = ndev->priv->dpm_clk_tbl[dpm_level].hclk; + ndev->dpm_level = dpm_level; +@@ -137,10 +122,6 @@ int npu4_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level) + ndev->npuclk_freq, ndev->hclk_freq); + + return 0; +- +-suspend_put: +- amdxdna_pm_suspend_put(ndev->xdna); +- return ret; + } + + int aie2_smu_init(struct amdxdna_dev_hdl *ndev) +diff --git a/drivers/accel/amdxdna/amdxdna_pci_drv.h b/drivers/accel/amdxdna/amdxdna_pci_drv.h +index c99477f5e454f..0d50c4c8b3533 100644 +--- a/drivers/accel/amdxdna/amdxdna_pci_drv.h ++++ b/drivers/accel/amdxdna/amdxdna_pci_drv.h +@@ -101,7 +101,6 @@ struct amdxdna_dev { + struct amdxdna_fw_ver fw_ver; + struct rw_semaphore notifier_lock; /* for mmu notifier*/ + struct workqueue_struct *notifier_wq; +- bool rpm_on; + }; + + /* +diff --git a/drivers/accel/amdxdna/amdxdna_pm.c b/drivers/accel/amdxdna/amdxdna_pm.c +index fa38e65d617c4..d024d480521c4 100644 +--- a/drivers/accel/amdxdna/amdxdna_pm.c ++++ b/drivers/accel/amdxdna/amdxdna_pm.c +@@ -15,14 +15,9 @@ int amdxdna_pm_suspend(struct device *dev) + { + struct amdxdna_dev *xdna = to_xdna_dev(dev_get_drvdata(dev)); + int ret = -EOPNOTSUPP; +- bool rpm; + +- if (xdna->dev_info->ops->suspend) { +- rpm = xdna->rpm_on; +- xdna->rpm_on = false; ++ if (xdna->dev_info->ops->suspend) + ret = xdna->dev_info->ops->suspend(xdna); +- xdna->rpm_on = rpm; +- } + + XDNA_DBG(xdna, "Suspend done ret %d", ret); + return ret; +@@ -32,14 +27,9 @@ int amdxdna_pm_resume(struct device *dev) + { + struct amdxdna_dev *xdna = to_xdna_dev(dev_get_drvdata(dev)); + int ret = -EOPNOTSUPP; +- bool rpm; + +- if (xdna->dev_info->ops->resume) { +- rpm = xdna->rpm_on; +- xdna->rpm_on = false; ++ if (xdna->dev_info->ops->resume) + ret = xdna->dev_info->ops->resume(xdna); +- xdna->rpm_on = rpm; +- } + + XDNA_DBG(xdna, "Resume done ret %d", ret); + return ret; +@@ -50,9 +40,6 @@ int amdxdna_pm_resume_get(struct amdxdna_dev *xdna) + struct device *dev = xdna->ddev.dev; + int ret; + +- if (!xdna->rpm_on) +- return 0; +- + ret = pm_runtime_resume_and_get(dev); + if (ret) { + XDNA_ERR(xdna, "Resume failed: %d", ret); +@@ -66,9 +53,6 @@ void amdxdna_pm_suspend_put(struct amdxdna_dev *xdna) + { + struct device *dev = xdna->ddev.dev; + +- if (!xdna->rpm_on) +- return; +- + pm_runtime_put_autosuspend(dev); + } + +@@ -81,14 +65,12 @@ void amdxdna_pm_init(struct amdxdna_dev *xdna) + pm_runtime_use_autosuspend(dev); + pm_runtime_allow(dev); + pm_runtime_put_autosuspend(dev); +- xdna->rpm_on = true; + } + + void amdxdna_pm_fini(struct amdxdna_dev *xdna) + { + struct device *dev = xdna->ddev.dev; + +- xdna->rpm_on = false; + pm_runtime_get_noresume(dev); + pm_runtime_forbid(dev); + } +-- +2.51.0 + diff --git a/queue-6.19/accel-amdxdna-fix-race-where-send-ring-appears-full-.patch b/queue-6.19/accel-amdxdna-fix-race-where-send-ring-appears-full-.patch new file mode 100644 index 0000000000..13d9b51fa6 --- /dev/null +++ b/queue-6.19/accel-amdxdna-fix-race-where-send-ring-appears-full-.patch @@ -0,0 +1,92 @@ +From ec9ce1be34c248da12b08168100d1c2d4b6df6f1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 10 Dec 2025 20:51:25 -0800 +Subject: accel/amdxdna: Fix race where send ring appears full due to delayed + head update + +From: Lizhi Hou + +[ Upstream commit 343f5683cfa443000904c88ce2e23656375fc51c ] + +The firmware sends a response and interrupts the driver before advancing +the mailbox send ring head pointer. As a result, the driver may observe +the response and attempt to send a new request before the firmware has +updated the head pointer. In this window, the send ring still appears +full, causing the driver to incorrectly fail the send operation. + +This race can be triggered more easily in a multithreaded environment, +leading to unexpected and spurious "send ring full" failures. + +To address this, poll the send ring head pointer for up to 100us before +returning a full-ring condition. This allows the firmware time to update +the head pointer. + +Fixes: b87f920b9344 ("accel/amdxdna: Support hardware mailbox") +Reviewed-by: Mario Limonciello (AMD) +Signed-off-by: Lizhi Hou +Link: https://patch.msgid.link/20251211045125.1724604-1-lizhi.hou@amd.com +Signed-off-by: Sasha Levin +--- + drivers/accel/amdxdna/amdxdna_mailbox.c | 27 +++++++++++++++---------- + 1 file changed, 16 insertions(+), 11 deletions(-) + +diff --git a/drivers/accel/amdxdna/amdxdna_mailbox.c b/drivers/accel/amdxdna/amdxdna_mailbox.c +index 858df97cd3fbd..8b72cf6bd6e4d 100644 +--- a/drivers/accel/amdxdna/amdxdna_mailbox.c ++++ b/drivers/accel/amdxdna/amdxdna_mailbox.c +@@ -207,26 +207,34 @@ mailbox_send_msg(struct mailbox_channel *mb_chann, struct mailbox_msg *mb_msg) + u32 head, tail; + u32 start_addr; + u32 tmp_tail; ++ int ret; + + head = mailbox_get_headptr(mb_chann, CHAN_RES_X2I); + tail = mb_chann->x2i_tail; +- ringbuf_size = mailbox_get_ringbuf_size(mb_chann, CHAN_RES_X2I); ++ ringbuf_size = mailbox_get_ringbuf_size(mb_chann, CHAN_RES_X2I) - sizeof(u32); + start_addr = mb_chann->res[CHAN_RES_X2I].rb_start_addr; + tmp_tail = tail + mb_msg->pkg_size; + +- if (tail < head && tmp_tail >= head) +- goto no_space; +- +- if (tail >= head && (tmp_tail > ringbuf_size - sizeof(u32) && +- mb_msg->pkg_size >= head)) +- goto no_space; + +- if (tail >= head && tmp_tail > ringbuf_size - sizeof(u32)) { ++check_again: ++ if (tail >= head && tmp_tail > ringbuf_size) { + write_addr = mb_chann->mb->res.ringbuf_base + start_addr + tail; + writel(TOMBSTONE, write_addr); + + /* tombstone is set. Write from the start of the ringbuf */ + tail = 0; ++ tmp_tail = tail + mb_msg->pkg_size; ++ } ++ ++ if (tail < head && tmp_tail >= head) { ++ ret = read_poll_timeout(mailbox_get_headptr, head, ++ tmp_tail < head || tail >= head, ++ 1, 100, false, mb_chann, CHAN_RES_X2I); ++ if (ret) ++ return ret; ++ ++ if (tail >= head) ++ goto check_again; + } + + write_addr = mb_chann->mb->res.ringbuf_base + start_addr + tail; +@@ -238,9 +246,6 @@ mailbox_send_msg(struct mailbox_channel *mb_chann, struct mailbox_msg *mb_msg) + mb_msg->pkg.header.id); + + return 0; +- +-no_space: +- return -ENOSPC; + } + + static int +-- +2.51.0 + diff --git a/queue-6.19/accel-amdxdna-hold-mm-structure-across-iommu_sva_unb.patch b/queue-6.19/accel-amdxdna-hold-mm-structure-across-iommu_sva_unb.patch new file mode 100644 index 0000000000..3d41e1ed3e --- /dev/null +++ b/queue-6.19/accel-amdxdna-hold-mm-structure-across-iommu_sva_unb.patch @@ -0,0 +1,64 @@ +From d8e07f61987e1b880268f9326b98236a1bffd102 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 16:23:56 -0800 +Subject: accel/amdxdna: Hold mm structure across iommu_sva_unbind_device() + +From: Lizhi Hou + +[ Upstream commit a9162439ad792afcddc04718408ec1380b7a5f63 ] + +Some tests trigger a crash in iommu_sva_unbind_device() due to +accessing iommu_mm after the associated mm structure has been +freed. + +Fix this by taking an explicit reference to the mm structure +after successfully binding the device, and releasing it only +after the device is unbound. This ensures the mm remains valid +for the entire SVA bind/unbind lifetime. + +Fixes: be462c97b7df ("accel/amdxdna: Add hardware context") +Reviewed-by: Mario Limonciello (AMD) +Signed-off-by: Lizhi Hou +Link: https://patch.msgid.link/20260128002356.1858122-1-lizhi.hou@amd.com +Signed-off-by: Sasha Levin +--- + drivers/accel/amdxdna/amdxdna_pci_drv.c | 3 +++ + drivers/accel/amdxdna/amdxdna_pci_drv.h | 1 + + 2 files changed, 4 insertions(+) + +diff --git a/drivers/accel/amdxdna/amdxdna_pci_drv.c b/drivers/accel/amdxdna/amdxdna_pci_drv.c +index fcc9be23b3de5..bcb0d77b63cbb 100644 +--- a/drivers/accel/amdxdna/amdxdna_pci_drv.c ++++ b/drivers/accel/amdxdna/amdxdna_pci_drv.c +@@ -83,6 +83,8 @@ static int amdxdna_drm_open(struct drm_device *ddev, struct drm_file *filp) + ret = -ENODEV; + goto unbind_sva; + } ++ client->mm = current->mm; ++ mmgrab(client->mm); + init_srcu_struct(&client->hwctx_srcu); + xa_init_flags(&client->hwctx_xa, XA_FLAGS_ALLOC); + mutex_init(&client->mm_lock); +@@ -119,6 +121,7 @@ static void amdxdna_drm_close(struct drm_device *ddev, struct drm_file *filp) + drm_gem_object_put(to_gobj(client->dev_heap)); + + iommu_sva_unbind_device(client->sva); ++ mmdrop(client->mm); + + XDNA_DBG(xdna, "pid %d closed", client->pid); + kfree(client); +diff --git a/drivers/accel/amdxdna/amdxdna_pci_drv.h b/drivers/accel/amdxdna/amdxdna_pci_drv.h +index 0d50c4c8b3533..ec21cb378a472 100644 +--- a/drivers/accel/amdxdna/amdxdna_pci_drv.h ++++ b/drivers/accel/amdxdna/amdxdna_pci_drv.h +@@ -130,6 +130,7 @@ struct amdxdna_client { + + struct iommu_sva *sva; + int pasid; ++ struct mm_struct *mm; + }; + + #define amdxdna_for_each_hwctx(client, hwctx_id, entry) \ +-- +2.51.0 + diff --git a/queue-6.19/accel-amdxdna-move-rpm-resume-into-job-run-function.patch b/queue-6.19/accel-amdxdna-move-rpm-resume-into-job-run-function.patch new file mode 100644 index 0000000000..5add26dbb8 --- /dev/null +++ b/queue-6.19/accel-amdxdna-move-rpm-resume-into-job-run-function.patch @@ -0,0 +1,103 @@ +From 780d5fb1fd6d1d0a7f901ae5c3448a1b02220753 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 09:11:17 -0800 +Subject: accel/amdxdna: Move RPM resume into job run function + +From: Lizhi Hou + +[ Upstream commit 69674c1c704c0199ca7a3947f3cdcd575973175d ] + +Currently, amdxdna_pm_resume_get() is called during job creation, and +amdxdna_pm_suspend_put() is called when the hardware notifies job +completion. If a job is canceled before it is run, no hardware +completion notification is generated, resulting in an unbalanced +runtime PM resume/suspend pair. + +Fix this by moving amdxdna_pm_resume_get() to the job run path, ensuring +runtime PM is only resumed for jobs that are actually executed. + +Fixes: 063db451832b ("accel/amdxdna: Enhance runtime power management") +Reviewed-by: Mario Limonciello (AMD) +Signed-off-by: Lizhi Hou +Link: https://patch.msgid.link/20260204171118.3165607-1-lizhi.hou@amd.com +Signed-off-by: Sasha Levin +--- + drivers/accel/amdxdna/aie2_ctx.c | 19 +++++++++---------- + 1 file changed, 9 insertions(+), 10 deletions(-) + +diff --git a/drivers/accel/amdxdna/aie2_ctx.c b/drivers/accel/amdxdna/aie2_ctx.c +index fe8f9783a73c7..37d05f2e986f9 100644 +--- a/drivers/accel/amdxdna/aie2_ctx.c ++++ b/drivers/accel/amdxdna/aie2_ctx.c +@@ -306,6 +306,10 @@ aie2_sched_job_run(struct drm_sched_job *sched_job) + kref_get(&job->refcnt); + fence = dma_fence_get(job->fence); + ++ ret = amdxdna_pm_resume_get(hwctx->client->xdna); ++ if (ret) ++ goto out; ++ + if (job->drv_cmd) { + switch (job->drv_cmd->opcode) { + case SYNC_DEBUG_BO: +@@ -332,6 +336,7 @@ aie2_sched_job_run(struct drm_sched_job *sched_job) + + out: + if (ret) { ++ amdxdna_pm_suspend_put(hwctx->client->xdna); + dma_fence_put(job->fence); + aie2_job_put(job); + mmput(job->mm); +@@ -988,15 +993,11 @@ int aie2_cmd_submit(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job, + goto free_chain; + } + +- ret = amdxdna_pm_resume_get(xdna); +- if (ret) +- goto cleanup_job; +- + retry: + ret = drm_gem_lock_reservations(job->bos, job->bo_cnt, &acquire_ctx); + if (ret) { + XDNA_WARN(xdna, "Failed to lock BOs, ret %d", ret); +- goto suspend_put; ++ goto cleanup_job; + } + + for (i = 0; i < job->bo_cnt; i++) { +@@ -1004,7 +1005,7 @@ int aie2_cmd_submit(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job, + if (ret) { + XDNA_WARN(xdna, "Failed to reserve fences %d", ret); + drm_gem_unlock_reservations(job->bos, job->bo_cnt, &acquire_ctx); +- goto suspend_put; ++ goto cleanup_job; + } + } + +@@ -1019,12 +1020,12 @@ int aie2_cmd_submit(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job, + msecs_to_jiffies(HMM_RANGE_DEFAULT_TIMEOUT); + } else if (time_after(jiffies, timeout)) { + ret = -ETIME; +- goto suspend_put; ++ goto cleanup_job; + } + + ret = aie2_populate_range(abo); + if (ret) +- goto suspend_put; ++ goto cleanup_job; + goto retry; + } + } +@@ -1050,8 +1051,6 @@ int aie2_cmd_submit(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job, + + return 0; + +-suspend_put: +- amdxdna_pm_suspend_put(xdna); + cleanup_job: + drm_sched_job_cleanup(&job->base); + free_chain: +-- +2.51.0 + diff --git a/queue-6.19/accel-amdxdna-remove-hardware-context-status.patch b/queue-6.19/accel-amdxdna-remove-hardware-context-status.patch new file mode 100644 index 0000000000..5241c5fdb8 --- /dev/null +++ b/queue-6.19/accel-amdxdna-remove-hardware-context-status.patch @@ -0,0 +1,153 @@ +From 4779de3a6e78729e0336d69027b12a17f8706586 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 13:24:50 -0800 +Subject: accel/amdxdna: Remove hardware context status + +From: Lizhi Hou + +[ Upstream commit b853007fdcdd64b49601a993c2b30c28279ae15d ] + +One newly supported command does not require hardware context configuration +to be performed upfront. As a result, checking hardware context status +causes this command to fail incorrectly. + +Remove hardware context status handling entirely. For other commands, +if userspace submits a request without configuring the hardware context +first, the firmware will report an error or time out as appropriate. + +Fixes: aac243092b70 ("accel/amdxdna: Add command execution") +Reviewed-by: Mario Limonciello (AMD) +Signed-off-by: Lizhi Hou +Link: https://patch.msgid.link/20260202212450.2681273-1-lizhi.hou@amd.com +Signed-off-by: Sasha Levin +--- + drivers/accel/amdxdna/aie2_ctx.c | 25 ++----------------------- + drivers/accel/amdxdna/aie2_message.c | 3 +++ + drivers/accel/amdxdna/amdxdna_ctx.h | 5 ----- + 3 files changed, 5 insertions(+), 28 deletions(-) + +diff --git a/drivers/accel/amdxdna/aie2_ctx.c b/drivers/accel/amdxdna/aie2_ctx.c +index c4a58c00e442a..ad5b5cd0bc81f 100644 +--- a/drivers/accel/amdxdna/aie2_ctx.c ++++ b/drivers/accel/amdxdna/aie2_ctx.c +@@ -47,17 +47,6 @@ static void aie2_job_put(struct amdxdna_sched_job *job) + kref_put(&job->refcnt, aie2_job_release); + } + +-static void aie2_hwctx_status_shift_stop(struct amdxdna_hwctx *hwctx) +-{ +- hwctx->old_status = hwctx->status; +- hwctx->status = HWCTX_STAT_STOP; +-} +- +-static void aie2_hwctx_status_restore(struct amdxdna_hwctx *hwctx) +-{ +- hwctx->status = hwctx->old_status; +-} +- + /* The bad_job is used in aie2_sched_job_timedout, otherwise, set it to NULL */ + static void aie2_hwctx_stop(struct amdxdna_dev *xdna, struct amdxdna_hwctx *hwctx, + struct drm_sched_job *bad_job) +@@ -84,11 +73,6 @@ static int aie2_hwctx_restart(struct amdxdna_dev *xdna, struct amdxdna_hwctx *hw + goto out; + } + +- if (hwctx->status != HWCTX_STAT_READY) { +- XDNA_DBG(xdna, "hwctx is not ready, status %d", hwctx->status); +- goto out; +- } +- + ret = aie2_config_cu(hwctx, NULL); + if (ret) { + XDNA_ERR(xdna, "Config cu failed, ret %d", ret); +@@ -140,7 +124,6 @@ static int aie2_hwctx_suspend_cb(struct amdxdna_hwctx *hwctx, void *arg) + + aie2_hwctx_wait_for_idle(hwctx); + aie2_hwctx_stop(xdna, hwctx, NULL); +- aie2_hwctx_status_shift_stop(hwctx); + + return 0; + } +@@ -162,7 +145,6 @@ static int aie2_hwctx_resume_cb(struct amdxdna_hwctx *hwctx, void *arg) + { + struct amdxdna_dev *xdna = hwctx->client->xdna; + +- aie2_hwctx_status_restore(hwctx); + return aie2_hwctx_restart(xdna, hwctx); + } + +@@ -315,7 +297,7 @@ aie2_sched_job_run(struct drm_sched_job *sched_job) + struct dma_fence *fence; + int ret; + +- if (hwctx->status != HWCTX_STAT_READY) ++ if (!hwctx->priv->mbox_chann) + return NULL; + + if (!mmget_not_zero(job->mm)) +@@ -666,7 +648,6 @@ int aie2_hwctx_init(struct amdxdna_hwctx *hwctx) + } + amdxdna_pm_suspend_put(xdna); + +- hwctx->status = HWCTX_STAT_INIT; + init_waitqueue_head(&priv->job_free_wq); + + XDNA_DBG(xdna, "hwctx %s init completed", hwctx->name); +@@ -710,7 +691,6 @@ void aie2_hwctx_fini(struct amdxdna_hwctx *hwctx) + /* Request fw to destroy hwctx and cancel the rest pending requests */ + drm_sched_stop(&hwctx->priv->sched, NULL); + aie2_release_resource(hwctx); +- hwctx->status = HWCTX_STAT_STOP; + drm_sched_start(&hwctx->priv->sched, 0); + + mutex_unlock(&xdna->dev_lock); +@@ -755,7 +735,7 @@ static int aie2_hwctx_cu_config(struct amdxdna_hwctx *hwctx, void *buf, u32 size + if (XDNA_MBZ_DBG(xdna, config->pad, sizeof(config->pad))) + return -EINVAL; + +- if (hwctx->status != HWCTX_STAT_INIT) { ++ if (hwctx->cus) { + XDNA_ERR(xdna, "Not support re-config CU"); + return -EINVAL; + } +@@ -786,7 +766,6 @@ static int aie2_hwctx_cu_config(struct amdxdna_hwctx *hwctx, void *buf, u32 size + } + + wmb(); /* To avoid locking in command submit when check status */ +- hwctx->status = HWCTX_STAT_READY; + + return 0; + +diff --git a/drivers/accel/amdxdna/aie2_message.c b/drivers/accel/amdxdna/aie2_message.c +index 273d6af9f6f52..2c5b27d90563e 100644 +--- a/drivers/accel/amdxdna/aie2_message.c ++++ b/drivers/accel/amdxdna/aie2_message.c +@@ -450,6 +450,9 @@ int aie2_config_cu(struct amdxdna_hwctx *hwctx, + if (!chann) + return -ENODEV; + ++ if (!hwctx->cus) ++ return 0; ++ + if (hwctx->cus->num_cus > MAX_NUM_CUS) { + XDNA_DBG(xdna, "Exceed maximum CU %d", MAX_NUM_CUS); + return -EINVAL; +diff --git a/drivers/accel/amdxdna/amdxdna_ctx.h b/drivers/accel/amdxdna/amdxdna_ctx.h +index b29449a92f607..16c85f08f03c6 100644 +--- a/drivers/accel/amdxdna/amdxdna_ctx.h ++++ b/drivers/accel/amdxdna/amdxdna_ctx.h +@@ -99,11 +99,6 @@ struct amdxdna_hwctx { + u32 start_col; + u32 num_col; + u32 num_unused_col; +-#define HWCTX_STAT_INIT 0 +-#define HWCTX_STAT_READY 1 +-#define HWCTX_STAT_STOP 2 +- u32 status; +- u32 old_status; + + struct amdxdna_qos_info qos; + struct amdxdna_hwctx_param_config_cu *cus; +-- +2.51.0 + diff --git a/queue-6.19/accel-amdxdna-stop-job-scheduling-across-aie2_releas.patch b/queue-6.19/accel-amdxdna-stop-job-scheduling-across-aie2_releas.patch new file mode 100644 index 0000000000..ee198ba0f0 --- /dev/null +++ b/queue-6.19/accel-amdxdna-stop-job-scheduling-across-aie2_releas.patch @@ -0,0 +1,54 @@ +From 13824331d7077ecbf29e1e546d5f1a3e341bed54 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 16:32:55 -0800 +Subject: accel/amdxdna: Stop job scheduling across aie2_release_resource() + +From: Lizhi Hou + +[ Upstream commit f1370241fe8045702bc9d0812b996791f0500f1b ] + +Running jobs on a hardware context while it is in the process of +releasing resources can lead to use-after-free and crashes. + +Fix this by stopping job scheduling before calling +aie2_release_resource() and restarting it after the release completes. +Additionally, aie2_sched_job_run() now checks whether the hardware +context is still active. + +Fixes: 4fd6ca90fc7f ("accel/amdxdna: Refactor hardware context destroy routine") +Reviewed-by: Mario Limonciello (AMD) +Signed-off-by: Lizhi Hou +Link: https://patch.msgid.link/20260130003255.2083255-1-lizhi.hou@amd.com +Signed-off-by: Sasha Levin +--- + drivers/accel/amdxdna/aie2_ctx.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/accel/amdxdna/aie2_ctx.c b/drivers/accel/amdxdna/aie2_ctx.c +index 42d876a427c59..2c36ed7e9639c 100644 +--- a/drivers/accel/amdxdna/aie2_ctx.c ++++ b/drivers/accel/amdxdna/aie2_ctx.c +@@ -315,6 +315,9 @@ aie2_sched_job_run(struct drm_sched_job *sched_job) + struct dma_fence *fence; + int ret; + ++ if (hwctx->status != HWCTX_STAT_READY) ++ return NULL; ++ + if (!mmget_not_zero(job->mm)) + return ERR_PTR(-ESRCH); + +@@ -693,7 +696,10 @@ void aie2_hwctx_fini(struct amdxdna_hwctx *hwctx) + aie2_hwctx_wait_for_idle(hwctx); + + /* Request fw to destroy hwctx and cancel the rest pending requests */ ++ drm_sched_stop(&hwctx->priv->sched, NULL); + aie2_release_resource(hwctx); ++ hwctx->status = HWCTX_STAT_STOP; ++ drm_sched_start(&hwctx->priv->sched, 0); + + mutex_unlock(&xdna->dev_lock); + drm_sched_entity_destroy(&hwctx->priv->entity); +-- +2.51.0 + diff --git a/queue-6.19/acpi-processor-update-cpuidle-driver-check-in-__acpi.patch b/queue-6.19/acpi-processor-update-cpuidle-driver-check-in-__acpi.patch new file mode 100644 index 0000000000..39612cc0c8 --- /dev/null +++ b/queue-6.19/acpi-processor-update-cpuidle-driver-check-in-__acpi.patch @@ -0,0 +1,48 @@ +From b71bafe3c1f2d97b5e10373e8e9c4da721b77059 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 23 Dec 2025 18:09:11 +0800 +Subject: ACPI: processor: Update cpuidle driver check in + __acpi_processor_start() + +From: Rafael J. Wysocki + +[ Upstream commit 0089ce1c056aee547115bdc25c223f8f88c08498 ] + +Commit 7a8c994cbb2d ("ACPI: processor: idle: Optimize ACPI idle +driver registration") moved the ACPI idle driver registration to +acpi_processor_driver_init() and acpi_processor_power_init() does +not register an idle driver any more. + +Accordingly, the cpuidle driver check in __acpi_processor_start() needs +to be updated to avoid calling acpi_processor_power_init() without a +cpuidle driver, in which case the registration of the cpuidle device +in that function would lead to a NULL pointer dereference in +__cpuidle_register_device(). + +Fixes: 7a8c994cbb2d ("ACPI: processor: idle: Optimize ACPI idle driver registration") +Signed-off-by: Rafael J. Wysocki +Reviewed-by: Mario Limonciello (AMD) +Tested-by: Borislav Petkov (AMD) +Link: https://patch.msgid.link/20251223100914.2407069-4-lihuisong@huawei.com +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/processor_driver.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c +index 65e779be64ffc..7644de24d2faa 100644 +--- a/drivers/acpi/processor_driver.c ++++ b/drivers/acpi/processor_driver.c +@@ -166,7 +166,7 @@ static int __acpi_processor_start(struct acpi_device *device) + if (result && !IS_ENABLED(CONFIG_ACPI_CPU_FREQ_PSS)) + dev_dbg(&device->dev, "CPPC data invalid or not present\n"); + +- if (!cpuidle_get_driver() || cpuidle_get_driver() == &acpi_idle_driver) ++ if (cpuidle_get_driver() == &acpi_idle_driver) + acpi_processor_power_init(pr); + + acpi_pss_perf_init(pr); +-- +2.51.0 + diff --git a/queue-6.19/acpica-fix-null-pointer-dereference-in-acpi_ev_addre.patch b/queue-6.19/acpica-fix-null-pointer-dereference-in-acpi_ev_addre.patch new file mode 100644 index 0000000000..af4d659867 --- /dev/null +++ b/queue-6.19/acpica-fix-null-pointer-dereference-in-acpi_ev_addre.patch @@ -0,0 +1,40 @@ +From b36195a34a3ada306997d9817df14c535ad3a44f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 13:20:17 +0100 +Subject: ACPICA: Fix NULL pointer dereference in + acpi_ev_address_space_dispatch() + +From: Alexey Simakov + +[ Upstream commit f851e03bce968ff9b3faad1b616062e1244fd38d ] + +Cover a missed execution path with a new check. + +Fixes: 0acf24ad7e10 ("ACPICA: Add support for PCC Opregion special context data") +Link: https://github.com/acpica/acpica/commit/f421dd9dd897 +Signed-off-by: Alexey Simakov +Signed-off-by: Rafael J. Wysocki +Link: https://patch.msgid.link/3030574.e9J7NaK4W3@rafael.j.wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/acpica/evregion.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c +index fa3475da7ea9b..b6198f73c81df 100644 +--- a/drivers/acpi/acpica/evregion.c ++++ b/drivers/acpi/acpica/evregion.c +@@ -163,7 +163,9 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, + return_ACPI_STATUS(AE_NOT_EXIST); + } + +- if (region_obj->region.space_id == ACPI_ADR_SPACE_PLATFORM_COMM) { ++ if (field_obj ++ && region_obj->region.space_id == ++ ACPI_ADR_SPACE_PLATFORM_COMM) { + struct acpi_pcc_info *ctx = + handler_desc->address_space.context; + +-- +2.51.0 + diff --git a/queue-6.19/af_unix-fix-memleak-of-newsk-in-unix_stream_connect.patch b/queue-6.19/af_unix-fix-memleak-of-newsk-in-unix_stream_connect.patch new file mode 100644 index 0000000000..876157303c --- /dev/null +++ b/queue-6.19/af_unix-fix-memleak-of-newsk-in-unix_stream_connect.patch @@ -0,0 +1,56 @@ +From 8dd982d29b06cbf9b6dcf9b855642e1b24875ade Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Feb 2026 23:22:34 +0000 +Subject: af_unix: Fix memleak of newsk in unix_stream_connect(). + +From: Kuniyuki Iwashima + +[ Upstream commit 6884028cd7f275f8bcb854a347265cb1fb0e4bea ] + +When prepare_peercred() fails in unix_stream_connect(), +unix_release_sock() is not called for newsk, and the memory +is leaked. + +Let's move prepare_peercred() before unix_create1(). + +Fixes: fd0a109a0f6b ("net, pidfs: prepare for handing out pidfds for reaped sk->sk_peer_pid") +Signed-off-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260207232236.2557549-1-kuniyu@google.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/unix/af_unix.c | 11 +++-------- + 1 file changed, 3 insertions(+), 8 deletions(-) + +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index d0511225799ba..f6d56e70c7a2c 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -1650,10 +1650,9 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr_unsized *uad + + timeo = sock_sndtimeo(sk, flags & O_NONBLOCK); + +- /* First of all allocate resources. +- * If we will make it after state is locked, +- * we will have to recheck all again in any case. +- */ ++ err = prepare_peercred(&peercred); ++ if (err) ++ goto out; + + /* create new sock for complete connection */ + newsk = unix_create1(net, NULL, 0, sock->type); +@@ -1662,10 +1661,6 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr_unsized *uad + goto out; + } + +- err = prepare_peercred(&peercred); +- if (err) +- goto out; +- + /* Allocate skb for sending to listening sock */ + skb = sock_wmalloc(newsk, 1, 0, GFP_KERNEL); + if (!skb) { +-- +2.51.0 + diff --git a/queue-6.19/alsa-compress_offload-relax-__free-variable-declarat.patch b/queue-6.19/alsa-compress_offload-relax-__free-variable-declarat.patch new file mode 100644 index 0000000000..f0b18200e6 --- /dev/null +++ b/queue-6.19/alsa-compress_offload-relax-__free-variable-declarat.patch @@ -0,0 +1,132 @@ +From a7f0452a6527761e148e492643c8e6d0ac59ef3e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Dec 2025 15:06:23 +0100 +Subject: ALSA: compress_offload: Relax __free() variable declarations + +From: Takashi Iwai + +[ Upstream commit 14324b8f0760ca6f56202bb4ad356ec459ce165b ] + +We used to have a variable declaration with __free() initialized with +NULL. This was to keep the old coding style rule, but recently it's +relaxed and rather recommends to follow the new rule to declare in +place of use for __free() -- which avoids potential deadlocks or UAFs +with nested cleanups. + +Although the current code has no bug, per se, let's follow the new +standard and move the declaration to the place of assignment. + +Fixes: 9b02221422a5 ("ALSA: compress_offload: Use automatic cleanup of kfree()") +Fixes: 04177158cf98 ("ALSA: compress_offload: introduce accel operation mode") +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20251216140634.171890-2-tiwai@suse.de +Signed-off-by: Sasha Levin +--- + sound/core/compress_offload.c | 28 ++++++++++++++++------------ + 1 file changed, 16 insertions(+), 12 deletions(-) + +diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c +index da514fef45bca..ed2eeb914c6db 100644 +--- a/sound/core/compress_offload.c ++++ b/sound/core/compress_offload.c +@@ -514,12 +514,12 @@ static int + snd_compr_get_codec_caps(struct snd_compr_stream *stream, unsigned long arg) + { + int retval; +- struct snd_compr_codec_caps *caps __free(kfree) = NULL; + + if (!stream->ops->get_codec_caps) + return -ENXIO; + +- caps = kzalloc(sizeof(*caps), GFP_KERNEL); ++ struct snd_compr_codec_caps *caps __free(kfree) = ++ kzalloc(sizeof(*caps), GFP_KERNEL); + if (!caps) + return -ENOMEM; + +@@ -647,7 +647,6 @@ snd_compress_check_input(struct snd_compr_stream *stream, struct snd_compr_param + static int + snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg) + { +- struct snd_compr_params *params __free(kfree) = NULL; + int retval; + + if (stream->runtime->state == SNDRV_PCM_STATE_OPEN || stream->next_track) { +@@ -655,7 +654,9 @@ snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg) + * we should allow parameter change only when stream has been + * opened not in other cases + */ +- params = memdup_user((void __user *)arg, sizeof(*params)); ++ struct snd_compr_params *params __free(kfree) = ++ memdup_user((void __user *)arg, sizeof(*params)); ++ + if (IS_ERR(params)) + return PTR_ERR(params); + +@@ -687,13 +688,13 @@ snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg) + static int + snd_compr_get_params(struct snd_compr_stream *stream, unsigned long arg) + { +- struct snd_codec *params __free(kfree) = NULL; + int retval; + + if (!stream->ops->get_params) + return -EBADFD; + +- params = kzalloc(sizeof(*params), GFP_KERNEL); ++ struct snd_codec *params __free(kfree) = ++ kzalloc(sizeof(*params), GFP_KERNEL); + if (!params) + return -ENOMEM; + retval = stream->ops->get_params(stream, params); +@@ -1104,12 +1105,13 @@ static int snd_compr_task_new(struct snd_compr_stream *stream, struct snd_compr_ + + static int snd_compr_task_create(struct snd_compr_stream *stream, unsigned long arg) + { +- struct snd_compr_task *task __free(kfree) = NULL; + int retval; + + if (stream->runtime->state != SNDRV_PCM_STATE_SETUP) + return -EPERM; +- task = memdup_user((void __user *)arg, sizeof(*task)); ++ ++ struct snd_compr_task *task __free(kfree) = ++ memdup_user((void __user *)arg, sizeof(*task)); + if (IS_ERR(task)) + return PTR_ERR(task); + retval = snd_compr_task_new(stream, task); +@@ -1165,12 +1167,13 @@ static int snd_compr_task_start(struct snd_compr_stream *stream, struct snd_comp + + static int snd_compr_task_start_ioctl(struct snd_compr_stream *stream, unsigned long arg) + { +- struct snd_compr_task *task __free(kfree) = NULL; + int retval; + + if (stream->runtime->state != SNDRV_PCM_STATE_SETUP) + return -EPERM; +- task = memdup_user((void __user *)arg, sizeof(*task)); ++ ++ struct snd_compr_task *task __free(kfree) = ++ memdup_user((void __user *)arg, sizeof(*task)); + if (IS_ERR(task)) + return PTR_ERR(task); + retval = snd_compr_task_start(stream, task); +@@ -1256,12 +1259,13 @@ static int snd_compr_task_status(struct snd_compr_stream *stream, + + static int snd_compr_task_status_ioctl(struct snd_compr_stream *stream, unsigned long arg) + { +- struct snd_compr_task_status *status __free(kfree) = NULL; + int retval; + + if (stream->runtime->state != SNDRV_PCM_STATE_SETUP) + return -EPERM; +- status = memdup_user((void __user *)arg, sizeof(*status)); ++ ++ struct snd_compr_task_status *status __free(kfree) = ++ memdup_user((void __user *)arg, sizeof(*status)); + if (IS_ERR(status)) + return PTR_ERR(status); + retval = snd_compr_task_status(stream, status); +-- +2.51.0 + diff --git a/queue-6.19/alsa-control-relax-__free-variable-declarations.patch b/queue-6.19/alsa-control-relax-__free-variable-declarations.patch new file mode 100644 index 0000000000..35eea26c9d --- /dev/null +++ b/queue-6.19/alsa-control-relax-__free-variable-declarations.patch @@ -0,0 +1,199 @@ +From fa63a268382db878f5701bd39451e0459fdff716 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Dec 2025 15:06:24 +0100 +Subject: ALSA: control: Relax __free() variable declarations + +From: Takashi Iwai + +[ Upstream commit 7b4721ca3159bce6338dbdf9188b785083571ed4 ] + +We used to have a variable declaration with __free() initialized with +NULL. This was to keep the old coding style rule, but recently it's +relaxed and rather recommends to follow the new rule to declare in +place of use for __free() -- which avoids potential deadlocks or UAFs +with nested cleanups. + +Although the current code has no bug, per se, let's follow the new +standard and move the declaration to the place of assignment (or +directly assign the allocated result) instead of NULL initializations. + +Fixes: 7dba48a474e6 ("ALSA: control_led: Use guard() for locking") +Fixes: 1052d9882269 ("ALSA: control: Use automatic cleanup of kfree()") +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20251216140634.171890-3-tiwai@suse.de +Signed-off-by: Sasha Levin +--- + sound/core/control.c | 12 ++++++------ + sound/core/control_compat.c | 21 +++++++++++---------- + sound/core/control_led.c | 12 ++++++------ + 3 files changed, 23 insertions(+), 22 deletions(-) + +diff --git a/sound/core/control.c b/sound/core/control.c +index 9c3fd5113a617..486d1bc4dac27 100644 +--- a/sound/core/control.c ++++ b/sound/core/control.c +@@ -867,9 +867,9 @@ EXPORT_SYMBOL(snd_ctl_find_id); + static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl, + unsigned int cmd, void __user *arg) + { +- struct snd_ctl_card_info *info __free(kfree) = NULL; ++ struct snd_ctl_card_info *info __free(kfree) = ++ kzalloc(sizeof(*info), GFP_KERNEL); + +- info = kzalloc(sizeof(*info), GFP_KERNEL); + if (! info) + return -ENOMEM; + scoped_guard(rwsem_read, &snd_ioctl_rwsem) { +@@ -1244,10 +1244,10 @@ static int snd_ctl_elem_read(struct snd_card *card, + static int snd_ctl_elem_read_user(struct snd_card *card, + struct snd_ctl_elem_value __user *_control) + { +- struct snd_ctl_elem_value *control __free(kfree) = NULL; + int result; ++ struct snd_ctl_elem_value *control __free(kfree) = ++ memdup_user(_control, sizeof(*control)); + +- control = memdup_user(_control, sizeof(*control)); + if (IS_ERR(control)) + return PTR_ERR(control); + +@@ -1320,11 +1320,11 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file, + static int snd_ctl_elem_write_user(struct snd_ctl_file *file, + struct snd_ctl_elem_value __user *_control) + { +- struct snd_ctl_elem_value *control __free(kfree) = NULL; + struct snd_card *card; + int result; ++ struct snd_ctl_elem_value *control __free(kfree) = ++ memdup_user(_control, sizeof(*control)); + +- control = memdup_user(_control, sizeof(*control)); + if (IS_ERR(control)) + return PTR_ERR(control); + +diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c +index 6459809ed3648..b8988a4bcd9b5 100644 +--- a/sound/core/control_compat.c ++++ b/sound/core/control_compat.c +@@ -80,10 +80,10 @@ static int snd_ctl_elem_info_compat(struct snd_ctl_file *ctl, + struct snd_ctl_elem_info32 __user *data32) + { + struct snd_card *card = ctl->card; +- struct snd_ctl_elem_info *data __free(kfree) = NULL; + int err; ++ struct snd_ctl_elem_info *data __free(kfree) = ++ kzalloc(sizeof(*data), GFP_KERNEL); + +- data = kzalloc(sizeof(*data), GFP_KERNEL); + if (! data) + return -ENOMEM; + +@@ -169,14 +169,15 @@ static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id, + int *countp) + { + struct snd_kcontrol *kctl; +- struct snd_ctl_elem_info *info __free(kfree) = NULL; + int err; + + guard(rwsem_read)(&card->controls_rwsem); + kctl = snd_ctl_find_id(card, id); + if (!kctl) + return -ENOENT; +- info = kzalloc(sizeof(*info), GFP_KERNEL); ++ ++ struct snd_ctl_elem_info *info __free(kfree) = ++ kzalloc(sizeof(*info), GFP_KERNEL); + if (info == NULL) + return -ENOMEM; + info->id = *id; +@@ -280,10 +281,10 @@ static int copy_ctl_value_to_user(void __user *userdata, + static int __ctl_elem_read_user(struct snd_card *card, + void __user *userdata, void __user *valuep) + { +- struct snd_ctl_elem_value *data __free(kfree) = NULL; + int err, type, count; ++ struct snd_ctl_elem_value *data __free(kfree) = ++ kzalloc(sizeof(*data), GFP_KERNEL); + +- data = kzalloc(sizeof(*data), GFP_KERNEL); + if (data == NULL) + return -ENOMEM; + +@@ -314,11 +315,11 @@ static int ctl_elem_read_user(struct snd_card *card, + static int __ctl_elem_write_user(struct snd_ctl_file *file, + void __user *userdata, void __user *valuep) + { +- struct snd_ctl_elem_value *data __free(kfree) = NULL; + struct snd_card *card = file->card; + int err, type, count; ++ struct snd_ctl_elem_value *data __free(kfree) = ++ kzalloc(sizeof(*data), GFP_KERNEL); + +- data = kzalloc(sizeof(*data), GFP_KERNEL); + if (data == NULL) + return -ENOMEM; + +@@ -378,9 +379,9 @@ static int snd_ctl_elem_add_compat(struct snd_ctl_file *file, + struct snd_ctl_elem_info32 __user *data32, + int replace) + { +- struct snd_ctl_elem_info *data __free(kfree) = NULL; ++ struct snd_ctl_elem_info *data __free(kfree) = ++ kzalloc(sizeof(*data), GFP_KERNEL); + +- data = kzalloc(sizeof(*data), GFP_KERNEL); + if (! data) + return -ENOMEM; + +diff --git a/sound/core/control_led.c b/sound/core/control_led.c +index e33dfcf863cf1..c7641d5084e7d 100644 +--- a/sound/core/control_led.c ++++ b/sound/core/control_led.c +@@ -245,12 +245,12 @@ DEFINE_FREE(snd_card_unref, struct snd_card *, if (_T) snd_card_unref(_T)) + static int snd_ctl_led_set_id(int card_number, struct snd_ctl_elem_id *id, + unsigned int group, bool set) + { +- struct snd_card *card __free(snd_card_unref) = NULL; + struct snd_kcontrol *kctl; + struct snd_kcontrol_volatile *vd; + unsigned int ioff, access, new_access; ++ struct snd_card *card __free(snd_card_unref) = ++ snd_card_ref(card_number); + +- card = snd_card_ref(card_number); + if (!card) + return -ENXIO; + guard(rwsem_write)(&card->controls_rwsem); +@@ -302,13 +302,13 @@ static void snd_ctl_led_clean(struct snd_card *card) + + static int snd_ctl_led_reset(int card_number, unsigned int group) + { +- struct snd_card *card __free(snd_card_unref) = NULL; + struct snd_ctl_led_ctl *lctl, *_lctl; + struct snd_ctl_led *led; + struct snd_kcontrol_volatile *vd; + bool change = false; ++ struct snd_card *card __free(snd_card_unref) = ++ snd_card_ref(card_number); + +- card = snd_card_ref(card_number); + if (!card) + return -ENXIO; + +@@ -598,11 +598,11 @@ static ssize_t list_show(struct device *dev, + struct device_attribute *attr, char *buf) + { + struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev); +- struct snd_card *card __free(snd_card_unref) = NULL; + struct snd_ctl_led_ctl *lctl; + size_t l = 0; ++ struct snd_card *card __free(snd_card_unref) = ++ snd_card_ref(led_card->number); + +- card = snd_card_ref(led_card->number); + if (!card) + return -ENXIO; + guard(rwsem_read)(&card->controls_rwsem); +-- +2.51.0 + diff --git a/queue-6.19/alsa-hda-fix-function-names-missing-function-paramet.patch b/queue-6.19/alsa-hda-fix-function-names-missing-function-paramet.patch new file mode 100644 index 0000000000..04a261eb41 --- /dev/null +++ b/queue-6.19/alsa-hda-fix-function-names-missing-function-paramet.patch @@ -0,0 +1,63 @@ +From cb2ed70129285ad3a10c51e634b60b558eaac824 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Jan 2026 10:59:51 -0800 +Subject: ALSA: hda - fix function names & missing function parameter + +From: Randy Dunlap + +[ Upstream commit b47ce586300b3c2b6650f4c7ac5c0f59c6bf6f4b ] + +Use the correct function names and add a function parameter description +to avoid kernel-doc warnings: + +hda_jack.h:97: warning: Function parameter or struct member 'cb' not + described in 'snd_hda_jack_detect_enable_callback' +hda_jack.h:97: warning: expecting prototype for snd_hda_jack_detect_enable(). + Prototype was for snd_hda_jack_detect_enable_callback() instead +hda_local.h:441: warning: expecting prototype for _snd_hda_set_pin_ctl(). + Prototype was for snd_hda_set_pin_ctl() instead + +Fixes: cdd03cedc5b5 ("ALSA: hda - Introduce snd_hda_set_pin_ctl*() helper functions") +Fixes: 5204a05d70d9 ("ALSA: hda - Add DP-MST jack support") +Signed-off-by: Randy Dunlap +Link: https://patch.msgid.link/20260106185951.2179242-1-rdunlap@infradead.org +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/hda/common/hda_jack.h | 4 ++-- + sound/hda/common/hda_local.h | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/sound/hda/common/hda_jack.h b/sound/hda/common/hda_jack.h +index ff7d289c034bf..e9b9970c59ed4 100644 +--- a/sound/hda/common/hda_jack.h ++++ b/sound/hda/common/hda_jack.h +@@ -82,10 +82,10 @@ snd_hda_jack_detect_enable_callback_mst(struct hda_codec *codec, hda_nid_t nid, + int dev_id, hda_jack_callback_fn func); + + /** +- * snd_hda_jack_detect_enable - enable the jack-detection ++ * snd_hda_jack_detect_enable_callback - enable the jack-detection + * @codec: the HDA codec + * @nid: pin NID to enable +- * @func: callback function to register ++ * @cb: callback function to register + * + * In the case of error, the return value will be a pointer embedded with + * errno. Check and handle the return value appropriately with standard +diff --git a/sound/hda/common/hda_local.h b/sound/hda/common/hda_local.h +index a7e53277a0fea..ab423f1cef549 100644 +--- a/sound/hda/common/hda_local.h ++++ b/sound/hda/common/hda_local.h +@@ -424,7 +424,7 @@ int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin, + unsigned int val, bool cached); + + /** +- * _snd_hda_set_pin_ctl - Set a pin-control value safely ++ * snd_hda_set_pin_ctl - Set a pin-control value safely + * @codec: the codec instance + * @pin: the pin NID to set the control + * @val: the pin-control value (AC_PINCTL_* bits) +-- +2.51.0 + diff --git a/queue-6.19/alsa-hda-relax-__free-variable-declarations.patch b/queue-6.19/alsa-hda-relax-__free-variable-declarations.patch new file mode 100644 index 0000000000..fa72317509 --- /dev/null +++ b/queue-6.19/alsa-hda-relax-__free-variable-declarations.patch @@ -0,0 +1,139 @@ +From 18360ffa98481e4c704b8f1281815b254dc30e36 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Dec 2025 15:06:31 +0100 +Subject: ALSA: hda: Relax __free() variable declarations + +From: Takashi Iwai + +[ Upstream commit 04c654624f41d3c3eee48e9837a52d8a2bbc7332 ] + +We used to have a variable declaration with __free() initialized with +NULL. This was to keep the old coding style rule, but recently it's +relaxed and rather recommends to follow the new rule to declare in +place of use for __free() -- which avoids potential deadlocks or UAFs +with nested cleanups. + +Although the current code has no bug, per se, let's follow the new +standard and move the declaration to the place of assignment (or +directly assign the allocated result) instead of NULL initializations. + +Fixes: ee0b0f5d32fe ("ALSA: hda/generic: Use auto cleanup for temporary buffers") +Fixes: 03c5c350e38d ("ALSA: hda/realtek: Add support for new HP G12 laptops") +Fixes: b0550d4c2dd8 ("ALSA: hda/common: Use auto cleanup for temporary buffers") +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20251216140634.171890-10-tiwai@suse.de +Signed-off-by: Sasha Levin +--- + sound/hda/codecs/generic.c | 4 ++-- + sound/hda/codecs/realtek/alc269.c | 4 ++-- + sound/hda/codecs/realtek/realtek.c | 5 +++-- + sound/hda/common/codec.c | 4 ++-- + sound/hda/common/sysfs.c | 5 +++-- + 5 files changed, 12 insertions(+), 10 deletions(-) + +diff --git a/sound/hda/codecs/generic.c b/sound/hda/codecs/generic.c +index 7bcf9aef8275f..443500a3518f4 100644 +--- a/sound/hda/codecs/generic.c ++++ b/sound/hda/codecs/generic.c +@@ -1984,15 +1984,15 @@ static int parse_output_paths(struct hda_codec *codec) + { + struct hda_gen_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; +- struct auto_pin_cfg *best_cfg __free(kfree) = NULL; + unsigned int val; + int best_badness = INT_MAX; + int badness; + bool fill_hardwired = true, fill_mio_first = true; + bool best_wired = true, best_mio = true; + bool hp_spk_swapped = false; ++ struct auto_pin_cfg *best_cfg __free(kfree) = ++ kmalloc(sizeof(*best_cfg), GFP_KERNEL); + +- best_cfg = kmalloc(sizeof(*best_cfg), GFP_KERNEL); + if (!best_cfg) + return -ENOMEM; + *best_cfg = *cfg; +diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c +index b66965a521076..0618a61413580 100644 +--- a/sound/hda/codecs/realtek/alc269.c ++++ b/sound/hda/codecs/realtek/alc269.c +@@ -2916,7 +2916,6 @@ static void find_cirrus_companion_amps(struct hda_codec *cdc) + { + struct device *dev = hda_codec_dev(cdc); + struct acpi_device *adev; +- struct fwnode_handle *fwnode __free(fwnode_handle) = NULL; + const char *bus = NULL; + static const struct { + const char *hid; +@@ -2946,7 +2945,8 @@ static void find_cirrus_companion_amps(struct hda_codec *cdc) + bus = "spi"; + } + +- fwnode = fwnode_handle_get(acpi_fwnode_handle(adev)); ++ struct fwnode_handle *fwnode __free(fwnode_handle) = ++ fwnode_handle_get(acpi_fwnode_handle(adev)); + acpi_dev_put(adev); + + if (!bus) { +diff --git a/sound/hda/codecs/realtek/realtek.c b/sound/hda/codecs/realtek/realtek.c +index ca377a5adadb5..efe20b4505290 100644 +--- a/sound/hda/codecs/realtek/realtek.c ++++ b/sound/hda/codecs/realtek/realtek.c +@@ -215,12 +215,13 @@ void alc_update_knob_master(struct hda_codec *codec, + { + unsigned int val; + struct snd_kcontrol *kctl; +- struct snd_ctl_elem_value *uctl __free(kfree) = NULL; + + kctl = snd_hda_find_mixer_ctl(codec, "Master Playback Volume"); + if (!kctl) + return; +- uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); ++ ++ struct snd_ctl_elem_value *uctl __free(kfree) = ++ kzalloc(sizeof(*uctl), GFP_KERNEL); + if (!uctl) + return; + val = snd_hda_codec_read(codec, jack->nid, 0, +diff --git a/sound/hda/common/codec.c b/sound/hda/common/codec.c +index c6d44168c7f9d..ffe7c69d5a32c 100644 +--- a/sound/hda/common/codec.c ++++ b/sound/hda/common/codec.c +@@ -1854,9 +1854,9 @@ static int check_follower_present(struct hda_codec *codec, + /* call kctl->put with the given value(s) */ + static int put_kctl_with_value(struct snd_kcontrol *kctl, int val) + { +- struct snd_ctl_elem_value *ucontrol __free(kfree) = NULL; ++ struct snd_ctl_elem_value *ucontrol __free(kfree) = ++ kzalloc(sizeof(*ucontrol), GFP_KERNEL); + +- ucontrol = kzalloc(sizeof(*ucontrol), GFP_KERNEL); + if (!ucontrol) + return -ENOMEM; + ucontrol->value.integer.value[0] = val; +diff --git a/sound/hda/common/sysfs.c b/sound/hda/common/sysfs.c +index f8c8483fd5e5f..bedf10b308850 100644 +--- a/sound/hda/common/sysfs.c ++++ b/sound/hda/common/sysfs.c +@@ -299,7 +299,6 @@ static void remove_trail_spaces(char *str) + + static int parse_hints(struct hda_codec *codec, const char *buf) + { +- char *key __free(kfree) = NULL; + char *val; + struct hda_hint *hint; + +@@ -308,7 +307,9 @@ static int parse_hints(struct hda_codec *codec, const char *buf) + return 0; + if (*buf == '=') + return -EINVAL; +- key = kstrndup_noeol(buf, 1024); ++ ++ char *key __free(kfree) = ++ kstrndup_noeol(buf, 1024); + if (!key) + return -ENOMEM; + /* extract key and val */ +-- +2.51.0 + diff --git a/queue-6.19/alsa-oss-delete-self-assignment.patch b/queue-6.19/alsa-oss-delete-self-assignment.patch new file mode 100644 index 0000000000..69bc4ffa76 --- /dev/null +++ b/queue-6.19/alsa-oss-delete-self-assignment.patch @@ -0,0 +1,36 @@ +From a2dbfd7b612c01a61865e7adac80ea53bd9a01e7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 16:41:47 +0300 +Subject: ALSA: oss: delete self assignment + +From: Dan Carpenter + +[ Upstream commit ee1afacc356c84bba4b89e0655ffdcfa84d4f714 ] + +No need to assign "uctl" to itself. Delete it. + +Fixes: 55f98ece9939 ("ALSA: oss: Relax __free() variable declarations") +Signed-off-by: Dan Carpenter +Link: https://patch.msgid.link/aYXvm2YoV2yRimhk@stanley.mountain +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/core/oss/mixer_oss.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c +index 69422ab2d8086..8d2d46d03301b 100644 +--- a/sound/core/oss/mixer_oss.c ++++ b/sound/core/oss/mixer_oss.c +@@ -792,7 +792,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned + struct snd_ctl_elem_info *uinfo __free(kfree) = + kzalloc(sizeof(*uinfo), GFP_KERNEL); + struct snd_ctl_elem_value *uctl __free(kfree) = +- uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); ++ kzalloc(sizeof(*uctl), GFP_KERNEL); + if (uinfo == NULL || uctl == NULL) + return -ENOMEM; + guard(rwsem_read)(&card->controls_rwsem); +-- +2.51.0 + diff --git a/queue-6.19/alsa-oss-relax-__free-variable-declarations.patch b/queue-6.19/alsa-oss-relax-__free-variable-declarations.patch new file mode 100644 index 0000000000..45f8ff496b --- /dev/null +++ b/queue-6.19/alsa-oss-relax-__free-variable-declarations.patch @@ -0,0 +1,268 @@ +From 38390084c22607164e721ec375f815b03d092da5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Dec 2025 15:06:26 +0100 +Subject: ALSA: oss: Relax __free() variable declarations + +From: Takashi Iwai + +[ Upstream commit 55f98ece9939a0ad5f83c6124dd1f00d678f9f46 ] + +We used to have a variable declaration with __free() initialized with +NULL. This was to keep the old coding style rule, but recently it's +relaxed and rather recommends to follow the new rule to declare in +place of use for __free() -- which avoids potential deadlocks or UAFs +with nested cleanups. + +Although the current code has no bug, per se, let's follow the new +standard and move the declaration to the place of assignment (or +directly assign the allocated result) instead of NULL initializations. + +Fixes: a55bc334d3df ("ALSA: pcm_oss: ump: Use automatic cleanup of kfree()") +Fixes: 6c40eec521af ("ALSA: mixer_oss: ump: Use automatic cleanup of kfree()") +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20251216140634.171890-5-tiwai@suse.de +Signed-off-by: Sasha Levin +--- + sound/core/oss/mixer_oss.c | 64 ++++++++++++++++++++------------------ + sound/core/oss/pcm_oss.c | 19 ++++++----- + 2 files changed, 45 insertions(+), 38 deletions(-) + +diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c +index e839a4bb93f81..69422ab2d8086 100644 +--- a/sound/core/oss/mixer_oss.c ++++ b/sound/core/oss/mixer_oss.c +@@ -517,8 +517,6 @@ static void snd_mixer_oss_get_volume1_vol(struct snd_mixer_oss_file *fmixer, + unsigned int numid, + int *left, int *right) + { +- struct snd_ctl_elem_info *uinfo __free(kfree) = NULL; +- struct snd_ctl_elem_value *uctl __free(kfree) = NULL; + struct snd_kcontrol *kctl; + struct snd_card *card = fmixer->card; + +@@ -528,8 +526,11 @@ static void snd_mixer_oss_get_volume1_vol(struct snd_mixer_oss_file *fmixer, + kctl = snd_ctl_find_numid(card, numid); + if (!kctl) + return; +- uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); +- uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); ++ ++ struct snd_ctl_elem_info *uinfo __free(kfree) = ++ kzalloc(sizeof(*uinfo), GFP_KERNEL); ++ struct snd_ctl_elem_value *uctl __free(kfree) = ++ kzalloc(sizeof(*uctl), GFP_KERNEL); + if (uinfo == NULL || uctl == NULL) + return; + if (kctl->info(kctl, uinfo)) +@@ -550,8 +551,6 @@ static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer, + int *left, int *right, + int route) + { +- struct snd_ctl_elem_info *uinfo __free(kfree) = NULL; +- struct snd_ctl_elem_value *uctl __free(kfree) = NULL; + struct snd_kcontrol *kctl; + struct snd_card *card = fmixer->card; + +@@ -561,8 +560,11 @@ static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer, + kctl = snd_ctl_find_numid(card, numid); + if (!kctl) + return; +- uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); +- uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); ++ ++ struct snd_ctl_elem_info *uinfo __free(kfree) = ++ kzalloc(sizeof(*uinfo), GFP_KERNEL); ++ struct snd_ctl_elem_value *uctl __free(kfree) = ++ kzalloc(sizeof(*uctl), GFP_KERNEL); + if (uinfo == NULL || uctl == NULL) + return; + if (kctl->info(kctl, uinfo)) +@@ -609,8 +611,6 @@ static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer, + unsigned int numid, + int left, int right) + { +- struct snd_ctl_elem_info *uinfo __free(kfree) = NULL; +- struct snd_ctl_elem_value *uctl __free(kfree) = NULL; + struct snd_kcontrol *kctl; + struct snd_card *card = fmixer->card; + int res; +@@ -621,8 +621,11 @@ static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer, + kctl = snd_ctl_find_numid(card, numid); + if (!kctl) + return; +- uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); +- uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); ++ ++ struct snd_ctl_elem_info *uinfo __free(kfree) = ++ kzalloc(sizeof(*uinfo), GFP_KERNEL); ++ struct snd_ctl_elem_value *uctl __free(kfree) = ++ kzalloc(sizeof(*uctl), GFP_KERNEL); + if (uinfo == NULL || uctl == NULL) + return; + if (kctl->info(kctl, uinfo)) +@@ -646,8 +649,6 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer, + int left, int right, + int route) + { +- struct snd_ctl_elem_info *uinfo __free(kfree) = NULL; +- struct snd_ctl_elem_value *uctl __free(kfree) = NULL; + struct snd_kcontrol *kctl; + struct snd_card *card = fmixer->card; + int res; +@@ -658,8 +659,11 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer, + kctl = snd_ctl_find_numid(card, numid); + if (!kctl) + return; +- uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); +- uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); ++ ++ struct snd_ctl_elem_info *uinfo __free(kfree) = ++ kzalloc(sizeof(*uinfo), GFP_KERNEL); ++ struct snd_ctl_elem_value *uctl __free(kfree) = ++ kzalloc(sizeof(*uctl), GFP_KERNEL); + if (uinfo == NULL || uctl == NULL) + return; + if (kctl->info(kctl, uinfo)) +@@ -783,12 +787,12 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned + struct snd_kcontrol *kctl; + struct snd_mixer_oss_slot *pslot; + struct slot *slot; +- struct snd_ctl_elem_info *uinfo __free(kfree) = NULL; +- struct snd_ctl_elem_value *uctl __free(kfree) = NULL; + int err, idx; + +- uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); +- uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); ++ struct snd_ctl_elem_info *uinfo __free(kfree) = ++ kzalloc(sizeof(*uinfo), GFP_KERNEL); ++ struct snd_ctl_elem_value *uctl __free(kfree) = ++ uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); + if (uinfo == NULL || uctl == NULL) + return -ENOMEM; + guard(rwsem_read)(&card->controls_rwsem); +@@ -825,13 +829,13 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned + struct snd_kcontrol *kctl; + struct snd_mixer_oss_slot *pslot; + struct slot *slot = NULL; +- struct snd_ctl_elem_info *uinfo __free(kfree) = NULL; +- struct snd_ctl_elem_value *uctl __free(kfree) = NULL; + int err; + unsigned int idx; + +- uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); +- uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); ++ struct snd_ctl_elem_info *uinfo __free(kfree) = ++ kzalloc(sizeof(*uinfo), GFP_KERNEL); ++ struct snd_ctl_elem_value *uctl __free(kfree) = ++ kzalloc(sizeof(*uctl), GFP_KERNEL); + if (uinfo == NULL || uctl == NULL) + return -ENOMEM; + guard(rwsem_read)(&card->controls_rwsem); +@@ -872,18 +876,18 @@ struct snd_mixer_oss_assign_table { + + static int snd_mixer_oss_build_test(struct snd_mixer_oss *mixer, struct slot *slot, const char *name, int index, int item) + { +- struct snd_ctl_elem_info *info __free(kfree) = NULL; + struct snd_kcontrol *kcontrol; + struct snd_card *card = mixer->card; + int err; + ++ struct snd_ctl_elem_info *info __free(kfree) = ++ kmalloc(sizeof(*info), GFP_KERNEL); ++ if (!info) ++ return -ENOMEM; + scoped_guard(rwsem_read, &card->controls_rwsem) { + kcontrol = snd_mixer_oss_test_id(mixer, name, index); + if (kcontrol == NULL) + return 0; +- info = kmalloc(sizeof(*info), GFP_KERNEL); +- if (!info) +- return -ENOMEM; + err = kcontrol->info(kcontrol, info); + if (err < 0) + return err; +@@ -1006,9 +1010,9 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer, + if (!ptr->index) + kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); + if (kctl) { +- struct snd_ctl_elem_info *uinfo __free(kfree) = NULL; ++ struct snd_ctl_elem_info *uinfo __free(kfree) = ++ kzalloc(sizeof(*uinfo), GFP_KERNEL); + +- uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); + if (!uinfo) + return -ENOMEM; + +diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c +index b12df5b5ddfc1..3bc94d34b35e7 100644 +--- a/sound/core/oss/pcm_oss.c ++++ b/sound/core/oss/pcm_oss.c +@@ -377,7 +377,6 @@ static int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm, + snd_pcm_hw_param_t var, unsigned int best, + int *dir) + { +- struct snd_pcm_hw_params *save __free(kfree) = NULL; + int v; + unsigned int saved_min; + int last = 0; +@@ -397,19 +396,22 @@ static int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm, + maxdir = 1; + max--; + } +- save = kmalloc(sizeof(*save), GFP_KERNEL); ++ ++ struct snd_pcm_hw_params *save __free(kfree) = ++ kmalloc(sizeof(*save), GFP_KERNEL); + if (save == NULL) + return -ENOMEM; + *save = *params; + saved_min = min; + min = snd_pcm_hw_param_min(pcm, params, var, min, &mindir); + if (min >= 0) { +- struct snd_pcm_hw_params *params1 __free(kfree) = NULL; + if (max < 0) + goto _end; + if ((unsigned int)min == saved_min && mindir == valdir) + goto _end; +- params1 = kmalloc(sizeof(*params1), GFP_KERNEL); ++ ++ struct snd_pcm_hw_params *params1 __free(kfree) = ++ kmalloc(sizeof(*params1), GFP_KERNEL); + if (params1 == NULL) + return -ENOMEM; + *params1 = *save; +@@ -781,10 +783,10 @@ static int choose_rate(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, unsigned int best_rate) + { + const struct snd_interval *it; +- struct snd_pcm_hw_params *save __free(kfree) = NULL; + unsigned int rate, prev; + +- save = kmalloc(sizeof(*save), GFP_KERNEL); ++ struct snd_pcm_hw_params *save __free(kfree) = ++ kmalloc(sizeof(*save), GFP_KERNEL); + if (save == NULL) + return -ENOMEM; + *save = *params; +@@ -1836,7 +1838,6 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file) + struct snd_pcm_substream *substream; + int err; + int direct; +- struct snd_pcm_hw_params *params __free(kfree) = NULL; + unsigned int formats = 0; + const struct snd_mask *format_mask; + int fmt; +@@ -1856,7 +1857,9 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file) + AFMT_S32_LE | AFMT_S32_BE | + AFMT_S24_LE | AFMT_S24_BE | + AFMT_S24_PACKED; +- params = kmalloc(sizeof(*params), GFP_KERNEL); ++ ++ struct snd_pcm_hw_params *params __free(kfree) = ++ kmalloc(sizeof(*params), GFP_KERNEL); + if (!params) + return -ENOMEM; + _snd_pcm_hw_params_any(params); +-- +2.51.0 + diff --git a/queue-6.19/alsa-pcm-relax-__free-variable-declarations.patch b/queue-6.19/alsa-pcm-relax-__free-variable-declarations.patch new file mode 100644 index 0000000000..5b9d30938a --- /dev/null +++ b/queue-6.19/alsa-pcm-relax-__free-variable-declarations.patch @@ -0,0 +1,268 @@ +From 9aded200add183bd4623c56b5ba69f57dc7957f8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Dec 2025 15:06:25 +0100 +Subject: ALSA: pcm: Relax __free() variable declarations + +From: Takashi Iwai + +[ Upstream commit f3d233daf011abbad2f6ebd0e545b42d2f378a4f ] + +We used to have a variable declaration with __free() initialized with +NULL. This was to keep the old coding style rule, but recently it's +relaxed and rather recommends to follow the new rule to declare in +place of use for __free() -- which avoids potential deadlocks or UAFs +with nested cleanups. + +Although the current code has no bug, per se, let's follow the new +standard and move the declaration to the place of assignment (or +directly assign the allocated result) instead of NULL initializations. + +Fixes: ae9213984864 ("ALSA: pcm: Use automatic cleanup of kfree()") +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20251216140634.171890-4-tiwai@suse.de +Signed-off-by: Sasha Levin +--- + sound/core/pcm.c | 4 ++-- + sound/core/pcm_compat.c | 9 ++++---- + sound/core/pcm_native.c | 50 +++++++++++++++++++++-------------------- + 3 files changed, 33 insertions(+), 30 deletions(-) + +diff --git a/sound/core/pcm.c b/sound/core/pcm.c +index 283aac441fa0a..0b512085eb63f 100644 +--- a/sound/core/pcm.c ++++ b/sound/core/pcm.c +@@ -328,13 +328,13 @@ static const char *snd_pcm_oss_format_name(int format) + static void snd_pcm_proc_info_read(struct snd_pcm_substream *substream, + struct snd_info_buffer *buffer) + { +- struct snd_pcm_info *info __free(kfree) = NULL; + int err; + + if (! substream) + return; + +- info = kmalloc(sizeof(*info), GFP_KERNEL); ++ struct snd_pcm_info *info __free(kfree) = ++ kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return; + +diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c +index 54eb9bd8eb218..e86f68f1f23c1 100644 +--- a/sound/core/pcm_compat.c ++++ b/sound/core/pcm_compat.c +@@ -235,7 +235,6 @@ static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream, + int refine, + struct snd_pcm_hw_params32 __user *data32) + { +- struct snd_pcm_hw_params *data __free(kfree) = NULL; + struct snd_pcm_runtime *runtime; + int err; + +@@ -243,7 +242,8 @@ static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream, + if (!runtime) + return -ENOTTY; + +- data = kmalloc(sizeof(*data), GFP_KERNEL); ++ struct snd_pcm_hw_params *data __free(kfree) = ++ kmalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + +@@ -332,7 +332,6 @@ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream, + compat_caddr_t buf; + compat_caddr_t __user *bufptr; + u32 frames; +- void __user **bufs __free(kfree) = NULL; + int err, ch, i; + + if (! substream->runtime) +@@ -349,7 +348,9 @@ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream, + get_user(frames, &data32->frames)) + return -EFAULT; + bufptr = compat_ptr(buf); +- bufs = kmalloc_array(ch, sizeof(void __user *), GFP_KERNEL); ++ ++ void __user **bufs __free(kfree) = ++ kmalloc_array(ch, sizeof(void __user *), GFP_KERNEL); + if (bufs == NULL) + return -ENOMEM; + for (i = 0; i < ch; i++) { +diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c +index 932a9bf98cbc0..844ee1b4d286f 100644 +--- a/sound/core/pcm_native.c ++++ b/sound/core/pcm_native.c +@@ -242,10 +242,10 @@ int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info) + int snd_pcm_info_user(struct snd_pcm_substream *substream, + struct snd_pcm_info __user * _info) + { +- struct snd_pcm_info *info __free(kfree) = NULL; + int err; ++ struct snd_pcm_info *info __free(kfree) = ++ kmalloc(sizeof(*info), GFP_KERNEL); + +- info = kmalloc(sizeof(*info), GFP_KERNEL); + if (! info) + return -ENOMEM; + err = snd_pcm_info(substream, info); +@@ -364,7 +364,6 @@ static int constrain_params_by_rules(struct snd_pcm_substream *substream, + struct snd_pcm_hw_constraints *constrs = + &substream->runtime->hw_constraints; + unsigned int k; +- unsigned int *rstamps __free(kfree) = NULL; + unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1]; + unsigned int stamp; + struct snd_pcm_hw_rule *r; +@@ -380,7 +379,8 @@ static int constrain_params_by_rules(struct snd_pcm_substream *substream, + * Each member of 'rstamps' array represents the sequence number of + * recent application of corresponding rule. + */ +- rstamps = kcalloc(constrs->rules_num, sizeof(unsigned int), GFP_KERNEL); ++ unsigned int *rstamps __free(kfree) = ++ kcalloc(constrs->rules_num, sizeof(unsigned int), GFP_KERNEL); + if (!rstamps) + return -ENOMEM; + +@@ -583,10 +583,10 @@ EXPORT_SYMBOL(snd_pcm_hw_refine); + static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params __user * _params) + { +- struct snd_pcm_hw_params *params __free(kfree) = NULL; + int err; ++ struct snd_pcm_hw_params *params __free(kfree) = ++ memdup_user(_params, sizeof(*params)); + +- params = memdup_user(_params, sizeof(*params)); + if (IS_ERR(params)) + return PTR_ERR(params); + +@@ -889,10 +889,10 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, + static int snd_pcm_hw_params_user(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params __user * _params) + { +- struct snd_pcm_hw_params *params __free(kfree) = NULL; + int err; ++ struct snd_pcm_hw_params *params __free(kfree) = ++ memdup_user(_params, sizeof(*params)); + +- params = memdup_user(_params, sizeof(*params)); + if (IS_ERR(params)) + return PTR_ERR(params); + +@@ -2267,7 +2267,6 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) + { + struct snd_pcm_file *pcm_file; + struct snd_pcm_substream *substream1; +- struct snd_pcm_group *group __free(kfree) = NULL; + struct snd_pcm_group *target_group; + bool nonatomic = substream->pcm->nonatomic; + CLASS(fd, f)(fd); +@@ -2283,7 +2282,8 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) + if (substream == substream1) + return -EINVAL; + +- group = kzalloc(sizeof(*group), GFP_KERNEL); ++ struct snd_pcm_group *group __free(kfree) = ++ kzalloc(sizeof(*group), GFP_KERNEL); + if (!group) + return -ENOMEM; + snd_pcm_group_init(group); +@@ -3291,7 +3291,6 @@ static int snd_pcm_xfern_frames_ioctl(struct snd_pcm_substream *substream, + { + struct snd_xfern xfern; + struct snd_pcm_runtime *runtime = substream->runtime; +- void *bufs __free(kfree) = NULL; + snd_pcm_sframes_t result; + + if (runtime->state == SNDRV_PCM_STATE_OPEN) +@@ -3303,7 +3302,8 @@ static int snd_pcm_xfern_frames_ioctl(struct snd_pcm_substream *substream, + if (copy_from_user(&xfern, _xfern, sizeof(xfern))) + return -EFAULT; + +- bufs = memdup_array_user(xfern.bufs, runtime->channels, sizeof(void *)); ++ void *bufs __free(kfree) = ++ memdup_array_user(xfern.bufs, runtime->channels, sizeof(void *)); + if (IS_ERR(bufs)) + return PTR_ERR(bufs); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) +@@ -3577,7 +3577,6 @@ static ssize_t snd_pcm_readv(struct kiocb *iocb, struct iov_iter *to) + struct snd_pcm_runtime *runtime; + snd_pcm_sframes_t result; + unsigned long i; +- void __user **bufs __free(kfree) = NULL; + snd_pcm_uframes_t frames; + const struct iovec *iov = iter_iov(to); + +@@ -3596,7 +3595,9 @@ static ssize_t snd_pcm_readv(struct kiocb *iocb, struct iov_iter *to) + if (!frame_aligned(runtime, iov->iov_len)) + return -EINVAL; + frames = bytes_to_samples(runtime, iov->iov_len); +- bufs = kmalloc_array(to->nr_segs, sizeof(void *), GFP_KERNEL); ++ ++ void __user **bufs __free(kfree) = ++ kmalloc_array(to->nr_segs, sizeof(void *), GFP_KERNEL); + if (bufs == NULL) + return -ENOMEM; + for (i = 0; i < to->nr_segs; ++i) { +@@ -3616,7 +3617,6 @@ static ssize_t snd_pcm_writev(struct kiocb *iocb, struct iov_iter *from) + struct snd_pcm_runtime *runtime; + snd_pcm_sframes_t result; + unsigned long i; +- void __user **bufs __free(kfree) = NULL; + snd_pcm_uframes_t frames; + const struct iovec *iov = iter_iov(from); + +@@ -3634,7 +3634,9 @@ static ssize_t snd_pcm_writev(struct kiocb *iocb, struct iov_iter *from) + !frame_aligned(runtime, iov->iov_len)) + return -EINVAL; + frames = bytes_to_samples(runtime, iov->iov_len); +- bufs = kmalloc_array(from->nr_segs, sizeof(void *), GFP_KERNEL); ++ ++ void __user **bufs __free(kfree) = ++ kmalloc_array(from->nr_segs, sizeof(void *), GFP_KERNEL); + if (bufs == NULL) + return -ENOMEM; + for (i = 0; i < from->nr_segs; ++i) { +@@ -4106,15 +4108,15 @@ static void snd_pcm_hw_convert_to_old_params(struct snd_pcm_hw_params_old *opara + static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params_old __user * _oparams) + { +- struct snd_pcm_hw_params *params __free(kfree) = NULL; +- struct snd_pcm_hw_params_old *oparams __free(kfree) = NULL; + int err; + +- params = kmalloc(sizeof(*params), GFP_KERNEL); ++ struct snd_pcm_hw_params *params __free(kfree) = ++ kmalloc(sizeof(*params), GFP_KERNEL); + if (!params) + return -ENOMEM; + +- oparams = memdup_user(_oparams, sizeof(*oparams)); ++ struct snd_pcm_hw_params_old *oparams __free(kfree) = ++ memdup_user(_oparams, sizeof(*oparams)); + if (IS_ERR(oparams)) + return PTR_ERR(oparams); + snd_pcm_hw_convert_from_old_params(params, oparams); +@@ -4135,15 +4137,15 @@ static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream, + static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params_old __user * _oparams) + { +- struct snd_pcm_hw_params *params __free(kfree) = NULL; +- struct snd_pcm_hw_params_old *oparams __free(kfree) = NULL; + int err; + +- params = kmalloc(sizeof(*params), GFP_KERNEL); ++ struct snd_pcm_hw_params *params __free(kfree) = ++ kmalloc(sizeof(*params), GFP_KERNEL); + if (!params) + return -ENOMEM; + +- oparams = memdup_user(_oparams, sizeof(*oparams)); ++ struct snd_pcm_hw_params_old *oparams __free(kfree) = ++ memdup_user(_oparams, sizeof(*oparams)); + if (IS_ERR(oparams)) + return PTR_ERR(oparams); + +-- +2.51.0 + diff --git a/queue-6.19/alsa-seq-oss-relax-__free-variable-declarations.patch b/queue-6.19/alsa-seq-oss-relax-__free-variable-declarations.patch new file mode 100644 index 0000000000..cdf28d66e4 --- /dev/null +++ b/queue-6.19/alsa-seq-oss-relax-__free-variable-declarations.patch @@ -0,0 +1,267 @@ +From 76be98c2d9dd4297a9dbc9b92c0320724992b6b5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Dec 2025 15:06:27 +0100 +Subject: ALSA: seq: oss: Relax __free() variable declarations + +From: Takashi Iwai + +[ Upstream commit df27c92753474cc8540e46a476119857ced7ae21 ] + +We used to have a variable declaration with __free() initialized with +NULL. This was to keep the old coding style rule, but recently it's +relaxed and rather recommends to follow the new rule to declare in +place of use for __free() -- which avoids potential deadlocks or UAFs +with nested cleanups. + +Although the current code has no bug, per se, let's follow the new +standard and move the declaration to the place of assignment (or +directly assign the allocated result) instead of NULL initializations. + +Fixes: 80ccbe91adab ("ALSA: seq: oss/synth: Clean up with guard and auto cleanup") +Fixes: 895a46e034f9 ("ALSA: seq: oss/midi: Cleanup with guard and auto-cleanup") +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20251216140634.171890-6-tiwai@suse.de +Signed-off-by: Sasha Levin +--- + sound/core/seq/oss/seq_oss_init.c | 4 +-- + sound/core/seq/oss/seq_oss_midi.c | 45 +++++++++++++++--------------- + sound/core/seq/oss/seq_oss_synth.c | 23 +++++++-------- + 3 files changed, 36 insertions(+), 36 deletions(-) + +diff --git a/sound/core/seq/oss/seq_oss_init.c b/sound/core/seq/oss/seq_oss_init.c +index 973f057eb731f..e0c368bd09cb6 100644 +--- a/sound/core/seq/oss/seq_oss_init.c ++++ b/sound/core/seq/oss/seq_oss_init.c +@@ -63,10 +63,10 @@ int __init + snd_seq_oss_create_client(void) + { + int rc; +- struct snd_seq_port_info *port __free(kfree) = NULL; + struct snd_seq_port_callback port_callback; ++ struct snd_seq_port_info *port __free(kfree) = ++ kzalloc(sizeof(*port), GFP_KERNEL); + +- port = kzalloc(sizeof(*port), GFP_KERNEL); + if (!port) + return -ENOMEM; + +diff --git a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c +index 023e5d0a4351d..2d48c25ff4df2 100644 +--- a/sound/core/seq/oss/seq_oss_midi.c ++++ b/sound/core/seq/oss/seq_oss_midi.c +@@ -65,11 +65,11 @@ static int send_midi_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, + int + snd_seq_oss_midi_lookup_ports(int client) + { +- struct snd_seq_client_info *clinfo __free(kfree) = NULL; +- struct snd_seq_port_info *pinfo __free(kfree) = NULL; ++ struct snd_seq_client_info *clinfo __free(kfree) = ++ kzalloc(sizeof(*clinfo), GFP_KERNEL); ++ struct snd_seq_port_info *pinfo __free(kfree) = ++ kzalloc(sizeof(*pinfo), GFP_KERNEL); + +- clinfo = kzalloc(sizeof(*clinfo), GFP_KERNEL); +- pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL); + if (!clinfo || !pinfo) + return -ENOMEM; + clinfo->client = -1; +@@ -305,10 +305,10 @@ int + snd_seq_oss_midi_open(struct seq_oss_devinfo *dp, int dev, int fmode) + { + int perm; +- struct seq_oss_midi *mdev __free(seq_oss_midi) = NULL; + struct snd_seq_port_subscribe subs; ++ struct seq_oss_midi *mdev __free(seq_oss_midi) = ++ get_mididev(dp, dev); + +- mdev = get_mididev(dp, dev); + if (!mdev) + return -ENODEV; + +@@ -364,10 +364,10 @@ snd_seq_oss_midi_open(struct seq_oss_devinfo *dp, int dev, int fmode) + int + snd_seq_oss_midi_close(struct seq_oss_devinfo *dp, int dev) + { +- struct seq_oss_midi *mdev __free(seq_oss_midi) = NULL; + struct snd_seq_port_subscribe subs; ++ struct seq_oss_midi *mdev __free(seq_oss_midi) = ++ get_mididev(dp, dev); + +- mdev = get_mididev(dp, dev); + if (!mdev) + return -ENODEV; + guard(mutex)(&mdev->open_mutex); +@@ -399,10 +399,10 @@ snd_seq_oss_midi_close(struct seq_oss_devinfo *dp, int dev) + int + snd_seq_oss_midi_filemode(struct seq_oss_devinfo *dp, int dev) + { +- struct seq_oss_midi *mdev __free(seq_oss_midi) = NULL; + int mode; ++ struct seq_oss_midi *mdev __free(seq_oss_midi) = ++ get_mididev(dp, dev); + +- mdev = get_mididev(dp, dev); + if (!mdev) + return 0; + +@@ -422,9 +422,9 @@ snd_seq_oss_midi_filemode(struct seq_oss_devinfo *dp, int dev) + void + snd_seq_oss_midi_reset(struct seq_oss_devinfo *dp, int dev) + { +- struct seq_oss_midi *mdev __free(seq_oss_midi) = NULL; ++ struct seq_oss_midi *mdev __free(seq_oss_midi) = ++ get_mididev(dp, dev); + +- mdev = get_mididev(dp, dev); + if (!mdev) + return; + if (!mdev->opened) +@@ -468,9 +468,9 @@ snd_seq_oss_midi_reset(struct seq_oss_devinfo *dp, int dev) + void + snd_seq_oss_midi_get_addr(struct seq_oss_devinfo *dp, int dev, struct snd_seq_addr *addr) + { +- struct seq_oss_midi *mdev __free(seq_oss_midi) = NULL; ++ struct seq_oss_midi *mdev __free(seq_oss_midi) = ++ get_mididev(dp, dev); + +- mdev = get_mididev(dp, dev); + if (!mdev) + return; + addr->client = mdev->client; +@@ -485,11 +485,11 @@ int + snd_seq_oss_midi_input(struct snd_seq_event *ev, int direct, void *private_data) + { + struct seq_oss_devinfo *dp = (struct seq_oss_devinfo *)private_data; +- struct seq_oss_midi *mdev __free(seq_oss_midi) = NULL; + + if (dp->readq == NULL) + return 0; +- mdev = find_slot(ev->source.client, ev->source.port); ++ struct seq_oss_midi *mdev __free(seq_oss_midi) = ++ find_slot(ev->source.client, ev->source.port); + if (!mdev) + return 0; + if (!(mdev->opened & PERM_READ)) +@@ -595,9 +595,9 @@ send_midi_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, struct seq + int + snd_seq_oss_midi_putc(struct seq_oss_devinfo *dp, int dev, unsigned char c, struct snd_seq_event *ev) + { +- struct seq_oss_midi *mdev __free(seq_oss_midi) = NULL; ++ struct seq_oss_midi *mdev __free(seq_oss_midi) = ++ get_mididev(dp, dev); + +- mdev = get_mididev(dp, dev); + if (!mdev) + return -ENODEV; + if (snd_midi_event_encode_byte(mdev->coder, c, ev)) { +@@ -613,9 +613,9 @@ snd_seq_oss_midi_putc(struct seq_oss_devinfo *dp, int dev, unsigned char c, stru + int + snd_seq_oss_midi_make_info(struct seq_oss_devinfo *dp, int dev, struct midi_info *inf) + { +- struct seq_oss_midi *mdev __free(seq_oss_midi) = NULL; ++ struct seq_oss_midi *mdev __free(seq_oss_midi) = ++ get_mididev(dp, dev); + +- mdev = get_mididev(dp, dev); + if (!mdev) + return -ENXIO; + inf->device = dev; +@@ -651,10 +651,9 @@ snd_seq_oss_midi_info_read(struct snd_info_buffer *buf) + + snd_iprintf(buf, "\nNumber of MIDI devices: %d\n", max_midi_devs); + for (i = 0; i < max_midi_devs; i++) { +- struct seq_oss_midi *mdev __free(seq_oss_midi) = NULL; +- + snd_iprintf(buf, "\nmidi %d: ", i); +- mdev = get_mdev(i); ++ struct seq_oss_midi *mdev __free(seq_oss_midi) = ++ get_mdev(i); + if (mdev == NULL) { + snd_iprintf(buf, "*empty*\n"); + continue; +diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c +index 8c4e5913c7e69..beea37ed942cb 100644 +--- a/sound/core/seq/oss/seq_oss_synth.c ++++ b/sound/core/seq/oss/seq_oss_synth.c +@@ -368,7 +368,6 @@ reset_channels(struct seq_oss_synthinfo *info) + void + snd_seq_oss_synth_reset(struct seq_oss_devinfo *dp, int dev) + { +- struct seq_oss_synth *rec __free(seq_oss_synth) = NULL; + struct seq_oss_synthinfo *info; + + info = get_synthinfo_nospec(dp, dev); +@@ -391,7 +390,8 @@ snd_seq_oss_synth_reset(struct seq_oss_devinfo *dp, int dev) + return; + } + +- rec = get_sdev(dev); ++ struct seq_oss_synth *rec __free(seq_oss_synth) = ++ get_sdev(dev); + if (rec == NULL) + return; + if (rec->oper.reset) { +@@ -415,7 +415,6 @@ int + snd_seq_oss_synth_load_patch(struct seq_oss_devinfo *dp, int dev, int fmt, + const char __user *buf, int p, int c) + { +- struct seq_oss_synth *rec __free(seq_oss_synth) = NULL; + struct seq_oss_synthinfo *info; + + info = get_synthinfo_nospec(dp, dev); +@@ -424,7 +423,9 @@ snd_seq_oss_synth_load_patch(struct seq_oss_devinfo *dp, int dev, int fmt, + + if (info->is_midi) + return 0; +- rec = get_synthdev(dp, dev); ++ ++ struct seq_oss_synth *rec __free(seq_oss_synth) = ++ get_synthdev(dp, dev); + if (!rec) + return -ENXIO; + +@@ -440,9 +441,9 @@ snd_seq_oss_synth_load_patch(struct seq_oss_devinfo *dp, int dev, int fmt, + struct seq_oss_synthinfo * + snd_seq_oss_synth_info(struct seq_oss_devinfo *dp, int dev) + { +- struct seq_oss_synth *rec __free(seq_oss_synth) = NULL; ++ struct seq_oss_synth *rec __free(seq_oss_synth) = ++ get_synthdev(dp, dev); + +- rec = get_synthdev(dp, dev); + if (rec) + return get_synthinfo_nospec(dp, dev); + return NULL; +@@ -495,13 +496,14 @@ snd_seq_oss_synth_addr(struct seq_oss_devinfo *dp, int dev, struct snd_seq_event + int + snd_seq_oss_synth_ioctl(struct seq_oss_devinfo *dp, int dev, unsigned int cmd, unsigned long addr) + { +- struct seq_oss_synth *rec __free(seq_oss_synth) = NULL; + struct seq_oss_synthinfo *info; + + info = get_synthinfo_nospec(dp, dev); + if (!info || info->is_midi) + return -ENXIO; +- rec = get_synthdev(dp, dev); ++ ++ struct seq_oss_synth *rec __free(seq_oss_synth) = ++ get_synthdev(dp, dev); + if (!rec) + return -ENXIO; + if (rec->oper.ioctl == NULL) +@@ -575,10 +577,9 @@ snd_seq_oss_synth_info_read(struct snd_info_buffer *buf) + + snd_iprintf(buf, "\nNumber of synth devices: %d\n", max_synth_devs); + for (i = 0; i < max_synth_devs; i++) { +- struct seq_oss_synth *rec __free(seq_oss_synth) = NULL; +- + snd_iprintf(buf, "\nsynth %d: ", i); +- rec = get_sdev(i); ++ struct seq_oss_synth *rec __free(seq_oss_synth) = ++ get_sdev(i); + if (rec == NULL) { + snd_iprintf(buf, "*empty*\n"); + continue; +-- +2.51.0 + diff --git a/queue-6.19/alsa-seq-relax-__free-variable-declarations.patch b/queue-6.19/alsa-seq-relax-__free-variable-declarations.patch new file mode 100644 index 0000000000..c4ec5fa958 --- /dev/null +++ b/queue-6.19/alsa-seq-relax-__free-variable-declarations.patch @@ -0,0 +1,769 @@ +From e1b25a8911212f3c6067140c0197ff29d954f2ff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Dec 2025 15:06:28 +0100 +Subject: ALSA: seq: Relax __free() variable declarations + +From: Takashi Iwai + +[ Upstream commit 13bc5c5394b22fd0a0585733bbbd9266159a840c ] + +We used to have a variable declaration with __free() initialized with +NULL. This was to keep the old coding style rule, but recently it's +relaxed and rather recommends to follow the new rule to declare in +place of use for __free() -- which avoids potential deadlocks or UAFs +with nested cleanups. + +Although the current code has no bug, per se, let's follow the new +standard and move the declaration to the place of assignment (or +directly assign the allocated result) instead of NULL initializations. + +Note that there is a remaining __free() with NULL initialization; it's +because of the non-trivial code conditionally assigning the data. + +Fixes: 04a86185b785 ("ALSA: seq: Clean up queue locking with auto cleanup") +Fixes: 0869afc958a0 ("ALSA: seq: Clean up port locking with auto cleanup") +Fixes: 99e16633958b ("ALSA: seq: Use auto-cleanup for client refcounting") +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20251216140634.171890-7-tiwai@suse.de +Signed-off-by: Sasha Levin +--- + sound/core/seq/seq_clientmgr.c | 171 ++++++++++++++++---------------- + sound/core/seq/seq_compat.c | 4 +- + sound/core/seq/seq_midi.c | 10 +- + sound/core/seq/seq_ports.c | 11 +- + sound/core/seq/seq_queue.c | 32 +++--- + sound/core/seq/seq_ump_client.c | 16 +-- + sound/core/seq/seq_virmidi.c | 4 +- + 7 files changed, 126 insertions(+), 122 deletions(-) + +diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c +index f9a6e497f997c..75a7a2af9d8c9 100644 +--- a/sound/core/seq/seq_clientmgr.c ++++ b/sound/core/seq/seq_clientmgr.c +@@ -494,9 +494,9 @@ static int check_port_perm(struct snd_seq_client_port *port, unsigned int flags) + */ + static struct snd_seq_client *get_event_dest_client(struct snd_seq_event *event) + { +- struct snd_seq_client *dest __free(snd_seq_client) = NULL; ++ struct snd_seq_client *dest __free(snd_seq_client) = ++ snd_seq_client_use_ptr(event->dest.client); + +- dest = snd_seq_client_use_ptr(event->dest.client); + if (dest == NULL) + return NULL; + if (! dest->accept_input) +@@ -565,9 +565,9 @@ static int bounce_error_event(struct snd_seq_client *client, + static int update_timestamp_of_queue(struct snd_seq_event *event, + int queue, int real_time) + { +- struct snd_seq_queue *q __free(snd_seq_queue) = NULL; ++ struct snd_seq_queue *q __free(snd_seq_queue) = ++ queueptr(queue); + +- q = queueptr(queue); + if (! q) + return 0; + event->queue = queue; +@@ -609,13 +609,13 @@ static int _snd_seq_deliver_single_event(struct snd_seq_client *client, + struct snd_seq_event *event, + int atomic, int hop) + { +- struct snd_seq_client *dest __free(snd_seq_client) = NULL; +- struct snd_seq_client_port *dest_port __free(snd_seq_port) = NULL; +- +- dest = get_event_dest_client(event); ++ struct snd_seq_client *dest __free(snd_seq_client) = ++ get_event_dest_client(event); + if (dest == NULL) + return -ENOENT; +- dest_port = snd_seq_port_use_ptr(dest, event->dest.port); ++ ++ struct snd_seq_client_port *dest_port __free(snd_seq_port) = ++ snd_seq_port_use_ptr(dest, event->dest.port); + if (dest_port == NULL) + return -ENOENT; + +@@ -672,7 +672,6 @@ static int __deliver_to_subscribers(struct snd_seq_client *client, + struct snd_seq_event *event, + int port, int atomic, int hop) + { +- struct snd_seq_client_port *src_port __free(snd_seq_port) = NULL; + struct snd_seq_subscribers *subs; + int err, result = 0, num_ev = 0; + union __snd_seq_event event_saved; +@@ -681,7 +680,9 @@ static int __deliver_to_subscribers(struct snd_seq_client *client, + + if (port < 0) + return 0; +- src_port = snd_seq_port_use_ptr(client, port); ++ ++ struct snd_seq_client_port *src_port __free(snd_seq_port) = ++ snd_seq_port_use_ptr(client, port); + if (!src_port) + return 0; + +@@ -801,13 +802,13 @@ static int snd_seq_deliver_event(struct snd_seq_client *client, struct snd_seq_e + */ + int snd_seq_dispatch_event(struct snd_seq_event_cell *cell, int atomic, int hop) + { +- struct snd_seq_client *client __free(snd_seq_client) = NULL; + int result; + + if (snd_BUG_ON(!cell)) + return -EINVAL; + +- client = snd_seq_client_use_ptr(cell->event.source.client); ++ struct snd_seq_client *client __free(snd_seq_client) = ++ snd_seq_client_use_ptr(cell->event.source.client); + if (client == NULL) { + snd_seq_cell_free(cell); /* release this cell */ + return -EINVAL; +@@ -1154,10 +1155,10 @@ static int snd_seq_ioctl_system_info(struct snd_seq_client *client, void *arg) + static int snd_seq_ioctl_running_mode(struct snd_seq_client *client, void *arg) + { + struct snd_seq_running_info *info = arg; +- struct snd_seq_client *cptr __free(snd_seq_client) = NULL; +- + /* requested client number */ +- cptr = client_load_and_use_ptr(info->client); ++ struct snd_seq_client *cptr __free(snd_seq_client) = ++ client_load_and_use_ptr(info->client); ++ + if (cptr == NULL) + return -ENOENT; /* don't change !!! */ + +@@ -1207,10 +1208,10 @@ static int snd_seq_ioctl_get_client_info(struct snd_seq_client *client, + void *arg) + { + struct snd_seq_client_info *client_info = arg; +- struct snd_seq_client *cptr __free(snd_seq_client) = NULL; +- + /* requested client number */ +- cptr = client_load_and_use_ptr(client_info->client); ++ struct snd_seq_client *cptr __free(snd_seq_client) = ++ client_load_and_use_ptr(client_info->client); ++ + if (cptr == NULL) + return -ENOENT; /* don't change !!! */ + +@@ -1344,14 +1345,14 @@ static int snd_seq_ioctl_delete_port(struct snd_seq_client *client, void *arg) + static int snd_seq_ioctl_get_port_info(struct snd_seq_client *client, void *arg) + { + struct snd_seq_port_info *info = arg; +- struct snd_seq_client *cptr __free(snd_seq_client) = NULL; +- struct snd_seq_client_port *port __free(snd_seq_port) = NULL; + +- cptr = client_load_and_use_ptr(info->addr.client); ++ struct snd_seq_client *cptr __free(snd_seq_client) = ++ client_load_and_use_ptr(info->addr.client); + if (cptr == NULL) + return -ENXIO; + +- port = snd_seq_port_use_ptr(cptr, info->addr.port); ++ struct snd_seq_client_port *port __free(snd_seq_port) = ++ snd_seq_port_use_ptr(cptr, info->addr.port); + if (port == NULL) + return -ENOENT; /* don't change */ + +@@ -1367,11 +1368,12 @@ static int snd_seq_ioctl_get_port_info(struct snd_seq_client *client, void *arg) + static int snd_seq_ioctl_set_port_info(struct snd_seq_client *client, void *arg) + { + struct snd_seq_port_info *info = arg; +- struct snd_seq_client_port *port __free(snd_seq_port) = NULL; + + if (info->addr.client != client->number) /* only set our own ports ! */ + return -EPERM; +- port = snd_seq_port_use_ptr(client, info->addr.port); ++ ++ struct snd_seq_client_port *port __free(snd_seq_port) = ++ snd_seq_port_use_ptr(client, info->addr.port); + if (port) { + snd_seq_set_port_info(port, info); + /* notify the change */ +@@ -1444,22 +1446,22 @@ static int snd_seq_ioctl_subscribe_port(struct snd_seq_client *client, + void *arg) + { + struct snd_seq_port_subscribe *subs = arg; +- struct snd_seq_client *receiver __free(snd_seq_client) = NULL; +- struct snd_seq_client *sender __free(snd_seq_client) = NULL; +- struct snd_seq_client_port *sport __free(snd_seq_port) = NULL; +- struct snd_seq_client_port *dport __free(snd_seq_port) = NULL; + int result; + +- receiver = client_load_and_use_ptr(subs->dest.client); ++ struct snd_seq_client *receiver __free(snd_seq_client) = ++ client_load_and_use_ptr(subs->dest.client); + if (!receiver) + return -EINVAL; +- sender = client_load_and_use_ptr(subs->sender.client); ++ struct snd_seq_client *sender __free(snd_seq_client) = ++ client_load_and_use_ptr(subs->sender.client); + if (!sender) + return -EINVAL; +- sport = snd_seq_port_use_ptr(sender, subs->sender.port); ++ struct snd_seq_client_port *sport __free(snd_seq_port) = ++ snd_seq_port_use_ptr(sender, subs->sender.port); + if (!sport) + return -EINVAL; +- dport = snd_seq_port_use_ptr(receiver, subs->dest.port); ++ struct snd_seq_client_port *dport __free(snd_seq_port) = ++ snd_seq_port_use_ptr(receiver, subs->dest.port); + if (!dport) + return -EINVAL; + +@@ -1483,22 +1485,22 @@ static int snd_seq_ioctl_unsubscribe_port(struct snd_seq_client *client, + void *arg) + { + struct snd_seq_port_subscribe *subs = arg; +- struct snd_seq_client *receiver __free(snd_seq_client) = NULL; +- struct snd_seq_client *sender __free(snd_seq_client) = NULL; +- struct snd_seq_client_port *sport __free(snd_seq_port) = NULL; +- struct snd_seq_client_port *dport __free(snd_seq_port) = NULL; + int result; + +- receiver = snd_seq_client_use_ptr(subs->dest.client); ++ struct snd_seq_client *receiver __free(snd_seq_client) = ++ snd_seq_client_use_ptr(subs->dest.client); + if (!receiver) + return -ENXIO; +- sender = snd_seq_client_use_ptr(subs->sender.client); ++ struct snd_seq_client *sender __free(snd_seq_client) = ++ snd_seq_client_use_ptr(subs->sender.client); + if (!sender) + return -ENXIO; +- sport = snd_seq_port_use_ptr(sender, subs->sender.port); ++ struct snd_seq_client_port *sport __free(snd_seq_port) = ++ snd_seq_port_use_ptr(sender, subs->sender.port); + if (!sport) + return -ENXIO; +- dport = snd_seq_port_use_ptr(receiver, subs->dest.port); ++ struct snd_seq_client_port *dport __free(snd_seq_port) = ++ snd_seq_port_use_ptr(receiver, subs->dest.port); + if (!dport) + return -ENXIO; + +@@ -1518,9 +1520,9 @@ static int snd_seq_ioctl_unsubscribe_port(struct snd_seq_client *client, + static int snd_seq_ioctl_create_queue(struct snd_seq_client *client, void *arg) + { + struct snd_seq_queue_info *info = arg; +- struct snd_seq_queue *q __free(snd_seq_queue) = NULL; ++ struct snd_seq_queue *q __free(snd_seq_queue) = ++ snd_seq_queue_alloc(client->number, info->locked, info->flags); + +- q = snd_seq_queue_alloc(client->number, info->locked, info->flags); + if (IS_ERR(q)) + return PTR_ERR(q); + +@@ -1549,9 +1551,9 @@ static int snd_seq_ioctl_get_queue_info(struct snd_seq_client *client, + void *arg) + { + struct snd_seq_queue_info *info = arg; +- struct snd_seq_queue *q __free(snd_seq_queue) = NULL; ++ struct snd_seq_queue *q __free(snd_seq_queue) = ++ queueptr(info->queue); + +- q = queueptr(info->queue); + if (q == NULL) + return -EINVAL; + +@@ -1569,7 +1571,6 @@ static int snd_seq_ioctl_set_queue_info(struct snd_seq_client *client, + void *arg) + { + struct snd_seq_queue_info *info = arg; +- struct snd_seq_queue *q __free(snd_seq_queue) = NULL; + + if (info->owner != client->number) + return -EINVAL; +@@ -1584,7 +1585,8 @@ static int snd_seq_ioctl_set_queue_info(struct snd_seq_client *client, + return -EPERM; + } + +- q = queueptr(info->queue); ++ struct snd_seq_queue *q __free(snd_seq_queue) = ++ queueptr(info->queue); + if (! q) + return -EINVAL; + if (q->owner != client->number) +@@ -1599,9 +1601,9 @@ static int snd_seq_ioctl_get_named_queue(struct snd_seq_client *client, + void *arg) + { + struct snd_seq_queue_info *info = arg; +- struct snd_seq_queue *q __free(snd_seq_queue) = NULL; ++ struct snd_seq_queue *q __free(snd_seq_queue) = ++ snd_seq_queue_find_name(info->name); + +- q = snd_seq_queue_find_name(info->name); + if (q == NULL) + return -EINVAL; + info->queue = q->queue; +@@ -1616,10 +1618,10 @@ static int snd_seq_ioctl_get_queue_status(struct snd_seq_client *client, + void *arg) + { + struct snd_seq_queue_status *status = arg; +- struct snd_seq_queue *queue __free(snd_seq_queue) = NULL; + struct snd_seq_timer *tmr; ++ struct snd_seq_queue *queue __free(snd_seq_queue) = ++ queueptr(status->queue); + +- queue = queueptr(status->queue); + if (queue == NULL) + return -EINVAL; + memset(status, 0, sizeof(*status)); +@@ -1644,10 +1646,10 @@ static int snd_seq_ioctl_get_queue_tempo(struct snd_seq_client *client, + void *arg) + { + struct snd_seq_queue_tempo *tempo = arg; +- struct snd_seq_queue *queue __free(snd_seq_queue) = NULL; + struct snd_seq_timer *tmr; ++ struct snd_seq_queue *queue __free(snd_seq_queue) = ++ queueptr(tempo->queue); + +- queue = queueptr(tempo->queue); + if (queue == NULL) + return -EINVAL; + memset(tempo, 0, sizeof(*tempo)); +@@ -1693,10 +1695,10 @@ static int snd_seq_ioctl_get_queue_timer(struct snd_seq_client *client, + void *arg) + { + struct snd_seq_queue_timer *timer = arg; +- struct snd_seq_queue *queue __free(snd_seq_queue) = NULL; + struct snd_seq_timer *tmr; ++ struct snd_seq_queue *queue __free(snd_seq_queue) = ++ queueptr(timer->queue); + +- queue = queueptr(timer->queue); + if (queue == NULL) + return -EINVAL; + +@@ -1726,10 +1728,10 @@ static int snd_seq_ioctl_set_queue_timer(struct snd_seq_client *client, + return -EINVAL; + + if (snd_seq_queue_check_access(timer->queue, client->number)) { +- struct snd_seq_queue *q __free(snd_seq_queue) = NULL; + struct snd_seq_timer *tmr; ++ struct snd_seq_queue *q __free(snd_seq_queue) = ++ queueptr(timer->queue); + +- q = queueptr(timer->queue); + if (q == NULL) + return -ENXIO; + guard(mutex)(&q->timer_mutex); +@@ -1788,9 +1790,9 @@ static int snd_seq_ioctl_get_client_pool(struct snd_seq_client *client, + void *arg) + { + struct snd_seq_client_pool *info = arg; +- struct snd_seq_client *cptr __free(snd_seq_client) = NULL; ++ struct snd_seq_client *cptr __free(snd_seq_client) = ++ client_load_and_use_ptr(info->client); + +- cptr = client_load_and_use_ptr(info->client); + if (cptr == NULL) + return -ENOENT; + memset(info, 0, sizeof(*info)); +@@ -1888,13 +1890,13 @@ static int snd_seq_ioctl_get_subscription(struct snd_seq_client *client, + void *arg) + { + struct snd_seq_port_subscribe *subs = arg; +- struct snd_seq_client *sender __free(snd_seq_client) = NULL; +- struct snd_seq_client_port *sport __free(snd_seq_port) = NULL; + +- sender = client_load_and_use_ptr(subs->sender.client); ++ struct snd_seq_client *sender __free(snd_seq_client) = ++ client_load_and_use_ptr(subs->sender.client); + if (!sender) + return -EINVAL; +- sport = snd_seq_port_use_ptr(sender, subs->sender.port); ++ struct snd_seq_client_port *sport __free(snd_seq_port) = ++ snd_seq_port_use_ptr(sender, subs->sender.port); + if (!sport) + return -EINVAL; + return snd_seq_port_get_subscription(&sport->c_src, &subs->dest, subs); +@@ -1907,16 +1909,16 @@ static int snd_seq_ioctl_get_subscription(struct snd_seq_client *client, + static int snd_seq_ioctl_query_subs(struct snd_seq_client *client, void *arg) + { + struct snd_seq_query_subs *subs = arg; +- struct snd_seq_client *cptr __free(snd_seq_client) = NULL; +- struct snd_seq_client_port *port __free(snd_seq_port) = NULL; + struct snd_seq_port_subs_info *group; + struct list_head *p; + int i; + +- cptr = client_load_and_use_ptr(subs->root.client); ++ struct snd_seq_client *cptr __free(snd_seq_client) = ++ client_load_and_use_ptr(subs->root.client); + if (!cptr) + return -ENXIO; +- port = snd_seq_port_use_ptr(cptr, subs->root.port); ++ struct snd_seq_client_port *port __free(snd_seq_port) = ++ snd_seq_port_use_ptr(cptr, subs->root.port); + if (!port) + return -ENXIO; + +@@ -1963,7 +1965,6 @@ static int snd_seq_ioctl_query_next_client(struct snd_seq_client *client, + void *arg) + { + struct snd_seq_client_info *info = arg; +- struct snd_seq_client *cptr __free(snd_seq_client) = NULL; + + /* search for next client */ + if (info->client < INT_MAX) +@@ -1971,7 +1972,8 @@ static int snd_seq_ioctl_query_next_client(struct snd_seq_client *client, + if (info->client < 0) + info->client = 0; + for (; info->client < SNDRV_SEQ_MAX_CLIENTS; info->client++) { +- cptr = client_load_and_use_ptr(info->client); ++ struct snd_seq_client *cptr __free(snd_seq_client) = ++ client_load_and_use_ptr(info->client); + if (cptr) { + get_client_info(cptr, info); + return 0; /* found */ +@@ -1987,16 +1989,16 @@ static int snd_seq_ioctl_query_next_port(struct snd_seq_client *client, + void *arg) + { + struct snd_seq_port_info *info = arg; +- struct snd_seq_client *cptr __free(snd_seq_client) = NULL; +- struct snd_seq_client_port *port __free(snd_seq_port) = NULL; + +- cptr = client_load_and_use_ptr(info->addr.client); ++ struct snd_seq_client *cptr __free(snd_seq_client) = ++ client_load_and_use_ptr(info->addr.client); + if (cptr == NULL) + return -ENXIO; + + /* search for next port */ + info->addr.port++; +- port = snd_seq_port_query_nearest(cptr, info); ++ struct snd_seq_client_port *port __free(snd_seq_port) = ++ snd_seq_port_query_nearest(cptr, info); + if (port == NULL) + return -ENOENT; + +@@ -2067,7 +2069,6 @@ static int snd_seq_ioctl_client_ump_info(struct snd_seq_client *caller, + { + struct snd_seq_client_ump_info __user *argp = + (struct snd_seq_client_ump_info __user *)arg; +- struct snd_seq_client *cptr __free(snd_seq_client) = NULL; + int client, type, err = 0; + size_t size; + void *p; +@@ -2083,7 +2084,9 @@ static int snd_seq_ioctl_client_ump_info(struct snd_seq_client *caller, + size = sizeof(struct snd_ump_endpoint_info); + else + size = sizeof(struct snd_ump_block_info); +- cptr = client_load_and_use_ptr(client); ++ ++ struct snd_seq_client *cptr __free(snd_seq_client) = ++ client_load_and_use_ptr(client); + if (!cptr) + return -ENOENT; + +@@ -2342,8 +2345,6 @@ EXPORT_SYMBOL(snd_seq_delete_kernel_client); + int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event *ev, + struct file *file, bool blocking) + { +- struct snd_seq_client *cptr __free(snd_seq_client) = NULL; +- + if (snd_BUG_ON(!ev)) + return -EINVAL; + +@@ -2360,7 +2361,8 @@ int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event *ev, + if (check_event_type_and_length(ev)) + return -EINVAL; + +- cptr = client_load_and_use_ptr(client); ++ struct snd_seq_client *cptr __free(snd_seq_client) = ++ client_load_and_use_ptr(client); + if (cptr == NULL) + return -EINVAL; + +@@ -2385,8 +2387,6 @@ EXPORT_SYMBOL(snd_seq_kernel_client_enqueue); + int snd_seq_kernel_client_dispatch(int client, struct snd_seq_event * ev, + int atomic, int hop) + { +- struct snd_seq_client *cptr __free(snd_seq_client) = NULL; +- + if (snd_BUG_ON(!ev)) + return -EINVAL; + +@@ -2397,7 +2397,8 @@ int snd_seq_kernel_client_dispatch(int client, struct snd_seq_event * ev, + if (check_event_type_and_length(ev)) + return -EINVAL; + +- cptr = snd_seq_client_use_ptr(client); ++ struct snd_seq_client *cptr __free(snd_seq_client) = ++ snd_seq_client_use_ptr(client); + if (cptr == NULL) + return -EINVAL; + +@@ -2450,9 +2451,9 @@ EXPORT_SYMBOL(snd_seq_kernel_client_ctl); + /* a similar like above but taking locks; used only from OSS sequencer layer */ + int snd_seq_kernel_client_ioctl(int clientid, unsigned int cmd, void *arg) + { +- struct snd_seq_client *client __free(snd_seq_client) = NULL; ++ struct snd_seq_client *client __free(snd_seq_client) = ++ client_load_and_use_ptr(clientid); + +- client = client_load_and_use_ptr(clientid); + if (!client) + return -ENXIO; + guard(mutex)(&client->ioctl_mutex); +@@ -2597,9 +2598,9 @@ void snd_seq_info_clients_read(struct snd_info_entry *entry, + + /* list the client table */ + for (c = 0; c < SNDRV_SEQ_MAX_CLIENTS; c++) { +- struct snd_seq_client *client __free(snd_seq_client) = NULL; ++ struct snd_seq_client *client __free(snd_seq_client) = ++ client_load_and_use_ptr(c); + +- client = client_load_and_use_ptr(c); + if (client == NULL) + continue; + if (client->type == NO_CLIENT) +diff --git a/sound/core/seq/seq_compat.c b/sound/core/seq/seq_compat.c +index 643af4c1e8386..260428747e337 100644 +--- a/sound/core/seq/seq_compat.c ++++ b/sound/core/seq/seq_compat.c +@@ -31,10 +31,10 @@ struct snd_seq_port_info32 { + static int snd_seq_call_port_info_ioctl(struct snd_seq_client *client, unsigned int cmd, + struct snd_seq_port_info32 __user *data32) + { +- struct snd_seq_port_info *data __free(kfree) = NULL; + int err; ++ struct snd_seq_port_info *data __free(kfree) = ++ kmalloc(sizeof(*data), GFP_KERNEL); + +- data = kmalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + +diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c +index 581e138a31159..73dbef8fb2ac0 100644 +--- a/sound/core/seq/seq_midi.c ++++ b/sound/core/seq/seq_midi.c +@@ -270,8 +270,6 @@ snd_seq_midisynth_probe(struct device *_dev) + struct snd_seq_device *dev = to_seq_dev(_dev); + struct seq_midisynth_client *client; + struct seq_midisynth *msynth, *ms; +- struct snd_seq_port_info *port __free(kfree) = NULL; +- struct snd_rawmidi_info *info __free(kfree) = NULL; + struct snd_rawmidi *rmidi = dev->private_data; + int newclient = 0; + unsigned int p, ports; +@@ -282,7 +280,9 @@ snd_seq_midisynth_probe(struct device *_dev) + + if (snd_BUG_ON(!card || device < 0 || device >= SNDRV_RAWMIDI_DEVICES)) + return -EINVAL; +- info = kmalloc(sizeof(*info), GFP_KERNEL); ++ ++ struct snd_rawmidi_info *info __free(kfree) = ++ kmalloc(sizeof(*info), GFP_KERNEL); + if (! info) + return -ENOMEM; + info->device = device; +@@ -320,7 +320,9 @@ snd_seq_midisynth_probe(struct device *_dev) + } + + msynth = kcalloc(ports, sizeof(struct seq_midisynth), GFP_KERNEL); +- port = kmalloc(sizeof(*port), GFP_KERNEL); ++ ++ struct snd_seq_port_info *port __free(kfree) = ++ kmalloc(sizeof(*port), GFP_KERNEL); + if (msynth == NULL || port == NULL) + goto __nomem; + +diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c +index 40fa379847e57..bbec34bba4f99 100644 +--- a/sound/core/seq/seq_ports.c ++++ b/sound/core/seq/seq_ports.c +@@ -211,14 +211,13 @@ static void clear_subscriber_list(struct snd_seq_client *client, + + list_for_each_safe(p, n, &grp->list_head) { + struct snd_seq_subscribers *subs; +- struct snd_seq_client *c __free(snd_seq_client) = NULL; +- struct snd_seq_client_port *aport __free(snd_seq_port) = NULL; + + subs = get_subscriber(p, is_src); +- if (is_src) +- aport = get_client_port(&subs->info.dest, &c); +- else +- aport = get_client_port(&subs->info.sender, &c); ++ struct snd_seq_client *c __free(snd_seq_client) = NULL; ++ struct snd_seq_client_port *aport __free(snd_seq_port) = ++ is_src ? ++ get_client_port(&subs->info.dest, &c) : ++ get_client_port(&subs->info.sender, &c); + delete_and_unsubscribe_port(client, port, subs, is_src, false); + + if (!aport) { +diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c +index f5c0e401c8ae5..c0c5e1424c5a1 100644 +--- a/sound/core/seq/seq_queue.c ++++ b/sound/core/seq/seq_queue.c +@@ -211,8 +211,9 @@ struct snd_seq_queue *snd_seq_queue_find_name(char *name) + int i; + + for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { +- struct snd_seq_queue *q __free(snd_seq_queue) = NULL; +- q = queueptr(i); ++ struct snd_seq_queue *q __free(snd_seq_queue) = ++ queueptr(i); ++ + if (q) { + if (strncmp(q->name, name, sizeof(q->name)) == 0) + return no_free_ptr(q); +@@ -285,12 +286,13 @@ void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop) + int snd_seq_enqueue_event(struct snd_seq_event_cell *cell, int atomic, int hop) + { + int dest, err; +- struct snd_seq_queue *q __free(snd_seq_queue) = NULL; + + if (snd_BUG_ON(!cell)) + return -EINVAL; + dest = cell->event.queue; /* destination queue */ +- q = queueptr(dest); ++ ++ struct snd_seq_queue *q __free(snd_seq_queue) = ++ queueptr(dest); + if (q == NULL) + return -EINVAL; + /* handle relative time stamps, convert them into absolute */ +@@ -403,10 +405,10 @@ int snd_seq_queue_set_owner(int queueid, int client, int locked) + int snd_seq_queue_timer_open(int queueid) + { + int result = 0; +- struct snd_seq_queue *queue __free(snd_seq_queue) = NULL; + struct snd_seq_timer *tmr; ++ struct snd_seq_queue *queue __free(snd_seq_queue) = ++ queueptr(queueid); + +- queue = queueptr(queueid); + if (queue == NULL) + return -EINVAL; + tmr = queue->timer; +@@ -423,10 +425,10 @@ int snd_seq_queue_timer_open(int queueid) + */ + int snd_seq_queue_timer_close(int queueid) + { +- struct snd_seq_queue *queue __free(snd_seq_queue) = NULL; + int result = 0; ++ struct snd_seq_queue *queue __free(snd_seq_queue) = ++ queueptr(queueid); + +- queue = queueptr(queueid); + if (queue == NULL) + return -EINVAL; + snd_seq_timer_close(queue); +@@ -479,9 +481,9 @@ static void queue_use(struct snd_seq_queue *queue, int client, int use) + */ + int snd_seq_queue_use(int queueid, int client, int use) + { +- struct snd_seq_queue *queue __free(snd_seq_queue) = NULL; ++ struct snd_seq_queue *queue __free(snd_seq_queue) = ++ queueptr(queueid); + +- queue = queueptr(queueid); + if (queue == NULL) + return -EINVAL; + guard(mutex)(&queue->timer_mutex); +@@ -496,9 +498,9 @@ int snd_seq_queue_use(int queueid, int client, int use) + */ + int snd_seq_queue_is_used(int queueid, int client) + { +- struct snd_seq_queue *q __free(snd_seq_queue) = NULL; ++ struct snd_seq_queue *q __free(snd_seq_queue) = ++ queueptr(queueid); + +- q = queueptr(queueid); + if (q == NULL) + return -EINVAL; /* invalid queue */ + return test_bit(client, q->clients_bitmap) ? 1 : 0; +@@ -642,11 +644,11 @@ static void snd_seq_queue_process_event(struct snd_seq_queue *q, + */ + int snd_seq_control_queue(struct snd_seq_event *ev, int atomic, int hop) + { +- struct snd_seq_queue *q __free(snd_seq_queue) = NULL; +- + if (snd_BUG_ON(!ev)) + return -EINVAL; +- q = queueptr(ev->data.queue.queue); ++ ++ struct snd_seq_queue *q __free(snd_seq_queue) = ++ queueptr(ev->data.queue.queue); + + if (q == NULL) + return -EINVAL; +diff --git a/sound/core/seq/seq_ump_client.c b/sound/core/seq/seq_ump_client.c +index 27247babb16de..14b82a31eb195 100644 +--- a/sound/core/seq/seq_ump_client.c ++++ b/sound/core/seq/seq_ump_client.c +@@ -214,13 +214,13 @@ static bool skip_group(struct seq_ump_client *client, struct snd_ump_group *grou + static int seq_ump_group_init(struct seq_ump_client *client, int group_index) + { + struct snd_ump_group *group = &client->ump->groups[group_index]; +- struct snd_seq_port_info *port __free(kfree) = NULL; + struct snd_seq_port_callback pcallbacks; + + if (skip_group(client, group)) + return 0; + +- port = kzalloc(sizeof(*port), GFP_KERNEL); ++ struct snd_seq_port_info *port __free(kfree) = ++ kzalloc(sizeof(*port), GFP_KERNEL); + if (!port) + return -ENOMEM; + +@@ -243,12 +243,12 @@ static int seq_ump_group_init(struct seq_ump_client *client, int group_index) + /* update the sequencer ports; called from notify_fb_change callback */ + static void update_port_infos(struct seq_ump_client *client) + { +- struct snd_seq_port_info *old __free(kfree) = NULL; +- struct snd_seq_port_info *new __free(kfree) = NULL; + int i, err; + +- old = kzalloc(sizeof(*old), GFP_KERNEL); +- new = kzalloc(sizeof(*new), GFP_KERNEL); ++ struct snd_seq_port_info *old __free(kfree) = ++ kzalloc(sizeof(*old), GFP_KERNEL); ++ struct snd_seq_port_info *new __free(kfree) = ++ kzalloc(sizeof(*new), GFP_KERNEL); + if (!old || !new) + return; + +@@ -278,12 +278,12 @@ static void update_port_infos(struct seq_ump_client *client) + /* create a UMP Endpoint port */ + static int create_ump_endpoint_port(struct seq_ump_client *client) + { +- struct snd_seq_port_info *port __free(kfree) = NULL; + struct snd_seq_port_callback pcallbacks; + unsigned int rawmidi_info = client->ump->core.info_flags; + int err; + +- port = kzalloc(sizeof(*port), GFP_KERNEL); ++ struct snd_seq_port_info *port __free(kfree) = ++ kzalloc(sizeof(*port), GFP_KERNEL); + if (!port) + return -ENOMEM; + +diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c +index 9e7fd4993a108..574493fbd50d0 100644 +--- a/sound/core/seq/seq_virmidi.c ++++ b/sound/core/seq/seq_virmidi.c +@@ -361,13 +361,13 @@ static int snd_virmidi_dev_attach_seq(struct snd_virmidi_dev *rdev) + { + int client; + struct snd_seq_port_callback pcallbacks; +- struct snd_seq_port_info *pinfo __free(kfree) = NULL; + int err; + + if (rdev->client >= 0) + return 0; + +- pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL); ++ struct snd_seq_port_info *pinfo __free(kfree) = ++ kzalloc(sizeof(*pinfo), GFP_KERNEL); + if (!pinfo) + return -ENOMEM; + +-- +2.51.0 + diff --git a/queue-6.19/alsa-timer-relax-__free-variable-declarations.patch b/queue-6.19/alsa-timer-relax-__free-variable-declarations.patch new file mode 100644 index 0000000000..29c48030a3 --- /dev/null +++ b/queue-6.19/alsa-timer-relax-__free-variable-declarations.patch @@ -0,0 +1,81 @@ +From ada6bb1143b70d0fd234e20e2ae68dbd7f0fc11d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Dec 2025 15:06:29 +0100 +Subject: ALSA: timer: Relax __free() variable declarations + +From: Takashi Iwai + +[ Upstream commit b1bf8ac5319010e0f73183bdb78c1daf5552c8cb ] + +We used to have a variable declaration with __free() initialized with +NULL. This was to keep the old coding style rule, but recently it's +relaxed and rather recommends to follow the new rule to declare in +place of use for __free() -- which avoids potential deadlocks or UAFs +with nested cleanups. + +Although the current code has no bug, per se, let's follow the new +standard and move the declaration to the place of assignment (or +directly assign the allocated result) instead of NULL initializations. + +Fixes: ed96f6394e1b ("ALSA: timer: Use automatic cleanup of kfree()") +Fixes: 37745918e0e7 ("ALSA: timer: Introduce virtual userspace-driven timers") +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20251216140634.171890-8-tiwai@suse.de +Signed-off-by: Sasha Levin +--- + sound/core/timer.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/sound/core/timer.c b/sound/core/timer.c +index d9fff5c87613e..9a4a1748ff80b 100644 +--- a/sound/core/timer.c ++++ b/sound/core/timer.c +@@ -1614,12 +1614,12 @@ static int snd_timer_user_next_device(struct snd_timer_id __user *_tid) + static int snd_timer_user_ginfo(struct file *file, + struct snd_timer_ginfo __user *_ginfo) + { +- struct snd_timer_ginfo *ginfo __free(kfree) = NULL; + struct snd_timer_id tid; + struct snd_timer *t; + struct list_head *p; ++ struct snd_timer_ginfo *ginfo __free(kfree) = ++ memdup_user(_ginfo, sizeof(*ginfo)); + +- ginfo = memdup_user(_ginfo, sizeof(*ginfo)); + if (IS_ERR(ginfo)) + return PTR_ERR(ginfo); + +@@ -1756,7 +1756,6 @@ static int snd_timer_user_info(struct file *file, + struct snd_timer_info __user *_info) + { + struct snd_timer_user *tu; +- struct snd_timer_info *info __free(kfree) = NULL; + struct snd_timer *t; + + tu = file->private_data; +@@ -1766,7 +1765,8 @@ static int snd_timer_user_info(struct file *file, + if (!t) + return -EBADFD; + +- info = kzalloc(sizeof(*info), GFP_KERNEL); ++ struct snd_timer_info *info __free(kfree) = ++ kzalloc(sizeof(*info), GFP_KERNEL); + if (! info) + return -ENOMEM; + info->card = t->card ? t->card->number : -1; +@@ -2192,10 +2192,10 @@ static int snd_utimer_ioctl_create(struct file *file, + struct snd_timer_uinfo __user *_utimer_info) + { + struct snd_utimer *utimer; +- struct snd_timer_uinfo *utimer_info __free(kfree) = NULL; + int err, timer_fd; ++ struct snd_timer_uinfo *utimer_info __free(kfree) = ++ memdup_user(_utimer_info, sizeof(*utimer_info)); + +- utimer_info = memdup_user(_utimer_info, sizeof(*utimer_info)); + if (IS_ERR(utimer_info)) + return PTR_ERR(utimer_info); + +-- +2.51.0 + diff --git a/queue-6.19/alsa-usb-audio-relax-__free-variable-declarations.patch b/queue-6.19/alsa-usb-audio-relax-__free-variable-declarations.patch new file mode 100644 index 0000000000..a126fe1b3c --- /dev/null +++ b/queue-6.19/alsa-usb-audio-relax-__free-variable-declarations.patch @@ -0,0 +1,284 @@ +From 9724e6a5084dd043922aa6210e78de569f6a3281 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Dec 2025 15:06:33 +0100 +Subject: ALSA: usb-audio: Relax __free() variable declarations + +From: Takashi Iwai + +[ Upstream commit 03f705b9ca58b91c6dffe64875ea3d9a38cad9b5 ] + +We used to have a variable declaration with __free() initialized with +NULL. This was to keep the old coding style rule, but recently it's +relaxed and rather recommends to follow the new rule to declare in +place of use for __free() -- which avoids potential deadlocks or UAFs +with nested cleanups. + +Although the current code has no bug, per se, let's follow the new +standard and move the declaration to the place of assignment (or +directly assign the allocated result) instead of NULL initializations. + +Note that there are still a few remaining __free(kfree) with NULL +initializations; they are because of the code complexity (the data +size calculation). + +Fixes: 43d4940c944c ("ALSA: usb: scarlett2: Clean ups with guard() and __free()") +Fixes: 46757a3e7d50 ("ALSA: FCP: Add Focusrite Control Protocol driver") +Fixes: f7d306b47a24 ("ALSA: usb-audio: Fix a DMA to stack memory bug") +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20251216140634.171890-12-tiwai@suse.de +Signed-off-by: Sasha Levin +--- + sound/usb/fcp.c | 36 ++++++++++++++++++------------------ + sound/usb/mixer_scarlett2.c | 21 ++++++++++----------- + sound/usb/quirks.c | 13 ++++++------- + 3 files changed, 34 insertions(+), 36 deletions(-) + +diff --git a/sound/usb/fcp.c b/sound/usb/fcp.c +index 11e9a96b46ffe..1f4595d1e217f 100644 +--- a/sound/usb/fcp.c ++++ b/sound/usb/fcp.c +@@ -182,10 +182,6 @@ static int fcp_usb(struct usb_mixer_interface *mixer, u32 opcode, + { + struct fcp_data *private = mixer->private_data; + struct usb_device *dev = mixer->chip->dev; +- struct fcp_usb_packet *req __free(kfree) = NULL; +- struct fcp_usb_packet *resp __free(kfree) = NULL; +- size_t req_buf_size = struct_size(req, data, req_size); +- size_t resp_buf_size = struct_size(resp, data, resp_size); + int retries = 0; + const int max_retries = 5; + int err; +@@ -193,10 +189,14 @@ static int fcp_usb(struct usb_mixer_interface *mixer, u32 opcode, + if (!mixer->urb) + return -ENODEV; + ++ struct fcp_usb_packet *req __free(kfree) = NULL; ++ size_t req_buf_size = struct_size(req, data, req_size); + req = kmalloc(req_buf_size, GFP_KERNEL); + if (!req) + return -ENOMEM; + ++ struct fcp_usb_packet *resp __free(kfree) = NULL; ++ size_t resp_buf_size = struct_size(resp, data, resp_size); + resp = kmalloc(resp_buf_size, GFP_KERNEL); + if (!resp) + return -ENOMEM; +@@ -300,16 +300,17 @@ static int fcp_usb(struct usb_mixer_interface *mixer, u32 opcode, + static int fcp_reinit(struct usb_mixer_interface *mixer) + { + struct fcp_data *private = mixer->private_data; +- void *step0_resp __free(kfree) = NULL; +- void *step2_resp __free(kfree) = NULL; + + if (mixer->urb) + return 0; + +- step0_resp = kmalloc(private->step0_resp_size, GFP_KERNEL); ++ void *step0_resp __free(kfree) = ++ kmalloc(private->step0_resp_size, GFP_KERNEL); + if (!step0_resp) + return -ENOMEM; +- step2_resp = kmalloc(private->step2_resp_size, GFP_KERNEL); ++ ++ void *step2_resp __free(kfree) = ++ kmalloc(private->step2_resp_size, GFP_KERNEL); + if (!step2_resp) + return -ENOMEM; + +@@ -464,7 +465,6 @@ static int fcp_ioctl_init(struct usb_mixer_interface *mixer, + struct fcp_init init; + struct usb_device *dev = mixer->chip->dev; + struct fcp_data *private = mixer->private_data; +- void *resp __free(kfree) = NULL; + void *step2_resp; + int err, buf_size; + +@@ -485,7 +485,8 @@ static int fcp_ioctl_init(struct usb_mixer_interface *mixer, + /* Allocate response buffer */ + buf_size = init.step0_resp_size + init.step2_resp_size; + +- resp = kmalloc(buf_size, GFP_KERNEL); ++ void *resp __free(kfree) = ++ kmalloc(buf_size, GFP_KERNEL); + if (!resp) + return -ENOMEM; + +@@ -619,7 +620,6 @@ static int fcp_ioctl_set_meter_map(struct usb_mixer_interface *mixer, + { + struct fcp_meter_map map; + struct fcp_data *private = mixer->private_data; +- s16 *tmp_map __free(kfree) = NULL; + int err; + + if (copy_from_user(&map, arg, sizeof(map))) +@@ -641,7 +641,8 @@ static int fcp_ioctl_set_meter_map(struct usb_mixer_interface *mixer, + return -EINVAL; + + /* Allocate and copy the map data */ +- tmp_map = memdup_array_user(arg->map, map.map_size, sizeof(s16)); ++ s16 *tmp_map __free(kfree) = ++ memdup_array_user(arg->map, map.map_size, sizeof(s16)); + if (IS_ERR(tmp_map)) + return PTR_ERR(tmp_map); + +@@ -651,17 +652,16 @@ static int fcp_ioctl_set_meter_map(struct usb_mixer_interface *mixer, + + /* If the control doesn't exist, create it */ + if (!private->meter_ctl) { +- s16 *new_map __free(kfree) = NULL; +- __le32 *meter_levels __free(kfree) = NULL; +- + /* Allocate buffer for the map */ +- new_map = kmalloc_array(map.map_size, sizeof(s16), GFP_KERNEL); ++ s16 *new_map __free(kfree) = ++ kmalloc_array(map.map_size, sizeof(s16), GFP_KERNEL); + if (!new_map) + return -ENOMEM; + + /* Allocate buffer for reading meter levels */ +- meter_levels = kmalloc_array(map.meter_slots, sizeof(__le32), +- GFP_KERNEL); ++ __le32 *meter_levels __free(kfree) = ++ kmalloc_array(map.meter_slots, sizeof(__le32), ++ GFP_KERNEL); + if (!meter_levels) + return -ENOMEM; + +diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c +index bef8c9e544dd3..88b7e42d159e0 100644 +--- a/sound/usb/mixer_scarlett2.c ++++ b/sound/usb/mixer_scarlett2.c +@@ -2377,18 +2377,18 @@ static int scarlett2_usb( + { + struct scarlett2_data *private = mixer->private_data; + struct usb_device *dev = mixer->chip->dev; +- struct scarlett2_usb_packet *req __free(kfree) = NULL; +- struct scarlett2_usb_packet *resp __free(kfree) = NULL; +- size_t req_buf_size = struct_size(req, data, req_size); +- size_t resp_buf_size = struct_size(resp, data, resp_size); + int retries = 0; + const int max_retries = 5; + int err; + ++ struct scarlett2_usb_packet *req __free(kfree) = NULL; ++ size_t req_buf_size = struct_size(req, data, req_size); + req = kmalloc(req_buf_size, GFP_KERNEL); + if (!req) + return -ENOMEM; + ++ struct scarlett2_usb_packet *resp __free(kfree) = NULL; ++ size_t resp_buf_size = struct_size(resp, data, resp_size); + resp = kmalloc(resp_buf_size, GFP_KERNEL); + if (!resp) + return -ENOMEM; +@@ -3919,9 +3919,9 @@ static int scarlett2_input_select_ctl_info( + struct scarlett2_data *private = mixer->private_data; + int inputs = private->info->gain_input_count; + int i, err; +- char **values __free(kfree) = NULL; ++ char **values __free(kfree) = ++ kcalloc(inputs, sizeof(char *), GFP_KERNEL); + +- values = kcalloc(inputs, sizeof(char *), GFP_KERNEL); + if (!values) + return -ENOMEM; + +@@ -9083,8 +9083,6 @@ static long scarlett2_hwdep_read(struct snd_hwdep *hw, + __le32 len; + } __packed req; + +- u8 *resp __free(kfree) = NULL; +- + /* Flash segment must first be selected */ + if (private->flash_write_state != SCARLETT2_FLASH_WRITE_STATE_SELECTED) + return -EINVAL; +@@ -9122,7 +9120,8 @@ static long scarlett2_hwdep_read(struct snd_hwdep *hw, + req.offset = cpu_to_le32(*offset); + req.len = cpu_to_le32(count); + +- resp = kzalloc(count, GFP_KERNEL); ++ u8 *resp __free(kfree) = ++ kzalloc(count, GFP_KERNEL); + if (!resp) + return -ENOMEM; + +@@ -9267,7 +9266,6 @@ static ssize_t scarlett2_devmap_read( + loff_t pos) + { + struct usb_mixer_interface *mixer = entry->private_data; +- u8 *resp_buf __free(kfree) = NULL; + const size_t block_size = SCARLETT2_DEVMAP_BLOCK_SIZE; + size_t copied = 0; + +@@ -9277,7 +9275,8 @@ static ssize_t scarlett2_devmap_read( + if (pos + count > entry->size) + count = entry->size - pos; + +- resp_buf = kmalloc(block_size, GFP_KERNEL); ++ u8 *resp_buf __free(kfree) = ++ kmalloc(block_size, GFP_KERNEL); + if (!resp_buf) + return -ENOMEM; + +diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c +index 2d9f28558874c..4f9d19bf1ccac 100644 +--- a/sound/usb/quirks.c ++++ b/sound/usb/quirks.c +@@ -555,7 +555,6 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip, + static int snd_usb_extigy_boot_quirk(struct usb_device *dev, struct usb_interface *intf) + { + struct usb_host_config *config = dev->actconfig; +- struct usb_device_descriptor *new_device_descriptor __free(kfree) = NULL; + int err; + + if (le16_to_cpu(get_cfg_desc(config)->wTotalLength) == EXTIGY_FIRMWARE_SIZE_OLD || +@@ -566,8 +565,8 @@ static int snd_usb_extigy_boot_quirk(struct usb_device *dev, struct usb_interfac + 0x10, 0x43, 0x0001, 0x000a, NULL, 0); + if (err < 0) + dev_dbg(&dev->dev, "error sending boot message: %d\n", err); +- +- new_device_descriptor = kmalloc(sizeof(*new_device_descriptor), GFP_KERNEL); ++ struct usb_device_descriptor *new_device_descriptor __free(kfree) = ++ kmalloc(sizeof(*new_device_descriptor), GFP_KERNEL); + if (!new_device_descriptor) + return -ENOMEM; + err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, +@@ -910,7 +909,6 @@ static void mbox2_setup_48_24_magic(struct usb_device *dev) + static int snd_usb_mbox2_boot_quirk(struct usb_device *dev) + { + struct usb_host_config *config = dev->actconfig; +- struct usb_device_descriptor *new_device_descriptor __free(kfree) = NULL; + int err; + u8 bootresponse[0x12]; + int fwsize; +@@ -945,7 +943,8 @@ static int snd_usb_mbox2_boot_quirk(struct usb_device *dev) + + dev_dbg(&dev->dev, "device initialised!\n"); + +- new_device_descriptor = kmalloc(sizeof(*new_device_descriptor), GFP_KERNEL); ++ struct usb_device_descriptor *new_device_descriptor __free(kfree) = ++ kmalloc(sizeof(*new_device_descriptor), GFP_KERNEL); + if (!new_device_descriptor) + return -ENOMEM; + +@@ -1267,7 +1266,6 @@ static void mbox3_setup_defaults(struct usb_device *dev) + static int snd_usb_mbox3_boot_quirk(struct usb_device *dev) + { + struct usb_host_config *config = dev->actconfig; +- struct usb_device_descriptor *new_device_descriptor __free(kfree) = NULL; + int err; + int descriptor_size; + +@@ -1280,7 +1278,8 @@ static int snd_usb_mbox3_boot_quirk(struct usb_device *dev) + + dev_dbg(&dev->dev, "MBOX3: device initialised!\n"); + +- new_device_descriptor = kmalloc(sizeof(*new_device_descriptor), GFP_KERNEL); ++ struct usb_device_descriptor *new_device_descriptor __free(kfree) = ++ kmalloc(sizeof(*new_device_descriptor), GFP_KERNEL); + if (!new_device_descriptor) + return -ENOMEM; + +-- +2.51.0 + diff --git a/queue-6.19/alsa-usx2y-relax-__free-variable-declarations.patch b/queue-6.19/alsa-usx2y-relax-__free-variable-declarations.patch new file mode 100644 index 0000000000..7f4ad8f721 --- /dev/null +++ b/queue-6.19/alsa-usx2y-relax-__free-variable-declarations.patch @@ -0,0 +1,99 @@ +From 99401e57b28ce416d64ee4a1d138d133e53bc74d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Dec 2025 15:06:32 +0100 +Subject: ALSA: usx2y: Relax __free() variable declarations + +From: Takashi Iwai + +[ Upstream commit 43cc944c8e28d26f152198278f81cf7f9955ff85 ] + +We used to have a variable declaration with __free() initialized with +NULL. This was to keep the old coding style rule, but recently it's +relaxed and rather recommends to follow the new rule to declare in +place of use for __free() -- which avoids potential deadlocks or UAFs +with nested cleanups. + +Although the current code has no bug, per se, let's follow the new +standard and move the declaration to the place of assignment (or +directly assign the allocated result) instead of NULL initializations. + +Fixes: 67afec157fe6 ("ALSA: usb-audio: us144mkii: Add MIDI support and mixer controlsj") +Fixes: a2a2210f2c2e ("ALSA: usb-audio: us144mkii: Implement audio playback and feedback") +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20251216140634.171890-11-tiwai@suse.de +Signed-off-by: Sasha Levin +--- + sound/usb/usx2y/us144mkii.c | 4 ++-- + sound/usb/usx2y/us144mkii_controls.c | 4 ++-- + sound/usb/usx2y/us144mkii_pcm.c | 4 ++-- + 3 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/sound/usb/usx2y/us144mkii.c b/sound/usb/usx2y/us144mkii.c +index f6572a576c150..bc71968df8e2c 100644 +--- a/sound/usb/usx2y/us144mkii.c ++++ b/sound/usb/usx2y/us144mkii.c +@@ -412,7 +412,6 @@ static int tascam_probe(struct usb_interface *intf, + struct snd_card *card; + struct tascam_card *tascam; + int err; +- char *handshake_buf __free(kfree) = NULL; + + if (dev->speed != USB_SPEED_HIGH) + dev_info( +@@ -439,7 +438,8 @@ static int tascam_probe(struct usb_interface *intf, + return -ENOENT; + } + +- handshake_buf = kmalloc(1, GFP_KERNEL); ++ char *handshake_buf __free(kfree) = ++ kmalloc(1, GFP_KERNEL); + if (!handshake_buf) + return -ENOMEM; + +diff --git a/sound/usb/usx2y/us144mkii_controls.c b/sound/usb/usx2y/us144mkii_controls.c +index 5d69441ef414b..62055fb8e7bac 100644 +--- a/sound/usb/usx2y/us144mkii_controls.c ++++ b/sound/usb/usx2y/us144mkii_controls.c +@@ -373,7 +373,6 @@ static int tascam_samplerate_get(struct snd_kcontrol *kcontrol, + { + struct tascam_card *tascam = + (struct tascam_card *)snd_kcontrol_chip(kcontrol); +- u8 *buf __free(kfree) = NULL; + int err; + u32 rate = 0; + +@@ -384,7 +383,8 @@ static int tascam_samplerate_get(struct snd_kcontrol *kcontrol, + } + } + +- buf = kmalloc(3, GFP_KERNEL); ++ u8 *buf __free(kfree) = ++ kmalloc(3, GFP_KERNEL); + if (!buf) + return -ENOMEM; + +diff --git a/sound/usb/usx2y/us144mkii_pcm.c b/sound/usb/usx2y/us144mkii_pcm.c +index 0c84304d46246..03dfb1f388012 100644 +--- a/sound/usb/usx2y/us144mkii_pcm.c ++++ b/sound/usb/usx2y/us144mkii_pcm.c +@@ -115,7 +115,6 @@ void process_capture_routing_us144mkii(struct tascam_card *tascam, + int us144mkii_configure_device_for_rate(struct tascam_card *tascam, int rate) + { + struct usb_device *dev = tascam->dev; +- u8 *rate_payload_buf __free(kfree) = NULL; + u16 rate_vendor_wValue; + int err = 0; + const u8 *current_payload_src; +@@ -148,7 +147,8 @@ int us144mkii_configure_device_for_rate(struct tascam_card *tascam, int rate) + return -EINVAL; + } + +- rate_payload_buf = kmemdup(current_payload_src, 3, GFP_KERNEL); ++ u8 *rate_payload_buf __free(kfree) = ++ kmemdup(current_payload_src, 3, GFP_KERNEL); + if (!rate_payload_buf) + return -ENOMEM; + +-- +2.51.0 + diff --git a/queue-6.19/alsa-vmaster-relax-__free-variable-declarations.patch b/queue-6.19/alsa-vmaster-relax-__free-variable-declarations.patch new file mode 100644 index 0000000000..482fb63193 --- /dev/null +++ b/queue-6.19/alsa-vmaster-relax-__free-variable-declarations.patch @@ -0,0 +1,77 @@ +From 55a0601c51535dc8870d1be2420786228e298b75 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Dec 2025 15:06:30 +0100 +Subject: ALSA: vmaster: Relax __free() variable declarations + +From: Takashi Iwai + +[ Upstream commit 3b7c7bda39e1e48f926fb3d280a5f5d20a939857 ] + +We used to have a variable declaration with __free() initialized with +NULL. This was to keep the old coding style rule, but recently it's +relaxed and rather recommends to follow the new rule to declare in +place of use for __free() -- which avoids potential deadlocks or UAFs +with nested cleanups. + +Although the current code has no bug, per se, let's follow the new +standard and move the declaration to the place of assignment (or +directly assign the allocated result) instead of NULL initializations. + +Fixes: fb9e197f3f27 ("ALSA: vmaster: Use automatic cleanup of kfree()") +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20251216140634.171890-9-tiwai@suse.de +Signed-off-by: Sasha Levin +--- + sound/core/vmaster.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/sound/core/vmaster.c b/sound/core/vmaster.c +index c657659b236c4..76cc64245f5df 100644 +--- a/sound/core/vmaster.c ++++ b/sound/core/vmaster.c +@@ -56,10 +56,10 @@ struct link_follower { + + static int follower_update(struct link_follower *follower) + { +- struct snd_ctl_elem_value *uctl __free(kfree) = NULL; + int err, ch; ++ struct snd_ctl_elem_value *uctl __free(kfree) = ++ kzalloc(sizeof(*uctl), GFP_KERNEL); + +- uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); + if (!uctl) + return -ENOMEM; + uctl->id = follower->follower.id; +@@ -74,7 +74,6 @@ static int follower_update(struct link_follower *follower) + /* get the follower ctl info and save the initial values */ + static int follower_init(struct link_follower *follower) + { +- struct snd_ctl_elem_info *uinfo __free(kfree) = NULL; + int err; + + if (follower->info.count) { +@@ -84,7 +83,8 @@ static int follower_init(struct link_follower *follower) + return 0; + } + +- uinfo = kmalloc(sizeof(*uinfo), GFP_KERNEL); ++ struct snd_ctl_elem_info *uinfo __free(kfree) = ++ kmalloc(sizeof(*uinfo), GFP_KERNEL); + if (!uinfo) + return -ENOMEM; + uinfo->id = follower->follower.id; +@@ -341,9 +341,9 @@ static int master_get(struct snd_kcontrol *kcontrol, + static int sync_followers(struct link_master *master, int old_val, int new_val) + { + struct link_follower *follower; +- struct snd_ctl_elem_value *uval __free(kfree) = NULL; ++ struct snd_ctl_elem_value *uval __free(kfree) = ++ kmalloc(sizeof(*uval), GFP_KERNEL); + +- uval = kmalloc(sizeof(*uval), GFP_KERNEL); + if (!uval) + return -ENOMEM; + list_for_each_entry(follower, &master->followers, list) { +-- +2.51.0 + diff --git a/queue-6.19/amd-xgbe-do-not-select-net_selftests-when-inet-is-di.patch b/queue-6.19/amd-xgbe-do-not-select-net_selftests-when-inet-is-di.patch new file mode 100644 index 0000000000..020afd462b --- /dev/null +++ b/queue-6.19/amd-xgbe-do-not-select-net_selftests-when-inet-is-di.patch @@ -0,0 +1,42 @@ +From bf396d9a492731f70cf1f50dcdbbcd7d3b949c73 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 20:30:20 +0530 +Subject: amd-xgbe: do not select NET_SELFTESTS when INET is disabled + +From: Raju Rangoju + +[ Upstream commit ee9241524b4682a34ed4b66d8c68c33304810b93 ] + +AMD_XGBE currently selects NET_SELFTESTS unconditionally. Since select +does not honor dependencies, this can force-enable NET_SELFTESTS even +when INET is disabled (e.g. INET=n randconfig builds). + +Fixes build issue when INET is disabled. + +Fixes: 862a64c83faf ("amd-xgbe: introduce support ethtool selftest") +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202602030920.SWN7cwzT-lkp@intel.com/ +Signed-off-by: Raju Rangoju +Link: https://patch.msgid.link/20260204150020.883639-1-Raju.Rangoju@amd.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/amd/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/amd/Kconfig b/drivers/net/ethernet/amd/Kconfig +index d54dca3074eb6..45e8d698781c1 100644 +--- a/drivers/net/ethernet/amd/Kconfig ++++ b/drivers/net/ethernet/amd/Kconfig +@@ -165,7 +165,7 @@ config AMD_XGBE + select CRC32 + select PHYLIB + select AMD_XGBE_HAVE_ECC if X86 +- select NET_SELFTESTS ++ imply NET_SELFTESTS + help + This driver supports the AMD 10GbE Ethernet device found on an + AMD SoC. +-- +2.51.0 + diff --git a/queue-6.19/arm-dts-allwinner-sun5i-a13-utoo-p66-delete-power-gp.patch b/queue-6.19/arm-dts-allwinner-sun5i-a13-utoo-p66-delete-power-gp.patch new file mode 100644 index 0000000000..7f9fb49dc7 --- /dev/null +++ b/queue-6.19/arm-dts-allwinner-sun5i-a13-utoo-p66-delete-power-gp.patch @@ -0,0 +1,46 @@ +From 5fac0ab7157743cdfbadcc11f64397c0eb202c1a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 25 Dec 2025 18:36:14 +0800 +Subject: ARM: dts: allwinner: sun5i-a13-utoo-p66: delete "power-gpios" + property + +From: Chen-Yu Tsai + +[ Upstream commit 0b2761eb1287bd9f62367cccf6626eb3107cef6f ] + +The P66's device tree includes the reference design dtsi files, which +defines a node and properties for the touchpanel in the common design. +The P66 dts file then overrides all the properties to match its own +design, but as the touchpanel model is different, a different schema +is matched. This other schema uses a different name for the GPIO. + +The original submission added the correct GPIO property, but did not +delete the one inherited from the reference design, causing validation +errors. + +Explicitly delete the incorrect GPIO property. + +Fixes: 2a53aff27236 ("ARM: dts: sun5i: Enable touchscreen on Utoo P66") +Reviewed-by: Jernej Skrabec +Link: https://patch.msgid.link/20251225103616.3203473-4-wens@kernel.org +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Sasha Levin +--- + arch/arm/boot/dts/allwinner/sun5i-a13-utoo-p66.dts | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/boot/dts/allwinner/sun5i-a13-utoo-p66.dts b/arch/arm/boot/dts/allwinner/sun5i-a13-utoo-p66.dts +index be486d28d04fa..428cab5a0e906 100644 +--- a/arch/arm/boot/dts/allwinner/sun5i-a13-utoo-p66.dts ++++ b/arch/arm/boot/dts/allwinner/sun5i-a13-utoo-p66.dts +@@ -102,6 +102,7 @@ &touchscreen { + /* The P66 uses a different EINT then the reference design */ + interrupts = <6 9 IRQ_TYPE_EDGE_FALLING>; /* EINT9 (PG9) */ + /* The icn8318 binding expects wake-gpios instead of power-gpios */ ++ /delete-property/ power-gpios; + wake-gpios = <&pio 1 3 GPIO_ACTIVE_HIGH>; /* PB3 */ + touchscreen-size-x = <800>; + touchscreen-size-y = <480>; +-- +2.51.0 + diff --git a/queue-6.19/arm-dts-lpc32xx-add-clocks-property-to-motor-control.patch b/queue-6.19/arm-dts-lpc32xx-add-clocks-property-to-motor-control.patch new file mode 100644 index 0000000000..6512b97970 --- /dev/null +++ b/queue-6.19/arm-dts-lpc32xx-add-clocks-property-to-motor-control.patch @@ -0,0 +1,35 @@ +From 8e5c173e3e13a1bff6e77092c3ef30a1a3af6cbd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Dec 2025 00:49:07 +0200 +Subject: arm: dts: lpc32xx: add clocks property to Motor Control PWM device + tree node + +From: Vladimir Zapolskiy + +[ Upstream commit 71630e581a0e34c03757f5c1706f57c853b92555 ] + +Motor Control PWM depends on its own supply clock, the clock gate control +is present in TIMCLK_CTRL1 register. + +Fixes: b7d41c937ed7 ("ARM: LPC32xx: Add the motor PWM to base dts file") +Signed-off-by: Vladimir Zapolskiy +Signed-off-by: Sasha Levin +--- + arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi +index 2236901a00313..8e9ed93da129e 100644 +--- a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi ++++ b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi +@@ -302,6 +302,7 @@ i2c2: i2c@400a8000 { + mpwm: pwm@400e8000 { + compatible = "nxp,lpc3220-motor-pwm"; + reg = <0x400e8000 0x78>; ++ clocks = <&clk LPC32XX_CLK_MCPWM>; + #pwm-cells = <3>; + status = "disabled"; + }; +-- +2.51.0 + diff --git a/queue-6.19/arm-vdso-patch-out-__vdso_clock_getres-if-unavailabl.patch b/queue-6.19/arm-vdso-patch-out-__vdso_clock_getres-if-unavailabl.patch new file mode 100644 index 0000000000..45b44ee6e3 --- /dev/null +++ b/queue-6.19/arm-vdso-patch-out-__vdso_clock_getres-if-unavailabl.patch @@ -0,0 +1,39 @@ +From 803069e3466f64a2b6b01f12f67b1b1d1bffc0cc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 23 Dec 2025 07:59:17 +0100 +Subject: ARM: VDSO: Patch out __vdso_clock_getres() if unavailable +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh + +[ Upstream commit b9fecf0dddfc55cd7d02b0011494da3c613f7cde ] + +The vDSO code hides symbols which are non-functional. +__vdso_clock_getres() was not added to this list when it got introduced. + +Fixes: 052e76a31b4a ("ARM: 8931/1: Add clock_getres entry point") +Signed-off-by: Thomas Weißschuh +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20251223-vdso-compat-time32-v1-6-97ea7a06a543@linutronix.de +Signed-off-by: Sasha Levin +--- + arch/arm/kernel/vdso.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/kernel/vdso.c b/arch/arm/kernel/vdso.c +index e38a30477f3d7..566c40f0f7c77 100644 +--- a/arch/arm/kernel/vdso.c ++++ b/arch/arm/kernel/vdso.c +@@ -161,6 +161,7 @@ static void __init patch_vdso(void *ehdr) + vdso_nullpatch_one(&einfo, "__vdso_gettimeofday"); + vdso_nullpatch_one(&einfo, "__vdso_clock_gettime"); + vdso_nullpatch_one(&einfo, "__vdso_clock_gettime64"); ++ vdso_nullpatch_one(&einfo, "__vdso_clock_getres"); + } + } + +-- +2.51.0 + diff --git a/queue-6.19/arm64-dts-amlogic-axg-assign-the-mmc-signal-clocks.patch b/queue-6.19/arm64-dts-amlogic-axg-assign-the-mmc-signal-clocks.patch new file mode 100644 index 0000000000..9e18c3e9c5 --- /dev/null +++ b/queue-6.19/arm64-dts-amlogic-axg-assign-the-mmc-signal-clocks.patch @@ -0,0 +1,52 @@ +From 6a95ccce8dda858fb42fdcd27c613210f8241583 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:08:50 +0100 +Subject: arm64: dts: amlogic: axg: assign the MMC signal clocks + +From: Jerome Brunet + +[ Upstream commit 13d3fe2318ef6e46d6fcfe13bc373827fdf2aeac ] + +The amlogic MMC driver operate with the assumption that MMC clock +is configured to provide 24MHz. It uses this path for low +rates such as 400kHz. + +Assign the clocks to make sure they are properly configured + +Fixes: 221cf34bac54 ("ARM64: dts: meson-axg: enable the eMMC controller") +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Link: https://patch.msgid.link/20260114-amlogic-mmc-clocks-followup-v1-3-a999fafbe0aa@baylibre.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-axg.dtsi | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi +index e95c91894968b..cc72491eaf6f5 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi +@@ -1960,6 +1960,9 @@ sd_emmc_b: mmc@5000 { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_B>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_B_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + sd_emmc_c: mmc@7000 { +@@ -1972,6 +1975,9 @@ sd_emmc_c: mmc@7000 { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_C>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_C_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + nfc: nand-controller@7800 { +-- +2.51.0 + diff --git a/queue-6.19/arm64-dts-amlogic-c3-assign-the-mmc-signal-clocks.patch b/queue-6.19/arm64-dts-amlogic-c3-assign-the-mmc-signal-clocks.patch new file mode 100644 index 0000000000..f27878b160 --- /dev/null +++ b/queue-6.19/arm64-dts-amlogic-c3-assign-the-mmc-signal-clocks.patch @@ -0,0 +1,53 @@ +From 1f5057e3fd53cb58e47a07615d612e7400429c54 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:08:48 +0100 +Subject: arm64: dts: amlogic: c3: assign the MMC signal clocks + +From: Jerome Brunet + +[ Upstream commit 69330fd2368371c4eb47d60ace6bca09763d24a0 ] + +The amlogic MMC driver operate with the assumption that MMC clock +is configured to provide 24MHz. It uses this path for low +rates such as 400kHz. + +Assign the clocks to make sure they are properly configured + +Fixes: 520b792e8317 ("arm64: dts: amlogic: add some device nodes for C3") +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Link: https://patch.msgid.link/20260114-amlogic-mmc-clocks-followup-v1-1-a999fafbe0aa@baylibre.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi b/arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi +index 13b7ac03f9b20..885d9d64e9e4e 100644 +--- a/arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi ++++ b/arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi +@@ -969,6 +969,10 @@ sdio: mmc@88000 { + no-sd; + resets = <&reset RESET_SD_EMMC_A>; + status = "disabled"; ++ ++ assigned-clocks = <&clkc_periphs CLKID_SD_EMMC_A>; ++ assigned-clock-rates = <24000000>; ++ + }; + + sd: mmc@8a000 { +@@ -984,6 +988,9 @@ sd: mmc@8a000 { + no-sdio; + resets = <&reset RESET_SD_EMMC_B>; + status = "disabled"; ++ ++ assigned-clocks = <&clkc_periphs CLKID_SD_EMMC_B>; ++ assigned-clock-rates = <24000000>; + }; + + nand: nand-controller@8d000 { +-- +2.51.0 + diff --git a/queue-6.19/arm64-dts-amlogic-g12-assign-the-mmc-a-signal-clock.patch b/queue-6.19/arm64-dts-amlogic-g12-assign-the-mmc-a-signal-clock.patch new file mode 100644 index 0000000000..f6bcc86644 --- /dev/null +++ b/queue-6.19/arm64-dts-amlogic-g12-assign-the-mmc-a-signal-clock.patch @@ -0,0 +1,42 @@ +From e69af8c72e431cbcb0b0d19e7c69dbd453b658d8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:08:53 +0100 +Subject: arm64: dts: amlogic: g12: assign the MMC A signal clock + +From: Jerome Brunet + +[ Upstream commit 3c941feaa363f1573a501452391ddf513394c84b ] + +The amlogic MMC driver operate with the assumption that MMC clock +is configured to provide 24MHz. It uses this path for low +rates such as 400kHz. + +Assign the clock to make sure it is properly configured + +Fixes: 8a6b3ca2d361 ("arm64: dts: meson: g12a: add SDIO controller") +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Link: https://patch.msgid.link/20260114-amlogic-mmc-clocks-followup-v1-6-a999fafbe0aa@baylibre.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +index 0085612cf7351..00609d2da6743 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +@@ -2431,6 +2431,9 @@ sd_emmc_a: mmc@ffe03000 { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_A>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_A_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + sd_emmc_b: mmc@ffe05000 { +-- +2.51.0 + diff --git a/queue-6.19/arm64-dts-amlogic-g12-assign-the-mmc-b-and-c-signal-.patch b/queue-6.19/arm64-dts-amlogic-g12-assign-the-mmc-b-and-c-signal-.patch new file mode 100644 index 0000000000..b328888d98 --- /dev/null +++ b/queue-6.19/arm64-dts-amlogic-g12-assign-the-mmc-b-and-c-signal-.patch @@ -0,0 +1,52 @@ +From ed93d698a764742cccac428dd57292c774a5eb63 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:08:52 +0100 +Subject: arm64: dts: amlogic: g12: assign the MMC B and C signal clocks + +From: Jerome Brunet + +[ Upstream commit be2ff5fdb0e83e32d4ec4e68a69875cec0d14621 ] + +The amlogic MMC driver operate with the assumption that MMC clock +is configured to provide 24MHz. It uses this path for low +rates such as 400kHz. + +Assign the clocks to make sure they are properly configured + +Fixes: 4759fd87b928 ("arm64: dts: meson: g12a: add mmc nodes") +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Link: https://patch.msgid.link/20260114-amlogic-mmc-clocks-followup-v1-5-a999fafbe0aa@baylibre.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +index ca455f634834b..0085612cf7351 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +@@ -2443,6 +2443,9 @@ sd_emmc_b: mmc@ffe05000 { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_B>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_B_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + sd_emmc_c: mmc@ffe07000 { +@@ -2455,6 +2458,9 @@ sd_emmc_c: mmc@ffe07000 { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_C>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_C_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + usb: usb@ffe09000 { +-- +2.51.0 + diff --git a/queue-6.19/arm64-dts-amlogic-gx-assign-the-mmc-signal-clocks.patch b/queue-6.19/arm64-dts-amlogic-gx-assign-the-mmc-signal-clocks.patch new file mode 100644 index 0000000000..b6428a611a --- /dev/null +++ b/queue-6.19/arm64-dts-amlogic-gx-assign-the-mmc-signal-clocks.patch @@ -0,0 +1,97 @@ +From 029b3edf82e11accb556a87cd3703e100bff2643 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:08:51 +0100 +Subject: arm64: dts: amlogic: gx: assign the MMC signal clocks + +From: Jerome Brunet + +[ Upstream commit 406706559046eebc09a31e8ae5e78620bfd746fe ] + +The amlogic MMC driver operate with the assumption that MMC clock +is configured to provide 24MHz. It uses this path for low +rates such as 400kHz. + +Assign the clocks to make sure they are properly configured + +Fixes: 50662499f911 ("ARM64: dts: meson-gx: Use correct mmc clock source 0") +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Link: https://patch.msgid.link/20260114-amlogic-mmc-clocks-followup-v1-4-a999fafbe0aa@baylibre.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 9 +++++++++ + arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 9 +++++++++ + 2 files changed, 18 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi +index f69923da07feb..a9c830a570cc6 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi +@@ -824,6 +824,9 @@ &sd_emmc_a { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_A>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_A_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &sd_emmc_b { +@@ -832,6 +835,9 @@ &sd_emmc_b { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_B>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_B_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &sd_emmc_c { +@@ -840,6 +846,9 @@ &sd_emmc_c { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_C>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_C_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &simplefb_hdmi { +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi +index ba535010a3c91..e202d84f06720 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi +@@ -894,6 +894,9 @@ &sd_emmc_a { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_A>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_A_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &sd_emmc_b { +@@ -902,6 +905,9 @@ &sd_emmc_b { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_B>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_B_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &sd_emmc_c { +@@ -910,6 +916,9 @@ &sd_emmc_c { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_C>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_C_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &simplefb_hdmi { +-- +2.51.0 + diff --git a/queue-6.19/arm64-dts-amlogic-meson-sm1-odroid-eliminate-odroid-.patch b/queue-6.19/arm64-dts-amlogic-meson-sm1-odroid-eliminate-odroid-.patch new file mode 100644 index 0000000000..6e5676650c --- /dev/null +++ b/queue-6.19/arm64-dts-amlogic-meson-sm1-odroid-eliminate-odroid-.patch @@ -0,0 +1,109 @@ +From cb0923ee779802616258c9b0803768791016d363 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 23:02:20 -0500 +Subject: arm64: dts: amlogic: meson-sm1-odroid: Eliminate Odroid HC4 power + glitches during boot. + +From: Eric Neulight + +[ Upstream commit 436418ef5baa024b7b15dd730c36d651c6aaaf47 ] + +Fix issue with Odroid HC4 (and all meson-sm1-odroid) DTS that causes +regulator power to momentarily glitch OFF-ON during boot. Add +regulator-boot-on to all regulator-fixed and regulator-gpio entries +that (1) define a gpio AND (2) define regulator-always-on. + +U-boot powers on devices necessary for boot then hands off the DTB to +the kernel. During probe, linux drivers/regulator/fixed.c and +gpio-regulator.c both first set the regulator control gpio (that U-boot +already turned ON) to default OFF before then setting it to the defined +(ON) state. This glitches the power to the affected devices, unless +regulator-boot-on is specified with it. In fact, U-boot has the same +behavior. So, during reboot, a power glitch can actually happen twice: +once when U-boot reads the DTB and probes the gpio and again when the +kernel reads the DTB and probes the gpio. + +Problem this fixes: On the Odroid HC4, power to the SATA ports glitches +during boot and causes some HDDs to do emergency head retract, which +should be avoided. On the HC4, power glitches to the SD card, USB, +SATA, and HDMI interfaces during boot. These are all boot devices. +A power glitch can potentially cause a problem for any sensitive devices +during boot. + +NOTE: This is not limited to just the HC4, likely an issue with ALL DTS +with regulator-fixed or regulator-gpio entries that (1) define a gpio +AND (2) define regulator-always-on. All such entries should also +include regulator-boot-on in order to avoid potential power glitches. +At worst, adding regulator-boot-on in such cases is harmless because of +regulator-always-on, and, at best, it eliminates detrimental power +glitches during boot. So, this is best-practice. + +Fixes: 164147f094ec5d0fc2c2098a888f4b50cf3096a7 ("arm64: dts: meson-sm1-odroid-hc4: add regulators controlled by GPIOH_8") +Fixes: 45d736ab17b44257e15e75e0dba364139fdb0983 ("arm64: dts: meson-sm1-odroid: add 5v regulator gpio") +Fixes: 1f80a5cf74a60997b92d2cde772edec093bec4d9 ("arm64: dts: meson-sm1-odroid: add missing enable gpio and supply for tf_io regulator") +Fixes: 88d537bc92ca035e2a9920b0abc750dd62146520 ("arm64: dts: meson: convert meson-sm1-odroid-c4 to dtsi") + +Signed-off-by: Eric Neulight +Reviewed-by: Neil Armstrong +Acked-by: Viacheslav Bocharov +Tested-by: Ricardo Pardini # on Odroid-HC4 5V HDD +Link: https://patch.msgid.link/20260116-odroid-hc4-dts-v1-1-459b601cd5cf@linuxdev.slmail.me +[narmstrong: fixed subject prefix] +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-sm1-odroid-hc4.dts | 2 ++ + arch/arm64/boot/dts/amlogic/meson-sm1-odroid.dtsi | 3 +++ + 2 files changed, 5 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-sm1-odroid-hc4.dts b/arch/arm64/boot/dts/amlogic/meson-sm1-odroid-hc4.dts +index 0170139b8d32f..3ece30a0a1fff 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-sm1-odroid-hc4.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-sm1-odroid-hc4.dts +@@ -52,6 +52,7 @@ p12v_0: regulator-p12v-0 { + + gpio = <&gpio GPIOH_8 GPIO_OPEN_DRAIN>; + enable-active-high; ++ regulator-boot-on; + regulator-always-on; + }; + +@@ -65,6 +66,7 @@ p12v_1: regulator-p12v-1 { + + gpio = <&gpio GPIOH_8 GPIO_OPEN_DRAIN>; + enable-active-high; ++ regulator-boot-on; + regulator-always-on; + }; + +diff --git a/arch/arm64/boot/dts/amlogic/meson-sm1-odroid.dtsi b/arch/arm64/boot/dts/amlogic/meson-sm1-odroid.dtsi +index c4524eb4f0996..0bce4e8d965f2 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-sm1-odroid.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-sm1-odroid.dtsi +@@ -37,6 +37,7 @@ tflash_vdd: regulator-tflash-vdd { + + gpio = <&gpio_ao GPIOAO_3 GPIO_OPEN_DRAIN>; + enable-active-high; ++ regulator-boot-on; + regulator-always-on; + }; + +@@ -50,6 +51,7 @@ tf_io: gpio-regulator-tf-io { + + enable-gpios = <&gpio_ao GPIOE_2 GPIO_OPEN_DRAIN>; + enable-active-high; ++ regulator-boot-on; + regulator-always-on; + + gpios = <&gpio_ao GPIOAO_6 GPIO_OPEN_SOURCE>; +@@ -81,6 +83,7 @@ vcc_5v: regulator-vcc-5v { + regulator-name = "5V"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; ++ regulator-boot-on; + regulator-always-on; + vin-supply = <&main_12v>; + gpio = <&gpio GPIOH_8 GPIO_OPEN_DRAIN>; +-- +2.51.0 + diff --git a/queue-6.19/arm64-dts-amlogic-s4-assign-mmc-b-clock-to-24mhz.patch b/queue-6.19/arm64-dts-amlogic-s4-assign-mmc-b-clock-to-24mhz.patch new file mode 100644 index 0000000000..e787dc0a51 --- /dev/null +++ b/queue-6.19/arm64-dts-amlogic-s4-assign-mmc-b-clock-to-24mhz.patch @@ -0,0 +1,51 @@ +From e8ef33b3f4ab38f865d38cbd557f10b9a235319c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 11:43:11 +0100 +Subject: arm64: dts: amlogic: s4: assign mmc b clock to 24MHz + +From: Jerome Brunet + +[ Upstream commit 86124a8becb43eed3103f2459399daee8af2c99d ] + +The amlogic MMC driver operate with the assumption that MMC clock +is configured to provide 24MHz. It uses this path for low +rates such as 400kHz. + +This assumption did hold true until but it now, but it is apparently +not the case with s4. The clock has been reported to provide 1GHz +instead. This is most likely due to how the bootloader is using the MMC +clock on this platform. + +Regardless of why the MMC clock rate is 1GHz, if the MMC driver expects +24MHz, the clock should be properly assigned, so assign it. + +Reported-by: Nick Xie +Closes: https://lore.kernel.org/linux-amlogic/20260113011931.40424-1-nick@khadas.com/ +Fixes: 3ab9d54b5d84 ("arm64: dts: amlogic: enable some device nodes for S4") +Tested-by: Nick Xie +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Link: https://patch.msgid.link/20260114-amlogic-s4-mmc-fixup-v3-1-a4d3e136b3f2@baylibre.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-s4.dtsi | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-s4.dtsi b/arch/arm64/boot/dts/amlogic/meson-s4.dtsi +index 9d99ed2994dfa..f314f07062abe 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-s4.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-s4.dtsi +@@ -838,6 +838,9 @@ sd: mmc@fe08a000 { + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_B>; + status = "disabled"; ++ ++ assigned-clocks = <&clkc_periphs CLKID_SD_EMMC_B>; ++ assigned-clock-rates = <24000000>; + }; + + emmc: mmc@fe08c000 { +-- +2.51.0 + diff --git a/queue-6.19/arm64-dts-amlogic-s4-fix-mmc-clock-assignment.patch b/queue-6.19/arm64-dts-amlogic-s4-fix-mmc-clock-assignment.patch new file mode 100644 index 0000000000..8befc8c17e --- /dev/null +++ b/queue-6.19/arm64-dts-amlogic-s4-fix-mmc-clock-assignment.patch @@ -0,0 +1,70 @@ +From 7049d2b243322132394033c92b196b39387168de Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 11:43:12 +0100 +Subject: arm64: dts: amlogic: s4: fix mmc clock assignment + +From: Jerome Brunet + +[ Upstream commit 3a115d42922cffc91b303992eadf220111d66c31 ] + +MMC A and C are mis-represented as having their "clkin0" input connected to +xtal while it is actually connected to the MMC clock, probably in an +attempt to provide 24MHz to the device on this input. + +Fix this and assign the clock to 24MHz to actually provide the required +rate. + +Fixes: 3ab9d54b5d84 ("arm64: dts: amlogic: enable some device nodes for S4") +Tested-by: Nick Xie +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Link: https://patch.msgid.link/20260114-amlogic-s4-mmc-fixup-v3-2-a4d3e136b3f2@baylibre.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-s4.dtsi | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-s4.dtsi b/arch/arm64/boot/dts/amlogic/meson-s4.dtsi +index f314f07062abe..dfc0a30a6e61b 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-s4.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-s4.dtsi +@@ -819,13 +819,16 @@ sdio: mmc@fe088000 { + reg = <0x0 0xfe088000 0x0 0x800>; + interrupts = ; + clocks = <&clkc_periphs CLKID_SDEMMC_A>, +- <&xtal>, ++ <&clkc_periphs CLKID_SD_EMMC_A>, + <&clkc_pll CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_A>; + cap-sdio-irq; + keep-power-in-suspend; + status = "disabled"; ++ ++ assigned-clocks = <&clkc_periphs CLKID_SD_EMMC_A>; ++ assigned-clock-rates = <24000000>; + }; + + sd: mmc@fe08a000 { +@@ -848,13 +851,16 @@ emmc: mmc@fe08c000 { + reg = <0x0 0xfe08c000 0x0 0x800>; + interrupts = ; + clocks = <&clkc_periphs CLKID_NAND>, +- <&xtal>, ++ <&clkc_periphs CLKID_SD_EMMC_C>, + <&clkc_pll CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_NAND_EMMC>; + no-sdio; + no-sd; + status = "disabled"; ++ ++ assigned-clocks = <&clkc_periphs CLKID_SD_EMMC_C>; ++ assigned-clock-rates = <24000000>; + }; + }; + }; +-- +2.51.0 + diff --git a/queue-6.19/arm64-dts-imx95-use-gpu_cgc-as-core-clock-for-gpu.patch b/queue-6.19/arm64-dts-imx95-use-gpu_cgc-as-core-clock-for-gpu.patch new file mode 100644 index 0000000000..1873b22093 --- /dev/null +++ b/queue-6.19/arm64-dts-imx95-use-gpu_cgc-as-core-clock-for-gpu.patch @@ -0,0 +1,57 @@ +From 91f8da0b48fa63e8dc650985389940e0a52c404d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 29 Nov 2025 15:31:30 +0100 +Subject: arm64: dts: imx95: Use GPU_CGC as core clock for GPU + +From: Marek Vasut + +[ Upstream commit fc61fdfdc4dd03fa5cea784e1969ed3df049c6c8 ] + +The i.MX95 imx-sm introduced new GPU_CGC clock since imx-sm commit +ca5e078833fa ("SM-128: Add clock management via CCM LPCG direct control") +which are downstream clock of GPU clock. These new GPU_CGC clock +gate the existing GPU clock. Currently, without clk_ignore_unused +on kernel command line, those new GPU_CGC clock are unused and the +kernel will disable them. This has no impact on i.MX95 A0/A1, but +does prevent GPU register access from working at all on i.MX95 B0. +The GPU_CGC clock are present on both i.MX95 A0/A1/B0, therefore +update the DT such, that the GPU core clock are the GPU_CGC clock. +When the panthor driver enables the GPU core clock, it enables both +the GPU_CGC as well as its parent GPU clock. + +Fixes: 67934f248e64 ("arm64: dts: imx95: Describe Mali G310 GPU") +Signed-off-by: Marek Vasut +Signed-off-by: Shawn Guo +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx95-clock.h | 1 + + arch/arm64/boot/dts/freescale/imx95.dtsi | 2 +- + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx95-clock.h b/arch/arm64/boot/dts/freescale/imx95-clock.h +index e1f91203e7947..22311612e4403 100644 +--- a/arch/arm64/boot/dts/freescale/imx95-clock.h ++++ b/arch/arm64/boot/dts/freescale/imx95-clock.h +@@ -183,5 +183,6 @@ + #define IMX95_CLK_SEL_A55P (IMX95_CCM_NUM_CLK_SRC + 123 + 7) + #define IMX95_CLK_SEL_DRAM (IMX95_CCM_NUM_CLK_SRC + 123 + 8) + #define IMX95_CLK_SEL_TEMPSENSE (IMX95_CCM_NUM_CLK_SRC + 123 + 9) ++#define IMX95_CLK_GPU_CGC (IMX95_CCM_NUM_CLK_SRC + 123 + 10) + + #endif /* __CLOCK_IMX95_H */ +diff --git a/arch/arm64/boot/dts/freescale/imx95.dtsi b/arch/arm64/boot/dts/freescale/imx95.dtsi +index a4d8548175594..55e2da094c889 100644 +--- a/arch/arm64/boot/dts/freescale/imx95.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx95.dtsi +@@ -2164,7 +2164,7 @@ netc_emdio: mdio@0,0 { + gpu: gpu@4d900000 { + compatible = "nxp,imx95-mali", "arm,mali-valhall-csf"; + reg = <0 0x4d900000 0 0x480000>; +- clocks = <&scmi_clk IMX95_CLK_GPU>, <&scmi_clk IMX95_CLK_GPUAPB>; ++ clocks = <&scmi_clk IMX95_CLK_GPU_CGC>, <&scmi_clk IMX95_CLK_GPUAPB>; + clock-names = "core", "coregroup"; + interrupts = , + , +-- +2.51.0 + diff --git a/queue-6.19/arm64-dts-mediatek-mt8183-jacuzzi-pico6-fix-typo-in-.patch b/queue-6.19/arm64-dts-mediatek-mt8183-jacuzzi-pico6-fix-typo-in-.patch new file mode 100644 index 0000000000..51f4a038c7 --- /dev/null +++ b/queue-6.19/arm64-dts-mediatek-mt8183-jacuzzi-pico6-fix-typo-in-.patch @@ -0,0 +1,36 @@ +From 566a6525a4a9982776809cdae0b49991ffa986d5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 12:47:41 +0100 +Subject: arm64: dts: mediatek: mt8183-jacuzzi-pico6: Fix typo in pinmux node + +From: AngeloGioacchino Del Regno + +[ Upstream commit b1fc81a986c9b8089db31e21a372cc8b6514e900 ] + +Rename "piins-bt-wakeup" to "pins-bt-wakeup" to fix a dtbs_check +warning happening due to this typo. + +Fixes: 055ef10ccdd4 ("arm64: dts: mt8183: Add jacuzzi pico/pico6 board") +Reviewed-by: Chen-Yu Tsai +Signed-off-by: AngeloGioacchino Del Regno +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-pico6.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-pico6.dts b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-pico6.dts +index cce326aec1aa5..40af5656d6f15 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-pico6.dts ++++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-pico6.dts +@@ -91,7 +91,7 @@ bluetooth@2 { + + &pio { + bt_pins_wakeup: bt-pins-wakeup { +- piins-bt-wakeup { ++ pins-bt-wakeup { + pinmux = ; + input-enable; + }; +-- +2.51.0 + diff --git a/queue-6.19/arm64-dts-qcom-agatti-add-cx_mem-dbgc-gpu-regions.patch b/queue-6.19/arm64-dts-qcom-agatti-add-cx_mem-dbgc-gpu-regions.patch new file mode 100644 index 0000000000..8296923b22 --- /dev/null +++ b/queue-6.19/arm64-dts-qcom-agatti-add-cx_mem-dbgc-gpu-regions.patch @@ -0,0 +1,49 @@ +From 713c14e6baf13e107ae8c25be6265a2a002c174e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Dec 2025 21:47:40 +0100 +Subject: arm64: dts: qcom: agatti: Add CX_MEM/DBGC GPU regions + +From: Konrad Dybcio + +[ Upstream commit 0fdcc948929a6d673bd0f90631dd6e42090c3dbd ] + +Describe the GPU register regions, with the former existing but not +being used much if at all on this silicon, and the latter containing +various debugging levers generally related to dumping the state of +the IP upon a crash. + +Fixes: 4faeef52c8e6 ("arm64: dts: qcom: qcm2290: Add GPU nodes") +Reported-by: Krzysztof Kozlowski +Closes: https://lore.kernel.org/linux-arm-msm/8a64f70b-8034-45e7-86a3-0015cf357132@oss.qualcomm.com/T/#m404f1425c36b61467760f058b696b8910340a063 +Signed-off-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Akhil P Oommen +Link: https://lore.kernel.org/r/20251229-topic-6115_2290_gpu_dbgc-v1-2-4a24d196389c@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/agatti.dtsi | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/agatti.dtsi b/arch/arm64/boot/dts/qcom/agatti.dtsi +index 8bf5c5583fc22..969ae1378db2c 100644 +--- a/arch/arm64/boot/dts/qcom/agatti.dtsi ++++ b/arch/arm64/boot/dts/qcom/agatti.dtsi +@@ -1591,8 +1591,12 @@ usb_dwc3_ss: endpoint { + + gpu: gpu@5900000 { + compatible = "qcom,adreno-07000200", "qcom,adreno"; +- reg = <0x0 0x05900000 0x0 0x40000>; +- reg-names = "kgsl_3d0_reg_memory"; ++ reg = <0x0 0x05900000 0x0 0x40000>, ++ <0x0 0x0599e000 0x0 0x1000>, ++ <0x0 0x05961000 0x0 0x800>; ++ reg-names = "kgsl_3d0_reg_memory", ++ "cx_mem", ++ "cx_dbgc"; + + interrupts = ; + +-- +2.51.0 + diff --git a/queue-6.19/arm64-dts-qcom-msm8994-octagon-fix-analog-devices-ve.patch b/queue-6.19/arm64-dts-qcom-msm8994-octagon-fix-analog-devices-ve.patch new file mode 100644 index 0000000000..d7846580fa --- /dev/null +++ b/queue-6.19/arm64-dts-qcom-msm8994-octagon-fix-analog-devices-ve.patch @@ -0,0 +1,43 @@ +From aee8376239de68a5a21c28537e30acad22d91c30 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Dec 2025 02:39:23 +0200 +Subject: arm64: dts: qcom: msm8994-octagon: Fix Analog Devices vendor prefix + of AD7147 + +From: Vladimir Zapolskiy + +[ Upstream commit 7db5fbe508deedec6c183d5056cf3c504c027f40 ] + +Trivial change, Analog Devices vendor prefix is "adi", but there is +a valid "ad" vendor prefix of another company, this may explain why +the issue hasn't been discovered by the automatic tests. + +A problem of not described compatible value is out of this change scope. + +Fixes: c636eeb751f6 ("arm64: dts: qcom: msm8994-octagon: Add AD7147 and APDS9930 sensors") +Signed-off-by: Vladimir Zapolskiy +Reviewed-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20251226003923.3341904-1-vladimir.zapolskiy@linaro.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/msm8994-msft-lumia-octagon.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/msm8994-msft-lumia-octagon.dtsi b/arch/arm64/boot/dts/qcom/msm8994-msft-lumia-octagon.dtsi +index 4c983b10dd925..7ace3540ef0a0 100644 +--- a/arch/arm64/boot/dts/qcom/msm8994-msft-lumia-octagon.dtsi ++++ b/arch/arm64/boot/dts/qcom/msm8994-msft-lumia-octagon.dtsi +@@ -378,7 +378,7 @@ &blsp2_i2c1 { + status = "okay"; + + sideinteraction: touch@2c { +- compatible = "ad,ad7147_captouch"; ++ compatible = "adi,ad7147_captouch"; + reg = <0x2c>; + + pinctrl-names = "default", "sleep"; +-- +2.51.0 + diff --git a/queue-6.19/arm64-dts-qcom-qrb4210-rb2-fix-uart3-wakeup-irq-stor.patch b/queue-6.19/arm64-dts-qcom-qrb4210-rb2-fix-uart3-wakeup-irq-stor.patch new file mode 100644 index 0000000000..586f9c30ef --- /dev/null +++ b/queue-6.19/arm64-dts-qcom-qrb4210-rb2-fix-uart3-wakeup-irq-stor.patch @@ -0,0 +1,43 @@ +From 005ae45135d2bff75b3349970014df6ad58abeb7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Jan 2026 03:01:16 +0200 +Subject: arm64: dts: qcom: qrb4210-rb2: Fix UART3 wakeup IRQ storm + +From: Dmitry Baryshkov + +[ Upstream commit c5dc4812f6bf397b82290c540085e9ec98b47b30 ] + +Follow commit 9c92d36b0b1e ("arm64: dts: qcom: qrb2210-rb1: Fix UART3 +wakeup IRQ storm") and apply the similar fix to the RB2 platform. + +Having RX / TX pins as pull up and wakup interrupt as high-level +triggered generates an interrupt storm when trying to suspend the +device. Avoid the storm by using the falling edge trigger (as all other +platforms do). + +Fixes: cab60b166575 ("arm64: dts: qcom: qrb4210-rb2: Enable bluetooth") +Reviewed-by: Konrad Dybcio +Signed-off-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260106-wcn3990-pwrctl-v2-6-0386204328be@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/qrb4210-rb2.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts b/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts +index 0cd36c54632fa..5f8613150bdd2 100644 +--- a/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts ++++ b/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts +@@ -694,7 +694,7 @@ sdc2_card_det_n: sd-card-det-n-state { + + &uart3 { + interrupts-extended = <&intc GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH>, +- <&tlmm 11 IRQ_TYPE_LEVEL_HIGH>; ++ <&tlmm 11 IRQ_TYPE_EDGE_FALLING>; + pinctrl-0 = <&uart3_default>; + pinctrl-1 = <&uart3_sleep>; + pinctrl-names = "default", "sleep"; +-- +2.51.0 + diff --git a/queue-6.19/arm64-dts-qcom-sdm630-fix-gpu_speed_bin-size.patch b/queue-6.19/arm64-dts-qcom-sdm630-fix-gpu_speed_bin-size.patch new file mode 100644 index 0000000000..e7f0567d4c --- /dev/null +++ b/queue-6.19/arm64-dts-qcom-sdm630-fix-gpu_speed_bin-size.patch @@ -0,0 +1,49 @@ +From dc8774980577ddf768fe504993c904fea57db07b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 11 Dec 2025 03:27:45 +0200 +Subject: arm64: dts: qcom: sdm630: fix gpu_speed_bin size + +From: Dmitry Baryshkov + +[ Upstream commit e814796dfcae8905682ac3ac2dd57f512a9f6726 ] + +Historically sdm630.dtsi has used 1 byte length for the gpu_speed_bin +cell, although it spans two bytes (offset 5, size 7 bits). It was being +accepted by the kernel because before the commit 7a06ef751077 ("nvmem: +core: fix bit offsets of more than one byte") the kernel didn't have +length check. After this commit nvmem core rejects QFPROM on sdm630 / +sdm660, making GPU and USB unusable on those platforms. + +Set the size of the gpu_speed_bin cell to 2 bytes, fixing the parsing +error. While we are at it, update the length to 8 bits as pointed out by +Alexey Minnekhanov. + +Fixes: b190fb010664 ("arm64: dts: qcom: sdm630: Add sdm630 dts file") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Reviewed-by: Alexey Minnekhanov +Link: https://lore.kernel.org/r/20251211-sdm630-fix-gpu-v2-1-92f0e736dba0@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm630.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/sdm630.dtsi b/arch/arm64/boot/dts/qcom/sdm630.dtsi +index 8b1a45a4e56ed..b383e480a394d 100644 +--- a/arch/arm64/boot/dts/qcom/sdm630.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm630.dtsi +@@ -598,8 +598,8 @@ qusb2_hstx_trim: hstx-trim@240 { + }; + + gpu_speed_bin: gpu-speed-bin@41a0 { +- reg = <0x41a2 0x1>; +- bits = <5 7>; ++ reg = <0x41a2 0x2>; ++ bits = <5 8>; + }; + }; + +-- +2.51.0 + diff --git a/queue-6.19/arm64-dts-qcom-sdm845-db845c-drop-cs-from-spio0.patch b/queue-6.19/arm64-dts-qcom-sdm845-db845c-drop-cs-from-spio0.patch new file mode 100644 index 0000000000..112790570b --- /dev/null +++ b/queue-6.19/arm64-dts-qcom-sdm845-db845c-drop-cs-from-spio0.patch @@ -0,0 +1,40 @@ +From 44f497cc977e212c19efa6eddeed419706cc6d91 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Jan 2026 03:01:17 +0200 +Subject: arm64: dts: qcom: sdm845-db845c: drop CS from SPIO0 + +From: Dmitry Baryshkov + +[ Upstream commit 8bfb696ccdc5bcfad7a45b84c2c8a36757070e19 ] + +On SDM845 SPI uses hardware-provided chip select, while specifying +cs-gpio makes the driver request GPIO pin, which on DB845c conflicts +with the normal host controllers pinctrl entry. + +Drop the cs-gpios property to restore SPI functionality. + +Fixes: cb29e7106d4e ("arm64: dts: qcom: db845c: Add support for MCP2517FD") +Reviewed-by: Konrad Dybcio +Signed-off-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260106-wcn3990-pwrctl-v2-7-0386204328be@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm845-db845c.dts | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts +index ce23f87e0316b..ad283a79bcdb4 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts ++++ b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts +@@ -850,7 +850,6 @@ &spi0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&qup_spi0_default>; +- cs-gpios = <&tlmm 3 GPIO_ACTIVE_LOW>; + + can@0 { + compatible = "microchip,mcp2517fd"; +-- +2.51.0 + diff --git a/queue-6.19/arm64-dts-qcom-sdm845-db845c-specify-power-for-wifi-.patch b/queue-6.19/arm64-dts-qcom-sdm845-db845c-specify-power-for-wifi-.patch new file mode 100644 index 0000000000..2531103521 --- /dev/null +++ b/queue-6.19/arm64-dts-qcom-sdm845-db845c-specify-power-for-wifi-.patch @@ -0,0 +1,50 @@ +From 8989200ad0c26b8e18b738b879b7a504870c44e2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Jan 2026 03:01:18 +0200 +Subject: arm64: dts: qcom: sdm845-db845c: specify power for WiFi CH1 + +From: Dmitry Baryshkov + +[ Upstream commit c303e89f7f17c29981d09f8beaaf60937ae8b1f2 ] + +Specify power supply for the second chain / antenna output of the +onboard WiFi chip. + +Fixes: 3f72e2d3e682 ("arm64: dts: qcom: Add Dragonboard 845c") +Reviewed-by: Konrad Dybcio +Signed-off-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260106-wcn3990-pwrctl-v2-8-0386204328be@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm845-db845c.dts | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts +index ad283a79bcdb4..5118b776a9bb3 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts ++++ b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts +@@ -379,6 +379,12 @@ vreg_l21a_2p95: ldo21 { + regulator-initial-mode = ; + }; + ++ vreg_l23a_3p3: ldo23 { ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3312000>; ++ regulator-initial-mode = ; ++ }; ++ + vreg_l24a_3p075: ldo24 { + regulator-min-microvolt = <3088000>; + regulator-max-microvolt = <3088000>; +@@ -1155,6 +1161,7 @@ &wifi { + vdd-1.8-xo-supply = <&vreg_l7a_1p8>; + vdd-1.3-rfa-supply = <&vreg_l17a_1p3>; + vdd-3.3-ch0-supply = <&vreg_l25a_3p3>; ++ vdd-3.3-ch1-supply = <&vreg_l23a_3p3>; + + qcom,snoc-host-cap-8bit-quirk; + qcom,calibration-variant = "Thundercomm_DB845C"; +-- +2.51.0 + diff --git a/queue-6.19/arm64-dts-qcom-sdm845-oneplus-don-t-keep-panel-regul.patch b/queue-6.19/arm64-dts-qcom-sdm845-oneplus-don-t-keep-panel-regul.patch new file mode 100644 index 0000000000..a9aec79ab9 --- /dev/null +++ b/queue-6.19/arm64-dts-qcom-sdm845-oneplus-don-t-keep-panel-regul.patch @@ -0,0 +1,39 @@ +From 369050d496fcfd0d05f6ba42fcbfd163b9fad2b2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 18 Nov 2025 15:52:26 +0100 +Subject: arm64: dts: qcom: sdm845-oneplus: Don't keep panel regulator always + on + +From: Casey Connolly + +[ Upstream commit 45d1f42d3e84b5880cf9fab1eb24a7818320eeb7 ] + +The panel regulator doesn't need to be always on, so remove this +property. + +Fixes: 288ef8a42612 ("arm64: dts: sdm845: add oneplus6/6t devices") +Signed-off-by: Casey Connolly +Signed-off-by: David Heidelberg +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251118-dts-oneplus-regulators-v2-2-3e67cea1e4e7@ixit.cz +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +index ee62adfa6af0b..5845bc3bb80b2 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +@@ -272,7 +272,6 @@ vreg_l14a_1p88: ldo14 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; +- regulator-always-on; + }; + + vreg_l17a_1p3: ldo17 { +-- +2.51.0 + diff --git a/queue-6.19/arm64-dts-qcom-sdm845-oneplus-don-t-mark-ts-supply-b.patch b/queue-6.19/arm64-dts-qcom-sdm845-oneplus-don-t-mark-ts-supply-b.patch new file mode 100644 index 0000000000..65331f9de4 --- /dev/null +++ b/queue-6.19/arm64-dts-qcom-sdm845-oneplus-don-t-mark-ts-supply-b.patch @@ -0,0 +1,39 @@ +From b6421178ec59c518a97ad42b51b741f3f7a3bf34 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 18 Nov 2025 15:52:25 +0100 +Subject: arm64: dts: qcom: sdm845-oneplus: Don't mark ts supply boot-on + +From: Casey Connolly + +[ Upstream commit c9b98b9dad9749bf2eb7336a6fca31a6af1039d7 ] + +The touchscreen isn't enabled by bootloader and doesn't need to be +enabled at boot, only when the driver probes, thus remove the +regulator-boot-on property. + +Fixes: 288ef8a42612 ("arm64: dts: sdm845: add oneplus6/6t devices") +Signed-off-by: Casey Connolly +Signed-off-by: David Heidelberg +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251118-dts-oneplus-regulators-v2-1-3e67cea1e4e7@ixit.cz +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +index db6dd04c51bb5..ee62adfa6af0b 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +@@ -148,7 +148,6 @@ ts_1p8_supply: ts-1p8-regulator { + + gpio = <&tlmm 88 0>; + enable-active-high; +- regulator-boot-on; + }; + + panel_vci_3v3: panel-vci-3v3-regulator { +-- +2.51.0 + diff --git a/queue-6.19/arm64-dts-qcom-sdm845-oneplus-mark-l14a-regulator-as.patch b/queue-6.19/arm64-dts-qcom-sdm845-oneplus-mark-l14a-regulator-as.patch new file mode 100644 index 0000000000..f55516144c --- /dev/null +++ b/queue-6.19/arm64-dts-qcom-sdm845-oneplus-mark-l14a-regulator-as.patch @@ -0,0 +1,38 @@ +From 739889cb628cea270bba5d0f94aa28a3d481ae9e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 18 Nov 2025 15:52:27 +0100 +Subject: arm64: dts: qcom: sdm845-oneplus: Mark l14a regulator as boot-on + +From: Casey Connolly + +[ Upstream commit ad33ee060be46794a03d033894c9db3a9d6c1a0f ] + +This regulator is used only for the display, which is enabled by the +bootloader and left on for continuous splash. Mark it as such. + +Fixes: 288ef8a42612 ("arm64: dts: sdm845: add oneplus6/6t devices") +Signed-off-by: Casey Connolly +Signed-off-by: David Heidelberg +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251118-dts-oneplus-regulators-v2-3-3e67cea1e4e7@ixit.cz +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +index 5845bc3bb80b2..8251f5a2f9475 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +@@ -272,6 +272,7 @@ vreg_l14a_1p88: ldo14 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; ++ regulator-boot-on; + }; + + vreg_l17a_1p3: ldo17 { +-- +2.51.0 + diff --git a/queue-6.19/arm64-dts-qcom-sdm850-huawei-matebook-e-2019-correct.patch b/queue-6.19/arm64-dts-qcom-sdm850-huawei-matebook-e-2019-correct.patch new file mode 100644 index 0000000000..115f559215 --- /dev/null +++ b/queue-6.19/arm64-dts-qcom-sdm850-huawei-matebook-e-2019-correct.patch @@ -0,0 +1,46 @@ +From 923cf83dab7fcfd5e989ca1e5cc026645aac4309 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Dec 2025 11:15:11 +0800 +Subject: arm64: dts: qcom: sdm850-huawei-matebook-e-2019: Correct ipa_fw_mem + for the driver to load successfully + +From: Jingzhou Zhu + +[ Upstream commit bc11f6f1d2470fa59846be077555f9d4b7c2c0d3 ] + +The ipa driver refuses to load with the old ipa_fw_mem in newer kernels. +Shrinking its size to 0x5a000 fixes the problem. + +Fixes: aab69794b55d ("arm64: dts: qcom: Add support for Huawei MateBook E 2019") + +Signed-off-by: Jingzhou Zhu +Link: https://lore.kernel.org/r/20251208031511.3284-3-newwheatzjz@zohomail.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm850-huawei-matebook-e-2019.dts | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/sdm850-huawei-matebook-e-2019.dts b/arch/arm64/boot/dts/qcom/sdm850-huawei-matebook-e-2019.dts +index a5f025ae7dbe6..f048653818702 100644 +--- a/arch/arm64/boot/dts/qcom/sdm850-huawei-matebook-e-2019.dts ++++ b/arch/arm64/boot/dts/qcom/sdm850-huawei-matebook-e-2019.dts +@@ -144,12 +144,12 @@ wlan_msa_mem: wlan-msa@8c400000 { + }; + + ipa_fw_mem: ipa-fw@8df00000 { +- reg = <0 0x8df00000 0 0x100000>; ++ reg = <0 0x8df00000 0 0x5a000>; + no-map; + }; + +- gpu_mem: gpu@97900000 { +- reg = <0 0x97900000 0 0x5000>; ++ gpu_mem: gpu@8df5a000 { ++ reg = <0 0x8df5a000 0 0x5000>; + no-map; + }; + +-- +2.51.0 + diff --git a/queue-6.19/arm64-dts-qcom-sdm850-huawei-matebook-e-2019-remove-.patch b/queue-6.19/arm64-dts-qcom-sdm850-huawei-matebook-e-2019-remove-.patch new file mode 100644 index 0000000000..3d856b76fc --- /dev/null +++ b/queue-6.19/arm64-dts-qcom-sdm850-huawei-matebook-e-2019-remove-.patch @@ -0,0 +1,61 @@ +From 676babd3ee55cdca903f8984576a67f85b8ce164 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Dec 2025 11:15:10 +0800 +Subject: arm64: dts: qcom: sdm850-huawei-matebook-e-2019: Remove duplicate + reserved-memroy nodes + +From: Jingzhou Zhu + +[ Upstream commit a499c40ccd8e748ef363e2d13fb7a5c0ed6a788a ] + +The adsp_mem and slpi_mem defined in sdm845.dtsi work well. Remove these +nodes here to avoid redefinition. + +Signed-off-by: Jingzhou Zhu +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20251208031511.3284-2-newwheatzjz@zohomail.com +Signed-off-by: Bjorn Andersson +Stable-dep-of: bc11f6f1d247 ("arm64: dts: qcom: sdm850-huawei-matebook-e-2019: Correct ipa_fw_mem for the driver to load successfully") +Signed-off-by: Sasha Levin +--- + .../boot/dts/qcom/sdm850-huawei-matebook-e-2019.dts | 11 ----------- + 1 file changed, 11 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/sdm850-huawei-matebook-e-2019.dts b/arch/arm64/boot/dts/qcom/sdm850-huawei-matebook-e-2019.dts +index 0ef9ea38a424a..a5f025ae7dbe6 100644 +--- a/arch/arm64/boot/dts/qcom/sdm850-huawei-matebook-e-2019.dts ++++ b/arch/arm64/boot/dts/qcom/sdm850-huawei-matebook-e-2019.dts +@@ -30,9 +30,7 @@ + /delete-node/ &ipa_fw_mem; + /delete-node/ &ipa_gsi_mem; + /delete-node/ &gpu_mem; +-/delete-node/ &adsp_mem; + /delete-node/ &wlan_msa_mem; +-/delete-node/ &slpi_mem; + + / { + model = "Huawei MateBook E 2019"; +@@ -145,20 +143,11 @@ wlan_msa_mem: wlan-msa@8c400000 { + no-map; + }; + +- adsp_mem: adsp@8c500000 { +- reg = <0 0x8c500000 0 0x1a00000>; +- no-map; +- }; +- + ipa_fw_mem: ipa-fw@8df00000 { + reg = <0 0x8df00000 0 0x100000>; + no-map; + }; + +- slpi_mem: slpi@96700000 { +- reg = <0 0x96700000 0 0x1200000>; +- }; +- + gpu_mem: gpu@97900000 { + reg = <0 0x97900000 0 0x5000>; + no-map; +-- +2.51.0 + diff --git a/queue-6.19/arm64-dts-qcom-sm6115-add-cx_mem-dbgc-gpu-regions.patch b/queue-6.19/arm64-dts-qcom-sm6115-add-cx_mem-dbgc-gpu-regions.patch new file mode 100644 index 0000000000..c428be5a2b --- /dev/null +++ b/queue-6.19/arm64-dts-qcom-sm6115-add-cx_mem-dbgc-gpu-regions.patch @@ -0,0 +1,49 @@ +From b1253608a426de4c04536cb2f348270a5d58a7b0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Dec 2025 21:47:41 +0100 +Subject: arm64: dts: qcom: sm6115: Add CX_MEM/DBGC GPU regions + +From: Konrad Dybcio + +[ Upstream commit 78c13dac18cf0e6f6cbc6ea85d4f967e6cca9562 ] + +Describe the GPU register regions, with the former existing but not +being used much if at all on this silicon, and the latter containing +various debugging levers generally related to dumping the state of +the IP upon a crash. + +Fixes: 11750af256f8 ("arm64: dts: qcom: sm6115: Add GPU nodes") +Reported-by: Krzysztof Kozlowski +Closes: https://lore.kernel.org/linux-arm-msm/8a64f70b-8034-45e7-86a3-0015cf357132@oss.qualcomm.com/T/#m404f1425c36b61467760f058b696b8910340a063 +Signed-off-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Akhil P Oommen +Link: https://lore.kernel.org/r/20251229-topic-6115_2290_gpu_dbgc-v1-3-4a24d196389c@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm6115.dtsi | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm6115.dtsi b/arch/arm64/boot/dts/qcom/sm6115.dtsi +index 5e2032c26ea38..4dba724f2c756 100644 +--- a/arch/arm64/boot/dts/qcom/sm6115.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm6115.dtsi +@@ -1715,8 +1715,12 @@ usb_dwc3_ss: endpoint { + + gpu: gpu@5900000 { + compatible = "qcom,adreno-610.0", "qcom,adreno"; +- reg = <0x0 0x05900000 0x0 0x40000>; +- reg-names = "kgsl_3d0_reg_memory"; ++ reg = <0x0 0x05900000 0x0 0x40000>, ++ <0x0 0x0599e000 0x0 0x1000>, ++ <0x0 0x05961000 0x0 0x800>; ++ reg-names = "kgsl_3d0_reg_memory", ++ "cx_mem", ++ "cx_dbgc"; + + /* There's no (real) GMU, so we have to handle quite a bunch of clocks! */ + clocks = <&gpucc GPU_CC_GX_GFX3D_CLK>, +-- +2.51.0 + diff --git a/queue-6.19/arm64-dts-qcom-sm8150-hdk-mtp-specify-zap-firmware-n.patch b/queue-6.19/arm64-dts-qcom-sm8150-hdk-mtp-specify-zap-firmware-n.patch new file mode 100644 index 0000000000..f92e40f252 --- /dev/null +++ b/queue-6.19/arm64-dts-qcom-sm8150-hdk-mtp-specify-zap-firmware-n.patch @@ -0,0 +1,58 @@ +From 46ea47bf526baa6ca3d4358dcd2bd5b8a24ecf15 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 13 Dec 2025 11:28:00 +0200 +Subject: arm64: dts: qcom: sm8150-hdk,mtp: specify ZAP firmware name + +From: Dmitry Baryshkov + +[ Upstream commit d43019ef200d567454a8f68e60a5b2df01d8c706 ] + +The DT file has GPU node enabled, but doesn't specify the file name of +the ZAP firmware, which means using a default file name. Specify the +name to the ZAP shader firmware, pointing to the file in the +linux-firmware repo. + +Fixes: f30ac26def18 ("arm64: dts: qcom: add sm8150 GPU nodes") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251213-zap-names-v1-1-c889af173911@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8150-hdk.dts | 4 ++++ + arch/arm64/boot/dts/qcom/sm8150-mtp.dts | 4 ++++ + 2 files changed, 8 insertions(+) + +diff --git a/arch/arm64/boot/dts/qcom/sm8150-hdk.dts b/arch/arm64/boot/dts/qcom/sm8150-hdk.dts +index 0339a572f34d0..1eea9c5c66847 100644 +--- a/arch/arm64/boot/dts/qcom/sm8150-hdk.dts ++++ b/arch/arm64/boot/dts/qcom/sm8150-hdk.dts +@@ -387,6 +387,10 @@ &gpu { + status = "okay"; + }; + ++&gpu_zap_shader { ++ firmware-name = "qcom/sm8150/a640_zap.mbn"; ++}; ++ + &i2c4 { + clock-frequency = <100000>; + +diff --git a/arch/arm64/boot/dts/qcom/sm8150-mtp.dts b/arch/arm64/boot/dts/qcom/sm8150-mtp.dts +index 12e8e1ada6d8b..0f2d511624a8b 100644 +--- a/arch/arm64/boot/dts/qcom/sm8150-mtp.dts ++++ b/arch/arm64/boot/dts/qcom/sm8150-mtp.dts +@@ -358,6 +358,10 @@ &gpu { + status = "okay"; + }; + ++&gpu_zap_shader { ++ firmware-name = "qcom/sm8150/a640_zap.mbn"; ++}; ++ + &pon { + mode-bootloader = <0x2>; + mode-recovery = <0x1>; +-- +2.51.0 + diff --git a/queue-6.19/arm64-dts-qcom-sm8250-hdk-specify-zap-firmware-name.patch b/queue-6.19/arm64-dts-qcom-sm8250-hdk-specify-zap-firmware-name.patch new file mode 100644 index 0000000000..a2cc8bde85 --- /dev/null +++ b/queue-6.19/arm64-dts-qcom-sm8250-hdk-specify-zap-firmware-name.patch @@ -0,0 +1,42 @@ +From cf7b15f62822f6b91e1528feb16af5f4ee6472d0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 13 Dec 2025 11:28:01 +0200 +Subject: arm64: dts: qcom: sm8250-hdk: specify ZAP firmware name + +From: Dmitry Baryshkov + +[ Upstream commit 95c121244a5d46435559bc74dbc7b5519394db08 ] + +The DT file has GPU node enabled, but doesn't specify the file name of +the ZAP firmware, which means using a default file name. Specify the +name to the ZAP shader firmware, pointing to the file in the +linux-firmware repo. + +Fixes: 04a3605b184e ("arm64: dts: qcom: add sm8250 GPU nodes") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251213-zap-names-v1-2-c889af173911@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8250-hdk.dts | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/arm64/boot/dts/qcom/sm8250-hdk.dts b/arch/arm64/boot/dts/qcom/sm8250-hdk.dts +index f5c193c6c5f9b..3ea9d2b1a7d58 100644 +--- a/arch/arm64/boot/dts/qcom/sm8250-hdk.dts ++++ b/arch/arm64/boot/dts/qcom/sm8250-hdk.dts +@@ -373,6 +373,10 @@ &gpu { + status = "okay"; + }; + ++&gpu_zap_shader { ++ firmware-name = "qcom/sm8250/a650_zap.mbn"; ++}; ++ + &pon { + mode-bootloader = <0x2>; + mode-recovery = <0x1>; +-- +2.51.0 + diff --git a/queue-6.19/arm64-dts-qcom-talos-drop-opp-shared-from-qup-opp-ta.patch b/queue-6.19/arm64-dts-qcom-talos-drop-opp-shared-from-qup-opp-ta.patch new file mode 100644 index 0000000000..dd519b840b --- /dev/null +++ b/queue-6.19/arm64-dts-qcom-talos-drop-opp-shared-from-qup-opp-ta.patch @@ -0,0 +1,43 @@ +From 85b8806e53aac7ef22f0566e4f8e16ffc3879867 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 11 Nov 2025 22:33:50 +0530 +Subject: arm64: dts: qcom: talos: Drop opp-shared from QUP OPP table + +From: Viken Dadhaniya + +[ Upstream commit dda4bdd325326dd67ae4401f4f3d35b9cf781e3f ] + +QUP devices are currently marked with opp-shared in their OPP table, +causing the kernel to treat them as part of a shared OPP domain. This +leads to the qcom_geni_serial driver failing to probe with error +-EBUSY (-16). + +Remove the opp-shared property to ensure the OPP framework treats the +QUP OPP table as device-specific, allowing the serial driver to probe +successfully + +Fixes: f6746dc9e379 ("arm64: dts: qcom: qcs615: Add QUPv3 configuration") +Signed-off-by: Viken Dadhaniya +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251111170350.525832-1-viken.dadhaniya@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/talos.dtsi | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/talos.dtsi b/arch/arm64/boot/dts/qcom/talos.dtsi +index 95d26e3136229..3ef21bae31742 100644 +--- a/arch/arm64/boot/dts/qcom/talos.dtsi ++++ b/arch/arm64/boot/dts/qcom/talos.dtsi +@@ -537,7 +537,6 @@ cdsp_smp2p_in: slave-kernel { + + qup_opp_table: opp-table-qup { + compatible = "operating-points-v2"; +- opp-shared; + + opp-75000000 { + opp-hz = /bits/ 64 <75000000>; +-- +2.51.0 + diff --git a/queue-6.19/arm64-dts-qcom-x1e-bus-is-40-bits-fix-64gb-models.patch b/queue-6.19/arm64-dts-qcom-x1e-bus-is-40-bits-fix-64gb-models.patch new file mode 100644 index 0000000000..f2fd5f2f83 --- /dev/null +++ b/queue-6.19/arm64-dts-qcom-x1e-bus-is-40-bits-fix-64gb-models.patch @@ -0,0 +1,42 @@ +From e39e90bf8545393d315de7b3f0ad32df6b8b2942 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Nov 2025 16:29:42 -0500 +Subject: arm64: dts: qcom: x1e: bus is 40-bits (fix 64GB models) + +From: Jonathan Marek + +[ Upstream commit b38dd256e11a4c8bd5a893e11fc42d493939c907 ] + +Unlike the phone SoCs this was copied from, x1e has a 40-bit physical bus. +The upper address space is used to support more than 32GB of memory. + +This fixes issues when DMA buffers are allocated outside the 36-bit range. + +Fixes: af16b00578a7 ("arm64: dts: qcom: Add base X1E80100 dtsi and the QCP dts") +Signed-off-by: Jonathan Marek +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251127212943.24480-1-jonathan@marek.ca +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/hamoa.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/hamoa.dtsi b/arch/arm64/boot/dts/qcom/hamoa.dtsi +index 9c9e567731556..83a0a0c3239d2 100644 +--- a/arch/arm64/boot/dts/qcom/hamoa.dtsi ++++ b/arch/arm64/boot/dts/qcom/hamoa.dtsi +@@ -791,8 +791,8 @@ soc: soc@0 { + + #address-cells = <2>; + #size-cells = <2>; +- dma-ranges = <0 0 0 0 0x10 0>; +- ranges = <0 0 0 0 0x10 0>; ++ dma-ranges = <0 0 0 0 0x100 0>; ++ ranges = <0 0 0 0 0x100 0>; + + gcc: clock-controller@100000 { + compatible = "qcom,x1e80100-gcc"; +-- +2.51.0 + diff --git a/queue-6.19/arm64-dts-qcom-x1e80100-fix-usb-combo-phys-ss1-and-s.patch b/queue-6.19/arm64-dts-qcom-x1e80100-fix-usb-combo-phys-ss1-and-s.patch new file mode 100644 index 0000000000..5989ef4870 --- /dev/null +++ b/queue-6.19/arm64-dts-qcom-x1e80100-fix-usb-combo-phys-ss1-and-s.patch @@ -0,0 +1,61 @@ +From e5c372912e1360bb0c8a058475197c6704d09162 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 3 Nov 2025 18:51:40 +0200 +Subject: arm64: dts: qcom: x1e80100: Fix USB combo PHYs SS1 and SS2 ref clocks + +From: Abel Vesa + +[ Upstream commit 3af51501e2b8c87564b5cda43b0e5c316cf54717 ] + +It seems the USB combo SS1 and SS2 ref clocks have another gate, unlike +the SS0. These gates are part of the TCSR clock controller. + +At least on Dell XPS 13 (9345), if the ref clock provided by the TCSR +clock controller for SS1 PHY is disabled on the clk_disable_unused late +initcall, the PHY fails to initialize. It doesn't happen on the SS0 PHY +and the SS2 is not used on this device. + +This doesn't seem to be a problem on CRD though. It might be that the +RPMh has a vote for it from some other consumer and does not actually +disable it when ther kernel drops its vote. + +Either way, these TCSR provided clocks seem to be the correct ones for +the SS1 and SS2, so use them instead. + +Fixes: 4af46b7bd66f ("arm64: dts: qcom: x1e80100: Add USB nodes") +Signed-off-by: Abel Vesa +Reviewed-by: Neil Armstrong +Reviewed-by: Taniya Das +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251103-dts-qcom-x1e80100-fix-combo-ref-clks-v1-1-f395ec3cb7e8@linaro.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/hamoa.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/hamoa.dtsi b/arch/arm64/boot/dts/qcom/hamoa.dtsi +index a17900eacb203..9c9e567731556 100644 +--- a/arch/arm64/boot/dts/qcom/hamoa.dtsi ++++ b/arch/arm64/boot/dts/qcom/hamoa.dtsi +@@ -2937,7 +2937,7 @@ usb_1_ss1_qmpphy: phy@fda000 { + reg = <0 0x00fda000 0 0x4000>; + + clocks = <&gcc GCC_USB3_SEC_PHY_AUX_CLK>, +- <&rpmhcc RPMH_CXO_CLK>, ++ <&tcsr TCSR_USB4_1_CLKREF_EN>, + <&gcc GCC_USB3_SEC_PHY_COM_AUX_CLK>, + <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>; + clock-names = "aux", +@@ -3008,7 +3008,7 @@ usb_1_ss2_qmpphy: phy@fdf000 { + reg = <0 0x00fdf000 0 0x4000>; + + clocks = <&gcc GCC_USB3_TERT_PHY_AUX_CLK>, +- <&rpmhcc RPMH_CXO_CLK>, ++ <&tcsr TCSR_USB4_2_CLKREF_EN>, + <&gcc GCC_USB3_TERT_PHY_COM_AUX_CLK>, + <&gcc GCC_USB3_TERT_PHY_PIPE_CLK>; + clock-names = "aux", +-- +2.51.0 + diff --git a/queue-6.19/arm64-dts-renesas-r9a09g047e57-smarc-remove-duplicat.patch b/queue-6.19/arm64-dts-renesas-r9a09g047e57-smarc-remove-duplicat.patch new file mode 100644 index 0000000000..06aaf291ce --- /dev/null +++ b/queue-6.19/arm64-dts-renesas-r9a09g047e57-smarc-remove-duplicat.patch @@ -0,0 +1,34 @@ +From 28e01f777e248f969176c0b7dc261d73e7518290 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 25 Nov 2025 17:52:06 +0100 +Subject: arm64: dts: renesas: r9a09g047e57-smarc: Remove duplicate SW_LCD_EN + +From: Geert Uytterhoeven + +[ Upstream commit 44cfd102ce28e749a07bb0f1668cf932077b1175 ] + +SW_LCD_EN is defined twice. + +Fixes: 9e95446b0cf93a91 ("arm64: dts: renesas: r9a09g047e57-smarc: Add gpio keys") +Signed-off-by: Geert Uytterhoeven +Link: https://patch.msgid.link/1f93558c62f4461f50935644ec831a7d2cb52630.1764089463.git.geert+renesas@glider.be +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/renesas/r9a09g047e57-smarc.dts | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/renesas/r9a09g047e57-smarc.dts b/arch/arm64/boot/dts/renesas/r9a09g047e57-smarc.dts +index 08e814c03fa85..ed6fcdc337a0b 100644 +--- a/arch/arm64/boot/dts/renesas/r9a09g047e57-smarc.dts ++++ b/arch/arm64/boot/dts/renesas/r9a09g047e57-smarc.dts +@@ -8,7 +8,6 @@ + /dts-v1/; + + /* Switch selection settings */ +-#define SW_LCD_EN 0 + #define SW_GPIO8_CAN0_STB 0 + #define SW_GPIO9_CAN1_STB 0 + #define SW_LCD_EN 0 +-- +2.51.0 + diff --git a/queue-6.19/arm64-dts-renesas-rzt2h-n2h-evk-common-use-gpio-for-.patch b/queue-6.19/arm64-dts-renesas-rzt2h-n2h-evk-common-use-gpio-for-.patch new file mode 100644 index 0000000000..8a9785425a --- /dev/null +++ b/queue-6.19/arm64-dts-renesas-rzt2h-n2h-evk-common-use-gpio-for-.patch @@ -0,0 +1,54 @@ +From 60585ba83de021eac6975ad541bff1371984f0bd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Jan 2026 13:13:19 +0000 +Subject: arm64: dts: renesas: rzt2h-n2h-evk-common: Use GPIO for SD0 write + protect + +From: Lad Prabhakar + +[ Upstream commit a1b1ee0348f889ec262482e16e9ff670617db7b0 ] + +Switch SD0 write-protect detection to a GPIO on the RZ/T2H and RZ/N2H +EVKs. Both boards use a full-size SD card slot on the SD0 channel with +a dedicated WP pin. + +The RZ/T2H and RZ/N2H SoCs use of_data_rcar_gen3, which sets +MMC_CAP2_NO_WRITE_PROTECT and causes the core to ignore the WP signal +unless a wp-gpios property is provided. Describe the WP pin as a GPIO +to allow the MMC core to evaluate the write-protect status correctly. + +Fixes: d065453e5ee0 ("arm64: dts: renesas: rzt2h-rzn2h-evk: Enable SD card slot") +Signed-off-by: Lad Prabhakar +Reviewed-by: Geert Uytterhoeven +Link: https://patch.msgid.link/20260106131319.643084-1-prabhakar.mahadev-lad.rj@bp.renesas.com +Signed-off-by: Geert Uytterhoeven +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/renesas/rzt2h-n2h-evk-common.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/renesas/rzt2h-n2h-evk-common.dtsi b/arch/arm64/boot/dts/renesas/rzt2h-n2h-evk-common.dtsi +index 3eed1f3948e8e..63bd91690b540 100644 +--- a/arch/arm64/boot/dts/renesas/rzt2h-n2h-evk-common.dtsi ++++ b/arch/arm64/boot/dts/renesas/rzt2h-n2h-evk-common.dtsi +@@ -224,8 +224,7 @@ data-pins { + ctrl-pins { + pinmux = , /* SD0_CLK */ + , /* SD0_CMD */ +- , /* SD0_CD */ +- ; /* SD0_WP */ ++ ; /* SD0_CD */ + }; + }; + +@@ -282,6 +281,7 @@ &sdhi0 { + pinctrl-names = "default", "state_uhs"; + vmmc-supply = <®_3p3v>; + vqmmc-supply = <&vqmmc_sdhi0>; ++ wp-gpios = <&pinctrl RZT2H_GPIO(22, 6) GPIO_ACTIVE_HIGH>; + bus-width = <4>; + sd-uhs-sdr50; + sd-uhs-sdr104; +-- +2.51.0 + diff --git a/queue-6.19/arm64-dts-ti-k3-am67a-kontron-sa67-base-fix-cma-node.patch b/queue-6.19/arm64-dts-ti-k3-am67a-kontron-sa67-base-fix-cma-node.patch new file mode 100644 index 0000000000..0011dee4d5 --- /dev/null +++ b/queue-6.19/arm64-dts-ti-k3-am67a-kontron-sa67-base-fix-cma-node.patch @@ -0,0 +1,38 @@ +From 4809b1f9f3b8c2b413da897830a13fa54245221f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 14:14:18 +0100 +Subject: arm64: dts: ti: k3-am67a-kontron-sa67-base: Fix CMA node + +From: Michael Walle + +[ Upstream commit 11a6a5bb72ce271de24330fd859e83f7bc281609 ] + +Fix the size of the CMA node by making it a 64bit size. This was +probably a copy&paste mistake. Also drop the unneeded alignment. + +Fixes: 1c3c4df06f9d ("arm64: dts: ti: Add support for Kontron SMARC-sAM67") +Signed-off-by: Michael Walle +Link: https://patch.msgid.link/20260115131431.1521102-2-mwalle@kernel.org +Signed-off-by: Nishanth Menon +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/ti/k3-am67a-kontron-sa67-base.dts | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/ti/k3-am67a-kontron-sa67-base.dts b/arch/arm64/boot/dts/ti/k3-am67a-kontron-sa67-base.dts +index 7169d934adac5..3be6c6d19def5 100644 +--- a/arch/arm64/boot/dts/ti/k3-am67a-kontron-sa67-base.dts ++++ b/arch/arm64/boot/dts/ti/k3-am67a-kontron-sa67-base.dts +@@ -85,8 +85,7 @@ reserved_memory: reserved-memory { + linux,cma { + compatible = "shared-dma-pool"; + reusable; +- size = <0x10000000>; +- alignment = <0x2000>; ++ size = <0x00 0x10000000>; + linux,cma-default; + }; + +-- +2.51.0 + diff --git a/queue-6.19/arm64-dts-ti-k3-am67a-kontron-sa67-base-fix-sd-card-.patch b/queue-6.19/arm64-dts-ti-k3-am67a-kontron-sa67-base-fix-sd-card-.patch new file mode 100644 index 0000000000..055fd058a5 --- /dev/null +++ b/queue-6.19/arm64-dts-ti-k3-am67a-kontron-sa67-base-fix-sd-card-.patch @@ -0,0 +1,36 @@ +From 7dc67a910480a7d6c3e2fd2e9f0a977a33bb8d94 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 14:14:19 +0100 +Subject: arm64: dts: ti: k3-am67a-kontron-sa67-base: Fix SD card regulator + +From: Michael Walle + +[ Upstream commit 53289af62b66812d07a7b0f5f9d62f429c94d317 ] + +The property "enable-active-high" was missing, as the default is +active-low. Add it. + +Fixes: 1c3c4df06f9d ("arm64: dts: ti: Add support for Kontron SMARC-sAM67") +Signed-off-by: Michael Walle +Link: https://patch.msgid.link/20260115131431.1521102-3-mwalle@kernel.org +Signed-off-by: Nishanth Menon +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/ti/k3-am67a-kontron-sa67-base.dts | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm64/boot/dts/ti/k3-am67a-kontron-sa67-base.dts b/arch/arm64/boot/dts/ti/k3-am67a-kontron-sa67-base.dts +index 3be6c6d19def5..95234c8460ed0 100644 +--- a/arch/arm64/boot/dts/ti/k3-am67a-kontron-sa67-base.dts ++++ b/arch/arm64/boot/dts/ti/k3-am67a-kontron-sa67-base.dts +@@ -173,6 +173,7 @@ vcc_3p3_sd_vio_s0: regulator-6 { + regulator-max-microvolt = <3300000>; + vin-supply = <&vcc_3p3_s0>; + regulator-boot-on; ++ enable-active-high; + enable-gpios = <&main_gpio0 7 GPIO_ACTIVE_HIGH>; + gpios = <&main_gpio0 8 GPIO_ACTIVE_HIGH>; + states = <3300000 0x0>, +-- +2.51.0 + diff --git a/queue-6.19/arm64-dts-ti-k3-am69-aquila-clover-fix-usb-c-sink-pd.patch b/queue-6.19/arm64-dts-ti-k3-am69-aquila-clover-fix-usb-c-sink-pd.patch new file mode 100644 index 0000000000..613435115a --- /dev/null +++ b/queue-6.19/arm64-dts-ti-k3-am69-aquila-clover-fix-usb-c-sink-pd.patch @@ -0,0 +1,40 @@ +From ea44504871dcd891bd20b63bd9f6834f5d95c2a8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Dec 2025 14:42:19 +0100 +Subject: arm64: dts: ti: k3-am69-aquila-clover: Fix USB-C Sink PDO + +From: Francesco Dolcini + +[ Upstream commit b548f3949937b55ee19ab418343f05700fdf7009 ] + +Change USB-C Sink PDO and the amount of power that the device can sink +to zero to maximize compatibility with other USB peers (the Aquila +Clover Board is not sinking any current, it is self powered). + +Fixes: 9f748a6177e1 ("arm64: dts: ti: am69-aquila: Add Clover") +Signed-off-by: Francesco Dolcini +Link: https://patch.msgid.link/20251204134220.129304-3-francesco@dolcini.it +Signed-off-by: Nishanth Menon +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/ti/k3-am69-aquila-clover.dts | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/ti/k3-am69-aquila-clover.dts b/arch/arm64/boot/dts/ti/k3-am69-aquila-clover.dts +index 55fd214a82e44..c816ba3bfbdf7 100644 +--- a/arch/arm64/boot/dts/ti/k3-am69-aquila-clover.dts ++++ b/arch/arm64/boot/dts/ti/k3-am69-aquila-clover.dts +@@ -280,8 +280,8 @@ connector { + try-power-role = "sink"; + self-powered; + source-pdos = ; +- sink-pdos = ; +- op-sink-microwatt = <1000000>; ++ sink-pdos = ; ++ op-sink-microwatt = <0>; + + ports { + #address-cells = <1>; +-- +2.51.0 + diff --git a/queue-6.19/arm64-dts-ti-k3-am69-aquila-dev-fix-usb-c-sink-pdo.patch b/queue-6.19/arm64-dts-ti-k3-am69-aquila-dev-fix-usb-c-sink-pdo.patch new file mode 100644 index 0000000000..bbd01345dd --- /dev/null +++ b/queue-6.19/arm64-dts-ti-k3-am69-aquila-dev-fix-usb-c-sink-pdo.patch @@ -0,0 +1,40 @@ +From b98e3655269c74d41807d81b635cd844f5459a26 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Dec 2025 14:42:18 +0100 +Subject: arm64: dts: ti: k3-am69-aquila-dev: Fix USB-C Sink PDO + +From: Francesco Dolcini + +[ Upstream commit 36ee9f8b1ae07fe82885a7a3553a5be347d3f978 ] + +Change USB-C Sink PDO and the amount of power that the device can sink +to zero to maximize compatibility with other USB peers (the Aquila +Development Board is not sinking any current, it is self powered). + +Fixes: 39ac6623b1d8 ("arm64: dts: ti: Add Aquila AM69 Support") +Signed-off-by: Francesco Dolcini +Link: https://patch.msgid.link/20251204134220.129304-2-francesco@dolcini.it +Signed-off-by: Nishanth Menon +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/ti/k3-am69-aquila-dev.dts | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/ti/k3-am69-aquila-dev.dts b/arch/arm64/boot/dts/ti/k3-am69-aquila-dev.dts +index c7ce804eac703..f48601ae38b7c 100644 +--- a/arch/arm64/boot/dts/ti/k3-am69-aquila-dev.dts ++++ b/arch/arm64/boot/dts/ti/k3-am69-aquila-dev.dts +@@ -399,8 +399,8 @@ connector { + try-power-role = "sink"; + self-powered; + source-pdos = ; +- sink-pdos = ; +- op-sink-microwatt = <1000000>; ++ sink-pdos = ; ++ op-sink-microwatt = <0>; + + ports { + #address-cells = <1>; +-- +2.51.0 + diff --git a/queue-6.19/arm64-dts-ti-k3-j784s4-j742s2-main-common.dtsi-refac.patch b/queue-6.19/arm64-dts-ti-k3-j784s4-j742s2-main-common.dtsi-refac.patch new file mode 100644 index 0000000000..a833595b16 --- /dev/null +++ b/queue-6.19/arm64-dts-ti-k3-j784s4-j742s2-main-common.dtsi-refac.patch @@ -0,0 +1,125 @@ +From ef54df57d2e9295479c0547fdfe25e944f02a226 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 14:21:13 +0530 +Subject: arm64: dts: ti: k3-j784s4-j742s2-main-common.dtsi: Refactor watchdog + instances for j784s4 + +From: Abhash Kumar Jha + +[ Upstream commit 61acc4428a7f52e0a13e226ba76f2ce2ca66c065 ] + +Each A72 core has one watchdog instance associated with it. Since j742s2 +has 4 A72 cores, the common file should not define 8 watchdog instances. + +Refactor the last 4 extra watchdogs from the common file to j784s4 +specific file, as j784s4 has 8 A72 cores and thus hardware description +requires 8 watchdog instances. + +Fixes: 9cc161a4509c ("arm64: dts: ti: Refactor J784s4 SoC files to a common file") +Signed-off-by: Abhash Kumar Jha +Reviewed-by: Udit Kumar +Link: https://patch.msgid.link/20260112085113.3476193-3-a-kumar2@ti.com +Signed-off-by: Nishanth Menon +Signed-off-by: Sasha Levin +--- + .../dts/ti/k3-j784s4-j742s2-main-common.dtsi | 36 ------------------- + arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi | 36 +++++++++++++++++++ + 2 files changed, 36 insertions(+), 36 deletions(-) + +diff --git a/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-main-common.dtsi b/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-main-common.dtsi +index 9cc0901d58fbf..c2636e624f18b 100644 +--- a/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-main-common.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-main-common.dtsi +@@ -2378,42 +2378,6 @@ watchdog3: watchdog@2230000 { + assigned-clock-parents = <&k3_clks 351 4>; + }; + +- watchdog4: watchdog@2240000 { +- compatible = "ti,j7-rti-wdt"; +- reg = <0x00 0x2240000 0x00 0x100>; +- clocks = <&k3_clks 352 0>; +- power-domains = <&k3_pds 352 TI_SCI_PD_EXCLUSIVE>; +- assigned-clocks = <&k3_clks 352 0>; +- assigned-clock-parents = <&k3_clks 352 4>; +- }; +- +- watchdog5: watchdog@2250000 { +- compatible = "ti,j7-rti-wdt"; +- reg = <0x00 0x2250000 0x00 0x100>; +- clocks = <&k3_clks 353 0>; +- power-domains = <&k3_pds 353 TI_SCI_PD_EXCLUSIVE>; +- assigned-clocks = <&k3_clks 353 0>; +- assigned-clock-parents = <&k3_clks 353 4>; +- }; +- +- watchdog6: watchdog@2260000 { +- compatible = "ti,j7-rti-wdt"; +- reg = <0x00 0x2260000 0x00 0x100>; +- clocks = <&k3_clks 354 0>; +- power-domains = <&k3_pds 354 TI_SCI_PD_EXCLUSIVE>; +- assigned-clocks = <&k3_clks 354 0>; +- assigned-clock-parents = <&k3_clks 354 4>; +- }; +- +- watchdog7: watchdog@2270000 { +- compatible = "ti,j7-rti-wdt"; +- reg = <0x00 0x2270000 0x00 0x100>; +- clocks = <&k3_clks 355 0>; +- power-domains = <&k3_pds 355 TI_SCI_PD_EXCLUSIVE>; +- assigned-clocks = <&k3_clks 355 0>; +- assigned-clock-parents = <&k3_clks 355 4>; +- }; +- + /* + * The following RTI instances are coupled with MCU R5Fs, c7x and + * GPU so keeping them reserved as these will be used by their +diff --git a/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi b/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi +index 5b7830a3c0975..78fcd0c40abcf 100644 +--- a/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi +@@ -6,6 +6,42 @@ + */ + + &cbass_main { ++ watchdog4: watchdog@2240000 { ++ compatible = "ti,j7-rti-wdt"; ++ reg = <0x00 0x2240000 0x00 0x100>; ++ clocks = <&k3_clks 352 0>; ++ power-domains = <&k3_pds 352 TI_SCI_PD_EXCLUSIVE>; ++ assigned-clocks = <&k3_clks 352 0>; ++ assigned-clock-parents = <&k3_clks 352 4>; ++ }; ++ ++ watchdog5: watchdog@2250000 { ++ compatible = "ti,j7-rti-wdt"; ++ reg = <0x00 0x2250000 0x00 0x100>; ++ clocks = <&k3_clks 353 0>; ++ power-domains = <&k3_pds 353 TI_SCI_PD_EXCLUSIVE>; ++ assigned-clocks = <&k3_clks 353 0>; ++ assigned-clock-parents = <&k3_clks 353 4>; ++ }; ++ ++ watchdog6: watchdog@2260000 { ++ compatible = "ti,j7-rti-wdt"; ++ reg = <0x00 0x2260000 0x00 0x100>; ++ clocks = <&k3_clks 354 0>; ++ power-domains = <&k3_pds 354 TI_SCI_PD_EXCLUSIVE>; ++ assigned-clocks = <&k3_clks 354 0>; ++ assigned-clock-parents = <&k3_clks 354 4>; ++ }; ++ ++ watchdog7: watchdog@2270000 { ++ compatible = "ti,j7-rti-wdt"; ++ reg = <0x00 0x2270000 0x00 0x100>; ++ clocks = <&k3_clks 355 0>; ++ power-domains = <&k3_pds 355 TI_SCI_PD_EXCLUSIVE>; ++ assigned-clocks = <&k3_clks 355 0>; ++ assigned-clock-parents = <&k3_clks 355 4>; ++ }; ++ + pcie2_rc: pcie@2920000 { + compatible = "ti,j784s4-pcie-host"; + reg = <0x00 0x02920000 0x00 0x1000>, +-- +2.51.0 + diff --git a/queue-6.19/arm64-dts-ti-k3-j784s4-main.dtsi-move-c71_3-node-to-.patch b/queue-6.19/arm64-dts-ti-k3-j784s4-main.dtsi-move-c71_3-node-to-.patch new file mode 100644 index 0000000000..1f5b9e8807 --- /dev/null +++ b/queue-6.19/arm64-dts-ti-k3-j784s4-main.dtsi-move-c71_3-node-to-.patch @@ -0,0 +1,73 @@ +From f514fac0768c41917818f4e8c7396cdb9b981c2c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 14:21:12 +0530 +Subject: arm64: dts: ti: k3-j784s4-main.dtsi: Move c71_3 node to appropriate + order + +From: Abhash Kumar Jha + +[ Upstream commit 24c9d5fb8bbf5e8c9e6fc2beffeb80ac2da83de4 ] + +The device tree nodes should be ordered by unit addresses in ascending +order. + +Correct the order by moving the c71_3 DSP node at the end as it has a +higher unit address. + +Signed-off-by: Abhash Kumar Jha +Reviewed-by: Udit Kumar +Link: https://patch.msgid.link/20260112085113.3476193-2-a-kumar2@ti.com +Signed-off-by: Nishanth Menon +Stable-dep-of: 61acc4428a7f ("arm64: dts: ti: k3-j784s4-j742s2-main-common.dtsi: Refactor watchdog instances for j784s4") +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi | 26 +++++++++++----------- + 1 file changed, 13 insertions(+), 13 deletions(-) + +diff --git a/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi b/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi +index 0160fe0da9838..5b7830a3c0975 100644 +--- a/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi +@@ -6,19 +6,6 @@ + */ + + &cbass_main { +- c71_3: dsp@67800000 { +- compatible = "ti,j721s2-c71-dsp"; +- reg = <0x00 0x67800000 0x00 0x00080000>, +- <0x00 0x67e00000 0x00 0x0000c000>; +- reg-names = "l2sram", "l1dram"; +- resets = <&k3_reset 40 1>; +- firmware-name = "j784s4-c71_3-fw"; +- ti,sci = <&sms>; +- ti,sci-dev-id = <40>; +- ti,sci-proc-ids = <0x33 0xff>; +- status = "disabled"; +- }; +- + pcie2_rc: pcie@2920000 { + compatible = "ti,j784s4-pcie-host"; + reg = <0x00 0x02920000 0x00 0x1000>, +@@ -113,6 +100,19 @@ serdes2: serdes@5020000 { + status = "disabled"; + }; + }; ++ ++ c71_3: dsp@67800000 { ++ compatible = "ti,j721s2-c71-dsp"; ++ reg = <0x00 0x67800000 0x00 0x00080000>, ++ <0x00 0x67e00000 0x00 0x0000c000>; ++ reg-names = "l2sram", "l1dram"; ++ resets = <&k3_reset 40 1>; ++ firmware-name = "j784s4-c71_3-fw"; ++ ti,sci = <&sms>; ++ ti,sci-dev-id = <40>; ++ ti,sci-proc-ids = <0x33 0xff>; ++ status = "disabled"; ++ }; + }; + + &scm_conf { +-- +2.51.0 + diff --git a/queue-6.19/arm64-dts-tqma8mpql-mba8mp-ras314-fix-hdmi-cec-pad-c.patch b/queue-6.19/arm64-dts-tqma8mpql-mba8mp-ras314-fix-hdmi-cec-pad-c.patch new file mode 100644 index 0000000000..fc8bf7e0d4 --- /dev/null +++ b/queue-6.19/arm64-dts-tqma8mpql-mba8mp-ras314-fix-hdmi-cec-pad-c.patch @@ -0,0 +1,37 @@ +From 4a983b96785f4d07331223a01b10882636cdd3bd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 11:53:13 +0100 +Subject: arm64: dts: tqma8mpql-mba8mp-ras314: Fix HDMI CEC pad control + settings + +From: Alexander Stein + +[ Upstream commit 53a5c1d98d1155ece4c9446c0fea55e17d08774a ] + +As per datasheet of the HDMI protection IC the CEC_IC pin has been +configured as open-drain. + +Fixes: ddabb3ce3f90 ("arm64: dts: freescale: add TQMa8MPQL on MBa8MP-RAS314") +Signed-off-by: Alexander Stein +Signed-off-by: Shawn Guo +Signed-off-by: Sasha Levin +--- + .../arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts +index f7346b3d35fe5..a122f2ed5f531 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts +@@ -704,7 +704,7 @@ pinctrl_hdmi: hdmigrp { + fsl,pins = , + , + , +- ; ++ ; + }; + + pinctrl_gpt1: gpt1grp { +-- +2.51.0 + diff --git a/queue-6.19/arm64-dts-tqma8mpql-mba8mpxl-fix-hdmi-cec-pad-contro.patch b/queue-6.19/arm64-dts-tqma8mpql-mba8mpxl-fix-hdmi-cec-pad-contro.patch new file mode 100644 index 0000000000..27679b099d --- /dev/null +++ b/queue-6.19/arm64-dts-tqma8mpql-mba8mpxl-fix-hdmi-cec-pad-contro.patch @@ -0,0 +1,36 @@ +From 8ac2180efa2af3965f4f7d0f0148a1a46e73c891 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 11:53:09 +0100 +Subject: arm64: dts: tqma8mpql-mba8mpxl: Fix HDMI CEC pad control settings + +From: Alexander Stein + +[ Upstream commit 8401527abb5e3a00c867b6597b8e1b29c80c9824 ] + +As per datasheet of the HDMI protection IC the CEC_IC pin has been +configured as open-drain. + +Fixes: 418d1d840e42 ("arm64: dts: freescale: add initial device tree for TQMa8MPQL with i.MX8MP") +Signed-off-by: Alexander Stein +Signed-off-by: Shawn Guo +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts +index 59642a8a2c445..c73d40fb789f6 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts +@@ -867,7 +867,7 @@ pinctrl_hdmi: hdmigrp { + fsl,pins = , + , + , +- ; ++ ; + }; + + pinctrl_hoggpio2: hoggpio2grp { +-- +2.51.0 + diff --git a/queue-6.19/arm64-gcs-fix-error-handling-in-arch_set_shadow_stac.patch b/queue-6.19/arm64-gcs-fix-error-handling-in-arch_set_shadow_stac.patch new file mode 100644 index 0000000000..4b02b0699b --- /dev/null +++ b/queue-6.19/arm64-gcs-fix-error-handling-in-arch_set_shadow_stac.patch @@ -0,0 +1,45 @@ +From 5ecc263222e26f8c6189cc033712152407fe218a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 10:32:51 -0800 +Subject: arm64/gcs: Fix error handling in arch_set_shadow_stack_status() + +From: Breno Leitao + +[ Upstream commit 53c998527ffa60f9deda8974a11ad39790684159 ] + +alloc_gcs() returns an error-encoded pointer on failure, which comes +from do_mmap(), not NULL. + +The current NULL check fails to detect errors, which could lead to using +an invalid GCS address. + +Use IS_ERR_VALUE() to properly detect errors, consistent with the +check in gcs_alloc_thread_stack(). + +Fixes: b57180c75c7e ("arm64/gcs: Implement shadow stack prctl() interface") +Reviewed-by: Mark Brown +Signed-off-by: Breno Leitao +Signed-off-by: Will Deacon +Signed-off-by: Sasha Levin +--- + arch/arm64/mm/gcs.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/mm/gcs.c b/arch/arm64/mm/gcs.c +index 6e93f78de79b1..04a23a497f205 100644 +--- a/arch/arm64/mm/gcs.c ++++ b/arch/arm64/mm/gcs.c +@@ -199,8 +199,8 @@ int arch_set_shadow_stack_status(struct task_struct *task, unsigned long arg) + + size = gcs_size(0); + gcs = alloc_gcs(0, size); +- if (!gcs) +- return -ENOMEM; ++ if (IS_ERR_VALUE(gcs)) ++ return gcs; + + task->thread.gcspr_el0 = gcs + size - sizeof(u64); + task->thread.gcs_base = gcs; +-- +2.51.0 + diff --git a/queue-6.19/asoc-cs4271-fix-resource-leak-in-cs4271_soc_resume.patch b/queue-6.19/asoc-cs4271-fix-resource-leak-in-cs4271_soc_resume.patch new file mode 100644 index 0000000000..873a4f751d --- /dev/null +++ b/queue-6.19/asoc-cs4271-fix-resource-leak-in-cs4271_soc_resume.patch @@ -0,0 +1,70 @@ +From c6089abba2a54be645b8160cb7f1d514eb00eac8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 10 Jan 2026 11:53:36 -0800 +Subject: ASoC: cs4271: Fix resource leak in cs4271_soc_resume() + +From: Harshit Mogalapalli + +[ Upstream commit fef1f756155c30511397bbcd9d55640ab2e44d99 ] + +Smatch detects this resource leak: + +sound/soc/codecs/cs4271.c:548 cs4271_soc_resume() warn: + 'cs4271->clk' from clk_prepare_enable() not released on lines: 540,546. + +Instead of direct returns, unprepare the clock and disable regulators on +the error paths. + +Fixes: cf6bf51b5325 ("ASoC: cs4271: Add support for the external mclk") +Fixes: 9a397f473657 ("ASoC: cs4271: add regulator consumer support") +Signed-off-by: Harshit Mogalapalli +Reviewed-by: Charles Keepax +Acked-by: Herve Codina +Reviewed-by: Alexander Sverdlin +Link: https://patch.msgid.link/20260110195337.2522347-1-harshit.m.mogalapalli@oracle.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/cs4271.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c +index 77dfc83a3c013..d8cdd37e9112b 100644 +--- a/sound/soc/codecs/cs4271.c ++++ b/sound/soc/codecs/cs4271.c +@@ -528,7 +528,7 @@ static int cs4271_soc_resume(struct snd_soc_component *component) + ret = clk_prepare_enable(cs4271->clk); + if (ret) { + dev_err(component->dev, "Failed to enable clk: %d\n", ret); +- return ret; ++ goto err_disable_regulators; + } + + /* Do a proper reset after power up */ +@@ -537,15 +537,21 @@ static int cs4271_soc_resume(struct snd_soc_component *component) + /* Restore codec state */ + ret = regcache_sync(cs4271->regmap); + if (ret < 0) +- return ret; ++ goto err_disable_clk; + + /* then disable the power-down bit */ + ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2, + CS4271_MODE2_PDN, 0); + if (ret < 0) +- return ret; ++ goto err_disable_clk; + + return 0; ++ ++err_disable_clk: ++ clk_disable_unprepare(cs4271->clk); ++err_disable_regulators: ++ regulator_bulk_disable(ARRAY_SIZE(cs4271->supplies), cs4271->supplies); ++ return ret; + } + #else + #define cs4271_soc_suspend NULL +-- +2.51.0 + diff --git a/queue-6.19/asoc-nau8821-cancel-delayed-work-on-component-remove.patch b/queue-6.19/asoc-nau8821-cancel-delayed-work-on-component-remove.patch new file mode 100644 index 0000000000..80b132ab81 --- /dev/null +++ b/queue-6.19/asoc-nau8821-cancel-delayed-work-on-component-remove.patch @@ -0,0 +1,72 @@ +From 26b6be406385a15a0f059bbb06643ac74997f922 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 31 Dec 2025 22:04:16 +0200 +Subject: ASoC: nau8821: Cancel delayed work on component remove + +From: Cristian Ciocaltea + +[ Upstream commit dbd3fd05cddfdeec1e49b0a66269881c09eebd17 ] + +Attempting to unload the driver while a jack detection work is pending +would likely crash the kernel when it is eventually scheduled for +execution: + +[ 1984.896308] BUG: unable to handle page fault for address: ffffffffc10c2a20 +[...] +[ 1984.896388] Hardware name: Valve Jupiter/Jupiter, BIOS F7A0131 01/30/2024 +[ 1984.896396] Workqueue: events nau8821_jdet_work [snd_soc_nau8821] +[ 1984.896414] RIP: 0010:__mutex_lock+0x9f/0x11d0 +[...] +[ 1984.896504] Call Trace: +[ 1984.896511] +[ 1984.896524] ? snd_soc_dapm_disable_pin+0x26/0x60 [snd_soc_core] +[ 1984.896572] ? snd_soc_dapm_disable_pin+0x26/0x60 [snd_soc_core] +[ 1984.896596] snd_soc_dapm_disable_pin+0x26/0x60 [snd_soc_core] +[ 1984.896622] nau8821_jdet_work+0xeb/0x1e0 [snd_soc_nau8821] +[ 1984.896636] process_one_work+0x211/0x590 +[ 1984.896649] ? srso_return_thunk+0x5/0x5f +[ 1984.896670] worker_thread+0x1cd/0x3a0 + +Cancel unscheduled jdet_work or wait for its execution to finish before +the component driver gets removed. + +Fixes: aab1ad11d69f ("ASoC: nau8821: new driver") +Fixes: ee70bacef1c6 ("ASoC: nau8821: Avoid unnecessary blocking in IRQ handler") +Signed-off-by: Cristian Ciocaltea +Link: https://patch.msgid.link/20251231-nau8821-cleanup-v1-2-6b0b76cbbb64@collabora.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/nau8821.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/sound/soc/codecs/nau8821.c b/sound/soc/codecs/nau8821.c +index 2d25a182f4abe..2e2714b475012 100644 +--- a/sound/soc/codecs/nau8821.c ++++ b/sound/soc/codecs/nau8821.c +@@ -1264,6 +1264,14 @@ static int nau8821_component_probe(struct snd_soc_component *component) + return 0; + } + ++static void nau8821_component_remove(struct snd_soc_component *component) ++{ ++ struct nau8821 *nau8821 = snd_soc_component_get_drvdata(component); ++ ++ if (nau8821->jdet_active) ++ cancel_delayed_work_sync(&nau8821->jdet_work); ++}; ++ + /** + * nau8821_calc_fll_param - Calculate FLL parameters. + * @fll_in: external clock provided to codec. +@@ -1621,6 +1629,7 @@ static int __maybe_unused nau8821_resume(struct snd_soc_component *component) + + static const struct snd_soc_component_driver nau8821_component_driver = { + .probe = nau8821_component_probe, ++ .remove = nau8821_component_remove, + .set_sysclk = nau8821_set_sysclk, + .set_pll = nau8821_set_fll, + .set_bias_level = nau8821_set_bias_level, +-- +2.51.0 + diff --git a/queue-6.19/asoc-nau8821-cancel-pending-work-before-suspend.patch b/queue-6.19/asoc-nau8821-cancel-pending-work-before-suspend.patch new file mode 100644 index 0000000000..98c5f9bc49 --- /dev/null +++ b/queue-6.19/asoc-nau8821-cancel-pending-work-before-suspend.patch @@ -0,0 +1,46 @@ +From 7dd7389f229b48ab999f3aa81c8b71b755aeb644 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 31 Dec 2025 22:04:17 +0200 +Subject: ASoC: nau8821: Cancel pending work before suspend + +From: Cristian Ciocaltea + +[ Upstream commit 7786b10688ac0ebeaff655923cbb2c7d34a98995 ] + +A jack detection work that is unscheduled or in progress while executing +the suspend handler could trigger a race condition. + +Ensure state consistency by cancelling any pending work or wait for its +execution to complete before processing the suspend. Since driver +(re)enables both insert and eject interrupts on resume, there is no risk +to miss the related jack events. Therefore, flush_delayed_work() is not +required here. + +Fixes: aab1ad11d69f ("ASoC: nau8821: new driver") +Fixes: ee70bacef1c6 ("ASoC: nau8821: Avoid unnecessary blocking in IRQ handler") +Signed-off-by: Cristian Ciocaltea +Link: https://patch.msgid.link/20251231-nau8821-cleanup-v1-3-6b0b76cbbb64@collabora.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/nau8821.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/sound/soc/codecs/nau8821.c b/sound/soc/codecs/nau8821.c +index 2e2714b475012..58d2d5e77c8f4 100644 +--- a/sound/soc/codecs/nau8821.c ++++ b/sound/soc/codecs/nau8821.c +@@ -1605,6 +1605,10 @@ static int __maybe_unused nau8821_suspend(struct snd_soc_component *component) + + if (nau8821->irq) + disable_irq(nau8821->irq); ++ ++ if (nau8821->jdet_active) ++ cancel_delayed_work_sync(&nau8821->jdet_work); ++ + snd_soc_dapm_force_bias_level(nau8821->dapm, SND_SOC_BIAS_OFF); + /* Power down codec power; don't support button wakeup */ + snd_soc_dapm_disable_pin(nau8821->dapm, "MICBIAS"); +-- +2.51.0 + diff --git a/queue-6.19/asoc-nau8821-fixup-nau8821_enable_jack_detect.patch b/queue-6.19/asoc-nau8821-fixup-nau8821_enable_jack_detect.patch new file mode 100644 index 0000000000..fcebf830e8 --- /dev/null +++ b/queue-6.19/asoc-nau8821-fixup-nau8821_enable_jack_detect.patch @@ -0,0 +1,84 @@ +From 41786200a54ed1f358a4a8a7586a116933af250e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 31 Dec 2025 22:04:15 +0200 +Subject: ASoC: nau8821: Fixup nau8821_enable_jack_detect() + +From: Cristian Ciocaltea + +[ Upstream commit 70237853edf0a69773a7370eb74ea2a44dfe3050 ] + +The nau8821_enable_jack_detect() function was supposed to allow enabling +or disabling jack events reporting. However, once enabled, any +subsequent invocation would fail and the following splat is shown: + +[ 3136.996771] Hardware name: Valve Jupiter/Jupiter, BIOS F7A0131 01/30/2024 +[ 3136.996773] Workqueue: events_unbound deferred_probe_work_func +[ 3136.996780] Call Trace: +[ 3136.996782] +[ 3136.996787] dump_stack_lvl+0x6e/0xa0 +[ 3136.996796] __setup_irq.cold+0x9c/0xce +[ 3136.996803] ? __pfx_irq_default_primary_handler+0x10/0x10 +[ 3136.996812] ? __pfx_nau8821_interrupt+0x10/0x10 [snd_soc_nau8821] +[ 3136.996825] request_threaded_irq+0xd9/0x160 +[ 3136.996853] devm_request_threaded_irq+0x71/0xd0 +[ 3136.996859] ? __pfx_nau8821_interrupt+0x10/0x10 [snd_soc_nau8821] +[ 3136.996882] nau8821_enable_jack_detect+0xa5/0xc0 [snd_soc_nau8821] +[ 3136.996901] acp5x_8821_init+0x8d/0xa0 [snd_soc_acp5x_mach] +[ 3136.996917] snd_soc_link_init+0x25/0x50 [snd_soc_core] +[ 3136.996958] snd_soc_bind_card+0x615/0xd00 [snd_soc_core] +[ 3136.997026] snd_soc_register_card+0x1b2/0x1c0 [snd_soc_core] +[ 3136.997064] devm_snd_soc_register_card+0x47/0x90 [snd_soc_core] +[ 3136.997108] acp5x_probe+0x72/0xb0 [snd_soc_acp5x_mach] +[...] +[ 3136.997508] nau8821 i2c-NVTN2020:00: Cannot request irq 58 (-16) + +Introduce jdet_active flag to driver data structure and use it to +provide one-time initialization of the jack detection work queue and +related interrupt line. + +Note this is also a prerequisite for additional fixes around module +unloading and suspend handling. + +Fixes: aab1ad11d69f ("ASoC: nau8821: new driver") +Signed-off-by: Cristian Ciocaltea +Link: https://patch.msgid.link/20251231-nau8821-cleanup-v1-1-6b0b76cbbb64@collabora.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/nau8821.c | 5 +++++ + sound/soc/codecs/nau8821.h | 1 + + 2 files changed, 6 insertions(+) + +diff --git a/sound/soc/codecs/nau8821.c b/sound/soc/codecs/nau8821.c +index 3beb3c44dc2c0..2d25a182f4abe 100644 +--- a/sound/soc/codecs/nau8821.c ++++ b/sound/soc/codecs/nau8821.c +@@ -1655,8 +1655,13 @@ int nau8821_enable_jack_detect(struct snd_soc_component *component, + int ret; + + nau8821->jack = jack; ++ ++ if (nau8821->jdet_active) ++ return 0; ++ + /* Initiate jack detection work queue */ + INIT_DELAYED_WORK(&nau8821->jdet_work, nau8821_jdet_work); ++ nau8821->jdet_active = true; + + ret = devm_request_threaded_irq(nau8821->dev, nau8821->irq, NULL, + nau8821_interrupt, IRQF_TRIGGER_LOW | IRQF_ONESHOT, +diff --git a/sound/soc/codecs/nau8821.h b/sound/soc/codecs/nau8821.h +index 88602923780d8..f9d7cd8cbd211 100644 +--- a/sound/soc/codecs/nau8821.h ++++ b/sound/soc/codecs/nau8821.h +@@ -562,6 +562,7 @@ struct nau8821 { + struct snd_soc_dapm_context *dapm; + struct snd_soc_jack *jack; + struct delayed_work jdet_work; ++ bool jdet_active; + int irq; + int clk_id; + int micbias_voltage; +-- +2.51.0 + diff --git a/queue-6.19/asoc-sdca-add-ability-to-connect-sdca-jacks-to-asoc-.patch b/queue-6.19/asoc-sdca-add-ability-to-connect-sdca-jacks-to-asoc-.patch new file mode 100644 index 0000000000..e1567f3756 --- /dev/null +++ b/queue-6.19/asoc-sdca-add-ability-to-connect-sdca-jacks-to-asoc-.patch @@ -0,0 +1,185 @@ +From 9e10875c72a0332c59cf8c560cd6ce469805ff9c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 15 Dec 2025 15:36:48 +0000 +Subject: ASoC: SDCA: Add ability to connect SDCA jacks to ASoC jacks + +From: Charles Keepax + +[ Upstream commit 82e12800f563baf663277ef0017f40a335b8e84c ] + +Add handling for the ASoC jack API to SDCA to allow user-space to be +hooked up normally. + +Signed-off-by: Charles Keepax +Link: https://patch.msgid.link/20251215153650.3913117-3-ckeepax@opensource.cirrus.com +Reviewed-by: Bard Liao +Signed-off-by: Mark Brown +Stable-dep-of: d7730c44b7dd ("ASoC: SDCA: Still process most of the jack detect if control is missing") +Signed-off-by: Sasha Levin +--- + include/sound/sdca_jack.h | 5 ++ + sound/soc/sdca/sdca_jack.c | 106 ++++++++++++++++++++++++++++++++++++- + 2 files changed, 110 insertions(+), 1 deletion(-) + +diff --git a/include/sound/sdca_jack.h b/include/sound/sdca_jack.h +index 9fad5f22cbb9e..3ec22046d3ebc 100644 +--- a/include/sound/sdca_jack.h ++++ b/include/sound/sdca_jack.h +@@ -12,16 +12,21 @@ + + struct sdca_interrupt; + struct snd_kcontrol; ++struct snd_soc_jack; + + /** + * struct jack_state - Jack state structure to keep data between interrupts + * @kctl: Pointer to the ALSA control attached to this jack ++ * @jack: Pointer to the ASoC jack struct for this jack + */ + struct jack_state { + struct snd_kcontrol *kctl; ++ struct snd_soc_jack *jack; + }; + + int sdca_jack_alloc_state(struct sdca_interrupt *interrupt); + int sdca_jack_process(struct sdca_interrupt *interrupt); ++int sdca_jack_set_jack(struct sdca_interrupt_info *info, struct snd_soc_jack *jack); ++int sdca_jack_report(struct sdca_interrupt *interrupt); + + #endif // __SDCA_JACK_H__ +diff --git a/sound/soc/sdca/sdca_jack.c b/sound/soc/sdca/sdca_jack.c +index 83b2b9cc81f00..5b9cf69cbcd6b 100644 +--- a/sound/soc/sdca/sdca_jack.c ++++ b/sound/soc/sdca/sdca_jack.c +@@ -17,11 +17,13 @@ + #include + #include + #include ++#include + #include + #include + #include + #include + #include ++#include + #include + + /** +@@ -114,7 +116,7 @@ int sdca_jack_process(struct sdca_interrupt *interrupt) + + snd_ctl_notify(card->snd_card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); + +- return 0; ++ return sdca_jack_report(interrupt); + } + EXPORT_SYMBOL_NS_GPL(sdca_jack_process, "SND_SOC_SDCA"); + +@@ -138,3 +140,105 @@ int sdca_jack_alloc_state(struct sdca_interrupt *interrupt) + return 0; + } + EXPORT_SYMBOL_NS_GPL(sdca_jack_alloc_state, "SND_SOC_SDCA"); ++ ++/** ++ * sdca_jack_set_jack - attach an ASoC jack to SDCA ++ * @info: SDCA interrupt information. ++ * @jack: ASoC jack to be attached. ++ * ++ * Return: Zero on success or a negative error code. ++ */ ++int sdca_jack_set_jack(struct sdca_interrupt_info *info, struct snd_soc_jack *jack) ++{ ++ int i, ret; ++ ++ guard(mutex)(&info->irq_lock); ++ ++ for (i = 0; i < SDCA_MAX_INTERRUPTS; i++) { ++ struct sdca_interrupt *interrupt = &info->irqs[i]; ++ struct sdca_control *control = interrupt->control; ++ struct sdca_entity *entity = interrupt->entity; ++ struct jack_state *jack_state; ++ ++ if (!interrupt->irq) ++ continue; ++ ++ switch (SDCA_CTL_TYPE(entity->type, control->sel)) { ++ case SDCA_CTL_TYPE_S(GE, DETECTED_MODE): ++ jack_state = interrupt->priv; ++ jack_state->jack = jack; ++ ++ /* Report initial state in case IRQ was already handled */ ++ ret = sdca_jack_report(interrupt); ++ if (ret) ++ return ret; ++ break; ++ default: ++ break; ++ } ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL_NS_GPL(sdca_jack_set_jack, "SND_SOC_SDCA"); ++ ++int sdca_jack_report(struct sdca_interrupt *interrupt) ++{ ++ struct jack_state *jack_state = interrupt->priv; ++ struct sdca_control_range *range; ++ enum sdca_terminal_type type; ++ unsigned int report = 0; ++ unsigned int reg, val; ++ int ret; ++ ++ reg = SDW_SDCA_CTL(interrupt->function->desc->adr, interrupt->entity->id, ++ SDCA_CTL_GE_SELECTED_MODE, 0); ++ ++ ret = regmap_read(interrupt->function_regmap, reg, &val); ++ if (ret) { ++ dev_err(interrupt->dev, "failed to read selected mode: %d\n", ret); ++ return ret; ++ } ++ ++ range = sdca_selector_find_range(interrupt->dev, interrupt->entity, ++ SDCA_CTL_GE_SELECTED_MODE, ++ SDCA_SELECTED_MODE_NCOLS, 0); ++ if (!range) ++ return -EINVAL; ++ ++ type = sdca_range_search(range, SDCA_SELECTED_MODE_INDEX, ++ val, SDCA_SELECTED_MODE_TERM_TYPE); ++ ++ switch (type) { ++ case SDCA_TERM_TYPE_LINEIN_STEREO: ++ case SDCA_TERM_TYPE_LINEIN_FRONT_LR: ++ case SDCA_TERM_TYPE_LINEIN_CENTER_LFE: ++ case SDCA_TERM_TYPE_LINEIN_SURROUND_LR: ++ case SDCA_TERM_TYPE_LINEIN_REAR_LR: ++ report = SND_JACK_LINEIN; ++ break; ++ case SDCA_TERM_TYPE_LINEOUT_STEREO: ++ case SDCA_TERM_TYPE_LINEOUT_FRONT_LR: ++ case SDCA_TERM_TYPE_LINEOUT_CENTER_LFE: ++ case SDCA_TERM_TYPE_LINEOUT_SURROUND_LR: ++ case SDCA_TERM_TYPE_LINEOUT_REAR_LR: ++ report = SND_JACK_LINEOUT; ++ break; ++ case SDCA_TERM_TYPE_MIC_JACK: ++ report = SND_JACK_MICROPHONE; ++ break; ++ case SDCA_TERM_TYPE_HEADPHONE_JACK: ++ report = SND_JACK_HEADPHONE; ++ break; ++ case SDCA_TERM_TYPE_HEADSET_JACK: ++ report = SND_JACK_HEADSET; ++ break; ++ default: ++ break; ++ } ++ ++ snd_soc_jack_report(jack_state->jack, report, 0xFFFF); ++ ++ return 0; ++} ++EXPORT_SYMBOL_NS_GPL(sdca_jack_report, "SND_SOC_SDCA"); +-- +2.51.0 + diff --git a/queue-6.19/asoc-sdca-allow-sample-width-wild-cards-in-set_usage.patch b/queue-6.19/asoc-sdca-allow-sample-width-wild-cards-in-set_usage.patch new file mode 100644 index 0000000000..2701d30d52 --- /dev/null +++ b/queue-6.19/asoc-sdca-allow-sample-width-wild-cards-in-set_usage.patch @@ -0,0 +1,39 @@ +From 75226225779b2016781d884c6483bf83fc1a6e03 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Dec 2025 14:22:04 +0000 +Subject: ASoC: SDCA: Allow sample width wild cards in set_usage() + +From: Simon Trimmer + +[ Upstream commit 87783532d34050e2bff6749a4fe9860e624a0540 ] + +The SDCA spec allows the sample rate and width to be wild cards, but the +current implementation of set_usage() only checked for a wild card of +the sample rate. + +Fixes: 4ed357f72a0e ("ASoC: SDCA: Add hw_params() helper function") +Signed-off-by: Simon Trimmer +Reviewed-by: Charles Keepax +Link: https://patch.msgid.link/20251216142204.183958-1-simont@opensource.cirrus.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sdca/sdca_asoc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/soc/sdca/sdca_asoc.c b/sound/soc/sdca/sdca_asoc.c +index 2d328bbb95b94..498aba9df5d9b 100644 +--- a/sound/soc/sdca/sdca_asoc.c ++++ b/sound/soc/sdca/sdca_asoc.c +@@ -1478,7 +1478,7 @@ static int set_usage(struct device *dev, struct regmap *regmap, + unsigned int rate = sdca_range(range, SDCA_USAGE_SAMPLE_RATE, i); + unsigned int width = sdca_range(range, SDCA_USAGE_SAMPLE_WIDTH, i); + +- if ((!rate || rate == target_rate) && width == target_width) { ++ if ((!rate || rate == target_rate) && (!width || width == target_width)) { + unsigned int usage = sdca_range(range, SDCA_USAGE_NUMBER, i); + unsigned int reg = SDW_SDCA_CTL(function->desc->adr, + entity->id, sel, 0); +-- +2.51.0 + diff --git a/queue-6.19/asoc-sdca-factor-out-jack-handling-into-new-c-file.patch b/queue-6.19/asoc-sdca-factor-out-jack-handling-into-new-c-file.patch new file mode 100644 index 0000000000..6adb694663 --- /dev/null +++ b/queue-6.19/asoc-sdca-factor-out-jack-handling-into-new-c-file.patch @@ -0,0 +1,342 @@ +From df00d7589aa29d4c66df04cefa9aa826d20e2a5d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 15 Dec 2025 15:36:47 +0000 +Subject: ASoC: SDCA: Factor out jack handling into new c file + +From: Charles Keepax + +[ Upstream commit 3addd63d1fba8d9013e00b06d9420e39271c0c4e ] + +The jack code is perhaps a bit large for being in the interrupt +code directly. Improve the encapsulation by factoring out the +jack handling code into a new c file, as is already done for HID +and FDL. Whilst doing so also add a jack_state structure to hold +the jack state for improved expandability in the future. + +Signed-off-by: Charles Keepax +Link: https://patch.msgid.link/20251215153650.3913117-2-ckeepax@opensource.cirrus.com +Reviewed-by: Bard Liao +Signed-off-by: Mark Brown +Stable-dep-of: d7730c44b7dd ("ASoC: SDCA: Still process most of the jack detect if control is missing") +Signed-off-by: Sasha Levin +--- + include/sound/sdca_jack.h | 27 ++++++ + sound/soc/sdca/Makefile | 2 +- + sound/soc/sdca/sdca_interrupts.c | 83 ++---------------- + sound/soc/sdca/sdca_jack.c | 140 +++++++++++++++++++++++++++++++ + 4 files changed, 175 insertions(+), 77 deletions(-) + create mode 100644 include/sound/sdca_jack.h + create mode 100644 sound/soc/sdca/sdca_jack.c + +diff --git a/include/sound/sdca_jack.h b/include/sound/sdca_jack.h +new file mode 100644 +index 0000000000000..9fad5f22cbb9e +--- /dev/null ++++ b/include/sound/sdca_jack.h +@@ -0,0 +1,27 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * The MIPI SDCA specification is available for public downloads at ++ * https://www.mipi.org/mipi-sdca-v1-0-download ++ * ++ * Copyright (C) 2025 Cirrus Logic, Inc. and ++ * Cirrus Logic International Semiconductor Ltd. ++ */ ++ ++#ifndef __SDCA_JACK_H__ ++#define __SDCA_JACK_H__ ++ ++struct sdca_interrupt; ++struct snd_kcontrol; ++ ++/** ++ * struct jack_state - Jack state structure to keep data between interrupts ++ * @kctl: Pointer to the ALSA control attached to this jack ++ */ ++struct jack_state { ++ struct snd_kcontrol *kctl; ++}; ++ ++int sdca_jack_alloc_state(struct sdca_interrupt *interrupt); ++int sdca_jack_process(struct sdca_interrupt *interrupt); ++ ++#endif // __SDCA_JACK_H__ +diff --git a/sound/soc/sdca/Makefile b/sound/soc/sdca/Makefile +index f6b73275d9649..b3b0f5d94c8de 100644 +--- a/sound/soc/sdca/Makefile ++++ b/sound/soc/sdca/Makefile +@@ -3,7 +3,7 @@ + snd-soc-sdca-y := sdca_functions.o sdca_device.o sdca_function_device.o \ + sdca_regmap.o sdca_asoc.o sdca_ump.o + snd-soc-sdca-$(CONFIG_SND_SOC_SDCA_HID) += sdca_hid.o +-snd-soc-sdca-$(CONFIG_SND_SOC_SDCA_IRQ) += sdca_interrupts.o ++snd-soc-sdca-$(CONFIG_SND_SOC_SDCA_IRQ) += sdca_interrupts.o sdca_jack.o + snd-soc-sdca-$(CONFIG_SND_SOC_SDCA_FDL) += sdca_fdl.o + + snd-soc-sdca-class-y := sdca_class.o +diff --git a/sound/soc/sdca/sdca_interrupts.c b/sound/soc/sdca/sdca_interrupts.c +index 8f6a2adfb6fbe..ff3a7e405fdcb 100644 +--- a/sound/soc/sdca/sdca_interrupts.c ++++ b/sound/soc/sdca/sdca_interrupts.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -155,14 +156,7 @@ static irqreturn_t detected_mode_handler(int irq, void *data) + { + struct sdca_interrupt *interrupt = data; + struct device *dev = interrupt->dev; +- struct snd_soc_component *component = interrupt->component; +- struct snd_soc_card *card = component->card; +- struct rw_semaphore *rwsem = &card->snd_card->controls_rwsem; +- struct snd_kcontrol *kctl = interrupt->priv; +- struct snd_ctl_elem_value *ucontrol __free(kfree) = NULL; +- struct soc_enum *soc_enum; + irqreturn_t irqret = IRQ_NONE; +- unsigned int reg, val; + int ret; + + ret = pm_runtime_get_sync(dev); +@@ -171,76 +165,9 @@ static irqreturn_t detected_mode_handler(int irq, void *data) + goto error; + } + +- if (!kctl) { +- const char *name __free(kfree) = kasprintf(GFP_KERNEL, "%s %s", +- interrupt->entity->label, +- SDCA_CTL_SELECTED_MODE_NAME); +- +- if (!name) +- goto error; +- +- kctl = snd_soc_component_get_kcontrol(component, name); +- if (!kctl) { +- dev_dbg(dev, "control not found: %s\n", name); +- goto error; +- } +- +- interrupt->priv = kctl; +- } +- +- soc_enum = (struct soc_enum *)kctl->private_value; +- +- reg = SDW_SDCA_CTL(interrupt->function->desc->adr, interrupt->entity->id, +- interrupt->control->sel, 0); +- +- ret = regmap_read(interrupt->function_regmap, reg, &val); +- if (ret < 0) { +- dev_err(dev, "failed to read detected mode: %d\n", ret); +- goto error; +- } +- +- switch (val) { +- case SDCA_DETECTED_MODE_DETECTION_IN_PROGRESS: +- case SDCA_DETECTED_MODE_JACK_UNKNOWN: +- reg = SDW_SDCA_CTL(interrupt->function->desc->adr, +- interrupt->entity->id, +- SDCA_CTL_GE_SELECTED_MODE, 0); +- +- /* +- * Selected mode is not normally marked as volatile register +- * (RW), but here force a read from the hardware. If the +- * detected mode is unknown we need to see what the device +- * selected as a "safe" option. +- */ +- regcache_drop_region(interrupt->function_regmap, reg, reg); +- +- ret = regmap_read(interrupt->function_regmap, reg, &val); +- if (ret) { +- dev_err(dev, "failed to re-check selected mode: %d\n", ret); +- goto error; +- } +- break; +- default: +- break; +- } +- +- dev_dbg(dev, "%s: %#x\n", interrupt->name, val); +- +- ucontrol = kzalloc(sizeof(*ucontrol), GFP_KERNEL); +- if (!ucontrol) +- goto error; +- +- ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(soc_enum, val); +- +- down_write(rwsem); +- ret = kctl->put(kctl, ucontrol); +- up_write(rwsem); +- if (ret < 0) { +- dev_err(dev, "failed to update selected mode: %d\n", ret); ++ ret = sdca_jack_process(interrupt); ++ if (ret) + goto error; +- } +- +- snd_ctl_notify(card->snd_card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); + + irqret = IRQ_HANDLED; + error: +@@ -536,6 +463,10 @@ int sdca_irq_populate(struct sdca_function_data *function, + handler = function_status_handler; + break; + case SDCA_CTL_TYPE_S(GE, DETECTED_MODE): ++ ret = sdca_jack_alloc_state(interrupt); ++ if (ret) ++ return ret; ++ + handler = detected_mode_handler; + break; + case SDCA_CTL_TYPE_S(XU, FDL_CURRENTOWNER): +diff --git a/sound/soc/sdca/sdca_jack.c b/sound/soc/sdca/sdca_jack.c +new file mode 100644 +index 0000000000000..83b2b9cc81f00 +--- /dev/null ++++ b/sound/soc/sdca/sdca_jack.c +@@ -0,0 +1,140 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Copyright (C) 2025 Cirrus Logic, Inc. and ++// Cirrus Logic International Semiconductor Ltd. ++ ++/* ++ * The MIPI SDCA specification is available for public downloads at ++ * https://www.mipi.org/mipi-sdca-v1-0-download ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/** ++ * sdca_jack_process - Process an SDCA jack event ++ * @interrupt: SDCA interrupt structure ++ * ++ * Return: Zero on success or a negative error code. ++ */ ++int sdca_jack_process(struct sdca_interrupt *interrupt) ++{ ++ struct device *dev = interrupt->dev; ++ struct snd_soc_component *component = interrupt->component; ++ struct snd_soc_card *card = component->card; ++ struct rw_semaphore *rwsem = &card->snd_card->controls_rwsem; ++ struct jack_state *state = interrupt->priv; ++ struct snd_kcontrol *kctl = state->kctl; ++ struct snd_ctl_elem_value *ucontrol __free(kfree) = NULL; ++ struct soc_enum *soc_enum; ++ unsigned int reg, val; ++ int ret; ++ ++ if (!kctl) { ++ const char *name __free(kfree) = kasprintf(GFP_KERNEL, "%s %s", ++ interrupt->entity->label, ++ SDCA_CTL_SELECTED_MODE_NAME); ++ ++ if (!name) ++ return -ENOMEM; ++ ++ kctl = snd_soc_component_get_kcontrol(component, name); ++ if (!kctl) { ++ dev_dbg(dev, "control not found: %s\n", name); ++ return -ENOENT; ++ } ++ ++ state->kctl = kctl; ++ } ++ ++ soc_enum = (struct soc_enum *)kctl->private_value; ++ ++ reg = SDW_SDCA_CTL(interrupt->function->desc->adr, interrupt->entity->id, ++ interrupt->control->sel, 0); ++ ++ ret = regmap_read(interrupt->function_regmap, reg, &val); ++ if (ret < 0) { ++ dev_err(dev, "failed to read detected mode: %d\n", ret); ++ return ret; ++ } ++ ++ switch (val) { ++ case SDCA_DETECTED_MODE_DETECTION_IN_PROGRESS: ++ case SDCA_DETECTED_MODE_JACK_UNKNOWN: ++ reg = SDW_SDCA_CTL(interrupt->function->desc->adr, ++ interrupt->entity->id, ++ SDCA_CTL_GE_SELECTED_MODE, 0); ++ ++ /* ++ * Selected mode is not normally marked as volatile register ++ * (RW), but here force a read from the hardware. If the ++ * detected mode is unknown we need to see what the device ++ * selected as a "safe" option. ++ */ ++ regcache_drop_region(interrupt->function_regmap, reg, reg); ++ ++ ret = regmap_read(interrupt->function_regmap, reg, &val); ++ if (ret) { ++ dev_err(dev, "failed to re-check selected mode: %d\n", ret); ++ return ret; ++ } ++ break; ++ default: ++ break; ++ } ++ ++ dev_dbg(dev, "%s: %#x\n", interrupt->name, val); ++ ++ ucontrol = kzalloc(sizeof(*ucontrol), GFP_KERNEL); ++ if (!ucontrol) ++ return -ENOMEM; ++ ++ ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(soc_enum, val); ++ ++ down_write(rwsem); ++ ret = kctl->put(kctl, ucontrol); ++ up_write(rwsem); ++ if (ret < 0) { ++ dev_err(dev, "failed to update selected mode: %d\n", ret); ++ return ret; ++ } ++ ++ snd_ctl_notify(card->snd_card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); ++ ++ return 0; ++} ++EXPORT_SYMBOL_NS_GPL(sdca_jack_process, "SND_SOC_SDCA"); ++ ++/** ++ * sdca_jack_alloc_state - allocate state for a jack interrupt ++ * @interrupt: SDCA interrupt structure. ++ * ++ * Return: Zero on success or a negative error code. ++ */ ++int sdca_jack_alloc_state(struct sdca_interrupt *interrupt) ++{ ++ struct device *dev = interrupt->dev; ++ struct jack_state *jack_state; ++ ++ jack_state = devm_kzalloc(dev, sizeof(*jack_state), GFP_KERNEL); ++ if (!jack_state) ++ return -ENOMEM; ++ ++ interrupt->priv = jack_state; ++ ++ return 0; ++} ++EXPORT_SYMBOL_NS_GPL(sdca_jack_alloc_state, "SND_SOC_SDCA"); +-- +2.51.0 + diff --git a/queue-6.19/asoc-sdca-handle-volatile-controls-correctly.patch b/queue-6.19/asoc-sdca-handle-volatile-controls-correctly.patch new file mode 100644 index 0000000000..6e894fb55d --- /dev/null +++ b/queue-6.19/asoc-sdca-handle-volatile-controls-correctly.patch @@ -0,0 +1,108 @@ +From 6d5e835d7f9fba65558cc3f5b7245122201e7772 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 12:59:39 +0000 +Subject: ASoC: SDCA: Handle volatile controls correctly + +From: Charles Keepax + +[ Upstream commit 9fad74b79e5ff353fe156c4b685cceffa5afdb1d ] + +There are very few volatile controls in SDCA that are exported +as ALSA controls, typically Detected Mode is the only common +one. However, the current code does not resume the device when +these ALSA controls are accessed, which will result in the +read/write failing. + +Add a new wrapper specifically for volatile controls that will do +the required pm_runtime operations before accessing the register. + +Fixes: c3ca24e3fcb6 ("ASoC: SDCA: Create ALSA controls from DisCo") +Signed-off-by: Charles Keepax +Link: https://patch.msgid.link/20260204125944.1134011-3-ckeepax@opensource.cirrus.com +Reviewed-by: Pierre-Louis Bossart +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sdca/sdca_asoc.c | 52 ++++++++++++++++++++++++++++++++++++-- + 1 file changed, 50 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/sdca/sdca_asoc.c b/sound/soc/sdca/sdca_asoc.c +index 498aba9df5d9b..9685281529e9f 100644 +--- a/sound/soc/sdca/sdca_asoc.c ++++ b/sound/soc/sdca/sdca_asoc.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -792,6 +793,48 @@ static int control_limit_kctl(struct device *dev, + return 0; + } + ++static int volatile_get_volsw(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); ++ struct device *dev = component->dev; ++ int ret; ++ ++ ret = pm_runtime_resume_and_get(dev); ++ if (ret < 0) { ++ dev_err(dev, "failed to resume reading %s: %d\n", ++ kcontrol->id.name, ret); ++ return ret; ++ } ++ ++ ret = snd_soc_get_volsw(kcontrol, ucontrol); ++ ++ pm_runtime_put(dev); ++ ++ return ret; ++} ++ ++static int volatile_put_volsw(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); ++ struct device *dev = component->dev; ++ int ret; ++ ++ ret = pm_runtime_resume_and_get(dev); ++ if (ret < 0) { ++ dev_err(dev, "failed to resume writing %s: %d\n", ++ kcontrol->id.name, ret); ++ return ret; ++ } ++ ++ ret = snd_soc_put_volsw(kcontrol, ucontrol); ++ ++ pm_runtime_put(dev); ++ ++ return ret; ++} ++ + static int populate_control(struct device *dev, + struct sdca_function_data *function, + struct sdca_entity *entity, +@@ -849,8 +892,13 @@ static int populate_control(struct device *dev, + (*kctl)->private_value = (unsigned long)mc; + (*kctl)->iface = SNDRV_CTL_ELEM_IFACE_MIXER; + (*kctl)->info = snd_soc_info_volsw; +- (*kctl)->get = snd_soc_get_volsw; +- (*kctl)->put = snd_soc_put_volsw; ++ if (control->is_volatile) { ++ (*kctl)->get = volatile_get_volsw; ++ (*kctl)->put = volatile_put_volsw; ++ } else { ++ (*kctl)->get = snd_soc_get_volsw; ++ (*kctl)->put = snd_soc_put_volsw; ++ } + + if (readonly_control(control)) + (*kctl)->access = SNDRV_CTL_ELEM_ACCESS_READ; +-- +2.51.0 + diff --git a/queue-6.19/asoc-sdca-remove-outdated-todo-comment.patch b/queue-6.19/asoc-sdca-remove-outdated-todo-comment.patch new file mode 100644 index 0000000000..a6ecf53782 --- /dev/null +++ b/queue-6.19/asoc-sdca-remove-outdated-todo-comment.patch @@ -0,0 +1,41 @@ +From 8d7599e3def1b2f8880f447ab40c5ce06dafbd1d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 12:59:38 +0000 +Subject: ASoC: SDCA: Remove outdated todo comment + +From: Charles Keepax + +[ Upstream commit b27b57f85fe3f0eca479556ac55bc9cbd1a5685a ] + +Support for -cn- properties has already been added, however the TODO +comment noting this feature was required was not removed. Remove the +now redundant comment. + +Fixes: 50a479527ef01 ("ASoC: SDCA: Add support for -cn- value properties") +Signed-off-by: Charles Keepax +Link: https://patch.msgid.link/20260204125944.1134011-2-ckeepax@opensource.cirrus.com +Reviewed-by: Pierre-Louis Bossart +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sdca/sdca_functions.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c +index 5a1f120487ef0..e86004c9dea03 100644 +--- a/sound/soc/sdca/sdca_functions.c ++++ b/sound/soc/sdca/sdca_functions.c +@@ -911,10 +911,6 @@ static int find_sdca_control_value(struct device *dev, struct sdca_entity *entit + return 0; + } + +-/* +- * TODO: Add support for -cn- properties, allowing different channels to have +- * different defaults etc. +- */ + static int find_sdca_entity_control(struct device *dev, struct sdca_entity *entity, + struct fwnode_handle *control_node, + struct sdca_control *control) +-- +2.51.0 + diff --git a/queue-6.19/asoc-sdca-still-process-most-of-the-jack-detect-if-c.patch b/queue-6.19/asoc-sdca-still-process-most-of-the-jack-detect-if-c.patch new file mode 100644 index 0000000000..af5766dad2 --- /dev/null +++ b/queue-6.19/asoc-sdca-still-process-most-of-the-jack-detect-if-c.patch @@ -0,0 +1,130 @@ +From d711a9e33b4b8102f9144ef14525319a8590943a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 12:59:40 +0000 +Subject: ASoC: SDCA: Still process most of the jack detect if control is + missing + +From: Charles Keepax + +[ Upstream commit d7730c44b7dddbc5063505ce9e0c21d8bf298368 ] + +DAPM creates its controls very late in the card creation, so +there is no call into the driver after the controls are created. This +means the jack IRQs can't be guaranteed to be registered after the ALSA +controls are available. If a jack IRQ is received before the controls +are available, currently the driver does not update the Selected Mode as +it is required by the specification to do. + +If the ALSA controls are not available update the Selected Mode directly +rather than going through the ALSA control. The ALSA control should pick +up the state once it is created. + +Fixes: b9ab3b618241 ("ASoC: SDCA: Add some initial IRQ handlers") +Signed-off-by: Charles Keepax +Link: https://patch.msgid.link/20260204125944.1134011-4-ckeepax@opensource.cirrus.com +Reviewed-by: Pierre-Louis Bossart +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sdca/sdca_jack.c | 52 ++++++++++++++++++++------------------ + 1 file changed, 28 insertions(+), 24 deletions(-) + +diff --git a/sound/soc/sdca/sdca_jack.c b/sound/soc/sdca/sdca_jack.c +index 5b9cf69cbcd6b..bfa621b744e1a 100644 +--- a/sound/soc/sdca/sdca_jack.c ++++ b/sound/soc/sdca/sdca_jack.c +@@ -41,10 +41,11 @@ int sdca_jack_process(struct sdca_interrupt *interrupt) + struct jack_state *state = interrupt->priv; + struct snd_kcontrol *kctl = state->kctl; + struct snd_ctl_elem_value *ucontrol __free(kfree) = NULL; +- struct soc_enum *soc_enum; + unsigned int reg, val; + int ret; + ++ guard(rwsem_write)(rwsem); ++ + if (!kctl) { + const char *name __free(kfree) = kasprintf(GFP_KERNEL, "%s %s", + interrupt->entity->label, +@@ -54,16 +55,12 @@ int sdca_jack_process(struct sdca_interrupt *interrupt) + return -ENOMEM; + + kctl = snd_soc_component_get_kcontrol(component, name); +- if (!kctl) { ++ if (!kctl) + dev_dbg(dev, "control not found: %s\n", name); +- return -ENOENT; +- } +- +- state->kctl = kctl; ++ else ++ state->kctl = kctl; + } + +- soc_enum = (struct soc_enum *)kctl->private_value; +- + reg = SDW_SDCA_CTL(interrupt->function->desc->adr, interrupt->entity->id, + interrupt->control->sel, 0); + +@@ -73,13 +70,12 @@ int sdca_jack_process(struct sdca_interrupt *interrupt) + return ret; + } + ++ reg = SDW_SDCA_CTL(interrupt->function->desc->adr, interrupt->entity->id, ++ SDCA_CTL_GE_SELECTED_MODE, 0); ++ + switch (val) { + case SDCA_DETECTED_MODE_DETECTION_IN_PROGRESS: + case SDCA_DETECTED_MODE_JACK_UNKNOWN: +- reg = SDW_SDCA_CTL(interrupt->function->desc->adr, +- interrupt->entity->id, +- SDCA_CTL_GE_SELECTED_MODE, 0); +- + /* + * Selected mode is not normally marked as volatile register + * (RW), but here force a read from the hardware. If the +@@ -100,21 +96,29 @@ int sdca_jack_process(struct sdca_interrupt *interrupt) + + dev_dbg(dev, "%s: %#x\n", interrupt->name, val); + +- ucontrol = kzalloc(sizeof(*ucontrol), GFP_KERNEL); +- if (!ucontrol) +- return -ENOMEM; ++ if (kctl) { ++ struct soc_enum *soc_enum = (struct soc_enum *)kctl->private_value; ++ ++ ucontrol = kzalloc(sizeof(*ucontrol), GFP_KERNEL); ++ if (!ucontrol) ++ return -ENOMEM; + +- ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(soc_enum, val); ++ ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(soc_enum, val); + +- down_write(rwsem); +- ret = kctl->put(kctl, ucontrol); +- up_write(rwsem); +- if (ret < 0) { +- dev_err(dev, "failed to update selected mode: %d\n", ret); +- return ret; +- } ++ ret = kctl->put(kctl, ucontrol); ++ if (ret < 0) { ++ dev_err(dev, "failed to update selected mode: %d\n", ret); ++ return ret; ++ } + +- snd_ctl_notify(card->snd_card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); ++ snd_ctl_notify(card->snd_card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); ++ } else { ++ ret = regmap_write(interrupt->function_regmap, reg, val); ++ if (ret) { ++ dev_err(dev, "failed to write selected mode: %d\n", ret); ++ return ret; ++ } ++ } + + return sdca_jack_report(interrupt); + } +-- +2.51.0 + diff --git a/queue-6.19/asoc-tegra-add-ahub-writeable_reg-for-rx-holes.patch b/queue-6.19/asoc-tegra-add-ahub-writeable_reg-for-rx-holes.patch new file mode 100644 index 0000000000..e50a5a5f94 --- /dev/null +++ b/queue-6.19/asoc-tegra-add-ahub-writeable_reg-for-rx-holes.patch @@ -0,0 +1,151 @@ +From cafb97eb8ec487341ab48b3509bf7bac99f060ee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 15:23:43 +0530 +Subject: ASoC: tegra: Add AHUB writeable_reg for RX holes + +From: Sheetal + +[ Upstream commit 0ba6286a71581aaf8413a55b9bd90ea3463fd23b ] + +Add writeable_reg callbacks for Tegra210/186 AHUB RX registers so the +flat cache only treats valid RX locations as writable, avoiding holes +in the register map. + +Fixes: 16e1bcc2caf4 ("ASoC: tegra: Add Tegra210 based AHUB driver") +Signed-off-by: Sheetal +Reviewed-by: Jon Hunter +Tested-by: Jon Hunter +Link: https://patch.msgid.link/20260123095346.1258556-2-sheetal@nvidia.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/tegra/tegra210_ahub.c | 57 +++++++++++++++++++++++++++++++++ + sound/soc/tegra/tegra210_ahub.h | 30 +++++++++++++++++ + 2 files changed, 87 insertions(+) + +diff --git a/sound/soc/tegra/tegra210_ahub.c b/sound/soc/tegra/tegra210_ahub.c +index e795907a3963a..fc5892056f832 100644 +--- a/sound/soc/tegra/tegra210_ahub.c ++++ b/sound/soc/tegra/tegra210_ahub.c +@@ -2049,6 +2049,61 @@ static const struct snd_soc_component_driver tegra264_ahub_component = { + .num_dapm_routes = ARRAY_SIZE(tegra264_ahub_routes), + }; + ++static bool tegra210_ahub_wr_reg(struct device *dev, unsigned int reg) ++{ ++ int part; ++ ++ if (reg % TEGRA210_XBAR_RX_STRIDE) ++ return false; ++ ++ for (part = 0; part < TEGRA210_XBAR_UPDATE_MAX_REG; part++) { ++ switch (reg & ~(part * TEGRA210_XBAR_PART1_RX)) { ++ case TEGRA210_AXBAR_PART_0_ADMAIF_RX1_0 ... TEGRA210_AXBAR_PART_0_ADMAIF_RX10_0: ++ case TEGRA210_AXBAR_PART_0_I2S1_RX1_0 ... TEGRA210_AXBAR_PART_0_I2S5_RX1_0: ++ case TEGRA210_AXBAR_PART_0_SFC1_RX1_0 ... TEGRA210_AXBAR_PART_0_SFC4_RX1_0: ++ case TEGRA210_AXBAR_PART_0_MIXER1_RX1_0 ... TEGRA210_AXBAR_PART_0_MIXER1_RX10_0: ++ case TEGRA210_AXBAR_PART_0_SPDIF1_RX1_0 ... TEGRA210_AXBAR_PART_0_SPDIF1_RX2_0: ++ case TEGRA210_AXBAR_PART_0_AFC1_RX1_0 ... TEGRA210_AXBAR_PART_0_AFC6_RX1_0: ++ case TEGRA210_AXBAR_PART_0_OPE1_RX1_0 ... TEGRA210_AXBAR_PART_0_OPE2_RX1_0: ++ case TEGRA210_AXBAR_PART_0_SPKPROT1_RX1_0: ++ case TEGRA210_AXBAR_PART_0_MVC1_RX1_0 ... TEGRA210_AXBAR_PART_0_MVC2_RX1_0: ++ case TEGRA210_AXBAR_PART_0_AMX1_RX1_0 ... TEGRA210_AXBAR_PART_0_ADX2_RX1_0: ++ return true; ++ default: ++ break; ++ } ++ } ++ ++ return false; ++} ++ ++static bool tegra186_ahub_wr_reg(struct device *dev, unsigned int reg) ++{ ++ int part; ++ ++ if (reg % TEGRA210_XBAR_RX_STRIDE) ++ return false; ++ ++ for (part = 0; part < TEGRA186_XBAR_UPDATE_MAX_REG; part++) { ++ switch (reg & ~(part * TEGRA210_XBAR_PART1_RX)) { ++ case TEGRA210_AXBAR_PART_0_ADMAIF_RX1_0 ... TEGRA186_AXBAR_PART_0_I2S6_RX1_0: ++ case TEGRA210_AXBAR_PART_0_SFC1_RX1_0 ... TEGRA210_AXBAR_PART_0_SFC4_RX1_0: ++ case TEGRA210_AXBAR_PART_0_MIXER1_RX1_0 ... TEGRA210_AXBAR_PART_0_MIXER1_RX10_0: ++ case TEGRA186_AXBAR_PART_0_DSPK1_RX1_0 ... TEGRA186_AXBAR_PART_0_DSPK2_RX1_0: ++ case TEGRA210_AXBAR_PART_0_AFC1_RX1_0 ... TEGRA210_AXBAR_PART_0_AFC6_RX1_0: ++ case TEGRA210_AXBAR_PART_0_OPE1_RX1_0: ++ case TEGRA186_AXBAR_PART_0_MVC1_RX1_0 ... TEGRA186_AXBAR_PART_0_MVC2_RX1_0: ++ case TEGRA186_AXBAR_PART_0_AMX1_RX1_0 ... TEGRA186_AXBAR_PART_0_AMX3_RX4_0: ++ case TEGRA210_AXBAR_PART_0_ADX1_RX1_0 ... TEGRA186_AXBAR_PART_0_ASRC1_RX7_0: ++ return true; ++ default: ++ break; ++ } ++ } ++ ++ return false; ++} ++ + static bool tegra264_ahub_wr_reg(struct device *dev, unsigned int reg) + { + int part; +@@ -2076,6 +2131,7 @@ static const struct regmap_config tegra210_ahub_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, ++ .writeable_reg = tegra210_ahub_wr_reg, + .max_register = TEGRA210_MAX_REGISTER_ADDR, + .cache_type = REGCACHE_FLAT, + }; +@@ -2084,6 +2140,7 @@ static const struct regmap_config tegra186_ahub_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, ++ .writeable_reg = tegra186_ahub_wr_reg, + .max_register = TEGRA186_MAX_REGISTER_ADDR, + .cache_type = REGCACHE_FLAT, + }; +diff --git a/sound/soc/tegra/tegra210_ahub.h b/sound/soc/tegra/tegra210_ahub.h +index f355b2cfd19b2..acbe640dd3b57 100644 +--- a/sound/soc/tegra/tegra210_ahub.h ++++ b/sound/soc/tegra/tegra210_ahub.h +@@ -68,6 +68,36 @@ + #define TEGRA210_MAX_REGISTER_ADDR (TEGRA210_XBAR_PART2_RX + \ + (TEGRA210_XBAR_RX_STRIDE * (TEGRA210_XBAR_AUDIO_RX_COUNT - 1))) + ++/* AXBAR register offsets */ ++#define TEGRA186_AXBAR_PART_0_AMX1_RX1_0 0x120 ++#define TEGRA186_AXBAR_PART_0_AMX3_RX4_0 0x14c ++#define TEGRA186_AXBAR_PART_0_ASRC1_RX7_0 0x1a8 ++#define TEGRA186_AXBAR_PART_0_DSPK1_RX1_0 0xc0 ++#define TEGRA186_AXBAR_PART_0_DSPK2_RX1_0 0xc4 ++#define TEGRA186_AXBAR_PART_0_I2S6_RX1_0 0x54 ++#define TEGRA186_AXBAR_PART_0_MVC1_RX1_0 0x110 ++#define TEGRA186_AXBAR_PART_0_MVC2_RX1_0 0x114 ++#define TEGRA210_AXBAR_PART_0_ADMAIF_RX10_0 0x24 ++#define TEGRA210_AXBAR_PART_0_ADMAIF_RX1_0 0x0 ++#define TEGRA210_AXBAR_PART_0_ADX1_RX1_0 0x160 ++#define TEGRA210_AXBAR_PART_0_ADX2_RX1_0 0x164 ++#define TEGRA210_AXBAR_PART_0_AFC1_RX1_0 0xd0 ++#define TEGRA210_AXBAR_PART_0_AFC6_RX1_0 0xe4 ++#define TEGRA210_AXBAR_PART_0_AMX1_RX1_0 0x140 ++#define TEGRA210_AXBAR_PART_0_I2S1_RX1_0 0x40 ++#define TEGRA210_AXBAR_PART_0_I2S5_RX1_0 0x50 ++#define TEGRA210_AXBAR_PART_0_MIXER1_RX10_0 0xa4 ++#define TEGRA210_AXBAR_PART_0_MIXER1_RX1_0 0x80 ++#define TEGRA210_AXBAR_PART_0_MVC1_RX1_0 0x120 ++#define TEGRA210_AXBAR_PART_0_MVC2_RX1_0 0x124 ++#define TEGRA210_AXBAR_PART_0_OPE1_RX1_0 0x100 ++#define TEGRA210_AXBAR_PART_0_OPE2_RX1_0 0x104 ++#define TEGRA210_AXBAR_PART_0_SFC1_RX1_0 0x60 ++#define TEGRA210_AXBAR_PART_0_SFC4_RX1_0 0x6c ++#define TEGRA210_AXBAR_PART_0_SPDIF1_RX1_0 0xc0 ++#define TEGRA210_AXBAR_PART_0_SPDIF1_RX2_0 0xc4 ++#define TEGRA210_AXBAR_PART_0_SPKPROT1_RX1_0 0x110 ++ + #define MUX_REG(id) (TEGRA210_XBAR_RX_STRIDE * (id)) + + #define MUX_VALUE(npart, nbit) (1 + (nbit) + (npart) * 32) +-- +2.51.0 + diff --git a/queue-6.19/ata-libata-add-ata_quirk_max_sec-and-convert-all-dev.patch b/queue-6.19/ata-libata-add-ata_quirk_max_sec-and-convert-all-dev.patch new file mode 100644 index 0000000000..4d95a1e7ac --- /dev/null +++ b/queue-6.19/ata-libata-add-ata_quirk_max_sec-and-convert-all-dev.patch @@ -0,0 +1,203 @@ +From 4ef36eedaba360256bf2a1269552e39338d81eb0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Dec 2025 13:21:31 +0100 +Subject: ata: libata: Add ATA_QUIRK_MAX_SEC and convert all device quirks + +From: Niklas Cassel + +[ Upstream commit 59b7bb3d48333889adb1dd2aac3ab0cf26714390 ] + +Add a new quirk ATA_QUIRK_MAX_SEC, which has a separate table with device +specific values. + +Convert all existing ATA_QUIRK_MAX_SEC_XXX device quirks in +__ata_dev_quirks to the new format. + +Quirks ATA_QUIRK_MAX_SEC_128 and ATA_QUIRK_MAX_SEC_1024 cannot be removed +yet, since they are also used by libata.force, which functionally, is a +separate user of the quirks. The quirks will be removed once all users +have been converted to use the new format. + +The quirk ATA_QUIRK_MAX_SEC_8191 can be removed since it has no equivalent +libata.force parameter. + +Signed-off-by: Niklas Cassel +Reviewed-by: Damien Le Moal +Reviewed-by: Martin K. Petersen +Signed-off-by: Damien Le Moal +Stable-dep-of: 5f64ae1ef639 ("ata: libata-core: Quirk INTEL SSDSC2KG480G8 max_sectors") +Signed-off-by: Sasha Levin +--- + drivers/ata/libata-core.c | 68 +++++++++++++++++++++++++++++++++------ + include/linux/ata.h | 1 - + include/linux/libata.h | 4 +-- + 3 files changed, 61 insertions(+), 12 deletions(-) + +diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c +index ddf9a7b28a594..d5151b9ca9141 100644 +--- a/drivers/ata/libata-core.c ++++ b/drivers/ata/libata-core.c +@@ -77,6 +77,7 @@ static unsigned int ata_dev_init_params(struct ata_device *dev, + static unsigned int ata_dev_set_xfermode(struct ata_device *dev); + static void ata_dev_xfermask(struct ata_device *dev); + static unsigned int ata_dev_quirks(const struct ata_device *dev); ++static u64 ata_dev_get_quirk_value(struct ata_device *dev, unsigned int quirk); + + static DEFINE_IDA(ata_ida); + +@@ -3152,9 +3153,10 @@ int ata_dev_configure(struct ata_device *dev) + dev->max_sectors = min_t(unsigned int, ATA_MAX_SECTORS_1024, + dev->max_sectors); + +- if (dev->quirks & ATA_QUIRK_MAX_SEC_8191) +- dev->max_sectors = min_t(unsigned int, ATA_MAX_SECTORS_8191, +- dev->max_sectors); ++ if (dev->quirks & ATA_QUIRK_MAX_SEC) ++ dev->max_sectors = min_t(unsigned int, dev->max_sectors, ++ ata_dev_get_quirk_value(dev, ++ ATA_QUIRK_MAX_SEC)); + + if (dev->quirks & ATA_QUIRK_MAX_SEC_LBA48) + dev->max_sectors = ATA_MAX_SECTORS_LBA48; +@@ -4008,7 +4010,7 @@ static const char * const ata_quirk_names[] = { + [__ATA_QUIRK_NO_DMA_LOG] = "nodmalog", + [__ATA_QUIRK_NOTRIM] = "notrim", + [__ATA_QUIRK_MAX_SEC_1024] = "maxsec1024", +- [__ATA_QUIRK_MAX_SEC_8191] = "maxsec8191", ++ [__ATA_QUIRK_MAX_SEC] = "maxsec", + [__ATA_QUIRK_MAX_TRIM_128M] = "maxtrim128m", + [__ATA_QUIRK_NO_NCQ_ON_ATI] = "noncqonati", + [__ATA_QUIRK_NO_LPM_ON_ATI] = "nolpmonati", +@@ -4053,6 +4055,21 @@ static void ata_dev_print_quirks(const struct ata_device *dev, + kfree(str); + } + ++struct ata_dev_quirk_value { ++ const char *model_num; ++ const char *model_rev; ++ u64 val; ++}; ++ ++static const struct ata_dev_quirk_value __ata_dev_max_sec_quirks[] = { ++ { "TORiSAN DVD-ROM DRD-N216", NULL, 128 }, ++ { "ST380013AS", "3.20", 1024 }, ++ { "LITEON CX1-JB*-HP", NULL, 1024 }, ++ { "LITEON EP1-*", NULL, 1024 }, ++ { "DELLBOSS VD", "MV.R00-0", 8191 }, ++ { }, ++}; ++ + struct ata_dev_quirks_entry { + const char *model_num; + const char *model_rev; +@@ -4097,7 +4114,7 @@ static const struct ata_dev_quirks_entry __ata_dev_quirks[] = { + { "ASMT109x- Config", NULL, ATA_QUIRK_DISABLE }, + + /* Weird ATAPI devices */ +- { "TORiSAN DVD-ROM DRD-N216", NULL, ATA_QUIRK_MAX_SEC_128 }, ++ { "TORiSAN DVD-ROM DRD-N216", NULL, ATA_QUIRK_MAX_SEC }, + { "QUANTUM DAT DAT72-000", NULL, ATA_QUIRK_ATAPI_MOD16_DMA }, + { "Slimtype DVD A DS8A8SH", NULL, ATA_QUIRK_MAX_SEC_LBA48 }, + { "Slimtype DVD A DS8A9SH", NULL, ATA_QUIRK_MAX_SEC_LBA48 }, +@@ -4106,20 +4123,20 @@ static const struct ata_dev_quirks_entry __ata_dev_quirks[] = { + * Causes silent data corruption with higher max sects. + * http://lkml.kernel.org/g/x49wpy40ysk.fsf@segfault.boston.devel.redhat.com + */ +- { "ST380013AS", "3.20", ATA_QUIRK_MAX_SEC_1024 }, ++ { "ST380013AS", "3.20", ATA_QUIRK_MAX_SEC }, + + /* + * These devices time out with higher max sects. + * https://bugzilla.kernel.org/show_bug.cgi?id=121671 + */ +- { "LITEON CX1-JB*-HP", NULL, ATA_QUIRK_MAX_SEC_1024 }, +- { "LITEON EP1-*", NULL, ATA_QUIRK_MAX_SEC_1024 }, ++ { "LITEON CX1-JB*-HP", NULL, ATA_QUIRK_MAX_SEC }, ++ { "LITEON EP1-*", NULL, ATA_QUIRK_MAX_SEC }, + + /* + * These devices time out with higher max sects. + * https://bugzilla.kernel.org/show_bug.cgi?id=220693 + */ +- { "DELLBOSS VD", "MV.R00-0", ATA_QUIRK_MAX_SEC_8191 }, ++ { "DELLBOSS VD", "MV.R00-0", ATA_QUIRK_MAX_SEC }, + + /* Devices we expect to fail diagnostics */ + +@@ -4372,6 +4389,39 @@ static unsigned int ata_dev_quirks(const struct ata_device *dev) + return 0; + } + ++static u64 ata_dev_get_max_sec_quirk_value(struct ata_device *dev) ++{ ++ unsigned char model_num[ATA_ID_PROD_LEN + 1]; ++ unsigned char model_rev[ATA_ID_FW_REV_LEN + 1]; ++ const struct ata_dev_quirk_value *ad = __ata_dev_max_sec_quirks; ++ u64 val = 0; ++ ++ ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num)); ++ ata_id_c_string(dev->id, model_rev, ATA_ID_FW_REV, sizeof(model_rev)); ++ ++ while (ad->model_num) { ++ if (glob_match(ad->model_num, model_num) && ++ (!ad->model_rev || glob_match(ad->model_rev, model_rev))) { ++ val = ad->val; ++ break; ++ } ++ ad++; ++ } ++ ++ ata_dev_warn(dev, "%s quirk is using value: %llu\n", ++ ata_quirk_names[__ATA_QUIRK_MAX_SEC], val); ++ ++ return val; ++} ++ ++static u64 ata_dev_get_quirk_value(struct ata_device *dev, unsigned int quirk) ++{ ++ if (quirk == ATA_QUIRK_MAX_SEC) ++ return ata_dev_get_max_sec_quirk_value(dev); ++ ++ return 0; ++} ++ + static bool ata_dev_nodma(const struct ata_device *dev) + { + /* +diff --git a/include/linux/ata.h b/include/linux/ata.h +index 54b416e269959..c9013e472aa3d 100644 +--- a/include/linux/ata.h ++++ b/include/linux/ata.h +@@ -29,7 +29,6 @@ enum { + ATA_MAX_SECTORS_128 = 128, + ATA_MAX_SECTORS = 256, + ATA_MAX_SECTORS_1024 = 1024, +- ATA_MAX_SECTORS_8191 = 8191, + ATA_MAX_SECTORS_LBA48 = 65535,/* avoid count to be 0000h */ + ATA_MAX_SECTORS_TAPE = 65535, + ATA_MAX_TRIM_RNUM = 64, /* 512-byte payload / (6-byte LBA + 2-byte range per entry) */ +diff --git a/include/linux/libata.h b/include/linux/libata.h +index 39534fafa36ae..11b6a44572acd 100644 +--- a/include/linux/libata.h ++++ b/include/linux/libata.h +@@ -75,7 +75,7 @@ enum ata_quirks { + __ATA_QUIRK_NO_DMA_LOG, /* Do not use DMA for log read */ + __ATA_QUIRK_NOTRIM, /* Do not use TRIM */ + __ATA_QUIRK_MAX_SEC_1024, /* Limit max sects to 1024 */ +- __ATA_QUIRK_MAX_SEC_8191, /* Limit max sects to 8191 */ ++ __ATA_QUIRK_MAX_SEC, /* Limit max sectors */ + __ATA_QUIRK_MAX_TRIM_128M, /* Limit max trim size to 128M */ + __ATA_QUIRK_NO_NCQ_ON_ATI, /* Disable NCQ on ATI chipset */ + __ATA_QUIRK_NO_LPM_ON_ATI, /* Disable LPM on ATI chipset */ +@@ -116,7 +116,7 @@ enum { + ATA_QUIRK_NO_DMA_LOG = (1U << __ATA_QUIRK_NO_DMA_LOG), + ATA_QUIRK_NOTRIM = (1U << __ATA_QUIRK_NOTRIM), + ATA_QUIRK_MAX_SEC_1024 = (1U << __ATA_QUIRK_MAX_SEC_1024), +- ATA_QUIRK_MAX_SEC_8191 = (1U << __ATA_QUIRK_MAX_SEC_8191), ++ ATA_QUIRK_MAX_SEC = (1U << __ATA_QUIRK_MAX_SEC), + ATA_QUIRK_MAX_TRIM_128M = (1U << __ATA_QUIRK_MAX_TRIM_128M), + ATA_QUIRK_NO_NCQ_ON_ATI = (1U << __ATA_QUIRK_NO_NCQ_ON_ATI), + ATA_QUIRK_NO_LPM_ON_ATI = (1U << __ATA_QUIRK_NO_LPM_ON_ATI), +-- +2.51.0 + diff --git a/queue-6.19/ata-libata-core-quirk-intel-ssdsc2kg480g8-max_sector.patch b/queue-6.19/ata-libata-core-quirk-intel-ssdsc2kg480g8-max_sector.patch new file mode 100644 index 0000000000..54262197d1 --- /dev/null +++ b/queue-6.19/ata-libata-core-quirk-intel-ssdsc2kg480g8-max_sector.patch @@ -0,0 +1,54 @@ +From 2bac4fe2c9fd71d5ba7ec36e7217f4d703719520 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 11:32:38 +0100 +Subject: ata: libata-core: Quirk INTEL SSDSC2KG480G8 max_sectors + +From: Niklas Cassel + +[ Upstream commit 5f64ae1ef639a2bab7e39497c55f76cc0682f108 ] + +Commit 9b8b84879d4a ("block: Increase BLK_DEF_MAX_SECTORS_CAP") increased +the default max_sectors_kb from 1280 KiB to 4096 KiB. + +INTEL SSDSC2KG480G8 with FW rev XCV10120 times out when sending I/Os of +size 4096 KiB. + +Enable ATA_QUIRK_MAX_SEC, with value 8191 (sectors) for this device, +since any I/O with more sectors than that lead to I/O timeouts. + +With this, the INTEL SSDSC2KG480G8 is usable again. + +Link: https://lore.kernel.org/linux-ide/176839089913.2398366.61500945766820256@eldamar.lan/ +Fixes: 9b8b84879d4a ("block: Increase BLK_DEF_MAX_SECTORS_CAP") +Signed-off-by: Niklas Cassel +Reviewed-by: Martin K. Petersen +Signed-off-by: Damien Le Moal +Signed-off-by: Sasha Levin +--- + drivers/ata/libata-core.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c +index d5151b9ca9141..fb148b1c3bdbf 100644 +--- a/drivers/ata/libata-core.c ++++ b/drivers/ata/libata-core.c +@@ -4067,6 +4067,7 @@ static const struct ata_dev_quirk_value __ata_dev_max_sec_quirks[] = { + { "LITEON CX1-JB*-HP", NULL, 1024 }, + { "LITEON EP1-*", NULL, 1024 }, + { "DELLBOSS VD", "MV.R00-0", 8191 }, ++ { "INTEL SSDSC2KG480G8", "XCV10120", 8191 }, + { }, + }; + +@@ -4324,6 +4325,8 @@ static const struct ata_dev_quirks_entry __ata_dev_quirks[] = { + + { "Micron*", NULL, ATA_QUIRK_ZERO_AFTER_TRIM }, + { "Crucial*", NULL, ATA_QUIRK_ZERO_AFTER_TRIM }, ++ { "INTEL SSDSC2KG480G8", "XCV10120", ATA_QUIRK_ZERO_AFTER_TRIM | ++ ATA_QUIRK_MAX_SEC }, + { "INTEL*SSD*", NULL, ATA_QUIRK_ZERO_AFTER_TRIM }, + { "SSD*INTEL*", NULL, ATA_QUIRK_ZERO_AFTER_TRIM }, + { "Samsung*SSD*", NULL, ATA_QUIRK_ZERO_AFTER_TRIM }, +-- +2.51.0 + diff --git a/queue-6.19/audit-move-the-compat_xxx_class-extern-declarations-.patch b/queue-6.19/audit-move-the-compat_xxx_class-extern-declarations-.patch new file mode 100644 index 0000000000..5ebdc9b944 --- /dev/null +++ b/queue-6.19/audit-move-the-compat_xxx_class-extern-declarations-.patch @@ -0,0 +1,77 @@ +From 5917c6b04b69ee62c9c04411e848112a58e6a8d9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 13:39:38 +0000 +Subject: audit: move the compat_xxx_class[] extern declarations to + audit_arch.h + +From: Ben Dooks + +[ Upstream commit 76489955c6d4a065ca69dc88faf7a50a59b66f35 ] + +The comapt_xxx_class symbols aren't declared in anything that +lib/comapt_audit.c is including (arm64 build) which is causing +the following sparse warnings: + +lib/compat_audit.c:7:10: warning: symbol 'compat_dir_class' + was not declared. Should it be static? +lib/compat_audit.c:12:10: warning: symbol 'compat_read_class' + was not declared. Should it be static? +lib/compat_audit.c:17:10: warning: symbol 'compat_write_class' + was not declared. Should it be static? +lib/compat_audit.c:22:10: warning: symbol 'compat_chattr_class' + was not declared. Should it be static? +lib/compat_audit.c:27:10: warning: symbol 'compat_signal_class' + was not declared. Should it be static? + +Trying to fix this by chaning compat_audit.c to inclde +does not work on arm64 due to compile errors with the extra includes +that changing this header makes. The simpler thing would be just to +move the definitons of these symbols out of into + which is included. + +Fixes: 4b58841149dca ("audit: Add generic compat syscall support") +Signed-off-by: Ben Dooks +[PM: rewrite subject line, fixed line length in description] +Signed-off-by: Paul Moore +Signed-off-by: Sasha Levin +--- + include/linux/audit.h | 6 ------ + include/linux/audit_arch.h | 7 +++++++ + 2 files changed, 7 insertions(+), 6 deletions(-) + +diff --git a/include/linux/audit.h b/include/linux/audit.h +index 536f8ee8da818..b8d8029c6c480 100644 +--- a/include/linux/audit.h ++++ b/include/linux/audit.h +@@ -128,12 +128,6 @@ enum audit_nfcfgop { + extern int __init audit_register_class(int class, unsigned *list); + extern int audit_classify_syscall(int abi, unsigned syscall); + extern int audit_classify_arch(int arch); +-/* only for compat system calls */ +-extern unsigned compat_write_class[]; +-extern unsigned compat_read_class[]; +-extern unsigned compat_dir_class[]; +-extern unsigned compat_chattr_class[]; +-extern unsigned compat_signal_class[]; + + /* audit_names->type values */ + #define AUDIT_TYPE_UNKNOWN 0 /* we don't know yet */ +diff --git a/include/linux/audit_arch.h b/include/linux/audit_arch.h +index 0e34d673ef171..2b8153791e6a5 100644 +--- a/include/linux/audit_arch.h ++++ b/include/linux/audit_arch.h +@@ -23,4 +23,11 @@ enum auditsc_class_t { + + extern int audit_classify_compat_syscall(int abi, unsigned syscall); + ++/* only for compat system calls */ ++extern unsigned compat_write_class[]; ++extern unsigned compat_read_class[]; ++extern unsigned compat_dir_class[]; ++extern unsigned compat_chattr_class[]; ++extern unsigned compat_signal_class[]; ++ + #endif +-- +2.51.0 + diff --git a/queue-6.19/auxdisplay-arm-charlcd-fix-release_mem_region-size.patch b/queue-6.19/auxdisplay-arm-charlcd-fix-release_mem_region-size.patch new file mode 100644 index 0000000000..f678ce6033 --- /dev/null +++ b/queue-6.19/auxdisplay-arm-charlcd-fix-release_mem_region-size.patch @@ -0,0 +1,39 @@ +From 3419f598f270f7fa427c3665aed517618627925d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Dec 2025 18:47:13 +0100 +Subject: auxdisplay: arm-charlcd: fix release_mem_region() size + +From: Thomas Fourier + +[ Upstream commit b5c23a4d291d2ac1dfdd574a68a3a68c8da3069e ] + +It seems like, after the request_mem_region(), the corresponding +release_mem_region() must take the same size. This was done +in (now removed due to previous refactoring) charlcd_remove() +but not in the error path in charlcd_probe(). + +Fixes: ce8962455e90 ("ARM: 6214/2: driver for the character LCD found in ARM refdesigns") +Signed-off-by: Thomas Fourier +Reviewed-by: Geert Uytterhoeven +Signed-off-by: Andy Shevchenko +Signed-off-by: Sasha Levin +--- + drivers/auxdisplay/arm-charlcd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/auxdisplay/arm-charlcd.c b/drivers/auxdisplay/arm-charlcd.c +index a7eae99a48f77..4e22882f57c9c 100644 +--- a/drivers/auxdisplay/arm-charlcd.c ++++ b/drivers/auxdisplay/arm-charlcd.c +@@ -323,7 +323,7 @@ static int __init charlcd_probe(struct platform_device *pdev) + out_no_irq: + iounmap(lcd->virtbase); + out_no_memregion: +- release_mem_region(lcd->phybase, SZ_4K); ++ release_mem_region(lcd->phybase, lcd->physize); + out_no_resource: + kfree(lcd); + return ret; +-- +2.51.0 + diff --git a/queue-6.19/backlight-aw99706-fix-build-errors-caused-by-wrong-g.patch b/queue-6.19/backlight-aw99706-fix-build-errors-caused-by-wrong-g.patch new file mode 100644 index 0000000000..becbd16938 --- /dev/null +++ b/queue-6.19/backlight-aw99706-fix-build-errors-caused-by-wrong-g.patch @@ -0,0 +1,50 @@ +From 44d861dbf8a33dac1aba00c168f2d4eb88e494c7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 11 Jan 2026 21:01:17 +0800 +Subject: backlight: aw99706: Fix build errors caused by wrong gpio header + +From: Junjie Cao + +[ Upstream commit b7db7d9c4ffc04210fe631f73a81746d6e2ef24b ] + +The driver uses GPIO descriptor API (devm_gpiod_get, +gpiod_set_value_cansleep, GPIOD_OUT_LOW) but includes the legacy + header instead of . + +When CONFIG_GPIOLIB is not set, does not include +, causing build errors: + + error: implicit declaration of function 'gpiod_set_value_cansleep' + error: implicit declaration of function 'devm_gpiod_get' + error: 'GPIOD_OUT_LOW' undeclared + +Fix by including the correct header . + +Fixes: 147b38a5ad06 ("backlight: aw99706: Add support for Awinic AW99706 backlight") +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202512171631.uKXlYwqu-lkp@intel.com/ +Signed-off-by: Junjie Cao +Reviewed-by: Daniel Thompson (RISCstar) +Link: https://patch.msgid.link/20260111130117.5041-1-junjie.cao@intel.com +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/video/backlight/aw99706.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/video/backlight/aw99706.c b/drivers/video/backlight/aw99706.c +index df5b23b2f7534..938f352aaab7f 100644 +--- a/drivers/video/backlight/aw99706.c ++++ b/drivers/video/backlight/aw99706.c +@@ -12,7 +12,7 @@ + #include + #include + #include +-#include ++#include + #include + #include + #include +-- +2.51.0 + diff --git a/queue-6.19/backlight-qcom-wled-change-pm8950-wled-configuration.patch b/queue-6.19/backlight-qcom-wled-change-pm8950-wled-configuration.patch new file mode 100644 index 0000000000..eea5ceec11 --- /dev/null +++ b/queue-6.19/backlight-qcom-wled-change-pm8950-wled-configuration.patch @@ -0,0 +1,42 @@ +From 2835c211e87a00e1d6e1218127badcd39fff5462 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 08:07:36 +0100 +Subject: backlight: qcom-wled: Change PM8950 WLED configurations +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Czémán + +[ Upstream commit 83333aa97441ba7ce32b91e8a007c72d316a1c67 ] + +PMI8950 WLED needs same configurations as PMI8994 WLED. + +Fixes: 10258bf4534b ("backlight: qcom-wled: Add PMI8950 compatible") +Signed-off-by: Barnabás Czémán +Reviewed-by: Konrad Dybcio +Reviewed-by: Daniel Thompson (RISCstar) +Link: https://patch.msgid.link/20260116-pmi8950-wled-v3-4-e6c93de84079@mainlining.org +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/video/backlight/qcom-wled.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c +index 5decbd39b7899..8054e4787725e 100644 +--- a/drivers/video/backlight/qcom-wled.c ++++ b/drivers/video/backlight/qcom-wled.c +@@ -1455,7 +1455,8 @@ static int wled_configure(struct wled *wled) + break; + + case 4: +- if (of_device_is_compatible(dev->of_node, "qcom,pmi8994-wled")) { ++ if (of_device_is_compatible(dev->of_node, "qcom,pmi8950-wled") || ++ of_device_is_compatible(dev->of_node, "qcom,pmi8994-wled")) { + u32_opts = pmi8994_wled_opts; + size = ARRAY_SIZE(pmi8994_wled_opts); + } else { +-- +2.51.0 + diff --git a/queue-6.19/backlight-qcom-wled-support-ovp-values-for-pmi8994.patch b/queue-6.19/backlight-qcom-wled-support-ovp-values-for-pmi8994.patch new file mode 100644 index 0000000000..ecae6020c4 --- /dev/null +++ b/queue-6.19/backlight-qcom-wled-support-ovp-values-for-pmi8994.patch @@ -0,0 +1,94 @@ +From 413e3f776502bd13f5e7f0df59ae854c8d1bc61b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 08:07:34 +0100 +Subject: backlight: qcom-wled: Support ovp values for PMI8994 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Czémán + +[ Upstream commit f29f972a6e7e3f187ea4d89b98a76c1981ca4d53 ] + +WLED4 found in PMI8994 supports different ovp values. + +Fixes: 6fc632d3e3e0 ("video: backlight: qcom-wled: Add PMI8994 compatible") +Signed-off-by: Barnabás Czémán +Reviewed-by: Konrad Dybcio +Reviewed-by: Daniel Thompson (RISCstar) +Link: https://patch.msgid.link/20260116-pmi8950-wled-v3-2-e6c93de84079@mainlining.org +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/video/backlight/qcom-wled.c | 41 +++++++++++++++++++++++++++-- + 1 file changed, 39 insertions(+), 2 deletions(-) + +diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c +index a63bb42c8f8b0..5decbd39b7899 100644 +--- a/drivers/video/backlight/qcom-wled.c ++++ b/drivers/video/backlight/qcom-wled.c +@@ -1244,6 +1244,15 @@ static const struct wled_var_cfg wled4_ovp_cfg = { + .size = ARRAY_SIZE(wled4_ovp_values), + }; + ++static const u32 pmi8994_wled_ovp_values[] = { ++ 31000, 29500, 19400, 17800, ++}; ++ ++static const struct wled_var_cfg pmi8994_wled_ovp_cfg = { ++ .values = pmi8994_wled_ovp_values, ++ .size = ARRAY_SIZE(pmi8994_wled_ovp_values), ++}; ++ + static inline u32 wled5_ovp_values_fn(u32 idx) + { + /* +@@ -1357,6 +1366,29 @@ static int wled_configure(struct wled *wled) + }, + }; + ++ const struct wled_u32_opts pmi8994_wled_opts[] = { ++ { ++ .name = "qcom,current-boost-limit", ++ .val_ptr = &cfg->boost_i_limit, ++ .cfg = &wled4_boost_i_limit_cfg, ++ }, ++ { ++ .name = "qcom,current-limit-microamp", ++ .val_ptr = &cfg->string_i_limit, ++ .cfg = &wled4_string_i_limit_cfg, ++ }, ++ { ++ .name = "qcom,ovp-millivolt", ++ .val_ptr = &cfg->ovp, ++ .cfg = &pmi8994_wled_ovp_cfg, ++ }, ++ { ++ .name = "qcom,switching-freq", ++ .val_ptr = &cfg->switch_freq, ++ .cfg = &wled3_switch_freq_cfg, ++ }, ++ }; ++ + const struct wled_u32_opts wled5_opts[] = { + { + .name = "qcom,current-boost-limit", +@@ -1423,8 +1455,13 @@ static int wled_configure(struct wled *wled) + break; + + case 4: +- u32_opts = wled4_opts; +- size = ARRAY_SIZE(wled4_opts); ++ if (of_device_is_compatible(dev->of_node, "qcom,pmi8994-wled")) { ++ u32_opts = pmi8994_wled_opts; ++ size = ARRAY_SIZE(pmi8994_wled_opts); ++ } else { ++ u32_opts = wled4_opts; ++ size = ARRAY_SIZE(wled4_opts); ++ } + *cfg = wled4_config_defaults; + wled->wled_set_brightness = wled4_set_brightness; + wled->wled_sync_toggle = wled3_sync_toggle; +-- +2.51.0 + diff --git a/queue-6.19/block-allow-ioc_pr_read_-ioctls-with-blk_open_read.patch b/queue-6.19/block-allow-ioc_pr_read_-ioctls-with-blk_open_read.patch new file mode 100644 index 0000000000..4405a5081a --- /dev/null +++ b/queue-6.19/block-allow-ioc_pr_read_-ioctls-with-blk_open_read.patch @@ -0,0 +1,146 @@ +From 6e299d1823e817932298e037a4a2e8a7722280f8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Feb 2026 11:36:17 -0500 +Subject: block: allow IOC_PR_READ_* ioctls with BLK_OPEN_READ + +From: Stefan Hajnoczi + +[ Upstream commit 5b88af7113feba2f0ae3402bb57cb5c94eea7dc3 ] + +The recently added IOC_PR_READ_* ioctls require the same BLK_OPEN_WRITE +permission as the older persistent reservation ioctls. This has the +drawback that udev triggers when the file descriptor is closed, +resulting in unnecessary activity like scanning partitions even though +these read-only ioctls do not modify the device. + +Change IOC_PR_READ_KEYS and IOC_PR_READ_RESERVATION to require +BLK_OPEN_READ. This prevents unnecessary activity every time `blkpr +--read-keys` or `blkpr --read-reservation` is invoked by shell scripts, +for example. + +It is safe to reduce the permission requirement from BLK_OPEN_WRITE to +BLK_OPEN_READ since these two ioctls do not modify the persistent +reservation state. Userspace cannot use the information fetched by these +ioctls to make changes to the device unless it later opens the device +with BLK_OPEN_WRITE. + +Fixes: 3e2cb9ee76c2 ("block: add IOC_PR_READ_RESERVATION ioctl") +Fixes: 22a1ffea5f80 ("block: add IOC_PR_READ_KEYS ioctl") +Cc: Christoph Hellwig +Cc: Martin Wilck +Cc: Benjamin Marzinski +Suggested-by: Hannes Reinecke +Signed-off-by: Stefan Hajnoczi +Reviewed-by: Christoph Hellwig +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + block/ioctl.c | 34 +++++++++++++++++++++++----------- + 1 file changed, 23 insertions(+), 11 deletions(-) + +diff --git a/block/ioctl.c b/block/ioctl.c +index 344478348a54e..337e4c3b65b2c 100644 +--- a/block/ioctl.c ++++ b/block/ioctl.c +@@ -318,7 +318,13 @@ int blkdev_compat_ptr_ioctl(struct block_device *bdev, blk_mode_t mode, + EXPORT_SYMBOL(blkdev_compat_ptr_ioctl); + #endif + +-static bool blkdev_pr_allowed(struct block_device *bdev, blk_mode_t mode) ++enum pr_direction { ++ PR_IN, /* read from device */ ++ PR_OUT, /* write to device */ ++}; ++ ++static bool blkdev_pr_allowed(struct block_device *bdev, blk_mode_t mode, ++ enum pr_direction dir) + { + /* no sense to make reservations for partitions */ + if (bdev_is_partition(bdev)) +@@ -326,11 +332,17 @@ static bool blkdev_pr_allowed(struct block_device *bdev, blk_mode_t mode) + + if (capable(CAP_SYS_ADMIN)) + return true; ++ + /* +- * Only allow unprivileged reservations if the file descriptor is open +- * for writing. ++ * Only allow unprivileged reservation _out_ commands if the file ++ * descriptor is open for writing. Allow reservation _in_ commands if ++ * the file descriptor is open for reading since they do not modify the ++ * device. + */ +- return mode & BLK_OPEN_WRITE; ++ if (dir == PR_IN) ++ return mode & BLK_OPEN_READ; ++ else ++ return mode & BLK_OPEN_WRITE; + } + + static int blkdev_pr_register(struct block_device *bdev, blk_mode_t mode, +@@ -339,7 +351,7 @@ static int blkdev_pr_register(struct block_device *bdev, blk_mode_t mode, + const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops; + struct pr_registration reg; + +- if (!blkdev_pr_allowed(bdev, mode)) ++ if (!blkdev_pr_allowed(bdev, mode, PR_OUT)) + return -EPERM; + if (!ops || !ops->pr_register) + return -EOPNOTSUPP; +@@ -357,7 +369,7 @@ static int blkdev_pr_reserve(struct block_device *bdev, blk_mode_t mode, + const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops; + struct pr_reservation rsv; + +- if (!blkdev_pr_allowed(bdev, mode)) ++ if (!blkdev_pr_allowed(bdev, mode, PR_OUT)) + return -EPERM; + if (!ops || !ops->pr_reserve) + return -EOPNOTSUPP; +@@ -375,7 +387,7 @@ static int blkdev_pr_release(struct block_device *bdev, blk_mode_t mode, + const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops; + struct pr_reservation rsv; + +- if (!blkdev_pr_allowed(bdev, mode)) ++ if (!blkdev_pr_allowed(bdev, mode, PR_OUT)) + return -EPERM; + if (!ops || !ops->pr_release) + return -EOPNOTSUPP; +@@ -393,7 +405,7 @@ static int blkdev_pr_preempt(struct block_device *bdev, blk_mode_t mode, + const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops; + struct pr_preempt p; + +- if (!blkdev_pr_allowed(bdev, mode)) ++ if (!blkdev_pr_allowed(bdev, mode, PR_OUT)) + return -EPERM; + if (!ops || !ops->pr_preempt) + return -EOPNOTSUPP; +@@ -411,7 +423,7 @@ static int blkdev_pr_clear(struct block_device *bdev, blk_mode_t mode, + const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops; + struct pr_clear c; + +- if (!blkdev_pr_allowed(bdev, mode)) ++ if (!blkdev_pr_allowed(bdev, mode, PR_OUT)) + return -EPERM; + if (!ops || !ops->pr_clear) + return -EOPNOTSUPP; +@@ -434,7 +446,7 @@ static int blkdev_pr_read_keys(struct block_device *bdev, blk_mode_t mode, + size_t keys_copy_len; + int ret; + +- if (!blkdev_pr_allowed(bdev, mode)) ++ if (!blkdev_pr_allowed(bdev, mode, PR_IN)) + return -EPERM; + if (!ops || !ops->pr_read_keys) + return -EOPNOTSUPP; +@@ -486,7 +498,7 @@ static int blkdev_pr_read_reservation(struct block_device *bdev, + struct pr_read_reservation out = {}; + int ret; + +- if (!blkdev_pr_allowed(bdev, mode)) ++ if (!blkdev_pr_allowed(bdev, mode, PR_IN)) + return -EPERM; + if (!ops || !ops->pr_read_reservation) + return -EOPNOTSUPP; +-- +2.51.0 + diff --git a/queue-6.19/block-don-t-use-strcpy-to-copy-blockdev-name.patch b/queue-6.19/block-don-t-use-strcpy-to-copy-blockdev-name.patch new file mode 100644 index 0000000000..f279da5918 --- /dev/null +++ b/queue-6.19/block-don-t-use-strcpy-to-copy-blockdev-name.patch @@ -0,0 +1,43 @@ +From c52ab041510ad492eef1fbe7bb9c07fe27f891fb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 12:35:28 +0100 +Subject: block: don't use strcpy to copy blockdev name + +From: Johannes Thumshirn + +[ Upstream commit ee4784a83fb21a2d16ebfdf8877fa6f6a1129150 ] + +0-day bot flagged the use of strcpy() in blk_trace_setup(), because the +source buffer can theoretically be bigger than the destination buffer. + +While none of the current callers pass a string bigger than +BLKTRACE_BDEV_SIZE, use strscpy() to prevent eventual future misuse and +silence the checker warnings. + +Reported-by: kernel test robot +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/r/202602020718.GUEIRyG9-lkp@intel.com/ +Fixes: 113cbd62824a ("blktrace: pass blk_user_trace2 to setup functions") +Signed-off-by: Johannes Thumshirn +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + kernel/trace/blktrace.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c +index d031c8d80be4f..c4db5c2e71037 100644 +--- a/kernel/trace/blktrace.c ++++ b/kernel/trace/blktrace.c +@@ -793,7 +793,7 @@ int blk_trace_setup(struct request_queue *q, char *name, dev_t dev, + return PTR_ERR(bt); + } + blk_trace_setup_finalize(q, name, 1, bt, &buts2); +- strcpy(buts.name, buts2.name); ++ strscpy(buts.name, buts2.name, BLKTRACE_BDEV_SIZE); + mutex_unlock(&q->debugfs_mutex); + + if (copy_to_user(arg, &buts, sizeof(buts))) { +-- +2.51.0 + diff --git a/queue-6.19/bluetooth-btintel_pcie-use-irqf_oneshot-and-default-.patch b/queue-6.19/bluetooth-btintel_pcie-use-irqf_oneshot-and-default-.patch new file mode 100644 index 0000000000..7079121006 --- /dev/null +++ b/queue-6.19/bluetooth-btintel_pcie-use-irqf_oneshot-and-default-.patch @@ -0,0 +1,61 @@ +From 97d1814855e776abd700b5aed1483777abc56d42 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:55:26 +0100 +Subject: Bluetooth: btintel_pcie: Use IRQF_ONESHOT and default primary handler + +From: Sebastian Andrzej Siewior + +[ Upstream commit 28abed6569c87eab9071ab56c64433c2f0d9ce51 ] + +There is no added value in btintel_pcie_msix_isr() compared to +irq_default_primary_handler(). + +Using a threaded interrupt without a dedicated primary handler mandates +the IRQF_ONESHOT flag to mask the interrupt source while the threaded +handler is active. Otherwise the interrupt can fire again before the +threaded handler had a chance to run. + +Use the default primary interrupt handler by specifying NULL and set +IRQF_ONESHOT so the interrupt source is masked until the secondary +handler is done. + +Fixes: c2b636b3f788d ("Bluetooth: btintel_pcie: Add support for PCIe transport") +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260128095540.863589-7-bigeasy@linutronix.de +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/btintel_pcie.c | 9 ++------- + 1 file changed, 2 insertions(+), 7 deletions(-) + +diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c +index 2936b535479f2..704767b334b98 100644 +--- a/drivers/bluetooth/btintel_pcie.c ++++ b/drivers/bluetooth/btintel_pcie.c +@@ -1431,11 +1431,6 @@ static void btintel_pcie_msix_rx_handle(struct btintel_pcie_data *data) + } + } + +-static irqreturn_t btintel_pcie_msix_isr(int irq, void *data) +-{ +- return IRQ_WAKE_THREAD; +-} +- + static inline bool btintel_pcie_is_rxq_empty(struct btintel_pcie_data *data) + { + return data->ia.cr_hia[BTINTEL_PCIE_RXQ_NUM] == data->ia.cr_tia[BTINTEL_PCIE_RXQ_NUM]; +@@ -1537,9 +1532,9 @@ static int btintel_pcie_setup_irq(struct btintel_pcie_data *data) + + err = devm_request_threaded_irq(&data->pdev->dev, + msix_entry->vector, +- btintel_pcie_msix_isr, ++ NULL, + btintel_pcie_irq_msix_handler, +- IRQF_SHARED, ++ IRQF_ONESHOT | IRQF_SHARED, + KBUILD_MODNAME, + msix_entry); + if (err) { +-- +2.51.0 + diff --git a/queue-6.19/bluetooth-hci_conn-fix-using-conn-le_-tx-rx-_phy-as-.patch b/queue-6.19/bluetooth-hci_conn-fix-using-conn-le_-tx-rx-_phy-as-.patch new file mode 100644 index 0000000000..1b1f9c73d9 --- /dev/null +++ b/queue-6.19/bluetooth-hci_conn-fix-using-conn-le_-tx-rx-_phy-as-.patch @@ -0,0 +1,135 @@ +From 544bf8c6aef0d25149007fcf48e4bd66009c7c8c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 10 Dec 2025 11:38:08 -0500 +Subject: Bluetooth: hci_conn: Fix using conn->le_{tx,rx}_phy as supported PHYs + +From: Luiz Augusto von Dentz + +[ Upstream commit 129d1ef3c5e60d51678e6359beaba85771a49e46 ] + +conn->le_{tx,rx}_phy is not actually a bitfield as it set by +HCI_EV_LE_PHY_UPDATE_COMPLETE it is actually correspond to the current +PHY in use not what is supported by the controller, so this introduces +different fields (conn->le_{tx,rx}_def_phys) to track what PHYs are +supported by the connection. + +Fixes: eab2404ba798 ("Bluetooth: Add BT_PHY socket option") +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + include/net/bluetooth/hci_core.h | 2 ++ + net/bluetooth/hci_conn.c | 17 +++++++++++------ + net/bluetooth/hci_event.c | 30 +++++++++++++++++++++++++++--- + 3 files changed, 40 insertions(+), 9 deletions(-) + +diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h +index 4263e71a23efb..8aadf4cdead2b 100644 +--- a/include/net/bluetooth/hci_core.h ++++ b/include/net/bluetooth/hci_core.h +@@ -730,6 +730,8 @@ struct hci_conn { + __u16 le_per_adv_data_offset; + __u8 le_adv_phy; + __u8 le_adv_sec_phy; ++ __u8 le_tx_def_phys; ++ __u8 le_rx_def_phys; + __u8 le_tx_phy; + __u8 le_rx_phy; + __s8 rssi; +diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c +index c3f7828bf9d54..5a4374ccf8e84 100644 +--- a/net/bluetooth/hci_conn.c ++++ b/net/bluetooth/hci_conn.c +@@ -1008,6 +1008,11 @@ static struct hci_conn *__hci_conn_add(struct hci_dev *hdev, int type, + /* conn->src should reflect the local identity address */ + hci_copy_identity_address(hdev, &conn->src, &conn->src_type); + conn->mtu = hdev->le_mtu ? hdev->le_mtu : hdev->acl_mtu; ++ /* Use the controller supported PHYS as default until the ++ * remote features are resolved. ++ */ ++ conn->le_tx_def_phys = hdev->le_tx_def_phys; ++ conn->le_rx_def_phys = hdev->le_tx_def_phys; + break; + case CIS_LINK: + /* conn->src should reflect the local identity address */ +@@ -2928,22 +2933,22 @@ u32 hci_conn_get_phy(struct hci_conn *conn) + break; + + case LE_LINK: +- if (conn->le_tx_phy & HCI_LE_SET_PHY_1M) ++ if (conn->le_tx_def_phys & HCI_LE_SET_PHY_1M) + phys |= BT_PHY_LE_1M_TX; + +- if (conn->le_rx_phy & HCI_LE_SET_PHY_1M) ++ if (conn->le_rx_def_phys & HCI_LE_SET_PHY_1M) + phys |= BT_PHY_LE_1M_RX; + +- if (conn->le_tx_phy & HCI_LE_SET_PHY_2M) ++ if (conn->le_tx_def_phys & HCI_LE_SET_PHY_2M) + phys |= BT_PHY_LE_2M_TX; + +- if (conn->le_rx_phy & HCI_LE_SET_PHY_2M) ++ if (conn->le_rx_def_phys & HCI_LE_SET_PHY_2M) + phys |= BT_PHY_LE_2M_RX; + +- if (conn->le_tx_phy & HCI_LE_SET_PHY_CODED) ++ if (conn->le_tx_def_phys & HCI_LE_SET_PHY_CODED) + phys |= BT_PHY_LE_CODED_TX; + +- if (conn->le_rx_phy & HCI_LE_SET_PHY_CODED) ++ if (conn->le_rx_def_phys & HCI_LE_SET_PHY_CODED) + phys |= BT_PHY_LE_CODED_RX; + + break; +diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c +index a9868f17ef40f..58075bf720554 100644 +--- a/net/bluetooth/hci_event.c ++++ b/net/bluetooth/hci_event.c +@@ -6607,8 +6607,20 @@ static void hci_le_remote_feat_complete_evt(struct hci_dev *hdev, void *data, + + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); + if (conn) { +- if (!ev->status) +- memcpy(conn->features[0], ev->features, 8); ++ if (!ev->status) { ++ memcpy(conn->le_features, ev->features, 8); ++ ++ /* Update supported PHYs */ ++ if (!(conn->le_features[1] & HCI_LE_PHY_2M)) { ++ conn->le_tx_def_phys &= ~HCI_LE_SET_PHY_2M; ++ conn->le_rx_def_phys &= ~HCI_LE_SET_PHY_2M; ++ } ++ ++ if (!(conn->le_features[1] & HCI_LE_PHY_CODED)) { ++ conn->le_tx_def_phys &= ~HCI_LE_SET_PHY_CODED; ++ conn->le_rx_def_phys &= ~HCI_LE_SET_PHY_CODED; ++ } ++ } + + if (conn->state == BT_CONFIG) { + __u8 status; +@@ -7221,9 +7233,21 @@ static void hci_le_read_all_remote_features_evt(struct hci_dev *hdev, + if (!conn) + goto unlock; + +- if (!ev->status) ++ if (!ev->status) { + memcpy(conn->le_features, ev->features, 248); + ++ /* Update supported PHYs */ ++ if (!(conn->le_features[1] & HCI_LE_PHY_2M)) { ++ conn->le_tx_def_phys &= ~HCI_LE_SET_PHY_2M; ++ conn->le_rx_def_phys &= ~HCI_LE_SET_PHY_2M; ++ } ++ ++ if (!(conn->le_features[1] & HCI_LE_PHY_CODED)) { ++ conn->le_tx_def_phys &= ~HCI_LE_SET_PHY_CODED; ++ conn->le_rx_def_phys &= ~HCI_LE_SET_PHY_CODED; ++ } ++ } ++ + if (conn->state == BT_CONFIG) { + __u8 status; + +-- +2.51.0 + diff --git a/queue-6.19/bonding-only-set-speed-duplex-to-unknown-if-getting-.patch b/queue-6.19/bonding-only-set-speed-duplex-to-unknown-if-getting-.patch new file mode 100644 index 0000000000..730baf57cc --- /dev/null +++ b/queue-6.19/bonding-only-set-speed-duplex-to-unknown-if-getting-.patch @@ -0,0 +1,74 @@ +From 33936de2ecf11aae0c6a561ef7786ea658f718f1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 15:11:52 +0100 +Subject: bonding: only set speed/duplex to unknown, if getting speed failed + +From: Thomas Bogendoerfer + +[ Upstream commit 48dec8d88af96039a4a17b8c2f148f2a4066e195 ] + +bond_update_speed_duplex() first set speed/duplex to unknown and +then asks slave driver for current speed/duplex. Since getting +speed/duplex might take longer there is a race, where this false state +is visible by /proc/net/bonding. With commit 691b2bf14946 ("bonding: + update port speed when getting bond speed") this race gets more visible, +if user space is calling ethtool on a regular base. + +Fix this by only setting speed/duplex to unknown, if link speed is +really unknown/unusable. + +Fixes: 98f41f694f46 ("bonding:update speed/duplex for NETDEV_CHANGE") +Signed-off-by: Thomas Bogendoerfer +Acked-by: Jay Vosburgh +Reviewed-by: Nikolay Aleksandrov +Reviewed-by: Hangbin Liu +Link: https://patch.msgid.link/20260203141153.51581-1-tbogendoerfer@suse.de +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/bonding/bond_main.c | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c +index 45bd2bb102ffd..47f13d86cb7ef 100644 +--- a/drivers/net/bonding/bond_main.c ++++ b/drivers/net/bonding/bond_main.c +@@ -791,26 +791,29 @@ static int bond_update_speed_duplex(struct slave *slave) + struct ethtool_link_ksettings ecmd; + int res; + +- slave->speed = SPEED_UNKNOWN; +- slave->duplex = DUPLEX_UNKNOWN; +- + res = __ethtool_get_link_ksettings(slave_dev, &ecmd); + if (res < 0) +- return 1; ++ goto speed_duplex_unknown; + if (ecmd.base.speed == 0 || ecmd.base.speed == ((__u32)-1)) +- return 1; ++ goto speed_duplex_unknown; + switch (ecmd.base.duplex) { + case DUPLEX_FULL: + case DUPLEX_HALF: + break; + default: +- return 1; ++ goto speed_duplex_unknown; + } + + slave->speed = ecmd.base.speed; + slave->duplex = ecmd.base.duplex; + + return 0; ++ ++speed_duplex_unknown: ++ slave->speed = SPEED_UNKNOWN; ++ slave->duplex = DUPLEX_UNKNOWN; ++ ++ return 1; + } + + const char *bond_slave_link_status(s8 link) +-- +2.51.0 + diff --git a/queue-6.19/bpf-bpf_scc_visit-instance-and-backedges-accumulatio.patch b/queue-6.19/bpf-bpf_scc_visit-instance-and-backedges-accumulatio.patch new file mode 100644 index 0000000000..559fd5c355 --- /dev/null +++ b/queue-6.19/bpf-bpf_scc_visit-instance-and-backedges-accumulatio.patch @@ -0,0 +1,76 @@ +From 5920718f37246b11a294d8b8811a59c27cbc558f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Dec 2025 23:13:07 -0800 +Subject: bpf: bpf_scc_visit instance and backedges accumulation for bpf_loop() + +From: Eduard Zingerman + +[ Upstream commit f597664454bde5ac45ceaf24da55b590ccfa60e3 ] + +Calls like bpf_loop() or bpf_for_each_map_elem() introduce loops that +are not explicitly present in the control-flow graph. The verifier +processes such calls by repeatedly interpreting the callback function +body within the same verification path (until the current state +converges with a previous state). + +Such loops require a bpf_scc_visit instance in order to allow the +accumulation of the state graph backedges. Otherwise, certain +checkpoint states created within the bodies of such loops will have +incomplete precision marks. + +See the next patch for an example of a program that leads to the +verifier accepting an unsafe program. + +Fixes: 96c6aa4c63af ("bpf: compute SCCs in program control flow graph") +Fixes: c9e31900b54c ("bpf: propagate read/precision marks over state graph backedges") +Reported-by: Breno Leitao +Signed-off-by: Eduard Zingerman +Tested-by: Breno Leitao +Link: https://lore.kernel.org/r/20251229-scc-for-callbacks-v1-1-ceadfe679900@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/verifier.c | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index 3135643d56955..646025bae96db 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -19835,8 +19835,10 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx) + } + } + if (bpf_calls_callback(env, insn_idx)) { +- if (states_equal(env, &sl->state, cur, RANGE_WITHIN)) ++ if (states_equal(env, &sl->state, cur, RANGE_WITHIN)) { ++ loop = true; + goto hit; ++ } + goto skip_inf_loop_check; + } + /* attempt to detect infinite loop to avoid unnecessary doomed work */ +@@ -25076,15 +25078,18 @@ static int compute_scc(struct bpf_verifier_env *env) + } + /* + * Assign SCC number only if component has two or more elements, +- * or if component has a self reference. ++ * or if component has a self reference, or if instruction is a ++ * callback calling function (implicit loop). + */ +- assign_scc = stack[stack_sz - 1] != w; +- for (j = 0; j < succ->cnt; ++j) { ++ assign_scc = stack[stack_sz - 1] != w; /* two or more elements? */ ++ for (j = 0; j < succ->cnt; ++j) { /* self reference? */ + if (succ->items[j] == w) { + assign_scc = true; + break; + } + } ++ if (bpf_calls_callback(env, w)) /* implicit loop? */ ++ assign_scc = true; + /* Pop component elements from stack */ + do { + t = stack[--stack_sz]; +-- +2.51.0 + diff --git a/queue-6.19/bpf-fix-bpf_xdp_store_bytes-proto-for-read-only-arg.patch b/queue-6.19/bpf-fix-bpf_xdp_store_bytes-proto-for-read-only-arg.patch new file mode 100644 index 0000000000..3358d6b05a --- /dev/null +++ b/queue-6.19/bpf-fix-bpf_xdp_store_bytes-proto-for-read-only-arg.patch @@ -0,0 +1,60 @@ +From c4c9156c1c7a9a2a2d912179ef38b1e9636ed296 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Jan 2026 17:08:37 +0100 +Subject: bpf: Fix bpf_xdp_store_bytes proto for read-only arg + +From: Paul Chaignon + +[ Upstream commit 6557f1565d779851c4db9c488c49c05a47a6e72f ] + +While making some maps in Cilium read-only from the BPF side, we noticed +that the bpf_xdp_store_bytes proto is incorrect. In particular, the +verifier was throwing the following error: + + ; ret = ctx_store_bytes(ctx, l3_off + offsetof(struct iphdr, saddr), + &nat->address, 4, 0); + 635: (79) r1 = *(u64 *)(r10 -144) ; R1=ctx() R10=fp0 fp-144=ctx() + 636: (b4) w2 = 26 ; R2=26 + 637: (b4) w4 = 4 ; R4=4 + 638: (b4) w5 = 0 ; R5=0 + 639: (85) call bpf_xdp_store_bytes#190 + write into map forbidden, value_size=6 off=0 size=4 + +nat comes from a BPF_F_RDONLY_PROG map, so R3 is a PTR_TO_MAP_VALUE. +The verifier checks the helper's memory access to R3 in +check_mem_size_reg, as it reaches ARG_CONST_SIZE argument. The third +argument has expected type ARG_PTR_TO_UNINIT_MEM, which includes the +MEM_WRITE flag. The verifier thus checks for a BPF_WRITE access on R3. +Given R3 points to a read-only map, the check fails. + +Conversely, ARG_PTR_TO_UNINIT_MEM can also lead to the helper reading +from uninitialized memory. + +This patch simply fixes the expected argument type to match that of +bpf_skb_store_bytes. + +Fixes: 3f364222d032 ("net: xdp: introduce bpf_xdp_pointer utility routine") +Signed-off-by: Paul Chaignon +Link: https://lore.kernel.org/r/9fa3c9f72d806e82541071c4df88b8cba28ad6a9.1769875479.git.paul.chaignon@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + net/core/filter.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/core/filter.c b/net/core/filter.c +index b1f8e2930e1c4..51318cb40f778 100644 +--- a/net/core/filter.c ++++ b/net/core/filter.c +@@ -4137,7 +4137,7 @@ static const struct bpf_func_proto bpf_xdp_store_bytes_proto = { + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_CTX, + .arg2_type = ARG_ANYTHING, +- .arg3_type = ARG_PTR_TO_UNINIT_MEM, ++ .arg3_type = ARG_PTR_TO_MEM | MEM_RDONLY, + .arg4_type = ARG_CONST_SIZE, + }; + +-- +2.51.0 + diff --git a/queue-6.19/bpf-fix-memory-access-flags-in-helper-prototypes.patch b/queue-6.19/bpf-fix-memory-access-flags-in-helper-prototypes.patch new file mode 100644 index 0000000000..77f57b07b3 --- /dev/null +++ b/queue-6.19/bpf-fix-memory-access-flags-in-helper-prototypes.patch @@ -0,0 +1,179 @@ +From d840a8680515f2b2c70fbd9b37d1a702662c4d75 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 16:28:46 +0800 +Subject: bpf: Fix memory access flags in helper prototypes + +From: Zesen Liu + +[ Upstream commit 802eef5afb1865bc5536a5302c068ba2215a1f72 ] + +After commit 37cce22dbd51 ("bpf: verifier: Refactor helper access type tracking"), +the verifier started relying on the access type flags in helper +function prototypes to perform memory access optimizations. + +Currently, several helper functions utilizing ARG_PTR_TO_MEM lack the +corresponding MEM_RDONLY or MEM_WRITE flags. This omission causes the +verifier to incorrectly assume that the buffer contents are unchanged +across the helper call. Consequently, the verifier may optimize away +subsequent reads based on this wrong assumption, leading to correctness +issues. + +For bpf_get_stack_proto_raw_tp, the original MEM_RDONLY was incorrect +since the helper writes to the buffer. Change it to ARG_PTR_TO_UNINIT_MEM +which correctly indicates write access to potentially uninitialized memory. + +Similar issues were recently addressed for specific helpers in commit +ac44dcc788b9 ("bpf: Fix verifier assumptions of bpf_d_path's output buffer") +and commit 2eb7648558a7 ("bpf: Specify access type of bpf_sysctl_get_name args"). + +Fix these prototypes by adding the correct memory access flags. + +Fixes: 37cce22dbd51 ("bpf: verifier: Refactor helper access type tracking") +Co-developed-by: Shuran Liu +Signed-off-by: Shuran Liu +Co-developed-by: Peili Gao +Signed-off-by: Peili Gao +Co-developed-by: Haoran Ni +Signed-off-by: Haoran Ni +Signed-off-by: Zesen Liu +Acked-by: Eduard Zingerman +Link: https://lore.kernel.org/r/20260120-helper_proto-v3-1-27b0180b4e77@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/helpers.c | 2 +- + kernel/bpf/syscall.c | 2 +- + kernel/trace/bpf_trace.c | 6 +++--- + net/core/filter.c | 20 ++++++++++---------- + 4 files changed, 15 insertions(+), 15 deletions(-) + +diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c +index db72b96f9c8c8..f66284f8ec2cc 100644 +--- a/kernel/bpf/helpers.c ++++ b/kernel/bpf/helpers.c +@@ -1077,7 +1077,7 @@ const struct bpf_func_proto bpf_snprintf_proto = { + .func = bpf_snprintf, + .gpl_only = true, + .ret_type = RET_INTEGER, +- .arg1_type = ARG_PTR_TO_MEM_OR_NULL, ++ .arg1_type = ARG_PTR_TO_MEM_OR_NULL | MEM_WRITE, + .arg2_type = ARG_CONST_SIZE_OR_ZERO, + .arg3_type = ARG_PTR_TO_CONST_STR, + .arg4_type = ARG_PTR_TO_MEM | PTR_MAYBE_NULL | MEM_RDONLY, +diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c +index 4ff82144f8853..ee116a3b7baf7 100644 +--- a/kernel/bpf/syscall.c ++++ b/kernel/bpf/syscall.c +@@ -6407,7 +6407,7 @@ static const struct bpf_func_proto bpf_kallsyms_lookup_name_proto = { + .func = bpf_kallsyms_lookup_name, + .gpl_only = false, + .ret_type = RET_INTEGER, +- .arg1_type = ARG_PTR_TO_MEM, ++ .arg1_type = ARG_PTR_TO_MEM | MEM_RDONLY, + .arg2_type = ARG_CONST_SIZE_OR_ZERO, + .arg3_type = ARG_ANYTHING, + .arg4_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_WRITE | MEM_ALIGNED, +diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c +index fe28d86f7c357..59c2394981c72 100644 +--- a/kernel/trace/bpf_trace.c ++++ b/kernel/trace/bpf_trace.c +@@ -1022,7 +1022,7 @@ const struct bpf_func_proto bpf_snprintf_btf_proto = { + .func = bpf_snprintf_btf, + .gpl_only = false, + .ret_type = RET_INTEGER, +- .arg1_type = ARG_PTR_TO_MEM, ++ .arg1_type = ARG_PTR_TO_MEM | MEM_WRITE, + .arg2_type = ARG_CONST_SIZE, + .arg3_type = ARG_PTR_TO_MEM | MEM_RDONLY, + .arg4_type = ARG_CONST_SIZE, +@@ -1526,7 +1526,7 @@ static const struct bpf_func_proto bpf_read_branch_records_proto = { + .gpl_only = true, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_CTX, +- .arg2_type = ARG_PTR_TO_MEM_OR_NULL, ++ .arg2_type = ARG_PTR_TO_MEM_OR_NULL | MEM_WRITE, + .arg3_type = ARG_CONST_SIZE_OR_ZERO, + .arg4_type = ARG_ANYTHING, + }; +@@ -1661,7 +1661,7 @@ static const struct bpf_func_proto bpf_get_stack_proto_raw_tp = { + .gpl_only = true, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_CTX, +- .arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY, ++ .arg2_type = ARG_PTR_TO_UNINIT_MEM, + .arg3_type = ARG_CONST_SIZE_OR_ZERO, + .arg4_type = ARG_ANYTHING, + }; +diff --git a/net/core/filter.c b/net/core/filter.c +index 029e560e32ce3..b1f8e2930e1c4 100644 +--- a/net/core/filter.c ++++ b/net/core/filter.c +@@ -6401,7 +6401,7 @@ static const struct bpf_func_proto bpf_xdp_fib_lookup_proto = { + .gpl_only = true, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_CTX, +- .arg2_type = ARG_PTR_TO_MEM, ++ .arg2_type = ARG_PTR_TO_MEM | MEM_WRITE, + .arg3_type = ARG_CONST_SIZE, + .arg4_type = ARG_ANYTHING, + }; +@@ -6456,7 +6456,7 @@ static const struct bpf_func_proto bpf_skb_fib_lookup_proto = { + .gpl_only = true, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_CTX, +- .arg2_type = ARG_PTR_TO_MEM, ++ .arg2_type = ARG_PTR_TO_MEM | MEM_WRITE, + .arg3_type = ARG_CONST_SIZE, + .arg4_type = ARG_ANYTHING, + }; +@@ -8010,9 +8010,9 @@ static const struct bpf_func_proto bpf_tcp_raw_gen_syncookie_ipv4_proto = { + .gpl_only = true, /* __cookie_v4_init_sequence() is GPL */ + .pkt_access = true, + .ret_type = RET_INTEGER, +- .arg1_type = ARG_PTR_TO_FIXED_SIZE_MEM, ++ .arg1_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_RDONLY, + .arg1_size = sizeof(struct iphdr), +- .arg2_type = ARG_PTR_TO_MEM, ++ .arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY, + .arg3_type = ARG_CONST_SIZE_OR_ZERO, + }; + +@@ -8042,9 +8042,9 @@ static const struct bpf_func_proto bpf_tcp_raw_gen_syncookie_ipv6_proto = { + .gpl_only = true, /* __cookie_v6_init_sequence() is GPL */ + .pkt_access = true, + .ret_type = RET_INTEGER, +- .arg1_type = ARG_PTR_TO_FIXED_SIZE_MEM, ++ .arg1_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_RDONLY, + .arg1_size = sizeof(struct ipv6hdr), +- .arg2_type = ARG_PTR_TO_MEM, ++ .arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY, + .arg3_type = ARG_CONST_SIZE_OR_ZERO, + }; + +@@ -8062,9 +8062,9 @@ static const struct bpf_func_proto bpf_tcp_raw_check_syncookie_ipv4_proto = { + .gpl_only = true, /* __cookie_v4_check is GPL */ + .pkt_access = true, + .ret_type = RET_INTEGER, +- .arg1_type = ARG_PTR_TO_FIXED_SIZE_MEM, ++ .arg1_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_RDONLY, + .arg1_size = sizeof(struct iphdr), +- .arg2_type = ARG_PTR_TO_FIXED_SIZE_MEM, ++ .arg2_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_RDONLY, + .arg2_size = sizeof(struct tcphdr), + }; + +@@ -8086,9 +8086,9 @@ static const struct bpf_func_proto bpf_tcp_raw_check_syncookie_ipv6_proto = { + .gpl_only = true, /* __cookie_v6_check is GPL */ + .pkt_access = true, + .ret_type = RET_INTEGER, +- .arg1_type = ARG_PTR_TO_FIXED_SIZE_MEM, ++ .arg1_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_RDONLY, + .arg1_size = sizeof(struct ipv6hdr), +- .arg2_type = ARG_PTR_TO_FIXED_SIZE_MEM, ++ .arg2_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_RDONLY, + .arg2_size = sizeof(struct tcphdr), + }; + #endif /* CONFIG_SYN_COOKIES */ +-- +2.51.0 + diff --git a/queue-6.19/bpf-fix-tcx-netkit-detach-permissions-when-prog-fd-i.patch b/queue-6.19/bpf-fix-tcx-netkit-detach-permissions-when-prog-fd-i.patch new file mode 100644 index 0000000000..57fa59101a --- /dev/null +++ b/queue-6.19/bpf-fix-tcx-netkit-detach-permissions-when-prog-fd-i.patch @@ -0,0 +1,88 @@ +From 5934bb3a754d121d7e7e6007f211acae005c13d4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 17:02:00 +0100 +Subject: bpf: Fix tcx/netkit detach permissions when prog fd isn't given + +From: Guillaume Gonnet + +[ Upstream commit ae23bc81ddf7c17b663c4ed1b21e35527b0a7131 ] + +This commit fixes a security issue where BPF_PROG_DETACH on tcx or +netkit devices could be executed by any user when no program fd was +provided, bypassing permission checks. The fix adds a capability +check for CAP_NET_ADMIN or CAP_SYS_ADMIN in this case. + +Fixes: e420bed02507 ("bpf: Add fd-based tcx multi-prog infra with link support") +Signed-off-by: Guillaume Gonnet +Link: https://lore.kernel.org/r/20260127160200.10395-1-ggonnet.linux@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + include/linux/bpf.h | 5 +++++ + include/linux/bpf_mprog.h | 10 ++++++++++ + kernel/bpf/syscall.c | 7 ++----- + 3 files changed, 17 insertions(+), 5 deletions(-) + +diff --git a/include/linux/bpf.h b/include/linux/bpf.h +index e5be698256d15..7b2e51216e736 100644 +--- a/include/linux/bpf.h ++++ b/include/linux/bpf.h +@@ -3243,6 +3243,11 @@ static inline void bpf_prog_report_arena_violation(bool write, unsigned long add + } + #endif /* CONFIG_BPF_SYSCALL */ + ++static inline bool bpf_net_capable(void) ++{ ++ return capable(CAP_NET_ADMIN) || capable(CAP_SYS_ADMIN); ++} ++ + static __always_inline int + bpf_probe_read_kernel_common(void *dst, u32 size, const void *unsafe_ptr) + { +diff --git a/include/linux/bpf_mprog.h b/include/linux/bpf_mprog.h +index 929225f7b0959..0b9f4caeeb0a3 100644 +--- a/include/linux/bpf_mprog.h ++++ b/include/linux/bpf_mprog.h +@@ -340,4 +340,14 @@ static inline bool bpf_mprog_supported(enum bpf_prog_type type) + return false; + } + } ++ ++static inline bool bpf_mprog_detach_empty(enum bpf_prog_type type) ++{ ++ switch (type) { ++ case BPF_PROG_TYPE_SCHED_CLS: ++ return bpf_net_capable(); ++ default: ++ return false; ++ } ++} + #endif /* __BPF_MPROG_H */ +diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c +index ee116a3b7baf7..763868d327b4a 100644 +--- a/kernel/bpf/syscall.c ++++ b/kernel/bpf/syscall.c +@@ -1366,11 +1366,6 @@ static int map_check_btf(struct bpf_map *map, struct bpf_token *token, + return ret; + } + +-static bool bpf_net_capable(void) +-{ +- return capable(CAP_NET_ADMIN) || capable(CAP_SYS_ADMIN); +-} +- + #define BPF_MAP_CREATE_LAST_FIELD excl_prog_hash_size + /* called via syscall */ + static int map_create(union bpf_attr *attr, bpfptr_t uattr) +@@ -4565,6 +4560,8 @@ static int bpf_prog_detach(const union bpf_attr *attr) + prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype); + if (IS_ERR(prog)) + return PTR_ERR(prog); ++ } else if (!bpf_mprog_detach_empty(ptype)) { ++ return -EPERM; + } + } else if (is_cgroup_prog_type(ptype, 0, false)) { + if (attr->attach_flags || attr->relative_fd) +-- +2.51.0 + diff --git a/queue-6.19/bpf-fix-verifier_bug_if-to-account-for-bpf_call.patch b/queue-6.19/bpf-fix-verifier_bug_if-to-account-for-bpf_call.patch new file mode 100644 index 0000000000..89e533be2b --- /dev/null +++ b/queue-6.19/bpf-fix-verifier_bug_if-to-account-for-bpf_call.patch @@ -0,0 +1,108 @@ +From 6b4a980db4052a6634a13238df96d4215655a29c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 12:59:11 +0100 +Subject: bpf: Fix verifier_bug_if to account for BPF_CALL +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Luis Gerhorst + +[ Upstream commit cd3b6a3d49f8061d0c4c7e4226783051fe592ae7 ] + +The BPF verifier assumes `insn_aux->nospec_result` is only set for +direct memory writes (e.g., `*(u32*)(r1+off) = r2`). However, the +assertion fails to account for helper calls (e.g., +`bpf_skb_load_bytes_relative`) that perform writes to stack memory. Make +the check more precise to resolve this. + +The problem is that `BPF_CALL` instructions have `BPF_CLASS(insn->code) +== BPF_JMP`, which triggers the warning check: + +- Helpers like `bpf_skb_load_bytes_relative` write to stack memory +- `check_helper_call()` loops through `meta.access_size`, calling + `check_mem_access(..., BPF_WRITE)` +- `check_stack_write()` sets `insn_aux->nospec_result = 1` +- Since `BPF_CALL` is encoded as `BPF_JMP | BPF_CALL`, the warning fires + +Execution flow: + +``` +1. Drop capabilities → Enable Spectre mitigation +2. Load BPF program + └─> do_check() + ├─> check_cond_jmp_op() → Marks dead branch as speculative + │ └─> push_stack(..., speculative=true) + ├─> pop_stack() → state->speculative = 1 + ├─> check_helper_call() → Processes helper in dead branch + │ └─> check_mem_access(..., BPF_WRITE) + │ └─> insn_aux->nospec_result = 1 + └─> Checks: state->speculative && insn_aux->nospec_result + └─> BPF_CLASS(insn->code) == BPF_JMP → WARNING +``` + +To fix the assert, it would be nice to be able to reuse +bpf_insn_successors() here, but bpf_insn_successors()->cnt is not +exactly what we want as it may also be 1 for BPF_JA. Instead, we could +check opcode_info.can_jump, but then we would have to share the table +between the functions. This would mean moving the table out of the +function and adding bpf_opcode_info(). As the verifier_bug_if() only +runs for insns with nospec_result set, the impact on verification time +would likely still be negligible. However, I assume sharing +bpf_opcode_info() between liveness.c and verifier.c will not be worth +it. It seems as only adjust_jmp_off() could also be simplified using it, +and there imm/off is touched. Thus it is maybe better to rely on exact +opcode/class matching there. + +Therefore, to avoid this sharing only for a verifier_bug_if(), just +check the opcode. This should now cover all opcodes for which can_jump +in bpf_insn_successors() is true. + +Parts of the description and example are taken from the bug report. + +Fixes: dadb59104c64 ("bpf: Fix aux usage after do_check_insn()") +Signed-off-by: Luis Gerhorst +Reported-by: Yinhao Hu +Reported-by: Kaiyan Mei +Reported-by: Dongliang Mu +Closes: https://lore.kernel.org/bpf/7678017d-b760-4053-a2d8-a6879b0dbeeb@hust.edu.cn/ +Link: https://lore.kernel.org/r/20260127115912.3026761-2-luis.gerhorst@fau.de +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/verifier.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index 8678ce5c97c5a..c9e2e22da3309 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -20615,17 +20615,19 @@ static int do_check(struct bpf_verifier_env *env) + * may skip a nospec patched-in after the jump. This can + * currently never happen because nospec_result is only + * used for the write-ops +- * `*(size*)(dst_reg+off)=src_reg|imm32` which must +- * never skip the following insn. Still, add a warning +- * to document this in case nospec_result is used +- * elsewhere in the future. ++ * `*(size*)(dst_reg+off)=src_reg|imm32` and helper ++ * calls. These must never skip the following insn ++ * (i.e., bpf_insn_successors()'s opcode_info.can_jump ++ * is false). Still, add a warning to document this in ++ * case nospec_result is used elsewhere in the future. + * + * All non-branch instructions have a single + * fall-through edge. For these, nospec_result should + * already work. + */ +- if (verifier_bug_if(BPF_CLASS(insn->code) == BPF_JMP || +- BPF_CLASS(insn->code) == BPF_JMP32, env, ++ if (verifier_bug_if((BPF_CLASS(insn->code) == BPF_JMP || ++ BPF_CLASS(insn->code) == BPF_JMP32) && ++ BPF_OP(insn->code) != BPF_CALL, env, + "speculation barrier after jump instruction may not have the desired effect")) + return -EFAULT; + process_bpf_exit: +-- +2.51.0 + diff --git a/queue-6.19/bpf-limit-bpf-program-signature-size.patch b/queue-6.19/bpf-limit-bpf-program-signature-size.patch new file mode 100644 index 0000000000..2f58efdab0 --- /dev/null +++ b/queue-6.19/bpf-limit-bpf-program-signature-size.patch @@ -0,0 +1,48 @@ +From ce9345b7cf50381f3225461e5ae959b210009e62 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 07:38:07 +0100 +Subject: bpf: Limit bpf program signature size + +From: KP Singh + +[ Upstream commit ea1535e28bb3773fc0b3cbd1f3842b808016990c ] + +Practical BPF signatures are significantly smaller than +KMALLOC_MAX_CACHE_SIZE + +Allowing larger sizes opens the door for abuse by passing excessive +size values and forcing the kernel into expensive allocation paths (via +kmalloc_large or vmalloc). + +Fixes: 349271568303 ("bpf: Implement signature verification for BPF programs") +Reported-by: Chris Mason +Signed-off-by: KP Singh +Acked-by: Daniel Borkmann +Link: https://lore.kernel.org/r/20260205063807.690823-1-kpsingh@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/syscall.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c +index 763868d327b4a..f89aa142f71b8 100644 +--- a/kernel/bpf/syscall.c ++++ b/kernel/bpf/syscall.c +@@ -2815,6 +2815,13 @@ static int bpf_prog_verify_signature(struct bpf_prog *prog, union bpf_attr *attr + void *sig; + int err = 0; + ++ /* ++ * Don't attempt to use kmalloc_large or vmalloc for signatures. ++ * Practical signature for BPF program should be below this limit. ++ */ ++ if (attr->signature_size > KMALLOC_MAX_CACHE_SIZE) ++ return -EINVAL; ++ + if (system_keyring_id_check(attr->keyring_id) == 0) + key = bpf_lookup_system_key(attr->keyring_id); + else +-- +2.51.0 + diff --git a/queue-6.19/bpf-preserve-id-of-register-in-sync_linked_regs.patch b/queue-6.19/bpf-preserve-id-of-register-in-sync_linked_regs.patch new file mode 100644 index 0000000000..7a6727557a --- /dev/null +++ b/queue-6.19/bpf-preserve-id-of-register-in-sync_linked_regs.patch @@ -0,0 +1,95 @@ +From 5872cb7dc42301ff2a0aa012a224e7bab3691200 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 07:11:40 -0800 +Subject: bpf: Preserve id of register in sync_linked_regs() + +From: Puranjay Mohan + +[ Upstream commit af9e89d8dd39530c8bd14c33ddf6b502df1071b6 ] + +sync_linked_regs() copies the id of known_reg to reg when propagating +bounds of known_reg to reg using the off of known_reg, but when +known_reg was linked to reg like: + +known_reg = reg ; both known_reg and reg get same id +known_reg += 4 ; known_reg gets off = 4, and its id gets BPF_ADD_CONST + +now when a call to sync_linked_regs() happens, let's say with the following: + +if known_reg >= 10 goto pc+2 + +known_reg's new bounds are propagated to reg but now reg gets +BPF_ADD_CONST from the copy. + +This means if another link to reg is created like: + +another_reg = reg ; another_reg should get the id of reg but + assign_scalar_id_before_mov() sees + BPF_ADD_CONST on reg and assigns a new id to it. + +As reg has a new id now, known_reg's link to reg is broken. If we find +new bounds for known_reg, they will not be propagated to reg. + +This can be seen in the selftest added in the next commit: + +0: (85) call bpf_get_prandom_u32#7 ; R0=scalar() +1: (57) r0 &= 255 ; R0=scalar(smin=smin32=0,smax=umax=smax32=umax32=255,var_off=(0x0; 0xff)) +2: (bf) r1 = r0 ; R0=scalar(id=1,smin=smin32=0,smax=umax=smax32=umax32=255,var_off=(0x0; 0xff)) R1=scalar(id=1,smin=smin32=0,smax=umax=smax32=umax32=255,var_off=(0x0; 0xff)) +3: (07) r1 += 4 ; R1=scalar(id=1+4,smin=umin=smin32=umin32=4,smax=umax=smax32=umax32=259,var_off=(0x0; 0x1ff)) +4: (a5) if r1 < 0xa goto pc+4 ; R1=scalar(id=1+4,smin=umin=smin32=umin32=10,smax=umax=smax32=umax32=259,var_off=(0x0; 0x1ff)) +5: (bf) r2 = r0 ; R0=scalar(id=2,smin=umin=smin32=umin32=6,smax=umax=smax32=umax32=255) R2=scalar(id=2,smin=umin=smin32=umin32=6,smax=umax=smax32=umax32=255) +6: (a5) if r1 < 0xe goto pc+2 ; R1=scalar(id=1+4,smin=umin=smin32=umin32=14,smax=umax=smax32=umax32=259,var_off=(0x0; 0x1ff)) +7: (35) if r0 >= 0xa goto pc+1 ; R0=scalar(id=2,smin=umin=smin32=umin32=6,smax=umax=smax32=umax32=9,var_off=(0x0; 0xf)) +8: (37) r0 /= 0 +div by zero + +When 4 is verified, r1's bounds are propagated to r0 but r0 also gets +BPF_ADD_CONST (bug). +When 5 is verified, r0 gets a new id (2) and its link with r1 is broken. + +After 6 we know r1 has bounds [14, 259] and therefore r0 should have +bounds [10, 255], therefore the branch at 7 is always taken. But because +r0's id was changed to 2, r1's new bounds are not propagated to r0. +The verifier still thinks r0 has bounds [6, 255] before 7 and execution +can reach div by zero. + +Fix this by preserving id in sync_linked_regs() like off and subreg_def. + +Fixes: 98d7ca374ba4 ("bpf: Track delta between "linked" registers.") +Signed-off-by: Puranjay Mohan +Acked-by: Eduard Zingerman +Link: https://lore.kernel.org/r/20260115151143.1344724-2-puranjay@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/verifier.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index 646025bae96db..8678ce5c97c5a 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -16827,6 +16827,7 @@ static void sync_linked_regs(struct bpf_verifier_state *vstate, struct bpf_reg_s + } else { + s32 saved_subreg_def = reg->subreg_def; + s32 saved_off = reg->off; ++ u32 saved_id = reg->id; + + fake_reg.type = SCALAR_VALUE; + __mark_reg_known(&fake_reg, (s32)reg->off - (s32)known_reg->off); +@@ -16834,10 +16835,11 @@ static void sync_linked_regs(struct bpf_verifier_state *vstate, struct bpf_reg_s + /* reg = known_reg; reg += delta */ + copy_register_state(reg, known_reg); + /* +- * Must preserve off, id and add_const flag, ++ * Must preserve off, id and subreg_def flag, + * otherwise another sync_linked_regs() will be incorrect. + */ + reg->off = saved_off; ++ reg->id = saved_id; + reg->subreg_def = saved_subreg_def; + + scalar32_min_max_add(reg, &fake_reg); +-- +2.51.0 + diff --git a/queue-6.19/bpf-require-frozen-map-for-calculating-map-hash.patch b/queue-6.19/bpf-require-frozen-map-for-calculating-map-hash.patch new file mode 100644 index 0000000000..28efe304f5 --- /dev/null +++ b/queue-6.19/bpf-require-frozen-map-for-calculating-map-hash.patch @@ -0,0 +1,51 @@ +From 0cbf37a91e9b6f1fe5d7cfa48a041a73719026c4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 08:07:55 +0100 +Subject: bpf: Require frozen map for calculating map hash + +From: KP Singh + +[ Upstream commit a2c86aa621c22f2a7e26c654f936d65cfff0aa91 ] + +Currently, bpf_map_get_info_by_fd calculates and caches the hash of the +map regardless of the map's frozen state. + +This leads to a TOCTOU bug where userspace can call +BPF_OBJ_GET_INFO_BY_FD to cache the hash and then modify the map +contents before freezing. + +Therefore, a trusted loader can be tricked into verifying the stale hash +while loading the modified contents. + +Fix this by returning -EPERM if the map is not frozen when the hash is +requested. This ensures the hash is only generated for the final, +immutable state of the map. + +Fixes: ea2e6467ac36 ("bpf: Return hashes of maps in BPF_OBJ_GET_INFO_BY_FD") +Reported-by: Toshi Piazza +Signed-off-by: KP Singh +Acked-by: Daniel Borkmann +Link: https://lore.kernel.org/r/20260205070755.695776-1-kpsingh@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/syscall.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c +index f89aa142f71b8..ce7db2f3be6f6 100644 +--- a/kernel/bpf/syscall.c ++++ b/kernel/bpf/syscall.c +@@ -5314,6 +5314,9 @@ static int bpf_map_get_info_by_fd(struct file *file, + if (info.hash_size != SHA256_DIGEST_SIZE) + return -EINVAL; + ++ if (!READ_ONCE(map->frozen)) ++ return -EPERM; ++ + err = map->ops->map_get_hash(map, SHA256_DIGEST_SIZE, map->sha); + if (err != 0) + return err; +-- +2.51.0 + diff --git a/queue-6.19/bpf-return-proper-address-for-non-zero-offsets-in-in.patch b/queue-6.19/bpf-return-proper-address-for-non-zero-offsets-in-in.patch new file mode 100644 index 0000000000..f06d8d9451 --- /dev/null +++ b/queue-6.19/bpf-return-proper-address-for-non-zero-offsets-in-in.patch @@ -0,0 +1,41 @@ +From 4363715ea8e32bfd25f65f8296a626f2f9962c16 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 11 Jan 2026 15:30:45 +0000 +Subject: bpf: Return proper address for non-zero offsets in insn array + +From: Anton Protopopov + +[ Upstream commit e3bd7bdf5ffe49d8381e42843f6e98cd0c78a1e8 ] + +The map_direct_value_addr() function of the instruction +array map incorrectly adds offset to the resulting address. +This is a bug, because later the resolve_pseudo_ldimm64() +function adds the offset. Fix it. Corresponding selftests +are added in a consequent commit. + +Fixes: 493d9e0d6083 ("bpf, x86: add support for indirect jumps") +Signed-off-by: Anton Protopopov +Reviewed-by: Emil Tsalapatis +Link: https://lore.kernel.org/r/20260111153047.8388-2-a.s.protopopov@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/bpf_insn_array.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/bpf/bpf_insn_array.c b/kernel/bpf/bpf_insn_array.c +index c96630cb75bf7..37b43102953ee 100644 +--- a/kernel/bpf/bpf_insn_array.c ++++ b/kernel/bpf/bpf_insn_array.c +@@ -126,7 +126,7 @@ static int insn_array_map_direct_value_addr(const struct bpf_map *map, u64 *imm, + return -EINVAL; + + /* from BPF's point of view, this map is a jump table */ +- *imm = (unsigned long)insn_array->ips + off; ++ *imm = (unsigned long)insn_array->ips; + + return 0; + } +-- +2.51.0 + diff --git a/queue-6.19/bpf-sockmap-fix-fionread-for-sockmap.patch b/queue-6.19/bpf-sockmap-fix-fionread-for-sockmap.patch new file mode 100644 index 0000000000..1317c27b39 --- /dev/null +++ b/queue-6.19/bpf-sockmap-fix-fionread-for-sockmap.patch @@ -0,0 +1,293 @@ +From 41f69980f00144c96ab561bbdf673d23b790d016 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 24 Jan 2026 19:32:44 +0800 +Subject: bpf, sockmap: Fix FIONREAD for sockmap + +From: Jiayuan Chen + +[ Upstream commit 929e30f9312514902133c45e51c79088421ab084 ] + +A socket using sockmap has its own independent receive queue: ingress_msg. +This queue may contain data from its own protocol stack or from other +sockets. + +Therefore, for sockmap, relying solely on copied_seq and rcv_nxt to +calculate FIONREAD is not enough. + +This patch adds a new msg_tot_len field in the psock structure to record +the data length in ingress_msg. Additionally, we implement new ioctl +interfaces for TCP and UDP to intercept FIONREAD operations. + +Note that we intentionally do not include sk_receive_queue data in the +FIONREAD result. Data in sk_receive_queue has not yet been processed by +the BPF verdict program, and may be redirected to other sockets or +dropped. Including it would create semantic ambiguity since this data +may never be readable by the user. + +Unix and VSOCK sockets have similar issues, but fixing them is outside +the scope of this patch as it would require more intrusive changes. + +Previous work by John Fastabend made some efforts towards FIONREAD support: +commit e5c6de5fa025 ("bpf, sockmap: Incorrectly handling copied_seq") +Although the current patch is based on the previous work by John Fastabend, +it is acceptable for our Fixes tag to point to the same commit. + + FD1:read() + -- FD1->copied_seq++ + | [read data] + | + [enqueue data] v + [sockmap] -> ingress to self -> ingress_msg queue +FD1 native stack ------> ^ +-- FD1->rcv_nxt++ -> redirect to other | [enqueue data] + | | + | ingress to FD1 + v ^ + ... | [sockmap] + FD2 native stack + +Fixes: 04919bed948dc ("tcp: Introduce tcp_read_skb()") +Signed-off-by: Jiayuan Chen +Reviewed-by: Jakub Sitnicki +Link: https://lore.kernel.org/r/20260124113314.113584-3-jiayuan.chen@linux.dev +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + include/linux/skmsg.h | 68 +++++++++++++++++++++++++++++++++++++++++-- + net/core/skmsg.c | 3 ++ + net/ipv4/tcp_bpf.c | 20 +++++++++++++ + net/ipv4/udp_bpf.c | 23 ++++++++++++--- + 4 files changed, 108 insertions(+), 6 deletions(-) + +diff --git a/include/linux/skmsg.h b/include/linux/skmsg.h +index dfdc158ab88c8..829b281d6c9c2 100644 +--- a/include/linux/skmsg.h ++++ b/include/linux/skmsg.h +@@ -97,6 +97,8 @@ struct sk_psock { + struct sk_buff_head ingress_skb; + struct list_head ingress_msg; + spinlock_t ingress_lock; ++ /** @msg_tot_len: Total bytes queued in ingress_msg list. */ ++ u32 msg_tot_len; + unsigned long state; + struct list_head link; + spinlock_t link_lock; +@@ -321,6 +323,27 @@ static inline void sock_drop(struct sock *sk, struct sk_buff *skb) + kfree_skb(skb); + } + ++static inline u32 sk_psock_get_msg_len_nolock(struct sk_psock *psock) ++{ ++ /* Used by ioctl to read msg_tot_len only; lock-free for performance */ ++ return READ_ONCE(psock->msg_tot_len); ++} ++ ++static inline void sk_psock_msg_len_add_locked(struct sk_psock *psock, int diff) ++{ ++ /* Use WRITE_ONCE to ensure correct read in sk_psock_get_msg_len_nolock(). ++ * ingress_lock should be held to prevent concurrent updates to msg_tot_len ++ */ ++ WRITE_ONCE(psock->msg_tot_len, psock->msg_tot_len + diff); ++} ++ ++static inline void sk_psock_msg_len_add(struct sk_psock *psock, int diff) ++{ ++ spin_lock_bh(&psock->ingress_lock); ++ sk_psock_msg_len_add_locked(psock, diff); ++ spin_unlock_bh(&psock->ingress_lock); ++} ++ + static inline bool sk_psock_queue_msg(struct sk_psock *psock, + struct sk_msg *msg) + { +@@ -329,6 +352,7 @@ static inline bool sk_psock_queue_msg(struct sk_psock *psock, + spin_lock_bh(&psock->ingress_lock); + if (sk_psock_test_state(psock, SK_PSOCK_TX_ENABLED)) { + list_add_tail(&msg->list, &psock->ingress_msg); ++ sk_psock_msg_len_add_locked(psock, msg->sg.size); + ret = true; + } else { + sk_msg_free(psock->sk, msg); +@@ -345,18 +369,25 @@ static inline struct sk_msg *sk_psock_dequeue_msg(struct sk_psock *psock) + + spin_lock_bh(&psock->ingress_lock); + msg = list_first_entry_or_null(&psock->ingress_msg, struct sk_msg, list); +- if (msg) ++ if (msg) { + list_del(&msg->list); ++ sk_psock_msg_len_add_locked(psock, -msg->sg.size); ++ } + spin_unlock_bh(&psock->ingress_lock); + return msg; + } + ++static inline struct sk_msg *sk_psock_peek_msg_locked(struct sk_psock *psock) ++{ ++ return list_first_entry_or_null(&psock->ingress_msg, struct sk_msg, list); ++} ++ + static inline struct sk_msg *sk_psock_peek_msg(struct sk_psock *psock) + { + struct sk_msg *msg; + + spin_lock_bh(&psock->ingress_lock); +- msg = list_first_entry_or_null(&psock->ingress_msg, struct sk_msg, list); ++ msg = sk_psock_peek_msg_locked(psock); + spin_unlock_bh(&psock->ingress_lock); + return msg; + } +@@ -523,6 +554,39 @@ static inline bool sk_psock_strp_enabled(struct sk_psock *psock) + return !!psock->saved_data_ready; + } + ++/* for tcp only, sk is locked */ ++static inline ssize_t sk_psock_msg_inq(struct sock *sk) ++{ ++ struct sk_psock *psock; ++ ssize_t inq = 0; ++ ++ psock = sk_psock_get(sk); ++ if (likely(psock)) { ++ inq = sk_psock_get_msg_len_nolock(psock); ++ sk_psock_put(sk, psock); ++ } ++ return inq; ++} ++ ++/* for udp only, sk is not locked */ ++static inline ssize_t sk_msg_first_len(struct sock *sk) ++{ ++ struct sk_psock *psock; ++ struct sk_msg *msg; ++ ssize_t inq = 0; ++ ++ psock = sk_psock_get(sk); ++ if (likely(psock)) { ++ spin_lock_bh(&psock->ingress_lock); ++ msg = sk_psock_peek_msg_locked(psock); ++ if (msg) ++ inq = msg->sg.size; ++ spin_unlock_bh(&psock->ingress_lock); ++ sk_psock_put(sk, psock); ++ } ++ return inq; ++} ++ + #if IS_ENABLED(CONFIG_NET_SOCK_MSG) + + #define BPF_F_STRPARSER (1UL << 1) +diff --git a/net/core/skmsg.c b/net/core/skmsg.c +index d402da5caadd6..ddde93dd8bc6d 100644 +--- a/net/core/skmsg.c ++++ b/net/core/skmsg.c +@@ -458,6 +458,7 @@ int __sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg + atomic_sub(copy, &sk->sk_rmem_alloc); + } + msg_rx->sg.size -= copy; ++ sk_psock_msg_len_add(psock, -copy); + + if (!sge->length) { + sk_msg_iter_var_next(i); +@@ -821,9 +822,11 @@ static void __sk_psock_purge_ingress_msg(struct sk_psock *psock) + list_del(&msg->list); + if (!msg->skb) + atomic_sub(msg->sg.size, &psock->sk->sk_rmem_alloc); ++ sk_psock_msg_len_add(psock, -msg->sg.size); + sk_msg_free(psock->sk, msg); + kfree(msg); + } ++ WARN_ON_ONCE(psock->msg_tot_len); + } + + static void __sk_psock_zap_ingress(struct sk_psock *psock) +diff --git a/net/ipv4/tcp_bpf.c b/net/ipv4/tcp_bpf.c +index 5c698fd7fbf81..ca8a5cb8e569d 100644 +--- a/net/ipv4/tcp_bpf.c ++++ b/net/ipv4/tcp_bpf.c +@@ -10,6 +10,7 @@ + + #include + #include ++#include + + void tcp_eat_skb(struct sock *sk, struct sk_buff *skb) + { +@@ -332,6 +333,24 @@ static int tcp_bpf_recvmsg_parser(struct sock *sk, + return copied; + } + ++static int tcp_bpf_ioctl(struct sock *sk, int cmd, int *karg) ++{ ++ bool slow; ++ ++ if (cmd != SIOCINQ) ++ return tcp_ioctl(sk, cmd, karg); ++ ++ /* works similar as tcp_ioctl */ ++ if (sk->sk_state == TCP_LISTEN) ++ return -EINVAL; ++ ++ slow = lock_sock_fast(sk); ++ *karg = sk_psock_msg_inq(sk); ++ unlock_sock_fast(sk, slow); ++ ++ return 0; ++} ++ + static int tcp_bpf_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, + int flags, int *addr_len) + { +@@ -610,6 +629,7 @@ static void tcp_bpf_rebuild_protos(struct proto prot[TCP_BPF_NUM_CFGS], + prot[TCP_BPF_BASE].close = sock_map_close; + prot[TCP_BPF_BASE].recvmsg = tcp_bpf_recvmsg; + prot[TCP_BPF_BASE].sock_is_readable = sk_msg_is_readable; ++ prot[TCP_BPF_BASE].ioctl = tcp_bpf_ioctl; + + prot[TCP_BPF_TX] = prot[TCP_BPF_BASE]; + prot[TCP_BPF_TX].sendmsg = tcp_bpf_sendmsg; +diff --git a/net/ipv4/udp_bpf.c b/net/ipv4/udp_bpf.c +index 0735d820e413f..91233e37cd97a 100644 +--- a/net/ipv4/udp_bpf.c ++++ b/net/ipv4/udp_bpf.c +@@ -5,6 +5,7 @@ + #include + #include + #include ++#include + + #include "udp_impl.h" + +@@ -111,12 +112,26 @@ enum { + static DEFINE_SPINLOCK(udpv6_prot_lock); + static struct proto udp_bpf_prots[UDP_BPF_NUM_PROTS]; + ++static int udp_bpf_ioctl(struct sock *sk, int cmd, int *karg) ++{ ++ if (cmd != SIOCINQ) ++ return udp_ioctl(sk, cmd, karg); ++ ++ /* Since we don't hold a lock, sk_receive_queue may contain data. ++ * BPF might only be processing this data at the moment. We only ++ * care about the data in the ingress_msg here. ++ */ ++ *karg = sk_msg_first_len(sk); ++ return 0; ++} ++ + static void udp_bpf_rebuild_protos(struct proto *prot, const struct proto *base) + { +- *prot = *base; +- prot->close = sock_map_close; +- prot->recvmsg = udp_bpf_recvmsg; +- prot->sock_is_readable = sk_msg_is_readable; ++ *prot = *base; ++ prot->close = sock_map_close; ++ prot->recvmsg = udp_bpf_recvmsg; ++ prot->sock_is_readable = sk_msg_is_readable; ++ prot->ioctl = udp_bpf_ioctl; + } + + static void udp_bpf_check_v6_needs_rebuild(struct proto *ops) +-- +2.51.0 + diff --git a/queue-6.19/bpf-sockmap-fix-incorrect-copied_seq-calculation.patch b/queue-6.19/bpf-sockmap-fix-incorrect-copied_seq-calculation.patch new file mode 100644 index 0000000000..c5c30d89a2 --- /dev/null +++ b/queue-6.19/bpf-sockmap-fix-incorrect-copied_seq-calculation.patch @@ -0,0 +1,178 @@ +From bdf8c39a7ec2c61b30bb23b95145feebce546cb2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 24 Jan 2026 19:32:43 +0800 +Subject: bpf, sockmap: Fix incorrect copied_seq calculation + +From: Jiayuan Chen + +[ Upstream commit b40cc5adaa80e1471095a62d78233b611d7a558c ] + +A socket using sockmap has its own independent receive queue: ingress_msg. +This queue may contain data from its own protocol stack or from other +sockets. + +The issue is that when reading from ingress_msg, we update tp->copied_seq +by default. However, if the data is not from its own protocol stack, +tcp->rcv_nxt is not increased. Later, if we convert this socket to a +native socket, reading from this socket may fail because copied_seq might +be significantly larger than rcv_nxt. + +This fix also addresses the syzkaller-reported bug referenced in the +Closes tag. + +This patch marks the skmsg objects in ingress_msg. When reading, we update +copied_seq only if the data is from its own protocol stack. + + FD1:read() + -- FD1->copied_seq++ + | [read data] + | + [enqueue data] v + [sockmap] -> ingress to self -> ingress_msg queue +FD1 native stack ------> ^ +-- FD1->rcv_nxt++ -> redirect to other | [enqueue data] + | | + | ingress to FD1 + v ^ + ... | [sockmap] + FD2 native stack + +Closes: https://syzkaller.appspot.com/bug?extid=06dbd397158ec0ea4983 +Fixes: 04919bed948dc ("tcp: Introduce tcp_read_skb()") +Reviewed-by: Jakub Sitnicki +Reviewed-by: John Fastabend +Signed-off-by: Jiayuan Chen +Link: https://lore.kernel.org/r/20260124113314.113584-2-jiayuan.chen@linux.dev +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + include/linux/skmsg.h | 2 ++ + net/core/skmsg.c | 27 ++++++++++++++++++++++++--- + net/ipv4/tcp_bpf.c | 5 +++-- + 3 files changed, 29 insertions(+), 5 deletions(-) + +diff --git a/include/linux/skmsg.h b/include/linux/skmsg.h +index 49847888c287a..dfdc158ab88c8 100644 +--- a/include/linux/skmsg.h ++++ b/include/linux/skmsg.h +@@ -141,6 +141,8 @@ int sk_msg_memcopy_from_iter(struct sock *sk, struct iov_iter *from, + struct sk_msg *msg, u32 bytes); + int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, + int len, int flags); ++int __sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, ++ int len, int flags, int *copied_from_self); + bool sk_msg_is_readable(struct sock *sk); + + static inline void sk_msg_check_to_free(struct sk_msg *msg, u32 i, u32 bytes) +diff --git a/net/core/skmsg.c b/net/core/skmsg.c +index 2ac7731e1e0a7..d402da5caadd6 100644 +--- a/net/core/skmsg.c ++++ b/net/core/skmsg.c +@@ -409,22 +409,26 @@ int sk_msg_memcopy_from_iter(struct sock *sk, struct iov_iter *from, + } + EXPORT_SYMBOL_GPL(sk_msg_memcopy_from_iter); + +-/* Receive sk_msg from psock->ingress_msg to @msg. */ +-int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, +- int len, int flags) ++int __sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, ++ int len, int flags, int *copied_from_self) + { + struct iov_iter *iter = &msg->msg_iter; + int peek = flags & MSG_PEEK; + struct sk_msg *msg_rx; + int i, copied = 0; ++ bool from_self; + + msg_rx = sk_psock_peek_msg(psock); ++ if (copied_from_self) ++ *copied_from_self = 0; ++ + while (copied != len) { + struct scatterlist *sge; + + if (unlikely(!msg_rx)) + break; + ++ from_self = msg_rx->sk == sk; + i = msg_rx->sg.start; + do { + struct page *page; +@@ -443,6 +447,9 @@ int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, + } + + copied += copy; ++ if (from_self && copied_from_self) ++ *copied_from_self += copy; ++ + if (likely(!peek)) { + sge->offset += copy; + sge->length -= copy; +@@ -487,6 +494,13 @@ int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, + out: + return copied; + } ++ ++/* Receive sk_msg from psock->ingress_msg to @msg. */ ++int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, ++ int len, int flags) ++{ ++ return __sk_msg_recvmsg(sk, psock, msg, len, flags, NULL); ++} + EXPORT_SYMBOL_GPL(sk_msg_recvmsg); + + bool sk_msg_is_readable(struct sock *sk) +@@ -616,6 +630,12 @@ static int sk_psock_skb_ingress_self(struct sk_psock *psock, struct sk_buff *skb + if (unlikely(!msg)) + return -EAGAIN; + skb_set_owner_r(skb, sk); ++ ++ /* This is used in tcp_bpf_recvmsg_parser() to determine whether the ++ * data originates from the socket's own protocol stack. No need to ++ * refcount sk because msg's lifetime is bound to sk via the ingress_msg. ++ */ ++ msg->sk = sk; + err = sk_psock_skb_ingress_enqueue(skb, off, len, psock, sk, msg, take_ref); + if (err < 0) + kfree(msg); +@@ -909,6 +929,7 @@ int sk_psock_msg_verdict(struct sock *sk, struct sk_psock *psock, + sk_msg_compute_data_pointers(msg); + msg->sk = sk; + ret = bpf_prog_run_pin_on_cpu(prog, msg); ++ msg->sk = NULL; + ret = sk_psock_map_verd(ret, msg->sk_redir); + psock->apply_bytes = msg->apply_bytes; + if (ret == __SK_REDIRECT) { +diff --git a/net/ipv4/tcp_bpf.c b/net/ipv4/tcp_bpf.c +index a268e1595b22a..5c698fd7fbf81 100644 +--- a/net/ipv4/tcp_bpf.c ++++ b/net/ipv4/tcp_bpf.c +@@ -226,6 +226,7 @@ static int tcp_bpf_recvmsg_parser(struct sock *sk, + int peek = flags & MSG_PEEK; + struct sk_psock *psock; + struct tcp_sock *tcp; ++ int copied_from_self = 0; + int copied = 0; + u32 seq; + +@@ -262,7 +263,7 @@ static int tcp_bpf_recvmsg_parser(struct sock *sk, + } + + msg_bytes_ready: +- copied = sk_msg_recvmsg(sk, psock, msg, len, flags); ++ copied = __sk_msg_recvmsg(sk, psock, msg, len, flags, &copied_from_self); + /* The typical case for EFAULT is the socket was gracefully + * shutdown with a FIN pkt. So check here the other case is + * some error on copy_page_to_iter which would be unexpected. +@@ -277,7 +278,7 @@ static int tcp_bpf_recvmsg_parser(struct sock *sk, + goto out; + } + } +- seq += copied; ++ seq += copied_from_self; + if (!copied) { + long timeo; + int data; +-- +2.51.0 + diff --git a/queue-6.19/btrfs-fix-block_group_tree-dirty_list-corruption.patch b/queue-6.19/btrfs-fix-block_group_tree-dirty_list-corruption.patch new file mode 100644 index 0000000000..1ff2c807d1 --- /dev/null +++ b/queue-6.19/btrfs-fix-block_group_tree-dirty_list-corruption.patch @@ -0,0 +1,150 @@ +From b4f0cd454b668102310173abe76370c130edb46d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 22 Dec 2025 16:15:44 -0800 +Subject: btrfs: fix block_group_tree dirty_list corruption + +From: Boris Burkov + +[ Upstream commit 3a1f4264daed4b419c325a7fe35e756cada3cf82 ] + +When the incompat flag EXTENT_TREE_V2 is set, we unconditionally add the +block group tree to the switch_commits list before calling +switch_commit_roots, as we do for the tree root and the chunk root. +However, the block group tree uses normal root dirty tracking and in any +transaction that does an allocation and dirties a block group, the block +group root will already be linked to a list by the dirty_list field and +this use of list_add_tail() is invalid and corrupts the prev/next +members of block_group_root->dirty_list. + +This is apparent on a subsequent list_del on the prev if we enable +CONFIG_DEBUG_LIST: + + [32.1571] ------------[ cut here ]------------ + [32.1572] list_del corruption. next->prev should beffff958890202538, but was ffff9588992bd538. (next=ffff958890201538) + [32.1575] WARNING: lib/list_debug.c:65 at 0x0, CPU#3: sync/607 + [32.1583] CPU: 3 UID: 0 PID: 607 Comm: sync Not tainted 6.18.0 #24PREEMPT(none) + [32.1585] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS1.17.0-4.fc41 04/01/2014 + [32.1587] RIP: 0010:__list_del_entry_valid_or_report+0x108/0x120 + [32.1593] RSP: 0018:ffffaa288287fdd0 EFLAGS: 00010202 + [32.1594] RAX: 0000000000000001 RBX: ffff95889326e800 RCX:ffff958890201538 + [32.1596] RDX: ffff9588992bd538 RSI: ffff958890202538 RDI:ffffffff82a41e00 + [32.1597] RBP: ffff958890202538 R08: ffffffff828fc1e8 R09:00000000ffffefff + [32.1599] R10: ffffffff8288c200 R11: ffffffff828e4200 R12:ffff958890201538 + [32.1601] R13: ffff95889326e958 R14: ffff958895c24000 R15:ffff958890202538 + [32.1603] FS: 00007f0c28eb5740(0000) GS:ffff958af2bd2000(0000)knlGS:0000000000000000 + [32.1605] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + [32.1607] CR2: 00007f0c28e8a3cc CR3: 0000000109942005 CR4:0000000000370ef0 + [32.1609] Call Trace: + [32.1610] + [32.1611] switch_commit_roots+0x82/0x1d0 [btrfs] + [32.1615] btrfs_commit_transaction+0x968/0x1550 [btrfs] + [32.1618] ? btrfs_attach_transaction_barrier+0x23/0x60 [btrfs] + [32.1621] __iterate_supers+0xe8/0x190 + [32.1622] ? __pfx_sync_fs_one_sb+0x10/0x10 + [32.1623] ksys_sync+0x63/0xb0 + [32.1624] __do_sys_sync+0xe/0x20 + [32.1625] do_syscall_64+0x73/0x450 + [32.1626] entry_SYSCALL_64_after_hwframe+0x76/0x7e + [32.1627] RIP: 0033:0x7f0c28d05d2b + [32.1632] RSP: 002b:00007ffc9d988048 EFLAGS: 00000246 ORIG_RAX:00000000000000a2 + [32.1634] RAX: ffffffffffffffda RBX: 00007ffc9d988228 RCX:00007f0c28d05d2b + [32.1636] RDX: 00007f0c28e02301 RSI: 00007ffc9d989b21 RDI:00007f0c28dba90d + [32.1637] RBP: 0000000000000001 R08: 0000000000000001 R09:0000000000000000 + [32.1639] R10: 0000000000000000 R11: 0000000000000246 R12:000055b96572cb80 + [32.1641] R13: 000055b96572b19f R14: 00007f0c28dfa434 R15:000055b96572b034 + [32.1643] + [32.1644] irq event stamp: 0 + [32.1644] hardirqs last enabled at (0): [<0000000000000000>] 0x0 + [32.1646] hardirqs last disabled at (0): []copy_process+0xb37/0x2260 + [32.1648] softirqs last enabled at (0): []copy_process+0xb37/0x2260 + [32.1650] softirqs last disabled at (0): [<0000000000000000>] 0x0 + [32.1652] ---[ end trace 0000000000000000 ]--- + +Furthermore, this list corruption eventually (when we happen to add a +new block group) results in getting the switch_commits and +dirty_cowonly_roots lists mixed up and attempting to call update_root +on the tree root which can't be found in the tree root, resulting in a +transaction abort: + + [87.8269] BTRFS critical (device nvme1n1): unable to find root key (1 0 0) in tree 1 + [87.8272] ------------[ cut here ]------------ + [87.8274] BTRFS: Transaction aborted (error -117) + [87.8275] WARNING: fs/btrfs/root-tree.c:153 at 0x0, CPU#4: sync/703 + [87.8285] CPU: 4 UID: 0 PID: 703 Comm: sync Not tainted 6.18.0 #25 PREEMPT(none) + [87.8287] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.17.0-4.fc41 04/01/2014 + [87.8289] RIP: 0010:btrfs_update_root+0x296/0x790 [btrfs] + [87.8295] RSP: 0018:ffffa58d035dfd60 EFLAGS: 00010282 + [87.8297] RAX: ffff9a59126ddb68 RBX: ffff9a59126dc000 RCX: 0000000000000000 + [87.8299] RDX: 0000000000000000 RSI: 00000000ffffff8b RDI: ffffffffc0b28270 + [87.8301] RBP: ffff9a5904aec000 R08: 0000000000000000 R09: 00000000ffffefff + [87.8303] R10: ffffffff9ac8c200 R11: ffffffff9ace4200 R12: 0000000000000001 + [87.8305] R13: ffff9a59041740e8 R14: ffff9a5904aec1f7 R15: ffff9a590fdefaf0 + [87.8307] FS: 00007f54cde6b740(0000) GS:ffff9a5b5a81c000(0000) knlGS:0000000000000000 + [87.8309] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + [87.8310] CR2: 00007f54cde403cc CR3: 0000000112902004 CR4: 0000000000370ef0 + [87.8312] Call Trace: + [87.8313] + [87.8314] ? _raw_spin_unlock+0x23/0x40 + [87.8315] commit_cowonly_roots+0x1ad/0x250 [btrfs] + [87.8317] ? btrfs_commit_transaction+0x79b/0x1560 [btrfs] + [87.8320] btrfs_commit_transaction+0x8aa/0x1560 [btrfs] + [87.8322] ? btrfs_attach_transaction_barrier+0x23/0x60 [btrfs] + [87.8325] __iterate_supers+0xf1/0x170 + [87.8326] ? __pfx_sync_fs_one_sb+0x10/0x10 + [87.8327] ksys_sync+0x63/0xb0 + [87.8328] __do_sys_sync+0xe/0x20 + [87.8329] do_syscall_64+0x73/0x450 + [87.8330] entry_SYSCALL_64_after_hwframe+0x76/0x7e + [87.8331] RIP: 0033:0x7f54cdd05d2b + [87.8336] RSP: 002b:00007fff1b58ff78 EFLAGS: 00000246 ORIG_RAX: 00000000000000a2 + [87.8338] RAX: ffffffffffffffda RBX: 00007fff1b590158 RCX: 00007f54cdd05d2b + [87.8340] RDX: 00007f54cde02301 RSI: 00007fff1b592b66 RDI: 00007f54cddba90d + [87.8342] RBP: 0000000000000001 R08: 0000000000000001 R09: 0000000000000000 + [87.8344] R10: 0000000000000000 R11: 0000000000000246 R12: 000055e07ca96b80 + [87.8346] R13: 000055e07ca9519f R14: 00007f54cddfa434 R15: 000055e07ca95034 + [87.8348] + [87.8348] irq event stamp: 0 + [87.8349] hardirqs last enabled at (0): [<0000000000000000>] 0x0 + [87.8351] hardirqs last disabled at (0): [] copy_process+0xb37/0x21e0 + [87.8353] softirqs last enabled at (0): [] copy_process+0xb37/0x21e0 + [87.8355] softirqs last disabled at (0): [<0000000000000000>] 0x0 + [87.8357] ---[ end trace 0000000000000000 ]--- + [87.8358] BTRFS: error (device nvme1n1 state A) in btrfs_update_root:153: errno=-117 Filesystem corrupted + [87.8360] BTRFS info (device nvme1n1 state EA): forced readonly + [87.8362] BTRFS warning (device nvme1n1 state EA): Skipping commit of aborted transaction. + [87.8364] BTRFS: error (device nvme1n1 state EA) in cleanup_transaction:2037: errno=-117 Filesystem corrupted + +Since the block group tree was pulled out of the extent tree and uses +normal root dirty tracking, remove the offending extra list_add. This +fixes the list corruption and the resulting fs corruption. + +Fixes: 14033b08a029 ("btrfs: don't save block group root into super block") +Reviewed-by: Filipe Manana +Signed-off-by: Boris Burkov +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/transaction.c | 7 ------- + 1 file changed, 7 deletions(-) + +diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c +index bd03f465e2d3e..e3e0d88d53476 100644 +--- a/fs/btrfs/transaction.c ++++ b/fs/btrfs/transaction.c +@@ -2500,13 +2500,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans) + list_add_tail(&fs_info->chunk_root->dirty_list, + &cur_trans->switch_commits); + +- if (btrfs_fs_incompat(fs_info, EXTENT_TREE_V2)) { +- btrfs_set_root_node(&fs_info->block_group_root->root_item, +- fs_info->block_group_root->node); +- list_add_tail(&fs_info->block_group_root->dirty_list, +- &cur_trans->switch_commits); +- } +- + switch_commit_roots(trans); + + ASSERT(list_empty(&cur_trans->dirty_bgs)); +-- +2.51.0 + diff --git a/queue-6.19/btrfs-fix-eexist-abort-due-to-non-consecutive-gaps-i.patch b/queue-6.19/btrfs-fix-eexist-abort-due-to-non-consecutive-gaps-i.patch new file mode 100644 index 0000000000..f75fe4b4bb --- /dev/null +++ b/queue-6.19/btrfs-fix-eexist-abort-due-to-non-consecutive-gaps-i.patch @@ -0,0 +1,496 @@ +From f14e77843d1f6f2dfc4f7debb54d30937d906dde Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 16:11:21 -0800 +Subject: btrfs: fix EEXIST abort due to non-consecutive gaps in chunk + allocation + +From: Boris Burkov + +[ Upstream commit b14c5e04bd0f722ed631845599d52d03fcae1bc1 ] + +I have been observing a number of systems aborting at +insert_dev_extents() in btrfs_create_pending_block_groups(). The +following is a sample stack trace of such an abort coming from forced +chunk allocation (typically behind CONFIG_BTRFS_EXPERIMENTAL) but this +can theoretically happen to any DUP chunk allocation. + + [81.801] ------------[ cut here ]------------ + [81.801] BTRFS: Transaction aborted (error -17) + [81.801] WARNING: fs/btrfs/block-group.c:2876 at btrfs_create_pending_block_groups+0x721/0x770 [btrfs], CPU#1: bash/319 + [81.802] Modules linked in: virtio_net btrfs xor zstd_compress raid6_pq null_blk + [81.803] CPU: 1 UID: 0 PID: 319 Comm: bash Kdump: loaded Not tainted 6.19.0-rc6+ #319 NONE + [81.803] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Arch Linux 1.17.0-2-2 04/01/2014 + [81.804] RIP: 0010:btrfs_create_pending_block_groups+0x723/0x770 [btrfs] + [81.806] RSP: 0018:ffffa36241a6bce8 EFLAGS: 00010282 + [81.806] RAX: 000000000000000d RBX: ffff8e699921e400 RCX: 0000000000000000 + [81.807] RDX: 0000000002040001 RSI: 00000000ffffffef RDI: ffffffffc0608bf0 + [81.807] RBP: 00000000ffffffef R08: ffff8e69830f6000 R09: 0000000000000007 + [81.808] R10: ffff8e699921e5e8 R11: 0000000000000000 R12: ffff8e6999228000 + [81.808] R13: ffff8e6984d82000 R14: ffff8e69966a69c0 R15: ffff8e69aa47b000 + [81.809] FS: 00007fec6bdd9740(0000) GS:ffff8e6b1b379000(0000) knlGS:0000000000000000 + [81.809] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + [81.810] CR2: 00005604833670f0 CR3: 0000000116679000 CR4: 00000000000006f0 + [81.810] Call Trace: + [81.810] + [81.810] __btrfs_end_transaction+0x3e/0x2b0 [btrfs] + [81.811] btrfs_force_chunk_alloc_store+0xcd/0x140 [btrfs] + [81.811] kernfs_fop_write_iter+0x15f/0x240 + [81.812] vfs_write+0x264/0x500 + [81.812] ksys_write+0x6c/0xe0 + [81.812] do_syscall_64+0x66/0x770 + [81.812] entry_SYSCALL_64_after_hwframe+0x76/0x7e + [81.813] RIP: 0033:0x7fec6be66197 + [81.814] RSP: 002b:00007fffb159dd30 EFLAGS: 00000202 ORIG_RAX: 0000000000000001 + [81.815] RAX: ffffffffffffffda RBX: 00007fec6bdd9740 RCX: 00007fec6be66197 + [81.815] RDX: 0000000000000002 RSI: 0000560483374f80 RDI: 0000000000000001 + [81.816] RBP: 0000560483374f80 R08: 0000000000000000 R09: 0000000000000000 + [81.816] R10: 0000000000000000 R11: 0000000000000202 R12: 0000000000000002 + [81.817] R13: 00007fec6bfb85c0 R14: 00007fec6bfb5ee0 R15: 00005604833729c0 + [81.817] + [81.817] irq event stamp: 20039 + [81.818] hardirqs last enabled at (20047): [] __up_console_sem+0x52/0x60 + [81.818] hardirqs last disabled at (20056): [] __up_console_sem+0x37/0x60 + [81.819] softirqs last enabled at (19470): [] __irq_exit_rcu+0x96/0xc0 + [81.819] softirqs last disabled at (19463): [] __irq_exit_rcu+0x96/0xc0 + [81.820] ---[ end trace 0000000000000000 ]--- + [81.820] BTRFS: error (device dm-7 state A) in btrfs_create_pending_block_groups:2876: errno=-17 Object already exists + +Inspecting these aborts with drgn, I observed a pattern of overlapping +chunk_maps. Note how stripe 1 of the first chunk overlaps in physical +address with stripe 0 of the second chunk. + +Physical Start Physical End Length Logical Type Stripe +---------------------------------------------------------------------------------------------------- +0x0000000102500000 0x0000000142500000 1.0G 0x0000000641d00000 META|DUP 0/2 +0x0000000142500000 0x0000000182500000 1.0G 0x0000000641d00000 META|DUP 1/2 +0x0000000142500000 0x0000000182500000 1.0G 0x0000000601d00000 META|DUP 0/2 +0x0000000182500000 0x00000001c2500000 1.0G 0x0000000601d00000 META|DUP 1/2 + +Now how could this possibly happen? All chunk allocation is protected by +the chunk_mutex so racing allocations should see a consistent view of +the CHUNK_ALLOCATED bit in the chunk allocation extent-io-tree +(device->alloc_state as set by chunk_map_device_set_bits()) The tree +itself is protected by a spin lock, and clearing/setting the bits is +always protected by fs_info->mapping_tree_lock, so no race is apparent. + +It turns out that there is a subtle bug in the logic regarding chunk +allocations that have happened in the current transaction, known as +"pending extents". The chunk allocation as defined in +find_free_dev_extent() is a loop which searches the commit root of the +dev_root and looks for gaps between DEV_EXTENT items. For those gaps, it +then checks alloc_state bitmap for any pending extents and adjusts the +hole that it finds accordingly. However, the logic in that adjustment +assumes that the first pending extent is the only one in that range. + +e.g., given a layout with two non-consecutive pending extents in a hole +passed to dev_extent_hole_check() via *hole_start and *hole_size: + + |----pending A----| real hole |----pending B----| + | candidate hole | + *hole_start *hole_start + *hole_size + +the code incorrectly returns a "hole" from the end of pending extent A +until the passed in hole end, failing to account for pending B. + +However, it is not entirely obvious that it is actually possible to +produce such a layout. I was able to reproduce it, but with some +contortions: I continued to use the force chunk allocation sysfs file +and I introduced a long delay (10 seconds) into the start of the cleaner +thread. I also prevented the unused bgs cleaning logic from ever +deleting metadata bgs. These help make it easier to deterministically +produce the condition but shouldn't really matter if you imagine the +conditions happening by race/luck. Allocations/frees can happen +concurrently with the cleaner thread preparing to process an unused +extent and both create some used chunks with an unused chunk +interleaved, all during one transaction. Then btrfs_delete_unused_bgs() +sees the unused one and clears it, leaving a range with several pending +chunk allocations and a gap in the middle. + +The basic idea is that the unused_bgs cleanup work happens on a worker +so if we allocate 3 block groups in one transaction, then the cleaner +work kicked off by the previous transaction comes through and deletes +the middle one of the 3, then the commit root shows no dev extents and +we have the bad pattern in the extent-io-tree. One final consideration +is that the code happens to loop to the next hole if there are no more +extents at all, so we need one more dev extent way past the area we are +working in. Something like the following demonstrates the technique: + + # push the BG frontier out to 20G + fallocate -l 20G $mnt/foo + # allocate one more that will prevent the "no more dev extents" luck + fallocate -l 1G $mnt/sticky + # sync + sync + # clear out the allocation area + rm $mnt/foo + sync + _cleaner + # let everything quiesce + sleep 20 + sync + + # dev tree should have one bg 20G out and the rest at the beginning.. + # sort of like an empty FS but with a random sticky chunk. + + # kick off the cleaner in the background, remember it will sleep 10s + # before doing interesting work + _cleaner & + + sleep 3 + + # create 3 trivial block groups, all empty, all immediately marked as unused. + echo 1 > "$(_btrfs_sysfs_space_info $dev metadata)/force_chunk_alloc" + echo 1 > "$(_btrfs_sysfs_space_info $dev data)/force_chunk_alloc" + echo 1 > "$(_btrfs_sysfs_space_info $dev metadata)/force_chunk_alloc" + + # let the cleaner thread definitely finish, it will remove the data bg + sleep 10 + + # this allocation sees the non-consecutive pending metadata chunks with + # data chunk gap of 1G and allocates a 2G extent in that hole. ENOSPC! + echo 1 > "$(_btrfs_sysfs_space_info $dev metadata)/force_chunk_alloc" + +As for the fix, it is not that obvious. I could not see a trivial way to +do it even by adding backup loops into find_free_dev_extent(), so I +opted to change the semantics of dev_extent_hole_check() to not stop +looping until it finds a sufficiently big hole. For clarity, this also +required changing the helper function contains_pending_extent() into two +new helpers which find the first pending extent and the first suitable +hole in a range. + +I attempted to clean up the documentation and range calculations to be +as consistent and clear as possible for the future. + +I also looked at the zoned case and concluded that the loop there is +different and not to be unified with this one. As far as I can tell, the +zoned check will only further constrain the hole so looping back to find +more holes is acceptable. Though given that zoned really only appends, I +find it highly unlikely that it is susceptible to this bug. + +Fixes: 1b9845081633 ("Btrfs: fix find_free_dev_extent() malfunction in case device tree has hole") +Reported-by: Dimitrios Apostolou +Closes: https://lore.kernel.org/linux-btrfs/q7760374-q1p4-029o-5149-26p28421s468@tzk.arg/ +Reviewed-by: Qu Wenruo +Signed-off-by: Boris Burkov +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/volumes.c | 243 ++++++++++++++++++++++++++++++++++----------- + 1 file changed, 183 insertions(+), 60 deletions(-) + +diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c +index 8a08412f3529a..99e167a697ba8 100644 +--- a/fs/btrfs/volumes.c ++++ b/fs/btrfs/volumes.c +@@ -1505,30 +1505,158 @@ struct btrfs_device *btrfs_scan_one_device(const char *path, + } + + /* +- * Try to find a chunk that intersects [start, start + len] range and when one +- * such is found, record the end of it in *start ++ * Find the first pending extent intersecting a range. ++ * ++ * @device: the device to search ++ * @start: start of the range to check ++ * @len: length of the range to check ++ * @pending_start: output pointer for the start of the found pending extent ++ * @pending_end: output pointer for the end of the found pending extent (inclusive) ++ * ++ * Search for a pending chunk allocation that intersects the half-open range ++ * [start, start + len). ++ * ++ * Return: true if a pending extent was found, false otherwise. ++ * If the return value is true, store the first pending extent in ++ * [*pending_start, *pending_end]. Otherwise, the two output variables ++ * may still be modified, to something outside the range and should not ++ * be used. + */ +-static bool contains_pending_extent(struct btrfs_device *device, u64 *start, +- u64 len) ++static bool first_pending_extent(struct btrfs_device *device, u64 start, u64 len, ++ u64 *pending_start, u64 *pending_end) + { +- u64 physical_start, physical_end; +- + lockdep_assert_held(&device->fs_info->chunk_mutex); + +- if (btrfs_find_first_extent_bit(&device->alloc_state, *start, +- &physical_start, &physical_end, ++ if (btrfs_find_first_extent_bit(&device->alloc_state, start, ++ pending_start, pending_end, + CHUNK_ALLOCATED, NULL)) { + +- if (in_range(physical_start, *start, len) || +- in_range(*start, physical_start, +- physical_end + 1 - physical_start)) { +- *start = physical_end + 1; ++ if (in_range(*pending_start, start, len) || ++ in_range(start, *pending_start, *pending_end + 1 - *pending_start)) { + return true; + } + } + return false; + } + ++/* ++ * Find the first real hole accounting for pending extents. ++ * ++ * @device: the device containing the candidate hole ++ * @start: input/output pointer for the hole start position ++ * @len: input/output pointer for the hole length ++ * @min_hole_size: the size of hole we are looking for ++ * ++ * Given a potential hole specified by [*start, *start + *len), check for pending ++ * chunk allocations within that range. If pending extents are found, the hole is ++ * adjusted to represent the first true free space that is large enough when ++ * accounting for pending chunks. ++ * ++ * Note that this function must handle various cases involving non consecutive ++ * pending extents. ++ * ++ * Returns: true if a suitable hole was found and false otherwise. ++ * If the return value is true, then *start and *len are set to represent the hole. ++ * If the return value is false, then *start is set to the largest hole we ++ * found and *len is set to its length. ++ * If there are no holes at all, then *start is set to the end of the range and ++ * *len is set to 0. ++ */ ++static bool find_hole_in_pending_extents(struct btrfs_device *device, u64 *start, ++ u64 *len, u64 min_hole_size) ++{ ++ u64 pending_start, pending_end; ++ u64 end; ++ u64 max_hole_start = 0; ++ u64 max_hole_len = 0; ++ ++ lockdep_assert_held(&device->fs_info->chunk_mutex); ++ ++ if (*len == 0) ++ return false; ++ ++ end = *start + *len - 1; ++ ++ /* ++ * Loop until we either see a large enough hole or check every pending ++ * extent overlapping the candidate hole. ++ * At every hole that we observe, record it if it is the new max. ++ * At the end of the iteration, set the output variables to the max hole. ++ */ ++ while (true) { ++ if (first_pending_extent(device, *start, *len, &pending_start, &pending_end)) { ++ /* ++ * Case 1: the pending extent overlaps the start of ++ * candidate hole. That means the true hole is after the ++ * pending extent, but we need to find the next pending ++ * extent to properly size the hole. In the next loop, ++ * we will reduce to case 2 or 3. ++ * e.g., ++ * ++ * |----pending A----| real hole |----pending B----| ++ * | candidate hole | ++ * *start end ++ */ ++ if (pending_start <= *start) { ++ *start = pending_end + 1; ++ goto next; ++ } ++ /* ++ * Case 2: The pending extent starts after *start (and overlaps ++ * [*start, end), so the first hole just goes up to the start ++ * of the pending extent. ++ * e.g., ++ * ++ * | real hole |----pending A----| ++ * | candidate hole | ++ * *start end ++ */ ++ *len = pending_start - *start; ++ if (*len > max_hole_len) { ++ max_hole_start = *start; ++ max_hole_len = *len; ++ } ++ if (*len >= min_hole_size) ++ break; ++ /* ++ * If the hole wasn't big enough, then we advance past ++ * the pending extent and keep looking. ++ */ ++ *start = pending_end + 1; ++ goto next; ++ } else { ++ /* ++ * Case 3: There is no pending extent overlapping the ++ * range [*start, *start + *len - 1], so the only remaining ++ * hole is the remaining range. ++ * e.g., ++ * ++ * | candidate hole | ++ * | real hole | ++ * *start end ++ */ ++ ++ if (*len > max_hole_len) { ++ max_hole_start = *start; ++ max_hole_len = *len; ++ } ++ break; ++ } ++next: ++ if (*start > end) ++ break; ++ *len = end - *start + 1; ++ } ++ if (max_hole_len) { ++ *start = max_hole_start; ++ *len = max_hole_len; ++ } else { ++ *start = end + 1; ++ *len = 0; ++ } ++ return max_hole_len >= min_hole_size; ++} ++ + static u64 dev_extent_search_start(struct btrfs_device *device) + { + switch (device->fs_devices->chunk_alloc_policy) { +@@ -1593,59 +1721,57 @@ static bool dev_extent_hole_check_zoned(struct btrfs_device *device, + } + + /* +- * Check if specified hole is suitable for allocation. ++ * Validate and adjust a hole for chunk allocation ++ * ++ * @device: the device containing the candidate hole ++ * @hole_start: input/output pointer for the hole start position ++ * @hole_size: input/output pointer for the hole size ++ * @num_bytes: minimum allocation size required + * +- * @device: the device which we have the hole +- * @hole_start: starting position of the hole +- * @hole_size: the size of the hole +- * @num_bytes: the size of the free space that we need ++ * Check if the specified hole is suitable for allocation and adjust it if ++ * necessary. The hole may be modified to skip over pending chunk allocations ++ * and to satisfy stricter zoned requirements on zoned filesystems. + * +- * This function may modify @hole_start and @hole_size to reflect the suitable +- * position for allocation. Returns 1 if hole position is updated, 0 otherwise. ++ * For regular (non-zoned) allocation, if the hole after adjustment is smaller ++ * than @num_bytes, the search continues past additional pending extents until ++ * either a sufficiently large hole is found or no more pending extents exist. ++ * ++ * Return: true if a suitable hole was found and false otherwise. ++ * If the return value is true, then *hole_start and *hole_size are set to ++ * represent the hole we found. ++ * If the return value is false, then *hole_start is set to the largest ++ * hole we found and *hole_size is set to its length. ++ * If there are no holes at all, then *hole_start is set to the end of the range ++ * and *hole_size is set to 0. + */ + static bool dev_extent_hole_check(struct btrfs_device *device, u64 *hole_start, + u64 *hole_size, u64 num_bytes) + { +- bool changed = false; +- u64 hole_end = *hole_start + *hole_size; ++ bool found = false; ++ const u64 hole_end = *hole_start + *hole_size - 1; + +- for (;;) { +- /* +- * Check before we set max_hole_start, otherwise we could end up +- * sending back this offset anyway. +- */ +- if (contains_pending_extent(device, hole_start, *hole_size)) { +- if (hole_end >= *hole_start) +- *hole_size = hole_end - *hole_start; +- else +- *hole_size = 0; +- changed = true; +- } ++ ASSERT(*hole_size > 0); + +- switch (device->fs_devices->chunk_alloc_policy) { +- default: +- btrfs_warn_unknown_chunk_allocation(device->fs_devices->chunk_alloc_policy); +- fallthrough; +- case BTRFS_CHUNK_ALLOC_REGULAR: +- /* No extra check */ +- break; +- case BTRFS_CHUNK_ALLOC_ZONED: +- if (dev_extent_hole_check_zoned(device, hole_start, +- hole_size, num_bytes)) { +- changed = true; +- /* +- * The changed hole can contain pending extent. +- * Loop again to check that. +- */ +- continue; +- } +- break; +- } ++again: ++ *hole_size = hole_end - *hole_start + 1; ++ found = find_hole_in_pending_extents(device, hole_start, hole_size, num_bytes); ++ if (!found) ++ return found; ++ ASSERT(*hole_size >= num_bytes); + ++ switch (device->fs_devices->chunk_alloc_policy) { ++ default: ++ btrfs_warn_unknown_chunk_allocation(device->fs_devices->chunk_alloc_policy); ++ fallthrough; ++ case BTRFS_CHUNK_ALLOC_REGULAR: ++ return found; ++ case BTRFS_CHUNK_ALLOC_ZONED: ++ if (dev_extent_hole_check_zoned(device, hole_start, hole_size, num_bytes)) ++ goto again; + break; + } + +- return changed; ++ return found; + } + + /* +@@ -1704,7 +1830,7 @@ static int find_free_dev_extent(struct btrfs_device *device, u64 num_bytes, + ret = -ENOMEM; + goto out; + } +-again: ++ + if (search_start >= search_end || + test_bit(BTRFS_DEV_STATE_REPLACE_TGT, &device->dev_state)) { + ret = -ENOSPC; +@@ -1791,11 +1917,7 @@ static int find_free_dev_extent(struct btrfs_device *device, u64 num_bytes, + */ + if (search_end > search_start) { + hole_size = search_end - search_start; +- if (dev_extent_hole_check(device, &search_start, &hole_size, +- num_bytes)) { +- btrfs_release_path(path); +- goto again; +- } ++ dev_extent_hole_check(device, &search_start, &hole_size, num_bytes); + + if (hole_size > max_hole_size) { + max_hole_start = search_start; +@@ -4844,6 +4966,7 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size) + u64 diff; + u64 start; + u64 free_diff = 0; ++ u64 pending_start, pending_end; + + new_size = round_down(new_size, fs_info->sectorsize); + start = new_size; +@@ -4889,7 +5012,7 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size) + * in-memory chunks are synced to disk so that the loop below sees them + * and relocates them accordingly. + */ +- if (contains_pending_extent(device, &start, diff)) { ++ if (first_pending_extent(device, start, diff, &pending_start, &pending_end)) { + mutex_unlock(&fs_info->chunk_mutex); + ret = btrfs_commit_transaction(trans); + if (ret) +-- +2.51.0 + diff --git a/queue-6.19/btrfs-qgroup-return-correct-error-when-deleting-qgro.patch b/queue-6.19/btrfs-qgroup-return-correct-error-when-deleting-qgro.patch new file mode 100644 index 0000000000..1f4c75d6c0 --- /dev/null +++ b/queue-6.19/btrfs-qgroup-return-correct-error-when-deleting-qgro.patch @@ -0,0 +1,43 @@ +From c8dda6e11cdd469971d19d1fc31bbbd6ae7496dd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 19:35:23 +0000 +Subject: btrfs: qgroup: return correct error when deleting qgroup relation + item + +From: Filipe Manana + +[ Upstream commit 51b1fcf71c88c3c89e7dcf07869c5de837b1f428 ] + +If we fail to delete the second qgroup relation item, we end up returning +success or -ENOENT in case the first item does not exist, instead of +returning the error from the second item deletion. + +Fixes: 73798c465b66 ("btrfs: qgroup: Try our best to delete qgroup relations") +Reviewed-by: Johannes Thumshirn +Signed-off-by: Filipe Manana +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/qgroup.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c +index 206587820fec0..c634e01140514 100644 +--- a/fs/btrfs/qgroup.c ++++ b/fs/btrfs/qgroup.c +@@ -1607,8 +1607,10 @@ static int __del_qgroup_relation(struct btrfs_trans_handle *trans, u64 src, + if (ret < 0 && ret != -ENOENT) + goto out; + ret2 = del_qgroup_relation_item(trans, dst, src); +- if (ret2 < 0 && ret2 != -ENOENT) ++ if (ret2 < 0 && ret2 != -ENOENT) { ++ ret = ret2; + goto out; ++ } + + /* At least one deletion succeeded, return 0 */ + if (!ret || !ret2) +-- +2.51.0 + diff --git a/queue-6.19/btrfs-zoned-don-t-zone-append-to-conventional-zone.patch b/queue-6.19/btrfs-zoned-don-t-zone-append-to-conventional-zone.patch new file mode 100644 index 0000000000..de7161a113 --- /dev/null +++ b/queue-6.19/btrfs-zoned-don-t-zone-append-to-conventional-zone.patch @@ -0,0 +1,117 @@ +From 465ad41c8d3d6a229ef6af445daf0a180ab62e7d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Dec 2025 13:42:23 +0100 +Subject: btrfs: zoned: don't zone append to conventional zone + +From: Johannes Thumshirn + +[ Upstream commit b39b26e017c7889181cb84032e22bef72e81cf29 ] + +In case of a zoned RAID, it can happen that a data write is targeting a +sequential write required zone and a conventional zone. In this case the +bio will be marked as REQ_OP_ZONE_APPEND but for the conventional zone, +this needs to be REQ_OP_WRITE. + +The setting of REQ_OP_ZONE_APPEND is deferred to the last possible time in +btrfs_submit_dev_bio(), but the decision if we can use zone append is +cached in btrfs_bio. + +CC: Naohiro Aota +Fixes: e9b9b911e03c ("btrfs: add raid stripe tree to features enabled with debug config") +Reviewed-by: Christoph Hellwig +Reviewed-by: Naohiro Aota +Signed-off-by: Johannes Thumshirn +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/bio.c | 19 +++++++++---------- + fs/btrfs/bio.h | 3 +++ + 2 files changed, 12 insertions(+), 10 deletions(-) + +diff --git a/fs/btrfs/bio.c b/fs/btrfs/bio.c +index fa1d321a2fb83..e4d382d3a7aea 100644 +--- a/fs/btrfs/bio.c ++++ b/fs/btrfs/bio.c +@@ -480,6 +480,8 @@ static void btrfs_clone_write_end_io(struct bio *bio) + + static void btrfs_submit_dev_bio(struct btrfs_device *dev, struct bio *bio) + { ++ u64 physical = bio->bi_iter.bi_sector << SECTOR_SHIFT; ++ + if (!dev || !dev->bdev || + test_bit(BTRFS_DEV_STATE_MISSING, &dev->dev_state) || + (btrfs_op(bio) == BTRFS_MAP_WRITE && +@@ -494,12 +496,13 @@ static void btrfs_submit_dev_bio(struct btrfs_device *dev, struct bio *bio) + * For zone append writing, bi_sector must point the beginning of the + * zone + */ +- if (bio_op(bio) == REQ_OP_ZONE_APPEND) { +- u64 physical = bio->bi_iter.bi_sector << SECTOR_SHIFT; ++ if (btrfs_bio(bio)->can_use_append && btrfs_dev_is_sequential(dev, physical)) { + u64 zone_start = round_down(physical, dev->fs_info->zone_size); + + ASSERT(btrfs_dev_is_sequential(dev, physical)); + bio->bi_iter.bi_sector = zone_start >> SECTOR_SHIFT; ++ bio->bi_opf &= ~REQ_OP_WRITE; ++ bio->bi_opf |= REQ_OP_ZONE_APPEND; + } + btrfs_debug(dev->fs_info, + "%s: rw %d 0x%x, sector=%llu, dev=%lu (%s id %llu), size=%u", +@@ -747,7 +750,6 @@ static bool btrfs_submit_chunk(struct btrfs_bio *bbio, int mirror_num) + u64 logical = bio->bi_iter.bi_sector << SECTOR_SHIFT; + u64 length = bio->bi_iter.bi_size; + u64 map_length = length; +- bool use_append = btrfs_use_zone_append(bbio); + struct btrfs_io_context *bioc = NULL; + struct btrfs_io_stripe smap; + blk_status_t status; +@@ -775,8 +777,10 @@ static bool btrfs_submit_chunk(struct btrfs_bio *bbio, int mirror_num) + if (bio_op(bio) == REQ_OP_WRITE && is_data_bbio(bbio)) + bbio->orig_logical = logical; + ++ bbio->can_use_append = btrfs_use_zone_append(bbio); ++ + map_length = min(map_length, length); +- if (use_append) ++ if (bbio->can_use_append) + map_length = btrfs_append_map_length(bbio, map_length); + + if (map_length < length) { +@@ -805,11 +809,6 @@ static bool btrfs_submit_chunk(struct btrfs_bio *bbio, int mirror_num) + } + + if (btrfs_op(bio) == BTRFS_MAP_WRITE) { +- if (use_append) { +- bio->bi_opf &= ~REQ_OP_WRITE; +- bio->bi_opf |= REQ_OP_ZONE_APPEND; +- } +- + if (is_data_bbio(bbio) && bioc && bioc->use_rst) { + /* + * No locking for the list update, as we only add to +@@ -836,7 +835,7 @@ static bool btrfs_submit_chunk(struct btrfs_bio *bbio, int mirror_num) + status = errno_to_blk_status(ret); + if (status) + goto fail; +- } else if (use_append || ++ } else if (bbio->can_use_append || + (btrfs_is_zoned(fs_info) && inode && + inode->flags & BTRFS_INODE_NODATASUM)) { + ret = btrfs_alloc_dummy_sum(bbio); +diff --git a/fs/btrfs/bio.h b/fs/btrfs/bio.h +index 1be74209f0b8d..246c7519dff39 100644 +--- a/fs/btrfs/bio.h ++++ b/fs/btrfs/bio.h +@@ -92,6 +92,9 @@ struct btrfs_bio { + /* Whether the csum generation for data write is async. */ + bool async_csum; + ++ /* Whether the bio is written using zone append. */ ++ bool can_use_append; ++ + /* + * This member must come last, bio_alloc_bioset will allocate enough + * bytes for entire btrfs_bio but relies on bio being last. +-- +2.51.0 + diff --git a/queue-6.19/char-misc-use-is_err-for-filp_open-return-value.patch b/queue-6.19/char-misc-use-is_err-for-filp_open-return-value.patch new file mode 100644 index 0000000000..b8f0531fd3 --- /dev/null +++ b/queue-6.19/char-misc-use-is_err-for-filp_open-return-value.patch @@ -0,0 +1,43 @@ +From 121bdac3d9369553768763b06a7f5d876045f8b0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 27 Dec 2025 02:02:48 +0300 +Subject: char: misc: Use IS_ERR() for filp_open() return value + +From: Alper Ak + +[ Upstream commit e849ada70c6b1ee22e9f4f5c0e38231dcee53f04 ] + +filp_open() never returns NULL, it returns either a valid pointer or an +error pointer. Using IS_ERR_OR_NULL() is unnecessary. Additionally, if +filp were NULL, PTR_ERR(NULL) would return 0, leading to a misleading +error message. + +Fixes: 74d8361be344 ("char: misc: add test cases") +Reported-by: kernel test robot +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/r/202506132058.thWZHlrb-lkp@intel.com/ +Signed-off-by: Alper Ak +Acked-by: Thadeu Lima de Souza Cascardo +Link: https://patch.msgid.link/20251226230248.113073-1-alperyasinak1@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/char/misc_minor_kunit.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/char/misc_minor_kunit.c b/drivers/char/misc_minor_kunit.c +index 6fc8b05169c57..e930c78e1ef97 100644 +--- a/drivers/char/misc_minor_kunit.c ++++ b/drivers/char/misc_minor_kunit.c +@@ -166,7 +166,7 @@ static void __init miscdev_test_can_open(struct kunit *test, struct miscdevice * + KUNIT_FAIL(test, "failed to create node\n"); + + filp = filp_open(devname, O_RDONLY, 0); +- if (IS_ERR_OR_NULL(filp)) ++ if (IS_ERR(filp)) + KUNIT_FAIL(test, "failed to open misc device: %ld\n", PTR_ERR(filp)); + else + fput(filp); +-- +2.51.0 + diff --git a/queue-6.19/clk-actions-owl-composite-convert-from-owl_divider_h.patch b/queue-6.19/clk-actions-owl-composite-convert-from-owl_divider_h.patch new file mode 100644 index 0000000000..dd615722fa --- /dev/null +++ b/queue-6.19/clk-actions-owl-composite-convert-from-owl_divider_h.patch @@ -0,0 +1,49 @@ +From 27cf0cffe45e0bcc3a5ac86e1164c6f8b0036988 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:16:22 -0500 +Subject: clk: actions: owl-composite: convert from + owl_divider_helper_round_rate() to divider_determine_rate() + +From: Brian Masney + +[ Upstream commit d0b7c5bf6c5520c35fecff34da83d390405d3eaf ] + +owl_divider_helper_round_rate() is just a wrapper for +divider_round_rate(), which is deprecated. Let's migrate to +divider_determine_rate() instead so that this deprecated API can be +removed. + +Acked-by: Manivannan Sadhasivam +Signed-off-by: Brian Masney +Stable-dep-of: 3ff3360440fa ("clk: actions: owl-divider: convert from divider_round_rate() to divider_determine_rate()") +Signed-off-by: Sasha Levin +--- + drivers/clk/actions/owl-composite.c | 11 +++-------- + 1 file changed, 3 insertions(+), 8 deletions(-) + +diff --git a/drivers/clk/actions/owl-composite.c b/drivers/clk/actions/owl-composite.c +index 00b74f8bc4375..9540444307d6c 100644 +--- a/drivers/clk/actions/owl-composite.c ++++ b/drivers/clk/actions/owl-composite.c +@@ -57,15 +57,10 @@ static int owl_comp_div_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) + { + struct owl_composite *comp = hw_to_owl_comp(hw); +- long rate; +- +- rate = owl_divider_helper_round_rate(&comp->common, &comp->rate.div_hw, +- req->rate, &req->best_parent_rate); +- if (rate < 0) +- return rate; ++ struct owl_divider_hw *div = &comp->rate.div_hw; + +- req->rate = rate; +- return 0; ++ return divider_determine_rate(&comp->common.hw, req, div->table, ++ div->width, div->div_flags); + } + + static unsigned long owl_comp_div_recalc_rate(struct clk_hw *hw, +-- +2.51.0 + diff --git a/queue-6.19/clk-actions-owl-divider-convert-from-divider_round_r.patch b/queue-6.19/clk-actions-owl-divider-convert-from-divider_round_r.patch new file mode 100644 index 0000000000..87d5ed242a --- /dev/null +++ b/queue-6.19/clk-actions-owl-divider-convert-from-divider_round_r.patch @@ -0,0 +1,84 @@ +From f9bfa9cdd42744fe3174aaf0bc467daacb9de412 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:16:23 -0500 +Subject: clk: actions: owl-divider: convert from divider_round_rate() to + divider_determine_rate() + +From: Brian Masney + +[ Upstream commit 3ff3360440fa8cc7ef5a4da628d3b770b46a4f73 ] + +The divider_round_rate() function is now deprecated, so let's migrate +to divider_determine_rate() instead so that this deprecated API can be +removed. Additionally, owl_divider_helper_round_rate() is no longer used, +so let's drop that from the header file as well. + +Note that when the main function itself was migrated to use +determine_rate, this was mistakenly converted to: + + req->rate = divider_round_rate(...) + +This is invalid in the case when an error occurs since it can set the +rate to a negative value. + +Fixes: 1b04e12a8bcc ("clk: actions: owl-divider: convert from round_rate() to determine_rate()") +Acked-by: Manivannan Sadhasivam +Signed-off-by: Brian Masney +Signed-off-by: Sasha Levin +--- + drivers/clk/actions/owl-divider.c | 17 ++--------------- + drivers/clk/actions/owl-divider.h | 5 ----- + 2 files changed, 2 insertions(+), 20 deletions(-) + +diff --git a/drivers/clk/actions/owl-divider.c b/drivers/clk/actions/owl-divider.c +index 118f1393c6780..316ace80e87e3 100644 +--- a/drivers/clk/actions/owl-divider.c ++++ b/drivers/clk/actions/owl-divider.c +@@ -13,26 +13,13 @@ + + #include "owl-divider.h" + +-long owl_divider_helper_round_rate(struct owl_clk_common *common, +- const struct owl_divider_hw *div_hw, +- unsigned long rate, +- unsigned long *parent_rate) +-{ +- return divider_round_rate(&common->hw, rate, parent_rate, +- div_hw->table, div_hw->width, +- div_hw->div_flags); +-} +- + static int owl_divider_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) + { + struct owl_divider *div = hw_to_owl_divider(hw); + +- req->rate = owl_divider_helper_round_rate(&div->common, &div->div_hw, +- req->rate, +- &req->best_parent_rate); +- +- return 0; ++ return divider_determine_rate(hw, req, div->div_hw.table, ++ div->div_hw.width, div->div_hw.div_flags); + } + + unsigned long owl_divider_helper_recalc_rate(struct owl_clk_common *common, +diff --git a/drivers/clk/actions/owl-divider.h b/drivers/clk/actions/owl-divider.h +index d76f58782c528..1d3bb4e5898a3 100644 +--- a/drivers/clk/actions/owl-divider.h ++++ b/drivers/clk/actions/owl-divider.h +@@ -56,11 +56,6 @@ static inline struct owl_divider *hw_to_owl_divider(struct clk_hw *hw) + return container_of(common, struct owl_divider, common); + } + +-long owl_divider_helper_round_rate(struct owl_clk_common *common, +- const struct owl_divider_hw *div_hw, +- unsigned long rate, +- unsigned long *parent_rate); +- + unsigned long owl_divider_helper_recalc_rate(struct owl_clk_common *common, + const struct owl_divider_hw *div_hw, + unsigned long parent_rate); +-- +2.51.0 + diff --git a/queue-6.19/clk-bm1880-convert-from-divider_round_rate-to-divide.patch b/queue-6.19/clk-bm1880-convert-from-divider_round_rate-to-divide.patch new file mode 100644 index 0000000000..cd71f8b9b1 --- /dev/null +++ b/queue-6.19/clk-bm1880-convert-from-divider_round_rate-to-divide.patch @@ -0,0 +1,49 @@ +From f4df6eface7d32925fbae9b80a613efa38d14fe0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:16:25 -0500 +Subject: clk: bm1880: convert from divider_round_rate() to + divider_determine_rate() + +From: Brian Masney + +[ Upstream commit 463b97bef0c9fb02b743d6b9f0d698cae81a1d9f ] + +The divider_round_rate() function is now deprecated, so let's migrate +to divider_determine_rate() instead so that this deprecated API can be +removed. + +Note that when the main function itself was migrated to use +determine_rate, this was mistakenly converted to: + + req->rate = divider_round_rate(...) + +This is invalid in the case when an error occurs since it can set the +rate to a negative value. + +Fixes: 64613d7fb42f ("clk: bm1880: convert from round_rate() to determine_rate()") +Acked-by: Manivannan Sadhasivam +Signed-off-by: Brian Masney +Signed-off-by: Sasha Levin +--- + drivers/clk/clk-bm1880.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/drivers/clk/clk-bm1880.c b/drivers/clk/clk-bm1880.c +index dac190bc6e19a..d2617fe16d2e4 100644 +--- a/drivers/clk/clk-bm1880.c ++++ b/drivers/clk/clk-bm1880.c +@@ -629,10 +629,7 @@ static int bm1880_clk_div_determine_rate(struct clk_hw *hw, + return 0; + } + +- req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, +- div->table, div->width, div->flags); +- +- return 0; ++ return divider_determine_rate(hw, req, div->table, div->width, div->flags); + } + + static int bm1880_clk_div_set_rate(struct clk_hw *hw, unsigned long rate, +-- +2.51.0 + diff --git a/queue-6.19/clk-hisilicon-clkdivider-hi6220-convert-from-divider.patch b/queue-6.19/clk-hisilicon-clkdivider-hi6220-convert-from-divider.patch new file mode 100644 index 0000000000..a1822f9f8e --- /dev/null +++ b/queue-6.19/clk-hisilicon-clkdivider-hi6220-convert-from-divider.patch @@ -0,0 +1,49 @@ +From c274ff2d29d3d10a9942c6ea05db5a1fc007d608 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:16:26 -0500 +Subject: clk: hisilicon: clkdivider-hi6220: convert from divider_round_rate() + to divider_determine_rate() + +From: Brian Masney + +[ Upstream commit e3a5249c140a1ded55937ba04247d530a85f0edc ] + +The divider_round_rate() function is now deprecated, so let's migrate +to divider_determine_rate() instead so that this deprecated API can be +removed. + +Note that when the main function itself was migrated to use +determine_rate, this was mistakenly converted to: + + req->rate = divider_round_rate(...) + +This is invalid in the case when an error occurs since it can set the +rate to a negative value. + +Fixes: 619a6210f398 ("clk: hisilicon: clkdivider-hi6220: convert from round_rate() to determine_rate()") +Signed-off-by: Brian Masney +Signed-off-by: Sasha Levin +--- + drivers/clk/hisilicon/clkdivider-hi6220.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/clk/hisilicon/clkdivider-hi6220.c b/drivers/clk/hisilicon/clkdivider-hi6220.c +index 6bae18a84cb6c..fd7ceb92d6515 100644 +--- a/drivers/clk/hisilicon/clkdivider-hi6220.c ++++ b/drivers/clk/hisilicon/clkdivider-hi6220.c +@@ -60,10 +60,8 @@ static int hi6220_clkdiv_determine_rate(struct clk_hw *hw, + { + struct hi6220_clk_divider *dclk = to_hi6220_clk_divider(hw); + +- req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, dclk->table, +- dclk->width, CLK_DIVIDER_ROUND_CLOSEST); +- +- return 0; ++ return divider_determine_rate(hw, req, dclk->table, dclk->width, ++ CLK_DIVIDER_ROUND_CLOSEST); + } + + static int hi6220_clkdiv_set_rate(struct clk_hw *hw, unsigned long rate, +-- +2.51.0 + diff --git a/queue-6.19/clk-loongson1-convert-from-divider_round_rate-to-div.patch b/queue-6.19/clk-loongson1-convert-from-divider_round_rate-to-div.patch new file mode 100644 index 0000000000..09692f1084 --- /dev/null +++ b/queue-6.19/clk-loongson1-convert-from-divider_round_rate-to-div.patch @@ -0,0 +1,50 @@ +From 8818c5f44d346714d656214d03083c522c30db9a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:16:27 -0500 +Subject: clk: loongson1: convert from divider_round_rate() to + divider_determine_rate() + +From: Brian Masney + +[ Upstream commit 11d3c676e7e0f00e3398199f85e47a0e22369866 ] + +The divider_round_rate() function is now deprecated, so let's migrate +to divider_determine_rate() instead so that this deprecated API can be +removed. + +Note that when the main function itself was migrated to use +determine_rate, this was mistakenly converted to: + + req->rate = divider_round_rate(...) + +This is invalid in the case when an error occurs since it can set the +rate to a negative value. + +Fixes: bb40a2ef4fc9 ("clk: loongson1: convert from round_rate() to determine_rate()") +Reviewed-by: Keguang Zhang +Tested-by: Keguang Zhang # on LS1B & LS1C +Signed-off-by: Brian Masney +Signed-off-by: Sasha Levin +--- + drivers/clk/clk-loongson1.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/drivers/clk/clk-loongson1.c b/drivers/clk/clk-loongson1.c +index f9f060d08a5fa..1674181a1107d 100644 +--- a/drivers/clk/clk-loongson1.c ++++ b/drivers/clk/clk-loongson1.c +@@ -99,10 +99,7 @@ static int ls1x_divider_determine_rate(struct clk_hw *hw, + struct ls1x_clk *ls1x_clk = to_ls1x_clk(hw); + const struct ls1x_clk_div_data *d = ls1x_clk->data; + +- req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, +- d->table, d->width, d->flags); +- +- return 0; ++ return divider_determine_rate(hw, req, d->table, d->width, d->flags); + } + + static int ls1x_divider_set_rate(struct clk_hw *hw, unsigned long rate, +-- +2.51.0 + diff --git a/queue-6.19/clk-mediatek-add-mfg_eb-as-parent-to-mt8196-mfgpll-c.patch b/queue-6.19/clk-mediatek-add-mfg_eb-as-parent-to-mt8196-mfgpll-c.patch new file mode 100644 index 0000000000..9312de360b --- /dev/null +++ b/queue-6.19/clk-mediatek-add-mfg_eb-as-parent-to-mt8196-mfgpll-c.patch @@ -0,0 +1,101 @@ +From 296ba4ca149667b31d218110448ee38440bba08b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 15 Dec 2025 11:24:02 +0100 +Subject: clk: mediatek: Add mfg_eb as parent to mt8196 mfgpll clocks + +From: Nicolas Frattaroli + +[ Upstream commit 19024c9980c331908de0680283d572b80308654e ] + +All the MFGPLL require MFG_EB to be on for any operation on them, and +they only tick when MFG_EB is on as well, therefore making this a +parent-child relationship. + +This dependency wasn't clear during the initial upstreaming of these +clock controllers, as it only made itself known when I could observe +the effects of the clock by bringing up a different piece of hardware. + +Add a new PLL_PARENT_EN flag to mediatek's clk-pll.h, and check for it +when initialising the pll to then translate it into the actual +CLK_OPS_PARENT_ENABLE flag. + +Then add the mfg_eb parent to the mfgpll clocks, and set the new +PLL_PARENT_EN flag. + +Fixes: 03dc02f8c7dc ("clk: mediatek: Add MT8196 mfg clock support") +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Nicolas Frattaroli +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + drivers/clk/mediatek/clk-mt8196-mfg.c | 13 +++++++------ + drivers/clk/mediatek/clk-pll.c | 3 +++ + drivers/clk/mediatek/clk-pll.h | 1 + + 3 files changed, 11 insertions(+), 6 deletions(-) + +diff --git a/drivers/clk/mediatek/clk-mt8196-mfg.c b/drivers/clk/mediatek/clk-mt8196-mfg.c +index ae1eb9de79ae2..f40795b47ff1f 100644 +--- a/drivers/clk/mediatek/clk-mt8196-mfg.c ++++ b/drivers/clk/mediatek/clk-mt8196-mfg.c +@@ -58,24 +58,25 @@ + .pcw_shift = _pcw_shift, \ + .pcwbits = _pcwbits, \ + .pcwibits = MT8196_INTEGER_BITS, \ ++ .parent_name = "mfg_eb", \ + } + + static const struct mtk_pll_data mfg_ao_plls[] = { +- PLL(CLK_MFG_AO_MFGPLL, "mfgpll", MFGPLL_CON0, MFGPLL_CON0, 0, 0, 0, +- BIT(0), MFGPLL_CON1, 24, 0, 0, 0, ++ PLL(CLK_MFG_AO_MFGPLL, "mfgpll", MFGPLL_CON0, MFGPLL_CON0, 0, 0, ++ PLL_PARENT_EN, BIT(0), MFGPLL_CON1, 24, 0, 0, 0, + MFGPLL_CON1, 0, 22), + }; + + static const struct mtk_pll_data mfgsc0_ao_plls[] = { + PLL(CLK_MFGSC0_AO_MFGPLL_SC0, "mfgpll-sc0", MFGPLL_SC0_CON0, +- MFGPLL_SC0_CON0, 0, 0, 0, BIT(0), MFGPLL_SC0_CON1, 24, 0, 0, 0, +- MFGPLL_SC0_CON1, 0, 22), ++ MFGPLL_SC0_CON0, 0, 0, PLL_PARENT_EN, BIT(0), MFGPLL_SC0_CON1, 24, ++ 0, 0, 0, MFGPLL_SC0_CON1, 0, 22), + }; + + static const struct mtk_pll_data mfgsc1_ao_plls[] = { + PLL(CLK_MFGSC1_AO_MFGPLL_SC1, "mfgpll-sc1", MFGPLL_SC1_CON0, +- MFGPLL_SC1_CON0, 0, 0, 0, BIT(0), MFGPLL_SC1_CON1, 24, 0, 0, 0, +- MFGPLL_SC1_CON1, 0, 22), ++ MFGPLL_SC1_CON0, 0, 0, PLL_PARENT_EN, BIT(0), MFGPLL_SC1_CON1, 24, ++ 0, 0, 0, MFGPLL_SC1_CON1, 0, 22), + }; + + static const struct of_device_id of_match_clk_mt8196_mfg[] = { +diff --git a/drivers/clk/mediatek/clk-pll.c b/drivers/clk/mediatek/clk-pll.c +index cd2b6ce551c6b..de3eb02670554 100644 +--- a/drivers/clk/mediatek/clk-pll.c ++++ b/drivers/clk/mediatek/clk-pll.c +@@ -358,6 +358,9 @@ struct clk_hw *mtk_clk_register_pll_ops(struct mtk_clk_pll *pll, + + init.name = data->name; + init.flags = (data->flags & PLL_AO) ? CLK_IS_CRITICAL : 0; ++ if (data->flags & PLL_PARENT_EN) ++ init.flags |= CLK_OPS_PARENT_ENABLE; ++ + init.ops = pll_ops; + if (data->parent_name) + init.parent_names = &data->parent_name; +diff --git a/drivers/clk/mediatek/clk-pll.h b/drivers/clk/mediatek/clk-pll.h +index d71c150ce83e4..de5a8fb7cbcfe 100644 +--- a/drivers/clk/mediatek/clk-pll.h ++++ b/drivers/clk/mediatek/clk-pll.h +@@ -21,6 +21,7 @@ struct mtk_pll_div_table { + + #define HAVE_RST_BAR BIT(0) + #define PLL_AO BIT(1) ++#define PLL_PARENT_EN BIT(2) + #define POSTDIV_MASK GENMASK(2, 0) + + struct mtk_pll_data { +-- +2.51.0 + diff --git a/queue-6.19/clk-mediatek-drop-__initconst-from-gates.patch b/queue-6.19/clk-mediatek-drop-__initconst-from-gates.patch new file mode 100644 index 0000000000..b45c0f6a62 --- /dev/null +++ b/queue-6.19/clk-mediatek-drop-__initconst-from-gates.patch @@ -0,0 +1,72 @@ +From 87da0dc8fbcb3d71c806de9d2d0382d4e9ac1831 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 23 Dec 2025 12:05:17 +0100 +Subject: clk: mediatek: Drop __initconst from gates + +From: Sjoerd Simons + +[ Upstream commit 871afb43e41ad4e8246438de495a939cd0f8113c ] + +Since commit 8ceff24a754a ("clk: mediatek: clk-gate: Refactor +mtk_clk_register_gate to use mtk_gate struct") the mtk_gate structs +are no longer just used for initialization/registration, but also at +runtime. So drop __initconst annotations. + +Fixes: 8ceff24a754a ("clk: mediatek: clk-gate: Refactor mtk_clk_register_gate to use mtk_gate struct") +Signed-off-by: Sjoerd Simons +Reviewed-by: AngeloGioacchino Del Regno +Reviewed-by: Laura Nao +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + drivers/clk/mediatek/clk-mt7981-eth.c | 6 +++--- + drivers/clk/mediatek/clk-mt8516.c | 2 +- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/clk/mediatek/clk-mt7981-eth.c b/drivers/clk/mediatek/clk-mt7981-eth.c +index 906aec9ddff54..0655ebb6c561f 100644 +--- a/drivers/clk/mediatek/clk-mt7981-eth.c ++++ b/drivers/clk/mediatek/clk-mt7981-eth.c +@@ -31,7 +31,7 @@ static const struct mtk_gate_regs sgmii0_cg_regs = { + .ops = &mtk_clk_gate_ops_no_setclr_inv, \ + } + +-static const struct mtk_gate sgmii0_clks[] __initconst = { ++static const struct mtk_gate sgmii0_clks[] = { + GATE_SGMII0(CLK_SGM0_TX_EN, "sgm0_tx_en", "usb_tx250m", 2), + GATE_SGMII0(CLK_SGM0_RX_EN, "sgm0_rx_en", "usb_eq_rx250m", 3), + GATE_SGMII0(CLK_SGM0_CK0_EN, "sgm0_ck0_en", "usb_ln0", 4), +@@ -53,7 +53,7 @@ static const struct mtk_gate_regs sgmii1_cg_regs = { + .ops = &mtk_clk_gate_ops_no_setclr_inv, \ + } + +-static const struct mtk_gate sgmii1_clks[] __initconst = { ++static const struct mtk_gate sgmii1_clks[] = { + GATE_SGMII1(CLK_SGM1_TX_EN, "sgm1_tx_en", "usb_tx250m", 2), + GATE_SGMII1(CLK_SGM1_RX_EN, "sgm1_rx_en", "usb_eq_rx250m", 3), + GATE_SGMII1(CLK_SGM1_CK1_EN, "sgm1_ck1_en", "usb_ln0", 4), +@@ -75,7 +75,7 @@ static const struct mtk_gate_regs eth_cg_regs = { + .ops = &mtk_clk_gate_ops_no_setclr_inv, \ + } + +-static const struct mtk_gate eth_clks[] __initconst = { ++static const struct mtk_gate eth_clks[] = { + GATE_ETH(CLK_ETH_FE_EN, "eth_fe_en", "netsys_2x", 6), + GATE_ETH(CLK_ETH_GP2_EN, "eth_gp2_en", "sgm_325m", 7), + GATE_ETH(CLK_ETH_GP1_EN, "eth_gp1_en", "sgm_325m", 8), +diff --git a/drivers/clk/mediatek/clk-mt8516.c b/drivers/clk/mediatek/clk-mt8516.c +index 21eb052b0a539..342a59019fea9 100644 +--- a/drivers/clk/mediatek/clk-mt8516.c ++++ b/drivers/clk/mediatek/clk-mt8516.c +@@ -544,7 +544,7 @@ static const struct mtk_gate_regs top5_cg_regs = { + #define GATE_TOP5(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &top5_cg_regs, _shift, &mtk_clk_gate_ops_setclr) + +-static const struct mtk_gate top_clks[] __initconst = { ++static const struct mtk_gate top_clks[] = { + /* TOP1 */ + GATE_TOP1(CLK_TOP_THEM, "them", "ahb_infra_sel", 1), + GATE_TOP1(CLK_TOP_APDMA, "apdma", "ahb_infra_sel", 2), +-- +2.51.0 + diff --git a/queue-6.19/clk-mediatek-fix-error-handling-in-runtime-pm-setup.patch b/queue-6.19/clk-mediatek-fix-error-handling-in-runtime-pm-setup.patch new file mode 100644 index 0000000000..fcf60bd21e --- /dev/null +++ b/queue-6.19/clk-mediatek-fix-error-handling-in-runtime-pm-setup.patch @@ -0,0 +1,66 @@ +From be84b38292d07cfeb6502f6ae0d34eeee4ef37f4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 23 Nov 2025 23:43:15 +0800 +Subject: clk: mediatek: Fix error handling in runtime PM setup + +From: Haotian Zhang + +[ Upstream commit aa2ad19210a6a444111bce55e8b69579f29318fb ] + +devm_pm_runtime_enable() can fail due to memory allocation. The current +code ignores its return value, and when pm_runtime_resume_and_get() fails, +it returns directly without unmapping the shared_io region. + +Add error handling for devm_pm_runtime_enable(). Reorder cleanup labels +to properly unmap shared_io on pm_runtime_resume_and_get() failure. + +Fixes: 2f7b1d8b5505 ("clk: mediatek: Do a runtime PM get on controllers during probe") +Signed-off-by: Haotian Zhang +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + drivers/clk/mediatek/clk-mtk.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c +index 19cd27941747a..deafe55a96cb1 100644 +--- a/drivers/clk/mediatek/clk-mtk.c ++++ b/drivers/clk/mediatek/clk-mtk.c +@@ -497,14 +497,16 @@ static int __mtk_clk_simple_probe(struct platform_device *pdev, + + + if (mcd->need_runtime_pm) { +- devm_pm_runtime_enable(&pdev->dev); ++ r = devm_pm_runtime_enable(&pdev->dev); ++ if (r) ++ goto unmap_io; + /* + * Do a pm_runtime_resume_and_get() to workaround a possible + * deadlock between clk_register() and the genpd framework. + */ + r = pm_runtime_resume_and_get(&pdev->dev); + if (r) +- return r; ++ goto unmap_io; + } + + /* Calculate how many clk_hw_onecell_data entries to allocate */ +@@ -618,11 +620,11 @@ static int __mtk_clk_simple_probe(struct platform_device *pdev, + free_data: + mtk_free_clk_data(clk_data); + free_base: +- if (mcd->shared_io && base) +- iounmap(base); +- + if (mcd->need_runtime_pm) + pm_runtime_put(&pdev->dev); ++unmap_io: ++ if (mcd->shared_io && base) ++ iounmap(base); + return r; + } + +-- +2.51.0 + diff --git a/queue-6.19/clk-meson-g12a-limit-the-hdmi-pll-od-to-4.patch b/queue-6.19/clk-meson-g12a-limit-the-hdmi-pll-od-to-4.patch new file mode 100644 index 0000000000..c40fa783ef --- /dev/null +++ b/queue-6.19/clk-meson-g12a-limit-the-hdmi-pll-od-to-4.patch @@ -0,0 +1,86 @@ +From daece0bc35e0dd68151a5a35f4b53cf24d5bb45f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Jan 2026 21:47:09 +0100 +Subject: clk: meson: g12a: Limit the HDMI PLL OD to /4 + +From: Martin Blumenstingl + +[ Upstream commit 7aa6c24697ef5db1402dd38743914493cd5b356d ] + +GXBB has the HDMI PLL OD in the HHI_HDMI_PLL_CNTL2 register while for +G12A/G12B/SM1 the OD has moved to HHI_HDMI_PLL_CNTL0. At first glance +the rest of the OD setup seems identical. + +However, looking at the downstream kernel sources as well as testing +shows that G12A/G12B/SM1 only supports three OD values: +- register value 0 means: divide by 1 +- register value 1 means: divide by 2 +- register value 2 means: divide by 4 + +Downstream sources are also only using OD register values 0, 1 and 2 +for G12A/G12B/SM1 (while for GXBB the downstream kernel sources are also +using value 3 which means: divide by 8). + +Add clk_div_table and have it replace the CLK_DIVIDER_POWER_OF_TWO flag +to make the kernel's view of this register match with how the hardware +actually works. + +Fixes: 085a4ea93d54 ("clk: meson: g12a: add peripheral clock controller") +Signed-off-by: Martin Blumenstingl +Link: https://lore.kernel.org/r/20260105204710.447779-3-martin.blumenstingl@googlemail.com +Signed-off-by: Jerome Brunet +Signed-off-by: Sasha Levin +--- + drivers/clk/meson/g12a.c | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c +index 185b6348251db..d0d4c7b6dc827 100644 +--- a/drivers/clk/meson/g12a.c ++++ b/drivers/clk/meson/g12a.c +@@ -777,12 +777,23 @@ static struct clk_regmap g12a_hdmi_pll_dco = { + }, + }; + ++/* ++ * G12/SM1 hdmi OD dividers are POWER_OF_TWO dividers but limited to /4. ++ * A divider value of 3 should map to /8 but instead map /4 so ignore it. ++ */ ++static const struct clk_div_table g12a_hdmi_pll_od_div_table[] = { ++ { .val = 0, .div = 1 }, ++ { .val = 1, .div = 2 }, ++ { .val = 2, .div = 4 }, ++ { /* sentinel */ } ++}; ++ + static struct clk_regmap g12a_hdmi_pll_od = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL0, + .shift = 16, + .width = 2, +- .flags = CLK_DIVIDER_POWER_OF_TWO, ++ .table = g12a_hdmi_pll_od_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od", +@@ -800,7 +811,7 @@ static struct clk_regmap g12a_hdmi_pll_od2 = { + .offset = HHI_HDMI_PLL_CNTL0, + .shift = 18, + .width = 2, +- .flags = CLK_DIVIDER_POWER_OF_TWO, ++ .table = g12a_hdmi_pll_od_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od2", +@@ -818,7 +829,7 @@ static struct clk_regmap g12a_hdmi_pll = { + .offset = HHI_HDMI_PLL_CNTL0, + .shift = 20, + .width = 2, +- .flags = CLK_DIVIDER_POWER_OF_TWO, ++ .table = g12a_hdmi_pll_od_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll", +-- +2.51.0 + diff --git a/queue-6.19/clk-meson-gxbb-limit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch b/queue-6.19/clk-meson-gxbb-limit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch new file mode 100644 index 0000000000..fe5d8d5664 --- /dev/null +++ b/queue-6.19/clk-meson-gxbb-limit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch @@ -0,0 +1,87 @@ +From c83a19957a21b713b2bc0d01bf6940ceeb099cb7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Jan 2026 21:47:08 +0100 +Subject: clk: meson: gxbb: Limit the HDMI PLL OD to /4 on GXL/GXM SoCs + +From: Martin Blumenstingl + +[ Upstream commit 5b1a43950fd3162af0ce52b13c14a2d29b179d4f ] + +GXBB has the HDMI PLL OD in the HHI_HDMI_PLL_CNTL2 register while for +GXL/GXM the OD has moved to HHI_HDMI_PLL_CNTL3. At first glance the rest +of the OD setup seems identical. + +However, looking at the downstream kernel sources as well as testing +shows that GXL only supports three OD values: +- register value 0 means: divide by 1 +- register value 1 means: divide by 2 +- register value 2 means: divide by 4 + +Using register value 3 (which on GXBB means: divide by 8) still divides +by 4 as verified using meson-clk-measure. Downstream sources are also +only using OD register values 0, 1 and 2 for GXL (while for GXBB the +downstream kernel sources are also using value 3). + +Add clk_div_table and have it replace the CLK_DIVIDER_POWER_OF_TWO flag +to make the kernel's view of this register match with how the hardware +actually works. + +Fixes: 69d92293274b ("clk: meson: add the gxl hdmi pll") +Signed-off-by: Martin Blumenstingl +Link: https://lore.kernel.org/r/20260105204710.447779-2-martin.blumenstingl@googlemail.com +Signed-off-by: Jerome Brunet +Signed-off-by: Sasha Levin +--- + drivers/clk/meson/gxbb.c | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c +index 5a229c4ffae10..ec9a3414875ac 100644 +--- a/drivers/clk/meson/gxbb.c ++++ b/drivers/clk/meson/gxbb.c +@@ -349,12 +349,23 @@ static struct clk_regmap gxbb_hdmi_pll = { + }, + }; + ++/* ++ * GXL hdmi OD dividers are POWER_OF_TWO dividers but limited to /4. ++ * A divider value of 3 should map to /8 but instead map /4 so ignore it. ++ */ ++static const struct clk_div_table gxl_hdmi_pll_od_div_table[] = { ++ { .val = 0, .div = 1 }, ++ { .val = 1, .div = 2 }, ++ { .val = 2, .div = 4 }, ++ { /* sentinel */ } ++}; ++ + static struct clk_regmap gxl_hdmi_pll_od = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL + 8, + .shift = 21, + .width = 2, +- .flags = CLK_DIVIDER_POWER_OF_TWO, ++ .table = gxl_hdmi_pll_od_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od", +@@ -372,7 +383,7 @@ static struct clk_regmap gxl_hdmi_pll_od2 = { + .offset = HHI_HDMI_PLL_CNTL + 8, + .shift = 23, + .width = 2, +- .flags = CLK_DIVIDER_POWER_OF_TWO, ++ .table = gxl_hdmi_pll_od_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od2", +@@ -390,7 +401,7 @@ static struct clk_regmap gxl_hdmi_pll = { + .offset = HHI_HDMI_PLL_CNTL + 8, + .shift = 19, + .width = 2, +- .flags = CLK_DIVIDER_POWER_OF_TWO, ++ .table = gxl_hdmi_pll_od_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll", +-- +2.51.0 + diff --git a/queue-6.19/clk-microchip-core-remove-duplicate-determine_rate-o.patch b/queue-6.19/clk-microchip-core-remove-duplicate-determine_rate-o.patch new file mode 100644 index 0000000000..bba502921e --- /dev/null +++ b/queue-6.19/clk-microchip-core-remove-duplicate-determine_rate-o.patch @@ -0,0 +1,65 @@ +From 4ce9ca0c34abd08e2dc12dc3b1632c1b089d3491 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Dec 2025 14:46:27 -0500 +Subject: clk: microchip: core: remove duplicate determine_rate on + pic32_sclk_ops + +From: Brian Masney + +[ Upstream commit d93faac66dc04650d924f8f9584216d14f48fb14 ] + +pic32_sclk_ops previously had a sclk_round_rate() member, and this was +recently converted over to sclk_determine_rate() with the help of a +Coccinelle semantic patch. pic32_sclk_ops now has two conflicting +determine_rate ops members. + +Prior to the conversion, pic32_sclk_ops already had a determine_rate +member that points to __clk_mux_determine_rate(). When both the +round_rate() and determine_rate() ops are defined, the clk core only +uses the determine_rate() op. Let's go ahead and drop the recently +converted sclk_determine_rate() to match the previous functionality +prior to the conversion. + +Fixes: e9f039c08cdc ("clk: microchip: core: convert from round_rate() to determine_rate()") +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202511222115.uvHrP95A-lkp@intel.com/ +Signed-off-by: Brian Masney +Reviewed-by: Claudiu Beznea +Link: https://lore.kernel.org/r/20251205-clk-microchip-fixes-v3-1-a02190705e47@redhat.com +Signed-off-by: Claudiu Beznea +Signed-off-by: Sasha Levin +--- + drivers/clk/microchip/clk-core.c | 10 ---------- + 1 file changed, 10 deletions(-) + +diff --git a/drivers/clk/microchip/clk-core.c b/drivers/clk/microchip/clk-core.c +index b34348d491f3e..a0163441dfe5c 100644 +--- a/drivers/clk/microchip/clk-core.c ++++ b/drivers/clk/microchip/clk-core.c +@@ -780,15 +780,6 @@ static unsigned long sclk_get_rate(struct clk_hw *hw, unsigned long parent_rate) + return parent_rate / div; + } + +-static int sclk_determine_rate(struct clk_hw *hw, +- struct clk_rate_request *req) +-{ +- req->rate = calc_best_divided_rate(req->rate, req->best_parent_rate, +- SLEW_SYSDIV, 1); +- +- return 0; +-} +- + static int sclk_set_rate(struct clk_hw *hw, + unsigned long rate, unsigned long parent_rate) + { +@@ -912,7 +903,6 @@ static int sclk_init(struct clk_hw *hw) + const struct clk_ops pic32_sclk_ops = { + .get_parent = sclk_get_parent, + .set_parent = sclk_set_parent, +- .determine_rate = sclk_determine_rate, + .set_rate = sclk_set_rate, + .recalc_rate = sclk_get_rate, + .init = sclk_init, +-- +2.51.0 + diff --git a/queue-6.19/clk-milbeaut-convert-from-divider_round_rate-to-divi.patch b/queue-6.19/clk-milbeaut-convert-from-divider_round_rate-to-divi.patch new file mode 100644 index 0000000000..f9b14318d5 --- /dev/null +++ b/queue-6.19/clk-milbeaut-convert-from-divider_round_rate-to-divi.patch @@ -0,0 +1,48 @@ +From 853d5ee487381b3f0503f3648c49d85afb3ebd3c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:16:29 -0500 +Subject: clk: milbeaut: convert from divider_round_rate() to + divider_determine_rate() + +From: Brian Masney + +[ Upstream commit 865e63b038c446d38593ddbcc362ebb62e6ff007 ] + +The divider_round_rate() function is now deprecated, so let's migrate +to divider_determine_rate() instead so that this deprecated API can be +removed. + +Note that when the main function itself was migrated to use +determine_rate, this was mistakenly converted to: + + req->rate = divider_round_rate(...) + +This is invalid in the case when an error occurs since it can set the +rate to a negative value. + +Fixes: 7b45988fcf78 ("clk: milbeaut: convert from round_rate() to determine_rate()") +Signed-off-by: Brian Masney +Signed-off-by: Sasha Levin +--- + drivers/clk/clk-milbeaut.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/drivers/clk/clk-milbeaut.c b/drivers/clk/clk-milbeaut.c +index b4f9b7143eaa6..bb94d02a76cf1 100644 +--- a/drivers/clk/clk-milbeaut.c ++++ b/drivers/clk/clk-milbeaut.c +@@ -407,10 +407,7 @@ static int m10v_clk_divider_determine_rate(struct clk_hw *hw, + return 0; + } + +- req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, +- divider->table, divider->width, divider->flags); +- +- return 0; ++ return divider_determine_rate(hw, req, divider->table, divider->width, divider->flags); + } + + static int m10v_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, +-- +2.51.0 + diff --git a/queue-6.19/clk-move-clk_-save-restore-_context-to-common_clk-se.patch b/queue-6.19/clk-move-clk_-save-restore-_context-to-common_clk-se.patch new file mode 100644 index 0000000000..f6eee481c7 --- /dev/null +++ b/queue-6.19/clk-move-clk_-save-restore-_context-to-common_clk-se.patch @@ -0,0 +1,117 @@ +From e26594f98f89f1ba6334e309c100c3b8c1b75832 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Dec 2025 10:42:26 +0100 +Subject: clk: Move clk_{save,restore}_context() to COMMON_CLK section + +From: Geert Uytterhoeven + +[ Upstream commit f47c1b77d0a2a9c0d49ec14302e74f933398d1a3 ] + +The clk_save_context() and clk_restore_context() helpers are only +implemented by the Common Clock Framework. They are not available when +using legacy clock frameworks. Dummy implementations are provided, but +only if no clock support is available at all. + +Hence when CONFIG_HAVE_CLK=y, but CONFIG_COMMON_CLK is not enabled: + + m68k-linux-gnu-ld: drivers/net/phy/air_en8811h.o: in function `en8811h_resume': + air_en8811h.c:(.text+0x83e): undefined reference to `clk_restore_context' + m68k-linux-gnu-ld: drivers/net/phy/air_en8811h.o: in function `en8811h_suspend': + air_en8811h.c:(.text+0x856): undefined reference to `clk_save_context' + +Fix this by moving forward declarations and dummy implementions from the +HAVE_CLK to the COMMON_CLK section. + +Fixes: 8b95d1ce3300c411 ("clk: Add functions to save/restore clock context en-masse") +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202511301553.eaEz1nEW-lkp@intel.com/ +Signed-off-by: Geert Uytterhoeven +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + include/linux/clk.h | 48 ++++++++++++++++++++++----------------------- + 1 file changed, 24 insertions(+), 24 deletions(-) + +diff --git a/include/linux/clk.h b/include/linux/clk.h +index b607482ca77e9..64ff118ffb1a1 100644 +--- a/include/linux/clk.h ++++ b/include/linux/clk.h +@@ -228,6 +228,23 @@ int devm_clk_rate_exclusive_get(struct device *dev, struct clk *clk); + */ + void clk_rate_exclusive_put(struct clk *clk); + ++/** ++ * clk_save_context - save clock context for poweroff ++ * ++ * Saves the context of the clock register for powerstates in which the ++ * contents of the registers will be lost. Occurs deep within the suspend ++ * code so locking is not necessary. ++ */ ++int clk_save_context(void); ++ ++/** ++ * clk_restore_context - restore clock context after poweroff ++ * ++ * This occurs with all clocks enabled. Occurs deep within the resume code ++ * so locking is not necessary. ++ */ ++void clk_restore_context(void); ++ + #else + + static inline int clk_notifier_register(struct clk *clk, +@@ -293,6 +310,13 @@ static inline int devm_clk_rate_exclusive_get(struct device *dev, struct clk *cl + + static inline void clk_rate_exclusive_put(struct clk *clk) {} + ++static inline int clk_save_context(void) ++{ ++ return 0; ++} ++ ++static inline void clk_restore_context(void) {} ++ + #endif + + #ifdef CONFIG_HAVE_CLK_PREPARE +@@ -933,23 +957,6 @@ struct clk *clk_get_parent(struct clk *clk); + */ + struct clk *clk_get_sys(const char *dev_id, const char *con_id); + +-/** +- * clk_save_context - save clock context for poweroff +- * +- * Saves the context of the clock register for powerstates in which the +- * contents of the registers will be lost. Occurs deep within the suspend +- * code so locking is not necessary. +- */ +-int clk_save_context(void); +- +-/** +- * clk_restore_context - restore clock context after poweroff +- * +- * This occurs with all clocks enabled. Occurs deep within the resume code +- * so locking is not necessary. +- */ +-void clk_restore_context(void); +- + #else /* !CONFIG_HAVE_CLK */ + + static inline struct clk *clk_get(struct device *dev, const char *id) +@@ -1129,13 +1136,6 @@ static inline struct clk *clk_get_sys(const char *dev_id, const char *con_id) + return NULL; + } + +-static inline int clk_save_context(void) +-{ +- return 0; +-} +- +-static inline void clk_restore_context(void) {} +- + #endif + + /* clk_prepare_enable helps cases using clk_enable in non-atomic context. */ +-- +2.51.0 + diff --git a/queue-6.19/clk-nuvoton-ma35d1-divider-convert-from-divider_roun.patch b/queue-6.19/clk-nuvoton-ma35d1-divider-convert-from-divider_roun.patch new file mode 100644 index 0000000000..26c9b90d46 --- /dev/null +++ b/queue-6.19/clk-nuvoton-ma35d1-divider-convert-from-divider_roun.patch @@ -0,0 +1,50 @@ +From e4502122a17a61552dbab40c7b74a72c3687126d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:16:30 -0500 +Subject: clk: nuvoton: ma35d1-divider: convert from divider_round_rate() to + divider_determine_rate() + +From: Brian Masney + +[ Upstream commit 9329d784ca9aad03b12508128797d40fd1f2e0c1 ] + +The divider_round_rate() function is now deprecated, so let's migrate +to divider_determine_rate() instead so that this deprecated API can be +removed. + +Note that when the main function itself was migrated to use +determine_rate, this was mistakenly converted to: + + req->rate = divider_round_rate(...) + +This is invalid in the case when an error occurs since it can set the +rate to a negative value. + +Fixes: 215f8aa095a1 ("clk: nuvoton: ma35d1-divider: convert from round_rate() to determine_rate()") +Signed-off-by: Brian Masney +Signed-off-by: Sasha Levin +--- + drivers/clk/nuvoton/clk-ma35d1-divider.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/drivers/clk/nuvoton/clk-ma35d1-divider.c b/drivers/clk/nuvoton/clk-ma35d1-divider.c +index e39f53d5bf457..e992e7c303419 100644 +--- a/drivers/clk/nuvoton/clk-ma35d1-divider.c ++++ b/drivers/clk/nuvoton/clk-ma35d1-divider.c +@@ -44,11 +44,8 @@ static int ma35d1_clkdiv_determine_rate(struct clk_hw *hw, + { + struct ma35d1_adc_clk_div *dclk = to_ma35d1_adc_clk_div(hw); + +- req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, +- dclk->table, dclk->width, +- CLK_DIVIDER_ROUND_CLOSEST); +- +- return 0; ++ return divider_determine_rate(hw, req, dclk->table, dclk->width, ++ CLK_DIVIDER_ROUND_CLOSEST); + } + + static int ma35d1_clkdiv_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) +-- +2.51.0 + diff --git a/queue-6.19/clk-nxp-lpc32xx-convert-from-divider_round_rate-to-d.patch b/queue-6.19/clk-nxp-lpc32xx-convert-from-divider_round_rate-to-d.patch new file mode 100644 index 0000000000..7ae43f66a6 --- /dev/null +++ b/queue-6.19/clk-nxp-lpc32xx-convert-from-divider_round_rate-to-d.patch @@ -0,0 +1,51 @@ +From 55bb49ab96ef66b902600411a27e8acda8b5a272 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:16:31 -0500 +Subject: clk: nxp: lpc32xx: convert from divider_round_rate() to + divider_determine_rate() + +From: Brian Masney + +[ Upstream commit af943663ccc266e6346e5645b13c0fca71d24395 ] + +The divider_round_rate() function is now deprecated, so let's migrate +to divider_determine_rate() instead so that this deprecated API can be +removed. + +Note that when the main function itself was migrated to use +determine_rate, this was mistakenly converted to: + + req->rate = divider_round_rate(...) + +This is invalid in the case when an error occurs since it can set the +rate to a negative value. + +Fixes: 0879768df240 ("clk: nxp: lpc32xx: convert from round_rate() to determine_rate()") +Tested-by: Vladimir Zapolskiy +Reviewed-by: Vladimir Zapolskiy +Signed-off-by: Brian Masney +Signed-off-by: Sasha Levin +--- + drivers/clk/nxp/clk-lpc32xx.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/clk/nxp/clk-lpc32xx.c b/drivers/clk/nxp/clk-lpc32xx.c +index 23f980cf6a2b5..ae2fa5341a2e4 100644 +--- a/drivers/clk/nxp/clk-lpc32xx.c ++++ b/drivers/clk/nxp/clk-lpc32xx.c +@@ -975,10 +975,8 @@ static int clk_divider_determine_rate(struct clk_hw *hw, + return 0; + } + +- req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, +- divider->table, divider->width, divider->flags); +- +- return 0; ++ return divider_determine_rate(hw, req, divider->table, divider->width, ++ divider->flags); + } + + static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, +-- +2.51.0 + diff --git a/queue-6.19/clk-qcom-alpha-pll-convert-from-divider_round_rate-t.patch b/queue-6.19/clk-qcom-alpha-pll-convert-from-divider_round_rate-t.patch new file mode 100644 index 0000000000..24a9adad81 --- /dev/null +++ b/queue-6.19/clk-qcom-alpha-pll-convert-from-divider_round_rate-t.patch @@ -0,0 +1,82 @@ +From 990bcb4219b2aa74b63274949444b8973f8cde77 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:16:32 -0500 +Subject: clk: qcom: alpha-pll: convert from divider_round_rate() to + divider_determine_rate() + +From: Brian Masney + +[ Upstream commit e1f08613e113f02a3ec18c9a7964de97f940acbf ] + +The divider_round_rate() function is now deprecated, so let's migrate +to divider_determine_rate() instead so that this deprecated API can be +removed. + +Note that when the main function itself was migrated to use +determine_rate, this was mistakenly converted to: + + req->rate = divider_round_rate(...) + +This is invalid in the case when an error occurs since it can set the +rate to a negative value. + +Fixes: 0e56e3369b60 ("clk: qcom: alpha-pll: convert from round_rate() to determine_rate()") +Signed-off-by: Brian Masney +Reviewed-by: Abel Vesa +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260108-clk-divider-round-rate-v1-14-535a3ed73bf3@redhat.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/clk-alpha-pll.c | 21 ++++++--------------- + 1 file changed, 6 insertions(+), 15 deletions(-) + +diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c +index 6aeba40358c11..a84e8bee65346 100644 +--- a/drivers/clk/qcom/clk-alpha-pll.c ++++ b/drivers/clk/qcom/clk-alpha-pll.c +@@ -1257,11 +1257,8 @@ static int clk_alpha_pll_postdiv_determine_rate(struct clk_hw *hw, + else + table = clk_alpha_div_table; + +- req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, +- table, pll->width, +- CLK_DIVIDER_POWER_OF_TWO); +- +- return 0; ++ return divider_determine_rate(hw, req, table, pll->width, ++ CLK_DIVIDER_POWER_OF_TWO); + } + + static int clk_alpha_pll_postdiv_ro_determine_rate(struct clk_hw *hw, +@@ -1617,11 +1614,8 @@ static int clk_trion_pll_postdiv_determine_rate(struct clk_hw *hw, + { + struct clk_alpha_pll_postdiv *pll = to_clk_alpha_pll_postdiv(hw); + +- req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, +- pll->post_div_table, +- pll->width, CLK_DIVIDER_ROUND_CLOSEST); +- +- return 0; ++ return divider_determine_rate(hw, req, pll->post_div_table, pll->width, ++ CLK_DIVIDER_ROUND_CLOSEST); + }; + + static int +@@ -1657,11 +1651,8 @@ static int clk_alpha_pll_postdiv_fabia_determine_rate(struct clk_hw *hw, + { + struct clk_alpha_pll_postdiv *pll = to_clk_alpha_pll_postdiv(hw); + +- req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, +- pll->post_div_table, +- pll->width, CLK_DIVIDER_ROUND_CLOSEST); +- +- return 0; ++ return divider_determine_rate(hw, req, pll->post_div_table, pll->width, ++ CLK_DIVIDER_ROUND_CLOSEST); + } + + static int clk_alpha_pll_postdiv_fabia_set_rate(struct clk_hw *hw, +-- +2.51.0 + diff --git a/queue-6.19/clk-qcom-dispcc-sdm845-enable-parents-for-pixel-cloc.patch b/queue-6.19/clk-qcom-dispcc-sdm845-enable-parents-for-pixel-cloc.patch new file mode 100644 index 0000000000..f1479b3ffc --- /dev/null +++ b/queue-6.19/clk-qcom-dispcc-sdm845-enable-parents-for-pixel-cloc.patch @@ -0,0 +1,49 @@ +From 38f15f023096e876e3c1f6a39ab03a6fb06bbacf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 12:44:43 +0100 +Subject: clk: qcom: dispcc-sdm845: Enable parents for pixel clocks + +From: Petr Hodina + +[ Upstream commit a1d63493634e98360140027fef49d82b1ff0a267 ] + +Add CLK_OPS_PARENT_ENABLE to MDSS pixel clock sources to ensure parent +clocks are enabled during clock operations, preventing potential +stability issues during display configuration. + +Fixes: 81351776c9fb ("clk: qcom: Add display clock controller driver for SDM845") +Signed-off-by: Petr Hodina +Reviewed-by: Dmitry Baryshkov +Reviewed-by: David Heidelberg +Link: https://lore.kernel.org/r/20260107-stability-discussion-v2-1-ef7717b435ff@protonmail.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sdm845.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/dispcc-sdm845.c b/drivers/clk/qcom/dispcc-sdm845.c +index 2f9e9665d7e93..78e43f6d75026 100644 +--- a/drivers/clk/qcom/dispcc-sdm845.c ++++ b/drivers/clk/qcom/dispcc-sdm845.c +@@ -280,7 +280,7 @@ static struct clk_rcg2 disp_cc_mdss_pclk0_clk_src = { + .name = "disp_cc_mdss_pclk0_clk_src", + .parent_data = disp_cc_parent_data_4, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_4), +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .ops = &clk_pixel_ops, + }, + }; +@@ -295,7 +295,7 @@ static struct clk_rcg2 disp_cc_mdss_pclk1_clk_src = { + .name = "disp_cc_mdss_pclk1_clk_src", + .parent_data = disp_cc_parent_data_4, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_4), +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .ops = &clk_pixel_ops, + }, + }; +-- +2.51.0 + diff --git a/queue-6.19/clk-qcom-dispcc-sm7150-fix-dispcc_mdss_pclk1_clk_src.patch b/queue-6.19/clk-qcom-dispcc-sm7150-fix-dispcc_mdss_pclk1_clk_src.patch new file mode 100644 index 0000000000..1170f4e4d0 --- /dev/null +++ b/queue-6.19/clk-qcom-dispcc-sm7150-fix-dispcc_mdss_pclk1_clk_src.patch @@ -0,0 +1,37 @@ +From 1a952233fb61ceb3898750be57d2e95549acfb2e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 17 Jan 2026 19:18:28 +0100 +Subject: clk: qcom: dispcc-sm7150: Fix dispcc_mdss_pclk1_clk_src + +From: David Heidelberg + +[ Upstream commit fab13d738c9bd645965464b881335f580d38a54e ] + +Set CLK_OPS_PARENT_ENABLE to ensure the parent gets prepared and enabled +when switching to it. + +Fixes: e3c13e0caa8c ("clk: qcom: dispcc-sm7150: Fix dispcc_mdss_pclk0_clk_src") +Signed-off-by: David Heidelberg +Link: https://lore.kernel.org/r/20260117-sm7150-dispcc-fix-v1-1-2f39966bcad2@ixit.cz +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sm7150.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/qcom/dispcc-sm7150.c b/drivers/clk/qcom/dispcc-sm7150.c +index 811d380a8e9f9..ed8e34ffd69b0 100644 +--- a/drivers/clk/qcom/dispcc-sm7150.c ++++ b/drivers/clk/qcom/dispcc-sm7150.c +@@ -371,7 +371,7 @@ static struct clk_rcg2 dispcc_mdss_pclk1_clk_src = { + .name = "dispcc_mdss_pclk1_clk_src", + .parent_data = dispcc_parent_data_4, + .num_parents = ARRAY_SIZE(dispcc_parent_data_4), +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .ops = &clk_pixel_ops, + }, + }; +-- +2.51.0 + diff --git a/queue-6.19/clk-qcom-gcc-glymur-update-the-sdcc-rcgs-to-use-shar.patch b/queue-6.19/clk-qcom-gcc-glymur-update-the-sdcc-rcgs-to-use-shar.patch new file mode 100644 index 0000000000..22c2325696 --- /dev/null +++ b/queue-6.19/clk-qcom-gcc-glymur-update-the-sdcc-rcgs-to-use-shar.patch @@ -0,0 +1,51 @@ +From e817c08cc44dbe6ce3d8a9e137b5a35fc92f326b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Nov 2025 23:27:43 +0530 +Subject: clk: qcom: gcc-glymur: Update the SDCC RCGs to use shared_floor_ops + +From: Jagadeesh Kona + +[ Upstream commit d5639a6d72810023d257c935cb763aea1ada1abc ] + +Use shared_floor_ops for the SDCC RCGs so the RCG is safely parked +during disable and the new parent configuration is programmed in +hardware only when the new parent is enabled, avoiding cases where +the RCG configuration fails to update. + +Fixes: efe504300a17 ("clk: qcom: gcc: Add support for Global Clock Controller") +Signed-off-by: Jagadeesh Kona +Reviewed-by: Imran Shaik +Reviewed-by: Taniya Das +Reviewed-by: Vladimir Zapolskiy +Link: https://lore.kernel.org/r/20251127-sdcc_shared_floor_ops-v2-8-473afc86589c@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-glymur.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-glymur.c b/drivers/clk/qcom/gcc-glymur.c +index deab819576d0e..238e205735ed5 100644 +--- a/drivers/clk/qcom/gcc-glymur.c ++++ b/drivers/clk/qcom/gcc-glymur.c +@@ -2317,7 +2317,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .parent_data = gcc_parent_data_17, + .num_parents = ARRAY_SIZE(gcc_parent_data_17), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +@@ -2339,7 +2339,7 @@ static struct clk_rcg2 gcc_sdcc4_apps_clk_src = { + .parent_data = gcc_parent_data_3, + .num_parents = ARRAY_SIZE(gcc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +-- +2.51.0 + diff --git a/queue-6.19/clk-qcom-gcc-ipq5018-flag-sleep-clock-as-critical.patch b/queue-6.19/clk-qcom-gcc-ipq5018-flag-sleep-clock-as-critical.patch new file mode 100644 index 0000000000..cb3cc4b229 --- /dev/null +++ b/queue-6.19/clk-qcom-gcc-ipq5018-flag-sleep-clock-as-critical.patch @@ -0,0 +1,37 @@ +From fa1bebdc93ee5809ead4d8c4e32a298147ee0f84 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 15:03:19 +0400 +Subject: clk: qcom: gcc-ipq5018: flag sleep clock as critical + +From: George Moussalem + +[ Upstream commit 04c4dc1f541135708d90a9b4632af51136f93ac3 ] + +The sleep clock never be disabled. To avoid the kernel trying to disable +it and keep it always on, flag it as critical. + +Fixes: e3fdbef1bab8 ("clk: qcom: Add Global Clock controller (GCC) driver for IPQ5018") +Signed-off-by: George Moussalem +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251128-ipq5018-sleep-clk-fix-v1-1-6f4b75ec336c@outlook.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-ipq5018.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/clk/qcom/gcc-ipq5018.c b/drivers/clk/qcom/gcc-ipq5018.c +index dcda2be8c1a51..64792cda06202 100644 +--- a/drivers/clk/qcom/gcc-ipq5018.c ++++ b/drivers/clk/qcom/gcc-ipq5018.c +@@ -1340,6 +1340,7 @@ static struct clk_branch gcc_sleep_clk_src = { + .name = "gcc_sleep_clk_src", + .parent_data = gcc_sleep_clk_data, + .num_parents = ARRAY_SIZE(gcc_sleep_clk_data), ++ .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +-- +2.51.0 + diff --git a/queue-6.19/clk-qcom-gcc-milos-update-the-sdcc-rcgs-to-use-share.patch b/queue-6.19/clk-qcom-gcc-milos-update-the-sdcc-rcgs-to-use-share.patch new file mode 100644 index 0000000000..195017d57b --- /dev/null +++ b/queue-6.19/clk-qcom-gcc-milos-update-the-sdcc-rcgs-to-use-share.patch @@ -0,0 +1,59 @@ +From 6c74fcf1f231e689f37f6c6b555f9c6955eaf1d5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Nov 2025 23:27:40 +0530 +Subject: clk: qcom: gcc-milos: Update the SDCC RCGs to use shared_floor_ops + +From: Jagadeesh Kona + +[ Upstream commit 08da8d7dabb161cea14c6d3ad9b5037aaf6d4b7e ] + +Use shared_floor_ops for the SDCC RCGs to avoid any overclocking +issues in SDCC usecases. + +Fixes: 88174d5d9422 ("clk: qcom: Add Global Clock controller (GCC) driver for Milos") +Reviewed-by: Taniya Das +Reviewed-by: Imran Shaik +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Vladimir Zapolskiy +Signed-off-by: Jagadeesh Kona +Link: https://lore.kernel.org/r/20251127-sdcc_shared_floor_ops-v2-5-473afc86589c@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-milos.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-milos.c b/drivers/clk/qcom/gcc-milos.c +index c9d61b05bafa1..81fa09ec55d7f 100644 +--- a/drivers/clk/qcom/gcc-milos.c ++++ b/drivers/clk/qcom/gcc-milos.c +@@ -917,7 +917,7 @@ static struct clk_rcg2 gcc_sdcc1_apps_clk_src = { + .name = "gcc_sdcc1_apps_clk_src", + .parent_data = gcc_parent_data_9, + .num_parents = ARRAY_SIZE(gcc_parent_data_9), +- .ops = &clk_rcg2_shared_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +@@ -938,7 +938,7 @@ static struct clk_rcg2 gcc_sdcc1_ice_core_clk_src = { + .name = "gcc_sdcc1_ice_core_clk_src", + .parent_data = gcc_parent_data_10, + .num_parents = ARRAY_SIZE(gcc_parent_data_10), +- .ops = &clk_rcg2_shared_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +@@ -962,7 +962,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .name = "gcc_sdcc2_apps_clk_src", + .parent_data = gcc_parent_data_11, + .num_parents = ARRAY_SIZE(gcc_parent_data_11), +- .ops = &clk_rcg2_shared_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +-- +2.51.0 + diff --git a/queue-6.19/clk-qcom-gcc-msm8917-remove-always_on-flag-from-cpp_.patch b/queue-6.19/clk-qcom-gcc-msm8917-remove-always_on-flag-from-cpp_.patch new file mode 100644 index 0000000000..c9b3fe4d52 --- /dev/null +++ b/queue-6.19/clk-qcom-gcc-msm8917-remove-always_on-flag-from-cpp_.patch @@ -0,0 +1,39 @@ +From 03d224602aacbacba0de790bca71ffb814d46883 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 17 Nov 2025 18:58:48 +0100 +Subject: clk: qcom: gcc-msm8917: Remove ALWAYS_ON flag from cpp_gdsc +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Czémán + +[ Upstream commit e4eb42f290aecac0ba355b1f8d7243be6de11f32 ] + +cpp_gdsc should not be always on, ALWAYS_ON flag was set accidentally. + +Fixes: 33cc27a47d3a ("clk: qcom: Add global clock controller driver for MSM8917") +Signed-off-by: Barnabás Czémán +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251117-fix-gdsc-cpp-msm8917-msm8953-v1-2-db33adcff28a@mainlining.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-msm8917.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/clk/qcom/gcc-msm8917.c b/drivers/clk/qcom/gcc-msm8917.c +index 0a1aa623cd49a..9d1c5a9953e2c 100644 +--- a/drivers/clk/qcom/gcc-msm8917.c ++++ b/drivers/clk/qcom/gcc-msm8917.c +@@ -3409,7 +3409,6 @@ static struct gdsc cpp_gdsc = { + .pd = { + .name = "cpp_gdsc", + }, +- .flags = ALWAYS_ON, + .pwrsts = PWRSTS_OFF_ON, + }; + +-- +2.51.0 + diff --git a/queue-6.19/clk-qcom-gcc-msm8953-remove-always_on-flag-from-cpp_.patch b/queue-6.19/clk-qcom-gcc-msm8953-remove-always_on-flag-from-cpp_.patch new file mode 100644 index 0000000000..d2f7dd0cf2 --- /dev/null +++ b/queue-6.19/clk-qcom-gcc-msm8953-remove-always_on-flag-from-cpp_.patch @@ -0,0 +1,39 @@ +From d14cf30e6996cb5334067cc7ee0d461c9b05f16e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 17 Nov 2025 18:58:47 +0100 +Subject: clk: qcom: gcc-msm8953: Remove ALWAYS_ON flag from cpp_gdsc +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Czémán + +[ Upstream commit 5f613e7034187179a9d088ff5fd02b1089d0cf20 ] + +cpp_gdsc should not be always on, ALWAYS_ON flag was set accidentally. + +Fixes: 9bb6cfc3c77e ("clk: qcom: Add Global Clock Controller driver for MSM8953") +Signed-off-by: Barnabás Czémán +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251117-fix-gdsc-cpp-msm8917-msm8953-v1-1-db33adcff28a@mainlining.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-msm8953.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/clk/qcom/gcc-msm8953.c b/drivers/clk/qcom/gcc-msm8953.c +index 8f29ecc74c50b..8fe1d3e421440 100644 +--- a/drivers/clk/qcom/gcc-msm8953.c ++++ b/drivers/clk/qcom/gcc-msm8953.c +@@ -3946,7 +3946,6 @@ static struct gdsc cpp_gdsc = { + .pd = { + .name = "cpp_gdsc", + }, +- .flags = ALWAYS_ON, + .pwrsts = PWRSTS_OFF_ON, + }; + +-- +2.51.0 + diff --git a/queue-6.19/clk-qcom-gcc-qdu1000-update-the-sdcc-rcgs-to-use-sha.patch b/queue-6.19/clk-qcom-gcc-qdu1000-update-the-sdcc-rcgs-to-use-sha.patch new file mode 100644 index 0000000000..1785c5ceca --- /dev/null +++ b/queue-6.19/clk-qcom-gcc-qdu1000-update-the-sdcc-rcgs-to-use-sha.patch @@ -0,0 +1,51 @@ +From c8f04dc9cbe8797a1d86c7fe03cb96c2d2e298cb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Nov 2025 23:27:42 +0530 +Subject: clk: qcom: gcc-qdu1000: Update the SDCC RCGs to use shared_floor_ops + +From: Jagadeesh Kona + +[ Upstream commit 947c4b326c1f4dc64aed42170b39c2cf551ba8ca ] + +Use shared_floor_ops for the SDCC RCGs so the RCG is safely parked +during disable and the new parent configuration is programmed in +hardware only when the new parent is enabled, avoiding cases where +the RCG configuration fails to update. + +Fixes: baa316580013 ("clk: qcom: gcc-qdu1000: Update the SDCC clock RCG ops") +Signed-off-by: Jagadeesh Kona +Reviewed-by: Imran Shaik +Reviewed-by: Taniya Das +Reviewed-by: Vladimir Zapolskiy +Link: https://lore.kernel.org/r/20251127-sdcc_shared_floor_ops-v2-7-473afc86589c@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-qdu1000.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-qdu1000.c b/drivers/clk/qcom/gcc-qdu1000.c +index dbe9e9437939a..915bb9b4ff813 100644 +--- a/drivers/clk/qcom/gcc-qdu1000.c ++++ b/drivers/clk/qcom/gcc-qdu1000.c +@@ -904,7 +904,7 @@ static struct clk_rcg2 gcc_sdcc5_apps_clk_src = { + .name = "gcc_sdcc5_apps_clk_src", + .parent_data = gcc_parent_data_8, + .num_parents = ARRAY_SIZE(gcc_parent_data_8), +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +@@ -923,7 +923,7 @@ static struct clk_rcg2 gcc_sdcc5_ice_core_clk_src = { + .name = "gcc_sdcc5_ice_core_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = ARRAY_SIZE(gcc_parent_data_2), +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +-- +2.51.0 + diff --git a/queue-6.19/clk-qcom-gcc-sdx75-update-the-sdcc-rcgs-to-use-share.patch b/queue-6.19/clk-qcom-gcc-sdx75-update-the-sdcc-rcgs-to-use-share.patch new file mode 100644 index 0000000000..906c35d8ec --- /dev/null +++ b/queue-6.19/clk-qcom-gcc-sdx75-update-the-sdcc-rcgs-to-use-share.patch @@ -0,0 +1,52 @@ +From a83b73cdaf7e0c076efa365a406941909dbc7b8e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Nov 2025 23:27:39 +0530 +Subject: clk: qcom: gcc-sdx75: Update the SDCC RCGs to use shared_floor_ops + +From: Jagadeesh Kona + +[ Upstream commit 4b057462bb61a6571608ba393e6e018c9da9c9c3 ] + +Use shared_floor_ops for the SDCC RCGs so the RCG is safely parked +during disable and the new parent configuration is programmed in +hardware only when the new parent is enabled, avoiding cases where +the RCG configuration fails to update. + +Fixes: 108cdc09b2de ("clk: qcom: Add GCC driver support for SDX75") +Reviewed-by: Taniya Das +Reviewed-by: Imran Shaik +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Vladimir Zapolskiy +Signed-off-by: Jagadeesh Kona +Link: https://lore.kernel.org/r/20251127-sdcc_shared_floor_ops-v2-4-473afc86589c@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-sdx75.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-sdx75.c b/drivers/clk/qcom/gcc-sdx75.c +index 453a6bf8e8786..1f3cd58483a2d 100644 +--- a/drivers/clk/qcom/gcc-sdx75.c ++++ b/drivers/clk/qcom/gcc-sdx75.c +@@ -1033,7 +1033,7 @@ static struct clk_rcg2 gcc_sdcc1_apps_clk_src = { + .name = "gcc_sdcc1_apps_clk_src", + .parent_data = gcc_parent_data_17, + .num_parents = ARRAY_SIZE(gcc_parent_data_17), +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +@@ -1057,7 +1057,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .name = "gcc_sdcc2_apps_clk_src", + .parent_data = gcc_parent_data_18, + .num_parents = ARRAY_SIZE(gcc_parent_data_18), +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +-- +2.51.0 + diff --git a/queue-6.19/clk-qcom-gcc-sm4450-update-the-sdcc-rcgs-to-use-shar.patch b/queue-6.19/clk-qcom-gcc-sm4450-update-the-sdcc-rcgs-to-use-shar.patch new file mode 100644 index 0000000000..24dc2f886d --- /dev/null +++ b/queue-6.19/clk-qcom-gcc-sm4450-update-the-sdcc-rcgs-to-use-shar.patch @@ -0,0 +1,61 @@ +From 639ab432af1f1a8b6a496b08fd686e93be3ba795 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Nov 2025 23:27:38 +0530 +Subject: clk: qcom: gcc-sm4450: Update the SDCC RCGs to use shared_floor_ops + +From: Jagadeesh Kona + +[ Upstream commit 458e8a082186335380a9ab83003a385aec9bb254 ] + +Use shared_floor_ops for the SDCC RCGs so the RCG is safely parked +during disable and the new parent configuration is programmed in +hardware only when the new parent is enabled, avoiding cases where +the RCG configuration fails to update. + +Fixes: c32c4ef98bac ("clk: qcom: Add GCC driver support for SM4450") +Reviewed-by: Taniya Das +Reviewed-by: Imran Shaik +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Vladimir Zapolskiy +Signed-off-by: Jagadeesh Kona +Link: https://lore.kernel.org/r/20251127-sdcc_shared_floor_ops-v2-3-473afc86589c@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-sm4450.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-sm4450.c b/drivers/clk/qcom/gcc-sm4450.c +index e2d9e4691c5b7..023d840e9f4ef 100644 +--- a/drivers/clk/qcom/gcc-sm4450.c ++++ b/drivers/clk/qcom/gcc-sm4450.c +@@ -769,7 +769,7 @@ static struct clk_rcg2 gcc_sdcc1_apps_clk_src = { + .parent_data = gcc_parent_data_4, + .num_parents = ARRAY_SIZE(gcc_parent_data_4), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +@@ -791,7 +791,7 @@ static struct clk_rcg2 gcc_sdcc1_ice_core_clk_src = { + .parent_data = gcc_parent_data_4, + .num_parents = ARRAY_SIZE(gcc_parent_data_4), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +@@ -815,7 +815,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .parent_data = gcc_parent_data_6, + .num_parents = ARRAY_SIZE(gcc_parent_data_6), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +-- +2.51.0 + diff --git a/queue-6.19/clk-qcom-gcc-sm8450-update-the-sdcc-rcgs-to-use-shar.patch b/queue-6.19/clk-qcom-gcc-sm8450-update-the-sdcc-rcgs-to-use-shar.patch new file mode 100644 index 0000000000..5c691c54b5 --- /dev/null +++ b/queue-6.19/clk-qcom-gcc-sm8450-update-the-sdcc-rcgs-to-use-shar.patch @@ -0,0 +1,52 @@ +From ab410f8160c6b0795f51250fb0f4798958500922 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Nov 2025 23:27:36 +0530 +Subject: clk: qcom: gcc-sm8450: Update the SDCC RCGs to use shared_floor_ops + +From: Jagadeesh Kona + +[ Upstream commit 89428516f99572a9c37ebbb7859595881e7025a0 ] + +Use shared_floor_ops for the SDCC RCGs so the RCG is safely parked +during disable and the new parent configuration is programmed in +hardware only when the new parent is enabled, avoiding cases where +the RCG configuration fails to update. + +Fixes: a27ac3806b0a ("clk: qcom: gcc-sm8450: Use floor ops for SDCC RCGs") +Reviewed-by: Taniya Das +Reviewed-by: Imran Shaik +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Vladimir Zapolskiy +Signed-off-by: Jagadeesh Kona +Link: https://lore.kernel.org/r/20251127-sdcc_shared_floor_ops-v2-1-473afc86589c@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-sm8450.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-sm8450.c b/drivers/clk/qcom/gcc-sm8450.c +index 65d7d52bce034..b18bb34889ab2 100644 +--- a/drivers/clk/qcom/gcc-sm8450.c ++++ b/drivers/clk/qcom/gcc-sm8450.c +@@ -1034,7 +1034,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .parent_data = gcc_parent_data_7, + .num_parents = ARRAY_SIZE(gcc_parent_data_7), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +@@ -1057,7 +1057,7 @@ static struct clk_rcg2 gcc_sdcc4_apps_clk_src = { + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +-- +2.51.0 + diff --git a/queue-6.19/clk-qcom-gcc-sm8550-use-floor-ops-for-sdcc-rcgs.patch b/queue-6.19/clk-qcom-gcc-sm8550-use-floor-ops-for-sdcc-rcgs.patch new file mode 100644 index 0000000000..5f8028de83 --- /dev/null +++ b/queue-6.19/clk-qcom-gcc-sm8550-use-floor-ops-for-sdcc-rcgs.patch @@ -0,0 +1,55 @@ +From a0fb27e27e38c60e4b675224cdc8888ee120d615 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 24 Nov 2025 23:20:11 +0200 +Subject: clk: qcom: gcc-sm8550: Use floor ops for SDCC RCGs + +From: Vladimir Zapolskiy + +[ Upstream commit 1c06e3956054fb5a0930f07b02726b1774b6c700 ] + +In line with commit a27ac3806b0a ("clk: qcom: gcc-sm8450: Use floor ops +for SDCC RCGs") done to fix issues with overclocked SD cards on SM8450 +powered boards set floor clock operations for SDCC RCGs on SM8550. + +This change fixes initialization of some SD cards, where the problem +is manifested by the SDHC driver: + + mmc0: Card appears overclocked; req 50000000 Hz, actual 100000000 Hz + mmc0: error -110 whilst initialising SD card + +Fixes: 955f2ea3b9e9 ("clk: qcom: Add GCC driver for SM8550") +Signed-off-by: Vladimir Zapolskiy +Reviewed-by: Neil Armstrong +Reviewed-by: Taniya Das +Link: https://lore.kernel.org/r/20251124212012.3660189-2-vladimir.zapolskiy@linaro.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-sm8550.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-sm8550.c b/drivers/clk/qcom/gcc-sm8550.c +index 862a9bf73bcb5..36a5b7de5b55d 100644 +--- a/drivers/clk/qcom/gcc-sm8550.c ++++ b/drivers/clk/qcom/gcc-sm8550.c +@@ -1025,7 +1025,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .parent_data = gcc_parent_data_9, + .num_parents = ARRAY_SIZE(gcc_parent_data_9), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_shared_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +@@ -1048,7 +1048,7 @@ static struct clk_rcg2 gcc_sdcc4_apps_clk_src = { + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_shared_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +-- +2.51.0 + diff --git a/queue-6.19/clk-qcom-gcc-sm8650-use-floor-ops-for-sdcc-rcgs.patch b/queue-6.19/clk-qcom-gcc-sm8650-use-floor-ops-for-sdcc-rcgs.patch new file mode 100644 index 0000000000..1482dcd1be --- /dev/null +++ b/queue-6.19/clk-qcom-gcc-sm8650-use-floor-ops-for-sdcc-rcgs.patch @@ -0,0 +1,55 @@ +From 9de28343835ea39dca109b37d5792a1e90d5b994 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 24 Nov 2025 23:20:12 +0200 +Subject: clk: qcom: gcc-sm8650: Use floor ops for SDCC RCGs + +From: Vladimir Zapolskiy + +[ Upstream commit 8c4415fd17cd5979c31a4bf303acc702e9726033 ] + +In line with commit a27ac3806b0a ("clk: qcom: gcc-sm8450: Use floor ops +for SDCC RCGs") done to fix issues with overclocked SD cards on SM8450 +powered boards set floor clock operations for SDCC RCGs on SM8650. + +This change fixes initialization of some SD cards, where the problem +is manifested by the SDHC driver: + + mmc0: Card appears overclocked; req 50000000 Hz, actual 100000000 Hz + mmc0: error -110 whilst initialising SD card + +Fixes: c58225b7e3d7 ("clk: qcom: add the SM8650 Global Clock Controller driver, part 1") +Signed-off-by: Vladimir Zapolskiy +Reviewed-by: Neil Armstrong +Reviewed-by: Taniya Das +Link: https://lore.kernel.org/r/20251124212012.3660189-3-vladimir.zapolskiy@linaro.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-sm8650.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-sm8650.c b/drivers/clk/qcom/gcc-sm8650.c +index 24f98062b9dd5..2dd6444ce0365 100644 +--- a/drivers/clk/qcom/gcc-sm8650.c ++++ b/drivers/clk/qcom/gcc-sm8650.c +@@ -1257,7 +1257,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .parent_data = gcc_parent_data_11, + .num_parents = ARRAY_SIZE(gcc_parent_data_11), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_shared_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +@@ -1279,7 +1279,7 @@ static struct clk_rcg2 gcc_sdcc4_apps_clk_src = { + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_shared_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +-- +2.51.0 + diff --git a/queue-6.19/clk-qcom-gcc-sm8750-update-the-sdcc-rcgs-to-use-shar.patch b/queue-6.19/clk-qcom-gcc-sm8750-update-the-sdcc-rcgs-to-use-shar.patch new file mode 100644 index 0000000000..259c7e7a0a --- /dev/null +++ b/queue-6.19/clk-qcom-gcc-sm8750-update-the-sdcc-rcgs-to-use-shar.patch @@ -0,0 +1,52 @@ +From b4684a3da9063bbe5ae18fe07b7c0f3d8528befb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Nov 2025 23:27:37 +0530 +Subject: clk: qcom: gcc-sm8750: Update the SDCC RCGs to use shared_floor_ops + +From: Jagadeesh Kona + +[ Upstream commit a7231d4aa084e485394f9214ec9bcb2d1f65dde9 ] + +Use shared_floor_ops for the SDCC RCGs so the RCG is safely parked +during disable and the new parent configuration is programmed in +hardware only when the new parent is enabled, avoiding cases where +the RCG configuration fails to update. + +Fixes: 3267c774f3ff ("clk: qcom: Add support for GCC on SM8750") +Reviewed-by: Taniya Das +Reviewed-by: Imran Shaik +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Vladimir Zapolskiy +Signed-off-by: Jagadeesh Kona +Link: https://lore.kernel.org/r/20251127-sdcc_shared_floor_ops-v2-2-473afc86589c@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-sm8750.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-sm8750.c b/drivers/clk/qcom/gcc-sm8750.c +index def86b71a3da5..db81569dd4b17 100644 +--- a/drivers/clk/qcom/gcc-sm8750.c ++++ b/drivers/clk/qcom/gcc-sm8750.c +@@ -1030,7 +1030,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .parent_data = gcc_parent_data_8, + .num_parents = ARRAY_SIZE(gcc_parent_data_8), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +@@ -1052,7 +1052,7 @@ static struct clk_rcg2 gcc_sdcc4_apps_clk_src = { + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +-- +2.51.0 + diff --git a/queue-6.19/clk-qcom-gcc-x1e80100-update-the-sdcc-rcgs-to-use-sh.patch b/queue-6.19/clk-qcom-gcc-x1e80100-update-the-sdcc-rcgs-to-use-sh.patch new file mode 100644 index 0000000000..86845c7b3a --- /dev/null +++ b/queue-6.19/clk-qcom-gcc-x1e80100-update-the-sdcc-rcgs-to-use-sh.patch @@ -0,0 +1,50 @@ +From e8b429935d06c34c157c37292d0da2bc6680342d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Nov 2025 23:27:41 +0530 +Subject: clk: qcom: gcc-x1e80100: Update the SDCC RCGs to use shared_floor_ops + +From: Jagadeesh Kona + +[ Upstream commit a468047c4e1c56783204a3ac551b843b4277c8fc ] + +Use shared_floor_ops for the SDCC RCGs so the RCG is safely parked +during disable and the new parent configuration is programmed in +hardware only when the new parent is enabled, avoiding cases where +the RCG configuration fails to update. + +Fixes: 161b7c401f4b ("clk: qcom: Add Global Clock controller (GCC) driver for X1E80100") +Signed-off-by: Jagadeesh Kona +Reviewed-by: Imran Shaik +Reviewed-by: Vladimir Zapolskiy +Link: https://lore.kernel.org/r/20251127-sdcc_shared_floor_ops-v2-6-473afc86589c@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-x1e80100.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-x1e80100.c b/drivers/clk/qcom/gcc-x1e80100.c +index b63c8abdd2fc2..e46e65e631513 100644 +--- a/drivers/clk/qcom/gcc-x1e80100.c ++++ b/drivers/clk/qcom/gcc-x1e80100.c +@@ -1516,7 +1516,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .parent_data = gcc_parent_data_9, + .num_parents = ARRAY_SIZE(gcc_parent_data_9), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +@@ -1538,7 +1538,7 @@ static struct clk_rcg2 gcc_sdcc4_apps_clk_src = { + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +-- +2.51.0 + diff --git a/queue-6.19/clk-qcom-gfx3d-add-parent-to-parent-request-map.patch b/queue-6.19/clk-qcom-gfx3d-add-parent-to-parent-request-map.patch new file mode 100644 index 0000000000..843304bb9d --- /dev/null +++ b/queue-6.19/clk-qcom-gfx3d-add-parent-to-parent-request-map.patch @@ -0,0 +1,67 @@ +From e90cf3a7e701339a73d0187202f2f6182218225d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 17 Jan 2026 05:54:47 +0200 +Subject: clk: qcom: gfx3d: add parent to parent request map + +From: Dmitry Baryshkov + +[ Upstream commit 2583cb925ca1ce450aa5d74a05a67448db970193 ] + +After commit d228ece36345 ("clk: divider: remove round_rate() in favor +of determine_rate()") determining GFX3D clock rate crashes, because the +passed parent map doesn't provide the expected best_parent_hw clock +(with the roundd_rate path before the offending commit the +best_parent_hw was ignored). + +Set the field in parent_req in addition to setting it in the req, +fixing the crash. + + clk_hw_round_rate (drivers/clk/clk.c:1764) (P) + clk_divider_bestdiv (drivers/clk/clk-divider.c:336) + divider_determine_rate (drivers/clk/clk-divider.c:358) + clk_alpha_pll_postdiv_determine_rate (drivers/clk/qcom/clk-alpha-pll.c:1275) + clk_core_determine_round_nolock (drivers/clk/clk.c:1606) + clk_core_round_rate_nolock (drivers/clk/clk.c:1701) + __clk_determine_rate (drivers/clk/clk.c:1741) + clk_gfx3d_determine_rate (drivers/clk/qcom/clk-rcg2.c:1268) + clk_core_determine_round_nolock (drivers/clk/clk.c:1606) + clk_core_round_rate_nolock (drivers/clk/clk.c:1701) + clk_core_round_rate_nolock (drivers/clk/clk.c:1710) + clk_round_rate (drivers/clk/clk.c:1804) + dev_pm_opp_set_rate (drivers/opp/core.c:1440 (discriminator 1)) + msm_devfreq_target (drivers/gpu/drm/msm/msm_gpu_devfreq.c:51) + devfreq_set_target (drivers/devfreq/devfreq.c:360) + devfreq_update_target (drivers/devfreq/devfreq.c:426) + devfreq_monitor (drivers/devfreq/devfreq.c:458) + process_one_work (arch/arm64/include/asm/jump_label.h:36 include/trace/events/workqueue.h:110 kernel/workqueue.c:3284) + worker_thread (kernel/workqueue.c:3356 (discriminator 2) kernel/workqueue.c:3443 (discriminator 2)) + kthread (kernel/kthread.c:467) + ret_from_fork (arch/arm64/kernel/entry.S:861) + +Fixes: 55213e1acec9 ("clk: qcom: Add gfx3d ping-pong PLL frequency switching") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Abel Vesa +Reviewed-by: Konrad Dybcio +Reviewed-by: Brian Masney +Link: https://lore.kernel.org/r/20260117-db820-fix-gfx3d-v1-1-0f8894d71d63@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/clk-rcg2.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c +index 2838d4cb2d58e..d0a5847f91114 100644 +--- a/drivers/clk/qcom/clk-rcg2.c ++++ b/drivers/clk/qcom/clk-rcg2.c +@@ -1264,6 +1264,7 @@ static int clk_gfx3d_determine_rate(struct clk_hw *hw, + if (req->max_rate < parent_req.max_rate) + parent_req.max_rate = req->max_rate; + ++ parent_req.best_parent_hw = req->best_parent_hw; + ret = __clk_determine_rate(req->best_parent_hw, &parent_req); + if (ret) + return ret; +-- +2.51.0 + diff --git a/queue-6.19/clk-qcom-rcg2-compute-2d-using-duty-fraction-directl.patch b/queue-6.19/clk-qcom-rcg2-compute-2d-using-duty-fraction-directl.patch new file mode 100644 index 0000000000..2e4b9b2db1 --- /dev/null +++ b/queue-6.19/clk-qcom-rcg2-compute-2d-using-duty-fraction-directl.patch @@ -0,0 +1,71 @@ +From 7c71026638769efe90c7a6ba264c3e01447912a3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Jan 2026 16:09:50 +0530 +Subject: clk: qcom: rcg2: compute 2d using duty fraction directly +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Taniya Das + +[ Upstream commit d6205a1878dd4cc9664c4b4829b68a29c0426efc ] + +The duty-cycle calculation in clk_rcg2_set_duty_cycle() currently +derives an intermediate percentage `duty_per = (num * 100) / den` and +then computes: + + d = DIV_ROUND_CLOSEST(n * duty_per * 2, 100); + +This introduces integer truncation at the percentage step (division by +`den`) and a redundant scaling by 100, which can reduce precision for +large `den` and skew the final rounding. + +Compute `2d` directly from the duty fraction to preserve precision and +avoid the unnecessary scaling: + + d = DIV_ROUND_CLOSEST(n * duty->num * 2, duty->den); + +This keeps the intended formula `d ≈ n * 2 * (num/den)` while performing +a single, final rounded division, improving accuracy especially for small +duty cycles or large denominators. It also removes the unused `duty_per` +variable, simplifying the code. + +There is no functional changes beyond improved numerical accuracy. + +Fixes: 7f891faf596ed ("clk: qcom: clk-rcg2: Add support for duty-cycle for RCG") +Signed-off-by: Taniya Das +Link: https://lore.kernel.org/r/20260105-duty_cycle_precision-v2-1-d1d466a6330a@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/clk-rcg2.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c +index e18cb8807d735..2838d4cb2d58e 100644 +--- a/drivers/clk/qcom/clk-rcg2.c ++++ b/drivers/clk/qcom/clk-rcg2.c +@@ -755,7 +755,7 @@ static int clk_rcg2_get_duty_cycle(struct clk_hw *hw, struct clk_duty *duty) + static int clk_rcg2_set_duty_cycle(struct clk_hw *hw, struct clk_duty *duty) + { + struct clk_rcg2 *rcg = to_clk_rcg2(hw); +- u32 notn_m, n, m, d, not2d, mask, duty_per, cfg; ++ u32 notn_m, n, m, d, not2d, mask, cfg; + int ret; + + /* Duty-cycle cannot be modified for non-MND RCGs */ +@@ -774,10 +774,8 @@ static int clk_rcg2_set_duty_cycle(struct clk_hw *hw, struct clk_duty *duty) + + n = (~(notn_m) + m) & mask; + +- duty_per = (duty->num * 100) / duty->den; +- + /* Calculate 2d value */ +- d = DIV_ROUND_CLOSEST(n * duty_per * 2, 100); ++ d = DIV_ROUND_CLOSEST(n * duty->num * 2, duty->den); + + /* + * Check bit widths of 2d. If D is too big reduce duty cycle. +-- +2.51.0 + diff --git a/queue-6.19/clk-qcom-regmap-divider-convert-from-divider_ro_roun.patch b/queue-6.19/clk-qcom-regmap-divider-convert-from-divider_ro_roun.patch new file mode 100644 index 0000000000..65f0d9b048 --- /dev/null +++ b/queue-6.19/clk-qcom-regmap-divider-convert-from-divider_ro_roun.patch @@ -0,0 +1,55 @@ +From 4d79492e21d84f09d2cced5d0b7da8a345631f0d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:16:33 -0500 +Subject: clk: qcom: regmap-divider: convert from divider_ro_round_rate() to + divider_ro_determine_rate() + +From: Brian Masney + +[ Upstream commit 349f02c0f5d4ee147c582b89cadd553bd534028a ] + +The divider_ro_round_rate() function is now deprecated, so let's migrate +to divider_ro_determine_rate() instead so that this deprecated API can +be removed. + +Note that when the main function itself was migrated to use +determine_rate, this was mistakenly converted to: + + req->rate = divider_round_rate(...) + +This is invalid in the case when an error occurs since it can set the +rate to a negative value. + +Fixes: b6f90511c165 ("clk: qcom: regmap-divider: convert from round_rate() to determine_rate()") +Signed-off-by: Brian Masney +Reviewed-by: Abel Vesa +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260108-clk-divider-round-rate-v1-15-535a3ed73bf3@redhat.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/clk-regmap-divider.c | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + +diff --git a/drivers/clk/qcom/clk-regmap-divider.c b/drivers/clk/qcom/clk-regmap-divider.c +index 4f5395f0ab6d0..af9c01dd78537 100644 +--- a/drivers/clk/qcom/clk-regmap-divider.c ++++ b/drivers/clk/qcom/clk-regmap-divider.c +@@ -26,12 +26,8 @@ static int div_ro_determine_rate(struct clk_hw *hw, + val >>= divider->shift; + val &= BIT(divider->width) - 1; + +- req->rate = divider_ro_round_rate(hw, req->rate, +- &req->best_parent_rate, NULL, +- divider->width, +- CLK_DIVIDER_ROUND_CLOSEST, val); +- +- return 0; ++ return divider_ro_determine_rate(hw, req, NULL, divider->width, ++ CLK_DIVIDER_ROUND_CLOSEST, val); + } + + static int div_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) +-- +2.51.0 + diff --git a/queue-6.19/clk-qcom-regmap-divider-convert-from-divider_round_r.patch b/queue-6.19/clk-qcom-regmap-divider-convert-from-divider_round_r.patch new file mode 100644 index 0000000000..50b4f182ef --- /dev/null +++ b/queue-6.19/clk-qcom-regmap-divider-convert-from-divider_round_r.patch @@ -0,0 +1,55 @@ +From 89f7625d22efa3568dabad26d5de8bf7313c22a8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:16:34 -0500 +Subject: clk: qcom: regmap-divider: convert from divider_round_rate() to + divider_determine_rate() + +From: Brian Masney + +[ Upstream commit d8300e6e078a3a44ac0c75c6d8ba46d78ab94035 ] + +The divider_round_rate() function is now deprecated, so let's migrate +to divider_determine_rate() instead so that this deprecated API can be +removed. + +Note that when the main function itself was migrated to use +determine_rate, this was mistakenly converted to: + + req->rate = divider_round_rate(...) + +This is invalid in the case when an error occurs since it can set the +rate to a negative value. + +Fixes: b6f90511c165 ("clk: qcom: regmap-divider: convert from round_rate() to determine_rate()") +Signed-off-by: Brian Masney +Reviewed-by: Abel Vesa +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260108-clk-divider-round-rate-v1-16-535a3ed73bf3@redhat.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/clk-regmap-divider.c | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + +diff --git a/drivers/clk/qcom/clk-regmap-divider.c b/drivers/clk/qcom/clk-regmap-divider.c +index af9c01dd78537..672e82caf2050 100644 +--- a/drivers/clk/qcom/clk-regmap-divider.c ++++ b/drivers/clk/qcom/clk-regmap-divider.c +@@ -34,12 +34,8 @@ static int div_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) + { + struct clk_regmap_div *divider = to_clk_regmap_div(hw); + +- req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, +- NULL, +- divider->width, +- CLK_DIVIDER_ROUND_CLOSEST); +- +- return 0; ++ return divider_determine_rate(hw, req, NULL, divider->width, ++ CLK_DIVIDER_ROUND_CLOSEST); + } + + static int div_set_rate(struct clk_hw *hw, unsigned long rate, +-- +2.51.0 + diff --git a/queue-6.19/clk-qcom-return-correct-error-code-in-qcom_cc_probe_.patch b/queue-6.19/clk-qcom-return-correct-error-code-in-qcom_cc_probe_.patch new file mode 100644 index 0000000000..4d268b7dd7 --- /dev/null +++ b/queue-6.19/clk-qcom-return-correct-error-code-in-qcom_cc_probe_.patch @@ -0,0 +1,42 @@ +From 2c5e2a428fb49aa10461e08fb7eabaaf6297432e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 17 Dec 2025 12:13:38 +0800 +Subject: clk: qcom: Return correct error code in qcom_cc_probe_by_index() + +From: Haotian Zhang + +[ Upstream commit 1e07ebe744fb522983bd52a4a6148601675330c7 ] + +When devm_platform_ioremap_resource() fails, it returns various +error codes. Returning a hardcoded -ENOMEM masks the actual +failure reason. + +Use PTR_ERR() to propagate the actual error code returned by +devm_platform_ioremap_resource() instead of -ENOMEM. + +Fixes: 75e0a1e30191 ("clk: qcom: define probe by index API as common API") +Signed-off-by: Haotian Zhang +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251217041338.2432-1-vulab@iscas.ac.cn +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/common.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c +index 1215918867741..eec369d2173b5 100644 +--- a/drivers/clk/qcom/common.c ++++ b/drivers/clk/qcom/common.c +@@ -454,7 +454,7 @@ int qcom_cc_probe_by_index(struct platform_device *pdev, int index, + + base = devm_platform_ioremap_resource(pdev, index); + if (IS_ERR(base)) +- return -ENOMEM; ++ return PTR_ERR(base); + + regmap = devm_regmap_init_mmio(&pdev->dev, base, desc->config); + if (IS_ERR(regmap)) +-- +2.51.0 + diff --git a/queue-6.19/clk-respect-clk_ops_parent_enable-during-recalc.patch b/queue-6.19/clk-respect-clk_ops_parent_enable-during-recalc.patch new file mode 100644 index 0000000000..b16f303c28 --- /dev/null +++ b/queue-6.19/clk-respect-clk_ops_parent_enable-during-recalc.patch @@ -0,0 +1,69 @@ +From 17b0f85bf6339d9e275389fa4ba8c9d2014a1bb7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 15 Dec 2025 11:23:58 +0100 +Subject: clk: Respect CLK_OPS_PARENT_ENABLE during recalc + +From: Nicolas Frattaroli + +[ Upstream commit 669917676e93fca5ea3c66fc9539830312bec58e ] + +When CLK_OPS_PARENT_ENABLE was introduced, it guarded various clock +operations, such as setting the rate or switching parents. However, +another operation that can and often does touch actual hardware state is +recalc_rate, which may also be affected by such a dependency. + +Add parent enables/disables where the recalc_rate op is called directly. + +Fixes: fc8726a2c021 ("clk: core: support clocks which requires parents enable (part 2)") +Fixes: a4b3518d146f ("clk: core: support clocks which requires parents enable (part 1)") +Reviewed-by: AngeloGioacchino Del Regno +Reviewed-by: Chen-Yu Tsai +Signed-off-by: Nicolas Frattaroli +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + drivers/clk/clk.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c +index 85d2f2481acf3..1b0f9d567f48e 100644 +--- a/drivers/clk/clk.c ++++ b/drivers/clk/clk.c +@@ -1921,7 +1921,14 @@ static unsigned long clk_recalc(struct clk_core *core, + unsigned long rate = parent_rate; + + if (core->ops->recalc_rate && !clk_pm_runtime_get(core)) { ++ if (core->flags & CLK_OPS_PARENT_ENABLE) ++ clk_core_prepare_enable(core->parent); ++ + rate = core->ops->recalc_rate(core->hw, parent_rate); ++ ++ if (core->flags & CLK_OPS_PARENT_ENABLE) ++ clk_core_disable_unprepare(core->parent); ++ + clk_pm_runtime_put(core); + } + return rate; +@@ -4031,6 +4038,9 @@ static int __clk_core_init(struct clk_core *core) + */ + clk_core_update_duty_cycle_nolock(core); + ++ if (core->flags & CLK_OPS_PARENT_ENABLE) ++ clk_core_prepare_enable(core->parent); ++ + /* + * Set clk's rate. The preferred method is to use .recalc_rate. For + * simple clocks and lazy developers the default fallback is to use the +@@ -4046,6 +4056,9 @@ static int __clk_core_init(struct clk_core *core) + rate = 0; + core->rate = core->req_rate = rate; + ++ if (core->flags & CLK_OPS_PARENT_ENABLE) ++ clk_core_disable_unprepare(core->parent); ++ + /* + * Enable CLK_IS_CRITICAL clocks so newly added critical clocks + * don't get accidentally disabled when walking the orphan tree and +-- +2.51.0 + diff --git a/queue-6.19/clk-rockchip-fix-error-pointer-check-after-rockchip_.patch b/queue-6.19/clk-rockchip-fix-error-pointer-check-after-rockchip_.patch new file mode 100644 index 0000000000..c92dc94f24 --- /dev/null +++ b/queue-6.19/clk-rockchip-fix-error-pointer-check-after-rockchip_.patch @@ -0,0 +1,39 @@ +From 6a200abea3b1931386e36bf3f8058b98482dc046 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 5 Aug 2025 07:03:58 +0400 +Subject: clk: rockchip: Fix error pointer check after + rockchip_clk_register_gate_link() + +From: Miaoqian Lin + +[ Upstream commit a8d722f03923b1c6166d39482c6df8f017e185d9 ] + +Replace NULL check with IS_ERR_OR_NULL() check after calling +rockchip_clk_register_gate_link() since this function +returns error pointers (ERR_PTR). + +Fixes: c62fa612cfa6 ("clk: rockchip: implement linked gate clock support") +Signed-off-by: Miaoqian Lin +Link: https://patch.msgid.link/20250805030358.3665878-1-linmq006@gmail.com +Signed-off-by: Heiko Stuebner +Signed-off-by: Sasha Levin +--- + drivers/clk/rockchip/clk.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c +index 2601df3b1066b..9ac9d13e87de0 100644 +--- a/drivers/clk/rockchip/clk.c ++++ b/drivers/clk/rockchip/clk.c +@@ -693,7 +693,7 @@ void rockchip_clk_register_late_branches(struct device *dev, + break; + } + +- if (!pdev) ++ if (IS_ERR_OR_NULL(pdev)) + dev_err(dev, "failed to register device for clock %s\n", list->name); + } + } +-- +2.51.0 + diff --git a/queue-6.19/clk-sophgo-sg2042-clkgen-convert-from-divider_round_.patch b/queue-6.19/clk-sophgo-sg2042-clkgen-convert-from-divider_round_.patch new file mode 100644 index 0000000000..33e83cd6c1 --- /dev/null +++ b/queue-6.19/clk-sophgo-sg2042-clkgen-convert-from-divider_round_.patch @@ -0,0 +1,72 @@ +From 2c7acaaa58c8ed8d8a2547e8c59d6997aca77a6a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:16:35 -0500 +Subject: clk: sophgo: sg2042-clkgen: convert from divider_round_rate() to + divider_determine_rate() + +From: Brian Masney + +[ Upstream commit 77b04dc19693510ce8ed1c6eda5f5b833e208816 ] + +The divider_round_rate() function is now deprecated, so let's migrate +to divider_determine_rate() instead so that this deprecated API can be +removed. + +Note that when the main function itself was migrated to use +determine_rate, this was mistakenly converted to: + + req->rate = divider_round_rate(...) + +This is invalid in the case when an error occurs since it can set the +rate to a negative value. + +Note that this commit also removes a debugging message that's not really +needed. + +Fixes: 9a3b6993613d ("clk: sophgo: sg2042-clkgen: convert from round_rate() to determine_rate()") +Tested-by: Chen Wang +Reviewed-by: Chen Wang +Signed-off-by: Brian Masney +Signed-off-by: Sasha Levin +--- + drivers/clk/sophgo/clk-sg2042-clkgen.c | 15 +++++---------- + 1 file changed, 5 insertions(+), 10 deletions(-) + +diff --git a/drivers/clk/sophgo/clk-sg2042-clkgen.c b/drivers/clk/sophgo/clk-sg2042-clkgen.c +index 683661b71787c..9725ac4e050a4 100644 +--- a/drivers/clk/sophgo/clk-sg2042-clkgen.c ++++ b/drivers/clk/sophgo/clk-sg2042-clkgen.c +@@ -180,7 +180,6 @@ static int sg2042_clk_divider_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) + { + struct sg2042_divider_clock *divider = to_sg2042_clk_divider(hw); +- unsigned long ret_rate; + u32 bestdiv; + + /* if read only, just return current value */ +@@ -191,17 +190,13 @@ static int sg2042_clk_divider_determine_rate(struct clk_hw *hw, + bestdiv = readl(divider->reg) >> divider->shift; + bestdiv &= clk_div_mask(divider->width); + } +- ret_rate = DIV_ROUND_UP_ULL((u64)req->best_parent_rate, bestdiv); +- } else { +- ret_rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, NULL, +- divider->width, divider->div_flags); +- } ++ req->rate = DIV_ROUND_UP_ULL((u64)req->best_parent_rate, bestdiv); + +- pr_debug("--> %s: divider_round_rate: val = %ld\n", +- clk_hw_get_name(hw), ret_rate); +- req->rate = ret_rate; ++ return 0; ++ } + +- return 0; ++ return divider_determine_rate(hw, req, NULL, divider->width, ++ divider->div_flags); + } + + static int sg2042_clk_divider_set_rate(struct clk_hw *hw, +-- +2.51.0 + diff --git a/queue-6.19/clk-spacemit-respect-kconfig-setting-when-building-m.patch b/queue-6.19/clk-spacemit-respect-kconfig-setting-when-building-m.patch new file mode 100644 index 0000000000..e3df7fad8b --- /dev/null +++ b/queue-6.19/clk-spacemit-respect-kconfig-setting-when-building-m.patch @@ -0,0 +1,166 @@ +From bb15ffdc608c78b46f56e2f808f01e25a6476bc5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 19 Dec 2025 09:28:17 +0800 +Subject: clk: spacemit: Respect Kconfig setting when building modules + +From: Inochi Amaoto + +[ Upstream commit 5ec8cbbc54c82c0bdae4dbf0e5aecf9817bde2b9 ] + +Currently, the SPACEMIT_CCU entry is only a switch for enabling entry +SPACEMIT_K1_CCU. It does not guide the build for common clock codes +even if it is a tristate entry. This makes this entry useless. + +Change the Makefile to add a separate build for common clock logic, +so the SPACEMIT_CCU entry takes effect, also add necessary +MODULE_LICENSE()/MODULE_DESCRIPTION()/EXPORT_SYMBOL() for the module +build. + +Fixes: 1b72c59db0ad ("clk: spacemit: Add clock support for SpacemiT K1 SoC") +Signed-off-by: Inochi Amaoto +Reviewed-by: Yixun Lan +Link: https://lore.kernel.org/r/20251219012819.440972-2-inochiama@gmail.com +Signed-off-by: Yixun Lan +Signed-off-by: Sasha Levin +--- + drivers/clk/spacemit/Makefile | 9 +++++++-- + drivers/clk/spacemit/ccu-k1.c | 1 + + drivers/clk/spacemit/ccu_common.c | 6 ++++++ + drivers/clk/spacemit/ccu_ddn.c | 1 + + drivers/clk/spacemit/ccu_mix.c | 9 +++++++++ + drivers/clk/spacemit/ccu_pll.c | 1 + + 6 files changed, 25 insertions(+), 2 deletions(-) + create mode 100644 drivers/clk/spacemit/ccu_common.c + +diff --git a/drivers/clk/spacemit/Makefile b/drivers/clk/spacemit/Makefile +index 5ec6da61db98e..ad2bf315109b8 100644 +--- a/drivers/clk/spacemit/Makefile ++++ b/drivers/clk/spacemit/Makefile +@@ -1,5 +1,10 @@ + # SPDX-License-Identifier: GPL-2.0 + +-obj-$(CONFIG_SPACEMIT_K1_CCU) = spacemit-ccu-k1.o +-spacemit-ccu-k1-y = ccu_pll.o ccu_mix.o ccu_ddn.o ++obj-$(CONFIG_SPACEMIT_CCU) += spacemit-ccu.o ++spacemit-ccu-y += ccu_common.o ++spacemit-ccu-y += ccu_pll.o ++spacemit-ccu-y += ccu_mix.o ++spacemit-ccu-y += ccu_ddn.o ++ ++obj-$(CONFIG_SPACEMIT_K1_CCU) += spacemit-ccu-k1.o + spacemit-ccu-k1-y += ccu-k1.o +diff --git a/drivers/clk/spacemit/ccu-k1.c b/drivers/clk/spacemit/ccu-k1.c +index 4761bc1e3b6e6..01d9485b615d3 100644 +--- a/drivers/clk/spacemit/ccu-k1.c ++++ b/drivers/clk/spacemit/ccu-k1.c +@@ -1204,6 +1204,7 @@ static struct platform_driver k1_ccu_driver = { + }; + module_platform_driver(k1_ccu_driver); + ++MODULE_IMPORT_NS("CLK_SPACEMIT"); + MODULE_DESCRIPTION("SpacemiT K1 CCU driver"); + MODULE_AUTHOR("Haylen Chu "); + MODULE_LICENSE("GPL"); +diff --git a/drivers/clk/spacemit/ccu_common.c b/drivers/clk/spacemit/ccu_common.c +new file mode 100644 +index 0000000000000..4412c4104dabb +--- /dev/null ++++ b/drivers/clk/spacemit/ccu_common.c +@@ -0,0 +1,6 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++ ++#include ++ ++MODULE_DESCRIPTION("SpacemiT CCU common clock driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/clk/spacemit/ccu_ddn.c b/drivers/clk/spacemit/ccu_ddn.c +index 5b16e273bee5b..b5540e0781ffa 100644 +--- a/drivers/clk/spacemit/ccu_ddn.c ++++ b/drivers/clk/spacemit/ccu_ddn.c +@@ -84,3 +84,4 @@ const struct clk_ops spacemit_ccu_ddn_ops = { + .determine_rate = ccu_ddn_determine_rate, + .set_rate = ccu_ddn_set_rate, + }; ++EXPORT_SYMBOL_NS_GPL(spacemit_ccu_ddn_ops, "CLK_SPACEMIT"); +diff --git a/drivers/clk/spacemit/ccu_mix.c b/drivers/clk/spacemit/ccu_mix.c +index 7b79908753723..67f8b12b4f5b7 100644 +--- a/drivers/clk/spacemit/ccu_mix.c ++++ b/drivers/clk/spacemit/ccu_mix.c +@@ -198,24 +198,28 @@ const struct clk_ops spacemit_ccu_gate_ops = { + .enable = ccu_gate_enable, + .is_enabled = ccu_gate_is_enabled, + }; ++EXPORT_SYMBOL_NS_GPL(spacemit_ccu_gate_ops, "CLK_SPACEMIT"); + + const struct clk_ops spacemit_ccu_factor_ops = { + .determine_rate = ccu_factor_determine_rate, + .recalc_rate = ccu_factor_recalc_rate, + .set_rate = ccu_factor_set_rate, + }; ++EXPORT_SYMBOL_NS_GPL(spacemit_ccu_factor_ops, "CLK_SPACEMIT"); + + const struct clk_ops spacemit_ccu_mux_ops = { + .determine_rate = ccu_mix_determine_rate, + .get_parent = ccu_mux_get_parent, + .set_parent = ccu_mux_set_parent, + }; ++EXPORT_SYMBOL_NS_GPL(spacemit_ccu_mux_ops, "CLK_SPACEMIT"); + + const struct clk_ops spacemit_ccu_div_ops = { + .determine_rate = ccu_mix_determine_rate, + .recalc_rate = ccu_div_recalc_rate, + .set_rate = ccu_mix_set_rate, + }; ++EXPORT_SYMBOL_NS_GPL(spacemit_ccu_div_ops, "CLK_SPACEMIT"); + + const struct clk_ops spacemit_ccu_factor_gate_ops = { + .disable = ccu_gate_disable, +@@ -226,6 +230,7 @@ const struct clk_ops spacemit_ccu_factor_gate_ops = { + .recalc_rate = ccu_factor_recalc_rate, + .set_rate = ccu_factor_set_rate, + }; ++EXPORT_SYMBOL_NS_GPL(spacemit_ccu_factor_gate_ops, "CLK_SPACEMIT"); + + const struct clk_ops spacemit_ccu_mux_gate_ops = { + .disable = ccu_gate_disable, +@@ -236,6 +241,7 @@ const struct clk_ops spacemit_ccu_mux_gate_ops = { + .get_parent = ccu_mux_get_parent, + .set_parent = ccu_mux_set_parent, + }; ++EXPORT_SYMBOL_NS_GPL(spacemit_ccu_mux_gate_ops, "CLK_SPACEMIT"); + + const struct clk_ops spacemit_ccu_div_gate_ops = { + .disable = ccu_gate_disable, +@@ -246,6 +252,7 @@ const struct clk_ops spacemit_ccu_div_gate_ops = { + .recalc_rate = ccu_div_recalc_rate, + .set_rate = ccu_mix_set_rate, + }; ++EXPORT_SYMBOL_NS_GPL(spacemit_ccu_div_gate_ops, "CLK_SPACEMIT"); + + const struct clk_ops spacemit_ccu_mux_div_gate_ops = { + .disable = ccu_gate_disable, +@@ -259,6 +266,7 @@ const struct clk_ops spacemit_ccu_mux_div_gate_ops = { + .recalc_rate = ccu_div_recalc_rate, + .set_rate = ccu_mix_set_rate, + }; ++EXPORT_SYMBOL_NS_GPL(spacemit_ccu_mux_div_gate_ops, "CLK_SPACEMIT"); + + const struct clk_ops spacemit_ccu_mux_div_ops = { + .get_parent = ccu_mux_get_parent, +@@ -268,3 +276,4 @@ const struct clk_ops spacemit_ccu_mux_div_ops = { + .recalc_rate = ccu_div_recalc_rate, + .set_rate = ccu_mix_set_rate, + }; ++EXPORT_SYMBOL_NS_GPL(spacemit_ccu_mux_div_ops, "CLK_SPACEMIT"); +diff --git a/drivers/clk/spacemit/ccu_pll.c b/drivers/clk/spacemit/ccu_pll.c +index d92f0dae65a49..76d0244873d87 100644 +--- a/drivers/clk/spacemit/ccu_pll.c ++++ b/drivers/clk/spacemit/ccu_pll.c +@@ -157,3 +157,4 @@ const struct clk_ops spacemit_ccu_pll_ops = { + .determine_rate = ccu_pll_determine_rate, + .is_enabled = ccu_pll_is_enabled, + }; ++EXPORT_SYMBOL_NS_GPL(spacemit_ccu_pll_ops, "CLK_SPACEMIT"); +-- +2.51.0 + diff --git a/queue-6.19/clk-sprd-div-convert-from-divider_round_rate-to-divi.patch b/queue-6.19/clk-sprd-div-convert-from-divider_round_rate-to-divi.patch new file mode 100644 index 0000000000..e396c0aaf3 --- /dev/null +++ b/queue-6.19/clk-sprd-div-convert-from-divider_round_rate-to-divi.patch @@ -0,0 +1,49 @@ +From 121fbe001352d9cdeb9372108de250c6d2c839e3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:16:36 -0500 +Subject: clk: sprd: div: convert from divider_round_rate() to + divider_determine_rate() + +From: Brian Masney + +[ Upstream commit f78fb9422980ceeb340fa3a2e370ae8845798ec7 ] + +The divider_round_rate() function is now deprecated, so let's migrate +to divider_determine_rate() instead so that this deprecated API can be +removed. + +Note that when the main function itself was migrated to use +determine_rate, this was mistakenly converted to: + + req->rate = divider_round_rate(...) + +This is invalid in the case when an error occurs since it can set the +rate to a negative value. + +Fixes: deb4740a5ff8 ("clk: sprd: div: convert from round_rate() to determine_rate()") +Signed-off-by: Brian Masney +Signed-off-by: Sasha Levin +--- + drivers/clk/sprd/div.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/drivers/clk/sprd/div.c b/drivers/clk/sprd/div.c +index 0134238819680..cd57163a7204c 100644 +--- a/drivers/clk/sprd/div.c ++++ b/drivers/clk/sprd/div.c +@@ -14,11 +14,7 @@ static int sprd_div_determine_rate(struct clk_hw *hw, + { + struct sprd_div *cd = hw_to_sprd_div(hw); + +- req->rate = divider_round_rate(&cd->common.hw, req->rate, +- &req->best_parent_rate, +- NULL, cd->div.width, 0); +- +- return 0; ++ return divider_determine_rate(&cd->common.hw, req, NULL, cd->div.width, 0); + } + + unsigned long sprd_div_helper_recalc_rate(struct sprd_clk_common *common, +-- +2.51.0 + diff --git a/queue-6.19/clk-stm32-stm32-core-convert-from-divider_ro_round_r.patch b/queue-6.19/clk-stm32-stm32-core-convert-from-divider_ro_round_r.patch new file mode 100644 index 0000000000..d92281aa4f --- /dev/null +++ b/queue-6.19/clk-stm32-stm32-core-convert-from-divider_ro_round_r.patch @@ -0,0 +1,72 @@ +From 431f8baad71b7eb405ef3e84809ac508e95d4f6f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:16:37 -0500 +Subject: clk: stm32: stm32-core: convert from divider_ro_round_rate() to + divider_ro_determine_rate() + +From: Brian Masney + +[ Upstream commit 6587c9dacc89ad7014bf601fe851955429f13230 ] + +The divider_ro_round_rate() function is now deprecated, so let's migrate +to divider_ro_determine_rate() instead so that this deprecated API can +be removed. + +Note that when the main function itself was migrated to use +determine_rate, this was mistakenly converted to: + + req->rate = divider_round_rate(...) + +This is invalid in the case when an error occurs since it can set the +rate to a negative value. + +Fixes: cd1cb38836c0 ("clk: stm32: stm32-core: convert from round_rate() to determine_rate()") +Signed-off-by: Brian Masney +Signed-off-by: Sasha Levin +--- + drivers/clk/stm32/clk-stm32-core.c | 22 +++++++--------------- + 1 file changed, 7 insertions(+), 15 deletions(-) + +diff --git a/drivers/clk/stm32/clk-stm32-core.c b/drivers/clk/stm32/clk-stm32-core.c +index 72825b9c36a4d..b95b9c591fda7 100644 +--- a/drivers/clk/stm32/clk-stm32-core.c ++++ b/drivers/clk/stm32/clk-stm32-core.c +@@ -369,13 +369,10 @@ static int clk_stm32_divider_determine_rate(struct clk_hw *hw, + val = readl(div->base + divider->offset) >> divider->shift; + val &= clk_div_mask(divider->width); + +- req->rate = divider_ro_round_rate(hw, req->rate, +- &req->best_parent_rate, +- divider->table, +- divider->width, +- divider->flags, val); +- +- return 0; ++ return divider_ro_determine_rate(hw, req, ++ divider->table, ++ divider->width, ++ divider->flags, val); + } + + req->rate = divider_round_rate_parent(hw, clk_hw_get_parent(hw), +@@ -455,14 +452,9 @@ static int clk_stm32_composite_determine_rate(struct clk_hw *hw, + val = readl(composite->base + divider->offset) >> divider->shift; + val &= clk_div_mask(divider->width); + +- rate = divider_ro_round_rate(hw, req->rate, &req->best_parent_rate, +- divider->table, divider->width, divider->flags, +- val); +- if (rate < 0) +- return rate; +- +- req->rate = rate; +- return 0; ++ return divider_ro_determine_rate(hw, req, divider->table, ++ divider->width, divider->flags, ++ val); + } + + rate = divider_round_rate_parent(hw, clk_hw_get_parent(hw), +-- +2.51.0 + diff --git a/queue-6.19/clk-stm32-stm32-core-convert-from-divider_round_rate.patch b/queue-6.19/clk-stm32-stm32-core-convert-from-divider_round_rate.patch new file mode 100644 index 0000000000..3f395637a2 --- /dev/null +++ b/queue-6.19/clk-stm32-stm32-core-convert-from-divider_round_rate.patch @@ -0,0 +1,77 @@ +From e070ae12b57c9ef56151c28751dc57e092f26bd0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:16:38 -0500 +Subject: clk: stm32: stm32-core: convert from divider_round_rate_parent() to + divider_determine_rate() + +From: Brian Masney + +[ Upstream commit 2532795a6d6bb9791d713ffa9d9433f293b45b14 ] + +The divider_round_rate_parent() function is now deprecated, so let's +migrate to divider_determine_rate() instead so that this deprecated API +can be removed. + +Note that when the main function itself was migrated to use +determine_rate, this was mistakenly converted to: + + req->rate = divider_round_rate(...) + +This is invalid in the case when an error occurs since it can set the +rate to a negative value. + +Fixes: cd1cb38836c0 ("clk: stm32: stm32-core: convert from round_rate() to determine_rate()") +Signed-off-by: Brian Masney +Signed-off-by: Sasha Levin +--- + drivers/clk/stm32/clk-stm32-core.c | 20 ++++---------------- + 1 file changed, 4 insertions(+), 16 deletions(-) + +diff --git a/drivers/clk/stm32/clk-stm32-core.c b/drivers/clk/stm32/clk-stm32-core.c +index b95b9c591fda7..e921c25a929c3 100644 +--- a/drivers/clk/stm32/clk-stm32-core.c ++++ b/drivers/clk/stm32/clk-stm32-core.c +@@ -375,13 +375,8 @@ static int clk_stm32_divider_determine_rate(struct clk_hw *hw, + divider->flags, val); + } + +- req->rate = divider_round_rate_parent(hw, clk_hw_get_parent(hw), +- req->rate, +- &req->best_parent_rate, +- divider->table, +- divider->width, divider->flags); +- +- return 0; ++ return divider_determine_rate(hw, req, divider->table, divider->width, ++ divider->flags); + } + + static unsigned long clk_stm32_divider_recalc_rate(struct clk_hw *hw, +@@ -438,7 +433,6 @@ static int clk_stm32_composite_determine_rate(struct clk_hw *hw, + { + struct clk_stm32_composite *composite = to_clk_stm32_composite(hw); + const struct stm32_div_cfg *divider; +- long rate; + + if (composite->div_id == NO_STM32_DIV) + return 0; +@@ -457,14 +451,8 @@ static int clk_stm32_composite_determine_rate(struct clk_hw *hw, + val); + } + +- rate = divider_round_rate_parent(hw, clk_hw_get_parent(hw), +- req->rate, &req->best_parent_rate, +- divider->table, divider->width, divider->flags); +- if (rate < 0) +- return rate; +- +- req->rate = rate; +- return 0; ++ return divider_determine_rate(hw, req, divider->table, divider->width, ++ divider->flags); + } + + static u8 clk_stm32_composite_get_parent(struct clk_hw *hw) +-- +2.51.0 + diff --git a/queue-6.19/clk-thead-th1520-ap-poll-for-pll-lock-and-wait-for-s.patch b/queue-6.19/clk-thead-th1520-ap-poll-for-pll-lock-and-wait-for-s.patch new file mode 100644 index 0000000000..8c9253a4e6 --- /dev/null +++ b/queue-6.19/clk-thead-th1520-ap-poll-for-pll-lock-and-wait-for-s.patch @@ -0,0 +1,150 @@ +From 8d1df9ffb64fa225f65874551eee7b0b858be398 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 20 Nov 2025 13:14:11 +0000 +Subject: clk: thead: th1520-ap: Poll for PLL lock and wait for stability + +From: Yao Zi + +[ Upstream commit 892abfbed71e8e0fc5d6ccee1e975904805c6327 ] + +All PLLs found on TH1520 SoC take 21250ns at maximum to lock, and their +lock status is indicated by register PLL_STS (offset 0x80 inside AP +clock controller). We should poll the register to ensure the PLL +actually locks after enabling it. + +Furthermore, a 30us delay is added after enabling the PLL, after which +the PLL could be considered stable as stated by vendor clock code. + +Fixes: 56a48c1833aa ("clk: thead: add support for enabling/disabling PLLs") +Reviewed-by: Drew Fustini +Signed-off-by: Yao Zi +Signed-off-by: Drew Fustini +Signed-off-by: Sasha Levin +--- + drivers/clk/thead/clk-th1520-ap.c | 34 +++++++++++++++++++++++++++++-- + 1 file changed, 32 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/thead/clk-th1520-ap.c b/drivers/clk/thead/clk-th1520-ap.c +index 71ad03a998e8e..d870f0c665f8a 100644 +--- a/drivers/clk/thead/clk-th1520-ap.c ++++ b/drivers/clk/thead/clk-th1520-ap.c +@@ -8,11 +8,14 @@ + #include + #include + #include ++#include + #include + #include + #include + #include + ++#define TH1520_PLL_STS 0x80 ++ + #define TH1520_PLL_POSTDIV2 GENMASK(26, 24) + #define TH1520_PLL_POSTDIV1 GENMASK(22, 20) + #define TH1520_PLL_FBDIV GENMASK(19, 8) +@@ -23,6 +26,13 @@ + #define TH1520_PLL_FRAC GENMASK(23, 0) + #define TH1520_PLL_FRAC_BITS 24 + ++/* ++ * All PLLs in TH1520 take 21250ns at maximum to lock, let's take its double ++ * for safety. ++ */ ++#define TH1520_PLL_LOCK_TIMEOUT_US 44 ++#define TH1520_PLL_STABLE_DELAY_US 30 ++ + struct ccu_internal { + u8 shift; + u8 width; +@@ -64,6 +74,7 @@ struct ccu_div { + + struct ccu_pll { + struct ccu_common common; ++ u32 lock_sts_mask; + }; + + #define TH_CCU_ARG(_shift, _width) \ +@@ -299,9 +310,21 @@ static void ccu_pll_disable(struct clk_hw *hw) + static int ccu_pll_enable(struct clk_hw *hw) + { + struct ccu_pll *pll = hw_to_ccu_pll(hw); ++ u32 reg; ++ int ret; + +- return regmap_clear_bits(pll->common.map, pll->common.cfg1, +- TH1520_PLL_VCO_RST); ++ regmap_clear_bits(pll->common.map, pll->common.cfg1, ++ TH1520_PLL_VCO_RST); ++ ++ ret = regmap_read_poll_timeout_atomic(pll->common.map, TH1520_PLL_STS, ++ reg, reg & pll->lock_sts_mask, ++ 5, TH1520_PLL_LOCK_TIMEOUT_US); ++ if (ret) ++ return ret; ++ ++ udelay(TH1520_PLL_STABLE_DELAY_US); ++ ++ return 0; + } + + static int ccu_pll_is_enabled(struct clk_hw *hw) +@@ -389,6 +412,7 @@ static struct ccu_pll cpu_pll0_clk = { + &clk_pll_ops, + CLK_IS_CRITICAL), + }, ++ .lock_sts_mask = BIT(1), + }; + + static struct ccu_pll cpu_pll1_clk = { +@@ -401,6 +425,7 @@ static struct ccu_pll cpu_pll1_clk = { + &clk_pll_ops, + CLK_IS_CRITICAL), + }, ++ .lock_sts_mask = BIT(4), + }; + + static struct ccu_pll gmac_pll_clk = { +@@ -413,6 +438,7 @@ static struct ccu_pll gmac_pll_clk = { + &clk_pll_ops, + CLK_IS_CRITICAL), + }, ++ .lock_sts_mask = BIT(3), + }; + + static const struct clk_hw *gmac_pll_clk_parent[] = { +@@ -433,6 +459,7 @@ static struct ccu_pll video_pll_clk = { + &clk_pll_ops, + CLK_IS_CRITICAL), + }, ++ .lock_sts_mask = BIT(7), + }; + + static const struct clk_hw *video_pll_clk_parent[] = { +@@ -453,6 +480,7 @@ static struct ccu_pll dpu0_pll_clk = { + &clk_pll_ops, + 0), + }, ++ .lock_sts_mask = BIT(8), + }; + + static const struct clk_hw *dpu0_pll_clk_parent[] = { +@@ -469,6 +497,7 @@ static struct ccu_pll dpu1_pll_clk = { + &clk_pll_ops, + 0), + }, ++ .lock_sts_mask = BIT(9), + }; + + static const struct clk_hw *dpu1_pll_clk_parent[] = { +@@ -485,6 +514,7 @@ static struct ccu_pll tee_pll_clk = { + &clk_pll_ops, + CLK_IS_CRITICAL), + }, ++ .lock_sts_mask = BIT(10), + }; + + static const struct clk_parent_data c910_i0_parents[] = { +-- +2.51.0 + diff --git a/queue-6.19/clk-versaclock3-convert-from-divider_round_rate-to-d.patch b/queue-6.19/clk-versaclock3-convert-from-divider_round_rate-to-d.patch new file mode 100644 index 0000000000..e3edfbb0e3 --- /dev/null +++ b/queue-6.19/clk-versaclock3-convert-from-divider_round_rate-to-d.patch @@ -0,0 +1,50 @@ +From bc2788eec59cf64d70c9a0252542fd1c997d1444 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:16:39 -0500 +Subject: clk: versaclock3: convert from divider_round_rate() to + divider_determine_rate() + +From: Brian Masney + +[ Upstream commit 56c1cfb488cc17944c200edad96191a70a3783ba ] + +The divider_round_rate() function is now deprecated, so let's migrate +to divider_determine_rate() instead so that this deprecated API can be +removed. + +Note that when the main function itself was migrated to use +determine_rate, this was mistakenly converted to: + + req->rate = divider_round_rate(...) + +This is invalid in the case when an error occurs since it can set the +rate to a negative value. + +Fixes: 9e3372b2ebac ("clk: versaclock3: convert from round_rate() to determine_rate()") +Signed-off-by: Brian Masney +Signed-off-by: Sasha Levin +--- + drivers/clk/clk-versaclock3.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/drivers/clk/clk-versaclock3.c b/drivers/clk/clk-versaclock3.c +index 1849863dbd673..27b6cf70f3ae1 100644 +--- a/drivers/clk/clk-versaclock3.c ++++ b/drivers/clk/clk-versaclock3.c +@@ -523,11 +523,8 @@ static int vc3_div_determine_rate(struct clk_hw *hw, + return 0; + } + +- req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, +- div_data->table, +- div_data->width, div_data->flags); +- +- return 0; ++ return divider_determine_rate(hw, req, div_data->table, div_data->width, ++ div_data->flags); + } + + static int vc3_div_set_rate(struct clk_hw *hw, unsigned long rate, +-- +2.51.0 + diff --git a/queue-6.19/clk-x86-cgu-convert-from-divider_round_rate-to-divid.patch b/queue-6.19/clk-x86-cgu-convert-from-divider_round_rate-to-divid.patch new file mode 100644 index 0000000000..3078444d82 --- /dev/null +++ b/queue-6.19/clk-x86-cgu-convert-from-divider_round_rate-to-divid.patch @@ -0,0 +1,49 @@ +From fdef8879d16cb0b2bf919e5d6b0b37b8909257ef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:16:40 -0500 +Subject: clk: x86: cgu: convert from divider_round_rate() to + divider_determine_rate() + +From: Brian Masney + +[ Upstream commit bb1b0e63dbbd7150324cb4d6aef7854dbe26a617 ] + +The divider_round_rate() function is now deprecated, so let's migrate +to divider_determine_rate() instead so that this deprecated API can be +removed. + +Note that when the main function itself was migrated to use +determine_rate, this was mistakenly converted to: + + req->rate = divider_round_rate(...) + +This is invalid in the case when an error occurs since it can set the +rate to a negative value. + +Fixes: f7a6bed91a19 ("clk: x86: cgu: convert from round_rate() to determine_rate()") +Signed-off-by: Brian Masney +Signed-off-by: Sasha Levin +--- + drivers/clk/x86/clk-cgu.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/clk/x86/clk-cgu.c b/drivers/clk/x86/clk-cgu.c +index d099667355f8d..92ee05d75af2b 100644 +--- a/drivers/clk/x86/clk-cgu.c ++++ b/drivers/clk/x86/clk-cgu.c +@@ -137,10 +137,8 @@ static int lgm_clk_divider_determine_rate(struct clk_hw *hw, + { + struct lgm_clk_divider *divider = to_lgm_clk_divider(hw); + +- req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, divider->table, +- divider->width, divider->flags); +- +- return 0; ++ return divider_determine_rate(hw, req, divider->table, divider->width, ++ divider->flags); + } + + static int +-- +2.51.0 + diff --git a/queue-6.19/clk-zynqmp-divider-convert-from-divider_round_rate-t.patch b/queue-6.19/clk-zynqmp-divider-convert-from-divider_round_rate-t.patch new file mode 100644 index 0000000000..0779561c66 --- /dev/null +++ b/queue-6.19/clk-zynqmp-divider-convert-from-divider_round_rate-t.patch @@ -0,0 +1,48 @@ +From 39b8fe59d641896e44e538c50236e371a1e2a6e0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:16:41 -0500 +Subject: clk: zynqmp: divider: convert from divider_round_rate() to + divider_determine_rate() + +From: Brian Masney + +[ Upstream commit 30a807808c69a1907001ffb79289237a2ee97cfa ] + +The divider_round_rate() function is now deprecated, so let's migrate +to divider_determine_rate() instead so that this deprecated API can be +removed. + +Note that when the main function itself was migrated to use +determine_rate, this was mistakenly converted to: + + req->rate = divider_round_rate(...) + +This is invalid in the case when an error occurs since it can set the +rate to a negative value. + +Fixes: 0f9cf96a01fd ("clk: zynqmp: divider: convert from round_rate() to determine_rate()") +Signed-off-by: Brian Masney +Signed-off-by: Sasha Levin +--- + drivers/clk/zynqmp/divider.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/zynqmp/divider.c b/drivers/clk/zynqmp/divider.c +index c824eeacd8ebd..de6f478d527d8 100644 +--- a/drivers/clk/zynqmp/divider.c ++++ b/drivers/clk/zynqmp/divider.c +@@ -151,8 +151,9 @@ static int zynqmp_clk_divider_determine_rate(struct clk_hw *hw, + + width = fls(divider->max_div); + +- req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, +- NULL, width, divider->flags); ++ ret = divider_determine_rate(hw, req, NULL, width, divider->flags); ++ if (ret != 0) ++ return ret; + + if (divider->is_frac && (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) && + (req->rate % req->best_parent_rate)) +-- +2.51.0 + diff --git a/queue-6.19/clk-zynqmp-divider-fix-zynqmp_clk_divider_determine_.patch b/queue-6.19/clk-zynqmp-divider-fix-zynqmp_clk_divider_determine_.patch new file mode 100644 index 0000000000..c0e558a4c4 --- /dev/null +++ b/queue-6.19/clk-zynqmp-divider-fix-zynqmp_clk_divider_determine_.patch @@ -0,0 +1,44 @@ +From 6a9864f7641e7b5a6b2db9d433c1a4ba18621446 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Dec 2025 12:42:11 +0100 +Subject: clk: zynqmp: divider: Fix zynqmp_clk_divider_determine_rate kerneldoc + +From: Krzysztof Kozlowski + +[ Upstream commit 1b8773864904c7a25e45f1b12ab505bdb7e06568 ] + +After renaming round_rate->determine, kerneldoc does not match anymore, +causing W=1 warnings: + + Warning: drivers/clk/zynqmp/divider.c:122 function parameter 'req' not described in 'zynqmp_clk_divider_determine_rate' + Warning: drivers/clk/zynqmp/divider.c:122 expecting prototype for zynqmp_clk_divider_round_rate(). Prototype was for zynqmp_clk_divider_determine_rate() instead + +Fixes: 0f9cf96a01fd ("clk: zynqmp: divider: convert from round_rate() to determine_rate()") +Signed-off-by: Krzysztof Kozlowski +Reviewed-by: Brian Masney +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + drivers/clk/zynqmp/divider.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/clk/zynqmp/divider.c b/drivers/clk/zynqmp/divider.c +index de6f478d527d8..984e577ea6711 100644 +--- a/drivers/clk/zynqmp/divider.c ++++ b/drivers/clk/zynqmp/divider.c +@@ -111,10 +111,9 @@ static unsigned long zynqmp_clk_divider_recalc_rate(struct clk_hw *hw, + } + + /** +- * zynqmp_clk_divider_round_rate() - Round rate of divider clock ++ * zynqmp_clk_divider_determine_rate() - Determine rate of divider clock + * @hw: handle between common and hardware-specific interfaces +- * @rate: rate of clock to be set +- * @prate: rate of parent clock ++ * @req: rate of clock to be set + * + * Return: 0 on success else error+reason + */ +-- +2.51.0 + diff --git a/queue-6.19/clk-zynqmp-pll-fix-zynqmp_clk_divider_determine_rate.patch b/queue-6.19/clk-zynqmp-pll-fix-zynqmp_clk_divider_determine_rate.patch new file mode 100644 index 0000000000..0dcbf90e10 --- /dev/null +++ b/queue-6.19/clk-zynqmp-pll-fix-zynqmp_clk_divider_determine_rate.patch @@ -0,0 +1,44 @@ +From df99821db13a12c59b2049d0e816abd29bd47f38 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Dec 2025 12:42:12 +0100 +Subject: clk: zynqmp: pll: Fix zynqmp_clk_divider_determine_rate kerneldoc + +From: Krzysztof Kozlowski + +[ Upstream commit 750e0e0a1652530618d2c07697618e705bc5061b ] + +After renaming round_rate->determine, kerneldoc does not match anymore, +causing W=1 warnings: + + pll.c:102 function parameter 'req' not described in 'zynqmp_pll_determine_rate' + pll.c:102 expecting prototype for zynqmp_pll_round_rate(). Prototype was for zynqmp_pll_determine_rate() instead + +Fixes: 193650c7a873 ("clk: zynqmp: pll: convert from round_rate() to determine_rate()") +Signed-off-by: Krzysztof Kozlowski +Reviewed-by: Brian Masney +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + drivers/clk/zynqmp/pll.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/clk/zynqmp/pll.c b/drivers/clk/zynqmp/pll.c +index 630a3936c97c3..6bc2c3934f564 100644 +--- a/drivers/clk/zynqmp/pll.c ++++ b/drivers/clk/zynqmp/pll.c +@@ -91,10 +91,9 @@ static inline void zynqmp_pll_set_mode(struct clk_hw *hw, bool on) + } + + /** +- * zynqmp_pll_round_rate() - Round a clock frequency ++ * zynqmp_pll_determine_rate() - Round a clock frequency + * @hw: Handle between common and hardware-specific interfaces +- * @rate: Desired clock frequency +- * @prate: Clock frequency of parent clock ++ * @req: Desired clock frequency + * + * Return: Frequency closest to @rate the hardware can generate + */ +-- +2.51.0 + diff --git a/queue-6.19/clocksource-drivers-timer-sp804-fix-an-oops-when-rea.patch b/queue-6.19/clocksource-drivers-timer-sp804-fix-an-oops-when-rea.patch new file mode 100644 index 0000000000..4d3facbfc7 --- /dev/null +++ b/queue-6.19/clocksource-drivers-timer-sp804-fix-an-oops-when-rea.patch @@ -0,0 +1,90 @@ +From ab6684a2aa9550656d0654164e54ea15a519ecd7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 25 Dec 2025 16:16:31 +0800 +Subject: clocksource/drivers/timer-sp804: Fix an Oops when read_current_timer + is called on ARM32 platforms where the SP804 is not registered as the + sched_clock. + +From: Stephen Eta Zhou + +[ Upstream commit 694921a93f3e3621e067afc545cedf6fe3b234a9 ] + +On SP804, the delay timer shares the same clkevt instance with +sched_clock. On some platforms, when +sp804_clocksource_and_sched_clock_init is called with use_sched_clock +not set to 1, sched_clkevt is not properly initialized. However, +sp804_register_delay_timer is invoked unconditionally, and +read_current_timer() subsequently calls sp804_read on an uninitialized +sched_clkevt, leading to a kernel Oops when accessing +sched_clkevt->value. + +Declare a dedicated clkevt instance exclusively for delay timer, +instead of sharing the same clkevt with sched_clock. This ensures +that read_current_timer continues to work correctly regardless of +whether SP804 is selected as the sched_clock. + +Fixes: 640594a04f11 ("clocksource/drivers/timer-sp804: Fix read_current_timer() issue when clock source is not registered") +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202512250520.APOMkYRQ-lkp@intel.com/ +Signed-off-by: Stephen Eta Zhou +Signed-off-by: Daniel Lezcano +Link: https://patch.msgid.link/20251225-fix_timersp804-v2-1-a366d7157f58@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/clocksource/timer-sp804.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/drivers/clocksource/timer-sp804.c b/drivers/clocksource/timer-sp804.c +index e82a95ea47247..d698584273596 100644 +--- a/drivers/clocksource/timer-sp804.c ++++ b/drivers/clocksource/timer-sp804.c +@@ -106,21 +106,25 @@ static u64 notrace sp804_read(void) + return ~readl_relaxed(sched_clkevt->value); + } + ++/* Register delay timer backed by the hardware counter */ + #ifdef CONFIG_ARM + static struct delay_timer delay; ++static struct sp804_clkevt *delay_clkevt; ++ + static unsigned long sp804_read_delay_timer_read(void) + { +- return sp804_read(); ++ return ~readl_relaxed(delay_clkevt->value); + } + +-static void sp804_register_delay_timer(int freq) ++static void sp804_register_delay_timer(struct sp804_clkevt *clk, int freq) + { ++ delay_clkevt = clk; + delay.freq = freq; + delay.read_current_timer = sp804_read_delay_timer_read; + register_current_timer_delay(&delay); + } + #else +-static inline void sp804_register_delay_timer(int freq) {} ++static inline void sp804_register_delay_timer(struct sp804_clkevt *clk, int freq) {} + #endif + + static int __init sp804_clocksource_and_sched_clock_init(void __iomem *base, +@@ -135,8 +139,6 @@ static int __init sp804_clocksource_and_sched_clock_init(void __iomem *base, + if (rate < 0) + return -EINVAL; + +- sp804_register_delay_timer(rate); +- + clkevt = sp804_clkevt_get(base); + + writel(0, clkevt->ctrl); +@@ -152,6 +154,8 @@ static int __init sp804_clocksource_and_sched_clock_init(void __iomem *base, + clocksource_mmio_init(clkevt->value, name, + rate, 200, 32, clocksource_mmio_readl_down); + ++ sp804_register_delay_timer(clkevt, rate); ++ + if (use_sched_clock) { + sched_clkevt = clkevt; + sched_clock_register(sp804_read, 32, rate); +-- +2.51.0 + diff --git a/queue-6.19/coresight-etm3x-fix-cpulocked-warning-on-cpuhp.patch b/queue-6.19/coresight-etm3x-fix-cpulocked-warning-on-cpuhp.patch new file mode 100644 index 0000000000..3d2fd75a94 --- /dev/null +++ b/queue-6.19/coresight-etm3x-fix-cpulocked-warning-on-cpuhp.patch @@ -0,0 +1,67 @@ +From 585465f98cddae8c5329d21868f941c5436395ba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:24:27 +0100 +Subject: coresight: etm3x: Fix cpulocked warning on cpuhp + +From: Antonio Borneo + +[ Upstream commit 1feb0377b9b816f89a04fc381eb19fc6bac9f4a4 ] + +When changes [1] and [2] have been applied to the driver etm4x, the +same modifications have been also collapsed in [3] and applied in +one shot to the driver etm3x. +While doing this, the driver etm3x has not been aligned to etm4x on +the use of non cpuslocked version of cpuhp callback setup APIs. + +The current code triggers two run-time warnings when the kernel is +compiled with CONFIG_PROVE_LOCKING=y. + +Use non cpuslocked version of cpuhp callback setup APIs in driver +etm3x, aligning it to the driver etm4x. + +[1] commit 2d1a8bfb61ec ("coresight: etm4x: Fix etm4_count race by + moving cpuhp callbacks to init") +[2] commit 22a550a306ad ("coresight: etm4x: Allow etm4x to be built + as a module") +[3] commit 97fe626ce64c ("coresight: etm3x: Allow etm3x to be built + as a module") + +Fixes: 97fe626ce64c ("coresight: etm3x: Allow etm3x to be built as a module") +Signed-off-by: Antonio Borneo +Signed-off-by: Suzuki K Poulose +Link: https://lore.kernel.org/r/20260108152427.357379-1-antonio.borneo@foss.st.com +Signed-off-by: Sasha Levin +--- + drivers/hwtracing/coresight/coresight-etm3x-core.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c +index a5e809589d3e3..0c011b7041696 100644 +--- a/drivers/hwtracing/coresight/coresight-etm3x-core.c ++++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c +@@ -795,16 +795,16 @@ static int __init etm_hp_setup(void) + { + int ret; + +- ret = cpuhp_setup_state_nocalls_cpuslocked(CPUHP_AP_ARM_CORESIGHT_STARTING, +- "arm/coresight:starting", +- etm_starting_cpu, etm_dying_cpu); ++ ret = cpuhp_setup_state_nocalls(CPUHP_AP_ARM_CORESIGHT_STARTING, ++ "arm/coresight:starting", ++ etm_starting_cpu, etm_dying_cpu); + + if (ret) + return ret; + +- ret = cpuhp_setup_state_nocalls_cpuslocked(CPUHP_AP_ONLINE_DYN, +- "arm/coresight:online", +- etm_online_cpu, NULL); ++ ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, ++ "arm/coresight:online", ++ etm_online_cpu, NULL); + + /* HP dyn state ID returned in ret on success */ + if (ret > 0) { +-- +2.51.0 + diff --git a/queue-6.19/coresight-tmc-etr-fix-race-condition-between-sysfs-a.patch b/queue-6.19/coresight-tmc-etr-fix-race-condition-between-sysfs-a.patch new file mode 100644 index 0000000000..22bc459e38 --- /dev/null +++ b/queue-6.19/coresight-tmc-etr-fix-race-condition-between-sysfs-a.patch @@ -0,0 +1,97 @@ +From 5a01cf06ae834ab92ff0fdb2f75f9d31583c06f0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 18:15:42 +0800 +Subject: coresight: tmc-etr: Fix race condition between sysfs and perf mode + +From: Yicong Yang + +[ Upstream commit e6e43e82c79c97917cbe356c07e8a6f3f982ab53 ] + +When trying to run perf and sysfs mode simultaneously, the WARN_ON() +in tmc_etr_enable_hw() is triggered sometimes: + + WARNING: CPU: 42 PID: 3911571 at drivers/hwtracing/coresight/coresight-tmc-etr.c:1060 tmc_etr_enable_hw+0xc0/0xd8 [coresight_tmc] + [..snip..] + Call trace: + tmc_etr_enable_hw+0xc0/0xd8 [coresight_tmc] (P) + tmc_enable_etr_sink+0x11c/0x250 [coresight_tmc] (L) + tmc_enable_etr_sink+0x11c/0x250 [coresight_tmc] + coresight_enable_path+0x1c8/0x218 [coresight] + coresight_enable_sysfs+0xa4/0x228 [coresight] + enable_source_store+0x58/0xa8 [coresight] + dev_attr_store+0x20/0x40 + sysfs_kf_write+0x4c/0x68 + kernfs_fop_write_iter+0x120/0x1b8 + vfs_write+0x2c8/0x388 + ksys_write+0x74/0x108 + __arm64_sys_write+0x24/0x38 + el0_svc_common.constprop.0+0x64/0x148 + do_el0_svc+0x24/0x38 + el0_svc+0x3c/0x130 + el0t_64_sync_handler+0xc8/0xd0 + el0t_64_sync+0x1ac/0x1b0 + ---[ end trace 0000000000000000 ]--- + +Since the enablement of sysfs mode is separeted into two critical regions, +one for sysfs buffer allocation and another for hardware enablement, it's +possible to race with the perf mode. Fix this by double check whether +the perf mode's been used before enabling the hardware in sysfs mode. + + mode: + [sysfs mode] [perf mode] + tmc_etr_get_sysfs_buffer() + spin_lock(&drvdata->spinlock) + [sysfs buffer allocation] + spin_unlock(&drvdata->spinlock) + spin_lock(&drvdata->spinlock) + tmc_etr_enable_hw() + drvdata->etr_buf = etr_perf->etr_buf + spin_unlock(&drvdata->spinlock) + spin_lock(&drvdata->spinlock) + tmc_etr_enable_hw() + WARN_ON(drvdata->etr_buf) // WARN sicne etr_buf initialized at + the perf side + spin_unlock(&drvdata->spinlock) + +With this fix, we retain the check for CS_MODE_PERF in get_etr_sysfs_buf. +This ensures we verify whether the perf mode's already running before we +actually allocate the buffer. Then we can save the time of +allocating/freeing the sysfs buffer if race with the perf mode. + +Fixes: 296b01fd106e ("coresight: Refactor out buffer allocation function for ETR") +Signed-off-by: Yicong Yang +Signed-off-by: Junhao He +Signed-off-by: Suzuki K Poulose +Link: https://lore.kernel.org/r/20260121101543.2017014-3-wangyushan12@huawei.com +Signed-off-by: Sasha Levin +--- + drivers/hwtracing/coresight/coresight-tmc-etr.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c +index e0d83ee01b77a..fc0a946053dde 100644 +--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c ++++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c +@@ -1306,6 +1306,19 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) + + raw_spin_lock_irqsave(&drvdata->spinlock, flags); + ++ /* ++ * Since the sysfs buffer allocation and the hardware enablement is not ++ * in the same critical region, it's possible to race with the perf. ++ */ ++ if (coresight_get_mode(csdev) == CS_MODE_PERF) { ++ drvdata->sysfs_buf = NULL; ++ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); ++ ++ /* Free allocated memory out side of the spinlock */ ++ tmc_etr_free_sysfs_buf(sysfs_buf); ++ return -EBUSY; ++ } ++ + /* + * In sysFS mode we can have multiple writers per sink. Since this + * sink is already enabled no memory is needed and the HW need not be +-- +2.51.0 + diff --git a/queue-6.19/cpufreq-intel_pstate-enable-asym-capacity-only-when-.patch b/queue-6.19/cpufreq-intel_pstate-enable-asym-capacity-only-when-.patch new file mode 100644 index 0000000000..11e92cb9a2 --- /dev/null +++ b/queue-6.19/cpufreq-intel_pstate-enable-asym-capacity-only-when-.patch @@ -0,0 +1,51 @@ +From 96c835ac247a055757ddd93c813fe9199bef6198 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 10:48:52 +0800 +Subject: cpufreq: intel_pstate: Enable asym capacity only when CPU SMT is not + possible + +From: Yaxiong Tian + +[ Upstream commit 1fedbb589448bee9f20bb2ed9c850d1d2cf9963c ] + +According to the description in the intel_pstate.rst documentation, +Capacity-Aware Scheduling and Energy-Aware Scheduling are only +supported on a hybrid processor without SMT. Previously, the system +used sched_smt_active() for judgment, which is not a strict condition +because users can switch it on or off via /sys at any time. + +This could lead to incorrect driver settings in certain scenarios. +For example, on a CPU that supports SMT, a user can disable SMT +via the nosmt parameter to enable asym capacity, and then re-enable +SMT via /sys. In such cases, some settings in the driver would no +longer be correct. + +To address this issue, replace sched_smt_active() with cpu_smt_possible(), +and only enable asym capacity when CPU SMT is not possible. + +Fixes: 929ebc93ccaa ("cpufreq: intel_pstate: Set asymmetric CPU capacity on hybrid systems") +Signed-off-by: Yaxiong Tian +[ rjw: Subject and changelog edits ] +Link: https://patch.msgid.link/20260203024852.301066-1-tianyaxiong@kylinos.cn +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/cpufreq/intel_pstate.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c +index ec4abe3745736..1625ec2d0d06a 100644 +--- a/drivers/cpufreq/intel_pstate.c ++++ b/drivers/cpufreq/intel_pstate.c +@@ -1161,7 +1161,7 @@ static void hybrid_init_cpu_capacity_scaling(bool refresh) + * the capacity of SMT threads is not deterministic even approximately, + * do not do that when SMT is in use. + */ +- if (hwp_is_hybrid && !sched_smt_active() && arch_enable_hybrid_capacity_scale()) { ++ if (hwp_is_hybrid && !cpu_smt_possible() && arch_enable_hybrid_capacity_scale()) { + hybrid_refresh_cpu_capacity_scaling(); + /* + * Disabling ITMT causes sched domains to be rebuilt to disable asym +-- +2.51.0 + diff --git a/queue-6.19/cpufreq-scmi-correct-scmi-explanation.patch b/queue-6.19/cpufreq-scmi-correct-scmi-explanation.patch new file mode 100644 index 0000000000..1b08246c2f --- /dev/null +++ b/queue-6.19/cpufreq-scmi-correct-scmi-explanation.patch @@ -0,0 +1,37 @@ +From a7baeb022942223236bd64365d5045e9c5608f2f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Jan 2026 22:33:30 +0300 +Subject: cpufreq: scmi: correct SCMI explanation + +From: Sergey Shtylyov + +[ Upstream commit 8c376f337a7e31c42949247e24eaad9a30d6c62c ] + +SCMI stands for System Control and Management Interface, not System Control +and Power Interface -- apparently, Sudeep Holla copied this line from his +SCPI driver and then just forgot to update the acronym explanation... :-) + +Fixes: 99d6bdf33877 ("cpufreq: add support for CPU DVFS based on SCMI message protocol") +Signed-off-by: Sergey Shtylyov +Reviewed-by: Sudeep Holla +Signed-off-by: Viresh Kumar +Signed-off-by: Sasha Levin +--- + drivers/cpufreq/scmi-cpufreq.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c +index d2a110079f5fd..e0e1756180b0c 100644 +--- a/drivers/cpufreq/scmi-cpufreq.c ++++ b/drivers/cpufreq/scmi-cpufreq.c +@@ -1,6 +1,6 @@ + // SPDX-License-Identifier: GPL-2.0 + /* +- * System Control and Power Interface (SCMI) based CPUFreq Interface driver ++ * System Control and Management Interface (SCMI) based CPUFreq Interface driver + * + * Copyright (C) 2018-2021 ARM Ltd. + * Sudeep Holla +-- +2.51.0 + diff --git a/queue-6.19/cpufreq-scmi-fix-device_node-reference-leak-in-scmi_.patch b/queue-6.19/cpufreq-scmi-fix-device_node-reference-leak-in-scmi_.patch new file mode 100644 index 0000000000..26876b8473 --- /dev/null +++ b/queue-6.19/cpufreq-scmi-fix-device_node-reference-leak-in-scmi_.patch @@ -0,0 +1,36 @@ +From b4403fa63e96207a0b4caf530e4028802575acbb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 23:32:06 +0800 +Subject: cpufreq: scmi: Fix device_node reference leak in scmi_cpu_domain_id() + +From: Felix Gu + +[ Upstream commit 0b7fbf9333fa4699a53145bad8ce74ea986caa13 ] + +When calling of_parse_phandle_with_args(), the caller is responsible +to call of_node_put() to release the reference of device node. +In scmi_cpu_domain_id(), it does not release the reference. + +Fixes: e336baa4193e ("cpufreq: scmi: Prepare to move OF parsing of domain-id to cpufreq") +Signed-off-by: Felix Gu +Signed-off-by: Viresh Kumar +Signed-off-by: Sasha Levin +--- + drivers/cpufreq/scmi-cpufreq.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c +index e0e1756180b0c..c7a3b038385b5 100644 +--- a/drivers/cpufreq/scmi-cpufreq.c ++++ b/drivers/cpufreq/scmi-cpufreq.c +@@ -101,6 +101,7 @@ static int scmi_cpu_domain_id(struct device *cpu_dev) + return -EINVAL; + } + ++ of_node_put(domain_id.np); + return domain_id.args[0]; + } + +-- +2.51.0 + diff --git a/queue-6.19/cpuidle-governors-menu-always-check-timers-with-tick.patch b/queue-6.19/cpuidle-governors-menu-always-check-timers-with-tick.patch new file mode 100644 index 0000000000..7ab3ded6e3 --- /dev/null +++ b/queue-6.19/cpuidle-governors-menu-always-check-timers-with-tick.patch @@ -0,0 +1,88 @@ +From 887e41ade345b369562527d186e434482e169bf8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 16:26:14 +0100 +Subject: cpuidle: governors: menu: Always check timers with tick stopped + +From: Rafael J. Wysocki + +[ Upstream commit 80606f4eb8d7484ab7f7d6f0fd30d71e6fbcf328 ] + +After commit 5484e31bbbff ("cpuidle: menu: Skip tick_nohz_get_sleep_length() +call in some cases"), if the return value of get_typical_interval() +multiplied by NSEC_PER_USEC is not greater than RESIDENCY_THRESHOLD_NS, +the menu governor will skip computing the time till the closest timer. +If that happens when the tick has been stopped already, the selected +idle state may be too deep due to the subsequent check comparing +predicted_ns with TICK_NSEC and causing its value to be replaced with +the expected time till the closest timer, which is KTIME_MAX in that +case. That will cause the deepest enabled idle state to be selected, +but the time till the closest timer very well may be shorter than the +target residency of that state, in which case a shallower state should +be used. + +Address this by making menu_select() always compute the time till the +closest timer when the tick has been stopped. + +Also move the predicted_ns check mentioned above into the branch in +which the time till the closest timer is determined because it only +needs to be done in that case. + +Fixes: 5484e31bbbff ("cpuidle: menu: Skip tick_nohz_get_sleep_length() call in some cases") +Signed-off-by: Rafael J. Wysocki +Reviewed-by: Christian Loehle +Link: https://patch.msgid.link/5959091.DvuYhMxLoT@rafael.j.wysocki +Signed-off-by: Sasha Levin +--- + drivers/cpuidle/governors/menu.c | 22 +++++++++++----------- + 1 file changed, 11 insertions(+), 11 deletions(-) + +diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c +index 64d6f7a1c7766..ca863ba03d454 100644 +--- a/drivers/cpuidle/governors/menu.c ++++ b/drivers/cpuidle/governors/menu.c +@@ -239,7 +239,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, + + /* Find the shortest expected idle interval. */ + predicted_ns = get_typical_interval(data) * NSEC_PER_USEC; +- if (predicted_ns > RESIDENCY_THRESHOLD_NS) { ++ if (predicted_ns > RESIDENCY_THRESHOLD_NS || tick_nohz_tick_stopped()) { + unsigned int timer_us; + + /* Determine the time till the closest timer. */ +@@ -259,6 +259,16 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, + RESOLUTION * DECAY * NSEC_PER_USEC); + /* Use the lowest expected idle interval to pick the idle state. */ + predicted_ns = min((u64)timer_us * NSEC_PER_USEC, predicted_ns); ++ /* ++ * If the tick is already stopped, the cost of possible short ++ * idle duration misprediction is much higher, because the CPU ++ * may be stuck in a shallow idle state for a long time as a ++ * result of it. In that case, say we might mispredict and use ++ * the known time till the closest timer event for the idle ++ * state selection. ++ */ ++ if (tick_nohz_tick_stopped() && predicted_ns < TICK_NSEC) ++ predicted_ns = data->next_timer_ns; + } else { + /* + * Because the next timer event is not going to be determined +@@ -284,16 +294,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, + return 0; + } + +- /* +- * If the tick is already stopped, the cost of possible short idle +- * duration misprediction is much higher, because the CPU may be stuck +- * in a shallow idle state for a long time as a result of it. In that +- * case, say we might mispredict and use the known time till the closest +- * timer event for the idle state selection. +- */ +- if (tick_nohz_tick_stopped() && predicted_ns < TICK_NSEC) +- predicted_ns = data->next_timer_ns; +- + /* + * Find the idle state with the lowest power while satisfying + * our constraints. +-- +2.51.0 + diff --git a/queue-6.19/crypto-caam-fix-netdev-memory-leak-in-dpaa2_caam_pro.patch b/queue-6.19/crypto-caam-fix-netdev-memory-leak-in-dpaa2_caam_pro.patch new file mode 100644 index 0000000000..2e7e88bbf3 --- /dev/null +++ b/queue-6.19/crypto-caam-fix-netdev-memory-leak-in-dpaa2_caam_pro.patch @@ -0,0 +1,145 @@ +From b7e78ce6ee6e1ed110f4c561da3fdfe954c2c037 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 09:55:24 +0800 +Subject: crypto: caam - fix netdev memory leak in dpaa2_caam_probe + +From: Jianpeng Chang + +[ Upstream commit 7d43252b3060b0ba4a192dce5dba85a3f39ffe39 ] + +When commit 0e1a4d427f58 ("crypto: caam: Unembed net_dev structure in +dpaa2") converted embedded net_device to dynamically allocated pointers, +it added cleanup in dpaa2_dpseci_disable() but missed adding cleanup in +dpaa2_dpseci_free() for error paths. + +This causes memory leaks when dpaa2_dpseci_dpio_setup() fails during probe +due to DPIO devices not being ready yet. The kernel's deferred probe +mechanism handles the retry successfully, but the netdevs allocated during +the failed probe attempt are never freed, resulting in kmemleak reports +showing multiple leaked netdev-related allocations all traced back to +dpaa2_caam_probe(). + +Fix this by preserving the CPU mask of allocated netdevs during setup and +using it for cleanup in dpaa2_dpseci_free(). This approach ensures that +only the CPUs that actually had netdevs allocated will be cleaned up, +avoiding potential issues with CPU hotplug scenarios. + +Fixes: 0e1a4d427f58 ("crypto: caam: Unembed net_dev structure in dpaa2") +Signed-off-by: Jianpeng Chang +Reviewed-by: Breno Leitao +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/caam/caamalg_qi2.c | 27 +++++++++++++++------------ + drivers/crypto/caam/caamalg_qi2.h | 2 ++ + 2 files changed, 17 insertions(+), 12 deletions(-) + +diff --git a/drivers/crypto/caam/caamalg_qi2.c b/drivers/crypto/caam/caamalg_qi2.c +index 107ccb2ade420..c6117c23eb25b 100644 +--- a/drivers/crypto/caam/caamalg_qi2.c ++++ b/drivers/crypto/caam/caamalg_qi2.c +@@ -4814,7 +4814,8 @@ static void dpaa2_dpseci_free(struct dpaa2_caam_priv *priv) + { + struct device *dev = priv->dev; + struct fsl_mc_device *ls_dev = to_fsl_mc_device(dev); +- int err; ++ struct dpaa2_caam_priv_per_cpu *ppriv; ++ int i, err; + + if (DPSECI_VER(priv->major_ver, priv->minor_ver) > DPSECI_VER(5, 3)) { + err = dpseci_reset(priv->mc_io, 0, ls_dev->mc_handle); +@@ -4822,6 +4823,12 @@ static void dpaa2_dpseci_free(struct dpaa2_caam_priv *priv) + dev_err(dev, "dpseci_reset() failed\n"); + } + ++ for_each_cpu(i, priv->clean_mask) { ++ ppriv = per_cpu_ptr(priv->ppriv, i); ++ free_netdev(ppriv->net_dev); ++ } ++ free_cpumask_var(priv->clean_mask); ++ + dpaa2_dpseci_congestion_free(priv); + dpseci_close(priv->mc_io, 0, ls_dev->mc_handle); + } +@@ -5007,16 +5014,15 @@ static int __cold dpaa2_dpseci_setup(struct fsl_mc_device *ls_dev) + struct device *dev = &ls_dev->dev; + struct dpaa2_caam_priv *priv; + struct dpaa2_caam_priv_per_cpu *ppriv; +- cpumask_var_t clean_mask; + int err, cpu; + u8 i; + + err = -ENOMEM; +- if (!zalloc_cpumask_var(&clean_mask, GFP_KERNEL)) +- goto err_cpumask; +- + priv = dev_get_drvdata(dev); + ++ if (!zalloc_cpumask_var(&priv->clean_mask, GFP_KERNEL)) ++ goto err_cpumask; ++ + priv->dev = dev; + priv->dpsec_id = ls_dev->obj_desc.id; + +@@ -5118,7 +5124,7 @@ static int __cold dpaa2_dpseci_setup(struct fsl_mc_device *ls_dev) + err = -ENOMEM; + goto err_alloc_netdev; + } +- cpumask_set_cpu(cpu, clean_mask); ++ cpumask_set_cpu(cpu, priv->clean_mask); + ppriv->net_dev->dev = *dev; + + netif_napi_add_tx_weight(ppriv->net_dev, &ppriv->napi, +@@ -5126,18 +5132,16 @@ static int __cold dpaa2_dpseci_setup(struct fsl_mc_device *ls_dev) + DPAA2_CAAM_NAPI_WEIGHT); + } + +- err = 0; +- goto free_cpumask; ++ return 0; + + err_alloc_netdev: +- free_dpaa2_pcpu_netdev(priv, clean_mask); ++ free_dpaa2_pcpu_netdev(priv, priv->clean_mask); + err_get_rx_queue: + dpaa2_dpseci_congestion_free(priv); + err_get_vers: + dpseci_close(priv->mc_io, 0, ls_dev->mc_handle); + err_open: +-free_cpumask: +- free_cpumask_var(clean_mask); ++ free_cpumask_var(priv->clean_mask); + err_cpumask: + return err; + } +@@ -5182,7 +5186,6 @@ static int __cold dpaa2_dpseci_disable(struct dpaa2_caam_priv *priv) + ppriv = per_cpu_ptr(priv->ppriv, i); + napi_disable(&ppriv->napi); + netif_napi_del(&ppriv->napi); +- free_netdev(ppriv->net_dev); + } + + return 0; +diff --git a/drivers/crypto/caam/caamalg_qi2.h b/drivers/crypto/caam/caamalg_qi2.h +index 61d1219a202fc..8e65b4b28c7ba 100644 +--- a/drivers/crypto/caam/caamalg_qi2.h ++++ b/drivers/crypto/caam/caamalg_qi2.h +@@ -42,6 +42,7 @@ + * @mc_io: pointer to MC portal's I/O object + * @domain: IOMMU domain + * @ppriv: per CPU pointers to privata data ++ * @clean_mask: CPU mask of CPUs that have allocated netdevs + */ + struct dpaa2_caam_priv { + int dpsec_id; +@@ -65,6 +66,7 @@ struct dpaa2_caam_priv { + + struct dpaa2_caam_priv_per_cpu __percpu *ppriv; + struct dentry *dfs_root; ++ cpumask_var_t clean_mask; + }; + + /** +-- +2.51.0 + diff --git a/queue-6.19/crypto-cavium-fix-dma_free_coherent-size.patch b/queue-6.19/crypto-cavium-fix-dma_free_coherent-size.patch new file mode 100644 index 0000000000..ea90279408 --- /dev/null +++ b/queue-6.19/crypto-cavium-fix-dma_free_coherent-size.patch @@ -0,0 +1,38 @@ +From 34fd1caab2572d79d7d61bfb14efacb858db4994 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 10:56:45 +0100 +Subject: crypto: cavium - fix dma_free_coherent() size + +From: Thomas Fourier + +[ Upstream commit 941676c30ba5b40a01bed92448f457ce62fd1f07 ] + +The size of the buffer in alloc_command_queues() is +curr->size + CPT_NEXT_CHUNK_PTR_SIZE, so used that length for +dma_free_coherent(). + +Fixes: c694b233295b ("crypto: cavium - Add the Virtual Function driver for CPT") +Signed-off-by: Thomas Fourier +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/cavium/cpt/cptvf_main.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/crypto/cavium/cpt/cptvf_main.c b/drivers/crypto/cavium/cpt/cptvf_main.c +index c246920e6f540..bccd680c7f7ee 100644 +--- a/drivers/crypto/cavium/cpt/cptvf_main.c ++++ b/drivers/crypto/cavium/cpt/cptvf_main.c +@@ -180,7 +180,8 @@ static void free_command_queues(struct cpt_vf *cptvf, + + hlist_for_each_entry_safe(chunk, node, &cqinfo->queue[i].chead, + nextchunk) { +- dma_free_coherent(&pdev->dev, chunk->size, ++ dma_free_coherent(&pdev->dev, ++ chunk->size + CPT_NEXT_CHUNK_PTR_SIZE, + chunk->head, + chunk->dma_addr); + chunk->head = NULL; +-- +2.51.0 + diff --git a/queue-6.19/crypto-ccp-add-an-s4-restore-flow.patch b/queue-6.19/crypto-ccp-add-an-s4-restore-flow.patch new file mode 100644 index 0000000000..368d066a0b --- /dev/null +++ b/queue-6.19/crypto-ccp-add-an-s4-restore-flow.patch @@ -0,0 +1,168 @@ +From 8e8ea763c8898eb1a42794c1399d9e40f5073efa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 22:11:30 -0600 +Subject: crypto: ccp - Add an S4 restore flow +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Mario Limonciello (AMD) + +[ Upstream commit 0ba2035026d0ab6c7c7e65ad8b418dc73d5700d9 ] + +The system will have lost power during S4. The ring used for TEE +communications needs to be initialized before use. + +Fixes: f892a21f51162 ("crypto: ccp - use generic power management") +Reported-by: Lars Francke +Closes: https://lore.kernel.org/platform-driver-x86/CAD-Ua_gfJnQSo8ucS_7ZwzuhoBRJ14zXP7s8b-zX3ZcxcyWePw@mail.gmail.com/ +Tested-by: Yijun Shen +Signed-off-by: Mario Limonciello (AMD) +Reviewed-by: Shyam Sundar S K +Reviewed-by: Tom Lendacky +Link: https://patch.msgid.link/20260116041132.153674-4-superm1@kernel.org +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/crypto/ccp/psp-dev.c | 11 +++++++++++ + drivers/crypto/ccp/sp-dev.c | 12 ++++++++++++ + drivers/crypto/ccp/sp-dev.h | 3 +++ + drivers/crypto/ccp/sp-pci.c | 16 +++++++++++++++- + drivers/crypto/ccp/tee-dev.c | 5 +++++ + drivers/crypto/ccp/tee-dev.h | 1 + + 6 files changed, 47 insertions(+), 1 deletion(-) + +diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c +index 9e21da0e298ad..5c7f7e02a7d8a 100644 +--- a/drivers/crypto/ccp/psp-dev.c ++++ b/drivers/crypto/ccp/psp-dev.c +@@ -351,6 +351,17 @@ struct psp_device *psp_get_master_device(void) + return sp ? sp->psp_data : NULL; + } + ++int psp_restore(struct sp_device *sp) ++{ ++ struct psp_device *psp = sp->psp_data; ++ int ret = 0; ++ ++ if (psp->tee_data) ++ ret = tee_restore(psp); ++ ++ return ret; ++} ++ + void psp_pci_init(void) + { + psp_master = psp_get_master_device(); +diff --git a/drivers/crypto/ccp/sp-dev.c b/drivers/crypto/ccp/sp-dev.c +index 3467f6db4f505..f204aa5df96e2 100644 +--- a/drivers/crypto/ccp/sp-dev.c ++++ b/drivers/crypto/ccp/sp-dev.c +@@ -230,6 +230,18 @@ int sp_resume(struct sp_device *sp) + return 0; + } + ++int sp_restore(struct sp_device *sp) ++{ ++ if (sp->psp_data) { ++ int ret = psp_restore(sp); ++ ++ if (ret) ++ return ret; ++ } ++ ++ return sp_resume(sp); ++} ++ + struct sp_device *sp_get_psp_master_device(void) + { + struct sp_device *i, *ret = NULL; +diff --git a/drivers/crypto/ccp/sp-dev.h b/drivers/crypto/ccp/sp-dev.h +index 1335a83fe052e..a83751cfd0060 100644 +--- a/drivers/crypto/ccp/sp-dev.h ++++ b/drivers/crypto/ccp/sp-dev.h +@@ -141,6 +141,7 @@ void sp_destroy(struct sp_device *sp); + + int sp_suspend(struct sp_device *sp); + int sp_resume(struct sp_device *sp); ++int sp_restore(struct sp_device *sp); + int sp_request_ccp_irq(struct sp_device *sp, irq_handler_t handler, + const char *name, void *data); + void sp_free_ccp_irq(struct sp_device *sp, void *data); +@@ -174,6 +175,7 @@ int psp_dev_init(struct sp_device *sp); + void psp_pci_init(void); + void psp_dev_destroy(struct sp_device *sp); + void psp_pci_exit(void); ++int psp_restore(struct sp_device *sp); + + #else /* !CONFIG_CRYPTO_DEV_SP_PSP */ + +@@ -181,6 +183,7 @@ static inline int psp_dev_init(struct sp_device *sp) { return 0; } + static inline void psp_pci_init(void) { } + static inline void psp_dev_destroy(struct sp_device *sp) { } + static inline void psp_pci_exit(void) { } ++static inline int psp_restore(struct sp_device *sp) { return 0; } + + #endif /* CONFIG_CRYPTO_DEV_SP_PSP */ + +diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c +index 8891ceee1d7d0..6ac805d99ccb3 100644 +--- a/drivers/crypto/ccp/sp-pci.c ++++ b/drivers/crypto/ccp/sp-pci.c +@@ -353,6 +353,13 @@ static int __maybe_unused sp_pci_resume(struct device *dev) + return sp_resume(sp); + } + ++static int __maybe_unused sp_pci_restore(struct device *dev) ++{ ++ struct sp_device *sp = dev_get_drvdata(dev); ++ ++ return sp_restore(sp); ++} ++ + #ifdef CONFIG_CRYPTO_DEV_SP_PSP + static const struct sev_vdata sevv1 = { + .cmdresp_reg = 0x10580, /* C2PMSG_32 */ +@@ -563,7 +570,14 @@ static const struct pci_device_id sp_pci_table[] = { + }; + MODULE_DEVICE_TABLE(pci, sp_pci_table); + +-static SIMPLE_DEV_PM_OPS(sp_pci_pm_ops, sp_pci_suspend, sp_pci_resume); ++static const struct dev_pm_ops sp_pci_pm_ops = { ++ .suspend = pm_sleep_ptr(sp_pci_suspend), ++ .resume = pm_sleep_ptr(sp_pci_resume), ++ .freeze = pm_sleep_ptr(sp_pci_suspend), ++ .thaw = pm_sleep_ptr(sp_pci_resume), ++ .poweroff = pm_sleep_ptr(sp_pci_suspend), ++ .restore_early = pm_sleep_ptr(sp_pci_restore), ++}; + + static struct pci_driver sp_pci_driver = { + .name = "ccp", +diff --git a/drivers/crypto/ccp/tee-dev.c b/drivers/crypto/ccp/tee-dev.c +index af881daa5855b..11c4b05e2f3a2 100644 +--- a/drivers/crypto/ccp/tee-dev.c ++++ b/drivers/crypto/ccp/tee-dev.c +@@ -366,3 +366,8 @@ int psp_check_tee_status(void) + return 0; + } + EXPORT_SYMBOL(psp_check_tee_status); ++ ++int tee_restore(struct psp_device *psp) ++{ ++ return tee_init_ring(psp->tee_data); ++} +diff --git a/drivers/crypto/ccp/tee-dev.h b/drivers/crypto/ccp/tee-dev.h +index ea9a2b7c05f57..c23416cb7bb37 100644 +--- a/drivers/crypto/ccp/tee-dev.h ++++ b/drivers/crypto/ccp/tee-dev.h +@@ -111,5 +111,6 @@ struct tee_ring_cmd { + + int tee_dev_init(struct psp_device *psp); + void tee_dev_destroy(struct psp_device *psp); ++int tee_restore(struct psp_device *psp); + + #endif /* __TEE_DEV_H__ */ +-- +2.51.0 + diff --git a/queue-6.19/crypto-ccp-declare-psp-dead-if-psp_cmd_tee_ring_init.patch b/queue-6.19/crypto-ccp-declare-psp-dead-if-psp_cmd_tee_ring_init.patch new file mode 100644 index 0000000000..bd80ff2e0e --- /dev/null +++ b/queue-6.19/crypto-ccp-declare-psp-dead-if-psp_cmd_tee_ring_init.patch @@ -0,0 +1,43 @@ +From d86b4aab90ada946a9a19f2b4170da190b9bccbf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 22:11:29 -0600 +Subject: crypto: ccp - Declare PSP dead if PSP_CMD_TEE_RING_INIT fails +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Mario Limonciello (AMD) + +[ Upstream commit 5e599d7871bf852e94e8aa08b99724635f2cbf96 ] + +tee_init_ring() only declares PSP dead if the command times out. +If there is any other failure it is still considered fatal though. +Set psp_dead for other failures as well. + +Fixes: 949a0c8dd3c2 ("crypto: ccp - Move direct access to some PSP registers out of TEE") +Tested-by: Yijun Shen +Signed-off-by: Mario Limonciello (AMD) +Acked-by: Tom Lendacky +Reviewed-by: Shyam Sundar S K +Link: https://patch.msgid.link/20260116041132.153674-3-superm1@kernel.org +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/crypto/ccp/tee-dev.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/crypto/ccp/tee-dev.c b/drivers/crypto/ccp/tee-dev.c +index 5e1d80724678d..af881daa5855b 100644 +--- a/drivers/crypto/ccp/tee-dev.c ++++ b/drivers/crypto/ccp/tee-dev.c +@@ -125,6 +125,7 @@ static int tee_init_ring(struct psp_tee_device *tee) + dev_err(tee->dev, "tee: ring init command failed (%#010lx)\n", + FIELD_GET(PSP_CMDRESP_STS, reg)); + tee_free_ring(tee); ++ psp_dead = true; + ret = -EIO; + } + +-- +2.51.0 + diff --git a/queue-6.19/crypto-ccp-factor-out-ring-destroy-handling-to-a-hel.patch b/queue-6.19/crypto-ccp-factor-out-ring-destroy-handling-to-a-hel.patch new file mode 100644 index 0000000000..a01bfa26e0 --- /dev/null +++ b/queue-6.19/crypto-ccp-factor-out-ring-destroy-handling-to-a-hel.patch @@ -0,0 +1,90 @@ +From c5d261ac33e1a978939591a4b6b676402810abf2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 22:11:31 -0600 +Subject: crypto: ccp - Factor out ring destroy handling to a helper +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Mario Limonciello (AMD) + +[ Upstream commit d95f87a65bce5f2f2a02ca6094ca4841d4073df3 ] + +The ring destroy command needs to be used in multiple places. Split +out the code to a helper. + +Tested-by: Yijun Shen +Signed-off-by: Mario Limonciello (AMD) +Acked-by: Tom Lendacky +Reviewed-by: Shyam Sundar S K +Link: https://patch.msgid.link/20260116041132.153674-5-superm1@kernel.org +Signed-off-by: Ilpo Järvinen +Stable-dep-of: 7b85137caf11 ("crypto: ccp - Send PSP_CMD_TEE_RING_DESTROY when PSP_CMD_TEE_RING_INIT fails") +Signed-off-by: Sasha Levin +--- + drivers/crypto/ccp/tee-dev.c | 36 ++++++++++++++++++++++++------------ + 1 file changed, 24 insertions(+), 12 deletions(-) + +diff --git a/drivers/crypto/ccp/tee-dev.c b/drivers/crypto/ccp/tee-dev.c +index 11c4b05e2f3a2..ef1430f86ad62 100644 +--- a/drivers/crypto/ccp/tee-dev.c ++++ b/drivers/crypto/ccp/tee-dev.c +@@ -86,6 +86,29 @@ static inline void tee_free_cmd_buffer(struct tee_init_ring_cmd *cmd) + kfree(cmd); + } + ++static bool tee_send_destroy_cmd(struct psp_tee_device *tee) ++{ ++ unsigned int reg; ++ int ret; ++ ++ ret = psp_mailbox_command(tee->psp, PSP_CMD_TEE_RING_DESTROY, NULL, ++ TEE_DEFAULT_CMD_TIMEOUT, ®); ++ if (ret) { ++ dev_err(tee->dev, "tee: ring destroy command timed out, disabling TEE support\n"); ++ psp_dead = true; ++ return false; ++ } ++ ++ if (FIELD_GET(PSP_CMDRESP_STS, reg)) { ++ dev_err(tee->dev, "tee: ring destroy command failed (%#010lx)\n", ++ FIELD_GET(PSP_CMDRESP_STS, reg)); ++ psp_dead = true; ++ return false; ++ } ++ ++ return true; ++} ++ + static int tee_init_ring(struct psp_tee_device *tee) + { + int ring_size = MAX_RING_BUFFER_ENTRIES * sizeof(struct tee_ring_cmd); +@@ -137,24 +160,13 @@ static int tee_init_ring(struct psp_tee_device *tee) + + static void tee_destroy_ring(struct psp_tee_device *tee) + { +- unsigned int reg; +- int ret; +- + if (!tee->rb_mgr.ring_start) + return; + + if (psp_dead) + goto free_ring; + +- ret = psp_mailbox_command(tee->psp, PSP_CMD_TEE_RING_DESTROY, NULL, +- TEE_DEFAULT_CMD_TIMEOUT, ®); +- if (ret) { +- dev_err(tee->dev, "tee: ring destroy command timed out, disabling TEE support\n"); +- psp_dead = true; +- } else if (FIELD_GET(PSP_CMDRESP_STS, reg)) { +- dev_err(tee->dev, "tee: ring destroy command failed (%#010lx)\n", +- FIELD_GET(PSP_CMDRESP_STS, reg)); +- } ++ tee_send_destroy_cmd(tee); + + free_ring: + tee_free_ring(tee); +-- +2.51.0 + diff --git a/queue-6.19/crypto-ccp-fix-a-case-where-snp_shutdown-is-missed.patch b/queue-6.19/crypto-ccp-fix-a-case-where-snp_shutdown-is-missed.patch new file mode 100644 index 0000000000..a57edfefd2 --- /dev/null +++ b/queue-6.19/crypto-ccp-fix-a-case-where-snp_shutdown-is-missed.patch @@ -0,0 +1,110 @@ +From 1851f637d242fedcec0c832b6ced88e1478f34f7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Jan 2026 10:22:17 -0700 +Subject: crypto: ccp - Fix a case where SNP_SHUTDOWN is missed + +From: Tom Lendacky + +[ Upstream commit 551120148b67e04527b405c5ec33a31593846ba4 ] + +If page reclaim fails in sev_ioctl_do_snp_platform_status() and SNP was +moved from UNINIT to INIT for the function, SNP is not moved back to +UNINIT state. Additionally, SNP is not required to be initialized in order +to execute the SNP_PLATFORM_STATUS command, so don't attempt to move to +INIT state and let SNP_PLATFORM_STATUS report the status as is. + +Fixes: ceac7fb89e8d ("crypto: ccp - Ensure implicit SEV/SNP init and shutdown in ioctls") +Signed-off-by: Tom Lendacky +Reviewed-by: Tycho Andersen (AMD) +Reviewed-by: Alexey Kardashevskiy +Signed-off-by: Tycho Andersen (AMD) +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/ccp/sev-dev.c | 46 ++++++++++++++++++------------------ + 1 file changed, 23 insertions(+), 23 deletions(-) + +diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c +index 956ea609d0cce..6e6011e363e3b 100644 +--- a/drivers/crypto/ccp/sev-dev.c ++++ b/drivers/crypto/ccp/sev-dev.c +@@ -2378,11 +2378,10 @@ static int sev_ioctl_do_pdh_export(struct sev_issue_cmd *argp, bool writable) + static int sev_ioctl_do_snp_platform_status(struct sev_issue_cmd *argp) + { + struct sev_device *sev = psp_master->sev_data; +- bool shutdown_required = false; + struct sev_data_snp_addr buf; + struct page *status_page; +- int ret, error; + void *data; ++ int ret; + + if (!argp->data) + return -EINVAL; +@@ -2393,31 +2392,35 @@ static int sev_ioctl_do_snp_platform_status(struct sev_issue_cmd *argp) + + data = page_address(status_page); + +- if (!sev->snp_initialized) { +- ret = snp_move_to_init_state(argp, &shutdown_required); +- if (ret) +- goto cleanup; +- } +- + /* +- * Firmware expects status page to be in firmware-owned state, otherwise +- * it will report firmware error code INVALID_PAGE_STATE (0x1A). ++ * SNP_PLATFORM_STATUS can be executed in any SNP state. But if executed ++ * when SNP has been initialized, the status page must be firmware-owned. + */ +- if (rmp_mark_pages_firmware(__pa(data), 1, true)) { +- ret = -EFAULT; +- goto cleanup; ++ if (sev->snp_initialized) { ++ /* ++ * Firmware expects the status page to be in Firmware state, ++ * otherwise it will report an error INVALID_PAGE_STATE. ++ */ ++ if (rmp_mark_pages_firmware(__pa(data), 1, true)) { ++ ret = -EFAULT; ++ goto cleanup; ++ } + } + + buf.address = __psp_pa(data); + ret = __sev_do_cmd_locked(SEV_CMD_SNP_PLATFORM_STATUS, &buf, &argp->error); + +- /* +- * Status page will be transitioned to Reclaim state upon success, or +- * left in Firmware state in failure. Use snp_reclaim_pages() to +- * transition either case back to Hypervisor-owned state. +- */ +- if (snp_reclaim_pages(__pa(data), 1, true)) +- return -EFAULT; ++ if (sev->snp_initialized) { ++ /* ++ * The status page will be in Reclaim state on success, or left ++ * in Firmware state on failure. Use snp_reclaim_pages() to ++ * transition either case back to Hypervisor-owned state. ++ */ ++ if (snp_reclaim_pages(__pa(data), 1, true)) { ++ snp_leak_pages(__page_to_pfn(status_page), 1); ++ return -EFAULT; ++ } ++ } + + if (ret) + goto cleanup; +@@ -2427,9 +2430,6 @@ static int sev_ioctl_do_snp_platform_status(struct sev_issue_cmd *argp) + ret = -EFAULT; + + cleanup: +- if (shutdown_required) +- __sev_snp_shutdown_locked(&error, false); +- + __free_pages(status_page, 0); + return ret; + } +-- +2.51.0 + diff --git a/queue-6.19/crypto-ccp-fix-a-crash-due-to-incorrect-cleanup-usag.patch b/queue-6.19/crypto-ccp-fix-a-crash-due-to-incorrect-cleanup-usag.patch new file mode 100644 index 0000000000..96e27e6ed2 --- /dev/null +++ b/queue-6.19/crypto-ccp-fix-a-crash-due-to-incorrect-cleanup-usag.patch @@ -0,0 +1,43 @@ +From 0881c75e8bb6561c8619314f87e7785ebe713ab1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 16:17:24 +0100 +Subject: crypto: ccp - Fix a crash due to incorrect cleanup usage of kfree + +From: Ella Ma + +[ Upstream commit d5abcc33ee76bc26d58b39dc1a097e43a99dd438 ] + +Annotating a local pointer variable, which will be assigned with the +kmalloc-family functions, with the `__cleanup(kfree)` attribute will +make the address of the local variable, rather than the address returned +by kmalloc, passed to kfree directly and lead to a crash due to invalid +deallocation of stack address. According to other places in the repo, +the correct usage should be `__free(kfree)`. The code coincidentally +compiled because the parameter type `void *` of kfree is compatible with +the desired type `struct { ... } **`. + +Fixes: a71475582ada ("crypto: ccp - reduce stack usage in ccp_run_aes_gcm_cmd") +Signed-off-by: Ella Ma +Acked-by: Tom Lendacky +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/ccp/ccp-ops.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/crypto/ccp/ccp-ops.c b/drivers/crypto/ccp/ccp-ops.c +index d78865d9d5f09..d0412e5847625 100644 +--- a/drivers/crypto/ccp/ccp-ops.c ++++ b/drivers/crypto/ccp/ccp-ops.c +@@ -642,7 +642,7 @@ ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) + struct ccp_data dst; + struct ccp_data aad; + struct ccp_op op; +- } *wa __cleanup(kfree) = kzalloc(sizeof *wa, GFP_KERNEL); ++ } *wa __free(kfree) = kzalloc(sizeof(*wa), GFP_KERNEL); + unsigned int dm_offset; + unsigned int authsize; + unsigned int jobid; +-- +2.51.0 + diff --git a/queue-6.19/crypto-ccp-narrow-scope-of-snp_range_list.patch b/queue-6.19/crypto-ccp-narrow-scope-of-snp_range_list.patch new file mode 100644 index 0000000000..171b417a48 --- /dev/null +++ b/queue-6.19/crypto-ccp-narrow-scope-of-snp_range_list.patch @@ -0,0 +1,64 @@ +From 025042c2827cbe774fda862363105d48c9d62c28 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Jan 2026 10:22:18 -0700 +Subject: crypto: ccp - narrow scope of snp_range_list + +From: Tycho Andersen (AMD) + +[ Upstream commit dc8ccab15081efc4f2c5a9fc7b209cd641d29177 ] + +snp_range_list is only used in __sev_snp_init_locked() in the SNP_INIT_EX +case, move the declaration there and add a __free() cleanup helper for it +instead of waiting until shutdown. + +Fixes: 1ca5614b84ee ("crypto: ccp: Add support to initialize the AMD-SP for SEV-SNP") +Reviewed-by: Alexey Kardashevskiy +Signed-off-by: Tycho Andersen (AMD) +Reviewed-by: Tom Lendacky +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/ccp/sev-dev.c | 13 +------------ + 1 file changed, 1 insertion(+), 12 deletions(-) + +diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c +index 6e6011e363e3b..1cdadddb744ed 100644 +--- a/drivers/crypto/ccp/sev-dev.c ++++ b/drivers/crypto/ccp/sev-dev.c +@@ -127,13 +127,6 @@ static size_t sev_es_tmr_size = SEV_TMR_SIZE; + #define NV_LENGTH (32 * 1024) + static void *sev_init_ex_buffer; + +-/* +- * SEV_DATA_RANGE_LIST: +- * Array containing range of pages that firmware transitions to HV-fixed +- * page state. +- */ +-static struct sev_data_range_list *snp_range_list; +- + static void __sev_firmware_shutdown(struct sev_device *sev, bool panic); + + static int snp_shutdown_on_panic(struct notifier_block *nb, +@@ -1361,6 +1354,7 @@ static int snp_filter_reserved_mem_regions(struct resource *rs, void *arg) + + static int __sev_snp_init_locked(int *error, unsigned int max_snp_asid) + { ++ struct sev_data_range_list *snp_range_list __free(kfree) = NULL; + struct psp_device *psp = psp_master; + struct sev_data_snp_init_ex data; + struct sev_device *sev; +@@ -2780,11 +2774,6 @@ static void __sev_firmware_shutdown(struct sev_device *sev, bool panic) + sev_init_ex_buffer = NULL; + } + +- if (snp_range_list) { +- kfree(snp_range_list); +- snp_range_list = NULL; +- } +- + __sev_snp_shutdown_locked(&error, panic); + } + +-- +2.51.0 + diff --git a/queue-6.19/crypto-ccp-send-psp_cmd_tee_ring_destroy-when-psp_cm.patch b/queue-6.19/crypto-ccp-send-psp_cmd_tee_ring_destroy-when-psp_cm.patch new file mode 100644 index 0000000000..65428bd57d --- /dev/null +++ b/queue-6.19/crypto-ccp-send-psp_cmd_tee_ring_destroy-when-psp_cm.patch @@ -0,0 +1,113 @@ +From 6dfbdc378a63708bbf4811713f23054ade926e05 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 22:11:32 -0600 +Subject: crypto: ccp - Send PSP_CMD_TEE_RING_DESTROY when + PSP_CMD_TEE_RING_INIT fails +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Mario Limonciello (AMD) + +[ Upstream commit 7b85137caf110a09a4a18f00f730de4709f9afc8 ] + +The hibernate resume sequence involves loading a resume kernel that is just +used for loading the hibernate image before shifting back to the existing +kernel. + +During that hibernate resume sequence the resume kernel may have loaded +the ccp driver. If this happens the resume kernel will also have called +PSP_CMD_TEE_RING_INIT but it will never have called +PSP_CMD_TEE_RING_DESTROY. + +This is problematic because the existing kernel needs to re-initialize the +ring. One could argue that the existing kernel should call destroy +as part of restore() but there is no guarantee that the resume kernel did +or didn't load the ccp driver. There is also no callback opportunity for +the resume kernel to destroy before handing back control to the existing +kernel. + +Similar problems could potentially exist with the use of kdump and +crash handling. I actually reproduced this issue like this: + +1) rmmod ccp +2) hibernate the system +3) resume the system +4) modprobe ccp + +The resume kernel will have loaded ccp but never destroyed and then when +I try to modprobe it fails. + +Because of these possible cases add a flow that checks the error code from +the PSP_CMD_TEE_RING_INIT call and tries to call PSP_CMD_TEE_RING_DESTROY +if it failed. If this succeeds then call PSP_CMD_TEE_RING_INIT again. + +Fixes: f892a21f51162 ("crypto: ccp - use generic power management") +Reported-by: Lars Francke +Closes: https://lore.kernel.org/platform-driver-x86/CAD-Ua_gfJnQSo8ucS_7ZwzuhoBRJ14zXP7s8b-zX3ZcxcyWePw@mail.gmail.com/ +Tested-by: Yijun Shen +Signed-off-by: Mario Limonciello (AMD) +Reviewed-by: Shyam Sundar S K +Acked-by: Tom Lendacky +Link: https://patch.msgid.link/20260116041132.153674-6-superm1@kernel.org +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/crypto/ccp/tee-dev.c | 14 ++++++++++++++ + include/linux/psp.h | 1 + + 2 files changed, 15 insertions(+) + +diff --git a/drivers/crypto/ccp/tee-dev.c b/drivers/crypto/ccp/tee-dev.c +index ef1430f86ad62..92ffa412622a2 100644 +--- a/drivers/crypto/ccp/tee-dev.c ++++ b/drivers/crypto/ccp/tee-dev.c +@@ -113,6 +113,7 @@ static int tee_init_ring(struct psp_tee_device *tee) + { + int ring_size = MAX_RING_BUFFER_ENTRIES * sizeof(struct tee_ring_cmd); + struct tee_init_ring_cmd *cmd; ++ bool retry = false; + unsigned int reg; + int ret; + +@@ -135,6 +136,7 @@ static int tee_init_ring(struct psp_tee_device *tee) + /* Send command buffer details to Trusted OS by writing to + * CPU-PSP message registers + */ ++retry_init: + ret = psp_mailbox_command(tee->psp, PSP_CMD_TEE_RING_INIT, cmd, + TEE_DEFAULT_CMD_TIMEOUT, ®); + if (ret) { +@@ -145,6 +147,18 @@ static int tee_init_ring(struct psp_tee_device *tee) + } + + if (FIELD_GET(PSP_CMDRESP_STS, reg)) { ++ /* ++ * During the hibernate resume sequence driver may have gotten loaded ++ * but the ring not properly destroyed. If the ring doesn't work, try ++ * to destroy and re-init once. ++ */ ++ if (!retry && FIELD_GET(PSP_CMDRESP_STS, reg) == PSP_TEE_STS_RING_BUSY) { ++ dev_info(tee->dev, "tee: ring init command failed with busy status, retrying\n"); ++ if (tee_send_destroy_cmd(tee)) { ++ retry = true; ++ goto retry_init; ++ } ++ } + dev_err(tee->dev, "tee: ring init command failed (%#010lx)\n", + FIELD_GET(PSP_CMDRESP_STS, reg)); + tee_free_ring(tee); +diff --git a/include/linux/psp.h b/include/linux/psp.h +index 92e60aeef21e1..b337dcce1e991 100644 +--- a/include/linux/psp.h ++++ b/include/linux/psp.h +@@ -18,6 +18,7 @@ + * and should include an appropriate local definition in their source file. + */ + #define PSP_CMDRESP_STS GENMASK(15, 0) ++#define PSP_TEE_STS_RING_BUSY 0x0000000d /* Ring already initialized */ + #define PSP_CMDRESP_CMD GENMASK(23, 16) + #define PSP_CMDRESP_RESERVED GENMASK(29, 24) + #define PSP_CMDRESP_RECOVERY BIT(30) +-- +2.51.0 + diff --git a/queue-6.19/crypto-hisilicon-consolidate-qp-creation-and-start-i.patch b/queue-6.19/crypto-hisilicon-consolidate-qp-creation-and-start-i.patch new file mode 100644 index 0000000000..9af512a011 --- /dev/null +++ b/queue-6.19/crypto-hisilicon-consolidate-qp-creation-and-start-i.patch @@ -0,0 +1,356 @@ +From b5b620563598f61ec453cba86e5c0dad70823d7c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 21:44:47 +0800 +Subject: crypto: hisilicon - consolidate qp creation and start in + hisi_qm_alloc_qps_node + +From: Chenghai Huang + +[ Upstream commit 72f3bbebff15e87171271d643ee2672fb8e92031 ] + +Consolidate the creation and start of qp into the function +hisi_qm_alloc_qps_node. This change eliminates the need for +each module to perform these steps in two separate phases +(creation and start). + +Signed-off-by: Chenghai Huang +Signed-off-by: Weili Qian +Signed-off-by: Herbert Xu +Stable-dep-of: 6aff4d977e2d ("crypto: hisilicon/hpre - support the hpre algorithm fallback") +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/hpre/hpre_crypto.c | 40 ++---------- + drivers/crypto/hisilicon/qm.c | 70 ++++++++++++++++----- + drivers/crypto/hisilicon/sec2/sec_crypto.c | 8 --- + drivers/crypto/hisilicon/zip/zip_crypto.c | 43 ++----------- + include/linux/hisi_acc_qm.h | 1 - + 5 files changed, 66 insertions(+), 96 deletions(-) + +diff --git a/drivers/crypto/hisilicon/hpre/hpre_crypto.c b/drivers/crypto/hisilicon/hpre/hpre_crypto.c +index 220022ae7afb6..f410e610eabaa 100644 +--- a/drivers/crypto/hisilicon/hpre/hpre_crypto.c ++++ b/drivers/crypto/hisilicon/hpre/hpre_crypto.c +@@ -156,27 +156,6 @@ static void hpre_dfx_add_req_time(struct hpre_asym_request *hpre_req) + ktime_get_ts64(&hpre_req->req_time); + } + +-static struct hisi_qp *hpre_get_qp_and_start(u8 type) +-{ +- struct hisi_qp *qp; +- int ret; +- +- qp = hpre_create_qp(type); +- if (!qp) { +- pr_err("Can not create hpre qp!\n"); +- return ERR_PTR(-ENODEV); +- } +- +- ret = hisi_qm_start_qp(qp, 0); +- if (ret < 0) { +- hisi_qm_free_qps(&qp, 1); +- pci_err(qp->qm->pdev, "Can not start qp!\n"); +- return ERR_PTR(-EINVAL); +- } +- +- return qp; +-} +- + static int hpre_get_data_dma_addr(struct hpre_asym_request *hpre_req, + struct scatterlist *data, unsigned int len, + int is_src, dma_addr_t *tmp) +@@ -316,9 +295,8 @@ static int hpre_alg_res_post_hf(struct hpre_ctx *ctx, struct hpre_sqe *sqe, + + static void hpre_ctx_clear(struct hpre_ctx *ctx, bool is_clear_all) + { +- if (is_clear_all) { ++ if (is_clear_all) + hisi_qm_free_qps(&ctx->qp, 1); +- } + + ctx->crt_g2_mode = false; + ctx->key_sz = 0; +@@ -403,11 +381,10 @@ static int hpre_ctx_init(struct hpre_ctx *ctx, u8 type) + struct hisi_qp *qp; + struct hpre *hpre; + +- qp = hpre_get_qp_and_start(type); +- if (IS_ERR(qp)) +- return PTR_ERR(qp); ++ qp = hpre_create_qp(type); ++ if (!qp) ++ return -ENODEV; + +- qp->qp_ctx = ctx; + qp->req_cb = hpre_alg_cb; + ctx->qp = qp; + ctx->dev = &qp->qm->pdev->dev; +@@ -597,9 +574,6 @@ static void hpre_dh_clear_ctx(struct hpre_ctx *ctx, bool is_clear_all) + struct device *dev = ctx->dev; + unsigned int sz = ctx->key_sz; + +- if (is_clear_all) +- hisi_qm_stop_qp(ctx->qp); +- + if (ctx->dh.g) { + dma_free_coherent(dev, sz, ctx->dh.g, ctx->dh.dma_g); + ctx->dh.g = NULL; +@@ -940,9 +914,6 @@ static void hpre_rsa_clear_ctx(struct hpre_ctx *ctx, bool is_clear_all) + unsigned int half_key_sz = ctx->key_sz >> 1; + struct device *dev = ctx->dev; + +- if (is_clear_all) +- hisi_qm_stop_qp(ctx->qp); +- + if (ctx->rsa.pubkey) { + dma_free_coherent(dev, ctx->key_sz << 1, + ctx->rsa.pubkey, ctx->rsa.dma_pubkey); +@@ -1112,9 +1083,6 @@ static void hpre_ecc_clear_ctx(struct hpre_ctx *ctx, bool is_clear_all) + unsigned int sz = ctx->key_sz; + unsigned int shift = sz << 1; + +- if (is_clear_all) +- hisi_qm_stop_qp(ctx->qp); +- + if (ctx->ecdh.p) { + /* ecdh: p->a->k->b */ + memzero_explicit(ctx->ecdh.p + shift, sz); +diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c +index 0f5e39884e4a3..b8e59f99f7007 100644 +--- a/drivers/crypto/hisilicon/qm.c ++++ b/drivers/crypto/hisilicon/qm.c +@@ -3553,6 +3553,14 @@ void hisi_qm_dev_err_uninit(struct hisi_qm *qm) + } + EXPORT_SYMBOL_GPL(hisi_qm_dev_err_uninit); + ++static void qm_release_qp_nolock(struct hisi_qp *qp) ++{ ++ struct hisi_qm *qm = qp->qm; ++ ++ qm->qp_in_used--; ++ idr_remove(&qm->qp_idr, qp->qp_id); ++} ++ + /** + * hisi_qm_free_qps() - free multiple queue pairs. + * @qps: The queue pairs need to be freed. +@@ -3565,8 +3573,15 @@ void hisi_qm_free_qps(struct hisi_qp **qps, int qp_num) + if (!qps || qp_num <= 0) + return; + +- for (i = qp_num - 1; i >= 0; i--) +- hisi_qm_release_qp(qps[i]); ++ down_write(&qps[0]->qm->qps_lock); ++ ++ for (i = qp_num - 1; i >= 0; i--) { ++ qm_stop_qp_nolock(qps[i]); ++ qm_release_qp_nolock(qps[i]); ++ } ++ ++ up_write(&qps[0]->qm->qps_lock); ++ qm_pm_put_sync(qps[0]->qm); + } + EXPORT_SYMBOL_GPL(hisi_qm_free_qps); + +@@ -3580,6 +3595,43 @@ static void free_list(struct list_head *head) + } + } + ++static int qm_get_and_start_qp(struct hisi_qm *qm, int qp_num, struct hisi_qp **qps, u8 *alg_type) ++{ ++ int i, ret; ++ ++ ret = qm_pm_get_sync(qm); ++ if (ret) ++ return ret; ++ ++ down_write(&qm->qps_lock); ++ for (i = 0; i < qp_num; i++) { ++ qps[i] = qm_create_qp_nolock(qm, alg_type[i]); ++ if (IS_ERR(qps[i])) { ++ ret = -ENODEV; ++ goto stop_and_free; ++ } ++ ++ ret = qm_start_qp_nolock(qps[i], 0); ++ if (ret) { ++ qm_release_qp_nolock(qps[i]); ++ goto stop_and_free; ++ } ++ } ++ up_write(&qm->qps_lock); ++ ++ return 0; ++ ++stop_and_free: ++ for (i--; i >= 0; i--) { ++ qm_stop_qp_nolock(qps[i]); ++ qm_release_qp_nolock(qps[i]); ++ } ++ up_write(&qm->qps_lock); ++ qm_pm_put_sync(qm); ++ ++ return ret; ++} ++ + static int hisi_qm_sort_devices(int node, struct list_head *head, + struct hisi_qm_list *qm_list) + { +@@ -3633,7 +3685,6 @@ int hisi_qm_alloc_qps_node(struct hisi_qm_list *qm_list, int qp_num, + struct hisi_qm_resource *tmp; + int ret = -ENODEV; + LIST_HEAD(head); +- int i; + + if (!qps || !qm_list || qp_num <= 0) + return -EINVAL; +@@ -3645,18 +3696,9 @@ int hisi_qm_alloc_qps_node(struct hisi_qm_list *qm_list, int qp_num, + } + + list_for_each_entry(tmp, &head, list) { +- for (i = 0; i < qp_num; i++) { +- qps[i] = hisi_qm_create_qp(tmp->qm, alg_type[i]); +- if (IS_ERR(qps[i])) { +- hisi_qm_free_qps(qps, i); +- break; +- } +- } +- +- if (i == qp_num) { +- ret = 0; ++ ret = qm_get_and_start_qp(tmp->qm, qp_num, qps, alg_type); ++ if (!ret) + break; +- } + } + + mutex_unlock(&qm_list->lock); +diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.c b/drivers/crypto/hisilicon/sec2/sec_crypto.c +index 364bd69c60883..d09d081f42dc7 100644 +--- a/drivers/crypto/hisilicon/sec2/sec_crypto.c ++++ b/drivers/crypto/hisilicon/sec2/sec_crypto.c +@@ -626,7 +626,6 @@ static int sec_create_qp_ctx(struct sec_ctx *ctx, int qp_ctx_id) + + qp_ctx = &ctx->qp_ctx[qp_ctx_id]; + qp = ctx->qps[qp_ctx_id]; +- qp->qp_ctx = qp_ctx; + qp_ctx->qp = qp; + qp_ctx->ctx = ctx; + +@@ -644,14 +643,8 @@ static int sec_create_qp_ctx(struct sec_ctx *ctx, int qp_ctx_id) + if (ret) + goto err_destroy_idr; + +- ret = hisi_qm_start_qp(qp, 0); +- if (ret < 0) +- goto err_resource_free; +- + return 0; + +-err_resource_free: +- sec_free_qp_ctx_resource(ctx, qp_ctx); + err_destroy_idr: + idr_destroy(&qp_ctx->req_idr); + return ret; +@@ -660,7 +653,6 @@ static int sec_create_qp_ctx(struct sec_ctx *ctx, int qp_ctx_id) + static void sec_release_qp_ctx(struct sec_ctx *ctx, + struct sec_qp_ctx *qp_ctx) + { +- hisi_qm_stop_qp(qp_ctx->qp); + sec_free_qp_ctx_resource(ctx, qp_ctx); + idr_destroy(&qp_ctx->req_idr); + } +diff --git a/drivers/crypto/hisilicon/zip/zip_crypto.c b/drivers/crypto/hisilicon/zip/zip_crypto.c +index 5fc2ed9d5eef3..e140d4f8afe0e 100644 +--- a/drivers/crypto/hisilicon/zip/zip_crypto.c ++++ b/drivers/crypto/hisilicon/zip/zip_crypto.c +@@ -381,32 +381,6 @@ static int hisi_zip_adecompress(struct acomp_req *acomp_req) + return ret; + } + +-static int hisi_zip_start_qp(struct hisi_qp *qp, struct hisi_zip_qp_ctx *qp_ctx, +- int alg_type, int req_type) +-{ +- struct device *dev = &qp->qm->pdev->dev; +- int ret; +- +- qp->alg_type = alg_type; +- qp->qp_ctx = qp_ctx; +- +- ret = hisi_qm_start_qp(qp, 0); +- if (ret < 0) { +- dev_err(dev, "failed to start qp (%d)!\n", ret); +- return ret; +- } +- +- qp_ctx->qp = qp; +- +- return 0; +-} +- +-static void hisi_zip_release_qp(struct hisi_zip_qp_ctx *qp_ctx) +-{ +- hisi_qm_stop_qp(qp_ctx->qp); +- hisi_qm_free_qps(&qp_ctx->qp, 1); +-} +- + static const struct hisi_zip_sqe_ops hisi_zip_ops = { + .sqe_type = 0x3, + .fill_addr = hisi_zip_fill_addr, +@@ -425,7 +399,7 @@ static int hisi_zip_ctx_init(struct hisi_zip_ctx *hisi_zip_ctx, u8 req_type, int + struct hisi_zip_qp_ctx *qp_ctx; + u8 alg_type[HZIP_CTX_Q_NUM]; + struct hisi_zip *hisi_zip; +- int ret, i, j; ++ int ret, i; + + /* alg_type = 0 for compress, 1 for decompress in hw sqe */ + for (i = 0; i < HZIP_CTX_Q_NUM; i++) +@@ -442,17 +416,9 @@ static int hisi_zip_ctx_init(struct hisi_zip_ctx *hisi_zip_ctx, u8 req_type, int + for (i = 0; i < HZIP_CTX_Q_NUM; i++) { + qp_ctx = &hisi_zip_ctx->qp_ctx[i]; + qp_ctx->ctx = hisi_zip_ctx; +- ret = hisi_zip_start_qp(qps[i], qp_ctx, i, req_type); +- if (ret) { +- for (j = i - 1; j >= 0; j--) +- hisi_qm_stop_qp(hisi_zip_ctx->qp_ctx[j].qp); +- +- hisi_qm_free_qps(qps, HZIP_CTX_Q_NUM); +- return ret; +- } +- + qp_ctx->zip_dev = hisi_zip; + qp_ctx->req_type = req_type; ++ qp_ctx->qp = qps[i]; + } + + hisi_zip_ctx->ops = &hisi_zip_ops; +@@ -462,10 +428,13 @@ static int hisi_zip_ctx_init(struct hisi_zip_ctx *hisi_zip_ctx, u8 req_type, int + + static void hisi_zip_ctx_exit(struct hisi_zip_ctx *hisi_zip_ctx) + { ++ struct hisi_qp *qps[HZIP_CTX_Q_NUM] = { NULL }; + int i; + + for (i = 0; i < HZIP_CTX_Q_NUM; i++) +- hisi_zip_release_qp(&hisi_zip_ctx->qp_ctx[i]); ++ qps[i] = hisi_zip_ctx->qp_ctx[i].qp; ++ ++ hisi_qm_free_qps(qps, HZIP_CTX_Q_NUM); + } + + static int hisi_zip_create_req_q(struct hisi_zip_ctx *ctx) +diff --git a/include/linux/hisi_acc_qm.h b/include/linux/hisi_acc_qm.h +index ef4d3a79bcb70..59f9858049586 100644 +--- a/include/linux/hisi_acc_qm.h ++++ b/include/linux/hisi_acc_qm.h +@@ -466,7 +466,6 @@ struct hisi_qp { + + struct hisi_qp_status qp_status; + struct hisi_qp_ops *hw_ops; +- void *qp_ctx; + void (*req_cb)(struct hisi_qp *qp, void *data); + void (*event_cb)(struct hisi_qp *qp); + +-- +2.51.0 + diff --git a/queue-6.19/crypto-hisilicon-hpre-extend-tag-field-to-64-bits-fo.patch b/queue-6.19/crypto-hisilicon-hpre-extend-tag-field-to-64-bits-fo.patch new file mode 100644 index 0000000000..c835d9997d --- /dev/null +++ b/queue-6.19/crypto-hisilicon-hpre-extend-tag-field-to-64-bits-fo.patch @@ -0,0 +1,340 @@ +From 6849f4206efaa0fa4649f4f5a2d155185c734cfc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 21:44:44 +0800 +Subject: crypto: hisilicon/hpre: extend tag field to 64 bits for better + performance + +From: lizhi + +[ Upstream commit 3a1984758197f7fd4c557dd98090e8e0cf9f498e ] + +This commit expands the tag field in hpre_sqe structure from 16-bit +to 64-bit. The change enables storing request addresses directly +in the tag field, allowing callback functions to access request messages +without the previous indirection mechanism. + +By eliminating the need for lookup tables, this modification reduces lock +contention and associated overhead, leading to improved efficiency and +simplified code. + +Fixes: c8b4b477079d ("crypto: hisilicon - add HiSilicon HPRE accelerator") +Signed-off-by: lizhi +Signed-off-by: Weili Qian +Signed-off-by: Chenghai Huang +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/hpre/hpre.h | 5 +- + drivers/crypto/hisilicon/hpre/hpre_crypto.c | 142 ++++---------------- + 2 files changed, 25 insertions(+), 122 deletions(-) + +diff --git a/drivers/crypto/hisilicon/hpre/hpre.h b/drivers/crypto/hisilicon/hpre/hpre.h +index 0f3ddbadbcf99..021dbd9a1d48f 100644 +--- a/drivers/crypto/hisilicon/hpre/hpre.h ++++ b/drivers/crypto/hisilicon/hpre/hpre.h +@@ -94,9 +94,8 @@ struct hpre_sqe { + __le64 key; + __le64 in; + __le64 out; +- __le16 tag; +- __le16 resv2; +-#define _HPRE_SQE_ALIGN_EXT 7 ++ __le64 tag; ++#define _HPRE_SQE_ALIGN_EXT 6 + __le32 rsvd1[_HPRE_SQE_ALIGN_EXT]; + }; + +diff --git a/drivers/crypto/hisilicon/hpre/hpre_crypto.c b/drivers/crypto/hisilicon/hpre/hpre_crypto.c +index 21ccf879f70c5..4197281c8dff5 100644 +--- a/drivers/crypto/hisilicon/hpre/hpre_crypto.c ++++ b/drivers/crypto/hisilicon/hpre/hpre_crypto.c +@@ -108,12 +108,10 @@ struct hpre_ecdh_ctx { + struct hpre_ctx { + struct hisi_qp *qp; + struct device *dev; +- struct hpre_asym_request **req_list; + struct hpre *hpre; + spinlock_t req_lock; + unsigned int key_sz; + bool crt_g2_mode; +- struct idr req_idr; + union { + struct hpre_rsa_ctx rsa; + struct hpre_dh_ctx dh; +@@ -136,7 +134,6 @@ struct hpre_asym_request { + struct kpp_request *ecdh; + } areq; + int err; +- int req_id; + hpre_cb cb; + struct timespec64 req_time; + }; +@@ -151,58 +148,13 @@ static inline unsigned int hpre_align_pd(void) + return (hpre_align_sz() - 1) & ~(crypto_tfm_ctx_alignment() - 1); + } + +-static int hpre_alloc_req_id(struct hpre_ctx *ctx) ++static void hpre_dfx_add_req_time(struct hpre_asym_request *hpre_req) + { +- unsigned long flags; +- int id; +- +- spin_lock_irqsave(&ctx->req_lock, flags); +- id = idr_alloc(&ctx->req_idr, NULL, 0, ctx->qp->sq_depth, GFP_ATOMIC); +- spin_unlock_irqrestore(&ctx->req_lock, flags); +- +- return id; +-} +- +-static void hpre_free_req_id(struct hpre_ctx *ctx, int req_id) +-{ +- unsigned long flags; +- +- spin_lock_irqsave(&ctx->req_lock, flags); +- idr_remove(&ctx->req_idr, req_id); +- spin_unlock_irqrestore(&ctx->req_lock, flags); +-} +- +-static int hpre_add_req_to_ctx(struct hpre_asym_request *hpre_req) +-{ +- struct hpre_ctx *ctx; +- struct hpre_dfx *dfx; +- int id; +- +- ctx = hpre_req->ctx; +- id = hpre_alloc_req_id(ctx); +- if (unlikely(id < 0)) +- return -EINVAL; +- +- ctx->req_list[id] = hpre_req; +- hpre_req->req_id = id; ++ struct hpre_ctx *ctx = hpre_req->ctx; ++ struct hpre_dfx *dfx = ctx->hpre->debug.dfx; + +- dfx = ctx->hpre->debug.dfx; + if (atomic64_read(&dfx[HPRE_OVERTIME_THRHLD].value)) + ktime_get_ts64(&hpre_req->req_time); +- +- return id; +-} +- +-static void hpre_rm_req_from_ctx(struct hpre_asym_request *hpre_req) +-{ +- struct hpre_ctx *ctx = hpre_req->ctx; +- int id = hpre_req->req_id; +- +- if (hpre_req->req_id >= 0) { +- hpre_req->req_id = HPRE_INVLD_REQ_ID; +- ctx->req_list[id] = NULL; +- hpre_free_req_id(ctx, id); +- } + } + + static struct hisi_qp *hpre_get_qp_and_start(u8 type) +@@ -340,26 +292,19 @@ static void hpre_hw_data_clr_all(struct hpre_ctx *ctx, + static int hpre_alg_res_post_hf(struct hpre_ctx *ctx, struct hpre_sqe *sqe, + void **kreq) + { +- struct hpre_asym_request *req; + unsigned int err, done, alg; +- int id; + + #define HPRE_NO_HW_ERR 0 + #define HPRE_HW_TASK_DONE 3 + #define HREE_HW_ERR_MASK GENMASK(10, 0) + #define HREE_SQE_DONE_MASK GENMASK(1, 0) + #define HREE_ALG_TYPE_MASK GENMASK(4, 0) +- id = (int)le16_to_cpu(sqe->tag); +- req = ctx->req_list[id]; +- hpre_rm_req_from_ctx(req); +- *kreq = req; ++ *kreq = (void *)le64_to_cpu(sqe->tag); + + err = (le32_to_cpu(sqe->dw0) >> HPRE_SQE_ALG_BITS) & + HREE_HW_ERR_MASK; +- + done = (le32_to_cpu(sqe->dw0) >> HPRE_SQE_DONE_SHIFT) & + HREE_SQE_DONE_MASK; +- + if (likely(err == HPRE_NO_HW_ERR && done == HPRE_HW_TASK_DONE)) + return 0; + +@@ -370,34 +315,9 @@ static int hpre_alg_res_post_hf(struct hpre_ctx *ctx, struct hpre_sqe *sqe, + return -EINVAL; + } + +-static int hpre_ctx_set(struct hpre_ctx *ctx, struct hisi_qp *qp, int qlen) +-{ +- struct hpre *hpre; +- +- if (!ctx || !qp || qlen < 0) +- return -EINVAL; +- +- spin_lock_init(&ctx->req_lock); +- ctx->qp = qp; +- ctx->dev = &qp->qm->pdev->dev; +- +- hpre = container_of(ctx->qp->qm, struct hpre, qm); +- ctx->hpre = hpre; +- ctx->req_list = kcalloc(qlen, sizeof(void *), GFP_KERNEL); +- if (!ctx->req_list) +- return -ENOMEM; +- ctx->key_sz = 0; +- ctx->crt_g2_mode = false; +- idr_init(&ctx->req_idr); +- +- return 0; +-} +- + static void hpre_ctx_clear(struct hpre_ctx *ctx, bool is_clear_all) + { + if (is_clear_all) { +- idr_destroy(&ctx->req_idr); +- kfree(ctx->req_list); + hisi_qm_free_qps(&ctx->qp, 1); + } + +@@ -467,29 +387,22 @@ static void hpre_rsa_cb(struct hpre_ctx *ctx, void *resp) + + static void hpre_alg_cb(struct hisi_qp *qp, void *resp) + { +- struct hpre_ctx *ctx = qp->qp_ctx; +- struct hpre_dfx *dfx = ctx->hpre->debug.dfx; ++ struct hpre_asym_request *h_req; + struct hpre_sqe *sqe = resp; +- struct hpre_asym_request *req = ctx->req_list[le16_to_cpu(sqe->tag)]; + +- if (unlikely(!req)) { +- atomic64_inc(&dfx[HPRE_INVALID_REQ_CNT].value); ++ h_req = (struct hpre_asym_request *)le64_to_cpu(sqe->tag); ++ if (unlikely(!h_req)) { ++ pr_err("Failed to get request, and qp_id is %u\n", qp->qp_id); + return; + } + +- req->cb(ctx, resp); +-} +- +-static void hpre_stop_qp_and_put(struct hisi_qp *qp) +-{ +- hisi_qm_stop_qp(qp); +- hisi_qm_free_qps(&qp, 1); ++ h_req->cb(h_req->ctx, resp); + } + + static int hpre_ctx_init(struct hpre_ctx *ctx, u8 type) + { + struct hisi_qp *qp; +- int ret; ++ struct hpre *hpre; + + qp = hpre_get_qp_and_start(type); + if (IS_ERR(qp)) +@@ -497,19 +410,21 @@ static int hpre_ctx_init(struct hpre_ctx *ctx, u8 type) + + qp->qp_ctx = ctx; + qp->req_cb = hpre_alg_cb; ++ spin_lock_init(&ctx->req_lock); ++ ctx->qp = qp; ++ ctx->dev = &qp->qm->pdev->dev; ++ hpre = container_of(ctx->qp->qm, struct hpre, qm); ++ ctx->hpre = hpre; ++ ctx->key_sz = 0; ++ ctx->crt_g2_mode = false; + +- ret = hpre_ctx_set(ctx, qp, qp->sq_depth); +- if (ret) +- hpre_stop_qp_and_put(qp); +- +- return ret; ++ return 0; + } + + static int hpre_msg_request_set(struct hpre_ctx *ctx, void *req, bool is_rsa) + { + struct hpre_asym_request *h_req; + struct hpre_sqe *msg; +- int req_id; + void *tmp; + + if (is_rsa) { +@@ -549,11 +464,8 @@ static int hpre_msg_request_set(struct hpre_ctx *ctx, void *req, bool is_rsa) + msg->task_len1 = (ctx->key_sz >> HPRE_BITS_2_BYTES_SHIFT) - 1; + h_req->ctx = ctx; + +- req_id = hpre_add_req_to_ctx(h_req); +- if (req_id < 0) +- return -EBUSY; +- +- msg->tag = cpu_to_le16((u16)req_id); ++ hpre_dfx_add_req_time(h_req); ++ msg->tag = cpu_to_le64((uintptr_t)h_req); + + return 0; + } +@@ -619,7 +531,6 @@ static int hpre_dh_compute_value(struct kpp_request *req) + return -EINPROGRESS; + + clear_all: +- hpre_rm_req_from_ctx(hpre_req); + hpre_hw_data_clr_all(ctx, hpre_req, req->dst, req->src); + + return ret; +@@ -828,7 +739,6 @@ static int hpre_rsa_enc(struct akcipher_request *req) + return -EINPROGRESS; + + clear_all: +- hpre_rm_req_from_ctx(hpre_req); + hpre_hw_data_clr_all(ctx, hpre_req, req->dst, req->src); + + return ret; +@@ -883,7 +793,6 @@ static int hpre_rsa_dec(struct akcipher_request *req) + return -EINPROGRESS; + + clear_all: +- hpre_rm_req_from_ctx(hpre_req); + hpre_hw_data_clr_all(ctx, hpre_req, req->dst, req->src); + + return ret; +@@ -1346,7 +1255,7 @@ static int hpre_ecdh_set_param(struct hpre_ctx *ctx, struct ecdh *params) + return 0; + } + +-static bool hpre_key_is_zero(char *key, unsigned short key_sz) ++static bool hpre_key_is_zero(const char *key, unsigned short key_sz) + { + int i; + +@@ -1488,7 +1397,6 @@ static int hpre_ecdh_msg_request_set(struct hpre_ctx *ctx, + { + struct hpre_asym_request *h_req; + struct hpre_sqe *msg; +- int req_id; + void *tmp; + + if (req->dst_len < ctx->key_sz << 1) { +@@ -1510,11 +1418,8 @@ static int hpre_ecdh_msg_request_set(struct hpre_ctx *ctx, + msg->task_len1 = (ctx->key_sz >> HPRE_BITS_2_BYTES_SHIFT) - 1; + h_req->ctx = ctx; + +- req_id = hpre_add_req_to_ctx(h_req); +- if (req_id < 0) +- return -EBUSY; +- +- msg->tag = cpu_to_le16((u16)req_id); ++ hpre_dfx_add_req_time(h_req); ++ msg->tag = cpu_to_le64((uintptr_t)h_req); + return 0; + } + +@@ -1612,7 +1517,6 @@ static int hpre_ecdh_compute_value(struct kpp_request *req) + return -EINPROGRESS; + + clear_all: +- hpre_rm_req_from_ctx(hpre_req); + hpre_ecdh_hw_data_clr_all(ctx, hpre_req, req->dst, req->src); + return ret; + } +-- +2.51.0 + diff --git a/queue-6.19/crypto-hisilicon-hpre-support-the-hpre-algorithm-fal.patch b/queue-6.19/crypto-hisilicon-hpre-support-the-hpre-algorithm-fal.patch new file mode 100644 index 0000000000..fa3cb402a0 --- /dev/null +++ b/queue-6.19/crypto-hisilicon-hpre-support-the-hpre-algorithm-fal.patch @@ -0,0 +1,527 @@ +From c55cdc70dbcc1989a65d3472e74ceba107d4b64b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 21:44:51 +0800 +Subject: crypto: hisilicon/hpre - support the hpre algorithm fallback + +From: Weili Qian + +[ Upstream commit 6aff4d977e2d582c5d6ff6afd5646c1a459490fa ] + +When all hardware queues are busy and no shareable queue, +new processes fail to apply for queues. To avoid affecting +tasks, support fallback mechanism when hardware queues are +unavailable. + +HPRE driver supports DH algorithm, limited to prime numbers up to 4K. +It supports prime numbers larger than 4K via fallback mechanism. + +Fixes: 05e7b906aa7c ("crypto: hisilicon/hpre - add 'ECDH' algorithm") +Signed-off-by: Weili Qian +Signed-off-by: Chenghai Huang +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/hpre/hpre_crypto.c | 238 ++++++++++++++++---- + 1 file changed, 199 insertions(+), 39 deletions(-) + +diff --git a/drivers/crypto/hisilicon/hpre/hpre_crypto.c b/drivers/crypto/hisilicon/hpre/hpre_crypto.c +index f410e610eabaa..839c1f6771436 100644 +--- a/drivers/crypto/hisilicon/hpre/hpre_crypto.c ++++ b/drivers/crypto/hisilicon/hpre/hpre_crypto.c +@@ -93,6 +93,7 @@ struct hpre_dh_ctx { + + char *g; /* m */ + dma_addr_t dma_g; ++ struct crypto_kpp *soft_tfm; + }; + + struct hpre_ecdh_ctx { +@@ -103,6 +104,7 @@ struct hpre_ecdh_ctx { + /* low address: x->y */ + unsigned char *g; + dma_addr_t dma_g; ++ struct crypto_kpp *soft_tfm; + }; + + struct hpre_ctx { +@@ -120,6 +122,7 @@ struct hpre_ctx { + unsigned int curve_id; + /* for high performance core */ + u8 enable_hpcore; ++ bool fallback; + }; + + struct hpre_asym_request { +@@ -382,8 +385,10 @@ static int hpre_ctx_init(struct hpre_ctx *ctx, u8 type) + struct hpre *hpre; + + qp = hpre_create_qp(type); +- if (!qp) ++ if (!qp) { ++ ctx->qp = NULL; + return -ENODEV; ++ } + + qp->req_cb = hpre_alg_cb; + ctx->qp = qp; +@@ -509,6 +514,48 @@ static int hpre_dh_compute_value(struct kpp_request *req) + return ret; + } + ++static struct kpp_request *hpre_dh_prepare_fb_req(struct kpp_request *req) ++{ ++ struct kpp_request *fb_req = kpp_request_ctx(req); ++ struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); ++ struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); ++ ++ kpp_request_set_tfm(fb_req, ctx->dh.soft_tfm); ++ kpp_request_set_callback(fb_req, req->base.flags, req->base.complete, req->base.data); ++ kpp_request_set_input(fb_req, req->src, req->src_len); ++ kpp_request_set_output(fb_req, req->dst, req->dst_len); ++ ++ return fb_req; ++} ++ ++static int hpre_dh_generate_public_key(struct kpp_request *req) ++{ ++ struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); ++ struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); ++ struct kpp_request *fb_req; ++ ++ if (ctx->fallback) { ++ fb_req = hpre_dh_prepare_fb_req(req); ++ return crypto_kpp_generate_public_key(fb_req); ++ } ++ ++ return hpre_dh_compute_value(req); ++} ++ ++static int hpre_dh_compute_shared_secret(struct kpp_request *req) ++{ ++ struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); ++ struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); ++ struct kpp_request *fb_req; ++ ++ if (ctx->fallback) { ++ fb_req = hpre_dh_prepare_fb_req(req); ++ return crypto_kpp_compute_shared_secret(fb_req); ++ } ++ ++ return hpre_dh_compute_value(req); ++} ++ + static int hpre_is_dh_params_length_valid(unsigned int key_sz) + { + #define _HPRE_DH_GRP1 768 +@@ -535,13 +582,6 @@ static int hpre_dh_set_params(struct hpre_ctx *ctx, struct dh *params) + struct device *dev = ctx->dev; + unsigned int sz; + +- if (params->p_size > HPRE_DH_MAX_P_SZ) +- return -EINVAL; +- +- if (hpre_is_dh_params_length_valid(params->p_size << +- HPRE_BITS_2_BYTES_SHIFT)) +- return -EINVAL; +- + sz = ctx->key_sz = params->p_size; + ctx->dh.xa_p = dma_alloc_coherent(dev, sz << 1, + &ctx->dh.dma_xa_p, GFP_KERNEL); +@@ -574,6 +614,9 @@ static void hpre_dh_clear_ctx(struct hpre_ctx *ctx, bool is_clear_all) + struct device *dev = ctx->dev; + unsigned int sz = ctx->key_sz; + ++ if (!ctx->qp) ++ return; ++ + if (ctx->dh.g) { + dma_free_coherent(dev, sz, ctx->dh.g, ctx->dh.dma_g); + ctx->dh.g = NULL; +@@ -599,6 +642,13 @@ static int hpre_dh_set_secret(struct crypto_kpp *tfm, const void *buf, + if (crypto_dh_decode_key(buf, len, ¶ms) < 0) + return -EINVAL; + ++ if (!ctx->qp) ++ goto set_soft_secret; ++ ++ if (hpre_is_dh_params_length_valid(params.p_size << ++ HPRE_BITS_2_BYTES_SHIFT)) ++ goto set_soft_secret; ++ + /* Free old secret if any */ + hpre_dh_clear_ctx(ctx, false); + +@@ -609,27 +659,55 @@ static int hpre_dh_set_secret(struct crypto_kpp *tfm, const void *buf, + memcpy(ctx->dh.xa_p + (ctx->key_sz - params.key_size), params.key, + params.key_size); + ++ ctx->fallback = false; + return 0; + + err_clear_ctx: + hpre_dh_clear_ctx(ctx, false); + return ret; ++set_soft_secret: ++ ctx->fallback = true; ++ return crypto_kpp_set_secret(ctx->dh.soft_tfm, buf, len); + } + + static unsigned int hpre_dh_max_size(struct crypto_kpp *tfm) + { + struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); + ++ if (ctx->fallback) ++ return crypto_kpp_maxsize(ctx->dh.soft_tfm); ++ + return ctx->key_sz; + } + + static int hpre_dh_init_tfm(struct crypto_kpp *tfm) + { + struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); ++ const char *alg = kpp_alg_name(tfm); ++ unsigned int reqsize; ++ int ret; ++ ++ ctx->dh.soft_tfm = crypto_alloc_kpp(alg, 0, CRYPTO_ALG_NEED_FALLBACK); ++ if (IS_ERR(ctx->dh.soft_tfm)) { ++ pr_err("Failed to alloc dh tfm!\n"); ++ return PTR_ERR(ctx->dh.soft_tfm); ++ } ++ ++ crypto_kpp_set_flags(ctx->dh.soft_tfm, crypto_kpp_get_flags(tfm)); ++ ++ reqsize = max(sizeof(struct hpre_asym_request) + hpre_align_pd(), ++ sizeof(struct kpp_request) + crypto_kpp_reqsize(ctx->dh.soft_tfm)); ++ kpp_set_reqsize(tfm, reqsize); + +- kpp_set_reqsize(tfm, sizeof(struct hpre_asym_request) + hpre_align_pd()); ++ ret = hpre_ctx_init(ctx, HPRE_V2_ALG_TYPE); ++ if (ret && ret != -ENODEV) { ++ crypto_free_kpp(ctx->dh.soft_tfm); ++ return ret; ++ } else if (ret == -ENODEV) { ++ ctx->fallback = true; ++ } + +- return hpre_ctx_init(ctx, HPRE_V2_ALG_TYPE); ++ return 0; + } + + static void hpre_dh_exit_tfm(struct crypto_kpp *tfm) +@@ -637,6 +715,7 @@ static void hpre_dh_exit_tfm(struct crypto_kpp *tfm) + struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); + + hpre_dh_clear_ctx(ctx, true); ++ crypto_free_kpp(ctx->dh.soft_tfm); + } + + static void hpre_rsa_drop_leading_zeros(const char **ptr, size_t *len) +@@ -676,9 +755,8 @@ static int hpre_rsa_enc(struct akcipher_request *req) + struct hpre_sqe *msg = &hpre_req->req; + int ret; + +- /* For 512 and 1536 bits key size, use soft tfm instead */ +- if (ctx->key_sz == HPRE_RSA_512BITS_KSZ || +- ctx->key_sz == HPRE_RSA_1536BITS_KSZ) { ++ /* For unsupported key size and unavailable devices, use soft tfm instead */ ++ if (ctx->fallback) { + akcipher_request_set_tfm(req, ctx->rsa.soft_tfm); + ret = crypto_akcipher_encrypt(req); + akcipher_request_set_tfm(req, tfm); +@@ -723,9 +801,8 @@ static int hpre_rsa_dec(struct akcipher_request *req) + struct hpre_sqe *msg = &hpre_req->req; + int ret; + +- /* For 512 and 1536 bits key size, use soft tfm instead */ +- if (ctx->key_sz == HPRE_RSA_512BITS_KSZ || +- ctx->key_sz == HPRE_RSA_1536BITS_KSZ) { ++ /* For unsupported key size and unavailable devices, use soft tfm instead */ ++ if (ctx->fallback) { + akcipher_request_set_tfm(req, ctx->rsa.soft_tfm); + ret = crypto_akcipher_decrypt(req); + akcipher_request_set_tfm(req, tfm); +@@ -778,8 +855,10 @@ static int hpre_rsa_set_n(struct hpre_ctx *ctx, const char *value, + ctx->key_sz = vlen; + + /* if invalid key size provided, we use software tfm */ +- if (!hpre_rsa_key_size_is_support(ctx->key_sz)) ++ if (!hpre_rsa_key_size_is_support(ctx->key_sz)) { ++ ctx->fallback = true; + return 0; ++ } + + ctx->rsa.pubkey = dma_alloc_coherent(ctx->dev, vlen << 1, + &ctx->rsa.dma_pubkey, +@@ -914,6 +993,9 @@ static void hpre_rsa_clear_ctx(struct hpre_ctx *ctx, bool is_clear_all) + unsigned int half_key_sz = ctx->key_sz >> 1; + struct device *dev = ctx->dev; + ++ if (!ctx->qp) ++ return; ++ + if (ctx->rsa.pubkey) { + dma_free_coherent(dev, ctx->key_sz << 1, + ctx->rsa.pubkey, ctx->rsa.dma_pubkey); +@@ -993,6 +1075,7 @@ static int hpre_rsa_setkey(struct hpre_ctx *ctx, const void *key, + goto free; + } + ++ ctx->fallback = false; + return 0; + + free: +@@ -1010,6 +1093,9 @@ static int hpre_rsa_setpubkey(struct crypto_akcipher *tfm, const void *key, + if (ret) + return ret; + ++ if (!ctx->qp) ++ return 0; ++ + return hpre_rsa_setkey(ctx, key, keylen, false); + } + +@@ -1023,6 +1109,9 @@ static int hpre_rsa_setprivkey(struct crypto_akcipher *tfm, const void *key, + if (ret) + return ret; + ++ if (!ctx->qp) ++ return 0; ++ + return hpre_rsa_setkey(ctx, key, keylen, true); + } + +@@ -1030,9 +1119,8 @@ static unsigned int hpre_rsa_max_size(struct crypto_akcipher *tfm) + { + struct hpre_ctx *ctx = akcipher_tfm_ctx(tfm); + +- /* For 512 and 1536 bits key size, use soft tfm instead */ +- if (ctx->key_sz == HPRE_RSA_512BITS_KSZ || +- ctx->key_sz == HPRE_RSA_1536BITS_KSZ) ++ /* For unsupported key size and unavailable devices, use soft tfm instead */ ++ if (ctx->fallback) + return crypto_akcipher_maxsize(ctx->rsa.soft_tfm); + + return ctx->key_sz; +@@ -1053,10 +1141,14 @@ static int hpre_rsa_init_tfm(struct crypto_akcipher *tfm) + hpre_align_pd()); + + ret = hpre_ctx_init(ctx, HPRE_V2_ALG_TYPE); +- if (ret) ++ if (ret && ret != -ENODEV) { + crypto_free_akcipher(ctx->rsa.soft_tfm); ++ return ret; ++ } else if (ret == -ENODEV) { ++ ctx->fallback = true; ++ } + +- return ret; ++ return 0; + } + + static void hpre_rsa_exit_tfm(struct crypto_akcipher *tfm) +@@ -1260,6 +1352,9 @@ static int hpre_ecdh_set_secret(struct crypto_kpp *tfm, const void *buf, + struct ecdh params; + int ret; + ++ if (ctx->fallback) ++ return crypto_kpp_set_secret(ctx->ecdh.soft_tfm, buf, len); ++ + if (crypto_ecdh_decode_key(buf, len, ¶ms) < 0) { + dev_err(dev, "failed to decode ecdh key!\n"); + return -EINVAL; +@@ -1485,23 +1580,82 @@ static int hpre_ecdh_compute_value(struct kpp_request *req) + return ret; + } + ++static int hpre_ecdh_generate_public_key(struct kpp_request *req) ++{ ++ struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); ++ struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); ++ int ret; ++ ++ if (ctx->fallback) { ++ kpp_request_set_tfm(req, ctx->ecdh.soft_tfm); ++ ret = crypto_kpp_generate_public_key(req); ++ kpp_request_set_tfm(req, tfm); ++ return ret; ++ } ++ ++ return hpre_ecdh_compute_value(req); ++} ++ ++static int hpre_ecdh_compute_shared_secret(struct kpp_request *req) ++{ ++ struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); ++ struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); ++ int ret; ++ ++ if (ctx->fallback) { ++ kpp_request_set_tfm(req, ctx->ecdh.soft_tfm); ++ ret = crypto_kpp_compute_shared_secret(req); ++ kpp_request_set_tfm(req, tfm); ++ return ret; ++ } ++ ++ return hpre_ecdh_compute_value(req); ++} ++ + static unsigned int hpre_ecdh_max_size(struct crypto_kpp *tfm) + { + struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); + ++ if (ctx->fallback) ++ return crypto_kpp_maxsize(ctx->ecdh.soft_tfm); ++ + /* max size is the pub_key_size, include x and y */ + return ctx->key_sz << 1; + } + ++static int hpre_ecdh_init_tfm(struct crypto_kpp *tfm) ++{ ++ struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); ++ const char *alg = kpp_alg_name(tfm); ++ int ret; ++ ++ ret = hpre_ctx_init(ctx, HPRE_V3_ECC_ALG_TYPE); ++ if (!ret) { ++ kpp_set_reqsize(tfm, sizeof(struct hpre_asym_request) + hpre_align_pd()); ++ return 0; ++ } else if (ret && ret != -ENODEV) { ++ return ret; ++ } ++ ++ ctx->ecdh.soft_tfm = crypto_alloc_kpp(alg, 0, CRYPTO_ALG_NEED_FALLBACK); ++ if (IS_ERR(ctx->ecdh.soft_tfm)) { ++ pr_err("Failed to alloc %s tfm!\n", alg); ++ return PTR_ERR(ctx->ecdh.soft_tfm); ++ } ++ ++ crypto_kpp_set_flags(ctx->ecdh.soft_tfm, crypto_kpp_get_flags(tfm)); ++ ctx->fallback = true; ++ ++ return 0; ++} ++ + static int hpre_ecdh_nist_p192_init_tfm(struct crypto_kpp *tfm) + { + struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); + + ctx->curve_id = ECC_CURVE_NIST_P192; + +- kpp_set_reqsize(tfm, sizeof(struct hpre_asym_request) + hpre_align_pd()); +- +- return hpre_ctx_init(ctx, HPRE_V3_ECC_ALG_TYPE); ++ return hpre_ecdh_init_tfm(tfm); + } + + static int hpre_ecdh_nist_p256_init_tfm(struct crypto_kpp *tfm) +@@ -1511,9 +1665,7 @@ static int hpre_ecdh_nist_p256_init_tfm(struct crypto_kpp *tfm) + ctx->curve_id = ECC_CURVE_NIST_P256; + ctx->enable_hpcore = 1; + +- kpp_set_reqsize(tfm, sizeof(struct hpre_asym_request) + hpre_align_pd()); +- +- return hpre_ctx_init(ctx, HPRE_V3_ECC_ALG_TYPE); ++ return hpre_ecdh_init_tfm(tfm); + } + + static int hpre_ecdh_nist_p384_init_tfm(struct crypto_kpp *tfm) +@@ -1522,15 +1674,18 @@ static int hpre_ecdh_nist_p384_init_tfm(struct crypto_kpp *tfm) + + ctx->curve_id = ECC_CURVE_NIST_P384; + +- kpp_set_reqsize(tfm, sizeof(struct hpre_asym_request) + hpre_align_pd()); +- +- return hpre_ctx_init(ctx, HPRE_V3_ECC_ALG_TYPE); ++ return hpre_ecdh_init_tfm(tfm); + } + + static void hpre_ecdh_exit_tfm(struct crypto_kpp *tfm) + { + struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); + ++ if (ctx->fallback) { ++ crypto_free_kpp(ctx->ecdh.soft_tfm); ++ return; ++ } ++ + hpre_ecc_clear_ctx(ctx, true); + } + +@@ -1548,13 +1703,14 @@ static struct akcipher_alg rsa = { + .cra_name = "rsa", + .cra_driver_name = "hpre-rsa", + .cra_module = THIS_MODULE, ++ .cra_flags = CRYPTO_ALG_NEED_FALLBACK, + }, + }; + + static struct kpp_alg dh = { + .set_secret = hpre_dh_set_secret, +- .generate_public_key = hpre_dh_compute_value, +- .compute_shared_secret = hpre_dh_compute_value, ++ .generate_public_key = hpre_dh_generate_public_key, ++ .compute_shared_secret = hpre_dh_compute_shared_secret, + .max_size = hpre_dh_max_size, + .init = hpre_dh_init_tfm, + .exit = hpre_dh_exit_tfm, +@@ -1564,14 +1720,15 @@ static struct kpp_alg dh = { + .cra_name = "dh", + .cra_driver_name = "hpre-dh", + .cra_module = THIS_MODULE, ++ .cra_flags = CRYPTO_ALG_NEED_FALLBACK, + }, + }; + + static struct kpp_alg ecdh_curves[] = { + { + .set_secret = hpre_ecdh_set_secret, +- .generate_public_key = hpre_ecdh_compute_value, +- .compute_shared_secret = hpre_ecdh_compute_value, ++ .generate_public_key = hpre_ecdh_generate_public_key, ++ .compute_shared_secret = hpre_ecdh_compute_shared_secret, + .max_size = hpre_ecdh_max_size, + .init = hpre_ecdh_nist_p192_init_tfm, + .exit = hpre_ecdh_exit_tfm, +@@ -1581,11 +1738,12 @@ static struct kpp_alg ecdh_curves[] = { + .cra_name = "ecdh-nist-p192", + .cra_driver_name = "hpre-ecdh-nist-p192", + .cra_module = THIS_MODULE, ++ .cra_flags = CRYPTO_ALG_NEED_FALLBACK, + }, + }, { + .set_secret = hpre_ecdh_set_secret, +- .generate_public_key = hpre_ecdh_compute_value, +- .compute_shared_secret = hpre_ecdh_compute_value, ++ .generate_public_key = hpre_ecdh_generate_public_key, ++ .compute_shared_secret = hpre_ecdh_compute_shared_secret, + .max_size = hpre_ecdh_max_size, + .init = hpre_ecdh_nist_p256_init_tfm, + .exit = hpre_ecdh_exit_tfm, +@@ -1595,11 +1753,12 @@ static struct kpp_alg ecdh_curves[] = { + .cra_name = "ecdh-nist-p256", + .cra_driver_name = "hpre-ecdh-nist-p256", + .cra_module = THIS_MODULE, ++ .cra_flags = CRYPTO_ALG_NEED_FALLBACK, + }, + }, { + .set_secret = hpre_ecdh_set_secret, +- .generate_public_key = hpre_ecdh_compute_value, +- .compute_shared_secret = hpre_ecdh_compute_value, ++ .generate_public_key = hpre_ecdh_generate_public_key, ++ .compute_shared_secret = hpre_ecdh_compute_shared_secret, + .max_size = hpre_ecdh_max_size, + .init = hpre_ecdh_nist_p384_init_tfm, + .exit = hpre_ecdh_exit_tfm, +@@ -1609,6 +1768,7 @@ static struct kpp_alg ecdh_curves[] = { + .cra_name = "ecdh-nist-p384", + .cra_driver_name = "hpre-ecdh-nist-p384", + .cra_module = THIS_MODULE, ++ .cra_flags = CRYPTO_ALG_NEED_FALLBACK, + }, + } + }; +-- +2.51.0 + diff --git a/queue-6.19/crypto-hisilicon-qm-centralize-the-sending-locks-of-.patch b/queue-6.19/crypto-hisilicon-qm-centralize-the-sending-locks-of-.patch new file mode 100644 index 0000000000..e6f78312f1 --- /dev/null +++ b/queue-6.19/crypto-hisilicon-qm-centralize-the-sending-locks-of-.patch @@ -0,0 +1,143 @@ +From 1193c2257d9f7203949f8613952c55c10d2ebd3f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 21:44:46 +0800 +Subject: crypto: hisilicon/qm - centralize the sending locks of each module + into qm + +From: Chenghai Huang + +[ Upstream commit 8cd9b608ee8dea78cac3f373bd5e3b3de2755d46 ] + +When a single queue used by multiple tfms, the protection of shared +resources by individual module driver programs is no longer +sufficient. The hisi_qp_send needs to be ensured by the lock in qp. + +Fixes: 5fdb4b345cfb ("crypto: hisilicon - add a lock for the qp send operation") +Signed-off-by: Chenghai Huang +Signed-off-by: Weili Qian +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/hpre/hpre_crypto.c | 4 ---- + drivers/crypto/hisilicon/qm.c | 16 ++++++++++++---- + drivers/crypto/hisilicon/zip/zip_crypto.c | 3 --- + include/linux/hisi_acc_qm.h | 1 + + 4 files changed, 13 insertions(+), 11 deletions(-) + +diff --git a/drivers/crypto/hisilicon/hpre/hpre_crypto.c b/drivers/crypto/hisilicon/hpre/hpre_crypto.c +index 4197281c8dff5..220022ae7afb6 100644 +--- a/drivers/crypto/hisilicon/hpre/hpre_crypto.c ++++ b/drivers/crypto/hisilicon/hpre/hpre_crypto.c +@@ -109,7 +109,6 @@ struct hpre_ctx { + struct hisi_qp *qp; + struct device *dev; + struct hpre *hpre; +- spinlock_t req_lock; + unsigned int key_sz; + bool crt_g2_mode; + union { +@@ -410,7 +409,6 @@ static int hpre_ctx_init(struct hpre_ctx *ctx, u8 type) + + qp->qp_ctx = ctx; + qp->req_cb = hpre_alg_cb; +- spin_lock_init(&ctx->req_lock); + ctx->qp = qp; + ctx->dev = &qp->qm->pdev->dev; + hpre = container_of(ctx->qp->qm, struct hpre, qm); +@@ -478,9 +476,7 @@ static int hpre_send(struct hpre_ctx *ctx, struct hpre_sqe *msg) + + do { + atomic64_inc(&dfx[HPRE_SEND_CNT].value); +- spin_lock_bh(&ctx->req_lock); + ret = hisi_qp_send(ctx->qp, msg); +- spin_unlock_bh(&ctx->req_lock); + if (ret != -EBUSY) + break; + atomic64_inc(&dfx[HPRE_SEND_BUSY_CNT].value); +diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c +index 5c80ca04a8d42..0f5e39884e4a3 100644 +--- a/drivers/crypto/hisilicon/qm.c ++++ b/drivers/crypto/hisilicon/qm.c +@@ -2369,26 +2369,33 @@ EXPORT_SYMBOL_GPL(hisi_qm_stop_qp); + int hisi_qp_send(struct hisi_qp *qp, const void *msg) + { + struct hisi_qp_status *qp_status = &qp->qp_status; +- u16 sq_tail = qp_status->sq_tail; +- u16 sq_tail_next = (sq_tail + 1) % qp->sq_depth; +- void *sqe = qm_get_avail_sqe(qp); ++ u16 sq_tail, sq_tail_next; ++ void *sqe; + ++ spin_lock_bh(&qp->qp_lock); + if (unlikely(atomic_read(&qp->qp_status.flags) == QP_STOP || + atomic_read(&qp->qm->status.flags) == QM_STOP || + qp->is_resetting)) { ++ spin_unlock_bh(&qp->qp_lock); + dev_info_ratelimited(&qp->qm->pdev->dev, "QP is stopped or resetting\n"); + return -EAGAIN; + } + +- if (!sqe) ++ sqe = qm_get_avail_sqe(qp); ++ if (!sqe) { ++ spin_unlock_bh(&qp->qp_lock); + return -EBUSY; ++ } + ++ sq_tail = qp_status->sq_tail; ++ sq_tail_next = (sq_tail + 1) % qp->sq_depth; + memcpy(sqe, msg, qp->qm->sqe_size); + qp->msg[sq_tail] = msg; + + qm_db(qp->qm, qp->qp_id, QM_DOORBELL_CMD_SQ, sq_tail_next, 0); + atomic_inc(&qp->qp_status.used); + qp_status->sq_tail = sq_tail_next; ++ spin_unlock_bh(&qp->qp_lock); + + return 0; + } +@@ -2968,6 +2975,7 @@ static int hisi_qp_memory_init(struct hisi_qm *qm, size_t dma_size, int id, + qp->qm = qm; + qp->qp_id = id; + ++ spin_lock_init(&qp->qp_lock); + spin_lock_init(&qp->backlog.lock); + INIT_LIST_HEAD(&qp->backlog.list); + +diff --git a/drivers/crypto/hisilicon/zip/zip_crypto.c b/drivers/crypto/hisilicon/zip/zip_crypto.c +index 8250a33ba5862..2f9035c016f3f 100644 +--- a/drivers/crypto/hisilicon/zip/zip_crypto.c ++++ b/drivers/crypto/hisilicon/zip/zip_crypto.c +@@ -217,7 +217,6 @@ static int hisi_zip_do_work(struct hisi_zip_qp_ctx *qp_ctx, + { + struct hisi_acc_sgl_pool *pool = qp_ctx->sgl_pool; + struct hisi_zip_dfx *dfx = &qp_ctx->zip_dev->dfx; +- struct hisi_zip_req_q *req_q = &qp_ctx->req_q; + struct acomp_req *a_req = req->req; + struct hisi_qp *qp = qp_ctx->qp; + struct device *dev = &qp->qm->pdev->dev; +@@ -250,9 +249,7 @@ static int hisi_zip_do_work(struct hisi_zip_qp_ctx *qp_ctx, + + /* send command to start a task */ + atomic64_inc(&dfx->send_cnt); +- spin_lock_bh(&req_q->req_lock); + ret = hisi_qp_send(qp, &zip_sqe); +- spin_unlock_bh(&req_q->req_lock); + if (unlikely(ret < 0)) { + atomic64_inc(&dfx->send_busy_cnt); + ret = -EAGAIN; +diff --git a/include/linux/hisi_acc_qm.h b/include/linux/hisi_acc_qm.h +index dd4323633d81e..ef4d3a79bcb70 100644 +--- a/include/linux/hisi_acc_qm.h ++++ b/include/linux/hisi_acc_qm.h +@@ -476,6 +476,7 @@ struct hisi_qp { + u16 pasid; + struct uacce_queue *uacce_q; + ++ spinlock_t qp_lock; + struct instance_backlog backlog; + const void **msg; + }; +-- +2.51.0 + diff --git a/queue-6.19/crypto-hisilicon-qm-enhance-the-configuration-of-req.patch b/queue-6.19/crypto-hisilicon-qm-enhance-the-configuration-of-req.patch new file mode 100644 index 0000000000..ff90057258 --- /dev/null +++ b/queue-6.19/crypto-hisilicon-qm-enhance-the-configuration-of-req.patch @@ -0,0 +1,248 @@ +From d843161b94ba1a1aa3bb767ef68cf6e97283a6fe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 21:44:45 +0800 +Subject: crypto: hisilicon/qm - enhance the configuration of req_type in queue + attributes + +From: Chenghai Huang + +[ Upstream commit 21452eaa06edb5f6038720e643aed0bbfffad9c3 ] + +Originally, when a queue was requested, it could only be configured +with the default algorithm type of 0. Now, when multiple tfms use +the same queue, the queue must be selected based on its attributes +to meet the requirements of tfm tasks. So the algorithm type +attribute of queue need to be distinguished. Just like a queue used +for compression in ZIP cannot be used for decompression tasks. + +Fixes: 3f1ec97aacf1 ("crypto: hisilicon/qm - Put device finding logic into QM") +Signed-off-by: Chenghai Huang +Signed-off-by: Weili Qian +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/hpre/hpre_main.c | 2 +- + drivers/crypto/hisilicon/qm.c | 8 ++++---- + drivers/crypto/hisilicon/sec2/sec_crypto.c | 1 - + drivers/crypto/hisilicon/sec2/sec_main.c | 21 ++++++++++++++++----- + drivers/crypto/hisilicon/zip/zip.h | 2 +- + drivers/crypto/hisilicon/zip/zip_crypto.c | 13 +++++++++---- + drivers/crypto/hisilicon/zip/zip_main.c | 4 ++-- + include/linux/hisi_acc_qm.h | 3 +-- + 8 files changed, 34 insertions(+), 20 deletions(-) + +diff --git a/drivers/crypto/hisilicon/hpre/hpre_main.c b/drivers/crypto/hisilicon/hpre/hpre_main.c +index b94fecd765eeb..884d5d0afaf41 100644 +--- a/drivers/crypto/hisilicon/hpre/hpre_main.c ++++ b/drivers/crypto/hisilicon/hpre/hpre_main.c +@@ -465,7 +465,7 @@ struct hisi_qp *hpre_create_qp(u8 type) + * type: 0 - RSA/DH. algorithm supported in V2, + * 1 - ECC algorithm in V3. + */ +- ret = hisi_qm_alloc_qps_node(&hpre_devices, 1, type, node, &qp); ++ ret = hisi_qm_alloc_qps_node(&hpre_devices, 1, &type, node, &qp); + if (!ret) + return qp; + +diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c +index 71071ac559d4b..5c80ca04a8d42 100644 +--- a/drivers/crypto/hisilicon/qm.c ++++ b/drivers/crypto/hisilicon/qm.c +@@ -3620,7 +3620,7 @@ static int hisi_qm_sort_devices(int node, struct list_head *head, + * not meet the requirements will return error. + */ + int hisi_qm_alloc_qps_node(struct hisi_qm_list *qm_list, int qp_num, +- u8 alg_type, int node, struct hisi_qp **qps) ++ u8 *alg_type, int node, struct hisi_qp **qps) + { + struct hisi_qm_resource *tmp; + int ret = -ENODEV; +@@ -3638,7 +3638,7 @@ int hisi_qm_alloc_qps_node(struct hisi_qm_list *qm_list, int qp_num, + + list_for_each_entry(tmp, &head, list) { + for (i = 0; i < qp_num; i++) { +- qps[i] = hisi_qm_create_qp(tmp->qm, alg_type); ++ qps[i] = hisi_qm_create_qp(tmp->qm, alg_type[i]); + if (IS_ERR(qps[i])) { + hisi_qm_free_qps(qps, i); + break; +@@ -3653,8 +3653,8 @@ int hisi_qm_alloc_qps_node(struct hisi_qm_list *qm_list, int qp_num, + + mutex_unlock(&qm_list->lock); + if (ret) +- pr_info("Failed to create qps, node[%d], alg[%u], qp[%d]!\n", +- node, alg_type, qp_num); ++ pr_info("Failed to create qps, node[%d], qp[%d]!\n", ++ node, qp_num); + + err: + free_list(&head); +diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.c b/drivers/crypto/hisilicon/sec2/sec_crypto.c +index 4e41235116e15..364bd69c60883 100644 +--- a/drivers/crypto/hisilicon/sec2/sec_crypto.c ++++ b/drivers/crypto/hisilicon/sec2/sec_crypto.c +@@ -626,7 +626,6 @@ static int sec_create_qp_ctx(struct sec_ctx *ctx, int qp_ctx_id) + + qp_ctx = &ctx->qp_ctx[qp_ctx_id]; + qp = ctx->qps[qp_ctx_id]; +- qp->req_type = 0; + qp->qp_ctx = qp_ctx; + qp_ctx->qp = qp; + qp_ctx->ctx = ctx; +diff --git a/drivers/crypto/hisilicon/sec2/sec_main.c b/drivers/crypto/hisilicon/sec2/sec_main.c +index 5eb2d68207426..7dd125f5f511f 100644 +--- a/drivers/crypto/hisilicon/sec2/sec_main.c ++++ b/drivers/crypto/hisilicon/sec2/sec_main.c +@@ -417,18 +417,29 @@ struct hisi_qp **sec_create_qps(void) + int node = cpu_to_node(raw_smp_processor_id()); + u32 ctx_num = ctx_q_num; + struct hisi_qp **qps; ++ u8 *type; + int ret; + + qps = kcalloc(ctx_num, sizeof(struct hisi_qp *), GFP_KERNEL); + if (!qps) + return NULL; + +- ret = hisi_qm_alloc_qps_node(&sec_devices, ctx_num, 0, node, qps); +- if (!ret) +- return qps; ++ /* The type of SEC is all 0, so just allocated by kcalloc */ ++ type = kcalloc(ctx_num, sizeof(u8), GFP_KERNEL); ++ if (!type) { ++ kfree(qps); ++ return NULL; ++ } + +- kfree(qps); +- return NULL; ++ ret = hisi_qm_alloc_qps_node(&sec_devices, ctx_num, type, node, qps); ++ if (ret) { ++ kfree(type); ++ kfree(qps); ++ return NULL; ++ } ++ ++ kfree(type); ++ return qps; + } + + u64 sec_get_alg_bitmap(struct hisi_qm *qm, u32 high, u32 low) +diff --git a/drivers/crypto/hisilicon/zip/zip.h b/drivers/crypto/hisilicon/zip/zip.h +index 9fb2a9c01132b..b83f228281ab1 100644 +--- a/drivers/crypto/hisilicon/zip/zip.h ++++ b/drivers/crypto/hisilicon/zip/zip.h +@@ -99,7 +99,7 @@ enum zip_cap_table_type { + ZIP_CORE5_BITMAP, + }; + +-int zip_create_qps(struct hisi_qp **qps, int qp_num, int node); ++int zip_create_qps(struct hisi_qp **qps, int qp_num, int node, u8 *alg_type); + int hisi_zip_register_to_crypto(struct hisi_qm *qm); + void hisi_zip_unregister_from_crypto(struct hisi_qm *qm); + bool hisi_zip_alg_support(struct hisi_qm *qm, u32 alg); +diff --git a/drivers/crypto/hisilicon/zip/zip_crypto.c b/drivers/crypto/hisilicon/zip/zip_crypto.c +index b4a656e0177d2..8250a33ba5862 100644 +--- a/drivers/crypto/hisilicon/zip/zip_crypto.c ++++ b/drivers/crypto/hisilicon/zip/zip_crypto.c +@@ -66,6 +66,7 @@ struct hisi_zip_qp_ctx { + struct hisi_acc_sgl_pool *sgl_pool; + struct hisi_zip *zip_dev; + struct hisi_zip_ctx *ctx; ++ u8 req_type; + }; + + struct hisi_zip_sqe_ops { +@@ -245,7 +246,7 @@ static int hisi_zip_do_work(struct hisi_zip_qp_ctx *qp_ctx, + goto err_unmap_input; + } + +- hisi_zip_fill_sqe(qp_ctx->ctx, &zip_sqe, qp->req_type, req); ++ hisi_zip_fill_sqe(qp_ctx->ctx, &zip_sqe, qp_ctx->req_type, req); + + /* send command to start a task */ + atomic64_inc(&dfx->send_cnt); +@@ -360,7 +361,6 @@ static int hisi_zip_start_qp(struct hisi_qp *qp, struct hisi_zip_qp_ctx *qp_ctx, + struct device *dev = &qp->qm->pdev->dev; + int ret; + +- qp->req_type = req_type; + qp->alg_type = alg_type; + qp->qp_ctx = qp_ctx; + +@@ -397,10 +397,15 @@ static int hisi_zip_ctx_init(struct hisi_zip_ctx *hisi_zip_ctx, u8 req_type, int + { + struct hisi_qp *qps[HZIP_CTX_Q_NUM] = { NULL }; + struct hisi_zip_qp_ctx *qp_ctx; ++ u8 alg_type[HZIP_CTX_Q_NUM]; + struct hisi_zip *hisi_zip; + int ret, i, j; + +- ret = zip_create_qps(qps, HZIP_CTX_Q_NUM, node); ++ /* alg_type = 0 for compress, 1 for decompress in hw sqe */ ++ for (i = 0; i < HZIP_CTX_Q_NUM; i++) ++ alg_type[i] = i; ++ ++ ret = zip_create_qps(qps, HZIP_CTX_Q_NUM, node, alg_type); + if (ret) { + pr_err("failed to create zip qps (%d)!\n", ret); + return -ENODEV; +@@ -409,7 +414,6 @@ static int hisi_zip_ctx_init(struct hisi_zip_ctx *hisi_zip_ctx, u8 req_type, int + hisi_zip = container_of(qps[0]->qm, struct hisi_zip, qm); + + for (i = 0; i < HZIP_CTX_Q_NUM; i++) { +- /* alg_type = 0 for compress, 1 for decompress in hw sqe */ + qp_ctx = &hisi_zip_ctx->qp_ctx[i]; + qp_ctx->ctx = hisi_zip_ctx; + ret = hisi_zip_start_qp(qps[i], qp_ctx, i, req_type); +@@ -422,6 +426,7 @@ static int hisi_zip_ctx_init(struct hisi_zip_ctx *hisi_zip_ctx, u8 req_type, int + } + + qp_ctx->zip_dev = hisi_zip; ++ qp_ctx->req_type = req_type; + } + + hisi_zip_ctx->ops = &hisi_zip_ops; +diff --git a/drivers/crypto/hisilicon/zip/zip_main.c b/drivers/crypto/hisilicon/zip/zip_main.c +index 4fcbe6bada066..85b26ef175485 100644 +--- a/drivers/crypto/hisilicon/zip/zip_main.c ++++ b/drivers/crypto/hisilicon/zip/zip_main.c +@@ -446,12 +446,12 @@ static const struct pci_device_id hisi_zip_dev_ids[] = { + }; + MODULE_DEVICE_TABLE(pci, hisi_zip_dev_ids); + +-int zip_create_qps(struct hisi_qp **qps, int qp_num, int node) ++int zip_create_qps(struct hisi_qp **qps, int qp_num, int node, u8 *alg_type) + { + if (node == NUMA_NO_NODE) + node = cpu_to_node(raw_smp_processor_id()); + +- return hisi_qm_alloc_qps_node(&zip_devices, qp_num, 0, node, qps); ++ return hisi_qm_alloc_qps_node(&zip_devices, qp_num, alg_type, node, qps); + } + + bool hisi_zip_alg_support(struct hisi_qm *qm, u32 alg) +diff --git a/include/linux/hisi_acc_qm.h b/include/linux/hisi_acc_qm.h +index 9485896d5dc08..dd4323633d81e 100644 +--- a/include/linux/hisi_acc_qm.h ++++ b/include/linux/hisi_acc_qm.h +@@ -457,7 +457,6 @@ struct hisi_qp { + u16 sq_depth; + u16 cq_depth; + u8 alg_type; +- u8 req_type; + + struct qm_dma qdma; + void *sqe; +@@ -583,7 +582,7 @@ struct hisi_acc_sgl_pool *hisi_acc_create_sgl_pool(struct device *dev, + void hisi_acc_free_sgl_pool(struct device *dev, + struct hisi_acc_sgl_pool *pool); + int hisi_qm_alloc_qps_node(struct hisi_qm_list *qm_list, int qp_num, +- u8 alg_type, int node, struct hisi_qp **qps); ++ u8 *alg_type, int node, struct hisi_qp **qps); + void hisi_qm_free_qps(struct hisi_qp **qps, int qp_num); + void hisi_qm_dev_shutdown(struct pci_dev *pdev); + void hisi_qm_wait_task_finish(struct hisi_qm *qm, struct hisi_qm_list *qm_list); +-- +2.51.0 + diff --git a/queue-6.19/crypto-hisilicon-sec-move-backlog-management-to-qp-a.patch b/queue-6.19/crypto-hisilicon-sec-move-backlog-management-to-qp-a.patch new file mode 100644 index 0000000000..a76d116c09 --- /dev/null +++ b/queue-6.19/crypto-hisilicon-sec-move-backlog-management-to-qp-a.patch @@ -0,0 +1,365 @@ +From 045fff99c81beb32fcf6107cb368f2697e6780bb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 21:44:43 +0800 +Subject: crypto: hisilicon/sec - move backlog management to qp and store sqe + in qp for callback + +From: Chenghai Huang + +[ Upstream commit 08eb67d23e5172a5d1e60f1f0acccee569fe10ba ] + +When multiple tfm use a same qp, the backlog data should be managed +centrally by the qp, rather than in the qp_ctx of each req. + +Additionally, since SEC_BD_TYPE1 and SEC_BD_TYPE2 cannot use the +tag of the sqe to carry the virtual address of the req, the sent +sqe is stored in the qp. This allows the callback function to get +the req address. To handle the differences between hardware types, +the callback functions are split into two separate implementations. + +Fixes: f0ae287c5045 ("crypto: hisilicon/sec2 - implement full backlog mode for sec") +Signed-off-by: Chenghai Huang +Signed-off-by: Weili Qian +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/qm.c | 20 ++++- + drivers/crypto/hisilicon/sec2/sec.h | 7 -- + drivers/crypto/hisilicon/sec2/sec_crypto.c | 88 +++++++++++----------- + include/linux/hisi_acc_qm.h | 8 ++ + 4 files changed, 69 insertions(+), 54 deletions(-) + +diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c +index d47bf06a90f7d..71071ac559d4b 100644 +--- a/drivers/crypto/hisilicon/qm.c ++++ b/drivers/crypto/hisilicon/qm.c +@@ -2219,6 +2219,7 @@ static void qp_stop_fail_cb(struct hisi_qp *qp) + for (i = 0; i < qp_used; i++) { + pos = (i + cur_head) % sq_depth; + qp->req_cb(qp, qp->sqe + (u32)(qm->sqe_size * pos)); ++ qm_cq_head_update(qp); + atomic_dec(&qp->qp_status.used); + } + } +@@ -2383,6 +2384,7 @@ int hisi_qp_send(struct hisi_qp *qp, const void *msg) + return -EBUSY; + + memcpy(sqe, msg, qp->qm->sqe_size); ++ qp->msg[sq_tail] = msg; + + qm_db(qp->qm, qp->qp_id, QM_DOORBELL_CMD_SQ, sq_tail_next, 0); + atomic_inc(&qp->qp_status.used); +@@ -2919,12 +2921,13 @@ EXPORT_SYMBOL_GPL(hisi_qm_wait_task_finish); + static void hisi_qp_memory_uninit(struct hisi_qm *qm, int num) + { + struct device *dev = &qm->pdev->dev; +- struct qm_dma *qdma; ++ struct hisi_qp *qp; + int i; + + for (i = num - 1; i >= 0; i--) { +- qdma = &qm->qp_array[i].qdma; +- dma_free_coherent(dev, qdma->size, qdma->va, qdma->dma); ++ qp = &qm->qp_array[i]; ++ dma_free_coherent(dev, qp->qdma.size, qp->qdma.va, qp->qdma.dma); ++ kfree(qp->msg); + kfree(qm->poll_data[i].qp_finish_id); + } + +@@ -2946,10 +2949,14 @@ static int hisi_qp_memory_init(struct hisi_qm *qm, size_t dma_size, int id, + return -ENOMEM; + + qp = &qm->qp_array[id]; ++ qp->msg = kmalloc_array(sq_depth, sizeof(void *), GFP_KERNEL); ++ if (!qp->msg) ++ goto err_free_qp_finish_id; ++ + qp->qdma.va = dma_alloc_coherent(dev, dma_size, &qp->qdma.dma, + GFP_KERNEL); + if (!qp->qdma.va) +- goto err_free_qp_finish_id; ++ goto err_free_qp_msg; + + qp->sqe = qp->qdma.va; + qp->sqe_dma = qp->qdma.dma; +@@ -2961,8 +2968,13 @@ static int hisi_qp_memory_init(struct hisi_qm *qm, size_t dma_size, int id, + qp->qm = qm; + qp->qp_id = id; + ++ spin_lock_init(&qp->backlog.lock); ++ INIT_LIST_HEAD(&qp->backlog.list); ++ + return 0; + ++err_free_qp_msg: ++ kfree(qp->msg); + err_free_qp_finish_id: + kfree(qm->poll_data[id].qp_finish_id); + return ret; +diff --git a/drivers/crypto/hisilicon/sec2/sec.h b/drivers/crypto/hisilicon/sec2/sec.h +index 81d0beda93b2b..0710977861f32 100644 +--- a/drivers/crypto/hisilicon/sec2/sec.h ++++ b/drivers/crypto/hisilicon/sec2/sec.h +@@ -82,11 +82,6 @@ struct sec_aead_req { + __u8 out_mac_buf[SEC_MAX_MAC_LEN]; + }; + +-struct sec_instance_backlog { +- struct list_head list; +- spinlock_t lock; +-}; +- + /* SEC request of Crypto */ + struct sec_req { + union { +@@ -112,7 +107,6 @@ struct sec_req { + bool use_pbuf; + + struct list_head list; +- struct sec_instance_backlog *backlog; + struct sec_request_buf buf; + }; + +@@ -172,7 +166,6 @@ struct sec_qp_ctx { + spinlock_t id_lock; + struct hisi_acc_sgl_pool *c_in_pool; + struct hisi_acc_sgl_pool *c_out_pool; +- struct sec_instance_backlog backlog; + u16 send_head; + }; + +diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.c b/drivers/crypto/hisilicon/sec2/sec_crypto.c +index 31590d01139a3..4e41235116e15 100644 +--- a/drivers/crypto/hisilicon/sec2/sec_crypto.c ++++ b/drivers/crypto/hisilicon/sec2/sec_crypto.c +@@ -54,7 +54,6 @@ + #define SEC_AUTH_CIPHER_V3 0x40 + #define SEC_FLAG_OFFSET 7 + #define SEC_FLAG_MASK 0x0780 +-#define SEC_TYPE_MASK 0x0F + #define SEC_DONE_MASK 0x0001 + #define SEC_ICV_MASK 0x000E + +@@ -148,7 +147,7 @@ static void sec_free_req_id(struct sec_req *req) + spin_unlock_bh(&qp_ctx->id_lock); + } + +-static u8 pre_parse_finished_bd(struct bd_status *status, void *resp) ++static void pre_parse_finished_bd(struct bd_status *status, void *resp) + { + struct sec_sqe *bd = resp; + +@@ -158,11 +157,9 @@ static u8 pre_parse_finished_bd(struct bd_status *status, void *resp) + SEC_FLAG_MASK) >> SEC_FLAG_OFFSET; + status->tag = le16_to_cpu(bd->type2.tag); + status->err_type = bd->type2.error_type; +- +- return bd->type_cipher_auth & SEC_TYPE_MASK; + } + +-static u8 pre_parse_finished_bd3(struct bd_status *status, void *resp) ++static void pre_parse_finished_bd3(struct bd_status *status, void *resp) + { + struct sec_sqe3 *bd3 = resp; + +@@ -172,8 +169,6 @@ static u8 pre_parse_finished_bd3(struct bd_status *status, void *resp) + SEC_FLAG_MASK) >> SEC_FLAG_OFFSET; + status->tag = le64_to_cpu(bd3->tag); + status->err_type = bd3->error_type; +- +- return le32_to_cpu(bd3->bd_param) & SEC_TYPE_MASK; + } + + static int sec_cb_status_check(struct sec_req *req, +@@ -244,7 +239,7 @@ static void sec_alg_send_backlog_soft(struct sec_ctx *ctx, struct sec_qp_ctx *qp + struct sec_req *req, *tmp; + int ret; + +- list_for_each_entry_safe(req, tmp, &qp_ctx->backlog.list, list) { ++ list_for_each_entry_safe(req, tmp, &qp_ctx->qp->backlog.list, list) { + list_del(&req->list); + ctx->req_op->buf_unmap(ctx, req); + if (req->req_id >= 0) +@@ -265,11 +260,12 @@ static void sec_alg_send_backlog_soft(struct sec_ctx *ctx, struct sec_qp_ctx *qp + + static void sec_alg_send_backlog(struct sec_ctx *ctx, struct sec_qp_ctx *qp_ctx) + { ++ struct hisi_qp *qp = qp_ctx->qp; + struct sec_req *req, *tmp; + int ret; + +- spin_lock_bh(&qp_ctx->backlog.lock); +- list_for_each_entry_safe(req, tmp, &qp_ctx->backlog.list, list) { ++ spin_lock_bh(&qp->backlog.lock); ++ list_for_each_entry_safe(req, tmp, &qp->backlog.list, list) { + ret = qp_send_message(req); + switch (ret) { + case -EINPROGRESS: +@@ -287,42 +283,46 @@ static void sec_alg_send_backlog(struct sec_ctx *ctx, struct sec_qp_ctx *qp_ctx) + } + + unlock: +- spin_unlock_bh(&qp_ctx->backlog.lock); ++ spin_unlock_bh(&qp->backlog.lock); + } + + static void sec_req_cb(struct hisi_qp *qp, void *resp) + { +- struct sec_qp_ctx *qp_ctx = qp->qp_ctx; +- struct sec_dfx *dfx = &qp_ctx->ctx->sec->debug.dfx; +- u8 type_supported = qp_ctx->ctx->type_supported; ++ const struct sec_sqe *sqe = qp->msg[qp->qp_status.cq_head]; ++ struct sec_req *req = container_of(sqe, struct sec_req, sec_sqe); ++ struct sec_ctx *ctx = req->ctx; ++ struct sec_dfx *dfx = &ctx->sec->debug.dfx; + struct bd_status status; +- struct sec_ctx *ctx; +- struct sec_req *req; + int err; +- u8 type; + +- if (type_supported == SEC_BD_TYPE2) { +- type = pre_parse_finished_bd(&status, resp); +- req = qp_ctx->req_list[status.tag]; +- } else { +- type = pre_parse_finished_bd3(&status, resp); +- req = (void *)(uintptr_t)status.tag; +- } ++ pre_parse_finished_bd(&status, resp); + +- if (unlikely(type != type_supported)) { +- atomic64_inc(&dfx->err_bd_cnt); +- pr_err("err bd type [%u]\n", type); +- return; +- } ++ req->err_type = status.err_type; ++ err = sec_cb_status_check(req, &status); ++ if (err) ++ atomic64_inc(&dfx->done_flag_cnt); + +- if (unlikely(!req)) { +- atomic64_inc(&dfx->invalid_req_cnt); +- atomic_inc(&qp->qp_status.used); +- return; +- } ++ atomic64_inc(&dfx->recv_cnt); + ++ ctx->req_op->buf_unmap(ctx, req); ++ ctx->req_op->callback(ctx, req, err); ++} ++ ++static void sec_req_cb3(struct hisi_qp *qp, void *resp) ++{ ++ struct bd_status status; ++ struct sec_ctx *ctx; ++ struct sec_dfx *dfx; ++ struct sec_req *req; ++ int err; ++ ++ pre_parse_finished_bd3(&status, resp); ++ ++ req = (void *)(uintptr_t)status.tag; + req->err_type = status.err_type; + ctx = req->ctx; ++ dfx = &ctx->sec->debug.dfx; ++ + err = sec_cb_status_check(req, &status); + if (err) + atomic64_inc(&dfx->done_flag_cnt); +@@ -330,7 +330,6 @@ static void sec_req_cb(struct hisi_qp *qp, void *resp) + atomic64_inc(&dfx->recv_cnt); + + ctx->req_op->buf_unmap(ctx, req); +- + ctx->req_op->callback(ctx, req, err); + } + +@@ -348,8 +347,10 @@ static int sec_alg_send_message_retry(struct sec_req *req) + + static int sec_alg_try_enqueue(struct sec_req *req) + { ++ struct hisi_qp *qp = req->qp_ctx->qp; ++ + /* Check if any request is already backlogged */ +- if (!list_empty(&req->backlog->list)) ++ if (!list_empty(&qp->backlog.list)) + return -EBUSY; + + /* Try to enqueue to HW ring */ +@@ -359,17 +360,18 @@ static int sec_alg_try_enqueue(struct sec_req *req) + + static int sec_alg_send_message_maybacklog(struct sec_req *req) + { ++ struct hisi_qp *qp = req->qp_ctx->qp; + int ret; + + ret = sec_alg_try_enqueue(req); + if (ret != -EBUSY) + return ret; + +- spin_lock_bh(&req->backlog->lock); ++ spin_lock_bh(&qp->backlog.lock); + ret = sec_alg_try_enqueue(req); + if (ret == -EBUSY) +- list_add_tail(&req->list, &req->backlog->list); +- spin_unlock_bh(&req->backlog->lock); ++ list_add_tail(&req->list, &qp->backlog.list); ++ spin_unlock_bh(&qp->backlog.lock); + + return ret; + } +@@ -629,13 +631,14 @@ static int sec_create_qp_ctx(struct sec_ctx *ctx, int qp_ctx_id) + qp_ctx->qp = qp; + qp_ctx->ctx = ctx; + +- qp->req_cb = sec_req_cb; ++ if (ctx->type_supported == SEC_BD_TYPE3) ++ qp->req_cb = sec_req_cb3; ++ else ++ qp->req_cb = sec_req_cb; + + spin_lock_init(&qp_ctx->req_lock); + idr_init(&qp_ctx->req_idr); +- spin_lock_init(&qp_ctx->backlog.lock); + spin_lock_init(&qp_ctx->id_lock); +- INIT_LIST_HEAD(&qp_ctx->backlog.list); + qp_ctx->send_head = 0; + + ret = sec_alloc_qp_ctx_resource(ctx, qp_ctx); +@@ -1952,7 +1955,6 @@ static int sec_request_init(struct sec_ctx *ctx, struct sec_req *req) + } while (req->req_id < 0 && ++i < ctx->sec->ctx_q_num); + + req->qp_ctx = qp_ctx; +- req->backlog = &qp_ctx->backlog; + + return 0; + } +diff --git a/include/linux/hisi_acc_qm.h b/include/linux/hisi_acc_qm.h +index ca1ec437a3ca3..9485896d5dc08 100644 +--- a/include/linux/hisi_acc_qm.h ++++ b/include/linux/hisi_acc_qm.h +@@ -447,6 +447,11 @@ struct hisi_qp_ops { + int (*fill_sqe)(void *sqe, void *q_parm, void *d_parm); + }; + ++struct instance_backlog { ++ struct list_head list; ++ spinlock_t lock; ++}; ++ + struct hisi_qp { + u32 qp_id; + u16 sq_depth; +@@ -471,6 +476,9 @@ struct hisi_qp { + bool is_in_kernel; + u16 pasid; + struct uacce_queue *uacce_q; ++ ++ struct instance_backlog backlog; ++ const void **msg; + }; + + static inline int vfs_num_set(const char *val, const struct kernel_param *kp) +-- +2.51.0 + diff --git a/queue-6.19/crypto-hisilicon-sec2-support-skcipher-aead-fallback.patch b/queue-6.19/crypto-hisilicon-sec2-support-skcipher-aead-fallback.patch new file mode 100644 index 0000000000..f6ca5e2c34 --- /dev/null +++ b/queue-6.19/crypto-hisilicon-sec2-support-skcipher-aead-fallback.patch @@ -0,0 +1,220 @@ +From 9ee490c39a678fdae33dc3b3ba414a937c459d7d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 21:44:52 +0800 +Subject: crypto: hisilicon/sec2 - support skcipher/aead fallback for hardware + queue unavailable + +From: Qi Tao + +[ Upstream commit e7507439628052363500d717caffb5c2241854dc ] + +When all hardware queues are busy and no shareable queue, +new processes fail to apply for queues. To avoid affecting +tasks, support fallback mechanism when hardware queues are +unavailable. + +Fixes: c16a70c1f253 ("crypto: hisilicon/sec - add new algorithm mode for AEAD") +Signed-off-by: Qi Tao +Signed-off-by: Chenghai Huang +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/sec2/sec_crypto.c | 62 ++++++++++++++++------ + 1 file changed, 47 insertions(+), 15 deletions(-) + +diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.c b/drivers/crypto/hisilicon/sec2/sec_crypto.c +index d09d081f42dc7..c462b58d30343 100644 +--- a/drivers/crypto/hisilicon/sec2/sec_crypto.c ++++ b/drivers/crypto/hisilicon/sec2/sec_crypto.c +@@ -663,10 +663,8 @@ static int sec_ctx_base_init(struct sec_ctx *ctx) + int i, ret; + + ctx->qps = sec_create_qps(); +- if (!ctx->qps) { +- pr_err("Can not create sec qps!\n"); ++ if (!ctx->qps) + return -ENODEV; +- } + + sec = container_of(ctx->qps[0]->qm, struct sec_dev, qm); + ctx->sec = sec; +@@ -702,6 +700,9 @@ static void sec_ctx_base_uninit(struct sec_ctx *ctx) + { + int i; + ++ if (!ctx->qps) ++ return; ++ + for (i = 0; i < ctx->sec->ctx_q_num; i++) + sec_release_qp_ctx(ctx, &ctx->qp_ctx[i]); + +@@ -713,6 +714,9 @@ static int sec_cipher_init(struct sec_ctx *ctx) + { + struct sec_cipher_ctx *c_ctx = &ctx->c_ctx; + ++ if (!ctx->qps) ++ return 0; ++ + c_ctx->c_key = dma_alloc_coherent(ctx->dev, SEC_MAX_KEY_SIZE, + &c_ctx->c_key_dma, GFP_KERNEL); + if (!c_ctx->c_key) +@@ -725,6 +729,9 @@ static void sec_cipher_uninit(struct sec_ctx *ctx) + { + struct sec_cipher_ctx *c_ctx = &ctx->c_ctx; + ++ if (!ctx->qps) ++ return; ++ + memzero_explicit(c_ctx->c_key, SEC_MAX_KEY_SIZE); + dma_free_coherent(ctx->dev, SEC_MAX_KEY_SIZE, + c_ctx->c_key, c_ctx->c_key_dma); +@@ -746,6 +753,9 @@ static void sec_auth_uninit(struct sec_ctx *ctx) + { + struct sec_auth_ctx *a_ctx = &ctx->a_ctx; + ++ if (!ctx->qps) ++ return; ++ + memzero_explicit(a_ctx->a_key, SEC_MAX_AKEY_SIZE); + dma_free_coherent(ctx->dev, SEC_MAX_AKEY_SIZE, + a_ctx->a_key, a_ctx->a_key_dma); +@@ -783,7 +793,7 @@ static int sec_skcipher_init(struct crypto_skcipher *tfm) + } + + ret = sec_ctx_base_init(ctx); +- if (ret) ++ if (ret && ret != -ENODEV) + return ret; + + ret = sec_cipher_init(ctx); +@@ -892,6 +902,9 @@ static int sec_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key, + struct device *dev = ctx->dev; + int ret; + ++ if (!ctx->qps) ++ goto set_soft_key; ++ + if (c_mode == SEC_CMODE_XTS) { + ret = xts_verify_key(tfm, key, keylen); + if (ret) { +@@ -922,13 +935,14 @@ static int sec_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key, + } + + memcpy(c_ctx->c_key, key, keylen); +- if (c_ctx->fbtfm) { +- ret = crypto_sync_skcipher_setkey(c_ctx->fbtfm, key, keylen); +- if (ret) { +- dev_err(dev, "failed to set fallback skcipher key!\n"); +- return ret; +- } ++ ++set_soft_key: ++ ret = crypto_sync_skcipher_setkey(c_ctx->fbtfm, key, keylen); ++ if (ret) { ++ dev_err(dev, "failed to set fallback skcipher key!\n"); ++ return ret; + } ++ + return 0; + } + +@@ -1392,6 +1406,9 @@ static int sec_aead_setkey(struct crypto_aead *tfm, const u8 *key, + struct crypto_authenc_keys keys; + int ret; + ++ if (!ctx->qps) ++ return sec_aead_fallback_setkey(a_ctx, tfm, key, keylen); ++ + ctx->a_ctx.a_alg = a_alg; + ctx->c_ctx.c_alg = c_alg; + c_ctx->c_mode = c_mode; +@@ -2048,6 +2065,9 @@ static int sec_skcipher_ctx_init(struct crypto_skcipher *tfm) + if (ret) + return ret; + ++ if (!ctx->qps) ++ return 0; ++ + if (ctx->sec->qm.ver < QM_HW_V3) { + ctx->type_supported = SEC_BD_TYPE2; + ctx->req_op = &sec_skcipher_req_ops; +@@ -2056,7 +2076,7 @@ static int sec_skcipher_ctx_init(struct crypto_skcipher *tfm) + ctx->req_op = &sec_skcipher_req_ops_v3; + } + +- return ret; ++ return 0; + } + + static void sec_skcipher_ctx_exit(struct crypto_skcipher *tfm) +@@ -2124,7 +2144,7 @@ static int sec_aead_ctx_init(struct crypto_aead *tfm, const char *hash_name) + int ret; + + ret = sec_aead_init(tfm); +- if (ret) { ++ if (ret && ret != -ENODEV) { + pr_err("hisi_sec2: aead init error!\n"); + return ret; + } +@@ -2166,7 +2186,7 @@ static int sec_aead_xcm_ctx_init(struct crypto_aead *tfm) + int ret; + + ret = sec_aead_init(tfm); +- if (ret) { ++ if (ret && ret != -ENODEV) { + dev_err(ctx->dev, "hisi_sec2: aead xcm init error!\n"); + return ret; + } +@@ -2311,6 +2331,9 @@ static int sec_skcipher_crypto(struct skcipher_request *sk_req, bool encrypt) + bool need_fallback = false; + int ret; + ++ if (!ctx->qps) ++ goto soft_crypto; ++ + if (!sk_req->cryptlen) { + if (ctx->c_ctx.c_mode == SEC_CMODE_XTS) + return -EINVAL; +@@ -2328,9 +2351,12 @@ static int sec_skcipher_crypto(struct skcipher_request *sk_req, bool encrypt) + return -EINVAL; + + if (unlikely(ctx->c_ctx.fallback || need_fallback)) +- return sec_skcipher_soft_crypto(ctx, sk_req, encrypt); ++ goto soft_crypto; + + return ctx->req_op->process(ctx, req); ++ ++soft_crypto: ++ return sec_skcipher_soft_crypto(ctx, sk_req, encrypt); + } + + static int sec_skcipher_encrypt(struct skcipher_request *sk_req) +@@ -2538,6 +2564,9 @@ static int sec_aead_crypto(struct aead_request *a_req, bool encrypt) + bool need_fallback = false; + int ret; + ++ if (!ctx->qps) ++ goto soft_crypto; ++ + req->flag = a_req->base.flags; + req->aead_req.aead_req = a_req; + req->c_req.encrypt = encrypt; +@@ -2548,11 +2577,14 @@ static int sec_aead_crypto(struct aead_request *a_req, bool encrypt) + ret = sec_aead_param_check(ctx, req, &need_fallback); + if (unlikely(ret)) { + if (need_fallback) +- return sec_aead_soft_crypto(ctx, a_req, encrypt); ++ goto soft_crypto; + return -EINVAL; + } + + return ctx->req_op->process(ctx, req); ++ ++soft_crypto: ++ return sec_aead_soft_crypto(ctx, a_req, encrypt); + } + + static int sec_aead_encrypt(struct aead_request *a_req) +-- +2.51.0 + diff --git a/queue-6.19/crypto-hisilicon-sgl-fix-inconsistent-map-unmap-dire.patch b/queue-6.19/crypto-hisilicon-sgl-fix-inconsistent-map-unmap-dire.patch new file mode 100644 index 0000000000..da13c7c2aa --- /dev/null +++ b/queue-6.19/crypto-hisilicon-sgl-fix-inconsistent-map-unmap-dire.patch @@ -0,0 +1,37 @@ +From 0286a6260751a60ead4b9ab33c2ac1cec263fee5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 19 Dec 2025 11:36:19 +0800 +Subject: crypto: hisilicon/sgl - fix inconsistent map/unmap direction issue + +From: Chenghai Huang + +[ Upstream commit 4154f7d3b1c133b909d20c44ecb8277e8482aa6b ] + +Ensure that the direction for dma_map_sg and dma_unmap_sg is +consistent. + +Fixes: 2566de3e06a3 ("crypto: hisilicon - Use fine grained DMA mapping direction") +Signed-off-by: Chenghai Huang +Reviewed-by: Zenghui Yu +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/sgl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/crypto/hisilicon/sgl.c b/drivers/crypto/hisilicon/sgl.c +index 24c7b6ab285ba..d41b34405c21c 100644 +--- a/drivers/crypto/hisilicon/sgl.c ++++ b/drivers/crypto/hisilicon/sgl.c +@@ -260,7 +260,7 @@ hisi_acc_sg_buf_map_to_hw_sgl(struct device *dev, struct scatterlist *sgl, + return curr_hw_sgl; + + err_unmap: +- dma_unmap_sg(dev, sgl, sg_n, DMA_BIDIRECTIONAL); ++ dma_unmap_sg(dev, sgl, sg_n, dir); + + return ERR_PTR(ret); + } +-- +2.51.0 + diff --git a/queue-6.19/crypto-hisilicon-trng-support-tfms-sharing-the-devic.patch b/queue-6.19/crypto-hisilicon-trng-support-tfms-sharing-the-devic.patch new file mode 100644 index 0000000000..81ae7b117a --- /dev/null +++ b/queue-6.19/crypto-hisilicon-trng-support-tfms-sharing-the-devic.patch @@ -0,0 +1,258 @@ +From 086a54ef467fd061003f26f934a4a1663c3b7b87 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 17 Jan 2026 15:18:21 +0800 +Subject: crypto: hisilicon/trng - support tfms sharing the device + +From: Weili Qian + +[ Upstream commit 3d3135057ff567d5c09fff4c9ef6391a684e8042 ] + +Since the number of devices is limited, and the number +of tfms may exceed the number of devices, to ensure that +tfms can be successfully allocated, support tfms +sharing the same device. + +Fixes: e4d9d10ef4be ("crypto: hisilicon/trng - add support for PRNG") +Signed-off-by: Weili Qian +Signed-off-by: Chenghai Huang +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/trng/trng.c | 121 +++++++++++++++++++-------- + 1 file changed, 86 insertions(+), 35 deletions(-) + +diff --git a/drivers/crypto/hisilicon/trng/trng.c b/drivers/crypto/hisilicon/trng/trng.c +index ac74df4a94712..5ca0b90859a81 100644 +--- a/drivers/crypto/hisilicon/trng/trng.c ++++ b/drivers/crypto/hisilicon/trng/trng.c +@@ -40,6 +40,7 @@ + #define SEED_SHIFT_24 24 + #define SEED_SHIFT_16 16 + #define SEED_SHIFT_8 8 ++#define SW_MAX_RANDOM_BYTES 65520 + + struct hisi_trng_list { + struct mutex lock; +@@ -53,8 +54,10 @@ struct hisi_trng { + struct list_head list; + struct hwrng rng; + u32 ver; +- bool is_used; +- struct mutex mutex; ++ u32 ctx_num; ++ /* The bytes of the random number generated since the last seeding. */ ++ u32 random_bytes; ++ struct mutex lock; + }; + + struct hisi_trng_ctx { +@@ -63,10 +66,14 @@ struct hisi_trng_ctx { + + static atomic_t trng_active_devs; + static struct hisi_trng_list trng_devices; ++static int hisi_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait); + +-static void hisi_trng_set_seed(struct hisi_trng *trng, const u8 *seed) ++static int hisi_trng_set_seed(struct hisi_trng *trng, const u8 *seed) + { + u32 val, seed_reg, i; ++ int ret; ++ ++ writel(0x0, trng->base + SW_DRBG_BLOCKS); + + for (i = 0; i < SW_DRBG_SEED_SIZE; + i += SW_DRBG_SEED_SIZE / SW_DRBG_SEED_REGS_NUM) { +@@ -78,6 +85,20 @@ static void hisi_trng_set_seed(struct hisi_trng *trng, const u8 *seed) + seed_reg = (i >> SW_DRBG_NUM_SHIFT) % SW_DRBG_SEED_REGS_NUM; + writel(val, trng->base + SW_DRBG_SEED(seed_reg)); + } ++ ++ writel(SW_DRBG_BLOCKS_NUM | (0x1 << SW_DRBG_ENABLE_SHIFT), ++ trng->base + SW_DRBG_BLOCKS); ++ writel(0x1, trng->base + SW_DRBG_INIT); ++ ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS, ++ val, val & BIT(0), SLEEP_US, TIMEOUT_US); ++ if (ret) { ++ pr_err("failed to init trng(%d)\n", ret); ++ return -EIO; ++ } ++ ++ trng->random_bytes = 0; ++ ++ return 0; + } + + static int hisi_trng_seed(struct crypto_rng *tfm, const u8 *seed, +@@ -85,8 +106,7 @@ static int hisi_trng_seed(struct crypto_rng *tfm, const u8 *seed, + { + struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm); + struct hisi_trng *trng = ctx->trng; +- u32 val = 0; +- int ret = 0; ++ int ret; + + if (slen < SW_DRBG_SEED_SIZE) { + pr_err("slen(%u) is not matched with trng(%d)\n", slen, +@@ -94,43 +114,45 @@ static int hisi_trng_seed(struct crypto_rng *tfm, const u8 *seed, + return -EINVAL; + } + +- writel(0x0, trng->base + SW_DRBG_BLOCKS); +- hisi_trng_set_seed(trng, seed); ++ mutex_lock(&trng->lock); ++ ret = hisi_trng_set_seed(trng, seed); ++ mutex_unlock(&trng->lock); + +- writel(SW_DRBG_BLOCKS_NUM | (0x1 << SW_DRBG_ENABLE_SHIFT), +- trng->base + SW_DRBG_BLOCKS); +- writel(0x1, trng->base + SW_DRBG_INIT); ++ return ret; ++} + +- ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS, +- val, val & BIT(0), SLEEP_US, TIMEOUT_US); +- if (ret) +- pr_err("fail to init trng(%d)\n", ret); ++static int hisi_trng_reseed(struct hisi_trng *trng) ++{ ++ u8 seed[SW_DRBG_SEED_SIZE]; ++ int size; + +- return ret; ++ if (!trng->random_bytes) ++ return 0; ++ ++ size = hisi_trng_read(&trng->rng, seed, SW_DRBG_SEED_SIZE, false); ++ if (size != SW_DRBG_SEED_SIZE) ++ return -EIO; ++ ++ return hisi_trng_set_seed(trng, seed); + } + +-static int hisi_trng_generate(struct crypto_rng *tfm, const u8 *src, +- unsigned int slen, u8 *dstn, unsigned int dlen) ++static int hisi_trng_get_bytes(struct hisi_trng *trng, u8 *dstn, unsigned int dlen) + { +- struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm); +- struct hisi_trng *trng = ctx->trng; + u32 data[SW_DRBG_DATA_NUM]; + u32 currsize = 0; + u32 val = 0; + int ret; + u32 i; + +- if (dlen > SW_DRBG_BLOCKS_NUM * SW_DRBG_BYTES || dlen == 0) { +- pr_err("dlen(%u) exceeds limit(%d)!\n", dlen, +- SW_DRBG_BLOCKS_NUM * SW_DRBG_BYTES); +- return -EINVAL; +- } ++ ret = hisi_trng_reseed(trng); ++ if (ret) ++ return ret; + + do { + ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS, +- val, val & BIT(1), SLEEP_US, TIMEOUT_US); ++ val, val & BIT(1), SLEEP_US, TIMEOUT_US); + if (ret) { +- pr_err("fail to generate random number(%d)!\n", ret); ++ pr_err("failed to generate random number(%d)!\n", ret); + break; + } + +@@ -145,30 +167,57 @@ static int hisi_trng_generate(struct crypto_rng *tfm, const u8 *src, + currsize = dlen; + } + ++ trng->random_bytes += SW_DRBG_BYTES; + writel(0x1, trng->base + SW_DRBG_GEN); + } while (currsize < dlen); + + return ret; + } + ++static int hisi_trng_generate(struct crypto_rng *tfm, const u8 *src, ++ unsigned int slen, u8 *dstn, unsigned int dlen) ++{ ++ struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm); ++ struct hisi_trng *trng = ctx->trng; ++ unsigned int currsize = 0; ++ unsigned int block_size; ++ int ret; ++ ++ if (!dstn || !dlen) { ++ pr_err("output is error, dlen %u!\n", dlen); ++ return -EINVAL; ++ } ++ ++ do { ++ block_size = min_t(unsigned int, dlen - currsize, SW_MAX_RANDOM_BYTES); ++ mutex_lock(&trng->lock); ++ ret = hisi_trng_get_bytes(trng, dstn + currsize, block_size); ++ mutex_unlock(&trng->lock); ++ if (ret) ++ return ret; ++ currsize += block_size; ++ } while (currsize < dlen); ++ ++ return 0; ++} ++ + static int hisi_trng_init(struct crypto_tfm *tfm) + { + struct hisi_trng_ctx *ctx = crypto_tfm_ctx(tfm); + struct hisi_trng *trng; +- int ret = -EBUSY; ++ u32 ctx_num = ~0; + + mutex_lock(&trng_devices.lock); + list_for_each_entry(trng, &trng_devices.list, list) { +- if (!trng->is_used) { +- trng->is_used = true; ++ if (trng->ctx_num < ctx_num) { ++ ctx_num = trng->ctx_num; + ctx->trng = trng; +- ret = 0; +- break; + } + } ++ ctx->trng->ctx_num++; + mutex_unlock(&trng_devices.lock); + +- return ret; ++ return 0; + } + + static void hisi_trng_exit(struct crypto_tfm *tfm) +@@ -176,7 +225,7 @@ static void hisi_trng_exit(struct crypto_tfm *tfm) + struct hisi_trng_ctx *ctx = crypto_tfm_ctx(tfm); + + mutex_lock(&trng_devices.lock); +- ctx->trng->is_used = false; ++ ctx->trng->ctx_num--; + mutex_unlock(&trng_devices.lock); + } + +@@ -238,7 +287,7 @@ static int hisi_trng_del_from_list(struct hisi_trng *trng) + int ret = -EBUSY; + + mutex_lock(&trng_devices.lock); +- if (!trng->is_used) { ++ if (!trng->ctx_num) { + list_del(&trng->list); + ret = 0; + } +@@ -262,7 +311,9 @@ static int hisi_trng_probe(struct platform_device *pdev) + if (IS_ERR(trng->base)) + return PTR_ERR(trng->base); + +- trng->is_used = false; ++ trng->ctx_num = 0; ++ trng->random_bytes = SW_MAX_RANDOM_BYTES; ++ mutex_init(&trng->lock); + trng->ver = readl(trng->base + HISI_TRNG_VERSION); + if (!trng_devices.is_init) { + INIT_LIST_HEAD(&trng_devices.list); +-- +2.51.0 + diff --git a/queue-6.19/crypto-hisilicon-zip-adjust-the-way-to-obtain-the-re.patch b/queue-6.19/crypto-hisilicon-zip-adjust-the-way-to-obtain-the-re.patch new file mode 100644 index 0000000000..64acc510a3 --- /dev/null +++ b/queue-6.19/crypto-hisilicon-zip-adjust-the-way-to-obtain-the-re.patch @@ -0,0 +1,128 @@ +From 4ca1cfbd798f4539dff65783f2237c042d6b90f6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 21:44:42 +0800 +Subject: crypto: hisilicon/zip - adjust the way to obtain the req in the + callback function + +From: Chenghai Huang + +[ Upstream commit 19c2475ce1984cf675ebfbbeaa5509b2fb1887d6 ] + +In the shared queue design, multiple tfms use same qp, and one qp +need to corresponds to multiple qp_ctx. So use tag to obtain the +req virtual address. Build a one-to-one relationship between tfm +and qp_ctx. finaly remove the old get_tag operation. + +Fixes: 2bcf36348ce5 ("crypto: hisilicon/zip - initialize operations about 'sqe' in 'acomp_alg.init'") +Signed-off-by: Chenghai Huang +Signed-off-by: Weili Qian +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/zip/zip_crypto.c | 24 +++++++++-------------- + 1 file changed, 9 insertions(+), 15 deletions(-) + +diff --git a/drivers/crypto/hisilicon/zip/zip_crypto.c b/drivers/crypto/hisilicon/zip/zip_crypto.c +index b97513981a3b7..b4a656e0177d2 100644 +--- a/drivers/crypto/hisilicon/zip/zip_crypto.c ++++ b/drivers/crypto/hisilicon/zip/zip_crypto.c +@@ -39,6 +39,7 @@ enum { + HZIP_CTX_Q_NUM + }; + ++#define GET_REQ_FROM_SQE(sqe) ((u64)(sqe)->dw26 | (u64)(sqe)->dw27 << 32) + #define COMP_NAME_TO_TYPE(alg_name) \ + (!strcmp((alg_name), "deflate") ? HZIP_ALG_TYPE_DEFLATE : 0) + +@@ -48,6 +49,7 @@ struct hisi_zip_req { + struct hisi_acc_hw_sgl *hw_dst; + dma_addr_t dma_src; + dma_addr_t dma_dst; ++ struct hisi_zip_qp_ctx *qp_ctx; + u16 req_id; + }; + +@@ -74,7 +76,6 @@ struct hisi_zip_sqe_ops { + void (*fill_req_type)(struct hisi_zip_sqe *sqe, u8 req_type); + void (*fill_tag)(struct hisi_zip_sqe *sqe, struct hisi_zip_req *req); + void (*fill_sqe_type)(struct hisi_zip_sqe *sqe, u8 sqe_type); +- u32 (*get_tag)(struct hisi_zip_sqe *sqe); + u32 (*get_status)(struct hisi_zip_sqe *sqe); + u32 (*get_dstlen)(struct hisi_zip_sqe *sqe); + }; +@@ -131,6 +132,7 @@ static struct hisi_zip_req *hisi_zip_create_req(struct hisi_zip_qp_ctx *qp_ctx, + req_cache = q + req_id; + req_cache->req_id = req_id; + req_cache->req = req; ++ req_cache->qp_ctx = qp_ctx; + + return req_cache; + } +@@ -181,7 +183,8 @@ static void hisi_zip_fill_req_type(struct hisi_zip_sqe *sqe, u8 req_type) + + static void hisi_zip_fill_tag(struct hisi_zip_sqe *sqe, struct hisi_zip_req *req) + { +- sqe->dw26 = req->req_id; ++ sqe->dw26 = lower_32_bits((u64)req); ++ sqe->dw27 = upper_32_bits((u64)req); + } + + static void hisi_zip_fill_sqe_type(struct hisi_zip_sqe *sqe, u8 sqe_type) +@@ -237,7 +240,7 @@ static int hisi_zip_do_work(struct hisi_zip_qp_ctx *qp_ctx, + &req->dma_dst, DMA_FROM_DEVICE); + if (IS_ERR(req->hw_dst)) { + ret = PTR_ERR(req->hw_dst); +- dev_err(dev, "failed to map the dst buffer to hw slg (%d)!\n", ++ dev_err(dev, "failed to map the dst buffer to hw sgl (%d)!\n", + ret); + goto err_unmap_input; + } +@@ -265,11 +268,6 @@ static int hisi_zip_do_work(struct hisi_zip_qp_ctx *qp_ctx, + return ret; + } + +-static u32 hisi_zip_get_tag(struct hisi_zip_sqe *sqe) +-{ +- return sqe->dw26; +-} +- + static u32 hisi_zip_get_status(struct hisi_zip_sqe *sqe) + { + return sqe->dw3 & HZIP_BD_STATUS_M; +@@ -282,14 +280,12 @@ static u32 hisi_zip_get_dstlen(struct hisi_zip_sqe *sqe) + + static void hisi_zip_acomp_cb(struct hisi_qp *qp, void *data) + { +- struct hisi_zip_qp_ctx *qp_ctx = qp->qp_ctx; ++ struct hisi_zip_sqe *sqe = data; ++ struct hisi_zip_req *req = (struct hisi_zip_req *)GET_REQ_FROM_SQE(sqe); ++ struct hisi_zip_qp_ctx *qp_ctx = req->qp_ctx; + const struct hisi_zip_sqe_ops *ops = qp_ctx->ctx->ops; + struct hisi_zip_dfx *dfx = &qp_ctx->zip_dev->dfx; +- struct hisi_zip_req_q *req_q = &qp_ctx->req_q; + struct device *dev = &qp->qm->pdev->dev; +- struct hisi_zip_sqe *sqe = data; +- u32 tag = ops->get_tag(sqe); +- struct hisi_zip_req *req = req_q->q + tag; + struct acomp_req *acomp_req = req->req; + int err = 0; + u32 status; +@@ -393,7 +389,6 @@ static const struct hisi_zip_sqe_ops hisi_zip_ops = { + .fill_req_type = hisi_zip_fill_req_type, + .fill_tag = hisi_zip_fill_tag, + .fill_sqe_type = hisi_zip_fill_sqe_type, +- .get_tag = hisi_zip_get_tag, + .get_status = hisi_zip_get_status, + .get_dstlen = hisi_zip_get_dstlen, + }; +@@ -581,7 +576,6 @@ static void hisi_zip_acomp_exit(struct crypto_acomp *tfm) + { + struct hisi_zip_ctx *ctx = crypto_tfm_ctx(&tfm->base); + +- hisi_zip_set_acomp_cb(ctx, NULL); + hisi_zip_release_sgl_pool(ctx); + hisi_zip_release_req_q(ctx); + hisi_zip_ctx_exit(ctx); +-- +2.51.0 + diff --git a/queue-6.19/crypto-hisilicon-zip-support-fallback-for-zip.patch b/queue-6.19/crypto-hisilicon-zip-support-fallback-for-zip.patch new file mode 100644 index 0000000000..5606417f7a --- /dev/null +++ b/queue-6.19/crypto-hisilicon-zip-support-fallback-for-zip.patch @@ -0,0 +1,152 @@ +From 61a28ff3e06da8b7ce73b4d70374458458833cde Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 21:44:50 +0800 +Subject: crypto: hisilicon/zip - support fallback for zip + +From: Chenghai Huang + +[ Upstream commit 73398f85a430cfebc2ff06ab836d6d9eb1484c79 ] + +When the hardware queue resource busy(no shareable queue) +or memery alloc fail in initialization of acomp_alg, use +soft algorithm to complete the work. + +Fixes: 1a9e6f59caee ("crypto: hisilicon/zip - remove zlib and gzip") +Signed-off-by: Chenghai Huang +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/Kconfig | 1 + + drivers/crypto/hisilicon/zip/zip_crypto.c | 50 +++++++++++++++++++---- + 2 files changed, 43 insertions(+), 8 deletions(-) + +diff --git a/drivers/crypto/hisilicon/Kconfig b/drivers/crypto/hisilicon/Kconfig +index 4835bdebdbb38..a0cb1a8186ac9 100644 +--- a/drivers/crypto/hisilicon/Kconfig ++++ b/drivers/crypto/hisilicon/Kconfig +@@ -57,6 +57,7 @@ config CRYPTO_DEV_HISI_ZIP + depends on UACCE || UACCE=n + depends on ACPI + select CRYPTO_DEV_HISI_QM ++ select CRYPTO_DEFLATE + help + Support for HiSilicon ZIP Driver + +diff --git a/drivers/crypto/hisilicon/zip/zip_crypto.c b/drivers/crypto/hisilicon/zip/zip_crypto.c +index 2f9035c016f3f..5fc2ed9d5eef3 100644 +--- a/drivers/crypto/hisilicon/zip/zip_crypto.c ++++ b/drivers/crypto/hisilicon/zip/zip_crypto.c +@@ -84,6 +84,7 @@ struct hisi_zip_sqe_ops { + struct hisi_zip_ctx { + struct hisi_zip_qp_ctx qp_ctx[HZIP_CTX_Q_NUM]; + const struct hisi_zip_sqe_ops *ops; ++ bool fallback; + }; + + static int sgl_sge_nr_set(const char *val, const struct kernel_param *kp) +@@ -110,6 +111,24 @@ static u16 sgl_sge_nr = HZIP_SGL_SGE_NR; + module_param_cb(sgl_sge_nr, &sgl_sge_nr_ops, &sgl_sge_nr, 0444); + MODULE_PARM_DESC(sgl_sge_nr, "Number of sge in sgl(1-255)"); + ++static int hisi_zip_fallback_do_work(struct acomp_req *acomp_req, bool is_decompress) ++{ ++ ACOMP_FBREQ_ON_STACK(fbreq, acomp_req); ++ int ret; ++ ++ if (!is_decompress) ++ ret = crypto_acomp_compress(fbreq); ++ else ++ ret = crypto_acomp_decompress(fbreq); ++ if (ret) { ++ pr_err("failed to do fallback work, ret=%d\n", ret); ++ return ret; ++ } ++ ++ acomp_req->dlen = fbreq->dlen; ++ return ret; ++} ++ + static struct hisi_zip_req *hisi_zip_create_req(struct hisi_zip_qp_ctx *qp_ctx, + struct acomp_req *req) + { +@@ -313,10 +332,15 @@ static int hisi_zip_acompress(struct acomp_req *acomp_req) + { + struct hisi_zip_ctx *ctx = crypto_tfm_ctx(acomp_req->base.tfm); + struct hisi_zip_qp_ctx *qp_ctx = &ctx->qp_ctx[HZIP_QPC_COMP]; +- struct device *dev = &qp_ctx->qp->qm->pdev->dev; + struct hisi_zip_req *req; ++ struct device *dev; + int ret; + ++ if (ctx->fallback) ++ return hisi_zip_fallback_do_work(acomp_req, 0); ++ ++ dev = &qp_ctx->qp->qm->pdev->dev; ++ + req = hisi_zip_create_req(qp_ctx, acomp_req); + if (IS_ERR(req)) + return PTR_ERR(req); +@@ -334,10 +358,15 @@ static int hisi_zip_adecompress(struct acomp_req *acomp_req) + { + struct hisi_zip_ctx *ctx = crypto_tfm_ctx(acomp_req->base.tfm); + struct hisi_zip_qp_ctx *qp_ctx = &ctx->qp_ctx[HZIP_QPC_DECOMP]; +- struct device *dev = &qp_ctx->qp->qm->pdev->dev; + struct hisi_zip_req *req; ++ struct device *dev; + int ret; + ++ if (ctx->fallback) ++ return hisi_zip_fallback_do_work(acomp_req, 1); ++ ++ dev = &qp_ctx->qp->qm->pdev->dev; ++ + req = hisi_zip_create_req(qp_ctx, acomp_req); + if (IS_ERR(req)) + return PTR_ERR(req); +@@ -546,7 +575,7 @@ static int hisi_zip_acomp_init(struct crypto_acomp *tfm) + ret = hisi_zip_ctx_init(ctx, COMP_NAME_TO_TYPE(alg_name), tfm->base.node); + if (ret) { + pr_err("failed to init ctx (%d)!\n", ret); +- return ret; ++ goto switch_to_soft; + } + + dev = &ctx->qp_ctx[0].qp->qm->pdev->dev; +@@ -571,16 +600,20 @@ static int hisi_zip_acomp_init(struct crypto_acomp *tfm) + hisi_zip_release_req_q(ctx); + err_ctx_exit: + hisi_zip_ctx_exit(ctx); +- return ret; ++switch_to_soft: ++ ctx->fallback = true; ++ return 0; + } + + static void hisi_zip_acomp_exit(struct crypto_acomp *tfm) + { + struct hisi_zip_ctx *ctx = crypto_tfm_ctx(&tfm->base); + +- hisi_zip_release_sgl_pool(ctx); +- hisi_zip_release_req_q(ctx); +- hisi_zip_ctx_exit(ctx); ++ if (!ctx->fallback) { ++ hisi_zip_release_sgl_pool(ctx); ++ hisi_zip_release_req_q(ctx); ++ hisi_zip_ctx_exit(ctx); ++ } + } + + static struct acomp_alg hisi_zip_acomp_deflate = { +@@ -591,7 +624,8 @@ static struct acomp_alg hisi_zip_acomp_deflate = { + .base = { + .cra_name = "deflate", + .cra_driver_name = "hisi-deflate-acomp", +- .cra_flags = CRYPTO_ALG_ASYNC, ++ .cra_flags = CRYPTO_ALG_ASYNC | ++ CRYPTO_ALG_NEED_FALLBACK, + .cra_module = THIS_MODULE, + .cra_priority = HZIP_ALG_PRIORITY, + .cra_ctxsize = sizeof(struct hisi_zip_ctx), +-- +2.51.0 + diff --git a/queue-6.19/crypto-inside-secure-eip93-fix-kernel-panic-in-drive.patch b/queue-6.19/crypto-inside-secure-eip93-fix-kernel-panic-in-drive.patch new file mode 100644 index 0000000000..b271aa3a3d --- /dev/null +++ b/queue-6.19/crypto-inside-secure-eip93-fix-kernel-panic-in-drive.patch @@ -0,0 +1,37 @@ +From 57155ca135fddbcfd906d00debe0219107d5add8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Dec 2025 22:17:17 +0100 +Subject: crypto: inside-secure/eip93 - fix kernel panic in driver detach + +From: Aleksander Jan Bajkowski + +[ Upstream commit b6e32ba6d32503440a3e3e16c8d0521cbb7e0c5d ] + +During driver detach, the same hash algorithm is unregistered multiple +times due to a wrong iterator. + +Fixes: 9739f5f93b78 ("crypto: eip93 - Add Inside Secure SafeXcel EIP-93 crypto engine support") +Signed-off-by: Aleksander Jan Bajkowski +Reviewed-by: Antoine Tenart +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/inside-secure/eip93/eip93-main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/crypto/inside-secure/eip93/eip93-main.c b/drivers/crypto/inside-secure/eip93/eip93-main.c +index 0b38a567da0e0..3cdc3308dcac8 100644 +--- a/drivers/crypto/inside-secure/eip93/eip93-main.c ++++ b/drivers/crypto/inside-secure/eip93/eip93-main.c +@@ -90,7 +90,7 @@ static void eip93_unregister_algs(unsigned int i) + crypto_unregister_aead(&eip93_algs[j]->alg.aead); + break; + case EIP93_ALG_TYPE_HASH: +- crypto_unregister_ahash(&eip93_algs[i]->alg.ahash); ++ crypto_unregister_ahash(&eip93_algs[j]->alg.ahash); + break; + } + } +-- +2.51.0 + diff --git a/queue-6.19/crypto-inside-secure-eip93-unregister-only-available.patch b/queue-6.19/crypto-inside-secure-eip93-unregister-only-available.patch new file mode 100644 index 0000000000..166db57906 --- /dev/null +++ b/queue-6.19/crypto-inside-secure-eip93-unregister-only-available.patch @@ -0,0 +1,164 @@ +From c6b490a1c594b487307ab9c02b79f024dc07cc17 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 11 Jan 2026 14:20:32 +0100 +Subject: crypto: inside-secure/eip93 - unregister only available algorithm + +From: Aleksander Jan Bajkowski + +[ Upstream commit 0ceeadc7b53a041d89d5843f6bf0ccb7c98b0b4f ] + +EIP93 has an options register. This register indicates which crypto +algorithms are implemented in silicon. Supported algorithms are +registered on this basis. Unregister algorithms on the same basis. +Currently, all algorithms are unregistered, even those not supported +by HW. This results in panic on platforms that don't have all options +implemented in silicon. + +Fixes: 9739f5f93b78 ("crypto: eip93 - Add Inside Secure SafeXcel EIP-93 crypto engine support") +Signed-off-by: Aleksander Jan Bajkowski +Acked-by: Antoine Tenart +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + .../crypto/inside-secure/eip93/eip93-main.c | 92 +++++++++++-------- + 1 file changed, 53 insertions(+), 39 deletions(-) + +diff --git a/drivers/crypto/inside-secure/eip93/eip93-main.c b/drivers/crypto/inside-secure/eip93/eip93-main.c +index 3cdc3308dcac8..b7fd9795062d4 100644 +--- a/drivers/crypto/inside-secure/eip93/eip93-main.c ++++ b/drivers/crypto/inside-secure/eip93/eip93-main.c +@@ -77,11 +77,44 @@ inline void eip93_irq_clear(struct eip93_device *eip93, u32 mask) + __raw_writel(mask, eip93->base + EIP93_REG_INT_CLR); + } + +-static void eip93_unregister_algs(unsigned int i) ++static int eip93_algo_is_supported(u32 alg_flags, u32 supported_algo_flags) ++{ ++ if ((IS_DES(alg_flags) || IS_3DES(alg_flags)) && ++ !(supported_algo_flags & EIP93_PE_OPTION_TDES)) ++ return 0; ++ ++ if (IS_AES(alg_flags) && ++ !(supported_algo_flags & EIP93_PE_OPTION_AES)) ++ return 0; ++ ++ if (IS_HASH_MD5(alg_flags) && ++ !(supported_algo_flags & EIP93_PE_OPTION_MD5)) ++ return 0; ++ ++ if (IS_HASH_SHA1(alg_flags) && ++ !(supported_algo_flags & EIP93_PE_OPTION_SHA_1)) ++ return 0; ++ ++ if (IS_HASH_SHA224(alg_flags) && ++ !(supported_algo_flags & EIP93_PE_OPTION_SHA_224)) ++ return 0; ++ ++ if (IS_HASH_SHA256(alg_flags) && ++ !(supported_algo_flags & EIP93_PE_OPTION_SHA_256)) ++ return 0; ++ ++ return 1; ++} ++ ++static void eip93_unregister_algs(u32 supported_algo_flags, unsigned int i) + { + unsigned int j; + + for (j = 0; j < i; j++) { ++ if (!eip93_algo_is_supported(eip93_algs[j]->flags, ++ supported_algo_flags)) ++ continue; ++ + switch (eip93_algs[j]->type) { + case EIP93_ALG_TYPE_SKCIPHER: + crypto_unregister_skcipher(&eip93_algs[j]->alg.skcipher); +@@ -106,49 +139,27 @@ static int eip93_register_algs(struct eip93_device *eip93, u32 supported_algo_fl + + eip93_algs[i]->eip93 = eip93; + +- if ((IS_DES(alg_flags) || IS_3DES(alg_flags)) && +- !(supported_algo_flags & EIP93_PE_OPTION_TDES)) ++ if (!eip93_algo_is_supported(alg_flags, supported_algo_flags)) + continue; + +- if (IS_AES(alg_flags)) { +- if (!(supported_algo_flags & EIP93_PE_OPTION_AES)) +- continue; ++ if (IS_AES(alg_flags) && !IS_HMAC(alg_flags)) { ++ if (supported_algo_flags & EIP93_PE_OPTION_AES_KEY128) ++ eip93_algs[i]->alg.skcipher.max_keysize = ++ AES_KEYSIZE_128; + +- if (!IS_HMAC(alg_flags)) { +- if (supported_algo_flags & EIP93_PE_OPTION_AES_KEY128) +- eip93_algs[i]->alg.skcipher.max_keysize = +- AES_KEYSIZE_128; ++ if (supported_algo_flags & EIP93_PE_OPTION_AES_KEY192) ++ eip93_algs[i]->alg.skcipher.max_keysize = ++ AES_KEYSIZE_192; + +- if (supported_algo_flags & EIP93_PE_OPTION_AES_KEY192) +- eip93_algs[i]->alg.skcipher.max_keysize = +- AES_KEYSIZE_192; ++ if (supported_algo_flags & EIP93_PE_OPTION_AES_KEY256) ++ eip93_algs[i]->alg.skcipher.max_keysize = ++ AES_KEYSIZE_256; + +- if (supported_algo_flags & EIP93_PE_OPTION_AES_KEY256) +- eip93_algs[i]->alg.skcipher.max_keysize = +- AES_KEYSIZE_256; +- +- if (IS_RFC3686(alg_flags)) +- eip93_algs[i]->alg.skcipher.max_keysize += +- CTR_RFC3686_NONCE_SIZE; +- } ++ if (IS_RFC3686(alg_flags)) ++ eip93_algs[i]->alg.skcipher.max_keysize += ++ CTR_RFC3686_NONCE_SIZE; + } + +- if (IS_HASH_MD5(alg_flags) && +- !(supported_algo_flags & EIP93_PE_OPTION_MD5)) +- continue; +- +- if (IS_HASH_SHA1(alg_flags) && +- !(supported_algo_flags & EIP93_PE_OPTION_SHA_1)) +- continue; +- +- if (IS_HASH_SHA224(alg_flags) && +- !(supported_algo_flags & EIP93_PE_OPTION_SHA_224)) +- continue; +- +- if (IS_HASH_SHA256(alg_flags) && +- !(supported_algo_flags & EIP93_PE_OPTION_SHA_256)) +- continue; +- + switch (eip93_algs[i]->type) { + case EIP93_ALG_TYPE_SKCIPHER: + ret = crypto_register_skcipher(&eip93_algs[i]->alg.skcipher); +@@ -167,7 +178,7 @@ static int eip93_register_algs(struct eip93_device *eip93, u32 supported_algo_fl + return 0; + + fail: +- eip93_unregister_algs(i); ++ eip93_unregister_algs(supported_algo_flags, i); + + return ret; + } +@@ -469,8 +480,11 @@ static int eip93_crypto_probe(struct platform_device *pdev) + static void eip93_crypto_remove(struct platform_device *pdev) + { + struct eip93_device *eip93 = platform_get_drvdata(pdev); ++ u32 algo_flags; ++ ++ algo_flags = readl(eip93->base + EIP93_REG_PE_OPTION_1); + +- eip93_unregister_algs(ARRAY_SIZE(eip93_algs)); ++ eip93_unregister_algs(algo_flags, ARRAY_SIZE(eip93_algs)); + eip93_cleanup(eip93); + } + +-- +2.51.0 + diff --git a/queue-6.19/crypto-octeontx-fix-dma_free_coherent-size.patch b/queue-6.19/crypto-octeontx-fix-dma_free_coherent-size.patch new file mode 100644 index 0000000000..5b6f1fae6a --- /dev/null +++ b/queue-6.19/crypto-octeontx-fix-dma_free_coherent-size.patch @@ -0,0 +1,38 @@ +From ad2a158b42257e8a4e06b4db02931e1a6075d265 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 11:12:57 +0100 +Subject: crypto: octeontx - fix dma_free_coherent() size + +From: Thomas Fourier + +[ Upstream commit 624a6760bf8464965c17c8df10b40b557eaa3002 ] + +The size of the buffer in alloc_command_queues() is +curr->size + OTX_CPT_NEXT_CHUNK_PTR_SIZE, so used that length for +dma_free_coherent(). + +Fixes: 10b4f09491bf ("crypto: marvell - add the Virtual Function driver for CPT") +Signed-off-by: Thomas Fourier +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/marvell/octeontx/otx_cptvf_main.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/crypto/marvell/octeontx/otx_cptvf_main.c b/drivers/crypto/marvell/octeontx/otx_cptvf_main.c +index 88a41d1ca5f64..6c0bfb3ea1c9f 100644 +--- a/drivers/crypto/marvell/octeontx/otx_cptvf_main.c ++++ b/drivers/crypto/marvell/octeontx/otx_cptvf_main.c +@@ -168,7 +168,8 @@ static void free_command_queues(struct otx_cptvf *cptvf, + chunk = list_first_entry(&cqinfo->queue[i].chead, + struct otx_cpt_cmd_chunk, nextchunk); + +- dma_free_coherent(&pdev->dev, chunk->size, ++ dma_free_coherent(&pdev->dev, ++ chunk->size + OTX_CPT_NEXT_CHUNK_PTR_SIZE, + chunk->head, + chunk->dma_addr); + chunk->head = NULL; +-- +2.51.0 + diff --git a/queue-6.19/crypto-qat-fix-parameter-order-used-in-icp_qat_fw_co.patch b/queue-6.19/crypto-qat-fix-parameter-order-used-in-icp_qat_fw_co.patch new file mode 100644 index 0000000000..cf6829538f --- /dev/null +++ b/queue-6.19/crypto-qat-fix-parameter-order-used-in-icp_qat_fw_co.patch @@ -0,0 +1,79 @@ +From 19b796dbd8660f3bde2c77dd81ceb523c99f5ac2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 20 Nov 2025 16:29:23 +0000 +Subject: crypto: qat - fix parameter order used in ICP_QAT_FW_COMN_FLAGS_BUILD + +From: Giovanni Cabiddu + +[ Upstream commit e3d036fecd6f89d4d262034de7bef8d6e49b661b ] + +The macro ICP_QAT_FW_COMN_FLAGS_BUILD sets flags in the firmware +descriptor to indicate: + + * Whether the content descriptor is a pointer or contains embedded + data. + * Whether the source and destination buffers are scatter-gather lists + or flat buffers. + +The correct parameter order is: + + * First: content descriptor type + * Second: source/destination pointer type + +In the asymmetric crypto code, the macro was used with the parameters +swapped. Although this does not cause functional issues, since both +macros currently evaluate to 0, it is incorrect. + +Fix the parameter order in the Diffie-Hellman and RSA code paths. + +Fixes: a990532023b9 ("crypto: qat - Add support for RSA algorithm") +Fixes: c9839143ebbf ("crypto: qat - Add DH support") +Reported-by: Qihua Dai # off-list +Reviewed-by: Ahsan Atta +Signed-off-by: Giovanni Cabiddu +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/intel/qat/qat_common/qat_asym_algs.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/crypto/intel/qat/qat_common/qat_asym_algs.c b/drivers/crypto/intel/qat/qat_common/qat_asym_algs.c +index 85c682e248fb9..e09b9edfce423 100644 +--- a/drivers/crypto/intel/qat/qat_common/qat_asym_algs.c ++++ b/drivers/crypto/intel/qat/qat_common/qat_asym_algs.c +@@ -255,8 +255,8 @@ static int qat_dh_compute_value(struct kpp_request *req) + qat_req->areq.dh = req; + msg->pke_hdr.service_type = ICP_QAT_FW_COMN_REQ_CPM_FW_PKE; + msg->pke_hdr.comn_req_flags = +- ICP_QAT_FW_COMN_FLAGS_BUILD(QAT_COMN_PTR_TYPE_FLAT, +- QAT_COMN_CD_FLD_TYPE_64BIT_ADR); ++ ICP_QAT_FW_COMN_FLAGS_BUILD(QAT_COMN_CD_FLD_TYPE_64BIT_ADR, ++ QAT_COMN_PTR_TYPE_FLAT); + + /* + * If no source is provided use g as base +@@ -731,8 +731,8 @@ static int qat_rsa_enc(struct akcipher_request *req) + qat_req->areq.rsa = req; + msg->pke_hdr.service_type = ICP_QAT_FW_COMN_REQ_CPM_FW_PKE; + msg->pke_hdr.comn_req_flags = +- ICP_QAT_FW_COMN_FLAGS_BUILD(QAT_COMN_PTR_TYPE_FLAT, +- QAT_COMN_CD_FLD_TYPE_64BIT_ADR); ++ ICP_QAT_FW_COMN_FLAGS_BUILD(QAT_COMN_CD_FLD_TYPE_64BIT_ADR, ++ QAT_COMN_PTR_TYPE_FLAT); + + qat_req->in.rsa.enc.e = ctx->dma_e; + qat_req->in.rsa.enc.n = ctx->dma_n; +@@ -867,8 +867,8 @@ static int qat_rsa_dec(struct akcipher_request *req) + qat_req->areq.rsa = req; + msg->pke_hdr.service_type = ICP_QAT_FW_COMN_REQ_CPM_FW_PKE; + msg->pke_hdr.comn_req_flags = +- ICP_QAT_FW_COMN_FLAGS_BUILD(QAT_COMN_PTR_TYPE_FLAT, +- QAT_COMN_CD_FLD_TYPE_64BIT_ADR); ++ ICP_QAT_FW_COMN_FLAGS_BUILD(QAT_COMN_CD_FLD_TYPE_64BIT_ADR, ++ QAT_COMN_PTR_TYPE_FLAT); + + if (ctx->crt_mode) { + qat_req->in.rsa.dec_crt.p = ctx->dma_p; +-- +2.51.0 + diff --git a/queue-6.19/crypto-qat-fix-warning-on-adf_pfvf_pf_proto.c.patch b/queue-6.19/crypto-qat-fix-warning-on-adf_pfvf_pf_proto.c.patch new file mode 100644 index 0000000000..8b953bd28c --- /dev/null +++ b/queue-6.19/crypto-qat-fix-warning-on-adf_pfvf_pf_proto.c.patch @@ -0,0 +1,63 @@ +From 85075962e6888628e54308bccb901931e314f804 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 20 Nov 2025 16:30:46 +0000 +Subject: crypto: qat - fix warning on adf_pfvf_pf_proto.c +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Giovanni Cabiddu + +[ Upstream commit 994689b8f91b02fdb5f64cba2412cde5ef3084b5 ] + +Building the QAT driver with -Wmaybe-uninitialized triggers warnings in +qat_common/adf_pfvf_pf_proto.c. Specifically, the variables blk_type, +blk_byte, and byte_max may be used uninitialized in handle_blkmsg_req(): + + make M=drivers/crypto/intel/qat W=1 C=2 "KCFLAGS=-Werror" \ + KBUILD_CFLAGS_KERNEL=-Wmaybe-uninitialized \ + CFLAGS_MODULE=-Wmaybe-uninitialized + + ... + warning: ‘byte_max’ may be used uninitialized [-Wmaybe-uninitialized] + warning: ‘blk_type’ may be used uninitialized [-Wmaybe-uninitialized] + warning: ‘blk_byte’ may be used uninitialized [-Wmaybe-uninitialized] + +Although the caller of handle_blkmsg_req() always provides a req.type +that is handled by the switch, the compiler cannot guarantee this. + +Add a default case to the switch statement to handle an invalid req.type. + +Fixes: 673184a2a58f ("crypto: qat - introduce support for PFVF block messages") +Signed-off-by: Giovanni Cabiddu +Reviewed-by: Ahsan Atta +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + .../crypto/intel/qat/qat_common/adf_pfvf_pf_proto.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/crypto/intel/qat/qat_common/adf_pfvf_pf_proto.c b/drivers/crypto/intel/qat/qat_common/adf_pfvf_pf_proto.c +index b9b5e744a3f16..af8dbc7517cf8 100644 +--- a/drivers/crypto/intel/qat/qat_common/adf_pfvf_pf_proto.c ++++ b/drivers/crypto/intel/qat/qat_common/adf_pfvf_pf_proto.c +@@ -148,6 +148,16 @@ static struct pfvf_message handle_blkmsg_req(struct adf_accel_vf_info *vf_info, + blk_byte = FIELD_GET(ADF_VF2PF_SMALL_BLOCK_BYTE_MASK, req.data); + byte_max = ADF_VF2PF_SMALL_BLOCK_BYTE_MAX; + break; ++ default: ++ dev_err(&GET_DEV(vf_info->accel_dev), ++ "Invalid BlockMsg type 0x%.4x received from VF%u\n", ++ req.type, vf_info->vf_nr); ++ resp.type = ADF_PF2VF_MSGTYPE_BLKMSG_RESP; ++ resp.data = FIELD_PREP(ADF_PF2VF_BLKMSG_RESP_TYPE_MASK, ++ ADF_PF2VF_BLKMSG_RESP_TYPE_ERROR) | ++ FIELD_PREP(ADF_PF2VF_BLKMSG_RESP_DATA_MASK, ++ ADF_PF2VF_UNSPECIFIED_ERROR); ++ return resp; + } + + /* Is this a request for CRC or data? */ +-- +2.51.0 + diff --git a/queue-6.19/crypto-starfive-fix-memory-leak-in-starfive_aes_aead.patch b/queue-6.19/crypto-starfive-fix-memory-leak-in-starfive_aes_aead.patch new file mode 100644 index 0000000000..8639c062b3 --- /dev/null +++ b/queue-6.19/crypto-starfive-fix-memory-leak-in-starfive_aes_aead.patch @@ -0,0 +1,60 @@ +From 701a218636c74b927b464c35309960c6e7fc8ac7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 15:10:16 +0000 +Subject: crypto: starfive - Fix memory leak in starfive_aes_aead_do_one_req() + +From: Zilin Guan + +[ Upstream commit ccb679fdae2e62ed92fd9acb25ed809c0226fcc6 ] + +The starfive_aes_aead_do_one_req() function allocates rctx->adata with +kzalloc() but fails to free it if sg_copy_to_buffer() or +starfive_aes_hw_init() fails, which lead to memory leaks. + +Since rctx->adata is unconditionally freed after the write_adata +operations, ensure consistent cleanup by freeing the allocation in these +earlier error paths as well. + +Compile tested only. Issue found using a prototype static analysis tool +and code review. + +Fixes: 7467147ef9bf ("crypto: starfive - Use dma for aes requests") +Signed-off-by: Zilin Guan +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/starfive/jh7110-aes.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/drivers/crypto/starfive/jh7110-aes.c b/drivers/crypto/starfive/jh7110-aes.c +index 426b24889af85..01195664cc7cd 100644 +--- a/drivers/crypto/starfive/jh7110-aes.c ++++ b/drivers/crypto/starfive/jh7110-aes.c +@@ -669,8 +669,10 @@ static int starfive_aes_aead_do_one_req(struct crypto_engine *engine, void *areq + return -ENOMEM; + + if (sg_copy_to_buffer(req->src, sg_nents_for_len(req->src, cryp->assoclen), +- rctx->adata, cryp->assoclen) != cryp->assoclen) ++ rctx->adata, cryp->assoclen) != cryp->assoclen) { ++ kfree(rctx->adata); + return -EINVAL; ++ } + } + + if (cryp->total_in) +@@ -681,8 +683,11 @@ static int starfive_aes_aead_do_one_req(struct crypto_engine *engine, void *areq + ctx->rctx = rctx; + + ret = starfive_aes_hw_init(ctx); +- if (ret) ++ if (ret) { ++ if (cryp->assoclen) ++ kfree(rctx->adata); + return ret; ++ } + + if (!cryp->assoclen) + goto write_text; +-- +2.51.0 + diff --git a/queue-6.19/cxl-core-fix-cxl_dport-debugfs-einj-entries.patch b/queue-6.19/cxl-core-fix-cxl_dport-debugfs-einj-entries.patch new file mode 100644 index 0000000000..1197928a9d --- /dev/null +++ b/queue-6.19/cxl-core-fix-cxl_dport-debugfs-einj-entries.patch @@ -0,0 +1,61 @@ +From 28f7feee544447d3b0cb25fdd6f9a927ba70ed52 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 07:57:38 -0600 +Subject: cxl/core: Fix cxl_dport debugfs EINJ entries + +From: Cheatham, Benjamin + +[ Upstream commit 4ed7952b9e87cf731ebc8251874416e60eb15230 ] + +Protocol error injection is only valid for CXL 2.0+ root ports and CXL +1.1 memory-mapped downstream ports as per the ACPI v6.5 spec (Table +8-31). The core code currently creates an 'einj_inject' file in CXL debugfs +for all CXL 1.1 downstream ports and all PCI CXL 2.0+ downstream ports. +This results in debugfs EINJ files that won't work due to platform/spec +restrictions. + +Fix by limiting 'einj_inject' file creation to only CXL 1.1 dports and +CXL 2.0+ root ports. Update the comment above the check to more accurately +represent the requirements expected by the EINJ module and ACPI spec. + +Fixes: 8039804cfa73 ("cxl/core: Add CXL EINJ debugfs files") +Signed-off-by: Ben Cheatham +Reviewed-by: Jonathan Cameron +Reviewed-by: Alison Schofield +Reviewed-by: Dave Jiang +Link: https://patch.msgid.link/6e9fb657-8264-4028-92e2-5428e2695bf1@amd.com +Signed-off-by: Dave Jiang +Signed-off-by: Sasha Levin +--- + drivers/cxl/core/port.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c +index 3310dbfae9d66..4717dcff264be 100644 +--- a/drivers/cxl/core/port.c ++++ b/drivers/cxl/core/port.c +@@ -822,16 +822,18 @@ DEFINE_DEBUGFS_ATTRIBUTE(cxl_einj_inject_fops, NULL, cxl_einj_inject, + + static void cxl_debugfs_create_dport_dir(struct cxl_dport *dport) + { ++ struct cxl_port *parent = parent_port_of(dport->port); + struct dentry *dir; + + if (!einj_cxl_is_initialized()) + return; + + /* +- * dport_dev needs to be a PCIe port for CXL 2.0+ ports because +- * EINJ expects a dport SBDF to be specified for 2.0 error injection. ++ * Protocol error injection is only available for CXL 2.0+ root ports ++ * and CXL 1.1 downstream ports + */ +- if (!dport->rch && !dev_is_pci(dport->dport_dev)) ++ if (!dport->rch && ++ !(dev_is_pci(dport->dport_dev) && parent && is_cxl_root(parent))) + return; + + dir = cxl_debugfs_create_dir(dev_name(dport->dport_dev)); +-- +2.51.0 + diff --git a/queue-6.19/cxl-fix-premature-commit_end-increment-on-decoder-co.patch b/queue-6.19/cxl-fix-premature-commit_end-increment-on-decoder-co.patch new file mode 100644 index 0000000000..dff82658cd --- /dev/null +++ b/queue-6.19/cxl-fix-premature-commit_end-increment-on-decoder-co.patch @@ -0,0 +1,62 @@ +From 119ff88ad7285cd133dd629c3102ec49d5f14425 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 14:45:52 +0800 +Subject: cxl: Fix premature commit_end increment on decoder commit failure + +From: Yuxiong Wang + +[ Upstream commit 7b6f9d9b1ea05c9c22570126547c780e8c6c3f62 ] + +In cxl_decoder_commit(), commit_end is incremented before verifying +whether the commit succeeded, and the CXL_DECODER_F_ENABLE bit in +cxld->flags is only set after a successful commit. As a result, if the +commit fails, commit_end has been incremented and cxld->reset() has no +effect since the flag is not set, so commit_end remains incorrectly +incremented. The inconsistency between commit_end and CXL_DECODER_F_ENABLE +causes failure during subsequent either commit or reset operations. + +Fix this by incrementing commit_end only after confirming the commit +succeeded. Also, remove the ineffective cxld->reset() call. According to +CXL Spec r4.0 8.2.4.20.12 Committing Decoder Programming, since +cxld_await_commit() has cleared the decoder commit bit on failure, no +additional reset is required. + +[dj: Fixed commit log 80 char wrapping. ] +[dj: Fix "Fixes" tag to correct hash length. ] +[dj: Change spec to r4.0. ] + +Fixes: 176baefb2eb5 ("cxl/hdm: Commit decoder state to hardware") +Signed-off-by: Yuxiong Wang +Acked-by: Huang Ying +Reviewed-by: Dave Jiang +Reviewed-by: Alison Schofield +Link: https://patch.msgid.link/20260129064552.31180-1-yuxiong.wang@linux.alibaba.com +Signed-off-by: Dave Jiang +Signed-off-by: Sasha Levin +--- + drivers/cxl/core/hdm.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c +index a7ad730763e85..bc4b0c8607258 100644 +--- a/drivers/cxl/core/hdm.c ++++ b/drivers/cxl/core/hdm.c +@@ -844,14 +844,13 @@ static int cxl_decoder_commit(struct cxl_decoder *cxld) + scoped_guard(rwsem_read, &cxl_rwsem.dpa) + setup_hw_decoder(cxld, hdm); + +- port->commit_end++; + rc = cxld_await_commit(hdm, cxld->id); + if (rc) { + dev_dbg(&port->dev, "%s: error %d committing decoder\n", + dev_name(&cxld->dev), rc); +- cxld->reset(cxld); + return rc; + } ++ port->commit_end++; + cxld->flags |= CXL_DECODER_F_ENABLE; + + return 0; +-- +2.51.0 + diff --git a/queue-6.19/cxl-hdm-fix-newline-character-in-dev_err-messages.patch b/queue-6.19/cxl-hdm-fix-newline-character-in-dev_err-messages.patch new file mode 100644 index 0000000000..47eb43c005 --- /dev/null +++ b/queue-6.19/cxl-hdm-fix-newline-character-in-dev_err-messages.patch @@ -0,0 +1,52 @@ +From 6b9bfaf1586405f17f5af0f82d5de8f39f0e3442 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 13:29:51 +0100 +Subject: cxl/hdm: Fix newline character in dev_err() messages + +From: Robert Richter + +[ Upstream commit e5b1887619403c2da25a5899cad3e1ab34e7717f ] + +The newline character is not placed at the end of the string. This +causes unintended line wraps, broken log level and unterminated log +messages. Fix that for all messages. + +Note that the messages are changed to use colons now instead of +parentheses, which is more common use. + +Fixes: 24b18197184a ("cxl/hdm: Extend DVSEC range register emulation for region enumeration") +Fixes: 9c57cde0dcbd ("cxl/hdm: Enumerate allocated DPA") +Signed-off-by: Robert Richter +Reviewed-by: Jonathan Cameron +Link: https://patch.msgid.link/20260109122952.639231-1-rrichter@amd.com +Signed-off-by: Dave Jiang +Signed-off-by: Sasha Levin +--- + drivers/cxl/core/hdm.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c +index eb5a3a7640c60..a7ad730763e85 100644 +--- a/drivers/cxl/core/hdm.c ++++ b/drivers/cxl/core/hdm.c +@@ -966,7 +966,7 @@ static int cxl_setup_hdm_decoder_from_dvsec( + rc = devm_cxl_dpa_reserve(cxled, *dpa_base, len, 0); + if (rc) { + dev_err(&port->dev, +- "decoder%d.%d: Failed to reserve DPA range %#llx - %#llx\n (%d)", ++ "decoder%d.%d: Failed to reserve DPA range %#llx - %#llx: %d\n", + port->id, cxld->id, *dpa_base, *dpa_base + len - 1, rc); + return rc; + } +@@ -1117,7 +1117,7 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld, + rc = devm_cxl_dpa_reserve(cxled, *dpa_base + skip, dpa_size, skip); + if (rc) { + dev_err(&port->dev, +- "decoder%d.%d: Failed to reserve DPA range %#llx - %#llx\n (%d)", ++ "decoder%d.%d: Failed to reserve DPA range %#llx - %#llx: %d\n", + port->id, cxld->id, *dpa_base, + *dpa_base + dpa_size + skip - 1, rc); + return rc; +-- +2.51.0 + diff --git a/queue-6.19/cxl-mem-fix-devm_cxl_memdev_edac_release-confusion.patch b/queue-6.19/cxl-mem-fix-devm_cxl_memdev_edac_release-confusion.patch new file mode 100644 index 0000000000..c801eed07b --- /dev/null +++ b/queue-6.19/cxl-mem-fix-devm_cxl_memdev_edac_release-confusion.patch @@ -0,0 +1,178 @@ +From 847d0efa57f12fe87641b5722ec80918d5497777 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 15 Dec 2025 16:56:11 -0800 +Subject: cxl/mem: Fix devm_cxl_memdev_edac_release() confusion + +From: Dan Williams + +[ Upstream commit 10016118b6fade907143a32a7aeaa777063dc79c ] + +A device release method is only for undoing allocations on the path to +preparing the device for device_add(). In contrast, devm allocations are +post device_add(), are acquired during / after ->probe() and are released +synchronous with ->remove(). + +So, a "devm" helper in a "release" method is a clear anti-pattern. + +Move this devm release action where it belongs, an action created at edac +object creation time. Otherwise, this leaks resources until +cxl_memdev_release() time which may be long after these xarray and error +record caches have gone idle. + +Note, this also fixes up the type of @cxlmd->err_rec_array which needlessly +dropped type-safety. + +Fixes: 0b5ccb0de1e2 ("cxl/edac: Support for finding memory operation attributes from the current boot") +Cc: Dave Jiang +Cc: Jonathan Cameron +Cc: Shiju Jose +Cc: Alison Schofield +Reviewed-by: Alison Schofield +Reviewed-by: Ben Cheatham +Reviewed-by: Dave Jiang +Reviewed-by: Jonathan Cameron +Tested-by: Shiju Jose +Reviewed-by: Shiju Jose +Tested-by: Alejandro Lucero +Link: https://patch.msgid.link/20251216005616.3090129-2-dan.j.williams@intel.com +Signed-off-by: Dan Williams +Signed-off-by: Dave Jiang +Signed-off-by: Sasha Levin +--- + drivers/cxl/core/edac.c | 64 ++++++++++++++++++++++----------------- + drivers/cxl/core/memdev.c | 1 - + drivers/cxl/cxlmem.h | 5 +-- + 3 files changed, 38 insertions(+), 32 deletions(-) + +diff --git a/drivers/cxl/core/edac.c b/drivers/cxl/core/edac.c +index 79994ca9bc9f3..81160260e26b7 100644 +--- a/drivers/cxl/core/edac.c ++++ b/drivers/cxl/core/edac.c +@@ -1988,6 +1988,40 @@ static int cxl_memdev_soft_ppr_init(struct cxl_memdev *cxlmd, + return 0; + } + ++static void err_rec_free(void *_cxlmd) ++{ ++ struct cxl_memdev *cxlmd = _cxlmd; ++ struct cxl_mem_err_rec *array_rec = cxlmd->err_rec_array; ++ struct cxl_event_gen_media *rec_gen_media; ++ struct cxl_event_dram *rec_dram; ++ unsigned long index; ++ ++ cxlmd->err_rec_array = NULL; ++ xa_for_each(&array_rec->rec_dram, index, rec_dram) ++ kfree(rec_dram); ++ xa_destroy(&array_rec->rec_dram); ++ ++ xa_for_each(&array_rec->rec_gen_media, index, rec_gen_media) ++ kfree(rec_gen_media); ++ xa_destroy(&array_rec->rec_gen_media); ++ kfree(array_rec); ++} ++ ++static int devm_cxl_memdev_setup_err_rec(struct cxl_memdev *cxlmd) ++{ ++ struct cxl_mem_err_rec *array_rec = ++ kzalloc(sizeof(*array_rec), GFP_KERNEL); ++ ++ if (!array_rec) ++ return -ENOMEM; ++ ++ xa_init(&array_rec->rec_gen_media); ++ xa_init(&array_rec->rec_dram); ++ cxlmd->err_rec_array = array_rec; ++ ++ return devm_add_action_or_reset(&cxlmd->dev, err_rec_free, cxlmd); ++} ++ + int devm_cxl_memdev_edac_register(struct cxl_memdev *cxlmd) + { + struct edac_dev_feature ras_features[CXL_NR_EDAC_DEV_FEATURES]; +@@ -2038,15 +2072,9 @@ int devm_cxl_memdev_edac_register(struct cxl_memdev *cxlmd) + } + + if (repair_inst) { +- struct cxl_mem_err_rec *array_rec = +- devm_kzalloc(&cxlmd->dev, sizeof(*array_rec), +- GFP_KERNEL); +- if (!array_rec) +- return -ENOMEM; +- +- xa_init(&array_rec->rec_gen_media); +- xa_init(&array_rec->rec_dram); +- cxlmd->err_rec_array = array_rec; ++ rc = devm_cxl_memdev_setup_err_rec(cxlmd); ++ if (rc) ++ return rc; + } + } + +@@ -2088,22 +2116,4 @@ int devm_cxl_region_edac_register(struct cxl_region *cxlr) + } + EXPORT_SYMBOL_NS_GPL(devm_cxl_region_edac_register, "CXL"); + +-void devm_cxl_memdev_edac_release(struct cxl_memdev *cxlmd) +-{ +- struct cxl_mem_err_rec *array_rec = cxlmd->err_rec_array; +- struct cxl_event_gen_media *rec_gen_media; +- struct cxl_event_dram *rec_dram; +- unsigned long index; +- +- if (!IS_ENABLED(CONFIG_CXL_EDAC_MEM_REPAIR) || !array_rec) +- return; +- +- xa_for_each(&array_rec->rec_dram, index, rec_dram) +- kfree(rec_dram); +- xa_destroy(&array_rec->rec_dram); + +- xa_for_each(&array_rec->rec_gen_media, index, rec_gen_media) +- kfree(rec_gen_media); +- xa_destroy(&array_rec->rec_gen_media); +-} +-EXPORT_SYMBOL_NS_GPL(devm_cxl_memdev_edac_release, "CXL"); +diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c +index e370d733e4400..4dff7f44d908e 100644 +--- a/drivers/cxl/core/memdev.c ++++ b/drivers/cxl/core/memdev.c +@@ -27,7 +27,6 @@ static void cxl_memdev_release(struct device *dev) + struct cxl_memdev *cxlmd = to_cxl_memdev(dev); + + ida_free(&cxl_memdev_ida, cxlmd->id); +- devm_cxl_memdev_edac_release(cxlmd); + kfree(cxlmd); + } + +diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h +index 434031a0c1f74..c12ab4fc95123 100644 +--- a/drivers/cxl/cxlmem.h ++++ b/drivers/cxl/cxlmem.h +@@ -63,7 +63,7 @@ struct cxl_memdev { + int depth; + u8 scrub_cycle; + int scrub_region_id; +- void *err_rec_array; ++ struct cxl_mem_err_rec *err_rec_array; + }; + + static inline struct cxl_memdev *to_cxl_memdev(struct device *dev) +@@ -877,7 +877,6 @@ int devm_cxl_memdev_edac_register(struct cxl_memdev *cxlmd); + int devm_cxl_region_edac_register(struct cxl_region *cxlr); + int cxl_store_rec_gen_media(struct cxl_memdev *cxlmd, union cxl_event *evt); + int cxl_store_rec_dram(struct cxl_memdev *cxlmd, union cxl_event *evt); +-void devm_cxl_memdev_edac_release(struct cxl_memdev *cxlmd); + #else + static inline int devm_cxl_memdev_edac_register(struct cxl_memdev *cxlmd) + { return 0; } +@@ -889,8 +888,6 @@ static inline int cxl_store_rec_gen_media(struct cxl_memdev *cxlmd, + static inline int cxl_store_rec_dram(struct cxl_memdev *cxlmd, + union cxl_event *evt) + { return 0; } +-static inline void devm_cxl_memdev_edac_release(struct cxl_memdev *cxlmd) +-{ return; } + #endif + + #ifdef CONFIG_CXL_SUSPEND +-- +2.51.0 + diff --git a/queue-6.19/device_cgroup-remove-branch-hint-after-code-refactor.patch b/queue-6.19/device_cgroup-remove-branch-hint-after-code-refactor.patch new file mode 100644 index 0000000000..6e2f898feb --- /dev/null +++ b/queue-6.19/device_cgroup-remove-branch-hint-after-code-refactor.patch @@ -0,0 +1,59 @@ +From f859102e68125ddea17875ee4d15cd6b134746f4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 06:06:36 -0800 +Subject: device_cgroup: remove branch hint after code refactor + +From: Breno Leitao + +[ Upstream commit 6784f274722559c0cdaaa418bc8b7b1d61c314f9 ] + +commit 4ef4ac360101 ("device_cgroup: avoid access to ->i_rdev in the +common case in devcgroup_inode_permission()") reordered the checks in +devcgroup_inode_permission() to check the inode mode before checking +i_rdev, for better cache behavior. + +However, the likely() annotation on the i_rdev check was not updated +to reflect the new code flow. Originally, when i_rdev was checked +first, likely(!inode->i_rdev) made sense because most inodes were(?) +regular files/directories, thus i_rdev == 0. + +After the reorder, by the time we reach the i_rdev check, we have +already confirmed the inode IS a block or character device. Block and +character special files are precisely defined by having a device number +(i_rdev), so !inode->i_rdev is now the rare edge case, not the common +case. + +Branch profiling confirmed this is 100% mispredicted: + + correct incorrect % Function File Line + ------- --------- - -------- ---- ---- + 0 2631904 100 devcgroup_inode_permission device_cgroup.h 24 + +Remove likely() to avoid giving the wrong hint to the CPU. + +Fixes: 4ef4ac360101 ("device_cgroup: avoid access to ->i_rdev in the common case in devcgroup_inode_permission()") +Signed-off-by: Breno Leitao +Link: https://patch.msgid.link/20260107-likely_device-v1-1-0c55f83a7e47@debian.org +Reviewed-by: Mateusz Guzik +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + include/linux/device_cgroup.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/linux/device_cgroup.h b/include/linux/device_cgroup.h +index 0864773a57e8f..822085bc2d202 100644 +--- a/include/linux/device_cgroup.h ++++ b/include/linux/device_cgroup.h +@@ -21,7 +21,7 @@ static inline int devcgroup_inode_permission(struct inode *inode, int mask) + if (likely(!S_ISBLK(inode->i_mode) && !S_ISCHR(inode->i_mode))) + return 0; + +- if (likely(!inode->i_rdev)) ++ if (!inode->i_rdev) + return 0; + + if (S_ISBLK(inode->i_mode)) +-- +2.51.0 + diff --git a/queue-6.19/dm-fix-unlocked-test-for-dm_suspended_md.patch b/queue-6.19/dm-fix-unlocked-test-for-dm_suspended_md.patch new file mode 100644 index 0000000000..f6dcf16d59 --- /dev/null +++ b/queue-6.19/dm-fix-unlocked-test-for-dm_suspended_md.patch @@ -0,0 +1,56 @@ +From 6195d456712f9120841c2c94a63d8df27ff578e3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 20:55:08 +0100 +Subject: dm: fix unlocked test for dm_suspended_md + +From: Mikulas Patocka + +[ Upstream commit 24c405fdbe215c45e57bba672cc42859038491ee ] + +The function dm_blk_report_zones tests if the device is suspended with +the "dm_suspended_md" call. However, this function is called without +holding any locks, so the device may be suspended just after it. + +Move the call to dm_suspended_md after dm_get_live_table, so that the +device can't be suspended after the suspended state was tested. + +Signed-off-by: Mikulas Patocka +Fixes: 37f53a2c60d0 ("dm: fix dm_blk_report_zones") +Reviewed-by: Benjamin Marzinski +Signed-off-by: Sasha Levin +--- + drivers/md/dm-zone.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/drivers/md/dm-zone.c b/drivers/md/dm-zone.c +index c95e417194b33..bc4e45862a220 100644 +--- a/drivers/md/dm-zone.c ++++ b/drivers/md/dm-zone.c +@@ -60,11 +60,13 @@ int dm_blk_report_zones(struct gendisk *disk, sector_t sector, + * Zone revalidation during __bind() is in progress, but this + * call is from a different process + */ +- if (dm_suspended_md(md)) +- return -EAGAIN; +- + map = dm_get_live_table(md, &srcu_idx); + put_table = true; ++ ++ if (dm_suspended_md(md)) { ++ ret = -EAGAIN; ++ goto do_put_table; ++ } + } else { + /* Zone revalidation during __bind() */ + map = zone_revalidate_map; +@@ -79,6 +81,7 @@ int dm_blk_report_zones(struct gendisk *disk, sector_t sector, + ret = dm_blk_do_report_zones(md, map, nr_zones, &dm_args); + } + ++do_put_table: + if (put_table) + dm_put_live_table(md, srcu_idx); + +-- +2.51.0 + diff --git a/queue-6.19/dm-use-bio_clone_blkg_association.patch b/queue-6.19/dm-use-bio_clone_blkg_association.patch new file mode 100644 index 0000000000..00823a2619 --- /dev/null +++ b/queue-6.19/dm-use-bio_clone_blkg_association.patch @@ -0,0 +1,44 @@ +From c50469ff828366ac9a7af0932fd4738dc83ed32f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 15:36:22 +0100 +Subject: dm: use bio_clone_blkg_association + +From: Mikulas Patocka + +[ Upstream commit 2df8b310bcfe76827fd71092f58a2493ee6590b0 ] + +The origin bio carries blk-cgroup information which could be set from +foreground(task_css(css) - wbc->wb->blkcg_css), so the blkcg won't +control buffer io since commit ca522482e3eaf ("dm: pass NULL bdev to +bio_alloc_clone"). The synchronous io is still under control by blkcg, +because 'bio->bi_blkg' is set by io submitting task which has been added +into 'cgroup.procs'. + +Fix it by using bio_clone_blkg_association when submitting a cloned bio. + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=220985 +Fixes: ca522482e3eaf ("dm: pass NULL bdev to bio_alloc_clone") +Reported-by: Zhihao Cheng +Signed-off-by: Mikulas Patocka +Tested-by: Zhihao Cheng +Signed-off-by: Sasha Levin +--- + drivers/md/dm.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/md/dm.c b/drivers/md/dm.c +index b632792022601..8e029f6289c10 100644 +--- a/drivers/md/dm.c ++++ b/drivers/md/dm.c +@@ -1364,6 +1364,8 @@ void dm_submit_bio_remap(struct bio *clone, struct bio *tgt_clone) + if (!tgt_clone) + tgt_clone = clone; + ++ bio_clone_blkg_association(tgt_clone, io->orig_bio); ++ + /* + * Account io->origin_bio to DM dev on behalf of target + * that took ownership of IO with DM_MAPIO_SUBMITTED. +-- +2.51.0 + diff --git a/queue-6.19/dm-use-read_once-in-dm_blk_report_zones.patch b/queue-6.19/dm-use-read_once-in-dm_blk_report_zones.patch new file mode 100644 index 0000000000..b503c20755 --- /dev/null +++ b/queue-6.19/dm-use-read_once-in-dm_blk_report_zones.patch @@ -0,0 +1,36 @@ +From 45af806c15af2fa23cf3527ce4c775bdbfedd878 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 20:56:20 +0100 +Subject: dm: use READ_ONCE in dm_blk_report_zones + +From: Mikulas Patocka + +[ Upstream commit e9f5a55b70ae6187ab64ef2d1232ae2738e31d1f ] + +The functon dm_blk_report_zones reads md->zone_revalidate_map, however it +may change while the function is running. Use READ_ONCE. + +Signed-off-by: Mikulas Patocka +Fixes: 37f53a2c60d0 ("dm: fix dm_blk_report_zones") +Reviewed-by: Benjamin Marzinski +Signed-off-by: Sasha Levin +--- + drivers/md/dm-zone.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/md/dm-zone.c b/drivers/md/dm-zone.c +index bc4e45862a220..f29acf64429a7 100644 +--- a/drivers/md/dm-zone.c ++++ b/drivers/md/dm-zone.c +@@ -50,7 +50,7 @@ int dm_blk_report_zones(struct gendisk *disk, sector_t sector, + { + struct mapped_device *md = disk->private_data; + struct dm_table *map; +- struct dm_table *zone_revalidate_map = md->zone_revalidate_map; ++ struct dm_table *zone_revalidate_map = READ_ONCE(md->zone_revalidate_map); + int srcu_idx, ret = -EIO; + bool put_table = false; + +-- +2.51.0 + diff --git a/queue-6.19/dma-dma-axi-dmac-fix-hw-scatter-gather-not-looking-a.patch b/queue-6.19/dma-dma-axi-dmac-fix-hw-scatter-gather-not-looking-a.patch new file mode 100644 index 0000000000..a2b09a6059 --- /dev/null +++ b/queue-6.19/dma-dma-axi-dmac-fix-hw-scatter-gather-not-looking-a.patch @@ -0,0 +1,51 @@ +From ee3eb771a68a2f6c75895109ee15ba780e0a0c23 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Nov 2025 16:22:26 +0000 +Subject: dma: dma-axi-dmac: fix HW scatter-gather not looking at the queue +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Nuno Sá + +[ Upstream commit bbcbafb99df41a1d81403eb4f5bb443b38228b57 ] + +For HW scatter gather transfers we still need to look for the queue. The +HW is capable of queueing 3 concurrent transfers and if we try more than +that we'll get the submit queue full and should return. Otherwise, if we +go ahead and program the new transfer, we end up discarding it. + +Fixes: e97dc7435972 ("dmaengine: axi-dmac: Add support for scatter-gather transfers") +Signed-off-by: Nuno Sá +base-commit: 398035178503bf662281bbffb4bebce1460a4bc5 +change-id: 20251104-axi-dmac-fixes-and-improvs-e3ad512a329c +Acked-by: Michael Hennerich +Link: https://patch.msgid.link/20251104-axi-dmac-fixes-and-improvs-v1-2-3e6fd9328f72@analog.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/dma/dma-axi-dmac.c | 8 +++----- + 1 file changed, 3 insertions(+), 5 deletions(-) + +diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c +index e22639822045f..0f25f6d8ae71f 100644 +--- a/drivers/dma/dma-axi-dmac.c ++++ b/drivers/dma/dma-axi-dmac.c +@@ -233,11 +233,9 @@ static void axi_dmac_start_transfer(struct axi_dmac_chan *chan) + unsigned int flags = 0; + unsigned int val; + +- if (!chan->hw_sg) { +- val = axi_dmac_read(dmac, AXI_DMAC_REG_START_TRANSFER); +- if (val) /* Queue is full, wait for the next SOT IRQ */ +- return; +- } ++ val = axi_dmac_read(dmac, AXI_DMAC_REG_START_TRANSFER); ++ if (val) /* Queue is full, wait for the next SOT IRQ */ ++ return; + + desc = chan->next_desc; + +-- +2.51.0 + diff --git a/queue-6.19/dma-dma-axi-dmac-fix-sw-cyclic-transfers.patch b/queue-6.19/dma-dma-axi-dmac-fix-sw-cyclic-transfers.patch new file mode 100644 index 0000000000..d6457e39a7 --- /dev/null +++ b/queue-6.19/dma-dma-axi-dmac-fix-sw-cyclic-transfers.patch @@ -0,0 +1,57 @@ +From b0f1f46bcbb50fc40ac71ba5e74b6e498cb622a1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Nov 2025 16:22:25 +0000 +Subject: dma: dma-axi-dmac: fix SW cyclic transfers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Nuno Sá + +[ Upstream commit 9bd257181fd5c996d922e9991500ad27987cfbf4 ] + +If 'hw_cyclic' is false we should still be able to do cyclic transfers in +"software". That was not working for the case where 'desc->num_sgs' is 1 +because 'chan->next_desc' is never set with the current desc which means +that the cyclic transfer only runs once and in the next SOT interrupt we +do nothing since vchan_next_desc() will return NULL. + +Fix it by setting 'chan->next_desc' as soon as we get a new desc via +vchan_next_desc(). + +Fixes: 0e3b67b348b8 ("dmaengine: Add support for the Analog Devices AXI-DMAC DMA controller") +Signed-off-by: Nuno Sá +base-commit: 398035178503bf662281bbffb4bebce1460a4bc5 +change-id: 20251104-axi-dmac-fixes-and-improvs-e3ad512a329c +Acked-by: Michael Hennerich +Link: https://patch.msgid.link/20251104-axi-dmac-fixes-and-improvs-v1-1-3e6fd9328f72@analog.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/dma/dma-axi-dmac.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c +index 5b06b0dc67ee1..e22639822045f 100644 +--- a/drivers/dma/dma-axi-dmac.c ++++ b/drivers/dma/dma-axi-dmac.c +@@ -247,6 +247,7 @@ static void axi_dmac_start_transfer(struct axi_dmac_chan *chan) + return; + list_move_tail(&vdesc->node, &chan->active_descs); + desc = to_axi_dmac_desc(vdesc); ++ chan->next_desc = desc; + } + sg = &desc->sg[desc->num_submitted]; + +@@ -265,8 +266,6 @@ static void axi_dmac_start_transfer(struct axi_dmac_chan *chan) + else + chan->next_desc = NULL; + flags |= AXI_DMAC_FLAG_LAST; +- } else { +- chan->next_desc = desc; + } + + sg->hw->id = axi_dmac_read(dmac, AXI_DMAC_REG_TRANSFER_ID); +-- +2.51.0 + diff --git a/queue-6.19/dmaengine-fsl-edma-don-t-explicitly-disable-clocks-i.patch b/queue-6.19/dmaengine-fsl-edma-don-t-explicitly-disable-clocks-i.patch new file mode 100644 index 0000000000..2efe3e80b6 --- /dev/null +++ b/queue-6.19/dmaengine-fsl-edma-don-t-explicitly-disable-clocks-i.patch @@ -0,0 +1,61 @@ +From 6f2de6be6970b233bd9aa2bc7436d18342f1de6e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Jan 2026 11:46:50 -0800 +Subject: dmaengine: fsl-edma: don't explicitly disable clocks in .remove() + +From: Jared Kangas + +[ Upstream commit 666c53e94c1d0bf0bdf14c49505ece9ddbe725bc ] + +The clocks in fsl_edma_engine::muxclk are allocated and enabled with +devm_clk_get_enabled(), which automatically cleans these resources up, +but these clocks are also manually disabled in fsl_edma_remove(). This +causes warnings on driver removal for each clock: + + edma_module already disabled + WARNING: CPU: 0 PID: 418 at drivers/clk/clk.c:1200 clk_core_disable+0x198/0x1c8 + [...] + Call trace: + clk_core_disable+0x198/0x1c8 (P) + clk_disable+0x34/0x58 + fsl_edma_remove+0x74/0xe8 [fsl_edma] + [...] + ---[ end trace 0000000000000000 ]--- + edma_module already unprepared + WARNING: CPU: 0 PID: 418 at drivers/clk/clk.c:1059 clk_core_unprepare+0x1f8/0x220 + [...] + Call trace: + clk_core_unprepare+0x1f8/0x220 (P) + clk_unprepare+0x34/0x58 + fsl_edma_remove+0x7c/0xe8 [fsl_edma] + [...] + ---[ end trace 0000000000000000 ]--- + +Fix these warnings by removing the unnecessary fsl_disable_clocks() call +in fsl_edma_remove(). + +Fixes: a9903de3aa16 ("dmaengine: fsl-edma: refactor using devm_clk_get_enabled") +Signed-off-by: Jared Kangas +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260113-fsl-edma-clock-removal-v1-1-2025b49e7bcc@redhat.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/dma/fsl-edma-main.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/dma/fsl-edma-main.c b/drivers/dma/fsl-edma-main.c +index a753b7cbfa7a3..dbcdd1e683190 100644 +--- a/drivers/dma/fsl-edma-main.c ++++ b/drivers/dma/fsl-edma-main.c +@@ -915,7 +915,6 @@ static void fsl_edma_remove(struct platform_device *pdev) + of_dma_controller_free(np); + dma_async_device_unregister(&fsl_edma->dma_dev); + fsl_edma_cleanup_vchan(&fsl_edma->dma_dev); +- fsl_disable_clocks(fsl_edma, fsl_edma->drvdata->dmamuxs); + } + + static int fsl_edma_suspend_late(struct device *dev) +-- +2.51.0 + diff --git a/queue-6.19/dmaengine-mediatek-uart-apdma-fix-above-4g-addressin.patch b/queue-6.19/dmaengine-mediatek-uart-apdma-fix-above-4g-addressin.patch new file mode 100644 index 0000000000..d0153ff3e5 --- /dev/null +++ b/queue-6.19/dmaengine-mediatek-uart-apdma-fix-above-4g-addressin.patch @@ -0,0 +1,83 @@ +From f71fdf79cc140670e180ff20e624c03bad827f14 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 13 Nov 2025 13:22:26 +0100 +Subject: dmaengine: mediatek: uart-apdma: Fix above 4G addressing TX/RX + +From: AngeloGioacchino Del Regno + +[ Upstream commit 58ab9d7b6651d21e1cff1777529f2d3dd0b4e851 ] + +The VFF_4G_SUPPORT register is named differently in datasheets, +and its name is "VFF_ADDR2"; was this named correctly from the +beginning it would've been clearer that there was a mistake in +the programming sequence. + +This register is supposed to hold the high bits to support the +DMA addressing above 4G (so, more than 32 bits) and not a bit +to "enable" the support for VFF 4G. + +Fix the name of this register, and also fix its usage by writing +the upper 32 bits of the dma_addr_t on it when the SoC supports +such feature. + +Fixes: 9135408c3ace ("dmaengine: mediatek: Add MediaTek UART APDMA support") +Signed-off-by: AngeloGioacchino Del Regno +Link: https://patch.msgid.link/20251113122229.23998-6-angelogioacchino.delregno@collabora.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/dma/mediatek/mtk-uart-apdma.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/dma/mediatek/mtk-uart-apdma.c b/drivers/dma/mediatek/mtk-uart-apdma.c +index 08e15177427b9..96c18c815f1df 100644 +--- a/drivers/dma/mediatek/mtk-uart-apdma.c ++++ b/drivers/dma/mediatek/mtk-uart-apdma.c +@@ -41,7 +41,7 @@ + #define VFF_STOP_CLR_B 0 + #define VFF_EN_CLR_B 0 + #define VFF_INT_EN_CLR_B 0 +-#define VFF_4G_SUPPORT_CLR_B 0 ++#define VFF_ADDR2_CLR_B 0 + + /* + * interrupt trigger level for tx +@@ -72,7 +72,7 @@ + /* TX: the buffer size SW can write. RX: the buffer size HW can write. */ + #define VFF_LEFT_SIZE 0x40 + #define VFF_DEBUG_STATUS 0x50 +-#define VFF_4G_SUPPORT 0x54 ++#define VFF_ADDR2 0x54 + + struct mtk_uart_apdmadev { + struct dma_device ddev; +@@ -149,7 +149,7 @@ static void mtk_uart_apdma_start_tx(struct mtk_chan *c) + mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_TX_INT_CLR_B); + + if (mtkd->support_33bits) +- mtk_uart_apdma_write(c, VFF_4G_SUPPORT, VFF_4G_EN_B); ++ mtk_uart_apdma_write(c, VFF_ADDR2, upper_32_bits(d->addr)); + } + + mtk_uart_apdma_write(c, VFF_EN, VFF_EN_B); +@@ -192,7 +192,7 @@ static void mtk_uart_apdma_start_rx(struct mtk_chan *c) + mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_RX_INT_CLR_B); + + if (mtkd->support_33bits) +- mtk_uart_apdma_write(c, VFF_4G_SUPPORT, VFF_4G_EN_B); ++ mtk_uart_apdma_write(c, VFF_ADDR2, upper_32_bits(d->addr)); + } + + mtk_uart_apdma_write(c, VFF_INT_EN, VFF_RX_INT_EN_B); +@@ -298,7 +298,7 @@ static int mtk_uart_apdma_alloc_chan_resources(struct dma_chan *chan) + } + + if (mtkd->support_33bits) +- mtk_uart_apdma_write(c, VFF_4G_SUPPORT, VFF_4G_SUPPORT_CLR_B); ++ mtk_uart_apdma_write(c, VFF_ADDR2, VFF_ADDR2_CLR_B); + + err_pm: + pm_runtime_put_noidle(mtkd->ddev.dev); +-- +2.51.0 + diff --git a/queue-6.19/docs-find-unused-docs.sh-fixup-directory-usage.patch b/queue-6.19/docs-find-unused-docs.sh-fixup-directory-usage.patch new file mode 100644 index 0000000000..8c6a4f0334 --- /dev/null +++ b/queue-6.19/docs-find-unused-docs.sh-fixup-directory-usage.patch @@ -0,0 +1,44 @@ +From 45c45b92fd8364834743cc634c13e4fd6e40eeeb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 2 Jan 2026 12:06:57 -0800 +Subject: docs: find-unused-docs.sh: fixup directory usage + +From: Randy Dunlap + +[ Upstream commit e970637707f4f8e5bd098b09090b755f2f57898b ] + +The recent move of this script from scripts/ to tools/docs/ +did not account for the 'cd' directory usage. +Update "cd .." to "cd ../.." to make the script self-correcting. + +This also eliminates a shell warning: +./tools/docs/find-unused-docs.sh: line 33: cd: Documentation/: No such file or directory + +Fixes: 184414c6a6ca ("docs: move find-unused-docs.sh to tools/docs") +Signed-off-by: Randy Dunlap +Fixes: 184414c6a6ca (docs: move find-unused-docs.sh to tools/docs) +Signed-off-by: Matthew Wilcox (Oracle) +Reviewed-by: Matthew Wilcox (Oracle) +Signed-off-by: Jonathan Corbet +Message-ID: <20260102200657.1040234-1-rdunlap@infradead.org> +Signed-off-by: Sasha Levin +--- + tools/docs/find-unused-docs.sh | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/docs/find-unused-docs.sh b/tools/docs/find-unused-docs.sh +index 05552dbda5bcb..ca4e607ec3f72 100755 +--- a/tools/docs/find-unused-docs.sh ++++ b/tools/docs/find-unused-docs.sh +@@ -28,7 +28,7 @@ if ! [ -d "$1" ]; then + fi + + cd "$( dirname "${BASH_SOURCE[0]}" )" +-cd .. ++cd ../.. + + cd Documentation/ + +-- +2.51.0 + diff --git a/queue-6.19/documentation-pci-endpoint-fix-ntb-vntb-copy-paste-e.patch b/queue-6.19/documentation-pci-endpoint-fix-ntb-vntb-copy-paste-e.patch new file mode 100644 index 0000000000..68f160d57f --- /dev/null +++ b/queue-6.19/documentation-pci-endpoint-fix-ntb-vntb-copy-paste-e.patch @@ -0,0 +1,82 @@ +From a08a902d073305c5dc8e4af16fc443b53ff4bf35 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 3 Nov 2025 09:28:30 +0200 +Subject: Documentation: PCI: endpoint: Fix ntb/vntb copy & paste errors + +From: Baruch Siach + +[ Upstream commit ad0c6da5be901f5c181490f683d22b416059bccb ] + +Fix copy & paste errors by changing the references from 'ntb' to 'vntb'. + +Fixes: 4ac8c8e52cd9 ("Documentation: PCI: Add specification for the PCI vNTB function device") +Signed-off-by: Baruch Siach +[mani: squashed the patches and fixed more errors] +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Reviewed-by: Frank Li +Link: https://patch.msgid.link/b51c2a69ffdbfa2c359f5cf33f3ad2acc3db87e4.1762154911.git.baruch@tkos.co.il +Signed-off-by: Sasha Levin +--- + Documentation/PCI/endpoint/pci-vntb-howto.rst | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/Documentation/PCI/endpoint/pci-vntb-howto.rst b/Documentation/PCI/endpoint/pci-vntb-howto.rst +index 9a7a2f0a68498..3679f5c302549 100644 +--- a/Documentation/PCI/endpoint/pci-vntb-howto.rst ++++ b/Documentation/PCI/endpoint/pci-vntb-howto.rst +@@ -52,14 +52,14 @@ pci-epf-vntb device, the following commands can be used:: + # cd /sys/kernel/config/pci_ep/ + # mkdir functions/pci_epf_vntb/func1 + +-The "mkdir func1" above creates the pci-epf-ntb function device that will ++The "mkdir func1" above creates the pci-epf-vntb function device that will + be probed by pci_epf_vntb driver. + + The PCI endpoint framework populates the directory with the following + configurable fields:: + +- # ls functions/pci_epf_ntb/func1 +- baseclass_code deviceid msi_interrupts pci-epf-ntb.0 ++ # ls functions/pci_epf_vntb/func1 ++ baseclass_code deviceid msi_interrupts pci-epf-vntb.0 + progif_code secondary subsys_id vendorid + cache_line_size interrupt_pin msix_interrupts primary + revid subclass_code subsys_vendor_id +@@ -111,13 +111,13 @@ A sample configuration for virtual NTB driver for virtual PCI bus:: + # echo 0x080A > functions/pci_epf_vntb/func1/pci_epf_vntb.0/vntb_pid + # echo 0x10 > functions/pci_epf_vntb/func1/pci_epf_vntb.0/vbus_number + +-Binding pci-epf-ntb Device to EP Controller ++Binding pci-epf-vntb Device to EP Controller + -------------------------------------------- + + NTB function device should be attached to PCI endpoint controllers + connected to the host. + +- # ln -s controllers/5f010000.pcie_ep functions/pci-epf-ntb/func1/primary ++ # ln -s controllers/5f010000.pcie_ep functions/pci_epf_vntb/func1/primary + + Once the above step is completed, the PCI endpoint controllers are ready to + establish a link with the host. +@@ -139,7 +139,7 @@ lspci Output at Host side + ------------------------- + + Note that the devices listed here correspond to the values populated in +-"Creating pci-epf-ntb Device" section above:: ++"Creating pci-epf-vntb Device" section above:: + + # lspci + 00:00.0 PCI bridge: Freescale Semiconductor Inc Device 0000 (rev 01) +@@ -152,7 +152,7 @@ lspci Output at EP Side / Virtual PCI bus + ----------------------------------------- + + Note that the devices listed here correspond to the values populated in +-"Creating pci-epf-ntb Device" section above:: ++"Creating pci-epf-vntb Device" section above:: + + # lspci + 10:00.0 Unassigned class [ffff]: Dawicontrol Computersysteme GmbH Device 1234 (rev ff) +-- +2.51.0 + diff --git a/queue-6.19/documentation-tracing-add-pci-tracepoint-documentati.patch b/queue-6.19/documentation-tracing-add-pci-tracepoint-documentati.patch new file mode 100644 index 0000000000..d81ed7264c --- /dev/null +++ b/queue-6.19/documentation-tracing-add-pci-tracepoint-documentati.patch @@ -0,0 +1,125 @@ +From 312466d6d34f272f3f0be7dd046a6817a9006b59 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 10 Dec 2025 21:29:07 +0800 +Subject: Documentation: tracing: Add PCI tracepoint documentation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Shuai Xue + +[ Upstream commit 8236fc613d44e59f6736d6c3e9efffaf26ab7f00 ] + +The PCI tracing system provides tracepoints to monitor critical hardware +events that can impact system performance and reliability. Add +documentation about it. + +Signed-off-by: Shuai Xue +[bhelgaas: squash fixes: +https://lore.kernel.org/r/20260108013956.14351-2-bagasdotme@gmail.com +https://lore.kernel.org/r/20260108013956.14351-3-bagasdotme@gmail.com] +Signed-off-by: Bjorn Helgaas +Reviewed-by: Ilpo Järvinen +Link: https://patch.msgid.link/20251210132907.58799-4-xueshuai@linux.alibaba.com +Signed-off-by: Sasha Levin +--- + Documentation/trace/events-pci.rst | 74 ++++++++++++++++++++++++++++++ + Documentation/trace/index.rst | 1 + + 2 files changed, 75 insertions(+) + create mode 100644 Documentation/trace/events-pci.rst + +diff --git a/Documentation/trace/events-pci.rst b/Documentation/trace/events-pci.rst +new file mode 100644 +index 0000000000000..03ff4ad30ddfa +--- /dev/null ++++ b/Documentation/trace/events-pci.rst +@@ -0,0 +1,74 @@ ++.. SPDX-License-Identifier: GPL-2.0 ++ ++=========================== ++Subsystem Trace Points: PCI ++=========================== ++ ++Overview ++======== ++The PCI tracing system provides tracepoints to monitor critical hardware events ++that can impact system performance and reliability. These events normally show ++up here: ++ ++ /sys/kernel/tracing/events/pci ++ ++Cf. include/trace/events/pci.h for the events definitions. ++ ++Available Tracepoints ++===================== ++ ++pci_hp_event ++------------ ++ ++Monitors PCI hotplug events including card insertion/removal and link ++state changes. ++:: ++ ++ pci_hp_event "%s slot:%s, event:%s\n" ++ ++**Event Types**: ++ ++* ``LINK_UP`` - PCIe link established ++* ``LINK_DOWN`` - PCIe link lost ++* ``CARD_PRESENT`` - Card detected in slot ++* ``CARD_NOT_PRESENT`` - Card removed from slot ++ ++**Example Usage**:: ++ ++ # Enable the tracepoint ++ echo 1 > /sys/kernel/debug/tracing/events/pci/pci_hp_event/enable ++ ++ # Monitor events (the following output is generated when a device is hotplugged) ++ cat /sys/kernel/debug/tracing/trace_pipe ++ irq/51-pciehp-88 [001] ..... 1311.177459: pci_hp_event: 0000:00:02.0 slot:10, event:CARD_PRESENT ++ ++ irq/51-pciehp-88 [001] ..... 1311.177566: pci_hp_event: 0000:00:02.0 slot:10, event:LINK_UP ++ ++pcie_link_event ++--------------- ++ ++Monitors PCIe link speed changes and provides detailed link status information. ++:: ++ ++ pcie_link_event "%s type:%d, reason:%d, cur_bus_speed:%d, max_bus_speed:%d, width:%u, flit_mode:%u, status:%s\n" ++ ++**Parameters**: ++ ++* ``type`` - PCIe device type (4=Root Port, etc.) ++* ``reason`` - Reason for link change: ++ ++ - ``0`` - Link retrain ++ - ``1`` - Bus enumeration ++ - ``2`` - Bandwidth notification enable ++ - ``3`` - Bandwidth notification IRQ ++ - ``4`` - Hotplug event ++ ++ ++**Example Usage**:: ++ ++ # Enable the tracepoint ++ echo 1 > /sys/kernel/debug/tracing/events/pci/pcie_link_event/enable ++ ++ # Monitor events (the following output is generated when a device is hotplugged) ++ cat /sys/kernel/debug/tracing/trace_pipe ++ irq/51-pciehp-88 [001] ..... 381.545386: pcie_link_event: 0000:00:02.0 type:4, reason:4, cur_bus_speed:20, max_bus_speed:23, width:1, flit_mode:0, status:DLLLA +diff --git a/Documentation/trace/index.rst b/Documentation/trace/index.rst +index b4a429dc4f7ad..0a40bfabcf19b 100644 +--- a/Documentation/trace/index.rst ++++ b/Documentation/trace/index.rst +@@ -54,6 +54,7 @@ applications. + events-power + events-nmi + events-msr ++ events-pci + boottime-trace + histogram + histogram-design +-- +2.51.0 + diff --git a/queue-6.19/dpll-zl3073x-fix-output-pin-phase-adjustment-sign.patch b/queue-6.19/dpll-zl3073x-fix-output-pin-phase-adjustment-sign.patch new file mode 100644 index 0000000000..0a1be47677 --- /dev/null +++ b/queue-6.19/dpll-zl3073x-fix-output-pin-phase-adjustment-sign.patch @@ -0,0 +1,67 @@ +From a4be718a28d7a6c27e57a270ba06c72060b81f99 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 19:10:55 +0100 +Subject: dpll: zl3073x: Fix output pin phase adjustment sign + +From: Ivan Vecera + +[ Upstream commit 5d41f95f5d0bd9db02f3f16a649d0631f71e9fdb ] + +The output pin phase adjustment functions incorrectly negate the phase +compensation value. + +Per the ZL3073x datasheet, the output phase compensation register is +simply a signed two's complement integer where: + - Positive values move the phase later in time + - Negative values move the phase earlier in time + +No negation is required. The erroneous negation caused phase adjustments +to be applied in the wrong direction. + +Note that input pin phase adjustment correctly uses negation because the +hardware has an inverted convention for input references (positive moves +phase earlier, negative moves phase later). + +Fixes: 6287262f761e ("dpll: zl3073x: Add support to adjust phase") +Signed-off-by: Ivan Vecera +Reviewed-by: Vadim Fedorenko +Link: https://patch.msgid.link/20260205181055.129768-1-ivecera@redhat.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/dpll/zl3073x/dpll.c | 12 ++++-------- + 1 file changed, 4 insertions(+), 8 deletions(-) + +diff --git a/drivers/dpll/zl3073x/dpll.c b/drivers/dpll/zl3073x/dpll.c +index 9879d85d29af0..a8001c9760382 100644 +--- a/drivers/dpll/zl3073x/dpll.c ++++ b/drivers/dpll/zl3073x/dpll.c +@@ -1039,10 +1039,8 @@ zl3073x_dpll_output_pin_phase_adjust_get(const struct dpll_pin *dpll_pin, + out_id = zl3073x_output_pin_out_get(pin->id); + out = zl3073x_out_state_get(zldev, out_id); + +- /* Convert value to ps and reverse two's complement negation applied +- * during 'set' +- */ +- *phase_adjust = -out->phase_comp * pin->phase_gran; ++ /* The value in the register is expressed in half synth clock cycles. */ ++ *phase_adjust = out->phase_comp * pin->phase_gran; + + return 0; + } +@@ -1064,10 +1062,8 @@ zl3073x_dpll_output_pin_phase_adjust_set(const struct dpll_pin *dpll_pin, + out_id = zl3073x_output_pin_out_get(pin->id); + out = *zl3073x_out_state_get(zldev, out_id); + +- /* The value in the register is stored as two's complement negation +- * of requested value and expressed in half synth clock cycles. +- */ +- out.phase_comp = -phase_adjust / pin->phase_gran; ++ /* The value in the register is expressed in half synth clock cycles. */ ++ out.phase_comp = phase_adjust / pin->phase_gran; + + /* Update output configuration from mailbox */ + return zl3073x_out_state_set(zldev, out_id, &out); +-- +2.51.0 + diff --git a/queue-6.19/drbd-always-set-blk_feat_stable_writes.patch b/queue-6.19/drbd-always-set-blk_feat_stable_writes.patch new file mode 100644 index 0000000000..39a144f8d4 --- /dev/null +++ b/queue-6.19/drbd-always-set-blk_feat_stable_writes.patch @@ -0,0 +1,94 @@ +From d3c62dd973464c1a50d4fdadc0a9d3a50799cc9a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 18:39:29 +0100 +Subject: drbd: always set BLK_FEAT_STABLE_WRITES +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Christoph Böhmwalder + +[ Upstream commit 2ebc8d600fb907fa6b1e7095c0b6d84fc47e91ea ] + +DRBD requires stable pages because it may read the same bio data +multiple times for local disk I/O and network transmission, and in +some cases for calculating checksums. + +The BLK_FEAT_STABLE_WRITES flag is set when the device is first +created, but blk_set_stacking_limits() clears it whenever a +backing device is attached. In some cases the flag may be +inherited from the backing device, but we want it to be enabled +at all times. + +Unconditionally re-enable BLK_FEAT_STABLE_WRITES in +drbd_reconsider_queue_parameters() after the queue parameter +negotiations. + +Also, document why we want this flag enabled in the first place. + +Fixes: 1a02f3a73f8c ("block: move the stable_writes flag to queue_limits") +Signed-off-by: Christoph Böhmwalder +Reviewed-by: Christoph Hellwig +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/block/drbd/drbd_main.c | 3 --- + drivers/block/drbd/drbd_nl.c | 20 +++++++++++++++++++- + 2 files changed, 19 insertions(+), 4 deletions(-) + +diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c +index c73376886e7a5..1f6ac9202b66a 100644 +--- a/drivers/block/drbd/drbd_main.c ++++ b/drivers/block/drbd/drbd_main.c +@@ -2659,9 +2659,6 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig + * connect. + */ + .max_hw_sectors = DRBD_MAX_BIO_SIZE_SAFE >> 8, +- .features = BLK_FEAT_WRITE_CACHE | BLK_FEAT_FUA | +- BLK_FEAT_ROTATIONAL | +- BLK_FEAT_STABLE_WRITES, + }; + + device = minor_to_device(minor); +diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c +index 91f3b8afb63ce..b502038be0a92 100644 +--- a/drivers/block/drbd/drbd_nl.c ++++ b/drivers/block/drbd/drbd_nl.c +@@ -1296,6 +1296,8 @@ void drbd_reconsider_queue_parameters(struct drbd_device *device, + lim.max_segments = drbd_backing_dev_max_segments(device); + } else { + lim.max_segments = BLK_MAX_SEGMENTS; ++ lim.features = BLK_FEAT_WRITE_CACHE | BLK_FEAT_FUA | ++ BLK_FEAT_ROTATIONAL | BLK_FEAT_STABLE_WRITES; + } + + lim.max_hw_sectors = new >> SECTOR_SHIFT; +@@ -1318,8 +1320,24 @@ void drbd_reconsider_queue_parameters(struct drbd_device *device, + lim.max_hw_discard_sectors = 0; + } + +- if (bdev) ++ if (bdev) { + blk_stack_limits(&lim, &b->limits, 0); ++ /* ++ * blk_set_stacking_limits() cleared the features, and ++ * blk_stack_limits() may or may not have inherited ++ * BLK_FEAT_STABLE_WRITES from the backing device. ++ * ++ * DRBD always requires stable writes because: ++ * 1. The same bio data is read for both local disk I/O and ++ * network transmission. If the page changes mid-flight, ++ * the local and remote copies could diverge. ++ * 2. When data integrity is enabled, DRBD calculates a ++ * checksum before sending the data. If the page changes ++ * between checksum calculation and transmission, the ++ * receiver will detect a checksum mismatch. ++ */ ++ lim.features |= BLK_FEAT_STABLE_WRITES; ++ } + + /* + * If we can handle "zeroes" efficiently on the protocol, we want to do +-- +2.51.0 + diff --git a/queue-6.19/drivers-iio-mpu3050-use-dev_err_probe-for-regulator-.patch b/queue-6.19/drivers-iio-mpu3050-use-dev_err_probe-for-regulator-.patch new file mode 100644 index 0000000000..8141f2f074 --- /dev/null +++ b/queue-6.19/drivers-iio-mpu3050-use-dev_err_probe-for-regulator-.patch @@ -0,0 +1,42 @@ +From e8ada45027b0c7b8eb47f14a9bb1849010518d43 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 17:34:25 +0200 +Subject: drivers: iio: mpu3050: use dev_err_probe for regulator request + +From: Svyatoslav Ryhel + +[ Upstream commit b010880b9936da14f8035585ab57577aa05be23a ] + +Regulator requesting may result in deferred probing error which will +abort driver probing. To avoid this just use dev_err_probe which handles +deferred probing. + +Fixes: 3904b28efb2c ("iio: gyro: Add driver for the MPU-3050 gyroscope") +Signed-off-by: Svyatoslav Ryhel +Reviewed-by: Andy Shevchenko +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/gyro/mpu3050-core.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/iio/gyro/mpu3050-core.c b/drivers/iio/gyro/mpu3050-core.c +index 67ae7d1012bc2..ee2fcd20545de 100644 +--- a/drivers/iio/gyro/mpu3050-core.c ++++ b/drivers/iio/gyro/mpu3050-core.c +@@ -1162,10 +1162,8 @@ int mpu3050_common_probe(struct device *dev, + mpu3050->regs[1].supply = mpu3050_reg_vlogic; + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(mpu3050->regs), + mpu3050->regs); +- if (ret) { +- dev_err(dev, "Cannot get regulators\n"); +- return ret; +- } ++ if (ret) ++ return dev_err_probe(dev, ret, "Cannot get regulators\n"); + + ret = mpu3050_power_up(mpu3050); + if (ret) +-- +2.51.0 + diff --git a/queue-6.19/drm-amd-display-don-t-repeat-dac-load-detection.patch b/queue-6.19/drm-amd-display-don-t-repeat-dac-load-detection.patch new file mode 100644 index 0000000000..042840ef9d --- /dev/null +++ b/queue-6.19/drm-amd-display-don-t-repeat-dac-load-detection.patch @@ -0,0 +1,49 @@ +From 17eb1942ec107c92a61d4608310090f098e273e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 6 Dec 2025 03:31:06 +0100 +Subject: drm/amd/display: Don't repeat DAC load detection +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 0d89268d20c961b6226a4aa948fdbe9f93021d95 ] + +The analog link detection code path had already performed the +DAC load detection by the time the EDID read is attempted. +So there is no need to repeat the DAC load detection, +we can know that no display is connected if no EDID is read. + +Fixes: ac1bb4952267 ("drm/amd/display: Use DAC load detection on analog connectors (v2)") +Suggested-by: Alex Hung +Reviewed-by: Alex Deucher +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/link/link_detection.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/link/link_detection.c b/drivers/gpu/drm/amd/display/dc/link/link_detection.c +index 4f48e7ea75110..f986b57381bab 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/link_detection.c ++++ b/drivers/gpu/drm/amd/display/dc/link/link_detection.c +@@ -1173,11 +1173,10 @@ static bool detect_link_and_local_sink(struct dc_link *link, + * - cheap DVI-A cable or adapter that doesn't connect DDC + */ + if (dc_connector_supports_analog(link->link_id.id)) { +- /* If we didn't do DAC load detection yet, do it now +- * to verify there really is a display connected. ++ /* If we didn't already detect a display using ++ * DAC load detection, we know it isn't connected. + */ +- if (link->type != dc_connection_analog_load && +- !link_detect_dac_load_detect(link)) { ++ if (link->type != dc_connection_analog_load) { + if (prev_sink) + dc_sink_release(prev_sink); + link_disconnect_sink(link); +-- +2.51.0 + diff --git a/queue-6.19/drm-amd-display-don-t-use-kernel-doc-comment-in-dc_r.patch b/queue-6.19/drm-amd-display-don-t-use-kernel-doc-comment-in-dc_r.patch new file mode 100644 index 0000000000..efa2996abe --- /dev/null +++ b/queue-6.19/drm-amd-display-don-t-use-kernel-doc-comment-in-dc_r.patch @@ -0,0 +1,41 @@ +From 31eb43d937a694334941bf8c05eae59016a0b6be Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 15 Dec 2025 18:38:57 +0700 +Subject: drm/amd/display: Don't use kernel-doc comment in + dc_register_software_state struct + +From: Bagas Sanjaya + +[ Upstream commit b1e2a6a57aa95f8192e8edb9edaecfd326745d32 ] + +Sphinx reports kernel-doc warning: + +WARNING: ./drivers/gpu/drm/amd/display/dc/dc.h:2796 This comment starts with '/**', but isn't a kernel-doc comment. Refer to Documentation/doc-guide/kernel-doc.rst + * Software state variables used to program register fields across the display pipeline + +Don't use kernel-doc comment syntax to fix it. + +Fixes: b0ff344fe70c ("drm/amd/display: Add interface to capture expected HW state from SW state") +Signed-off-by: Bagas Sanjaya +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/dc.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h +index 29edfa51ea2cc..0a9758a042586 100644 +--- a/drivers/gpu/drm/amd/display/dc/dc.h ++++ b/drivers/gpu/drm/amd/display/dc/dc.h +@@ -2793,7 +2793,7 @@ void dc_get_underflow_debug_data_for_otg(struct dc *dc, int primary_otg_inst, st + + void dc_get_power_feature_status(struct dc *dc, int primary_otg_inst, struct power_features *out_data); + +-/** ++/* + * Software state variables used to program register fields across the display pipeline + */ + struct dc_register_software_state { +-- +2.51.0 + diff --git a/queue-6.19/drm-amd-display-pass-proper-dac-encoder-id-to-vbios.patch b/queue-6.19/drm-amd-display-pass-proper-dac-encoder-id-to-vbios.patch new file mode 100644 index 0000000000..122e9d3e51 --- /dev/null +++ b/queue-6.19/drm-amd-display-pass-proper-dac-encoder-id-to-vbios.patch @@ -0,0 +1,140 @@ +From db8afc79595714a5adc5ced587d21397773166c8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 6 Dec 2025 03:31:02 +0100 +Subject: drm/amd/display: Pass proper DAC encoder ID to VBIOS +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 436d0d22aa7035a9f9b24fb14cd0e84d6571ea87 ] + +Similarly to the analog_engine field, add a new analog_id field +which contains the encoder ID of the analog encoder that +corresponds to the link encoder. + +Previously, the default encoder ID of the link encoder was used, +which meant that we passed the wrong ID in case of DVI-I. + +Fixes: 5834c33fd3f6 ("drm/amd/display: Add concept of analog encoders (v2)") +Reviewed-by: Alex Deucher +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c | 2 ++ + drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h | 2 ++ + drivers/gpu/drm/amd/display/dc/link/link_factory.c | 11 ++++++----- + .../amd/display/dc/resource/dce110/dce110_resource.c | 2 ++ + 4 files changed, 12 insertions(+), 5 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +index 87dbb8d7ed27d..5c1a10f77733a 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c ++++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +@@ -850,6 +850,7 @@ void dce110_link_encoder_construct( + enc110->base.funcs = &dce110_lnk_enc_funcs; + enc110->base.ctx = init_data->ctx; + enc110->base.id = init_data->encoder; ++ enc110->base.analog_id = init_data->analog_encoder; + + enc110->base.hpd_source = init_data->hpd_source; + enc110->base.connector = init_data->connector; +@@ -1793,6 +1794,7 @@ void dce60_link_encoder_construct( + enc110->base.funcs = &dce60_lnk_enc_funcs; + enc110->base.ctx = init_data->ctx; + enc110->base.id = init_data->encoder; ++ enc110->base.analog_id = init_data->analog_encoder; + + enc110->base.hpd_source = init_data->hpd_source; + enc110->base.connector = init_data->connector; +diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h +index df512920a9fab..e638325e35ecf 100644 +--- a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h ++++ b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h +@@ -47,6 +47,7 @@ struct encoder_init_data { + enum hpd_source_id hpd_source; + /* TODO: in DAL2, here was pointer to EventManagerInterface */ + struct graphics_object_id encoder; ++ struct graphics_object_id analog_encoder; + enum engine_id analog_engine; + struct dc_context *ctx; + enum transmitter transmitter; +@@ -81,6 +82,7 @@ struct link_encoder { + int32_t aux_channel_offset; + struct dc_context *ctx; + struct graphics_object_id id; ++ struct graphics_object_id analog_id; + struct graphics_object_id connector; + uint32_t output_signals; + enum engine_id preferred_engine; +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 c79c18efb6f89..d9cb6b6714009 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/link_factory.c ++++ b/drivers/gpu/drm/amd/display/dc/link/link_factory.c +@@ -433,20 +433,19 @@ static enum channel_id get_ddc_line(struct dc_link *link) + return channel; + } + +-static enum engine_id find_analog_engine(struct dc_link *link) ++static enum engine_id find_analog_engine(struct dc_link *link, struct graphics_object_id *enc) + { + struct dc_bios *bp = link->ctx->dc_bios; +- struct graphics_object_id encoder = {0}; + enum bp_result bp_result = BP_RESULT_OK; + int i; + + for (i = 0; i < 3; i++) { +- bp_result = bp->funcs->get_src_obj(bp, link->link_id, i, &encoder); ++ bp_result = bp->funcs->get_src_obj(bp, link->link_id, i, enc); + + if (bp_result != BP_RESULT_OK) + return ENGINE_ID_UNKNOWN; + +- switch (encoder.id) { ++ switch (enc->id) { + case ENCODER_ID_INTERNAL_DAC1: + case ENCODER_ID_INTERNAL_KLDSCP_DAC1: + return ENGINE_ID_DACA; +@@ -456,6 +455,7 @@ static enum engine_id find_analog_engine(struct dc_link *link) + } + } + ++ memset(enc, 0, sizeof(*enc)); + return ENGINE_ID_UNKNOWN; + } + +@@ -508,7 +508,7 @@ static bool construct_phy(struct dc_link *link, + */ + bp_funcs->get_src_obj(bios, link->link_id, 0, &link_encoder); + transmitter_from_encoder = translate_encoder_to_transmitter(link_encoder); +- link_analog_engine = find_analog_engine(link); ++ link_analog_engine = find_analog_engine(link, &enc_init_data.analog_encoder); + + if (transmitter_from_encoder == TRANSMITTER_UNKNOWN && + !analog_engine_supported(link_analog_engine)) { +@@ -648,6 +648,7 @@ static bool construct_phy(struct dc_link *link, + enc_init_data.channel = get_ddc_line(link); + enc_init_data.hpd_source = get_hpd_line(link); + enc_init_data.transmitter = transmitter_from_encoder; ++ enc_init_data.analog_engine = find_analog_engine(link, &enc_init_data.analog_encoder); + enc_init_data.encoder = link_encoder; + enc_init_data.analog_engine = link_analog_engine; + +diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce110/dce110_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce110/dce110_resource.c +index cd54382c0af3e..7c09825cd9bd3 100644 +--- a/drivers/gpu/drm/amd/display/dc/resource/dce110/dce110_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/resource/dce110/dce110_resource.c +@@ -895,6 +895,8 @@ static void get_pixel_clock_parameters( + */ + pixel_clk_params->requested_pix_clk_100hz = stream->timing.pix_clk_100hz; + pixel_clk_params->encoder_object_id = stream->link->link_enc->id; ++ if (dc_is_rgb_signal(pipe_ctx->stream->signal)) ++ pixel_clk_params->encoder_object_id = stream->link->link_enc->analog_id; + pixel_clk_params->signal_type = pipe_ctx->stream->signal; + pixel_clk_params->controller_id = pipe_ctx->stream_res.tg->inst + 1; + /* TODO: un-hardcode*/ +-- +2.51.0 + diff --git a/queue-6.19/drm-amd-display-remove-unused-encoder-types.patch b/queue-6.19/drm-amd-display-remove-unused-encoder-types.patch new file mode 100644 index 0000000000..8d082f8911 --- /dev/null +++ b/queue-6.19/drm-amd-display-remove-unused-encoder-types.patch @@ -0,0 +1,130 @@ +From 4bc44692a9e67526675ab69431080b00f72b5c67 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 21 Nov 2025 11:48:49 -0500 +Subject: drm/amd/display: Remove unused encoder types + +From: Ivan Lipski + +[ Upstream commit 4ab27b01df629545de5a5f9889867b0f19438cd8 ] + +[Why&How] +We only support ENCODER_ID_INTERNAL_UNIPHY encoders now, so NUTMEG & TRAVIS +can be removed from translate_encoder_to_transmitter. + +Also refactor to use local variables of transmitter to exit early. + +V2: Fix construct_phy check for TRANSMITTER_UKNOWN + +Signed-off-by: Ivan Lipski +Reviewed-by: Harry Wentland +Tested-by: Dan Wheeler +Signed-off-by: Alex Deucher +Stable-dep-of: 436d0d22aa70 ("drm/amd/display: Pass proper DAC encoder ID to VBIOS") +Signed-off-by: Sasha Levin +--- + .../drm/amd/display/dc/link/link_factory.c | 47 +++++-------------- + 1 file changed, 12 insertions(+), 35 deletions(-) + +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 a6e2b0821969b..b3ca83f918747 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/link_factory.c ++++ b/drivers/gpu/drm/amd/display/dc/link/link_factory.c +@@ -350,24 +350,6 @@ static enum transmitter translate_encoder_to_transmitter( + return TRANSMITTER_UNKNOWN; + } + break; +- case ENCODER_ID_EXTERNAL_NUTMEG: +- switch (encoder.enum_id) { +- case ENUM_ID_1: +- return TRANSMITTER_NUTMEG_CRT; +- default: +- return TRANSMITTER_UNKNOWN; +- } +- break; +- case ENCODER_ID_EXTERNAL_TRAVIS: +- switch (encoder.enum_id) { +- case ENUM_ID_1: +- return TRANSMITTER_TRAVIS_CRT; +- case ENUM_ID_2: +- return TRANSMITTER_TRAVIS_LCD; +- default: +- return TRANSMITTER_UNKNOWN; +- } +- break; + default: + return TRANSMITTER_UNKNOWN; + } +@@ -477,14 +459,6 @@ static enum engine_id find_analog_engine(struct dc_link *link) + return ENGINE_ID_UNKNOWN; + } + +-static bool transmitter_supported(const enum transmitter transmitter) +-{ +- return transmitter != TRANSMITTER_UNKNOWN && +- transmitter != TRANSMITTER_NUTMEG_CRT && +- transmitter != TRANSMITTER_TRAVIS_CRT && +- transmitter != TRANSMITTER_TRAVIS_LCD; +-} +- + static bool analog_engine_supported(const enum engine_id engine_id) + { + return engine_id == ENGINE_ID_DACA || +@@ -502,6 +476,8 @@ static bool construct_phy(struct dc_link *link, + struct dc_bios *bios = init_params->dc->ctx->dc_bios; + const struct dc_vbios_funcs *bp_funcs = bios->funcs; + struct bp_disp_connector_caps_info disp_connect_caps_info = { 0 }; ++ struct graphics_object_id link_encoder = { 0 }; ++ enum transmitter transmitter_from_encoder; + + DC_LOGGER_INIT(dc_ctx->logger); + +@@ -522,21 +498,21 @@ static bool construct_phy(struct dc_link *link, + link->link_id = + bios->funcs->get_connector_id(bios, init_params->connector_index); + ++ link->ep_type = DISPLAY_ENDPOINT_PHY; ++ ++ DC_LOG_DC("BIOS object table - link_id: %d", link->link_id.id); ++ + /* Determine early if the link has any supported encoders, + * so that we avoid initializing DDC and HPD, etc. + */ +- bp_funcs->get_src_obj(bios, link->link_id, 0, &enc_init_data.encoder); +- enc_init_data.transmitter = translate_encoder_to_transmitter(enc_init_data.encoder); ++ bp_funcs->get_src_obj(bios, link->link_id, 0, &link_encoder); ++ transmitter_from_encoder = translate_encoder_to_transmitter(link_encoder); + enc_init_data.analog_engine = find_analog_engine(link); + +- link->ep_type = DISPLAY_ENDPOINT_PHY; +- +- DC_LOG_DC("BIOS object table - link_id: %d", link->link_id.id); +- +- if (!transmitter_supported(enc_init_data.transmitter) && ++ if (transmitter_from_encoder == TRANSMITTER_UNKNOWN && + !analog_engine_supported(enc_init_data.analog_engine)) { + DC_LOG_WARNING("link_id %d has unsupported encoder\n", link->link_id.id); +- goto unsupported_fail; ++ goto create_fail; + } + + if (bios->funcs->get_disp_connector_caps_info) { +@@ -670,6 +646,8 @@ static bool construct_phy(struct dc_link *link, + enc_init_data.connector = link->link_id; + enc_init_data.channel = get_ddc_line(link); + enc_init_data.hpd_source = get_hpd_line(link); ++ enc_init_data.transmitter = transmitter_from_encoder; ++ enc_init_data.encoder = link_encoder; + + link->hpd_src = enc_init_data.hpd_source; + +@@ -806,7 +784,6 @@ static bool construct_phy(struct dc_link *link, + link->hpd_gpio = NULL; + } + +-unsupported_fail: + DC_LOG_DC("BIOS object table - %s failed.\n", __func__); + return false; + } +-- +2.51.0 + diff --git a/queue-6.19/drm-amd-display-update-dc_connection_dac_load-to-dc_.patch b/queue-6.19/drm-amd-display-update-dc_connection_dac_load-to-dc_.patch new file mode 100644 index 0000000000..4163739ac2 --- /dev/null +++ b/queue-6.19/drm-amd-display-update-dc_connection_dac_load-to-dc_.patch @@ -0,0 +1,94 @@ +From e68d211f4b00804ea7e109c59bd7e33d5fea80a5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Dec 2025 12:09:08 -0700 +Subject: drm/amd/display: Update dc_connection_dac_load to + dc_connection_analog_load + +From: Alex Hung + +[ Upstream commit 57c8690a84bec025a8bc22e5f867fd660c4a3e76 ] + +Update to a more accurate name dc_connection_analog_load. + +Reviewed-by: Harry Wentland +Signed-off-by: Alex Hung +Signed-off-by: Chenyu Chen +Tested-by: Daniel Wheeler +Signed-off-by: Alex Deucher +Stable-dep-of: 0d89268d20c9 ("drm/amd/display: Don't repeat DAC load detection") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 +- + drivers/gpu/drm/amd/display/dc/dc_types.h | 2 +- + drivers/gpu/drm/amd/display/dc/link/link_detection.c | 8 ++++---- + 3 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +index a8a59126b2d2b..b31bd6fa70181 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -7434,7 +7434,7 @@ amdgpu_dm_connector_poll(struct amdgpu_dm_connector *aconnector, bool force) + * + * Only allow to poll such a connector again when forcing. + */ +- if (!force && link->local_sink && link->type == dc_connection_dac_load) ++ if (!force && link->local_sink && link->type == dc_connection_analog_load) + return connector->status; + + mutex_lock(&aconnector->hpd_lock); +diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h +index f46039f642034..3e63d7bda1661 100644 +--- a/drivers/gpu/drm/amd/display/dc/dc_types.h ++++ b/drivers/gpu/drm/amd/display/dc/dc_types.h +@@ -354,7 +354,7 @@ enum dc_connection_type { + dc_connection_single, + dc_connection_mst_branch, + dc_connection_sst_branch, +- dc_connection_dac_load ++ dc_connection_analog_load + }; + + struct dc_csc_adjustments { +diff --git a/drivers/gpu/drm/amd/display/dc/link/link_detection.c b/drivers/gpu/drm/amd/display/dc/link/link_detection.c +index 7fa6bc97a9193..4f48e7ea75110 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/link_detection.c ++++ b/drivers/gpu/drm/amd/display/dc/link/link_detection.c +@@ -1176,7 +1176,7 @@ static bool detect_link_and_local_sink(struct dc_link *link, + /* If we didn't do DAC load detection yet, do it now + * to verify there really is a display connected. + */ +- if (link->type != dc_connection_dac_load && ++ if (link->type != dc_connection_analog_load && + !link_detect_dac_load_detect(link)) { + if (prev_sink) + dc_sink_release(prev_sink); +@@ -1185,7 +1185,7 @@ static bool detect_link_and_local_sink(struct dc_link *link, + } + + DC_LOG_INFO("%s detected analog display without EDID\n", __func__); +- link->type = dc_connection_dac_load; ++ link->type = dc_connection_analog_load; + sink->edid_caps.analog = true; + break; + } +@@ -1372,7 +1372,7 @@ static bool detect_link_and_local_sink(struct dc_link *link, + * @link: DC link to evaluate (must support analog signalling). + * @type: Updated with the detected connection type: + * dc_connection_single (analog via DDC), +- * dc_connection_dac_load (via load-detect), ++ * dc_connection_analog_load (via load-detect), + * or dc_connection_none. + * + * Return: true if detection completed. +@@ -1388,7 +1388,7 @@ static bool link_detect_analog(struct dc_link *link, enum dc_connection_type *ty + } + + if (link_detect_dac_load_detect(link)) { +- *type = dc_connection_dac_load; ++ *type = dc_connection_analog_load; + return true; + } + +-- +2.51.0 + diff --git a/queue-6.19/drm-amd-display-use-local-variable-for-analog_engine.patch b/queue-6.19/drm-amd-display-use-local-variable-for-analog_engine.patch new file mode 100644 index 0000000000..9df8165014 --- /dev/null +++ b/queue-6.19/drm-amd-display-use-local-variable-for-analog_engine.patch @@ -0,0 +1,59 @@ +From e5113789ab8be95cf2d6d8fd1ee0a93f826919a4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 21 Nov 2025 11:54:31 -0500 +Subject: drm/amd/display: Use local variable for analog_engine initialization + +From: Ivan Lipski + +[ Upstream commit 6afc422e1a49d18b63f7042fb1cb6f519a972c8a ] + +[Why&How] +Use local variable for analog_engine retrieval and check if it is supported +instead of the struct parameter. + +Signed-off-by: Ivan Lipski +Reviewed-by: Harry Wentland +Tested-by: Dan Wheeler +Signed-off-by: Alex Deucher +Stable-dep-of: 436d0d22aa70 ("drm/amd/display: Pass proper DAC encoder ID to VBIOS") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/link/link_factory.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +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 b3ca83f918747..c79c18efb6f89 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/link_factory.c ++++ b/drivers/gpu/drm/amd/display/dc/link/link_factory.c +@@ -478,6 +478,7 @@ static bool construct_phy(struct dc_link *link, + struct bp_disp_connector_caps_info disp_connect_caps_info = { 0 }; + struct graphics_object_id link_encoder = { 0 }; + enum transmitter transmitter_from_encoder; ++ enum engine_id link_analog_engine; + + DC_LOGGER_INIT(dc_ctx->logger); + +@@ -507,10 +508,10 @@ static bool construct_phy(struct dc_link *link, + */ + bp_funcs->get_src_obj(bios, link->link_id, 0, &link_encoder); + transmitter_from_encoder = translate_encoder_to_transmitter(link_encoder); +- enc_init_data.analog_engine = find_analog_engine(link); ++ link_analog_engine = find_analog_engine(link); + + if (transmitter_from_encoder == TRANSMITTER_UNKNOWN && +- !analog_engine_supported(enc_init_data.analog_engine)) { ++ !analog_engine_supported(link_analog_engine)) { + DC_LOG_WARNING("link_id %d has unsupported encoder\n", link->link_id.id); + goto create_fail; + } +@@ -648,6 +649,7 @@ static bool construct_phy(struct dc_link *link, + enc_init_data.hpd_source = get_hpd_line(link); + enc_init_data.transmitter = transmitter_from_encoder; + enc_init_data.encoder = link_encoder; ++ enc_init_data.analog_engine = link_analog_engine; + + link->hpd_src = enc_init_data.hpd_source; + +-- +2.51.0 + diff --git a/queue-6.19/drm-amd-drop-amdgpu-kernel-modesetting-enabled-messa.patch b/queue-6.19/drm-amd-drop-amdgpu-kernel-modesetting-enabled-messa.patch new file mode 100644 index 0000000000..63ebe30b43 --- /dev/null +++ b/queue-6.19/drm-amd-drop-amdgpu-kernel-modesetting-enabled-messa.patch @@ -0,0 +1,40 @@ +From a24c450a8cfda6ad68811c04b8e3532bffdd0309 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 14 Dec 2025 19:12:19 -0600 +Subject: drm/amd: Drop "amdgpu kernel modesetting enabled" message + +From: Mario Limonciello (AMD) + +[ Upstream commit 8644084a74a4573278d6f454c6638ccd5965f4e2 ] + +The behavior for amdgpu was changed with commit e00e5c223878 +("drm/amdgpu: adjust drm_firmware_drivers_only() handling") to +potentially allow loading even if nomodeset was set, so the +message is no longer accurate. + +Just drop it to avoid confusion. + +Fixes: e00e5c223878 ("drm/amdgpu: adjust drm_firmware_drivers_only() handling") +Signed-off-by: Mario Limonciello (AMD) +Reviewed-by: Aurabindo Pillai +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +index 39387da8586b4..83567ade84298 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +@@ -3172,7 +3172,6 @@ static int __init amdgpu_init(void) + if (r) + goto error_fence; + +- DRM_INFO("amdgpu kernel modesetting enabled.\n"); + amdgpu_register_atpx_handler(); + amdgpu_acpi_detect(); + +-- +2.51.0 + diff --git a/queue-6.19/drm-amd-pm-fix-unneeded-semicolon-warning.patch b/queue-6.19/drm-amd-pm-fix-unneeded-semicolon-warning.patch new file mode 100644 index 0000000000..3943c3228f --- /dev/null +++ b/queue-6.19/drm-amd-pm-fix-unneeded-semicolon-warning.patch @@ -0,0 +1,39 @@ +From 013b043486c636616ae4090dda7f589f45cf6af4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 10:11:09 +0530 +Subject: drm/amd/pm: Fix unneeded semicolon warning + +From: Lijo Lazar + +[ Upstream commit 05138e8ff287188be7b1bedf022c8b4fd1f09a25 ] + +Fix the warning reported. +drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c:909:3-4: Unneeded semicolon + +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202601182157.r1AfndME-lkp@intel.com/ +Fixes: b480f573a8ab ("drm/amd/pm: Use gpu metrics 1.9 for SMUv13.0.12") +Signed-off-by: Lijo Lazar +Reviewed-by: Asad Kamal +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c +index 9e635f733fbfd..370326ec65d94 100644 +--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c ++++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c +@@ -922,7 +922,7 @@ void smu_v13_0_12_get_gpu_metrics(struct smu_context *smu, void **table, + gpu_metrics->gfx_below_host_limit_total_acc + [i] = SMUQ10_ROUND( + metrics->GfxclkBelowHostLimitTotalAcc[inst]); +- }; ++ } + } + + gpu_metrics->xgmi_link_width = metrics->XgmiWidth; +-- +2.51.0 + diff --git a/queue-6.19/drm-amd-pm-return-eopnotsupp-when-can-t-read-power-l.patch b/queue-6.19/drm-amd-pm-return-eopnotsupp-when-can-t-read-power-l.patch new file mode 100644 index 0000000000..418f4d3f7d --- /dev/null +++ b/queue-6.19/drm-amd-pm-return-eopnotsupp-when-can-t-read-power-l.patch @@ -0,0 +1,43 @@ +From 3ece813d35be52d1032ad701c83e40c615365052 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 21:36:25 +0100 +Subject: drm/amd/pm: Return -EOPNOTSUPP when can't read power limit +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit e53dcefe30df4f317161f36e8bc11926e7dd7a2e ] + +So that hwmon_attributes_visible() will see that the power2_cap +attributes should not be visible on GPUs that don't support +the get_power_limit() function. + +This fixes an error when running the "sensors" command on SI. + +Fixes: 12c958d1db36 ("drm/amd/pm: Expose ppt1 limit for gc_v9_5_0") +Reviewed-by: Alex Deucher +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/amdgpu_dpm.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c +index 302af1fb6901e..9c9e96655c4be 100644 +--- a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c ++++ b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c +@@ -1589,7 +1589,7 @@ int amdgpu_dpm_get_power_limit(struct amdgpu_device *adev, + int ret = 0; + + if (!pp_funcs->get_power_limit) +- return -ENODATA; ++ return -EOPNOTSUPP; + + mutex_lock(&adev->pm.mutex); + ret = pp_funcs->get_power_limit(adev->powerplay.pp_handle, +-- +2.51.0 + diff --git a/queue-6.19/drm-amdgpu-describe-amd_ip_block_type_ras-in-amd_ip_.patch b/queue-6.19/drm-amdgpu-describe-amd_ip_block_type_ras-in-amd_ip_.patch new file mode 100644 index 0000000000..b9e360d83e --- /dev/null +++ b/queue-6.19/drm-amdgpu-describe-amd_ip_block_type_ras-in-amd_ip_.patch @@ -0,0 +1,38 @@ +From 8c3eb8548b6ce362f85f8f9cc9fbd83741e0b9a4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 15 Dec 2025 18:38:58 +0700 +Subject: drm/amdgpu: Describe @AMD_IP_BLOCK_TYPE_RAS in amd_ip_block_type enum + +From: Bagas Sanjaya + +[ Upstream commit d8ccbb5e228b093eba19027a281274e7faf2da4c ] + +Sphinx reports kernel-doc warning: + +WARNING: ./drivers/gpu/drm/amd/include/amd_shared.h:113 Enum value 'AMD_IP_BLOCK_TYPE_RAS' not described in enum 'amd_ip_block_type' + +Describe the value to fix it. + +Fixes: 7169e706c82d ("drm/amdgpu: Add ras module ip block to amdgpu discovery") +Signed-off-by: Bagas Sanjaya +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/include/amd_shared.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/include/amd_shared.h b/drivers/gpu/drm/amd/include/amd_shared.h +index 17945094a1383..ac2d3701e2bdc 100644 +--- a/drivers/gpu/drm/amd/include/amd_shared.h ++++ b/drivers/gpu/drm/amd/include/amd_shared.h +@@ -89,6 +89,7 @@ enum amd_apu_flags { + * @AMD_IP_BLOCK_TYPE_VPE: Video Processing Engine + * @AMD_IP_BLOCK_TYPE_UMSCH_MM: User Mode Scheduler for Multimedia + * @AMD_IP_BLOCK_TYPE_ISP: Image Signal Processor ++* @AMD_IP_BLOCK_TYPE_RAS: Reliability, Availability, Serviceability + * @AMD_IP_BLOCK_TYPE_NUM: Total number of IP block types + */ + enum amd_ip_block_type { +-- +2.51.0 + diff --git a/queue-6.19/drm-amdgpu-don-t-attach-the-tlb-fence-for-si.patch b/queue-6.19/drm-amdgpu-don-t-attach-the-tlb-fence-for-si.patch new file mode 100644 index 0000000000..70021f7710 --- /dev/null +++ b/queue-6.19/drm-amdgpu-don-t-attach-the-tlb-fence-for-si.patch @@ -0,0 +1,43 @@ +From dbfc19b5702978fa4b17e252cbbccb9dfefa4786 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Dec 2025 14:24:03 -0500 +Subject: drm/amdgpu: don't attach the tlb fence for SI +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Alex Deucher + +[ Upstream commit 820b3d376e8a102c6aeab737ec6edebbbb710e04 ] + +SI hardware doesn't support pasids, user mode queues, or +KIQ/MES so there is no need for this. Doing so results in +a segfault as these callbacks are non-existent for SI. + +Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4744 +Fixes: f3854e04b708 ("drm/amdgpu: attach tlb fence to the PTs update") +Reviewed-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +index a67285118c37b..c362d4dfb5bbb 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +@@ -1069,7 +1069,9 @@ amdgpu_vm_tlb_flush(struct amdgpu_vm_update_params *params, + } + + /* Prepare a TLB flush fence to be attached to PTs */ +- if (!params->unlocked) { ++ if (!params->unlocked && ++ /* SI doesn't support pasid or KIQ/MES */ ++ params->adev->family > AMDGPU_FAMILY_SI) { + amdgpu_vm_tlb_fence_create(params->adev, vm, fence); + + /* Makes sure no PD/PT is freed before the flush */ +-- +2.51.0 + diff --git a/queue-6.19/drm-amdgpu-drop-mmio_remap-domain-bit-and-keep-it-in.patch b/queue-6.19/drm-amdgpu-drop-mmio_remap-domain-bit-and-keep-it-in.patch new file mode 100644 index 0000000000..50c8824d77 --- /dev/null +++ b/queue-6.19/drm-amdgpu-drop-mmio_remap-domain-bit-and-keep-it-in.patch @@ -0,0 +1,322 @@ +From 9498aa88a24d88c5995e90d7fda6214685a8517b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Dec 2025 16:12:41 +0100 +Subject: drm/amdgpu: Drop MMIO_REMAP domain bit and keep it Internal +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Christian König + +[ Upstream commit 96e97a562d067a6d867862db79864cc66aae99c2 ] + +"AMDGPU_GEM_DOMAIN_MMIO_REMAP" - Never activated as UAPI and it turned +out that this was to inflexible. + +Allocate the MMIO_REMAP buffer object as a regular GEM BO and explicitly +move it into the fixed AMDGPU_PL_MMIO_REMAP placement at the TTM level. + +This avoids relying on GEM domain bits for MMIO_REMAP, keeps the +placement purely internal, and makes the lifetime and pinning of the +global MMIO_REMAP BO explicit. The BO is pinned in TTM so it cannot be +migrated or evicted. + +The corresponding free path relies on normal DRM teardown ordering, +where no further user ioctls can access the global BO once TTM teardown +begins. + +v2 (Srini): +- Updated patch title. +- Drop use of AMDGPU_GEM_DOMAIN_MMIO_REMAP in amdgpu_ttm.c. The + MMIO_REMAP domain bit is removed from UAPI, so keep the MMIO_REMAP BO + allocation domain-less (bp.domain = 0) and rely on the TTM placement + (AMDGPU_PL_MMIO_REMAP) for backing/pinning. +- Keep fdinfo/mem-stats visibility for MMIO_REMAP by classifying BOs + based on bo->tbo.resource->mem_type == AMDGPU_PL_MMIO_REMAP, since the + domain bit is removed. + +v3: Squash patches #1 & #3 + +Fixes: 056132483724 ("drm/amdgpu/uapi: Introduce AMDGPU_GEM_DOMAIN_MMIO_REMAP") +Fixes: 2a7a794eb82c ("drm/amdgpu/ttm: Allocate/Free 4K MMIO_REMAP Singleton") +Cc: Alex Deucher +Cc: Christian König +Cc: Leo Liu +Cc: Ruijing Dong +Cc: David (Ming Qiang) Wu +Signed-off-by: Srinivasan Shanmugam +Signed-off-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 3 - + drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 21 +++--- + drivers/gpu/drm/amd/amdgpu/amdgpu_object.h | 2 - + drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 77 ++++++++++++++-------- + include/uapi/drm/amdgpu_drm.h | 6 +- + 5 files changed, 60 insertions(+), 49 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +index 3e38c5db29871..5a93cbadc4f44 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +@@ -458,9 +458,6 @@ int amdgpu_gem_create_ioctl(struct drm_device *dev, void *data, + /* always clear VRAM */ + flags |= AMDGPU_GEM_CREATE_VRAM_CLEARED; + +- if (args->in.domains & AMDGPU_GEM_DOMAIN_MMIO_REMAP) +- return -EINVAL; +- + /* create a gem object to contain this object in */ + if (args->in.domains & (AMDGPU_GEM_DOMAIN_GDS | + AMDGPU_GEM_DOMAIN_GWS | AMDGPU_GEM_DOMAIN_OA)) { +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +index e08f58de4b17f..f51ad28d0cbd5 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +@@ -153,14 +153,6 @@ void amdgpu_bo_placement_from_domain(struct amdgpu_bo *abo, u32 domain) + c++; + } + +- if (domain & AMDGPU_GEM_DOMAIN_MMIO_REMAP) { +- places[c].fpfn = 0; +- places[c].lpfn = 0; +- places[c].mem_type = AMDGPU_PL_MMIO_REMAP; +- places[c].flags = 0; +- c++; +- } +- + if (domain & AMDGPU_GEM_DOMAIN_GTT) { + places[c].fpfn = 0; + places[c].lpfn = 0; +@@ -1534,8 +1526,17 @@ u64 amdgpu_bo_gpu_offset_no_check(struct amdgpu_bo *bo) + */ + uint32_t amdgpu_bo_mem_stats_placement(struct amdgpu_bo *bo) + { +- uint32_t domain = bo->preferred_domains & AMDGPU_GEM_DOMAIN_MASK; ++ u32 domain; + ++ /* ++ * MMIO_REMAP is internal now, so it no longer maps from a userspace ++ * domain bit. Keep fdinfo/mem-stats visibility by checking the actual ++ * TTM placement. ++ */ ++ if (bo->tbo.resource && bo->tbo.resource->mem_type == AMDGPU_PL_MMIO_REMAP) ++ return AMDGPU_PL_MMIO_REMAP; ++ ++ domain = bo->preferred_domains & AMDGPU_GEM_DOMAIN_MASK; + if (!domain) + return TTM_PL_SYSTEM; + +@@ -1554,8 +1555,6 @@ uint32_t amdgpu_bo_mem_stats_placement(struct amdgpu_bo *bo) + return AMDGPU_PL_OA; + case AMDGPU_GEM_DOMAIN_DOORBELL: + return AMDGPU_PL_DOORBELL; +- case AMDGPU_GEM_DOMAIN_MMIO_REMAP: +- return AMDGPU_PL_MMIO_REMAP; + default: + return TTM_PL_SYSTEM; + } +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h +index 52c2d1731aabf..912c9afaf9e11 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h +@@ -168,8 +168,6 @@ static inline unsigned amdgpu_mem_type_to_domain(u32 mem_type) + return AMDGPU_GEM_DOMAIN_OA; + case AMDGPU_PL_DOORBELL: + return AMDGPU_GEM_DOMAIN_DOORBELL; +- case AMDGPU_PL_MMIO_REMAP: +- return AMDGPU_GEM_DOMAIN_MMIO_REMAP; + default: + break; + } +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +index ac67886acaa24..c200d5dc7b6bd 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +@@ -1812,42 +1812,45 @@ static void amdgpu_ttm_pools_fini(struct amdgpu_device *adev) + } + + /** +- * amdgpu_ttm_mmio_remap_bo_init - Allocate the singleton 4K MMIO_REMAP BO ++ * amdgpu_ttm_mmio_remap_bo_init - Allocate the singleton MMIO_REMAP BO + * @adev: amdgpu device + * +- * Allocates a one-page (4K) GEM BO in AMDGPU_GEM_DOMAIN_MMIO_REMAP when the ++ * Allocates a global BO with backing AMDGPU_PL_MMIO_REMAP when the + * hardware exposes a remap base (adev->rmmio_remap.bus_addr) and the host + * PAGE_SIZE is <= AMDGPU_GPU_PAGE_SIZE (4K). The BO is created as a regular + * GEM object (amdgpu_bo_create). + * +- * The BO is created as a normal GEM object via amdgpu_bo_create(), then +- * reserved and pinned at the TTM level (ttm_bo_pin()) so it can never be +- * migrated or evicted. No CPU mapping is established here. +- * + * Return: + * * 0 on success or intentional skip (feature not present/unsupported) + * * negative errno on allocation failure + */ +-static int amdgpu_ttm_mmio_remap_bo_init(struct amdgpu_device *adev) ++static int amdgpu_ttm_alloc_mmio_remap_bo(struct amdgpu_device *adev) + { ++ struct ttm_operation_ctx ctx = { false, false }; ++ struct ttm_placement placement; ++ struct ttm_buffer_object *tbo; ++ struct ttm_place placements; + struct amdgpu_bo_param bp; ++ struct ttm_resource *tmp; + int r; + + /* Skip if HW doesn't expose remap, or if PAGE_SIZE > AMDGPU_GPU_PAGE_SIZE (4K). */ + if (!adev->rmmio_remap.bus_addr || PAGE_SIZE > AMDGPU_GPU_PAGE_SIZE) + return 0; + ++ /* ++ * Allocate a BO first and then move it to AMDGPU_PL_MMIO_REMAP. ++ * The initial TTM resource assigned by amdgpu_bo_create() is ++ * replaced below with a fixed MMIO_REMAP placement. ++ */ + memset(&bp, 0, sizeof(bp)); +- +- /* Create exactly one GEM BO in the MMIO_REMAP domain. */ +- bp.type = ttm_bo_type_device; /* userspace-mappable GEM */ +- bp.size = AMDGPU_GPU_PAGE_SIZE; /* 4K */ ++ bp.type = ttm_bo_type_device; ++ bp.size = AMDGPU_GPU_PAGE_SIZE; + bp.byte_align = AMDGPU_GPU_PAGE_SIZE; +- bp.domain = AMDGPU_GEM_DOMAIN_MMIO_REMAP; ++ bp.domain = 0; + bp.flags = 0; + bp.resv = NULL; + bp.bo_ptr_size = sizeof(struct amdgpu_bo); +- + r = amdgpu_bo_create(adev, &bp, &adev->rmmio_remap.bo); + if (r) + return r; +@@ -1856,42 +1859,60 @@ static int amdgpu_ttm_mmio_remap_bo_init(struct amdgpu_device *adev) + if (r) + goto err_unref; + ++ tbo = &adev->rmmio_remap.bo->tbo; ++ + /* + * MMIO_REMAP is a fixed I/O placement (AMDGPU_PL_MMIO_REMAP). +- * Use TTM-level pin so the BO cannot be evicted/migrated, +- * independent of GEM domains. This +- * enforces the “fixed I/O window” + */ +- ttm_bo_pin(&adev->rmmio_remap.bo->tbo); ++ placement.num_placement = 1; ++ placement.placement = &placements; ++ placements.fpfn = 0; ++ placements.lpfn = 0; ++ placements.mem_type = AMDGPU_PL_MMIO_REMAP; ++ placements.flags = 0; ++ /* Force the BO into the fixed MMIO_REMAP placement */ ++ r = ttm_bo_mem_space(tbo, &placement, &tmp, &ctx); ++ if (unlikely(r)) ++ goto err_unlock; ++ ++ ttm_resource_free(tbo, &tbo->resource); ++ ttm_bo_assign_mem(tbo, tmp); ++ ttm_bo_pin(tbo); + + amdgpu_bo_unreserve(adev->rmmio_remap.bo); + return 0; + ++err_unlock: ++ amdgpu_bo_unreserve(adev->rmmio_remap.bo); ++ + err_unref: +- if (adev->rmmio_remap.bo) +- amdgpu_bo_unref(&adev->rmmio_remap.bo); ++ amdgpu_bo_unref(&adev->rmmio_remap.bo); + adev->rmmio_remap.bo = NULL; + return r; + } + + /** +- * amdgpu_ttm_mmio_remap_bo_fini - Free the singleton MMIO_REMAP BO ++ * amdgpu_ttm_free_mmio_remap_bo - Free the singleton MMIO_REMAP BO + * @adev: amdgpu device + * + * Frees the kernel-owned MMIO_REMAP BO if it was allocated by + * amdgpu_ttm_mmio_remap_bo_init(). + */ +-static void amdgpu_ttm_mmio_remap_bo_fini(struct amdgpu_device *adev) ++static void amdgpu_ttm_free_mmio_remap_bo(struct amdgpu_device *adev) + { +- struct amdgpu_bo *bo = adev->rmmio_remap.bo; +- +- if (!bo) +- return; /* <-- safest early exit */ ++ if (!adev->rmmio_remap.bo) ++ return; + + if (!amdgpu_bo_reserve(adev->rmmio_remap.bo, true)) { + ttm_bo_unpin(&adev->rmmio_remap.bo->tbo); + amdgpu_bo_unreserve(adev->rmmio_remap.bo); + } ++ ++ /* ++ * At this point we rely on normal DRM teardown ordering: ++ * no new user ioctls can access the global MMIO_REMAP BO ++ * once TTM teardown begins. ++ */ + amdgpu_bo_unref(&adev->rmmio_remap.bo); + adev->rmmio_remap.bo = NULL; + } +@@ -2075,8 +2096,8 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) + return r; + } + +- /* Allocate the singleton MMIO_REMAP BO (4K) if supported */ +- r = amdgpu_ttm_mmio_remap_bo_init(adev); ++ /* Allocate the singleton MMIO_REMAP BO if supported */ ++ r = amdgpu_ttm_alloc_mmio_remap_bo(adev); + if (r) + return r; + +@@ -2143,7 +2164,7 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev) + amdgpu_bo_free_kernel(&adev->mman.sdma_access_bo, NULL, + &adev->mman.sdma_access_ptr); + +- amdgpu_ttm_mmio_remap_bo_fini(adev); ++ amdgpu_ttm_free_mmio_remap_bo(adev); + amdgpu_ttm_fw_reserve_vram_fini(adev); + amdgpu_ttm_drv_reserve_vram_fini(adev); + +diff --git a/include/uapi/drm/amdgpu_drm.h b/include/uapi/drm/amdgpu_drm.h +index f80aa4c9d88fd..ba82810866297 100644 +--- a/include/uapi/drm/amdgpu_drm.h ++++ b/include/uapi/drm/amdgpu_drm.h +@@ -105,8 +105,6 @@ extern "C" { + * + * %AMDGPU_GEM_DOMAIN_DOORBELL Doorbell. It is an MMIO region for + * signalling user mode queues. +- * +- * %AMDGPU_GEM_DOMAIN_MMIO_REMAP MMIO remap page (special mapping for HDP flushing). + */ + #define AMDGPU_GEM_DOMAIN_CPU 0x1 + #define AMDGPU_GEM_DOMAIN_GTT 0x2 +@@ -115,15 +113,13 @@ extern "C" { + #define AMDGPU_GEM_DOMAIN_GWS 0x10 + #define AMDGPU_GEM_DOMAIN_OA 0x20 + #define AMDGPU_GEM_DOMAIN_DOORBELL 0x40 +-#define AMDGPU_GEM_DOMAIN_MMIO_REMAP 0x80 + #define AMDGPU_GEM_DOMAIN_MASK (AMDGPU_GEM_DOMAIN_CPU | \ + AMDGPU_GEM_DOMAIN_GTT | \ + AMDGPU_GEM_DOMAIN_VRAM | \ + AMDGPU_GEM_DOMAIN_GDS | \ + AMDGPU_GEM_DOMAIN_GWS | \ + AMDGPU_GEM_DOMAIN_OA | \ +- AMDGPU_GEM_DOMAIN_DOORBELL | \ +- AMDGPU_GEM_DOMAIN_MMIO_REMAP) ++ AMDGPU_GEM_DOMAIN_DOORBELL) + + /* Flag that CPU access will be required for the case of VRAM domain */ + #define AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED (1 << 0) +-- +2.51.0 + diff --git a/queue-6.19/drm-amdgpu-ttm-pin-4k-mmio_remap-singleton-bo-at-ini.patch b/queue-6.19/drm-amdgpu-ttm-pin-4k-mmio_remap-singleton-bo-at-ini.patch new file mode 100644 index 0000000000..958c8e8c18 --- /dev/null +++ b/queue-6.19/drm-amdgpu-ttm-pin-4k-mmio_remap-singleton-bo-at-ini.patch @@ -0,0 +1,100 @@ +From 3bca8740b9f813e814ef4269343494cac4f3ed4e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Oct 2025 19:46:53 +0530 +Subject: drm/amdgpu/ttm: Pin 4K MMIO_REMAP Singleton BO at Init v2 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Srinivasan Shanmugam + +[ Upstream commit de8955508b72f8a88afc3f2cbb62334d5f79ccc3 ] + +MMIO_REMAP (HDP flush page) is a hardware I/O window exposed via a PCI +BAR. It must not migrate or be evicted. + +Allocate a single 4 KB GEM BO in AMDGPU_GEM_DOMAIN_MMIO_REMAP during TTM +initialization when the hardware exposes a remap bus address and the +host page size is <= 4 KiB. Reserve the BO and pin it at the TTM level +so it remains fixed for its lifetime. No CPU mapping is established +here. + +On teardown, reserve, unpin, and free the BO if present. + +This prepares the object to be shared (e.g., via dma-buf) without +triggering placement changes or no CPU-access migration + +v2: Added extra NULL checks + +Suggested-by: Christian König +Suggested-by: Alex Deucher +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Christian König +Signed-off-by: Alex Deucher +Stable-dep-of: 96e97a562d06 ("drm/amdgpu: Drop MMIO_REMAP domain bit and keep it Internal") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 32 +++++++++++++++++++++++++ + 1 file changed, 32 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +index 2b931e855abd9..ac67886acaa24 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +@@ -1820,6 +1820,10 @@ static void amdgpu_ttm_pools_fini(struct amdgpu_device *adev) + * PAGE_SIZE is <= AMDGPU_GPU_PAGE_SIZE (4K). The BO is created as a regular + * GEM object (amdgpu_bo_create). + * ++ * The BO is created as a normal GEM object via amdgpu_bo_create(), then ++ * reserved and pinned at the TTM level (ttm_bo_pin()) so it can never be ++ * migrated or evicted. No CPU mapping is established here. ++ * + * Return: + * * 0 on success or intentional skip (feature not present/unsupported) + * * negative errno on allocation failure +@@ -1848,7 +1852,26 @@ static int amdgpu_ttm_mmio_remap_bo_init(struct amdgpu_device *adev) + if (r) + return r; + ++ r = amdgpu_bo_reserve(adev->rmmio_remap.bo, true); ++ if (r) ++ goto err_unref; ++ ++ /* ++ * MMIO_REMAP is a fixed I/O placement (AMDGPU_PL_MMIO_REMAP). ++ * Use TTM-level pin so the BO cannot be evicted/migrated, ++ * independent of GEM domains. This ++ * enforces the “fixed I/O window” ++ */ ++ ttm_bo_pin(&adev->rmmio_remap.bo->tbo); ++ ++ amdgpu_bo_unreserve(adev->rmmio_remap.bo); + return 0; ++ ++err_unref: ++ if (adev->rmmio_remap.bo) ++ amdgpu_bo_unref(&adev->rmmio_remap.bo); ++ adev->rmmio_remap.bo = NULL; ++ return r; + } + + /** +@@ -1860,6 +1883,15 @@ static int amdgpu_ttm_mmio_remap_bo_init(struct amdgpu_device *adev) + */ + static void amdgpu_ttm_mmio_remap_bo_fini(struct amdgpu_device *adev) + { ++ struct amdgpu_bo *bo = adev->rmmio_remap.bo; ++ ++ if (!bo) ++ return; /* <-- safest early exit */ ++ ++ if (!amdgpu_bo_reserve(adev->rmmio_remap.bo, true)) { ++ ttm_bo_unpin(&adev->rmmio_remap.bo->tbo); ++ amdgpu_bo_unreserve(adev->rmmio_remap.bo); ++ } + amdgpu_bo_unref(&adev->rmmio_remap.bo); + adev->rmmio_remap.bo = NULL; + } +-- +2.51.0 + diff --git a/queue-6.19/drm-amdgpu-use-explicit-vcn-instance-0-in-sr-iov-ini.patch b/queue-6.19/drm-amdgpu-use-explicit-vcn-instance-0-in-sr-iov-ini.patch new file mode 100644 index 0000000000..c049336d22 --- /dev/null +++ b/queue-6.19/drm-amdgpu-use-explicit-vcn-instance-0-in-sr-iov-ini.patch @@ -0,0 +1,179 @@ +From aed3431f1274ad82c231658b2a31db4874df6ede Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 15:25:25 +0530 +Subject: drm/amdgpu: Use explicit VCN instance 0 in SR-IOV init +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Srinivasan Shanmugam + +[ Upstream commit af26fa751c2eef66916acbf0d3c3e9159da56186 ] + +vcn_v2_0_start_sriov() declares a local variable "i" initialized to zero +and uses it only as the instance index in SOC15_REG_OFFSET(UVD, i, ...). +The value is never changed and all other fields are taken from +adev->vcn.inst[0], so this path only ever programs VCN instance 0. + +This triggered a Smatch: +warn: iterator 'i' not incremented + +Replace the dummy iterator with an explicit instance index of 0 in +SOC15_REG_OFFSET() calls. + +Fixes: dd26858a9cd8 ("drm/amdgpu: implement initialization part on VCN2.0 for SRIOV") +Reported by: Dan Carpenter +Cc: darlington Opara +Cc: Jinage Zhao +Cc: Monk Liu +Cc: Emily Deng +Cc: Christian König +Cc: Alex Deucher +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Emily Deng +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c | 45 ++++++++++++++------------- + 1 file changed, 23 insertions(+), 22 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c +index 8897dcc9c1a0a..e35fae9cdaf66 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c +@@ -1964,7 +1964,8 @@ static int vcn_v2_0_start_sriov(struct amdgpu_device *adev) + struct mmsch_v2_0_cmd_end end = { {0} }; + struct mmsch_v2_0_init_header *header; + uint32_t *init_table = adev->virt.mm_table.cpu_addr; +- uint8_t i = 0; ++ ++ /* This path only programs VCN instance 0. */ + + header = (struct mmsch_v2_0_init_header *)init_table; + direct_wt.cmd_header.command_type = MMSCH_COMMAND__DIRECT_REG_WRITE; +@@ -1983,93 +1984,93 @@ static int vcn_v2_0_start_sriov(struct amdgpu_device *adev) + size = AMDGPU_GPU_PAGE_ALIGN(adev->vcn.inst[0].fw->size + 4); + + MMSCH_V2_0_INSERT_DIRECT_RD_MOD_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_STATUS), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_STATUS), + 0xFFFFFFFF, 0x00000004); + + /* mc resume*/ + if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW), + adev->firmware.ucode[AMDGPU_UCODE_ID_VCN].tmr_mc_addr_lo); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE_64BIT_BAR_HIGH), + adev->firmware.ucode[AMDGPU_UCODE_ID_VCN].tmr_mc_addr_hi); + offset = 0; + } else { + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW), + lower_32_bits(adev->vcn.inst->gpu_addr)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE_64BIT_BAR_HIGH), + upper_32_bits(adev->vcn.inst->gpu_addr)); + offset = size; + } + + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_OFFSET0), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_OFFSET0), + 0); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_SIZE0), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_SIZE0), + size); + + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE1_64BIT_BAR_LOW), + lower_32_bits(adev->vcn.inst->gpu_addr + offset)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE1_64BIT_BAR_HIGH), + upper_32_bits(adev->vcn.inst->gpu_addr + offset)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_OFFSET1), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_OFFSET1), + 0); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_SIZE1), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_SIZE1), + AMDGPU_VCN_STACK_SIZE); + + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE2_64BIT_BAR_LOW), + lower_32_bits(adev->vcn.inst->gpu_addr + offset + + AMDGPU_VCN_STACK_SIZE)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE2_64BIT_BAR_HIGH), + upper_32_bits(adev->vcn.inst->gpu_addr + offset + + AMDGPU_VCN_STACK_SIZE)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_OFFSET2), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_OFFSET2), + 0); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_SIZE2), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_SIZE2), + AMDGPU_VCN_CONTEXT_SIZE); + + for (r = 0; r < adev->vcn.inst[0].num_enc_rings; ++r) { + ring = &adev->vcn.inst->ring_enc[r]; + ring->wptr = 0; + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_RB_BASE_LO), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_RB_BASE_LO), + lower_32_bits(ring->gpu_addr)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_RB_BASE_HI), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_RB_BASE_HI), + upper_32_bits(ring->gpu_addr)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_RB_SIZE), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_RB_SIZE), + ring->ring_size / 4); + } + + ring = &adev->vcn.inst->ring_dec; + ring->wptr = 0; + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_RBC_RB_64BIT_BAR_LOW), + lower_32_bits(ring->gpu_addr)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH), + upper_32_bits(ring->gpu_addr)); + /* force RBC into idle state */ +@@ -2080,7 +2081,7 @@ static int vcn_v2_0_start_sriov(struct amdgpu_device *adev) + tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1); + tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_RBC_RB_CNTL), tmp); ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_RBC_RB_CNTL), tmp); + + /* add end packet */ + tmp = sizeof(struct mmsch_v2_0_cmd_end); +-- +2.51.0 + diff --git a/queue-6.19/drm-amdkfd-fix-signal_eviction_fence-bool-return-val.patch b/queue-6.19/drm-amdkfd-fix-signal_eviction_fence-bool-return-val.patch new file mode 100644 index 0000000000..6653b39931 --- /dev/null +++ b/queue-6.19/drm-amdkfd-fix-signal_eviction_fence-bool-return-val.patch @@ -0,0 +1,79 @@ +From a7a6cdccdc789979cb1d7fc484566bc05609adbd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 17 Dec 2025 15:21:57 +0530 +Subject: drm/amdkfd: Fix signal_eviction_fence() bool return value +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Srinivasan Shanmugam + +[ Upstream commit 31dc58adda9874420ab8fa5a2f9c43377745753a ] + +signal_eviction_fence() is declared to return bool, but returns -EINVAL +when no eviction fence is present. This makes the "no fence" or "the +NULL-fence" path evaluate to true and triggers a Smatch warning. + +v2: Return true instead to explicitly indicate that there is no eviction +fence to signal and that eviction is already complete. This matches the +existing caller logic where a NULL fence means "nothing to do" and +allows restore handling to proceed normally. (Christian) + +Fixes the below: +drivers/gpu/drm/amd/amdgpu/../amdkfd/kfd_process.c:2099 signal_eviction_fence() +warn: '(-22)' is not bool + +drivers/gpu/drm/amd/amdgpu/../amdkfd/kfd_process.c + 2090 static bool signal_eviction_fence(struct kfd_process *p) + ^^^^ + + 2091 { + 2092 struct dma_fence *ef; + 2093 bool ret; + 2094 + 2095 rcu_read_lock(); + 2096 ef = dma_fence_get_rcu_safe(&p->ef); + 2097 rcu_read_unlock(); + 2098 if (!ef) +--> 2099 return -EINVAL; + + This should be either true or false. + Probably true because presumably + it has been tested? + + 2100 + 2101 ret = dma_fence_check_and_signal(ef); + 2102 dma_fence_put(ef); + 2103 + 2104 return ret; + 2105 } + +Fixes: 37865e02e6cc ("drm/amdkfd: Fix eviction fence handling") +Reported by: Dan Carpenter +Cc: Philip Yang +Cc: Gang BA +Cc: Felix Kuehling +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Christian König +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdkfd/kfd_process.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c +index a085faac9fe1a..5c15168f4faf6 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c +@@ -1996,7 +1996,7 @@ static int signal_eviction_fence(struct kfd_process *p) + ef = dma_fence_get_rcu_safe(&p->ef); + rcu_read_unlock(); + if (!ef) +- return -EINVAL; ++ return true; + + ret = dma_fence_signal(ef); + dma_fence_put(ef); +-- +2.51.0 + diff --git a/queue-6.19/drm-atomic-convert-drm_atomic_get_-old-new-_colorop_.patch b/queue-6.19/drm-atomic-convert-drm_atomic_get_-old-new-_colorop_.patch new file mode 100644 index 0000000000..00f3f55b6c --- /dev/null +++ b/queue-6.19/drm-atomic-convert-drm_atomic_get_-old-new-_colorop_.patch @@ -0,0 +1,213 @@ +From 7b5e34bc07749a1ce9d48655ee77b2254732bb11 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 19 Dec 2025 13:49:39 +0200 +Subject: drm/atomic: convert drm_atomic_get_{old, new}_colorop_state() into + proper functions + +From: Jani Nikula + +[ Upstream commit e05b08d7d0162cf77fff119367fb1a2d5ab3e669 ] + +There is no real reason to include drm_colorop.h from drm_atomic.h, as +drm_atomic_get_{old,new}_colorop_state() have no real reason to be +static inline. + +Convert the static inlines to proper functions, and drop the include to +reduce the include dependencies and improve data hiding. + +v2: Fix vkms build failures (Alex) + +Fixes: cfc27680ee20 ("drm/colorop: Introduce new drm_colorop mode object") +Cc: Simon Ser +Cc: Alex Hung +Cc: Harry Wentland +Cc: Daniel Stone +Cc: Melissa Wen +Cc: Sebastian Wick +Cc: Alex Hung +Reviewed-by: Alex Hung +Link: https://patch.msgid.link/20251219114939.1069851-1-jani.nikula@intel.com +Signed-off-by: Jani Nikula +Signed-off-by: Sasha Levin +--- + .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 3 ++ + drivers/gpu/drm/drm_atomic.c | 32 +++++++++++++++ + drivers/gpu/drm/drm_atomic_helper.c | 1 + + .../drm/i915/display/intel_display_types.h | 1 + + drivers/gpu/drm/vkms/vkms_composer.c | 1 + + drivers/gpu/drm/vkms/vkms_drv.c | 1 + + include/drm/drm_atomic.h | 39 ++++--------------- + 7 files changed, 47 insertions(+), 31 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +index 1dcc79b35225f..20a76d81d532d 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +@@ -23,6 +23,9 @@ + * Authors: AMD + * + */ ++ ++#include ++ + #include "amdgpu.h" + #include "amdgpu_mode.h" + #include "amdgpu_dm.h" +diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c +index 67e095e398a34..06f0205664fc5 100644 +--- a/drivers/gpu/drm/drm_atomic.c ++++ b/drivers/gpu/drm/drm_atomic.c +@@ -641,6 +641,38 @@ drm_atomic_get_colorop_state(struct drm_atomic_state *state, + } + EXPORT_SYMBOL(drm_atomic_get_colorop_state); + ++/** ++ * drm_atomic_get_old_colorop_state - get colorop state, if it exists ++ * @state: global atomic state object ++ * @colorop: colorop to grab ++ * ++ * This function returns the old colorop state for the given colorop, or ++ * NULL if the colorop is not part of the global atomic state. ++ */ ++struct drm_colorop_state * ++drm_atomic_get_old_colorop_state(struct drm_atomic_state *state, ++ struct drm_colorop *colorop) ++{ ++ return state->colorops[drm_colorop_index(colorop)].old_state; ++} ++EXPORT_SYMBOL(drm_atomic_get_old_colorop_state); ++ ++/** ++ * drm_atomic_get_new_colorop_state - get colorop state, if it exists ++ * @state: global atomic state object ++ * @colorop: colorop to grab ++ * ++ * This function returns the new colorop state for the given colorop, or ++ * NULL if the colorop is not part of the global atomic state. ++ */ ++struct drm_colorop_state * ++drm_atomic_get_new_colorop_state(struct drm_atomic_state *state, ++ struct drm_colorop *colorop) ++{ ++ return state->colorops[drm_colorop_index(colorop)].new_state; ++} ++EXPORT_SYMBOL(drm_atomic_get_new_colorop_state); ++ + static bool + plane_switching_crtc(const struct drm_plane_state *old_plane_state, + const struct drm_plane_state *new_plane_state) +diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c +index 5beea645035f2..cc1f0c102414f 100644 +--- a/drivers/gpu/drm/drm_atomic_helper.c ++++ b/drivers/gpu/drm/drm_atomic_helper.c +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + #include + #include + #include +diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h +index 06bf8f7c0989b..6e26751e8d0e3 100644 +--- a/drivers/gpu/drm/i915/display/intel_display_types.h ++++ b/drivers/gpu/drm/i915/display/intel_display_types.h +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + #include + #include + #include +diff --git a/drivers/gpu/drm/vkms/vkms_composer.c b/drivers/gpu/drm/vkms/vkms_composer.c +index 3cf3f26e0d8ea..cd85de4ffd03d 100644 +--- a/drivers/gpu/drm/vkms/vkms_composer.c ++++ b/drivers/gpu/drm/vkms/vkms_composer.c +@@ -5,6 +5,7 @@ + #include + #include + #include ++#include + #include + #include + #include +diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c +index dd1402f437736..434c295f44ba6 100644 +--- a/drivers/gpu/drm/vkms/vkms_drv.c ++++ b/drivers/gpu/drm/vkms/vkms_drv.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + #include + #include +diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h +index 43783891d3594..ff1fecd30478a 100644 +--- a/include/drm/drm_atomic.h ++++ b/include/drm/drm_atomic.h +@@ -30,7 +30,6 @@ + + #include + #include +-#include + + /** + * struct drm_crtc_commit - track modeset commits on a CRTC +@@ -707,6 +706,14 @@ drm_atomic_get_plane_state(struct drm_atomic_state *state, + struct drm_colorop_state * + drm_atomic_get_colorop_state(struct drm_atomic_state *state, + struct drm_colorop *colorop); ++ ++struct drm_colorop_state * ++drm_atomic_get_old_colorop_state(struct drm_atomic_state *state, ++ struct drm_colorop *colorop); ++struct drm_colorop_state * ++drm_atomic_get_new_colorop_state(struct drm_atomic_state *state, ++ struct drm_colorop *colorop); ++ + struct drm_connector_state * __must_check + drm_atomic_get_connector_state(struct drm_atomic_state *state, + struct drm_connector *connector); +@@ -803,36 +810,6 @@ drm_atomic_get_new_plane_state(const struct drm_atomic_state *state, + return state->planes[drm_plane_index(plane)].new_state; + } + +-/** +- * drm_atomic_get_old_colorop_state - get colorop state, if it exists +- * @state: global atomic state object +- * @colorop: colorop to grab +- * +- * This function returns the old colorop state for the given colorop, or +- * NULL if the colorop is not part of the global atomic state. +- */ +-static inline struct drm_colorop_state * +-drm_atomic_get_old_colorop_state(struct drm_atomic_state *state, +- struct drm_colorop *colorop) +-{ +- return state->colorops[drm_colorop_index(colorop)].old_state; +-} +- +-/** +- * drm_atomic_get_new_colorop_state - get colorop state, if it exists +- * @state: global atomic state object +- * @colorop: colorop to grab +- * +- * This function returns the new colorop state for the given colorop, or +- * NULL if the colorop is not part of the global atomic state. +- */ +-static inline struct drm_colorop_state * +-drm_atomic_get_new_colorop_state(struct drm_atomic_state *state, +- struct drm_colorop *colorop) +-{ +- return state->colorops[drm_colorop_index(colorop)].new_state; +-} +- + /** + * drm_atomic_get_old_connector_state - get connector state, if it exists + * @state: global atomic state object +-- +2.51.0 + diff --git a/queue-6.19/drm-buddy-release-free_trees-array-on-buddy-mm-teard.patch b/queue-6.19/drm-buddy-release-free_trees-array-on-buddy-mm-teard.patch new file mode 100644 index 0000000000..ba0f0de042 --- /dev/null +++ b/queue-6.19/drm-buddy-release-free_trees-array-on-buddy-mm-teard.patch @@ -0,0 +1,63 @@ +From c65a378163350aa8fc526feaf4c8e2162a54104f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Dec 2025 11:27:14 +0100 +Subject: drm/buddy: release free_trees array on buddy mm teardown +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Michał Grzelak + +[ Upstream commit 7d0507772406e129329983b8b807e5b499bd74fd ] + +During initialization of DRM buddy memory manager at drm_buddy_init, +mm->free_trees array is allocated for both clear and dirty RB trees. +During cleanup happening at drm_buddy_fini it is never freed, leading to +following memory leaks observed on xe module load & unload cycles: + + kmemleak_alloc+0x4a/0x90 + __kmalloc_cache_noprof+0x488/0x800 + drm_buddy_init+0xc2/0x330 [drm_buddy] + __xe_ttm_vram_mgr_init+0xc3/0x190 [xe] + xe_ttm_stolen_mgr_init+0xf5/0x9d0 [xe] + xe_device_probe+0x326/0x9e0 [xe] + xe_pci_probe+0x39a/0x610 [xe] + local_pci_probe+0x47/0xb0 + pci_device_probe+0xf3/0x260 + really_probe+0xf1/0x3c0 + __driver_probe_device+0x8c/0x180 + driver_probe_device+0x24/0xd0 + __driver_attach+0x10f/0x220 + bus_for_each_dev+0x7f/0xe0 + driver_attach+0x1e/0x30 + bus_add_driver+0x151/0x290 + +Deallocate array for free trees when cleaning up buddy memory manager +in the same way as if going through out_free_tree label. + +Fixes: d4cd665c98c1 ("drm/buddy: Separate clear and dirty free block trees") +Signed-off-by: Michał Grzelak +Reviewed-by: Lucas De Marchi +Reviewed-by: Matthew Auld +Signed-off-by: Arunpravin Paneer Selvam +Link: https://patch.msgid.link/20251208102714.4008260-2-michal.grzelak@intel.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/drm_buddy.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/drm_buddy.c b/drivers/gpu/drm/drm_buddy.c +index 2f279b46bd2cf..8308116058cc1 100644 +--- a/drivers/gpu/drm/drm_buddy.c ++++ b/drivers/gpu/drm/drm_buddy.c +@@ -420,6 +420,7 @@ void drm_buddy_fini(struct drm_buddy *mm) + + for_each_free_tree(i) + kfree(mm->free_trees[i]); ++ kfree(mm->free_trees); + kfree(mm->roots); + } + EXPORT_SYMBOL(drm_buddy_fini); +-- +2.51.0 + diff --git a/queue-6.19/drm-display-dp_mst-add-protection-against-0-vcpi.patch b/queue-6.19/drm-display-dp_mst-add-protection-against-0-vcpi.patch new file mode 100644 index 0000000000..31dd6ea561 --- /dev/null +++ b/queue-6.19/drm-display-dp_mst-add-protection-against-0-vcpi.patch @@ -0,0 +1,97 @@ +From 5d33be450de9d2672887928f9b78ae4760efebc7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 19 Nov 2025 15:16:50 +0530 +Subject: drm/display/dp_mst: Add protection against 0 vcpi + +From: Suraj Kandpal + +[ Upstream commit 342ccffd9f77fc29fe1c05fd145e4d842bd2feaa ] + +When releasing a timeslot there is a slight chance we may end up +with the wrong payload mask due to overflow if the delayed_destroy_work +ends up coming into play after a DP 2.1 monitor gets disconnected +which causes vcpi to become 0 then we try to make the payload = +~BIT(vcpi - 1) which is a negative shift. VCPI id should never +really be 0 hence skip changing the payload mask if VCPI is 0. + +Otherwise it leads to +<7> [515.287237] xe 0000:03:00.0: [drm:drm_dp_mst_get_port_malloc +[drm_display_helper]] port ffff888126ce9000 (3) +<4> [515.287267] -----------[ cut here ]----------- +<3> [515.287268] UBSAN: shift-out-of-bounds in +../drivers/gpu/drm/display/drm_dp_mst_topology.c:4575:36 +<3> [515.287271] shift exponent -1 is negative +<4> [515.287275] CPU: 7 UID: 0 PID: 3108 Comm: kworker/u64:33 Tainted: G +S U 6.17.0-rc6-lgci-xe-xe-3795-3e79699fa1b216e92+ #1 PREEMPT(voluntary) +<4> [515.287279] Tainted: [S]=CPU_OUT_OF_SPEC, [U]=USER +<4> [515.287279] Hardware name: ASUS System Product Name/PRIME Z790-P +WIFI, BIOS 1645 03/15/2024 +<4> [515.287281] Workqueue: drm_dp_mst_wq drm_dp_delayed_destroy_work +[drm_display_helper] +<4> [515.287303] Call Trace: +<4> [515.287304] +<4> [515.287306] dump_stack_lvl+0xc1/0xf0 +<4> [515.287313] dump_stack+0x10/0x20 +<4> [515.287316] __ubsan_handle_shift_out_of_bounds+0x133/0x2e0 +<4> [515.287324] ? drm_atomic_get_private_obj_state+0x186/0x1d0 +<4> [515.287333] drm_dp_atomic_release_time_slots.cold+0x17/0x3d +[drm_display_helper] +<4> [515.287355] mst_connector_atomic_check+0x159/0x180 [xe] +<4> [515.287546] drm_atomic_helper_check_modeset+0x4d9/0xfa0 +<4> [515.287550] ? __ww_mutex_lock.constprop.0+0x6f/0x1a60 +<4> [515.287562] intel_atomic_check+0x119/0x2b80 [xe] +<4> [515.287740] ? find_held_lock+0x31/0x90 +<4> [515.287747] ? lock_release+0xce/0x2a0 +<4> [515.287754] drm_atomic_check_only+0x6a2/0xb40 +<4> [515.287758] ? drm_atomic_add_affected_connectors+0x12b/0x140 +<4> [515.287765] drm_atomic_commit+0x6e/0xf0 +<4> [515.287766] ? _pfx__drm_printfn_info+0x10/0x10 +<4> [515.287774] drm_client_modeset_commit_atomic+0x25c/0x2b0 +<4> [515.287794] drm_client_modeset_commit_locked+0x60/0x1b0 +<4> [515.287795] ? mutex_lock_nested+0x1b/0x30 +<4> [515.287801] drm_client_modeset_commit+0x26/0x50 +<4> [515.287804] __drm_fb_helper_restore_fbdev_mode_unlocked+0xdc/0x110 +<4> [515.287810] drm_fb_helper_hotplug_event+0x120/0x140 +<4> [515.287814] drm_fbdev_client_hotplug+0x28/0xd0 +<4> [515.287819] drm_client_hotplug+0x6c/0xf0 +<4> [515.287824] drm_client_dev_hotplug+0x9e/0xd0 +<4> [515.287829] drm_kms_helper_hotplug_event+0x1a/0x30 +<4> [515.287834] drm_dp_delayed_destroy_work+0x3df/0x410 +[drm_display_helper] +<4> [515.287861] process_one_work+0x22b/0x6f0 +<4> [515.287874] worker_thread+0x1e8/0x3d0 +<4> [515.287879] ? __pfx_worker_thread+0x10/0x10 +<4> [515.287882] kthread+0x11c/0x250 +<4> [515.287886] ? __pfx_kthread+0x10/0x10 +<4> [515.287890] ret_from_fork+0x2d7/0x310 +<4> [515.287894] ? __pfx_kthread+0x10/0x10 +<4> [515.287897] ret_from_fork_asm+0x1a/0x30 + +Closes: https://gitlab.freedesktop.org/drm/xe/kernel/-/issues/6303 +Signed-off-by: Suraj Kandpal +Reviewed-by: Imre Deak +Reviewed-by: Lyude Paul +Link: https://patch.msgid.link/20251119094650.799135-1-suraj.kandpal@intel.com +Stable-dep-of: e05b08d7d016 ("drm/atomic: convert drm_atomic_get_{old, new}_colorop_state() into proper functions") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/display/drm_dp_mst_topology.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c +index 64e5c176d5cce..be749dcad3b58 100644 +--- a/drivers/gpu/drm/display/drm_dp_mst_topology.c ++++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c +@@ -4572,7 +4572,8 @@ int drm_dp_atomic_release_time_slots(struct drm_atomic_state *state, + if (!payload->delete) { + payload->pbn = 0; + payload->delete = true; +- topology_state->payload_mask &= ~BIT(payload->vcpi - 1); ++ if (payload->vcpi > 0) ++ topology_state->payload_mask &= ~BIT(payload->vcpi - 1); + } + + return 0; +-- +2.51.0 + diff --git a/queue-6.19/drm-hisilicon-hibmc-add-dp-mode-valid-check.patch b/queue-6.19/drm-hisilicon-hibmc-add-dp-mode-valid-check.patch new file mode 100644 index 0000000000..39074bac27 --- /dev/null +++ b/queue-6.19/drm-hisilicon-hibmc-add-dp-mode-valid-check.patch @@ -0,0 +1,115 @@ +From 4ed11ad0d7967643b4bc29b02ad8fcc1e7d0c99a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 10 Dec 2025 10:37:57 +0800 +Subject: drm/hisilicon/hibmc: add dp mode valid check + +From: Baihan Li + +[ Upstream commit 607805abfb747b98f43aa57d6d9ba4caed4d106f ] + +If DP is connected, check the DP BW in mode_valid_ctx() to ensure +that DP's link rate supports high-resolution data transmission. + +Fixes: 0ab6ea261c1f ("drm/hisilicon/hibmc: add dp module in hibmc") +Signed-off-by: Baihan Li +Signed-off-by: Yongbang Shi +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Tao Tian +Link: https://patch.msgid.link/20251210023759.3944834-3-shiyongbang@huawei.com +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + .../gpu/drm/hisilicon/hibmc/dp/dp_config.h | 2 ++ + drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c | 10 ++++++++++ + drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h | 2 ++ + .../gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c | 19 +++++++++++++++++++ + 4 files changed, 33 insertions(+) + +diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_config.h b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_config.h +index 08f9e1caf7fcb..efb30a7584758 100644 +--- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_config.h ++++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_config.h +@@ -17,5 +17,7 @@ + #define HIBMC_DP_LINK_RATE_CAL 27 + #define HIBMC_DP_SYNC_DELAY(lanes) ((lanes) == 0x2 ? 86 : 46) + #define HIBMC_DP_INT_ENABLE 0xc ++/* HIBMC_DP_LINK_RATE_CAL * 10000 * 80% = 216000 */ ++#define DP_MODE_VALI_CAL 216000 + + #endif +diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c +index 0ec6ace2d0822..37549dafa06ca 100644 +--- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c ++++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c +@@ -264,6 +264,16 @@ void hibmc_dp_reset_link(struct hibmc_dp *dp) + dp->dp_dev->link.status.channel_equalized = false; + } + ++u8 hibmc_dp_get_link_rate(struct hibmc_dp *dp) ++{ ++ return dp->dp_dev->link.cap.link_rate; ++} ++ ++u8 hibmc_dp_get_lanes(struct hibmc_dp *dp) ++{ ++ return dp->dp_dev->link.cap.lanes; ++} ++ + static const struct hibmc_dp_color_raw g_rgb_raw[] = { + {CBAR_COLOR_BAR, 0x000, 0x000, 0x000}, + {CBAR_WHITE, 0xfff, 0xfff, 0xfff}, +diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h +index 59c1eae153c55..31316fe1ea8db 100644 +--- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h ++++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h +@@ -66,5 +66,7 @@ void hibmc_dp_hpd_cfg(struct hibmc_dp *dp); + void hibmc_dp_enable_int(struct hibmc_dp *dp); + void hibmc_dp_disable_int(struct hibmc_dp *dp); + bool hibmc_dp_check_hpd_status(struct hibmc_dp *dp, int exp_status); ++u8 hibmc_dp_get_link_rate(struct hibmc_dp *dp); ++u8 hibmc_dp_get_lanes(struct hibmc_dp *dp); + + #endif +diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c +index 4a66a107900a1..616821e3c933b 100644 +--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c ++++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c +@@ -13,6 +13,7 @@ + #include "hibmc_drm_drv.h" + #include "dp/dp_hw.h" + #include "dp/dp_comm.h" ++#include "dp/dp_config.h" + + #define DP_MASKED_SINK_HPD_PLUG_INT BIT(2) + +@@ -81,9 +82,27 @@ static int hibmc_dp_detect(struct drm_connector *connector, + return connector_status_disconnected; + } + ++static int hibmc_dp_mode_valid(struct drm_connector *connector, ++ const struct drm_display_mode *mode, ++ struct drm_modeset_acquire_ctx *ctx, ++ enum drm_mode_status *status) ++{ ++ struct hibmc_dp *dp = to_hibmc_dp(connector); ++ u64 cur_val, max_val; ++ ++ /* check DP link BW */ ++ cur_val = (u64)mode->clock * HIBMC_DP_BPP; ++ max_val = (u64)hibmc_dp_get_link_rate(dp) * DP_MODE_VALI_CAL * hibmc_dp_get_lanes(dp); ++ ++ *status = cur_val > max_val ? MODE_CLOCK_HIGH : MODE_OK; ++ ++ return 0; ++} ++ + static const struct drm_connector_helper_funcs hibmc_dp_conn_helper_funcs = { + .get_modes = hibmc_dp_connector_get_modes, + .detect_ctx = hibmc_dp_detect, ++ .mode_valid_ctx = hibmc_dp_mode_valid, + }; + + static int hibmc_dp_late_register(struct drm_connector *connector) +-- +2.51.0 + diff --git a/queue-6.19/drm-hisilicon-hibmc-adding-reset-colorbar-cfg-in-dp-.patch b/queue-6.19/drm-hisilicon-hibmc-adding-reset-colorbar-cfg-in-dp-.patch new file mode 100644 index 0000000000..2495e1b80a --- /dev/null +++ b/queue-6.19/drm-hisilicon-hibmc-adding-reset-colorbar-cfg-in-dp-.patch @@ -0,0 +1,42 @@ +From fdb7f32c1ea13159627d12d59367a5508d78a476 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 10 Dec 2025 10:37:59 +0800 +Subject: drm/hisilicon/hibmc: Adding reset colorbar cfg in dp init. + +From: Baihan Li + +[ Upstream commit 6dad7fa8581e96321ec8a6a4f8160762466f539a ] + +Add colorbar disable operation before reset chontroller, to make sure +colorbar status is clear in the DP init, so if rmmod the driver and the +previous colorbar configuration will not affect the next time insmod the +driver. + +Fixes: 3c7623fb5bb6 ("drm/hisilicon/hibmc: Enable this hot plug detect of irq feature") +Signed-off-by: Baihan Li +Signed-off-by: Yongbang Shi +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Tao Tian +Link: https://patch.msgid.link/20251210023759.3944834-5-shiyongbang@huawei.com +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c +index 8f8ca940b6b26..d5bd3c45649b2 100644 +--- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c ++++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c +@@ -180,6 +180,8 @@ int hibmc_dp_hw_init(struct hibmc_dp *dp) + /* int init */ + writel(0, dp_dev->base + HIBMC_DP_INTR_ENABLE); + writel(HIBMC_DP_INT_RST, dp_dev->base + HIBMC_DP_INTR_ORIGINAL_STATUS); ++ /* clr colorbar */ ++ writel(0, dp_dev->base + HIBMC_DP_COLOR_BAR_CTRL); + /* rst */ + writel(0, dp_dev->base + HIBMC_DP_DPTX_RST_CTRL); + usleep_range(30, 50); +-- +2.51.0 + diff --git a/queue-6.19/drm-hisilicon-hibmc-fix-dp-probabilistical-detect-er.patch b/queue-6.19/drm-hisilicon-hibmc-fix-dp-probabilistical-detect-er.patch new file mode 100644 index 0000000000..2b6256928c --- /dev/null +++ b/queue-6.19/drm-hisilicon-hibmc-fix-dp-probabilistical-detect-er.patch @@ -0,0 +1,219 @@ +From e4896c03f77139d6918da0126ce081ba41b5d016 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 10 Dec 2025 10:37:56 +0800 +Subject: drm/hisilicon/hibmc: fix dp probabilistical detect errors after HPD + irq + +From: Baihan Li + +[ Upstream commit 3906e7a3b26d683868704fe262db443207f392fe ] + +The issue is that drm_connector_helper_detect_from_ddc() returns wrong +status when plugging or unplugging the monitor, which may cause the link +failed err.[0] Use HPD pin status in DP's detect_ctx() for real physical +monitor in/out, and implement a complete DP detection including read DPCD, +check if it's a branch device and its sink count for different situations. + +[0]: + hibme-drm 0000:83:00.0: [drm] *ERROR* channel equalization failed 5 times + hibme-drm 0000:83:00.0: [drm] *ERROR* channel equalization failed 5 times + hibme-drm 0000:83:00.0: [drm] *ERROR* dp link training failed, ret: -16 + hibmc-drm 0000:83:00.0: [drm] *ERROR* hibme dp mode set failed: -16 + +Fixes: 3c7623fb5bb6 ("drm/hisilicon/hibmc: Enable this hot plug detect of irq feature") +Signed-off-by: Baihan Li +Signed-off-by: Yongbang Shi +Reviewed-by: Tao Tian +Link: https://patch.msgid.link/20251210023759.3944834-2-shiyongbang@huawei.com +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/hisilicon/hibmc/dp/dp_comm.h | 4 ++ + drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c | 19 +++++++ + drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h | 6 +++ + drivers/gpu/drm/hisilicon/hibmc/dp/dp_reg.h | 3 ++ + .../gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c | 52 +++++++++++++++++-- + 5 files changed, 80 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_comm.h b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_comm.h +index 4add05c7f161a..f9ee7ebfec55c 100644 +--- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_comm.h ++++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_comm.h +@@ -40,6 +40,10 @@ struct hibmc_dp_dev { + struct mutex lock; /* protects concurrent RW in hibmc_dp_reg_write_field() */ + struct hibmc_dp_link link; + u8 dpcd[DP_RECEIVER_CAP_SIZE]; ++ u8 downstream_ports[DP_MAX_DOWNSTREAM_PORTS]; ++ struct drm_dp_desc desc; ++ bool is_branch; ++ int hpd_status; + void __iomem *serdes_base; + }; + +diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c +index 8f0daec7d1749..0ec6ace2d0822 100644 +--- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c ++++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c +@@ -2,6 +2,7 @@ + // Copyright (c) 2024 Hisilicon Limited. + + #include ++#include + #include + #include "dp_config.h" + #include "dp_comm.h" +@@ -305,3 +306,21 @@ void hibmc_dp_set_cbar(struct hibmc_dp *dp, const struct hibmc_dp_cbar_cfg *cfg) + hibmc_dp_reg_write_field(dp_dev, HIBMC_DP_COLOR_BAR_CTRL, BIT(0), cfg->enable); + writel(HIBMC_DP_SYNC_EN_MASK, dp_dev->base + HIBMC_DP_TIMING_SYNC_CTRL); + } ++ ++bool hibmc_dp_check_hpd_status(struct hibmc_dp *dp, int exp_status) ++{ ++ u32 status; ++ int ret; ++ ++ ret = readl_poll_timeout(dp->dp_dev->base + HIBMC_DP_HPD_STATUS, status, ++ FIELD_GET(HIBMC_DP_HPD_CUR_STATE, status) == exp_status, ++ 1000, 100000); /* DP spec says 100ms */ ++ if (ret) { ++ drm_dbg_dp(dp->drm_dev, "wait hpd status timeout"); ++ return false; ++ } ++ ++ dp->dp_dev->hpd_status = exp_status; ++ ++ return true; ++} +diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h +index 665f5b166dfb5..59c1eae153c55 100644 +--- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h ++++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h +@@ -14,6 +14,11 @@ + + struct hibmc_dp_dev; + ++enum hibmc_hpd_status { ++ HIBMC_HPD_OUT, ++ HIBMC_HPD_IN, ++}; ++ + enum hibmc_dp_cbar_pattern { + CBAR_COLOR_BAR, + CBAR_WHITE, +@@ -60,5 +65,6 @@ void hibmc_dp_reset_link(struct hibmc_dp *dp); + void hibmc_dp_hpd_cfg(struct hibmc_dp *dp); + void hibmc_dp_enable_int(struct hibmc_dp *dp); + void hibmc_dp_disable_int(struct hibmc_dp *dp); ++bool hibmc_dp_check_hpd_status(struct hibmc_dp *dp, int exp_status); + + #endif +diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_reg.h b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_reg.h +index 394b1e933c3ae..64306abcd9866 100644 +--- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_reg.h ++++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_reg.h +@@ -24,6 +24,9 @@ + #define HIBMC_DP_CFG_AUX_READY_DATA_BYTE GENMASK(16, 12) + #define HIBMC_DP_CFG_AUX GENMASK(24, 17) + ++#define HIBMC_DP_HPD_STATUS 0x98 ++#define HIBMC_DP_HPD_CUR_STATE GENMASK(7, 4) ++ + #define HIBMC_DP_PHYIF_CTRL0 0xa0 + #define HIBMC_DP_CFG_SCRAMBLE_EN BIT(0) + #define HIBMC_DP_CFG_PAT_SEL GENMASK(7, 4) +diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c +index d06832e62e966..4a66a107900a1 100644 +--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c ++++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c +@@ -12,6 +12,7 @@ + + #include "hibmc_drm_drv.h" + #include "dp/dp_hw.h" ++#include "dp/dp_comm.h" + + #define DP_MASKED_SINK_HPD_PLUG_INT BIT(2) + +@@ -31,12 +32,53 @@ static int hibmc_dp_connector_get_modes(struct drm_connector *connector) + return count; + } + ++static bool hibmc_dp_get_dpcd(struct hibmc_dp_dev *dp_dev) ++{ ++ int ret; ++ ++ ret = drm_dp_read_dpcd_caps(dp_dev->aux, dp_dev->dpcd); ++ if (ret) ++ return false; ++ ++ dp_dev->is_branch = drm_dp_is_branch(dp_dev->dpcd); ++ ++ ret = drm_dp_read_desc(dp_dev->aux, &dp_dev->desc, dp_dev->is_branch); ++ if (ret) ++ return false; ++ ++ ret = drm_dp_read_downstream_info(dp_dev->aux, dp_dev->dpcd, dp_dev->downstream_ports); ++ if (ret) ++ return false; ++ ++ return true; ++} ++ + static int hibmc_dp_detect(struct drm_connector *connector, + struct drm_modeset_acquire_ctx *ctx, bool force) + { +- mdelay(200); ++ struct hibmc_dp *dp = to_hibmc_dp(connector); ++ struct hibmc_dp_dev *dp_dev = dp->dp_dev; ++ int ret; ++ ++ if (dp->irq_status) { ++ if (dp_dev->hpd_status != HIBMC_HPD_IN) ++ return connector_status_disconnected; ++ } ++ ++ if (!hibmc_dp_get_dpcd(dp_dev)) ++ return connector_status_disconnected; ++ ++ if (!dp_dev->is_branch) ++ return connector_status_connected; ++ ++ if (drm_dp_read_sink_count_cap(connector, dp_dev->dpcd, &dp_dev->desc) && ++ dp_dev->downstream_ports[0] & DP_DS_PORT_HPD) { ++ ret = drm_dp_read_sink_count(dp_dev->aux); ++ if (ret > 0) ++ return connector_status_connected; ++ } + +- return drm_connector_helper_detect_from_ddc(connector, ctx, force); ++ return connector_status_disconnected; + } + + static const struct drm_connector_helper_funcs hibmc_dp_conn_helper_funcs = { +@@ -115,7 +157,7 @@ irqreturn_t hibmc_dp_hpd_isr(int irq, void *arg) + { + struct drm_device *dev = (struct drm_device *)arg; + struct hibmc_drm_private *priv = to_hibmc_drm_private(dev); +- int idx; ++ int idx, exp_status; + + if (!drm_dev_enter(dev, &idx)) + return -ENODEV; +@@ -123,12 +165,14 @@ irqreturn_t hibmc_dp_hpd_isr(int irq, void *arg) + if (priv->dp.irq_status & DP_MASKED_SINK_HPD_PLUG_INT) { + drm_dbg_dp(&priv->dev, "HPD IN isr occur!\n"); + hibmc_dp_hpd_cfg(&priv->dp); ++ exp_status = HIBMC_HPD_IN; + } else { + drm_dbg_dp(&priv->dev, "HPD OUT isr occur!\n"); + hibmc_dp_reset_link(&priv->dp); ++ exp_status = HIBMC_HPD_OUT; + } + +- if (dev->registered) ++ if (hibmc_dp_check_hpd_status(&priv->dp, exp_status)) + drm_connector_helper_hpd_irq_event(&priv->dp.connector); + + drm_dev_exit(idx); +-- +2.51.0 + diff --git a/queue-6.19/drm-hisilicon-hibmc-fix-no-showing-problem-with-load.patch b/queue-6.19/drm-hisilicon-hibmc-fix-no-showing-problem-with-load.patch new file mode 100644 index 0000000000..123266c379 --- /dev/null +++ b/queue-6.19/drm-hisilicon-hibmc-fix-no-showing-problem-with-load.patch @@ -0,0 +1,56 @@ +From 8a3b6629b44d3d5d07fd08c9dc20ee2b38e613e2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 10 Dec 2025 10:37:58 +0800 +Subject: drm/hisilicon/hibmc: fix no showing problem with loading hibmc + manually + +From: Baihan Li + +[ Upstream commit 0607052a6aee1e3d218a99fae70ba9f14b3b47ed ] + +When using command rmmod and insmod, there is no showing in second time +insmoding. Because DP controller won't send HPD signals, if connection +doesn't change or controller isn't reset. So add reset before unreset +in hibmc_dp_hw_init(). + +And also need to move the HDCP cfg after DP controller de-resets, so +that HDCP configuration takes effect. + +Fixes: 3c7623fb5bb6 ("drm/hisilicon/hibmc: Enable this hot plug detect of irq feature") +Signed-off-by: Baihan Li +Signed-off-by: Yongbang Shi +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Tao Tian +Link: https://patch.msgid.link/20251210023759.3944834-4-shiyongbang@huawei.com +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c +index 37549dafa06ca..8f8ca940b6b26 100644 +--- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c ++++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c +@@ -177,13 +177,16 @@ int hibmc_dp_hw_init(struct hibmc_dp *dp) + dp_dev->link.cap.lanes = 0x2; + dp_dev->link.cap.link_rate = DP_LINK_BW_8_1; + +- /* hdcp data */ +- writel(HIBMC_DP_HDCP, dp_dev->base + HIBMC_DP_HDCP_CFG); + /* int init */ + writel(0, dp_dev->base + HIBMC_DP_INTR_ENABLE); + writel(HIBMC_DP_INT_RST, dp_dev->base + HIBMC_DP_INTR_ORIGINAL_STATUS); + /* rst */ ++ writel(0, dp_dev->base + HIBMC_DP_DPTX_RST_CTRL); ++ usleep_range(30, 50); ++ /* de-rst */ + writel(HIBMC_DP_DPTX_RST, dp_dev->base + HIBMC_DP_DPTX_RST_CTRL); ++ /* hdcp data */ ++ writel(HIBMC_DP_HDCP, dp_dev->base + HIBMC_DP_HDCP_CFG); + /* clock enable */ + writel(HIBMC_DP_CLK_EN, dp_dev->base + HIBMC_DP_DPTX_CLK_CTRL); + +-- +2.51.0 + diff --git a/queue-6.19/drm-i915-colorop-do-not-include-headers-from-headers.patch b/queue-6.19/drm-i915-colorop-do-not-include-headers-from-headers.patch new file mode 100644 index 0000000000..ccface9412 --- /dev/null +++ b/queue-6.19/drm-i915-colorop-do-not-include-headers-from-headers.patch @@ -0,0 +1,57 @@ +From f0f10300bb400c9deade87eda684c3800260d57b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 16:18:07 +0200 +Subject: drm/i915/colorop: do not include headers from headers + +From: Jani Nikula + +[ Upstream commit 6a3591522930897c3fdb326c5d48b906b5c30b71 ] + +drm_colorop.h doesn't need the intel_display_types.h include for +anything. Don't include headers from headers if it can be avoided. + +Fixes: 3e9b06559aa1 ("drm/i915: Add intel_color_op") +Cc: Suraj Kandpal +Cc: Chaitanya Kumar Borah +Cc: Uma Shankar +Reviewed-by: Chaitanya Kumar Borah +Link: https://patch.msgid.link/20251218141807.409751-1-jani.nikula@intel.com +Signed-off-by: Jani Nikula +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/i915/display/intel_colorop.c | 2 ++ + drivers/gpu/drm/i915/display/intel_colorop.h | 4 +++- + 2 files changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/i915/display/intel_colorop.c b/drivers/gpu/drm/i915/display/intel_colorop.c +index f2fc0d8780cee..1d84933f05aa9 100644 +--- a/drivers/gpu/drm/i915/display/intel_colorop.c ++++ b/drivers/gpu/drm/i915/display/intel_colorop.c +@@ -2,7 +2,9 @@ + /* + * Copyright © 2025 Intel Corporation + */ ++ + #include "intel_colorop.h" ++#include "intel_display_types.h" + + struct intel_colorop *to_intel_colorop(struct drm_colorop *colorop) + { +diff --git a/drivers/gpu/drm/i915/display/intel_colorop.h b/drivers/gpu/drm/i915/display/intel_colorop.h +index 21d58eb9f3d0f..9276eee6e75a3 100644 +--- a/drivers/gpu/drm/i915/display/intel_colorop.h ++++ b/drivers/gpu/drm/i915/display/intel_colorop.h +@@ -6,7 +6,9 @@ + #ifndef __INTEL_COLOROP_H__ + #define __INTEL_COLOROP_H__ + +-#include "intel_display_types.h" ++enum intel_color_block; ++struct drm_colorop; ++struct intel_colorop; + + struct intel_colorop *to_intel_colorop(struct drm_colorop *colorop); + struct intel_colorop *intel_colorop_alloc(void); +-- +2.51.0 + diff --git a/queue-6.19/drm-i915-display-fix-the-pixel-normalization-handlin.patch b/queue-6.19/drm-i915-display-fix-the-pixel-normalization-handlin.patch new file mode 100644 index 0000000000..ed5c50f4bc --- /dev/null +++ b/queue-6.19/drm-i915-display-fix-the-pixel-normalization-handlin.patch @@ -0,0 +1,161 @@ +From 5dd2231c52461d2f221234829724e21596bbfbbb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 11:59:19 +0200 +Subject: drm/i915/display: fix the pixel normalization handling for xe3p_lpd + +From: Vinod Govindapillai + +[ Upstream commit 3e28a67a85f9b569066f6dfcddadb39294c0c9d4 ] + +Pixel normalizer is enabled with normalization factor as 1.0 for +FP16 formats in order to support FBC for those formats in xe3p_lpd. +Previously pixel normalizer gets disabled during the plane disable +routine. But there could be plane format settings without explicitly +calling the plane disable in-between and we could endup keeping the +pixel normalizer enabled for formats which we don't require that. +This is causing crc mismatches in yuv formats and FIFO underruns in +planar formats like NV12. Fix this by updating the pixel normalizer +configuration based on the pixel formats explicitly during the plane +settings arm calls itself - enable it for FP16 and disable it for +other formats in HDR capable planes. + +v2: avoid redundant pixel normalization setting updates + +v3: moved the normalization factor definition to intel_fbc.c and some + updates to comments + +v4: simplified the pixel normalizer setting handling + +Fixes: 5298eea7ed20 ("drm/i915/xe3p_lpd: use pixel normalizer for fp16 formats for FBC") +Signed-off-by: Vinod Govindapillai +Reviewed-by: Uma Shankar +Link: https://patch.msgid.link/20260130095919.107805-1-vinod.govindapillai@intel.com +(cherry picked from commit c0dc68f4e2aa7eddb9ec6d95931f9576d8fe7334) +Signed-off-by: Joonas Lahtinen +Signed-off-by: Sasha Levin +--- + .../drm/i915/display/intel_display_device.h | 1 + + drivers/gpu/drm/i915/display/intel_fbc.c | 10 +++--- + drivers/gpu/drm/i915/display/intel_fbc.h | 3 +- + .../drm/i915/display/skl_universal_plane.c | 36 +++++++++---------- + 4 files changed, 26 insertions(+), 24 deletions(-) + +diff --git a/drivers/gpu/drm/i915/display/intel_display_device.h b/drivers/gpu/drm/i915/display/intel_display_device.h +index b559ef43d5470..6944d081f0ad3 100644 +--- a/drivers/gpu/drm/i915/display/intel_display_device.h ++++ b/drivers/gpu/drm/i915/display/intel_display_device.h +@@ -189,6 +189,7 @@ struct intel_display_platforms { + #define HAS_MSO(__display) (DISPLAY_VER(__display) >= 12) + #define HAS_OVERLAY(__display) (DISPLAY_INFO(__display)->has_overlay) + #define HAS_PIPEDMC(__display) (DISPLAY_VER(__display) >= 12) ++#define HAS_PIXEL_NORMALIZER(__display) (DISPLAY_VER(__display) >= 35) + #define HAS_PSR(__display) (DISPLAY_INFO(__display)->has_psr) + #define HAS_PSR_HW_TRACKING(__display) (DISPLAY_INFO(__display)->has_psr_hw_tracking) + #define HAS_PSR2_SEL_FETCH(__display) (DISPLAY_VER(__display) >= 12) +diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c +index 437d2fda20a7e..8d387709f25cc 100644 +--- a/drivers/gpu/drm/i915/display/intel_fbc.c ++++ b/drivers/gpu/drm/i915/display/intel_fbc.c +@@ -1120,13 +1120,15 @@ static bool xe3p_lpd_fbc_pixel_format_is_valid(const struct intel_plane_state *p + } + } + +-bool +-intel_fbc_is_enable_pixel_normalizer(const struct intel_plane_state *plane_state) ++bool intel_fbc_need_pixel_normalizer(const struct intel_plane_state *plane_state) + { + struct intel_display *display = to_intel_display(plane_state); + +- return DISPLAY_VER(display) >= 35 && +- xe3p_lpd_fbc_fp16_format_is_valid(plane_state); ++ if (HAS_PIXEL_NORMALIZER(display) && ++ xe3p_lpd_fbc_fp16_format_is_valid(plane_state)) ++ return true; ++ ++ return false; + } + + static bool pixel_format_is_valid(const struct intel_plane_state *plane_state) +diff --git a/drivers/gpu/drm/i915/display/intel_fbc.h b/drivers/gpu/drm/i915/display/intel_fbc.h +index 91424563206a3..7e2416b29a0ea 100644 +--- a/drivers/gpu/drm/i915/display/intel_fbc.h ++++ b/drivers/gpu/drm/i915/display/intel_fbc.h +@@ -53,7 +53,6 @@ void intel_fbc_prepare_dirty_rect(struct intel_atomic_state *state, + struct intel_crtc *crtc); + void intel_fbc_dirty_rect_update_noarm(struct intel_dsb *dsb, + struct intel_plane *plane); +-bool +-intel_fbc_is_enable_pixel_normalizer(const struct intel_plane_state *plane_state); ++bool intel_fbc_need_pixel_normalizer(const struct intel_plane_state *plane_state); + + #endif /* __INTEL_FBC_H__ */ +diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c +index ee8e24497d2cf..ed14b9ea2ad2d 100644 +--- a/drivers/gpu/drm/i915/display/skl_universal_plane.c ++++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c +@@ -892,23 +892,20 @@ static void icl_plane_disable_sel_fetch_arm(struct intel_dsb *dsb, + intel_de_write_dsb(display, dsb, SEL_FETCH_PLANE_CTL(pipe, plane->id), 0); + } + +-static void x3p_lpd_plane_update_pixel_normalizer(struct intel_dsb *dsb, +- struct intel_plane *plane, +- bool enable) ++static bool plane_has_normalizer(struct intel_plane *plane) + { + struct intel_display *display = to_intel_display(plane); +- enum intel_fbc_id fbc_id = skl_fbc_id_for_pipe(plane->pipe); +- u32 val; + +- /* Only HDR planes have pixel normalizer and don't matter if no FBC */ +- if (!skl_plane_has_fbc(display, fbc_id, plane->id)) +- return; ++ return HAS_PIXEL_NORMALIZER(display) && icl_is_hdr_plane(display, plane->id); ++} + +- val = enable ? PLANE_PIXEL_NORMALIZE_NORM_FACTOR(PLANE_PIXEL_NORMALIZE_NORM_FACTOR_1_0) | +- PLANE_PIXEL_NORMALIZE_ENABLE : 0; ++static u32 pixel_normalizer_value(const struct intel_plane_state *plane_state) ++{ ++ if (!intel_fbc_need_pixel_normalizer(plane_state)) ++ return 0; + +- intel_de_write_dsb(display, dsb, +- PLANE_PIXEL_NORMALIZE(plane->pipe, plane->id), val); ++ return PLANE_PIXEL_NORMALIZE_ENABLE | ++ PLANE_PIXEL_NORMALIZE_NORM_FACTOR(PLANE_PIXEL_NORMALIZE_NORM_FACTOR_1_0); + } + + static void +@@ -927,8 +924,9 @@ icl_plane_disable_arm(struct intel_dsb *dsb, + + icl_plane_disable_sel_fetch_arm(dsb, plane, crtc_state); + +- if (DISPLAY_VER(display) >= 35) +- x3p_lpd_plane_update_pixel_normalizer(dsb, plane, false); ++ if (plane_has_normalizer(plane)) ++ intel_de_write_dsb(display, dsb, ++ PLANE_PIXEL_NORMALIZE(plane->pipe, plane->id), 0); + + intel_de_write_dsb(display, dsb, PLANE_CTL(pipe, plane_id), 0); + intel_de_write_dsb(display, dsb, PLANE_SURF(pipe, plane_id), 0); +@@ -1677,11 +1675,13 @@ icl_plane_update_arm(struct intel_dsb *dsb, + + /* + * In order to have FBC for fp16 formats pixel normalizer block must be +- * active. Check if pixel normalizer block need to be enabled for FBC. +- * If needed, use normalization factor as 1.0 and enable the block. ++ * active. For FP16 formats, use normalization factor as 1.0 and enable ++ * the block. + */ +- if (intel_fbc_is_enable_pixel_normalizer(plane_state)) +- x3p_lpd_plane_update_pixel_normalizer(dsb, plane, true); ++ if (plane_has_normalizer(plane)) ++ intel_de_write_dsb(display, dsb, ++ PLANE_PIXEL_NORMALIZE(plane->pipe, plane->id), ++ pixel_normalizer_value(plane_state)); + + /* + * The control register self-arms if the plane was previously +-- +2.51.0 + diff --git a/queue-6.19/drm-msm-a2xx-fix-pixel-shader-start-on-a225.patch b/queue-6.19/drm-msm-a2xx-fix-pixel-shader-start-on-a225.patch new file mode 100644 index 0000000000..5a4c76c033 --- /dev/null +++ b/queue-6.19/drm-msm-a2xx-fix-pixel-shader-start-on-a225.patch @@ -0,0 +1,42 @@ +From 0219fce30441b87719bd84f065d94f8787ed4ea7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 21 Nov 2025 18:13:03 +0200 +Subject: drm/msm/a2xx: fix pixel shader start on A225 + +From: Dmitry Baryshkov + +[ Upstream commit 6a7b0a670ba4d283285d76d45233cbecc5af5e40 ] + +A225 has a different PixelShader start address, write correct address +while initializing GPU. + +Fixes: 21af872cd8c6 ("drm/msm/adreno: add a2xx") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Patchwork: https://patchwork.freedesktop.org/patch/689906/ +Message-ID: <20251121-a225-v1-1-a1bab651d186@oss.qualcomm.com> +Signed-off-by: Rob Clark +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/adreno/a2xx_gpu.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/msm/adreno/a2xx_gpu.c b/drivers/gpu/drm/msm/adreno/a2xx_gpu.c +index 1b1ee14b65cf0..f6e48bb8cc69e 100644 +--- a/drivers/gpu/drm/msm/adreno/a2xx_gpu.c ++++ b/drivers/gpu/drm/msm/adreno/a2xx_gpu.c +@@ -77,7 +77,10 @@ static bool a2xx_me_init(struct msm_gpu *gpu) + + /* Vertex and Pixel Shader Start Addresses in instructions + * (3 DWORDS per instruction) */ +- OUT_RING(ring, 0x80000180); ++ if (adreno_is_a225(adreno_gpu)) ++ OUT_RING(ring, 0x80000300); ++ else ++ OUT_RING(ring, 0x80000180); + /* Maximum Contexts */ + OUT_RING(ring, 0x00000001); + /* Write Confirm Interval and The CP will wait the +-- +2.51.0 + diff --git a/queue-6.19/drm-msm-disp-dpu-add-merge3d-support-for-sc7280.patch b/queue-6.19/drm-msm-disp-dpu-add-merge3d-support-for-sc7280.patch new file mode 100644 index 0000000000..2b8658c2ae --- /dev/null +++ b/queue-6.19/drm-msm-disp-dpu-add-merge3d-support-for-sc7280.patch @@ -0,0 +1,83 @@ +From e92427aec3274b3fe958664d4c3c08e270916c87 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 1 Jan 2026 10:34:38 +0530 +Subject: drm/msm/disp/dpu: add merge3d support for sc7280 + +From: Mahadevan P + +[ Upstream commit 2892de3f4f985fa779c330468e2f341fdb762ccd ] + +On SC7280 targets, display modes with a width greater than the +max_mixer_width (2400) are rejected during mode validation when +merge3d is disabled. This limitation exists because, without a +3D merge block, two layer mixers cannot be combined(non-DSC interface), +preventing large layers from being split across mixers. As a result, +higher resolution modes cannot be supported. + +Enable merge3d support on SC7280 to allow combining streams from +two layer mixers into a single non-DSC interface. This capability +removes the width restriction and enables buffer sizes beyond the +2400-pixel limit. + +Fixes: 591e34a091d1 ("drm/msm/disp/dpu1: add support for display for SC7280 target") +Signed-off-by: Mahadevan P +Reviewed-by: Dmitry Baryshkov +Patchwork: https://patchwork.freedesktop.org/patch/696713/ +Link: https://lore.kernel.org/r/20260101-4k-v2-1-712ae3c1f816@oss.qualcomm.com +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + .../gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h +index 8f978b9c34520..2f8688224f343 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h +@@ -13,6 +13,7 @@ static const struct dpu_caps sc7280_dpu_caps = { + .has_dim_layer = true, + .has_idle_pc = true, + .max_linewidth = 2400, ++ .has_3d_merge = true, + .pixel_ram_size = DEFAULT_PIXEL_RAM_SIZE, + }; + +@@ -134,17 +135,24 @@ static const struct dpu_pingpong_cfg sc7280_pp[] = { + .name = "pingpong_2", .id = PINGPONG_2, + .base = 0x6b000, .len = 0, + .sblk = &sc7280_pp_sblk, +- .merge_3d = 0, ++ .merge_3d = MERGE_3D_1, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 10), + }, { + .name = "pingpong_3", .id = PINGPONG_3, + .base = 0x6c000, .len = 0, + .sblk = &sc7280_pp_sblk, +- .merge_3d = 0, ++ .merge_3d = MERGE_3D_1, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 11), + }, + }; + ++static const struct dpu_merge_3d_cfg sc7280_merge_3d[] = { ++ { ++ .name = "merge_3d_1", .id = MERGE_3D_1, ++ .base = 0x4f000, .len = 0x8, ++ }, ++}; ++ + /* NOTE: sc7280 only has one DSC hard slice encoder */ + static const struct dpu_dsc_cfg sc7280_dsc[] = { + { +@@ -247,6 +255,8 @@ const struct dpu_mdss_cfg dpu_sc7280_cfg = { + .mixer = sc7280_lm, + .pingpong_count = ARRAY_SIZE(sc7280_pp), + .pingpong = sc7280_pp, ++ .merge_3d_count = ARRAY_SIZE(sc7280_merge_3d), ++ .merge_3d = sc7280_merge_3d, + .dsc_count = ARRAY_SIZE(sc7280_dsc), + .dsc = sc7280_dsc, + .wb_count = ARRAY_SIZE(sc7280_wb), +-- +2.51.0 + diff --git a/queue-6.19/drm-msm-disp-set-num_planes-to-1-for-interleaved-yuv.patch b/queue-6.19/drm-msm-disp-set-num_planes-to-1-for-interleaved-yuv.patch new file mode 100644 index 0000000000..9756acabe5 --- /dev/null +++ b/queue-6.19/drm-msm-disp-set-num_planes-to-1-for-interleaved-yuv.patch @@ -0,0 +1,61 @@ +From 3a7723f9565d6a99800771971da40fec24ec8c9a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 Nov 2025 05:43:28 +0200 +Subject: drm/msm/disp: set num_planes to 1 for interleaved YUV formats + +From: Dmitry Baryshkov + +[ Upstream commit 6421e1c5075b7e1536a8fcbe6b4086db07103048 ] + +Interleaved YUV formats use only one plane for all pixel data. Specify +num_planes = 1 for those formats. This was left unnoticed since +_dpu_format_populate_plane_sizes_linear() overrides layout->num_planes. + +Fixes: 25fdd5933e4c ("drm/msm: Add SDM845 DPU support") +Reviewed-by: Jessica Zhang +Patchwork: https://patchwork.freedesktop.org/patch/688162/ +Link: https://lore.kernel.org/r/20251114-dpu-formats-v3-1-cae312379d49@oss.qualcomm.com +Tested-by: Luca Weiss # qcm6490-fairphone-fp5 +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/disp/mdp_format.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/msm/disp/mdp_format.c b/drivers/gpu/drm/msm/disp/mdp_format.c +index 426782d50cb49..eebedb1a2636e 100644 +--- a/drivers/gpu/drm/msm/disp/mdp_format.c ++++ b/drivers/gpu/drm/msm/disp/mdp_format.c +@@ -479,25 +479,25 @@ static const struct msm_format mdp_formats[] = { + 0, BPC8, BPC8, BPC8, + C2_R_Cr, C0_G_Y, C1_B_Cb, C0_G_Y, + false, CHROMA_H2V1, 4, 2, MSM_FORMAT_FLAG_YUV, +- MDP_FETCH_LINEAR, 2), ++ MDP_FETCH_LINEAR, 1), + + INTERLEAVED_YUV_FMT(UYVY, + 0, BPC8, BPC8, BPC8, + C1_B_Cb, C0_G_Y, C2_R_Cr, C0_G_Y, + false, CHROMA_H2V1, 4, 2, MSM_FORMAT_FLAG_YUV, +- MDP_FETCH_LINEAR, 2), ++ MDP_FETCH_LINEAR, 1), + + INTERLEAVED_YUV_FMT(YUYV, + 0, BPC8, BPC8, BPC8, + C0_G_Y, C1_B_Cb, C0_G_Y, C2_R_Cr, + false, CHROMA_H2V1, 4, 2, MSM_FORMAT_FLAG_YUV, +- MDP_FETCH_LINEAR, 2), ++ MDP_FETCH_LINEAR, 1), + + INTERLEAVED_YUV_FMT(YVYU, + 0, BPC8, BPC8, BPC8, + C0_G_Y, C2_R_Cr, C0_G_Y, C1_B_Cb, + false, CHROMA_H2V1, 4, 2, MSM_FORMAT_FLAG_YUV, +- MDP_FETCH_LINEAR, 2), ++ MDP_FETCH_LINEAR, 1), + + /* 3 plane YUV */ + PLANAR_YUV_FMT(YUV420, +-- +2.51.0 + diff --git a/queue-6.19/drm-msm-dp-avoid-division-by-zero-in-msm_dp_ctrl_con.patch b/queue-6.19/drm-msm-dp-avoid-division-by-zero-in-msm_dp_ctrl_con.patch new file mode 100644 index 0000000000..1de3bd6918 --- /dev/null +++ b/queue-6.19/drm-msm-dp-avoid-division-by-zero-in-msm_dp_ctrl_con.patch @@ -0,0 +1,90 @@ +From c5517554a45c8baecfa1e800a8aed95543e68b18 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Jan 2026 17:00:31 -0700 +Subject: drm/msm/dp: Avoid division by zero in msm_dp_ctrl_config_msa() + +From: Nathan Chancellor + +[ Upstream commit f185076da44c774241a16a82a7773ece3c1c607b ] + +An (admittedly problematic) optimization change in LLVM 20 [1] turns +known division by zero into the equivalent of __builtin_unreachable(), +which invokes undefined behavior if it is encountered in a control flow +graph, destroying code generation. When compile testing for x86_64, +objtool flags an instance of this optimization triggering in +msm_dp_ctrl_config_msa(), inlined into msm_dp_ctrl_on_stream(): + + drivers/gpu/drm/msm/msm.o: warning: objtool: msm_dp_ctrl_on_stream(): unexpected end of section .text.msm_dp_ctrl_on_stream + +The zero division happens if the else branch in the first if statement +in msm_dp_ctrl_config_msa() is taken because pixel_div is initialized to +zero and it is not possible for LLVM to eliminate the else branch since +rate is still not known after inlining into msm_dp_ctrl_on_stream(). + +Transform the if statements into a switch statement with a default case +with the existing error print and an early return to avoid the invalid +division. Add a comment to note this helps the compiler, even though the +case is known to be unreachable. With this, pixel_dev's default zero +initialization can be dropped, as it is dead with this change. + +Fixes: c943b4948b58 ("drm/msm/dp: add displayPort driver support") +Link: https://github.com/llvm/llvm-project/commit/37932643abab699e8bb1def08b7eb4eae7ff1448 [1] +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202601081959.9UVJEOfP-lkp@intel.com/ +Suggested-by: Konrad Dybcio +Signed-off-by: Nathan Chancellor +Reviewed-by: Dmitry Baryshkov +Patchwork: https://patchwork.freedesktop.org/patch/698355/ +Link: https://lore.kernel.org/r/20260113-drm-msm-dp_ctrl-avoid-zero-div-v2-1-f1aa67bf6e8e@kernel.org +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/dp/dp_ctrl.c | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c +index cbcc7c2f0ffc4..94411870a5e0a 100644 +--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c ++++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c +@@ -2395,20 +2395,32 @@ static void msm_dp_ctrl_config_msa(struct msm_dp_ctrl_private *ctrl, + bool is_ycbcr_420) + { + u32 pixel_m, pixel_n; +- u32 mvid, nvid, pixel_div = 0, dispcc_input_rate; ++ u32 mvid, nvid, pixel_div, dispcc_input_rate; + u32 const nvid_fixed = DP_LINK_CONSTANT_N_VALUE; + u32 const link_rate_hbr2 = 540000; + u32 const link_rate_hbr3 = 810000; + unsigned long den, num; + +- if (rate == link_rate_hbr3) ++ switch (rate) { ++ case link_rate_hbr3: + pixel_div = 6; +- else if (rate == 162000 || rate == 270000) +- pixel_div = 2; +- else if (rate == link_rate_hbr2) ++ break; ++ case link_rate_hbr2: + pixel_div = 4; +- else ++ break; ++ case 162000: ++ case 270000: ++ pixel_div = 2; ++ break; ++ default: ++ /* ++ * This cannot be reached but the compiler is not able to know ++ * that statically so return early to avoid a possibly invalid ++ * division. ++ */ + DRM_ERROR("Invalid pixel mux divider\n"); ++ return; ++ } + + dispcc_input_rate = (rate * 10) / pixel_div; + +-- +2.51.0 + diff --git a/queue-6.19/drm-msm-dp-update-msm_dp_controller-ids-for-sa8775p.patch b/queue-6.19/drm-msm-dp-update-msm_dp_controller-ids-for-sa8775p.patch new file mode 100644 index 0000000000..84b867c6a4 --- /dev/null +++ b/queue-6.19/drm-msm-dp-update-msm_dp_controller-ids-for-sa8775p.patch @@ -0,0 +1,41 @@ +From 5a621e3141f3a39c9db9defe9683f5a11b821fe6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 25 Nov 2025 16:26:20 +0530 +Subject: drm/msm/dp: Update msm_dp_controller IDs for sa8775p + +From: Mani Chandana Ballary Kuntumalla + +[ Upstream commit 1338e8ae4084e55c0359a79e617b2ae183d01579 ] + +The Qualcomm SA8775P platform comes with 2 DisplayPort controllers +for each mdss. Update controller id for DPTX0 and DPTX1 of mdss1. + +Fixes: dcb380d19e58 ("drm/msm/dp: Add DisplayPort controller for SA8775P") +Signed-off-by: Mani Chandana Ballary Kuntumalla +Reviewed-by: Dmitry Baryshkov +Patchwork: https://patchwork.freedesktop.org/patch/690234/ +Link: https://lore.kernel.org/r/20251125105622.1755651-2-quic_mkuntuma@quicinc.com +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/dp/dp_display.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c +index 9bd9cd5c1e03c..a082f4d3ebe27 100644 +--- a/drivers/gpu/drm/msm/dp/dp_display.c ++++ b/drivers/gpu/drm/msm/dp/dp_display.c +@@ -141,8 +141,8 @@ static const struct msm_dp_desc msm_dp_desc_glymur[] = { + static const struct msm_dp_desc msm_dp_desc_sa8775p[] = { + { .io_start = 0x0af54000, .id = MSM_DP_CONTROLLER_0, .wide_bus_supported = true }, + { .io_start = 0x0af5c000, .id = MSM_DP_CONTROLLER_1, .wide_bus_supported = true }, +- { .io_start = 0x22154000, .id = MSM_DP_CONTROLLER_2, .wide_bus_supported = true }, +- { .io_start = 0x2215c000, .id = MSM_DP_CONTROLLER_3, .wide_bus_supported = true }, ++ { .io_start = 0x22154000, .id = MSM_DP_CONTROLLER_0, .wide_bus_supported = true }, ++ { .io_start = 0x2215c000, .id = MSM_DP_CONTROLLER_1, .wide_bus_supported = true }, + {} + }; + +-- +2.51.0 + diff --git a/queue-6.19/drm-msm-dpu-drop-intr_start-from-dpu-3.x-catalog-fil.patch b/queue-6.19/drm-msm-dpu-drop-intr_start-from-dpu-3.x-catalog-fil.patch new file mode 100644 index 0000000000..f370bc7371 --- /dev/null +++ b/queue-6.19/drm-msm-dpu-drop-intr_start-from-dpu-3.x-catalog-fil.patch @@ -0,0 +1,115 @@ +From d596c4eb403eae521e8fb17297627a76ea36d92e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 28 Dec 2025 06:02:27 +0200 +Subject: drm/msm/dpu: drop intr_start from DPU 3.x catalog files + +From: Dmitry Baryshkov + +[ Upstream commit f4a8e3a34ea4129c743c0d1d050b91b6511abf11 ] + +DPU 3.x don't have separate intr_start interrupt, drop it from catalog +files. + +Fixes: 94391a14fc27 ("drm/msm/dpu1: Add MSM8998 to hw catalog") +Fixes: 7204df5e7e68 ("drm/msm/dpu: add support for SDM660 and SDM630 platforms") +Patchwork: https://patchwork.freedesktop.org/patch/696488/ +Link: https://lore.kernel.org/r/20251228-mdp5-drop-dpu3-v4-1-7497c3d39179@oss.qualcomm.com +Tested-by: Alexey Minnekhanov +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_0_msm8998.h | 5 ----- + drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_2_sdm660.h | 5 ----- + drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_3_sdm630.h | 5 ----- + 3 files changed, 15 deletions(-) + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_0_msm8998.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_0_msm8998.h +index f91220496082b..b1b03d8b30fa0 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_0_msm8998.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_0_msm8998.h +@@ -42,24 +42,19 @@ static const struct dpu_ctl_cfg msm8998_ctl[] = { + .name = "ctl_0", .id = CTL_0, + .base = 0x1000, .len = 0x94, + .features = BIT(DPU_CTL_SPLIT_DISPLAY), +- .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 9), + }, { + .name = "ctl_1", .id = CTL_1, + .base = 0x1200, .len = 0x94, +- .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 10), + }, { + .name = "ctl_2", .id = CTL_2, + .base = 0x1400, .len = 0x94, + .features = BIT(DPU_CTL_SPLIT_DISPLAY), +- .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 11), + }, { + .name = "ctl_3", .id = CTL_3, + .base = 0x1600, .len = 0x94, +- .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 12), + }, { + .name = "ctl_4", .id = CTL_4, + .base = 0x1800, .len = 0x94, +- .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 13), + }, + }; + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_2_sdm660.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_2_sdm660.h +index 8f9a097147c02..64df4e80ea43d 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_2_sdm660.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_2_sdm660.h +@@ -37,24 +37,19 @@ static const struct dpu_ctl_cfg sdm660_ctl[] = { + .name = "ctl_0", .id = CTL_0, + .base = 0x1000, .len = 0x94, + .features = BIT(DPU_CTL_SPLIT_DISPLAY), +- .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 9), + }, { + .name = "ctl_1", .id = CTL_1, + .base = 0x1200, .len = 0x94, +- .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 10), + }, { + .name = "ctl_2", .id = CTL_2, + .base = 0x1400, .len = 0x94, + .features = BIT(DPU_CTL_SPLIT_DISPLAY), +- .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 11), + }, { + .name = "ctl_3", .id = CTL_3, + .base = 0x1600, .len = 0x94, +- .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 12), + }, { + .name = "ctl_4", .id = CTL_4, + .base = 0x1800, .len = 0x94, +- .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 13), + }, + }; + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_3_sdm630.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_3_sdm630.h +index 0ad18bd273ff8..b409af8999182 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_3_sdm630.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_3_sdm630.h +@@ -36,24 +36,19 @@ static const struct dpu_ctl_cfg sdm630_ctl[] = { + .name = "ctl_0", .id = CTL_0, + .base = 0x1000, .len = 0x94, + .features = BIT(DPU_CTL_SPLIT_DISPLAY), +- .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 9), + }, { + .name = "ctl_1", .id = CTL_1, + .base = 0x1200, .len = 0x94, +- .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 10), + }, { + .name = "ctl_2", .id = CTL_2, + .base = 0x1400, .len = 0x94, + .features = BIT(DPU_CTL_SPLIT_DISPLAY), +- .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 11), + }, { + .name = "ctl_3", .id = CTL_3, + .base = 0x1600, .len = 0x94, +- .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 12), + }, { + .name = "ctl_4", .id = CTL_4, + .base = 0x1800, .len = 0x94, +- .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 13), + }, + }; + +-- +2.51.0 + diff --git a/queue-6.19/drm-msm-dpu-fix-cmd-panels-on-dpu-1.x-3.x.patch b/queue-6.19/drm-msm-dpu-fix-cmd-panels-on-dpu-1.x-3.x.patch new file mode 100644 index 0000000000..0714fd867e --- /dev/null +++ b/queue-6.19/drm-msm-dpu-fix-cmd-panels-on-dpu-1.x-3.x.patch @@ -0,0 +1,48 @@ +From dc9d86c63340bd7e02e5ee2955941b1f6947a9a9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 28 Dec 2025 06:02:28 +0200 +Subject: drm/msm/dpu: fix CMD panels on DPU 1.x - 3.x + +From: Dmitry Baryshkov + +[ Upstream commit 59ca3d11f5311d9167015fe4f431701614ae0048 ] + +DPU units before 4.x don't have a separate CTL_START IRQ to mark the +begin of the data transfer. In such a case, wait for the frame transfer +to complete rather than trying to wait for the CTL_START interrupt (and +obviously hitting the timeout). + +Fixes: 050770cbbd26 ("drm/msm/dpu: Fix timeout issues on command mode panels") +Reported-by: Alexey Minnekhanov +Closes: https://lore.kernel.org/r/8e1d33ff-d902-4ae9-9162-e00d17a5e6d1@postmarketos.org +Patchwork: https://patchwork.freedesktop.org/patch/696490/ +Link: https://lore.kernel.org/r/20251228-mdp5-drop-dpu3-v4-2-7497c3d39179@oss.qualcomm.com +Tested-by: Alexey Minnekhanov +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c +index 0ec6d67c7c70b..93db1484f6069 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c +@@ -681,10 +681,11 @@ static int dpu_encoder_phys_cmd_wait_for_commit_done( + if (!dpu_encoder_phys_cmd_is_master(phys_enc)) + return 0; + +- if (phys_enc->hw_ctl->ops.is_started(phys_enc->hw_ctl)) +- return dpu_encoder_phys_cmd_wait_for_tx_complete(phys_enc); ++ if (phys_enc->irq[INTR_IDX_CTL_START] && ++ !phys_enc->hw_ctl->ops.is_started(phys_enc->hw_ctl)) ++ return _dpu_encoder_phys_cmd_wait_for_ctl_start(phys_enc); + +- return _dpu_encoder_phys_cmd_wait_for_ctl_start(phys_enc); ++ return dpu_encoder_phys_cmd_wait_for_tx_complete(phys_enc); + } + + static void dpu_encoder_phys_cmd_handle_post_kickoff( +-- +2.51.0 + diff --git a/queue-6.19/drm-msm-dpu-fix-sspp_ubwc_static_ctrl-programming-on.patch b/queue-6.19/drm-msm-dpu-fix-sspp_ubwc_static_ctrl-programming-on.patch new file mode 100644 index 0000000000..a935a06e80 --- /dev/null +++ b/queue-6.19/drm-msm-dpu-fix-sspp_ubwc_static_ctrl-programming-on.patch @@ -0,0 +1,93 @@ +From 665ec7beaabb9e01ccf8b1d563f16a3e8d33d6b4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 14:16:40 +0200 +Subject: drm/msm/dpu: fix SSPP_UBWC_STATIC_CTRL programming on UBWC 5.x+ + +From: Dmitry Baryshkov + +[ Upstream commit 258b080dc280e927d200af51992048ec818d0491 ] + +Code in dpu_hw_sspp_setup_format() doesn't handle UBWC versions bigger +than 4.0. Replace switch-case with if-else checks, making sure that the +register is initialized on UBWC 5.x (and later) hosts. + +Fixes: c2577fc1740d ("drm/msm/dpu: Add support for SM8750") +Tested-by: Val Packett # x1e80100-dell-latitude-7455 +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Patchwork: https://patchwork.freedesktop.org/patch/699280/ +Link: https://lore.kernel.org/r/20260119-msm-ubwc-fixes-v4-4-0987acc0427f@oss.qualcomm.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c | 45 +++++++++++---------- + 1 file changed, 24 insertions(+), 21 deletions(-) + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c +index 6ff4902fce08e..f275b14da4ffd 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c +@@ -284,6 +284,7 @@ static void dpu_hw_sspp_setup_format(struct dpu_sw_pipe *pipe, + + if (fmt->fetch_mode != MDP_FETCH_LINEAR) { + u32 hbb = ctx->ubwc->highest_bank_bit - 13; ++ u32 ctrl_val; + + if (MSM_FORMAT_IS_UBWC(fmt)) + opmode |= MDSS_MDP_OP_BWC_EN; +@@ -291,30 +292,32 @@ static void dpu_hw_sspp_setup_format(struct dpu_sw_pipe *pipe, + DPU_REG_WRITE(c, SSPP_FETCH_CONFIG, + DPU_FETCH_CONFIG_RESET_VALUE | + hbb << 18); +- switch (ctx->ubwc->ubwc_enc_version) { +- case UBWC_1_0: ++ ++ if (ctx->ubwc->ubwc_enc_version == UBWC_1_0) { + fast_clear = fmt->alpha_enable ? BIT(31) : 0; +- DPU_REG_WRITE(c, ubwc_ctrl_off, +- fast_clear | (ctx->ubwc->ubwc_swizzle & 0x1) | +- BIT(8) | +- (hbb << 4)); +- break; +- case UBWC_2_0: ++ ctrl_val = fast_clear | (ctx->ubwc->ubwc_swizzle & 0x1) | ++ BIT(8) | (hbb << 4); ++ } else if (ctx->ubwc->ubwc_enc_version == UBWC_2_0) { + fast_clear = fmt->alpha_enable ? BIT(31) : 0; +- DPU_REG_WRITE(c, ubwc_ctrl_off, +- fast_clear | (ctx->ubwc->ubwc_swizzle) | +- (hbb << 4)); +- break; +- case UBWC_3_0: +- DPU_REG_WRITE(c, ubwc_ctrl_off, +- BIT(30) | (ctx->ubwc->ubwc_swizzle) | +- (hbb << 4)); +- break; +- case UBWC_4_0: +- DPU_REG_WRITE(c, ubwc_ctrl_off, +- MSM_FORMAT_IS_YUV(fmt) ? 0 : BIT(30)); +- break; ++ ctrl_val = fast_clear | ctx->ubwc->ubwc_swizzle | (hbb << 4); ++ } else if (ctx->ubwc->ubwc_enc_version == UBWC_3_0) { ++ ctrl_val = BIT(30) | (ctx->ubwc->ubwc_swizzle) | (hbb << 4); ++ } else if (ctx->ubwc->ubwc_enc_version == UBWC_4_0) { ++ ctrl_val = MSM_FORMAT_IS_YUV(fmt) ? 0 : BIT(30); ++ } else if (ctx->ubwc->ubwc_enc_version <= UBWC_6_0) { ++ if (MSM_FORMAT_IS_YUV(fmt)) ++ ctrl_val = 0; ++ else if (MSM_FORMAT_IS_DX(fmt)) /* or FP16, but it's unsupported */ ++ ctrl_val = BIT(30); ++ else ++ ctrl_val = BIT(30) | BIT(31); ++ /* SDE also sets bits for lossy formats, but we don't support them yet */ ++ } else { ++ DRM_WARN_ONCE("Unsupported UBWC version %x\n", ctx->ubwc->ubwc_enc_version); ++ ctrl_val = 0; + } ++ ++ DPU_REG_WRITE(c, ubwc_ctrl_off, ctrl_val); + } + + opmode |= MDSS_MDP_OP_PE_OVERRIDE; +-- +2.51.0 + diff --git a/queue-6.19/drm-msm-dpu-fix-wd-timer-handling-on-dpu-8.x.patch b/queue-6.19/drm-msm-dpu-fix-wd-timer-handling-on-dpu-8.x.patch new file mode 100644 index 0000000000..40817a6c0f --- /dev/null +++ b/queue-6.19/drm-msm-dpu-fix-wd-timer-handling-on-dpu-8.x.patch @@ -0,0 +1,198 @@ +From 3f4dcc4b752ac445b75898429ddc29ad4e6a7ee0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Dec 2025 09:17:57 +0200 +Subject: drm/msm/dpu: fix WD timer handling on DPU 8.x + +From: Dmitry Baryshkov + +[ Upstream commit 794b0e68caba49b950b42ec32e364028c2facf57 ] + +Since DPU 8.x Watchdog timer settings were moved from the TOP to the +INTF block. Support programming the timer in the INTF block. Fixes tag +points to the commit which removed register access to those registers on +DPU 8.x+ (and which also should have added proper support for WD timer +on those devices). + +Fixes: 43e3293fc614 ("drm/msm/dpu: add support for MDP_TOP blackhole") +Reviewed-by: Marijn Suijten +Signed-off-by: Dmitry Baryshkov +Patchwork: https://patchwork.freedesktop.org/patch/696586/ +Link: https://lore.kernel.org/r/20251230-intf-fix-wd-v6-2-98203d150611@oss.qualcomm.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 4 +- + drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c | 49 +++++++++++++++++++-- + drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h | 3 +- + drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c | 7 --- + drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h | 7 +++ + 5 files changed, 57 insertions(+), 13 deletions(-) + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +index af5122a514bd1..eba1d52211f68 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +@@ -786,13 +786,13 @@ static void _dpu_encoder_update_vsync_source(struct dpu_encoder_virt *dpu_enc, + } + + vsync_cfg.vsync_source = disp_info->vsync_source; ++ vsync_cfg.frame_rate = drm_mode_vrefresh(&dpu_enc->base.crtc->state->adjusted_mode); + + if (hw_mdptop->ops.setup_vsync_source) { + for (i = 0; i < dpu_enc->num_phys_encs; i++) + vsync_cfg.ppnumber[i] = dpu_enc->hw_pp[i]->idx; + + vsync_cfg.pp_count = dpu_enc->num_phys_encs; +- vsync_cfg.frame_rate = drm_mode_vrefresh(&dpu_enc->base.crtc->state->adjusted_mode); + + hw_mdptop->ops.setup_vsync_source(hw_mdptop, &vsync_cfg); + } +@@ -802,7 +802,7 @@ static void _dpu_encoder_update_vsync_source(struct dpu_encoder_virt *dpu_enc, + + if (phys_enc->has_intf_te && phys_enc->hw_intf->ops.vsync_sel) + phys_enc->hw_intf->ops.vsync_sel(phys_enc->hw_intf, +- vsync_cfg.vsync_source); ++ &vsync_cfg); + } + } + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c +index a80ac82a96255..7e620f5909849 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c +@@ -67,6 +67,10 @@ + #define INTF_MISR_CTRL 0x180 + #define INTF_MISR_SIGNATURE 0x184 + ++#define INTF_WD_TIMER_0_CTL 0x230 ++#define INTF_WD_TIMER_0_CTL2 0x234 ++#define INTF_WD_TIMER_0_LOAD_VALUE 0x238 ++ + #define INTF_MUX 0x25C + #define INTF_STATUS 0x26C + #define INTF_AVR_CONTROL 0x270 +@@ -475,7 +479,20 @@ static int dpu_hw_intf_get_vsync_info(struct dpu_hw_intf *intf, + } + + static void dpu_hw_intf_vsync_sel(struct dpu_hw_intf *intf, +- enum dpu_vsync_source vsync_source) ++ struct dpu_vsync_source_cfg *cfg) ++{ ++ struct dpu_hw_blk_reg_map *c; ++ ++ if (!intf) ++ return; ++ ++ c = &intf->hw; ++ ++ DPU_REG_WRITE(c, INTF_TEAR_MDP_VSYNC_SEL, (cfg->vsync_source & 0xf)); ++} ++ ++static void dpu_hw_intf_vsync_sel_v8(struct dpu_hw_intf *intf, ++ struct dpu_vsync_source_cfg *cfg) + { + struct dpu_hw_blk_reg_map *c; + +@@ -484,7 +501,30 @@ static void dpu_hw_intf_vsync_sel(struct dpu_hw_intf *intf, + + c = &intf->hw; + +- DPU_REG_WRITE(c, INTF_TEAR_MDP_VSYNC_SEL, (vsync_source & 0xf)); ++ if (cfg->vsync_source >= DPU_VSYNC_SOURCE_WD_TIMER_4 && ++ cfg->vsync_source <= DPU_VSYNC_SOURCE_WD_TIMER_1) { ++ pr_warn_once("DPU 8.x supports only GPIOs and timer0 as TE sources\n"); ++ return; ++ } ++ ++ if (cfg->vsync_source == DPU_VSYNC_SOURCE_WD_TIMER_0) { ++ u32 reg; ++ ++ DPU_REG_WRITE(c, INTF_WD_TIMER_0_LOAD_VALUE, ++ CALCULATE_WD_LOAD_VALUE(cfg->frame_rate)); ++ ++ DPU_REG_WRITE(c, INTF_WD_TIMER_0_CTL, BIT(0)); /* clear timer */ ++ ++ reg = BIT(8); /* enable heartbeat timer */ ++ reg |= BIT(0); /* enable WD timer */ ++ reg |= BIT(1); /* select default 16 clock ticks */ ++ DPU_REG_WRITE(c, INTF_WD_TIMER_0_CTL2, reg); ++ ++ /* make sure that timers are enabled/disabled for vsync state */ ++ wmb(); ++ } ++ ++ dpu_hw_intf_vsync_sel(intf, cfg); + } + + static void dpu_hw_intf_disable_autorefresh(struct dpu_hw_intf *intf, +@@ -598,7 +638,10 @@ struct dpu_hw_intf *dpu_hw_intf_init(struct drm_device *dev, + c->ops.enable_tearcheck = dpu_hw_intf_enable_te; + c->ops.disable_tearcheck = dpu_hw_intf_disable_te; + c->ops.connect_external_te = dpu_hw_intf_connect_external_te; +- c->ops.vsync_sel = dpu_hw_intf_vsync_sel; ++ if (mdss_rev->core_major_ver >= 8) ++ c->ops.vsync_sel = dpu_hw_intf_vsync_sel_v8; ++ else ++ c->ops.vsync_sel = dpu_hw_intf_vsync_sel; + c->ops.disable_autorefresh = dpu_hw_intf_disable_autorefresh; + } + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h +index 5a19cd74fa947..f6ef2c21b66d4 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h +@@ -12,6 +12,7 @@ + #include "dpu_hw_util.h" + + struct dpu_hw_intf; ++struct dpu_vsync_source_cfg; + + /* intf timing settings */ + struct dpu_hw_intf_timing_params { +@@ -104,7 +105,7 @@ struct dpu_hw_intf_ops { + + int (*connect_external_te)(struct dpu_hw_intf *intf, bool enable_external_te); + +- void (*vsync_sel)(struct dpu_hw_intf *intf, enum dpu_vsync_source vsync_source); ++ void (*vsync_sel)(struct dpu_hw_intf *intf, struct dpu_vsync_source_cfg *cfg); + + void (*disable_autorefresh)(struct dpu_hw_intf *intf, uint32_t encoder_id, u16 vdisplay); + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c +index 96dc10589bee6..1ebd75d4f9be8 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c +@@ -22,13 +22,6 @@ + #define TRAFFIC_SHAPER_WR_CLIENT(num) (0x060 + (num * 4)) + #define TRAFFIC_SHAPER_FIXPOINT_FACTOR 4 + +-#define MDP_TICK_COUNT 16 +-#define XO_CLK_RATE 19200 +-#define MS_TICKS_IN_SEC 1000 +- +-#define CALCULATE_WD_LOAD_VALUE(fps) \ +- ((uint32_t)((MS_TICKS_IN_SEC * XO_CLK_RATE)/(MDP_TICK_COUNT * fps))) +- + static void dpu_hw_setup_split_pipe(struct dpu_hw_mdp *mdp, + struct split_pipe_cfg *cfg) + { +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h +index 67b08e99335dc..6fe65bc3bff4e 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h +@@ -21,6 +21,13 @@ + + #define TO_S15D16(_x_)((_x_) << 7) + ++#define MDP_TICK_COUNT 16 ++#define XO_CLK_RATE 19200 ++#define MS_TICKS_IN_SEC 1000 ++ ++#define CALCULATE_WD_LOAD_VALUE(fps) \ ++ ((uint32_t)((MS_TICKS_IN_SEC * XO_CLK_RATE)/(MDP_TICK_COUNT * fps))) ++ + extern const struct dpu_csc_cfg dpu_csc_YUV2RGB_601L; + extern const struct dpu_csc_cfg dpu_csc10_YUV2RGB_601L; + extern const struct dpu_csc_cfg dpu_csc10_rgb2yuv_601l; +-- +2.51.0 + diff --git a/queue-6.19/drm-msm-dpu-offset-hbb-values-written-to-dpu-by-13.patch b/queue-6.19/drm-msm-dpu-offset-hbb-values-written-to-dpu-by-13.patch new file mode 100644 index 0000000000..888b3af936 --- /dev/null +++ b/queue-6.19/drm-msm-dpu-offset-hbb-values-written-to-dpu-by-13.patch @@ -0,0 +1,68 @@ +From 6af72287fbe0957ac0612cf51fc4bc35daed4edb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 14:16:38 +0200 +Subject: drm/msm/dpu: offset HBB values written to DPU by -13 + +From: Dmitry Baryshkov + +[ Upstream commit 7ead14d4b9742b5ed244f35b999f0fe26dc23586 ] + +As in all other places, the Highest Bank Bit value should be programmed +into the hardware with the offset of -13. Correct the value written +into the register to prevent unpredictable results. + +Fixes: 227d4ce0b09e ("drm/msm: Offset MDSS HBB value by 13") +Tested-by: Val Packett # x1e80100-dell-latitude-7455 +Reviewed-by: Konrad Dybcio +Signed-off-by: Dmitry Baryshkov +Patchwork: https://patchwork.freedesktop.org/patch/699276/ +Link: https://lore.kernel.org/r/20260119-msm-ubwc-fixes-v4-2-0987acc0427f@oss.qualcomm.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c +index 6f1fc790ad6d8..b66c4cb5760c9 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c +@@ -270,30 +270,32 @@ static void dpu_hw_sspp_setup_format(struct dpu_sw_pipe *pipe, + ((fmt->bpp - 1) << 9); + + if (fmt->fetch_mode != MDP_FETCH_LINEAR) { ++ u32 hbb = ctx->ubwc->highest_bank_bit - 13; ++ + if (MSM_FORMAT_IS_UBWC(fmt)) + opmode |= MDSS_MDP_OP_BWC_EN; + src_format |= (fmt->fetch_mode & 3) << 30; /*FRAME_FORMAT */ + DPU_REG_WRITE(c, SSPP_FETCH_CONFIG, + DPU_FETCH_CONFIG_RESET_VALUE | +- ctx->ubwc->highest_bank_bit << 18); ++ hbb << 18); + switch (ctx->ubwc->ubwc_enc_version) { + case UBWC_1_0: + fast_clear = fmt->alpha_enable ? BIT(31) : 0; + DPU_REG_WRITE(c, SSPP_UBWC_STATIC_CTRL, + fast_clear | (ctx->ubwc->ubwc_swizzle & 0x1) | + BIT(8) | +- (ctx->ubwc->highest_bank_bit << 4)); ++ (hbb << 4)); + break; + case UBWC_2_0: + fast_clear = fmt->alpha_enable ? BIT(31) : 0; + DPU_REG_WRITE(c, SSPP_UBWC_STATIC_CTRL, + fast_clear | (ctx->ubwc->ubwc_swizzle) | +- (ctx->ubwc->highest_bank_bit << 4)); ++ (hbb << 4)); + break; + case UBWC_3_0: + DPU_REG_WRITE(c, SSPP_UBWC_STATIC_CTRL, + BIT(30) | (ctx->ubwc->ubwc_swizzle) | +- (ctx->ubwc->highest_bank_bit << 4)); ++ (hbb << 4)); + break; + case UBWC_4_0: + DPU_REG_WRITE(c, SSPP_UBWC_STATIC_CTRL, +-- +2.51.0 + diff --git a/queue-6.19/drm-msm-dpu-program-correct-register-for-ubwc-config.patch b/queue-6.19/drm-msm-dpu-program-correct-register-for-ubwc-config.patch new file mode 100644 index 0000000000..1022c2e9dd --- /dev/null +++ b/queue-6.19/drm-msm-dpu-program-correct-register-for-ubwc-config.patch @@ -0,0 +1,109 @@ +From 81f99e95c908c9a4cd0a1a092ffe6fe0bde2db44 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 14:16:39 +0200 +Subject: drm/msm/dpu: program correct register for UBWC config on DPU 8.x+ + +From: Dmitry Baryshkov + +[ Upstream commit 5dcec3fc1311c277369a4bdf8b292781e5cc91fd ] + +Since DPU 8.0 there is a separate register for the second rectangle, +which needs to be programmed with the UBWC config if multirect is being +used. Write pipe's UBWC configuration to the correct register. + +Fixes: 100d7ef6995d ("drm/msm/dpu: add support for SM8450") +Tested-by: Val Packett # x1e80100-dell-latitude-7455 +Reviewed-by: Konrad Dybcio +Signed-off-by: Dmitry Baryshkov +Patchwork: https://patchwork.freedesktop.org/patch/699277/ +Link: https://lore.kernel.org/r/20260119-msm-ubwc-fixes-v4-3-0987acc0427f@oss.qualcomm.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c | 25 ++++++++++++++++----- + 1 file changed, 19 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c +index b66c4cb5760c9..6ff4902fce08e 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c +@@ -72,6 +72,8 @@ + #define SSPP_EXCL_REC_XY_REC1 0x188 + #define SSPP_EXCL_REC_SIZE 0x1B4 + #define SSPP_EXCL_REC_XY 0x1B8 ++#define SSPP_UBWC_STATIC_CTRL_REC1 0x1c0 ++#define SSPP_UBWC_ERROR_STATUS_REC1 0x1c8 + #define SSPP_CLK_CTRL 0x330 + + /* SSPP_SRC_OP_MODE & OP_MODE_REC1 */ +@@ -215,7 +217,7 @@ static void dpu_hw_sspp_setup_format(struct dpu_sw_pipe *pipe, + u32 chroma_samp, unpack, src_format; + u32 opmode = 0; + u32 fast_clear = 0; +- u32 op_mode_off, unpack_pat_off, format_off; ++ u32 op_mode_off, unpack_pat_off, format_off, ubwc_ctrl_off, ubwc_error_off; + + if (!ctx || !fmt) + return; +@@ -225,10 +227,21 @@ static void dpu_hw_sspp_setup_format(struct dpu_sw_pipe *pipe, + op_mode_off = SSPP_SRC_OP_MODE; + unpack_pat_off = SSPP_SRC_UNPACK_PATTERN; + format_off = SSPP_SRC_FORMAT; ++ ubwc_ctrl_off = SSPP_UBWC_STATIC_CTRL; ++ ubwc_error_off = SSPP_UBWC_ERROR_STATUS; + } else { + op_mode_off = SSPP_SRC_OP_MODE_REC1; + unpack_pat_off = SSPP_SRC_UNPACK_PATTERN_REC1; + format_off = SSPP_SRC_FORMAT_REC1; ++ ++ /* reg wasn't present before DPU 8.0 */ ++ if (ctx->mdss_ver->core_major_ver >= 8) { ++ ubwc_ctrl_off = SSPP_UBWC_STATIC_CTRL_REC1; ++ ubwc_error_off = SSPP_UBWC_ERROR_STATUS_REC1; ++ } else { ++ ubwc_ctrl_off = SSPP_UBWC_STATIC_CTRL; ++ ubwc_error_off = SSPP_UBWC_ERROR_STATUS; ++ } + } + + c = &ctx->hw; +@@ -281,24 +294,24 @@ static void dpu_hw_sspp_setup_format(struct dpu_sw_pipe *pipe, + switch (ctx->ubwc->ubwc_enc_version) { + case UBWC_1_0: + fast_clear = fmt->alpha_enable ? BIT(31) : 0; +- DPU_REG_WRITE(c, SSPP_UBWC_STATIC_CTRL, ++ DPU_REG_WRITE(c, ubwc_ctrl_off, + fast_clear | (ctx->ubwc->ubwc_swizzle & 0x1) | + BIT(8) | + (hbb << 4)); + break; + case UBWC_2_0: + fast_clear = fmt->alpha_enable ? BIT(31) : 0; +- DPU_REG_WRITE(c, SSPP_UBWC_STATIC_CTRL, ++ DPU_REG_WRITE(c, ubwc_ctrl_off, + fast_clear | (ctx->ubwc->ubwc_swizzle) | + (hbb << 4)); + break; + case UBWC_3_0: +- DPU_REG_WRITE(c, SSPP_UBWC_STATIC_CTRL, ++ DPU_REG_WRITE(c, ubwc_ctrl_off, + BIT(30) | (ctx->ubwc->ubwc_swizzle) | + (hbb << 4)); + break; + case UBWC_4_0: +- DPU_REG_WRITE(c, SSPP_UBWC_STATIC_CTRL, ++ DPU_REG_WRITE(c, ubwc_ctrl_off, + MSM_FORMAT_IS_YUV(fmt) ? 0 : BIT(30)); + break; + } +@@ -327,7 +340,7 @@ static void dpu_hw_sspp_setup_format(struct dpu_sw_pipe *pipe, + DPU_REG_WRITE(c, op_mode_off, opmode); + + /* clear previous UBWC error */ +- DPU_REG_WRITE(c, SSPP_UBWC_ERROR_STATUS, BIT(31)); ++ DPU_REG_WRITE(c, ubwc_error_off, BIT(31)); + } + + static void dpu_hw_sspp_setup_pe_config(struct dpu_hw_sspp *ctx, +-- +2.51.0 + diff --git a/queue-6.19/drm-msm-dpu-set-vsync-source-irrespective-of-mdp-top.patch b/queue-6.19/drm-msm-dpu-set-vsync-source-irrespective-of-mdp-top.patch new file mode 100644 index 0000000000..5538851d3d --- /dev/null +++ b/queue-6.19/drm-msm-dpu-set-vsync-source-irrespective-of-mdp-top.patch @@ -0,0 +1,68 @@ +From 1131dd44ef733e9c79a23e77545597db08b941d7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Dec 2025 09:17:56 +0200 +Subject: drm/msm/dpu: Set vsync source irrespective of mdp top support + +From: Teguh Sobirin + +[ Upstream commit 1ad9880f059c9b0943e53714f9a59924cb035bbb ] + +Since DPU 5.x the vsync source TE setup is split between MDP TOP and +INTF blocks. Currently all code to setup vsync_source is only executed +if MDP TOP implements the setup_vsync_source() callback. However on +DPU >= 8.x this callback is not implemented, making DPU driver skip all +vsync setup. Move the INTF part out of this condition, letting DPU +driver to setup TE vsync selection on all new DPU devices. + +Signed-off-by: Teguh Sobirin +Fixes: 2f69e5458447 ("drm/msm/dpu: skip watchdog timer programming through TOP on >= SM8450") +[DB: restored top->ops.setup_vsync_source call] +Reviewed-by: Marijn Suijten +Signed-off-by: Dmitry Baryshkov +Patchwork: https://patchwork.freedesktop.org/patch/696584/ +Link: https://lore.kernel.org/r/20251230-intf-fix-wd-v6-1-98203d150611@oss.qualcomm.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +index 9f3957f24c6a3..af5122a514bd1 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +@@ -785,6 +785,8 @@ static void _dpu_encoder_update_vsync_source(struct dpu_encoder_virt *dpu_enc, + return; + } + ++ vsync_cfg.vsync_source = disp_info->vsync_source; ++ + if (hw_mdptop->ops.setup_vsync_source) { + for (i = 0; i < dpu_enc->num_phys_encs; i++) + vsync_cfg.ppnumber[i] = dpu_enc->hw_pp[i]->idx; +@@ -792,17 +794,15 @@ static void _dpu_encoder_update_vsync_source(struct dpu_encoder_virt *dpu_enc, + vsync_cfg.pp_count = dpu_enc->num_phys_encs; + vsync_cfg.frame_rate = drm_mode_vrefresh(&dpu_enc->base.crtc->state->adjusted_mode); + +- vsync_cfg.vsync_source = disp_info->vsync_source; +- + hw_mdptop->ops.setup_vsync_source(hw_mdptop, &vsync_cfg); ++ } + +- for (i = 0; i < dpu_enc->num_phys_encs; i++) { +- phys_enc = dpu_enc->phys_encs[i]; ++ for (i = 0; i < dpu_enc->num_phys_encs; i++) { ++ phys_enc = dpu_enc->phys_encs[i]; + +- if (phys_enc->has_intf_te && phys_enc->hw_intf->ops.vsync_sel) +- phys_enc->hw_intf->ops.vsync_sel(phys_enc->hw_intf, +- vsync_cfg.vsync_source); +- } ++ if (phys_enc->has_intf_te && phys_enc->hw_intf->ops.vsync_sel) ++ phys_enc->hw_intf->ops.vsync_sel(phys_enc->hw_intf, ++ vsync_cfg.vsync_source); + } + } + +-- +2.51.0 + diff --git a/queue-6.19/drm-msm-dsi_phy_14nm-convert-from-divider_round_rate.patch b/queue-6.19/drm-msm-dsi_phy_14nm-convert-from-divider_round_rate.patch new file mode 100644 index 0000000000..4c0ed95d7e --- /dev/null +++ b/queue-6.19/drm-msm-dsi_phy_14nm-convert-from-divider_round_rate.patch @@ -0,0 +1,55 @@ +From 723dabe5c0d32844dd4281134e4003b76ddacd61 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:16:42 -0500 +Subject: drm/msm/dsi_phy_14nm: convert from divider_round_rate() to + divider_determine_rate() + +From: Brian Masney + +[ Upstream commit 1d232f793d4dbffd329ad48b52954d4c8ca24db5 ] + +The divider_round_rate() function is now deprecated, so let's migrate +to divider_determine_rate() instead so that this deprecated API can be +removed. + +Note that when the main function itself was migrated to use +determine_rate, this was mistakenly converted to: + + req->rate = divider_round_rate(...) + +This is invalid in the case when an error occurs since it can set the +rate to a negative value. + +Fixes: cc41f29a6b04 ("drm/msm/dsi_phy_14nm: convert from round_rate() to determine_rate()") +Signed-off-by: Brian Masney +Reviewed-by: Konrad Dybcio +Reviewed-by: Abel Vesa +Patchwork: https://patchwork.freedesktop.org/patch/697613/ +Link: https://lore.kernel.org/r/20260108-clk-divider-round-rate-v1-24-535a3ed73bf3@redhat.com +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c +index fdefcbd9c2848..a156c7e7cea83 100644 +--- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c ++++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c +@@ -628,12 +628,7 @@ static int dsi_pll_14nm_postdiv_determine_rate(struct clk_hw *hw, + + DBG("DSI%d PLL parent rate=%lu", pll_14nm->phy->id, req->rate); + +- req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, +- NULL, +- postdiv->width, +- postdiv->flags); +- +- return 0; ++ return divider_determine_rate(hw, req, NULL, postdiv->width, postdiv->flags); + } + + static int dsi_pll_14nm_postdiv_set_rate(struct clk_hw *hw, unsigned long rate, +-- +2.51.0 + diff --git a/queue-6.19/drm-msm-fix-gmem_base-for-gen8.patch b/queue-6.19/drm-msm-fix-gmem_base-for-gen8.patch new file mode 100644 index 0000000000..b993b1f086 --- /dev/null +++ b/queue-6.19/drm-msm-fix-gmem_base-for-gen8.patch @@ -0,0 +1,39 @@ +From 82693516cd5ea721404e1d0971c9f06c1e0cfbc5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 07:37:29 -0800 +Subject: drm/msm: Fix GMEM_BASE for gen8 + +From: Rob Clark + +[ Upstream commit dc220915ddb2d1c646a7d0816b398e73ed5a5d50 ] + +This should also be zero for gen8. This does change a7xx-gen1 to zero. +It was almost certainly incorrect before, but we have no such devices in +CI currently. + +Fixes: 288a93200892 ("drm/msm/adreno: Introduce A8x GPU Support") +Signed-off-by: Rob Clark +Patchwork: https://patchwork.freedesktop.org/patch/697779/ +Message-ID: <20260109153730.130462-3-robin.clark@oss.qualcomm.com> +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/adreno/adreno_gpu.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c +index 1c80909e63cab..d5fe6f6f0decc 100644 +--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c ++++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c +@@ -376,8 +376,7 @@ int adreno_get_param(struct msm_gpu *gpu, struct msm_context *ctx, + *value = adreno_gpu->info->gmem; + return 0; + case MSM_PARAM_GMEM_BASE: +- if (adreno_is_a650_family(adreno_gpu) || +- adreno_is_a740_family(adreno_gpu)) ++ if (adreno_gpu->info->family >= ADRENO_6XX_GEN4) + *value = 0; + else + *value = 0x100000; +-- +2.51.0 + diff --git a/queue-6.19/drm-msm-fix-x2-85-tpl1_dbg_eco_cntl1.patch b/queue-6.19/drm-msm-fix-x2-85-tpl1_dbg_eco_cntl1.patch new file mode 100644 index 0000000000..44a843956a --- /dev/null +++ b/queue-6.19/drm-msm-fix-x2-85-tpl1_dbg_eco_cntl1.patch @@ -0,0 +1,37 @@ +From 1c4b4e600905f7e295258e5073c59d6e9083da3e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 07:37:28 -0800 +Subject: drm/msm: Fix x2-85 TPL1_DBG_ECO_CNTL1 + +From: Rob Clark + +[ Upstream commit 56cd8adff8cbe82a13a1db998f1353d68ed84305 ] + +We actually need to set b26, just claiming to do so is not enough :-) + +Fixes: 01ff3bf27215 ("drm/msm/a8xx: Add support for Adreno X2-85 GPU") +Signed-off-by: Rob Clark +Reviewed-by: Dmitry Baryshkov +Patchwork: https://patchwork.freedesktop.org/patch/697778/ +Message-ID: <20260109153730.130462-2-robin.clark@oss.qualcomm.com> +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/adreno/a6xx_catalog.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_catalog.c b/drivers/gpu/drm/msm/adreno/a6xx_catalog.c +index 4c042133261c9..550a53a7865eb 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_catalog.c ++++ b/drivers/gpu/drm/msm/adreno/a6xx_catalog.c +@@ -1689,7 +1689,7 @@ static const struct adreno_reglist_pipe x285_nonctxt_regs[] = { + { REG_A7XX_SP_READ_SEL, 0x0001ff00, BIT(PIPE_NONE) }, + { REG_A6XX_TPL1_DBG_ECO_CNTL, 0x10000000, BIT(PIPE_NONE) }, + /* BIT(26): Disable final clamp for bicubic filtering */ +- { REG_A6XX_TPL1_DBG_ECO_CNTL1, 0x00000720, BIT(PIPE_NONE) }, ++ { REG_A6XX_TPL1_DBG_ECO_CNTL1, 0x04000720, BIT(PIPE_NONE) }, + { REG_A6XX_UCHE_MODE_CNTL, 0x80080000, BIT(PIPE_NONE) }, + { REG_A8XX_UCHE_CCHE_MODE_CNTL, 0x00001000, BIT(PIPE_NONE) }, + { REG_A8XX_UCHE_CCHE_CACHE_WAYS, 0x00000800, BIT(PIPE_NONE) }, +-- +2.51.0 + diff --git a/queue-6.19/drm-msm-mdss-correct-hbb-programmed-on-ubwc-5.x-and-.patch b/queue-6.19/drm-msm-mdss-correct-hbb-programmed-on-ubwc-5.x-and-.patch new file mode 100644 index 0000000000..1148ea2653 --- /dev/null +++ b/queue-6.19/drm-msm-mdss-correct-hbb-programmed-on-ubwc-5.x-and-.patch @@ -0,0 +1,41 @@ +From 750daf014717e5bf3e61f25f0e56ad5a1e53e8dc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 14:16:37 +0200 +Subject: drm/msm/mdss: correct HBB programmed on UBWC 5.x and 6.x devices + +From: Dmitry Baryshkov + +[ Upstream commit e6177c7a2401b87b016728b75992926971d871fc ] + +As in the previous generations, on UBWC 5.x and 6.x devices the Highest +Bank Bit value should be programmed into the hardware with the offset of +-13. Correct the value written into the register to prevent +unpredictable results. + +Fixes: 227d4ce0b09e ("drm/msm: Offset MDSS HBB value by 13") +Tested-by: Val Packett # x1e80100-dell-latitude-7455 +Reviewed-by: Konrad Dybcio +Signed-off-by: Dmitry Baryshkov +Patchwork: https://patchwork.freedesktop.org/patch/699274/ +Link: https://lore.kernel.org/r/20260119-msm-ubwc-fixes-v4-1-0987acc0427f@oss.qualcomm.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/msm_mdss.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/msm/msm_mdss.c b/drivers/gpu/drm/msm/msm_mdss.c +index bf9a33e925ac8..910242f5a71f2 100644 +--- a/drivers/gpu/drm/msm/msm_mdss.c ++++ b/drivers/gpu/drm/msm/msm_mdss.c +@@ -229,7 +229,7 @@ static void msm_mdss_setup_ubwc_dec_50(struct msm_mdss *msm_mdss) + { + const struct qcom_ubwc_cfg_data *data = msm_mdss->mdss_data; + u32 value = MDSS_UBWC_STATIC_UBWC_SWIZZLE(data->ubwc_swizzle) | +- MDSS_UBWC_STATIC_HIGHEST_BANK_BIT(data->highest_bank_bit); ++ MDSS_UBWC_STATIC_HIGHEST_BANK_BIT(data->highest_bank_bit - 13); + + if (data->ubwc_bank_spread) + value |= MDSS_UBWC_STATIC_UBWC_BANK_SPREAD; +-- +2.51.0 + diff --git a/queue-6.19/drm-panel-sw43408-remove-manual-invocation-of-unprep.patch b/queue-6.19/drm-panel-sw43408-remove-manual-invocation-of-unprep.patch new file mode 100644 index 0000000000..8e86a3bbd6 --- /dev/null +++ b/queue-6.19/drm-panel-sw43408-remove-manual-invocation-of-unprep.patch @@ -0,0 +1,40 @@ +From d4d5011c581377223bf48fdff542dce7bff7556a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 14 Dec 2025 15:51:21 +0100 +Subject: drm/panel: sw43408: Remove manual invocation of unprepare at remove + +From: David Heidelberg + +[ Upstream commit cbc1e99a9e0a6c8b22ddcbb40ca37457066f9493 ] + +The drm_panel_remove should take care of disable/unprepare. Remove the +manual call from the sw43408_remove function. + +Fixes: 069a6c0e94f9 ("drm: panel: Add LG sw43408 panel driver") +Reviewed-by: Dmitry Baryshkov +Signed-off-by: David Heidelberg +Signed-off-by: Neil Armstrong +Link: https://patch.msgid.link/20251214-pixel-3-v7-5-b1c0cf6f224d@ixit.cz +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panel/panel-lg-sw43408.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/drivers/gpu/drm/panel/panel-lg-sw43408.c b/drivers/gpu/drm/panel/panel-lg-sw43408.c +index 46a56ea92ad9f..6e307fba658f7 100644 +--- a/drivers/gpu/drm/panel/panel-lg-sw43408.c ++++ b/drivers/gpu/drm/panel/panel-lg-sw43408.c +@@ -294,10 +294,6 @@ static void sw43408_remove(struct mipi_dsi_device *dsi) + struct sw43408_panel *ctx = mipi_dsi_get_drvdata(dsi); + int ret; + +- ret = sw43408_unprepare(&ctx->base); +- if (ret < 0) +- dev_err(&dsi->dev, "failed to unprepare panel: %d\n", ret); +- + ret = mipi_dsi_detach(dsi); + if (ret < 0) + dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret); +-- +2.51.0 + diff --git a/queue-6.19/drm-panthor-evict-groups-before-vm-termination.patch b/queue-6.19/drm-panthor-evict-groups-before-vm-termination.patch new file mode 100644 index 0000000000..66c8ba2e63 --- /dev/null +++ b/queue-6.19/drm-panthor-evict-groups-before-vm-termination.patch @@ -0,0 +1,90 @@ +From f58df5d927f23245c6bdbc05e25169c64630a7fd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 19 Dec 2025 10:35:44 +0100 +Subject: drm/panthor: Evict groups before VM termination + +From: Ketil Johnsen + +[ Upstream commit 565ed40b5fc1242f7538a016fce5a85f802d4fb5 ] + +Ensure all related groups are evicted and suspended before VM +destruction takes place. + +This fixes an issue where panthor_vm_destroy() destroys and unmaps the +heap context while there are still on slot groups using this. +The FW will do a write out to the heap context when a CSG (group) is +suspended, so a premature unmap of the heap context will cause a +GPU page fault. +This page fault is quite harmless, and do not affect the continued +operation of the GPU. + +Fixes: 647810ec2476 ("drm/panthor: Add the MMU/VM logical block") +Reviewed-by: Boris Brezillon +Signed-off-by: Ketil Johnsen +Reviewed-by: Liviu Dudau +Reviewed-by: Steven Price +Link: https://patch.msgid.link/20251219093546.1227697-1-ketil.johnsen@arm.com +Co-developed-by: Boris Brezillon +Signed-off-by: Boris Brezillon +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panthor/panthor_mmu.c | 4 ++++ + drivers/gpu/drm/panthor/panthor_sched.c | 14 ++++++++++++++ + drivers/gpu/drm/panthor/panthor_sched.h | 1 + + 3 files changed, 19 insertions(+) + +diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c +index f6339963e4960..9194bad4b6196 100644 +--- a/drivers/gpu/drm/panthor/panthor_mmu.c ++++ b/drivers/gpu/drm/panthor/panthor_mmu.c +@@ -1503,6 +1503,10 @@ static void panthor_vm_destroy(struct panthor_vm *vm) + + vm->destroyed = true; + ++ /* Tell scheduler to stop all GPU work related to this VM */ ++ if (refcount_read(&vm->as.active_cnt) > 0) ++ panthor_sched_prepare_for_vm_destruction(vm->ptdev); ++ + mutex_lock(&vm->heaps.lock); + panthor_heap_pool_destroy(vm->heaps.pool); + vm->heaps.pool = NULL; +diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c +index 6ac4cec52f9e4..bd397d773d72b 100644 +--- a/drivers/gpu/drm/panthor/panthor_sched.c ++++ b/drivers/gpu/drm/panthor/panthor_sched.c +@@ -2805,6 +2805,20 @@ void panthor_sched_report_mmu_fault(struct panthor_device *ptdev) + panthor_sched_immediate_tick(ptdev); + } + ++void panthor_sched_prepare_for_vm_destruction(struct panthor_device *ptdev) ++{ ++ /* FW can write out internal state, like the heap context, during CSG ++ * suspend. It is therefore important that the scheduler has fully ++ * evicted any pending and related groups before VM destruction can ++ * safely continue. Failure to do so can lead to GPU page faults. ++ * A controlled termination of a Panthor instance involves destroying ++ * the group(s) before the VM. This means any relevant group eviction ++ * has already been initiated by this point, and we just need to ++ * ensure that any pending tick_work() has been completed. ++ */ ++ flush_work(&ptdev->scheduler->tick_work.work); ++} ++ + void panthor_sched_resume(struct panthor_device *ptdev) + { + /* Force a tick to re-evaluate after a resume. */ +diff --git a/drivers/gpu/drm/panthor/panthor_sched.h b/drivers/gpu/drm/panthor/panthor_sched.h +index f4a475aa34c0a..9a8692de8aded 100644 +--- a/drivers/gpu/drm/panthor/panthor_sched.h ++++ b/drivers/gpu/drm/panthor/panthor_sched.h +@@ -50,6 +50,7 @@ void panthor_sched_suspend(struct panthor_device *ptdev); + void panthor_sched_resume(struct panthor_device *ptdev); + + void panthor_sched_report_mmu_fault(struct panthor_device *ptdev); ++void panthor_sched_prepare_for_vm_destruction(struct panthor_device *ptdev); + void panthor_sched_report_fw_events(struct panthor_device *ptdev, u32 events); + + void panthor_fdinfo_gather_group_samples(struct panthor_file *pfile); +-- +2.51.0 + diff --git a/queue-6.19/drm-panthor-fix-immediate-ticking-on-a-disabled-tick.patch b/queue-6.19/drm-panthor-fix-immediate-ticking-on-a-disabled-tick.patch new file mode 100644 index 0000000000..73925357ae --- /dev/null +++ b/queue-6.19/drm-panthor-fix-immediate-ticking-on-a-disabled-tick.patch @@ -0,0 +1,61 @@ +From faaed592f269db6cb46fae59c70b74d471073297 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 10:48:36 +0100 +Subject: drm/panthor: Fix immediate ticking on a disabled tick + +From: Boris Brezillon + +[ Upstream commit 4356d21994f4ff5c87305b874939b359f16f6677 ] + +We have a few paths where we schedule the tick work immediately without +changing the resched_target. If the tick was stopped, this would lead +to a remaining_jiffies that's always > 0, and it wouldn't force a full +tick in that case. Add extra checks to cover that case properly. + +v2: +- Fix typo +- Simplify the code as suggested by Steve + +v3: +- Collect R-b + +Fixes: de8548813824 ("drm/panthor: Add the scheduler logical block") +Reviewed-by: Steven Price +Reviewed-by: Chia-I Wu +Link: https://patch.msgid.link/20251128094839.3856402-6-boris.brezillon@collabora.com +Signed-off-by: Boris Brezillon +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panthor/panthor_sched.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c +index 3f502cc7cfd1f..20d21e35d05ab 100644 +--- a/drivers/gpu/drm/panthor/panthor_sched.c ++++ b/drivers/gpu/drm/panthor/panthor_sched.c +@@ -2470,6 +2470,7 @@ static void tick_work(struct work_struct *work) + tick_work.work); + struct panthor_device *ptdev = sched->ptdev; + struct panthor_sched_tick_ctx ctx; ++ u64 resched_target = sched->resched_target; + u64 remaining_jiffies = 0, resched_delay; + u64 now = get_jiffies_64(); + int prio, ret, cookie; +@@ -2482,8 +2483,12 @@ static void tick_work(struct work_struct *work) + if (drm_WARN_ON(&ptdev->base, ret)) + goto out_dev_exit; + +- if (time_before64(now, sched->resched_target)) +- remaining_jiffies = sched->resched_target - now; ++ /* If the tick is stopped, calculate when the next tick would be */ ++ if (resched_target == U64_MAX) ++ resched_target = sched->last_tick + sched->tick_period; ++ ++ if (time_before64(now, resched_target)) ++ remaining_jiffies = resched_target - now; + + full_tick = remaining_jiffies == 0; + +-- +2.51.0 + diff --git a/queue-6.19/drm-panthor-fix-null-pointer-dereference-on-panthor_.patch b/queue-6.19/drm-panthor-fix-null-pointer-dereference-on-panthor_.patch new file mode 100644 index 0000000000..9cf43645c7 --- /dev/null +++ b/queue-6.19/drm-panthor-fix-null-pointer-dereference-on-panthor_.patch @@ -0,0 +1,47 @@ +From 1c8a0cb05c1b4c97d371ca2c9f41122299999b92 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 15 Dec 2025 20:33:12 +0000 +Subject: drm/panthor: Fix NULL pointer dereference on panthor_fw_unplug + +From: Karunika Choo + +[ Upstream commit 920c6af98e98e6afedf6318a75bac95af8415c6c ] + +This patch removes the MCU halt and wait for halt procedures during +panthor_fw_unplug() as the MCU can be in a variety of states or the FW +may not even be loaded/initialized at all, the latter of which can lead +to a NULL pointer dereference. + +It should be safe on unplug to just disable the MCU without waiting for +it to halt as it may not be able to. + +Fixes: 514072549865 ("drm/panthor: Support GLB_REQ.STATE field for Mali-G1 GPUs") +Suggested-by: Boris Brezillon +Signed-off-by: Karunika Choo +Reviewed-by: Liviu Dudau +Reviewed-by: Boris Brezillon +Link: https://patch.msgid.link/20251215203312.1084182-1-karunika.choo@arm.com +Signed-off-by: Boris Brezillon +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panthor/panthor_fw.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/drivers/gpu/drm/panthor/panthor_fw.c b/drivers/gpu/drm/panthor/panthor_fw.c +index 94a3cd6dfa6de..9533b1a31820e 100644 +--- a/drivers/gpu/drm/panthor/panthor_fw.c ++++ b/drivers/gpu/drm/panthor/panthor_fw.c +@@ -1260,10 +1260,6 @@ void panthor_fw_unplug(struct panthor_device *ptdev) + if (ptdev->fw->irq.irq) + panthor_job_irq_suspend(&ptdev->fw->irq); + +- panthor_fw_halt_mcu(ptdev); +- if (!panthor_fw_wait_mcu_halted(ptdev)) +- drm_warn(&ptdev->base, "Failed to halt MCU on unplug"); +- + panthor_fw_stop(ptdev); + } + +-- +2.51.0 + diff --git a/queue-6.19/drm-panthor-fix-panthor_gpu_coherency_set.patch b/queue-6.19/drm-panthor-fix-panthor_gpu_coherency_set.patch new file mode 100644 index 0000000000..392fd24403 --- /dev/null +++ b/queue-6.19/drm-panthor-fix-panthor_gpu_coherency_set.patch @@ -0,0 +1,57 @@ +From 5d134e7e49ea739efa083b064aff2c7ac3d953de Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Dec 2025 11:08:29 +0100 +Subject: drm/panthor: Fix panthor_gpu_coherency_set() + +From: Boris Brezillon + +[ Upstream commit 9beb8dca9e749e9983e70b22e9823e6fcd519f91 ] + +GPU_COHERENCY_PROTOCOL takes one of GPU_COHERENCY_xx +not BIT(GPU_COHERENCY_xx). + +v3: +- New commit + +v4: +- Add Steve's R-b + +v5: +- No changes + +v6: +- No changes + +v7: +- No changes + +v8: +- No changes + +Cc: Akash Goel +Fixes: dd7db8d911a1 ("drm/panthor: Explicitly set the coherency mode") +Reported-by: Steven Price +Reviewed-by: Steven Price +Link: https://patch.msgid.link/20251208100841.730527-3-boris.brezillon@collabora.com +Signed-off-by: Boris Brezillon +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panthor/panthor_gpu.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/panthor/panthor_gpu.c b/drivers/gpu/drm/panthor/panthor_gpu.c +index 9cb5dee932120..ff5231269518e 100644 +--- a/drivers/gpu/drm/panthor/panthor_gpu.c ++++ b/drivers/gpu/drm/panthor/panthor_gpu.c +@@ -51,7 +51,7 @@ struct panthor_gpu { + static void panthor_gpu_coherency_set(struct panthor_device *ptdev) + { + gpu_write(ptdev, GPU_COHERENCY_PROTOCOL, +- ptdev->coherent ? GPU_COHERENCY_PROT_BIT(ACE_LITE) : GPU_COHERENCY_NONE); ++ ptdev->coherent ? GPU_COHERENCY_ACE_LITE : GPU_COHERENCY_NONE); + } + + static void panthor_gpu_l2_config_set(struct panthor_device *ptdev) +-- +2.51.0 + diff --git a/queue-6.19/drm-panthor-fix-queue_reset_timeout_locked.patch b/queue-6.19/drm-panthor-fix-queue_reset_timeout_locked.patch new file mode 100644 index 0000000000..688bede983 --- /dev/null +++ b/queue-6.19/drm-panthor-fix-queue_reset_timeout_locked.patch @@ -0,0 +1,67 @@ +From 0fb3aa725a85c4ebba4a5ebcf95a65550e7bd4da Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Dec 2025 09:40:28 -0800 +Subject: drm/panthor: fix queue_reset_timeout_locked + +From: Chia-I Wu + +[ Upstream commit ac5b392a8c355001c4c3f230a0e4b1f904e359ca ] + +queue_check_job_completion calls queue_reset_timeout_locked to reset the +timeout when progress is made. We want the reset to happen when the +timeout is running, not when it is suspended. + +Fixes: 345c5b7cc0f85 ("drm/panthor: Make the timeout per-queue instead of per-job") +Signed-off-by: Chia-I Wu +Signed-off-by: Liviu Dudau +Link: https://patch.msgid.link/20251202174028.1600218-1-olvaffe@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panthor/panthor_sched.c | 24 ++++++++++++------------ + 1 file changed, 12 insertions(+), 12 deletions(-) + +diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c +index f53fa51d51694..6ac4cec52f9e4 100644 +--- a/drivers/gpu/drm/panthor/panthor_sched.c ++++ b/drivers/gpu/drm/panthor/panthor_sched.c +@@ -1072,18 +1072,6 @@ group_is_idle(struct panthor_group *group) + return hweight32(inactive_queues) == group->queue_count; + } + +-static void +-queue_reset_timeout_locked(struct panthor_queue *queue) +-{ +- lockdep_assert_held(&queue->fence_ctx.lock); +- +- if (queue->timeout.remaining != MAX_SCHEDULE_TIMEOUT) { +- mod_delayed_work(queue->scheduler.timeout_wq, +- &queue->timeout.work, +- msecs_to_jiffies(JOB_TIMEOUT_MS)); +- } +-} +- + static bool + group_can_run(struct panthor_group *group) + { +@@ -1100,6 +1088,18 @@ queue_timeout_is_suspended(struct panthor_queue *queue) + return queue->timeout.remaining != MAX_SCHEDULE_TIMEOUT; + } + ++static void ++queue_reset_timeout_locked(struct panthor_queue *queue) ++{ ++ lockdep_assert_held(&queue->fence_ctx.lock); ++ ++ if (!queue_timeout_is_suspended(queue)) { ++ mod_delayed_work(queue->scheduler.timeout_wq, ++ &queue->timeout.work, ++ msecs_to_jiffies(JOB_TIMEOUT_MS)); ++ } ++} ++ + static void + queue_suspend_timeout_locked(struct panthor_queue *queue) + { +-- +2.51.0 + diff --git a/queue-6.19/drm-panthor-fix-the-full_tick-check.patch b/queue-6.19/drm-panthor-fix-the-full_tick-check.patch new file mode 100644 index 0000000000..e60f54e69c --- /dev/null +++ b/queue-6.19/drm-panthor-fix-the-full_tick-check.patch @@ -0,0 +1,64 @@ +From 97d2c5b4c7f1d037619edab089209997c007ac9f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 10:48:34 +0100 +Subject: drm/panthor: Fix the full_tick check + +From: Boris Brezillon + +[ Upstream commit a3c2d0b40b108bd45d44f6c1dfa33c39d577adcd ] + +We have a full tick when the remaining time to the next tick is zero, +not the other way around. Declare a full_tick variable so we don't get +that test wrong in other places. + +v2: +- Add R-b + +v3: +- Collect R-b + +Fixes: de8548813824 ("drm/panthor: Add the scheduler logical block") +Reviewed-by: Steven Price +Reviewed-by: Chia-I Wu +Link: https://patch.msgid.link/20251128094839.3856402-4-boris.brezillon@collabora.com +Signed-off-by: Boris Brezillon +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panthor/panthor_sched.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c +index a6b8024e1a3cd..3b52c23849339 100644 +--- a/drivers/gpu/drm/panthor/panthor_sched.c ++++ b/drivers/gpu/drm/panthor/panthor_sched.c +@@ -2483,6 +2483,7 @@ static void tick_work(struct work_struct *work) + u64 remaining_jiffies = 0, resched_delay; + u64 now = get_jiffies_64(); + int prio, ret, cookie; ++ bool full_tick; + + if (!drm_dev_enter(&ptdev->base, &cookie)) + return; +@@ -2494,15 +2495,17 @@ static void tick_work(struct work_struct *work) + if (time_before64(now, sched->resched_target)) + remaining_jiffies = sched->resched_target - now; + ++ full_tick = remaining_jiffies == 0; ++ + mutex_lock(&sched->lock); + if (panthor_device_reset_is_pending(sched->ptdev)) + goto out_unlock; + +- tick_ctx_init(sched, &ctx, remaining_jiffies != 0); ++ tick_ctx_init(sched, &ctx, full_tick); + if (ctx.csg_upd_failed_mask) + goto out_cleanup_ctx; + +- if (remaining_jiffies) { ++ if (!full_tick) { + /* Scheduling forced in the middle of a tick. Only RT groups + * can preempt non-RT ones. Currently running RT groups can't be + * preempted. +-- +2.51.0 + diff --git a/queue-6.19/drm-panthor-fix-the-group-priority-rotation-logic.patch b/queue-6.19/drm-panthor-fix-the-group-priority-rotation-logic.patch new file mode 100644 index 0000000000..67b07ca553 --- /dev/null +++ b/queue-6.19/drm-panthor-fix-the-group-priority-rotation-logic.patch @@ -0,0 +1,140 @@ +From b83155ebb493ebdd26b8ae459a71098af793da57 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 10:48:35 +0100 +Subject: drm/panthor: Fix the group priority rotation logic + +From: Boris Brezillon + +[ Upstream commit 55429c51d5db3db24c2ad561944c6a0ca922d476 ] + +When rotating group priorities, we want the group with the +highest priority to go back to the end of the queue, and all +other active groups to get their priority bumped, otherwise +some groups will never get a chance to run with the highest +priority. This implies moving the rotation itself to +tick_work(), and only dealing with old group ordering in +tick_ctx_insert_old_group(). + +v2: +- Add R-b +- Fix the commit message + +v3: +- Drop the full_tick argument in tick_ctx_init() +- Collect R-b + +Fixes: de8548813824 ("drm/panthor: Add the scheduler logical block") +Reviewed-by: Steven Price +Reviewed-by: Chia-I Wu +Link: https://patch.msgid.link/20251128094839.3856402-5-boris.brezillon@collabora.com +Signed-off-by: Boris Brezillon +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panthor/panthor_sched.c | 52 +++++++++++++++---------- + 1 file changed, 31 insertions(+), 21 deletions(-) + +diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c +index 3b52c23849339..3f502cc7cfd1f 100644 +--- a/drivers/gpu/drm/panthor/panthor_sched.c ++++ b/drivers/gpu/drm/panthor/panthor_sched.c +@@ -2085,31 +2085,22 @@ tick_ctx_pick_groups_from_list(const struct panthor_scheduler *sched, + static void + tick_ctx_insert_old_group(struct panthor_scheduler *sched, + struct panthor_sched_tick_ctx *ctx, +- struct panthor_group *group, +- bool full_tick) ++ struct panthor_group *group) + { + struct panthor_csg_slot *csg_slot = &sched->csg_slots[group->csg_id]; + struct panthor_group *other_group; + +- if (!full_tick) { +- list_add_tail(&group->run_node, &ctx->old_groups[group->priority]); +- return; +- } +- +- /* Rotate to make sure groups with lower CSG slot +- * priorities have a chance to get a higher CSG slot +- * priority next time they get picked. This priority +- * has an impact on resource request ordering, so it's +- * important to make sure we don't let one group starve +- * all other groups with the same group priority. +- */ ++ /* Class groups in descending priority order so we can easily rotate. */ + list_for_each_entry(other_group, + &ctx->old_groups[csg_slot->group->priority], + run_node) { + struct panthor_csg_slot *other_csg_slot = &sched->csg_slots[other_group->csg_id]; + +- if (other_csg_slot->priority > csg_slot->priority) { +- list_add_tail(&csg_slot->group->run_node, &other_group->run_node); ++ /* Our group has a higher prio than the one we're testing against, ++ * place it just before. ++ */ ++ if (csg_slot->priority > other_csg_slot->priority) { ++ list_add_tail(&group->run_node, &other_group->run_node); + return; + } + } +@@ -2119,8 +2110,7 @@ tick_ctx_insert_old_group(struct panthor_scheduler *sched, + + static void + tick_ctx_init(struct panthor_scheduler *sched, +- struct panthor_sched_tick_ctx *ctx, +- bool full_tick) ++ struct panthor_sched_tick_ctx *ctx) + { + struct panthor_device *ptdev = sched->ptdev; + struct panthor_csg_slots_upd_ctx upd_ctx; +@@ -2158,7 +2148,7 @@ tick_ctx_init(struct panthor_scheduler *sched, + group->fatal_queues |= GENMASK(group->queue_count - 1, 0); + } + +- tick_ctx_insert_old_group(sched, ctx, group, full_tick); ++ tick_ctx_insert_old_group(sched, ctx, group); + csgs_upd_ctx_queue_reqs(ptdev, &upd_ctx, i, + csg_iface->output->ack ^ CSG_STATUS_UPDATE, + CSG_STATUS_UPDATE); +@@ -2501,7 +2491,7 @@ static void tick_work(struct work_struct *work) + if (panthor_device_reset_is_pending(sched->ptdev)) + goto out_unlock; + +- tick_ctx_init(sched, &ctx, full_tick); ++ tick_ctx_init(sched, &ctx); + if (ctx.csg_upd_failed_mask) + goto out_cleanup_ctx; + +@@ -2527,9 +2517,29 @@ static void tick_work(struct work_struct *work) + for (prio = PANTHOR_CSG_PRIORITY_COUNT - 1; + prio >= 0 && !tick_ctx_is_full(sched, &ctx); + prio--) { ++ struct panthor_group *old_highest_prio_group = ++ list_first_entry_or_null(&ctx.old_groups[prio], ++ struct panthor_group, run_node); ++ ++ /* Pull out the group with the highest prio for rotation. */ ++ if (old_highest_prio_group) ++ list_del(&old_highest_prio_group->run_node); ++ ++ /* Re-insert old active groups so they get a chance to run with higher prio. */ ++ tick_ctx_pick_groups_from_list(sched, &ctx, &ctx.old_groups[prio], true, true); ++ ++ /* Fill the remaining slots with runnable groups. */ + tick_ctx_pick_groups_from_list(sched, &ctx, &sched->groups.runnable[prio], + true, false); +- tick_ctx_pick_groups_from_list(sched, &ctx, &ctx.old_groups[prio], true, true); ++ ++ /* Re-insert the old group with the highest prio, and give it a chance to be ++ * scheduled again (but with a lower prio) if there's room left. ++ */ ++ if (old_highest_prio_group) { ++ list_add_tail(&old_highest_prio_group->run_node, &ctx.old_groups[prio]); ++ tick_ctx_pick_groups_from_list(sched, &ctx, &ctx.old_groups[prio], ++ true, true); ++ } + } + + /* If we have free CSG slots left, pick idle groups */ +-- +2.51.0 + diff --git a/queue-6.19/drm-panthor-fix-the-logic-that-decides-when-to-stop-.patch b/queue-6.19/drm-panthor-fix-the-logic-that-decides-when-to-stop-.patch new file mode 100644 index 0000000000..01eba2ad8b --- /dev/null +++ b/queue-6.19/drm-panthor-fix-the-logic-that-decides-when-to-stop-.patch @@ -0,0 +1,130 @@ +From f897b74234a6294a74af106e28c6ce423aa7d92d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 10:48:37 +0100 +Subject: drm/panthor: Fix the logic that decides when to stop ticking + +From: Boris Brezillon + +[ Upstream commit 61d9a43d70dc3e1709ecd14a34f6d5f01e21dfc9 ] + +When we have multiple active groups with the same priority, we need to +keep ticking for the priority rotation to take place. If we don't do +that, we might starve slots with lower priorities. + +It's annoying to deal with that in tick_ctx_update_resched_target(), +so let's add a ::stop_tick field to the tick context which is +initialized to true, and downgraded to false as soon as we detect +something that requires to tick to happen. This way we can complement +the current logic with extra conditions if needed. + +v2: +- Add R-b + +v3: +- Drop panthor_sched_tick_ctx::min_priority (no longer relevant) +- Collect R-b + +Fixes: de8548813824 ("drm/panthor: Add the scheduler logical block") +Reviewed-by: Steven Price +Reviewed-by: Chia-I Wu +Link: https://patch.msgid.link/20251128094839.3856402-7-boris.brezillon@collabora.com +Signed-off-by: Boris Brezillon +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panthor/panthor_sched.c | 44 ++++++++++--------------- + 1 file changed, 17 insertions(+), 27 deletions(-) + +diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c +index 20d21e35d05ab..484a58b419c08 100644 +--- a/drivers/gpu/drm/panthor/panthor_sched.c ++++ b/drivers/gpu/drm/panthor/panthor_sched.c +@@ -2020,10 +2020,10 @@ struct panthor_sched_tick_ctx { + struct list_head groups[PANTHOR_CSG_PRIORITY_COUNT]; + u32 idle_group_count; + u32 group_count; +- enum panthor_csg_priority min_priority; + struct panthor_vm *vms[MAX_CS_PER_CSG]; + u32 as_count; + bool immediate_tick; ++ bool stop_tick; + u32 csg_upd_failed_mask; + }; + +@@ -2066,17 +2066,21 @@ tick_ctx_pick_groups_from_list(const struct panthor_scheduler *sched, + if (!owned_by_tick_ctx) + group_get(group); + +- list_move_tail(&group->run_node, &ctx->groups[group->priority]); + ctx->group_count++; ++ ++ /* If we have more than one active group with the same priority, ++ * we need to keep ticking to rotate the CSG priority. ++ */ + if (group_is_idle(group)) + ctx->idle_group_count++; ++ else if (!list_empty(&ctx->groups[group->priority])) ++ ctx->stop_tick = false; ++ ++ list_move_tail(&group->run_node, &ctx->groups[group->priority]); + + if (i == ctx->as_count) + ctx->vms[ctx->as_count++] = group->vm; + +- if (ctx->min_priority > group->priority) +- ctx->min_priority = group->priority; +- + if (tick_ctx_is_full(sched, ctx)) + return; + } +@@ -2120,7 +2124,7 @@ tick_ctx_init(struct panthor_scheduler *sched, + memset(ctx, 0, sizeof(*ctx)); + csgs_upd_ctx_init(&upd_ctx); + +- ctx->min_priority = PANTHOR_CSG_PRIORITY_COUNT; ++ ctx->stop_tick = true; + for (i = 0; i < ARRAY_SIZE(ctx->groups); i++) { + INIT_LIST_HEAD(&ctx->groups[i]); + INIT_LIST_HEAD(&ctx->old_groups[i]); +@@ -2432,32 +2436,18 @@ static u64 + tick_ctx_update_resched_target(struct panthor_scheduler *sched, + const struct panthor_sched_tick_ctx *ctx) + { +- /* We had space left, no need to reschedule until some external event happens. */ +- if (!tick_ctx_is_full(sched, ctx)) +- goto no_tick; +- +- /* If idle groups were scheduled, no need to wake up until some external +- * event happens (group unblocked, new job submitted, ...). +- */ +- if (ctx->idle_group_count) +- goto no_tick; ++ u64 resched_target; + +- if (drm_WARN_ON(&sched->ptdev->base, ctx->min_priority >= PANTHOR_CSG_PRIORITY_COUNT)) ++ if (ctx->stop_tick) + goto no_tick; + +- /* If there are groups of the same priority waiting, we need to +- * keep the scheduler ticking, otherwise, we'll just wait for +- * new groups with higher priority to be queued. +- */ +- if (!list_empty(&sched->groups.runnable[ctx->min_priority])) { +- u64 resched_target = sched->last_tick + sched->tick_period; ++ resched_target = sched->last_tick + sched->tick_period; + +- if (time_before64(sched->resched_target, sched->last_tick) || +- time_before64(resched_target, sched->resched_target)) +- sched->resched_target = resched_target; ++ if (time_before64(sched->resched_target, sched->last_tick) || ++ time_before64(resched_target, sched->resched_target)) ++ sched->resched_target = resched_target; + +- return sched->resched_target - sched->last_tick; +- } ++ return sched->resched_target - sched->last_tick; + + no_tick: + sched->resched_target = U64_MAX; +-- +2.51.0 + diff --git a/queue-6.19/drm-panthor-make-sure-we-resume-the-tick-when-new-jo.patch b/queue-6.19/drm-panthor-make-sure-we-resume-the-tick-when-new-jo.patch new file mode 100644 index 0000000000..d632a10d86 --- /dev/null +++ b/queue-6.19/drm-panthor-make-sure-we-resume-the-tick-when-new-jo.patch @@ -0,0 +1,109 @@ +From 3adf4566e4bc9558697dd977c2bc151960ed4324 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 10:48:38 +0100 +Subject: drm/panthor: Make sure we resume the tick when new jobs are submitted + +From: Boris Brezillon + +[ Upstream commit 99820b4b7e50d9651f01d2d55b6b9ba92dcc5b99 ] + +If the group is already assigned a slot but was idle before this job +submission, we need to make sure the priority rotation happens in the +future. Extract the existing logic living in group_schedule_locked() +and call this new sched_resume_tick() helper from the "group is +assigned a slot" path. + +v2: +- Add R-b + +v3: +- Re-use queue_mask to clear the bit +- Collect R-b + +Fixes: de8548813824 ("drm/panthor: Add the scheduler logical block") +Reviewed-by: Steven Price +Reviewed-by: Chia-I Wu +Link: https://patch.msgid.link/20251128094839.3856402-8-boris.brezillon@collabora.com +Signed-off-by: Boris Brezillon +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panthor/panthor_sched.c | 43 +++++++++++++++++++------ + 1 file changed, 34 insertions(+), 9 deletions(-) + +diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c +index 484a58b419c08..f53fa51d51694 100644 +--- a/drivers/gpu/drm/panthor/panthor_sched.c ++++ b/drivers/gpu/drm/panthor/panthor_sched.c +@@ -2659,14 +2659,33 @@ static void sync_upd_work(struct work_struct *work) + sched_queue_delayed_work(sched, tick, 0); + } + ++static void sched_resume_tick(struct panthor_device *ptdev) ++{ ++ struct panthor_scheduler *sched = ptdev->scheduler; ++ u64 delay_jiffies, now; ++ ++ drm_WARN_ON(&ptdev->base, sched->resched_target != U64_MAX); ++ ++ /* Scheduler tick was off, recalculate the resched_target based on the ++ * last tick event, and queue the scheduler work. ++ */ ++ now = get_jiffies_64(); ++ sched->resched_target = sched->last_tick + sched->tick_period; ++ if (sched->used_csg_slot_count == sched->csg_slot_count && ++ time_before64(now, sched->resched_target)) ++ delay_jiffies = min_t(unsigned long, sched->resched_target - now, ULONG_MAX); ++ else ++ delay_jiffies = 0; ++ ++ sched_queue_delayed_work(sched, tick, delay_jiffies); ++} ++ + static void group_schedule_locked(struct panthor_group *group, u32 queue_mask) + { + struct panthor_device *ptdev = group->ptdev; + struct panthor_scheduler *sched = ptdev->scheduler; + struct list_head *queue = &sched->groups.runnable[group->priority]; +- u64 delay_jiffies = 0; + bool was_idle; +- u64 now; + + if (!group_can_run(group)) + return; +@@ -2711,13 +2730,7 @@ static void group_schedule_locked(struct panthor_group *group, u32 queue_mask) + /* Scheduler tick was off, recalculate the resched_target based on the + * last tick event, and queue the scheduler work. + */ +- now = get_jiffies_64(); +- sched->resched_target = sched->last_tick + sched->tick_period; +- if (sched->used_csg_slot_count == sched->csg_slot_count && +- time_before64(now, sched->resched_target)) +- delay_jiffies = min_t(unsigned long, sched->resched_target - now, ULONG_MAX); +- +- sched_queue_delayed_work(sched, tick, delay_jiffies); ++ sched_resume_tick(ptdev); + } + + static void queue_stop(struct panthor_queue *queue, +@@ -3351,6 +3364,18 @@ queue_run_job(struct drm_sched_job *sched_job) + if (group->csg_id < 0) { + group_schedule_locked(group, BIT(job->queue_idx)); + } else { ++ u32 queue_mask = BIT(job->queue_idx); ++ bool resume_tick = group_is_idle(group) && ++ (group->idle_queues & queue_mask) && ++ !(group->blocked_queues & queue_mask) && ++ sched->resched_target == U64_MAX; ++ ++ /* We just added something to the queue, so it's no longer idle. */ ++ group->idle_queues &= ~queue_mask; ++ ++ if (resume_tick) ++ sched_resume_tick(ptdev); ++ + gpu_write(ptdev, CSF_DOORBELL(queue->doorbell_id), 1); + if (!sched->pm.has_ref && + !(group->blocked_queues & BIT(job->queue_idx))) { +-- +2.51.0 + diff --git a/queue-6.19/drm-panthor-recover-from-panthor_gpu_flush_caches-fa.patch b/queue-6.19/drm-panthor-recover-from-panthor_gpu_flush_caches-fa.patch new file mode 100644 index 0000000000..7266e8260a --- /dev/null +++ b/queue-6.19/drm-panthor-recover-from-panthor_gpu_flush_caches-fa.patch @@ -0,0 +1,108 @@ +From 96e68de8c62e8c56b70b7d37f330c63198e1a990 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 09:48:37 +0100 +Subject: drm/panthor: Recover from panthor_gpu_flush_caches() failures + +From: Boris Brezillon + +[ Upstream commit 3c0a60195b37af83bbbaf223cd3a78945bace49e ] + +We have seen a few cases where the whole memory subsystem is blocked +and flush operations never complete. When that happens, we want to: + +- schedule a reset, so we can recover from this situation +- in the reset path, we need to reset the pending_reqs so we can send + new commands after the reset +- if more panthor_gpu_flush_caches() operations are queued after + the timeout, we skip them and return -EIO directly to avoid needless + waits (the memory block won't miraculously work again) + +Note that we drop the WARN_ON()s because these hangs can be triggered +with buggy GPU jobs created by the UMD, and there's no way we can +prevent it. We do keep the error messages though. + +v2: +- New patch + +v3: +- Collect R-b +- Explicitly mention the fact we dropped the WARN_ON()s in the commit + message + +v4: +- No changes + +Fixes: 5cd894e258c4 ("drm/panthor: Add the GPU logical block") +Reviewed-by: Steven Price +Link: https://patch.msgid.link/20251128084841.3804658-4-boris.brezillon@collabora.com +Signed-off-by: Boris Brezillon +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panthor/panthor_gpu.c | 19 ++++++++++++------- + 1 file changed, 12 insertions(+), 7 deletions(-) + +diff --git a/drivers/gpu/drm/panthor/panthor_gpu.c b/drivers/gpu/drm/panthor/panthor_gpu.c +index 06b231b2460ab..9cb5dee932120 100644 +--- a/drivers/gpu/drm/panthor/panthor_gpu.c ++++ b/drivers/gpu/drm/panthor/panthor_gpu.c +@@ -289,38 +289,42 @@ int panthor_gpu_l2_power_on(struct panthor_device *ptdev) + int panthor_gpu_flush_caches(struct panthor_device *ptdev, + u32 l2, u32 lsc, u32 other) + { +- bool timedout = false; + unsigned long flags; ++ int ret = 0; + + /* Serialize cache flush operations. */ + guard(mutex)(&ptdev->gpu->cache_flush_lock); + + spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags); +- if (!drm_WARN_ON(&ptdev->base, +- ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED)) { ++ if (!(ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED)) { + ptdev->gpu->pending_reqs |= GPU_IRQ_CLEAN_CACHES_COMPLETED; + gpu_write(ptdev, GPU_CMD, GPU_FLUSH_CACHES(l2, lsc, other)); ++ } else { ++ ret = -EIO; + } + spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags); + ++ if (ret) ++ return ret; ++ + if (!wait_event_timeout(ptdev->gpu->reqs_acked, + !(ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED), + msecs_to_jiffies(100))) { + spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags); + if ((ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED) != 0 && + !(gpu_read(ptdev, GPU_INT_RAWSTAT) & GPU_IRQ_CLEAN_CACHES_COMPLETED)) +- timedout = true; ++ ret = -ETIMEDOUT; + else + ptdev->gpu->pending_reqs &= ~GPU_IRQ_CLEAN_CACHES_COMPLETED; + spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags); + } + +- if (timedout) { ++ if (ret) { ++ panthor_device_schedule_reset(ptdev); + drm_err(&ptdev->base, "Flush caches timeout"); +- return -ETIMEDOUT; + } + +- return 0; ++ return ret; + } + + /** +@@ -360,6 +364,7 @@ int panthor_gpu_soft_reset(struct panthor_device *ptdev) + return -ETIMEDOUT; + } + ++ ptdev->gpu->pending_reqs = 0; + return 0; + } + +-- +2.51.0 + diff --git a/queue-6.19/drm-panthor-remove-redundant-call-to-disable-the-mcu.patch b/queue-6.19/drm-panthor-remove-redundant-call-to-disable-the-mcu.patch new file mode 100644 index 0000000000..a2e200d5e5 --- /dev/null +++ b/queue-6.19/drm-panthor-remove-redundant-call-to-disable-the-mcu.patch @@ -0,0 +1,36 @@ +From 370dcddcdcf7dce2fcc742307e37d55132e5aafa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Dec 2025 09:19:11 +0000 +Subject: drm/panthor: Remove redundant call to disable the MCU + +From: Akash Goel + +[ Upstream commit cedf6765ecfd60197d90437ec648feb8b3e31cb1 ] + +This commit removes the redundant call to disable the MCU firmware +in the suspend path. + +Fixes: 514072549865 ("drm/panthor: Support GLB_REQ.STATE field for Mali-G1 GPUs") +Signed-off-by: Akash Goel +Signed-off-by: Liviu Dudau +Link: https://patch.msgid.link/20251203091911.145623-1-akash.goel@arm.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panthor/panthor_fw.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/gpu/drm/panthor/panthor_fw.c b/drivers/gpu/drm/panthor/panthor_fw.c +index 1a5e3c1a27fbc..94a3cd6dfa6de 100644 +--- a/drivers/gpu/drm/panthor/panthor_fw.c ++++ b/drivers/gpu/drm/panthor/panthor_fw.c +@@ -1187,7 +1187,6 @@ void panthor_fw_pre_reset(struct panthor_device *ptdev, bool on_hang) + else + ptdev->reset.fast = true; + } +- panthor_fw_stop(ptdev); + + panthor_job_irq_suspend(&ptdev->fw->irq); + panthor_fw_stop(ptdev); +-- +2.51.0 + diff --git a/queue-6.19/drm-plane-fix-is_err-vs-null-bug-drm_plane_create_co.patch b/queue-6.19/drm-plane-fix-is_err-vs-null-bug-drm_plane_create_co.patch new file mode 100644 index 0000000000..cd039a8e27 --- /dev/null +++ b/queue-6.19/drm-plane-fix-is_err-vs-null-bug-drm_plane_create_co.patch @@ -0,0 +1,41 @@ +From b6a1732e7895f56f0d71a648b28858f08f167869 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Dec 2025 14:09:25 +0300 +Subject: drm/plane: Fix IS_ERR() vs NULL bug + drm_plane_create_color_pipeline_property() + +From: Dan Carpenter + +[ Upstream commit 470cb09a2936d3c1ff8aeff46e3c14dcc4314e9b ] + +The drm_property_create_enum() function returns NULL on error, it never +returns error pointers. Fix the error checking to match. + +Fixes: 2afc3184f3b3 ("drm/plane: Add COLOR PIPELINE property") +Signed-off-by: Dan Carpenter +Signed-off-by: Simon Ser +Link: https://patch.msgid.link/aTK9ZR0sMgqSACow@stanley.mountain +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/drm_plane.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c +index b143589717e64..bed2562bf911b 100644 +--- a/drivers/gpu/drm/drm_plane.c ++++ b/drivers/gpu/drm/drm_plane.c +@@ -1867,9 +1867,9 @@ int drm_plane_create_color_pipeline_property(struct drm_plane *plane, + prop = drm_property_create_enum(plane->dev, DRM_MODE_PROP_ATOMIC, + "COLOR_PIPELINE", + all_pipelines, len); +- if (IS_ERR(prop)) { ++ if (!prop) { + kfree(all_pipelines); +- return PTR_ERR(prop); ++ return -ENOMEM; + } + + drm_object_attach_property(&plane->base, prop, 0); +-- +2.51.0 + diff --git a/queue-6.19/drm-rockchip-dw_hdmi_qp-fix-rk3576-hpd-interrupt-han.patch b/queue-6.19/drm-rockchip-dw_hdmi_qp-fix-rk3576-hpd-interrupt-han.patch new file mode 100644 index 0000000000..340f4b74ec --- /dev/null +++ b/queue-6.19/drm-rockchip-dw_hdmi_qp-fix-rk3576-hpd-interrupt-han.patch @@ -0,0 +1,54 @@ +From 8da3dee10c19cacc816eb6c97645699c2b93b4bb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 18:24:43 +0200 +Subject: drm/rockchip: dw_hdmi_qp: Fix RK3576 HPD interrupt handling + +From: Cristian Ciocaltea + +[ Upstream commit 5f7be8afc40c5ccf1be0410514703e50a49532c0 ] + +The threaded interrupt handler on RK3576 checks HPD IRQ status before +deciding to continue with interrupt clearing and unmasking. + +This is not only redundant, since a similar verification has been +already performed by the hard IRQ handler before masking the interrupt, +but is also error prone, because it might happen that hardware clears +the status register right after the masking operation completes, and +before the threaded handler reads its value. + +The consequence is that HPD IRQ gets never unmasked, which breaks +hotplug detection until reloading the driver or rebooting the system. + +Drop the unnecessary verification of the HPD interrupt status from the +threaded interrupt handler. + +Fixes: 36439120efbd ("drm/rockchip: dw_hdmi_qp: Add basic RK3576 HDMI output support") +Signed-off-by: Cristian Ciocaltea +Signed-off-by: Heiko Stuebner +Link: https://patch.msgid.link/20260115-dw-hdmi-qp-hpd-v1-1-e59c166eaa65@collabora.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c +index 8604342f99432..c7158b1b8c59e 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c +@@ -280,12 +280,7 @@ static irqreturn_t dw_hdmi_qp_rk3576_hardirq(int irq, void *dev_id) + static irqreturn_t dw_hdmi_qp_rk3576_irq(int irq, void *dev_id) + { + struct rockchip_hdmi_qp *hdmi = dev_id; +- u32 intr_stat, val; +- +- regmap_read(hdmi->regmap, RK3576_IOC_HDMI_HPD_STATUS, &intr_stat); +- +- if (!intr_stat) +- return IRQ_NONE; ++ u32 val; + + val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_CLR, 1); + regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val); +-- +2.51.0 + diff --git a/queue-6.19/drm-xe-pf-fix-.bulk_profile-sched_priority-descripti.patch b/queue-6.19/drm-xe-pf-fix-.bulk_profile-sched_priority-descripti.patch new file mode 100644 index 0000000000..144fbb8470 --- /dev/null +++ b/queue-6.19/drm-xe-pf-fix-.bulk_profile-sched_priority-descripti.patch @@ -0,0 +1,41 @@ +From fee05fa3067a192bcdbb7e81d2be5195c08678df Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 15 Nov 2025 16:26:58 +0100 +Subject: drm/xe/pf: Fix .bulk_profile/sched_priority description +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Michal Wajdeczko + +[ Upstream commit 5a062505aa0ed5f9124c22f07da6ba58950475b2 ] + +The .bulk_profile/sched_priority file is always write-only, unlike +the profile/sched_priority files which can be either read-write or +read-only (in case of PF or VFs respectively). + +Fixes: 6b514ed2d9a7 ("drm/xe/pf: Add documentation for sriov_admin attributes") +Signed-off-by: Michal Wajdeczko +Reviewed-by: Piotr Piórkowski +Link: https://patch.msgid.link/20251115152659.10853-1-michal.wajdeczko@intel.com +Signed-off-by: Sasha Levin +--- + Documentation/ABI/testing/sysfs-driver-intel-xe-sriov | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Documentation/ABI/testing/sysfs-driver-intel-xe-sriov b/Documentation/ABI/testing/sysfs-driver-intel-xe-sriov +index 2fd7e9b7bacc0..7f5ef9eada531 100644 +--- a/Documentation/ABI/testing/sysfs-driver-intel-xe-sriov ++++ b/Documentation/ABI/testing/sysfs-driver-intel-xe-sriov +@@ -119,7 +119,7 @@ Description: + The GT preemption timeout (PT) in [us] to be applied to all functions. + See sriov_admin/{pf,vf}/profile/preempt_timeout_us for more details. + +- sched_priority: (RW/RO) string ++ sched_priority: (WO) string + The GT scheduling priority to be applied for all functions. + See sriov_admin/{pf,vf}/profile/sched_priority for more details. + +-- +2.51.0 + diff --git a/queue-6.19/drm-xe-ptl-disable-dcc-on-ptl.patch b/queue-6.19/drm-xe-ptl-disable-dcc-on-ptl.patch new file mode 100644 index 0000000000..2e2fe05a52 --- /dev/null +++ b/queue-6.19/drm-xe-ptl-disable-dcc-on-ptl.patch @@ -0,0 +1,87 @@ +From f46f21c58c58eba3f553c800724204bfb4f2d13f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 16:59:17 -0800 +Subject: drm/xe/ptl: Disable DCC on PTL + +From: Vinay Belgaumkar + +[ Upstream commit 801a6e61f5fbab2c0dd76c8360f45b625b49e410 ] + +On PTL, the recommendation is to disable DCC(Duty Cycle Control) as +it may cause some regressions due to added latencies. Upcoming GuC +releases will disable DCC on PTL as well, but we need to force it in +KMD so that this behavior is propagated to older kernels. + +v2: Update commit message (Rodrigo) +v3: Rebase +v4: Fix typo: s/propagted/propagated + +Fixes: 5cdb71d3b0db ("drm/xe/ptl: Add GuC FW definition for PTL") +Cc: Daniele Ceraolo Spurio +Cc: Rodrigo Vivi +Signed-off-by: Vinay Belgaumkar +Link: https://patch.msgid.link/20260124005917.398522-1-vinay.belgaumkar@intel.com +Reviewed-by: Rodrigo Vivi +Signed-off-by: Rodrigo Vivi +(cherry picked from commit 40ee63f5df2d5c6471b583df800aac89dc0502a4) +Signed-off-by: Rodrigo Vivi +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/xe/xe_guc_pc.c | 34 ++++++++++++++++++++++++++++++++++ + 1 file changed, 34 insertions(+) + +diff --git a/drivers/gpu/drm/xe/xe_guc_pc.c b/drivers/gpu/drm/xe/xe_guc_pc.c +index 951a49fb1d3e4..7f09cf0e495fe 100644 +--- a/drivers/gpu/drm/xe/xe_guc_pc.c ++++ b/drivers/gpu/drm/xe/xe_guc_pc.c +@@ -1214,6 +1214,36 @@ int xe_guc_pc_set_power_profile(struct xe_guc_pc *pc, const char *buf) + return ret; + } + ++static int pc_action_set_dcc(struct xe_guc_pc *pc, bool enable) ++{ ++ int ret; ++ ++ ret = pc_action_set_param(pc, ++ SLPC_PARAM_TASK_ENABLE_DCC, ++ enable); ++ if (!ret) ++ return pc_action_set_param(pc, ++ SLPC_PARAM_TASK_DISABLE_DCC, ++ !enable); ++ else ++ return ret; ++} ++ ++static int pc_modify_defaults(struct xe_guc_pc *pc) ++{ ++ struct xe_device *xe = pc_to_xe(pc); ++ struct xe_gt *gt = pc_to_gt(pc); ++ int ret = 0; ++ ++ if (xe->info.platform == XE_PANTHERLAKE) { ++ ret = pc_action_set_dcc(pc, false); ++ if (unlikely(ret)) ++ xe_gt_err(gt, "Failed to modify DCC default: %pe\n", ERR_PTR(ret)); ++ } ++ ++ return ret; ++} ++ + /** + * xe_guc_pc_start - Start GuC's Power Conservation component + * @pc: Xe_GuC_PC instance +@@ -1271,6 +1301,10 @@ int xe_guc_pc_start(struct xe_guc_pc *pc) + ktime_ms_delta(ktime_get(), earlier)); + } + ++ ret = pc_modify_defaults(pc); ++ if (ret) ++ return ret; ++ + ret = pc_init_freqs(pc); + if (ret) + goto out; +-- +2.51.0 + diff --git a/queue-6.19/drm-xe-unregister-drm-device-on-probe-error.patch b/queue-6.19/drm-xe-unregister-drm-device-on-probe-error.patch new file mode 100644 index 0000000000..843ba03260 --- /dev/null +++ b/queue-6.19/drm-xe-unregister-drm-device-on-probe-error.patch @@ -0,0 +1,91 @@ +From 965c07f149cf3fb760637d49235b4937a0a2945e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 21:10:42 +0000 +Subject: drm/xe: Unregister drm device on probe error + +From: Shuicheng Lin + +[ Upstream commit 96c2c72b817d70e8d110e78b0162e044a0c41f9f ] + +Call drm_dev_unregister() when xe_device_probe() fails after successful +drm_dev_register(). This ensures the DRM device is promptly unregistered +before returning an error, avoiding leaving it registered on the failure +path. +Otherwise, there is warn message if xe_device_probe() is called again: +" +[ 207.322365] [drm:drm_minor_register] +[ 207.322381] debugfs: '128' already exists in 'dri' +[ 207.322432] sysfs: cannot create duplicate filename '/devices/pci0000:00/0000:00:01.0/0000:01:00.0/0000:02:01.0/0000:03:00.0/drm/renderD128' +[ 207.322435] CPU: 5 UID: 0 PID: 10261 Comm: modprobe Tainted: G B W 6.19.0-rc2-lgci-xe-kernel+ #223 PREEMPT(voluntary) +[ 207.322439] Tainted: [B]=BAD_PAGE, [W]=WARN +[ 207.322440] Hardware name: ASUS System Product Name/PRIME Z790-P WIFI, BIOS 0812 02/24/2023 +[ 207.322441] Call Trace: +[ 207.322442] +[ 207.322443] dump_stack_lvl+0xa0/0xc0 +[ 207.322446] dump_stack+0x10/0x20 +[ 207.322448] sysfs_warn_dup+0xd5/0x110 +[ 207.322451] sysfs_create_dir_ns+0x1f6/0x280 +[ 207.322453] ? __pfx_sysfs_create_dir_ns+0x10/0x10 +[ 207.322455] ? lock_acquire+0x1a4/0x2e0 +[ 207.322458] ? __kasan_check_read+0x11/0x20 +[ 207.322461] kobject_add_internal+0x28d/0x8e0 +[ 207.322464] kobject_add+0x11f/0x1f0 +[ 207.322465] ? lock_acquire+0x1a4/0x2e0 +[ 207.322467] ? __pfx_kobject_add+0x10/0x10 +[ 207.322469] ? __kasan_check_write+0x14/0x20 +[ 207.322471] ? kobject_put+0x62/0x4a0 +[ 207.322473] ? get_device_parent.isra.0+0x1bb/0x4c0 +[ 207.322475] ? kobject_put+0x62/0x4a0 +[ 207.322477] device_add+0x2d7/0x1500 +[ 207.322479] ? __pfx_device_add+0x10/0x10 +[ 207.322481] ? drm_debugfs_add_file+0xfa/0x170 +[ 207.322483] ? drm_debugfs_add_files+0x82/0xd0 +[ 207.322485] ? drm_debugfs_add_files+0x82/0xd0 +[ 207.322487] drm_minor_register+0x10a/0x2d0 +[ 207.322489] drm_dev_register+0x143/0x860 +[ 207.322491] ? xe_configfs_get_psmi_enabled+0x12/0x90 [xe] +[ 207.322667] xe_device_probe+0x185b/0x2c40 [xe] +[ 207.322812] ? __pfx___drm_dev_dbg+0x10/0x10 +[ 207.322815] ? add_dr+0x180/0x220 +[ 207.322818] ? __pfx___drmm_mutex_release+0x10/0x10 +[ 207.322821] ? __pfx_xe_device_probe+0x10/0x10 [xe] +[ 207.322966] ? xe_pm_init_early+0x33a/0x410 [xe] +[ 207.323136] xe_pci_probe+0x936/0x1250 [xe] +[ 207.323298] ? lock_acquire+0x1a4/0x2e0 +[ 207.323302] ? __pfx_xe_pci_probe+0x10/0x10 [xe] +[ 207.323464] local_pci_probe+0xe6/0x1a0 +[ 207.323468] pci_device_probe+0x523/0x840 +[ 207.323470] ? __pfx_pci_device_probe+0x10/0x10 +[ 207.323473] ? sysfs_do_create_link_sd.isra.0+0x8c/0x110 +[ 207.323476] ? sysfs_create_link+0x48/0xc0 +[ 207.323479] really_probe+0x1fd/0x8a0 +... +" + +Fixes: dd08ebf6c352 ("drm/xe: Introduce a new DRM driver for Intel GPUs") +Signed-off-by: Shuicheng Lin +Reviewed-by: Jonathan Cavitt +Link: https://patch.msgid.link/20260109211041.2446012-2-shuicheng.lin@intel.com +Signed-off-by: Matt Roper +(cherry picked from commit 60bfb8baf8f0d5b0d521744dfd01c880ce1a23f3) +Signed-off-by: Rodrigo Vivi +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/xe/xe_device.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c +index 9a6d49fcd8e49..ef5acef32f416 100644 +--- a/drivers/gpu/drm/xe/xe_device.c ++++ b/drivers/gpu/drm/xe/xe_device.c +@@ -976,6 +976,7 @@ int xe_device_probe(struct xe_device *xe) + + err_unregister_display: + xe_display_unregister(xe); ++ drm_dev_unregister(&xe->drm); + + return err; + } +-- +2.51.0 + diff --git a/queue-6.19/edac-altera-remove-irqf_oneshot.patch b/queue-6.19/edac-altera-remove-irqf_oneshot.patch new file mode 100644 index 0000000000..102da4380c --- /dev/null +++ b/queue-6.19/edac-altera-remove-irqf_oneshot.patch @@ -0,0 +1,74 @@ +From a8fb5b9bafef7e1d23587b5bb11fcff6d12ecee7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:55:30 +0100 +Subject: EDAC/altera: Remove IRQF_ONESHOT + +From: Sebastian Andrzej Siewior + +[ Upstream commit 5c858d6c66304b4c7579582ec5235f02d43578ea ] + +Passing IRQF_ONESHOT ensures that the interrupt source is masked until +the secondary (threaded) handler is done. If only a primary handler is +used then the flag makes no sense because the interrupt can not fire +(again) while its handler is running. + +The flag also prevents force-threading of the primary handler and the +irq-core will warn about this. + +Remove IRQF_ONESHOT from irqflags. + +Fixes: a29d64a45eed1 ("EDAC, altera: Add IRQ Flags to disable IRQ while handling") +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260128095540.863589-11-bigeasy@linutronix.de +Signed-off-by: Sasha Levin +--- + drivers/edac/altera_edac.c | 11 ++++------- + 1 file changed, 4 insertions(+), 7 deletions(-) + +diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c +index 0c5b94e64ea15..4edd2088c2db6 100644 +--- a/drivers/edac/altera_edac.c ++++ b/drivers/edac/altera_edac.c +@@ -1563,8 +1563,7 @@ static int altr_portb_setup(struct altr_edac_device_dev *device) + goto err_release_group_1; + } + rc = devm_request_irq(&altdev->ddev, altdev->sb_irq, +- prv->ecc_irq_handler, +- IRQF_ONESHOT | IRQF_TRIGGER_HIGH, ++ prv->ecc_irq_handler, IRQF_TRIGGER_HIGH, + ecc_name, altdev); + if (rc) { + edac_printk(KERN_ERR, EDAC_DEVICE, "PortB SBERR IRQ error\n"); +@@ -1587,8 +1586,7 @@ static int altr_portb_setup(struct altr_edac_device_dev *device) + goto err_release_group_1; + } + rc = devm_request_irq(&altdev->ddev, altdev->db_irq, +- prv->ecc_irq_handler, +- IRQF_ONESHOT | IRQF_TRIGGER_HIGH, ++ prv->ecc_irq_handler, IRQF_TRIGGER_HIGH, + ecc_name, altdev); + if (rc) { + edac_printk(KERN_ERR, EDAC_DEVICE, "PortB DBERR IRQ error\n"); +@@ -1970,8 +1968,7 @@ static int altr_edac_a10_device_add(struct altr_arria10_edac *edac, + goto err_release_group1; + } + rc = devm_request_irq(edac->dev, altdev->sb_irq, prv->ecc_irq_handler, +- IRQF_ONESHOT | IRQF_TRIGGER_HIGH, +- ecc_name, altdev); ++ IRQF_TRIGGER_HIGH, ecc_name, altdev); + if (rc) { + edac_printk(KERN_ERR, EDAC_DEVICE, "No SBERR IRQ resource\n"); + goto err_release_group1; +@@ -1993,7 +1990,7 @@ static int altr_edac_a10_device_add(struct altr_arria10_edac *edac, + goto err_release_group1; + } + rc = devm_request_irq(edac->dev, altdev->db_irq, prv->ecc_irq_handler, +- IRQF_ONESHOT | IRQF_TRIGGER_HIGH, ++ IRQF_TRIGGER_HIGH, + ecc_name, altdev); + if (rc) { + edac_printk(KERN_ERR, EDAC_DEVICE, "No DBERR IRQ resource\n"); +-- +2.51.0 + diff --git a/queue-6.19/edac-amd64-avoid-a-wformat-security-warning.patch b/queue-6.19/edac-amd64-avoid-a-wformat-security-warning.patch new file mode 100644 index 0000000000..fce2be9cf1 --- /dev/null +++ b/queue-6.19/edac-amd64-avoid-a-wformat-security-warning.patch @@ -0,0 +1,47 @@ +From da3ca8d595f5c4a3eac997402b3fd1225bc9b901 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Dec 2025 11:02:25 +0100 +Subject: EDAC/amd64: Avoid a -Wformat-security warning + +From: Arnd Bergmann + +[ Upstream commit c816ba1dcd931b9db8d66c71e1ae34ddcdbf968f ] + +Using a variable as a format string causes a (default-disabled) warning: + + drivers/edac/amd64_edac.c: In function 'per_family_init': + drivers/edac/amd64_edac.c:3914:17: error: format not a string literal and no format arguments [-Werror=format-security] + 3914 | scnprintf(pvt->ctl_name, sizeof(pvt->ctl_name), tmp_name); + | ^~~~~~~~~ + +The code here is safe, but in order to enable the warning by default in the +future, change this instance to pass the name indirectly. + +Fixes: e9abd990aefd ("EDAC/amd64: Generate ctl_name string at runtime") +Signed-off-by: Arnd Bergmann +Signed-off-by: Borislav Petkov (AMD) +Reviewed-by: Avadhut Naik +Reviewed-by: Qiuxu Zhuo +Reviewed-by: Yazen Ghannam +Link: https://patch.msgid.link/20251204100231.1034557-1-arnd@kernel.org +Signed-off-by: Sasha Levin +--- + drivers/edac/amd64_edac.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c +index 2391f3469961a..63fca0ee2c23b 100644 +--- a/drivers/edac/amd64_edac.c ++++ b/drivers/edac/amd64_edac.c +@@ -3911,7 +3911,7 @@ static int per_family_init(struct amd64_pvt *pvt) + } + + if (tmp_name) +- scnprintf(pvt->ctl_name, sizeof(pvt->ctl_name), tmp_name); ++ scnprintf(pvt->ctl_name, sizeof(pvt->ctl_name), "%s", tmp_name); + else + scnprintf(pvt->ctl_name, sizeof(pvt->ctl_name), "F%02Xh_M%02Xh", + pvt->fam, pvt->model); +-- +2.51.0 + diff --git a/queue-6.19/edac-i5000-fix-snprintf-size-calculation-in-calculat.patch b/queue-6.19/edac-i5000-fix-snprintf-size-calculation-in-calculat.patch new file mode 100644 index 0000000000..048ee3a3ca --- /dev/null +++ b/queue-6.19/edac-i5000-fix-snprintf-size-calculation-in-calculat.patch @@ -0,0 +1,40 @@ +From e825d6d672d0064ecdec05ba63a2e7acf1911242 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 17:36:59 +0300 +Subject: EDAC/i5000: Fix snprintf() size calculation in calculate_dimm_size() + +From: Dan Carpenter + +[ Upstream commit 7b5c7e83ac405ff9ecbdd92b37a477f4288f8814 ] + +The snprintf() can't really overflow because we're writing a max of 42 +bytes to a PAGE_SIZE buffer. But the limit calculation doesn't take +the first 11 bytes that we wrote into consideration so the limit is +not correct. Just fix it for correctness even though it doesn't +affect runtime. + +Fixes: 64e1fdaf55d6 ("i5000_edac: Fix the logic that retrieves memory information") +Signed-off-by: Dan Carpenter +Signed-off-by: Tony Luck +Reviewed-by: Qiuxu Zhuo +Link: https://patch.msgid.link/07cd652c51e77aad5a8350e1a7cd9407e5bbe373.1765290801.git.dan.carpenter@linaro.org +Signed-off-by: Sasha Levin +--- + drivers/edac/i5000_edac.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c +index 4a1bebc1ff14d..471b8540d18b0 100644 +--- a/drivers/edac/i5000_edac.c ++++ b/drivers/edac/i5000_edac.c +@@ -1111,6 +1111,7 @@ static void calculate_dimm_size(struct i5000_pvt *pvt) + + n = snprintf(p, space, " "); + p += n; ++ space -= n; + for (branch = 0; branch < MAX_BRANCHES; branch++) { + n = snprintf(p, space, " branch %d | ", branch); + p += n; +-- +2.51.0 + diff --git a/queue-6.19/edac-i5400-fix-snprintf-limit-calculation-in-calcula.patch b/queue-6.19/edac-i5400-fix-snprintf-limit-calculation-in-calcula.patch new file mode 100644 index 0000000000..75ea4c4026 --- /dev/null +++ b/queue-6.19/edac-i5400-fix-snprintf-limit-calculation-in-calcula.patch @@ -0,0 +1,49 @@ +From 81a843ec92c420b19ae80c0e77a7895b4b50e484 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 17:37:04 +0300 +Subject: EDAC/i5400: Fix snprintf() limit calculation in calculate_dimm_size() + +From: Dan Carpenter + +[ Upstream commit 72f12683611344853ab030fe7d19b23970ed2bd8 ] + +The snprintf() can't really overflow because we're writing a max of 42 +bytes to a PAGE_SIZE buffer. But my static checker complains because +the limit calculation doesn't take the first 11 space characters that +we wrote into the buffer into consideration. Fix this for the sake of +correctness even though it doesn't affect runtime. + +Also delete an earlier "space -= n;" which was not used. + +Fixes: 68d086f89b80 ("i5400_edac: improve debug messages to better represent the filled memory") +Signed-off-by: Dan Carpenter +Signed-off-by: Tony Luck +Reviewed-by: Qiuxu Zhuo +Link: https://patch.msgid.link/ccd06b91748e7ed8e33eeb2ff1e7b98700879304.1765290801.git.dan.carpenter@linaro.org +Signed-off-by: Sasha Levin +--- + drivers/edac/i5400_edac.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/edac/i5400_edac.c b/drivers/edac/i5400_edac.c +index b5cf25905b059..fb49a1d1df112 100644 +--- a/drivers/edac/i5400_edac.c ++++ b/drivers/edac/i5400_edac.c +@@ -1026,13 +1026,13 @@ static void calculate_dimm_size(struct i5400_pvt *pvt) + space -= n; + } + +- space -= n; + edac_dbg(2, "%s\n", mem_buffer); + p = mem_buffer; + space = PAGE_SIZE; + + n = snprintf(p, space, " "); + p += n; ++ space -= n; + for (branch = 0; branch < MAX_BRANCHES; branch++) { + n = snprintf(p, space, " branch %d | ", branch); + p += n; +-- +2.51.0 + diff --git a/queue-6.19/erofs-avoid-noisy-messages-for-transient-enomem.patch b/queue-6.19/erofs-avoid-noisy-messages-for-transient-enomem.patch new file mode 100644 index 0000000000..a5cb7718ff --- /dev/null +++ b/queue-6.19/erofs-avoid-noisy-messages-for-transient-enomem.patch @@ -0,0 +1,54 @@ +From 6b8ff75f0807c37e972545cc4e31e0549861abd8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Dec 2025 14:09:45 +0800 +Subject: erofs: avoid noisy messages for transient -ENOMEM + +From: Gao Xiang + +[ Upstream commit 9aa64b62a73cbca226c0144dcf3cdf97294e0641 ] + +EROFS may allocate temporary pages using GFP_NOWAIT | GFP_NORETRY +when pcl->besteffort is off (e.g., for readahead requests). + +If the allocation fails, the original request will fall back to +synchronous read, so the failure is transient. + +Such fallback can frequently happen in low memory scenarios, but since +these failures are expected and temporary, avoid printing error +messages like below: + +[ 7425.184264] erofs (device sr0): failed to decompress (lz4) -ENOMEM @ pa 148447232 size 28672 => 26788 +[ 7426.244267] erofs (device sr0): failed to decompress (lz4) -ENOMEM @ pa 149422080 size 28672 => 15903 +[ 7426.245508] erofs (device sr0): failed to decompress (lz4) -ENOMEM @ pa 138440704 size 28672 => 39294 +... +[ 7504.258373] erofs (device sr0): failed to decompress (lz4) -ENOMEM @ pa 93581312 size 20480 => 47366 + +Fixes: 831faabed812 ("erofs: improve decompression error reporting") +Reviewed-by: Chao Yu +Signed-off-by: Gao Xiang +Signed-off-by: Sasha Levin +--- + fs/erofs/zdata.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c +index 70e1597dec8a6..c62908f1ce478 100644 +--- a/fs/erofs/zdata.c ++++ b/fs/erofs/zdata.c +@@ -1324,9 +1324,10 @@ static int z_erofs_decompress_pcluster(struct z_erofs_backend *be, bool eio) + GFP_NOWAIT | __GFP_NORETRY + }, be->pagepool); + if (IS_ERR(reason)) { +- erofs_err(be->sb, "failed to decompress (%s) %pe @ pa %llu size %u => %u", +- alg->name, reason, pcl->pos, +- pcl->pclustersize, pcl->length); ++ if (pcl->besteffort || reason != ERR_PTR(-ENOMEM)) ++ erofs_err(be->sb, "failed to decompress (%s) %pe @ pa %llu size %u => %u", ++ alg->name, reason, pcl->pos, ++ pcl->pclustersize, pcl->length); + err = PTR_ERR(reason); + } else if (unlikely(reason)) { + erofs_err(be->sb, "failed to decompress (%s) %s @ pa %llu size %u => %u", +-- +2.51.0 + diff --git a/queue-6.19/erofs-fix-inline-data-read-failure-for-ztailpacking-.patch b/queue-6.19/erofs-fix-inline-data-read-failure-for-ztailpacking-.patch new file mode 100644 index 0000000000..9a1744b27e --- /dev/null +++ b/queue-6.19/erofs-fix-inline-data-read-failure-for-ztailpacking-.patch @@ -0,0 +1,128 @@ +From 695c3622299505f801ffa54187ccc678a6427329 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 16:25:36 +0800 +Subject: erofs: fix inline data read failure for ztailpacking pclusters + +From: Gao Xiang + +[ Upstream commit c134a40f86efb8d6b5a949ef70e06d5752209be5 ] + +Compressed folios for ztailpacking pclusters must be valid before adding +these pclusters to I/O chains. Otherwise, z_erofs_decompress_pcluster() +may assume they are already valid and then trigger a NULL pointer +dereference. + +It is somewhat hard to reproduce because the inline data is in the same +block as the tail of the compressed indexes, which are usually read just +before. However, it may still happen if a fatal signal arrives while +read_mapping_folio() is running, as shown below: + + erofs: (device dm-1): z_erofs_pcluster_begin: failed to get inline data -4 + Unable to handle kernel NULL pointer dereference at virtual address 0000000000000008 + + ... + + pc : z_erofs_decompress_queue+0x4c8/0xa14 + lr : z_erofs_decompress_queue+0x160/0xa14 + sp : ffffffc08b3eb3a0 + x29: ffffffc08b3eb570 x28: ffffffc08b3eb418 x27: 0000000000001000 + x26: ffffff8086ebdbb8 x25: ffffff8086ebdbb8 x24: 0000000000000001 + x23: 0000000000000008 x22: 00000000fffffffb x21: dead000000000700 + x20: 00000000000015e7 x19: ffffff808babb400 x18: ffffffc089edc098 + x17: 00000000c006287d x16: 00000000c006287d x15: 0000000000000004 + x14: ffffff80ba8f8000 x13: 0000000000000004 x12: 00000006589a77c9 + x11: 0000000000000015 x10: 0000000000000000 x9 : 0000000000000000 + x8 : 0000000000000000 x7 : 0000000000000000 x6 : 000000000000003f + x5 : 0000000000000040 x4 : ffffffffffffffe0 x3 : 0000000000000020 + x2 : 0000000000000008 x1 : 0000000000000000 x0 : 0000000000000000 + Call trace: + z_erofs_decompress_queue+0x4c8/0xa14 + z_erofs_runqueue+0x908/0x97c + z_erofs_read_folio+0x128/0x228 + filemap_read_folio+0x68/0x128 + filemap_get_pages+0x44c/0x8b4 + filemap_read+0x12c/0x5b8 + generic_file_read_iter+0x4c/0x15c + do_iter_readv_writev+0x188/0x1e0 + vfs_iter_read+0xac/0x1a4 + backing_file_read_iter+0x170/0x34c + ovl_read_iter+0xf0/0x140 + vfs_read+0x28c/0x344 + ksys_read+0x80/0xf0 + __arm64_sys_read+0x24/0x34 + invoke_syscall+0x60/0x114 + el0_svc_common+0x88/0xe4 + do_el0_svc+0x24/0x30 + el0_svc+0x40/0xa8 + el0t_64_sync_handler+0x70/0xbc + el0t_64_sync+0x1bc/0x1c0 + +Fix this by reading the inline data before allocating and adding +the pclusters to the I/O chains. + +Fixes: cecf864d3d76 ("erofs: support inline data decompression") +Reported-by: Zhiguo Niu +Reviewed-and-tested-by: Zhiguo Niu +Signed-off-by: Gao Xiang +Signed-off-by: Sasha Levin +--- + fs/erofs/zdata.c | 30 ++++++++++++++++-------------- + 1 file changed, 16 insertions(+), 14 deletions(-) + +diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c +index c62908f1ce478..b71fcf4be484a 100644 +--- a/fs/erofs/zdata.c ++++ b/fs/erofs/zdata.c +@@ -805,14 +805,26 @@ static int z_erofs_pcluster_begin(struct z_erofs_frontend *fe) + struct erofs_map_blocks *map = &fe->map; + struct super_block *sb = fe->inode->i_sb; + struct z_erofs_pcluster *pcl = NULL; +- void *ptr; ++ void *ptr = NULL; + int ret; + + DBG_BUGON(fe->pcl); + /* must be Z_EROFS_PCLUSTER_TAIL or pointed to previous pcluster */ + DBG_BUGON(!fe->head); + +- if (!(map->m_flags & EROFS_MAP_META)) { ++ if (map->m_flags & EROFS_MAP_META) { ++ ret = erofs_init_metabuf(&map->buf, sb, ++ erofs_inode_in_metabox(fe->inode)); ++ if (ret) ++ return ret; ++ ptr = erofs_bread(&map->buf, map->m_pa, false); ++ if (IS_ERR(ptr)) { ++ erofs_err(sb, "failed to read inline data %pe @ pa %llu of nid %llu", ++ ptr, map->m_pa, EROFS_I(fe->inode)->nid); ++ return PTR_ERR(ptr); ++ } ++ ptr = map->buf.page; ++ } else { + while (1) { + rcu_read_lock(); + pcl = xa_load(&EROFS_SB(sb)->managed_pslots, map->m_pa); +@@ -852,18 +864,8 @@ static int z_erofs_pcluster_begin(struct z_erofs_frontend *fe) + /* bind cache first when cached decompression is preferred */ + z_erofs_bind_cache(fe); + } else { +- ret = erofs_init_metabuf(&map->buf, sb, +- erofs_inode_in_metabox(fe->inode)); +- if (ret) +- return ret; +- ptr = erofs_bread(&map->buf, map->m_pa, false); +- if (IS_ERR(ptr)) { +- ret = PTR_ERR(ptr); +- erofs_err(sb, "failed to get inline folio %d", ret); +- return ret; +- } +- folio_get(page_folio(map->buf.page)); +- WRITE_ONCE(fe->pcl->compressed_bvecs[0].page, map->buf.page); ++ folio_get(page_folio((struct page *)ptr)); ++ WRITE_ONCE(fe->pcl->compressed_bvecs[0].page, ptr); + fe->pcl->pageofs_in = map->m_pa & ~PAGE_MASK; + fe->mode = Z_EROFS_PCLUSTER_FOLLOWED_NOINPLACE; + } +-- +2.51.0 + diff --git a/queue-6.19/erofs-handle-end-of-filesystem-properly-for-file-bac.patch b/queue-6.19/erofs-handle-end-of-filesystem-properly-for-file-bac.patch new file mode 100644 index 0000000000..c9deb158f7 --- /dev/null +++ b/queue-6.19/erofs-handle-end-of-filesystem-properly-for-file-bac.patch @@ -0,0 +1,64 @@ +From 8c0d37bc7be9b03f9008fc2f3eb92e7a3e8517bf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 15:54:22 +0800 +Subject: erofs: handle end of filesystem properly for file-backed mounts + +From: Gao Xiang + +[ Upstream commit bc804a8d7e865ef47fb7edcaf5e77d18bf444ebc ] + +I/O requests beyond the end of the filesystem should be zeroed out, +similar to loopback devices and that is what we expect. + +Fixes: ce63cb62d794 ("erofs: support unencoded inodes for fileio") +Signed-off-by: Gao Xiang +Signed-off-by: Sasha Levin +--- + fs/erofs/fileio.c | 20 ++++++++------------ + 1 file changed, 8 insertions(+), 12 deletions(-) + +diff --git a/fs/erofs/fileio.c b/fs/erofs/fileio.c +index 1673c5416fba1..2a778a02681a0 100644 +--- a/fs/erofs/fileio.c ++++ b/fs/erofs/fileio.c +@@ -25,21 +25,17 @@ static void erofs_fileio_ki_complete(struct kiocb *iocb, long ret) + container_of(iocb, struct erofs_fileio_rq, iocb); + struct folio_iter fi; + +- if (ret > 0) { +- if (ret != rq->bio.bi_iter.bi_size) { +- bio_advance(&rq->bio, ret); +- zero_fill_bio(&rq->bio); +- } +- ret = 0; ++ if (ret >= 0 && ret != rq->bio.bi_iter.bi_size) { ++ bio_advance(&rq->bio, ret); ++ zero_fill_bio(&rq->bio); + } +- if (rq->bio.bi_end_io) { +- if (ret < 0 && !rq->bio.bi_status) +- rq->bio.bi_status = errno_to_blk_status(ret); +- } else { ++ if (!rq->bio.bi_end_io) { + bio_for_each_folio_all(fi, &rq->bio) { + DBG_BUGON(folio_test_uptodate(fi.folio)); +- erofs_onlinefolio_end(fi.folio, ret, false); ++ erofs_onlinefolio_end(fi.folio, ret < 0, false); + } ++ } else if (ret < 0 && !rq->bio.bi_status) { ++ rq->bio.bi_status = errno_to_blk_status(ret); + } + bio_endio(&rq->bio); + bio_uninit(&rq->bio); +@@ -50,7 +46,7 @@ static void erofs_fileio_ki_complete(struct kiocb *iocb, long ret) + static void erofs_fileio_rq_submit(struct erofs_fileio_rq *rq) + { + struct iov_iter iter; +- int ret; ++ ssize_t ret; + + if (!rq) + return; +-- +2.51.0 + diff --git a/queue-6.19/erofs-use-pe-format-specifier-for-error-pointers.patch b/queue-6.19/erofs-use-pe-format-specifier-for-error-pointers.patch new file mode 100644 index 0000000000..756c2f0cbc --- /dev/null +++ b/queue-6.19/erofs-use-pe-format-specifier-for-error-pointers.patch @@ -0,0 +1,40 @@ +From 86702fcadb0575b0c265b31b3bdcb5a3ef117435 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Dec 2025 17:31:38 +0800 +Subject: erofs: Use %pe format specifier for error pointers + +From: Ferry Meng + +[ Upstream commit 19bfef0178c64a6281a44687380b082e69215e06 ] + +%pe will print a symbolic error name (e.g,. -ENOMEM), opposed to the +raw errno (e.g,. -12) produced by PTR_ERR(). + +Signed-off-by: Ferry Meng +Reviewed-by: Gao Xiang +Reviewed-by: Chao Yu +Signed-off-by: Gao Xiang +Stable-dep-of: 9aa64b62a73c ("erofs: avoid noisy messages for transient -ENOMEM") +Signed-off-by: Sasha Levin +--- + fs/erofs/zdata.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c +index 3d31f7840ca04..70e1597dec8a6 100644 +--- a/fs/erofs/zdata.c ++++ b/fs/erofs/zdata.c +@@ -1324,8 +1324,8 @@ static int z_erofs_decompress_pcluster(struct z_erofs_backend *be, bool eio) + GFP_NOWAIT | __GFP_NORETRY + }, be->pagepool); + if (IS_ERR(reason)) { +- erofs_err(be->sb, "failed to decompress (%s) %ld @ pa %llu size %u => %u", +- alg->name, PTR_ERR(reason), pcl->pos, ++ erofs_err(be->sb, "failed to decompress (%s) %pe @ pa %llu size %u => %u", ++ alg->name, reason, pcl->pos, + pcl->pclustersize, pcl->length); + err = PTR_ERR(reason); + } else if (unlikely(reason)) { +-- +2.51.0 + diff --git a/queue-6.19/evm-use-ordered-xattrs-list-to-calculate-hmac-in-evm.patch b/queue-6.19/evm-use-ordered-xattrs-list-to-calculate-hmac-in-evm.patch new file mode 100644 index 0000000000..562f05e2c9 --- /dev/null +++ b/queue-6.19/evm-use-ordered-xattrs-list-to-calculate-hmac-in-evm.patch @@ -0,0 +1,70 @@ +From c1ce80ef2531f9af27c24ab869640e8563777a1b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 15:53:41 +0100 +Subject: evm: Use ordered xattrs list to calculate HMAC in evm_init_hmac() + +From: Roberto Sassu + +[ Upstream commit 0496fc9cdc384f67be4413b1c6156eb64fccd5c4 ] + +Commit 8e5d9f916a96 ("smack: deduplicate xattr setting in +smack_inode_init_security()") introduced xattr_dupval() to simplify setting +the xattrs to be provided by the SMACK LSM on inode creation, in the +smack_inode_init_security(). + +Unfortunately, moving lsm_get_xattr_slot() caused the SMACK64TRANSMUTE +xattr be added in the array of new xattrs before SMACK64. This causes the +HMAC of xattrs calculated by evm_init_hmac() for new files to diverge from +the one calculated by both evm_calc_hmac_or_hash() and evmctl. + +evm_init_hmac() calculates the HMAC of the xattrs of new files based on the +order LSMs provide them, while evm_calc_hmac_or_hash() and evmctl calculate +the HMAC based on an ordered xattrs list. + +Fix the issue by making evm_init_hmac() calculate the HMAC of new files +based on the ordered xattrs list too. + +Fixes: 8e5d9f916a96 ("smack: deduplicate xattr setting in smack_inode_init_security()") +Signed-off-by: Roberto Sassu +Signed-off-by: Mimi Zohar +Signed-off-by: Sasha Levin +--- + security/integrity/evm/evm_crypto.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c +index a5e730ffda57f..5a8cef45bacf0 100644 +--- a/security/integrity/evm/evm_crypto.c ++++ b/security/integrity/evm/evm_crypto.c +@@ -401,6 +401,7 @@ int evm_init_hmac(struct inode *inode, const struct xattr *xattrs, + { + struct shash_desc *desc; + const struct xattr *xattr; ++ struct xattr_list *xattr_entry; + + desc = init_desc(EVM_XATTR_HMAC, HASH_ALGO_SHA1); + if (IS_ERR(desc)) { +@@ -408,11 +409,16 @@ int evm_init_hmac(struct inode *inode, const struct xattr *xattrs, + return PTR_ERR(desc); + } + +- for (xattr = xattrs; xattr->name; xattr++) { +- if (!evm_protected_xattr(xattr->name)) +- continue; ++ list_for_each_entry_lockless(xattr_entry, &evm_config_xattrnames, ++ list) { ++ for (xattr = xattrs; xattr->name; xattr++) { ++ if (strcmp(xattr_entry->name + ++ XATTR_SECURITY_PREFIX_LEN, xattr->name) != 0) ++ continue; + +- crypto_shash_update(desc, xattr->value, xattr->value_len); ++ crypto_shash_update(desc, xattr->value, ++ xattr->value_len); ++ } + } + + hmac_add_misc(desc, inode, EVM_XATTR_HMAC, hmac_val); +-- +2.51.0 + diff --git a/queue-6.19/ext4-fast-commit-make-s_fc_lock-reclaim-safe.patch b/queue-6.19/ext4-fast-commit-make-s_fc_lock-reclaim-safe.patch new file mode 100644 index 0000000000..35178c0ae2 --- /dev/null +++ b/queue-6.19/ext4-fast-commit-make-s_fc_lock-reclaim-safe.patch @@ -0,0 +1,301 @@ +From 1e730fefd46321e5e395f953cb8ae249ad48cf79 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Jan 2026 20:06:21 +0800 +Subject: ext4: fast commit: make s_fc_lock reclaim-safe + +From: Li Chen + +[ Upstream commit 491f2927ae097e2d405afe0b3fe841931ab8aad2 ] + +s_fc_lock can be acquired from inode eviction and thus is +reclaim unsafe. Since the fast commit path holds s_fc_lock while writing +the commit log, allocations under the lock can enter reclaim and invert +the lock order with fs_reclaim. Add ext4_fc_lock()/ext4_fc_unlock() +helpers which acquire s_fc_lock under memalloc_nofs_save()/restore() +context and use them everywhere so allocations under the lock cannot +recurse into filesystem reclaim. + +Fixes: 6593714d67ba ("ext4: hold s_fc_lock while during fast commit") +Signed-off-by: Li Chen +Reviewed-by: Baokun Li +Reviewed-by: Zhang Yi +Reviewed-by: Jan Kara +Link: https://patch.msgid.link/20260106120621.440126-1-me@linux.beauty +Signed-off-by: Theodore Ts'o +Signed-off-by: Sasha Levin +--- + fs/ext4/ext4.h | 16 ++++++++++++++ + fs/ext4/fast_commit.c | 51 ++++++++++++++++++++++++------------------- + 2 files changed, 44 insertions(+), 23 deletions(-) + +diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h +index 56112f201cace..1524276aeac79 100644 +--- a/fs/ext4/ext4.h ++++ b/fs/ext4/ext4.h +@@ -1795,6 +1795,10 @@ struct ext4_sb_info { + * Main fast commit lock. This lock protects accesses to the + * following fields: + * ei->i_fc_list, s_fc_dentry_q, s_fc_q, s_fc_bytes, s_fc_bh. ++ * ++ * s_fc_lock can be taken from reclaim context (inode eviction) and is ++ * thus reclaim unsafe. Use ext4_fc_lock()/ext4_fc_unlock() helpers ++ * when acquiring / releasing the lock. + */ + struct mutex s_fc_lock; + struct buffer_head *s_fc_bh; +@@ -1839,6 +1843,18 @@ static inline void ext4_writepages_up_write(struct super_block *sb, int ctx) + percpu_up_write(&EXT4_SB(sb)->s_writepages_rwsem); + } + ++static inline int ext4_fc_lock(struct super_block *sb) ++{ ++ mutex_lock(&EXT4_SB(sb)->s_fc_lock); ++ return memalloc_nofs_save(); ++} ++ ++static inline void ext4_fc_unlock(struct super_block *sb, int ctx) ++{ ++ memalloc_nofs_restore(ctx); ++ mutex_unlock(&EXT4_SB(sb)->s_fc_lock); ++} ++ + static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino) + { + return ino == EXT4_ROOT_INO || +diff --git a/fs/ext4/fast_commit.c b/fs/ext4/fast_commit.c +index fa66b08de9994..5bd57d7f921b9 100644 +--- a/fs/ext4/fast_commit.c ++++ b/fs/ext4/fast_commit.c +@@ -231,16 +231,16 @@ static bool ext4_fc_disabled(struct super_block *sb) + void ext4_fc_del(struct inode *inode) + { + struct ext4_inode_info *ei = EXT4_I(inode); +- struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); + struct ext4_fc_dentry_update *fc_dentry; + wait_queue_head_t *wq; ++ int alloc_ctx; + + if (ext4_fc_disabled(inode->i_sb)) + return; + +- mutex_lock(&sbi->s_fc_lock); ++ alloc_ctx = ext4_fc_lock(inode->i_sb); + if (list_empty(&ei->i_fc_list) && list_empty(&ei->i_fc_dilist)) { +- mutex_unlock(&sbi->s_fc_lock); ++ ext4_fc_unlock(inode->i_sb, alloc_ctx); + return; + } + +@@ -275,9 +275,9 @@ void ext4_fc_del(struct inode *inode) + #endif + prepare_to_wait(wq, &wait.wq_entry, TASK_UNINTERRUPTIBLE); + if (ext4_test_inode_state(inode, EXT4_STATE_FC_FLUSHING_DATA)) { +- mutex_unlock(&sbi->s_fc_lock); ++ ext4_fc_unlock(inode->i_sb, alloc_ctx); + schedule(); +- mutex_lock(&sbi->s_fc_lock); ++ alloc_ctx = ext4_fc_lock(inode->i_sb); + } + finish_wait(wq, &wait.wq_entry); + } +@@ -288,7 +288,7 @@ void ext4_fc_del(struct inode *inode) + * dentry create references, since it is not needed to log it anyways. + */ + if (list_empty(&ei->i_fc_dilist)) { +- mutex_unlock(&sbi->s_fc_lock); ++ ext4_fc_unlock(inode->i_sb, alloc_ctx); + return; + } + +@@ -298,7 +298,7 @@ void ext4_fc_del(struct inode *inode) + list_del_init(&fc_dentry->fcd_dilist); + + WARN_ON(!list_empty(&ei->i_fc_dilist)); +- mutex_unlock(&sbi->s_fc_lock); ++ ext4_fc_unlock(inode->i_sb, alloc_ctx); + + release_dentry_name_snapshot(&fc_dentry->fcd_name); + kmem_cache_free(ext4_fc_dentry_cachep, fc_dentry); +@@ -315,6 +315,7 @@ void ext4_fc_mark_ineligible(struct super_block *sb, int reason, handle_t *handl + tid_t tid; + bool has_transaction = true; + bool is_ineligible; ++ int alloc_ctx; + + if (ext4_fc_disabled(sb)) + return; +@@ -329,12 +330,12 @@ void ext4_fc_mark_ineligible(struct super_block *sb, int reason, handle_t *handl + has_transaction = false; + read_unlock(&sbi->s_journal->j_state_lock); + } +- mutex_lock(&sbi->s_fc_lock); ++ alloc_ctx = ext4_fc_lock(sb); + is_ineligible = ext4_test_mount_flag(sb, EXT4_MF_FC_INELIGIBLE); + if (has_transaction && (!is_ineligible || tid_gt(tid, sbi->s_fc_ineligible_tid))) + sbi->s_fc_ineligible_tid = tid; + ext4_set_mount_flag(sb, EXT4_MF_FC_INELIGIBLE); +- mutex_unlock(&sbi->s_fc_lock); ++ ext4_fc_unlock(sb, alloc_ctx); + WARN_ON(reason >= EXT4_FC_REASON_MAX); + sbi->s_fc_stats.fc_ineligible_reason_count[reason]++; + } +@@ -358,6 +359,7 @@ static int ext4_fc_track_template( + struct ext4_inode_info *ei = EXT4_I(inode); + struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); + tid_t tid = 0; ++ int alloc_ctx; + int ret; + + tid = handle->h_transaction->t_tid; +@@ -373,14 +375,14 @@ static int ext4_fc_track_template( + if (!enqueue) + return ret; + +- mutex_lock(&sbi->s_fc_lock); ++ alloc_ctx = ext4_fc_lock(inode->i_sb); + if (list_empty(&EXT4_I(inode)->i_fc_list)) + list_add_tail(&EXT4_I(inode)->i_fc_list, + (sbi->s_journal->j_flags & JBD2_FULL_COMMIT_ONGOING || + sbi->s_journal->j_flags & JBD2_FAST_COMMIT_ONGOING) ? + &sbi->s_fc_q[FC_Q_STAGING] : + &sbi->s_fc_q[FC_Q_MAIN]); +- mutex_unlock(&sbi->s_fc_lock); ++ ext4_fc_unlock(inode->i_sb, alloc_ctx); + + return ret; + } +@@ -402,6 +404,7 @@ static int __track_dentry_update(handle_t *handle, struct inode *inode, + struct inode *dir = dentry->d_parent->d_inode; + struct super_block *sb = inode->i_sb; + struct ext4_sb_info *sbi = EXT4_SB(sb); ++ int alloc_ctx; + + spin_unlock(&ei->i_fc_lock); + +@@ -425,7 +428,7 @@ static int __track_dentry_update(handle_t *handle, struct inode *inode, + take_dentry_name_snapshot(&node->fcd_name, dentry); + INIT_LIST_HEAD(&node->fcd_dilist); + INIT_LIST_HEAD(&node->fcd_list); +- mutex_lock(&sbi->s_fc_lock); ++ alloc_ctx = ext4_fc_lock(sb); + if (sbi->s_journal->j_flags & JBD2_FULL_COMMIT_ONGOING || + sbi->s_journal->j_flags & JBD2_FAST_COMMIT_ONGOING) + list_add_tail(&node->fcd_list, +@@ -446,7 +449,7 @@ static int __track_dentry_update(handle_t *handle, struct inode *inode, + WARN_ON(!list_empty(&ei->i_fc_dilist)); + list_add_tail(&node->fcd_dilist, &ei->i_fc_dilist); + } +- mutex_unlock(&sbi->s_fc_lock); ++ ext4_fc_unlock(sb, alloc_ctx); + spin_lock(&ei->i_fc_lock); + + return 0; +@@ -1046,18 +1049,19 @@ static int ext4_fc_perform_commit(journal_t *journal) + struct blk_plug plug; + int ret = 0; + u32 crc = 0; ++ int alloc_ctx; + + /* + * Step 1: Mark all inodes on s_fc_q[MAIN] with + * EXT4_STATE_FC_FLUSHING_DATA. This prevents these inodes from being + * freed until the data flush is over. + */ +- mutex_lock(&sbi->s_fc_lock); ++ alloc_ctx = ext4_fc_lock(sb); + list_for_each_entry(iter, &sbi->s_fc_q[FC_Q_MAIN], i_fc_list) { + ext4_set_inode_state(&iter->vfs_inode, + EXT4_STATE_FC_FLUSHING_DATA); + } +- mutex_unlock(&sbi->s_fc_lock); ++ ext4_fc_unlock(sb, alloc_ctx); + + /* Step 2: Flush data for all the eligible inodes. */ + ret = ext4_fc_flush_data(journal); +@@ -1067,7 +1071,7 @@ static int ext4_fc_perform_commit(journal_t *journal) + * any error from step 2. This ensures that waiters waiting on + * EXT4_STATE_FC_FLUSHING_DATA can resume. + */ +- mutex_lock(&sbi->s_fc_lock); ++ alloc_ctx = ext4_fc_lock(sb); + list_for_each_entry(iter, &sbi->s_fc_q[FC_Q_MAIN], i_fc_list) { + ext4_clear_inode_state(&iter->vfs_inode, + EXT4_STATE_FC_FLUSHING_DATA); +@@ -1084,7 +1088,7 @@ static int ext4_fc_perform_commit(journal_t *journal) + * prepare_to_wait() in ext4_fc_del(). + */ + smp_mb(); +- mutex_unlock(&sbi->s_fc_lock); ++ ext4_fc_unlock(sb, alloc_ctx); + + /* + * If we encountered error in Step 2, return it now after clearing +@@ -1101,12 +1105,12 @@ static int ext4_fc_perform_commit(journal_t *journal) + * previous handles are now drained. We now mark the inodes on the + * commit queue as being committed. + */ +- mutex_lock(&sbi->s_fc_lock); ++ alloc_ctx = ext4_fc_lock(sb); + list_for_each_entry(iter, &sbi->s_fc_q[FC_Q_MAIN], i_fc_list) { + ext4_set_inode_state(&iter->vfs_inode, + EXT4_STATE_FC_COMMITTING); + } +- mutex_unlock(&sbi->s_fc_lock); ++ ext4_fc_unlock(sb, alloc_ctx); + jbd2_journal_unlock_updates(journal); + + /* +@@ -1117,6 +1121,7 @@ static int ext4_fc_perform_commit(journal_t *journal) + blkdev_issue_flush(journal->j_fs_dev); + + blk_start_plug(&plug); ++ alloc_ctx = ext4_fc_lock(sb); + /* Step 6: Write fast commit blocks to disk. */ + if (sbi->s_fc_bytes == 0) { + /* +@@ -1134,7 +1139,6 @@ static int ext4_fc_perform_commit(journal_t *journal) + } + + /* Step 6.2: Now write all the dentry updates. */ +- mutex_lock(&sbi->s_fc_lock); + ret = ext4_fc_commit_dentry_updates(journal, &crc); + if (ret) + goto out; +@@ -1156,7 +1160,7 @@ static int ext4_fc_perform_commit(journal_t *journal) + ret = ext4_fc_write_tail(sb, crc); + + out: +- mutex_unlock(&sbi->s_fc_lock); ++ ext4_fc_unlock(sb, alloc_ctx); + blk_finish_plug(&plug); + return ret; + } +@@ -1290,6 +1294,7 @@ static void ext4_fc_cleanup(journal_t *journal, int full, tid_t tid) + struct ext4_sb_info *sbi = EXT4_SB(sb); + struct ext4_inode_info *ei; + struct ext4_fc_dentry_update *fc_dentry; ++ int alloc_ctx; + + if (full && sbi->s_fc_bh) + sbi->s_fc_bh = NULL; +@@ -1297,7 +1302,7 @@ static void ext4_fc_cleanup(journal_t *journal, int full, tid_t tid) + trace_ext4_fc_cleanup(journal, full, tid); + jbd2_fc_release_bufs(journal); + +- mutex_lock(&sbi->s_fc_lock); ++ alloc_ctx = ext4_fc_lock(sb); + while (!list_empty(&sbi->s_fc_q[FC_Q_MAIN])) { + ei = list_first_entry(&sbi->s_fc_q[FC_Q_MAIN], + struct ext4_inode_info, +@@ -1356,7 +1361,7 @@ static void ext4_fc_cleanup(journal_t *journal, int full, tid_t tid) + + if (full) + sbi->s_fc_bytes = 0; +- mutex_unlock(&sbi->s_fc_lock); ++ ext4_fc_unlock(sb, alloc_ctx); + trace_ext4_fc_stats(sb); + } + +-- +2.51.0 + diff --git a/queue-6.19/fat-avoid-parent-link-count-underflow-in-rmdir.patch b/queue-6.19/fat-avoid-parent-link-count-underflow-in-rmdir.patch new file mode 100644 index 0000000000..ca4f54fef9 --- /dev/null +++ b/queue-6.19/fat-avoid-parent-link-count-underflow-in-rmdir.patch @@ -0,0 +1,74 @@ +From 4cf89575d3950ec5b2abed4e48d03f48d3b8797c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 1 Jan 2026 19:11:48 +0800 +Subject: fat: avoid parent link count underflow in rmdir + +From: Zhiyu Zhang + +[ Upstream commit 8cafcb881364af5ef3a8b9fed4db254054033d8a ] + +Corrupted FAT images can leave a directory inode with an incorrect +i_nlink (e.g. 2 even though subdirectories exist). rmdir then +unconditionally calls drop_nlink(dir) and can drive i_nlink to 0, +triggering the WARN_ON in drop_nlink(). + +Add a sanity check in vfat_rmdir() and msdos_rmdir(): only drop the +parent link count when it is at least 3, otherwise report a filesystem +error. + +Link: https://lkml.kernel.org/r/20260101111148.1437-1-zhiyuzhang999@gmail.com +Fixes: 9a53c3a783c2 ("[PATCH] r/o bind mounts: unlink: monitor i_nlink") +Signed-off-by: Zhiyu Zhang +Reported-by: Zhiyu Zhang +Closes: https://lore.kernel.org/linux-fsdevel/aVN06OKsKxZe6-Kv@casper.infradead.org/T/#t +Tested-by: Zhiyu Zhang +Acked-by: OGAWA Hirofumi +Cc: Al Viro +Cc: Christian Brauner +Cc: Jan Kara +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/fat/namei_msdos.c | 7 ++++++- + fs/fat/namei_vfat.c | 7 ++++++- + 2 files changed, 12 insertions(+), 2 deletions(-) + +diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c +index 0b920ee40a7f9..262ec1b790b56 100644 +--- a/fs/fat/namei_msdos.c ++++ b/fs/fat/namei_msdos.c +@@ -325,7 +325,12 @@ static int msdos_rmdir(struct inode *dir, struct dentry *dentry) + err = fat_remove_entries(dir, &sinfo); /* and releases bh */ + if (err) + goto out; +- drop_nlink(dir); ++ if (dir->i_nlink >= 3) ++ drop_nlink(dir); ++ else { ++ fat_fs_error(sb, "parent dir link count too low (%u)", ++ dir->i_nlink); ++ } + + clear_nlink(inode); + fat_truncate_time(inode, NULL, S_CTIME); +diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c +index 5dbc4cbb8fce3..47ff083cfc7e6 100644 +--- a/fs/fat/namei_vfat.c ++++ b/fs/fat/namei_vfat.c +@@ -803,7 +803,12 @@ static int vfat_rmdir(struct inode *dir, struct dentry *dentry) + err = fat_remove_entries(dir, &sinfo); /* and releases bh */ + if (err) + goto out; +- drop_nlink(dir); ++ if (dir->i_nlink >= 3) ++ drop_nlink(dir); ++ else { ++ fat_fs_error(sb, "parent dir link count too low (%u)", ++ dir->i_nlink); ++ } + + clear_nlink(inode); + fat_truncate_time(inode, NULL, S_ATIME|S_MTIME); +-- +2.51.0 + diff --git a/queue-6.19/fbdev-au1200fb-fix-a-memory-leak-in-au1200fb_drv_pro.patch b/queue-6.19/fbdev-au1200fb-fix-a-memory-leak-in-au1200fb_drv_pro.patch new file mode 100644 index 0000000000..adb8579e3a --- /dev/null +++ b/queue-6.19/fbdev-au1200fb-fix-a-memory-leak-in-au1200fb_drv_pro.patch @@ -0,0 +1,43 @@ +From 00a83b8ef50baa23b16bd3b9a538b645163c5d6e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 20:14:58 +0800 +Subject: fbdev: au1200fb: Fix a memory leak in au1200fb_drv_probe() + +From: Felix Gu + +[ Upstream commit ce4e25198a6aaaaf36248edf8daf3d744ec8e309 ] + +In au1200fb_drv_probe(), when platform_get_irq fails(), it directly +returns from the function with an error code, which causes a memory +leak. + +Replace it with a goto label to ensure proper cleanup. + +Fixes: 4e88761f5f8c ("fbdev: au1200fb: Fix missing IRQ check in au1200fb_drv_probe") +Signed-off-by: Felix Gu +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/au1200fb.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/video/fbdev/au1200fb.c b/drivers/video/fbdev/au1200fb.c +index ed770222660b5..685e629e7e164 100644 +--- a/drivers/video/fbdev/au1200fb.c ++++ b/drivers/video/fbdev/au1200fb.c +@@ -1724,8 +1724,10 @@ static int au1200fb_drv_probe(struct platform_device *dev) + + /* Now hook interrupt too */ + irq = platform_get_irq(dev, 0); +- if (irq < 0) +- return irq; ++ if (irq < 0) { ++ ret = irq; ++ goto failed; ++ } + + ret = request_irq(irq, au1200fb_handle_irq, + IRQF_SHARED, "lcd", (void *)dev); +-- +2.51.0 + diff --git a/queue-6.19/fbdev-of_display_timing-fix-device-node-reference-le.patch b/queue-6.19/fbdev-of_display_timing-fix-device-node-reference-le.patch new file mode 100644 index 0000000000..68f7192528 --- /dev/null +++ b/queue-6.19/fbdev-of_display_timing-fix-device-node-reference-le.patch @@ -0,0 +1,56 @@ +From 7a0885dcbdc422e5af1991f6179d332d9bf7cd83 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Jan 2026 20:48:33 +0800 +Subject: fbdev: of_display_timing: Fix device node reference leak in + of_get_display_timings() + +From: Felix Gu + +[ Upstream commit c39ee2d264f98efa14aa46c9942114cb03c7baa6 ] + +Use for_each_child_of_node_scoped instead of for_each_child_of_node +to ensure automatic of_node_put on early exit paths, preventing +device node reference leak. + +Fixes: cc3f414cf2e4 ("video: add of helper for display timings/videomode") +Signed-off-by: Felix Gu +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/of_display_timing.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/video/of_display_timing.c b/drivers/video/of_display_timing.c +index bebd371c6b93e..a4cd446ac5a59 100644 +--- a/drivers/video/of_display_timing.c ++++ b/drivers/video/of_display_timing.c +@@ -195,7 +195,7 @@ struct display_timings *of_get_display_timings(const struct device_node *np) + disp->num_timings = 0; + disp->native_mode = 0; + +- for_each_child_of_node(timings_np, entry) { ++ for_each_child_of_node_scoped(timings_np, child) { + struct display_timing *dt; + int r; + +@@ -206,7 +206,7 @@ struct display_timings *of_get_display_timings(const struct device_node *np) + goto timingfail; + } + +- r = of_parse_display_timing(entry, dt); ++ r = of_parse_display_timing(child, dt); + if (r) { + /* + * to not encourage wrong devicetrees, fail in case of +@@ -218,7 +218,7 @@ struct display_timings *of_get_display_timings(const struct device_node *np) + goto timingfail; + } + +- if (native_mode == entry) ++ if (native_mode == child) + disp->native_mode = disp->num_timings; + + disp->timings[disp->num_timings] = dt; +-- +2.51.0 + diff --git a/queue-6.19/firmware-arm_ffa-correct-32-bit-response-handling-in.patch b/queue-6.19/firmware-arm_ffa-correct-32-bit-response-handling-in.patch new file mode 100644 index 0000000000..cf536829b4 --- /dev/null +++ b/queue-6.19/firmware-arm_ffa-correct-32-bit-response-handling-in.patch @@ -0,0 +1,119 @@ +From bc10f0da08dc6db06989e49a1906a23c1bad6319 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 14:20:01 +0000 +Subject: firmware: arm_ffa: Correct 32-bit response handling in + NOTIFICATION_INFO_GET + +From: Sudeep Holla + +[ Upstream commit be4d4543f78074fbebd530ba5109d39a2a34e668 ] + +The FF-A specification allows NOTIFICATION_INFO_GET to return either a +64-bit (FFA_FN64_SUCCESS) or a 32-bit (FFA_SUCCESS) response, depending on +whether the firmware chooses the SMC64 or SMC32 calling convention. + +The driver previously detected the response format by checking ret.a0, but +still interpreted the returned ID lists (x3..x17 or w3..w7) as if they always +followed the 64-bit SMC64 layout. In the SMC32 case, the upper 32 bits of +each argument register are undefined by the calling convention, meaning the +driver could read stale or garbage values when parsing notification IDs. + +This resulted in incorrectly decoded partition/VCPU IDs whenever the FF-A +firmware used an SMC32 return path. + +Fix the issue by: + +- Introducing logic to map list indices to the correct u16 offsets, + depending on whether the response width matches the kernel word size + or is a 32-bit response on a 64-bit kernel. +- Ensuring that the packed ID list is parsed using the proper layout, + avoiding reads from undefined upper halves in the SMC32 case. + +With this change, NOTIFICATION_INFO_GET now correctly interprets ID list +entries regardless of the response width, aligning the driver with the FF-A +specification. + +Fixes: 3522be48d82b ("firmware: arm_ffa: Implement the NOTIFICATION_INFO_GET interface") +Reported-by: Sourav Mohapatra +Message-Id: <20251218142001.2457111-1-sudeep.holla@arm.com> +Signed-off-by: Sudeep Holla +Signed-off-by: Sasha Levin +--- + drivers/firmware/arm_ffa/driver.c | 33 +++++++++++++++++++++++++++---- + 1 file changed, 29 insertions(+), 4 deletions(-) + +diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c +index c72ee47565856..c501c3104b3a4 100644 +--- a/drivers/firmware/arm_ffa/driver.c ++++ b/drivers/firmware/arm_ffa/driver.c +@@ -981,10 +981,27 @@ static void __do_sched_recv_cb(u16 part_id, u16 vcpu, bool is_per_vcpu) + } + } + ++/* ++ * Map logical ID index to the u16 index within the packed ID list. ++ * ++ * For native responses (FF-A width == kernel word size), IDs are ++ * tightly packed: idx -> idx. ++ * ++ * For 32-bit responses on a 64-bit kernel, each 64-bit register ++ * contributes 4 x u16 values but only the lower 2 are defined; the ++ * upper 2 are garbage. This mapping skips those upper halves: ++ * 0,1,2,3,4,5,... -> 0,1,4,5,8,9,... ++ */ ++static int list_idx_to_u16_idx(int idx, bool is_native_resp) ++{ ++ return is_native_resp ? idx : idx + 2 * (idx >> 1); ++} ++ + static void ffa_notification_info_get(void) + { +- int idx, list, max_ids, lists_cnt, ids_processed, ids_count[MAX_IDS_64]; +- bool is_64b_resp; ++ int ids_processed, ids_count[MAX_IDS_64]; ++ int idx, list, max_ids, lists_cnt; ++ bool is_64b_resp, is_native_resp; + ffa_value_t ret; + u64 id_list; + +@@ -1001,6 +1018,7 @@ static void ffa_notification_info_get(void) + } + + is_64b_resp = (ret.a0 == FFA_FN64_SUCCESS); ++ is_native_resp = (ret.a0 == FFA_FN_NATIVE(SUCCESS)); + + ids_processed = 0; + lists_cnt = FIELD_GET(NOTIFICATION_INFO_GET_ID_COUNT, ret.a2); +@@ -1017,12 +1035,16 @@ static void ffa_notification_info_get(void) + + /* Process IDs */ + for (list = 0; list < lists_cnt; list++) { ++ int u16_idx; + u16 vcpu_id, part_id, *packed_id_list = (u16 *)&ret.a3; + + if (ids_processed >= max_ids - 1) + break; + +- part_id = packed_id_list[ids_processed++]; ++ u16_idx = list_idx_to_u16_idx(ids_processed, ++ is_native_resp); ++ part_id = packed_id_list[u16_idx]; ++ ids_processed++; + + if (ids_count[list] == 1) { /* Global Notification */ + __do_sched_recv_cb(part_id, 0, false); +@@ -1034,7 +1056,10 @@ static void ffa_notification_info_get(void) + if (ids_processed >= max_ids - 1) + break; + +- vcpu_id = packed_id_list[ids_processed++]; ++ u16_idx = list_idx_to_u16_idx(ids_processed, ++ is_native_resp); ++ vcpu_id = packed_id_list[u16_idx]; ++ ids_processed++; + + __do_sched_recv_cb(part_id, vcpu_id, true); + } +-- +2.51.0 + diff --git a/queue-6.19/firmware-cs_dsp-don-t-use-__free-in-cs_dsp_load-and-.patch b/queue-6.19/firmware-cs_dsp-don-t-use-__free-in-cs_dsp_load-and-.patch new file mode 100644 index 0000000000..003151f835 --- /dev/null +++ b/queue-6.19/firmware-cs_dsp-don-t-use-__free-in-cs_dsp_load-and-.patch @@ -0,0 +1,74 @@ +From 5dafde6a547d1f24a3c4d5101d55f00aca1e600e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Dec 2025 16:07:29 +0000 +Subject: firmware: cs_dsp: Don't use __free() in cs_dsp_load() and + cs_dsp_load_coeff() + +From: Richard Fitzgerald + +[ Upstream commit ae9ccaed3f6701ee0fe40ad919516e0aa0844f21 ] + +Replace the __free(kfree) in cs_dsp_load() and cs_dsp_load_coeff() with +a kfree(buf) at the end of the function. + +The use of __free() can create new cleanup bugs that are difficult to spot +because the defective code is idiomatically correct regular C. In these two +functions the __free() was mixed with gotos, and also used the suspect +declaration __free(kfree) = NULL;. + +The __free() did not do anything to simplify the code. There aren't any +early returns after the pointer is set, and the __free() can be replaced by +a kfree() at the end of the function. + +Signed-off-by: Richard Fitzgerald +Fixes: 900baa6e7bb0 ("firmware: cs_dsp: Remove redundant download buffer allocator") +Link: https://patch.msgid.link/20251201160729.231867-1-rf@opensource.cirrus.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/firmware/cirrus/cs_dsp.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/drivers/firmware/cirrus/cs_dsp.c b/drivers/firmware/cirrus/cs_dsp.c +index 57296f48dad0a..abed96fa5853a 100644 +--- a/drivers/firmware/cirrus/cs_dsp.c ++++ b/drivers/firmware/cirrus/cs_dsp.c +@@ -1488,7 +1488,7 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware, + const struct wmfw_region *region; + const struct cs_dsp_region *mem; + const char *region_name; +- u8 *buf __free(kfree) = NULL; ++ u8 *buf = NULL; + size_t buf_len = 0; + size_t region_len; + unsigned int reg; +@@ -1643,6 +1643,8 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware, + + ret = 0; + out_fw: ++ kfree(buf); ++ + if (ret == -EOVERFLOW) + cs_dsp_err(dsp, "%s: file content overflows file data\n", file); + +@@ -2174,7 +2176,7 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware + struct cs_dsp_alg_region *alg_region; + const char *region_name; + int ret, pos, blocks, type, offset, reg, version; +- u8 *buf __free(kfree) = NULL; ++ u8 *buf = NULL; + size_t buf_len = 0; + size_t region_len; + +@@ -2353,6 +2355,8 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware + + ret = 0; + out_fw: ++ kfree(buf); ++ + if (ret == -EOVERFLOW) + cs_dsp_err(dsp, "%s: file content overflows file data\n", file); + +-- +2.51.0 + diff --git a/queue-6.19/firmware-cs_dsp-remove-__free-from-cs_dsp_debugfs_st.patch b/queue-6.19/firmware-cs_dsp-remove-__free-from-cs_dsp_debugfs_st.patch new file mode 100644 index 0000000000..fa014ba3c5 --- /dev/null +++ b/queue-6.19/firmware-cs_dsp-remove-__free-from-cs_dsp_debugfs_st.patch @@ -0,0 +1,68 @@ +From 4f64d70d3e7c2179dda2a771981b8ce721ae45ea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Dec 2025 11:34:25 +0000 +Subject: firmware: cs_dsp: Remove __free() from cs_dsp_debugfs_string_read() + +From: Richard Fitzgerald + +[ Upstream commit 7a9fa7fda93b7b3ae515f40f67bbf8e1d16337e8 ] + +Don't use __free(kfree) in cs_dsp_debugfs_string_read. Instead use +normal kfree() to cleanup. + +The use of __free() can create new cleanup bugs that are difficult to spot +because the defective code is idiomatically correct regular C. This +function used the suspect declaration __free(kfree) = NULL;. + +The __free(kfree) didn't really do anything here. The function can be +rearranged to avoid any need to return or goto within the code. + +Signed-off-by: Richard Fitzgerald +Fixes: 3045e29d248b ("firmware: cs_dsp: Append \n to debugfs string during read") +Link: https://patch.msgid.link/20251202113425.413700-1-rf@opensource.cirrus.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/firmware/cirrus/cs_dsp.c | 23 ++++++++++++++--------- + 1 file changed, 14 insertions(+), 9 deletions(-) + +diff --git a/drivers/firmware/cirrus/cs_dsp.c b/drivers/firmware/cirrus/cs_dsp.c +index 73d201e7d9927..57296f48dad0a 100644 +--- a/drivers/firmware/cirrus/cs_dsp.c ++++ b/drivers/firmware/cirrus/cs_dsp.c +@@ -412,18 +412,23 @@ static ssize_t cs_dsp_debugfs_string_read(struct cs_dsp *dsp, + size_t count, loff_t *ppos, + const char **pstr) + { +- const char *str __free(kfree) = NULL; ++ const char *str; ++ ssize_t ret = 0; + + scoped_guard(mutex, &dsp->pwr_lock) { +- if (!*pstr) +- return 0; +- +- str = kasprintf(GFP_KERNEL, "%s\n", *pstr); +- if (!str) +- return -ENOMEM; +- +- return simple_read_from_buffer(user_buf, count, ppos, str, strlen(str)); ++ if (*pstr) { ++ str = kasprintf(GFP_KERNEL, "%s\n", *pstr); ++ if (str) { ++ ret = simple_read_from_buffer(user_buf, count, ++ ppos, str, strlen(str)); ++ kfree(str); ++ } else { ++ ret = -ENOMEM; ++ } ++ } + } ++ ++ return ret; + } + + static ssize_t cs_dsp_debugfs_wmfw_read(struct file *file, +-- +2.51.0 + diff --git a/queue-6.19/fs-add-linux-init_task.h-for-init_fs.patch b/queue-6.19/fs-add-linux-init_task.h-for-init_fs.patch new file mode 100644 index 0000000000..a342c002d4 --- /dev/null +++ b/queue-6.19/fs-add-linux-init_task.h-for-init_fs.patch @@ -0,0 +1,40 @@ +From d34d710654ebeb757a2804ae626c45435271bd1f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 11:58:56 +0000 +Subject: fs: add for 'init_fs' + +From: Ben Dooks + +[ Upstream commit 589cff4975afe1a4eaaa1d961652f50b1628d78d ] + +The init_fs symbol is defined in but was +not included in fs/fs_struct.c so fix by adding the include. + +Fixes the following sparse warning: +fs/fs_struct.c:150:18: warning: symbol 'init_fs' was not declared. Should it be static? + +Fixes: 3e93cd671813e ("Take fs_struct handling to new file") +Signed-off-by: Ben Dooks +Link: https://patch.msgid.link/20260108115856.238027-1-ben.dooks@codethink.co.uk +Reviewed-by: Jan Kara +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/fs_struct.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/fs_struct.c b/fs/fs_struct.c +index b8c46c5a38a05..394875d06fd60 100644 +--- a/fs/fs_struct.c ++++ b/fs/fs_struct.c +@@ -6,6 +6,7 @@ + #include + #include + #include ++#include + #include "internal.h" + + /* +-- +2.51.0 + diff --git a/queue-6.19/fs-move-initializing-f_mode-before-file_ref_init.patch b/queue-6.19/fs-move-initializing-f_mode-before-file_ref_init.patch new file mode 100644 index 0000000000..0f338d337a --- /dev/null +++ b/queue-6.19/fs-move-initializing-f_mode-before-file_ref_init.patch @@ -0,0 +1,56 @@ +From 4fa41e2d2d31dfa890a56790f1a881ed3f44fba2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 22:15:36 +0100 +Subject: fs: move initializing f_mode before file_ref_init() + +From: Amir Goldstein + +[ Upstream commit 1219e0feaefc9697f738b223540e8e8906291cb3 ] + +The comment above file_ref_init() says: +"We're SLAB_TYPESAFE_BY_RCU so initialize f_ref last." +but file_set_fsnotify_mode() was added after file_ref_init(). + +Move it right after setting f_mode, where it makes more sense. + +Fixes: 711f9b8fbe4f4 ("fsnotify: disable pre-content and permission events by default") +Signed-off-by: Amir Goldstein +Link: https://patch.msgid.link/20260109211536.3565697-1-amir73il@gmail.com +Reviewed-by: Jan Kara +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/file_table.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/fs/file_table.c b/fs/file_table.c +index cd4a3db4659ac..34244fccf2edf 100644 +--- a/fs/file_table.c ++++ b/fs/file_table.c +@@ -176,6 +176,11 @@ static int init_file(struct file *f, int flags, const struct cred *cred) + + f->f_flags = flags; + f->f_mode = OPEN_FMODE(flags); ++ /* ++ * Disable permission and pre-content events for all files by default. ++ * They may be enabled later by fsnotify_open_perm_and_set_mode(). ++ */ ++ file_set_fsnotify_mode(f, FMODE_NONOTIFY_PERM); + + f->f_op = NULL; + f->f_mapping = NULL; +@@ -197,11 +202,6 @@ static int init_file(struct file *f, int flags, const struct cred *cred) + * refcount bumps we should reinitialize the reused file first. + */ + file_ref_init(&f->f_ref, 1); +- /* +- * Disable permission and pre-content events for all files by default. +- * They may be enabled later by fsnotify_open_perm_and_set_mode(). +- */ +- file_set_fsnotify_mode(f, FMODE_NONOTIFY_PERM); + return 0; + } + +-- +2.51.0 + diff --git a/queue-6.19/fs-nfs-fix-readdir-slow-start-regression.patch b/queue-6.19/fs-nfs-fix-readdir-slow-start-regression.patch new file mode 100644 index 0000000000..8caeb0f337 --- /dev/null +++ b/queue-6.19/fs-nfs-fix-readdir-slow-start-regression.patch @@ -0,0 +1,54 @@ +From 3fdc787913d740a6768a072ae3bc17b0e6cd859e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 27 Dec 2025 12:46:29 +0200 +Subject: fs/nfs: Fix readdir slow-start regression + +From: Sagi Grimberg + +[ Upstream commit 42e7c876b182da65723700f6bc507a8aecb10d3b ] + +Commit 580f236737d1 ("NFS: Adjust the amount of readahead +performed by NFS readdir") reduces the amount of readahead names +caching done by the client. + +The downside of this approach is READDIR now may suffer from +a slow-start issue, where initially it will fetch names that fit +in a single page, then in 2, 4, 8 until the maximum supported +transfer size (usually 1M). + +This patch tries to take a balanced approach between mitigating +the slow-start issue still maintaining some efficiency gains. + +Fixes: 580f236737d1 ("NFS: Adjust the amount of readahead performed by NFS readdir") +Signed-off-by: Sagi Grimberg +Signed-off-by: Anna Schumaker +Signed-off-by: Sasha Levin +--- + fs/nfs/dir.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c +index e3654f4a1b9aa..571bb40880b2d 100644 +--- a/fs/nfs/dir.c ++++ b/fs/nfs/dir.c +@@ -73,7 +73,7 @@ const struct address_space_operations nfs_dir_aops = { + .free_folio = nfs_readdir_clear_array, + }; + +-#define NFS_INIT_DTSIZE PAGE_SIZE ++#define NFS_INIT_DTSIZE SZ_64K + + static struct nfs_open_dir_context * + alloc_nfs_open_dir_context(struct inode *dir) +@@ -84,7 +84,7 @@ alloc_nfs_open_dir_context(struct inode *dir) + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL_ACCOUNT); + if (ctx != NULL) { + ctx->attr_gencount = nfsi->attr_gencount; +- ctx->dtsize = NFS_INIT_DTSIZE; ++ ctx->dtsize = min(NFS_SERVER(dir)->dtsize, NFS_INIT_DTSIZE); + spin_lock(&dir->i_lock); + if (list_empty(&nfsi->open_files) && + (nfsi->cache_validity & NFS_INO_DATA_INVAL_DEFER)) +-- +2.51.0 + diff --git a/queue-6.19/fs-tests-exec-drop-duplicate-bprm_stack_limits-test-.patch b/queue-6.19/fs-tests-exec-drop-duplicate-bprm_stack_limits-test-.patch new file mode 100644 index 0000000000..948e7405e3 --- /dev/null +++ b/queue-6.19/fs-tests-exec-drop-duplicate-bprm_stack_limits-test-.patch @@ -0,0 +1,48 @@ +From bc7e330f6d76cf2021f254e8a194f95110a760ee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 18:59:50 +0100 +Subject: fs/tests: exec: drop duplicate bprm_stack_limits test vectors + +From: Titouan Ameline de Cadeville + +[ Upstream commit 46a03ea50b5f380bdb99178b8f90b39c6ba1f528 ] + +Remove duplicate entries from the bprm_stack_limits KUnit test vector +table. The duplicates do not add coverage and only increase test size. + +Signed-off-by: Titouan Ameline de Cadeville +Fixes: 60371f43e56b ("exec: Add KUnit test for bprm_stack_limits()") +Link: https://patch.msgid.link/20260203175950.43710-1-titouan.ameline@gmail.com +Signed-off-by: Kees Cook +Signed-off-by: Sasha Levin +--- + fs/tests/exec_kunit.c | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/fs/tests/exec_kunit.c b/fs/tests/exec_kunit.c +index 7c77d039680bb..f412d1a0f6bba 100644 +--- a/fs/tests/exec_kunit.c ++++ b/fs/tests/exec_kunit.c +@@ -87,9 +87,6 @@ static const struct bprm_stack_limits_result bprm_stack_limits_results[] = { + .argc = 0, .envc = ARG_MAX / sizeof(void *) - 1 }, + .expected_argmin = ULONG_MAX - sizeof(void *) }, + /* Raising rlim_stack / 4 to _STK_LIM / 4 * 3 will see more space. */ +- { { .p = ULONG_MAX, .rlim_stack.rlim_cur = 4 * (_STK_LIM / 4 * 3), +- .argc = 0, .envc = 0 }, +- .expected_argmin = ULONG_MAX - (_STK_LIM / 4 * 3) + sizeof(void *) }, + { { .p = ULONG_MAX, .rlim_stack.rlim_cur = 4 * (_STK_LIM / 4 * 3), + .argc = 0, .envc = 0 }, + .expected_argmin = ULONG_MAX - (_STK_LIM / 4 * 3) + sizeof(void *) }, +@@ -103,9 +100,6 @@ static const struct bprm_stack_limits_result bprm_stack_limits_results[] = { + { { .p = ULONG_MAX, .rlim_stack.rlim_cur = 4 * _STK_LIM, + .argc = 0, .envc = 0 }, + .expected_argmin = ULONG_MAX - (_STK_LIM / 4 * 3) + sizeof(void *) }, +- { { .p = ULONG_MAX, .rlim_stack.rlim_cur = 4 * _STK_LIM, +- .argc = 0, .envc = 0 }, +- .expected_argmin = ULONG_MAX - (_STK_LIM / 4 * 3) + sizeof(void *) }, + }; + + static void exec_test_bprm_stack_limits(struct kunit *test) +-- +2.51.0 + diff --git a/queue-6.19/ftrace-bpf-remove-ftrace_ops_fl_jmp-ftrace_ops-flag.patch b/queue-6.19/ftrace-bpf-remove-ftrace_ops_fl_jmp-ftrace_ops-flag.patch new file mode 100644 index 0000000000..b940af9b6a --- /dev/null +++ b/queue-6.19/ftrace-bpf-remove-ftrace_ops_fl_jmp-ftrace_ops-flag.patch @@ -0,0 +1,175 @@ +From 8306d0aebaa88523d252c7cbc4b5d39c96c24a27 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Dec 2025 15:50:02 +0100 +Subject: ftrace,bpf: Remove FTRACE_OPS_FL_JMP ftrace_ops flag +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jiri Olsa + +[ Upstream commit 4be42c92220128b3128854a2d6b0f0ad0bcedbdb ] + +At the moment the we allow the jmp attach only for ftrace_ops that +has FTRACE_OPS_FL_JMP set. This conflicts with following changes +where we use single ftrace_ops object for all direct call sites, +so all could be be attached via just call or jmp. + +We already limit the jmp attach support with config option and bit +(LSB) set on the trampoline address. It turns out that's actually +enough to limit the jmp attach for architecture and only for chosen +addresses (with LSB bit set). + +Each user of register_ftrace_direct or modify_ftrace_direct can set +the trampoline bit (LSB) to indicate it has to be attached by jmp. + +The bpf trampoline generation code uses trampoline flags to generate +jmp-attach specific code and ftrace inner code uses the trampoline +bit (LSB) to handle return from jmp attachment, so there's no harm +to remove the FTRACE_OPS_FL_JMP bit. + +The fexit/fmodret performance stays the same (did not drop), +current code: + + fentry : 77.904 ± 0.546M/s + fexit : 62.430 ± 0.554M/s + fmodret : 66.503 ± 0.902M/s + +with this change: + + fentry : 80.472 ± 0.061M/s + fexit : 63.995 ± 0.127M/s + fmodret : 67.362 ± 0.175M/s + +Fixes: 25e4e3565d45 ("ftrace: Introduce FTRACE_OPS_FL_JMP") +Signed-off-by: Jiri Olsa +Signed-off-by: Andrii Nakryiko +Acked-by: Andrii Nakryiko +Reviewed-by: Steven Rostedt (Google) +Link: https://lore.kernel.org/bpf/20251230145010.103439-2-jolsa@kernel.org +Signed-off-by: Sasha Levin +--- + include/linux/ftrace.h | 1 - + kernel/bpf/trampoline.c | 32 ++++++++++++++------------------ + kernel/trace/ftrace.c | 14 -------------- + 3 files changed, 14 insertions(+), 33 deletions(-) + +diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h +index a3a8989e3268d..cc869c59c1a68 100644 +--- a/include/linux/ftrace.h ++++ b/include/linux/ftrace.h +@@ -359,7 +359,6 @@ enum { + FTRACE_OPS_FL_DIRECT = BIT(17), + FTRACE_OPS_FL_SUBOP = BIT(18), + FTRACE_OPS_FL_GRAPH = BIT(19), +- FTRACE_OPS_FL_JMP = BIT(20), + }; + + #ifndef CONFIG_DYNAMIC_FTRACE_WITH_ARGS +diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c +index 976d89011b157..b9a358d7a78f1 100644 +--- a/kernel/bpf/trampoline.c ++++ b/kernel/bpf/trampoline.c +@@ -214,10 +214,15 @@ static int modify_fentry(struct bpf_trampoline *tr, u32 orig_flags, + int ret; + + if (tr->func.ftrace_managed) { ++ unsigned long addr = (unsigned long) new_addr; ++ ++ if (bpf_trampoline_use_jmp(tr->flags)) ++ addr = ftrace_jmp_set(addr); ++ + if (lock_direct_mutex) +- ret = modify_ftrace_direct(tr->fops, (long)new_addr); ++ ret = modify_ftrace_direct(tr->fops, addr); + else +- ret = modify_ftrace_direct_nolock(tr->fops, (long)new_addr); ++ ret = modify_ftrace_direct_nolock(tr->fops, addr); + } else { + ret = bpf_trampoline_update_fentry(tr, orig_flags, old_addr, + new_addr); +@@ -240,10 +245,15 @@ static int register_fentry(struct bpf_trampoline *tr, void *new_addr) + } + + if (tr->func.ftrace_managed) { ++ unsigned long addr = (unsigned long) new_addr; ++ ++ if (bpf_trampoline_use_jmp(tr->flags)) ++ addr = ftrace_jmp_set(addr); ++ + ret = ftrace_set_filter_ip(tr->fops, (unsigned long)ip, 0, 1); + if (ret) + return ret; +- ret = register_ftrace_direct(tr->fops, (long)new_addr); ++ ret = register_ftrace_direct(tr->fops, addr); + } else { + ret = bpf_trampoline_update_fentry(tr, 0, NULL, new_addr); + } +@@ -499,13 +509,6 @@ static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mut + if (err) + goto out_free; + +-#ifdef CONFIG_DYNAMIC_FTRACE_WITH_JMP +- if (bpf_trampoline_use_jmp(tr->flags)) +- tr->fops->flags |= FTRACE_OPS_FL_JMP; +- else +- tr->fops->flags &= ~FTRACE_OPS_FL_JMP; +-#endif +- + WARN_ON(tr->cur_image && total == 0); + if (tr->cur_image) + /* progs already running at this address */ +@@ -533,15 +536,8 @@ static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mut + tr->cur_image = im; + out: + /* If any error happens, restore previous flags */ +- if (err) { ++ if (err) + tr->flags = orig_flags; +-#ifdef CONFIG_DYNAMIC_FTRACE_WITH_JMP +- if (bpf_trampoline_use_jmp(tr->flags)) +- tr->fops->flags |= FTRACE_OPS_FL_JMP; +- else +- tr->fops->flags &= ~FTRACE_OPS_FL_JMP; +-#endif +- } + kfree(tlinks); + return err; + +diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c +index aa758efc37314..93f617e1f191d 100644 +--- a/kernel/trace/ftrace.c ++++ b/kernel/trace/ftrace.c +@@ -6049,15 +6049,8 @@ int register_ftrace_direct(struct ftrace_ops *ops, unsigned long addr) + if (ftrace_hash_empty(hash)) + return -EINVAL; + +- /* This is a "raw" address, and this should never happen. */ +- if (WARN_ON_ONCE(ftrace_is_jmp(addr))) +- return -EINVAL; +- + mutex_lock(&direct_mutex); + +- if (ops->flags & FTRACE_OPS_FL_JMP) +- addr = ftrace_jmp_set(addr); +- + /* Make sure requested entries are not already registered.. */ + size = 1 << hash->size_bits; + for (i = 0; i < size; i++) { +@@ -6178,13 +6171,6 @@ __modify_ftrace_direct(struct ftrace_ops *ops, unsigned long addr) + + lockdep_assert_held_once(&direct_mutex); + +- /* This is a "raw" address, and this should never happen. */ +- if (WARN_ON_ONCE(ftrace_is_jmp(addr))) +- return -EINVAL; +- +- if (ops->flags & FTRACE_OPS_FL_JMP) +- addr = ftrace_jmp_set(addr); +- + /* Enable the tmp_ops to have the same functions as the direct ops */ + ftrace_ops_init(&tmp_ops); + tmp_ops.func_hash = ops->func_hash; +-- +2.51.0 + diff --git a/queue-6.19/genirq-set-irqf_cond_oneshot-in-devm_request_irq.patch b/queue-6.19/genirq-set-irqf_cond_oneshot-in-devm_request_irq.patch new file mode 100644 index 0000000000..807856695e --- /dev/null +++ b/queue-6.19/genirq-set-irqf_cond_oneshot-in-devm_request_irq.patch @@ -0,0 +1,43 @@ +From 9130241ba23aaedc8a49f2d095ddb276f9a831d0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:55:21 +0100 +Subject: genirq: Set IRQF_COND_ONESHOT in devm_request_irq(). + +From: Sebastian Andrzej Siewior + +[ Upstream commit 943b052ded21feb84f293d40b06af3181cd0d0d7 ] + +The flag IRQF_COND_ONESHOT was already force-added to request_irq() because +the ACPI SCI interrupt handler is using the IRQF_ONESHOT flag which breaks +all shared handlers. + +devm_request_irq() needs the same change since some users, such as +int0002_vgpio, are using this function instead. + +Add IRQF_COND_ONESHOT to the flags passed to devm_request_irq(). + +Fixes: c37927a203fa2 ("genirq: Set IRQF_COND_ONESHOT in request_irq()") +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260128095540.863589-2-bigeasy@linutronix.de +Signed-off-by: Sasha Levin +--- + include/linux/interrupt.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h +index 266f2b39213a0..b2bb878abd113 100644 +--- a/include/linux/interrupt.h ++++ b/include/linux/interrupt.h +@@ -228,7 +228,7 @@ static inline int __must_check + devm_request_irq(struct device *dev, unsigned int irq, irq_handler_t handler, + unsigned long irqflags, const char *devname, void *dev_id) + { +- return devm_request_threaded_irq(dev, irq, handler, NULL, irqflags, ++ return devm_request_threaded_irq(dev, irq, handler, NULL, irqflags | IRQF_COND_ONESHOT, + devname, dev_id); + } + +-- +2.51.0 + diff --git a/queue-6.19/gfs2-fix-memory-leaks-in-gfs2_fill_super-error-path.patch b/queue-6.19/gfs2-fix-memory-leaks-in-gfs2_fill_super-error-path.patch new file mode 100644 index 0000000000..b64cf9bb53 --- /dev/null +++ b/queue-6.19/gfs2-fix-memory-leaks-in-gfs2_fill_super-error-path.patch @@ -0,0 +1,95 @@ +From 530d4bed3648f7adc8b8b8f3dc729b75c66f7a96 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 07:50:33 +0530 +Subject: gfs2: fix memory leaks in gfs2_fill_super error path + +From: Deepanshu Kartikey + +[ Upstream commit da6f5bbc2e7902f578b503f2a4c3d8d09ca4b102 ] + +Fix two memory leaks in the gfs2_fill_super() error handling path when +transitioning a filesystem to read-write mode fails. + +First leak: kthread objects (thread_struct, task_struct, etc.) +When gfs2_freeze_lock_shared() fails after init_threads() succeeds, the +created kernel threads (logd and quotad) are never destroyed. This +occurs because the fail_per_node label doesn't call +gfs2_destroy_threads(). + +Second leak: quota bitmap buffer (8192 bytes) +When gfs2_make_fs_rw() fails after gfs2_quota_init() succeeds but +before other operations complete, the allocated quota bitmap is never +freed. + +The fix moves thread cleanup to the fail_per_node label to handle all +error paths uniformly. gfs2_destroy_threads() is safe to call +unconditionally as it checks for NULL pointers. Quota cleanup is added +in gfs2_make_fs_rw() to properly handle the withdrawal case where +quota initialization succeeds but the filesystem is then withdrawn. + +Thread leak backtrace (gfs2_freeze_lock_shared failure): + unreferenced object 0xffff88801d7bca80 (size 4480): + copy_process+0x3a1/0x4670 kernel/fork.c:2422 + kernel_clone+0xf3/0x6e0 kernel/fork.c:2779 + kthread_create_on_node+0x100/0x150 kernel/kthread.c:478 + init_threads+0xab/0x350 fs/gfs2/ops_fstype.c:611 + gfs2_fill_super+0xe5c/0x1240 fs/gfs2/ops_fstype.c:1265 + +Quota leak backtrace (gfs2_make_fs_rw failure): + unreferenced object 0xffff88812de7c000 (size 8192): + gfs2_quota_init+0xe5/0x820 fs/gfs2/quota.c:1409 + gfs2_make_fs_rw+0x7a/0xe0 fs/gfs2/super.c:149 + gfs2_fill_super+0xfbb/0x1240 fs/gfs2/ops_fstype.c:1275 + +Reported-by: syzbot+aac438d7a1c44071e04b@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=aac438d7a1c44071e04b +Fixes: 6c7410f44961 ("gfs2: gfs2_freeze_lock_shared cleanup") +Fixes: b66f723bb552 ("gfs2: Improve gfs2_make_fs_rw error handling") +Link: https://lore.kernel.org/all/20260131062509.77974-1-kartikey406@gmail.com/T/ [v1] +Signed-off-by: Deepanshu Kartikey +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Sasha Levin +--- + fs/gfs2/ops_fstype.c | 2 +- + fs/gfs2/super.c | 4 +++- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c +index e7a88b717991a..c7d57de7c8f06 100644 +--- a/fs/gfs2/ops_fstype.c ++++ b/fs/gfs2/ops_fstype.c +@@ -1276,7 +1276,6 @@ static int gfs2_fill_super(struct super_block *sb, struct fs_context *fc) + + if (error) { + gfs2_freeze_unlock(sdp); +- gfs2_destroy_threads(sdp); + fs_err(sdp, "can't make FS RW: %d\n", error); + goto fail_per_node; + } +@@ -1286,6 +1285,7 @@ static int gfs2_fill_super(struct super_block *sb, struct fs_context *fc) + + fail_per_node: + init_per_node(sdp, UNDO); ++ gfs2_destroy_threads(sdp); + fail_inodes: + init_inodes(sdp, UNDO); + fail_sb: +diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c +index f6cd907b3ec6c..d96160636161c 100644 +--- a/fs/gfs2/super.c ++++ b/fs/gfs2/super.c +@@ -147,8 +147,10 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp) + } + + error = gfs2_quota_init(sdp); +- if (!error && gfs2_withdrawn(sdp)) ++ if (!error && gfs2_withdrawn(sdp)) { ++ gfs2_quota_cleanup(sdp); + error = -EIO; ++ } + if (!error) + set_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags); + return error; +-- +2.51.0 + diff --git a/queue-6.19/gfs2-fix-slab-use-after-free-in-qd_put.patch b/queue-6.19/gfs2-fix-slab-use-after-free-in-qd_put.patch new file mode 100644 index 0000000000..79cd6f97a1 --- /dev/null +++ b/queue-6.19/gfs2-fix-slab-use-after-free-in-qd_put.patch @@ -0,0 +1,45 @@ +From 7d6e2f5fdfda761983bb57bbb733f736367a6d33 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 14 Dec 2025 16:47:34 +0000 +Subject: gfs2: Fix slab-use-after-free in qd_put + +From: Andreas Gruenbacher + +[ Upstream commit 22150a7d401d9e9169b9b68e05bed95f7f49bf69 ] + +Commit a475c5dd16e5 ("gfs2: Free quota data objects synchronously") +started freeing quota data objects during filesystem shutdown instead of +putting them back onto the LRU list, but it failed to remove these +objects from the LRU list, causing LRU list corruption. This caused +use-after-free when the shrinker (gfs2_qd_shrink_scan) tried to access +already-freed objects on the LRU list. + +Fix this by removing qd objects from the LRU list before freeing them in +qd_put(). + +Initial fix from Deepanshu Kartikey . + +Fixes: a475c5dd16e5 ("gfs2: Free quota data objects synchronously") +Reported-by: syzbot+046b605f01802054bff0@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=046b605f01802054bff0 +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Sasha Levin +--- + fs/gfs2/quota.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c +index b1692f12a602a..2b499b554e876 100644 +--- a/fs/gfs2/quota.c ++++ b/fs/gfs2/quota.c +@@ -334,6 +334,7 @@ static void qd_put(struct gfs2_quota_data *qd) + lockref_mark_dead(&qd->qd_lockref); + spin_unlock(&qd->qd_lockref.lock); + ++ list_lru_del_obj(&gfs2_qd_lru, &qd->qd_lru); + gfs2_qd_dispose(qd); + return; + } +-- +2.51.0 + diff --git a/queue-6.19/gfs2-fix-use-after-free-in-iomap-inline-data-write-p.patch b/queue-6.19/gfs2-fix-use-after-free-in-iomap-inline-data-write-p.patch new file mode 100644 index 0000000000..0f21371fe9 --- /dev/null +++ b/queue-6.19/gfs2-fix-use-after-free-in-iomap-inline-data-write-p.patch @@ -0,0 +1,84 @@ +From 1ee6c4fbcd924ad5cb925dff697ea16a653700f2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 14:51:34 +0530 +Subject: gfs2: Fix use-after-free in iomap inline data write path + +From: Deepanshu Kartikey + +[ Upstream commit faddeb848305e79db89ee0479bb0e33380656321 ] + +The inline data buffer head (dibh) is being released prematurely in +gfs2_iomap_begin() via release_metapath() while iomap->inline_data +still points to dibh->b_data. This causes a use-after-free when +iomap_write_end_inline() later attempts to write to the inline data +area. + +The bug sequence: +1. gfs2_iomap_begin() calls gfs2_meta_inode_buffer() to read inode + metadata into dibh +2. Sets iomap->inline_data = dibh->b_data + sizeof(struct gfs2_dinode) +3. Calls release_metapath() which calls brelse(dibh), dropping refcount + to 0 +4. kswapd reclaims the page (~39ms later in the syzbot report) +5. iomap_write_end_inline() tries to memcpy() to iomap->inline_data +6. KASAN detects use-after-free write to freed memory + +Fix by storing dibh in iomap->private and incrementing its refcount +with get_bh() in gfs2_iomap_begin(). The buffer is then properly +released in gfs2_iomap_end() after the inline write completes, +ensuring the page stays alive for the entire iomap operation. + +Note: A C reproducer is not available for this issue. The fix is based +on analysis of the KASAN report and code review showing the buffer head +is freed before use. + +[agruenba: Take buffer head reference in gfs2_iomap_begin() to avoid +leaks in gfs2_iomap_get() and gfs2_iomap_alloc().] + +Reported-by: syzbot+ea1cd4aa4d1e98458a55@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=ea1cd4aa4d1e98458a55 +Fixes: d0a22a4b03b8 ("gfs2: Fix iomap write page reclaim deadlock") +Signed-off-by: Deepanshu Kartikey +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Sasha Levin +--- + fs/gfs2/bmap.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c +index 131091520de6b..fdcac8e3f2ba2 100644 +--- a/fs/gfs2/bmap.c ++++ b/fs/gfs2/bmap.c +@@ -1127,10 +1127,18 @@ static int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length, + goto out_unlock; + break; + default: +- goto out_unlock; ++ goto out; + } + + ret = gfs2_iomap_begin_write(inode, pos, length, flags, iomap, &mp); ++ if (ret) ++ goto out_unlock; ++ ++out: ++ if (iomap->type == IOMAP_INLINE) { ++ iomap->private = metapath_dibh(&mp); ++ get_bh(iomap->private); ++ } + + out_unlock: + release_metapath(&mp); +@@ -1144,6 +1152,9 @@ static int gfs2_iomap_end(struct inode *inode, loff_t pos, loff_t length, + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); + ++ if (iomap->private) ++ brelse(iomap->private); ++ + switch (flags & (IOMAP_WRITE | IOMAP_ZERO)) { + case IOMAP_WRITE: + if (flags & IOMAP_DIRECT) +-- +2.51.0 + diff --git a/queue-6.19/gfs2-initialize-bio-bi_opf-early.patch b/queue-6.19/gfs2-initialize-bio-bi_opf-early.patch new file mode 100644 index 0000000000..b282f27dc3 --- /dev/null +++ b/queue-6.19/gfs2-initialize-bio-bi_opf-early.patch @@ -0,0 +1,214 @@ +From dd0e2b01dac77135ed1a74b9478e3753c7bcd045 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 11 Dec 2025 01:55:47 +0000 +Subject: gfs2: Initialize bio->bi_opf early + +From: Andreas Gruenbacher + +[ Upstream commit 4a94f052e0982794aa65312fe8b69999e4494a20 ] + +Pass the right blk_opf_t value to bio_alloc() so that ->bi_ops is +initialized correctly and doesn't have to be changed later. Adjust the +call chain to pass that value through to where it is needed (and only +there). + +Add a separate blk_opf_t argument to gfs2_chain_bio() instead of copying +the value from the previous bio. + +Fixes: 8a157e0a0aa5 ("gfs2: Fix use of bio_chain") +Reported-by: syzbot+f6539d4ce3f775aee0cc@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=f6539d4ce3f775aee0cc +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Sasha Levin +--- + fs/gfs2/log.c | 7 ++++--- + fs/gfs2/lops.c | 37 ++++++++++++++++++++----------------- + fs/gfs2/lops.h | 4 ++-- + 3 files changed, 26 insertions(+), 22 deletions(-) + +diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c +index 2a3b9d10eba78..347df29d610e6 100644 +--- a/fs/gfs2/log.c ++++ b/fs/gfs2/log.c +@@ -888,8 +888,9 @@ void gfs2_write_log_header(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd, + sb->s_blocksize - LH_V1_SIZE - 4); + lh->lh_crc = cpu_to_be32(crc); + +- gfs2_log_write(sdp, jd, page, sb->s_blocksize, 0, dblock); +- gfs2_log_submit_write(&jd->jd_log_bio, REQ_OP_WRITE | op_flags); ++ gfs2_log_write(sdp, jd, page, sb->s_blocksize, 0, dblock, ++ REQ_OP_WRITE | op_flags); ++ gfs2_log_submit_write(&jd->jd_log_bio); + } + + /** +@@ -1096,7 +1097,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) + if (gfs2_withdrawn(sdp)) + goto out_withdraw; + if (sdp->sd_jdesc) +- gfs2_log_submit_write(&sdp->sd_jdesc->jd_log_bio, REQ_OP_WRITE); ++ gfs2_log_submit_write(&sdp->sd_jdesc->jd_log_bio); + if (gfs2_withdrawn(sdp)) + goto out_withdraw; + +diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c +index aa9e9fe25c2f7..c3317432a25b3 100644 +--- a/fs/gfs2/lops.c ++++ b/fs/gfs2/lops.c +@@ -231,19 +231,17 @@ static void gfs2_end_log_write(struct bio *bio) + /** + * gfs2_log_submit_write - Submit a pending log write bio + * @biop: Address of the bio pointer +- * @opf: REQ_OP | op_flags + * + * Submit any pending part-built or full bio to the block device. If + * there is no pending bio, then this is a no-op. + */ + +-void gfs2_log_submit_write(struct bio **biop, blk_opf_t opf) ++void gfs2_log_submit_write(struct bio **biop) + { + struct bio *bio = *biop; + if (bio) { + struct gfs2_sbd *sdp = bio->bi_private; + atomic_inc(&sdp->sd_log_in_flight); +- bio->bi_opf = opf; + submit_bio(bio); + *biop = NULL; + } +@@ -254,6 +252,7 @@ void gfs2_log_submit_write(struct bio **biop, blk_opf_t opf) + * @sdp: The super block + * @blkno: The device block number we want to write to + * @end_io: The bi_end_io callback ++ * @opf: REQ_OP | op_flags + * + * Allocate a new bio, initialize it with the given parameters and return it. + * +@@ -261,10 +260,10 @@ void gfs2_log_submit_write(struct bio **biop, blk_opf_t opf) + */ + + static struct bio *gfs2_log_alloc_bio(struct gfs2_sbd *sdp, u64 blkno, +- bio_end_io_t *end_io) ++ bio_end_io_t *end_io, blk_opf_t opf) + { + struct super_block *sb = sdp->sd_vfs; +- struct bio *bio = bio_alloc(sb->s_bdev, BIO_MAX_VECS, 0, GFP_NOIO); ++ struct bio *bio = bio_alloc(sb->s_bdev, BIO_MAX_VECS, opf, GFP_NOIO); + + bio->bi_iter.bi_sector = blkno << sdp->sd_fsb2bb_shift; + bio->bi_end_io = end_io; +@@ -303,10 +302,10 @@ static struct bio *gfs2_log_get_bio(struct gfs2_sbd *sdp, u64 blkno, + nblk >>= sdp->sd_fsb2bb_shift; + if (blkno == nblk && !flush) + return bio; +- gfs2_log_submit_write(biop, op); ++ gfs2_log_submit_write(biop); + } + +- *biop = gfs2_log_alloc_bio(sdp, blkno, end_io); ++ *biop = gfs2_log_alloc_bio(sdp, blkno, end_io, op); + return *biop; + } + +@@ -318,6 +317,7 @@ static struct bio *gfs2_log_get_bio(struct gfs2_sbd *sdp, u64 blkno, + * @size: the size of the data to write + * @offset: the offset within the page + * @blkno: block number of the log entry ++ * @opf: REQ_OP | op_flags + * + * Try and add the page segment to the current bio. If that fails, + * submit the current bio to the device and create a new one, and +@@ -326,17 +326,17 @@ static struct bio *gfs2_log_get_bio(struct gfs2_sbd *sdp, u64 blkno, + + void gfs2_log_write(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd, + struct page *page, unsigned size, unsigned offset, +- u64 blkno) ++ u64 blkno, blk_opf_t opf) + { + struct bio *bio; + int ret; + +- bio = gfs2_log_get_bio(sdp, blkno, &jd->jd_log_bio, REQ_OP_WRITE, ++ bio = gfs2_log_get_bio(sdp, blkno, &jd->jd_log_bio, opf, + gfs2_end_log_write, false); + ret = bio_add_page(bio, page, size, offset); + if (ret == 0) { + bio = gfs2_log_get_bio(sdp, blkno, &jd->jd_log_bio, +- REQ_OP_WRITE, gfs2_end_log_write, true); ++ opf, gfs2_end_log_write, true); + ret = bio_add_page(bio, page, size, offset); + WARN_ON(ret == 0); + } +@@ -359,7 +359,7 @@ static void gfs2_log_write_bh(struct gfs2_sbd *sdp, struct buffer_head *bh) + dblock = gfs2_log_bmap(sdp->sd_jdesc, sdp->sd_log_flush_head); + gfs2_log_incr_head(sdp); + gfs2_log_write(sdp, sdp->sd_jdesc, folio_page(bh->b_folio, 0), +- bh->b_size, bh_offset(bh), dblock); ++ bh->b_size, bh_offset(bh), dblock, REQ_OP_WRITE); + } + + /** +@@ -380,7 +380,8 @@ static void gfs2_log_write_page(struct gfs2_sbd *sdp, struct page *page) + + dblock = gfs2_log_bmap(sdp->sd_jdesc, sdp->sd_log_flush_head); + gfs2_log_incr_head(sdp); +- gfs2_log_write(sdp, sdp->sd_jdesc, page, sb->s_blocksize, 0, dblock); ++ gfs2_log_write(sdp, sdp->sd_jdesc, page, sb->s_blocksize, 0, dblock, ++ REQ_OP_WRITE); + } + + /** +@@ -477,11 +478,12 @@ static void gfs2_jhead_process_page(struct gfs2_jdesc *jd, unsigned long index, + folio_put_refs(folio, 2); + } + +-static struct bio *gfs2_chain_bio(struct bio *prev, unsigned int nr_iovecs) ++static struct bio *gfs2_chain_bio(struct bio *prev, unsigned int nr_iovecs, ++ blk_opf_t opf) + { + struct bio *new; + +- new = bio_alloc(prev->bi_bdev, nr_iovecs, prev->bi_opf, GFP_NOIO); ++ new = bio_alloc(prev->bi_bdev, nr_iovecs, opf, GFP_NOIO); + bio_clone_blkg_association(new, prev); + new->bi_iter.bi_sector = bio_end_sector(prev); + bio_chain(new, prev); +@@ -546,7 +548,8 @@ int gfs2_find_jhead(struct gfs2_jdesc *jd, struct gfs2_log_header_host *head) + unsigned int blocks = + (PAGE_SIZE - off) >> bsize_shift; + +- bio = gfs2_chain_bio(bio, blocks); ++ bio = gfs2_chain_bio(bio, blocks, ++ REQ_OP_READ); + goto add_block_to_new_bio; + } + } +@@ -556,8 +559,8 @@ int gfs2_find_jhead(struct gfs2_jdesc *jd, struct gfs2_log_header_host *head) + submit_bio(bio); + } + +- bio = gfs2_log_alloc_bio(sdp, dblock, gfs2_end_log_read); +- bio->bi_opf = REQ_OP_READ; ++ bio = gfs2_log_alloc_bio(sdp, dblock, gfs2_end_log_read, ++ REQ_OP_READ); + add_block_to_new_bio: + bio_add_folio_nofail(bio, folio, bsize, off); + block_added: +diff --git a/fs/gfs2/lops.h b/fs/gfs2/lops.h +index 010a4696406bb..772557b63b48b 100644 +--- a/fs/gfs2/lops.h ++++ b/fs/gfs2/lops.h +@@ -16,8 +16,8 @@ void gfs2_log_incr_head(struct gfs2_sbd *sdp); + u64 gfs2_log_bmap(struct gfs2_jdesc *jd, unsigned int lbn); + void gfs2_log_write(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd, + struct page *page, unsigned size, unsigned offset, +- u64 blkno); +-void gfs2_log_submit_write(struct bio **biop, blk_opf_t opf); ++ u64 blkno, blk_opf_t opf); ++void gfs2_log_submit_write(struct bio **biop); + void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh); + int gfs2_find_jhead(struct gfs2_jdesc *jd, + struct gfs2_log_header_host *head); +-- +2.51.0 + diff --git a/queue-6.19/gfs2-rename-gfs2_log_submit_-bio-write.patch b/queue-6.19/gfs2-rename-gfs2_log_submit_-bio-write.patch new file mode 100644 index 0000000000..3a5fbf6537 --- /dev/null +++ b/queue-6.19/gfs2-rename-gfs2_log_submit_-bio-write.patch @@ -0,0 +1,90 @@ +From 92bbae11a4228400bf00c4cd36ea8d47ae8892f1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 11 Dec 2025 03:24:32 +0000 +Subject: gfs2: Rename gfs2_log_submit_{bio -> write} + +From: Andreas Gruenbacher + +[ Upstream commit 59d81037d32ff1e415dcaa359c238c9ca730932d ] + +Rename gfs2_log_submit_bio() to gfs2_log_submit_write(): this function +isn't used for submitting log reads. + +Signed-off-by: Andreas Gruenbacher +Stable-dep-of: 4a94f052e098 ("gfs2: Initialize bio->bi_opf early") +Signed-off-by: Sasha Levin +--- + fs/gfs2/log.c | 4 ++-- + fs/gfs2/lops.c | 6 +++--- + fs/gfs2/lops.h | 2 +- + 3 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c +index 8312cd2cdae47..2a3b9d10eba78 100644 +--- a/fs/gfs2/log.c ++++ b/fs/gfs2/log.c +@@ -889,7 +889,7 @@ void gfs2_write_log_header(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd, + lh->lh_crc = cpu_to_be32(crc); + + gfs2_log_write(sdp, jd, page, sb->s_blocksize, 0, dblock); +- gfs2_log_submit_bio(&jd->jd_log_bio, REQ_OP_WRITE | op_flags); ++ gfs2_log_submit_write(&jd->jd_log_bio, REQ_OP_WRITE | op_flags); + } + + /** +@@ -1096,7 +1096,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) + if (gfs2_withdrawn(sdp)) + goto out_withdraw; + if (sdp->sd_jdesc) +- gfs2_log_submit_bio(&sdp->sd_jdesc->jd_log_bio, REQ_OP_WRITE); ++ gfs2_log_submit_write(&sdp->sd_jdesc->jd_log_bio, REQ_OP_WRITE); + if (gfs2_withdrawn(sdp)) + goto out_withdraw; + +diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c +index d27a0b1080a97..aa9e9fe25c2f7 100644 +--- a/fs/gfs2/lops.c ++++ b/fs/gfs2/lops.c +@@ -229,7 +229,7 @@ static void gfs2_end_log_write(struct bio *bio) + } + + /** +- * gfs2_log_submit_bio - Submit any pending log bio ++ * gfs2_log_submit_write - Submit a pending log write bio + * @biop: Address of the bio pointer + * @opf: REQ_OP | op_flags + * +@@ -237,7 +237,7 @@ static void gfs2_end_log_write(struct bio *bio) + * there is no pending bio, then this is a no-op. + */ + +-void gfs2_log_submit_bio(struct bio **biop, blk_opf_t opf) ++void gfs2_log_submit_write(struct bio **biop, blk_opf_t opf) + { + struct bio *bio = *biop; + if (bio) { +@@ -303,7 +303,7 @@ static struct bio *gfs2_log_get_bio(struct gfs2_sbd *sdp, u64 blkno, + nblk >>= sdp->sd_fsb2bb_shift; + if (blkno == nblk && !flush) + return bio; +- gfs2_log_submit_bio(biop, op); ++ gfs2_log_submit_write(biop, op); + } + + *biop = gfs2_log_alloc_bio(sdp, blkno, end_io); +diff --git a/fs/gfs2/lops.h b/fs/gfs2/lops.h +index be740bf336664..010a4696406bb 100644 +--- a/fs/gfs2/lops.h ++++ b/fs/gfs2/lops.h +@@ -17,7 +17,7 @@ u64 gfs2_log_bmap(struct gfs2_jdesc *jd, unsigned int lbn); + void gfs2_log_write(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd, + struct page *page, unsigned size, unsigned offset, + u64 blkno); +-void gfs2_log_submit_bio(struct bio **biop, blk_opf_t opf); ++void gfs2_log_submit_write(struct bio **biop, blk_opf_t opf); + void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh); + int gfs2_find_jhead(struct gfs2_jdesc *jd, + struct gfs2_log_header_host *head); +-- +2.51.0 + diff --git a/queue-6.19/gfs2-retries-missing-in-gfs2_-rename-exchange.patch b/queue-6.19/gfs2-retries-missing-in-gfs2_-rename-exchange.patch new file mode 100644 index 0000000000..e3292ac090 --- /dev/null +++ b/queue-6.19/gfs2-retries-missing-in-gfs2_-rename-exchange.patch @@ -0,0 +1,178 @@ +From e578c910b970a872ef695c5d962696f9671d4f62 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 22:59:12 +0000 +Subject: gfs2: Retries missing in gfs2_{rename,exchange} + +From: Andreas Gruenbacher + +[ Upstream commit 11d763f0b0afc2cf5f92f4adae5dbbbbef712f8f ] + +Fix a bug in gfs2's asynchronous glock handling for rename and exchange +operations. The original async implementation from commit ad26967b9afa +("gfs2: Use async glocks for rename") mentioned that retries were needed +but never implemented them, causing operations to fail with -ESTALE +instead of retrying on timeout. + +Also makes the waiting interruptible. + +In addition, the timeouts used were too high for situations in which +timing out is a rare but expected scenario. Switch to shorter timeouts +with randomization and exponentional backoff. + +Fixes: ad26967b9afa ("gfs2: Use async glocks for rename") +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Sasha Levin +--- + fs/gfs2/glock.c | 36 +++++++++++++++++++++++++++--------- + fs/gfs2/glock.h | 3 ++- + fs/gfs2/inode.c | 18 ++++++++++++++---- + 3 files changed, 43 insertions(+), 14 deletions(-) + +diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c +index 92e029104d8a4..289851d70130b 100644 +--- a/fs/gfs2/glock.c ++++ b/fs/gfs2/glock.c +@@ -1284,31 +1284,45 @@ static int glocks_pending(unsigned int num_gh, struct gfs2_holder *ghs) + * gfs2_glock_async_wait - wait on multiple asynchronous glock acquisitions + * @num_gh: the number of holders in the array + * @ghs: the glock holder array ++ * @retries: number of retries attempted so far + * + * Returns: 0 on success, meaning all glocks have been granted and are held. + * -ESTALE if the request timed out, meaning all glocks were released, + * and the caller should retry the operation. + */ + +-int gfs2_glock_async_wait(unsigned int num_gh, struct gfs2_holder *ghs) ++int gfs2_glock_async_wait(unsigned int num_gh, struct gfs2_holder *ghs, ++ unsigned int retries) + { + struct gfs2_sbd *sdp = ghs[0].gh_gl->gl_name.ln_sbd; +- int i, ret = 0, timeout = 0; + unsigned long start_time = jiffies; ++ int i, ret = 0; ++ long timeout; + + might_sleep(); +- /* +- * Total up the (minimum hold time * 2) of all glocks and use that to +- * determine the max amount of time we should wait. +- */ +- for (i = 0; i < num_gh; i++) +- timeout += ghs[i].gh_gl->gl_hold_time << 1; + +- if (!wait_event_timeout(sdp->sd_async_glock_wait, ++ timeout = GL_GLOCK_MIN_HOLD; ++ if (retries) { ++ unsigned int max_shift; ++ long incr; ++ ++ /* Add a random delay and increase the timeout exponentially. */ ++ max_shift = BITS_PER_LONG - 2 - __fls(GL_GLOCK_HOLD_INCR); ++ incr = min(GL_GLOCK_HOLD_INCR << min(retries - 1, max_shift), ++ 10 * HZ - GL_GLOCK_MIN_HOLD); ++ schedule_timeout_interruptible(get_random_long() % (incr / 3)); ++ if (signal_pending(current)) ++ goto interrupted; ++ timeout += (incr / 3) + get_random_long() % (incr / 3); ++ } ++ ++ if (!wait_event_interruptible_timeout(sdp->sd_async_glock_wait, + !glocks_pending(num_gh, ghs), timeout)) { + ret = -ESTALE; /* request timed out. */ + goto out; + } ++ if (signal_pending(current)) ++ goto interrupted; + + for (i = 0; i < num_gh; i++) { + struct gfs2_holder *gh = &ghs[i]; +@@ -1332,6 +1346,10 @@ int gfs2_glock_async_wait(unsigned int num_gh, struct gfs2_holder *ghs) + } + } + return ret; ++ ++interrupted: ++ ret = -EINTR; ++ goto out; + } + + /** +diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h +index 55d5985f32a08..dccbf36b8cb10 100644 +--- a/fs/gfs2/glock.h ++++ b/fs/gfs2/glock.h +@@ -204,7 +204,8 @@ int gfs2_glock_poll(struct gfs2_holder *gh); + int gfs2_instantiate(struct gfs2_holder *gh); + int gfs2_glock_holder_ready(struct gfs2_holder *gh); + int gfs2_glock_wait(struct gfs2_holder *gh); +-int gfs2_glock_async_wait(unsigned int num_gh, struct gfs2_holder *ghs); ++int gfs2_glock_async_wait(unsigned int num_gh, struct gfs2_holder *ghs, ++ unsigned int retries); + void gfs2_glock_dq(struct gfs2_holder *gh); + void gfs2_glock_dq_wait(struct gfs2_holder *gh); + void gfs2_glock_dq_uninit(struct gfs2_holder *gh); +diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c +index 36618e3531996..b6ed069b34872 100644 +--- a/fs/gfs2/inode.c ++++ b/fs/gfs2/inode.c +@@ -1495,7 +1495,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, + unsigned int num_gh; + int dir_rename = 0; + struct gfs2_diradd da = { .nr_blocks = 0, .save_loc = 0, }; +- unsigned int x; ++ unsigned int retries = 0, x; + int error; + + gfs2_holder_mark_uninitialized(&r_gh); +@@ -1545,12 +1545,17 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, + num_gh++; + } + ++again: + for (x = 0; x < num_gh; x++) { + error = gfs2_glock_nq(ghs + x); + if (error) + goto out_gunlock; + } +- error = gfs2_glock_async_wait(num_gh, ghs); ++ error = gfs2_glock_async_wait(num_gh, ghs, retries); ++ if (error == -ESTALE) { ++ retries++; ++ goto again; ++ } + if (error) + goto out_gunlock; + +@@ -1739,7 +1744,7 @@ static int gfs2_exchange(struct inode *odir, struct dentry *odentry, + struct gfs2_sbd *sdp = GFS2_SB(odir); + struct gfs2_holder ghs[4], r_gh; + unsigned int num_gh; +- unsigned int x; ++ unsigned int retries = 0, x; + umode_t old_mode = oip->i_inode.i_mode; + umode_t new_mode = nip->i_inode.i_mode; + int error; +@@ -1783,13 +1788,18 @@ static int gfs2_exchange(struct inode *odir, struct dentry *odentry, + gfs2_holder_init(nip->i_gl, LM_ST_EXCLUSIVE, GL_ASYNC, ghs + num_gh); + num_gh++; + ++again: + for (x = 0; x < num_gh; x++) { + error = gfs2_glock_nq(ghs + x); + if (error) + goto out_gunlock; + } + +- error = gfs2_glock_async_wait(num_gh, ghs); ++ error = gfs2_glock_async_wait(num_gh, ghs, retries); ++ if (error == -ESTALE) { ++ retries++; ++ goto again; ++ } + if (error) + goto out_gunlock; + +-- +2.51.0 + diff --git a/queue-6.19/gpib-fix-error-code-in-ibonline.patch b/queue-6.19/gpib-fix-error-code-in-ibonline.patch new file mode 100644 index 0000000000..71b5c24104 --- /dev/null +++ b/queue-6.19/gpib-fix-error-code-in-ibonline.patch @@ -0,0 +1,42 @@ +From 7f41f92db6ec8db5f5ff3834a0cdfaeeea9cc1ab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 10:17:49 +0300 +Subject: gpib: Fix error code in ibonline() + +From: Dan Carpenter + +[ Upstream commit 96118565d24e7691e423d73be224b3a3fffc4680 ] + +This accidentally returns 1 on error, but it should return negative +error codes. + +Fixes: 9dde4559e939 ("staging: gpib: Add GPIB common core driver") +Signed-off-by: Dan Carpenter +Link: https://patch.msgid.link/aSlMnaT1M104NJb2@stanley.mountain +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/gpib/common/iblib.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpib/common/iblib.c b/drivers/gpib/common/iblib.c +index 7cbb6a467177d..b672dd6aad25f 100644 +--- a/drivers/gpib/common/iblib.c ++++ b/drivers/gpib/common/iblib.c +@@ -227,11 +227,10 @@ int ibonline(struct gpib_board *board) + #ifndef CONFIG_NIOS2 + board->autospoll_task = kthread_run(&autospoll_thread, board, + "gpib%d_autospoll_kthread", board->minor); +- retval = IS_ERR(board->autospoll_task); +- if (retval) { ++ if (IS_ERR(board->autospoll_task)) { + dev_err(board->gpib_dev, "failed to create autospoll thread\n"); + board->interface->detach(board); +- return retval; ++ return PTR_ERR(board->autospoll_task); + } + #endif + board->online = 1; +-- +2.51.0 + diff --git a/queue-6.19/gpib-fix-error-code-in-ni_usb_write_registers.patch b/queue-6.19/gpib-fix-error-code-in-ni_usb_write_registers.patch new file mode 100644 index 0000000000..a392aeaca5 --- /dev/null +++ b/queue-6.19/gpib-fix-error-code-in-ni_usb_write_registers.patch @@ -0,0 +1,37 @@ +From 09b6b8097898cfd891d6d94523bf9593ae9c4963 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 10:17:57 +0300 +Subject: gpib: Fix error code in ni_usb_write_registers() + +From: Dan Carpenter + +[ Upstream commit 484e62252212c5b5fc62eaee5e4977143cb159c6 ] + +If ni_usb_receive_bulk_msg() succeeds but without reading 16 bytes, then +the error code needs to be set. The current code returns success. + +Fixes: 4e127de14fa7 ("staging: gpib: Add National Instruments USB GPIB driver") +Signed-off-by: Dan Carpenter +Link: https://patch.msgid.link/aSlMpbE4IrQuBGFS@stanley.mountain +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/gpib/ni_usb/ni_usb_gpib.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpib/ni_usb/ni_usb_gpib.c b/drivers/gpib/ni_usb/ni_usb_gpib.c +index 1f8412de9fa32..fdcaa6c00bfea 100644 +--- a/drivers/gpib/ni_usb/ni_usb_gpib.c ++++ b/drivers/gpib/ni_usb/ni_usb_gpib.c +@@ -566,7 +566,7 @@ static int ni_usb_write_registers(struct ni_usb_priv *ni_priv, + retval, bytes_read); + ni_usb_dump_raw_block(in_data, bytes_read); + kfree(in_data); +- return retval; ++ return retval ?: -EINVAL; + } + + mutex_unlock(&ni_priv->addressed_transfer_lock); +-- +2.51.0 + diff --git a/queue-6.19/gpib-fix-memory-leak-in-ni_usb_init.patch b/queue-6.19/gpib-fix-memory-leak-in-ni_usb_init.patch new file mode 100644 index 0000000000..4b373143e0 --- /dev/null +++ b/queue-6.19/gpib-fix-memory-leak-in-ni_usb_init.patch @@ -0,0 +1,67 @@ +From 0d07890a484af8f9fb3589c9d6d0a9faeb61e581 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Dec 2025 03:45:46 +0000 +Subject: gpib: Fix memory leak in ni_usb_init() + +From: Zilin Guan + +[ Upstream commit b89921eed8cf2d97250bac4be38dbcfbf048b586 ] + +In ni_usb_init(), if ni_usb_setup_init() fails, the function returns +-EFAULT without freeing the allocated writes buffer, leading to a +memory leak. + +Additionally, ni_usb_setup_init() returns 0 on failure, which causes +ni_usb_init() to return -EFAULT, an inappropriate error code for this +situation. + +Fix the leak by freeing writes in the error path. Modify +ni_usb_setup_init() to return -EINVAL on failure and propagate this +error code in ni_usb_init(). + +Fixes: 4e127de14fa7 ("staging: gpib: Add National Instruments USB GPIB driver") +Suggested-by: Greg KH +Suggested-by: Dave Penkler +Co-developed-by: Jianhao Xu +Signed-off-by: Jianhao Xu +Signed-off-by: Zilin Guan +Link: https://patch.msgid.link/20251230034546.929452-1-zilin@seu.edu.cn +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/gpib/ni_usb/ni_usb_gpib.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/drivers/gpib/ni_usb/ni_usb_gpib.c b/drivers/gpib/ni_usb/ni_usb_gpib.c +index fdcaa6c00bfea..b6fddb437f552 100644 +--- a/drivers/gpib/ni_usb/ni_usb_gpib.c ++++ b/drivers/gpib/ni_usb/ni_usb_gpib.c +@@ -1780,7 +1780,7 @@ static int ni_usb_setup_init(struct gpib_board *board, struct ni_usb_register *w + i++; + if (i > NUM_INIT_WRITES) { + dev_err(&usb_dev->dev, "bug!, buffer overrun, i=%i\n", i); +- return 0; ++ return -EINVAL; + } + return i; + } +@@ -1799,10 +1799,12 @@ static int ni_usb_init(struct gpib_board *board) + return -ENOMEM; + + writes_len = ni_usb_setup_init(board, writes); +- if (writes_len) +- retval = ni_usb_write_registers(ni_priv, writes, writes_len, &ibsta); +- else +- return -EFAULT; ++ if (writes_len < 0) { ++ kfree(writes); ++ return writes_len; ++ } ++ ++ retval = ni_usb_write_registers(ni_priv, writes, writes_len, &ibsta); + kfree(writes); + if (retval) { + dev_err(&usb_dev->dev, "register write failed, retval=%i\n", retval); +-- +2.51.0 + diff --git a/queue-6.19/gpu-nova-core-check-for-overflow-to-dmatrfbase1.patch b/queue-6.19/gpu-nova-core-check-for-overflow-to-dmatrfbase1.patch new file mode 100644 index 0000000000..6383bf84a1 --- /dev/null +++ b/queue-6.19/gpu-nova-core-check-for-overflow-to-dmatrfbase1.patch @@ -0,0 +1,57 @@ +From 723ac9ab0e6345676a640127502cfaf6fde6d0d0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 14:16:46 -0600 +Subject: gpu: nova-core: check for overflow to DMATRFBASE1 + +From: Timur Tabi + +[ Upstream commit 5cf76277cdec872aef9ff2e9008ae129bb303787 ] + +The NV_PFALCON_FALCON_DMATRFBASE/1 register pair supports DMA addresses +up to 49 bits only, but the write to DMATRFBASE1 could exceed that. +To mitigate, check first that the DMA address will fit. + +Reviewed-by: John Hubbard +Reviewed-by: Joel Fernandes +Fixes: 69f5cd67ce41 ("gpu: nova-core: add falcon register definitions and base code") +Signed-off-by: Timur Tabi +Link: https://patch.msgid.link/20260107201647.2490140-1-ttabi@nvidia.com +[ Import ::kernel::dma::DmaMask. - Danilo ] +Signed-off-by: Danilo Krummrich +Signed-off-by: Sasha Levin +--- + drivers/gpu/nova-core/falcon.rs | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon.rs +index 82c661aef594f..3ab33ea36d9c8 100644 +--- a/drivers/gpu/nova-core/falcon.rs ++++ b/drivers/gpu/nova-core/falcon.rs +@@ -8,7 +8,10 @@ + + use kernel::{ + device, +- dma::DmaAddress, ++ dma::{ ++ DmaAddress, ++ DmaMask, // ++ }, + io::poll::read_poll_timeout, + prelude::*, + sync::aref::ARef, +@@ -472,6 +475,12 @@ fn dma_wr>( + return Err(EINVAL); + } + ++ // The DMATRFBASE/1 register pair only supports a 49-bit address. ++ if dma_start > DmaMask::new::<49>().value() { ++ dev_err!(self.dev, "DMA address {:#x} exceeds 49 bits\n", dma_start); ++ return Err(ERANGE); ++ } ++ + // DMA transfers can only be done in units of 256 bytes. Compute how many such transfers we + // need to perform. + let num_transfers = load_offsets.len.div_ceil(DMA_LEN); +-- +2.51.0 + diff --git a/queue-6.19/hfsplus-return-error-when-node-already-exists-in-hfs.patch b/queue-6.19/hfsplus-return-error-when-node-already-exists-in-hfs.patch new file mode 100644 index 0000000000..785666a211 --- /dev/null +++ b/queue-6.19/hfsplus-return-error-when-node-already-exists-in-hfs.patch @@ -0,0 +1,58 @@ +From 3b513d1eec6f82df9e5fe954c5cc2f0cbe3bf1bc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Dec 2025 02:19:38 +0530 +Subject: hfsplus: return error when node already exists in hfs_bnode_create + +From: Shardul Bankar + +[ Upstream commit d8a73cc46c8462a969a7516131feb3096f4c49d3 ] + +When hfs_bnode_create() finds that a node is already hashed (which should +not happen in normal operation), it currently returns the existing node +without incrementing its reference count. This causes a reference count +inconsistency that leads to a kernel panic when the node is later freed +in hfs_bnode_put(): + + kernel BUG at fs/hfsplus/bnode.c:676! + BUG_ON(!atomic_read(&node->refcnt)) + +This scenario can occur when hfs_bmap_alloc() attempts to allocate a node +that is already in use (e.g., when node 0's bitmap bit is incorrectly +unset), or due to filesystem corruption. + +Returning an existing node from a create path is not normal operation. + +Fix this by returning ERR_PTR(-EEXIST) instead of the node when it's +already hashed. This properly signals the error condition to callers, +which already check for IS_ERR() return values. + +Reported-by: syzbot+1c8ff72d0cd8a50dfeaa@syzkaller.appspotmail.com +Link: https://syzkaller.appspot.com/bug?extid=1c8ff72d0cd8a50dfeaa +Link: https://lore.kernel.org/all/784415834694f39902088fa8946850fc1779a318.camel@ibm.com/ +Fixes: 634725a92938 ("[PATCH] hfs: cleanup HFS+ prints") +Signed-off-by: Shardul Bankar +Reviewed-by: Viacheslav Dubeyko +Signed-off-by: Viacheslav Dubeyko +Link: https://lore.kernel.org/r/20251229204938.1907089-1-shardul.b@mpiricsoftware.com +Signed-off-by: Viacheslav Dubeyko +Signed-off-by: Sasha Levin +--- + fs/hfsplus/bnode.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/hfsplus/bnode.c b/fs/hfsplus/bnode.c +index 191661af96778..250a226336ea7 100644 +--- a/fs/hfsplus/bnode.c ++++ b/fs/hfsplus/bnode.c +@@ -629,7 +629,7 @@ struct hfs_bnode *hfs_bnode_create(struct hfs_btree *tree, u32 num) + if (node) { + pr_crit("new node %u already hashed?\n", num); + WARN_ON(1); +- return node; ++ return ERR_PTR(-EEXIST); + } + node = __hfs_bnode_create(tree, num); + if (!node) +-- +2.51.0 + diff --git a/queue-6.19/hid-intel-ish-hid-fix-null-ptr-deref-in-ishtp_bus_re.patch b/queue-6.19/hid-intel-ish-hid-fix-null-ptr-deref-in-ishtp_bus_re.patch new file mode 100644 index 0000000000..371f5bee10 --- /dev/null +++ b/queue-6.19/hid-intel-ish-hid-fix-null-ptr-deref-in-ishtp_bus_re.patch @@ -0,0 +1,50 @@ +From 431c798148eca3b9e2ea61c5edf55356baa688fd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 13:34:56 +0800 +Subject: HID: intel-ish-hid: fix NULL-ptr-deref in + ishtp_bus_remove_all_clients + +From: Ryan Lin + +[ Upstream commit 56f7db581ee73af53cd512e00a6261a025bf1d58 ] + +During a warm reset flow, the cl->device pointer may be NULL if the +reset occurs while clients are still being enumerated. Accessing +cl->device->reference_count without a NULL check leads to a kernel panic. + +This issue was identified during multi-unit warm reboot stress clycles. +Add a defensive NULL check for cl->device to ensure stability under +such intensive testing conditions. + +KASAN: null-ptr-deref in range [0000000000000000-0000000000000007] +Workqueue: ish_fw_update_wq fw_reset_work_fn + +Call Trace: + ishtp_bus_remove_all_clients+0xbe/0x130 [intel_ishtp] + ishtp_reset_handler+0x85/0x1a0 [intel_ishtp] + fw_reset_work_fn+0x8a/0xc0 [intel_ish_ipc] + +Fixes: 3703f53b99e4a ("HID: intel_ish-hid: ISH Transport layer") +Signed-off-by: Ryan Lin +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/intel-ish-hid/ishtp/bus.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/hid/intel-ish-hid/ishtp/bus.c b/drivers/hid/intel-ish-hid/ishtp/bus.c +index c3915f3a060ea..b890fbf97a75c 100644 +--- a/drivers/hid/intel-ish-hid/ishtp/bus.c ++++ b/drivers/hid/intel-ish-hid/ishtp/bus.c +@@ -730,7 +730,7 @@ void ishtp_bus_remove_all_clients(struct ishtp_device *ishtp_dev, + spin_lock_irqsave(&ishtp_dev->cl_list_lock, flags); + list_for_each_entry(cl, &ishtp_dev->cl_list, link) { + cl->state = ISHTP_CL_DISCONNECTED; +- if (warm_reset && cl->device->reference_count) ++ if (warm_reset && cl->device && cl->device->reference_count) + continue; + + /* +-- +2.51.0 + diff --git a/queue-6.19/hid-intel-thc-hid-intel-thc-fix-wrong-register-field.patch b/queue-6.19/hid-intel-thc-hid-intel-thc-fix-wrong-register-field.patch new file mode 100644 index 0000000000..886d6be82e --- /dev/null +++ b/queue-6.19/hid-intel-thc-hid-intel-thc-fix-wrong-register-field.patch @@ -0,0 +1,46 @@ +From 1dad447f9eac519641d08f30d2e5a9291f6e9888 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 11:01:44 +0800 +Subject: HID: Intel-thc-hid: Intel-thc: Fix wrong register fields updating + +From: Even Xu + +[ Upstream commit e4aa247d94a04574297a8bc9fabbede0dcba1ab6 ] + +Clear the target bit fields in register before setting new values. This +ensures proper field updates by removing any existing bits that might +interfere with the new configuration. + +Fixes: 22da60f0304b ("HID: Intel-thc-hid: Intel-thc: Introduce interrupt delay control") +Fixes: 45e92a093099 ("HID: Intel-thc-hid: Intel-thc: Introduce max input size control") +Signed-off-by: Even Xu +Tested-by: Rui Zhang +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c +index 7e220a4c5ded7..d8e195189e4bf 100644 +--- a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c ++++ b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c +@@ -1597,6 +1597,7 @@ int thc_i2c_set_rx_max_size(struct thc_device *dev, u32 max_rx_size) + if (ret) + return ret; + ++ val = val & ~THC_M_PRT_SPI_ICRRD_OPCODE_I2C_MAX_SIZE; + val |= FIELD_PREP(THC_M_PRT_SPI_ICRRD_OPCODE_I2C_MAX_SIZE, max_rx_size); + + ret = regmap_write(dev->thc_regmap, THC_M_PRT_SPI_ICRRD_OPCODE_OFFSET, val); +@@ -1667,6 +1668,7 @@ int thc_i2c_set_rx_int_delay(struct thc_device *dev, u32 delay_us) + return ret; + + /* THC hardware counts at 10us unit */ ++ val = val & ~THC_M_PRT_SPI_ICRRD_OPCODE_I2C_INTERVAL; + val |= FIELD_PREP(THC_M_PRT_SPI_ICRRD_OPCODE_I2C_INTERVAL, DIV_ROUND_UP(delay_us, 10)); + + ret = regmap_write(dev->thc_regmap, THC_M_PRT_SPI_ICRRD_OPCODE_OFFSET, val); +-- +2.51.0 + diff --git a/queue-6.19/hid-playstation-add-missing-check-for-input_ff_creat.patch b/queue-6.19/hid-playstation-add-missing-check-for-input_ff_creat.patch new file mode 100644 index 0000000000..17a664640a --- /dev/null +++ b/queue-6.19/hid-playstation-add-missing-check-for-input_ff_creat.patch @@ -0,0 +1,41 @@ +From 9b099a9d0afd9ff613753bac8bb98623b3257654 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 17 Nov 2025 16:28:08 +0800 +Subject: HID: playstation: Add missing check for input_ff_create_memless + +From: Haotian Zhang + +[ Upstream commit e6807641ac94e832988655a1c0e60ccc806b76dc ] + +The ps_gamepad_create() function calls input_ff_create_memless() +without verifying its return value, which can lead to incorrect +behavior or potential crashes when FF effects are triggered. + +Add a check for the return value of input_ff_create_memless(). + +Fixes: 51151098d7ab ("HID: playstation: add DualSense classic rumble support.") +Signed-off-by: Haotian Zhang +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-playstation.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c +index e4dfcf26b04e7..2ec6d4445e84b 100644 +--- a/drivers/hid/hid-playstation.c ++++ b/drivers/hid/hid-playstation.c +@@ -774,7 +774,9 @@ ps_gamepad_create(struct hid_device *hdev, + #if IS_ENABLED(CONFIG_PLAYSTATION_FF) + if (play_effect) { + input_set_capability(gamepad, EV_FF, FF_RUMBLE); +- input_ff_create_memless(gamepad, NULL, play_effect); ++ ret = input_ff_create_memless(gamepad, NULL, play_effect); ++ if (ret) ++ return ERR_PTR(ret); + } + #endif + +-- +2.51.0 + diff --git a/queue-6.19/hisi_acc_vfio_pci-fix-vf-reset-timeout-issue.patch b/queue-6.19/hisi_acc_vfio_pci-fix-vf-reset-timeout-issue.patch new file mode 100644 index 0000000000..db81b4a472 --- /dev/null +++ b/queue-6.19/hisi_acc_vfio_pci-fix-vf-reset-timeout-issue.patch @@ -0,0 +1,93 @@ +From fbaf271442c84f41240385f694e08567746592d4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 10:02:02 +0800 +Subject: hisi_acc_vfio_pci: fix VF reset timeout issue + +From: Weili Qian + +[ Upstream commit a22099ed7936f8e8dabbdbadd97d56047797116b ] + +If device error occurs during live migration, qemu will +reset the VF. At this time, VF reset and device reset are performed +simultaneously. The VF reset will timeout. Therefore, the QM_RESETTING +flag is used to ensure that VF reset and device reset are performed +serially. + +Fixes: b0eed085903e ("hisi_acc_vfio_pci: Add support for VFIO live migration") +Signed-off-by: Weili Qian +Link: https://lore.kernel.org/r/20260122020205.2884497-2-liulongfang@huawei.com +Signed-off-by: Alex Williamson +Signed-off-by: Sasha Levin +--- + .../vfio/pci/hisilicon/hisi_acc_vfio_pci.c | 24 +++++++++++++++++++ + .../vfio/pci/hisilicon/hisi_acc_vfio_pci.h | 2 ++ + 2 files changed, 26 insertions(+) + +diff --git a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c +index cf45f6370c369..d1e8053640a98 100644 +--- a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c ++++ b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c +@@ -1188,9 +1188,32 @@ hisi_acc_vfio_pci_get_device_state(struct vfio_device *vdev, + return 0; + } + ++static void hisi_acc_vf_pci_reset_prepare(struct pci_dev *pdev) ++{ ++ struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_drvdata(pdev); ++ struct hisi_qm *qm = hisi_acc_vdev->pf_qm; ++ struct device *dev = &qm->pdev->dev; ++ u32 delay = 0; ++ ++ /* All reset requests need to be queued for processing */ ++ while (test_and_set_bit(QM_RESETTING, &qm->misc_ctl)) { ++ msleep(1); ++ if (++delay > QM_RESET_WAIT_TIMEOUT) { ++ dev_err(dev, "reset prepare failed\n"); ++ return; ++ } ++ } ++ ++ hisi_acc_vdev->set_reset_flag = true; ++} ++ + static void hisi_acc_vf_pci_aer_reset_done(struct pci_dev *pdev) + { + struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_drvdata(pdev); ++ struct hisi_qm *qm = hisi_acc_vdev->pf_qm; ++ ++ if (hisi_acc_vdev->set_reset_flag) ++ clear_bit(QM_RESETTING, &qm->misc_ctl); + + if (hisi_acc_vdev->core_device.vdev.migration_flags != + VFIO_MIGRATION_STOP_COPY) +@@ -1734,6 +1757,7 @@ static const struct pci_device_id hisi_acc_vfio_pci_table[] = { + MODULE_DEVICE_TABLE(pci, hisi_acc_vfio_pci_table); + + static const struct pci_error_handlers hisi_acc_vf_err_handlers = { ++ .reset_prepare = hisi_acc_vf_pci_reset_prepare, + .reset_done = hisi_acc_vf_pci_aer_reset_done, + .error_detected = vfio_pci_core_aer_err_detected, + }; +diff --git a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h +index cd55eba64dfb2..a3d91a31e3d88 100644 +--- a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h ++++ b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h +@@ -27,6 +27,7 @@ + + #define ERROR_CHECK_TIMEOUT 100 + #define CHECK_DELAY_TIME 100 ++#define QM_RESET_WAIT_TIMEOUT 60000 + + #define QM_SQC_VFT_BASE_SHIFT_V2 28 + #define QM_SQC_VFT_BASE_MASK_V2 GENMASK(15, 0) +@@ -128,6 +129,7 @@ struct hisi_acc_vf_migration_file { + struct hisi_acc_vf_core_device { + struct vfio_pci_core_device core_device; + u8 match_done; ++ bool set_reset_flag; + /* + * io_base is only valid when dev_opened is true, + * which is protected by open_mutex. +-- +2.51.0 + diff --git a/queue-6.19/hrtimer-fix-trace-oddity.patch b/queue-6.19/hrtimer-fix-trace-oddity.patch new file mode 100644 index 0000000000..097ac77ff4 --- /dev/null +++ b/queue-6.19/hrtimer-fix-trace-oddity.patch @@ -0,0 +1,43 @@ +From 975a045fa93cef5fd98f5c9e7fce243d72cb9203 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 11:38:34 +0100 +Subject: hrtimer: Fix trace oddity + +From: Thomas Gleixner + +[ Upstream commit 5d6446f409da00e5a389125ddb5ce09f5bc404c9 ] + +It turns out that __run_hrtimer() will trace like: + + -0 [032] d.h2. 20705.474563: hrtimer_cancel: hrtimer=0xff2db8f77f8226e8 + -0 [032] d.h1. 20705.474563: hrtimer_expire_entry: hrtimer=0xff2db8f77f8226e8 now=20699452001850 function=tick_nohz_handler/0x0 + +Which is a bit nonsensical, the timer doesn't get canceled on +expiration. The cause is the use of the incorrect debug helper. + +Fixes: c6a2a1770245 ("hrtimer: Add tracepoint for hrtimers") +Reported-by: Peter Zijlstra (Intel) +Signed-off-by: Thomas Gleixner +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260121143208.219595606@infradead.org +Signed-off-by: Sasha Levin +--- + kernel/time/hrtimer.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c +index 0e4bc1ca15ff1..84c8ab2a0cebf 100644 +--- a/kernel/time/hrtimer.c ++++ b/kernel/time/hrtimer.c +@@ -1742,7 +1742,7 @@ static void __run_hrtimer(struct hrtimer_cpu_base *cpu_base, + + lockdep_assert_held(&cpu_base->lock); + +- debug_deactivate(timer); ++ debug_hrtimer_deactivate(timer); + base->running = timer; + + /* +-- +2.51.0 + diff --git a/queue-6.19/hwmon-pmbus-mpq8785-fix-vout_mode-mismatch-during-id.patch b/queue-6.19/hwmon-pmbus-mpq8785-fix-vout_mode-mismatch-during-id.patch new file mode 100644 index 0000000000..a85ed50247 --- /dev/null +++ b/queue-6.19/hwmon-pmbus-mpq8785-fix-vout_mode-mismatch-during-id.patch @@ -0,0 +1,81 @@ +From 4678f12620be39d2a3ab25a423e67ab0c2818b51 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Feb 2026 15:26:34 +0800 +Subject: hwmon: (pmbus/mpq8785) fix VOUT_MODE mismatch during identification + +From: Carl Lee + +[ Upstream commit 9e33c1dba22431bea9b2bf48adf56859e52fc7ec ] + +When MPQ8785 reports VOUT_MODE as VID mode, mpq8785_identify() +configures the driver for direct mode. The subsequent +pmbus_identify_common() check then fails due to a mismatch +between the reported mode and the configured mode, causing +device initialization to fail. + +Override the reported VOUT_MODE to direct mode to keep the +driver configuration consistent with the reported mode and +allow successful device initialization. + +This does not change how voltages are interpreted, but avoids +a false identification failure caused by mismatched mode +handling. + +Fixes: f20b4a931130c ("hwmon: Add driver for MPS MPQ8785 Synchronous Step-Down Converter") +Signed-off-by: Carl Lee +Link: https://lore.kernel.org/r/20260210-dt-bindings-hwmon-pmbus-mpq8785-add-mpq8786-support-v3-1-84636ccfe76f@amd.com +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + drivers/hwmon/pmbus/mpq8785.c | 28 ++++++++++++++++++++++++++++ + 1 file changed, 28 insertions(+) + +diff --git a/drivers/hwmon/pmbus/mpq8785.c b/drivers/hwmon/pmbus/mpq8785.c +index 1f56aaf4dde80..87bd039c77b9b 100644 +--- a/drivers/hwmon/pmbus/mpq8785.c ++++ b/drivers/hwmon/pmbus/mpq8785.c +@@ -47,6 +47,33 @@ static int mpq8785_identify(struct i2c_client *client, + return 0; + }; + ++static int mpq8785_read_byte_data(struct i2c_client *client, int page, int reg) ++{ ++ int ret; ++ ++ switch (reg) { ++ case PMBUS_VOUT_MODE: ++ ret = pmbus_read_byte_data(client, page, reg); ++ if (ret < 0) ++ return ret; ++ ++ if ((ret >> 5) == 1) { ++ /* ++ * The MPQ8785 chip reports VOUT_MODE as VID mode, but the driver ++ * treats VID as direct mode. Without this, identification would fail ++ * due to mode mismatch. ++ * This override ensures the reported mode matches the driver ++ * configuration, allowing successful initialization. ++ */ ++ return PB_VOUT_MODE_DIRECT; ++ } ++ ++ return ret; ++ default: ++ return -ENODATA; ++ } ++} ++ + static int mpm82504_read_word_data(struct i2c_client *client, int page, + int phase, int reg) + { +@@ -129,6 +156,7 @@ static int mpq8785_probe(struct i2c_client *client) + break; + case mpq8785: + info->identify = mpq8785_identify; ++ info->read_byte_data = mpq8785_read_byte_data; + break; + default: + return -ENODEV; +-- +2.51.0 + diff --git a/queue-6.19/hwrng-airoha-set-rng-quality-to-900.patch b/queue-6.19/hwrng-airoha-set-rng-quality-to-900.patch new file mode 100644 index 0000000000..918432f05e --- /dev/null +++ b/queue-6.19/hwrng-airoha-set-rng-quality-to-900.patch @@ -0,0 +1,67 @@ +From 2470f1ca6e6c752ba95bdaa2717b3bc984a9a902 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Jan 2026 21:41:49 +0100 +Subject: hwrng: airoha - set rng quality to 900 + +From: Aleksander Jan Bajkowski + +[ Upstream commit c0008a29a006091d7f9d288620c2456afa23ff27 ] + +Airoha uses RAW mode to collect noise from the TRNG. These appear to +be unprocessed oscillations from the tero loop. For this reason, they +do not have a perfect distribution and entropy. Simple noise compression +reduces its size by 9%, so setting the quality to 900 seems reasonable. +The same value is used by the downstream driver. + +Compare the size before and after compression: +$ ls -l random_airoha* +-rw-r--r-- 1 aleksander aleksander 76546048 Jan 3 23:43 random_airoha +-rw-rw-r-- 1 aleksander aleksander 69783562 Jan 5 20:23 random_airoha.zip + +FIPS test results: +$ cat random_airoha | rngtest -c 10000 +rngtest 2.6 +Copyright (c) 2004 by Henrique de Moraes Holschuh +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +rngtest: starting FIPS tests... +rngtest: bits received from input: 200000032 +rngtest: FIPS 140-2 successes: 0 +rngtest: FIPS 140-2 failures: 10000 +rngtest: FIPS 140-2(2001-10-10) Monobit: 9957 +rngtest: FIPS 140-2(2001-10-10) Poker: 10000 +rngtest: FIPS 140-2(2001-10-10) Runs: 10000 +rngtest: FIPS 140-2(2001-10-10) Long run: 4249 +rngtest: FIPS 140-2(2001-10-10) Continuous run: 0 +rngtest: input channel speed: (min=953.674; avg=27698.935; max=19073.486)Mibits/s +rngtest: FIPS tests speed: (min=59.791; avg=298.028; max=328.853)Mibits/s +rngtest: Program run time: 647638 microseconds + +In general, these data look like real noise, but with lower entropy +than expected. + +Fixes: e53ca8efcc5e ("hwrng: airoha - add support for Airoha EN7581 TRNG") +Suggested-by: Benjamin Larsson +Signed-off-by: Aleksander Jan Bajkowski +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/char/hw_random/airoha-trng.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/char/hw_random/airoha-trng.c b/drivers/char/hw_random/airoha-trng.c +index 1dbfa9505c214..9a648f6d9fd40 100644 +--- a/drivers/char/hw_random/airoha-trng.c ++++ b/drivers/char/hw_random/airoha-trng.c +@@ -212,6 +212,7 @@ static int airoha_trng_probe(struct platform_device *pdev) + trng->rng.init = airoha_trng_init; + trng->rng.cleanup = airoha_trng_cleanup; + trng->rng.read = airoha_trng_read; ++ trng->rng.quality = 900; + + ret = devm_hwrng_register(dev, &trng->rng); + if (ret) { +-- +2.51.0 + diff --git a/queue-6.19/hwrng-core-use-rcu-and-work_struct-to-fix-race-condi.patch b/queue-6.19/hwrng-core-use-rcu-and-work_struct-to-fix-race-condi.patch new file mode 100644 index 0000000000..9c9413d83e --- /dev/null +++ b/queue-6.19/hwrng-core-use-rcu-and-work_struct-to-fix-race-condi.patch @@ -0,0 +1,446 @@ +From 17cb4eaaf9241cfa154416b38f9f668f2c3682aa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 06:50:16 +0900 +Subject: hwrng: core - use RCU and work_struct to fix race condition + +From: Lianjie Wang + +[ Upstream commit cc2f39d6ac48e6e3cb2d6240bc0d6df839dd0828 ] + +Currently, hwrng_fill is not cleared until the hwrng_fillfn() thread +exits. Since hwrng_unregister() reads hwrng_fill outside the rng_mutex +lock, a concurrent hwrng_unregister() may call kthread_stop() again on +the same task. + +Additionally, if hwrng_unregister() is called immediately after +hwrng_register(), the stopped thread may have never been executed. Thus, +hwrng_fill remains dirty even after hwrng_unregister() returns. In this +case, subsequent calls to hwrng_register() will fail to start new +threads, and hwrng_unregister() will call kthread_stop() on the same +freed task. In both cases, a use-after-free occurs: + +refcount_t: addition on 0; use-after-free. +WARNING: ... at lib/refcount.c:25 refcount_warn_saturate+0xec/0x1c0 +Call Trace: + kthread_stop+0x181/0x360 + hwrng_unregister+0x288/0x380 + virtrng_remove+0xe3/0x200 + +This patch fixes the race by protecting the global hwrng_fill pointer +inside the rng_mutex lock, so that hwrng_fillfn() thread is stopped only +once, and calls to kthread_run() and kthread_stop() are serialized +with the lock held. + +To avoid deadlock in hwrng_fillfn() while being stopped with the lock +held, we convert current_rng to RCU, so that get_current_rng() can read +current_rng without holding the lock. To remove the lock from put_rng(), +we also delay the actual cleanup into a work_struct. + +Since get_current_rng() no longer returns ERR_PTR values, the IS_ERR() +checks are removed from its callers. + +With hwrng_fill protected by the rng_mutex lock, hwrng_fillfn() can no +longer clear hwrng_fill itself. Therefore, if hwrng_fillfn() returns +directly after current_rng is dropped, kthread_stop() would be called on +a freed task_struct later. To fix this, hwrng_fillfn() calls schedule() +now to keep the task alive until being stopped. The kthread_stop() call +is also moved from hwrng_unregister() to drop_current_rng(), ensuring +kthread_stop() is called on all possible paths where current_rng becomes +NULL, so that the thread would not wait forever. + +Fixes: be4000bc4644 ("hwrng: create filler thread") +Suggested-by: Herbert Xu +Signed-off-by: Lianjie Wang +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/char/hw_random/core.c | 168 +++++++++++++++++++++------------- + include/linux/hw_random.h | 2 + + 2 files changed, 107 insertions(+), 63 deletions(-) + +diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c +index 96d7fe41b373d..aba92d777f726 100644 +--- a/drivers/char/hw_random/core.c ++++ b/drivers/char/hw_random/core.c +@@ -20,23 +20,25 @@ + #include + #include + #include ++#include + #include + #include + #include + #include + #include ++#include + + #define RNG_MODULE_NAME "hw_random" + + #define RNG_BUFFER_SIZE (SMP_CACHE_BYTES < 32 ? 32 : SMP_CACHE_BYTES) + +-static struct hwrng *current_rng; ++static struct hwrng __rcu *current_rng; + /* the current rng has been explicitly chosen by user via sysfs */ + static int cur_rng_set_by_user; + static struct task_struct *hwrng_fill; + /* list of registered rngs */ + static LIST_HEAD(rng_list); +-/* Protects rng_list and current_rng */ ++/* Protects rng_list, hwrng_fill and updating on current_rng */ + static DEFINE_MUTEX(rng_mutex); + /* Protects rng read functions, data_avail, rng_buffer and rng_fillbuf */ + static DEFINE_MUTEX(reading_mutex); +@@ -64,18 +66,39 @@ static size_t rng_buffer_size(void) + return RNG_BUFFER_SIZE; + } + +-static inline void cleanup_rng(struct kref *kref) ++static void cleanup_rng_work(struct work_struct *work) + { +- struct hwrng *rng = container_of(kref, struct hwrng, ref); ++ struct hwrng *rng = container_of(work, struct hwrng, cleanup_work); ++ ++ /* ++ * Hold rng_mutex here so we serialize in case they set_current_rng ++ * on rng again immediately. ++ */ ++ mutex_lock(&rng_mutex); ++ ++ /* Skip if rng has been reinitialized. */ ++ if (kref_read(&rng->ref)) { ++ mutex_unlock(&rng_mutex); ++ return; ++ } + + if (rng->cleanup) + rng->cleanup(rng); + + complete(&rng->cleanup_done); ++ mutex_unlock(&rng_mutex); ++} ++ ++static inline void cleanup_rng(struct kref *kref) ++{ ++ struct hwrng *rng = container_of(kref, struct hwrng, ref); ++ ++ schedule_work(&rng->cleanup_work); + } + + static int set_current_rng(struct hwrng *rng) + { ++ struct hwrng *old_rng; + int err; + + BUG_ON(!mutex_is_locked(&rng_mutex)); +@@ -84,8 +107,14 @@ static int set_current_rng(struct hwrng *rng) + if (err) + return err; + +- drop_current_rng(); +- current_rng = rng; ++ old_rng = rcu_dereference_protected(current_rng, ++ lockdep_is_held(&rng_mutex)); ++ rcu_assign_pointer(current_rng, rng); ++ ++ if (old_rng) { ++ synchronize_rcu(); ++ kref_put(&old_rng->ref, cleanup_rng); ++ } + + /* if necessary, start hwrng thread */ + if (!hwrng_fill) { +@@ -101,47 +130,56 @@ static int set_current_rng(struct hwrng *rng) + + static void drop_current_rng(void) + { +- BUG_ON(!mutex_is_locked(&rng_mutex)); +- if (!current_rng) ++ struct hwrng *rng; ++ ++ rng = rcu_dereference_protected(current_rng, ++ lockdep_is_held(&rng_mutex)); ++ if (!rng) + return; + ++ RCU_INIT_POINTER(current_rng, NULL); ++ synchronize_rcu(); ++ ++ if (hwrng_fill) { ++ kthread_stop(hwrng_fill); ++ hwrng_fill = NULL; ++ } ++ + /* decrease last reference for triggering the cleanup */ +- kref_put(¤t_rng->ref, cleanup_rng); +- current_rng = NULL; ++ kref_put(&rng->ref, cleanup_rng); + } + +-/* Returns ERR_PTR(), NULL or refcounted hwrng */ ++/* Returns NULL or refcounted hwrng */ + static struct hwrng *get_current_rng_nolock(void) + { +- if (current_rng) +- kref_get(¤t_rng->ref); ++ struct hwrng *rng; ++ ++ rng = rcu_dereference_protected(current_rng, ++ lockdep_is_held(&rng_mutex)); ++ if (rng) ++ kref_get(&rng->ref); + +- return current_rng; ++ return rng; + } + + static struct hwrng *get_current_rng(void) + { + struct hwrng *rng; + +- if (mutex_lock_interruptible(&rng_mutex)) +- return ERR_PTR(-ERESTARTSYS); ++ rcu_read_lock(); ++ rng = rcu_dereference(current_rng); ++ if (rng) ++ kref_get(&rng->ref); + +- rng = get_current_rng_nolock(); ++ rcu_read_unlock(); + +- mutex_unlock(&rng_mutex); + return rng; + } + + static void put_rng(struct hwrng *rng) + { +- /* +- * Hold rng_mutex here so we serialize in case they set_current_rng +- * on rng again immediately. +- */ +- mutex_lock(&rng_mutex); + if (rng) + kref_put(&rng->ref, cleanup_rng); +- mutex_unlock(&rng_mutex); + } + + static int hwrng_init(struct hwrng *rng) +@@ -213,10 +251,6 @@ static ssize_t rng_dev_read(struct file *filp, char __user *buf, + + while (size) { + rng = get_current_rng(); +- if (IS_ERR(rng)) { +- err = PTR_ERR(rng); +- goto out; +- } + if (!rng) { + err = -ENODEV; + goto out; +@@ -303,7 +337,7 @@ static struct miscdevice rng_miscdev = { + + static int enable_best_rng(void) + { +- struct hwrng *rng, *new_rng = NULL; ++ struct hwrng *rng, *cur_rng, *new_rng = NULL; + int ret = -ENODEV; + + BUG_ON(!mutex_is_locked(&rng_mutex)); +@@ -321,7 +355,9 @@ static int enable_best_rng(void) + new_rng = rng; + } + +- ret = ((new_rng == current_rng) ? 0 : set_current_rng(new_rng)); ++ cur_rng = rcu_dereference_protected(current_rng, ++ lockdep_is_held(&rng_mutex)); ++ ret = ((new_rng == cur_rng) ? 0 : set_current_rng(new_rng)); + if (!ret) + cur_rng_set_by_user = 0; + +@@ -371,8 +407,6 @@ static ssize_t rng_current_show(struct device *dev, + struct hwrng *rng; + + rng = get_current_rng(); +- if (IS_ERR(rng)) +- return PTR_ERR(rng); + + ret = sysfs_emit(buf, "%s\n", rng ? rng->name : "none"); + put_rng(rng); +@@ -416,8 +450,6 @@ static ssize_t rng_quality_show(struct device *dev, + struct hwrng *rng; + + rng = get_current_rng(); +- if (IS_ERR(rng)) +- return PTR_ERR(rng); + + if (!rng) /* no need to put_rng */ + return -ENODEV; +@@ -432,6 +464,7 @@ static ssize_t rng_quality_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) + { ++ struct hwrng *rng; + u16 quality; + int ret = -EINVAL; + +@@ -448,12 +481,13 @@ static ssize_t rng_quality_store(struct device *dev, + goto out; + } + +- if (!current_rng) { ++ rng = rcu_dereference_protected(current_rng, lockdep_is_held(&rng_mutex)); ++ if (!rng) { + ret = -ENODEV; + goto out; + } + +- current_rng->quality = quality; ++ rng->quality = quality; + current_quality = quality; /* obsolete */ + + /* the best available RNG may have changed */ +@@ -489,8 +523,20 @@ static int hwrng_fillfn(void *unused) + struct hwrng *rng; + + rng = get_current_rng(); +- if (IS_ERR(rng) || !rng) ++ if (!rng) { ++ /* ++ * Keep the task_struct alive until kthread_stop() ++ * is called to avoid UAF in drop_current_rng(). ++ */ ++ while (!kthread_should_stop()) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ if (!kthread_should_stop()) ++ schedule(); ++ } ++ set_current_state(TASK_RUNNING); + break; ++ } ++ + mutex_lock(&reading_mutex); + rc = rng_get_data(rng, rng_fillbuf, + rng_buffer_size(), 1); +@@ -518,14 +564,13 @@ static int hwrng_fillfn(void *unused) + add_hwgenerator_randomness((void *)rng_fillbuf, rc, + entropy >> 10, true); + } +- hwrng_fill = NULL; + return 0; + } + + int hwrng_register(struct hwrng *rng) + { + int err = -EINVAL; +- struct hwrng *tmp; ++ struct hwrng *cur_rng, *tmp; + + if (!rng->name || (!rng->data_read && !rng->read)) + goto out; +@@ -540,6 +585,7 @@ int hwrng_register(struct hwrng *rng) + } + list_add_tail(&rng->list, &rng_list); + ++ INIT_WORK(&rng->cleanup_work, cleanup_rng_work); + init_completion(&rng->cleanup_done); + complete(&rng->cleanup_done); + init_completion(&rng->dying); +@@ -547,16 +593,19 @@ int hwrng_register(struct hwrng *rng) + /* Adjust quality field to always have a proper value */ + rng->quality = min3(default_quality, 1024, rng->quality ?: 1024); + +- if (!cur_rng_set_by_user && +- (!current_rng || rng->quality > current_rng->quality)) { +- /* +- * Set new rng as current as the new rng source +- * provides better entropy quality and was not +- * chosen by userspace. +- */ +- err = set_current_rng(rng); +- if (err) +- goto out_unlock; ++ if (!cur_rng_set_by_user) { ++ cur_rng = rcu_dereference_protected(current_rng, ++ lockdep_is_held(&rng_mutex)); ++ if (!cur_rng || rng->quality > cur_rng->quality) { ++ /* ++ * Set new rng as current as the new rng source ++ * provides better entropy quality and was not ++ * chosen by userspace. ++ */ ++ err = set_current_rng(rng); ++ if (err) ++ goto out_unlock; ++ } + } + mutex_unlock(&rng_mutex); + return 0; +@@ -569,14 +618,17 @@ EXPORT_SYMBOL_GPL(hwrng_register); + + void hwrng_unregister(struct hwrng *rng) + { +- struct hwrng *new_rng; ++ struct hwrng *cur_rng; + int err; + + mutex_lock(&rng_mutex); + + list_del(&rng->list); + complete_all(&rng->dying); +- if (current_rng == rng) { ++ ++ cur_rng = rcu_dereference_protected(current_rng, ++ lockdep_is_held(&rng_mutex)); ++ if (cur_rng == rng) { + err = enable_best_rng(); + if (err) { + drop_current_rng(); +@@ -584,17 +636,7 @@ void hwrng_unregister(struct hwrng *rng) + } + } + +- new_rng = get_current_rng_nolock(); +- if (list_empty(&rng_list)) { +- mutex_unlock(&rng_mutex); +- if (hwrng_fill) +- kthread_stop(hwrng_fill); +- } else +- mutex_unlock(&rng_mutex); +- +- if (new_rng) +- put_rng(new_rng); +- ++ mutex_unlock(&rng_mutex); + wait_for_completion(&rng->cleanup_done); + } + EXPORT_SYMBOL_GPL(hwrng_unregister); +@@ -682,7 +724,7 @@ static int __init hwrng_modinit(void) + static void __exit hwrng_modexit(void) + { + mutex_lock(&rng_mutex); +- BUG_ON(current_rng); ++ WARN_ON(rcu_access_pointer(current_rng)); + kfree(rng_buffer); + kfree(rng_fillbuf); + mutex_unlock(&rng_mutex); +diff --git a/include/linux/hw_random.h b/include/linux/hw_random.h +index b424555753b11..b77bc55a4cf35 100644 +--- a/include/linux/hw_random.h ++++ b/include/linux/hw_random.h +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + + /** + * struct hwrng - Hardware Random Number Generator driver +@@ -48,6 +49,7 @@ struct hwrng { + /* internal. */ + struct list_head list; + struct kref ref; ++ struct work_struct cleanup_work; + struct completion cleanup_done; + struct completion dying; + }; +-- +2.51.0 + diff --git a/queue-6.19/hwspinlock-omap-handle-devm_pm_runtime_enable-errors.patch b/queue-6.19/hwspinlock-omap-handle-devm_pm_runtime_enable-errors.patch new file mode 100644 index 0000000000..555e1f3b8a --- /dev/null +++ b/queue-6.19/hwspinlock-omap-handle-devm_pm_runtime_enable-errors.patch @@ -0,0 +1,44 @@ +From f3dec2c7d388db62d92851697c3a5cd63cbc0080 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 24 Nov 2025 18:48:05 +0800 +Subject: hwspinlock: omap: Handle devm_pm_runtime_enable() errors + +From: Haotian Zhang + +[ Upstream commit 3bd4edd67b034f8e1f61c86e0eb098de6179e3f2 ] + +Although unlikely, devm_pm_runtime_enable() can fail due to memory +allocations. Without proper error handling, the subsequent +pm_runtime_resume_and_get() call may operate on incorrectly +initialized runtime PM state. + +Add error handling to check the return value of +devm_pm_runtime_enable() and return on failure. + +Fixes: 25f7d74d4514 ("hwspinlock: omap: Use devm_pm_runtime_enable() helper") +Signed-off-by: Haotian Zhang +Link: https://patch.msgid.link/20251124104805.135-1-vulab@iscas.ac.cn +Signed-off-by: Kevin Hilman +Signed-off-by: Sasha Levin +--- + drivers/hwspinlock/omap_hwspinlock.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/hwspinlock/omap_hwspinlock.c b/drivers/hwspinlock/omap_hwspinlock.c +index 27b47b8623c09..2d8de835bc242 100644 +--- a/drivers/hwspinlock/omap_hwspinlock.c ++++ b/drivers/hwspinlock/omap_hwspinlock.c +@@ -88,7 +88,9 @@ static int omap_hwspinlock_probe(struct platform_device *pdev) + * make sure the module is enabled and clocked before reading + * the module SYSSTATUS register + */ +- devm_pm_runtime_enable(&pdev->dev); ++ ret = devm_pm_runtime_enable(&pdev->dev); ++ if (ret) ++ return ret; + ret = pm_runtime_resume_and_get(&pdev->dev); + if (ret < 0) + return ret; +-- +2.51.0 + diff --git a/queue-6.19/i3c-dw-fix-memory-leak-in-dw_i3c_master_i2c_xfers.patch b/queue-6.19/i3c-dw-fix-memory-leak-in-dw_i3c_master_i2c_xfers.patch new file mode 100644 index 0000000000..c28bb6ff78 --- /dev/null +++ b/queue-6.19/i3c-dw-fix-memory-leak-in-dw_i3c_master_i2c_xfers.patch @@ -0,0 +1,45 @@ +From 0577d85a060e43653ae841124635eb561651644d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 08:11:21 +0000 +Subject: i3c: dw: Fix memory leak in dw_i3c_master_i2c_xfers() + +From: Zilin Guan + +[ Upstream commit 2537089413514caaa9a5fdeeac3a34d45100f747 ] + +The dw_i3c_master_i2c_xfers() function allocates memory for the xfer +structure using dw_i3c_master_alloc_xfer(). If pm_runtime_resume_and_get() +fails, the function returns without freeing the allocated xfer, resulting +in a memory leak. + +Add a dw_i3c_master_free_xfer() call to the error path to ensure the +allocated memory is properly freed. + +Compile tested only. Issue found using a prototype static analysis tool +and code review. + +Fixes: 62fe9d06f570 ("i3c: dw: Add power management support") +Signed-off-by: Zilin Guan +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260126081121.644099-1-zilin@seu.edu.cn +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master/dw-i3c-master.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c +index d5b0704040562..4033bc16677ff 100644 +--- a/drivers/i3c/master/dw-i3c-master.c ++++ b/drivers/i3c/master/dw-i3c-master.c +@@ -1099,6 +1099,7 @@ static int dw_i3c_master_i2c_xfers(struct i2c_dev_desc *dev, + dev_err(master->dev, + "<%s> cannot resume i3c bus master, err: %d\n", + __func__, ret); ++ dw_i3c_master_free_xfer(xfer); + return ret; + } + +-- +2.51.0 + diff --git a/queue-6.19/i3c-dw-initialize-spinlock-to-avoid-upsetting-lockde.patch b/queue-6.19/i3c-dw-initialize-spinlock-to-avoid-upsetting-lockde.patch new file mode 100644 index 0000000000..660ad8c490 --- /dev/null +++ b/queue-6.19/i3c-dw-initialize-spinlock-to-avoid-upsetting-lockde.patch @@ -0,0 +1,39 @@ +From b3cde64ae6972ef640b61c25f1a48b40caf35331 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 15:29:42 +0100 +Subject: i3c: dw: Initialize spinlock to avoid upsetting lockdep + +From: Fredrik Markstrom + +[ Upstream commit b58eaa4761ab02fc38c39d674a6bcdd55e00f388 ] + +The devs_lock spinlock introduced when adding support for ibi:s was +never initialized. + +Fixes: e389b1d72a624 ("i3c: dw: Add support for in-band interrupts") +Suggested-by: Jani Nurminen +Signed-off-by: Fredrik Markstrom +Reviewed-by: Ivar Holmqvist +Link: https://patch.msgid.link/20260116-i3c_dw_initialize_spinlock-v3-1-cf707b6ed75f@est.tech +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master/dw-i3c-master.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c +index 889e2ed5bc830..d5b0704040562 100644 +--- a/drivers/i3c/master/dw-i3c-master.c ++++ b/drivers/i3c/master/dw-i3c-master.c +@@ -1570,6 +1570,8 @@ int dw_i3c_common_probe(struct dw_i3c_master *master, + spin_lock_init(&master->xferqueue.lock); + INIT_LIST_HEAD(&master->xferqueue.list); + ++ spin_lock_init(&master->devs_lock); ++ + writel(INTR_ALL, master->regs + INTR_STATUS); + irq = platform_get_irq(pdev, 0); + ret = devm_request_irq(&pdev->dev, irq, +-- +2.51.0 + diff --git a/queue-6.19/i3c-master-update-hot-join-flag-only-on-success.patch b/queue-6.19/i3c-master-update-hot-join-flag-only-on-success.patch new file mode 100644 index 0000000000..c71f857ed9 --- /dev/null +++ b/queue-6.19/i3c-master-update-hot-join-flag-only-on-success.patch @@ -0,0 +1,39 @@ +From 97619f9f264d88465f94e993034c87ed1f30f2a0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Jan 2026 09:26:44 +0200 +Subject: i3c: master: Update hot-join flag only on success + +From: Adrian Hunter + +[ Upstream commit f0775157b9f9a28ae3eabc8d05b0bc52e8056c80 ] + +To prevent inconsistent state when an error occurs, ensure the hot-join +flag is updated only when enabling or disabling hot-join succeeds. + +Fixes: 317bacf960a48 ("i3c: master: add enable(disable) hot join in sys entry") +Signed-off-by: Adrian Hunter +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260113072702.16268-4-adrian.hunter@intel.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c +index 1bc3c90684028..5408332861a1b 100644 +--- a/drivers/i3c/master.c ++++ b/drivers/i3c/master.c +@@ -618,7 +618,8 @@ static int i3c_set_hotjoin(struct i3c_master_controller *master, bool enable) + else + ret = master->ops->disable_hotjoin(master); + +- master->hotjoin = enable; ++ if (!ret) ++ master->hotjoin = enable; + + i3c_bus_normaluse_unlock(&master->bus); + +-- +2.51.0 + diff --git a/queue-6.19/i3c-move-device-name-assignment-after-i3c_bus_init.patch b/queue-6.19/i3c-move-device-name-assignment-after-i3c_bus_init.patch new file mode 100644 index 0000000000..d11b9b28e9 --- /dev/null +++ b/queue-6.19/i3c-move-device-name-assignment-after-i3c_bus_init.patch @@ -0,0 +1,46 @@ +From ae52cd984c8829149f05b375a4dc9db1351bbc01 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 14:07:22 +0800 +Subject: i3c: Move device name assignment after i3c_bus_init + +From: Billy Tsai + +[ Upstream commit 3502cea99c7ceb331458cbd34ef6792c83144687 ] + +Move device name initialization to occur after i3c_bus_init() +so that i3cbus->id is guaranteed to be assigned before it is used. + +Fixes: 9d4f219807d5 ("i3c: fix refcount inconsistency in i3c_master_register") +Signed-off-by: Billy Tsai +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260112-upstream_i3c_fix-v1-1-cbbf2cb71809@aspeedtech.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c +index 7f606c8716480..1bc3c90684028 100644 +--- a/drivers/i3c/master.c ++++ b/drivers/i3c/master.c +@@ -2881,7 +2881,6 @@ int i3c_master_register(struct i3c_master_controller *master, + INIT_LIST_HEAD(&master->boardinfo.i3c); + + device_initialize(&master->dev); +- dev_set_name(&master->dev, "i3c-%d", i3cbus->id); + + master->dev.dma_mask = parent->dma_mask; + master->dev.coherent_dma_mask = parent->coherent_dma_mask; +@@ -2891,6 +2890,8 @@ int i3c_master_register(struct i3c_master_controller *master, + if (ret) + goto err_put_dev; + ++ dev_set_name(&master->dev, "i3c-%d", i3cbus->id); ++ + ret = of_populate_i3c_bus(master); + if (ret) + goto err_put_dev; +-- +2.51.0 + diff --git a/queue-6.19/ib-cache-update-gid-cache-on-client-reregister-event.patch b/queue-6.19/ib-cache-update-gid-cache-on-client-reregister-event.patch new file mode 100644 index 0000000000..ffd3d4ff22 --- /dev/null +++ b/queue-6.19/ib-cache-update-gid-cache-on-client-reregister-event.patch @@ -0,0 +1,54 @@ +From 4768c22ebfb49c13b1e615fd913ea11a90ca93da Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 31 Dec 2025 14:07:45 +0100 +Subject: IB/cache: update gid cache on client reregister event +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Etienne AUJAMES + +[ Upstream commit ddd6c8c873e912cb1ead79def54de5e24ff71c80 ] + +Some HCAs (e.g: ConnectX4) do not trigger a IB_EVENT_GID_CHANGE on +subnet prefix update from SM (PortInfo). + +Since the commit d58c23c92548 ("IB/core: Only update PKEY and GID caches +on respective events"), the GID cache is updated exclusively on +IB_EVENT_GID_CHANGE. If this event is not emitted, the subnet prefix in the +IPoIB interface’s hardware address remains set to its default value +(0xfe80000000000000). + +Then rdma_bind_addr() failed because it relies on hardware address to +find the port GID (subnet_prefix + port GUID). + +This patch fixes this issue by updating the GID cache on +IB_EVENT_CLIENT_REREGISTER event (emitted on PortInfo::ClientReregister=1). + +Fixes: d58c23c92548 ("IB/core: Only update PKEY and GID caches on respective events") +Signed-off-by: Etienne AUJAMES +Link: https://patch.msgid.link/aVUfsO58QIDn5bGX@eaujamesFR0130 +Reviewed-by: Parav Pandit +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/cache.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c +index 81cf3c902e819..0fc1c5bce2f0d 100644 +--- a/drivers/infiniband/core/cache.c ++++ b/drivers/infiniband/core/cache.c +@@ -1537,7 +1537,8 @@ static void ib_cache_event_task(struct work_struct *_work) + * the cache. + */ + ret = ib_cache_update(work->event.device, work->event.element.port_num, +- work->event.event == IB_EVENT_GID_CHANGE, ++ work->event.event == IB_EVENT_GID_CHANGE || ++ work->event.event == IB_EVENT_CLIENT_REREGISTER, + work->event.event == IB_EVENT_PKEY_CHANGE, + work->enforce_security); + +-- +2.51.0 + diff --git a/queue-6.19/ib-mlx5-fix-port-speed-query-for-representors.patch b/queue-6.19/ib-mlx5-fix-port-speed-query-for-representors.patch new file mode 100644 index 0000000000..7b5d0c1424 --- /dev/null +++ b/queue-6.19/ib-mlx5-fix-port-speed-query-for-representors.patch @@ -0,0 +1,63 @@ +From b971f66aff05d1ceb36d5c7d66934293afbca054 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 14:26:45 +0200 +Subject: IB/mlx5: Fix port speed query for representors + +From: Or Har-Toov + +[ Upstream commit 18ea78e2ae83d1d86a72d21d9511927e57e2c0e1 ] + +When querying speed information for a representor in switchdev mode, +the code previously used the first device in the eswitch, which may not +match the device that actually owns the representor. In setups such as +multi-port eswitch or LAG, this led to incorrect port attributes being +reported. + +Fix this by retrieving the correct core device from the representor's +eswitch before querying its port attributes. + +Fixes: 27f9e0ccb6da ("net/mlx5: Lag, Add single RDMA device in multiport mode") +Signed-off-by: Or Har-Toov +Reviewed-by: Mark Bloch +Signed-off-by: Edward Srouji +Link: https://patch.msgid.link/20260115-port-speed-query-fix-v2-1-3bde6a3c78e7@nvidia.com +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/hw/mlx5/main.c | 20 ++++++++++++++------ + 1 file changed, 14 insertions(+), 6 deletions(-) + +diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c +index 3485a9a3d75e0..9997479410005 100644 +--- a/drivers/infiniband/hw/mlx5/main.c ++++ b/drivers/infiniband/hw/mlx5/main.c +@@ -561,12 +561,20 @@ static int mlx5_query_port_roce(struct ib_device *device, u32 port_num, + * of an error it will still be zeroed out. + * Use native port in case of reps + */ +- if (dev->is_rep) +- err = mlx5_query_port_ptys(mdev, out, sizeof(out), MLX5_PTYS_EN, +- 1, 0); +- else +- err = mlx5_query_port_ptys(mdev, out, sizeof(out), MLX5_PTYS_EN, +- mdev_port_num, 0); ++ if (dev->is_rep) { ++ struct mlx5_eswitch_rep *rep; ++ ++ rep = dev->port[port_num - 1].rep; ++ if (rep) { ++ mdev = mlx5_eswitch_get_core_dev(rep->esw); ++ WARN_ON(!mdev); ++ } ++ mdev_port_num = 1; ++ } ++ ++ err = mlx5_query_port_ptys(mdev, out, sizeof(out), MLX5_PTYS_EN, ++ mdev_port_num, 0); ++ + if (err) + goto out; + ext = !!MLX5_GET_ETH_PROTO(ptys_reg, out, true, eth_proto_capability); +-- +2.51.0 + diff --git a/queue-6.19/iio-pressure-mprls0025pa-fix-interrupt-flag.patch b/queue-6.19/iio-pressure-mprls0025pa-fix-interrupt-flag.patch new file mode 100644 index 0000000000..fa4d5c2c61 --- /dev/null +++ b/queue-6.19/iio-pressure-mprls0025pa-fix-interrupt-flag.patch @@ -0,0 +1,40 @@ +From 53cc58998e50c7b82eeca85bf5f532ef8b956929 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:55:32 +0200 +Subject: iio: pressure: mprls0025pa: fix interrupt flag + +From: Petre Rodan + +[ Upstream commit fff3f1a7d805684e4701a70bfaeba39622b59dbc ] + +Interrupt falling/rising flags should only be defined in the device tree. + +Fixes: 713337d9143e ("iio: pressure: Honeywell mprls0025pa pressure sensor") +Signed-off-by: Petre Rodan +Reviewed-by: Andy Shevchenko +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/pressure/mprls0025pa.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/iio/pressure/mprls0025pa.c b/drivers/iio/pressure/mprls0025pa.c +index 2336f2760eaeb..4b23f87a822b1 100644 +--- a/drivers/iio/pressure/mprls0025pa.c ++++ b/drivers/iio/pressure/mprls0025pa.c +@@ -418,10 +418,8 @@ int mpr_common_probe(struct device *dev, const struct mpr_ops *ops, int irq) + data->offset = div_s64_rem(offset, NANO, &data->offset2); + + if (data->irq > 0) { +- ret = devm_request_irq(dev, data->irq, mpr_eoc_handler, +- IRQF_TRIGGER_RISING, +- dev_name(dev), +- data); ++ ret = devm_request_irq(dev, data->irq, mpr_eoc_handler, 0, ++ dev_name(dev), data); + if (ret) + return dev_err_probe(dev, ret, + "request irq %d failed\n", data->irq); +-- +2.51.0 + diff --git a/queue-6.19/iio-pressure-mprls0025pa-fix-pressure-calculation.patch b/queue-6.19/iio-pressure-mprls0025pa-fix-pressure-calculation.patch new file mode 100644 index 0000000000..35d5be2863 --- /dev/null +++ b/queue-6.19/iio-pressure-mprls0025pa-fix-pressure-calculation.patch @@ -0,0 +1,110 @@ +From 856ec41aafa10a136e1054827bdddc10df582cc1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:55:34 +0200 +Subject: iio: pressure: mprls0025pa: fix pressure calculation + +From: Petre Rodan + +[ Upstream commit d63403d4e31ae537fefc5c0ee9d90f29b4fc532b ] + +A sign change is needed for proper calculation of the pressure. + +This is a minor fix since it only affects users that might have custom +silicon from Honeywell that has honeywell,pmin-pascal != 0. + +Also due to the fact that raw pressure values can not be lower +than output_min (400k-3.3M) there is no need to calculate a decimal for +the offset. + +Fixes: 713337d9143e ("iio: pressure: Honeywell mprls0025pa pressure sensor") +Signed-off-by: Petre Rodan +Reviewed-by: Andy Shevchenko +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/pressure/mprls0025pa.c | 26 +++++++++++--------------- + drivers/iio/pressure/mprls0025pa.h | 2 -- + 2 files changed, 11 insertions(+), 17 deletions(-) + +diff --git a/drivers/iio/pressure/mprls0025pa.c b/drivers/iio/pressure/mprls0025pa.c +index 6ba45d4c16b30..d4133fef91fac 100644 +--- a/drivers/iio/pressure/mprls0025pa.c ++++ b/drivers/iio/pressure/mprls0025pa.c +@@ -59,7 +59,7 @@ + * + * Values given to the userspace in sysfs interface: + * * raw - press_cnt +- * * offset - (-1 * outputmin) - pmin / scale ++ * * offset - (-1 * outputmin) + pmin / scale + * note: With all sensors from the datasheet pmin = 0 + * which reduces the offset to (-1 * outputmin) + */ +@@ -313,8 +313,7 @@ static int mpr_read_raw(struct iio_dev *indio_dev, + return IIO_VAL_INT_PLUS_NANO; + case IIO_CHAN_INFO_OFFSET: + *val = data->offset; +- *val2 = data->offset2; +- return IIO_VAL_INT_PLUS_NANO; ++ return IIO_VAL_INT; + default: + return -EINVAL; + } +@@ -330,8 +329,9 @@ int mpr_common_probe(struct device *dev, const struct mpr_ops *ops, int irq) + struct mpr_data *data; + struct iio_dev *indio_dev; + const char *triplet; +- s64 scale, offset; ++ s64 odelta, pdelta; + u32 func; ++ s32 tmp; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) +@@ -405,17 +405,13 @@ int mpr_common_probe(struct device *dev, const struct mpr_ops *ops, int irq) + data->outmin = mpr_func_spec[data->function].output_min; + data->outmax = mpr_func_spec[data->function].output_max; + +- /* use 64 bit calculation for preserving a reasonable precision */ +- scale = div_s64(((s64)(data->pmax - data->pmin)) * NANO, +- data->outmax - data->outmin); +- data->scale = div_s64_rem(scale, NANO, &data->scale2); +- /* +- * multiply with NANO before dividing by scale and later divide by NANO +- * again. +- */ +- offset = ((-1LL) * (s64)data->outmin) * NANO - +- div_s64(div_s64((s64)data->pmin * NANO, scale), NANO); +- data->offset = div_s64_rem(offset, NANO, &data->offset2); ++ odelta = data->outmax - data->outmin; ++ pdelta = data->pmax - data->pmin; ++ ++ data->scale = div_s64_rem(div_s64(pdelta * NANO, odelta), NANO, &tmp); ++ data->scale2 = tmp; ++ ++ data->offset = div_s64(odelta * data->pmin, pdelta) - data->outmin; + + if (data->irq > 0) { + ret = devm_request_irq(dev, data->irq, mpr_eoc_handler, 0, +diff --git a/drivers/iio/pressure/mprls0025pa.h b/drivers/iio/pressure/mprls0025pa.h +index d62a018eaff32..b6944b3051267 100644 +--- a/drivers/iio/pressure/mprls0025pa.h ++++ b/drivers/iio/pressure/mprls0025pa.h +@@ -53,7 +53,6 @@ enum mpr_func_id { + * @scale: pressure scale + * @scale2: pressure scale, decimal number + * @offset: pressure offset +- * @offset2: pressure offset, decimal number + * @gpiod_reset: reset + * @irq: end of conversion irq. used to distinguish between irq mode and + * reading in a loop until data is ready +@@ -75,7 +74,6 @@ struct mpr_data { + int scale; + int scale2; + int offset; +- int offset2; + struct gpio_desc *gpiod_reset; + int irq; + struct completion completion; +-- +2.51.0 + diff --git a/queue-6.19/iio-pressure-mprls0025pa-fix-scan_type-struct.patch b/queue-6.19/iio-pressure-mprls0025pa-fix-scan_type-struct.patch new file mode 100644 index 0000000000..84854297ef --- /dev/null +++ b/queue-6.19/iio-pressure-mprls0025pa-fix-scan_type-struct.patch @@ -0,0 +1,47 @@ +From b14d10e341d367c5354458de55da6886d0076c5b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:55:33 +0200 +Subject: iio: pressure: mprls0025pa: fix scan_type struct + +From: Petre Rodan + +[ Upstream commit 8a228e036926f7e57421d750c3724e63f11b808a ] + +Fix the scan_type sign and realbits assignment. + +The pressure is a 24bit unsigned int between output_min and output_max. + + transfer function A: 10% to 90% of 2^24 + transfer function B: 2.5% to 22.5% of 2^24 + transfer function C: 20% to 80% of 2^24 +[MPR_FUNCTION_A] = { .output_min = 1677722, .output_max = 15099494 } +[MPR_FUNCTION_B] = { .output_min = 419430, .output_max = 3774874 } +[MPR_FUNCTION_C] = { .output_min = 3355443, .output_max = 13421773 } + +Fixes: 713337d9143e ("iio: pressure: Honeywell mprls0025pa pressure sensor") +Signed-off-by: Petre Rodan +Reviewed-by: Andy Shevchenko +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/pressure/mprls0025pa.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/iio/pressure/mprls0025pa.c b/drivers/iio/pressure/mprls0025pa.c +index 4b23f87a822b1..6ba45d4c16b30 100644 +--- a/drivers/iio/pressure/mprls0025pa.c ++++ b/drivers/iio/pressure/mprls0025pa.c +@@ -160,8 +160,8 @@ static const struct iio_chan_spec mpr_channels[] = { + BIT(IIO_CHAN_INFO_OFFSET), + .scan_index = 0, + .scan_type = { +- .sign = 's', +- .realbits = 32, ++ .sign = 'u', ++ .realbits = 24, + .storagebits = 32, + .endianness = IIO_CPU, + }, +-- +2.51.0 + diff --git a/queue-6.19/iio-pressure-mprls0025pa-fix-spi-cs-delay-violation.patch b/queue-6.19/iio-pressure-mprls0025pa-fix-spi-cs-delay-violation.patch new file mode 100644 index 0000000000..dc7bee23fd --- /dev/null +++ b/queue-6.19/iio-pressure-mprls0025pa-fix-spi-cs-delay-violation.patch @@ -0,0 +1,71 @@ +From c2468edc9f6afb069681a724e774742ca608ce17 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:55:31 +0200 +Subject: iio: pressure: mprls0025pa: fix SPI CS delay violation + +From: Petre Rodan + +[ Upstream commit 583fa86ca581595b1f534a8de6d49ba8b3bf7196 ] + +Based on the sensor datasheet in chapter 7.6 SPI timing, Table 20, +during the SPI transfer there is a minimum time interval requirement +between the CS being asserted and the first clock edge (tHDSS). +This minimum interval of 2.5us is being violated if two consecutive SPI +transfers are queued up. + +Fixes: a0858f0cd28e ("iio: pressure: mprls0025pa add SPI driver") +Datasheet: https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/micropressure-mpr-series/documents/sps-siot-mpr-series-datasheet-32332628-ciid-172626.pdf?download=false +Signed-off-by: Petre Rodan +Reviewed-by: Andy Shevchenko +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/pressure/mprls0025pa_spi.c | 19 ++++++++++++++----- + 1 file changed, 14 insertions(+), 5 deletions(-) + +diff --git a/drivers/iio/pressure/mprls0025pa_spi.c b/drivers/iio/pressure/mprls0025pa_spi.c +index e6bb75de34119..cf17eb2e72083 100644 +--- a/drivers/iio/pressure/mprls0025pa_spi.c ++++ b/drivers/iio/pressure/mprls0025pa_spi.c +@@ -8,6 +8,7 @@ + * https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/micropressure-mpr-series/documents/sps-siot-mpr-series-datasheet-32332628-ciid-172626.pdf + */ + ++#include + #include + #include + #include +@@ -40,17 +41,25 @@ static int mpr_spi_xfer(struct mpr_data *data, const u8 cmd, const u8 pkt_len) + { + struct spi_device *spi = to_spi_device(data->dev); + struct mpr_spi_buf *buf = spi_get_drvdata(spi); +- struct spi_transfer xfer = { }; ++ struct spi_transfer xfers[2] = { }; + + if (pkt_len > MPR_MEASUREMENT_RD_SIZE) + return -EOVERFLOW; + + buf->tx[0] = cmd; +- xfer.tx_buf = buf->tx; +- xfer.rx_buf = data->buffer; +- xfer.len = pkt_len; + +- return spi_sync_transfer(spi, &xfer, 1); ++ /* ++ * Dummy transfer with no data, just cause a 2.5us+ delay between the CS assert ++ * and the first clock edge as per the datasheet tHDSS timing requirement. ++ */ ++ xfers[0].delay.value = 2500; ++ xfers[0].delay.unit = SPI_DELAY_UNIT_NSECS; ++ ++ xfers[1].tx_buf = buf->tx; ++ xfers[1].rx_buf = data->buffer; ++ xfers[1].len = pkt_len; ++ ++ return spi_sync_transfer(spi, xfers, ARRAY_SIZE(xfers)); + } + + static const struct mpr_ops mpr_spi_ops = { +-- +2.51.0 + diff --git a/queue-6.19/iio-pressure-mprls0025pa-fix-spi_transfer-struct-ini.patch b/queue-6.19/iio-pressure-mprls0025pa-fix-spi_transfer-struct-ini.patch new file mode 100644 index 0000000000..b4f143932c --- /dev/null +++ b/queue-6.19/iio-pressure-mprls0025pa-fix-spi_transfer-struct-ini.patch @@ -0,0 +1,36 @@ +From 56ac06f3a4b8ffb899e60ab5afc62adb08b6a119 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:55:30 +0200 +Subject: iio: pressure: mprls0025pa: fix spi_transfer struct initialisation + +From: Petre Rodan + +[ Upstream commit 1e0ac56c92e26115cbc8cfc639843725cb3a7d6a ] + +Make sure that the spi_transfer struct is zeroed out before use. + +Fixes: a0858f0cd28e ("iio: pressure: mprls0025pa add SPI driver") +Signed-off-by: Petre Rodan +Reviewed-by: Andy Shevchenko +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/pressure/mprls0025pa_spi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/iio/pressure/mprls0025pa_spi.c b/drivers/iio/pressure/mprls0025pa_spi.c +index d04102f8a4a03..e6bb75de34119 100644 +--- a/drivers/iio/pressure/mprls0025pa_spi.c ++++ b/drivers/iio/pressure/mprls0025pa_spi.c +@@ -40,7 +40,7 @@ static int mpr_spi_xfer(struct mpr_data *data, const u8 cmd, const u8 pkt_len) + { + struct spi_device *spi = to_spi_device(data->dev); + struct mpr_spi_buf *buf = spi_get_drvdata(spi); +- struct spi_transfer xfer; ++ struct spi_transfer xfer = { }; + + if (pkt_len > MPR_MEASUREMENT_RD_SIZE) + return -EOVERFLOW; +-- +2.51.0 + diff --git a/queue-6.19/iio-sca3000-fix-a-resource-leak-in-sca3000_probe.patch b/queue-6.19/iio-sca3000-fix-a-resource-leak-in-sca3000_probe.patch new file mode 100644 index 0000000000..c24c8cd654 --- /dev/null +++ b/queue-6.19/iio-sca3000-fix-a-resource-leak-in-sca3000_probe.patch @@ -0,0 +1,42 @@ +From 2868b6cd59a1567b92ee0e2f79f7359775991a36 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 22:49:49 -0800 +Subject: iio: sca3000: Fix a resource leak in sca3000_probe() + +From: Harshit Mogalapalli + +[ Upstream commit 62b44ebc1f2c71db3ca2d4737c52e433f6f03038 ] + +spi->irq from request_threaded_irq() not released when +iio_device_register() fails. Add an return value check and jump to a +common error handler when iio_device_register() fails. + +Fixes: 9a4936dc89a3 ("staging:iio:accel:sca3000 Tidy up probe order to avoid a race.") +Signed-off-by: Harshit Mogalapalli +Reviewed-by: Andy Shevchenko +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/accel/sca3000.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/iio/accel/sca3000.c b/drivers/iio/accel/sca3000.c +index bfa8a3f5a92f4..9ef4d6e274669 100644 +--- a/drivers/iio/accel/sca3000.c ++++ b/drivers/iio/accel/sca3000.c +@@ -1489,7 +1489,11 @@ static int sca3000_probe(struct spi_device *spi) + if (ret) + goto error_free_irq; + +- return iio_device_register(indio_dev); ++ ret = iio_device_register(indio_dev); ++ if (ret) ++ goto error_free_irq; ++ ++ return 0; + + error_free_irq: + if (spi->irq) +-- +2.51.0 + diff --git a/queue-6.19/iio-test-drop-dangling-symbol-in-gain-time-scale-hel.patch b/queue-6.19/iio-test-drop-dangling-symbol-in-gain-time-scale-hel.patch new file mode 100644 index 0000000000..a81c71da72 --- /dev/null +++ b/queue-6.19/iio-test-drop-dangling-symbol-in-gain-time-scale-hel.patch @@ -0,0 +1,36 @@ +From aa5746f46980a70bbe6db321a80c2cbd58c8d03e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 27 Dec 2025 23:10:29 -0800 +Subject: iio: test: drop dangling symbol in gain-time-scale helpers + +From: Randy Dunlap + +[ Upstream commit d63d868b312478523670b76007dcc5eaedc3ee07 ] + +The code for this never went upstream. It was replaced by other code, +so this should be dropped. + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=216748 +Fixes: cf996f039679 ("iio: test: test gain-time-scale helpers") +Signed-off-by: Randy Dunlap +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/test/Kconfig | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/iio/test/Kconfig b/drivers/iio/test/Kconfig +index 6e65e929791ca..4fc17dd0dcd77 100644 +--- a/drivers/iio/test/Kconfig ++++ b/drivers/iio/test/Kconfig +@@ -8,7 +8,6 @@ config IIO_GTS_KUNIT_TEST + tristate "Test IIO gain-time-scale helpers" if !KUNIT_ALL_TESTS + depends on KUNIT + select IIO_GTS_HELPER +- select TEST_KUNIT_DEVICE_HELPERS + default KUNIT_ALL_TESTS + help + build unit tests for the IIO light sensor gain-time-scale helpers. +-- +2.51.0 + diff --git a/queue-6.19/ima-fix-stack-out-of-bounds-in-is_bprm_creds_for_exe.patch b/queue-6.19/ima-fix-stack-out-of-bounds-in-is_bprm_creds_for_exe.patch new file mode 100644 index 0000000000..d61af81fed --- /dev/null +++ b/queue-6.19/ima-fix-stack-out-of-bounds-in-is_bprm_creds_for_exe.patch @@ -0,0 +1,196 @@ +From 1b4fc62d639a3114b505a80b56a3ef92cb59c135 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 27 Dec 2025 21:18:54 -0600 +Subject: ima: Fix stack-out-of-bounds in is_bprm_creds_for_exec() + +From: Chris J Arges + +[ Upstream commit 377cae9851e8559e9d8b82a78c1ac0abeb18839c ] + +KASAN reported a stack-out-of-bounds access in ima_appraise_measurement +from is_bprm_creds_for_exec: + +BUG: KASAN: stack-out-of-bounds in ima_appraise_measurement+0x12dc/0x16a0 + Read of size 1 at addr ffffc9000160f940 by task sudo/550 +The buggy address belongs to stack of task sudo/550 +and is located at offset 24 in frame: + ima_appraise_measurement+0x0/0x16a0 +This frame has 2 objects: + [48, 56) 'file' + [80, 148) 'hash' + +This is caused by using container_of on the *file pointer. This offset +calculation is what triggers the stack-out-of-bounds error. + +In order to fix this, pass in a bprm_is_check boolean which can be set +depending on how process_measurement is called. If the caller has a +linux_binprm pointer and the function is BPRM_CHECK we can determine +is_check and set it then. Otherwise set it to false. + +Fixes: 95b3cdafd7cb7 ("ima: instantiate the bprm_creds_for_exec() hook") + +Signed-off-by: Chris J Arges +Signed-off-by: Mimi Zohar +Signed-off-by: Sasha Levin +--- + security/integrity/ima/ima.h | 6 ++++-- + security/integrity/ima/ima_appraise.c | 16 +++------------- + security/integrity/ima/ima_main.c | 22 +++++++++++++--------- + 3 files changed, 20 insertions(+), 24 deletions(-) + +diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h +index e3d71d8d56e38..89ebe98ffc5e5 100644 +--- a/security/integrity/ima/ima.h ++++ b/security/integrity/ima/ima.h +@@ -441,7 +441,8 @@ int ima_check_blacklist(struct ima_iint_cache *iint, + int ima_appraise_measurement(enum ima_hooks func, struct ima_iint_cache *iint, + struct file *file, const unsigned char *filename, + struct evm_ima_xattr_data *xattr_value, +- int xattr_len, const struct modsig *modsig); ++ int xattr_len, const struct modsig *modsig, ++ bool bprm_is_check); + int ima_must_appraise(struct mnt_idmap *idmap, struct inode *inode, + int mask, enum ima_hooks func); + void ima_update_xattr(struct ima_iint_cache *iint, struct file *file); +@@ -466,7 +467,8 @@ static inline int ima_appraise_measurement(enum ima_hooks func, + const unsigned char *filename, + struct evm_ima_xattr_data *xattr_value, + int xattr_len, +- const struct modsig *modsig) ++ const struct modsig *modsig, ++ bool bprm_is_check) + { + return INTEGRITY_UNKNOWN; + } +diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c +index 5149ff4fd50d2..16c20c578ea87 100644 +--- a/security/integrity/ima/ima_appraise.c ++++ b/security/integrity/ima/ima_appraise.c +@@ -470,17 +470,6 @@ int ima_check_blacklist(struct ima_iint_cache *iint, + return rc; + } + +-static bool is_bprm_creds_for_exec(enum ima_hooks func, struct file *file) +-{ +- struct linux_binprm *bprm; +- +- if (func == BPRM_CHECK) { +- bprm = container_of(&file, struct linux_binprm, file); +- return bprm->is_check; +- } +- return false; +-} +- + /* + * ima_appraise_measurement - appraise file measurement + * +@@ -492,7 +481,8 @@ static bool is_bprm_creds_for_exec(enum ima_hooks func, struct file *file) + int ima_appraise_measurement(enum ima_hooks func, struct ima_iint_cache *iint, + struct file *file, const unsigned char *filename, + struct evm_ima_xattr_data *xattr_value, +- int xattr_len, const struct modsig *modsig) ++ int xattr_len, const struct modsig *modsig, ++ bool bprm_is_check) + { + static const char op[] = "appraise_data"; + int audit_msgno = AUDIT_INTEGRITY_DATA; +@@ -514,7 +504,7 @@ int ima_appraise_measurement(enum ima_hooks func, struct ima_iint_cache *iint, + * of the script interpreter(userspace). Differentiate kernel and + * userspace enforced integrity audit messages. + */ +- if (is_bprm_creds_for_exec(func, file)) ++ if (bprm_is_check) + audit_msgno = AUDIT_INTEGRITY_USERSPACE; + + /* If reading the xattr failed and there's no modsig, error out. */ +diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c +index 5770cf691912a..1d6229b156fb1 100644 +--- a/security/integrity/ima/ima_main.c ++++ b/security/integrity/ima/ima_main.c +@@ -236,7 +236,8 @@ static void ima_file_free(struct file *file) + static int process_measurement(struct file *file, const struct cred *cred, + struct lsm_prop *prop, char *buf, loff_t size, + int mask, enum ima_hooks func, +- enum kernel_read_file_id read_id) ++ enum kernel_read_file_id read_id, ++ bool bprm_is_check) + { + struct inode *real_inode, *inode = file_inode(file); + struct ima_iint_cache *iint = NULL; +@@ -426,7 +427,8 @@ static int process_measurement(struct file *file, const struct cred *cred, + inode_lock(inode); + rc = ima_appraise_measurement(func, iint, file, + pathname, xattr_value, +- xattr_len, modsig); ++ xattr_len, modsig, ++ bprm_is_check); + inode_unlock(inode); + } + if (!rc) +@@ -493,14 +495,15 @@ static int ima_file_mmap(struct file *file, unsigned long reqprot, + + if (reqprot & PROT_EXEC) { + ret = process_measurement(file, current_cred(), &prop, NULL, +- 0, MAY_EXEC, MMAP_CHECK_REQPROT, 0); ++ 0, MAY_EXEC, MMAP_CHECK_REQPROT, 0, ++ false); + if (ret) + return ret; + } + + if (prot & PROT_EXEC) + return process_measurement(file, current_cred(), &prop, NULL, +- 0, MAY_EXEC, MMAP_CHECK, 0); ++ 0, MAY_EXEC, MMAP_CHECK, 0, false); + + return 0; + } +@@ -584,7 +587,8 @@ static int ima_bprm_check(struct linux_binprm *bprm) + + security_current_getlsmprop_subj(&prop); + return process_measurement(bprm->file, current_cred(), +- &prop, NULL, 0, MAY_EXEC, BPRM_CHECK, 0); ++ &prop, NULL, 0, MAY_EXEC, BPRM_CHECK, 0, ++ bprm->is_check); + } + + /** +@@ -614,7 +618,7 @@ static int ima_creds_check(struct linux_binprm *bprm, const struct file *file) + + security_current_getlsmprop_subj(&prop); + return process_measurement((struct file *)file, bprm->cred, &prop, NULL, +- 0, MAY_EXEC, CREDS_CHECK, 0); ++ 0, MAY_EXEC, CREDS_CHECK, 0, false); + } + + /** +@@ -662,7 +666,7 @@ static int ima_file_check(struct file *file, int mask) + security_current_getlsmprop_subj(&prop); + return process_measurement(file, current_cred(), &prop, NULL, 0, + mask & (MAY_READ | MAY_WRITE | MAY_EXEC | +- MAY_APPEND), FILE_CHECK, 0); ++ MAY_APPEND), FILE_CHECK, 0, false); + } + + static int __ima_inode_hash(struct inode *inode, struct file *file, char *buf, +@@ -881,7 +885,7 @@ static int ima_read_file(struct file *file, enum kernel_read_file_id read_id, + func = read_idmap[read_id] ?: FILE_CHECK; + security_current_getlsmprop_subj(&prop); + return process_measurement(file, current_cred(), &prop, NULL, 0, +- MAY_READ, func, 0); ++ MAY_READ, func, 0, false); + } + + const int read_idmap[READING_MAX_ID] = { +@@ -925,7 +929,7 @@ static int ima_post_read_file(struct file *file, char *buf, loff_t size, + func = read_idmap[read_id] ?: FILE_CHECK; + security_current_getlsmprop_subj(&prop); + return process_measurement(file, current_cred(), &prop, buf, size, +- MAY_READ, func, read_id); ++ MAY_READ, func, read_id, false); + } + + /** +-- +2.51.0 + diff --git a/queue-6.19/inet-raw-sockets-using-ipproto_raw-must-drop-incomin.patch b/queue-6.19/inet-raw-sockets-using-ipproto_raw-must-drop-incomin.patch new file mode 100644 index 0000000000..449ee40296 --- /dev/null +++ b/queue-6.19/inet-raw-sockets-using-ipproto_raw-must-drop-incomin.patch @@ -0,0 +1,94 @@ +From 7fd2655ab3875cf87a5ef4181b1b17e6770734c5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 19:25:09 +0000 +Subject: inet: RAW sockets using IPPROTO_RAW MUST drop incoming ICMP + +From: Eric Dumazet + +[ Upstream commit c89477ad79446867394360b29bb801010fc3ff22 ] + +Yizhou Zhao reported that simply having one RAW socket on protocol +IPPROTO_RAW (255) was dangerous. + + socket(AF_INET, SOCK_RAW, 255); + +A malicious incoming ICMP packet can set the protocol field to 255 +and match this socket, leading to FNHE cache changes. + +inner = IP(src="192.168.2.1", dst="8.8.8.8", proto=255)/Raw("TEST") +pkt = IP(src="192.168.1.1", dst="192.168.2.1")/ICMP(type=3, code=4, nexthopmtu=576)/inner + +"man 7 raw" states: + + A protocol of IPPROTO_RAW implies enabled IP_HDRINCL and is able + to send any IP protocol that is specified in the passed header. + Receiving of all IP protocols via IPPROTO_RAW is not possible + using raw sockets. + +Make sure we drop these malicious packets. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: Yizhou Zhao +Link: https://lore.kernel.org/netdev/20251109134600.292125-1-zhaoyz24@mails.tsinghua.edu.cn/ +Signed-off-by: Eric Dumazet +Reviewed-by: David Ahern +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260203192509.682208-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/icmp.c | 14 ++++++++++---- + net/ipv6/icmp.c | 6 ++++++ + 2 files changed, 16 insertions(+), 4 deletions(-) + +diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c +index 4abbec2f47ef5..4acbbc703e798 100644 +--- a/net/ipv4/icmp.c ++++ b/net/ipv4/icmp.c +@@ -1031,16 +1031,22 @@ static void icmp_socket_deliver(struct sk_buff *skb, u32 info) + /* Checkin full IP header plus 8 bytes of protocol to + * avoid additional coding at protocol handlers. + */ +- if (!pskb_may_pull(skb, iph->ihl * 4 + 8)) { +- __ICMP_INC_STATS(dev_net_rcu(skb->dev), ICMP_MIB_INERRORS); +- return; +- } ++ if (!pskb_may_pull(skb, iph->ihl * 4 + 8)) ++ goto out; ++ ++ /* IPPROTO_RAW sockets are not supposed to receive anything. */ ++ if (protocol == IPPROTO_RAW) ++ goto out; + + raw_icmp_error(skb, protocol, info); + + ipprot = rcu_dereference(inet_protos[protocol]); + if (ipprot && ipprot->err_handler) + ipprot->err_handler(skb, info); ++ return; ++ ++out: ++ __ICMP_INC_STATS(dev_net_rcu(skb->dev), ICMP_MIB_INERRORS); + } + + static bool icmp_tag_validation(int proto) +diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c +index 9d37e7711bc2b..a77f3113ef23b 100644 +--- a/net/ipv6/icmp.c ++++ b/net/ipv6/icmp.c +@@ -1066,6 +1066,12 @@ enum skb_drop_reason icmpv6_notify(struct sk_buff *skb, u8 type, + if (reason != SKB_NOT_DROPPED_YET) + goto out; + ++ if (nexthdr == IPPROTO_RAW) { ++ /* Add a more specific reason later ? */ ++ reason = SKB_DROP_REASON_NOT_SPECIFIED; ++ goto out; ++ } ++ + /* BUGGG_FUTURE: we should try to parse exthdrs in this packet. + Without this we will not able f.e. to make source routed + pmtu discovery. +-- +2.51.0 + diff --git a/queue-6.19/input-adp5589-remove-a-leftover-header-file.patch b/queue-6.19/input-adp5589-remove-a-leftover-header-file.patch new file mode 100644 index 0000000000..f7ffca7fca --- /dev/null +++ b/queue-6.19/input-adp5589-remove-a-leftover-header-file.patch @@ -0,0 +1,217 @@ +From 75ebf9a3a4fcace7405e96dec86dfa551321cc68 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Jan 2026 17:11:40 +0200 +Subject: Input: adp5589 - remove a leftover header file +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Vladimir Zapolskiy + +[ Upstream commit f8a6e5eac701369afb5d69aba875dc5fec93003d ] + +In commit 3bdbd0858df6 ("Input: adp5589: remove the driver") the last user +of include/linux/input/adp5589.h was removed along with the whole driver, +thus the header file can be also removed. + +Signed-off-by: Vladimir Zapolskiy +Reviewed-by: Laurent Pinchart +Reviewed-by: Nuno Sá +Fixes: 3bdbd0858df6 ("Input: adp5589: remove the driver") +Link: https://patch.msgid.link/20260113151140.3843753-1-vz@mleia.com +Signed-off-by: Dmitry Torokhov +Signed-off-by: Sasha Levin +--- + include/linux/input/adp5589.h | 180 ---------------------------------- + 1 file changed, 180 deletions(-) + delete mode 100644 include/linux/input/adp5589.h + +diff --git a/include/linux/input/adp5589.h b/include/linux/input/adp5589.h +deleted file mode 100644 +index 0e4742c8c81e3..0000000000000 +--- a/include/linux/input/adp5589.h ++++ /dev/null +@@ -1,180 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0-only */ +-/* +- * Analog Devices ADP5589/ADP5585 I/O Expander and QWERTY Keypad Controller +- * +- * Copyright 2010-2011 Analog Devices Inc. +- */ +- +-#ifndef _ADP5589_H +-#define _ADP5589_H +- +-/* +- * ADP5589 specific GPI and Keymap defines +- */ +- +-#define ADP5589_KEYMAPSIZE 88 +- +-#define ADP5589_GPI_PIN_ROW0 97 +-#define ADP5589_GPI_PIN_ROW1 98 +-#define ADP5589_GPI_PIN_ROW2 99 +-#define ADP5589_GPI_PIN_ROW3 100 +-#define ADP5589_GPI_PIN_ROW4 101 +-#define ADP5589_GPI_PIN_ROW5 102 +-#define ADP5589_GPI_PIN_ROW6 103 +-#define ADP5589_GPI_PIN_ROW7 104 +-#define ADP5589_GPI_PIN_COL0 105 +-#define ADP5589_GPI_PIN_COL1 106 +-#define ADP5589_GPI_PIN_COL2 107 +-#define ADP5589_GPI_PIN_COL3 108 +-#define ADP5589_GPI_PIN_COL4 109 +-#define ADP5589_GPI_PIN_COL5 110 +-#define ADP5589_GPI_PIN_COL6 111 +-#define ADP5589_GPI_PIN_COL7 112 +-#define ADP5589_GPI_PIN_COL8 113 +-#define ADP5589_GPI_PIN_COL9 114 +-#define ADP5589_GPI_PIN_COL10 115 +-#define GPI_LOGIC1 116 +-#define GPI_LOGIC2 117 +- +-#define ADP5589_GPI_PIN_ROW_BASE ADP5589_GPI_PIN_ROW0 +-#define ADP5589_GPI_PIN_ROW_END ADP5589_GPI_PIN_ROW7 +-#define ADP5589_GPI_PIN_COL_BASE ADP5589_GPI_PIN_COL0 +-#define ADP5589_GPI_PIN_COL_END ADP5589_GPI_PIN_COL10 +- +-#define ADP5589_GPI_PIN_BASE ADP5589_GPI_PIN_ROW_BASE +-#define ADP5589_GPI_PIN_END ADP5589_GPI_PIN_COL_END +- +-#define ADP5589_GPIMAPSIZE_MAX (ADP5589_GPI_PIN_END - ADP5589_GPI_PIN_BASE + 1) +- +-/* +- * ADP5585 specific GPI and Keymap defines +- */ +- +-#define ADP5585_KEYMAPSIZE 30 +- +-#define ADP5585_GPI_PIN_ROW0 37 +-#define ADP5585_GPI_PIN_ROW1 38 +-#define ADP5585_GPI_PIN_ROW2 39 +-#define ADP5585_GPI_PIN_ROW3 40 +-#define ADP5585_GPI_PIN_ROW4 41 +-#define ADP5585_GPI_PIN_ROW5 42 +-#define ADP5585_GPI_PIN_COL0 43 +-#define ADP5585_GPI_PIN_COL1 44 +-#define ADP5585_GPI_PIN_COL2 45 +-#define ADP5585_GPI_PIN_COL3 46 +-#define ADP5585_GPI_PIN_COL4 47 +-#define GPI_LOGIC 48 +- +-#define ADP5585_GPI_PIN_ROW_BASE ADP5585_GPI_PIN_ROW0 +-#define ADP5585_GPI_PIN_ROW_END ADP5585_GPI_PIN_ROW5 +-#define ADP5585_GPI_PIN_COL_BASE ADP5585_GPI_PIN_COL0 +-#define ADP5585_GPI_PIN_COL_END ADP5585_GPI_PIN_COL4 +- +-#define ADP5585_GPI_PIN_BASE ADP5585_GPI_PIN_ROW_BASE +-#define ADP5585_GPI_PIN_END ADP5585_GPI_PIN_COL_END +- +-#define ADP5585_GPIMAPSIZE_MAX (ADP5585_GPI_PIN_END - ADP5585_GPI_PIN_BASE + 1) +- +-struct adp5589_gpi_map { +- unsigned short pin; +- unsigned short sw_evt; +-}; +- +-/* scan_cycle_time */ +-#define ADP5589_SCAN_CYCLE_10ms 0 +-#define ADP5589_SCAN_CYCLE_20ms 1 +-#define ADP5589_SCAN_CYCLE_30ms 2 +-#define ADP5589_SCAN_CYCLE_40ms 3 +- +-/* RESET_CFG */ +-#define RESET_PULSE_WIDTH_500us 0 +-#define RESET_PULSE_WIDTH_1ms 1 +-#define RESET_PULSE_WIDTH_2ms 2 +-#define RESET_PULSE_WIDTH_10ms 3 +- +-#define RESET_TRIG_TIME_0ms (0 << 2) +-#define RESET_TRIG_TIME_1000ms (1 << 2) +-#define RESET_TRIG_TIME_1500ms (2 << 2) +-#define RESET_TRIG_TIME_2000ms (3 << 2) +-#define RESET_TRIG_TIME_2500ms (4 << 2) +-#define RESET_TRIG_TIME_3000ms (5 << 2) +-#define RESET_TRIG_TIME_3500ms (6 << 2) +-#define RESET_TRIG_TIME_4000ms (7 << 2) +- +-#define RESET_PASSTHRU_EN (1 << 5) +-#define RESET1_POL_HIGH (1 << 6) +-#define RESET1_POL_LOW (0 << 6) +-#define RESET2_POL_HIGH (1 << 7) +-#define RESET2_POL_LOW (0 << 7) +- +-/* ADP5589 Mask Bits: +- * C C C C C C C C C C C | R R R R R R R R +- * 1 9 8 7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0 +- * 0 +- * ---------------- BIT ------------------ +- * 1 1 1 1 1 1 1 1 1 0 0 | 0 0 0 0 0 0 0 0 +- * 8 7 6 5 4 3 2 1 0 9 8 | 7 6 5 4 3 2 1 0 +- */ +- +-#define ADP_ROW(x) (1 << (x)) +-#define ADP_COL(x) (1 << (x + 8)) +-#define ADP5589_ROW_MASK 0xFF +-#define ADP5589_COL_MASK 0xFF +-#define ADP5589_COL_SHIFT 8 +-#define ADP5589_MAX_ROW_NUM 7 +-#define ADP5589_MAX_COL_NUM 10 +- +-/* ADP5585 Mask Bits: +- * C C C C C | R R R R R R +- * 4 3 2 1 0 | 5 4 3 2 1 0 +- * +- * ---- BIT -- ----------- +- * 1 0 0 0 0 | 0 0 0 0 0 0 +- * 0 9 8 7 6 | 5 4 3 2 1 0 +- */ +- +-#define ADP5585_ROW_MASK 0x3F +-#define ADP5585_COL_MASK 0x1F +-#define ADP5585_ROW_SHIFT 0 +-#define ADP5585_COL_SHIFT 6 +-#define ADP5585_MAX_ROW_NUM 5 +-#define ADP5585_MAX_COL_NUM 4 +- +-#define ADP5585_ROW(x) (1 << ((x) & ADP5585_ROW_MASK)) +-#define ADP5585_COL(x) (1 << (((x) & ADP5585_COL_MASK) + ADP5585_COL_SHIFT)) +- +-/* Put one of these structures in i2c_board_info platform_data */ +- +-struct adp5589_kpad_platform_data { +- unsigned keypad_en_mask; /* Keypad (Rows/Columns) enable mask */ +- const unsigned short *keymap; /* Pointer to keymap */ +- unsigned short keymapsize; /* Keymap size */ +- bool repeat; /* Enable key repeat */ +- bool en_keylock; /* Enable key lock feature (ADP5589 only)*/ +- unsigned char unlock_key1; /* Unlock Key 1 (ADP5589 only) */ +- unsigned char unlock_key2; /* Unlock Key 2 (ADP5589 only) */ +- unsigned char unlock_timer; /* Time in seconds [0..7] between the two unlock keys 0=disable (ADP5589 only) */ +- unsigned char scan_cycle_time; /* Time between consecutive scan cycles */ +- unsigned char reset_cfg; /* Reset config */ +- unsigned short reset1_key_1; /* Reset Key 1 */ +- unsigned short reset1_key_2; /* Reset Key 2 */ +- unsigned short reset1_key_3; /* Reset Key 3 */ +- unsigned short reset2_key_1; /* Reset Key 1 */ +- unsigned short reset2_key_2; /* Reset Key 2 */ +- unsigned debounce_dis_mask; /* Disable debounce mask */ +- unsigned pull_dis_mask; /* Disable all pull resistors mask */ +- unsigned pullup_en_100k; /* Pull-Up 100k Enable Mask */ +- unsigned pullup_en_300k; /* Pull-Up 300k Enable Mask */ +- unsigned pulldown_en_300k; /* Pull-Down 300k Enable Mask */ +- const struct adp5589_gpi_map *gpimap; +- unsigned short gpimapsize; +- const struct adp5589_gpio_platform_data *gpio_data; +-}; +- +-struct i2c_client; /* forward declaration */ +- +-struct adp5589_gpio_platform_data { +- int gpio_start; /* GPIO Chip base # */ +-}; +- +-#endif +-- +2.51.0 + diff --git a/queue-6.19/interconnect-mediatek-aggregate-bandwidth-with-satur.patch b/queue-6.19/interconnect-mediatek-aggregate-bandwidth-with-satur.patch new file mode 100644 index 0000000000..1ed91bbab9 --- /dev/null +++ b/queue-6.19/interconnect-mediatek-aggregate-bandwidth-with-satur.patch @@ -0,0 +1,54 @@ +From 10a36b5d3a05e043f29dbf947081c7424fb2113b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 24 Nov 2025 12:07:02 +0100 +Subject: interconnect: mediatek: Aggregate bandwidth with saturating add + +From: Nicolas Frattaroli + +[ Upstream commit 6ffd02b82243d9907b5f5d2c7a2fc6a62669eece ] + +By using a regular non-overflow-checking add, the MediaTek icc-emi +driver will happy wrap at U32_MAX + 1 to 0. As it's common for the +interconnect core to fill in INT_MAX values, this is not a hypothetical +situation, but something that actually happens in regular use. This +would be pretty disasterous if anything used this driver. + +Replace the addition with an overflow-checked addition from overflow.h, +and saturate to U32_MAX if an overflow is detected. + +Fixes: b45293799f75 ("interconnect: mediatek: Add MediaTek MT8183/8195 EMI Interconnect driver") +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Nicolas Frattaroli +Link: https://lore.kernel.org/r/20251124-mt8196-dvfsrc-v2-13-d9c1334db9f3@collabora.com +Signed-off-by: Georgi Djakov +Signed-off-by: Sasha Levin +--- + drivers/interconnect/mediatek/icc-emi.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/interconnect/mediatek/icc-emi.c b/drivers/interconnect/mediatek/icc-emi.c +index 182aa2b0623af..dfa3a9cd93998 100644 +--- a/drivers/interconnect/mediatek/icc-emi.c ++++ b/drivers/interconnect/mediatek/icc-emi.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -22,7 +23,9 @@ static int mtk_emi_icc_aggregate(struct icc_node *node, u32 tag, u32 avg_bw, + { + struct mtk_icc_node *in = node->data; + +- *agg_avg += avg_bw; ++ if (check_add_overflow(*agg_avg, avg_bw, agg_avg)) ++ *agg_avg = U32_MAX; ++ + *agg_peak = max_t(u32, *agg_peak, peak_bw); + + in->sum_avg = *agg_avg; +-- +2.51.0 + diff --git a/queue-6.19/interconnect-mediatek-don-t-hijack-parent-device.patch b/queue-6.19/interconnect-mediatek-don-t-hijack-parent-device.patch new file mode 100644 index 0000000000..2335ee319b --- /dev/null +++ b/queue-6.19/interconnect-mediatek-don-t-hijack-parent-device.patch @@ -0,0 +1,53 @@ +From cef0624165d53dfa42e017114999aa7176b25657 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 24 Nov 2025 12:07:01 +0100 +Subject: interconnect: mediatek: Don't hijack parent device + +From: Nicolas Frattaroli + +[ Upstream commit 510f8214440c553e81774c5822437ccf154e9e38 ] + +If the intention is that users of the interconnect declare their +relationship to the child icc_emi node of the dvfsrc controller, then +this code never worked. That's because it uses the parent dvfsrc device +as the device it passes to the interconnect core framework, which means +all the OF parsing is broken. + +Use the actual device instead, and pass the dvfsrc parent into the +dvfsrc calls. + +Fixes: b45293799f75 ("interconnect: mediatek: Add MediaTek MT8183/8195 EMI Interconnect driver") +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Nicolas Frattaroli +Link: https://lore.kernel.org/r/20251124-mt8196-dvfsrc-v2-12-d9c1334db9f3@collabora.com +Signed-off-by: Georgi Djakov +Signed-off-by: Sasha Levin +--- + drivers/interconnect/mediatek/icc-emi.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/interconnect/mediatek/icc-emi.c b/drivers/interconnect/mediatek/icc-emi.c +index 7da740b5fa8d6..182aa2b0623af 100644 +--- a/drivers/interconnect/mediatek/icc-emi.c ++++ b/drivers/interconnect/mediatek/icc-emi.c +@@ -40,7 +40,7 @@ static int mtk_emi_icc_set(struct icc_node *src, struct icc_node *dst) + if (unlikely(!src->provider)) + return -EINVAL; + +- dev = src->provider->dev; ++ dev = src->provider->dev->parent; + + switch (node->ep) { + case 0: +@@ -97,7 +97,7 @@ int mtk_emi_icc_probe(struct platform_device *pdev) + if (!data) + return -ENOMEM; + +- provider->dev = pdev->dev.parent; ++ provider->dev = dev; + provider->set = mtk_emi_icc_set; + provider->aggregate = mtk_emi_icc_aggregate; + provider->xlate = of_icc_xlate_onecell; +-- +2.51.0 + diff --git a/queue-6.19/interconnect-qcom-qcs8300-fix-the-num_links-for-nsp-.patch b/queue-6.19/interconnect-qcom-qcs8300-fix-the-num_links-for-nsp-.patch new file mode 100644 index 0000000000..d517ddfb74 --- /dev/null +++ b/queue-6.19/interconnect-qcom-qcs8300-fix-the-num_links-for-nsp-.patch @@ -0,0 +1,47 @@ +From 738cb7048409c0b10ba4863141810e5a9faa7e38 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 09:30:10 +0000 +Subject: interconnect: qcom: qcs8300: fix the num_links for nsp icc node + +From: Raviteja Laggyshetty + +[ Upstream commit 3dc4092fe5c8baf6bf4e882b44615f19564a5076 ] + +The qxm_nsp node is configured with an incorrect num_links value, +causing remoteproc driver to fail probing because it cannot acquire the +interconnect path for qxm_nsp -> ebi. This results in the following +error in dmesg: + + platform 26300000.remoteproc: deferred probe pending: + qcom_q6v5_pas: failed to acquire interconnect path + +Set num_links to 2 to match the two link_nodes, allowing remoteproc +clients to obtain the correct path handle and vote on qxm_nsp -> ebi. + +Fixes: 874be3339c85 ("interconnect: qcom: qcs8300: convert to dynamic IDs") +Signed-off-by: Raviteja Laggyshetty +Reviewed-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260120-monaco_num_links_fix_nsp_ebi_path-v3-1-536be21ce3ff@oss.qualcomm.com +Signed-off-by: Georgi Djakov +Signed-off-by: Sasha Levin +--- + drivers/interconnect/qcom/qcs8300.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/interconnect/qcom/qcs8300.c b/drivers/interconnect/qcom/qcs8300.c +index 70a377bbcf293..bc403a9bf68c6 100644 +--- a/drivers/interconnect/qcom/qcs8300.c ++++ b/drivers/interconnect/qcom/qcs8300.c +@@ -629,7 +629,7 @@ static struct qcom_icc_node qxm_nsp = { + .name = "qxm_nsp", + .channels = 2, + .buswidth = 32, +- .num_links = 1, ++ .num_links = 2, + .link_nodes = { &qns_hcp, &qns_nsp_gemnoc }, + }; + +-- +2.51.0 + diff --git a/queue-6.19/io_uring-cancel-de-unionize-file-and-user_data-in-st.patch b/queue-6.19/io_uring-cancel-de-unionize-file-and-user_data-in-st.patch new file mode 100644 index 0000000000..16a7fe7c1d --- /dev/null +++ b/queue-6.19/io_uring-cancel-de-unionize-file-and-user_data-in-st.patch @@ -0,0 +1,45 @@ +From cf4374eb3eef295c79a32a812aa486871fc6c5e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 14:16:27 -0700 +Subject: io_uring/cancel: de-unionize file and user_data in struct + io_cancel_data + +From: Jens Axboe + +[ Upstream commit 22dbb0987bd1e0ec3b1e4ad20756a98f99aa4a08 ] + +By having them share the same space in struct io_cancel_data, it ends up +disallowing IORING_ASYNC_CANCEL_FD|IORING_ASYNC_CANCEL_USERDATA from +working. Eg you cannot match on both a file and user_data for +cancelation purposes. This obviously isn't a common use case as nobody +has reported this, but it does result in -ENOENT potentially being +returned when trying to match on both, rather than actually doing what +the API says it would. + +Fixes: 4bf94615b888 ("io_uring: allow IORING_OP_ASYNC_CANCEL with 'fd' key") +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + io_uring/cancel.h | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/io_uring/cancel.h b/io_uring/cancel.h +index 6783961ede1bf..1b201a0943030 100644 +--- a/io_uring/cancel.h ++++ b/io_uring/cancel.h +@@ -6,10 +6,8 @@ + + struct io_cancel_data { + struct io_ring_ctx *ctx; +- union { +- u64 data; +- struct file *file; +- }; ++ u64 data; ++ struct file *file; + u8 opcode; + u32 flags; + int seq; +-- +2.51.0 + diff --git a/queue-6.19/io_uring-delay-sqarray-static-branch-disablement.patch b/queue-6.19/io_uring-delay-sqarray-static-branch-disablement.patch new file mode 100644 index 0000000000..0742f736f6 --- /dev/null +++ b/queue-6.19/io_uring-delay-sqarray-static-branch-disablement.patch @@ -0,0 +1,66 @@ +From 37ed2e15a7ac849a6156b1ff2897631a50932398 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 15 Feb 2026 22:06:52 +0000 +Subject: io_uring: delay sqarray static branch disablement + +From: Pavel Begunkov + +[ Upstream commit 56112578c71213a10c995a56835bddb5e9ab1ed0 ] + +io_key_has_sqarray static branch can be easily switched on/off by the +user every time patching the kernel. That can be very disruptive as it +might require heavy synchronisation across all CPUs. Use deferred static +keys, which can rate-limit it by deferring, batching and potentially +effectively eliminating dec+inc pairs. + +Fixes: 9b296c625ac1d ("io_uring: static_key for !IORING_SETUP_NO_SQARRAY") +Signed-off-by: Pavel Begunkov +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + io_uring/io_uring.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c +index 8aa671ba43474..63efd60829f37 100644 +--- a/io_uring/io_uring.c ++++ b/io_uring/io_uring.c +@@ -138,7 +138,7 @@ + static void io_queue_sqe(struct io_kiocb *req, unsigned int extra_flags); + static void __io_req_caches_free(struct io_ring_ctx *ctx); + +-static __read_mostly DEFINE_STATIC_KEY_FALSE(io_key_has_sqarray); ++static __read_mostly DEFINE_STATIC_KEY_DEFERRED_FALSE(io_key_has_sqarray, HZ); + + struct kmem_cache *req_cachep; + static struct workqueue_struct *iou_wq __ro_after_init; +@@ -2375,7 +2375,7 @@ static bool io_get_sqe(struct io_ring_ctx *ctx, const struct io_uring_sqe **sqe) + unsigned mask = ctx->sq_entries - 1; + unsigned head = ctx->cached_sq_head++ & mask; + +- if (static_branch_unlikely(&io_key_has_sqarray) && ++ if (static_branch_unlikely(&io_key_has_sqarray.key) && + (!(ctx->flags & IORING_SETUP_NO_SQARRAY))) { + head = READ_ONCE(ctx->sq_array[head]); + if (unlikely(head >= ctx->sq_entries)) { +@@ -2867,7 +2867,7 @@ static __cold void io_ring_ctx_free(struct io_ring_ctx *ctx) + io_rings_free(ctx); + + if (!(ctx->flags & IORING_SETUP_NO_SQARRAY)) +- static_branch_dec(&io_key_has_sqarray); ++ static_branch_slow_dec_deferred(&io_key_has_sqarray); + + percpu_ref_exit(&ctx->refs); + free_uid(ctx->user); +@@ -3600,7 +3600,7 @@ static __cold int io_uring_create(struct io_ctx_config *config) + ctx->clock_offset = 0; + + if (!(ctx->flags & IORING_SETUP_NO_SQARRAY)) +- static_branch_inc(&io_key_has_sqarray); ++ static_branch_deferred_inc(&io_key_has_sqarray); + + if ((ctx->flags & IORING_SETUP_DEFER_TASKRUN) && + !(ctx->flags & IORING_SETUP_IOPOLL) && +-- +2.51.0 + diff --git a/queue-6.19/io_uring-eventfd-remove-unused-ctx-evfd_last_cq_tail.patch b/queue-6.19/io_uring-eventfd-remove-unused-ctx-evfd_last_cq_tail.patch new file mode 100644 index 0000000000..affc7cad4e --- /dev/null +++ b/queue-6.19/io_uring-eventfd-remove-unused-ctx-evfd_last_cq_tail.patch @@ -0,0 +1,47 @@ +From c3a392f95856637b81bc9aec8bcaf5b6ef0a47f1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 11:21:32 -0700 +Subject: io_uring/eventfd: remove unused ctx->evfd_last_cq_tail member + +From: Jens Axboe + +[ Upstream commit 07f3c3a1cd56c2048a92dad0c11f15e4ac3888c1 ] + +A previous commit got rid of any use of this member, but forgot to +remove it. Kill it. + +Fixes: f4bb2f65bb81 ("io_uring/eventfd: move ctx->evfd_last_cq_tail into io_ev_fd") +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + include/linux/io_uring_types.h | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/include/linux/io_uring_types.h b/include/linux/io_uring_types.h +index a3e8ddc9b380f..4c9770536eb5d 100644 +--- a/include/linux/io_uring_types.h ++++ b/include/linux/io_uring_types.h +@@ -444,6 +444,9 @@ struct io_ring_ctx { + struct list_head defer_list; + unsigned nr_drained; + ++ /* protected by ->completion_lock */ ++ unsigned nr_req_allocated; ++ + #ifdef CONFIG_NET_RX_BUSY_POLL + struct list_head napi_list; /* track busy poll napi_id */ + spinlock_t napi_lock; /* napi_list lock */ +@@ -456,10 +459,6 @@ struct io_ring_ctx { + DECLARE_HASHTABLE(napi_ht, 4); + #endif + +- /* protected by ->completion_lock */ +- unsigned evfd_last_cq_tail; +- unsigned nr_req_allocated; +- + /* + * Protection for resize vs mmap races - both the mmap and resize + * side will need to grab this lock, to prevent either side from +-- +2.51.0 + diff --git a/queue-6.19/io_uring-kbuf-fix-memory-leak-if-io_buffer_add_list-.patch b/queue-6.19/io_uring-kbuf-fix-memory-leak-if-io_buffer_add_list-.patch new file mode 100644 index 0000000000..bf9720b1e0 --- /dev/null +++ b/queue-6.19/io_uring-kbuf-fix-memory-leak-if-io_buffer_add_list-.patch @@ -0,0 +1,43 @@ +From 9ee1f182fffe2a945c9b5f8407e0ac338050c10c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 08:38:20 -0700 +Subject: io_uring/kbuf: fix memory leak if io_buffer_add_list fails + +From: Jens Axboe + +[ Upstream commit 442ae406603a94f1a263654494f425302ceb0445 ] + +io_register_pbuf_ring() ignores the return value of io_buffer_add_list(), +which can fail if xa_store() returns an error (e.g., -ENOMEM). When this +happens, the function returns 0 (success) to the caller, but the +io_buffer_list structure is neither added to the xarray nor freed. + +In practice this requires failure injection to hit, hence not a real +issue. But it should get fixed up none the less. + +Fixes: c7fb19428d67 ("io_uring: add support for ring mapped supplied buffers") +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + io_uring/kbuf.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/io_uring/kbuf.c b/io_uring/kbuf.c +index 796d131107ddb..67d4fe576473a 100644 +--- a/io_uring/kbuf.c ++++ b/io_uring/kbuf.c +@@ -669,8 +669,9 @@ int io_register_pbuf_ring(struct io_ring_ctx *ctx, void __user *arg) + bl->buf_ring = br; + if (reg.flags & IOU_PBUF_RING_INC) + bl->flags |= IOBL_INC; +- io_buffer_add_list(ctx, bl, reg.bgid); +- return 0; ++ ret = io_buffer_add_list(ctx, bl, reg.bgid); ++ if (!ret) ++ return 0; + fail: + io_free_region(ctx->user, &bl->region); + kfree(bl); +-- +2.51.0 + diff --git a/queue-6.19/io_uring-sync-validate-passed-in-offset.patch b/queue-6.19/io_uring-sync-validate-passed-in-offset.patch new file mode 100644 index 0000000000..a8242461e1 --- /dev/null +++ b/queue-6.19/io_uring-sync-validate-passed-in-offset.patch @@ -0,0 +1,36 @@ +From a31c000bf2b2efa1eda6b5cd2b9ae1f7b52d8233 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 11:48:56 -0700 +Subject: io_uring/sync: validate passed in offset + +From: Jens Axboe + +[ Upstream commit 649dd18f559891bdafc5532d737c7dfb56060a6d ] + +Check if the passed in offset is negative once cast to sync->off. This +ensures that -EINVAL is returned for that case, like it would be for +sync_file_range(2). + +Fixes: c992fe2925d7 ("io_uring: add fsync support") +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + io_uring/sync.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/io_uring/sync.c b/io_uring/sync.c +index cea2d381ffd2a..ab7fa1cd7dd63 100644 +--- a/io_uring/sync.c ++++ b/io_uring/sync.c +@@ -62,6 +62,8 @@ int io_fsync_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) + return -EINVAL; + + sync->off = READ_ONCE(sqe->off); ++ if (sync->off < 0) ++ return -EINVAL; + sync->len = READ_ONCE(sqe->len); + req->flags |= REQ_F_FORCE_ASYNC; + return 0; +-- +2.51.0 + diff --git a/queue-6.19/io_uring-use-release-acquire-ordering-for-ioring_set.patch b/queue-6.19/io_uring-use-release-acquire-ordering-for-ioring_set.patch new file mode 100644 index 0000000000..b835368027 --- /dev/null +++ b/queue-6.19/io_uring-use-release-acquire-ordering-for-ioring_set.patch @@ -0,0 +1,93 @@ +From 8c6d3b428ebd4f2d570c4d642f086b0a27bbd0ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Jan 2026 14:05:40 -0700 +Subject: io_uring: use release-acquire ordering for IORING_SETUP_R_DISABLED + +From: Caleb Sander Mateos + +[ Upstream commit 7a8737e1132ff07ca225aa7a4008f87319b5b1ca ] + +io_uring_enter(), __io_msg_ring_data(), and io_msg_send_fd() read +ctx->flags and ctx->submitter_task without holding the ctx's uring_lock. +This means they may race with the assignment to ctx->submitter_task and +the clearing of IORING_SETUP_R_DISABLED from ctx->flags in +io_register_enable_rings(). Ensure the correct ordering of the +ctx->flags and ctx->submitter_task memory accesses by storing to +ctx->flags using release ordering and loading it using acquire ordering. + +Signed-off-by: Caleb Sander Mateos +Fixes: 4add705e4eeb ("io_uring: remove io_register_submitter") +Reviewed-by: Joanne Koong +Reviewed-by: Gabriel Krisman Bertazi +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + io_uring/io_uring.c | 6 +++++- + io_uring/msg_ring.c | 12 ++++++++++-- + io_uring/register.c | 3 ++- + 3 files changed, 17 insertions(+), 4 deletions(-) + +diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c +index b7a077c11c21a..8aa671ba43474 100644 +--- a/io_uring/io_uring.c ++++ b/io_uring/io_uring.c +@@ -3256,7 +3256,11 @@ SYSCALL_DEFINE6(io_uring_enter, unsigned int, fd, u32, to_submit, + + ctx = file->private_data; + ret = -EBADFD; +- if (unlikely(ctx->flags & IORING_SETUP_R_DISABLED)) ++ /* ++ * Keep IORING_SETUP_R_DISABLED check before submitter_task load ++ * in io_uring_add_tctx_node() -> __io_uring_add_tctx_node_from_submit() ++ */ ++ if (unlikely(smp_load_acquire(&ctx->flags) & IORING_SETUP_R_DISABLED)) + goto out; + + /* +diff --git a/io_uring/msg_ring.c b/io_uring/msg_ring.c +index 7063ea7964e75..87b4d306cf1b6 100644 +--- a/io_uring/msg_ring.c ++++ b/io_uring/msg_ring.c +@@ -125,7 +125,11 @@ static int __io_msg_ring_data(struct io_ring_ctx *target_ctx, + return -EINVAL; + if (!(msg->flags & IORING_MSG_RING_FLAGS_PASS) && msg->dst_fd) + return -EINVAL; +- if (target_ctx->flags & IORING_SETUP_R_DISABLED) ++ /* ++ * Keep IORING_SETUP_R_DISABLED check before submitter_task load ++ * in io_msg_data_remote() -> io_msg_remote_post() ++ */ ++ if (smp_load_acquire(&target_ctx->flags) & IORING_SETUP_R_DISABLED) + return -EBADFD; + + if (io_msg_need_remote(target_ctx)) +@@ -245,7 +249,11 @@ static int io_msg_send_fd(struct io_kiocb *req, unsigned int issue_flags) + return -EINVAL; + if (target_ctx == ctx) + return -EINVAL; +- if (target_ctx->flags & IORING_SETUP_R_DISABLED) ++ /* ++ * Keep IORING_SETUP_R_DISABLED check before submitter_task load ++ * in io_msg_fd_remote() ++ */ ++ if (smp_load_acquire(&target_ctx->flags) & IORING_SETUP_R_DISABLED) + return -EBADFD; + if (!msg->src_file) { + int ret = io_msg_grab_file(req, issue_flags); +diff --git a/io_uring/register.c b/io_uring/register.c +index 3d3822ff3fd9e..12318c276068e 100644 +--- a/io_uring/register.c ++++ b/io_uring/register.c +@@ -193,7 +193,8 @@ static int io_register_enable_rings(struct io_ring_ctx *ctx) + if (ctx->restrictions.registered) + ctx->restricted = 1; + +- ctx->flags &= ~IORING_SETUP_R_DISABLED; ++ /* Keep submitter_task store before clearing IORING_SETUP_R_DISABLED */ ++ smp_store_release(&ctx->flags, ctx->flags & ~IORING_SETUP_R_DISABLED); + if (ctx->sq_data && wq_has_sleeper(&ctx->sq_data->wait)) + wake_up(&ctx->sq_data->wait); + return 0; +-- +2.51.0 + diff --git a/queue-6.19/iomap-fix-invalid-folio-access-after-folio_end_read.patch b/queue-6.19/iomap-fix-invalid-folio-access-after-folio_end_read.patch new file mode 100644 index 0000000000..ed961c114f --- /dev/null +++ b/queue-6.19/iomap-fix-invalid-folio-access-after-folio_end_read.patch @@ -0,0 +1,165 @@ +From 337f8361294a2890d35618d88cd8428b1031116e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 14:41:07 -0800 +Subject: iomap: fix invalid folio access after folio_end_read() + +From: Joanne Koong + +[ Upstream commit aa35dd5cbc060bc3e28ad22b1d76eefa3f024030 ] + +If the folio does not have an iomap_folio_state (ifs) attached and the +folio gets read in by the filesystem's IO helper, folio_end_read() will +be called by the IO helper at any time. For this case, we cannot access +the folio after dispatching it to the IO helper, eg subsequent accesses +like + + if (ctx->cur_folio && + offset_in_folio(ctx->cur_folio, iter->pos) == 0) { + +are incorrect. + +Fix these invalid accesses by invalidating ctx->cur_folio if all bytes +of the folio have been read in by the IO helper. + +This allows us to also remove the +1 bias added for the ifs case. The +bias was previously added to ensure that if all bytes are read in, the +IO helper does not end the read on the folio until iomap has decremented +the bias. + +Fixes: b2f35ac4146d ("iomap: add caller-provided callbacks for read and readahead") +Signed-off-by: Joanne Koong +Link: https://patch.msgid.link/20260126224107.2182262-2-joannelkoong@gmail.com +Reviewed-by: Christoph Hellwig +Reviewed-by: Matthew Wilcox (Oracle) +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/iomap/buffered-io.c | 51 ++++++++++++++++++++++-------------------- + 1 file changed, 27 insertions(+), 24 deletions(-) + +diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c +index 6beb876658c09..e3bedcbb5f1ea 100644 +--- a/fs/iomap/buffered-io.c ++++ b/fs/iomap/buffered-io.c +@@ -409,8 +409,6 @@ static void iomap_read_init(struct folio *folio) + struct iomap_folio_state *ifs = folio->private; + + if (ifs) { +- size_t len = folio_size(folio); +- + /* + * ifs->read_bytes_pending is used to track how many bytes are + * read in asynchronously by the IO helper. We need to track +@@ -418,23 +416,19 @@ static void iomap_read_init(struct folio *folio) + * reading in all the necessary ranges of the folio and can end + * the read. + * +- * Increase ->read_bytes_pending by the folio size to start, and +- * add a +1 bias. We'll subtract the bias and any uptodate / +- * zeroed ranges that did not require IO in iomap_read_end() +- * after we're done processing the folio. ++ * Increase ->read_bytes_pending by the folio size to start. ++ * We'll subtract any uptodate / zeroed ranges that did not ++ * require IO in iomap_read_end() after we're done processing ++ * the folio. + * + * We do this because otherwise, we would have to increment + * ifs->read_bytes_pending every time a range in the folio needs + * to be read in, which can get expensive since the spinlock + * needs to be held whenever modifying ifs->read_bytes_pending. +- * +- * We add the bias to ensure the read has not been ended on the +- * folio when iomap_read_end() is called, even if the IO helper +- * has already finished reading in the entire folio. + */ + spin_lock_irq(&ifs->state_lock); + WARN_ON_ONCE(ifs->read_bytes_pending != 0); +- ifs->read_bytes_pending = len + 1; ++ ifs->read_bytes_pending = folio_size(folio); + spin_unlock_irq(&ifs->state_lock); + } + } +@@ -465,11 +459,9 @@ static void iomap_read_end(struct folio *folio, size_t bytes_submitted) + + /* + * Subtract any bytes that were initially accounted to +- * read_bytes_pending but skipped for IO. The +1 accounts for +- * the bias we added in iomap_read_init(). ++ * read_bytes_pending but skipped for IO. + */ +- ifs->read_bytes_pending -= +- (folio_size(folio) + 1 - bytes_submitted); ++ ifs->read_bytes_pending -= folio_size(folio) - bytes_submitted; + + /* + * If !ifs->read_bytes_pending, this means all pending reads by +@@ -483,14 +475,16 @@ static void iomap_read_end(struct folio *folio, size_t bytes_submitted) + spin_unlock_irq(&ifs->state_lock); + if (end_read) + folio_end_read(folio, uptodate); +- } else if (!bytes_submitted) { ++ } else { + /* +- * If there were no bytes submitted, this means we are +- * responsible for unlocking the folio here, since no IO helper +- * has taken ownership of it. If there were bytes submitted, +- * then the IO helper will end the read via +- * iomap_finish_folio_read(). ++ * If a folio without an ifs is submitted to the IO helper, the ++ * read must be on the entire folio and the IO helper takes ++ * ownership of the folio. This means we should only enter ++ * iomap_read_end() for the !ifs case if no bytes were submitted ++ * to the IO helper, in which case we are responsible for ++ * unlocking the folio here. + */ ++ WARN_ON_ONCE(bytes_submitted); + folio_unlock(folio); + } + } +@@ -502,6 +496,7 @@ static int iomap_read_folio_iter(struct iomap_iter *iter, + loff_t pos = iter->pos; + loff_t length = iomap_length(iter); + struct folio *folio = ctx->cur_folio; ++ size_t folio_len = folio_size(folio); + size_t poff, plen; + loff_t pos_diff; + int ret; +@@ -515,8 +510,7 @@ static int iomap_read_folio_iter(struct iomap_iter *iter, + + ifs_alloc(iter->inode, folio, iter->flags); + +- length = min_t(loff_t, length, +- folio_size(folio) - offset_in_folio(folio, pos)); ++ length = min_t(loff_t, length, folio_len - offset_in_folio(folio, pos)); + while (length) { + iomap_adjust_read_range(iter->inode, folio, &pos, length, &poff, + &plen); +@@ -542,7 +536,15 @@ static int iomap_read_folio_iter(struct iomap_iter *iter, + ret = ctx->ops->read_folio_range(iter, ctx, plen); + if (ret) + return ret; ++ + *bytes_submitted += plen; ++ /* ++ * If the entire folio has been read in by the IO ++ * helper, then the helper owns the folio and will end ++ * the read on it. ++ */ ++ if (*bytes_submitted == folio_len) ++ ctx->cur_folio = NULL; + } + + ret = iomap_iter_advance(iter, plen); +@@ -575,7 +577,8 @@ void iomap_read_folio(const struct iomap_ops *ops, + if (ctx->ops->submit_read) + ctx->ops->submit_read(ctx); + +- iomap_read_end(folio, bytes_submitted); ++ if (ctx->cur_folio) ++ iomap_read_end(ctx->cur_folio, bytes_submitted); + } + EXPORT_SYMBOL_GPL(iomap_read_folio); + +-- +2.51.0 + diff --git a/queue-6.19/iomap-fix-submission-side-handling-of-completion-sid.patch b/queue-6.19/iomap-fix-submission-side-handling-of-completion-sid.patch new file mode 100644 index 0000000000..6babc91320 --- /dev/null +++ b/queue-6.19/iomap-fix-submission-side-handling-of-completion-sid.patch @@ -0,0 +1,49 @@ +From 78e4857dc65aefff804cc091b044ceb0696dee21 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 06:53:38 +0100 +Subject: iomap: fix submission side handling of completion side errors + +From: Christoph Hellwig + +[ Upstream commit 4ad357e39b2ecd5da7bcc7e840ee24d179593cd5 ] + +The "if (dio->error)" in iomap_dio_bio_iter exists to stop submitting +more bios when a completion already return an error. Commit cfe057f7db1f +("iomap_dio_actor(): fix iov_iter bugs") made it revert the iov by +"copied", which is very wrong given that we've already consumed that +range and submitted a bio for it. + +Fixes: cfe057f7db1f ("iomap_dio_actor(): fix iov_iter bugs") +Signed-off-by: Christoph Hellwig +Reviewed-by: Damien Le Moal +Reviewed-by: Darrick J. Wong +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + fs/iomap/direct-io.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/fs/iomap/direct-io.c b/fs/iomap/direct-io.c +index 8e273408453a9..6ec4940e019c6 100644 +--- a/fs/iomap/direct-io.c ++++ b/fs/iomap/direct-io.c +@@ -442,9 +442,13 @@ static int iomap_dio_bio_iter(struct iomap_iter *iter, struct iomap_dio *dio) + nr_pages = bio_iov_vecs_to_alloc(dio->submit.iter, BIO_MAX_VECS); + do { + size_t n; +- if (dio->error) { +- iov_iter_revert(dio->submit.iter, copied); +- copied = ret = 0; ++ ++ /* ++ * If completions already occurred and reported errors, give up now and ++ * don't bother submitting more bios. ++ */ ++ if (unlikely(data_race(dio->error))) { ++ ret = 0; + goto out; + } + +-- +2.51.0 + diff --git a/queue-6.19/iommu-amd-use-core-s-primary-handler-and-set-irqf_on.patch b/queue-6.19/iommu-amd-use-core-s-primary-handler-and-set-irqf_on.patch new file mode 100644 index 0000000000..9c9483617d --- /dev/null +++ b/queue-6.19/iommu-amd-use-core-s-primary-handler-and-set-irqf_on.patch @@ -0,0 +1,95 @@ +From 8f16b884730ba4cbfbf7f90e4e9fb31cf313d397 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:55:23 +0100 +Subject: iommu/amd: Use core's primary handler and set IRQF_ONESHOT + +From: Sebastian Andrzej Siewior + +[ Upstream commit 5bfcdccb4d18d3909b7f87942be67fd6bdc00c1d ] + +request_threaded_irq() is invoked with a primary and a secondary handler +and no flags are passed. The primary handler is the same as +irq_default_primary_handler() so there is no need to have an identical +copy. + +The lack of the IRQF_ONESHOT can be dangerous because the interrupt +source is not masked while the threaded handler is active. This means, +especially on LEVEL typed interrupt lines, the interrupt can fire again +before the threaded handler had a chance to run. + +Use the default primary interrupt handler by specifying NULL and set +IRQF_ONESHOT so the interrupt source is masked until the secondary +handler is done. + +Fixes: 72fe00f01f9a3 ("x86/amd-iommu: Use threaded interupt handler") +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260128095540.863589-4-bigeasy@linutronix.de +Signed-off-by: Sasha Levin +--- + drivers/iommu/amd/amd_iommu.h | 1 - + drivers/iommu/amd/init.c | 12 ++++-------- + drivers/iommu/amd/iommu.c | 5 ----- + 3 files changed, 4 insertions(+), 14 deletions(-) + +diff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h +index b742ef1adb352..df1c238dc8885 100644 +--- a/drivers/iommu/amd/amd_iommu.h ++++ b/drivers/iommu/amd/amd_iommu.h +@@ -15,7 +15,6 @@ irqreturn_t amd_iommu_int_thread(int irq, void *data); + irqreturn_t amd_iommu_int_thread_evtlog(int irq, void *data); + irqreturn_t amd_iommu_int_thread_pprlog(int irq, void *data); + irqreturn_t amd_iommu_int_thread_galog(int irq, void *data); +-irqreturn_t amd_iommu_int_handler(int irq, void *data); + void amd_iommu_restart_log(struct amd_iommu *iommu, const char *evt_type, + u8 cntrl_intr, u8 cntrl_log, + u32 status_run_mask, u32 status_overflow_mask); +diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c +index 384c90b4f90a0..62a7a718acf8f 100644 +--- a/drivers/iommu/amd/init.c ++++ b/drivers/iommu/amd/init.c +@@ -2356,12 +2356,8 @@ static int iommu_setup_msi(struct amd_iommu *iommu) + if (r) + return r; + +- r = request_threaded_irq(iommu->dev->irq, +- amd_iommu_int_handler, +- amd_iommu_int_thread, +- 0, "AMD-Vi", +- iommu); +- ++ r = request_threaded_irq(iommu->dev->irq, NULL, amd_iommu_int_thread, ++ IRQF_ONESHOT, "AMD-Vi", iommu); + if (r) { + pci_disable_msi(iommu->dev); + return r; +@@ -2535,8 +2531,8 @@ static int __iommu_setup_intcapxt(struct amd_iommu *iommu, const char *devname, + return irq; + } + +- ret = request_threaded_irq(irq, amd_iommu_int_handler, +- thread_fn, 0, devname, iommu); ++ ret = request_threaded_irq(irq, NULL, thread_fn, IRQF_ONESHOT, devname, ++ iommu); + if (ret) { + irq_domain_free_irqs(irq, 1); + irq_domain_remove(domain); +diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c +index 7c12be1b247f4..0f9045ce93af1 100644 +--- a/drivers/iommu/amd/iommu.c ++++ b/drivers/iommu/amd/iommu.c +@@ -1151,11 +1151,6 @@ irqreturn_t amd_iommu_int_thread(int irq, void *data) + return IRQ_HANDLED; + } + +-irqreturn_t amd_iommu_int_handler(int irq, void *data) +-{ +- return IRQ_WAKE_THREAD; +-} +- + /**************************************************************************** + * + * IOMMU command queuing functions +-- +2.51.0 + diff --git a/queue-6.19/iommu-vt-d-clear-present-bit-before-tearing-down-con.patch b/queue-6.19/iommu-vt-d-clear-present-bit-before-tearing-down-con.patch new file mode 100644 index 0000000000..397070713c --- /dev/null +++ b/queue-6.19/iommu-vt-d-clear-present-bit-before-tearing-down-con.patch @@ -0,0 +1,128 @@ +From db2e6b1066c19a23701b5c8bc5e45c4797293866 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 09:48:55 +0800 +Subject: iommu/vt-d: Clear Present bit before tearing down context entry +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Lu Baolu + +[ Upstream commit c1e4f1dccbe9d7656d1c6872ebeadb5992d0aaa2 ] + +When tearing down a context entry, the current implementation zeros the +entire 128-bit entry using multiple 64-bit writes. This creates a window +where the hardware can fetch a "torn" entry — where some fields are +already zeroed while the 'Present' bit is still set — leading to +unpredictable behavior or spurious faults. + +While x86 provides strong write ordering, the compiler may reorder writes +to the two 64-bit halves of the context entry. Even without compiler +reordering, the hardware fetch is not guaranteed to be atomic with +respect to multiple CPU writes. + +Align with the "Guidance to Software for Invalidations" in the VT-d spec +(Section 6.5.3.3) by implementing the recommended ownership handshake: + +1. Clear only the 'Present' (P) bit of the context entry first to + signal the transition of ownership from hardware to software. +2. Use dma_wmb() to ensure the cleared bit is visible to the IOMMU. +3. Perform the required cache and context-cache invalidation to ensure + hardware no longer has cached references to the entry. +4. Fully zero out the entry only after the invalidation is complete. + +Also, add a dma_wmb() to context_set_present() to ensure the entry +is fully initialized before the 'Present' bit becomes visible. + +Fixes: ba39592764ed2 ("Intel IOMMU: Intel IOMMU driver") +Reported-by: Dmytro Maluka +Closes: https://lore.kernel.org/all/aTG7gc7I5wExai3S@google.com/ +Signed-off-by: Lu Baolu +Reviewed-by: Dmytro Maluka +Reviewed-by: Samiullah Khawaja +Reviewed-by: Kevin Tian +Link: https://lore.kernel.org/r/20260120061816.2132558-3-baolu.lu@linux.intel.com +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/intel/iommu.c | 4 +++- + drivers/iommu/intel/iommu.h | 21 ++++++++++++++++++++- + drivers/iommu/intel/pasid.c | 5 ++++- + 3 files changed, 27 insertions(+), 3 deletions(-) + +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index 134302fbcd926..c66cc51f9e51e 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -1240,10 +1240,12 @@ static void domain_context_clear_one(struct device_domain_info *info, u8 bus, u8 + } + + did = context_domain_id(context); +- context_clear_entry(context); ++ context_clear_present(context); + __iommu_flush_cache(iommu, context, sizeof(*context)); + spin_unlock(&iommu->lock); + intel_context_flush_no_pasid(info, context, did); ++ context_clear_entry(context); ++ __iommu_flush_cache(iommu, context, sizeof(*context)); + } + + int __domain_setup_first_level(struct intel_iommu *iommu, struct device *dev, +diff --git a/drivers/iommu/intel/iommu.h b/drivers/iommu/intel/iommu.h +index 25c5e22096d44..599913fb65d59 100644 +--- a/drivers/iommu/intel/iommu.h ++++ b/drivers/iommu/intel/iommu.h +@@ -900,7 +900,26 @@ static inline int pfn_level_offset(u64 pfn, int level) + + static inline void context_set_present(struct context_entry *context) + { +- context->lo |= 1; ++ u64 val; ++ ++ dma_wmb(); ++ val = READ_ONCE(context->lo) | 1; ++ WRITE_ONCE(context->lo, val); ++} ++ ++/* ++ * Clear the Present (P) bit (bit 0) of a context table entry. This initiates ++ * the transition of the entry's ownership from hardware to software. The ++ * caller is responsible for fulfilling the invalidation handshake recommended ++ * by the VT-d spec, Section 6.5.3.3 (Guidance to Software for Invalidations). ++ */ ++static inline void context_clear_present(struct context_entry *context) ++{ ++ u64 val; ++ ++ val = READ_ONCE(context->lo) & GENMASK_ULL(63, 1); ++ WRITE_ONCE(context->lo, val); ++ dma_wmb(); + } + + static inline void context_set_fault_enable(struct context_entry *context) +diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c +index b611ad070e729..db535385778bd 100644 +--- a/drivers/iommu/intel/pasid.c ++++ b/drivers/iommu/intel/pasid.c +@@ -1024,7 +1024,7 @@ static int device_pasid_table_setup(struct device *dev, u8 bus, u8 devfn) + } + + if (context_copied(iommu, bus, devfn)) { +- context_clear_entry(context); ++ context_clear_present(context); + __iommu_flush_cache(iommu, context, sizeof(*context)); + + /* +@@ -1044,6 +1044,9 @@ static int device_pasid_table_setup(struct device *dev, u8 bus, u8 devfn) + iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH); + devtlb_invalidation_with_pasid(iommu, dev, IOMMU_NO_PASID); + ++ context_clear_entry(context); ++ __iommu_flush_cache(iommu, context, sizeof(*context)); ++ + /* + * At this point, the device is supposed to finish reset at + * its driver probe stage, so no in-flight DMA will exist, +-- +2.51.0 + diff --git a/queue-6.19/iommu-vt-d-clear-present-bit-before-tearing-down-pas.patch b/queue-6.19/iommu-vt-d-clear-present-bit-before-tearing-down-pas.patch new file mode 100644 index 0000000000..d5458875e2 --- /dev/null +++ b/queue-6.19/iommu-vt-d-clear-present-bit-before-tearing-down-pas.patch @@ -0,0 +1,104 @@ +From 956ab8d1e04dc27db7d6850bfc2fba0aa19b2685 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 09:48:54 +0800 +Subject: iommu/vt-d: Clear Present bit before tearing down PASID entry + +From: Lu Baolu + +[ Upstream commit 75ed00055c059dedc47b5daaaa2f8a7a019138ff ] + +The Intel VT-d Scalable Mode PASID table entry consists of 512 bits (64 +bytes). When tearing down an entry, the current implementation zeros the +entire 64-byte structure immediately using multiple 64-bit writes. + +Since the IOMMU hardware may fetch these 64 bytes using multiple +internal transactions (e.g., four 128-bit bursts), updating or zeroing +the entire entry while it is active (P=1) risks a "torn" read. If a +hardware fetch occurs simultaneously with the CPU zeroing the entry, the +hardware could observe an inconsistent state, leading to unpredictable +behavior or spurious faults. + +Follow the "Guidance to Software for Invalidations" in the VT-d spec +(Section 6.5.3.3) by implementing the recommended ownership handshake: + +1. Clear only the 'Present' (P) bit of the PASID entry. +2. Use a dma_wmb() to ensure the cleared bit is visible to hardware + before proceeding. +3. Execute the required invalidation sequence (PASID cache, IOTLB, and + Device-TLB flush) to ensure the hardware has released all cached + references. +4. Only after the flushes are complete, zero out the remaining fields + of the PASID entry. + +Also, add a dma_wmb() in pasid_set_present() to ensure that all other +fields of the PASID entry are visible to the hardware before the Present +bit is set. + +Fixes: 0bbeb01a4faf ("iommu/vt-d: Manage scalalble mode PASID tables") +Signed-off-by: Lu Baolu +Reviewed-by: Dmytro Maluka +Reviewed-by: Samiullah Khawaja +Reviewed-by: Kevin Tian +Link: https://lore.kernel.org/r/20260120061816.2132558-2-baolu.lu@linux.intel.com +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/intel/pasid.c | 6 +++++- + drivers/iommu/intel/pasid.h | 14 ++++++++++++++ + 2 files changed, 19 insertions(+), 1 deletion(-) + +diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c +index 77b9b147ab50e..b611ad070e729 100644 +--- a/drivers/iommu/intel/pasid.c ++++ b/drivers/iommu/intel/pasid.c +@@ -273,7 +273,7 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev, + + did = pasid_get_domain_id(pte); + pgtt = pasid_pte_get_pgtt(pte); +- intel_pasid_clear_entry(dev, pasid, fault_ignore); ++ pasid_clear_present(pte); + spin_unlock(&iommu->lock); + + if (!ecap_coherent(iommu->ecap)) +@@ -287,6 +287,10 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev, + iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH); + + devtlb_invalidation_with_pasid(iommu, dev, pasid); ++ intel_pasid_clear_entry(dev, pasid, fault_ignore); ++ if (!ecap_coherent(iommu->ecap)) ++ clflush_cache_range(pte, sizeof(*pte)); ++ + if (!fault_ignore) + intel_iommu_drain_pasid_prq(dev, pasid); + } +diff --git a/drivers/iommu/intel/pasid.h b/drivers/iommu/intel/pasid.h +index 3809793e0259f..b67b2dc4ad9c0 100644 +--- a/drivers/iommu/intel/pasid.h ++++ b/drivers/iommu/intel/pasid.h +@@ -234,9 +234,23 @@ static inline void pasid_set_wpe(struct pasid_entry *pe) + */ + static inline void pasid_set_present(struct pasid_entry *pe) + { ++ dma_wmb(); + pasid_set_bits(&pe->val[0], 1 << 0, 1); + } + ++/* ++ * Clear the Present (P) bit (bit 0) of a scalable-mode PASID table entry. ++ * This initiates the transition of the entry's ownership from hardware ++ * to software. The caller is responsible for fulfilling the invalidation ++ * handshake recommended by the VT-d spec, Section 6.5.3.3 (Guidance to ++ * Software for Invalidations). ++ */ ++static inline void pasid_clear_present(struct pasid_entry *pe) ++{ ++ pasid_set_bits(&pe->val[0], 1 << 0, 0); ++ dma_wmb(); ++} ++ + /* + * Setup Page Walk Snoop bit (Bit 87) of a scalable mode PASID + * entry. +-- +2.51.0 + diff --git a/queue-6.19/iommu-vt-d-fix-race-condition-during-pasid-entry-rep.patch b/queue-6.19/iommu-vt-d-fix-race-condition-during-pasid-entry-rep.patch new file mode 100644 index 0000000000..ab727c460f --- /dev/null +++ b/queue-6.19/iommu-vt-d-fix-race-condition-during-pasid-entry-rep.patch @@ -0,0 +1,365 @@ +From 8fb35bdf1c0be20be6746ecd9be192e2c25da95a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 09:48:56 +0800 +Subject: iommu/vt-d: Fix race condition during PASID entry replacement +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Lu Baolu + +[ Upstream commit c3b1edea3791fa91ab7032faa90355913ad9451b ] + +The Intel VT-d PASID table entry is 512 bits (64 bytes). When replacing +an active PASID entry (e.g., during domain replacement), the current +implementation calculates a new entry on the stack and copies it to the +table using a single structure assignment. + + struct pasid_entry *pte, new_pte; + + pte = intel_pasid_get_entry(dev, pasid); + pasid_pte_config_first_level(iommu, &new_pte, ...); + *pte = new_pte; + +Because the hardware may fetch the 512-bit PASID entry in multiple +128-bit chunks, updating the entire entry while it is active (Present +bit set) risks a "torn" read. In this scenario, the IOMMU hardware +could observe an inconsistent state — partially new data and partially +old data — leading to unpredictable behavior or spurious faults. + +Fix this by removing the unsafe "replace" helpers and following the +"clear-then-update" flow, which ensures the Present bit is cleared and +the required invalidation handshake is completed before the new +configuration is applied. + +Fixes: 7543ee63e811 ("iommu/vt-d: Add pasid replace helpers") +Signed-off-by: Lu Baolu +Reviewed-by: Samiullah Khawaja +Reviewed-by: Kevin Tian +Link: https://lore.kernel.org/r/20260120061816.2132558-4-baolu.lu@linux.intel.com +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/intel/iommu.c | 29 +++--- + drivers/iommu/intel/nested.c | 9 +- + drivers/iommu/intel/pasid.c | 184 ----------------------------------- + drivers/iommu/intel/pasid.h | 14 --- + 4 files changed, 16 insertions(+), 220 deletions(-) + +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index c66cc51f9e51e..705828b06e329 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -1252,12 +1252,10 @@ int __domain_setup_first_level(struct intel_iommu *iommu, struct device *dev, + ioasid_t pasid, u16 did, phys_addr_t fsptptr, + int flags, struct iommu_domain *old) + { +- if (!old) +- return intel_pasid_setup_first_level(iommu, dev, fsptptr, pasid, +- did, flags); +- return intel_pasid_replace_first_level(iommu, dev, fsptptr, pasid, did, +- iommu_domain_did(old, iommu), +- flags); ++ if (old) ++ intel_pasid_tear_down_entry(iommu, dev, pasid, false); ++ ++ return intel_pasid_setup_first_level(iommu, dev, fsptptr, pasid, did, flags); + } + + static int domain_setup_second_level(struct intel_iommu *iommu, +@@ -1265,23 +1263,20 @@ static int domain_setup_second_level(struct intel_iommu *iommu, + struct device *dev, ioasid_t pasid, + struct iommu_domain *old) + { +- if (!old) +- return intel_pasid_setup_second_level(iommu, domain, +- dev, pasid); +- return intel_pasid_replace_second_level(iommu, domain, dev, +- iommu_domain_did(old, iommu), +- pasid); ++ if (old) ++ intel_pasid_tear_down_entry(iommu, dev, pasid, false); ++ ++ return intel_pasid_setup_second_level(iommu, domain, dev, pasid); + } + + static int domain_setup_passthrough(struct intel_iommu *iommu, + struct device *dev, ioasid_t pasid, + struct iommu_domain *old) + { +- if (!old) +- return intel_pasid_setup_pass_through(iommu, dev, pasid); +- return intel_pasid_replace_pass_through(iommu, dev, +- iommu_domain_did(old, iommu), +- pasid); ++ if (old) ++ intel_pasid_tear_down_entry(iommu, dev, pasid, false); ++ ++ return intel_pasid_setup_pass_through(iommu, dev, pasid); + } + + static int domain_setup_first_level(struct intel_iommu *iommu, +diff --git a/drivers/iommu/intel/nested.c b/drivers/iommu/intel/nested.c +index a3fb8c193ca64..e9a440e9c960b 100644 +--- a/drivers/iommu/intel/nested.c ++++ b/drivers/iommu/intel/nested.c +@@ -136,11 +136,10 @@ static int domain_setup_nested(struct intel_iommu *iommu, + struct device *dev, ioasid_t pasid, + struct iommu_domain *old) + { +- if (!old) +- return intel_pasid_setup_nested(iommu, dev, pasid, domain); +- return intel_pasid_replace_nested(iommu, dev, pasid, +- iommu_domain_did(old, iommu), +- domain); ++ if (old) ++ intel_pasid_tear_down_entry(iommu, dev, pasid, false); ++ ++ return intel_pasid_setup_nested(iommu, dev, pasid, domain); + } + + static int intel_nested_set_dev_pasid(struct iommu_domain *domain, +diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c +index db535385778bd..34b209b88be2a 100644 +--- a/drivers/iommu/intel/pasid.c ++++ b/drivers/iommu/intel/pasid.c +@@ -417,50 +417,6 @@ int intel_pasid_setup_first_level(struct intel_iommu *iommu, struct device *dev, + return 0; + } + +-int intel_pasid_replace_first_level(struct intel_iommu *iommu, +- struct device *dev, phys_addr_t fsptptr, +- u32 pasid, u16 did, u16 old_did, +- int flags) +-{ +- struct pasid_entry *pte, new_pte; +- +- if (!ecap_flts(iommu->ecap)) { +- pr_err("No first level translation support on %s\n", +- iommu->name); +- return -EINVAL; +- } +- +- if ((flags & PASID_FLAG_FL5LP) && !cap_fl5lp_support(iommu->cap)) { +- pr_err("No 5-level paging support for first-level on %s\n", +- iommu->name); +- return -EINVAL; +- } +- +- pasid_pte_config_first_level(iommu, &new_pte, fsptptr, did, flags); +- +- spin_lock(&iommu->lock); +- pte = intel_pasid_get_entry(dev, pasid); +- if (!pte) { +- spin_unlock(&iommu->lock); +- return -ENODEV; +- } +- +- if (!pasid_pte_is_present(pte)) { +- spin_unlock(&iommu->lock); +- return -EINVAL; +- } +- +- WARN_ON(old_did != pasid_get_domain_id(pte)); +- +- *pte = new_pte; +- spin_unlock(&iommu->lock); +- +- intel_pasid_flush_present(iommu, dev, pasid, old_did, pte); +- intel_iommu_drain_pasid_prq(dev, pasid); +- +- return 0; +-} +- + /* + * Set up the scalable mode pasid entry for second only translation type. + */ +@@ -527,51 +483,6 @@ int intel_pasid_setup_second_level(struct intel_iommu *iommu, + return 0; + } + +-int intel_pasid_replace_second_level(struct intel_iommu *iommu, +- struct dmar_domain *domain, +- struct device *dev, u16 old_did, +- u32 pasid) +-{ +- struct pasid_entry *pte, new_pte; +- u16 did; +- +- /* +- * If hardware advertises no support for second level +- * translation, return directly. +- */ +- if (!ecap_slts(iommu->ecap)) { +- pr_err("No second level translation support on %s\n", +- iommu->name); +- return -EINVAL; +- } +- +- did = domain_id_iommu(domain, iommu); +- +- pasid_pte_config_second_level(iommu, &new_pte, domain, did); +- +- spin_lock(&iommu->lock); +- pte = intel_pasid_get_entry(dev, pasid); +- if (!pte) { +- spin_unlock(&iommu->lock); +- return -ENODEV; +- } +- +- if (!pasid_pte_is_present(pte)) { +- spin_unlock(&iommu->lock); +- return -EINVAL; +- } +- +- WARN_ON(old_did != pasid_get_domain_id(pte)); +- +- *pte = new_pte; +- spin_unlock(&iommu->lock); +- +- intel_pasid_flush_present(iommu, dev, pasid, old_did, pte); +- intel_iommu_drain_pasid_prq(dev, pasid); +- +- return 0; +-} +- + /* + * Set up dirty tracking on a second only or nested translation type. + */ +@@ -684,38 +595,6 @@ int intel_pasid_setup_pass_through(struct intel_iommu *iommu, + return 0; + } + +-int intel_pasid_replace_pass_through(struct intel_iommu *iommu, +- struct device *dev, u16 old_did, +- u32 pasid) +-{ +- struct pasid_entry *pte, new_pte; +- u16 did = FLPT_DEFAULT_DID; +- +- pasid_pte_config_pass_through(iommu, &new_pte, did); +- +- spin_lock(&iommu->lock); +- pte = intel_pasid_get_entry(dev, pasid); +- if (!pte) { +- spin_unlock(&iommu->lock); +- return -ENODEV; +- } +- +- if (!pasid_pte_is_present(pte)) { +- spin_unlock(&iommu->lock); +- return -EINVAL; +- } +- +- WARN_ON(old_did != pasid_get_domain_id(pte)); +- +- *pte = new_pte; +- spin_unlock(&iommu->lock); +- +- intel_pasid_flush_present(iommu, dev, pasid, old_did, pte); +- intel_iommu_drain_pasid_prq(dev, pasid); +- +- return 0; +-} +- + /* + * Set the page snoop control for a pasid entry which has been set up. + */ +@@ -849,69 +728,6 @@ int intel_pasid_setup_nested(struct intel_iommu *iommu, struct device *dev, + return 0; + } + +-int intel_pasid_replace_nested(struct intel_iommu *iommu, +- struct device *dev, u32 pasid, +- u16 old_did, struct dmar_domain *domain) +-{ +- struct iommu_hwpt_vtd_s1 *s1_cfg = &domain->s1_cfg; +- struct dmar_domain *s2_domain = domain->s2_domain; +- u16 did = domain_id_iommu(domain, iommu); +- struct pasid_entry *pte, new_pte; +- +- /* Address width should match the address width supported by hardware */ +- switch (s1_cfg->addr_width) { +- case ADDR_WIDTH_4LEVEL: +- break; +- case ADDR_WIDTH_5LEVEL: +- if (!cap_fl5lp_support(iommu->cap)) { +- dev_err_ratelimited(dev, +- "5-level paging not supported\n"); +- return -EINVAL; +- } +- break; +- default: +- dev_err_ratelimited(dev, "Invalid stage-1 address width %d\n", +- s1_cfg->addr_width); +- return -EINVAL; +- } +- +- if ((s1_cfg->flags & IOMMU_VTD_S1_SRE) && !ecap_srs(iommu->ecap)) { +- pr_err_ratelimited("No supervisor request support on %s\n", +- iommu->name); +- return -EINVAL; +- } +- +- if ((s1_cfg->flags & IOMMU_VTD_S1_EAFE) && !ecap_eafs(iommu->ecap)) { +- pr_err_ratelimited("No extended access flag support on %s\n", +- iommu->name); +- return -EINVAL; +- } +- +- pasid_pte_config_nestd(iommu, &new_pte, s1_cfg, s2_domain, did); +- +- spin_lock(&iommu->lock); +- pte = intel_pasid_get_entry(dev, pasid); +- if (!pte) { +- spin_unlock(&iommu->lock); +- return -ENODEV; +- } +- +- if (!pasid_pte_is_present(pte)) { +- spin_unlock(&iommu->lock); +- return -EINVAL; +- } +- +- WARN_ON(old_did != pasid_get_domain_id(pte)); +- +- *pte = new_pte; +- spin_unlock(&iommu->lock); +- +- intel_pasid_flush_present(iommu, dev, pasid, old_did, pte); +- intel_iommu_drain_pasid_prq(dev, pasid); +- +- return 0; +-} +- + /* + * Interfaces to setup or teardown a pasid table to the scalable-mode + * context table entry: +diff --git a/drivers/iommu/intel/pasid.h b/drivers/iommu/intel/pasid.h +index b67b2dc4ad9c0..48d3bb6b68dea 100644 +--- a/drivers/iommu/intel/pasid.h ++++ b/drivers/iommu/intel/pasid.h +@@ -316,20 +316,6 @@ int intel_pasid_setup_pass_through(struct intel_iommu *iommu, + struct device *dev, u32 pasid); + int intel_pasid_setup_nested(struct intel_iommu *iommu, struct device *dev, + u32 pasid, struct dmar_domain *domain); +-int intel_pasid_replace_first_level(struct intel_iommu *iommu, +- struct device *dev, phys_addr_t fsptptr, +- u32 pasid, u16 did, u16 old_did, int flags); +-int intel_pasid_replace_second_level(struct intel_iommu *iommu, +- struct dmar_domain *domain, +- struct device *dev, u16 old_did, +- u32 pasid); +-int intel_pasid_replace_pass_through(struct intel_iommu *iommu, +- struct device *dev, u16 old_did, +- u32 pasid); +-int intel_pasid_replace_nested(struct intel_iommu *iommu, +- struct device *dev, u32 pasid, +- u16 old_did, struct dmar_domain *domain); +- + void intel_pasid_tear_down_entry(struct intel_iommu *iommu, + struct device *dev, u32 pasid, + bool fault_ignore); +-- +2.51.0 + diff --git a/queue-6.19/iommu-vt-d-flush-cache-for-pasid-table-before-using-.patch b/queue-6.19/iommu-vt-d-flush-cache-for-pasid-table-before-using-.patch new file mode 100644 index 0000000000..2b26135d9b --- /dev/null +++ b/queue-6.19/iommu-vt-d-flush-cache-for-pasid-table-before-using-.patch @@ -0,0 +1,55 @@ +From 805448ceb2b87c4bbf93c9f0d2c8df2089e7b74d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 09:48:52 +0800 +Subject: iommu/vt-d: Flush cache for PASID table before using it + +From: Dmytro Maluka + +[ Upstream commit 22d169bdd2849fe6bd18c2643742e1c02be6451c ] + +When writing the address of a freshly allocated zero-initialized PASID +table to a PASID directory entry, do that after the CPU cache flush for +this PASID table, not before it, to avoid the time window when this +PASID table may be already used by non-coherent IOMMU hardware while +its contents in RAM is still some random old data, not zero-initialized. + +Fixes: 194b3348bdbb ("iommu/vt-d: Fix PASID directory pointer coherency") +Signed-off-by: Dmytro Maluka +Reviewed-by: Kevin Tian +Link: https://lore.kernel.org/r/20251221123508.37495-1-dmaluka@chromium.org +Signed-off-by: Lu Baolu +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/intel/pasid.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c +index 3e2255057079c..77b9b147ab50e 100644 +--- a/drivers/iommu/intel/pasid.c ++++ b/drivers/iommu/intel/pasid.c +@@ -153,6 +153,9 @@ static struct pasid_entry *intel_pasid_get_entry(struct device *dev, u32 pasid) + if (!entries) + return NULL; + ++ if (!ecap_coherent(info->iommu->ecap)) ++ clflush_cache_range(entries, VTD_PAGE_SIZE); ++ + /* + * The pasid directory table entry won't be freed after + * allocation. No worry about the race with free and +@@ -165,10 +168,8 @@ static struct pasid_entry *intel_pasid_get_entry(struct device *dev, u32 pasid) + iommu_free_pages(entries); + goto retry; + } +- if (!ecap_coherent(info->iommu->ecap)) { +- clflush_cache_range(entries, VTD_PAGE_SIZE); ++ if (!ecap_coherent(info->iommu->ecap)) + clflush_cache_range(&dir[dir_index].val, sizeof(*dir)); +- } + } + + return &entries[index]; +-- +2.51.0 + diff --git a/queue-6.19/iommupt-do-not-set-c-bit-on-mmio-backed-ptes.patch b/queue-6.19/iommupt-do-not-set-c-bit-on-mmio-backed-ptes.patch new file mode 100644 index 0000000000..c0c3127151 --- /dev/null +++ b/queue-6.19/iommupt-do-not-set-c-bit-on-mmio-backed-ptes.patch @@ -0,0 +1,70 @@ +From f50127e4db73e845c3b14ecafc0d25c168754deb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 03:19:20 +0800 +Subject: iommupt: Do not set C-bit on MMIO backed PTEs + +From: Wei Wang + +[ Upstream commit e2692c4eeaa4bd945b7bae156b4cac55d6a0c730 ] + +AMD Secure Memory Encryption (SME) marks individual memory pages as +encrypted by setting the C-bit in page table entries. According to the +AMD APM,any pages corresponding to MMIO addresses must be configured +with the C-bit clear. + +The current *_iommu_set_prot() implementation sets the C-bit on all PTEs +in the IOMMU page tables. This is incorrect for PTEs backed by MMIO, and +can break PCIe peer-to-peer communication when IOVA is used. Fix this by +avoiding the C-bit for MMIO-backed mappings. + +For amdv2 IOMMU page tables, there is a usage scenario for GVA->GPA +mappings, and for the trusted MMIO in the TEE-IO case, the C-bit will need +to be added to GPA. However, SNP guests do not yet support vIOMMU, and the +trusted MMIO support is not ready in upstream. Adding the C-bit for trusted +MMIO can be considered once those features land. + +Fixes: 879ced2bab1b ("iommupt: Add the AMD IOMMU v1 page table format") +Fixes: aef5de756ea8 ("iommupt: Add the x86 64 bit page table format") +Suggested-by: Jason Gunthorpe +Signed-off-by: Wei Wang +Reviewed-by: Jason Gunthorpe +Reviewed-by: Kevin Tian +Reviewed-by: Vasant Hegde +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/generic_pt/fmt/amdv1.h | 3 ++- + drivers/iommu/generic_pt/fmt/x86_64.h | 3 ++- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/iommu/generic_pt/fmt/amdv1.h b/drivers/iommu/generic_pt/fmt/amdv1.h +index aa8e1a8ec95fd..3b2c41d9654d7 100644 +--- a/drivers/iommu/generic_pt/fmt/amdv1.h ++++ b/drivers/iommu/generic_pt/fmt/amdv1.h +@@ -354,7 +354,8 @@ static inline int amdv1pt_iommu_set_prot(struct pt_common *common, + * Ideally we'd have an IOMMU_ENCRYPTED flag set by higher levels to + * control this. For now if the tables use sme_set then so do the ptes. + */ +- if (pt_feature(common, PT_FEAT_AMDV1_ENCRYPT_TABLES)) ++ if (pt_feature(common, PT_FEAT_AMDV1_ENCRYPT_TABLES) && ++ !(iommu_prot & IOMMU_MMIO)) + pte = __sme_set(pte); + + attrs->descriptor_bits = pte; +diff --git a/drivers/iommu/generic_pt/fmt/x86_64.h b/drivers/iommu/generic_pt/fmt/x86_64.h +index 210748d9d6e8a..ed9a47cbb6e02 100644 +--- a/drivers/iommu/generic_pt/fmt/x86_64.h ++++ b/drivers/iommu/generic_pt/fmt/x86_64.h +@@ -227,7 +227,8 @@ static inline int x86_64_pt_iommu_set_prot(struct pt_common *common, + * Ideally we'd have an IOMMU_ENCRYPTED flag set by higher levels to + * control this. For now if the tables use sme_set then so do the ptes. + */ +- if (pt_feature(common, PT_FEAT_X86_64_AMD_ENCRYPT_TABLES)) ++ if (pt_feature(common, PT_FEAT_X86_64_AMD_ENCRYPT_TABLES) && ++ !(iommu_prot & IOMMU_MMIO)) + pte = __sme_set(pte); + + attrs->descriptor_bits = pte; +-- +2.51.0 + diff --git a/queue-6.19/ionic-rate-limit-unknown-xcvr-type-messages.patch b/queue-6.19/ionic-rate-limit-unknown-xcvr-type-messages.patch new file mode 100644 index 0000000000..10dadb4301 --- /dev/null +++ b/queue-6.19/ionic-rate-limit-unknown-xcvr-type-messages.patch @@ -0,0 +1,51 @@ +From cb2519679d9e3b35f5ae2e5f5a6077626583e033 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 14:46:51 -0800 +Subject: ionic: Rate limit unknown xcvr type messages + +From: Eric Joyner + +[ Upstream commit cdb1634de3bf197c0d86487d1fb84c128a79cc7c ] + +Running ethtool repeatedly with a transceiver unknown to the driver or +firmware will cause the driver to spam the kernel logs with "unknown +xcvr type" messages which can distract from real issues; and this isn't +interesting information outside of debugging. Fix this by rate limiting +the output so that there are still notifications but not so many that +they flood the log. + +Using dev_dbg_once() would reduce the number of messages further, but +this would miss the case where a different unknown transceiver type is +plugged in, and its status is requested. + +Fixes: 4d03e00a2140 ("ionic: Add initial ethtool support") +Signed-off-by: Eric Joyner +Reviewed-by: Brett Creeley +Link: https://patch.msgid.link/20260206224651.1491-1-eric.joyner@amd.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/pensando/ionic/ionic_ethtool.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c +index 2d9efadb5d2ae..347b0aff100b9 100644 +--- a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c ++++ b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c +@@ -263,9 +263,10 @@ static int ionic_get_link_ksettings(struct net_device *netdev, + /* This means there's no module plugged in */ + break; + default: +- dev_info(lif->ionic->dev, "unknown xcvr type pid=%d / 0x%x\n", +- idev->port_info->status.xcvr.pid, +- idev->port_info->status.xcvr.pid); ++ dev_dbg_ratelimited(lif->ionic->dev, ++ "unknown xcvr type pid=%d / 0x%x\n", ++ idev->port_info->status.xcvr.pid, ++ idev->port_info->status.xcvr.pid); + break; + } + +-- +2.51.0 + diff --git a/queue-6.19/ipc-don-t-audit-capability-check-in-ipc_permissions.patch b/queue-6.19/ipc-don-t-audit-capability-check-in-ipc_permissions.patch new file mode 100644 index 0000000000..3da4f0228b --- /dev/null +++ b/queue-6.19/ipc-don-t-audit-capability-check-in-ipc_permissions.patch @@ -0,0 +1,68 @@ +From 1d106dbcf4f90f05a3b1e8c504a4b6c048bb4dd7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 15:13:03 +0100 +Subject: ipc: don't audit capability check in ipc_permissions() + +From: Ondrej Mosnacek + +[ Upstream commit 8924336531e21b187d724b5fdf5277269c9ec22c ] + +The IPC sysctls implement the ctl_table_root::permissions hook and they +override the file access mode based on the CAP_CHECKPOINT_RESTORE +capability, which is being checked regardless of whether any access is +actually denied or not, so if an LSM denies the capability, an audit +record may be logged even when access is in fact granted. + +It wouldn't be viable to restructure the sysctl permission logic to only +check the capability when the access would be actually denied if it's not +granted. Thus, do the same as in net_ctl_permissions() (net/sysctl_net.c) +- switch from ns_capable() to ns_capable_noaudit(), so that the check +never emits an audit record. + +Link: https://lkml.kernel.org/r/20260122141303.241133-1-omosnace@redhat.com +Fixes: 0889f44e2810 ("ipc: Check permissions for checkpoint_restart sysctls at open time") +Signed-off-by: Ondrej Mosnacek +Acked-by: Alexey Gladkov +Acked-by: Serge Hallyn +Cc: Eric Biederman +Cc: Paul Moore +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + include/linux/capability.h | 6 ++++++ + ipc/ipc_sysctl.c | 2 +- + 2 files changed, 7 insertions(+), 1 deletion(-) + +diff --git a/include/linux/capability.h b/include/linux/capability.h +index 1fb08922552c7..37db92b3d6f89 100644 +--- a/include/linux/capability.h ++++ b/include/linux/capability.h +@@ -203,6 +203,12 @@ static inline bool checkpoint_restore_ns_capable(struct user_namespace *ns) + ns_capable(ns, CAP_SYS_ADMIN); + } + ++static inline bool checkpoint_restore_ns_capable_noaudit(struct user_namespace *ns) ++{ ++ return ns_capable_noaudit(ns, CAP_CHECKPOINT_RESTORE) || ++ ns_capable_noaudit(ns, CAP_SYS_ADMIN); ++} ++ + /* audit system wants to get cap info from files as well */ + int get_vfs_caps_from_disk(struct mnt_idmap *idmap, + const struct dentry *dentry, +diff --git a/ipc/ipc_sysctl.c b/ipc/ipc_sysctl.c +index 15b17e86e198c..9b087ebeb643b 100644 +--- a/ipc/ipc_sysctl.c ++++ b/ipc/ipc_sysctl.c +@@ -214,7 +214,7 @@ static int ipc_permissions(struct ctl_table_header *head, const struct ctl_table + if (((table->data == &ns->ids[IPC_SEM_IDS].next_id) || + (table->data == &ns->ids[IPC_MSG_IDS].next_id) || + (table->data == &ns->ids[IPC_SHM_IDS].next_id)) && +- checkpoint_restore_ns_capable(ns->user_ns)) ++ checkpoint_restore_ns_capable_noaudit(ns->user_ns)) + mode = 0666; + else + #endif +-- +2.51.0 + diff --git a/queue-6.19/irqchip-sifive-plic-handle-number-of-hardware-interr.patch b/queue-6.19/irqchip-sifive-plic-handle-number-of-hardware-interr.patch new file mode 100644 index 0000000000..468abe9d76 --- /dev/null +++ b/queue-6.19/irqchip-sifive-plic-handle-number-of-hardware-interr.patch @@ -0,0 +1,231 @@ +From 1157da44dfe8c04b791244e0db8d9d369cf7ddb7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 20:16:12 +0100 +Subject: irqchip/sifive-plic: Handle number of hardware interrupts correctly + +From: Thomas Gleixner + +[ Upstream commit 42e025b719c128bdf8ff88584589a1e4a2448c81 ] + +The driver is handling the number of hardware interrupts inconsistently. + +The reason is that the firmware enumerates the maximum number of device +interrupts, but the actual number of hardware interrupts is one more +because hardware interrupt 0 is reserved. + +There are two loop variants where this matters: + + 1) Iterating over the device interrupts + + for (irq = 1; irq < total_irqs; irq++) + + 2) Iterating over the number of interrupt register groups + + for (grp = 0; grp < irq_groups; grp++) + +The current code stores the number of device interrupts and that requires +to write the loops as: + + 1) for (irq = 1; irq <= device_irqs; irq++) + + 2) for (grp = 0; grp < DIV_ROUND_UP(device_irqs + 1); grp++) + +But the code gets it wrong all over the place. Just fixing up the +conditions and off by ones is not a sustainable solution as the next changes +will reintroduce the same bugs over and over. + +Sanitize it by storing the total number of hardware interrupts during probe +and precalculating the number of groups. To future proof it mark +priv::total_irqs __private, provide a correct iterator macro and adjust the +code to this. + +Marking it private allows sparse (C=1 build) to catch direct access to this +member: + + drivers/irqchip/irq-sifive-plic.c:270:9: warning: dereference of noderef expression + +That should prevent at least the most obvious future damage in that area. + +Fixes: e80f0b6a2cf3 ("irqchip/irq-sifive-plic: Add syscore callbacks for hibernation") +Reported-by: Yangyu Chen +Signed-off-by: Thomas Gleixner +Tested-by: Yangyu Chen +Link: https://patch.msgid.link/87ikcd36i9.ffs@tglx +Signed-off-by: Sasha Levin +--- + drivers/irqchip/irq-sifive-plic.c | 82 +++++++++++++++++-------------- + 1 file changed, 45 insertions(+), 37 deletions(-) + +diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c +index 210a579596377..60fd8f91762b1 100644 +--- a/drivers/irqchip/irq-sifive-plic.c ++++ b/drivers/irqchip/irq-sifive-plic.c +@@ -68,15 +68,17 @@ + #define PLIC_QUIRK_CP100_CLAIM_REGISTER_ERRATUM 1 + + struct plic_priv { +- struct fwnode_handle *fwnode; +- struct cpumask lmask; +- struct irq_domain *irqdomain; +- void __iomem *regs; +- unsigned long plic_quirks; +- unsigned int nr_irqs; +- unsigned long *prio_save; +- u32 gsi_base; +- int acpi_plic_id; ++ struct fwnode_handle *fwnode; ++ struct cpumask lmask; ++ struct irq_domain *irqdomain; ++ void __iomem *regs; ++ unsigned long plic_quirks; ++ /* device interrupts + 1 to compensate for the reserved hwirq 0 */ ++ unsigned int __private total_irqs; ++ unsigned int irq_groups; ++ unsigned long *prio_save; ++ u32 gsi_base; ++ int acpi_plic_id; + }; + + struct plic_handler { +@@ -91,6 +93,12 @@ struct plic_handler { + u32 *enable_save; + struct plic_priv *priv; + }; ++ ++/* ++ * Macro to deal with the insanity of hardware interrupt 0 being reserved */ ++#define for_each_device_irq(iter, priv) \ ++ for (unsigned int iter = 1; iter < ACCESS_PRIVATE(priv, total_irqs); iter++) ++ + static int plic_parent_irq __ro_after_init; + static bool plic_global_setup_done __ro_after_init; + static DEFINE_PER_CPU(struct plic_handler, plic_handlers); +@@ -257,14 +265,11 @@ static int plic_irq_set_type(struct irq_data *d, unsigned int type) + + static int plic_irq_suspend(void *data) + { +- struct plic_priv *priv; +- +- priv = per_cpu_ptr(&plic_handlers, smp_processor_id())->priv; ++ struct plic_priv *priv = this_cpu_ptr(&plic_handlers)->priv; + +- /* irq ID 0 is reserved */ +- for (unsigned int i = 1; i < priv->nr_irqs; i++) { +- __assign_bit(i, priv->prio_save, +- readl(priv->regs + PRIORITY_BASE + i * PRIORITY_PER_ID)); ++ for_each_device_irq(irq, priv) { ++ __assign_bit(irq, priv->prio_save, ++ readl(priv->regs + PRIORITY_BASE + irq * PRIORITY_PER_ID)); + } + + return 0; +@@ -272,18 +277,15 @@ static int plic_irq_suspend(void *data) + + static void plic_irq_resume(void *data) + { +- unsigned int i, index, cpu; ++ struct plic_priv *priv = this_cpu_ptr(&plic_handlers)->priv; ++ unsigned int index, cpu; + unsigned long flags; + u32 __iomem *reg; +- struct plic_priv *priv; +- +- priv = per_cpu_ptr(&plic_handlers, smp_processor_id())->priv; + +- /* irq ID 0 is reserved */ +- for (i = 1; i < priv->nr_irqs; i++) { +- index = BIT_WORD(i); +- writel((priv->prio_save[index] & BIT_MASK(i)) ? 1 : 0, +- priv->regs + PRIORITY_BASE + i * PRIORITY_PER_ID); ++ for_each_device_irq(irq, priv) { ++ index = BIT_WORD(irq); ++ writel((priv->prio_save[index] & BIT_MASK(irq)) ? 1 : 0, ++ priv->regs + PRIORITY_BASE + irq * PRIORITY_PER_ID); + } + + for_each_present_cpu(cpu) { +@@ -293,7 +295,7 @@ static void plic_irq_resume(void *data) + continue; + + raw_spin_lock_irqsave(&handler->enable_lock, flags); +- for (i = 0; i < DIV_ROUND_UP(priv->nr_irqs, 32); i++) { ++ for (unsigned int i = 0; i < priv->irq_groups; i++) { + reg = handler->enable_base + i * sizeof(u32); + writel(handler->enable_save[i], reg); + } +@@ -431,7 +433,7 @@ static u32 cp100_isolate_pending_irq(int nr_irq_groups, struct plic_handler *han + + static irq_hw_number_t cp100_get_hwirq(struct plic_handler *handler, void __iomem *claim) + { +- int nr_irq_groups = DIV_ROUND_UP(handler->priv->nr_irqs, 32); ++ int nr_irq_groups = handler->priv->irq_groups; + u32 __iomem *enable = handler->enable_base; + irq_hw_number_t hwirq = 0; + u32 iso_mask; +@@ -614,7 +616,6 @@ static int plic_probe(struct fwnode_handle *fwnode) + struct plic_handler *handler; + u32 nr_irqs, parent_hwirq; + struct plic_priv *priv; +- irq_hw_number_t hwirq; + void __iomem *regs; + int id, context_id; + u32 gsi_base; +@@ -647,7 +648,16 @@ static int plic_probe(struct fwnode_handle *fwnode) + + priv->fwnode = fwnode; + priv->plic_quirks = plic_quirks; +- priv->nr_irqs = nr_irqs; ++ /* ++ * The firmware provides the number of device interrupts. As ++ * hardware interrupt 0 is reserved, the number of total interrupts ++ * is nr_irqs + 1. ++ */ ++ nr_irqs++; ++ ACCESS_PRIVATE(priv, total_irqs) = nr_irqs; ++ /* Precalculate the number of register groups */ ++ priv->irq_groups = DIV_ROUND_UP(nr_irqs, 32); ++ + priv->regs = regs; + priv->gsi_base = gsi_base; + priv->acpi_plic_id = id; +@@ -686,7 +696,7 @@ static int plic_probe(struct fwnode_handle *fwnode) + u32 __iomem *enable_base = priv->regs + CONTEXT_ENABLE_BASE + + i * CONTEXT_ENABLE_SIZE; + +- for (int j = 0; j <= nr_irqs / 32; j++) ++ for (int j = 0; j < priv->irq_groups; j++) + writel(0, enable_base + j); + } + continue; +@@ -718,23 +728,21 @@ static int plic_probe(struct fwnode_handle *fwnode) + context_id * CONTEXT_ENABLE_SIZE; + handler->priv = priv; + +- handler->enable_save = kcalloc(DIV_ROUND_UP(nr_irqs, 32), +- sizeof(*handler->enable_save), GFP_KERNEL); ++ handler->enable_save = kcalloc(priv->irq_groups, sizeof(*handler->enable_save), ++ GFP_KERNEL); + if (!handler->enable_save) { + error = -ENOMEM; + goto fail_cleanup_contexts; + } + done: +- for (hwirq = 1; hwirq <= nr_irqs; hwirq++) { ++ for_each_device_irq(hwirq, priv) { + plic_toggle(handler, hwirq, 0); +- writel(1, priv->regs + PRIORITY_BASE + +- hwirq * PRIORITY_PER_ID); ++ writel(1, priv->regs + PRIORITY_BASE + hwirq * PRIORITY_PER_ID); + } + nr_handlers++; + } + +- priv->irqdomain = irq_domain_create_linear(fwnode, nr_irqs + 1, +- &plic_irqdomain_ops, priv); ++ priv->irqdomain = irq_domain_create_linear(fwnode, nr_irqs, &plic_irqdomain_ops, priv); + if (WARN_ON(!priv->irqdomain)) { + error = -ENOMEM; + goto fail_cleanup_contexts; +-- +2.51.0 + diff --git a/queue-6.19/jfs-avoid-wtautological-constant-out-of-range-compar.patch b/queue-6.19/jfs-avoid-wtautological-constant-out-of-range-compar.patch new file mode 100644 index 0000000000..a70f74e5b1 --- /dev/null +++ b/queue-6.19/jfs-avoid-wtautological-constant-out-of-range-compar.patch @@ -0,0 +1,56 @@ +From 572368f68ba0600f7f86eae9958fbd011262dabe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 21:43:45 +0100 +Subject: jfs: avoid -Wtautological-constant-out-of-range-compare warning + +From: Arnd Bergmann + +[ Upstream commit 7833570dae833028337bb53b7f389825b910c100 ] + +A recent change for the range check started triggering a clang warning: + +fs/jfs/jfs_dtree.c:2906:31: error: result of comparison of constant 128 with expression of type 's8' (aka 'signed char') is always false [-Werror,-Wtautological-constant-out-of-range-compare] + 2906 | if (stbl[i] < 0 || stbl[i] >= DTPAGEMAXSLOT) { + | ~~~~~~~ ^ ~~~~~~~~~~~~~ +fs/jfs/jfs_dtree.c:3111:30: error: result of comparison of constant 128 with expression of type 's8' (aka 'signed char') is always false [-Werror,-Wtautological-constant-out-of-range-compare] + 3111 | if (stbl[0] < 0 || stbl[0] >= DTPAGEMAXSLOT) { + | ~~~~~~~ ^ ~~~~~~~~~~~~~ + +Both the old and the new check were useless, but the previous version +apparently did not lead to the warning. + +Remove the extraneous range check for simplicity. + +Fixes: cafc6679824a ("jfs: replace hardcoded magic number with DTPAGEMAXSLOT constant") +Signed-off-by: Arnd Bergmann +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_dtree.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c +index 0ab83bb7bbdf9..9ab3f2fc61d17 100644 +--- a/fs/jfs/jfs_dtree.c ++++ b/fs/jfs/jfs_dtree.c +@@ -2903,7 +2903,7 @@ int jfs_readdir(struct file *file, struct dir_context *ctx) + stbl = DT_GETSTBL(p); + + for (i = index; i < p->header.nextindex; i++) { +- if (stbl[i] < 0 || stbl[i] >= DTPAGEMAXSLOT) { ++ if (stbl[i] < 0) { + jfs_err("JFS: Invalid stbl[%d] = %d for inode %ld, block = %lld", + i, stbl[i], (long)ip->i_ino, (long long)bn); + free_page(dirent_buf); +@@ -3108,7 +3108,7 @@ static int dtReadFirst(struct inode *ip, struct btstack * btstack) + /* get the leftmost entry */ + stbl = DT_GETSTBL(p); + +- if (stbl[0] < 0 || stbl[0] >= DTPAGEMAXSLOT) { ++ if (stbl[0] < 0) { + DT_PUTPAGE(mp); + jfs_error(ip->i_sb, "stbl[0] out of bound\n"); + return -EIO; +-- +2.51.0 + diff --git a/queue-6.19/kallsyms-bpf-rename-__bpf_address_lookup-to-bpf_addr.patch b/queue-6.19/kallsyms-bpf-rename-__bpf_address_lookup-to-bpf_addr.patch new file mode 100644 index 0000000000..9d0bbfd1bd --- /dev/null +++ b/queue-6.19/kallsyms-bpf-rename-__bpf_address_lookup-to-bpf_addr.patch @@ -0,0 +1,186 @@ +From 3f13b1d11530260f3fc441271f3f3e85be8534b4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 14:59:18 +0100 +Subject: kallsyms/bpf: rename __bpf_address_lookup() to bpf_address_lookup() + +From: Petr Mladek + +[ Upstream commit cd6735896d0343942cf3dafb48ce32eb79341990 ] + +bpf_address_lookup() has been used only in kallsyms_lookup_buildid(). It +was supposed to set @modname and @modbuildid when the symbol was in a +module. + +But it always just cleared @modname because BPF symbols were never in a +module. And it did not clear @modbuildid because the pointer was not +passed. + +The wrapper is no longer needed. Both @modname and @modbuildid are now +always initialized to NULL in kallsyms_lookup_buildid(). + +Remove the wrapper and rename __bpf_address_lookup() to +bpf_address_lookup() because this variant is used everywhere. + +[akpm@linux-foundation.org: fix loongarch] +Link: https://lkml.kernel.org/r/20251128135920.217303-6-pmladek@suse.com +Fixes: 9294523e3768 ("module: add printk formats to add module build ID to stacktraces") +Signed-off-by: Petr Mladek +Acked-by: Alexei Starovoitov +Cc: Aaron Tomlin +Cc: Daniel Borkman +Cc: Daniel Gomez +Cc: John Fastabend +Cc: Kees Cook +Cc: Luis Chamberalin +Cc: Marc Rutland +Cc: "Masami Hiramatsu (Google)" +Cc: Petr Pavlu +Cc: Sami Tolvanen +Cc: Steven Rostedt (Google) +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + arch/arm64/net/bpf_jit_comp.c | 2 +- + arch/loongarch/net/bpf_jit.c | 2 +- + arch/powerpc/net/bpf_jit_comp.c | 2 +- + include/linux/filter.h | 26 ++++---------------------- + kernel/bpf/core.c | 4 ++-- + kernel/kallsyms.c | 5 ++--- + 6 files changed, 11 insertions(+), 30 deletions(-) + +diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c +index b6eb7a465ad24..1d657bd3ce655 100644 +--- a/arch/arm64/net/bpf_jit_comp.c ++++ b/arch/arm64/net/bpf_jit_comp.c +@@ -2951,7 +2951,7 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type old_t, + u64 plt_target = 0ULL; + bool poking_bpf_entry; + +- if (!__bpf_address_lookup((unsigned long)ip, &size, &offset, namebuf)) ++ if (!bpf_address_lookup((unsigned long)ip, &size, &offset, namebuf)) + /* Only poking bpf text is supported. Since kernel function + * entry is set up by ftrace, we reply on ftrace to poke kernel + * functions. +diff --git a/arch/loongarch/net/bpf_jit.c b/arch/loongarch/net/bpf_jit.c +index d1d5a65308b9e..3b63bc5b99d9a 100644 +--- a/arch/loongarch/net/bpf_jit.c ++++ b/arch/loongarch/net/bpf_jit.c +@@ -1319,7 +1319,7 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type old_t, + /* Only poking bpf text is supported. Since kernel function entry + * is set up by ftrace, we rely on ftrace to poke kernel functions. + */ +- if (!__bpf_address_lookup((unsigned long)ip, &size, &offset, namebuf)) ++ if (!bpf_address_lookup((unsigned long)ip, &size, &offset, namebuf)) + return -ENOTSUPP; + + image = ip - offset; +diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c +index 5e976730b2f5f..e199976e410a1 100644 +--- a/arch/powerpc/net/bpf_jit_comp.c ++++ b/arch/powerpc/net/bpf_jit_comp.c +@@ -1122,7 +1122,7 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type old_t, + bpf_func = (unsigned long)ip; + + /* We currently only support poking bpf programs */ +- if (!__bpf_address_lookup(bpf_func, &size, &offset, name)) { ++ if (!bpf_address_lookup(bpf_func, &size, &offset, name)) { + pr_err("%s (0x%lx): kernel/modules are not supported\n", __func__, bpf_func); + return -EOPNOTSUPP; + } +diff --git a/include/linux/filter.h b/include/linux/filter.h +index fd54fed8f95f3..7452817d707d1 100644 +--- a/include/linux/filter.h ++++ b/include/linux/filter.h +@@ -1375,24 +1375,13 @@ static inline bool bpf_jit_kallsyms_enabled(void) + return false; + } + +-int __bpf_address_lookup(unsigned long addr, unsigned long *size, +- unsigned long *off, char *sym); ++int bpf_address_lookup(unsigned long addr, unsigned long *size, ++ unsigned long *off, char *sym); + bool is_bpf_text_address(unsigned long addr); + int bpf_get_kallsym(unsigned int symnum, unsigned long *value, char *type, + char *sym); + struct bpf_prog *bpf_prog_ksym_find(unsigned long addr); + +-static inline int +-bpf_address_lookup(unsigned long addr, unsigned long *size, +- unsigned long *off, char **modname, char *sym) +-{ +- int ret = __bpf_address_lookup(addr, size, off, sym); +- +- if (ret && modname) +- *modname = NULL; +- return ret; +-} +- + void bpf_prog_kallsyms_add(struct bpf_prog *fp); + void bpf_prog_kallsyms_del(struct bpf_prog *fp); + +@@ -1431,8 +1420,8 @@ static inline bool bpf_jit_kallsyms_enabled(void) + } + + static inline int +-__bpf_address_lookup(unsigned long addr, unsigned long *size, +- unsigned long *off, char *sym) ++bpf_address_lookup(unsigned long addr, unsigned long *size, ++ unsigned long *off, char *sym) + { + return 0; + } +@@ -1453,13 +1442,6 @@ static inline struct bpf_prog *bpf_prog_ksym_find(unsigned long addr) + return NULL; + } + +-static inline int +-bpf_address_lookup(unsigned long addr, unsigned long *size, +- unsigned long *off, char **modname, char *sym) +-{ +- return 0; +-} +- + static inline void bpf_prog_kallsyms_add(struct bpf_prog *fp) + { + } +diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c +index 1b9b18e5b03cb..85c0feaae0d3c 100644 +--- a/kernel/bpf/core.c ++++ b/kernel/bpf/core.c +@@ -713,8 +713,8 @@ static struct bpf_ksym *bpf_ksym_find(unsigned long addr) + return n ? container_of(n, struct bpf_ksym, tnode) : NULL; + } + +-int __bpf_address_lookup(unsigned long addr, unsigned long *size, +- unsigned long *off, char *sym) ++int bpf_address_lookup(unsigned long addr, unsigned long *size, ++ unsigned long *off, char *sym) + { + struct bpf_ksym *ksym; + int ret = 0; +diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c +index 049e296f586cc..7417dd5f8a796 100644 +--- a/kernel/kallsyms.c ++++ b/kernel/kallsyms.c +@@ -345,7 +345,7 @@ int kallsyms_lookup_size_offset(unsigned long addr, unsigned long *symbolsize, + return 1; + } + return !!module_address_lookup(addr, symbolsize, offset, NULL, NULL, namebuf) || +- !!__bpf_address_lookup(addr, symbolsize, offset, namebuf); ++ !!bpf_address_lookup(addr, symbolsize, offset, namebuf); + } + + static int kallsyms_lookup_buildid(unsigned long addr, +@@ -377,8 +377,7 @@ static int kallsyms_lookup_buildid(unsigned long addr, + ret = module_address_lookup(addr, symbolsize, offset, + modname, modbuildid, namebuf); + if (!ret) +- ret = bpf_address_lookup(addr, symbolsize, +- offset, modname, namebuf); ++ ret = bpf_address_lookup(addr, symbolsize, offset, namebuf); + + if (!ret) + ret = ftrace_mod_address_lookup(addr, symbolsize, +-- +2.51.0 + diff --git a/queue-6.19/kallsyms-ftrace-set-module-buildid-in-ftrace_mod_add.patch b/queue-6.19/kallsyms-ftrace-set-module-buildid-in-ftrace_mod_add.patch new file mode 100644 index 0000000000..5843ae581b --- /dev/null +++ b/queue-6.19/kallsyms-ftrace-set-module-buildid-in-ftrace_mod_add.patch @@ -0,0 +1,100 @@ +From b61784a0617c138ff471f175009244d21a6f094e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 14:59:19 +0100 +Subject: kallsyms/ftrace: set module buildid in ftrace_mod_address_lookup() + +From: Petr Mladek + +[ Upstream commit e8a1e7eaa19d0b757b06a2f913e3eeb4b1c002c6 ] + +__sprint_symbol() might access an invalid pointer when +kallsyms_lookup_buildid() returns a symbol found by +ftrace_mod_address_lookup(). + +The ftrace lookup function must set both @modname and @modbuildid the same +way as module_address_lookup(). + +Link: https://lkml.kernel.org/r/20251128135920.217303-7-pmladek@suse.com +Fixes: 9294523e3768 ("module: add printk formats to add module build ID to stacktraces") +Signed-off-by: Petr Mladek +Reviewed-by: Aaron Tomlin +Acked-by: Steven Rostedt (Google) +Cc: Alexei Starovoitov +Cc: Daniel Borkman +Cc: Daniel Gomez +Cc: John Fastabend +Cc: Kees Cook +Cc: Luis Chamberalin +Cc: Marc Rutland +Cc: "Masami Hiramatsu (Google)" +Cc: Petr Pavlu +Cc: Sami Tolvanen +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + include/linux/ftrace.h | 6 ++++-- + kernel/kallsyms.c | 4 ++-- + kernel/trace/ftrace.c | 5 ++++- + 3 files changed, 10 insertions(+), 5 deletions(-) + +diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h +index cc869c59c1a68..fa74ae5cc9dae 100644 +--- a/include/linux/ftrace.h ++++ b/include/linux/ftrace.h +@@ -87,11 +87,13 @@ struct ftrace_hash; + defined(CONFIG_DYNAMIC_FTRACE) + int + ftrace_mod_address_lookup(unsigned long addr, unsigned long *size, +- unsigned long *off, char **modname, char *sym); ++ unsigned long *off, char **modname, ++ const unsigned char **modbuildid, char *sym); + #else + static inline int + ftrace_mod_address_lookup(unsigned long addr, unsigned long *size, +- unsigned long *off, char **modname, char *sym) ++ unsigned long *off, char **modname, ++ const unsigned char **modbuildid, char *sym) + { + return 0; + } +diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c +index 7417dd5f8a796..cdd6e025935d3 100644 +--- a/kernel/kallsyms.c ++++ b/kernel/kallsyms.c +@@ -380,8 +380,8 @@ static int kallsyms_lookup_buildid(unsigned long addr, + ret = bpf_address_lookup(addr, symbolsize, offset, namebuf); + + if (!ret) +- ret = ftrace_mod_address_lookup(addr, symbolsize, +- offset, modname, namebuf); ++ ret = ftrace_mod_address_lookup(addr, symbolsize, offset, ++ modname, modbuildid, namebuf); + + return ret; + } +diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c +index 93f617e1f191d..e835d878038b2 100644 +--- a/kernel/trace/ftrace.c ++++ b/kernel/trace/ftrace.c +@@ -7739,7 +7739,8 @@ ftrace_func_address_lookup(struct ftrace_mod_map *mod_map, + + int + ftrace_mod_address_lookup(unsigned long addr, unsigned long *size, +- unsigned long *off, char **modname, char *sym) ++ unsigned long *off, char **modname, ++ const unsigned char **modbuildid, char *sym) + { + struct ftrace_mod_map *mod_map; + int ret = 0; +@@ -7751,6 +7752,8 @@ ftrace_mod_address_lookup(unsigned long addr, unsigned long *size, + if (ret) { + if (modname) + *modname = mod_map->mod->name; ++ if (modbuildid) ++ *modbuildid = module_buildid(mod_map->mod); + break; + } + } +-- +2.51.0 + diff --git a/queue-6.19/leds-expresswire-fix-chip-state-breakage.patch b/queue-6.19/leds-expresswire-fix-chip-state-breakage.patch new file mode 100644 index 0000000000..747dd7605a --- /dev/null +++ b/queue-6.19/leds-expresswire-fix-chip-state-breakage.patch @@ -0,0 +1,129 @@ +From cbf45a3b2383f6eac9e8efdf60f1fc0bb9444d3c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 17 Dec 2025 19:14:23 +0100 +Subject: leds: expresswire: Fix chip state breakage +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Duje Mihanović + +[ Upstream commit f4b830a5371914239756b0599e5dc9d4c328e387 ] + +It is possible to put the KTD2801 chip in an unknown/undefined state by +changing the brightness very rapidly (for example, with a brightness +slider). When this happens, the brightness is stuck on max and cannot be +changed until the chip is power cycled. + +Fix this by disabling interrupts while talking to the chip. While at it, +make expresswire_power_off() use fsleep() and also unexport some +functions meant to be internal. + +Fixes: 1368d06dd2c9 ("leds: Introduce ExpressWire library") +Tested-by: Karel Balej +Signed-off-by: Duje Mihanović +Link: https://patch.msgid.link/20251217-expresswire-fix-v2-1-4a02b10acd96@dujemihanovic.xyz +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/leds/leds-expresswire.c | 24 +++++++++++++++++------- + include/linux/leds-expresswire.h | 3 --- + 2 files changed, 17 insertions(+), 10 deletions(-) + +diff --git a/drivers/leds/leds-expresswire.c b/drivers/leds/leds-expresswire.c +index bb69be228a6d3..25c6b159a6ee9 100644 +--- a/drivers/leds/leds-expresswire.c ++++ b/drivers/leds/leds-expresswire.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -16,37 +17,41 @@ + void expresswire_power_off(struct expresswire_common_props *props) + { + gpiod_set_value_cansleep(props->ctrl_gpio, 0); +- usleep_range(props->timing.poweroff_us, props->timing.poweroff_us * 2); ++ fsleep(props->timing.poweroff_us); + } + EXPORT_SYMBOL_NS_GPL(expresswire_power_off, "EXPRESSWIRE"); + + void expresswire_enable(struct expresswire_common_props *props) + { ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ + gpiod_set_value(props->ctrl_gpio, 1); + udelay(props->timing.detect_delay_us); + gpiod_set_value(props->ctrl_gpio, 0); + udelay(props->timing.detect_us); + gpiod_set_value(props->ctrl_gpio, 1); ++ ++ local_irq_restore(flags); + } + EXPORT_SYMBOL_NS_GPL(expresswire_enable, "EXPRESSWIRE"); + +-void expresswire_start(struct expresswire_common_props *props) ++static void expresswire_start(struct expresswire_common_props *props) + { + gpiod_set_value(props->ctrl_gpio, 1); + udelay(props->timing.data_start_us); + } +-EXPORT_SYMBOL_NS_GPL(expresswire_start, "EXPRESSWIRE"); + +-void expresswire_end(struct expresswire_common_props *props) ++static void expresswire_end(struct expresswire_common_props *props) + { + gpiod_set_value(props->ctrl_gpio, 0); + udelay(props->timing.end_of_data_low_us); + gpiod_set_value(props->ctrl_gpio, 1); + udelay(props->timing.end_of_data_high_us); + } +-EXPORT_SYMBOL_NS_GPL(expresswire_end, "EXPRESSWIRE"); + +-void expresswire_set_bit(struct expresswire_common_props *props, bool bit) ++static void expresswire_set_bit(struct expresswire_common_props *props, bool bit) + { + if (bit) { + gpiod_set_value(props->ctrl_gpio, 0); +@@ -60,13 +65,18 @@ void expresswire_set_bit(struct expresswire_common_props *props, bool bit) + udelay(props->timing.short_bitset_us); + } + } +-EXPORT_SYMBOL_NS_GPL(expresswire_set_bit, "EXPRESSWIRE"); + + void expresswire_write_u8(struct expresswire_common_props *props, u8 val) + { ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ + expresswire_start(props); + for (int i = 7; i >= 0; i--) + expresswire_set_bit(props, val & BIT(i)); + expresswire_end(props); ++ ++ local_irq_restore(flags); + } + EXPORT_SYMBOL_NS_GPL(expresswire_write_u8, "EXPRESSWIRE"); +diff --git a/include/linux/leds-expresswire.h b/include/linux/leds-expresswire.h +index a422921f4159f..7f8c4795f69fa 100644 +--- a/include/linux/leds-expresswire.h ++++ b/include/linux/leds-expresswire.h +@@ -30,9 +30,6 @@ struct expresswire_common_props { + + void expresswire_power_off(struct expresswire_common_props *props); + void expresswire_enable(struct expresswire_common_props *props); +-void expresswire_start(struct expresswire_common_props *props); +-void expresswire_end(struct expresswire_common_props *props); +-void expresswire_set_bit(struct expresswire_common_props *props, bool bit); + void expresswire_write_u8(struct expresswire_common_props *props, u8 val); + + #endif /* _LEDS_EXPRESSWIRE_H */ +-- +2.51.0 + diff --git a/queue-6.19/leds-qcom-lpg-check-the-return-value-of-regmap_bulk_.patch b/queue-6.19/leds-qcom-lpg-check-the-return-value-of-regmap_bulk_.patch new file mode 100644 index 0000000000..5537931cc0 --- /dev/null +++ b/queue-6.19/leds-qcom-lpg-check-the-return-value-of-regmap_bulk_.patch @@ -0,0 +1,55 @@ +From 41e47a8c8d282fcc928e7c2097be1f9bd7fb2349 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 01:51:33 +0800 +Subject: leds: qcom-lpg: Check the return value of regmap_bulk_write() + +From: Haotian Zhang + +[ Upstream commit f42033b5ce8c79c5db645916c9a72ee3e10cecfa ] + +The lpg_lut_store() function currently ignores the return value of +regmap_bulk_write() and always returns 0. This can cause hardware write +failures to go undetected, leading the caller to believe LUT programming +succeeded when it may have failed. + +Check the return value of regmap_bulk_write() in lpg_lut_store and return +the error to the caller on failure. + +Fixes: 24e2d05d1b68 ("leds: Add driver for Qualcomm LPG") +Signed-off-by: Haotian Zhang +Link: https://patch.msgid.link/20260108175133.638-1-vulab@iscas.ac.cn +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/leds/rgb/leds-qcom-lpg.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/leds/rgb/leds-qcom-lpg.c b/drivers/leds/rgb/leds-qcom-lpg.c +index 72da0bf469ad8..f54851dfb42fc 100644 +--- a/drivers/leds/rgb/leds-qcom-lpg.c ++++ b/drivers/leds/rgb/leds-qcom-lpg.c +@@ -369,7 +369,7 @@ static int lpg_lut_store(struct lpg *lpg, struct led_pattern *pattern, + { + unsigned int idx; + u16 val; +- int i; ++ int i, ret; + + idx = bitmap_find_next_zero_area(lpg->lut_bitmap, lpg->lut_size, + 0, len, 0); +@@ -379,8 +379,10 @@ static int lpg_lut_store(struct lpg *lpg, struct led_pattern *pattern, + for (i = 0; i < len; i++) { + val = pattern[i].brightness; + +- regmap_bulk_write(lpg->map, lpg->lut_base + LPG_LUT_REG(idx + i), +- &val, sizeof(val)); ++ ret = regmap_bulk_write(lpg->map, lpg->lut_base + LPG_LUT_REG(idx + i), ++ &val, sizeof(val)); ++ if (ret) ++ return ret; + } + + bitmap_set(lpg->lut_bitmap, idx, len); +-- +2.51.0 + diff --git a/queue-6.19/lib-kconfig.debug-fix-bootparam_hung_task_panic-comm.patch b/queue-6.19/lib-kconfig.debug-fix-bootparam_hung_task_panic-comm.patch new file mode 100644 index 0000000000..678d52ff3d --- /dev/null +++ b/queue-6.19/lib-kconfig.debug-fix-bootparam_hung_task_panic-comm.patch @@ -0,0 +1,51 @@ +From 768e8d716f0b30e46c8c6787e70fb133ab8b19d3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Jan 2026 15:01:40 +0100 +Subject: lib/Kconfig.debug: fix BOOTPARAM_HUNG_TASK_PANIC comment + +From: Tomas Glozar + +[ Upstream commit dbac35bee8fc844c2d8d6417af874a170a44d41f ] + +The comment for CONFIG_BOOTPARAM_HUNG_TASK_PANIC says: + + Say N if unsure. + +but since commit 9544f9e6947f ("hung_task: panic when there are more than +N hung tasks at the same time"), N is not a valid value for the option, +leading to a warning at build time: + + .config:11736:warning: symbol value 'n' invalid for BOOTPARAM_HUNG_TASK_PANIC + +as well as an error when given to menuconfig. + +Fix the comment to say '0' instead of 'N'. + +Link: https://lkml.kernel.org/r/20260106140140.136446-1-tglozar@redhat.com +Fixes: 9544f9e6947f ("hung_task: panic when there are more than N hung tasks at the same time") +Signed-off-by: Tomas Glozar +Reported-by: Johnny Mnemonic +Reviewed-by: Lance Yang +Cc: Li RongQing +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + lib/Kconfig.debug | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug +index ba36939fda79b..cda3cf1fa302c 100644 +--- a/lib/Kconfig.debug ++++ b/lib/Kconfig.debug +@@ -1273,7 +1273,7 @@ config BOOTPARAM_HUNG_TASK_PANIC + high-availability systems that have uptime guarantees and + where a hung tasks must be resolved ASAP. + +- Say N if unsure. ++ Say 0 if unsure. + + config DETECT_HUNG_TASK_BLOCKER + bool "Dump Hung Tasks Blocker" +-- +2.51.0 + diff --git a/queue-6.19/lib-kstrtox-fix-kstrtobool-docstring-to-mention-enab.patch b/queue-6.19/lib-kstrtox-fix-kstrtobool-docstring-to-mention-enab.patch new file mode 100644 index 0000000000..d0831ccd11 --- /dev/null +++ b/queue-6.19/lib-kstrtox-fix-kstrtobool-docstring-to-mention-enab.patch @@ -0,0 +1,44 @@ +From 849db7a41af8e88e3d125d1f2d2612b321be5a94 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 27 Dec 2025 14:52:29 +0530 +Subject: lib/kstrtox: fix kstrtobool() docstring to mention enabled/disabled + +From: Chaitanya Mishra + +[ Upstream commit 1921044eebf1d6861a6de1a76e3f63729a45e712 ] + +Commit ae5b3500856f ("kstrtox: add support for enabled and disabled in +kstrtobool()") added support for 'e'/'E' (enabled) and 'd'/'D' (disabled) +inputs, but did not update the docstring accordingly. + +Update the docstring to include 'Ee' (for true) and 'Dd' (for false) in +the list of accepted first characters. + +Link: https://lkml.kernel.org/r/20251227092229.57330-1-chaitanyamishra.ai@gmail.com +Fixes: ae5b3500856f ("kstrtox: add support for enabled and disabled in kstrtobool()") +Signed-off-by: Chaitanya Mishra +Cc: Mario Limonciello +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + lib/kstrtox.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/lib/kstrtox.c b/lib/kstrtox.c +index bdde40cd69d78..97be2a39f5371 100644 +--- a/lib/kstrtox.c ++++ b/lib/kstrtox.c +@@ -340,8 +340,8 @@ EXPORT_SYMBOL(kstrtos8); + * @s: input string + * @res: result + * +- * This routine returns 0 iff the first character is one of 'YyTt1NnFf0', or +- * [oO][NnFf] for "on" and "off". Otherwise it will return -EINVAL. Value ++ * This routine returns 0 iff the first character is one of 'EeYyTt1DdNnFf0', ++ * or [oO][NnFf] for "on" and "off". Otherwise it will return -EINVAL. Value + * pointed to by res is updated upon finding a match. + */ + noinline +-- +2.51.0 + diff --git a/queue-6.19/libbpf-fix-oob-read-in-btf_dump_get_bitfield_value.patch b/queue-6.19/libbpf-fix-oob-read-in-btf_dump_get_bitfield_value.patch new file mode 100644 index 0000000000..574c7e914b --- /dev/null +++ b/queue-6.19/libbpf-fix-oob-read-in-btf_dump_get_bitfield_value.patch @@ -0,0 +1,59 @@ +From 88977634f48922230018ab7f5c9e7b7e41c8a234 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 05:05:27 +0530 +Subject: libbpf: Fix OOB read in btf_dump_get_bitfield_value + +From: Varun R Mallya + +[ Upstream commit 5714ca8cba5ed736f3733663c446cbee63a10a64 ] + +When dumping bitfield data, btf_dump_get_bitfield_value() reads data +based on the underlying type's size (t->size). However, it does not +verify that the provided data buffer (data_sz) is large enough to +contain these bytes. + +If btf_dump__dump_type_data() is called with a buffer smaller than +the type's size, this leads to an out-of-bounds read. This was +confirmed by AddressSanitizer in the linked issue. + +Fix this by ensuring we do not read past the provided data_sz limit. + +Fixes: a1d3cc3c5eca ("libbpf: Avoid use of __int128 in typed dump display") +Reported-by: Harrison Green +Suggested-by: Alan Maguire +Signed-off-by: Varun R Mallya +Signed-off-by: Andrii Nakryiko +Link: https://lore.kernel.org/bpf/20260106233527.163487-1-varunrmallya@gmail.com + +Closes: https://github.com/libbpf/libbpf/issues/928 +Signed-off-by: Sasha Levin +--- + tools/lib/bpf/btf_dump.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/tools/lib/bpf/btf_dump.c b/tools/lib/bpf/btf_dump.c +index 6388392f49a0b..53c6624161d79 100644 +--- a/tools/lib/bpf/btf_dump.c ++++ b/tools/lib/bpf/btf_dump.c +@@ -1762,9 +1762,18 @@ static int btf_dump_get_bitfield_value(struct btf_dump *d, + __u16 left_shift_bits, right_shift_bits; + const __u8 *bytes = data; + __u8 nr_copy_bits; ++ __u8 start_bit, nr_bytes; + __u64 num = 0; + int i; + ++ /* Calculate how many bytes cover the bitfield */ ++ start_bit = bits_offset % 8; ++ nr_bytes = (start_bit + bit_sz + 7) / 8; ++ ++ /* Bound check */ ++ if (data + nr_bytes > d->typed_dump->data_end) ++ return -E2BIG; ++ + /* Maximum supported bitfield size is 64 bits */ + if (t->size > 8) { + pr_warn("unexpected bitfield size %d\n", t->size); +-- +2.51.0 + diff --git a/queue-6.19/mcb-fix-incorrect-sanity-check.patch b/queue-6.19/mcb-fix-incorrect-sanity-check.patch new file mode 100644 index 0000000000..b5c4c541df --- /dev/null +++ b/queue-6.19/mcb-fix-incorrect-sanity-check.patch @@ -0,0 +1,62 @@ +From ef73c15e42d25a92b54b04e3846bb31fb538e6a8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 12:21:41 +0100 +Subject: mcb: fix incorrect sanity check + +From: Jose Javier Rodriguez Barbarin + +[ Upstream commit bc2e4bc952e26dd93b978588219044bd8b24237b ] + +__mcb_register_driver() makes some sanity checks over mcb_driver +to check if .probe and .remove callbacks are set. However, since commit +3bd13ae04ccc ("gpio: menz127: simplify error path and remove remove()") +removed the .remove callback from menz127-gpio.c, not all mcb device +drivers implement .remove callback. + +Remove .remove check to ensure all mcb device drivers can be loaded. + +Signed-off-by: Jose Javier Rodriguez Barbarin +Fixes: 3bd13ae04ccc ("gpio: menz127: simplify error path and remove remove()") +[ jth: added statement about menz127-gpio.c ] +Signed-off-by: Johannes Thumshirn +Link: https://patch.msgid.link/16fb55bd59d9c1d2ce2443f41d4dec2048f9a8ec.1768562302.git.jth@kernel.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/mcb/mcb-core.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/drivers/mcb/mcb-core.c b/drivers/mcb/mcb-core.c +index c1367223e71a0..3d487d75c483d 100644 +--- a/drivers/mcb/mcb-core.c ++++ b/drivers/mcb/mcb-core.c +@@ -85,7 +85,8 @@ static void mcb_remove(struct device *dev) + struct mcb_device *mdev = to_mcb_device(dev); + struct module *carrier_mod; + +- mdrv->remove(mdev); ++ if (mdrv->remove) ++ mdrv->remove(mdev); + + carrier_mod = mdev->dev.parent->driver->owner; + module_put(carrier_mod); +@@ -176,13 +177,13 @@ static const struct device_type mcb_carrier_device_type = { + * @owner: The @mcb_driver's module + * @mod_name: The name of the @mcb_driver's module + * +- * Register a @mcb_driver at the system. Perform some sanity checks, if +- * the .probe and .remove methods are provided by the driver. ++ * Register a @mcb_driver at the system. Perform a sanity check, if ++ * .probe method is provided by the driver. + */ + int __mcb_register_driver(struct mcb_driver *drv, struct module *owner, + const char *mod_name) + { +- if (!drv->probe || !drv->remove) ++ if (!drv->probe) + return -EINVAL; + + drv->driver.owner = owner; +-- +2.51.0 + diff --git a/queue-6.19/mctp-i2c-initialise-event-handler-read-bytes.patch b/queue-6.19/mctp-i2c-initialise-event-handler-read-bytes.patch new file mode 100644 index 0000000000..73d5b7ad50 --- /dev/null +++ b/queue-6.19/mctp-i2c-initialise-event-handler-read-bytes.patch @@ -0,0 +1,43 @@ +From 316ab82fdc75a05811f26fc64c436aa69f863fa2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Jan 2026 17:01:16 +0800 +Subject: mctp i2c: initialise event handler read bytes + +From: Matt Johnston + +[ Upstream commit 2a14e91b6d76639dac70ea170f4384c1ee3cb48d ] + +Set a 0xff value for i2c reads of an mctp-i2c device. Otherwise reads +will return "val" from the i2c bus driver. For i2c-aspeed and +i2c-npcm7xx that is a stack uninitialised u8. + +Tested with "i2ctransfer -y 1 r10@0x34" where 0x34 is a mctp-i2c +instance, now it returns all 0xff. + +Fixes: f5b8abf9fc3d ("mctp i2c: MCTP I2C binding driver") +Signed-off-by: Matt Johnston +Link: https://patch.msgid.link/20260113-mctp-read-fix-v1-1-70c4b59c741c@codeconstruct.com.au +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/mctp/mctp-i2c.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/mctp/mctp-i2c.c b/drivers/net/mctp/mctp-i2c.c +index ecda1cc36391c..8043b57bdf250 100644 +--- a/drivers/net/mctp/mctp-i2c.c ++++ b/drivers/net/mctp/mctp-i2c.c +@@ -243,7 +243,10 @@ static int mctp_i2c_slave_cb(struct i2c_client *client, + + switch (event) { + case I2C_SLAVE_READ_REQUESTED: ++ case I2C_SLAVE_READ_PROCESSED: ++ /* MCTP I2C transport only uses writes */ + midev->rx_pos = 0; ++ *val = 0xff; + break; + case I2C_SLAVE_WRITE_RECEIVED: + if (midev->rx_pos < MCTP_I2C_BUFSZ) { +-- +2.51.0 + diff --git a/queue-6.19/md-fix-return-value-of-mddev_trylock.patch b/queue-6.19/md-fix-return-value-of-mddev_trylock.patch new file mode 100644 index 0000000000..3c79579c36 --- /dev/null +++ b/queue-6.19/md-fix-return-value-of-mddev_trylock.patch @@ -0,0 +1,43 @@ +From a2fb2beb6396349f9bdf593c6410fae34c9fbc9d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 15:39:27 +0800 +Subject: md: fix return value of mddev_trylock + +From: Xiao Ni + +[ Upstream commit 05c8de4f09b08e97c6ecb190dcec0e68b167cb03 ] + +A return value of 0 is treaded as successful lock acquisition. In fact, a +return value of 1 means getting the lock successfully. + +Link: https://lore.kernel.org/linux-raid/20260127073951.17248-1-xni@redhat.com +Fixes: 9e59d609763f ("md: call del_gendisk in control path") +Reported-by: Bart Van Assche +Closes: https://lore.kernel.org/linux-raid/20250611073108.25463-1-xni@redhat.com/T/#mfa369ef5faa4aa58e13e6d9fdb88aecd862b8f2f +Signed-off-by: Xiao Ni +Reviewed-by: Bart Van Assche +Reviewed-by: Li Nan +Signed-off-by: Yu Kuai +Signed-off-by: Sasha Levin +--- + drivers/md/md.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/md/md.h b/drivers/md/md.h +index 6985f2829bbd6..3bfbee595156d 100644 +--- a/drivers/md/md.h ++++ b/drivers/md/md.h +@@ -737,8 +737,8 @@ static inline int mddev_trylock(struct mddev *mddev) + int ret; + + ret = mutex_trylock(&mddev->reconfig_mutex); +- if (!ret && test_bit(MD_DELETED, &mddev->flags)) { +- ret = -ENODEV; ++ if (ret && test_bit(MD_DELETED, &mddev->flags)) { ++ ret = 0; + mutex_unlock(&mddev->reconfig_mutex); + } + return ret; +-- +2.51.0 + diff --git a/queue-6.19/md-md-llbitmap-fix-percpu_ref-not-resurrected-on-sus.patch b/queue-6.19/md-md-llbitmap-fix-percpu_ref-not-resurrected-on-sus.patch new file mode 100644 index 0000000000..d629130f5a --- /dev/null +++ b/queue-6.19/md-md-llbitmap-fix-percpu_ref-not-resurrected-on-sus.patch @@ -0,0 +1,47 @@ +From 3c84fe0cfdab50b38d9a292384581f5d1b23ada1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 24 Jan 2026 02:26:23 +0800 +Subject: md/md-llbitmap: fix percpu_ref not resurrected on suspend timeout + +From: Yu Kuai + +[ Upstream commit d119bd2e1643cc023210ff3c6f0657e4f914e71d ] + +When llbitmap_suspend_timeout() times out waiting for percpu_ref to +become zero, it returns -ETIMEDOUT without resurrecting the percpu_ref. +The caller (md_llbitmap_daemon_fn) then continues to the next page +without calling llbitmap_resume(), leaving the percpu_ref in a killed +state permanently. + +Fix this by resurrecting the percpu_ref before returning the error, +ensuring the page control structure remains usable for subsequent +operations. + +Link: https://lore.kernel.org/linux-raid/20260123182623.3718551-3-yukuai@fnnas.com +Fixes: 5ab829f1971d ("md/md-llbitmap: introduce new lockless bitmap") +Signed-off-by: Yu Kuai +Reviewed-by: Li Nan +Signed-off-by: Sasha Levin +--- + drivers/md/md-llbitmap.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/md-llbitmap.c b/drivers/md/md-llbitmap.c +index 9c1ade19b7741..cd713a7dc2706 100644 +--- a/drivers/md/md-llbitmap.c ++++ b/drivers/md/md-llbitmap.c +@@ -712,8 +712,10 @@ static int llbitmap_suspend_timeout(struct llbitmap *llbitmap, int page_idx) + percpu_ref_kill(&pctl->active); + + if (!wait_event_timeout(pctl->wait, percpu_ref_is_zero(&pctl->active), +- llbitmap->mddev->bitmap_info.daemon_sleep * HZ)) ++ llbitmap->mddev->bitmap_info.daemon_sleep * HZ)) { ++ percpu_ref_resurrect(&pctl->active); + return -ETIMEDOUT; ++ } + + return 0; + } +-- +2.51.0 + diff --git a/queue-6.19/md-raid1-fix-memory-leak-in-raid1_run.patch b/queue-6.19/md-raid1-fix-memory-leak-in-raid1_run.patch new file mode 100644 index 0000000000..519024423a --- /dev/null +++ b/queue-6.19/md-raid1-fix-memory-leak-in-raid1_run.patch @@ -0,0 +1,46 @@ +From fb464d1fb7cd9530d7efb849dcfa897a5d8e6007 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 07:15:33 +0000 +Subject: md/raid1: fix memory leak in raid1_run() + +From: Zilin Guan + +[ Upstream commit 6abc7d5dcf0ee0f85e16e41c87fbd06231f28753 ] + +raid1_run() calls setup_conf() which registers a thread via +md_register_thread(). If raid1_set_limits() fails, the previously +registered thread is not unregistered, resulting in a memory leak +of the md_thread structure and the thread resource itself. + +Add md_unregister_thread() to the error path to properly cleanup +the thread, which aligns with the error handling logic of other paths +in this function. + +Compile tested only. Issue found using a prototype static analysis tool +and code review. + +Link: https://lore.kernel.org/linux-raid/20260126071533.606263-1-zilin@seu.edu.cn +Fixes: 97894f7d3c29 ("md/raid1: use the atomic queue limit update APIs") +Signed-off-by: Zilin Guan +Reviewed-by: Li Nan +Signed-off-by: Yu Kuai +Signed-off-by: Sasha Levin +--- + drivers/md/raid1.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c +index 57d50465eed1b..cc9914bd15c19 100644 +--- a/drivers/md/raid1.c ++++ b/drivers/md/raid1.c +@@ -3254,6 +3254,7 @@ static int raid1_run(struct mddev *mddev) + if (!mddev_is_dm(mddev)) { + ret = raid1_set_limits(mddev); + if (ret) { ++ md_unregister_thread(mddev, &conf->thread); + if (!mddev->private) + raid1_free(mddev, conf); + return ret; +-- +2.51.0 + diff --git a/queue-6.19/md-raid10-fix-any_working-flag-handling-in-raid10_sy.patch b/queue-6.19/md-raid10-fix-any_working-flag-handling-in-raid10_sy.patch new file mode 100644 index 0000000000..4d6bad41f2 --- /dev/null +++ b/queue-6.19/md-raid10-fix-any_working-flag-handling-in-raid10_sy.patch @@ -0,0 +1,47 @@ +From c2580598ea88fb7bc93750d29545edd611fa5e42 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Jan 2026 19:02:58 +0800 +Subject: md/raid10: fix any_working flag handling in raid10_sync_request + +From: Li Nan + +[ Upstream commit 99582edb3f62e8ee6c34512021368f53f9b091f2 ] + +In raid10_sync_request(), 'any_working' indicates if any IO will +be submitted. When there's only one In_sync disk with badblocks, +'any_working' might be set to 1 but no IO is submitted. Fix it by +setting 'any_working' after badblock checks. + +Link: https://lore.kernel.org/linux-raid/20260105110300.1442509-11-linan666@huaweicloud.com +Fixes: e875ecea266a ("md/raid10 record bad blocks as needed during recovery.") +Signed-off-by: Li Nan +Reviewed-by: Yu Kuai +Signed-off-by: Yu Kuai +Signed-off-by: Sasha Levin +--- + drivers/md/raid10.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c +index 84be4cc7e8739..3a591e60a1449 100644 +--- a/drivers/md/raid10.c ++++ b/drivers/md/raid10.c +@@ -3402,7 +3402,6 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr, + !test_bit(In_sync, &rdev->flags)) + continue; + /* This is where we read from */ +- any_working = 1; + sector = r10_bio->devs[j].addr; + + if (is_badblock(rdev, sector, max_sync, +@@ -3417,6 +3416,7 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr, + continue; + } + } ++ any_working = 1; + bio = r10_bio->devs[0].bio; + bio->bi_next = biolist; + biolist = bio; +-- +2.51.0 + diff --git a/queue-6.19/md-raid5-fix-io-hang-with-degraded-array-with-llbitm.patch b/queue-6.19/md-raid5-fix-io-hang-with-degraded-array-with-llbitm.patch new file mode 100644 index 0000000000..7b01dc176d --- /dev/null +++ b/queue-6.19/md-raid5-fix-io-hang-with-degraded-array-with-llbitm.patch @@ -0,0 +1,48 @@ +From 30fca7e6e4bf3c4d35f90b525ce7939d72996f63 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 24 Jan 2026 02:26:22 +0800 +Subject: md/raid5: fix IO hang with degraded array with llbitmap + +From: Yu Kuai + +[ Upstream commit cd1635d844d26471c56c0a432abdee12fc9ad735 ] + +When llbitmap bit state is still unwritten, any new write should force +rcw, as bitmap_ops->blocks_synced() is checked in handle_stripe_dirtying(). +However, later the same check is missing in need_this_block(), causing +stripe to deadloop during handling because handle_stripe() will decide +to go to handle_stripe_fill(), meanwhile need_this_block() always return +0 and nothing is handled. + +Link: https://lore.kernel.org/linux-raid/20260123182623.3718551-2-yukuai@fnnas.com +Fixes: 5ab829f1971d ("md/md-llbitmap: introduce new lockless bitmap") +Signed-off-by: Yu Kuai +Reviewed-by: Li Nan +Signed-off-by: Sasha Levin +--- + drivers/md/raid5.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c +index a85878b009f9a..bdf248db1330a 100644 +--- a/drivers/md/raid5.c ++++ b/drivers/md/raid5.c +@@ -3751,9 +3751,14 @@ static int need_this_block(struct stripe_head *sh, struct stripe_head_state *s, + struct r5dev *dev = &sh->dev[disk_idx]; + struct r5dev *fdev[2] = { &sh->dev[s->failed_num[0]], + &sh->dev[s->failed_num[1]] }; ++ struct mddev *mddev = sh->raid_conf->mddev; ++ bool force_rcw = false; + int i; +- bool force_rcw = (sh->raid_conf->rmw_level == PARITY_DISABLE_RMW); + ++ if (sh->raid_conf->rmw_level == PARITY_DISABLE_RMW || ++ (mddev->bitmap_ops && mddev->bitmap_ops->blocks_synced && ++ !mddev->bitmap_ops->blocks_synced(mddev, sh->sector))) ++ force_rcw = true; + + if (test_bit(R5_LOCKED, &dev->flags) || + test_bit(R5_UPTODATE, &dev->flags)) +-- +2.51.0 + diff --git a/queue-6.19/md-raid5-fix-raid5_run-to-return-error-when-log_init.patch b/queue-6.19/md-raid5-fix-raid5_run-to-return-error-when-log_init.patch new file mode 100644 index 0000000000..02662baec5 --- /dev/null +++ b/queue-6.19/md-raid5-fix-raid5_run-to-return-error-when-log_init.patch @@ -0,0 +1,47 @@ +From db31552a39999b9defc9d02da3567a65403ba38d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 01:12:29 +0800 +Subject: md/raid5: fix raid5_run() to return error when log_init() fails + +From: Yu Kuai + +[ Upstream commit 2d9f7150ac197ce79c9c917a004d4cf0b26ad7e0 ] + +Since commit f63f17350e53 ("md/raid5: use the atomic queue limit +update APIs"), the abort path in raid5_run() returns 'ret' instead of +-EIO. However, if log_init() fails, 'ret' is still 0 from the previous +successful call, causing raid5_run() to return success despite the +failure. + +Fix this by capturing the return value from log_init(). + +Link: https://lore.kernel.org/linux-raid/20260114171241.3043364-2-yukuai@fnnas.com +Fixes: f63f17350e53 ("md/raid5: use the atomic queue limit update APIs") +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/r/202601130531.LGfcZsa4-lkp@intel.com/ +Signed-off-by: Yu Kuai +Reviewed-by: Li Nan +Reviewed-by: Xiao Ni +Reviewed-by: Christoph Hellwig +Signed-off-by: Sasha Levin +--- + drivers/md/raid5.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c +index 8dc98f545969f..a85878b009f9a 100644 +--- a/drivers/md/raid5.c ++++ b/drivers/md/raid5.c +@@ -8057,7 +8057,8 @@ static int raid5_run(struct mddev *mddev) + goto abort; + } + +- if (log_init(conf, journal_dev, raid5_has_ppl(conf))) ++ ret = log_init(conf, journal_dev, raid5_has_ppl(conf)); ++ if (ret) + goto abort; + + return 0; +-- +2.51.0 + diff --git a/queue-6.19/media-ccs-accommodate-c-phy-into-the-calculation.patch b/queue-6.19/media-ccs-accommodate-c-phy-into-the-calculation.patch new file mode 100644 index 0000000000..98086b9c85 --- /dev/null +++ b/queue-6.19/media-ccs-accommodate-c-phy-into-the-calculation.patch @@ -0,0 +1,53 @@ +From 5e3f7b40e27f85f9ed4990852154d2a0f9ea918a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 18:57:07 +0100 +Subject: media: ccs: Accommodate C-PHY into the calculation + +From: David Heidelberg + +[ Upstream commit 3085977e734dab74adebb1dda195befce25addff ] + +We need to set correct mode for PLL to calculate correct frequency. +Signalling mode is known at this point, so use it for that. + +Fixes: 47b6eaf36eba ("media: ccs-pll: Differentiate between CSI-2 D-PHY and C-PHY") +Reviewed-by: Mehdi Djait +Signed-off-by: David Heidelberg +[Sakari Ailus: Drop extra newline.] +Signed-off-by: Sakari Ailus +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/i2c/ccs/ccs-core.c | 16 +++++++++++++++- + 1 file changed, 15 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c +index f8523140784c7..43f7d515bab67 100644 +--- a/drivers/media/i2c/ccs/ccs-core.c ++++ b/drivers/media/i2c/ccs/ccs-core.c +@@ -3425,7 +3425,21 @@ static int ccs_probe(struct i2c_client *client) + sensor->scale_m = CCS_LIM(sensor, SCALER_N_MIN); + + /* prepare PLL configuration input values */ +- sensor->pll.bus_type = CCS_PLL_BUS_TYPE_CSI2_DPHY; ++ switch (sensor->hwcfg.csi_signalling_mode) { ++ case CCS_CSI_SIGNALING_MODE_CSI_2_CPHY: ++ sensor->pll.bus_type = CCS_PLL_BUS_TYPE_CSI2_CPHY; ++ break; ++ case CCS_CSI_SIGNALING_MODE_CSI_2_DPHY: ++ case SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK: ++ case SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_STROBE: ++ sensor->pll.bus_type = CCS_PLL_BUS_TYPE_CSI2_DPHY; ++ break; ++ default: ++ dev_err(&client->dev, "unsupported signalling mode %u\n", ++ sensor->hwcfg.csi_signalling_mode); ++ rval = -EINVAL; ++ goto out_cleanup; ++ } + sensor->pll.csi2.lanes = sensor->hwcfg.lanes; + if (CCS_LIM(sensor, CLOCK_CALCULATION) & + CCS_CLOCK_CALCULATION_LANE_SPEED) { +-- +2.51.0 + diff --git a/queue-6.19/media-chips-media-wave5-fix-memory-leak-on-codec_inf.patch b/queue-6.19/media-chips-media-wave5-fix-memory-leak-on-codec_inf.patch new file mode 100644 index 0000000000..5a7f17c496 --- /dev/null +++ b/queue-6.19/media-chips-media-wave5-fix-memory-leak-on-codec_inf.patch @@ -0,0 +1,63 @@ +From ab686328645d7172853f75886636684c28a1e990 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 11 Nov 2025 14:57:06 +0000 +Subject: media: chips-media: wave5: Fix memory leak on codec_info allocation + failure + +From: Zilin Guan + +[ Upstream commit a519e21e32398459ba357e67b541402f7295ee1b ] + +In wave5_vpu_open_enc() and wave5_vpu_open_dec(), a vpu instance is +allocated via kzalloc(). If the subsequent allocation for inst->codec_info +fails, the functions return -ENOMEM without freeing the previously +allocated instance, causing a memory leak. + +Fix this by calling kfree() on the instance in this error path to ensure +it is properly released. + +Fixes: 9707a6254a8a6 ("media: chips-media: wave5: Add the v4l2 layer") +Signed-off-by: Zilin Guan +Signed-off-by: Nicolas Dufresne +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c | 4 +++- + drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c | 4 +++- + 2 files changed, 6 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c +index e3038c18ca362..a4387ed58cac3 100644 +--- a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c ++++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c +@@ -1753,8 +1753,10 @@ static int wave5_vpu_open_dec(struct file *filp) + spin_lock_init(&inst->state_spinlock); + + inst->codec_info = kzalloc(sizeof(*inst->codec_info), GFP_KERNEL); +- if (!inst->codec_info) ++ if (!inst->codec_info) { ++ kfree(inst); + return -ENOMEM; ++ } + + v4l2_fh_init(&inst->v4l2_fh, vdev); + v4l2_fh_add(&inst->v4l2_fh, filp); +diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c +index 9bfaa9fb3ceb3..94fb5d7c87021 100644 +--- a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c ++++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c +@@ -1578,8 +1578,10 @@ static int wave5_vpu_open_enc(struct file *filp) + inst->ops = &wave5_vpu_enc_inst_ops; + + inst->codec_info = kzalloc(sizeof(*inst->codec_info), GFP_KERNEL); +- if (!inst->codec_info) ++ if (!inst->codec_info) { ++ kfree(inst); + return -ENOMEM; ++ } + + v4l2_fh_init(&inst->v4l2_fh, vdev); + v4l2_fh_add(&inst->v4l2_fh, filp); +-- +2.51.0 + diff --git a/queue-6.19/media-pci-mg4b-use-irqf_no_thread.patch b/queue-6.19/media-pci-mg4b-use-irqf_no_thread.patch new file mode 100644 index 0000000000..9672dc701b --- /dev/null +++ b/queue-6.19/media-pci-mg4b-use-irqf_no_thread.patch @@ -0,0 +1,39 @@ +From 78b0d1fe3d4a270003c8239961b67efa000f6cd3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:55:40 +0100 +Subject: media: pci: mg4b: Use IRQF_NO_THREAD + +From: Sebastian Andrzej Siewior + +[ Upstream commit ef92b98f5f6758a049898b53aa30476010db04fa ] + +The interrupt handler iio_trigger_generic_data_rdy_poll() will invoke other +interrupt handlers and this supposed to happen from hard interrupt context. + +Use IRQF_NO_THREAD to forbid forced-threading. + +Fixes: 0ab13674a9bd1 ("media: pci: mgb4: Added Digiteq Automotive MGB4 driver") +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260128095540.863589-21-bigeasy@linutronix.de +Signed-off-by: Sasha Levin +--- + drivers/media/pci/mgb4/mgb4_trigger.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/media/pci/mgb4/mgb4_trigger.c b/drivers/media/pci/mgb4/mgb4_trigger.c +index 4f9a35904b418..70cad324df608 100644 +--- a/drivers/media/pci/mgb4/mgb4_trigger.c ++++ b/drivers/media/pci/mgb4/mgb4_trigger.c +@@ -115,7 +115,7 @@ static int probe_trigger(struct iio_dev *indio_dev, int irq) + if (!st->trig) + return -ENOMEM; + +- ret = request_irq(irq, &iio_trigger_generic_data_rdy_poll, 0, ++ ret = request_irq(irq, &iio_trigger_generic_data_rdy_poll, IRQF_NO_THREAD, + "mgb4-trigger", st->trig); + if (ret) + goto error_free_trig; +-- +2.51.0 + diff --git a/queue-6.19/media-uvcvideo-fix-allocation-for-small-frame-sizes.patch b/queue-6.19/media-uvcvideo-fix-allocation-for-small-frame-sizes.patch new file mode 100644 index 0000000000..8b69b28134 --- /dev/null +++ b/queue-6.19/media-uvcvideo-fix-allocation-for-small-frame-sizes.patch @@ -0,0 +1,57 @@ +From 2e602be5967f923f6a15b08b4ac58c9c7659bc86 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 10:32:13 +0000 +Subject: media: uvcvideo: Fix allocation for small frame sizes + +From: Ricardo Ribalda + +[ Upstream commit 40d3ac25c11310bfaa50ed7614846ef75cb69a1e ] + +If a frame has size of less or equal than one packet size +uvc_alloc_urb_buffers() is unable to allocate memory for it due to a +off-by-one error. + +Fix the off-by-one-error and now that we are at it, make sure that +stream->urb_size has always a valid value when we return from the +function, even when an error happens. + +Fixes: efdc8a9585ce ("V4L/DVB (10295): uvcvideo: Retry URB buffers allocation when the system is low on memory.") +Reported-by: Itay Chamiel +Closes: https://lore.kernel.org/linux-media/CANiDSCsSoZf2LsCCoWAUbCg6tJT-ypXR1B85aa6rAdMVYr2iBQ@mail.gmail.com/T/#t +Co-developed-by: Itay Chamiel +Signed-off-by: Itay Chamiel +Signed-off-by: Ricardo Ribalda +Reviewed-by: Laurent Pinchart +Tested-by: Itay Chamiel +Link: https://patch.msgid.link/20260114-uvc-alloc-urb-v1-1-cedf3fb66711@chromium.org +Signed-off-by: Laurent Pinchart +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/usb/uvc/uvc_video.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c +index 2094e059d7d39..ec76595f3c4be 100644 +--- a/drivers/media/usb/uvc/uvc_video.c ++++ b/drivers/media/usb/uvc/uvc_video.c +@@ -1812,7 +1812,7 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream, + npackets = UVC_MAX_PACKETS; + + /* Retry allocations until one succeed. */ +- for (; npackets > 1; npackets /= 2) { ++ for (; npackets > 0; npackets /= 2) { + stream->urb_size = psize * npackets; + + for (i = 0; i < UVC_URBS; ++i) { +@@ -1837,6 +1837,7 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream, + uvc_dbg(stream->dev, VIDEO, + "Failed to allocate URB buffers (%u bytes per packet)\n", + psize); ++ stream->urb_size = 0; + return 0; + } + +-- +2.51.0 + diff --git a/queue-6.19/mei-late_bind-fix-struct-intel_lb_component_ops-kern.patch b/queue-6.19/mei-late_bind-fix-struct-intel_lb_component_ops-kern.patch new file mode 100644 index 0000000000..aa086ddf53 --- /dev/null +++ b/queue-6.19/mei-late_bind-fix-struct-intel_lb_component_ops-kern.patch @@ -0,0 +1,46 @@ +From 52a31348988b2faa63acb7aa3aaf165089444cb1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 18:02:26 +0200 +Subject: mei: late_bind: fix struct intel_lb_component_ops kernel-doc + +From: Jani Nikula + +[ Upstream commit 936cae9254e55a39aeaa0c156a764d22f319338b ] + +Fix kernel-doc warnings on struct intel_lb_component_ops: + +Warning: include/drm/intel/intel_lb_mei_interface.h:55 Incorrect use of + kernel-doc format: * push_payload - Sends a payload to the + authentication firmware + +And a bunch more. There isn't really support for documenting function +pointer struct members in kernel-doc, but at least reference the member +properly. + +Fixes: 741eeabb7c78 ("mei: late_bind: add late binding component driver") +Cc: Alexander Usyskin +Reviewed-by: Nitin Gote +Link: https://patch.msgid.link/20260107160226.2381388-1-jani.nikula@intel.com +Signed-off-by: Jani Nikula +Signed-off-by: Sasha Levin +--- + include/drm/intel/intel_lb_mei_interface.h | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/include/drm/intel/intel_lb_mei_interface.h b/include/drm/intel/intel_lb_mei_interface.h +index d65be2cba2ab9..0850738a30fc7 100644 +--- a/include/drm/intel/intel_lb_mei_interface.h ++++ b/include/drm/intel/intel_lb_mei_interface.h +@@ -53,7 +53,8 @@ enum intel_lb_status { + */ + struct intel_lb_component_ops { + /** +- * push_payload - Sends a payload to the authentication firmware ++ * @push_payload: Sends a payload to the authentication firmware ++ * + * @dev: Device struct corresponding to the mei device + * @type: Payload type (see &enum intel_lb_type) + * @flags: Payload flags bitmap (e.g. %INTEL_LB_FLAGS_IS_PERSISTENT) +-- +2.51.0 + diff --git a/queue-6.19/mfd-arizona-fix-regulator-resource-leak-on-wm5102_cl.patch b/queue-6.19/mfd-arizona-fix-regulator-resource-leak-on-wm5102_cl.patch new file mode 100644 index 0000000000..b0534cccec --- /dev/null +++ b/queue-6.19/mfd-arizona-fix-regulator-resource-leak-on-wm5102_cl.patch @@ -0,0 +1,43 @@ +From b708ed21864a8e88fe1cf4d491dc365eff35a09d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 14 Dec 2025 22:58:03 +0800 +Subject: mfd: arizona: Fix regulator resource leak on + wm5102_clear_write_sequencer() failure + +From: Haotian Zhang + +[ Upstream commit 4feb753ba6e5e5bbaba868b841a2db41c21e56fa ] + +The wm5102_clear_write_sequencer() helper may return an error +and just return, bypassing the cleanup sequence and causing +regulators to remain enabled, leading to a resource leak. + +Change the direct return to jump to the err_reset label to +properly free the resources. + +Fixes: 1c1c6bba57f5 ("mfd: wm5102: Ensure we always boot the device fully") +Signed-off-by: Haotian Zhang +Reviewed-by: Charles Keepax +Link: https://patch.msgid.link/20251214145804.2037-1-vulab@iscas.ac.cn +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/mfd/arizona-core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c +index 85ff8717d8504..91975536d14d2 100644 +--- a/drivers/mfd/arizona-core.c ++++ b/drivers/mfd/arizona-core.c +@@ -1100,7 +1100,7 @@ int arizona_dev_init(struct arizona *arizona) + } else if (val & 0x01) { + ret = wm5102_clear_write_sequencer(arizona); + if (ret) +- return ret; ++ goto err_reset; + } + break; + default: +-- +2.51.0 + diff --git a/queue-6.19/mfd-sec-fix-irq-domain-names-duplication.patch b/queue-6.19/mfd-sec-fix-irq-domain-names-duplication.patch new file mode 100644 index 0000000000..48653ecabd --- /dev/null +++ b/queue-6.19/mfd-sec-fix-irq-domain-names-duplication.patch @@ -0,0 +1,43 @@ +From e8c8645e07c9be6c416e690b7fb39aa199189906 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Jan 2026 16:25:46 +0000 +Subject: mfd: sec: Fix IRQ domain names duplication +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: André Draszik + +[ Upstream commit b60c2dba6d3c3ad72a7c30bbd8eda07d8a49bc7f ] + +For the S2MPG10 IRQ and chained IRQ, regmap IRQ will try to create a +folder with the same name which is impossible and fails with: + + debugfs: ':firmware:power-management:pmic' already exists in 'domains' + +Add domain_suffix to the chained IRQ chip driver to fix it. + +Fixes: ee19b52c31b3 ("mfd: sec: Use chained IRQs for s2mpg10") +Signed-off-by: André Draszik +Link: https://patch.msgid.link/20260105-s2mpg10-chained-irq-domain-suffix-v1-1-01ab16204b97@linaro.org +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/mfd/sec-irq.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/mfd/sec-irq.c b/drivers/mfd/sec-irq.c +index 74ac70002d1fc..ff2671186e89f 100644 +--- a/drivers/mfd/sec-irq.c ++++ b/drivers/mfd/sec-irq.c +@@ -198,6 +198,7 @@ static const struct regmap_irq_chip s2mpg10_irq_chip = { + + static const struct regmap_irq_chip s2mpg10_irq_chip_pmic = { + .name = "s2mpg10-pmic", ++ .domain_suffix = "pmic", + .status_base = S2MPG10_PMIC_INT1, + .mask_base = S2MPG10_PMIC_INT1M, + .num_regs = 6, +-- +2.51.0 + diff --git a/queue-6.19/mfd-simple-mfd-i2c-add-delta-tn48m-cpld-support.patch b/queue-6.19/mfd-simple-mfd-i2c-add-delta-tn48m-cpld-support.patch new file mode 100644 index 0000000000..2973cfa441 --- /dev/null +++ b/queue-6.19/mfd-simple-mfd-i2c-add-delta-tn48m-cpld-support.patch @@ -0,0 +1,67 @@ +From 641229ffb7be428fff30d86ed0bc489c7661743f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 17:14:52 +0100 +Subject: mfd: simple-mfd-i2c: Add Delta TN48M CPLD support + +From: Robert Marko + +[ Upstream commit 8f34c1a64c5394d2b51d3fba197947dc4b0b48a0 ] + +Delta TN48M switches have a Lattice CPLD that serves +multiple purposes including being a GPIO expander. + +So, lets use the simple I2C MFD driver to provide the MFD core. + +Also add a virtual symbol which pulls in the simple-mfd-i2c driver and +provide a common symbol on which the subdevice drivers can depend on. + +Fixes: b3dcb5de6209 ("gpio: Add Delta TN48M CPLD GPIO driver") +Signed-off-by: Robert Marko +Link: https://lore.kernel.org/20220131133049.77780-2-robert.marko@sartura.hr +Link: https://lore.kernel.org/linux-gpio/20260112064950.3837737-1-rdunlap@infradead.org/ +Signed-off-by: Linus Walleij +Link: https://patch.msgid.link/20260112-mfd-tn48m-v11-1-00c798d8cd2a@kernel.org +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/mfd/Kconfig | 11 +++++++++++ + drivers/mfd/simple-mfd-i2c.c | 1 + + 2 files changed, 12 insertions(+) + +diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig +index aace5766b38aa..f7f12a0428aa2 100644 +--- a/drivers/mfd/Kconfig ++++ b/drivers/mfd/Kconfig +@@ -407,6 +407,17 @@ config MFD_CS47L92 + help + Support for Cirrus Logic CS42L92, CS47L92 and CS47L93 Smart Codecs + ++config MFD_TN48M_CPLD ++ tristate "Delta Networks TN48M switch CPLD driver" ++ depends on I2C ++ depends on ARCH_MVEBU || COMPILE_TEST ++ select MFD_SIMPLE_MFD_I2C ++ help ++ Select this option to enable support for Delta Networks TN48M switch ++ CPLD. It consists of reset and GPIO drivers. CPLD provides GPIOS-s ++ for the SFP slots as well as power supply related information. ++ SFP support depends on the GPIO driver being selected. ++ + config PMIC_DA903X + bool "Dialog Semiconductor DA9030/DA9034 PMIC Support" + depends on I2C=y +diff --git a/drivers/mfd/simple-mfd-i2c.c b/drivers/mfd/simple-mfd-i2c.c +index 8b751d8e3b5ae..7315fad618e44 100644 +--- a/drivers/mfd/simple-mfd-i2c.c ++++ b/drivers/mfd/simple-mfd-i2c.c +@@ -116,6 +116,7 @@ static const struct simple_mfd_data spacemit_p1 = { + }; + + static const struct of_device_id simple_mfd_i2c_of_match[] = { ++ { .compatible = "delta,tn48m-cpld" }, + { .compatible = "fsl,ls1028aqds-fpga" }, + { .compatible = "fsl,lx2160aqds-fpga" }, + { .compatible = "fsl,lx2160ardb-fpga" }, +-- +2.51.0 + diff --git a/queue-6.19/mfd-wm8350-core-use-irqf_oneshot.patch b/queue-6.19/mfd-wm8350-core-use-irqf_oneshot.patch new file mode 100644 index 0000000000..301236dfff --- /dev/null +++ b/queue-6.19/mfd-wm8350-core-use-irqf_oneshot.patch @@ -0,0 +1,48 @@ +From 250faa85d1964fd3566dda9841d5bb658ada0561 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:55:35 +0100 +Subject: mfd: wm8350-core: Use IRQF_ONESHOT + +From: Sebastian Andrzej Siewior + +[ Upstream commit 553b4999cbe231b5011cb8db05a3092dec168aca ] + +Using a threaded interrupt without a dedicated primary handler mandates +the IRQF_ONESHOT flag to mask the interrupt source while the threaded +handler is active. Otherwise the interrupt can fire again before the +threaded handler had a chance to run. + +Mark explained that this should not happen with this hardware since it +is a slow irqchip which is behind an I2C/ SPI bus but the IRQ-core will +refuse to accept such a handler. + +Set IRQF_ONESHOT so the interrupt source is masked until the secondary +handler is done. + +Fixes: 1c6c69525b40e ("genirq: Reject bogus threaded irq requests") +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Reviewed-by: Charles Keepax +Reviewed-by: Andy Shevchenko +Link: https://patch.msgid.link/20260128095540.863589-16-bigeasy@linutronix.de +Signed-off-by: Sasha Levin +--- + include/linux/mfd/wm8350/core.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/linux/mfd/wm8350/core.h b/include/linux/mfd/wm8350/core.h +index 5f70d3b5d1b1a..097ef4dfcdac8 100644 +--- a/include/linux/mfd/wm8350/core.h ++++ b/include/linux/mfd/wm8350/core.h +@@ -667,7 +667,7 @@ static inline int wm8350_register_irq(struct wm8350 *wm8350, int irq, + return -ENODEV; + + return request_threaded_irq(irq + wm8350->irq_base, NULL, +- handler, flags, name, data); ++ handler, flags | IRQF_ONESHOT, name, data); + } + + static inline void wm8350_free_irq(struct wm8350 *wm8350, int irq, void *data) +-- +2.51.0 + diff --git a/queue-6.19/mips-loongson32-drop-a-dangling-kconfig-symbol.patch b/queue-6.19/mips-loongson32-drop-a-dangling-kconfig-symbol.patch new file mode 100644 index 0000000000..ccc63d245a --- /dev/null +++ b/queue-6.19/mips-loongson32-drop-a-dangling-kconfig-symbol.patch @@ -0,0 +1,36 @@ +From 18e307dd94bbd2e0caefdd75e94f4dd7ed80ce3f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 28 Dec 2025 11:04:43 -0800 +Subject: mips: LOONGSON32: drop a dangling Kconfig symbol + +From: Randy Dunlap + +[ Upstream commit d463fc5ca1ace0b2e8bb764df04fc12ecd6f8e2b ] + +CPU_HAS_LOAD_STORE_LR is not used anywhere in the kernel sources, +so drop it. + +Fixes: 85c4354076ca ("MIPS: loongson32: Switch to generic core") +Signed-off-by: Randy Dunlap +Reviewed-by: Keguang Zhang +Signed-off-by: Thomas Bogendoerfer +Signed-off-by: Sasha Levin +--- + arch/mips/Kconfig | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig +index b88b97139fa8e..d87db7c535ea1 100644 +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -1408,7 +1408,6 @@ config CPU_LOONGSON32 + select CPU_MIPS32 + select CPU_MIPSR2 + select CPU_HAS_PREFETCH +- select CPU_HAS_LOAD_STORE_LR + select CPU_SUPPORTS_32BIT_KERNEL + select CPU_SUPPORTS_HIGHMEM + select CPU_SUPPORTS_CPUFREQ +-- +2.51.0 + diff --git a/queue-6.19/mm-slab-fix-false-lockdep-warning-in-__kfree_rcu_she.patch b/queue-6.19/mm-slab-fix-false-lockdep-warning-in-__kfree_rcu_she.patch new file mode 100644 index 0000000000..f67cf5d7b8 --- /dev/null +++ b/queue-6.19/mm-slab-fix-false-lockdep-warning-in-__kfree_rcu_she.patch @@ -0,0 +1,130 @@ +From b44b5b1cf64e97e503e794e458a53f23817b6647 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 07:52:40 +0100 +Subject: mm/slab: fix false lockdep warning in __kfree_rcu_sheaf() + +From: Harry Yoo + +[ Upstream commit f8b4cd2dad097e4ea5aed3511f42b9eb771e7b19 ] + +kvfree_call_rcu() can be called while holding a raw_spinlock_t. +Since __kfree_rcu_sheaf() may acquire a spinlock_t (which becomes a +sleeping lock on PREEMPT_RT) and violate lock nesting rules, +kvfree_call_rcu() bypasses the sheaves layer entirely on PREEMPT_RT. + +However, lockdep still complains about acquiring spinlock_t while holding +raw_spinlock_t, even on !PREEMPT_RT where spinlock_t is a spinning lock. +This causes a false lockdep warning [1]: + + ============================= + [ BUG: Invalid wait context ] + 6.19.0-rc6-next-20260120 #21508 Not tainted + ----------------------------- + migration/1/23 is trying to lock: + ffff8afd01054e98 (&barn->lock){..-.}-{3:3}, at: barn_get_empty_sheaf+0x1d/0xb0 + other info that might help us debug this: + context-{5:5} + 3 locks held by migration/1/23: + #0: ffff8afd01fd89a8 (&p->pi_lock){-.-.}-{2:2}, at: __balance_push_cpu_stop+0x3f/0x200 + #1: ffffffff9f15c5c8 (rcu_read_lock){....}-{1:3}, at: cpuset_cpus_allowed_fallback+0x27/0x250 + #2: ffff8afd1f470be0 ((local_lock_t *)&pcs->lock){+.+.}-{3:3}, at: __kfree_rcu_sheaf+0x52/0x3d0 + stack backtrace: + CPU: 1 UID: 0 PID: 23 Comm: migration/1 Not tainted 6.19.0-rc6-next-20260120 #21508 PREEMPTLAZY + Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.14.0-0-g155821a1990b-prebuilt.qemu.org 04/01/2014 + Stopper: __balance_push_cpu_stop+0x0/0x200 <- balance_push+0x118/0x170 + Call Trace: + + __dump_stack+0x22/0x30 + dump_stack_lvl+0x60/0x80 + dump_stack+0x19/0x24 + __lock_acquire+0xd3a/0x28e0 + ? __lock_acquire+0x5a9/0x28e0 + ? __lock_acquire+0x5a9/0x28e0 + ? barn_get_empty_sheaf+0x1d/0xb0 + lock_acquire+0xc3/0x270 + ? barn_get_empty_sheaf+0x1d/0xb0 + ? __kfree_rcu_sheaf+0x52/0x3d0 + _raw_spin_lock_irqsave+0x47/0x70 + ? barn_get_empty_sheaf+0x1d/0xb0 + barn_get_empty_sheaf+0x1d/0xb0 + ? __kfree_rcu_sheaf+0x52/0x3d0 + __kfree_rcu_sheaf+0x19f/0x3d0 + kvfree_call_rcu+0xaf/0x390 + set_cpus_allowed_force+0xc8/0xf0 + [...] + + +This wasn't triggered until sheaves were enabled for all slab caches, +since kfree_rcu() wasn't being called with a raw spinlock held for +caches with sheaves (vma, maple node). + +As suggested by Vlastimil Babka, fix this by using a lockdep map with +LD_WAIT_CONFIG wait type to tell lockdep that acquiring spinlock_t is valid +in this case, as those spinlocks won't be used on PREEMPT_RT. + +Note that kfree_rcu_sheaf_map should be acquired using _try() variant, +otherwise the acquisition of the lockdep map itself will trigger an invalid +wait context warning. + +Reported-by: Paul E. McKenney +Closes: https://lore.kernel.org/linux-mm/c858b9af-2510-448b-9ab3-058f7b80dd42@paulmck-laptop [1] +Fixes: ec66e0d59952 ("slab: add sheaf support for batching kfree_rcu() operations") +Suggested-by: Vlastimil Babka +Signed-off-by: Harry Yoo +Reviewed-by: Sebastian Andrzej Siewior +Signed-off-by: Vlastimil Babka +Signed-off-by: Sasha Levin +--- + mm/slub.c | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +diff --git a/mm/slub.c b/mm/slub.c +index cdc1e652ec52f..e1583757331e7 100644 +--- a/mm/slub.c ++++ b/mm/slub.c +@@ -6265,11 +6265,29 @@ static void rcu_free_sheaf(struct rcu_head *head) + free_empty_sheaf(s, sheaf); + } + ++/* ++ * kvfree_call_rcu() can be called while holding a raw_spinlock_t. Since ++ * __kfree_rcu_sheaf() may acquire a spinlock_t (sleeping lock on PREEMPT_RT), ++ * this would violate lock nesting rules. Therefore, kvfree_call_rcu() avoids ++ * this problem by bypassing the sheaves layer entirely on PREEMPT_RT. ++ * ++ * However, lockdep still complains that it is invalid to acquire spinlock_t ++ * while holding raw_spinlock_t, even on !PREEMPT_RT where spinlock_t is a ++ * spinning lock. Tell lockdep that acquiring spinlock_t is valid here ++ * by temporarily raising the wait-type to LD_WAIT_CONFIG. ++ */ ++static DEFINE_WAIT_OVERRIDE_MAP(kfree_rcu_sheaf_map, LD_WAIT_CONFIG); ++ + bool __kfree_rcu_sheaf(struct kmem_cache *s, void *obj) + { + struct slub_percpu_sheaves *pcs; + struct slab_sheaf *rcu_sheaf; + ++ if (WARN_ON_ONCE(IS_ENABLED(CONFIG_PREEMPT_RT))) ++ return false; ++ ++ lock_map_acquire_try(&kfree_rcu_sheaf_map); ++ + if (!local_trylock(&s->cpu_sheaves->lock)) + goto fail; + +@@ -6346,10 +6364,12 @@ bool __kfree_rcu_sheaf(struct kmem_cache *s, void *obj) + local_unlock(&s->cpu_sheaves->lock); + + stat(s, FREE_RCU_SHEAF); ++ lock_map_release(&kfree_rcu_sheaf_map); + return true; + + fail: + stat(s, FREE_RCU_SHEAF_FAIL); ++ lock_map_release(&kfree_rcu_sheaf_map); + return false; + } + +-- +2.51.0 + diff --git a/queue-6.19/mmc-rtsx_pci_sdmmc-increase-power-on-settling-delay-.patch b/queue-6.19/mmc-rtsx_pci_sdmmc-increase-power-on-settling-delay-.patch new file mode 100644 index 0000000000..3e8260f4cd --- /dev/null +++ b/queue-6.19/mmc-rtsx_pci_sdmmc-increase-power-on-settling-delay-.patch @@ -0,0 +1,40 @@ +From 045e78c672183388982745b95625b7ffdf401d9a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 4 Jan 2026 22:02:36 -0800 +Subject: mmc: rtsx_pci_sdmmc: increase power-on settling delay to 5ms + +From: Matthew Schwartz + +[ Upstream commit aced969e9bf3701dc75cfca57c78c031b7875b9d ] + +The existing 1ms delay in sd_power_on is insufficient and causes resume +errors around 4% of the time. + +Increasing the delay to 5ms resolves this issue after testing 300 +s2idle cycles. + +Fixes: 1f311c94aabd ("mmc: rtsx: add 74 Clocks in power on flow") +Signed-off-by: Matthew Schwartz +Link: https://patch.msgid.link/20260105060236.400366-3-matthew.schwartz@linux.dev +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/mmc/host/rtsx_pci_sdmmc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c +index 4db3328f46dfb..b6cf1803c7d27 100644 +--- a/drivers/mmc/host/rtsx_pci_sdmmc.c ++++ b/drivers/mmc/host/rtsx_pci_sdmmc.c +@@ -937,7 +937,7 @@ static int sd_power_on(struct realtek_pci_sdmmc *host, unsigned char power_mode) + if (err < 0) + return err; + +- mdelay(1); ++ mdelay(5); + + err = rtsx_pci_write_register(pcr, CARD_OE, SD_OUTPUT_EN, SD_OUTPUT_EN); + if (err < 0) +-- +2.51.0 + diff --git a/queue-6.19/module-add-helper-function-for-reading-module_buildi.patch b/queue-6.19/module-add-helper-function-for-reading-module_buildi.patch new file mode 100644 index 0000000000..12df4d07c2 --- /dev/null +++ b/queue-6.19/module-add-helper-function-for-reading-module_buildi.patch @@ -0,0 +1,80 @@ +From dfc9b2042489b7f2600541ab5a9e703e5d44c0ad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 14:59:16 +0100 +Subject: module: add helper function for reading module_buildid() + +From: Petr Mladek + +[ Upstream commit acfdbb4ab2910ff6f03becb569c23ac7b2223913 ] + +Add a helper function for reading the optional "build_id" member of struct +module. It is going to be used also in ftrace_mod_address_lookup(). + +Use "#ifdef" instead of "#if IS_ENABLED()" to match the declaration of the +optional field in struct module. + +Link: https://lkml.kernel.org/r/20251128135920.217303-4-pmladek@suse.com +Signed-off-by: Petr Mladek +Reviewed-by: Daniel Gomez +Reviewed-by: Petr Pavlu +Cc: Aaron Tomlin +Cc: Alexei Starovoitov +Cc: Daniel Borkman +Cc: John Fastabend +Cc: Kees Cook +Cc: Luis Chamberalin +Cc: Marc Rutland +Cc: "Masami Hiramatsu (Google)" +Cc: Sami Tolvanen +Cc: Steven Rostedt (Google) +Signed-off-by: Andrew Morton +Stable-dep-of: e8a1e7eaa19d ("kallsyms/ftrace: set module buildid in ftrace_mod_address_lookup()") +Signed-off-by: Sasha Levin +--- + include/linux/module.h | 9 +++++++++ + kernel/module/kallsyms.c | 9 ++------- + 2 files changed, 11 insertions(+), 7 deletions(-) + +diff --git a/include/linux/module.h b/include/linux/module.h +index d80c3ea574726..ac254525014cd 100644 +--- a/include/linux/module.h ++++ b/include/linux/module.h +@@ -748,6 +748,15 @@ static inline void __module_get(struct module *module) + __mod ? __mod->name : "kernel"; \ + }) + ++static inline const unsigned char *module_buildid(struct module *mod) ++{ ++#ifdef CONFIG_STACKTRACE_BUILD_ID ++ return mod->build_id; ++#else ++ return NULL; ++#endif ++} ++ + /* Dereference module function descriptor */ + void *dereference_module_function_descriptor(struct module *mod, void *ptr); + +diff --git a/kernel/module/kallsyms.c b/kernel/module/kallsyms.c +index 00a60796327c0..0fc11e45df9b9 100644 +--- a/kernel/module/kallsyms.c ++++ b/kernel/module/kallsyms.c +@@ -334,13 +334,8 @@ int module_address_lookup(unsigned long addr, + if (mod) { + if (modname) + *modname = mod->name; +- if (modbuildid) { +-#if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID) +- *modbuildid = mod->build_id; +-#else +- *modbuildid = NULL; +-#endif +- } ++ if (modbuildid) ++ *modbuildid = module_buildid(mod); + + sym = find_kallsyms_symbol(mod, addr, size, offset); + +-- +2.51.0 + diff --git a/queue-6.19/mptcp-do-not-account-for-ooo-in-mptcp_rcvbuf_grow.patch b/queue-6.19/mptcp-do-not-account-for-ooo-in-mptcp_rcvbuf_grow.patch new file mode 100644 index 0000000000..4761d48ce7 --- /dev/null +++ b/queue-6.19/mptcp-do-not-account-for-ooo-in-mptcp_rcvbuf_grow.patch @@ -0,0 +1,63 @@ +From 8e8f225fa7f251560f9e57f55043bd9237ee9ce2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 19:41:17 +0100 +Subject: mptcp: do not account for OoO in mptcp_rcvbuf_grow() + +From: Paolo Abeni + +[ Upstream commit 6b329393502e5857662b851a13f947209c588587 ] + +MPTCP-level OoOs are physiological when multiple subflows are active +concurrently and will not cause retransmissions nor are caused by +drops. + +Accounting for them in mptcp_rcvbuf_grow() causes the rcvbuf slowly +drifting towards tcp_rmem[2]. + +Remove such accounting. Note that subflows will still account for TCP-level +OoO when the MPTCP-level rcvbuf is propagated. + +This also closes a subtle and very unlikely race condition with rcvspace +init; active sockets with user-space holding the msk-level socket lock, +could complete such initialization in the receive callback, after that the +first OoO data reaches the rcvbuf and potentially triggering a divide by +zero Oops. + +Fixes: e118cdc34dd1 ("mptcp: rcvbuf auto-tuning improvement") +Signed-off-by: Paolo Abeni +Reviewed-by: Mat Martineau +Signed-off-by: Matthieu Baerts (NGI0) +Link: https://patch.msgid.link/20260203-net-next-mptcp-misc-feat-6-20-v1-1-31ec8bfc56d1@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/mptcp/protocol.c | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c +index 8d32336674181..cfa38bdaf2a92 100644 +--- a/net/mptcp/protocol.c ++++ b/net/mptcp/protocol.c +@@ -224,9 +224,6 @@ static bool mptcp_rcvbuf_grow(struct sock *sk, u32 newval) + do_div(grow, oldval); + rcvwin += grow << 1; + +- if (!RB_EMPTY_ROOT(&msk->out_of_order_queue)) +- rcvwin += MPTCP_SKB_CB(msk->ooo_last_skb)->end_seq - msk->ack_seq; +- + cap = READ_ONCE(net->ipv4.sysctl_tcp_rmem[2]); + + rcvbuf = min_t(u32, mptcp_space_from_win(sk, rcvwin), cap); +@@ -350,9 +347,6 @@ static void mptcp_data_queue_ofo(struct mptcp_sock *msk, struct sk_buff *skb) + end: + skb_condense(skb); + skb_set_owner_r(skb, sk); +- /* do not grow rcvbuf for not-yet-accepted or orphaned sockets. */ +- if (sk->sk_socket) +- mptcp_rcvbuf_grow(sk, msk->rcvq_space.space); + } + + static void mptcp_init_skb(struct sock *ssk, struct sk_buff *skb, int offset, +-- +2.51.0 + diff --git a/queue-6.19/mptcp-fix-receive-space-timestamp-initialization.patch b/queue-6.19/mptcp-fix-receive-space-timestamp-initialization.patch new file mode 100644 index 0000000000..c8cf71113e --- /dev/null +++ b/queue-6.19/mptcp-fix-receive-space-timestamp-initialization.patch @@ -0,0 +1,92 @@ +From 3192267ff97471b69594c3378e80f4e3d380db9c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 19:41:18 +0100 +Subject: mptcp: fix receive space timestamp initialization + +From: Paolo Abeni + +[ Upstream commit 70274765fef555af92a1532d5bd5450c691fca9d ] + +MPTCP initialize the receive buffer stamp in mptcp_rcv_space_init(), +using the provided subflow stamp. Such helper is invoked in several +places; for passive sockets, space init happened at clone time. + +In such scenario, MPTCP ends-up accesses the subflow stamp before +its initialization, leading to quite randomic timing for the first +receive buffer auto-tune event, as the timestamp for newly created +subflow is not refreshed there. + +Fix the issue moving the stamp initialization out of the mentioned helper, +at the data transfer start, and always using a fresh timestamp. + +Fixes: 013e3179dbd2 ("mptcp: fix rcv space initialization") +Reviewed-by: Mat Martineau +Signed-off-by: Paolo Abeni +Signed-off-by: Matthieu Baerts (NGI0) +Link: https://patch.msgid.link/20260203-net-next-mptcp-misc-feat-6-20-v1-2-31ec8bfc56d1@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/mptcp/protocol.c | 8 ++++---- + net/mptcp/protocol.h | 5 +++++ + 2 files changed, 9 insertions(+), 4 deletions(-) + +diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c +index cfa38bdaf2a92..bad9fc0f27d9c 100644 +--- a/net/mptcp/protocol.c ++++ b/net/mptcp/protocol.c +@@ -2082,8 +2082,8 @@ static void mptcp_rcv_space_adjust(struct mptcp_sock *msk, int copied) + + msk->rcvq_space.copied += copied; + +- mstamp = div_u64(tcp_clock_ns(), NSEC_PER_USEC); +- time = tcp_stamp_us_delta(mstamp, msk->rcvq_space.time); ++ mstamp = mptcp_stamp(); ++ time = tcp_stamp_us_delta(mstamp, READ_ONCE(msk->rcvq_space.time)); + + rtt_us = msk->rcvq_space.rtt_us; + if (rtt_us && time < (rtt_us >> 3)) +@@ -3543,6 +3543,7 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk, + __mptcp_propagate_sndbuf(nsk, ssk); + + mptcp_rcv_space_init(msk, ssk); ++ msk->rcvq_space.time = mptcp_stamp(); + + if (mp_opt->suboptions & OPTION_MPTCP_MPC_ACK) + __mptcp_subflow_fully_established(msk, subflow, mp_opt); +@@ -3560,8 +3561,6 @@ void mptcp_rcv_space_init(struct mptcp_sock *msk, const struct sock *ssk) + msk->rcvq_space.copied = 0; + msk->rcvq_space.rtt_us = 0; + +- msk->rcvq_space.time = tp->tcp_mstamp; +- + /* initial rcv_space offering made to peer */ + msk->rcvq_space.space = min_t(u32, tp->rcv_wnd, + TCP_INIT_CWND * tp->advmss); +@@ -3757,6 +3756,7 @@ void mptcp_finish_connect(struct sock *ssk) + * accessing the field below + */ + WRITE_ONCE(msk->local_key, subflow->local_key); ++ WRITE_ONCE(msk->rcvq_space.time, mptcp_stamp()); + + mptcp_pm_new_connection(msk, ssk, 0); + } +diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h +index 66e9735007912..39afd44e072f2 100644 +--- a/net/mptcp/protocol.h ++++ b/net/mptcp/protocol.h +@@ -915,6 +915,11 @@ static inline bool mptcp_is_fully_established(struct sock *sk) + READ_ONCE(mptcp_sk(sk)->fully_established); + } + ++static inline u64 mptcp_stamp(void) ++{ ++ return div_u64(tcp_clock_ns(), NSEC_PER_USEC); ++} ++ + void mptcp_rcv_space_init(struct mptcp_sock *msk, const struct sock *ssk); + void mptcp_data_ready(struct sock *sk, struct sock *ssk); + bool mptcp_finish_join(struct sock *sk); +-- +2.51.0 + diff --git a/queue-6.19/mtd-intel-dg-fix-accessing-regions-before-setting-nr.patch b/queue-6.19/mtd-intel-dg-fix-accessing-regions-before-setting-nr.patch new file mode 100644 index 0000000000..f1feffe1d0 --- /dev/null +++ b/queue-6.19/mtd-intel-dg-fix-accessing-regions-before-setting-nr.patch @@ -0,0 +1,66 @@ +From 350df8f7c9d2bafe3489206ca8a9f912819cbbd1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 07:22:37 +0200 +Subject: mtd: intel-dg: Fix accessing regions before setting nregions + +From: Alexander Usyskin + +[ Upstream commit 779c59274d03cc5c07237a2c845dfb71cff77705 ] + +The regions array is counted by nregions, but it's set only after +accessing it: + +[] UBSAN: array-index-out-of-bounds in drivers/mtd/devices/mtd_intel_dg.c:750:15 +[] index 0 is out of range for type ' [*]' + +Fix it by also fixing an undesired behavior: the loop silently ignores +ENOMEM and continues setting the other entries. + +CC: Gustavo A. R. Silva +CC: Raag Jadav +Reported-by: Jani Partanen +Closes: https://lore.kernel.org/all/caca6c67-4f1d-49f1-948f-e63b6b937b29@sotapeli.fi +Fixes: ceb5ab3cb646 ("mtd: add driver for intel graphics non-volatile memory device") +Signed-off-by: Lucas De Marchi +Signed-off-by: Alexander Usyskin +Reviewed-by: Raag Jadav +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/devices/mtd_intel_dg.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/drivers/mtd/devices/mtd_intel_dg.c b/drivers/mtd/devices/mtd_intel_dg.c +index 2bab30dcd35fd..7f751c48a76d4 100644 +--- a/drivers/mtd/devices/mtd_intel_dg.c ++++ b/drivers/mtd/devices/mtd_intel_dg.c +@@ -770,6 +770,7 @@ static int intel_dg_mtd_probe(struct auxiliary_device *aux_dev, + + kref_init(&nvm->refcnt); + mutex_init(&nvm->lock); ++ nvm->nregions = nregions; + + for (n = 0, i = 0; i < INTEL_DG_NVM_REGIONS; i++) { + if (!invm->regions[i].name) +@@ -777,13 +778,15 @@ static int intel_dg_mtd_probe(struct auxiliary_device *aux_dev, + + char *name = kasprintf(GFP_KERNEL, "%s.%s", + dev_name(&aux_dev->dev), invm->regions[i].name); +- if (!name) +- continue; ++ if (!name) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ + nvm->regions[n].name = name; + nvm->regions[n].id = i; + n++; + } +- nvm->nregions = n; /* in case where kasprintf fail */ + + ret = devm_pm_runtime_enable(device); + if (ret < 0) { +-- +2.51.0 + diff --git a/queue-6.19/mtd-parsers-fix-memory-leak-in-mtd_parser_tplink_saf.patch b/queue-6.19/mtd-parsers-fix-memory-leak-in-mtd_parser_tplink_saf.patch new file mode 100644 index 0000000000..e16779db81 --- /dev/null +++ b/queue-6.19/mtd-parsers-fix-memory-leak-in-mtd_parser_tplink_saf.patch @@ -0,0 +1,42 @@ +From c15869709a7550beded84c76ee1e40f6ccb3da5d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 13:09:50 +0000 +Subject: mtd: parsers: Fix memory leak in mtd_parser_tplink_safeloader_parse() + +From: Zilin Guan + +[ Upstream commit 980ce2b02dd06a4fdf5fee38b2e14becf9cf7b8b ] + +The function mtd_parser_tplink_safeloader_parse() allocates buf via +mtd_parser_tplink_safeloader_read_table(). If the allocation for +parts[idx].name fails inside the loop, the code jumps to the err_free +label without freeing buf, leading to a memory leak. + +Fix this by freeing the temporary buffer buf in the err_free label. + +Compile tested only. Issue found using a prototype static analysis tool +and code review. + +Fixes: 00a3588084be ("mtd: parsers: add TP-Link SafeLoader partitions table parser") +Signed-off-by: Zilin Guan +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/parsers/tplink_safeloader.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/mtd/parsers/tplink_safeloader.c b/drivers/mtd/parsers/tplink_safeloader.c +index e358a029dc70c..4fcaf92d22e4f 100644 +--- a/drivers/mtd/parsers/tplink_safeloader.c ++++ b/drivers/mtd/parsers/tplink_safeloader.c +@@ -116,6 +116,7 @@ static int mtd_parser_tplink_safeloader_parse(struct mtd_info *mtd, + return idx; + + err_free: ++ kfree(buf); + for (idx -= 1; idx >= 0; idx--) + kfree(parts[idx].name); + err_free_parts: +-- +2.51.0 + diff --git a/queue-6.19/mtd-parsers-ofpart-fix-of-node-refcount-leak-in-pars.patch b/queue-6.19/mtd-parsers-ofpart-fix-of-node-refcount-leak-in-pars.patch new file mode 100644 index 0000000000..66201ba34d --- /dev/null +++ b/queue-6.19/mtd-parsers-ofpart-fix-of-node-refcount-leak-in-pars.patch @@ -0,0 +1,84 @@ +From 7a90e67a236320ca58597cd40f185ab334263090 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 05:26:08 +0000 +Subject: mtd: parsers: ofpart: fix OF node refcount leak in + parse_fixed_partitions() + +From: Weigang He + +[ Upstream commit 7cce81df7d26d44123bd7620715c8349d96793d7 ] + +of_get_child_by_name() returns a node pointer with refcount incremented, +which must be released with of_node_put() when done. However, in +parse_fixed_partitions(), when dedicated is true (i.e., a "partitions" +subnode was found), the ofpart_node obtained from of_get_child_by_name() +is never released on any code path. + +Add of_node_put(ofpart_node) calls on all exit paths when dedicated is +true to fix the reference count leak. + +This bug was detected by our static analysis tool. + +Fixes: 562b4e91d3b2 ("mtd: parsers: ofpart: fix parsing subpartitions") +Signed-off-by: Weigang He +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/parsers/ofpart_core.c | 16 ++++++++++++++-- + 1 file changed, 14 insertions(+), 2 deletions(-) + +diff --git a/drivers/mtd/parsers/ofpart_core.c b/drivers/mtd/parsers/ofpart_core.c +index abfa687989182..09961c6f39496 100644 +--- a/drivers/mtd/parsers/ofpart_core.c ++++ b/drivers/mtd/parsers/ofpart_core.c +@@ -77,6 +77,7 @@ static int parse_fixed_partitions(struct mtd_info *master, + of_id = of_match_node(parse_ofpart_match_table, ofpart_node); + if (dedicated && !of_id) { + /* The 'partitions' subnode might be used by another parser */ ++ of_node_put(ofpart_node); + return 0; + } + +@@ -91,12 +92,18 @@ static int parse_fixed_partitions(struct mtd_info *master, + nr_parts++; + } + +- if (nr_parts == 0) ++ if (nr_parts == 0) { ++ if (dedicated) ++ of_node_put(ofpart_node); + return 0; ++ } + + parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL); +- if (!parts) ++ if (!parts) { ++ if (dedicated) ++ of_node_put(ofpart_node); + return -ENOMEM; ++ } + + i = 0; + for_each_child_of_node(ofpart_node, pp) { +@@ -175,6 +182,9 @@ static int parse_fixed_partitions(struct mtd_info *master, + if (quirks && quirks->post_parse) + quirks->post_parse(master, parts, nr_parts); + ++ if (dedicated) ++ of_node_put(ofpart_node); ++ + *pparts = parts; + return nr_parts; + +@@ -183,6 +193,8 @@ static int parse_fixed_partitions(struct mtd_info *master, + master->name, pp, mtd_node); + ret = -EINVAL; + ofpart_none: ++ if (dedicated) ++ of_node_put(ofpart_node); + of_node_put(pp); + kfree(parts); + return ret; +-- +2.51.0 + diff --git a/queue-6.19/mtd-rawnand-cadence-fix-return-type-of-cdma-send-and.patch b/queue-6.19/mtd-rawnand-cadence-fix-return-type-of-cdma-send-and.patch new file mode 100644 index 0000000000..cbfb9606f4 --- /dev/null +++ b/queue-6.19/mtd-rawnand-cadence-fix-return-type-of-cdma-send-and.patch @@ -0,0 +1,40 @@ +From 58b2aa3a08856000e770416b88f28ae3400ed753 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 19 Dec 2025 03:09:30 -0800 +Subject: mtd: rawnand: cadence: Fix return type of CDMA send-and-wait helper + +From: Alok Tiwari + +[ Upstream commit 6d8226cbbf124bb5613b532216b74c886a4361b7 ] + +cadence_nand_cdma_send_and_wait() propagates negative errno values +from cadence_nand_cdma_send(), returns -ETIMEDOUT on failure and -EIO +when the CDMA engine reports a command failure. + +However, it is declared as u32, causing error codes to wrap. +Change the return type to int to correctly propagate errors. + +Fixes: ec4ba01e894d ("mtd: rawnand: Add new Cadence NAND driver to MTD subsystem") +Signed-off-by: Alok Tiwari +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/nand/raw/cadence-nand-controller.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/nand/raw/cadence-nand-controller.c b/drivers/mtd/nand/raw/cadence-nand-controller.c +index 5f037753f78c8..99135ec230105 100644 +--- a/drivers/mtd/nand/raw/cadence-nand-controller.c ++++ b/drivers/mtd/nand/raw/cadence-nand-controller.c +@@ -1066,7 +1066,7 @@ static int cadence_nand_cdma_send(struct cdns_nand_ctrl *cdns_ctrl, + } + + /* Send SDMA command and wait for finish. */ +-static u32 ++static int + cadence_nand_cdma_send_and_wait(struct cdns_nand_ctrl *cdns_ctrl, + u8 thread) + { +-- +2.51.0 + diff --git a/queue-6.19/mtd-spinand-fix-kernel-doc.patch b/queue-6.19/mtd-spinand-fix-kernel-doc.patch new file mode 100644 index 0000000000..a383f8f417 --- /dev/null +++ b/queue-6.19/mtd-spinand-fix-kernel-doc.patch @@ -0,0 +1,36 @@ +From e7427c38f94eb8ddfd9d6b26219ea071e88d7a67 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 18:18:02 +0100 +Subject: mtd: spinand: Fix kernel doc + +From: Miquel Raynal + +[ Upstream commit a57b1f07d2d35843a7ada30c8cf9a215c0931868 ] + +The @data buffer is 5 bytes, not 4, it has been extended for the need of +devices with an extra ID bytes. + +Fixes: 34a956739d29 ("mtd: spinand: Add support for 5-byte IDs") +Reviewed-by: Tudor Ambarus +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + include/linux/mtd/spinand.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h +index ce76f5c632e17..049d55c38d522 100644 +--- a/include/linux/mtd/spinand.h ++++ b/include/linux/mtd/spinand.h +@@ -287,7 +287,7 @@ struct spinand_device; + + /** + * struct spinand_id - SPI NAND id structure +- * @data: buffer containing the id bytes. Currently 4 bytes large, but can ++ * @data: buffer containing the id bytes. Currently 5 bytes large, but can + * be extended if required + * @len: ID length + */ +-- +2.51.0 + diff --git a/queue-6.19/net-atm-fix-crash-due-to-unvalidated-vcc-pointer-in-.patch b/queue-6.19/net-atm-fix-crash-due-to-unvalidated-vcc-pointer-in-.patch new file mode 100644 index 0000000000..5466272f03 --- /dev/null +++ b/queue-6.19/net-atm-fix-crash-due-to-unvalidated-vcc-pointer-in-.patch @@ -0,0 +1,154 @@ +From a0f58d6bb264e79cb505f48ddc8c144f61f872eb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 17:54:51 +0800 +Subject: net: atm: fix crash due to unvalidated vcc pointer in sigd_send() + +From: Jiayuan Chen + +[ Upstream commit ae88a5d2f29b69819dc7b04086734439d074a643 ] + +Reproducer available at [1]. + +The ATM send path (sendmsg -> vcc_sendmsg -> sigd_send) reads the vcc +pointer from msg->vcc and uses it directly without any validation. This +pointer comes from userspace via sendmsg() and can be arbitrarily forged: + + int fd = socket(AF_ATMSVC, SOCK_DGRAM, 0); + ioctl(fd, ATMSIGD_CTRL); // become ATM signaling daemon + struct msghdr msg = { .msg_iov = &iov, ... }; + *(unsigned long *)(buf + 4) = 0xdeadbeef; // fake vcc pointer + sendmsg(fd, &msg, 0); // kernel dereferences 0xdeadbeef + +In normal operation, the kernel sends the vcc pointer to the signaling +daemon via sigd_enq() when processing operations like connect(), bind(), +or listen(). The daemon is expected to return the same pointer when +responding. However, a malicious daemon can send arbitrary pointer values. + +Fix this by introducing find_get_vcc() which validates the pointer by +searching through vcc_hash (similar to how sigd_close() iterates over +all VCCs), and acquires a reference via sock_hold() if found. + +Since struct atm_vcc embeds struct sock as its first member, they share +the same lifetime. Therefore using sock_hold/sock_put is sufficient to +keep the vcc alive while it is being used. + +Note that there may be a race with sigd_close() which could mark the vcc +with various flags (e.g., ATM_VF_RELEASED) after find_get_vcc() returns. +However, sock_hold() guarantees the memory remains valid, so this race +only affects the logical state, not memory safety. + +[1]: https://gist.github.com/mrpre/1ba5949c45529c511152e2f4c755b0f3 +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: syzbot+1f22cb1769f249df9fa0@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/69039850.a70a0220.5b2ed.005d.GAE@google.com/T/ +Signed-off-by: Jiayuan Chen +Link: https://patch.msgid.link/20260205095501.131890-1-jiayuan.chen@linux.dev +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/atm/signaling.c | 56 +++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 54 insertions(+), 2 deletions(-) + +diff --git a/net/atm/signaling.c b/net/atm/signaling.c +index e70ae2c113f95..358fbe5e4d1d0 100644 +--- a/net/atm/signaling.c ++++ b/net/atm/signaling.c +@@ -22,6 +22,36 @@ + + struct atm_vcc *sigd = NULL; + ++/* ++ * find_get_vcc - validate and get a reference to a vcc pointer ++ * @vcc: the vcc pointer to validate ++ * ++ * This function validates that @vcc points to a registered VCC in vcc_hash. ++ * If found, it increments the socket reference count and returns the vcc. ++ * The caller must call sock_put(sk_atm(vcc)) when done. ++ * ++ * Returns the vcc pointer if valid, NULL otherwise. ++ */ ++static struct atm_vcc *find_get_vcc(struct atm_vcc *vcc) ++{ ++ int i; ++ ++ read_lock(&vcc_sklist_lock); ++ for (i = 0; i < VCC_HTABLE_SIZE; i++) { ++ struct sock *s; ++ ++ sk_for_each(s, &vcc_hash[i]) { ++ if (atm_sk(s) == vcc) { ++ sock_hold(s); ++ read_unlock(&vcc_sklist_lock); ++ return vcc; ++ } ++ } ++ } ++ read_unlock(&vcc_sklist_lock); ++ return NULL; ++} ++ + static void sigd_put_skb(struct sk_buff *skb) + { + if (!sigd) { +@@ -69,7 +99,14 @@ static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb) + + msg = (struct atmsvc_msg *) skb->data; + WARN_ON(refcount_sub_and_test(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc)); +- vcc = *(struct atm_vcc **) &msg->vcc; ++ ++ vcc = find_get_vcc(*(struct atm_vcc **)&msg->vcc); ++ if (!vcc) { ++ pr_debug("invalid vcc pointer in msg\n"); ++ dev_kfree_skb(skb); ++ return -EINVAL; ++ } ++ + pr_debug("%d (0x%lx)\n", (int)msg->type, (unsigned long)vcc); + sk = sk_atm(vcc); + +@@ -100,7 +137,16 @@ static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb) + clear_bit(ATM_VF_WAITING, &vcc->flags); + break; + case as_indicate: +- vcc = *(struct atm_vcc **)&msg->listen_vcc; ++ /* Release the reference from msg->vcc, we'll use msg->listen_vcc instead */ ++ sock_put(sk); ++ ++ vcc = find_get_vcc(*(struct atm_vcc **)&msg->listen_vcc); ++ if (!vcc) { ++ pr_debug("invalid listen_vcc pointer in msg\n"); ++ dev_kfree_skb(skb); ++ return -EINVAL; ++ } ++ + sk = sk_atm(vcc); + pr_debug("as_indicate!!!\n"); + lock_sock(sk); +@@ -115,6 +161,8 @@ static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb) + sk->sk_state_change(sk); + as_indicate_complete: + release_sock(sk); ++ /* Paired with find_get_vcc(msg->listen_vcc) above */ ++ sock_put(sk); + return 0; + case as_close: + set_bit(ATM_VF_RELEASED, &vcc->flags); +@@ -131,11 +179,15 @@ static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb) + break; + default: + pr_alert("bad message type %d\n", (int)msg->type); ++ /* Paired with find_get_vcc(msg->vcc) above */ ++ sock_put(sk); + return -EINVAL; + } + sk->sk_state_change(sk); + out: + dev_kfree_skb(skb); ++ /* Paired with find_get_vcc(msg->vcc) above */ ++ sock_put(sk); + return 0; + } + +-- +2.51.0 + diff --git a/queue-6.19/net-hns3-fix-double-free-issue-for-tx-spare-buffer.patch b/queue-6.19/net-hns3-fix-double-free-issue-for-tx-spare-buffer.patch new file mode 100644 index 0000000000..4502711c5a --- /dev/null +++ b/queue-6.19/net-hns3-fix-double-free-issue-for-tx-spare-buffer.patch @@ -0,0 +1,74 @@ +From ef48faa412e10c9905bd3fd5dd6ca2dbe15f8d5a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 20:17:19 +0800 +Subject: net: hns3: fix double free issue for tx spare buffer + +From: Jian Shen + +[ Upstream commit 6d2f142b1e4b203387a92519d9d2e34752a79dbb ] + +In hns3_set_ringparam(), a temporary copy (tmp_rings) of the ring structure +is created for rollback. However, the tx_spare pointer in the original +ring handle is incorrectly left pointing to the old backup memory. + +Later, if memory allocation fails in hns3_init_all_ring() during the setup, +the error path attempts to free all newly allocated rings. Since tx_spare +contains a stale (non-NULL) pointer from the backup, it is mistaken for +a newly allocated buffer and is erroneously freed, leading to a double-free +of the backup memory. + +The root cause is that the tx_spare field was not cleared after its value +was saved in tmp_rings, leaving a dangling pointer. + +Fix this by setting tx_spare to NULL in the original ring structure +when the creation of the new `tx_spare` fails. This ensures the +error cleanup path only frees genuinely newly allocated buffers. + +Fixes: 907676b130711 ("net: hns3: use tx bounce buffer for small packets") +Signed-off-by: Jian Shen +Signed-off-by: Jijie Shao +Reviewed-by: Jacob Keller +Link: https://patch.msgid.link/20260205121719.3285730-1-shaojijie@huawei.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +index 7a9573dcab741..e879b04e21b0c 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +@@ -1048,13 +1048,13 @@ static void hns3_init_tx_spare_buffer(struct hns3_enet_ring *ring) + int order; + + if (!alloc_size) +- return; ++ goto not_init; + + order = get_order(alloc_size); + if (order > MAX_PAGE_ORDER) { + if (net_ratelimit()) + dev_warn(ring_to_dev(ring), "failed to allocate tx spare buffer, exceed to max order\n"); +- return; ++ goto not_init; + } + + tx_spare = devm_kzalloc(ring_to_dev(ring), sizeof(*tx_spare), +@@ -1092,6 +1092,13 @@ static void hns3_init_tx_spare_buffer(struct hns3_enet_ring *ring) + devm_kfree(ring_to_dev(ring), tx_spare); + devm_kzalloc_error: + ring->tqp->handle->kinfo.tx_spare_buf_size = 0; ++not_init: ++ /* When driver init or reset_init, the ring->tx_spare is always NULL; ++ * but when called from hns3_set_ringparam, it's usually not NULL, and ++ * will be restored if hns3_init_all_ring() failed. So it's safe to set ++ * ring->tx_spare to NULL here. ++ */ ++ ring->tx_spare = NULL; + } + + /* Use hns3_tx_spare_space() to make sure there is enough buffer +-- +2.51.0 + diff --git a/queue-6.19/net-mctp-i2c-fix-duplicate-reception-of-old-data.patch b/queue-6.19/net-mctp-i2c-fix-duplicate-reception-of-old-data.patch new file mode 100644 index 0000000000..e514a8f613 --- /dev/null +++ b/queue-6.19/net-mctp-i2c-fix-duplicate-reception-of-old-data.patch @@ -0,0 +1,49 @@ +From 544dc69a8ab90310036874b9a9e75e12c3672f30 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 18:18:29 +0800 +Subject: net: mctp-i2c: fix duplicate reception of old data + +From: Jian Zhang + +[ Upstream commit ae4744e173fadd092c43eda4ca92dcb74645225a ] + +The MCTP I2C slave callback did not handle I2C_SLAVE_READ_REQUESTED +events. As a result, i2c read event will trigger repeated reception of +old data, reset rx_pos when a read request is received. + +Signed-off-by: Jian Zhang +Link: https://patch.msgid.link/20260108101829.1140448-1-zhangjian.3032@bytedance.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 2a14e91b6d76 ("mctp i2c: initialise event handler read bytes") +Signed-off-by: Sasha Levin +--- + drivers/net/mctp/mctp-i2c.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/mctp/mctp-i2c.c b/drivers/net/mctp/mctp-i2c.c +index f782d93f826ef..ecda1cc36391c 100644 +--- a/drivers/net/mctp/mctp-i2c.c ++++ b/drivers/net/mctp/mctp-i2c.c +@@ -242,6 +242,9 @@ static int mctp_i2c_slave_cb(struct i2c_client *client, + return 0; + + switch (event) { ++ case I2C_SLAVE_READ_REQUESTED: ++ midev->rx_pos = 0; ++ break; + case I2C_SLAVE_WRITE_RECEIVED: + if (midev->rx_pos < MCTP_I2C_BUFSZ) { + midev->rx_buffer[midev->rx_pos] = *val; +@@ -279,6 +282,9 @@ static int mctp_i2c_recv(struct mctp_i2c_dev *midev) + size_t recvlen; + int status; + ++ if (midev->rx_pos == 0) ++ return 0; ++ + /* + 1 for the PEC */ + if (midev->rx_pos < MCTP_I2C_MINLEN + 1) { + ndev->stats.rx_length_errors++; +-- +2.51.0 + diff --git a/queue-6.19/net-renesas-rswitch-fix-forwarding-offload-statemach.patch b/queue-6.19/net-renesas-rswitch-fix-forwarding-offload-statemach.patch new file mode 100644 index 0000000000..8cbddd0284 --- /dev/null +++ b/queue-6.19/net-renesas-rswitch-fix-forwarding-offload-statemach.patch @@ -0,0 +1,73 @@ +From 65cb901f2f9de326f9e4ded50e70866bebf5bfe3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 14:41:53 +0100 +Subject: net: renesas: rswitch: fix forwarding offload statemachine + +From: Michael Dege + +[ Upstream commit e9a5073a98d940837cbb95e71eed1f28f48e7b30 ] + +A change of the port state of one port, caused the state of another +port to change. This behvior was unintended. + +Fixes: b7502b1043de ("net: renesas: rswitch: add offloading for L2 switching") +Signed-off-by: Michael Dege +Link: https://patch.msgid.link/20260206-fix-offloading-statemachine-v3-1-07bfba07d03e@renesas.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/renesas/rswitch_l2.c | 15 +++++++-------- + 1 file changed, 7 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/ethernet/renesas/rswitch_l2.c b/drivers/net/ethernet/renesas/rswitch_l2.c +index 4a69ec77d69c6..9433cd8adced9 100644 +--- a/drivers/net/ethernet/renesas/rswitch_l2.c ++++ b/drivers/net/ethernet/renesas/rswitch_l2.c +@@ -1,7 +1,7 @@ + // SPDX-License-Identifier: GPL-2.0 + /* Renesas Ethernet Switch device driver + * +- * Copyright (C) 2025 Renesas Electronics Corporation ++ * Copyright (C) 2025 - 2026 Renesas Electronics Corporation + */ + + #include +@@ -60,6 +60,7 @@ static void rswitch_update_l2_hw_learning(struct rswitch_private *priv) + static void rswitch_update_l2_hw_forwarding(struct rswitch_private *priv) + { + struct rswitch_device *rdev; ++ bool new_forwarding_offload; + unsigned int fwd_mask; + + /* calculate fwd_mask with zeroes in bits corresponding to ports that +@@ -73,8 +74,9 @@ static void rswitch_update_l2_hw_forwarding(struct rswitch_private *priv) + } + + rswitch_for_all_ports(priv, rdev) { +- if ((rdev_for_l2_offload(rdev) && rdev->forwarding_requested) || +- rdev->forwarding_offloaded) { ++ new_forwarding_offload = (rdev_for_l2_offload(rdev) && rdev->forwarding_requested); ++ ++ if (new_forwarding_offload || rdev->forwarding_offloaded) { + /* Update allowed offload destinations even for ports + * with L2 offload enabled earlier. + * +@@ -84,13 +86,10 @@ static void rswitch_update_l2_hw_forwarding(struct rswitch_private *priv) + priv->addr + FWPC2(rdev->port)); + } + +- if (rdev_for_l2_offload(rdev) && +- rdev->forwarding_requested && +- !rdev->forwarding_offloaded) { ++ if (new_forwarding_offload && !rdev->forwarding_offloaded) + rswitch_change_l2_hw_offloading(rdev, true, false); +- } else if (rdev->forwarding_offloaded) { ++ else if (!new_forwarding_offload && rdev->forwarding_offloaded) + rswitch_change_l2_hw_offloading(rdev, false, false); +- } + } + } + +-- +2.51.0 + diff --git a/queue-6.19/net-sunhme-fix-sbus-regression.patch b/queue-6.19/net-sunhme-fix-sbus-regression.patch new file mode 100644 index 0000000000..68fb3a9843 --- /dev/null +++ b/queue-6.19/net-sunhme-fix-sbus-regression.patch @@ -0,0 +1,73 @@ +From 15d01f751dd71106cbf94c494d9c22f175e2e1e6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 17:09:59 +0100 +Subject: net: sunhme: Fix sbus regression +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: René Rebe + +[ Upstream commit 8c5d17834ec104d0abd1bda52fbc04e647fab274 ] + +Commit cc216e4b44ce ("net: sunhme: Switch SBUS to devres") changed +explicit sized of_ioremap with BMAC_REG_SIZEs to +devm_platform_ioremap_resource mapping all the resource. However, +this does not work on my Sun Ultra 2 with SBUS HMEs: + +hme f0072f38: error -EBUSY: can't request region for resource [mem 0x1ffe8c07000-0x1ffe8c0701f] +hme f0072f38: Cannot map TCVR registers. +hme f0072f38: probe with driver hme failed with error -16 +hme f007ab44: error -EBUSY: can't request region for resource [mem 0x1ff28c07000-0x1ff28c0701f] +hme f007ab44: Cannot map TCVR registers. +hme f007ab44: probe with driver hme failed with error -16 + +Turns out the open-firmware resources overlap, at least on this +machines and PROM version: + +hexdump /proc/device-tree/sbus@1f,0/SUNW,hme@2,8c00000/reg: +00 00 00 02 08 c0 00 00 00 00 01 08 +00 00 00 02 08 c0 20 00 00 00 20 00 +00 00 00 02 08 c0 40 00 00 00 20 00 +00 00 00 02 08 c0 60 00 00 00 20 00 +00 00 00 02 08 c0 70 00 00 00 00 20 + +And the driver previously explicitly mapped way smaller mmio regions: + +/proc/iomem: +1ff28c00000-1ff28c00107 : HME Global Regs +1ff28c02000-1ff28c02033 : HME TX Regs +1ff28c04000-1ff28c0401f : HME RX Regs +1ff28c06000-1ff28c0635f : HME BIGMAC Regs +1ff28c07000-1ff28c0701f : HME Tranceiver Regs + +Quirk this specific issue by truncating the previous resource to not +overlap into the TCVR registers. + +Fixes: cc216e4b44ce ("net: sunhme: Switch SBUS to devres") +Signed-off-by: René Rebe +Reviewed-by: Sean Anderson +Link: https://patch.msgid.link/20260205.170959.89574674688839340.rene@exactco.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/sun/sunhme.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/ethernet/sun/sunhme.c b/drivers/net/ethernet/sun/sunhme.c +index 48f0a96c0e9e3..6669980829980 100644 +--- a/drivers/net/ethernet/sun/sunhme.c ++++ b/drivers/net/ethernet/sun/sunhme.c +@@ -2551,6 +2551,9 @@ static int happy_meal_sbus_probe_one(struct platform_device *op, int is_qfe) + goto err_out_clear_quattro; + } + ++ /* BIGMAC may have bogus sizes */ ++ if ((op->resource[3].end - op->resource[3].start) >= BMAC_REG_SIZE) ++ op->resource[3].end = op->resource[3].start + BMAC_REG_SIZE - 1; + hp->bigmacregs = devm_platform_ioremap_resource(op, 3); + if (IS_ERR(hp->bigmacregs)) { + dev_err(&op->dev, "Cannot map BIGMAC registers.\n"); +-- +2.51.0 + diff --git a/queue-6.19/netfilter-nf_conncount-fix-tracking-of-connections-f.patch b/queue-6.19/netfilter-nf_conncount-fix-tracking-of-connections-f.patch new file mode 100644 index 0000000000..bafab35187 --- /dev/null +++ b/queue-6.19/netfilter-nf_conncount-fix-tracking-of-connections-f.patch @@ -0,0 +1,69 @@ +From 304765e00cb452ac4c22cbafe9acea183df72740 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 21:35:46 +0100 +Subject: netfilter: nf_conncount: fix tracking of connections from localhost + +From: Fernando Fernandez Mancera + +[ Upstream commit de8a70cefcb26cdceaafdc5ac144712681419c29 ] + +Since commit be102eb6a0e7 ("netfilter: nf_conncount: rework API to use +sk_buff directly"), we skip the adding and trigger a GC when the ct is +confirmed. For connections originated from local to local it doesn't +work because the connection is confirmed on POSTROUTING, therefore +tracking on the INPUT hook is always skipped. + +In order to fix this, we check whether skb input ifindex is set to +loopback ifindex. If it is then we fallback on a GC plus track operation +skipping the optimization. This fallback is necessary to avoid +duplicated tracking of a packet train e.g 10 UDP datagrams sent on a +burst when initiating the connection. + +Tested with xt_connlimit/nft_connlimit and OVS limit and with a HTTP +server and iperf3 on UDP mode. + +Fixes: be102eb6a0e7 ("netfilter: nf_conncount: rework API to use sk_buff directly") +Reported-by: Michal Slabihoudek +Closes: https://lore.kernel.org/netfilter/6989BD9F-8C24-4397-9AD7-4613B28BF0DB@gooddata.com/ +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_conncount.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +diff --git a/net/netfilter/nf_conncount.c b/net/netfilter/nf_conncount.c +index 288936f5c1bf9..14e62b3263cd9 100644 +--- a/net/netfilter/nf_conncount.c ++++ b/net/netfilter/nf_conncount.c +@@ -179,14 +179,25 @@ static int __nf_conncount_add(struct net *net, + return -ENOENT; + + if (ct && nf_ct_is_confirmed(ct)) { +- err = -EEXIST; +- goto out_put; ++ /* local connections are confirmed in postrouting so confirmation ++ * might have happened before hitting connlimit ++ */ ++ if (skb->skb_iif != LOOPBACK_IFINDEX) { ++ err = -EEXIST; ++ goto out_put; ++ } ++ ++ /* this is likely a local connection, skip optimization to avoid ++ * adding duplicates from a 'packet train' ++ */ ++ goto check_connections; + } + + if ((u32)jiffies == list->last_gc && + (list->count - list->last_gc_count) < CONNCOUNT_GC_MAX_COLLECT) + goto add_new_node; + ++check_connections: + /* check the saved connections */ + list_for_each_entry_safe(conn, conn_n, &list->head, node) { + if (collect > CONNCOUNT_GC_MAX_COLLECT) +-- +2.51.0 + diff --git a/queue-6.19/netfilter-nf_conncount-increase-the-connection-clean.patch b/queue-6.19/netfilter-nf_conncount-increase-the-connection-clean.patch new file mode 100644 index 0000000000..8dab89869f --- /dev/null +++ b/queue-6.19/netfilter-nf_conncount-increase-the-connection-clean.patch @@ -0,0 +1,123 @@ +From 4dc4cdc9852099333fb6443e4d660c33cb6c81f3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 17 Dec 2025 15:46:41 +0100 +Subject: netfilter: nf_conncount: increase the connection clean up limit to 64 + +From: Fernando Fernandez Mancera + +[ Upstream commit 21d033e472735ecec677f1ae46d6740b5e47a4f3 ] + +After the optimization to only perform one GC per jiffy, a new problem +was introduced. If more than 8 new connections are tracked per jiffy the +list won't be cleaned up fast enough possibly reaching the limit +wrongly. + +In order to prevent this issue, only skip the GC if it was already +triggered during the same jiffy and the increment is lower than the +clean up limit. In addition, increase the clean up limit to 64 +connections to avoid triggering GC too often and do more effective GCs. + +This has been tested using a HTTP server and several +performance tools while having nft_connlimit/xt_connlimit or OVS limit +configured. + +Output of slowhttptest + OVS limit at 52000 connections: + + slow HTTP test status on 340th second: + initializing: 0 + pending: 432 + connected: 51998 + error: 0 + closed: 0 + service available: YES + +Fixes: d265929930e2 ("netfilter: nf_conncount: reduce unnecessary GC") +Reported-by: Aleksandra Rukomoinikova +Closes: https://lore.kernel.org/netfilter/b2064e7b-0776-4e14-adb6-c68080987471@k2.cloud/ +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + include/net/netfilter/nf_conntrack_count.h | 1 + + net/netfilter/nf_conncount.c | 15 ++++++++++----- + 2 files changed, 11 insertions(+), 5 deletions(-) + +diff --git a/include/net/netfilter/nf_conntrack_count.h b/include/net/netfilter/nf_conntrack_count.h +index 52a06de41aa0f..cf0166520cf33 100644 +--- a/include/net/netfilter/nf_conntrack_count.h ++++ b/include/net/netfilter/nf_conntrack_count.h +@@ -13,6 +13,7 @@ struct nf_conncount_list { + u32 last_gc; /* jiffies at most recent gc */ + struct list_head head; /* connections with the same filtering key */ + unsigned int count; /* length of list */ ++ unsigned int last_gc_count; /* length of list at most recent gc */ + }; + + struct nf_conncount_data *nf_conncount_init(struct net *net, unsigned int keylen); +diff --git a/net/netfilter/nf_conncount.c b/net/netfilter/nf_conncount.c +index 8487808c87614..288936f5c1bf9 100644 +--- a/net/netfilter/nf_conncount.c ++++ b/net/netfilter/nf_conncount.c +@@ -34,8 +34,9 @@ + + #define CONNCOUNT_SLOTS 256U + +-#define CONNCOUNT_GC_MAX_NODES 8 +-#define MAX_KEYLEN 5 ++#define CONNCOUNT_GC_MAX_NODES 8 ++#define CONNCOUNT_GC_MAX_COLLECT 64 ++#define MAX_KEYLEN 5 + + /* we will save the tuples of all connections we care about */ + struct nf_conncount_tuple { +@@ -182,12 +183,13 @@ static int __nf_conncount_add(struct net *net, + goto out_put; + } + +- if ((u32)jiffies == list->last_gc) ++ if ((u32)jiffies == list->last_gc && ++ (list->count - list->last_gc_count) < CONNCOUNT_GC_MAX_COLLECT) + goto add_new_node; + + /* check the saved connections */ + list_for_each_entry_safe(conn, conn_n, &list->head, node) { +- if (collect > CONNCOUNT_GC_MAX_NODES) ++ if (collect > CONNCOUNT_GC_MAX_COLLECT) + break; + + found = find_or_evict(net, list, conn); +@@ -230,6 +232,7 @@ static int __nf_conncount_add(struct net *net, + nf_ct_put(found_ct); + } + list->last_gc = (u32)jiffies; ++ list->last_gc_count = list->count; + + add_new_node: + if (WARN_ON_ONCE(list->count > INT_MAX)) { +@@ -277,6 +280,7 @@ void nf_conncount_list_init(struct nf_conncount_list *list) + spin_lock_init(&list->list_lock); + INIT_LIST_HEAD(&list->head); + list->count = 0; ++ list->last_gc_count = 0; + list->last_gc = (u32)jiffies; + } + EXPORT_SYMBOL_GPL(nf_conncount_list_init); +@@ -316,13 +320,14 @@ static bool __nf_conncount_gc_list(struct net *net, + } + + nf_ct_put(found_ct); +- if (collected > CONNCOUNT_GC_MAX_NODES) ++ if (collected > CONNCOUNT_GC_MAX_COLLECT) + break; + } + + if (!list->count) + ret = true; + list->last_gc = (u32)jiffies; ++ list->last_gc_count = list->count; + + return ret; + } +-- +2.51.0 + diff --git a/queue-6.19/netfilter-nf_tables-reset-table-validation-state-on-.patch b/queue-6.19/netfilter-nf_tables-reset-table-validation-state-on-.patch new file mode 100644 index 0000000000..481ed870d3 --- /dev/null +++ b/queue-6.19/netfilter-nf_tables-reset-table-validation-state-on-.patch @@ -0,0 +1,59 @@ +From 3b57f1433bb2624d7c3cd6fc58b88f7627431567 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 12:26:54 +0100 +Subject: netfilter: nf_tables: reset table validation state on abort + +From: Florian Westphal + +[ Upstream commit 6f93616a7323d646d18db9c09f147e453b40fdd7 ] + +If a transaction fails the final validation in the commit hook, the table +validation state is changed to NFT_VALIDATE_DO and a replay of the batch is +performed. Every rule insert will then do a graph validation. + +This is much slower, but provides better error reporting to the user +because we can point at the rule that introduces the validation issue. + +Without this reset the affected table(s) remain in full validation mode, +i.e. on next transaction we start with slow-mode. + +This makes the next transaction after a failed incremental update very slow: + + # time iptables-restore < /tmp/ruleset + real 0m0.496s [..] + # time iptables -A CALLEE -j CALLER + iptables v1.8.11 (nf_tables): RULE_APPEND failed (Too many links): rule in chain CALLEE + real 0m0.022s [..] + # time iptables-restore < /tmp/ruleset + real 1m22.355s [..] + +After this patch, 2nd iptables-restore is back to ~0.5s. + +Fixes: 9a32e9850686 ("netfilter: nf_tables: don't write table validation state without mutex") +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_tables_api.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c +index be92750e2af3a..ec9e5e2a9f277 100644 +--- a/net/netfilter/nf_tables_api.c ++++ b/net/netfilter/nf_tables_api.c +@@ -11536,6 +11536,13 @@ static int nf_tables_abort(struct net *net, struct sk_buff *skb, + ret = __nf_tables_abort(net, action); + nft_gc_seq_end(nft_net, gc_seq); + ++ if (action == NFNL_ABORT_NONE) { ++ struct nft_table *table; ++ ++ list_for_each_entry(table, &nft_net->tables, list) ++ table->validate_state = NFT_VALIDATE_SKIP; ++ } ++ + WARN_ON_ONCE(!list_empty(&nft_net->commit_list)); + + /* module autoload needs to happen after GC sequence update because it +-- +2.51.0 + diff --git a/queue-6.19/netfilter-nfnetlink_queue-do-shared-unconfirmed-chec.patch b/queue-6.19/netfilter-nfnetlink_queue-do-shared-unconfirmed-chec.patch new file mode 100644 index 0000000000..6d1b0d46d1 --- /dev/null +++ b/queue-6.19/netfilter-nfnetlink_queue-do-shared-unconfirmed-chec.patch @@ -0,0 +1,246 @@ +From 286992675ebb497308fd141e31c1aa2d2e1cead8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 20 Nov 2025 17:17:06 +0100 +Subject: netfilter: nfnetlink_queue: do shared-unconfirmed check before + segmentation + +From: Florian Westphal + +[ Upstream commit 207b3ebacb6113acaaec0d171d5307032c690004 ] + +Ulrich reports a regression with nfqueue: + +If an application did not set the 'F_GSO' capability flag and a gso +packet with an unconfirmed nf_conn entry is received all packets are +now dropped instead of queued, because the check happens after +skb_gso_segment(). In that case, we did have exclusive ownership +of the skb and its associated conntrack entry. The elevated use +count is due to skb_clone happening via skb_gso_segment(). + +Move the check so that its peformed vs. the aggregated packet. + +Then, annotate the individual segments except the first one so we +can do a 2nd check at reinject time. + +For the normal case, where userspace does in-order reinjects, this avoids +packet drops: first reinjected segment continues traversal and confirms +entry, remaining segments observe the confirmed entry. + +While at it, simplify nf_ct_drop_unconfirmed(): We only care about +unconfirmed entries with a refcnt > 1, there is no need to special-case +dying entries. + +This only happens with UDP. With TCP, the only unconfirmed packet will +be the TCP SYN, those aren't aggregated by GRO. + +Next patch adds a udpgro test case to cover this scenario. + +Reported-by: Ulrich Weber +Fixes: 7d8dc1c7be8d ("netfilter: nf_queue: drop packets with cloned unconfirmed conntracks") +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + include/net/netfilter/nf_queue.h | 1 + + net/netfilter/nfnetlink_queue.c | 123 +++++++++++++++++++------------ + 2 files changed, 75 insertions(+), 49 deletions(-) + +diff --git a/include/net/netfilter/nf_queue.h b/include/net/netfilter/nf_queue.h +index e6803831d6af5..45eb26b2e95b3 100644 +--- a/include/net/netfilter/nf_queue.h ++++ b/include/net/netfilter/nf_queue.h +@@ -21,6 +21,7 @@ struct nf_queue_entry { + struct net_device *physout; + #endif + struct nf_hook_state state; ++ bool nf_ct_is_unconfirmed; + u16 size; /* sizeof(entry) + saved route keys */ + u16 queue_num; + +diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c +index 336e3ad18e72d..34548213f2f14 100644 +--- a/net/netfilter/nfnetlink_queue.c ++++ b/net/netfilter/nfnetlink_queue.c +@@ -438,6 +438,34 @@ static void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict) + nf_queue_entry_free(entry); + } + ++/* return true if the entry has an unconfirmed conntrack attached that isn't owned by us ++ * exclusively. ++ */ ++static bool nf_ct_drop_unconfirmed(const struct nf_queue_entry *entry, bool *is_unconfirmed) ++{ ++#if IS_ENABLED(CONFIG_NF_CONNTRACK) ++ struct nf_conn *ct = (void *)skb_nfct(entry->skb); ++ ++ if (!ct || nf_ct_is_confirmed(ct)) ++ return false; ++ ++ if (is_unconfirmed) ++ *is_unconfirmed = true; ++ ++ /* in some cases skb_clone() can occur after initial conntrack ++ * pickup, but conntrack assumes exclusive skb->_nfct ownership for ++ * unconfirmed entries. ++ * ++ * This happens for br_netfilter and with ip multicast routing. ++ * This can't be solved with serialization here because one clone ++ * could have been queued for local delivery or could be transmitted ++ * in parallel on another CPU. ++ */ ++ return refcount_read(&ct->ct_general.use) > 1; ++#endif ++ return false; ++} ++ + static void nfqnl_reinject(struct nf_queue_entry *entry, unsigned int verdict) + { + const struct nf_ct_hook *ct_hook; +@@ -465,6 +493,24 @@ static void nfqnl_reinject(struct nf_queue_entry *entry, unsigned int verdict) + break; + } + } ++ ++ if (verdict != NF_DROP && entry->nf_ct_is_unconfirmed) { ++ /* If first queued segment was already reinjected then ++ * there is a good chance the ct entry is now confirmed. ++ * ++ * Handle the rare cases: ++ * - out-of-order verdict ++ * - threaded userspace reinjecting in parallel ++ * - first segment was dropped ++ * ++ * In all of those cases we can't handle this packet ++ * because we can't be sure that another CPU won't modify ++ * nf_conn->ext in parallel which isn't allowed. ++ */ ++ if (nf_ct_drop_unconfirmed(entry, NULL)) ++ verdict = NF_DROP; ++ } ++ + nf_reinject(entry, verdict); + } + +@@ -894,49 +940,6 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue, + return NULL; + } + +-static bool nf_ct_drop_unconfirmed(const struct nf_queue_entry *entry) +-{ +-#if IS_ENABLED(CONFIG_NF_CONNTRACK) +- static const unsigned long flags = IPS_CONFIRMED | IPS_DYING; +- struct nf_conn *ct = (void *)skb_nfct(entry->skb); +- unsigned long status; +- unsigned int use; +- +- if (!ct) +- return false; +- +- status = READ_ONCE(ct->status); +- if ((status & flags) == IPS_DYING) +- return true; +- +- if (status & IPS_CONFIRMED) +- return false; +- +- /* in some cases skb_clone() can occur after initial conntrack +- * pickup, but conntrack assumes exclusive skb->_nfct ownership for +- * unconfirmed entries. +- * +- * This happens for br_netfilter and with ip multicast routing. +- * We can't be solved with serialization here because one clone could +- * have been queued for local delivery. +- */ +- use = refcount_read(&ct->ct_general.use); +- if (likely(use == 1)) +- return false; +- +- /* Can't decrement further? Exclusive ownership. */ +- if (!refcount_dec_not_one(&ct->ct_general.use)) +- return false; +- +- skb_set_nfct(entry->skb, 0); +- /* No nf_ct_put(): we already decremented .use and it cannot +- * drop down to 0. +- */ +- return true; +-#endif +- return false; +-} +- + static int + __nfqnl_enqueue_packet(struct net *net, struct nfqnl_instance *queue, + struct nf_queue_entry *entry) +@@ -953,9 +956,6 @@ __nfqnl_enqueue_packet(struct net *net, struct nfqnl_instance *queue, + } + spin_lock_bh(&queue->lock); + +- if (nf_ct_drop_unconfirmed(entry)) +- goto err_out_free_nskb; +- + if (queue->queue_total >= queue->queue_maxlen) + goto err_out_queue_drop; + +@@ -998,7 +998,6 @@ __nfqnl_enqueue_packet(struct net *net, struct nfqnl_instance *queue, + else + net_warn_ratelimited("nf_queue: hash insert failed: %d\n", err); + } +-err_out_free_nskb: + kfree_skb(nskb); + err_out_unlock: + spin_unlock_bh(&queue->lock); +@@ -1077,9 +1076,10 @@ __nfqnl_enqueue_packet_gso(struct net *net, struct nfqnl_instance *queue, + static int + nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) + { +- unsigned int queued; +- struct nfqnl_instance *queue; + struct sk_buff *skb, *segs, *nskb; ++ bool ct_is_unconfirmed = false; ++ struct nfqnl_instance *queue; ++ unsigned int queued; + int err = -ENOBUFS; + struct net *net = entry->state.net; + struct nfnl_queue_net *q = nfnl_queue_pernet(net); +@@ -1103,6 +1103,15 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) + break; + } + ++ /* Check if someone already holds another reference to ++ * unconfirmed ct. If so, we cannot queue the skb: ++ * concurrent modifications of nf_conn->ext are not ++ * allowed and we can't know if another CPU isn't ++ * processing the same nf_conn entry in parallel. ++ */ ++ if (nf_ct_drop_unconfirmed(entry, &ct_is_unconfirmed)) ++ return -EINVAL; ++ + if (!skb_is_gso(skb) || ((queue->flags & NFQA_CFG_F_GSO) && !skb_is_gso_sctp(skb))) + return __nfqnl_enqueue_packet(net, queue, entry); + +@@ -1116,7 +1125,23 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) + goto out_err; + queued = 0; + err = 0; ++ + skb_list_walk_safe(segs, segs, nskb) { ++ if (ct_is_unconfirmed && queued > 0) { ++ /* skb_gso_segment() increments the ct refcount. ++ * This is a problem for unconfirmed (not in hash) ++ * entries, those can race when reinjections happen ++ * in parallel. ++ * ++ * Annotate this for all queued entries except the ++ * first one. ++ * ++ * As long as the first one is reinjected first it ++ * will do the confirmation for us. ++ */ ++ entry->nf_ct_is_unconfirmed = ct_is_unconfirmed; ++ } ++ + if (err == 0) + err = __nfqnl_enqueue_packet_gso(net, queue, + segs, entry); +-- +2.51.0 + diff --git a/queue-6.19/netfilter-nfnetlink_queue-optimize-verdict-lookup-wi.patch b/queue-6.19/netfilter-nfnetlink_queue-optimize-verdict-lookup-wi.patch new file mode 100644 index 0000000000..00208c3535 --- /dev/null +++ b/queue-6.19/netfilter-nfnetlink_queue-optimize-verdict-lookup-wi.patch @@ -0,0 +1,318 @@ +From eb44c96881c507781fec75d568a93e9394539840 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 14:09:30 -0800 +Subject: netfilter: nfnetlink_queue: optimize verdict lookup with hash table + +From: Scott Mitchell + +[ Upstream commit e19079adcd26a25d7d3e586b1837493361fdf8b6 ] + +The current implementation uses a linear list to find queued packets by +ID when processing verdicts from userspace. With large queue depths and +out-of-order verdicting, this O(n) lookup becomes a significant +bottleneck, causing userspace verdict processing to dominate CPU time. + +Replace the linear search with a hash table for O(1) average-case +packet lookup by ID. A global rhashtable spanning all network +namespaces attributes hash bucket memory to kernel but is subject to +fixed upper bound. + +Signed-off-by: Scott Mitchell +Signed-off-by: Florian Westphal +Stable-dep-of: 207b3ebacb61 ("netfilter: nfnetlink_queue: do shared-unconfirmed check before segmentation") +Signed-off-by: Sasha Levin +--- + include/net/netfilter/nf_queue.h | 3 + + net/netfilter/nfnetlink_queue.c | 146 ++++++++++++++++++++++++------- + 2 files changed, 119 insertions(+), 30 deletions(-) + +diff --git a/include/net/netfilter/nf_queue.h b/include/net/netfilter/nf_queue.h +index 4aeffddb75861..e6803831d6af5 100644 +--- a/include/net/netfilter/nf_queue.h ++++ b/include/net/netfilter/nf_queue.h +@@ -6,11 +6,13 @@ + #include + #include + #include ++#include + #include + + /* Each queued (to userspace) skbuff has one of these. */ + struct nf_queue_entry { + struct list_head list; ++ struct rhash_head hash_node; + struct sk_buff *skb; + unsigned int id; + unsigned int hook_index; /* index in hook_entries->hook[] */ +@@ -20,6 +22,7 @@ struct nf_queue_entry { + #endif + struct nf_hook_state state; + u16 size; /* sizeof(entry) + saved route keys */ ++ u16 queue_num; + + /* extra space to store route keys */ + }; +diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c +index 8b7b39d8a1091..336e3ad18e72d 100644 +--- a/net/netfilter/nfnetlink_queue.c ++++ b/net/netfilter/nfnetlink_queue.c +@@ -30,6 +30,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -47,6 +49,8 @@ + #endif + + #define NFQNL_QMAX_DEFAULT 1024 ++#define NFQNL_HASH_MIN 1024 ++#define NFQNL_HASH_MAX 1048576 + + /* We're using struct nlattr which has 16bit nla_len. Note that nla_len + * includes the header length. Thus, the maximum packet length that we +@@ -56,6 +60,26 @@ + */ + #define NFQNL_MAX_COPY_RANGE (0xffff - NLA_HDRLEN) + ++/* Composite key for packet lookup: (net, queue_num, packet_id) */ ++struct nfqnl_packet_key { ++ possible_net_t net; ++ u32 packet_id; ++ u16 queue_num; ++} __aligned(sizeof(u32)); /* jhash2 requires 32-bit alignment */ ++ ++/* Global rhashtable - one for entire system, all netns */ ++static struct rhashtable nfqnl_packet_map __read_mostly; ++ ++/* Helper to initialize composite key */ ++static inline void nfqnl_init_key(struct nfqnl_packet_key *key, ++ struct net *net, u32 packet_id, u16 queue_num) ++{ ++ memset(key, 0, sizeof(*key)); ++ write_pnet(&key->net, net); ++ key->packet_id = packet_id; ++ key->queue_num = queue_num; ++} ++ + struct nfqnl_instance { + struct hlist_node hlist; /* global list of queues */ + struct rcu_head rcu; +@@ -100,6 +124,39 @@ static inline u_int8_t instance_hashfn(u_int16_t queue_num) + return ((queue_num >> 8) ^ queue_num) % INSTANCE_BUCKETS; + } + ++/* Extract composite key from nf_queue_entry for hashing */ ++static u32 nfqnl_packet_obj_hashfn(const void *data, u32 len, u32 seed) ++{ ++ const struct nf_queue_entry *entry = data; ++ struct nfqnl_packet_key key; ++ ++ nfqnl_init_key(&key, entry->state.net, entry->id, entry->queue_num); ++ ++ return jhash2((u32 *)&key, sizeof(key) / sizeof(u32), seed); ++} ++ ++/* Compare stack-allocated key against entry */ ++static int nfqnl_packet_obj_cmpfn(struct rhashtable_compare_arg *arg, ++ const void *obj) ++{ ++ const struct nfqnl_packet_key *key = arg->key; ++ const struct nf_queue_entry *entry = obj; ++ ++ return !net_eq(entry->state.net, read_pnet(&key->net)) || ++ entry->queue_num != key->queue_num || ++ entry->id != key->packet_id; ++} ++ ++static const struct rhashtable_params nfqnl_rhashtable_params = { ++ .head_offset = offsetof(struct nf_queue_entry, hash_node), ++ .key_len = sizeof(struct nfqnl_packet_key), ++ .obj_hashfn = nfqnl_packet_obj_hashfn, ++ .obj_cmpfn = nfqnl_packet_obj_cmpfn, ++ .automatic_shrinking = true, ++ .min_size = NFQNL_HASH_MIN, ++ .max_size = NFQNL_HASH_MAX, ++}; ++ + static struct nfqnl_instance * + instance_lookup(struct nfnl_queue_net *q, u_int16_t queue_num) + { +@@ -191,33 +248,45 @@ instance_destroy(struct nfnl_queue_net *q, struct nfqnl_instance *inst) + spin_unlock(&q->instances_lock); + } + +-static inline void ++static int + __enqueue_entry(struct nfqnl_instance *queue, struct nf_queue_entry *entry) + { +- list_add_tail(&entry->list, &queue->queue_list); +- queue->queue_total++; ++ int err; ++ ++ entry->queue_num = queue->queue_num; ++ ++ err = rhashtable_insert_fast(&nfqnl_packet_map, &entry->hash_node, ++ nfqnl_rhashtable_params); ++ if (unlikely(err)) ++ return err; ++ ++ list_add_tail(&entry->list, &queue->queue_list); ++ queue->queue_total++; ++ ++ return 0; + } + + static void + __dequeue_entry(struct nfqnl_instance *queue, struct nf_queue_entry *entry) + { ++ rhashtable_remove_fast(&nfqnl_packet_map, &entry->hash_node, ++ nfqnl_rhashtable_params); + list_del(&entry->list); + queue->queue_total--; + } + + static struct nf_queue_entry * +-find_dequeue_entry(struct nfqnl_instance *queue, unsigned int id) ++find_dequeue_entry(struct nfqnl_instance *queue, unsigned int id, ++ struct net *net) + { +- struct nf_queue_entry *entry = NULL, *i; ++ struct nfqnl_packet_key key; ++ struct nf_queue_entry *entry; + +- spin_lock_bh(&queue->lock); ++ nfqnl_init_key(&key, net, id, queue->queue_num); + +- list_for_each_entry(i, &queue->queue_list, list) { +- if (i->id == id) { +- entry = i; +- break; +- } +- } ++ spin_lock_bh(&queue->lock); ++ entry = rhashtable_lookup_fast(&nfqnl_packet_map, &key, ++ nfqnl_rhashtable_params); + + if (entry) + __dequeue_entry(queue, entry); +@@ -407,8 +476,7 @@ nfqnl_flush(struct nfqnl_instance *queue, nfqnl_cmpfn cmpfn, unsigned long data) + spin_lock_bh(&queue->lock); + list_for_each_entry_safe(entry, next, &queue->queue_list, list) { + if (!cmpfn || cmpfn(entry, data)) { +- list_del(&entry->list); +- queue->queue_total--; ++ __dequeue_entry(queue, entry); + nfqnl_reinject(entry, NF_DROP); + } + } +@@ -888,23 +956,23 @@ __nfqnl_enqueue_packet(struct net *net, struct nfqnl_instance *queue, + if (nf_ct_drop_unconfirmed(entry)) + goto err_out_free_nskb; + +- if (queue->queue_total >= queue->queue_maxlen) { +- if (queue->flags & NFQA_CFG_F_FAIL_OPEN) { +- failopen = 1; +- err = 0; +- } else { +- queue->queue_dropped++; +- net_warn_ratelimited("nf_queue: full at %d entries, dropping packets(s)\n", +- queue->queue_total); +- } +- goto err_out_free_nskb; +- } ++ if (queue->queue_total >= queue->queue_maxlen) ++ goto err_out_queue_drop; ++ + entry->id = ++queue->id_sequence; + *packet_id_ptr = htonl(entry->id); + ++ /* Insert into hash BEFORE unicast. If failure don't send to userspace. */ ++ err = __enqueue_entry(queue, entry); ++ if (unlikely(err)) ++ goto err_out_queue_drop; ++ + /* nfnetlink_unicast will either free the nskb or add it to a socket */ + err = nfnetlink_unicast(nskb, net, queue->peer_portid); + if (err < 0) { ++ /* Unicast failed - remove entry we just inserted */ ++ __dequeue_entry(queue, entry); ++ + if (queue->flags & NFQA_CFG_F_FAIL_OPEN) { + failopen = 1; + err = 0; +@@ -914,11 +982,22 @@ __nfqnl_enqueue_packet(struct net *net, struct nfqnl_instance *queue, + goto err_out_unlock; + } + +- __enqueue_entry(queue, entry); +- + spin_unlock_bh(&queue->lock); + return 0; + ++err_out_queue_drop: ++ if (queue->flags & NFQA_CFG_F_FAIL_OPEN) { ++ failopen = 1; ++ err = 0; ++ } else { ++ queue->queue_dropped++; ++ ++ if (queue->queue_total >= queue->queue_maxlen) ++ net_warn_ratelimited("nf_queue: full at %d entries, dropping packets(s)\n", ++ queue->queue_total); ++ else ++ net_warn_ratelimited("nf_queue: hash insert failed: %d\n", err); ++ } + err_out_free_nskb: + kfree_skb(nskb); + err_out_unlock: +@@ -1430,7 +1509,7 @@ static int nfqnl_recv_verdict(struct sk_buff *skb, const struct nfnl_info *info, + + verdict = ntohl(vhdr->verdict); + +- entry = find_dequeue_entry(queue, ntohl(vhdr->id)); ++ entry = find_dequeue_entry(queue, ntohl(vhdr->id), info->net); + if (entry == NULL) + return -ENOENT; + +@@ -1781,10 +1860,14 @@ static int __init nfnetlink_queue_init(void) + { + int status; + ++ status = rhashtable_init(&nfqnl_packet_map, &nfqnl_rhashtable_params); ++ if (status < 0) ++ return status; ++ + status = register_pernet_subsys(&nfnl_queue_net_ops); + if (status < 0) { + pr_err("failed to register pernet ops\n"); +- goto out; ++ goto cleanup_rhashtable; + } + + netlink_register_notifier(&nfqnl_rtnl_notifier); +@@ -1809,7 +1892,8 @@ static int __init nfnetlink_queue_init(void) + cleanup_netlink_notifier: + netlink_unregister_notifier(&nfqnl_rtnl_notifier); + unregister_pernet_subsys(&nfnl_queue_net_ops); +-out: ++cleanup_rhashtable: ++ rhashtable_destroy(&nfqnl_packet_map); + return status; + } + +@@ -1821,6 +1905,8 @@ static void __exit nfnetlink_queue_fini(void) + netlink_unregister_notifier(&nfqnl_rtnl_notifier); + unregister_pernet_subsys(&nfnl_queue_net_ops); + ++ rhashtable_destroy(&nfqnl_packet_map); ++ + rcu_barrier(); /* Wait for completion of call_rcu()'s */ + } + +-- +2.51.0 + diff --git a/queue-6.19/netfilter-nft_compat-add-more-restrictions-on-netlin.patch b/queue-6.19/netfilter-nft_compat-add-more-restrictions-on-netlin.patch new file mode 100644 index 0000000000..c3ec6059a8 --- /dev/null +++ b/queue-6.19/netfilter-nft_compat-add-more-restrictions-on-netlin.patch @@ -0,0 +1,71 @@ +From b44e94d4d5fb0e6e69408c5c581e9dd7baaeca54 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 19 Aug 2022 16:16:07 +0200 +Subject: netfilter: nft_compat: add more restrictions on netlink attributes + +From: Florian Westphal + +[ Upstream commit cda26c645946b08f070f20c166d4736767e4a805 ] + +As far as I can see nothing bad can happen when NFTA_TARGET/MATCH_NAME +are too large because this calls x_tables helpers which check for the +length, but it seems better to already reject it during netlink parsing. + +Rest of the changes avoid silent u8/u16 truncations. + +For _TYPE, its expected to be only 1 or 0. In x_tables world, this +variable is set by kernel, for IPT_SO_GET_REVISION_TARGET its 1, for +all others its set to 0. + +As older versions of nf_tables permitted any value except 1 to mean 'match', +keep this as-is but sanitize the value for consistency. + +Fixes: 0ca743a55991 ("netfilter: nf_tables: add compatibility layer for x_tables") +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_compat.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/net/netfilter/nft_compat.c b/net/netfilter/nft_compat.c +index 72711d62fddfa..08f620311b03f 100644 +--- a/net/netfilter/nft_compat.c ++++ b/net/netfilter/nft_compat.c +@@ -134,7 +134,8 @@ static void nft_target_eval_bridge(const struct nft_expr *expr, + } + + static const struct nla_policy nft_target_policy[NFTA_TARGET_MAX + 1] = { +- [NFTA_TARGET_NAME] = { .type = NLA_NUL_STRING }, ++ [NFTA_TARGET_NAME] = { .type = NLA_NUL_STRING, ++ .len = XT_EXTENSION_MAXNAMELEN, }, + [NFTA_TARGET_REV] = NLA_POLICY_MAX(NLA_BE32, 255), + [NFTA_TARGET_INFO] = { .type = NLA_BINARY }, + }; +@@ -434,7 +435,8 @@ static void nft_match_eval(const struct nft_expr *expr, + } + + static const struct nla_policy nft_match_policy[NFTA_MATCH_MAX + 1] = { +- [NFTA_MATCH_NAME] = { .type = NLA_NUL_STRING }, ++ [NFTA_MATCH_NAME] = { .type = NLA_NUL_STRING, ++ .len = XT_EXTENSION_MAXNAMELEN }, + [NFTA_MATCH_REV] = NLA_POLICY_MAX(NLA_BE32, 255), + [NFTA_MATCH_INFO] = { .type = NLA_BINARY }, + }; +@@ -693,7 +695,12 @@ static int nfnl_compat_get_rcu(struct sk_buff *skb, + + name = nla_data(tb[NFTA_COMPAT_NAME]); + rev = ntohl(nla_get_be32(tb[NFTA_COMPAT_REV])); +- target = ntohl(nla_get_be32(tb[NFTA_COMPAT_TYPE])); ++ /* x_tables api checks for 'target == 1' to mean target, ++ * everything else means 'match'. ++ * In x_tables world, the number is set by kernel, not ++ * userspace. ++ */ ++ target = nla_get_be32(tb[NFTA_COMPAT_TYPE]) == htonl(1); + + switch(family) { + case AF_INET: +-- +2.51.0 + diff --git a/queue-6.19/netfilter-nft_counter-fix-reset-of-counters-on-32bit.patch b/queue-6.19/netfilter-nft_counter-fix-reset-of-counters-on-32bit.patch new file mode 100644 index 0000000000..0fdbec8153 --- /dev/null +++ b/queue-6.19/netfilter-nft_counter-fix-reset-of-counters-on-32bit.patch @@ -0,0 +1,75 @@ +From 434c88bf4f1d7ce1bd47a50450a741a93dd46efd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 14:48:30 +0100 +Subject: netfilter: nft_counter: fix reset of counters on 32bit archs + +From: Anders Grahn + +[ Upstream commit 1e13f27e0675552161ab1778be9a23a636dde8a7 ] + +nft_counter_reset() calls u64_stats_add() with a negative value to reset +the counter. This will work on 64bit archs, hence the negative value +added will wrap as a 64bit value which then can wrap the stat counter as +well. + +On 32bit archs, the added negative value will wrap as a 32bit value and +_not_ wrapping the stat counter properly. In most cases, this would just +lead to a very large 32bit value being added to the stat counter. + +Fix by introducing u64_stats_sub(). + +Fixes: 4a1d3acd6ea8 ("netfilter: nft_counter: Use u64_stats_t for statistic.") +Signed-off-by: Anders Grahn +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + include/linux/u64_stats_sync.h | 10 ++++++++++ + net/netfilter/nft_counter.c | 4 ++-- + 2 files changed, 12 insertions(+), 2 deletions(-) + +diff --git a/include/linux/u64_stats_sync.h b/include/linux/u64_stats_sync.h +index 457879938fc19..3366090a86bd2 100644 +--- a/include/linux/u64_stats_sync.h ++++ b/include/linux/u64_stats_sync.h +@@ -89,6 +89,11 @@ static inline void u64_stats_add(u64_stats_t *p, unsigned long val) + local64_add(val, &p->v); + } + ++static inline void u64_stats_sub(u64_stats_t *p, s64 val) ++{ ++ local64_sub(val, &p->v); ++} ++ + static inline void u64_stats_inc(u64_stats_t *p) + { + local64_inc(&p->v); +@@ -130,6 +135,11 @@ static inline void u64_stats_add(u64_stats_t *p, unsigned long val) + p->v += val; + } + ++static inline void u64_stats_sub(u64_stats_t *p, s64 val) ++{ ++ p->v -= val; ++} ++ + static inline void u64_stats_inc(u64_stats_t *p) + { + p->v++; +diff --git a/net/netfilter/nft_counter.c b/net/netfilter/nft_counter.c +index cc73253294963..0d70325280cc5 100644 +--- a/net/netfilter/nft_counter.c ++++ b/net/netfilter/nft_counter.c +@@ -117,8 +117,8 @@ static void nft_counter_reset(struct nft_counter_percpu_priv *priv, + nft_sync = this_cpu_ptr(&nft_counter_sync); + + u64_stats_update_begin(nft_sync); +- u64_stats_add(&this_cpu->packets, -total->packets); +- u64_stats_add(&this_cpu->bytes, -total->bytes); ++ u64_stats_sub(&this_cpu->packets, total->packets); ++ u64_stats_sub(&this_cpu->bytes, total->bytes); + u64_stats_update_end(nft_sync); + + local_bh_enable(); +-- +2.51.0 + diff --git a/queue-6.19/netfilter-nft_set_hash-fix-get-operation-on-big-endi.patch b/queue-6.19/netfilter-nft_set_hash-fix-get-operation-on-big-endi.patch new file mode 100644 index 0000000000..07fcf2bb02 --- /dev/null +++ b/queue-6.19/netfilter-nft_set_hash-fix-get-operation-on-big-endi.patch @@ -0,0 +1,57 @@ +From 9358d9339326521502682eaf6902e534dc17c851 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 20:13:45 +0100 +Subject: netfilter: nft_set_hash: fix get operation on big endian + +From: Florian Westphal + +[ Upstream commit 2f635adbe2642d398a0be3ab245accd2987be0c3 ] + +tests/shell/testcases/packetpath/set_match_nomatch_hash_fast +fails on big endian with: + +Error: Could not process rule: No such file or directory +reset element ip test s { 244.147.90.126 } +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Fatal: Cannot fetch element "244.147.90.126" + +... because the wrong bucket is searched, jhash() and jhash1_word are +not interchangeable on big endian. + +Fixes: 3b02b0adc242 ("netfilter: nft_set_hash: fix lookups with fixed size hash on big endian") +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_set_hash.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/net/netfilter/nft_set_hash.c b/net/netfilter/nft_set_hash.c +index ba01ce75d6dea..739b992bde591 100644 +--- a/net/netfilter/nft_set_hash.c ++++ b/net/netfilter/nft_set_hash.c +@@ -619,15 +619,20 @@ static struct nft_elem_priv * + nft_hash_get(const struct net *net, const struct nft_set *set, + const struct nft_set_elem *elem, unsigned int flags) + { ++ const u32 *key = (const u32 *)&elem->key.val; + struct nft_hash *priv = nft_set_priv(set); + u8 genmask = nft_genmask_cur(net); + struct nft_hash_elem *he; + u32 hash; + +- hash = jhash(elem->key.val.data, set->klen, priv->seed); ++ if (set->klen == 4) ++ hash = jhash_1word(*key, priv->seed); ++ else ++ hash = jhash(key, set->klen, priv->seed); ++ + hash = reciprocal_scale(hash, priv->buckets); + hlist_for_each_entry_rcu(he, &priv->table[hash], node) { +- if (!memcmp(nft_set_ext_key(&he->ext), elem->key.val.data, set->klen) && ++ if (!memcmp(nft_set_ext_key(&he->ext), key, set->klen) && + nft_set_elem_active(&he->ext, genmask)) + return &he->priv; + } +-- +2.51.0 + diff --git a/queue-6.19/netfilter-nft_set_rbtree-check-for-partial-overlaps-.patch b/queue-6.19/netfilter-nft_set_rbtree-check-for-partial-overlaps-.patch new file mode 100644 index 0000000000..331a5e3a0f --- /dev/null +++ b/queue-6.19/netfilter-nft_set_rbtree-check-for-partial-overlaps-.patch @@ -0,0 +1,90 @@ +From 4956246f75b202026cc25b0e72d6c6c51b9f1f20 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 13:33:44 +0100 +Subject: netfilter: nft_set_rbtree: check for partial overlaps in anonymous + sets + +From: Pablo Neira Ayuso + +[ Upstream commit 4780ec142cbb24b794129d3080eee5cac2943ffc ] + +Userspace provides an optimized representation in case intervals are +adjacent, where the end element is omitted. + +The existing partial overlap detection logic skips anonymous set checks +on start elements for this reason. + +However, it is possible to add intervals that overlap to this anonymous +where two start elements with the same, eg. A-B, A-C where C < B. + + start end + A B + start end + A C + +Restore the check on overlapping start elements to report an overlap. + +Fixes: c9e6978e2725 ("netfilter: nft_set_rbtree: Switch to node list walk for overlap detection") +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_set_rbtree.c | 30 +++++++++++++++++++++++++----- + 1 file changed, 25 insertions(+), 5 deletions(-) + +diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c +index eacb3acc2b957..f2a1aa8860184 100644 +--- a/net/netfilter/nft_set_rbtree.c ++++ b/net/netfilter/nft_set_rbtree.c +@@ -309,11 +309,23 @@ static bool nft_rbtree_update_first(const struct nft_set *set, + return false; + } + ++/* Only for anonymous sets which do not allow updates, all element are active. */ ++static struct nft_rbtree_elem *nft_rbtree_prev_active(struct nft_rbtree_elem *rbe) ++{ ++ struct rb_node *node; ++ ++ node = rb_prev(&rbe->node); ++ if (!node) ++ return NULL; ++ ++ return rb_entry(node, struct nft_rbtree_elem, node); ++} ++ + static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set, + struct nft_rbtree_elem *new, + struct nft_elem_priv **elem_priv) + { +- struct nft_rbtree_elem *rbe, *rbe_le = NULL, *rbe_ge = NULL; ++ struct nft_rbtree_elem *rbe, *rbe_le = NULL, *rbe_ge = NULL, *rbe_prev; + struct rb_node *node, *next, *parent, **p, *first = NULL; + struct nft_rbtree *priv = nft_set_priv(set); + u8 cur_genmask = nft_genmask_cur(net); +@@ -451,11 +463,19 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set, + /* - new start element with existing closest, less or equal key value + * being a start element: partial overlap, reported as -ENOTEMPTY. + * Anonymous sets allow for two consecutive start element since they +- * are constant, skip them to avoid bogus overlap reports. ++ * are constant, but validate that this new start element does not ++ * sit in between an existing start and end elements: partial overlap, ++ * reported as -ENOTEMPTY. + */ +- if (!nft_set_is_anonymous(set) && rbe_le && +- nft_rbtree_interval_start(rbe_le) && nft_rbtree_interval_start(new)) +- return -ENOTEMPTY; ++ if (rbe_le && ++ nft_rbtree_interval_start(rbe_le) && nft_rbtree_interval_start(new)) { ++ if (!nft_set_is_anonymous(set)) ++ return -ENOTEMPTY; ++ ++ rbe_prev = nft_rbtree_prev_active(rbe_le); ++ if (rbe_prev && nft_rbtree_interval_end(rbe_prev)) ++ return -ENOTEMPTY; ++ } + + /* - new end element with existing closest, less or equal key value + * being a end element: partial overlap, reported as -ENOTEMPTY. +-- +2.51.0 + diff --git a/queue-6.19/netfilter-nft_set_rbtree-don-t-gc-elements-on-insert.patch b/queue-6.19/netfilter-nft_set_rbtree-don-t-gc-elements-on-insert.patch new file mode 100644 index 0000000000..fd21a2b8bb --- /dev/null +++ b/queue-6.19/netfilter-nft_set_rbtree-don-t-gc-elements-on-insert.patch @@ -0,0 +1,301 @@ +From 8d9d1707debc8919c1a61ca643778936da293f36 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 15:06:21 +0100 +Subject: netfilter: nft_set_rbtree: don't gc elements on insert + +From: Florian Westphal + +[ Upstream commit 35f83a75529a829b0939708b003652f7b4f3df9a ] + +During insertion we can queue up expired elements for garbage +collection. + +In case of later abort, the commit hook will never be called. +Packet path and 'get' requests will find free'd elements in the +binary search blob: + + nft_set_ext_key include/net/netfilter/nf_tables.h:800 [inline] + nft_array_get_cmp+0x1f6/0x2a0 net/netfilter/nft_set_rbtree.c:133 + __inline_bsearch include/linux/bsearch.h:15 [inline] + bsearch+0x50/0xc0 lib/bsearch.c:33 + nft_rbtree_get+0x16b/0x400 net/netfilter/nft_set_rbtree.c:169 + nft_setelem_get net/netfilter/nf_tables_api.c:6495 [inline] + nft_get_set_elem+0x420/0xaa0 net/netfilter/nf_tables_api.c:6543 + nf_tables_getsetelem+0x448/0x5e0 net/netfilter/nf_tables_api.c:6632 + nfnetlink_rcv_msg+0x8ae/0x12c0 net/netfilter/nfnetlink.c:290 + +Also, when we insert an element that triggers -EEXIST, and that insertion +happens to also zap a timed-out entry, we end up with same issue: +Neither commit nor abort hook is called. + +Fix this by removing gc api usage during insertion. + +The blamed commit also removes concurrency of the rbtree with the +packet path, so we can now safely rb_erase() the element and move +it to a new expired list that can be reaped in the commit hook +before building the next blob iteration. + +This also avoids the need to rebuild the blob in the abort path: +Expired elements seen during insertion attempts are kept around +until a transaction passes. + +Reported-by: syzbot+d417922a3e7935517ef6@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=d417922a3e7935517ef6 +Fixes: 7e43e0a1141d ("netfilter: nft_set_rbtree: translate rbtree to array for binary search") +Signed-off-by: Florian Westphal +Stable-dep-of: 782f2688128e ("netfilter: nft_set_rbtree: validate element belonging to interval") +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_set_rbtree.c | 136 ++++++++++++++++----------------- + 1 file changed, 68 insertions(+), 68 deletions(-) + +diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c +index 6470bc5d38749..14b4256bb00d0 100644 +--- a/net/netfilter/nft_set_rbtree.c ++++ b/net/netfilter/nft_set_rbtree.c +@@ -34,11 +34,15 @@ struct nft_rbtree { + struct nft_array __rcu *array; + struct nft_array *array_next; + unsigned long last_gc; ++ struct list_head expired; + }; + + struct nft_rbtree_elem { + struct nft_elem_priv priv; +- struct rb_node node; ++ union { ++ struct rb_node node; ++ struct list_head list; ++ }; + struct nft_set_ext ext; + }; + +@@ -186,13 +190,16 @@ nft_rbtree_get(const struct net *net, const struct nft_set *set, + return &rbe->priv; + } + +-static void nft_rbtree_gc_elem_remove(struct net *net, struct nft_set *set, +- struct nft_rbtree *priv, +- struct nft_rbtree_elem *rbe) ++static void nft_rbtree_gc_elem_move(struct net *net, struct nft_set *set, ++ struct nft_rbtree *priv, ++ struct nft_rbtree_elem *rbe) + { + lockdep_assert_held_write(&priv->lock); + nft_setelem_data_deactivate(net, set, &rbe->priv); + rb_erase(&rbe->node, &priv->root); ++ ++ /* collected later on in commit callback */ ++ list_add(&rbe->list, &priv->expired); + } + + static const struct nft_rbtree_elem * +@@ -203,11 +210,6 @@ nft_rbtree_gc_elem(const struct nft_set *__set, struct nft_rbtree *priv, + struct rb_node *prev = rb_prev(&rbe->node); + struct net *net = read_pnet(&set->net); + struct nft_rbtree_elem *rbe_prev; +- struct nft_trans_gc *gc; +- +- gc = nft_trans_gc_alloc(set, 0, GFP_ATOMIC); +- if (!gc) +- return ERR_PTR(-ENOMEM); + + /* search for end interval coming before this element. + * end intervals don't carry a timeout extension, they +@@ -225,28 +227,10 @@ nft_rbtree_gc_elem(const struct nft_set *__set, struct nft_rbtree *priv, + rbe_prev = NULL; + if (prev) { + rbe_prev = rb_entry(prev, struct nft_rbtree_elem, node); +- nft_rbtree_gc_elem_remove(net, set, priv, rbe_prev); +- +- /* There is always room in this trans gc for this element, +- * memory allocation never actually happens, hence, the warning +- * splat in such case. No need to set NFT_SET_ELEM_DEAD_BIT, +- * this is synchronous gc which never fails. +- */ +- gc = nft_trans_gc_queue_sync(gc, GFP_ATOMIC); +- if (WARN_ON_ONCE(!gc)) +- return ERR_PTR(-ENOMEM); +- +- nft_trans_gc_elem_add(gc, rbe_prev); ++ nft_rbtree_gc_elem_move(net, set, priv, rbe_prev); + } + +- nft_rbtree_gc_elem_remove(net, set, priv, rbe); +- gc = nft_trans_gc_queue_sync(gc, GFP_ATOMIC); +- if (WARN_ON_ONCE(!gc)) +- return ERR_PTR(-ENOMEM); +- +- nft_trans_gc_elem_add(gc, rbe); +- +- nft_trans_gc_queue_sync_done(gc); ++ nft_rbtree_gc_elem_move(net, set, priv, rbe); + + return rbe_prev; + } +@@ -708,29 +692,13 @@ static void nft_rbtree_walk(const struct nft_ctx *ctx, + } + } + +-static void nft_rbtree_gc_remove(struct net *net, struct nft_set *set, +- struct nft_rbtree *priv, +- struct nft_rbtree_elem *rbe) +-{ +- nft_setelem_data_deactivate(net, set, &rbe->priv); +- nft_rbtree_erase(priv, rbe); +-} +- +-static void nft_rbtree_gc(struct nft_set *set) ++static void nft_rbtree_gc_scan(struct nft_set *set) + { + struct nft_rbtree *priv = nft_set_priv(set); + struct nft_rbtree_elem *rbe, *rbe_end = NULL; + struct net *net = read_pnet(&set->net); + u64 tstamp = nft_net_tstamp(net); + struct rb_node *node, *next; +- struct nft_trans_gc *gc; +- +- set = nft_set_container_of(priv); +- net = read_pnet(&set->net); +- +- gc = nft_trans_gc_alloc(set, 0, GFP_KERNEL); +- if (!gc) +- return; + + for (node = rb_first(&priv->root); node ; node = next) { + next = rb_next(node); +@@ -748,34 +716,46 @@ static void nft_rbtree_gc(struct nft_set *set) + if (!__nft_set_elem_expired(&rbe->ext, tstamp)) + continue; + +- gc = nft_trans_gc_queue_sync(gc, GFP_KERNEL); +- if (!gc) +- goto try_later; +- + /* end element needs to be removed first, it has + * no timeout extension. + */ ++ write_lock_bh(&priv->lock); + if (rbe_end) { +- nft_rbtree_gc_remove(net, set, priv, rbe_end); +- nft_trans_gc_elem_add(gc, rbe_end); ++ nft_rbtree_gc_elem_move(net, set, priv, rbe_end); + rbe_end = NULL; + } + +- gc = nft_trans_gc_queue_sync(gc, GFP_KERNEL); +- if (!gc) +- goto try_later; +- +- nft_rbtree_gc_remove(net, set, priv, rbe); +- nft_trans_gc_elem_add(gc, rbe); ++ nft_rbtree_gc_elem_move(net, set, priv, rbe); ++ write_unlock_bh(&priv->lock); + } + +-try_later: ++ priv->last_gc = jiffies; ++} ++ ++static void nft_rbtree_gc_queue(struct nft_set *set) ++{ ++ struct nft_rbtree *priv = nft_set_priv(set); ++ struct nft_rbtree_elem *rbe, *rbe_end; ++ struct nft_trans_gc *gc; ++ ++ if (list_empty(&priv->expired)) ++ return; + +- if (gc) { +- gc = nft_trans_gc_catchall_sync(gc); +- nft_trans_gc_queue_sync_done(gc); +- priv->last_gc = jiffies; ++ gc = nft_trans_gc_alloc(set, 0, GFP_KERNEL); ++ if (!gc) ++ return; ++ ++ list_for_each_entry_safe(rbe, rbe_end, &priv->expired, list) { ++ list_del(&rbe->list); ++ nft_trans_gc_elem_add(gc, rbe); ++ ++ gc = nft_trans_gc_queue_sync(gc, GFP_KERNEL); ++ if (!gc) ++ return; + } ++ ++ gc = nft_trans_gc_catchall_sync(gc); ++ nft_trans_gc_queue_sync_done(gc); + } + + static u64 nft_rbtree_privsize(const struct nlattr * const nla[], +@@ -794,6 +774,7 @@ static int nft_rbtree_init(const struct nft_set *set, + + rwlock_init(&priv->lock); + priv->root = RB_ROOT; ++ INIT_LIST_HEAD(&priv->expired); + + priv->array = NULL; + priv->array_next = NULL; +@@ -811,10 +792,15 @@ static void nft_rbtree_destroy(const struct nft_ctx *ctx, + const struct nft_set *set) + { + struct nft_rbtree *priv = nft_set_priv(set); +- struct nft_rbtree_elem *rbe; ++ struct nft_rbtree_elem *rbe, *next; + struct nft_array *array; + struct rb_node *node; + ++ list_for_each_entry_safe(rbe, next, &priv->expired, list) { ++ list_del(&rbe->list); ++ nf_tables_set_elem_destroy(ctx, set, &rbe->priv); ++ } ++ + while ((node = priv->root.rb_node) != NULL) { + rb_erase(node, &priv->root); + rbe = rb_entry(node, struct nft_rbtree_elem, node); +@@ -861,13 +847,21 @@ static void nft_rbtree_commit(struct nft_set *set) + u32 num_intervals = 0; + struct rb_node *node; + +- if (time_after_eq(jiffies, priv->last_gc + nft_set_gc_interval(set))) +- nft_rbtree_gc(set); +- + /* No changes, skip, eg. elements updates only. */ + if (!priv->array_next) + return; + ++ /* GC can be performed if the binary search blob is going ++ * to be rebuilt. It has to be done in two phases: first ++ * scan tree and move all expired elements to the expired ++ * list. ++ * ++ * Then, after blob has been re-built and published to other ++ * CPUs, queue collected entries for freeing. ++ */ ++ if (time_after_eq(jiffies, priv->last_gc + nft_set_gc_interval(set))) ++ nft_rbtree_gc_scan(set); ++ + /* Reverse walk to create an array from smaller to largest interval. */ + node = rb_last(&priv->root); + if (node) +@@ -914,10 +908,16 @@ static void nft_rbtree_commit(struct nft_set *set) + num_intervals++; + err_out: + priv->array_next->num_intervals = num_intervals; +- old = rcu_replace_pointer(priv->array, priv->array_next, true); ++ old = rcu_replace_pointer(priv->array, priv->array_next, ++ lockdep_is_held(&nft_pernet(read_pnet(&set->net))->commit_mutex)); + priv->array_next = NULL; + if (old) + call_rcu(&old->rcu_head, nft_array_free_rcu); ++ ++ /* New blob is public, queue collected entries for freeing. ++ * call_rcu ensures elements stay around until readers are done. ++ */ ++ nft_rbtree_gc_queue(set); + } + + static void nft_rbtree_abort(const struct nft_set *set) +-- +2.51.0 + diff --git a/queue-6.19/netfilter-nft_set_rbtree-fix-bogus-eexist-with-nlm_f.patch b/queue-6.19/netfilter-nft_set_rbtree-fix-bogus-eexist-with-nlm_f.patch new file mode 100644 index 0000000000..ac8238fec6 --- /dev/null +++ b/queue-6.19/netfilter-nft_set_rbtree-fix-bogus-eexist-with-nlm_f.patch @@ -0,0 +1,80 @@ +From 20b97c94893b4f581b47a4fb34c717759f95a01b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 13:33:43 +0100 +Subject: netfilter: nft_set_rbtree: fix bogus EEXIST with NLM_F_CREATE with + null interval + +From: Pablo Neira Ayuso + +[ Upstream commit 7f9203f41aae8eea74fba6a3370da41332eabcda ] + +Userspace adds a non-matching null element to the kernel for historical +reasons. This null element is added when the set is populated with +elements. Inclusion of this element is conditional, therefore, +userspace needs to dump the set content to check for its presence. + +If the NLM_F_CREATE flag is turned on, this becomes an issue because +kernel bogusly reports EEXIST. + +Add special case to ignore NLM_F_CREATE in this case, therefore, +re-adding the nul-element never fails. + +Fixes: c016c7e45ddf ("netfilter: nf_tables: honor NLM_F_EXCL flag in set element insertion") +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_tables_api.c | 5 +++++ + net/netfilter/nft_set_rbtree.c | 13 +++++++++++++ + 2 files changed, 18 insertions(+) + +diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c +index ec9e5e2a9f277..198b9c739b559 100644 +--- a/net/netfilter/nf_tables_api.c ++++ b/net/netfilter/nf_tables_api.c +@@ -7635,6 +7635,11 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, + * and an existing one. + */ + err = -EEXIST; ++ } else if (err == -ECANCELED) { ++ /* ECANCELED reports an existing nul-element in ++ * interval sets. ++ */ ++ err = 0; + } + goto err_element_clash; + } +diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c +index ca594161b8402..eacb3acc2b957 100644 +--- a/net/netfilter/nft_set_rbtree.c ++++ b/net/netfilter/nft_set_rbtree.c +@@ -39,6 +39,13 @@ static bool nft_rbtree_interval_start(const struct nft_rbtree_elem *rbe) + return !nft_rbtree_interval_end(rbe); + } + ++static bool nft_rbtree_interval_null(const struct nft_set *set, ++ const struct nft_rbtree_elem *rbe) ++{ ++ return (!memchr_inv(nft_set_ext_key(&rbe->ext), 0, set->klen) && ++ nft_rbtree_interval_end(rbe)); ++} ++ + static int nft_rbtree_cmp(const struct nft_set *set, + const struct nft_rbtree_elem *e1, + const struct nft_rbtree_elem *e2) +@@ -431,6 +438,12 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set, + */ + if (rbe_le && !nft_rbtree_cmp(set, new, rbe_le) && + nft_rbtree_interval_end(rbe_le) == nft_rbtree_interval_end(new)) { ++ /* - ignore null interval, otherwise NLM_F_CREATE bogusly ++ * reports EEXIST. ++ */ ++ if (nft_rbtree_interval_null(set, new)) ++ return -ECANCELED; ++ + *elem_priv = &rbe_le->priv; + return -EEXIST; + } +-- +2.51.0 + diff --git a/queue-6.19/netfilter-nft_set_rbtree-remove-seqcount_rwlock_t.patch b/queue-6.19/netfilter-nft_set_rbtree-remove-seqcount_rwlock_t.patch new file mode 100644 index 0000000000..30722b4109 --- /dev/null +++ b/queue-6.19/netfilter-nft_set_rbtree-remove-seqcount_rwlock_t.patch @@ -0,0 +1,63 @@ +From 77429f61d945744df1b4cd4dd9510221114c734f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 01:08:47 +0100 +Subject: netfilter: nft_set_rbtree: remove seqcount_rwlock_t + +From: Pablo Neira Ayuso + +[ Upstream commit 5599fa810b503eafc2bd8cd15bd45f35fc8ff6b9 ] + +After the conversion to binary search array, this is not required anymore. +Remove it. + +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Florian Westphal +Stable-dep-of: 782f2688128e ("netfilter: nft_set_rbtree: validate element belonging to interval") +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_set_rbtree.c | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c +index 1b0502cc87301..6470bc5d38749 100644 +--- a/net/netfilter/nft_set_rbtree.c ++++ b/net/netfilter/nft_set_rbtree.c +@@ -33,7 +33,6 @@ struct nft_rbtree { + rwlock_t lock; + struct nft_array __rcu *array; + struct nft_array *array_next; +- seqcount_rwlock_t count; + unsigned long last_gc; + }; + +@@ -572,9 +571,7 @@ static int nft_rbtree_insert(const struct net *net, const struct nft_set *set, + cond_resched(); + + write_lock_bh(&priv->lock); +- write_seqcount_begin(&priv->count); + err = __nft_rbtree_insert(net, set, rbe, elem_priv); +- write_seqcount_end(&priv->count); + write_unlock_bh(&priv->lock); + } while (err == -EAGAIN); + +@@ -584,9 +581,7 @@ static int nft_rbtree_insert(const struct net *net, const struct nft_set *set, + static void nft_rbtree_erase(struct nft_rbtree *priv, struct nft_rbtree_elem *rbe) + { + write_lock_bh(&priv->lock); +- write_seqcount_begin(&priv->count); + rb_erase(&rbe->node, &priv->root); +- write_seqcount_end(&priv->count); + write_unlock_bh(&priv->lock); + } + +@@ -798,7 +793,6 @@ static int nft_rbtree_init(const struct nft_set *set, + BUILD_BUG_ON(offsetof(struct nft_rbtree_elem, priv) != 0); + + rwlock_init(&priv->lock); +- seqcount_rwlock_init(&priv->count, &priv->lock); + priv->root = RB_ROOT; + + priv->array = NULL; +-- +2.51.0 + diff --git a/queue-6.19/netfilter-nft_set_rbtree-translate-rbtree-to-array-f.patch b/queue-6.19/netfilter-nft_set_rbtree-translate-rbtree-to-array-f.patch new file mode 100644 index 0000000000..83211e4289 --- /dev/null +++ b/queue-6.19/netfilter-nft_set_rbtree-translate-rbtree-to-array-f.patch @@ -0,0 +1,508 @@ +From 73031bafbbb73a2a772f7750f56b22277801d256 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 01:08:45 +0100 +Subject: netfilter: nft_set_rbtree: translate rbtree to array for binary + search + +From: Pablo Neira Ayuso + +[ Upstream commit 7e43e0a1141deec651a60109dab3690854107298 ] + +The rbtree can temporarily store overlapping inactive elements during +the transaction processing, leading to false negative lookups. + +To address this issue, this patch adds a .commit function that walks the +the rbtree to build a array of intervals of ordered elements. This +conversion compacts the two singleton elements that represent the start +and the end of the interval into a single interval object for space +efficient. + +Binary search is O(log n), similar to rbtree lookup time, therefore, +performance number should be similar, and there is an implementation +available under lib/bsearch.c and include/linux/bsearch.h that is used +for this purpose. + +This slightly increases memory consumption for this new array that +stores pointers to the start and the end of the interval. + +With this patch: + + # time nft -f 100k-intervals-set.nft + + real 0m4.218s + user 0m3.544s + sys 0m0.400s + +Without this patch: + + # time nft -f 100k-intervals-set.nft + + real 0m3.920s + user 0m3.547s + sys 0m0.276s + +With this patch, with IPv4 intervals: + + baseline rbtree (match on first field only): 15254954pps + +Without this patch: + + baseline rbtree (match on first field only): 10256119pps + +This provides a ~50% improvement in matching intervals from packet path. + +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Florian Westphal +Stable-dep-of: 782f2688128e ("netfilter: nft_set_rbtree: validate element belonging to interval") +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_set_rbtree.c | 341 +++++++++++++++++++++++++-------- + 1 file changed, 257 insertions(+), 84 deletions(-) + +diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c +index f2a1aa8860184..04e696c87f4a0 100644 +--- a/net/netfilter/nft_set_rbtree.c ++++ b/net/netfilter/nft_set_rbtree.c +@@ -10,14 +10,29 @@ + #include + #include + #include ++#include + #include + #include + #include + #include + ++struct nft_array_interval { ++ struct nft_set_ext *from; ++ struct nft_set_ext *to; ++}; ++ ++struct nft_array { ++ u32 max_intervals; ++ u32 num_intervals; ++ struct nft_array_interval *intervals; ++ struct rcu_head rcu_head; ++}; ++ + struct nft_rbtree { + struct rb_root root; + rwlock_t lock; ++ struct nft_array __rcu *array; ++ struct nft_array *array_next; + seqcount_rwlock_t count; + unsigned long last_gc; + }; +@@ -54,90 +69,6 @@ static int nft_rbtree_cmp(const struct nft_set *set, + set->klen); + } + +-static bool nft_rbtree_elem_expired(const struct nft_rbtree_elem *rbe) +-{ +- return nft_set_elem_expired(&rbe->ext); +-} +- +-static const struct nft_set_ext * +-__nft_rbtree_lookup(const struct net *net, const struct nft_set *set, +- const u32 *key, unsigned int seq) +-{ +- struct nft_rbtree *priv = nft_set_priv(set); +- const struct nft_rbtree_elem *rbe, *interval = NULL; +- u8 genmask = nft_genmask_cur(net); +- const struct rb_node *parent; +- int d; +- +- parent = rcu_dereference_raw(priv->root.rb_node); +- while (parent != NULL) { +- if (read_seqcount_retry(&priv->count, seq)) +- return NULL; +- +- rbe = rb_entry(parent, struct nft_rbtree_elem, node); +- +- d = memcmp(nft_set_ext_key(&rbe->ext), key, set->klen); +- if (d < 0) { +- parent = rcu_dereference_raw(parent->rb_left); +- if (interval && +- !nft_rbtree_cmp(set, rbe, interval) && +- nft_rbtree_interval_end(rbe) && +- nft_rbtree_interval_start(interval)) +- continue; +- if (nft_set_elem_active(&rbe->ext, genmask) && +- !nft_rbtree_elem_expired(rbe)) +- interval = rbe; +- } else if (d > 0) +- parent = rcu_dereference_raw(parent->rb_right); +- else { +- if (!nft_set_elem_active(&rbe->ext, genmask)) { +- parent = rcu_dereference_raw(parent->rb_left); +- continue; +- } +- +- if (nft_rbtree_elem_expired(rbe)) +- return NULL; +- +- if (nft_rbtree_interval_end(rbe)) { +- if (nft_set_is_anonymous(set)) +- return NULL; +- parent = rcu_dereference_raw(parent->rb_left); +- interval = NULL; +- continue; +- } +- +- return &rbe->ext; +- } +- } +- +- if (set->flags & NFT_SET_INTERVAL && interval != NULL && +- nft_rbtree_interval_start(interval)) +- return &interval->ext; +- +- return NULL; +-} +- +-INDIRECT_CALLABLE_SCOPE +-const struct nft_set_ext * +-nft_rbtree_lookup(const struct net *net, const struct nft_set *set, +- const u32 *key) +-{ +- struct nft_rbtree *priv = nft_set_priv(set); +- unsigned int seq = read_seqcount_begin(&priv->count); +- const struct nft_set_ext *ext; +- +- ext = __nft_rbtree_lookup(net, set, key, seq); +- if (ext || !read_seqcount_retry(&priv->count, seq)) +- return ext; +- +- read_lock_bh(&priv->lock); +- seq = read_seqcount_begin(&priv->count); +- ext = __nft_rbtree_lookup(net, set, key, seq); +- read_unlock_bh(&priv->lock); +- +- return ext; +-} +- + static bool __nft_rbtree_get(const struct net *net, const struct nft_set *set, + const u32 *key, struct nft_rbtree_elem **elem, + unsigned int seq, unsigned int flags, u8 genmask) +@@ -228,6 +159,60 @@ nft_rbtree_get(const struct net *net, const struct nft_set *set, + return &rbe->priv; + } + ++struct nft_array_lookup_ctx { ++ const u32 *key; ++ u32 klen; ++}; ++ ++static int nft_array_lookup_cmp(const void *pkey, const void *entry) ++{ ++ const struct nft_array_interval *interval = entry; ++ const struct nft_array_lookup_ctx *ctx = pkey; ++ int a, b; ++ ++ if (!interval->from) ++ return 1; ++ ++ a = memcmp(ctx->key, nft_set_ext_key(interval->from), ctx->klen); ++ if (!interval->to) ++ b = -1; ++ else ++ b = memcmp(ctx->key, nft_set_ext_key(interval->to), ctx->klen); ++ ++ if (a >= 0 && b < 0) ++ return 0; ++ ++ if (a < 0) ++ return -1; ++ ++ return 1; ++} ++ ++INDIRECT_CALLABLE_SCOPE ++const struct nft_set_ext * ++nft_rbtree_lookup(const struct net *net, const struct nft_set *set, ++ const u32 *key) ++{ ++ struct nft_rbtree *priv = nft_set_priv(set); ++ struct nft_array *array = rcu_dereference(priv->array); ++ const struct nft_array_interval *interval; ++ struct nft_array_lookup_ctx ctx = { ++ .key = key, ++ .klen = set->klen, ++ }; ++ ++ if (!array) ++ return NULL; ++ ++ interval = bsearch(&ctx, array->intervals, array->num_intervals, ++ sizeof(struct nft_array_interval), ++ nft_array_lookup_cmp); ++ if (!interval || nft_set_elem_expired(interval->from)) ++ return NULL; ++ ++ return interval->from; ++} ++ + static void nft_rbtree_gc_elem_remove(struct net *net, struct nft_set *set, + struct nft_rbtree *priv, + struct nft_rbtree_elem *rbe) +@@ -514,6 +499,87 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set, + return 0; + } + ++static int nft_array_intervals_alloc(struct nft_array *array, u32 max_intervals) ++{ ++ struct nft_array_interval *intervals; ++ ++ intervals = kvcalloc(max_intervals, sizeof(struct nft_array_interval), ++ GFP_KERNEL_ACCOUNT); ++ if (!intervals) ++ return -ENOMEM; ++ ++ if (array->intervals) ++ kvfree(array->intervals); ++ ++ array->intervals = intervals; ++ array->max_intervals = max_intervals; ++ ++ return 0; ++} ++ ++static struct nft_array *nft_array_alloc(u32 max_intervals) ++{ ++ struct nft_array *array; ++ ++ array = kzalloc(sizeof(*array), GFP_KERNEL_ACCOUNT); ++ if (!array) ++ return NULL; ++ ++ if (nft_array_intervals_alloc(array, max_intervals) < 0) { ++ kfree(array); ++ return NULL; ++ } ++ ++ return array; ++} ++ ++#define NFT_ARRAY_EXTRA_SIZE 10240 ++ ++/* Similar to nft_rbtree_{u,k}size to hide details to userspace, but consider ++ * packed representation coming from userspace for anonymous sets too. ++ */ ++static u32 nft_array_elems(const struct nft_set *set) ++{ ++ u32 nelems = atomic_read(&set->nelems); ++ ++ /* Adjacent intervals are represented with a single start element in ++ * anonymous sets, use the current element counter as is. ++ */ ++ if (nft_set_is_anonymous(set)) ++ return nelems; ++ ++ /* Add extra room for never matching interval at the beginning and open ++ * interval at the end which only use a single element to represent it. ++ * The conversion to array will compact intervals, this allows reduce ++ * memory consumption. ++ */ ++ return (nelems / 2) + 2; ++} ++ ++static int nft_array_may_resize(const struct nft_set *set) ++{ ++ u32 nelems = nft_array_elems(set), new_max_intervals; ++ struct nft_rbtree *priv = nft_set_priv(set); ++ struct nft_array *array; ++ ++ if (!priv->array_next) { ++ array = nft_array_alloc(nelems + NFT_ARRAY_EXTRA_SIZE); ++ if (!array) ++ return -ENOMEM; ++ ++ priv->array_next = array; ++ } ++ ++ if (nelems < priv->array_next->max_intervals) ++ return 0; ++ ++ new_max_intervals = priv->array_next->max_intervals + NFT_ARRAY_EXTRA_SIZE; ++ if (nft_array_intervals_alloc(priv->array_next, new_max_intervals) < 0) ++ return -ENOMEM; ++ ++ return 0; ++} ++ + static int nft_rbtree_insert(const struct net *net, const struct nft_set *set, + const struct nft_set_elem *elem, + struct nft_elem_priv **elem_priv) +@@ -522,6 +588,9 @@ static int nft_rbtree_insert(const struct net *net, const struct nft_set *set, + struct nft_rbtree *priv = nft_set_priv(set); + int err; + ++ if (nft_array_may_resize(set) < 0) ++ return -ENOMEM; ++ + do { + if (fatal_signal_pending(current)) + return -EINTR; +@@ -586,6 +655,9 @@ nft_rbtree_deactivate(const struct net *net, const struct nft_set *set, + u64 tstamp = nft_net_tstamp(net); + int d; + ++ if (nft_array_may_resize(set) < 0) ++ return NULL; ++ + while (parent != NULL) { + rbe = rb_entry(parent, struct nft_rbtree_elem, node); + +@@ -648,6 +720,11 @@ static void nft_rbtree_walk(const struct nft_ctx *ctx, + switch (iter->type) { + case NFT_ITER_UPDATE: + lockdep_assert_held(&nft_pernet(ctx->net)->commit_mutex); ++ ++ if (nft_array_may_resize(set) < 0) { ++ iter->err = -ENOMEM; ++ break; ++ } + nft_rbtree_do_walk(ctx, set, iter); + break; + case NFT_ITER_READ: +@@ -750,14 +827,24 @@ static int nft_rbtree_init(const struct nft_set *set, + seqcount_rwlock_init(&priv->count, &priv->lock); + priv->root = RB_ROOT; + ++ priv->array = NULL; ++ priv->array_next = NULL; ++ + return 0; + } + ++static void __nft_array_free(struct nft_array *array) ++{ ++ kvfree(array->intervals); ++ kfree(array); ++} ++ + static void nft_rbtree_destroy(const struct nft_ctx *ctx, + const struct nft_set *set) + { + struct nft_rbtree *priv = nft_set_priv(set); + struct nft_rbtree_elem *rbe; ++ struct nft_array *array; + struct rb_node *node; + + while ((node = priv->root.rb_node) != NULL) { +@@ -765,6 +852,12 @@ static void nft_rbtree_destroy(const struct nft_ctx *ctx, + rbe = rb_entry(node, struct nft_rbtree_elem, node); + nf_tables_set_elem_destroy(ctx, set, &rbe->priv); + } ++ ++ array = rcu_dereference_protected(priv->array, true); ++ if (array) ++ __nft_array_free(array); ++ if (priv->array_next) ++ __nft_array_free(priv->array_next); + } + + static bool nft_rbtree_estimate(const struct nft_set_desc *desc, u32 features, +@@ -785,12 +878,91 @@ static bool nft_rbtree_estimate(const struct nft_set_desc *desc, u32 features, + return true; + } + ++static void nft_array_free_rcu(struct rcu_head *rcu_head) ++{ ++ struct nft_array *array = container_of(rcu_head, struct nft_array, rcu_head); ++ ++ __nft_array_free(array); ++} ++ + static void nft_rbtree_commit(struct nft_set *set) + { + struct nft_rbtree *priv = nft_set_priv(set); ++ struct nft_rbtree_elem *rbe, *prev_rbe; ++ struct nft_array *old; ++ u32 num_intervals = 0; ++ struct rb_node *node; + + if (time_after_eq(jiffies, priv->last_gc + nft_set_gc_interval(set))) + nft_rbtree_gc(set); ++ ++ /* No changes, skip, eg. elements updates only. */ ++ if (!priv->array_next) ++ return; ++ ++ /* Reverse walk to create an array from smaller to largest interval. */ ++ node = rb_last(&priv->root); ++ if (node) ++ prev_rbe = rb_entry(node, struct nft_rbtree_elem, node); ++ else ++ prev_rbe = NULL; ++ ++ while (prev_rbe) { ++ rbe = prev_rbe; ++ ++ if (nft_rbtree_interval_start(rbe)) ++ priv->array_next->intervals[num_intervals].from = &rbe->ext; ++ else if (nft_rbtree_interval_end(rbe)) ++ priv->array_next->intervals[num_intervals++].to = &rbe->ext; ++ ++ if (num_intervals >= priv->array_next->max_intervals) { ++ pr_warn_once("malformed interval set from userspace?"); ++ goto err_out; ++ } ++ ++ node = rb_prev(node); ++ if (!node) ++ break; ++ ++ prev_rbe = rb_entry(node, struct nft_rbtree_elem, node); ++ ++ /* For anonymous sets, when adjacent ranges are found, ++ * the end element is not added to the set to pack the set ++ * representation. Use next start element to complete this ++ * interval. ++ */ ++ if (nft_rbtree_interval_start(rbe) && ++ nft_rbtree_interval_start(prev_rbe) && ++ priv->array_next->intervals[num_intervals].from) ++ priv->array_next->intervals[num_intervals++].to = &prev_rbe->ext; ++ ++ if (num_intervals >= priv->array_next->max_intervals) { ++ pr_warn_once("malformed interval set from userspace?"); ++ goto err_out; ++ } ++ } ++ ++ if (priv->array_next->intervals[num_intervals].from) ++ num_intervals++; ++err_out: ++ priv->array_next->num_intervals = num_intervals; ++ old = rcu_replace_pointer(priv->array, priv->array_next, true); ++ priv->array_next = NULL; ++ if (old) ++ call_rcu(&old->rcu_head, nft_array_free_rcu); ++} ++ ++static void nft_rbtree_abort(const struct nft_set *set) ++{ ++ struct nft_rbtree *priv = nft_set_priv(set); ++ struct nft_array *array_next; ++ ++ if (!priv->array_next) ++ return; ++ ++ array_next = priv->array_next; ++ priv->array_next = NULL; ++ __nft_array_free(array_next); + } + + static void nft_rbtree_gc_init(const struct nft_set *set) +@@ -854,6 +1026,7 @@ const struct nft_set_type nft_set_rbtree_type = { + .flush = nft_rbtree_flush, + .activate = nft_rbtree_activate, + .commit = nft_rbtree_commit, ++ .abort = nft_rbtree_abort, + .gc_init = nft_rbtree_gc_init, + .lookup = nft_rbtree_lookup, + .walk = nft_rbtree_walk, +-- +2.51.0 + diff --git a/queue-6.19/netfilter-nft_set_rbtree-use-binary-search-array-in-.patch b/queue-6.19/netfilter-nft_set_rbtree-use-binary-search-array-in-.patch new file mode 100644 index 0000000000..733a69401d --- /dev/null +++ b/queue-6.19/netfilter-nft_set_rbtree-use-binary-search-array-in-.patch @@ -0,0 +1,198 @@ +From 3a0cd4d0c3585dd716c7b94f444addbdc8c8dd56 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 01:08:46 +0100 +Subject: netfilter: nft_set_rbtree: use binary search array in get command + +From: Pablo Neira Ayuso + +[ Upstream commit 2aa34191f06fc5af4f70241518a8554370d86054 ] + +Rework .get interface to use the binary search array, this needs a specific +lookup function to match on end intervals (<=). Packet path lookup is slight +different because match is on lesser value, not equal (ie. <). + +After this patch, seqcount can be removed in a follow up patch. + +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Florian Westphal +Stable-dep-of: 782f2688128e ("netfilter: nft_set_rbtree: validate element belonging to interval") +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_set_rbtree.c | 154 ++++++++++++++------------------- + 1 file changed, 64 insertions(+), 90 deletions(-) + +diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c +index 04e696c87f4a0..1b0502cc87301 100644 +--- a/net/netfilter/nft_set_rbtree.c ++++ b/net/netfilter/nft_set_rbtree.c +@@ -69,96 +69,6 @@ static int nft_rbtree_cmp(const struct nft_set *set, + set->klen); + } + +-static bool __nft_rbtree_get(const struct net *net, const struct nft_set *set, +- const u32 *key, struct nft_rbtree_elem **elem, +- unsigned int seq, unsigned int flags, u8 genmask) +-{ +- struct nft_rbtree_elem *rbe, *interval = NULL; +- struct nft_rbtree *priv = nft_set_priv(set); +- const struct rb_node *parent; +- const void *this; +- int d; +- +- parent = rcu_dereference_raw(priv->root.rb_node); +- while (parent != NULL) { +- if (read_seqcount_retry(&priv->count, seq)) +- return false; +- +- rbe = rb_entry(parent, struct nft_rbtree_elem, node); +- +- this = nft_set_ext_key(&rbe->ext); +- d = memcmp(this, key, set->klen); +- if (d < 0) { +- parent = rcu_dereference_raw(parent->rb_left); +- if (!(flags & NFT_SET_ELEM_INTERVAL_END)) +- interval = rbe; +- } else if (d > 0) { +- parent = rcu_dereference_raw(parent->rb_right); +- if (flags & NFT_SET_ELEM_INTERVAL_END) +- interval = rbe; +- } else { +- if (!nft_set_elem_active(&rbe->ext, genmask)) { +- parent = rcu_dereference_raw(parent->rb_left); +- continue; +- } +- +- if (nft_set_elem_expired(&rbe->ext)) +- return false; +- +- if (!nft_set_ext_exists(&rbe->ext, NFT_SET_EXT_FLAGS) || +- (*nft_set_ext_flags(&rbe->ext) & NFT_SET_ELEM_INTERVAL_END) == +- (flags & NFT_SET_ELEM_INTERVAL_END)) { +- *elem = rbe; +- return true; +- } +- +- if (nft_rbtree_interval_end(rbe)) +- interval = NULL; +- +- parent = rcu_dereference_raw(parent->rb_left); +- } +- } +- +- if (set->flags & NFT_SET_INTERVAL && interval != NULL && +- nft_set_elem_active(&interval->ext, genmask) && +- !nft_set_elem_expired(&interval->ext) && +- ((!nft_rbtree_interval_end(interval) && +- !(flags & NFT_SET_ELEM_INTERVAL_END)) || +- (nft_rbtree_interval_end(interval) && +- (flags & NFT_SET_ELEM_INTERVAL_END)))) { +- *elem = interval; +- return true; +- } +- +- return false; +-} +- +-static struct nft_elem_priv * +-nft_rbtree_get(const struct net *net, const struct nft_set *set, +- const struct nft_set_elem *elem, unsigned int flags) +-{ +- struct nft_rbtree *priv = nft_set_priv(set); +- unsigned int seq = read_seqcount_begin(&priv->count); +- struct nft_rbtree_elem *rbe = ERR_PTR(-ENOENT); +- const u32 *key = (const u32 *)&elem->key.val; +- u8 genmask = nft_genmask_cur(net); +- bool ret; +- +- ret = __nft_rbtree_get(net, set, key, &rbe, seq, flags, genmask); +- if (ret || !read_seqcount_retry(&priv->count, seq)) +- return &rbe->priv; +- +- read_lock_bh(&priv->lock); +- seq = read_seqcount_begin(&priv->count); +- ret = __nft_rbtree_get(net, set, key, &rbe, seq, flags, genmask); +- read_unlock_bh(&priv->lock); +- +- if (!ret) +- return ERR_PTR(-ENOENT); +- +- return &rbe->priv; +-} +- + struct nft_array_lookup_ctx { + const u32 *key; + u32 klen; +@@ -213,6 +123,70 @@ nft_rbtree_lookup(const struct net *net, const struct nft_set *set, + return interval->from; + } + ++struct nft_array_get_ctx { ++ const u32 *key; ++ unsigned int flags; ++ u32 klen; ++}; ++ ++static int nft_array_get_cmp(const void *pkey, const void *entry) ++{ ++ const struct nft_array_interval *interval = entry; ++ const struct nft_array_get_ctx *ctx = pkey; ++ int a, b; ++ ++ if (!interval->from) ++ return 1; ++ ++ a = memcmp(ctx->key, nft_set_ext_key(interval->from), ctx->klen); ++ if (!interval->to) ++ b = -1; ++ else ++ b = memcmp(ctx->key, nft_set_ext_key(interval->to), ctx->klen); ++ ++ if (a >= 0) { ++ if (ctx->flags & NFT_SET_ELEM_INTERVAL_END && b <= 0) ++ return 0; ++ else if (b < 0) ++ return 0; ++ } ++ ++ if (a < 0) ++ return -1; ++ ++ return 1; ++} ++ ++static struct nft_elem_priv * ++nft_rbtree_get(const struct net *net, const struct nft_set *set, ++ const struct nft_set_elem *elem, unsigned int flags) ++{ ++ struct nft_rbtree *priv = nft_set_priv(set); ++ struct nft_array *array = rcu_dereference(priv->array); ++ const struct nft_array_interval *interval; ++ struct nft_array_get_ctx ctx = { ++ .key = (const u32 *)&elem->key.val, ++ .flags = flags, ++ .klen = set->klen, ++ }; ++ struct nft_rbtree_elem *rbe; ++ ++ if (!array) ++ return ERR_PTR(-ENOENT); ++ ++ interval = bsearch(&ctx, array->intervals, array->num_intervals, ++ sizeof(struct nft_array_interval), nft_array_get_cmp); ++ if (!interval || nft_set_elem_expired(interval->from)) ++ return ERR_PTR(-ENOENT); ++ ++ if (flags & NFT_SET_ELEM_INTERVAL_END) ++ rbe = container_of(interval->to, struct nft_rbtree_elem, ext); ++ else ++ rbe = container_of(interval->from, struct nft_rbtree_elem, ext); ++ ++ return &rbe->priv; ++} ++ + static void nft_rbtree_gc_elem_remove(struct net *net, struct nft_set *set, + struct nft_rbtree *priv, + struct nft_rbtree_elem *rbe) +-- +2.51.0 + diff --git a/queue-6.19/netfilter-nft_set_rbtree-validate-element-belonging-.patch b/queue-6.19/netfilter-nft_set_rbtree-validate-element-belonging-.patch new file mode 100644 index 0000000000..8b75383fcd --- /dev/null +++ b/queue-6.19/netfilter-nft_set_rbtree-validate-element-belonging-.patch @@ -0,0 +1,294 @@ +From cb47108ec805be35309d566163a7f6c6f3ca659b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 13:33:45 +0100 +Subject: netfilter: nft_set_rbtree: validate element belonging to interval + +From: Pablo Neira Ayuso + +[ Upstream commit 782f2688128eca6d05a48be1c247f68d86afc168 ] + +The existing partial overlap detection does not check if the elements +belong to the interval, eg. + + add element inet x y { 1.1.1.1-2.2.2.2, 4.4.4.4-5.5.5.5 } + add element inet x y { 1.1.1.1-5.5.5.5 } => this should fail: ENOENT + +Similar situation occurs with deletions: + + add element inet x y { 1.1.1.1-2.2.2.2, 4.4.4.4-5.5.5.5} + delete element inet x y { 1.1.1.1-5.5.5.5 } => this should fail: ENOENT + +This currently works via mitigation by nft in userspace, which is +performing the overlap detection before sending the elements to the +kernel. This requires a previous netlink dump of the set content which +slows down incremental updates on interval sets, because a netlink set +content dump is needed. + +This patch extends the existing overlap detection to track the most +recent start element that already exists. The pointer to the existing +start element is stored as a cookie (no pointer dereference is ever +possible). If the end element is added and it already exists, then +check that the existing end element is adjacent to the already existing +start element. Similar logic applies to element deactivation. + +This patch also annotates the timestamp to identify if start cookie +comes from an older batch, in such case reset it. Otherwise, a failing +create element command leaves the start cookie in place, resulting in +bogus error reporting. + +There is still a few more corner cases of overlap detection related to +the open interval that are addressed in follow up patches. + +This is address an early design mistake where an interval is expressed +as two elements, using the NFT_SET_ELEM_INTERVAL_END flag, instead of +the more recent NFTA_SET_ELEM_KEY_END attribute that pipapo already +uses. + +Fixes: 7c84d41416d8 ("netfilter: nft_set_rbtree: Detect partial overlaps on insertion") +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_set_rbtree.c | 147 ++++++++++++++++++++++++++++++++- + 1 file changed, 143 insertions(+), 4 deletions(-) + +diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c +index 14b4256bb00d0..a4fb5b517d9de 100644 +--- a/net/netfilter/nft_set_rbtree.c ++++ b/net/netfilter/nft_set_rbtree.c +@@ -33,8 +33,10 @@ struct nft_rbtree { + rwlock_t lock; + struct nft_array __rcu *array; + struct nft_array *array_next; ++ unsigned long start_rbe_cookie; + unsigned long last_gc; + struct list_head expired; ++ u64 last_tstamp; + }; + + struct nft_rbtree_elem { +@@ -263,16 +265,85 @@ static struct nft_rbtree_elem *nft_rbtree_prev_active(struct nft_rbtree_elem *rb + return rb_entry(node, struct nft_rbtree_elem, node); + } + ++static struct nft_rbtree_elem * ++__nft_rbtree_next_active(struct rb_node *node, u8 genmask) ++{ ++ struct nft_rbtree_elem *next_rbe; ++ ++ while (node) { ++ next_rbe = rb_entry(node, struct nft_rbtree_elem, node); ++ if (!nft_set_elem_active(&next_rbe->ext, genmask)) { ++ node = rb_next(node); ++ continue; ++ } ++ ++ return next_rbe; ++ } ++ ++ return NULL; ++} ++ ++static struct nft_rbtree_elem * ++nft_rbtree_next_active(struct nft_rbtree_elem *rbe, u8 genmask) ++{ ++ return __nft_rbtree_next_active(rb_next(&rbe->node), genmask); ++} ++ ++static void nft_rbtree_maybe_reset_start_cookie(struct nft_rbtree *priv, ++ u64 tstamp) ++{ ++ if (priv->last_tstamp != tstamp) { ++ priv->start_rbe_cookie = 0; ++ priv->last_tstamp = tstamp; ++ } ++} ++ ++static void nft_rbtree_set_start_cookie(struct nft_rbtree *priv, ++ const struct nft_rbtree_elem *rbe) ++{ ++ priv->start_rbe_cookie = (unsigned long)rbe; ++} ++ ++static bool nft_rbtree_cmp_start_cookie(struct nft_rbtree *priv, ++ const struct nft_rbtree_elem *rbe) ++{ ++ return priv->start_rbe_cookie == (unsigned long)rbe; ++} ++ ++static bool nft_rbtree_insert_same_interval(const struct net *net, ++ struct nft_rbtree *priv, ++ struct nft_rbtree_elem *rbe) ++{ ++ u8 genmask = nft_genmask_next(net); ++ struct nft_rbtree_elem *next_rbe; ++ ++ if (!priv->start_rbe_cookie) ++ return true; ++ ++ next_rbe = nft_rbtree_next_active(rbe, genmask); ++ if (next_rbe) { ++ /* Closest start element differs from last element added. */ ++ if (nft_rbtree_interval_start(next_rbe) && ++ nft_rbtree_cmp_start_cookie(priv, next_rbe)) { ++ priv->start_rbe_cookie = 0; ++ return true; ++ } ++ } ++ ++ priv->start_rbe_cookie = 0; ++ ++ return false; ++} ++ + static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set, + struct nft_rbtree_elem *new, +- struct nft_elem_priv **elem_priv) ++ struct nft_elem_priv **elem_priv, u64 tstamp) + { + struct nft_rbtree_elem *rbe, *rbe_le = NULL, *rbe_ge = NULL, *rbe_prev; + struct rb_node *node, *next, *parent, **p, *first = NULL; + struct nft_rbtree *priv = nft_set_priv(set); + u8 cur_genmask = nft_genmask_cur(net); + u8 genmask = nft_genmask_next(net); +- u64 tstamp = nft_net_tstamp(net); + int d; + + /* Descend the tree to search for an existing element greater than the +@@ -378,12 +449,18 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set, + } + } + ++ if (nft_rbtree_interval_null(set, new)) ++ priv->start_rbe_cookie = 0; ++ else if (nft_rbtree_interval_start(new) && priv->start_rbe_cookie) ++ priv->start_rbe_cookie = 0; ++ + /* - new start element matching existing start element: full overlap + * reported as -EEXIST, cleared by caller if NLM_F_EXCL is not given. + */ + if (rbe_ge && !nft_rbtree_cmp(set, new, rbe_ge) && + nft_rbtree_interval_start(rbe_ge) == nft_rbtree_interval_start(new)) { + *elem_priv = &rbe_ge->priv; ++ nft_rbtree_set_start_cookie(priv, rbe_ge); + return -EEXIST; + } + +@@ -399,6 +476,11 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set, + return -ECANCELED; + + *elem_priv = &rbe_le->priv; ++ ++ /* - start and end element belong to the same interval. */ ++ if (!nft_rbtree_insert_same_interval(net, priv, rbe_le)) ++ return -ENOTEMPTY; ++ + return -EEXIST; + } + +@@ -543,8 +625,11 @@ static int nft_rbtree_insert(const struct net *net, const struct nft_set *set, + { + struct nft_rbtree_elem *rbe = nft_elem_priv_cast(elem->priv); + struct nft_rbtree *priv = nft_set_priv(set); ++ u64 tstamp = nft_net_tstamp(net); + int err; + ++ nft_rbtree_maybe_reset_start_cookie(priv, tstamp); ++ + if (nft_array_may_resize(set) < 0) + return -ENOMEM; + +@@ -555,7 +640,7 @@ static int nft_rbtree_insert(const struct net *net, const struct nft_set *set, + cond_resched(); + + write_lock_bh(&priv->lock); +- err = __nft_rbtree_insert(net, set, rbe, elem_priv); ++ err = __nft_rbtree_insert(net, set, rbe, elem_priv, tstamp); + write_unlock_bh(&priv->lock); + } while (err == -EAGAIN); + +@@ -588,6 +673,48 @@ static void nft_rbtree_activate(const struct net *net, + nft_clear(net, &rbe->ext); + } + ++static struct nft_rbtree_elem * ++nft_rbtree_next_inactive(struct nft_rbtree_elem *rbe, u8 genmask) ++{ ++ struct nft_rbtree_elem *next_rbe; ++ struct rb_node *node; ++ ++ node = rb_next(&rbe->node); ++ if (node) { ++ next_rbe = rb_entry(node, struct nft_rbtree_elem, node); ++ if (nft_rbtree_interval_start(next_rbe) && ++ !nft_set_elem_active(&next_rbe->ext, genmask)) ++ return next_rbe; ++ } ++ ++ return NULL; ++} ++ ++static bool nft_rbtree_deactivate_same_interval(const struct net *net, ++ struct nft_rbtree *priv, ++ struct nft_rbtree_elem *rbe) ++{ ++ u8 genmask = nft_genmask_next(net); ++ struct nft_rbtree_elem *next_rbe; ++ ++ if (!priv->start_rbe_cookie) ++ return true; ++ ++ next_rbe = nft_rbtree_next_inactive(rbe, genmask); ++ if (next_rbe) { ++ /* Closest start element differs from last element added. */ ++ if (nft_rbtree_interval_start(next_rbe) && ++ nft_rbtree_cmp_start_cookie(priv, next_rbe)) { ++ priv->start_rbe_cookie = 0; ++ return true; ++ } ++ } ++ ++ priv->start_rbe_cookie = 0; ++ ++ return false; ++} ++ + static void nft_rbtree_flush(const struct net *net, + const struct nft_set *set, + struct nft_elem_priv *elem_priv) +@@ -602,12 +729,18 @@ nft_rbtree_deactivate(const struct net *net, const struct nft_set *set, + const struct nft_set_elem *elem) + { + struct nft_rbtree_elem *rbe, *this = nft_elem_priv_cast(elem->priv); +- const struct nft_rbtree *priv = nft_set_priv(set); ++ struct nft_rbtree *priv = nft_set_priv(set); + const struct rb_node *parent = priv->root.rb_node; + u8 genmask = nft_genmask_next(net); + u64 tstamp = nft_net_tstamp(net); + int d; + ++ nft_rbtree_maybe_reset_start_cookie(priv, tstamp); ++ ++ if (nft_rbtree_interval_start(this) || ++ nft_rbtree_interval_null(set, this)) ++ priv->start_rbe_cookie = 0; ++ + if (nft_array_may_resize(set) < 0) + return NULL; + +@@ -635,6 +768,12 @@ nft_rbtree_deactivate(const struct net *net, const struct nft_set *set, + parent = parent->rb_left; + continue; + } ++ ++ if (nft_rbtree_interval_start(rbe)) ++ nft_rbtree_set_start_cookie(priv, rbe); ++ else if (!nft_rbtree_deactivate_same_interval(net, priv, rbe)) ++ return NULL; ++ + nft_rbtree_flush(net, set, &rbe->priv); + return &rbe->priv; + } +-- +2.51.0 + diff --git a/queue-6.19/netfilter-nft_set_rbtree-validate-open-interval-over.patch b/queue-6.19/netfilter-nft_set_rbtree-validate-open-interval-over.patch new file mode 100644 index 0000000000..6ae30c0a54 --- /dev/null +++ b/queue-6.19/netfilter-nft_set_rbtree-validate-open-interval-over.patch @@ -0,0 +1,308 @@ +From d1c38973ac2ecdaa0019796bbffa616c52ab655c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 13:33:46 +0100 +Subject: netfilter: nft_set_rbtree: validate open interval overlap + +From: Pablo Neira Ayuso + +[ Upstream commit 648946966a08e4cb1a71619e3d1b12bd7642de7b ] + +Open intervals do not have an end element, in particular an open +interval at the end of the set is hard to validate because of it is +lacking the end element, and interval validation relies on such end +element to perform the checks. + +This patch adds a new flag field to struct nft_set_elem, this is not an +issue because this is a temporary object that is allocated in the stack +from the insert/deactivate path. This flag field is used to specify that +this is the last element in this add/delete command. + +The last flag is used, in combination with the start element cookie, to +check if there is a partial overlap, eg. + + Already exists: 255.255.255.0-255.255.255.254 + Add interval: 255.255.255.0-255.255.255.255 + ~~~~~~~~~~~~~ + start element overlap + +Basically, the idea is to check for an existing end element in the set +if there is an overlap with an existing start element. + +However, the last open interval can come in any position in the add +command, the corner case can get a bit more complicated: + + Already exists: 255.255.255.0-255.255.255.254 + Add intervals: 255.255.255.0-255.255.255.255,255.255.255.0-255.255.255.254 + ~~~~~~~~~~~~~ + start element overlap + +To catch this overlap, annotate that the new start element is a possible +overlap, then report the overlap if the next element is another start +element that confirms that previous element in an open interval at the +end of the set. + +For deletions, do not update the start cookie when deleting an open +interval, otherwise this can trigger spurious EEXIST when adding new +elements. + +Unfortunately, there is no NFT_SET_ELEM_INTERVAL_OPEN flag which would +make easier to detect open interval overlaps. + +Fixes: 7c84d41416d8 ("netfilter: nft_set_rbtree: Detect partial overlaps on insertion") +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + include/net/netfilter/nf_tables.h | 4 ++ + net/netfilter/nf_tables_api.c | 21 +++++++-- + net/netfilter/nft_set_rbtree.c | 71 ++++++++++++++++++++++++++----- + 3 files changed, 82 insertions(+), 14 deletions(-) + +diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h +index 0e266c2d0e7f0..7eac73f9b4ce3 100644 +--- a/include/net/netfilter/nf_tables.h ++++ b/include/net/netfilter/nf_tables.h +@@ -278,6 +278,8 @@ struct nft_userdata { + unsigned char data[]; + }; + ++#define NFT_SET_ELEM_INTERNAL_LAST 0x1 ++ + /* placeholder structure for opaque set element backend representation. */ + struct nft_elem_priv { }; + +@@ -287,6 +289,7 @@ struct nft_elem_priv { }; + * @key: element key + * @key_end: closing element key + * @data: element data ++ * @flags: flags + * @priv: element private data and extensions + */ + struct nft_set_elem { +@@ -302,6 +305,7 @@ struct nft_set_elem { + u32 buf[NFT_DATA_VALUE_MAXLEN / sizeof(u32)]; + struct nft_data val; + } data; ++ u32 flags; + struct nft_elem_priv *priv; + }; + +diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c +index 198b9c739b559..daef07ee09427 100644 +--- a/net/netfilter/nf_tables_api.c ++++ b/net/netfilter/nf_tables_api.c +@@ -7269,7 +7269,8 @@ static u32 nft_set_maxsize(const struct nft_set *set) + } + + static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, +- const struct nlattr *attr, u32 nlmsg_flags) ++ const struct nlattr *attr, u32 nlmsg_flags, ++ bool last) + { + struct nft_expr *expr_array[NFT_SET_EXPR_MAX] = {}; + struct nlattr *nla[NFTA_SET_ELEM_MAX + 1]; +@@ -7555,6 +7556,11 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, + if (flags) + *nft_set_ext_flags(ext) = flags; + ++ if (last) ++ elem.flags = NFT_SET_ELEM_INTERNAL_LAST; ++ else ++ elem.flags = 0; ++ + if (obj) + *nft_set_ext_obj(ext) = obj; + +@@ -7718,7 +7724,8 @@ static int nf_tables_newsetelem(struct sk_buff *skb, + nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla); + + nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) { +- err = nft_add_set_elem(&ctx, set, attr, info->nlh->nlmsg_flags); ++ err = nft_add_set_elem(&ctx, set, attr, info->nlh->nlmsg_flags, ++ nla_is_last(attr, rem)); + if (err < 0) { + NL_SET_BAD_ATTR(extack, attr); + return err; +@@ -7841,7 +7848,7 @@ static void nft_trans_elems_destroy_abort(const struct nft_ctx *ctx, + } + + static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set, +- const struct nlattr *attr) ++ const struct nlattr *attr, bool last) + { + struct nlattr *nla[NFTA_SET_ELEM_MAX + 1]; + struct nft_set_ext_tmpl tmpl; +@@ -7909,6 +7916,11 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set, + if (flags) + *nft_set_ext_flags(ext) = flags; + ++ if (last) ++ elem.flags = NFT_SET_ELEM_INTERNAL_LAST; ++ else ++ elem.flags = 0; ++ + trans = nft_trans_elem_alloc(ctx, NFT_MSG_DELSETELEM, set); + if (trans == NULL) + goto fail_trans; +@@ -8056,7 +8068,8 @@ static int nf_tables_delsetelem(struct sk_buff *skb, + return nft_set_flush(&ctx, set, genmask); + + nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) { +- err = nft_del_setelem(&ctx, set, attr); ++ err = nft_del_setelem(&ctx, set, attr, ++ nla_is_last(attr, rem)); + if (err == -ENOENT && + NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYSETELEM) + continue; +diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c +index a4fb5b517d9de..644d4b9167057 100644 +--- a/net/netfilter/nft_set_rbtree.c ++++ b/net/netfilter/nft_set_rbtree.c +@@ -304,10 +304,19 @@ static void nft_rbtree_set_start_cookie(struct nft_rbtree *priv, + priv->start_rbe_cookie = (unsigned long)rbe; + } + ++static void nft_rbtree_set_start_cookie_open(struct nft_rbtree *priv, ++ const struct nft_rbtree_elem *rbe, ++ unsigned long open_interval) ++{ ++ priv->start_rbe_cookie = (unsigned long)rbe | open_interval; ++} ++ ++#define NFT_RBTREE_OPEN_INTERVAL 1UL ++ + static bool nft_rbtree_cmp_start_cookie(struct nft_rbtree *priv, + const struct nft_rbtree_elem *rbe) + { +- return priv->start_rbe_cookie == (unsigned long)rbe; ++ return (priv->start_rbe_cookie & ~NFT_RBTREE_OPEN_INTERVAL) == (unsigned long)rbe; + } + + static bool nft_rbtree_insert_same_interval(const struct net *net, +@@ -337,13 +346,14 @@ static bool nft_rbtree_insert_same_interval(const struct net *net, + + static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set, + struct nft_rbtree_elem *new, +- struct nft_elem_priv **elem_priv, u64 tstamp) ++ struct nft_elem_priv **elem_priv, u64 tstamp, bool last) + { + struct nft_rbtree_elem *rbe, *rbe_le = NULL, *rbe_ge = NULL, *rbe_prev; + struct rb_node *node, *next, *parent, **p, *first = NULL; + struct nft_rbtree *priv = nft_set_priv(set); + u8 cur_genmask = nft_genmask_cur(net); + u8 genmask = nft_genmask_next(net); ++ unsigned long open_interval = 0; + int d; + + /* Descend the tree to search for an existing element greater than the +@@ -449,10 +459,18 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set, + } + } + +- if (nft_rbtree_interval_null(set, new)) +- priv->start_rbe_cookie = 0; +- else if (nft_rbtree_interval_start(new) && priv->start_rbe_cookie) ++ if (nft_rbtree_interval_null(set, new)) { + priv->start_rbe_cookie = 0; ++ } else if (nft_rbtree_interval_start(new) && priv->start_rbe_cookie) { ++ if (nft_set_is_anonymous(set)) { ++ priv->start_rbe_cookie = 0; ++ } else if (priv->start_rbe_cookie & NFT_RBTREE_OPEN_INTERVAL) { ++ /* Previous element is an open interval that partially ++ * overlaps with an existing non-open interval. ++ */ ++ return -ENOTEMPTY; ++ } ++ } + + /* - new start element matching existing start element: full overlap + * reported as -EEXIST, cleared by caller if NLM_F_EXCL is not given. +@@ -460,7 +478,27 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set, + if (rbe_ge && !nft_rbtree_cmp(set, new, rbe_ge) && + nft_rbtree_interval_start(rbe_ge) == nft_rbtree_interval_start(new)) { + *elem_priv = &rbe_ge->priv; +- nft_rbtree_set_start_cookie(priv, rbe_ge); ++ ++ /* - Corner case: new start element of open interval (which ++ * comes as last element in the batch) overlaps the start of ++ * an existing interval with an end element: partial overlap. ++ */ ++ node = rb_first(&priv->root); ++ rbe = __nft_rbtree_next_active(node, genmask); ++ if (rbe && nft_rbtree_interval_end(rbe)) { ++ rbe = nft_rbtree_next_active(rbe, genmask); ++ if (rbe && ++ nft_rbtree_interval_start(rbe) && ++ !nft_rbtree_cmp(set, new, rbe)) { ++ if (last) ++ return -ENOTEMPTY; ++ ++ /* Maybe open interval? */ ++ open_interval = NFT_RBTREE_OPEN_INTERVAL; ++ } ++ } ++ nft_rbtree_set_start_cookie_open(priv, rbe_ge, open_interval); ++ + return -EEXIST; + } + +@@ -515,6 +553,12 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set, + nft_rbtree_interval_end(rbe_ge) && nft_rbtree_interval_end(new)) + return -ENOTEMPTY; + ++ /* - start element overlaps an open interval but end element is new: ++ * partial overlap, reported as -ENOEMPTY. ++ */ ++ if (!rbe_ge && priv->start_rbe_cookie && nft_rbtree_interval_end(new)) ++ return -ENOTEMPTY; ++ + /* Accepted element: pick insertion point depending on key value */ + parent = NULL; + p = &priv->root.rb_node; +@@ -624,6 +668,7 @@ static int nft_rbtree_insert(const struct net *net, const struct nft_set *set, + struct nft_elem_priv **elem_priv) + { + struct nft_rbtree_elem *rbe = nft_elem_priv_cast(elem->priv); ++ bool last = !!(elem->flags & NFT_SET_ELEM_INTERNAL_LAST); + struct nft_rbtree *priv = nft_set_priv(set); + u64 tstamp = nft_net_tstamp(net); + int err; +@@ -640,8 +685,12 @@ static int nft_rbtree_insert(const struct net *net, const struct nft_set *set, + cond_resched(); + + write_lock_bh(&priv->lock); +- err = __nft_rbtree_insert(net, set, rbe, elem_priv, tstamp); ++ err = __nft_rbtree_insert(net, set, rbe, elem_priv, tstamp, last); + write_unlock_bh(&priv->lock); ++ ++ if (nft_rbtree_interval_end(rbe)) ++ priv->start_rbe_cookie = 0; ++ + } while (err == -EAGAIN); + + return err; +@@ -729,6 +778,7 @@ nft_rbtree_deactivate(const struct net *net, const struct nft_set *set, + const struct nft_set_elem *elem) + { + struct nft_rbtree_elem *rbe, *this = nft_elem_priv_cast(elem->priv); ++ bool last = !!(elem->flags & NFT_SET_ELEM_INTERNAL_LAST); + struct nft_rbtree *priv = nft_set_priv(set); + const struct rb_node *parent = priv->root.rb_node; + u8 genmask = nft_genmask_next(net); +@@ -769,9 +819,10 @@ nft_rbtree_deactivate(const struct net *net, const struct nft_set *set, + continue; + } + +- if (nft_rbtree_interval_start(rbe)) +- nft_rbtree_set_start_cookie(priv, rbe); +- else if (!nft_rbtree_deactivate_same_interval(net, priv, rbe)) ++ if (nft_rbtree_interval_start(rbe)) { ++ if (!last) ++ nft_rbtree_set_start_cookie(priv, rbe); ++ } else if (!nft_rbtree_deactivate_same_interval(net, priv, rbe)) + return NULL; + + nft_rbtree_flush(net, set, &rbe->priv); +-- +2.51.0 + diff --git a/queue-6.19/netfs-avoid-double-increment-of-retry_count-in-subre.patch b/queue-6.19/netfs-avoid-double-increment-of-retry_count-in-subre.patch new file mode 100644 index 0000000000..7a29efc6c3 --- /dev/null +++ b/queue-6.19/netfs-avoid-double-increment-of-retry_count-in-subre.patch @@ -0,0 +1,38 @@ +From 0f7514ca5bc25bccbd59cd5e29d84b953265e205 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Jan 2026 14:03:05 +0530 +Subject: netfs: avoid double increment of retry_count in subreq + +From: Shyam Prasad N + +[ Upstream commit a5ca32d031bbba5160e1f555aabb75a3f40f918d ] + +This change fixes the instance of double incrementing of +retry_count. The increment of this count already happens +when netfs_reissue_write gets called. Incrementing this +value before is not necessary. + +Fixes: 4acb665cf4f3 ("netfs: Work around recursion by abandoning retry if nothing read") +Acked-by: David Howells +Signed-off-by: Shyam Prasad N +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/netfs/write_retry.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/fs/netfs/write_retry.c b/fs/netfs/write_retry.c +index fc9c3e0d34d81..29489a23a2209 100644 +--- a/fs/netfs/write_retry.c ++++ b/fs/netfs/write_retry.c +@@ -98,7 +98,6 @@ static void netfs_retry_write_stream(struct netfs_io_request *wreq, + subreq->start = start; + subreq->len = len; + __clear_bit(NETFS_SREQ_NEED_RETRY, &subreq->flags); +- subreq->retry_count++; + trace_netfs_sreq(subreq, netfs_sreq_trace_retry); + + /* Renegotiate max_len (wsize) */ +-- +2.51.0 + diff --git a/queue-6.19/nfc-hci-shdlc-stop-timers-and-work-before-freeing-co.patch b/queue-6.19/nfc-hci-shdlc-stop-timers-and-work-before-freeing-co.patch new file mode 100644 index 0000000000..d38f5ec210 --- /dev/null +++ b/queue-6.19/nfc-hci-shdlc-stop-timers-and-work-before-freeing-co.patch @@ -0,0 +1,52 @@ +From 012f7678b4ed675194628fc528d2f91aecc95fbc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 14:31:57 +0300 +Subject: nfc: hci: shdlc: Stop timers and work before freeing context + +From: Votokina Victoria + +[ Upstream commit c9efde1e537baed7648a94022b43836a348a074f ] + +llc_shdlc_deinit() purges SHDLC skb queues and frees the llc_shdlc +structure while its timers and state machine work may still be active. + +Timer callbacks can schedule sm_work, and sm_work accesses SHDLC state +and the skb queues. If teardown happens in parallel with a queued/running +work item, it can lead to UAF and other shutdown races. + +Stop all SHDLC timers and cancel sm_work synchronously before purging the +queues and freeing the context. + +Found by Linux Verification Center (linuxtesting.org) with SVACE. + +Fixes: 4a61cd6687fc ("NFC: Add an shdlc llc module to llc core") +Signed-off-by: Votokina Victoria +Link: https://patch.msgid.link/20260203113158.2008723-1-Victoria.Votokina@kaspersky.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/nfc/hci/llc_shdlc.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/net/nfc/hci/llc_shdlc.c b/net/nfc/hci/llc_shdlc.c +index 4fc37894860c9..08c8aa1530d8a 100644 +--- a/net/nfc/hci/llc_shdlc.c ++++ b/net/nfc/hci/llc_shdlc.c +@@ -762,6 +762,14 @@ static void llc_shdlc_deinit(struct nfc_llc *llc) + { + struct llc_shdlc *shdlc = nfc_llc_get_data(llc); + ++ timer_shutdown_sync(&shdlc->connect_timer); ++ timer_shutdown_sync(&shdlc->t1_timer); ++ timer_shutdown_sync(&shdlc->t2_timer); ++ shdlc->t1_active = false; ++ shdlc->t2_active = false; ++ ++ cancel_work_sync(&shdlc->sm_work); ++ + skb_queue_purge(&shdlc->rcv_q); + skb_queue_purge(&shdlc->send_q); + skb_queue_purge(&shdlc->ack_pending_q); +-- +2.51.0 + diff --git a/queue-6.19/nfs-localio-handle-short-writes-by-retrying.patch b/queue-6.19/nfs-localio-handle-short-writes-by-retrying.patch new file mode 100644 index 0000000000..8194c2b606 --- /dev/null +++ b/queue-6.19/nfs-localio-handle-short-writes-by-retrying.patch @@ -0,0 +1,121 @@ +From a768fe228dd9b5b2e9de925eb6a63dde0278a34c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 3 Jan 2026 12:14:59 -0500 +Subject: NFS/localio: Handle short writes by retrying + +From: Trond Myklebust + +[ Upstream commit 615762059d284b863f9163b53679d95b3dcdd495 ] + +The current code for handling short writes in localio just truncates the +I/O and then sets an error. While that is close to how the ordinary NFS +code behaves, it does mean there is a chance the data that got written +is lost because it isn't persisted. +To fix this, change localio so that the upper layers can direct the +behaviour to persist any unstable data by rewriting it, and then +continuing writing until an ENOSPC is hit. + +Fixes: 70ba381e1a43 ("nfs: add LOCALIO support") +Signed-off-by: Trond Myklebust +Reviewed-by: Mike Snitzer +Signed-off-by: Anna Schumaker +Signed-off-by: Sasha Levin +--- + fs/nfs/localio.c | 64 +++++++++++++++++++++++++++++++++++------------- + 1 file changed, 47 insertions(+), 17 deletions(-) + +diff --git a/fs/nfs/localio.c b/fs/nfs/localio.c +index 41fbcb3f9167e..00bbac6c9fe40 100644 +--- a/fs/nfs/localio.c ++++ b/fs/nfs/localio.c +@@ -58,6 +58,11 @@ struct nfs_local_fsync_ctx { + static bool localio_enabled __read_mostly = true; + module_param(localio_enabled, bool, 0644); + ++static int nfs_local_do_read(struct nfs_local_kiocb *iocb, ++ const struct rpc_call_ops *call_ops); ++static int nfs_local_do_write(struct nfs_local_kiocb *iocb, ++ const struct rpc_call_ops *call_ops); ++ + static inline bool nfs_client_is_local(const struct nfs_client *clp) + { + return !!rcu_access_pointer(clp->cl_uuid.net); +@@ -542,13 +547,50 @@ nfs_local_iocb_release(struct nfs_local_kiocb *iocb) + nfs_local_iocb_free(iocb); + } + +-static void +-nfs_local_pgio_release(struct nfs_local_kiocb *iocb) ++static void nfs_local_pgio_restart(struct nfs_local_kiocb *iocb, ++ struct nfs_pgio_header *hdr) ++{ ++ int status = 0; ++ ++ iocb->kiocb.ki_pos = hdr->args.offset; ++ iocb->kiocb.ki_flags &= ~(IOCB_DSYNC | IOCB_SYNC | IOCB_DIRECT); ++ iocb->kiocb.ki_complete = NULL; ++ iocb->aio_complete_work = NULL; ++ iocb->end_iter_index = -1; ++ ++ switch (hdr->rw_mode) { ++ case FMODE_READ: ++ nfs_local_iters_init(iocb, ITER_DEST); ++ status = nfs_local_do_read(iocb, hdr->task.tk_ops); ++ break; ++ case FMODE_WRITE: ++ nfs_local_iters_init(iocb, ITER_SOURCE); ++ status = nfs_local_do_write(iocb, hdr->task.tk_ops); ++ break; ++ default: ++ status = -EOPNOTSUPP; ++ } ++ ++ if (status != 0) { ++ nfs_local_iocb_release(iocb); ++ hdr->task.tk_status = status; ++ nfs_local_hdr_release(hdr, hdr->task.tk_ops); ++ } ++} ++ ++static void nfs_local_pgio_release(struct nfs_local_kiocb *iocb) + { + struct nfs_pgio_header *hdr = iocb->hdr; ++ struct rpc_task *task = &hdr->task; ++ ++ task->tk_action = NULL; ++ task->tk_ops->rpc_call_done(task, hdr); + +- nfs_local_iocb_release(iocb); +- nfs_local_hdr_release(hdr, hdr->task.tk_ops); ++ if (task->tk_action == NULL) { ++ nfs_local_iocb_release(iocb); ++ task->tk_ops->rpc_release(hdr); ++ } else ++ nfs_local_pgio_restart(iocb, hdr); + } + + /* +@@ -773,19 +815,7 @@ static void nfs_local_write_done(struct nfs_local_kiocb *iocb) + pr_info_ratelimited("nfs: Unexpected direct I/O write alignment failure\n"); + } + +- /* Handle short writes as if they are ENOSPC */ +- status = hdr->res.count; +- if (status > 0 && status < hdr->args.count) { +- hdr->mds_offset += status; +- hdr->args.offset += status; +- hdr->args.pgbase += status; +- hdr->args.count -= status; +- nfs_set_pgio_error(hdr, -ENOSPC, hdr->args.offset); +- status = -ENOSPC; +- /* record -ENOSPC in terms of nfs_local_pgio_done */ +- (void) nfs_local_pgio_done(iocb, status, true); +- } +- if (hdr->task.tk_status < 0) ++ if (status < 0) + nfs_reset_boot_verifier(hdr->inode); + } + +-- +2.51.0 + diff --git a/queue-6.19/nfs-localio-prevent-direct-reclaim-recursion-into-nf.patch b/queue-6.19/nfs-localio-prevent-direct-reclaim-recursion-into-nf.patch new file mode 100644 index 0000000000..3bbf62e7db --- /dev/null +++ b/queue-6.19/nfs-localio-prevent-direct-reclaim-recursion-into-nf.patch @@ -0,0 +1,77 @@ +From d6e5dc5db0bbb420334dd644dcbd215108668d80 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 11:08:55 -0500 +Subject: NFS/localio: prevent direct reclaim recursion into NFS via + nfs_writepages + +From: Mike Snitzer + +[ Upstream commit 67435d2d8a33a75f9647724952cb1b18279d2e95 ] + +LOCALIO is an NFS loopback mount optimization that avoids using the +network for READ, WRITE and COMMIT if the NFS client and server are +determined to be on the same system. But because LOCALIO is still +fundamentally "just NFS loopback mount" it is susceptible to recursion +deadlock via direct reclaim, e.g.: NFS LOCALIO down to XFS and then +back into NFS via nfs_writepages. + +Fix LOCALIO's potential for direct reclaim deadlock by ensuring that +all its page cache allocations are done from GFP_NOFS context. + +Thanks to Ben Coddington for pointing out commit ad22c7a043c2 ("xfs: +prevent stack overflows from page cache allocation"). + +Reported-by: John Cagle +Tested-by: Allen Lu +Suggested-by: Benjamin Coddington +Fixes: 70ba381e1a43 ("nfs: add LOCALIO support") +Signed-off-by: Mike Snitzer +Signed-off-by: Anna Schumaker +Signed-off-by: Sasha Levin +--- + fs/nfs/localio.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/fs/nfs/localio.c b/fs/nfs/localio.c +index 00bbac6c9fe40..84f53f27a9089 100644 +--- a/fs/nfs/localio.c ++++ b/fs/nfs/localio.c +@@ -291,6 +291,18 @@ nfs_local_open_fh(struct nfs_client *clp, const struct cred *cred, + } + EXPORT_SYMBOL_GPL(nfs_local_open_fh); + ++/* ++ * Ensure all page cache allocations are done from GFP_NOFS context to ++ * prevent direct reclaim recursion back into NFS via nfs_writepages. ++ */ ++static void ++nfs_local_mapping_set_gfp_nofs_context(struct address_space *m) ++{ ++ gfp_t gfp_mask = mapping_gfp_mask(m); ++ ++ mapping_set_gfp_mask(m, (gfp_mask & ~(__GFP_FS))); ++} ++ + static void + nfs_local_iocb_free(struct nfs_local_kiocb *iocb) + { +@@ -315,6 +327,7 @@ nfs_local_iocb_alloc(struct nfs_pgio_header *hdr, + return NULL; + } + ++ nfs_local_mapping_set_gfp_nofs_context(file->f_mapping); + init_sync_kiocb(&iocb->kiocb, file); + + iocb->hdr = hdr; +@@ -1004,6 +1017,8 @@ nfs_local_run_commit(struct file *filp, struct nfs_commit_data *data) + end = LLONG_MAX; + } + ++ nfs_local_mapping_set_gfp_nofs_context(filp->f_mapping); ++ + dprintk("%s: commit %llu - %llu\n", __func__, start, end); + return vfs_fsync_range(filp, start, end, 0); + } +-- +2.51.0 + diff --git a/queue-6.19/nfs-localio-remove-eagain-handling-in-nfs_local_doio.patch b/queue-6.19/nfs-localio-remove-eagain-handling-in-nfs_local_doio.patch new file mode 100644 index 0000000000..37ddeb8f32 --- /dev/null +++ b/queue-6.19/nfs-localio-remove-eagain-handling-in-nfs_local_doio.patch @@ -0,0 +1,43 @@ +From 944c78a4333887e393b7f217f3a78c3097a2fd9d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 11:08:57 -0500 +Subject: NFS/localio: remove -EAGAIN handling in nfs_local_doio() + +From: Mike Snitzer + +[ Upstream commit e72a73957613653f50375db1f3a3fbb907a9c40b ] + +Handling -EAGAIN in nfs_local_doio() was introduced with commit +0978e5b85fc08 (nfs_do_local_{read,write} were made to have negative +checks for correspoding iter method) but commit e43e9a3a3d66 +since eliminated the possibility for this -EAGAIN early return. + +So remove nfs_local_doio()'s -EAGAIN handling that calls +nfs_localio_disable_client() -- while it should never happen from +nfs_do_local_{read,write} this particular -EAGAIN handling is now +"dead" and so it has become a liability. + +Fixes: e43e9a3a3d66 ("nfs/localio: refactor iocb initialization") +Signed-off-by: Mike Snitzer +Signed-off-by: Anna Schumaker +Signed-off-by: Sasha Levin +--- + fs/nfs/localio.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/fs/nfs/localio.c b/fs/nfs/localio.c +index f553ac0e1d86e..3bd4f28c8afc2 100644 +--- a/fs/nfs/localio.c ++++ b/fs/nfs/localio.c +@@ -989,8 +989,6 @@ int nfs_local_doio(struct nfs_client *clp, struct nfsd_file *localio, + } + + if (status != 0) { +- if (status == -EAGAIN) +- nfs_localio_disable_client(clp); + nfs_local_iocb_release(iocb); + hdr->task.tk_status = status; + nfs_local_hdr_release(hdr, call_ops); +-- +2.51.0 + diff --git a/queue-6.19/nfs-localio-use-gfp_noio-and-non-memreclaim-workqueu.patch b/queue-6.19/nfs-localio-use-gfp_noio-and-non-memreclaim-workqueu.patch new file mode 100644 index 0000000000..e1488ff57f --- /dev/null +++ b/queue-6.19/nfs-localio-use-gfp_noio-and-non-memreclaim-workqueu.patch @@ -0,0 +1,80 @@ +From 3074a51fbba1fd8ffd051397ffa79df9ccfc3a32 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 11:08:56 -0500 +Subject: NFS/localio: use GFP_NOIO and non-memreclaim workqueue in + nfs_local_commit + +From: Mike Snitzer + +[ Upstream commit 9bb0060f7860aa4561c5b21163dd45ceb66946a9 ] + +nfslocaliod_workqueue is a non-memreclaim workqueue (it isn't +initialized with WQ_MEM_RECLAIM), see commit b9f5dd57f4a5 +("nfs/localio: use dedicated workqueues for filesystem read and +write"). + +Use nfslocaliod_workqueue for LOCALIO's SYNC work. + +Also, set PF_LOCAL_THROTTLE | PF_MEMALLOC_NOIO in +nfs_local_fsync_work. + +Fixes: b9f5dd57f4a5 ("nfs/localio: use dedicated workqueues for filesystem read and write") +Signed-off-by: Mike Snitzer +Signed-off-by: Anna Schumaker +Signed-off-by: Sasha Levin +--- + fs/nfs/localio.c | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +diff --git a/fs/nfs/localio.c b/fs/nfs/localio.c +index 84f53f27a9089..f553ac0e1d86e 100644 +--- a/fs/nfs/localio.c ++++ b/fs/nfs/localio.c +@@ -1060,17 +1060,22 @@ nfs_local_fsync_ctx_free(struct nfs_local_fsync_ctx *ctx) + static void + nfs_local_fsync_work(struct work_struct *work) + { ++ unsigned long old_flags = current->flags; + struct nfs_local_fsync_ctx *ctx; + int status; + + ctx = container_of(work, struct nfs_local_fsync_ctx, work); + ++ current->flags |= PF_LOCAL_THROTTLE | PF_MEMALLOC_NOIO; ++ + status = nfs_local_run_commit(nfs_to->nfsd_file_file(ctx->localio), + ctx->data); + nfs_local_commit_done(ctx->data, status); + if (ctx->done != NULL) + complete(ctx->done); + nfs_local_fsync_ctx_free(ctx); ++ ++ current->flags = old_flags; + } + + static struct nfs_local_fsync_ctx * +@@ -1094,7 +1099,7 @@ int nfs_local_commit(struct nfsd_file *localio, + { + struct nfs_local_fsync_ctx *ctx; + +- ctx = nfs_local_fsync_ctx_alloc(data, localio, GFP_KERNEL); ++ ctx = nfs_local_fsync_ctx_alloc(data, localio, GFP_NOIO); + if (!ctx) { + nfs_local_commit_done(data, -ENOMEM); + nfs_local_release_commit_data(localio, data, call_ops); +@@ -1106,10 +1111,10 @@ int nfs_local_commit(struct nfsd_file *localio, + if (how & FLUSH_SYNC) { + DECLARE_COMPLETION_ONSTACK(done); + ctx->done = &done; +- queue_work(nfsiod_workqueue, &ctx->work); ++ queue_work(nfslocaliod_workqueue, &ctx->work); + wait_for_completion(&done); + } else +- queue_work(nfsiod_workqueue, &ctx->work); ++ queue_work(nfslocaliod_workqueue, &ctx->work); + + return 0; + } +-- +2.51.0 + diff --git a/queue-6.19/nfs-nfserr_inval-is-not-defined-by-nfsv2.patch b/queue-6.19/nfs-nfserr_inval-is-not-defined-by-nfsv2.patch new file mode 100644 index 0000000000..fe6a334443 --- /dev/null +++ b/queue-6.19/nfs-nfserr_inval-is-not-defined-by-nfsv2.patch @@ -0,0 +1,78 @@ +From b757cc24dc012c9fdafc9f092463c04b76cd87d6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 19:28:50 -0500 +Subject: NFS: NFSERR_INVAL is not defined by NFSv2 + +From: Chuck Lever + +[ Upstream commit 0ac903d1bfdce8ff40657c2b7d996947b72b6645 ] + +A documenting comment in include/uapi/linux/nfs.h claims incorrectly +that NFSv2 defines NFSERR_INVAL. There is no such definition in either +RFC 1094 or https://pubs.opengroup.org/onlinepubs/9629799/chap7.htm + +NFS3ERR_INVAL is introduced in RFC 1813. + +NFSD returns NFSERR_INVAL for PROC_GETACL, which has no +specification (yet). + +However, nfsd_map_status() maps nfserr_symlink and nfserr_wrong_type +to nfserr_inval, which does not align with RFC 1094. This logic was +introduced only recently by commit 438f81e0e92a ("nfsd: move error +choice for incorrect object types to version-specific code."). Given +that we have no INVAL or SERVERFAULT status in NFSv2, probably the +only choice is NFSERR_IO. + +Fixes: 438f81e0e92a ("nfsd: move error choice for incorrect object types to version-specific code.") +Reviewed-by: NeilBrown +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs2acl.c | 2 +- + fs/nfsd/nfsproc.c | 2 +- + include/uapi/linux/nfs.h | 2 +- + 3 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c +index 5fb202acb0fd0..0ac538c761800 100644 +--- a/fs/nfsd/nfs2acl.c ++++ b/fs/nfsd/nfs2acl.c +@@ -45,7 +45,7 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst *rqstp) + inode = d_inode(fh->fh_dentry); + + if (argp->mask & ~NFS_ACL_MASK) { +- resp->status = nfserr_inval; ++ resp->status = nfserr_io; + goto out; + } + resp->mask = argp->mask; +diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c +index 481e789a76974..8873033d1e82f 100644 +--- a/fs/nfsd/nfsproc.c ++++ b/fs/nfsd/nfsproc.c +@@ -33,7 +33,7 @@ static __be32 nfsd_map_status(__be32 status) + break; + case nfserr_symlink: + case nfserr_wrong_type: +- status = nfserr_inval; ++ status = nfserr_io; + break; + } + return status; +diff --git a/include/uapi/linux/nfs.h b/include/uapi/linux/nfs.h +index 71c7196d32817..e629c49535345 100644 +--- a/include/uapi/linux/nfs.h ++++ b/include/uapi/linux/nfs.h +@@ -55,7 +55,7 @@ + NFSERR_NODEV = 19, /* v2 v3 v4 */ + NFSERR_NOTDIR = 20, /* v2 v3 v4 */ + NFSERR_ISDIR = 21, /* v2 v3 v4 */ +- NFSERR_INVAL = 22, /* v2 v3 v4 */ ++ NFSERR_INVAL = 22, /* v3 v4 */ + NFSERR_FBIG = 27, /* v2 v3 v4 */ + NFSERR_NOSPC = 28, /* v2 v3 v4 */ + NFSERR_ROFS = 30, /* v2 v3 v4 */ +-- +2.51.0 + diff --git a/queue-6.19/nfsd-do-not-allow-exporting-of-special-kernel-filesy.patch b/queue-6.19/nfsd-do-not-allow-exporting-of-special-kernel-filesy.patch new file mode 100644 index 0000000000..933308599b --- /dev/null +++ b/queue-6.19/nfsd-do-not-allow-exporting-of-special-kernel-filesy.patch @@ -0,0 +1,81 @@ +From fd699bb80e0e56b5eb6b083694d7da4a892097ee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 11:02:12 +0100 +Subject: nfsd: do not allow exporting of special kernel filesystems + +From: Amir Goldstein + +[ Upstream commit b3c78bc53630d14a5770451ede3a30e7052f3b8b ] + +pidfs and nsfs recently gained support for encode/decode of file handles +via name_to_handle_at(2)/open_by_handle_at(2). + +These special kernel filesystems have custom ->open() and ->permission() +export methods, which nfsd does not respect and it was never meant to be +used for exporting those filesystems by nfsd. + +Therefore, do not allow nfsd to export filesystems with custom ->open() +or ->permission() methods. + +Fixes: b3caba8f7a34a ("pidfs: implement file handle support") +Fixes: 5222470b2fbb3 ("nsfs: support file handles") +Reviewed-by: Jeff Layton +Signed-off-by: Amir Goldstein +Link: https://patch.msgid.link/20260129100212.49727-3-amir73il@gmail.com +Reviewed-by: Chuck Lever +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/nfsd/export.c | 8 +++++--- + include/linux/exportfs.h | 9 +++++++++ + 2 files changed, 14 insertions(+), 3 deletions(-) + +diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c +index 2a1499f2ad196..09fe268fe2c76 100644 +--- a/fs/nfsd/export.c ++++ b/fs/nfsd/export.c +@@ -427,7 +427,8 @@ static int check_export(const struct path *path, int *flags, unsigned char *uuid + * either a device number (so FS_REQUIRES_DEV needed) + * or an FSID number (so NFSEXP_FSID or ->uuid is needed). + * 2: We must be able to find an inode from a filehandle. +- * This means that s_export_op must be set. ++ * This means that s_export_op must be set and comply with ++ * the requirements for remote filesystem export. + * 3: We must not currently be on an idmapped mount. + */ + if (!(inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV) && +@@ -437,8 +438,9 @@ static int check_export(const struct path *path, int *flags, unsigned char *uuid + return -EINVAL; + } + +- if (!exportfs_can_decode_fh(inode->i_sb->s_export_op)) { +- dprintk("exp_export: export of invalid fs type.\n"); ++ if (!exportfs_may_export(inode->i_sb->s_export_op)) { ++ dprintk("exp_export: export of invalid fs type (%s).\n", ++ inode->i_sb->s_type->name); + return -EINVAL; + } + +diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h +index f0cf2714ec52d..9bd93d6bd9a49 100644 +--- a/include/linux/exportfs.h ++++ b/include/linux/exportfs.h +@@ -317,6 +317,15 @@ static inline bool exportfs_can_decode_fh(const struct export_operations *nop) + return nop && nop->fh_to_dentry; + } + ++static inline bool exportfs_may_export(const struct export_operations *nop) ++{ ++ /* ++ * Do not allow nfs export for filesystems with custom ->open() or ++ * ->permission() ops, which nfsd does not respect (e.g. pidfs, nsfs). ++ */ ++ return exportfs_can_decode_fh(nop) && !nop->open && !nop->permission; ++} ++ + static inline bool exportfs_can_encode_fh(const struct export_operations *nop, + int fh_flags) + { +-- +2.51.0 + diff --git a/queue-6.19/nfsd-never-defer-requests-during-idmap-lookup.patch b/queue-6.19/nfsd-never-defer-requests-during-idmap-lookup.patch new file mode 100644 index 0000000000..6a3f0ee067 --- /dev/null +++ b/queue-6.19/nfsd-never-defer-requests-during-idmap-lookup.patch @@ -0,0 +1,152 @@ +From d3af91b51165664113b3168a038af542e3a2a5fc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 22 Dec 2025 14:30:04 -0500 +Subject: nfsd: never defer requests during idmap lookup + +From: Anthony Iliopoulos + +[ Upstream commit f9c206cdc4266caad6a9a7f46341420a10f03ccb ] + +During v4 request compound arg decoding, some ops (e.g. SETATTR) +can trigger idmap lookup upcalls. When those upcall responses get +delayed beyond the allowed time limit, cache_check() will mark the +request for deferral and cause it to be dropped. + +This prevents nfs4svc_encode_compoundres from being executed, and +thus the session slot flag NFSD4_SLOT_INUSE never gets cleared. +Subsequent client requests will fail with NFSERR_JUKEBOX, given +that the slot will be marked as in-use, making the SEQUENCE op +fail. + +Fix this by making sure that the RQ_USEDEFERRAL flag is always +clear during nfs4svc_decode_compoundargs(), since no v4 request +should ever be deferred. + +Fixes: 2f425878b6a7 ("nfsd: don't use the deferral service, return NFS4ERR_DELAY") +Signed-off-by: Anthony Iliopoulos +Reviewed-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4idmap.c | 48 +++++++++++++++++++++++++++++++++++++++------ + fs/nfsd/nfs4proc.c | 2 -- + fs/nfsd/nfs4xdr.c | 16 +++++++++++++++ + 3 files changed, 58 insertions(+), 8 deletions(-) + +diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c +index 8cca1329f3485..b5b3d45979c9b 100644 +--- a/fs/nfsd/nfs4idmap.c ++++ b/fs/nfsd/nfs4idmap.c +@@ -643,13 +643,31 @@ static __be32 encode_name_from_id(struct xdr_stream *xdr, + return idmap_id_to_name(xdr, rqstp, type, id); + } + +-__be32 +-nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen, +- kuid_t *uid) ++/** ++ * nfsd_map_name_to_uid - Map user@domain to local UID ++ * @rqstp: RPC execution context ++ * @name: user@domain name to be mapped ++ * @namelen: length of name, in bytes ++ * @uid: OUT: mapped local UID value ++ * ++ * Returns nfs_ok on success or an NFSv4 status code on failure. ++ */ ++__be32 nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, ++ size_t namelen, kuid_t *uid) + { + __be32 status; + u32 id = -1; + ++ /* ++ * The idmap lookup below triggers an upcall that invokes ++ * cache_check(). RQ_USEDEFERRAL must be clear to prevent ++ * cache_check() from setting RQ_DROPME via svc_defer(). ++ * NFSv4 servers are not permitted to drop requests. Also ++ * RQ_DROPME will force NFSv4.1 session slot processing to ++ * be skipped. ++ */ ++ WARN_ON_ONCE(test_bit(RQ_USEDEFERRAL, &rqstp->rq_flags)); ++ + if (name == NULL || namelen == 0) + return nfserr_inval; + +@@ -660,13 +678,31 @@ nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen, + return status; + } + +-__be32 +-nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, size_t namelen, +- kgid_t *gid) ++/** ++ * nfsd_map_name_to_gid - Map user@domain to local GID ++ * @rqstp: RPC execution context ++ * @name: user@domain name to be mapped ++ * @namelen: length of name, in bytes ++ * @gid: OUT: mapped local GID value ++ * ++ * Returns nfs_ok on success or an NFSv4 status code on failure. ++ */ ++__be32 nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, ++ size_t namelen, kgid_t *gid) + { + __be32 status; + u32 id = -1; + ++ /* ++ * The idmap lookup below triggers an upcall that invokes ++ * cache_check(). RQ_USEDEFERRAL must be clear to prevent ++ * cache_check() from setting RQ_DROPME via svc_defer(). ++ * NFSv4 servers are not permitted to drop requests. Also ++ * RQ_DROPME will force NFSv4.1 session slot processing to ++ * be skipped. ++ */ ++ WARN_ON_ONCE(test_bit(RQ_USEDEFERRAL, &rqstp->rq_flags)); ++ + if (name == NULL || namelen == 0) + return nfserr_inval; + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 9ec08dd4fe823..f780024f9a088 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -3011,8 +3011,6 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) + BUG_ON(cstate->replay_owner); + out: + cstate->status = status; +- /* Reset deferral mechanism for RPC deferrals */ +- set_bit(RQ_USEDEFERRAL, &rqstp->rq_flags); + return rpc_success; + } + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 51ef97c254568..5065727204b95 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -6013,6 +6013,22 @@ nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + args->ops = args->iops; + args->rqstp = rqstp; + ++ /* ++ * NFSv4 operation decoders can invoke svc cache lookups ++ * that trigger svc_defer() when RQ_USEDEFERRAL is set, ++ * setting RQ_DROPME. This creates two problems: ++ * ++ * 1. Non-idempotency: Compounds make it too hard to avoid ++ * problems if a request is deferred and replayed. ++ * ++ * 2. Session slot leakage (NFSv4.1+): If RQ_DROPME is set ++ * during decode but SEQUENCE executes successfully, the ++ * session slot will be marked INUSE. The request is then ++ * dropped before encoding, so the slot is never released, ++ * rendering it permanently unusable by the client. ++ */ ++ clear_bit(RQ_USEDEFERRAL, &rqstp->rq_flags); ++ + return nfsd4_decode_compound(args); + } + +-- +2.51.0 + diff --git a/queue-6.19/nvdimm-virtio_pmem-serialize-flush-requests.patch b/queue-6.19/nvdimm-virtio_pmem-serialize-flush-requests.patch new file mode 100644 index 0000000000..e3ed1cca02 --- /dev/null +++ b/queue-6.19/nvdimm-virtio_pmem-serialize-flush-requests.patch @@ -0,0 +1,98 @@ +From 90c67e9a9333c09d8051fd688b9943fc81b82c28 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 10:13:51 +0800 +Subject: nvdimm: virtio_pmem: serialize flush requests + +From: Li Chen + +[ Upstream commit a9ba6733c7f1096c4506bf4e34a546e07242df74 ] + +Under heavy concurrent flush traffic, virtio-pmem can overflow its request +virtqueue (req_vq): virtqueue_add_sgs() starts returning -ENOSPC and the +driver logs "no free slots in the virtqueue". Shortly after that the +device enters VIRTIO_CONFIG_S_NEEDS_RESET and flush requests fail with +"virtio pmem device needs a reset". + +Serialize virtio_pmem_flush() with a per-device mutex so only one flush +request is in-flight at a time. This prevents req_vq descriptor overflow +under high concurrency. + +Reproducer (guest with virtio-pmem): + - mkfs.ext4 -F /dev/pmem0 + - mount -t ext4 -o dax,noatime /dev/pmem0 /mnt/bench + - fio: ioengine=io_uring rw=randwrite bs=4k iodepth=64 numjobs=64 + direct=1 fsync=1 runtime=30s time_based=1 + - dmesg: "no free slots in the virtqueue" + "virtio pmem device needs a reset" + +Fixes: 6e84200c0a29 ("virtio-pmem: Add virtio pmem driver") +Signed-off-by: Li Chen +Acked-by: Pankaj Gupta +Acked-by: Michael S. Tsirkin +Link: https://patch.msgid.link/20260203021353.121091-1-me@linux.beauty +Signed-off-by: Ira Weiny +Signed-off-by: Sasha Levin +--- + drivers/nvdimm/nd_virtio.c | 3 ++- + drivers/nvdimm/virtio_pmem.c | 1 + + drivers/nvdimm/virtio_pmem.h | 4 ++++ + 3 files changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/nvdimm/nd_virtio.c b/drivers/nvdimm/nd_virtio.c +index c3f07be4aa22a..af82385be7c6a 100644 +--- a/drivers/nvdimm/nd_virtio.c ++++ b/drivers/nvdimm/nd_virtio.c +@@ -44,6 +44,8 @@ static int virtio_pmem_flush(struct nd_region *nd_region) + unsigned long flags; + int err, err1; + ++ guard(mutex)(&vpmem->flush_lock); ++ + /* + * Don't bother to submit the request to the device if the device is + * not activated. +@@ -53,7 +55,6 @@ static int virtio_pmem_flush(struct nd_region *nd_region) + return -EIO; + } + +- might_sleep(); + req_data = kmalloc(sizeof(*req_data), GFP_KERNEL); + if (!req_data) + return -ENOMEM; +diff --git a/drivers/nvdimm/virtio_pmem.c b/drivers/nvdimm/virtio_pmem.c +index 2396d19ce5496..77b1966619059 100644 +--- a/drivers/nvdimm/virtio_pmem.c ++++ b/drivers/nvdimm/virtio_pmem.c +@@ -64,6 +64,7 @@ static int virtio_pmem_probe(struct virtio_device *vdev) + goto out_err; + } + ++ mutex_init(&vpmem->flush_lock); + vpmem->vdev = vdev; + vdev->priv = vpmem; + err = init_vq(vpmem); +diff --git a/drivers/nvdimm/virtio_pmem.h b/drivers/nvdimm/virtio_pmem.h +index 0dddefe594c46..f72cf17f9518f 100644 +--- a/drivers/nvdimm/virtio_pmem.h ++++ b/drivers/nvdimm/virtio_pmem.h +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + #include + + struct virtio_pmem_request { +@@ -35,6 +36,9 @@ struct virtio_pmem { + /* Virtio pmem request queue */ + struct virtqueue *req_vq; + ++ /* Serialize flush requests to the device. */ ++ struct mutex flush_lock; ++ + /* nvdimm bus registers virtio pmem device */ + struct nvdimm_bus *nvdimm_bus; + struct nvdimm_bus_descriptor nd_desc; +-- +2.51.0 + diff --git a/queue-6.19/nvmem-an8855-drop-an-unused-kconfig-symbol.patch b/queue-6.19/nvmem-an8855-drop-an-unused-kconfig-symbol.patch new file mode 100644 index 0000000000..13cb5c82ac --- /dev/null +++ b/queue-6.19/nvmem-an8855-drop-an-unused-kconfig-symbol.patch @@ -0,0 +1,38 @@ +From ef95ace2e2b92a3cdf2c0865f4a69aa453f647fe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 17:08:45 +0000 +Subject: nvmem: an8855: drop an unused Kconfig symbol + +From: Randy Dunlap + +[ Upstream commit 4796eaafd6a170db012395a40385d2baf4f4d118 ] + +MFD_AIROHA_AN8855 is referenced here but never defined, so drop it +from the Kconfig file. + +Fixes: e2258cfd9b98 ("nvmem: an8855: Add support for Airoha AN8855 Switch EFUSE") +Signed-off-by: Randy Dunlap +Signed-off-by: Srinivas Kandagatla +Link: https://patch.msgid.link/20260116170846.733558-4-srini@kernel.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/nvmem/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig +index bf47a982cf629..74ddbd0f79b0e 100644 +--- a/drivers/nvmem/Kconfig ++++ b/drivers/nvmem/Kconfig +@@ -30,7 +30,7 @@ source "drivers/nvmem/layouts/Kconfig" + + config NVMEM_AN8855_EFUSE + tristate "Airoha AN8855 eFuse support" +- depends on MFD_AIROHA_AN8855 || COMPILE_TEST ++ depends on COMPILE_TEST + help + Say y here to enable support for reading eFuses on Airoha AN8855 + Switch. These are e.g. used to store factory programmed +-- +2.51.0 + diff --git a/queue-6.19/octeon_ep-disable-per-ring-interrupts.patch b/queue-6.19/octeon_ep-disable-per-ring-interrupts.patch new file mode 100644 index 0000000000..98de5f880b --- /dev/null +++ b/queue-6.19/octeon_ep-disable-per-ring-interrupts.patch @@ -0,0 +1,119 @@ +From 73e50abf8194876b553c4263b46e754445267420 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 11:15:06 +0000 +Subject: octeon_ep: disable per ring interrupts + +From: Vimlesh Kumar + +[ Upstream commit 73e6ffa37cebee152c07c5f2b8bc70fd2899ea6e ] + +Disable the MSI-X per ring interrupt for every PF ring when PF +netdev goes down. + +Fixes: 1f2c2d0cee023 ("octeon_ep: add hardware configuration APIs") +Signed-off-by: Sathesh Edara +Signed-off-by: Shinas Rasheed +Signed-off-by: Vimlesh Kumar +Link: https://patch.msgid.link/20260206111510.1045092-2-vimleshk@marvell.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + .../ethernet/marvell/octeon_ep/octep_cn9k_pf.c | 18 +++++++++++++++--- + .../ethernet/marvell/octeon_ep/octep_cnxk_pf.c | 18 +++++++++++++++--- + .../marvell/octeon_ep/octep_regs_cn9k_pf.h | 1 + + .../marvell/octeon_ep/octep_regs_cnxk_pf.h | 1 + + 4 files changed, 32 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c b/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c +index b5805969404fa..f0bcb5f3c1474 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c +@@ -696,14 +696,26 @@ static void octep_enable_interrupts_cn93_pf(struct octep_device *oct) + /* Disable all interrupts */ + static void octep_disable_interrupts_cn93_pf(struct octep_device *oct) + { +- u64 intr_mask = 0ULL; ++ u64 reg_val, intr_mask = 0ULL; + int srn, num_rings, i; + + srn = CFG_GET_PORTS_PF_SRN(oct->conf); + num_rings = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); + +- for (i = 0; i < num_rings; i++) +- intr_mask |= (0x1ULL << (srn + i)); ++ for (i = 0; i < num_rings; i++) { ++ intr_mask |= BIT_ULL(srn + i); ++ reg_val = octep_read_csr64(oct, ++ CN93_SDP_R_IN_INT_LEVELS(srn + i)); ++ reg_val &= ~CN93_INT_ENA_BIT; ++ octep_write_csr64(oct, ++ CN93_SDP_R_IN_INT_LEVELS(srn + i), reg_val); ++ ++ reg_val = octep_read_csr64(oct, ++ CN93_SDP_R_OUT_INT_LEVELS(srn + i)); ++ reg_val &= ~CN93_INT_ENA_BIT; ++ octep_write_csr64(oct, ++ CN93_SDP_R_OUT_INT_LEVELS(srn + i), reg_val); ++ } + + octep_write_csr64(oct, CN93_SDP_EPF_IRERR_RINT_ENA_W1C, intr_mask); + octep_write_csr64(oct, CN93_SDP_EPF_ORERR_RINT_ENA_W1C, intr_mask); +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c b/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c +index 5de0b5ecbc5fd..07e00887c6940 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c +@@ -720,14 +720,26 @@ static void octep_enable_interrupts_cnxk_pf(struct octep_device *oct) + /* Disable all interrupts */ + static void octep_disable_interrupts_cnxk_pf(struct octep_device *oct) + { +- u64 intr_mask = 0ULL; ++ u64 reg_val, intr_mask = 0ULL; + int srn, num_rings, i; + + srn = CFG_GET_PORTS_PF_SRN(oct->conf); + num_rings = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); + +- for (i = 0; i < num_rings; i++) +- intr_mask |= (0x1ULL << (srn + i)); ++ for (i = 0; i < num_rings; i++) { ++ intr_mask |= BIT_ULL(srn + i); ++ reg_val = octep_read_csr64(oct, ++ CNXK_SDP_R_IN_INT_LEVELS(srn + i)); ++ reg_val &= ~CNXK_INT_ENA_BIT; ++ octep_write_csr64(oct, ++ CNXK_SDP_R_IN_INT_LEVELS(srn + i), reg_val); ++ ++ reg_val = octep_read_csr64(oct, ++ CNXK_SDP_R_OUT_INT_LEVELS(srn + i)); ++ reg_val &= ~CNXK_INT_ENA_BIT; ++ octep_write_csr64(oct, ++ CNXK_SDP_R_OUT_INT_LEVELS(srn + i), reg_val); ++ } + + octep_write_csr64(oct, CNXK_SDP_EPF_IRERR_RINT_ENA_W1C, intr_mask); + octep_write_csr64(oct, CNXK_SDP_EPF_ORERR_RINT_ENA_W1C, intr_mask); +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cn9k_pf.h b/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cn9k_pf.h +index ca473502d7a02..95f1dfff90cce 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cn9k_pf.h ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cn9k_pf.h +@@ -386,5 +386,6 @@ + #define CN93_PEM_BAR4_INDEX 7 + #define CN93_PEM_BAR4_INDEX_SIZE 0x400000ULL + #define CN93_PEM_BAR4_INDEX_OFFSET (CN93_PEM_BAR4_INDEX * CN93_PEM_BAR4_INDEX_SIZE) ++#define CN93_INT_ENA_BIT BIT_ULL(62) + + #endif /* _OCTEP_REGS_CN9K_PF_H_ */ +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h b/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h +index e637d7c8224d4..4d172a552f80c 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h +@@ -412,5 +412,6 @@ + #define CNXK_PEM_BAR4_INDEX 7 + #define CNXK_PEM_BAR4_INDEX_SIZE 0x400000ULL + #define CNXK_PEM_BAR4_INDEX_OFFSET (CNXK_PEM_BAR4_INDEX * CNXK_PEM_BAR4_INDEX_SIZE) ++#define CNXK_INT_ENA_BIT BIT_ULL(62) + + #endif /* _OCTEP_REGS_CNXK_PF_H_ */ +-- +2.51.0 + diff --git a/queue-6.19/octeon_ep-ensure-dbell-baddr-updation.patch b/queue-6.19/octeon_ep-ensure-dbell-baddr-updation.patch new file mode 100644 index 0000000000..e5675c2745 --- /dev/null +++ b/queue-6.19/octeon_ep-ensure-dbell-baddr-updation.patch @@ -0,0 +1,186 @@ +From 04da88aeaa1b54f138e6c0fcf6cd399752dc97f0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 11:15:07 +0000 +Subject: octeon_ep: ensure dbell BADDR updation + +From: Vimlesh Kumar + +[ Upstream commit ce8fe3fc4f99efd872120301c0f72f2e90ab9769 ] + +Make sure the OUT DBELL base address reflects the +latest values written to it. + +Fix: +Add a wait until the OUT DBELL base address register +is updated with the DMA ring descriptor address, +and modify the setup_oq function to properly +handle failures. + +Fixes: 0807dc76f3bf5 ("octeon_ep: support Octeon CN10K devices") +Signed-off-by: Sathesh Edara +Signed-off-by: Shinas Rasheed +Signed-off-by: Vimlesh Kumar +Link: https://patch.msgid.link/20260206111510.1045092-3-vimleshk@marvell.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + .../marvell/octeon_ep/octep_cn9k_pf.c | 3 +- + .../marvell/octeon_ep/octep_cnxk_pf.c | 46 +++++++++++++++---- + .../ethernet/marvell/octeon_ep/octep_main.h | 2 +- + .../net/ethernet/marvell/octeon_ep/octep_rx.c | 8 +++- + 4 files changed, 48 insertions(+), 11 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c b/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c +index f0bcb5f3c1474..01e82d0b6b2cd 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c +@@ -307,7 +307,7 @@ static void octep_setup_iq_regs_cn93_pf(struct octep_device *oct, int iq_no) + } + + /* Setup registers for a hardware Rx Queue */ +-static void octep_setup_oq_regs_cn93_pf(struct octep_device *oct, int oq_no) ++static int octep_setup_oq_regs_cn93_pf(struct octep_device *oct, int oq_no) + { + u64 reg_val; + u64 oq_ctl = 0ULL; +@@ -355,6 +355,7 @@ static void octep_setup_oq_regs_cn93_pf(struct octep_device *oct, int oq_no) + reg_val = ((u64)time_threshold << 32) | + CFG_GET_OQ_INTR_PKT(oct->conf); + octep_write_csr64(oct, CN93_SDP_R_OUT_INT_LEVELS(oq_no), reg_val); ++ return 0; + } + + /* Setup registers for a PF mailbox */ +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c b/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c +index 07e00887c6940..09a3f1d0645b8 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + + #include "octep_config.h" + #include "octep_main.h" +@@ -327,12 +328,14 @@ static void octep_setup_iq_regs_cnxk_pf(struct octep_device *oct, int iq_no) + } + + /* Setup registers for a hardware Rx Queue */ +-static void octep_setup_oq_regs_cnxk_pf(struct octep_device *oct, int oq_no) ++static int octep_setup_oq_regs_cnxk_pf(struct octep_device *oct, int oq_no) + { +- u64 reg_val; +- u64 oq_ctl = 0ULL; +- u32 time_threshold = 0; + struct octep_oq *oq = oct->oq[oq_no]; ++ unsigned long t_out_jiffies; ++ u32 time_threshold = 0; ++ u64 oq_ctl = 0ULL; ++ u64 reg_ba_val; ++ u64 reg_val; + + oq_no += CFG_GET_PORTS_PF_SRN(oct->conf); + reg_val = octep_read_csr64(oct, CNXK_SDP_R_OUT_CONTROL(oq_no)); +@@ -343,6 +346,36 @@ static void octep_setup_oq_regs_cnxk_pf(struct octep_device *oct, int oq_no) + reg_val = octep_read_csr64(oct, CNXK_SDP_R_OUT_CONTROL(oq_no)); + } while (!(reg_val & CNXK_R_OUT_CTL_IDLE)); + } ++ octep_write_csr64(oct, CNXK_SDP_R_OUT_WMARK(oq_no), oq->max_count); ++ /* Wait for WMARK to get applied */ ++ usleep_range(10, 15); ++ ++ octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_BADDR(oq_no), ++ oq->desc_ring_dma); ++ octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_RSIZE(oq_no), ++ oq->max_count); ++ reg_ba_val = octep_read_csr64(oct, CNXK_SDP_R_OUT_SLIST_BADDR(oq_no)); ++ ++ if (reg_ba_val != oq->desc_ring_dma) { ++ t_out_jiffies = jiffies + 10 * HZ; ++ do { ++ if (reg_ba_val == ULLONG_MAX) ++ return -EFAULT; ++ octep_write_csr64(oct, ++ CNXK_SDP_R_OUT_SLIST_BADDR(oq_no), ++ oq->desc_ring_dma); ++ octep_write_csr64(oct, ++ CNXK_SDP_R_OUT_SLIST_RSIZE(oq_no), ++ oq->max_count); ++ reg_ba_val = ++ octep_read_csr64(oct, ++ CNXK_SDP_R_OUT_SLIST_BADDR(oq_no)); ++ } while ((reg_ba_val != oq->desc_ring_dma) && ++ time_before(jiffies, t_out_jiffies)); ++ ++ if (reg_ba_val != oq->desc_ring_dma) ++ return -EAGAIN; ++ } + + reg_val &= ~(CNXK_R_OUT_CTL_IMODE); + reg_val &= ~(CNXK_R_OUT_CTL_ROR_P); +@@ -356,10 +389,6 @@ static void octep_setup_oq_regs_cnxk_pf(struct octep_device *oct, int oq_no) + reg_val |= (CNXK_R_OUT_CTL_ES_P); + + octep_write_csr64(oct, CNXK_SDP_R_OUT_CONTROL(oq_no), reg_val); +- octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_BADDR(oq_no), +- oq->desc_ring_dma); +- octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_RSIZE(oq_no), +- oq->max_count); + + oq_ctl = octep_read_csr64(oct, CNXK_SDP_R_OUT_CONTROL(oq_no)); + +@@ -385,6 +414,7 @@ static void octep_setup_oq_regs_cnxk_pf(struct octep_device *oct, int oq_no) + reg_val &= ~0xFFFFFFFFULL; + reg_val |= CFG_GET_OQ_WMARK(oct->conf); + octep_write_csr64(oct, CNXK_SDP_R_OUT_WMARK(oq_no), reg_val); ++ return 0; + } + + /* Setup registers for a PF mailbox */ +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_main.h b/drivers/net/ethernet/marvell/octeon_ep/octep_main.h +index 81ac4267811c8..35d0ff289a70d 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_main.h ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_main.h +@@ -77,7 +77,7 @@ struct octep_pci_win_regs { + + struct octep_hw_ops { + void (*setup_iq_regs)(struct octep_device *oct, int q); +- void (*setup_oq_regs)(struct octep_device *oct, int q); ++ int (*setup_oq_regs)(struct octep_device *oct, int q); + void (*setup_mbox_regs)(struct octep_device *oct, int mbox); + + irqreturn_t (*mbox_intr_handler)(void *ioq_vector); +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c b/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c +index 82b6b19e76b47..f2a7c6a76c742 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c +@@ -12,6 +12,8 @@ + #include "octep_config.h" + #include "octep_main.h" + ++static void octep_oq_free_ring_buffers(struct octep_oq *oq); ++ + static void octep_oq_reset_indices(struct octep_oq *oq) + { + oq->host_read_idx = 0; +@@ -170,11 +172,15 @@ static int octep_setup_oq(struct octep_device *oct, int q_no) + goto oq_fill_buff_err; + + octep_oq_reset_indices(oq); +- oct->hw_ops.setup_oq_regs(oct, q_no); ++ if (oct->hw_ops.setup_oq_regs(oct, q_no)) ++ goto oq_setup_err; ++ + oct->num_oqs++; + + return 0; + ++oq_setup_err: ++ octep_oq_free_ring_buffers(oq); + oq_fill_buff_err: + vfree(oq->buff_info); + oq->buff_info = NULL; +-- +2.51.0 + diff --git a/queue-6.19/octeon_ep_vf-ensure-dbell-baddr-updation.patch b/queue-6.19/octeon_ep_vf-ensure-dbell-baddr-updation.patch new file mode 100644 index 0000000000..2683ec9d9a --- /dev/null +++ b/queue-6.19/octeon_ep_vf-ensure-dbell-baddr-updation.patch @@ -0,0 +1,174 @@ +From 17b8543bccfd0ead7ced7316846577af5757940e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 11:15:08 +0000 +Subject: octeon_ep_vf: ensure dbell BADDR updation + +From: Vimlesh Kumar + +[ Upstream commit 484e834d53cffa91c311631271f83130cf6e9e7c ] + +Make sure the OUT DBELL base address reflects the +latest values written to it. + +Fix: +Add a wait until the OUT DBELL base address register +is updated with the DMA ring descriptor address, +and modify the setup_oq function to properly +handle failures. + +Fixes: 2c0c32c72be29 ("octeon_ep_vf: add hardware configuration APIs") +Signed-off-by: Sathesh Edara +Signed-off-by: Shinas Rasheed +Signed-off-by: Vimlesh Kumar +Link: https://patch.msgid.link/20260206111510.1045092-4-vimleshk@marvell.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + .../marvell/octeon_ep_vf/octep_vf_cn9k.c | 3 +- + .../marvell/octeon_ep_vf/octep_vf_cnxk.c | 39 +++++++++++++++++-- + .../marvell/octeon_ep_vf/octep_vf_main.h | 2 +- + .../marvell/octeon_ep_vf/octep_vf_rx.c | 8 +++- + 4 files changed, 46 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cn9k.c b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cn9k.c +index 88937fce75f14..4c769b27c2789 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cn9k.c ++++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cn9k.c +@@ -196,7 +196,7 @@ static void octep_vf_setup_iq_regs_cn93(struct octep_vf_device *oct, int iq_no) + } + + /* Setup registers for a hardware Rx Queue */ +-static void octep_vf_setup_oq_regs_cn93(struct octep_vf_device *oct, int oq_no) ++static int octep_vf_setup_oq_regs_cn93(struct octep_vf_device *oct, int oq_no) + { + struct octep_vf_oq *oq = oct->oq[oq_no]; + u32 time_threshold = 0; +@@ -239,6 +239,7 @@ static void octep_vf_setup_oq_regs_cn93(struct octep_vf_device *oct, int oq_no) + time_threshold = CFG_GET_OQ_INTR_TIME(oct->conf); + reg_val = ((u64)time_threshold << 32) | CFG_GET_OQ_INTR_PKT(oct->conf); + octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_INT_LEVELS(oq_no), reg_val); ++ return 0; + } + + /* Setup registers for a VF mailbox */ +diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cnxk.c b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cnxk.c +index 1f79dfad42c62..a968b93a67943 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cnxk.c ++++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_cnxk.c +@@ -199,11 +199,13 @@ static void octep_vf_setup_iq_regs_cnxk(struct octep_vf_device *oct, int iq_no) + } + + /* Setup registers for a hardware Rx Queue */ +-static void octep_vf_setup_oq_regs_cnxk(struct octep_vf_device *oct, int oq_no) ++static int octep_vf_setup_oq_regs_cnxk(struct octep_vf_device *oct, int oq_no) + { + struct octep_vf_oq *oq = oct->oq[oq_no]; ++ unsigned long t_out_jiffies; + u32 time_threshold = 0; + u64 oq_ctl = ULL(0); ++ u64 reg_ba_val; + u64 reg_val; + + reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_CONTROL(oq_no)); +@@ -214,6 +216,38 @@ static void octep_vf_setup_oq_regs_cnxk(struct octep_vf_device *oct, int oq_no) + reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_CONTROL(oq_no)); + } while (!(reg_val & CNXK_VF_R_OUT_CTL_IDLE)); + } ++ octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_WMARK(oq_no), ++ oq->max_count); ++ /* Wait for WMARK to get applied */ ++ usleep_range(10, 15); ++ ++ octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_SLIST_BADDR(oq_no), ++ oq->desc_ring_dma); ++ octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_SLIST_RSIZE(oq_no), ++ oq->max_count); ++ reg_ba_val = octep_vf_read_csr64(oct, ++ CNXK_VF_SDP_R_OUT_SLIST_BADDR(oq_no)); ++ if (reg_ba_val != oq->desc_ring_dma) { ++ t_out_jiffies = jiffies + 10 * HZ; ++ do { ++ if (reg_ba_val == ULLONG_MAX) ++ return -EFAULT; ++ octep_vf_write_csr64(oct, ++ CNXK_VF_SDP_R_OUT_SLIST_BADDR ++ (oq_no), oq->desc_ring_dma); ++ octep_vf_write_csr64(oct, ++ CNXK_VF_SDP_R_OUT_SLIST_RSIZE ++ (oq_no), oq->max_count); ++ reg_ba_val = ++ octep_vf_read_csr64(oct, ++ CNXK_VF_SDP_R_OUT_SLIST_BADDR ++ (oq_no)); ++ } while ((reg_ba_val != oq->desc_ring_dma) && ++ time_before(jiffies, t_out_jiffies)); ++ ++ if (reg_ba_val != oq->desc_ring_dma) ++ return -EAGAIN; ++ } + + reg_val &= ~(CNXK_VF_R_OUT_CTL_IMODE); + reg_val &= ~(CNXK_VF_R_OUT_CTL_ROR_P); +@@ -227,8 +261,6 @@ static void octep_vf_setup_oq_regs_cnxk(struct octep_vf_device *oct, int oq_no) + reg_val |= (CNXK_VF_R_OUT_CTL_ES_P); + + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_CONTROL(oq_no), reg_val); +- octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_SLIST_BADDR(oq_no), oq->desc_ring_dma); +- octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_SLIST_RSIZE(oq_no), oq->max_count); + + oq_ctl = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_CONTROL(oq_no)); + /* Clear the ISIZE and BSIZE (22-0) */ +@@ -250,6 +282,7 @@ static void octep_vf_setup_oq_regs_cnxk(struct octep_vf_device *oct, int oq_no) + reg_val &= ~GENMASK_ULL(31, 0); + reg_val |= CFG_GET_OQ_WMARK(oct->conf); + octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_WMARK(oq_no), reg_val); ++ return 0; + } + + /* Setup registers for a VF mailbox */ +diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.h b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.h +index b9f13506f4620..c74cd2369e90d 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.h ++++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.h +@@ -55,7 +55,7 @@ struct octep_vf_mmio { + + struct octep_vf_hw_ops { + void (*setup_iq_regs)(struct octep_vf_device *oct, int q); +- void (*setup_oq_regs)(struct octep_vf_device *oct, int q); ++ int (*setup_oq_regs)(struct octep_vf_device *oct, int q); + void (*setup_mbox_regs)(struct octep_vf_device *oct, int mbox); + + irqreturn_t (*non_ioq_intr_handler)(void *ioq_vector); +diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c +index d70c8be3cfc40..6f865dbbba6c6 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c ++++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c +@@ -12,6 +12,8 @@ + #include "octep_vf_config.h" + #include "octep_vf_main.h" + ++static void octep_vf_oq_free_ring_buffers(struct octep_vf_oq *oq); ++ + static void octep_vf_oq_reset_indices(struct octep_vf_oq *oq) + { + oq->host_read_idx = 0; +@@ -171,11 +173,15 @@ static int octep_vf_setup_oq(struct octep_vf_device *oct, int q_no) + goto oq_fill_buff_err; + + octep_vf_oq_reset_indices(oq); +- oct->hw_ops.setup_oq_regs(oct, q_no); ++ if (oct->hw_ops.setup_oq_regs(oct, q_no)) ++ goto oq_setup_err; ++ + oct->num_oqs++; + + return 0; + ++oq_setup_err: ++ octep_vf_oq_free_ring_buffers(oq); + oq_fill_buff_err: + vfree(oq->buff_info); + oq->buff_info = NULL; +-- +2.51.0 + diff --git a/queue-6.19/octeontx2-af-fix-pf-driver-crash-with-kexec-kernel-b.patch b/queue-6.19/octeontx2-af-fix-pf-driver-crash-with-kexec-kernel-b.patch new file mode 100644 index 0000000000..c82ffbfec6 --- /dev/null +++ b/queue-6.19/octeontx2-af-fix-pf-driver-crash-with-kexec-kernel-b.patch @@ -0,0 +1,62 @@ +From bfc7062157252a92f767c1ce27b3dc60bc561a2d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 10:37:01 +0530 +Subject: octeontx2-af: Fix PF driver crash with kexec kernel booting + +From: Anshumali Gaur + +[ Upstream commit 2d2d574309e3ae84ee794869a5da8b4c38753a94 ] + +During a kexec reboot the hardware is not power-cycled, so AF state from +the old kernel can persist into the new kernel. When AF and PF drivers +are built as modules, the PF driver may probe before AF reinitializes +the hardware. + +The PF driver treats the RVUM block revision as an indication that AF +initialization is complete. If this value is left uncleared at shutdown, +PF may incorrectly assume AF is ready and access stale hardware state, +leading to a crash. + +Clear the RVUM block revision during AF shutdown to avoid PF +mis-detecting AF readiness after kexec. + +Fixes: 54494aa5d1e6 ("octeontx2-af: Add Marvell OcteonTX2 RVU AF driver") +Signed-off-by: Anshumali Gaur +Reviewed-by: Jacob Keller +Link: https://patch.msgid.link/20260203050701.2616685-1-agaur@marvell.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/octeontx2/af/rvu.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +index 747fbdf2a908f..8530df8b3fdaf 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +@@ -3632,11 +3632,22 @@ static void rvu_remove(struct pci_dev *pdev) + devm_kfree(&pdev->dev, rvu); + } + ++static void rvu_shutdown(struct pci_dev *pdev) ++{ ++ struct rvu *rvu = pci_get_drvdata(pdev); ++ ++ if (!rvu) ++ return; ++ ++ rvu_clear_rvum_blk_revid(rvu); ++} ++ + static struct pci_driver rvu_driver = { + .name = DRV_NAME, + .id_table = rvu_id_table, + .probe = rvu_probe, + .remove = rvu_remove, ++ .shutdown = rvu_shutdown, + }; + + static int __init rvu_init_module(void) +-- +2.51.0 + diff --git a/queue-6.19/octeontx2-pf-unregister-devlink-on-probe-failure.patch b/queue-6.19/octeontx2-pf-unregister-devlink-on-probe-failure.patch new file mode 100644 index 0000000000..75cfe2ad94 --- /dev/null +++ b/queue-6.19/octeontx2-pf-unregister-devlink-on-probe-failure.patch @@ -0,0 +1,36 @@ +From 9f2c097597bb8fbb9509bf92c918a5c0e1284820 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 23:56:45 +0530 +Subject: octeontx2-pf: Unregister devlink on probe failure + +From: Hariprasad Kelam + +[ Upstream commit 943f3b8bfbf297cf74392b50a7108ce1fe4cbd8c ] + +When probe fails after devlink registration, the missing devlink unregister +call causing a memory leak. + +Fixes: 2da489432747 ("octeontx2-pf: devlink params support to set mcam entry count") +Signed-off-by: Hariprasad Kelam +Link: https://patch.msgid.link/20260206182645.4032737-1-hkelam@marvell.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +index 6b2d8559f0eb1..444bb67494ab7 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c ++++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +@@ -3315,6 +3315,7 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id) + err_sriov_cleannup: + otx2_sriov_vfcfg_cleanup(pf); + err_pf_sriov_init: ++ otx2_unregister_dl(pf); + otx2_shutdown_tc(pf); + err_mcam_flow_del: + otx2_mcam_flow_del(pf); +-- +2.51.0 + diff --git a/queue-6.19/of-unittest-fix-possible-null-pointer-dereferences-i.patch b/queue-6.19/of-unittest-fix-possible-null-pointer-dereferences-i.patch new file mode 100644 index 0000000000..6a73578042 --- /dev/null +++ b/queue-6.19/of-unittest-fix-possible-null-pointer-dereferences-i.patch @@ -0,0 +1,49 @@ +From 4fc12f36682fc840e58c8558749cb5199a6e4f2b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Jan 2026 15:14:38 +0800 +Subject: of: unittest: fix possible null-pointer dereferences in + of_unittest_property_copy() + +From: Tuo Li + +[ Upstream commit d289cb7fcefe41a54d8f9c6d0e0947f5f82b15c6 ] + +This function first duplicates p1 and p2 into new, and then checks whether +the duplication succeeds. However, if the duplication fails (e.g., +kzalloc() returns NULL in __of_prop_dup()), new will be NULL but is still +dereferenced in __of_prop_free(). To ensure that the unit test continues to +run even when duplication fails, add a NULL check before calling +__of_prop_free(). + +Fixes: 1c5e3d9bf33b ("of: Add a helper to free property struct") +Signed-off-by: Tuo Li +Link: https://patch.msgid.link/20260105071438.156186-1-islituo@gmail.com +Signed-off-by: Rob Herring (Arm) +Signed-off-by: Sasha Levin +--- + drivers/of/unittest.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c +index 3b773aaf9d050..9c184e93f50c6 100644 +--- a/drivers/of/unittest.c ++++ b/drivers/of/unittest.c +@@ -804,11 +804,13 @@ static void __init of_unittest_property_copy(void) + + new = __of_prop_dup(&p1, GFP_KERNEL); + unittest(new && propcmp(&p1, new), "empty property didn't copy correctly\n"); +- __of_prop_free(new); ++ if (new) ++ __of_prop_free(new); + + new = __of_prop_dup(&p2, GFP_KERNEL); + unittest(new && propcmp(&p2, new), "non-empty property didn't copy correctly\n"); +- __of_prop_free(new); ++ if (new) ++ __of_prop_free(new); + #endif + } + +-- +2.51.0 + diff --git a/queue-6.19/opp-return-correct-value-in-dev_pm_opp_get_level.patch b/queue-6.19/opp-return-correct-value-in-dev_pm_opp_get_level.patch new file mode 100644 index 0000000000..4518b4f959 --- /dev/null +++ b/queue-6.19/opp-return-correct-value-in-dev_pm_opp_get_level.patch @@ -0,0 +1,40 @@ +From c4fa3355882b1a263e6ab5d4cb25f26d3314e618 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 14:03:44 +0000 +Subject: OPP: Return correct value in dev_pm_opp_get_level + +From: Aleks Todorov + +[ Upstream commit 0b7277e02dabba2a9921a7f4761ae6e627e7297a ] + +Commit 073d3d2ca7d4 ("OPP: Level zero is valid") modified the +documentation for this function to indicate that errors should return a +non-zero value to avoid colliding with the OPP level zero, however +forgot to actually update the return. + +No in-tree kernel code depends on the error value being 0. + +Fixes: 073d3d2ca7d4 ("OPP: Level zero is valid") +Signed-off-by: Aleks Todorov +Signed-off-by: Viresh Kumar +Signed-off-by: Sasha Levin +--- + drivers/opp/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/opp/core.c b/drivers/opp/core.c +index dbebb8c829bcb..ae43c656f108c 100644 +--- a/drivers/opp/core.c ++++ b/drivers/opp/core.c +@@ -241,7 +241,7 @@ unsigned int dev_pm_opp_get_level(struct dev_pm_opp *opp) + { + if (IS_ERR_OR_NULL(opp) || !opp->available) { + pr_err("%s: Invalid parameters\n", __func__); +- return 0; ++ return U32_MAX; + } + + return opp->level; +-- +2.51.0 + diff --git a/queue-6.19/ovl-fix-uninit-value-in-ovl_fill_real.patch b/queue-6.19/ovl-fix-uninit-value-in-ovl_fill_real.patch new file mode 100644 index 0000000000..dd02ca1095 --- /dev/null +++ b/queue-6.19/ovl-fix-uninit-value-in-ovl_fill_real.patch @@ -0,0 +1,58 @@ +From cc22f64d2576cbafc7d078ea25fdf32e7d5eed96 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 14:24:04 +0100 +Subject: ovl: Fix uninit-value in ovl_fill_real + +From: Qing Wang + +[ Upstream commit 1992330d90dd766fcf1730fd7bf2d6af65370ac4 ] + +Syzbot reported a KMSAN uninit-value issue in ovl_fill_real. + +This iusse's call chain is: +__do_sys_getdents64() + -> iterate_dir() + ... + -> ext4_readdir() + -> fscrypt_fname_alloc_buffer() // alloc + -> fscrypt_fname_disk_to_usr // write without tail '\0' + -> dir_emit() + -> ovl_fill_real() // read by strcmp() + +The string is used to store the decrypted directory entry name for an +encrypted inode. As shown in the call chain, fscrypt_fname_disk_to_usr() +write it without null-terminate. However, ovl_fill_real() uses strcmp() to +compare the name against "..", which assumes a null-terminated string and +may trigger a KMSAN uninit-value warning when the buffer tail contains +uninit data. + +Reported-by: syzbot+d130f98b2c265fae5297@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=d130f98b2c265fae5297 +Fixes: 4edb83bb1041 ("ovl: constant d_ino for non-merge dirs") +Signed-off-by: Qing Wang +Signed-off-by: Amir Goldstein +Link: https://patch.msgid.link/20260128132406.23768-2-amir73il@gmail.com +Acked-by: Miklos Szeredi +Reviewed-by: Eric Biggers +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/overlayfs/readdir.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c +index 160960bb0ad0b..724ec9d93fc82 100644 +--- a/fs/overlayfs/readdir.c ++++ b/fs/overlayfs/readdir.c +@@ -755,7 +755,7 @@ static bool ovl_fill_real(struct dir_context *ctx, const char *name, + struct dir_context *orig_ctx = rdt->orig_ctx; + bool res; + +- if (rdt->parent_ino && strcmp(name, "..") == 0) { ++ if (rdt->parent_ino && namelen == 2 && !strncmp(name, "..", 2)) { + ino = rdt->parent_ino; + } else if (rdt->cache) { + struct ovl_cache_entry *p; +-- +2.51.0 + diff --git a/queue-6.19/partial-revert-x86-xen-fix-balloon-target-initializa.patch b/queue-6.19/partial-revert-x86-xen-fix-balloon-target-initializa.patch new file mode 100644 index 0000000000..7ede0c12ac --- /dev/null +++ b/queue-6.19/partial-revert-x86-xen-fix-balloon-target-initializa.patch @@ -0,0 +1,140 @@ +From 836936abc99825ca2d91c07e4aada3f85432226b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 12:05:08 +0100 +Subject: Partial revert "x86/xen: fix balloon target initialization for PVH + dom0" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Roger Pau Monne + +[ Upstream commit 0949c646d64697428ff6257d52efa5093566868d ] + +This partially reverts commit 87af633689ce16ddb166c80f32b120e50b1295de so +the current memory target for PV guests is still fetched from +start_info->nr_pages, which matches exactly what the toolstack sets the +initial memory target to. + +Using get_num_physpages() is possible on PV also, but needs adjusting to +take into account the ISA hole and the PFN at 0 not considered usable +memory despite being populated, and hence would need extra adjustments. +Instead of carrying those extra adjustments switch back to the previous +code. That leaves Linux with a difference in how current memory target is +obtained for HVM vs PV, but that's better than adding extra logic just for +PV. + +However if switching to start_info->nr_pages for PV domains we need to +differentiate between released pages (freed back to the hypervisor) as +opposed to pages in the physmap which are not populated to start with. +Introduce a new xen_unpopulated_pages to account for papges that have +never been populated, and hence in the PV case don't need subtracting. + +Fixes: 87af633689ce ("x86/xen: fix balloon target initialization for PVH dom0") +Reported-by: James Dingwall +Signed-off-by: Roger Pau Monné +Reviewed-by: Juergen Gross +Signed-off-by: Juergen Gross +Message-ID: <20260128110510.46425-2-roger.pau@citrix.com> +Signed-off-by: Sasha Levin +--- + arch/x86/xen/enlighten.c | 2 +- + drivers/xen/balloon.c | 19 +++++++++++++++---- + drivers/xen/unpopulated-alloc.c | 3 +++ + include/xen/xen.h | 2 ++ + 4 files changed, 21 insertions(+), 5 deletions(-) + +diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c +index 53282dc7d5ac5..23b91bf9b6630 100644 +--- a/arch/x86/xen/enlighten.c ++++ b/arch/x86/xen/enlighten.c +@@ -470,7 +470,7 @@ int __init arch_xen_unpopulated_init(struct resource **res) + * driver to know how much of the physmap is unpopulated and + * set an accurate initial memory target. + */ +- xen_released_pages += xen_extra_mem[i].n_pfns; ++ xen_unpopulated_pages += xen_extra_mem[i].n_pfns; + /* Zero so region is not also added to the balloon driver. */ + xen_extra_mem[i].n_pfns = 0; + } +diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c +index 49c3f99263943..8c44a25a7d2b9 100644 +--- a/drivers/xen/balloon.c ++++ b/drivers/xen/balloon.c +@@ -724,6 +724,7 @@ static int __init balloon_add_regions(void) + static int __init balloon_init(void) + { + struct task_struct *task; ++ unsigned long current_pages; + int rc; + + if (!xen_domain()) +@@ -731,12 +732,18 @@ static int __init balloon_init(void) + + pr_info("Initialising balloon driver\n"); + +- if (xen_released_pages >= get_num_physpages()) { +- WARN(1, "Released pages underflow current target"); +- return -ERANGE; ++ if (xen_pv_domain()) { ++ if (xen_released_pages >= xen_start_info->nr_pages) ++ goto underflow; ++ current_pages = min(xen_start_info->nr_pages - ++ xen_released_pages, max_pfn); ++ } else { ++ if (xen_unpopulated_pages >= get_num_physpages()) ++ goto underflow; ++ current_pages = get_num_physpages() - xen_unpopulated_pages; + } + +- balloon_stats.current_pages = get_num_physpages() - xen_released_pages; ++ balloon_stats.current_pages = current_pages; + balloon_stats.target_pages = balloon_stats.current_pages; + balloon_stats.balloon_low = 0; + balloon_stats.balloon_high = 0; +@@ -767,6 +774,10 @@ static int __init balloon_init(void) + xen_balloon_init(); + + return 0; ++ ++ underflow: ++ WARN(1, "Released pages underflow current target"); ++ return -ERANGE; + } + subsys_initcall(balloon_init); + +diff --git a/drivers/xen/unpopulated-alloc.c b/drivers/xen/unpopulated-alloc.c +index d6fc2aefe2646..1dc0b495c8e59 100644 +--- a/drivers/xen/unpopulated-alloc.c ++++ b/drivers/xen/unpopulated-alloc.c +@@ -18,6 +18,9 @@ static unsigned int list_count; + + static struct resource *target_resource; + ++/* Pages to subtract from the memory count when setting balloon target. */ ++unsigned long xen_unpopulated_pages __initdata; ++ + /* + * If arch is not happy with system "iomem_resource" being used for + * the region allocation it can provide it's own view by creating specific +diff --git a/include/xen/xen.h b/include/xen/xen.h +index 61854e3f28377..f280c5dcf9236 100644 +--- a/include/xen/xen.h ++++ b/include/xen/xen.h +@@ -69,11 +69,13 @@ extern u64 xen_saved_max_mem_size; + #endif + + #ifdef CONFIG_XEN_UNPOPULATED_ALLOC ++extern unsigned long xen_unpopulated_pages; + int xen_alloc_unpopulated_pages(unsigned int nr_pages, struct page **pages); + void xen_free_unpopulated_pages(unsigned int nr_pages, struct page **pages); + #include + int arch_xen_unpopulated_init(struct resource **res); + #else ++#define xen_unpopulated_pages 0UL + #include + static inline int xen_alloc_unpopulated_pages(unsigned int nr_pages, + struct page **pages) +-- +2.51.0 + diff --git a/queue-6.19/pci-acpi-restrict-program_hpx_type2-to-aer-bits.patch b/queue-6.19/pci-acpi-restrict-program_hpx_type2-to-aer-bits.patch new file mode 100644 index 0000000000..2e5330fe92 --- /dev/null +++ b/queue-6.19/pci-acpi-restrict-program_hpx_type2-to-aer-bits.patch @@ -0,0 +1,200 @@ +From 1e117d6e96aa1b2aa50bda9ca551e1450fd56f7b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 18:52:33 +0100 +Subject: PCI/ACPI: Restrict program_hpx_type2() to AER bits +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: HÃ¥kon Bugge + +[ Upstream commit 9abf79c8d7b40db0e5a34aa8c744ea60ff9a3fcf ] + +Previously program_hpx_type2() applied PCIe settings unconditionally, +which could incorrectly change bits like Extended Tag Field Enable and +Enable Relaxed Ordering. + +When _HPX was added to ACPI r3.0, the intent of the PCIe Setting +Record (Type 2) in sec 6.2.7.3 was to configure AER registers when the +OS does not own the AER Capability: + + The PCI Express setting record contains ... [the AER] Uncorrectable + Error Mask, Uncorrectable Error Severity, Correctable Error Mask + ... to be used when configuring registers in the Advanced Error + Reporting Extended Capability Structure ... + + OSPM [1] will only evaluate _HPX with Setting Record – Type 2 if + OSPM is not controlling the PCI Express Advanced Error Reporting + capability. + +ACPI r3.0b, sec 6.2.7.3, added more AER registers, including registers +in the PCIe Capability with AER-related bits, and the restriction that +the OS use this only when it owns PCIe native hotplug: + + ... when configuring PCI Express registers in the Advanced Error + Reporting Extended Capability Structure *or PCI Express Capability + Structure* ... + + An OS that has assumed ownership of native hot plug but does not + ... have ownership of the AER register set must use ... the Type 2 + record to program the AER registers ... + + However, since the Type 2 record also includes register bits that + have functions other than AER, the OS must ignore values ... that + are not applicable. + +Restrict program_hpx_type2() to only the intended purpose: + + - Apply settings only when OS owns PCIe native hotplug but not AER, + + - Only touch the AER-related bits (Error Reporting Enables) in Device + Control + + - Don't touch Link Control at all, since nothing there seems AER-related, + but log _HPX settings for debugging purposes + +Note that Read Completion Boundary is now configured elsewhere, since it is +unrelated to _HPX. + +[1] Operating System-directed configuration and Power Management + +Fixes: 40abb96c51bb ("[PATCH] pciehp: Fix programming hotplug parameters") +Signed-off-by: HÃ¥kon Bugge +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260129175237.727059-3-haakon.bugge@oracle.com +Signed-off-by: Sasha Levin +--- + drivers/pci/pci-acpi.c | 59 +++++++++++++++++------------------------- + drivers/pci/pci.h | 3 +++ + drivers/pci/pcie/aer.c | 3 --- + 3 files changed, 27 insertions(+), 38 deletions(-) + +diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c +index 9369377725fa0..0162acfb57896 100644 +--- a/drivers/pci/pci-acpi.c ++++ b/drivers/pci/pci-acpi.c +@@ -271,21 +271,6 @@ static acpi_status decode_type1_hpx_record(union acpi_object *record, + return AE_OK; + } + +-static bool pcie_root_rcb_set(struct pci_dev *dev) +-{ +- struct pci_dev *rp = pcie_find_root_port(dev); +- u16 lnkctl; +- +- if (!rp) +- return false; +- +- pcie_capability_read_word(rp, PCI_EXP_LNKCTL, &lnkctl); +- if (lnkctl & PCI_EXP_LNKCTL_RCB) +- return true; +- +- return false; +-} +- + /* _HPX PCI Express Setting Record (Type 2) */ + struct hpx_type2 { + u32 revision; +@@ -311,6 +296,7 @@ static void program_hpx_type2(struct pci_dev *dev, struct hpx_type2 *hpx) + { + int pos; + u32 reg32; ++ const struct pci_host_bridge *host; + + if (!hpx) + return; +@@ -318,6 +304,15 @@ static void program_hpx_type2(struct pci_dev *dev, struct hpx_type2 *hpx) + if (!pci_is_pcie(dev)) + return; + ++ host = pci_find_host_bridge(dev->bus); ++ ++ /* ++ * Only do the _HPX Type 2 programming if OS owns PCIe native ++ * hotplug but not AER. ++ */ ++ if (!host->native_pcie_hotplug || host->native_aer) ++ return; ++ + if (hpx->revision > 1) { + pci_warn(dev, "PCIe settings rev %d not supported\n", + hpx->revision); +@@ -325,33 +320,27 @@ static void program_hpx_type2(struct pci_dev *dev, struct hpx_type2 *hpx) + } + + /* +- * Don't allow _HPX to change MPS or MRRS settings. We manage +- * those to make sure they're consistent with the rest of the +- * platform. ++ * We only allow _HPX to program DEVCTL bits related to AER, namely ++ * PCI_EXP_DEVCTL_CERE, PCI_EXP_DEVCTL_NFERE, PCI_EXP_DEVCTL_FERE, ++ * and PCI_EXP_DEVCTL_URRE. ++ * ++ * The rest of DEVCTL is managed by the OS to make sure it's ++ * consistent with the rest of the platform. + */ +- hpx->pci_exp_devctl_and |= PCI_EXP_DEVCTL_PAYLOAD | +- PCI_EXP_DEVCTL_READRQ; +- hpx->pci_exp_devctl_or &= ~(PCI_EXP_DEVCTL_PAYLOAD | +- PCI_EXP_DEVCTL_READRQ); ++ hpx->pci_exp_devctl_and |= ~PCI_EXP_AER_FLAGS; ++ hpx->pci_exp_devctl_or &= PCI_EXP_AER_FLAGS; + + /* Initialize Device Control Register */ + pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL, + ~hpx->pci_exp_devctl_and, hpx->pci_exp_devctl_or); + +- /* Initialize Link Control Register */ ++ /* Log if _HPX attempts to modify Link Control Register */ + if (pcie_cap_has_lnkctl(dev)) { +- +- /* +- * If the Root Port supports Read Completion Boundary of +- * 128, set RCB to 128. Otherwise, clear it. +- */ +- hpx->pci_exp_lnkctl_and |= PCI_EXP_LNKCTL_RCB; +- hpx->pci_exp_lnkctl_or &= ~PCI_EXP_LNKCTL_RCB; +- if (pcie_root_rcb_set(dev)) +- hpx->pci_exp_lnkctl_or |= PCI_EXP_LNKCTL_RCB; +- +- pcie_capability_clear_and_set_word(dev, PCI_EXP_LNKCTL, +- ~hpx->pci_exp_lnkctl_and, hpx->pci_exp_lnkctl_or); ++ if (hpx->pci_exp_lnkctl_and != 0xffff || ++ hpx->pci_exp_lnkctl_or != 0) ++ pci_info(dev, "_HPX attempts Link Control setting (AND %#06x OR %#06x)\n", ++ hpx->pci_exp_lnkctl_and, ++ hpx->pci_exp_lnkctl_or); + } + + /* Find Advanced Error Reporting Enhanced Capability */ +diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h +index 0e67014aa0013..e3c2852c80fbd 100644 +--- a/drivers/pci/pci.h ++++ b/drivers/pci/pci.h +@@ -88,6 +88,9 @@ struct pcie_tlp_log; + #define PCI_BUS_BRIDGE_MEM_WINDOW 1 + #define PCI_BUS_BRIDGE_PREF_MEM_WINDOW 2 + ++#define PCI_EXP_AER_FLAGS (PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE | \ ++ PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE) ++ + extern const unsigned char pcie_link_speed[]; + extern bool pci_early_dump; + +diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c +index e0bcaa896803c..9472d86cef552 100644 +--- a/drivers/pci/pcie/aer.c ++++ b/drivers/pci/pcie/aer.c +@@ -239,9 +239,6 @@ void pcie_ecrc_get_policy(char *str) + } + #endif /* CONFIG_PCIE_ECRC */ + +-#define PCI_EXP_AER_FLAGS (PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE | \ +- PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE) +- + int pcie_aer_is_native(struct pci_dev *dev) + { + struct pci_host_bridge *host = pci_find_host_bridge(dev->bus); +-- +2.51.0 + diff --git a/queue-6.19/pci-add-acs-quirk-for-pericom-pi7c9x2g404-switches-1.patch b/queue-6.19/pci-add-acs-quirk-for-pericom-pi7c9x2g404-switches-1.patch new file mode 100644 index 0000000000..c443865cba --- /dev/null +++ b/queue-6.19/pci-add-acs-quirk-for-pericom-pi7c9x2g404-switches-1.patch @@ -0,0 +1,46 @@ +From ae991995b387af7ba35cd8e76ff3f45c30915a26 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 17:08:33 +0100 +Subject: PCI: Add ACS quirk for Pericom PI7C9X2G404 switches [12d8:b404] + +From: Nicolas Cavallari + +[ Upstream commit 5907a90551e9f7968781f3a6ab8684458959beb3 ] + +12d8:b404 is apparently another PCI ID for Pericom PI7C9X2G404 (as +identified by the chip silkscreen and lspci). + +It is also affected by the PI7C9X2G errata (e.g. a network card attached +to it fails under load when P2P Redirect Request is enabled), so apply +the same quirk to this PCI ID too. + +PCI bridge [0604]: Pericom Semiconductor PI7C9X2G404 EV/SV PCIe2 4-Port/4-Lane Packet Switch [12d8:b404] (rev 01) + +Fixes: acd61ffb2f16 ("PCI: Add ACS quirk for Pericom PI7C9X2G switches") +Closes: https://lore.kernel.org/all/a1d926f0-4cb5-4877-a4df-617902648d80@green-communications.fr/ +Signed-off-by: Nicolas Cavallari +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260119160915.26456-1-nicolas.cavallari@green-communications.fr +Signed-off-by: Sasha Levin +--- + drivers/pci/quirks.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index 211b7f72d103e..6df78efd7f6dc 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -6189,6 +6189,10 @@ DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_PERICOM, 0x2303, + pci_fixup_pericom_acs_store_forward); + DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_PERICOM, 0x2303, + pci_fixup_pericom_acs_store_forward); ++DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_PERICOM, 0xb404, ++ pci_fixup_pericom_acs_store_forward); ++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_PERICOM, 0xb404, ++ pci_fixup_pericom_acs_store_forward); + + static void nvidia_ion_ahci_fixup(struct pci_dev *pdev) + { +-- +2.51.0 + diff --git a/queue-6.19/pci-add-preceding-capability-position-support-in-pci.patch b/queue-6.19/pci-add-preceding-capability-position-support-in-pci.patch new file mode 100644 index 0000000000..e43921c8c1 --- /dev/null +++ b/queue-6.19/pci-add-preceding-capability-position-support-in-pci.patch @@ -0,0 +1,236 @@ +From cbce633a9dda97218460ea1794af21f077ab45d8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 9 Nov 2025 22:59:40 -0800 +Subject: PCI: Add preceding capability position support in PCI_FIND_NEXT_*_CAP + macros + +From: Qiang Yu + +[ Upstream commit a2582e05e39adf9ab82a02561cd6f70738540ae0 ] + +Add support for finding the preceding capability position in PCI +capability list by extending the capability finding macros with an +additional parameter. This functionality is essential for modifying PCI +capability list, as it provides the necessary information to update the +"next" pointer of the predecessor capability when removing entries. + +Modify two macros to accept a new 'prev_ptr' parameter: +- PCI_FIND_NEXT_CAP - Now accepts 'prev_ptr' parameter for standard + capabilities +- PCI_FIND_NEXT_EXT_CAP - Now accepts 'prev_ptr' parameter for extended + capabilities + +When a capability is found, these macros: +- Store the position of the preceding capability in *prev_ptr + (if prev_ptr != NULL) +- Maintain all existing functionality when prev_ptr is NULL + +Update current callers to accommodate this API change by passing NULL to +'prev_ptr' argument if they do not care about the preceding capability +position. + +No functional changes to driver behavior result from this commit as it +maintains the existing capability finding functionality while adding the +infrastructure for future capability removal operations. + +Signed-off-by: Qiang Yu +Signed-off-by: Manivannan Sadhasivam +Link: https://patch.msgid.link/20251109-remove_cap-v1-1-2208f46f4dc2@oss.qualcomm.com +Stable-dep-of: 72cb5ed2a5c6 ("PCI: dwc: ep: Add per-PF BAR and inbound ATU mapping support") +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/cadence/pcie-cadence.c | 4 ++-- + .../pci/controller/dwc/pcie-designware-ep.c | 2 +- + drivers/pci/controller/dwc/pcie-designware.c | 6 ++--- + drivers/pci/pci.c | 8 +++---- + drivers/pci/pci.h | 23 +++++++++++++++---- + 5 files changed, 29 insertions(+), 14 deletions(-) + +diff --git a/drivers/pci/controller/cadence/pcie-cadence.c b/drivers/pci/controller/cadence/pcie-cadence.c +index e6f1a4ac0fb7a..a1eada56edba7 100644 +--- a/drivers/pci/controller/cadence/pcie-cadence.c ++++ b/drivers/pci/controller/cadence/pcie-cadence.c +@@ -13,13 +13,13 @@ + u8 cdns_pcie_find_capability(struct cdns_pcie *pcie, u8 cap) + { + return PCI_FIND_NEXT_CAP(cdns_pcie_read_cfg, PCI_CAPABILITY_LIST, +- cap, pcie); ++ cap, NULL, pcie); + } + EXPORT_SYMBOL_GPL(cdns_pcie_find_capability); + + u16 cdns_pcie_find_ext_capability(struct cdns_pcie *pcie, u8 cap) + { +- return PCI_FIND_NEXT_EXT_CAP(cdns_pcie_read_cfg, 0, cap, pcie); ++ return PCI_FIND_NEXT_EXT_CAP(cdns_pcie_read_cfg, 0, cap, NULL, pcie); + } + EXPORT_SYMBOL_GPL(cdns_pcie_find_ext_capability); + +diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c +index 19571ac2b9617..f6c54625486e2 100644 +--- a/drivers/pci/controller/dwc/pcie-designware-ep.c ++++ b/drivers/pci/controller/dwc/pcie-designware-ep.c +@@ -72,7 +72,7 @@ EXPORT_SYMBOL_GPL(dw_pcie_ep_reset_bar); + static u8 dw_pcie_ep_find_capability(struct dw_pcie_ep *ep, u8 func_no, u8 cap) + { + return PCI_FIND_NEXT_CAP(dw_pcie_ep_read_cfg, PCI_CAPABILITY_LIST, +- cap, ep, func_no); ++ cap, NULL, ep, func_no); + } + + /** +diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c +index 75fc8b767fccf..5d7a7e6f5724e 100644 +--- a/drivers/pci/controller/dwc/pcie-designware.c ++++ b/drivers/pci/controller/dwc/pcie-designware.c +@@ -226,13 +226,13 @@ void dw_pcie_version_detect(struct dw_pcie *pci) + u8 dw_pcie_find_capability(struct dw_pcie *pci, u8 cap) + { + return PCI_FIND_NEXT_CAP(dw_pcie_read_cfg, PCI_CAPABILITY_LIST, cap, +- pci); ++ NULL, pci); + } + EXPORT_SYMBOL_GPL(dw_pcie_find_capability); + + u16 dw_pcie_find_ext_capability(struct dw_pcie *pci, u8 cap) + { +- return PCI_FIND_NEXT_EXT_CAP(dw_pcie_read_cfg, 0, cap, pci); ++ return PCI_FIND_NEXT_EXT_CAP(dw_pcie_read_cfg, 0, cap, NULL, pci); + } + EXPORT_SYMBOL_GPL(dw_pcie_find_ext_capability); + +@@ -246,7 +246,7 @@ static u16 __dw_pcie_find_vsec_capability(struct dw_pcie *pci, u16 vendor_id, + return 0; + + while ((vsec = PCI_FIND_NEXT_EXT_CAP(dw_pcie_read_cfg, vsec, +- PCI_EXT_CAP_ID_VNDR, pci))) { ++ PCI_EXT_CAP_ID_VNDR, NULL, pci))) { + header = dw_pcie_readl_dbi(pci, vsec + PCI_VNDR_HEADER); + if (PCI_VNDR_HEADER_ID(header) == vsec_id) + return vsec; +diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c +index d9d531e8283c2..a05978f5cf2c7 100644 +--- a/drivers/pci/pci.c ++++ b/drivers/pci/pci.c +@@ -426,7 +426,7 @@ static int pci_dev_str_match(struct pci_dev *dev, const char *p, + static u8 __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn, + u8 pos, int cap) + { +- return PCI_FIND_NEXT_CAP(pci_bus_read_config, pos, cap, bus, devfn); ++ return PCI_FIND_NEXT_CAP(pci_bus_read_config, pos, cap, NULL, bus, devfn); + } + + u8 pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap) +@@ -531,7 +531,7 @@ u16 pci_find_next_ext_capability(struct pci_dev *dev, u16 start, int cap) + return 0; + + return PCI_FIND_NEXT_EXT_CAP(pci_bus_read_config, start, cap, +- dev->bus, dev->devfn); ++ NULL, dev->bus, dev->devfn); + } + EXPORT_SYMBOL_GPL(pci_find_next_ext_capability); + +@@ -600,7 +600,7 @@ static u8 __pci_find_next_ht_cap(struct pci_dev *dev, u8 pos, int ht_cap) + mask = HT_5BIT_CAP_MASK; + + pos = PCI_FIND_NEXT_CAP(pci_bus_read_config, pos, +- PCI_CAP_ID_HT, dev->bus, dev->devfn); ++ PCI_CAP_ID_HT, NULL, dev->bus, dev->devfn); + while (pos) { + rc = pci_read_config_byte(dev, pos + 3, &cap); + if (rc != PCIBIOS_SUCCESSFUL) +@@ -611,7 +611,7 @@ static u8 __pci_find_next_ht_cap(struct pci_dev *dev, u8 pos, int ht_cap) + + pos = PCI_FIND_NEXT_CAP(pci_bus_read_config, + pos + PCI_CAP_LIST_NEXT, +- PCI_CAP_ID_HT, dev->bus, ++ PCI_CAP_ID_HT, NULL, dev->bus, + dev->devfn); + } + +diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h +index e3c2852c80fbd..36f32b8af6ab3 100644 +--- a/drivers/pci/pci.h ++++ b/drivers/pci/pci.h +@@ -106,17 +106,21 @@ bool pcie_cap_has_rtctl(const struct pci_dev *dev); + * @read_cfg: Function pointer for reading PCI config space + * @start: Starting position to begin search + * @cap: Capability ID to find ++ * @prev_ptr: Pointer to store position of preceding capability (optional) + * @args: Arguments to pass to read_cfg function + * +- * Search the capability list in PCI config space to find @cap. ++ * Search the capability list in PCI config space to find @cap. If ++ * found, update *prev_ptr with the position of the preceding capability ++ * (if prev_ptr != NULL) + * Implements TTL (time-to-live) protection against infinite loops. + * + * Return: Position of the capability if found, 0 otherwise. + */ +-#define PCI_FIND_NEXT_CAP(read_cfg, start, cap, args...) \ ++#define PCI_FIND_NEXT_CAP(read_cfg, start, cap, prev_ptr, args...) \ + ({ \ + int __ttl = PCI_FIND_CAP_TTL; \ +- u8 __id, __found_pos = 0; \ ++ u8 __id, __found_pos = 0; \ ++ u8 __prev_pos = (start); \ + u8 __pos = (start); \ + u16 __ent; \ + \ +@@ -135,9 +139,12 @@ bool pcie_cap_has_rtctl(const struct pci_dev *dev); + \ + if (__id == (cap)) { \ + __found_pos = __pos; \ ++ if (prev_ptr != NULL) \ ++ *(u8 *)prev_ptr = __prev_pos; \ + break; \ + } \ + \ ++ __prev_pos = __pos; \ + __pos = FIELD_GET(PCI_CAP_LIST_NEXT_MASK, __ent); \ + } \ + __found_pos; \ +@@ -149,21 +156,26 @@ bool pcie_cap_has_rtctl(const struct pci_dev *dev); + * @read_cfg: Function pointer for reading PCI config space + * @start: Starting position to begin search (0 for initial search) + * @cap: Extended capability ID to find ++ * @prev_ptr: Pointer to store position of preceding capability (optional) + * @args: Arguments to pass to read_cfg function + * + * Search the extended capability list in PCI config space to find @cap. ++ * If found, update *prev_ptr with the position of the preceding capability ++ * (if prev_ptr != NULL) + * Implements TTL protection against infinite loops using a calculated + * maximum search count. + * + * Return: Position of the capability if found, 0 otherwise. + */ +-#define PCI_FIND_NEXT_EXT_CAP(read_cfg, start, cap, args...) \ ++#define PCI_FIND_NEXT_EXT_CAP(read_cfg, start, cap, prev_ptr, args...) \ + ({ \ + u16 __pos = (start) ?: PCI_CFG_SPACE_SIZE; \ + u16 __found_pos = 0; \ ++ u16 __prev_pos; \ + int __ttl, __ret; \ + u32 __header; \ + \ ++ __prev_pos = __pos; \ + __ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8; \ + while (__ttl-- > 0 && __pos >= PCI_CFG_SPACE_SIZE) { \ + __ret = read_cfg##_dword(args, __pos, &__header); \ +@@ -175,9 +187,12 @@ bool pcie_cap_has_rtctl(const struct pci_dev *dev); + \ + if (PCI_EXT_CAP_ID(__header) == (cap) && __pos != start) {\ + __found_pos = __pos; \ ++ if (prev_ptr != NULL) \ ++ *(u16 *)prev_ptr = __prev_pos; \ + break; \ + } \ + \ ++ __prev_pos = __pos; \ + __pos = PCI_EXT_CAP_NEXT(__header); \ + } \ + __found_pos; \ +-- +2.51.0 + diff --git a/queue-6.19/pci-add-wq_percpu-to-alloc_workqueue-users.patch b/queue-6.19/pci-add-wq_percpu-to-alloc_workqueue-users.patch new file mode 100644 index 0000000000..bf9611a8b4 --- /dev/null +++ b/queue-6.19/pci-add-wq_percpu-to-alloc_workqueue-users.patch @@ -0,0 +1,144 @@ +From 5d384a3c2ba9cfd9c2af3f5d2931ed2b1959d49e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 7 Nov 2025 15:25:26 +0100 +Subject: PCI: Add WQ_PERCPU to alloc_workqueue() users + +From: Marco Crivellari + +[ Upstream commit 78f5d0d5a23dd81106cbe999d9dcd522964a8f1a ] + +Currently work items enqueued by schedule_delayed_work() use "system_wq" (a +per-CPU wq), while queue_delayed_work() uses WORK_CPU_UNBOUND (used when a +CPU is not specified). The same applies to schedule_work() that is using +system_wq and queue_work(), that makes use again of WORK_CPU_UNBOUND. This +lack of consistency cannot be addressed without refactoring the API. + +alloc_workqueue() treats all queues as per-CPU by default, while unbound +workqueues must opt-in via WQ_UNBOUND. + +This default is suboptimal: most workloads benefit from unbound queues, +allowing the scheduler to place worker threads where they're needed and +reducing noise when CPUs are isolated. + +This continues the effort to refactor workqueue APIs, which began with the +introduction of new workqueues and a new alloc_workqueue() flag in: + + 128ea9f6ccfb ("workqueue: Add system_percpu_wq and system_dfl_wq") + 930c2ea566af ("workqueue: Add new WQ_PERCPU flag") + +Add WQ_PERCPU to explicitly request alloc_workqueue() to be per-CPU when +WQ_UNBOUND has not been specified. + +With the introduction of the WQ_PERCPU flag (equivalent to !WQ_UNBOUND), +any alloc_workqueue() caller that doesn't explicitly specify WQ_UNBOUND +must now use WQ_PERCPU. + +Once migration is complete, WQ_UNBOUND can be removed and unbound will +become the implicit default. + +Suggested-by: Tejun Heo +Signed-off-by: Marco Crivellari +[bhelgaas: squash similar commits] +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20251107142526.234685-1-marco.crivellari@suse.com +Link: https://patch.msgid.link/20251107142835.237636-1-marco.crivellari@suse.com +Link: https://patch.msgid.link/20251107143108.240025-1-marco.crivellari@suse.com +Link: https://patch.msgid.link/20251107143335.242342-1-marco.crivellari@suse.com +Link: https://patch.msgid.link/20251107143624.244978-1-marco.crivellari@suse.com +Stable-dep-of: 03f336a869b3 ("PCI: endpoint: Add missing NULL check for alloc_workqueue()") +Signed-off-by: Sasha Levin +--- + drivers/pci/endpoint/functions/pci-epf-mhi.c | 2 +- + drivers/pci/endpoint/functions/pci-epf-ntb.c | 4 ++-- + drivers/pci/endpoint/functions/pci-epf-test.c | 2 +- + drivers/pci/endpoint/functions/pci-epf-vntb.c | 4 ++-- + drivers/pci/hotplug/pnv_php.c | 2 +- + drivers/pci/hotplug/shpchp_core.c | 3 ++- + 6 files changed, 9 insertions(+), 8 deletions(-) + +diff --git a/drivers/pci/endpoint/functions/pci-epf-mhi.c b/drivers/pci/endpoint/functions/pci-epf-mhi.c +index 6643a88c7a0ce..27de533f05716 100644 +--- a/drivers/pci/endpoint/functions/pci-epf-mhi.c ++++ b/drivers/pci/endpoint/functions/pci-epf-mhi.c +@@ -686,7 +686,7 @@ static int pci_epf_mhi_dma_init(struct pci_epf_mhi *epf_mhi) + goto err_release_tx; + } + +- epf_mhi->dma_wq = alloc_workqueue("pci_epf_mhi_dma_wq", 0, 0); ++ epf_mhi->dma_wq = alloc_workqueue("pci_epf_mhi_dma_wq", WQ_PERCPU, 0); + if (!epf_mhi->dma_wq) { + ret = -ENOMEM; + goto err_release_rx; +diff --git a/drivers/pci/endpoint/functions/pci-epf-ntb.c b/drivers/pci/endpoint/functions/pci-epf-ntb.c +index e01a98e74d211..9ea8b57d69d79 100644 +--- a/drivers/pci/endpoint/functions/pci-epf-ntb.c ++++ b/drivers/pci/endpoint/functions/pci-epf-ntb.c +@@ -2124,8 +2124,8 @@ static int __init epf_ntb_init(void) + { + int ret; + +- kpcintb_workqueue = alloc_workqueue("kpcintb", WQ_MEM_RECLAIM | +- WQ_HIGHPRI, 0); ++ kpcintb_workqueue = alloc_workqueue("kpcintb", ++ WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_PERCPU, 0); + ret = pci_epf_register_driver(&epf_ntb_driver); + if (ret) { + destroy_workqueue(kpcintb_workqueue); +diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c +index debd235253c5b..62804120cd79a 100644 +--- a/drivers/pci/endpoint/functions/pci-epf-test.c ++++ b/drivers/pci/endpoint/functions/pci-epf-test.c +@@ -1188,7 +1188,7 @@ static int __init pci_epf_test_init(void) + int ret; + + kpcitest_workqueue = alloc_workqueue("kpcitest", +- WQ_MEM_RECLAIM | WQ_HIGHPRI, 0); ++ WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_PERCPU, 0); + if (!kpcitest_workqueue) { + pr_err("Failed to allocate the kpcitest work queue\n"); + return -ENOMEM; +diff --git a/drivers/pci/endpoint/functions/pci-epf-vntb.c b/drivers/pci/endpoint/functions/pci-epf-vntb.c +index 3ecc5059f92b3..a098727f784bd 100644 +--- a/drivers/pci/endpoint/functions/pci-epf-vntb.c ++++ b/drivers/pci/endpoint/functions/pci-epf-vntb.c +@@ -1651,8 +1651,8 @@ static int __init epf_ntb_init(void) + { + int ret; + +- kpcintb_workqueue = alloc_workqueue("kpcintb", WQ_MEM_RECLAIM | +- WQ_HIGHPRI, 0); ++ kpcintb_workqueue = alloc_workqueue("kpcintb", ++ WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_PERCPU, 0); + ret = pci_epf_register_driver(&epf_ntb_driver); + if (ret) { + destroy_workqueue(kpcintb_workqueue); +diff --git a/drivers/pci/hotplug/pnv_php.c b/drivers/pci/hotplug/pnv_php.c +index c5345bff9a553..35f1758126c68 100644 +--- a/drivers/pci/hotplug/pnv_php.c ++++ b/drivers/pci/hotplug/pnv_php.c +@@ -802,7 +802,7 @@ static struct pnv_php_slot *pnv_php_alloc_slot(struct device_node *dn) + } + + /* Allocate workqueue for this slot's interrupt handling */ +- php_slot->wq = alloc_workqueue("pciehp-%s", 0, 0, php_slot->name); ++ php_slot->wq = alloc_workqueue("pciehp-%s", WQ_PERCPU, 0, php_slot->name); + if (!php_slot->wq) { + SLOT_WARN(php_slot, "Cannot alloc workqueue\n"); + kfree(php_slot->name); +diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c +index 0c341453afc60..56308515ecbaf 100644 +--- a/drivers/pci/hotplug/shpchp_core.c ++++ b/drivers/pci/hotplug/shpchp_core.c +@@ -80,7 +80,8 @@ static int init_slots(struct controller *ctrl) + slot->device = ctrl->slot_device_offset + i; + slot->number = ctrl->first_slot + (ctrl->slot_num_inc * i); + +- slot->wq = alloc_workqueue("shpchp-%d", 0, 0, slot->number); ++ slot->wq = alloc_workqueue("shpchp-%d", WQ_PERCPU, 0, ++ slot->number); + if (!slot->wq) { + retval = -ENOMEM; + goto error_slot; +-- +2.51.0 + diff --git a/queue-6.19/pci-check-parent-for-null-in-of_pci_bus_release_doma.patch b/queue-6.19/pci-check-parent-for-null-in-of_pci_bus_release_doma.patch new file mode 100644 index 0000000000..0f507be49e --- /dev/null +++ b/queue-6.19/pci-check-parent-for-null-in-of_pci_bus_release_doma.patch @@ -0,0 +1,42 @@ +From 83ab167950b255b8b25ccfd6638a5db751904c8a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 23:39:42 +0300 +Subject: PCI: Check parent for NULL in of_pci_bus_release_domain_nr() + +From: Sergey Shtylyov + +[ Upstream commit f7245901de8978d829f80b3d8e36ed9a8fd18049 ] + +of_pci_bus_find_domain_nr() allows its parent parameter to be NULL but +of_pci_bus_release_domain_nr() (that undoes its effect) doesn't -- that +means it's going to blow up while calling of_get_pci_domain_nr() if the +parent parameter indeed happens to be NULL. Add the missing NULL check. + +Found by Linux Verification Center (linuxtesting.org) with the Svace static +analysis tool. + +Fixes: c14f7ccc9f5d ("PCI: Assign PCI domain IDs by ida_alloc()") +Signed-off-by: Sergey Shtylyov +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260127203944.28588-1-s.shtylyov@auroraos.dev +Signed-off-by: Sasha Levin +--- + drivers/pci/pci.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c +index 86ccbd0efb495..d9d531e8283c2 100644 +--- a/drivers/pci/pci.c ++++ b/drivers/pci/pci.c +@@ -6594,7 +6594,7 @@ static void of_pci_bus_release_domain_nr(struct device *parent, int domain_nr) + return; + + /* Release domain from IDA where it was allocated. */ +- if (of_get_pci_domain_nr(parent->of_node) == domain_nr) ++ if (parent && of_get_pci_domain_nr(parent->of_node) == domain_nr) + ida_free(&pci_domain_nr_static_ida, domain_nr); + else + ida_free(&pci_domain_nr_dynamic_ida, domain_nr); +-- +2.51.0 + diff --git a/queue-6.19/pci-do-not-attempt-to-set-exttag-for-vfs.patch b/queue-6.19/pci-do-not-attempt-to-set-exttag-for-vfs.patch new file mode 100644 index 0000000000..55de87b580 --- /dev/null +++ b/queue-6.19/pci-do-not-attempt-to-set-exttag-for-vfs.patch @@ -0,0 +1,49 @@ +From 707a38a71254e7accf4a9d02b697ab1ac160ebcf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 12 Nov 2025 10:54:40 +0100 +Subject: PCI: Do not attempt to set ExtTag for VFs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: HÃ¥kon Bugge + +[ Upstream commit 73711730a1128d91ebca1a6994ceeb18f36cb0cd ] + +The bit for enabling extended tags is Reserved and Preserved (RsvdP) for +VFs, according to PCIe r7.0 section 7.5.3.4 table 7.21. Hence, bail out +early from pci_configure_extended_tags() if the device is a VF. + +Otherwise, we may see incorrect log messages such as: + + kernel: pci 0000:af:00.2: enabling Extended Tags + +(af:00.2 is a VF) + +Fixes: 60db3a4d8cc9 ("PCI: Enable PCIe Extended Tags if supported") +Signed-off-by: HÃ¥kon Bugge +Signed-off-by: Bjorn Helgaas +Reviewed-by: Zhu Yanjun +Link: https://patch.msgid.link/20251112095442.1913258-1-haakon.bugge@oracle.com +Signed-off-by: Sasha Levin +--- + drivers/pci/probe.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c +index 41183aed8f5d9..86665658d7047 100644 +--- a/drivers/pci/probe.c ++++ b/drivers/pci/probe.c +@@ -2270,7 +2270,8 @@ int pci_configure_extended_tags(struct pci_dev *dev, void *ign) + u16 ctl; + int ret; + +- if (!pci_is_pcie(dev)) ++ /* PCI_EXP_DEVCTL_EXT_TAG is RsvdP in VFs */ ++ if (!pci_is_pcie(dev) || dev->is_virtfn) + return 0; + + ret = pcie_capability_read_dword(dev, PCI_EXP_DEVCAP, &cap); +-- +2.51.0 + diff --git a/queue-6.19/pci-dwc-add-new-apis-to-remove-standard-and-extended.patch b/queue-6.19/pci-dwc-add-new-apis-to-remove-standard-and-extended.patch new file mode 100644 index 0000000000..0b7c8170ce --- /dev/null +++ b/queue-6.19/pci-dwc-add-new-apis-to-remove-standard-and-extended.patch @@ -0,0 +1,111 @@ +From 19948103d784aba70bedb1272e767ef8e38c97b6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 9 Nov 2025 22:59:41 -0800 +Subject: PCI: dwc: Add new APIs to remove standard and extended Capability + +From: Qiang Yu + +[ Upstream commit 0183562f1e824c0ca6c918309a0978e9a269af3e ] + +On some platforms, certain PCIe Capabilities may be present in hardware +but are not fully implemented as defined in PCIe spec. These incomplete +capabilities should be hidden from the PCI framework to prevent unexpected +behavior. + +Introduce two APIs to remove a specific PCIe Capability and Extended +Capability by updating the previous capability's next offset field to skip +over the unwanted capability. These APIs allow RC drivers to easily hide +unsupported or partially implemented capabilities from software. + +Co-developed-by: Wenbin Yao +Signed-off-by: Wenbin Yao +Signed-off-by: Qiang Yu +Signed-off-by: Manivannan Sadhasivam +Link: https://patch.msgid.link/20251109-remove_cap-v1-2-2208f46f4dc2@oss.qualcomm.com +Stable-dep-of: 72cb5ed2a5c6 ("PCI: dwc: ep: Add per-PF BAR and inbound ATU mapping support") +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-designware.c | 53 ++++++++++++++++++++ + drivers/pci/controller/dwc/pcie-designware.h | 2 + + 2 files changed, 55 insertions(+) + +diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c +index 5d7a7e6f5724e..345365ea97c74 100644 +--- a/drivers/pci/controller/dwc/pcie-designware.c ++++ b/drivers/pci/controller/dwc/pcie-designware.c +@@ -236,6 +236,59 @@ u16 dw_pcie_find_ext_capability(struct dw_pcie *pci, u8 cap) + } + EXPORT_SYMBOL_GPL(dw_pcie_find_ext_capability); + ++void dw_pcie_remove_capability(struct dw_pcie *pci, u8 cap) ++{ ++ u8 cap_pos, pre_pos, next_pos; ++ u16 reg; ++ ++ cap_pos = PCI_FIND_NEXT_CAP(dw_pcie_read_cfg, PCI_CAPABILITY_LIST, cap, ++ &pre_pos, pci); ++ if (!cap_pos) ++ return; ++ ++ reg = dw_pcie_readw_dbi(pci, cap_pos); ++ next_pos = (reg & 0xff00) >> 8; ++ ++ dw_pcie_dbi_ro_wr_en(pci); ++ if (pre_pos == PCI_CAPABILITY_LIST) ++ dw_pcie_writeb_dbi(pci, PCI_CAPABILITY_LIST, next_pos); ++ else ++ dw_pcie_writeb_dbi(pci, pre_pos + 1, next_pos); ++ dw_pcie_dbi_ro_wr_dis(pci); ++} ++EXPORT_SYMBOL_GPL(dw_pcie_remove_capability); ++ ++void dw_pcie_remove_ext_capability(struct dw_pcie *pci, u8 cap) ++{ ++ int cap_pos, next_pos, pre_pos; ++ u32 pre_header, header; ++ ++ cap_pos = PCI_FIND_NEXT_EXT_CAP(dw_pcie_read_cfg, 0, cap, &pre_pos, pci); ++ if (!cap_pos) ++ return; ++ ++ header = dw_pcie_readl_dbi(pci, cap_pos); ++ /* ++ * If the first cap at offset PCI_CFG_SPACE_SIZE is removed, ++ * only set it's capid to zero as it cannot be skipped. ++ */ ++ if (cap_pos == PCI_CFG_SPACE_SIZE) { ++ dw_pcie_dbi_ro_wr_en(pci); ++ dw_pcie_writel_dbi(pci, cap_pos, header & 0xffff0000); ++ dw_pcie_dbi_ro_wr_dis(pci); ++ return; ++ } ++ ++ pre_header = dw_pcie_readl_dbi(pci, pre_pos); ++ next_pos = PCI_EXT_CAP_NEXT(header); ++ ++ dw_pcie_dbi_ro_wr_en(pci); ++ dw_pcie_writel_dbi(pci, pre_pos, ++ (pre_header & 0xfffff) | (next_pos << 20)); ++ dw_pcie_dbi_ro_wr_dis(pci); ++} ++EXPORT_SYMBOL_GPL(dw_pcie_remove_ext_capability); ++ + static u16 __dw_pcie_find_vsec_capability(struct dw_pcie *pci, u16 vendor_id, + u16 vsec_id) + { +diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h +index 31685951a0804..aec4af5194b51 100644 +--- a/drivers/pci/controller/dwc/pcie-designware.h ++++ b/drivers/pci/controller/dwc/pcie-designware.h +@@ -562,6 +562,8 @@ void dw_pcie_version_detect(struct dw_pcie *pci); + + u8 dw_pcie_find_capability(struct dw_pcie *pci, u8 cap); + u16 dw_pcie_find_ext_capability(struct dw_pcie *pci, u8 cap); ++void dw_pcie_remove_capability(struct dw_pcie *pci, u8 cap); ++void dw_pcie_remove_ext_capability(struct dw_pcie *pci, u8 cap); + u16 dw_pcie_find_rasdes_capability(struct dw_pcie *pci); + u16 dw_pcie_find_ptm_capability(struct dw_pcie *pci); + +-- +2.51.0 + diff --git a/queue-6.19/pci-dwc-advertise-dynamic-inbound-mapping-support.patch b/queue-6.19/pci-dwc-advertise-dynamic-inbound-mapping-support.patch new file mode 100644 index 0000000000..d151ce7fa6 --- /dev/null +++ b/queue-6.19/pci-dwc-advertise-dynamic-inbound-mapping-support.patch @@ -0,0 +1,239 @@ +From a36df9137d96e6e5a8729c00d07dbb13b7a04c85 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 24 Jan 2026 23:50:07 +0900 +Subject: PCI: dwc: Advertise dynamic inbound mapping support + +From: Koichiro Den + +[ Upstream commit c0f1506f63546308e894469ceb0f1fadbdf9d2f9 ] + +The DesignWare EP core has supported updating the inbound iATU mapping +for an already configured BAR (i.e. allowing pci_epc_set_bar() to be +called again without a prior pci_epc_clear_bar()) since +commit 4284c88fff0e ("PCI: designware-ep: Allow pci_epc_set_bar() update +inbound map address"). + +Now that this capability is exposed via the dynamic_inbound_mapping EPC +feature bit, set it for DWC-based EP glue drivers using a common +initializer macro to avoid duplicating the same flag in each driver. + +Note that pci-layerscape-ep.c is untouched. It currently constructs the +feature struct dynamically in ls_pcie_ep_init(). Once converted to a +static feature definition, it will use DWC_EPC_COMMON_FEATURES as well. + +Signed-off-by: Koichiro Den +Signed-off-by: Manivannan Sadhasivam +Reviewed-by: Niklas Cassel +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260124145012.2794108-4-den@valinux.co.jp +Stable-dep-of: 72cb5ed2a5c6 ("PCI: dwc: ep: Add per-PF BAR and inbound ATU mapping support") +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pci-dra7xx.c | 1 + + drivers/pci/controller/dwc/pci-imx6.c | 3 +++ + drivers/pci/controller/dwc/pci-keystone.c | 1 + + drivers/pci/controller/dwc/pcie-artpec6.c | 1 + + drivers/pci/controller/dwc/pcie-designware-plat.c | 1 + + drivers/pci/controller/dwc/pcie-designware.h | 3 +++ + drivers/pci/controller/dwc/pcie-dw-rockchip.c | 2 ++ + drivers/pci/controller/dwc/pcie-keembay.c | 1 + + drivers/pci/controller/dwc/pcie-qcom-ep.c | 1 + + drivers/pci/controller/dwc/pcie-rcar-gen4.c | 1 + + drivers/pci/controller/dwc/pcie-stm32-ep.c | 1 + + drivers/pci/controller/dwc/pcie-tegra194.c | 1 + + drivers/pci/controller/dwc/pcie-uniphier-ep.c | 2 ++ + 13 files changed, 19 insertions(+) + +diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c +index 01cfd9aeb0b81..d5d26229063f2 100644 +--- a/drivers/pci/controller/dwc/pci-dra7xx.c ++++ b/drivers/pci/controller/dwc/pci-dra7xx.c +@@ -424,6 +424,7 @@ static int dra7xx_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no, + } + + static const struct pci_epc_features dra7xx_pcie_epc_features = { ++ DWC_EPC_COMMON_FEATURES, + .linkup_notifier = true, + .msi_capable = true, + }; +diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c +index 4668fc9648bff..f28e335bbbfaf 100644 +--- a/drivers/pci/controller/dwc/pci-imx6.c ++++ b/drivers/pci/controller/dwc/pci-imx6.c +@@ -1387,6 +1387,7 @@ static int imx_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, + } + + static const struct pci_epc_features imx8m_pcie_epc_features = { ++ DWC_EPC_COMMON_FEATURES, + .msi_capable = true, + .bar[BAR_1] = { .type = BAR_RESERVED, }, + .bar[BAR_3] = { .type = BAR_RESERVED, }, +@@ -1396,6 +1397,7 @@ static const struct pci_epc_features imx8m_pcie_epc_features = { + }; + + static const struct pci_epc_features imx8q_pcie_epc_features = { ++ DWC_EPC_COMMON_FEATURES, + .msi_capable = true, + .bar[BAR_1] = { .type = BAR_RESERVED, }, + .bar[BAR_3] = { .type = BAR_RESERVED, }, +@@ -1416,6 +1418,7 @@ static const struct pci_epc_features imx8q_pcie_epc_features = { + * BAR5 | Enable | 32-bit | 64 KB | Programmable Size + */ + static const struct pci_epc_features imx95_pcie_epc_features = { ++ DWC_EPC_COMMON_FEATURES, + .msi_capable = true, + .bar[BAR_1] = { .type = BAR_FIXED, .fixed_size = SZ_64K, }, + .align = SZ_4K, +diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c +index f86d9111f863f..20fa4dadb82af 100644 +--- a/drivers/pci/controller/dwc/pci-keystone.c ++++ b/drivers/pci/controller/dwc/pci-keystone.c +@@ -930,6 +930,7 @@ static int ks_pcie_am654_raise_irq(struct dw_pcie_ep *ep, u8 func_no, + } + + static const struct pci_epc_features ks_pcie_am654_epc_features = { ++ DWC_EPC_COMMON_FEATURES, + .msi_capable = true, + .msix_capable = true, + .bar[BAR_0] = { .type = BAR_RESERVED, }, +diff --git a/drivers/pci/controller/dwc/pcie-artpec6.c b/drivers/pci/controller/dwc/pcie-artpec6.c +index f4a136ee2daf3..e994b75986c34 100644 +--- a/drivers/pci/controller/dwc/pcie-artpec6.c ++++ b/drivers/pci/controller/dwc/pcie-artpec6.c +@@ -370,6 +370,7 @@ static int artpec6_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no, + } + + static const struct pci_epc_features artpec6_pcie_epc_features = { ++ DWC_EPC_COMMON_FEATURES, + .msi_capable = true, + }; + +diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c +index 12f41886c65d1..8530746ec5cbb 100644 +--- a/drivers/pci/controller/dwc/pcie-designware-plat.c ++++ b/drivers/pci/controller/dwc/pcie-designware-plat.c +@@ -61,6 +61,7 @@ static int dw_plat_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, + } + + static const struct pci_epc_features dw_plat_pcie_epc_features = { ++ DWC_EPC_COMMON_FEATURES, + .msi_capable = true, + .msix_capable = true, + }; +diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h +index 8a99a9c393f53..205fb55fca8c0 100644 +--- a/drivers/pci/controller/dwc/pcie-designware.h ++++ b/drivers/pci/controller/dwc/pcie-designware.h +@@ -305,6 +305,9 @@ + /* Default eDMA LLP memory size */ + #define DMA_LLP_MEM_SIZE PAGE_SIZE + ++/* Common struct pci_epc_feature bits among DWC EP glue drivers */ ++#define DWC_EPC_COMMON_FEATURES .dynamic_inbound_mapping = true ++ + struct dw_pcie; + struct dw_pcie_rp; + struct dw_pcie_ep; +diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c +index 2f865f67a10a7..bf8ec3ca6f689 100644 +--- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c ++++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c +@@ -362,6 +362,7 @@ static int rockchip_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no, + } + + static const struct pci_epc_features rockchip_pcie_epc_features_rk3568 = { ++ DWC_EPC_COMMON_FEATURES, + .linkup_notifier = true, + .msi_capable = true, + .msix_capable = true, +@@ -382,6 +383,7 @@ static const struct pci_epc_features rockchip_pcie_epc_features_rk3568 = { + * BARs) would be overwritten, resulting in (all other BARs) no longer working. + */ + static const struct pci_epc_features rockchip_pcie_epc_features_rk3588 = { ++ DWC_EPC_COMMON_FEATURES, + .linkup_notifier = true, + .msi_capable = true, + .msix_capable = true, +diff --git a/drivers/pci/controller/dwc/pcie-keembay.c b/drivers/pci/controller/dwc/pcie-keembay.c +index 60e74ac782af3..2666a9c3d67e7 100644 +--- a/drivers/pci/controller/dwc/pcie-keembay.c ++++ b/drivers/pci/controller/dwc/pcie-keembay.c +@@ -309,6 +309,7 @@ static int keembay_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, + } + + static const struct pci_epc_features keembay_pcie_epc_features = { ++ DWC_EPC_COMMON_FEATURES, + .msi_capable = true, + .msix_capable = true, + .bar[BAR_0] = { .only_64bit = true, }, +diff --git a/drivers/pci/controller/dwc/pcie-qcom-ep.c b/drivers/pci/controller/dwc/pcie-qcom-ep.c +index f1bc0ac81a928..5e990c7a5879f 100644 +--- a/drivers/pci/controller/dwc/pcie-qcom-ep.c ++++ b/drivers/pci/controller/dwc/pcie-qcom-ep.c +@@ -820,6 +820,7 @@ static void qcom_pcie_ep_init_debugfs(struct qcom_pcie_ep *pcie_ep) + } + + static const struct pci_epc_features qcom_pcie_epc_features = { ++ DWC_EPC_COMMON_FEATURES, + .linkup_notifier = true, + .msi_capable = true, + .align = SZ_4K, +diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c +index 80778917d2ddd..a6912e85e4ddc 100644 +--- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c ++++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c +@@ -420,6 +420,7 @@ static int rcar_gen4_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, + } + + static const struct pci_epc_features rcar_gen4_pcie_epc_features = { ++ DWC_EPC_COMMON_FEATURES, + .msi_capable = true, + .bar[BAR_1] = { .type = BAR_RESERVED, }, + .bar[BAR_3] = { .type = BAR_RESERVED, }, +diff --git a/drivers/pci/controller/dwc/pcie-stm32-ep.c b/drivers/pci/controller/dwc/pcie-stm32-ep.c +index 2cecf32d2b0f3..c1944b40ce02f 100644 +--- a/drivers/pci/controller/dwc/pcie-stm32-ep.c ++++ b/drivers/pci/controller/dwc/pcie-stm32-ep.c +@@ -70,6 +70,7 @@ static int stm32_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no, + } + + static const struct pci_epc_features stm32_pcie_epc_features = { ++ DWC_EPC_COMMON_FEATURES, + .msi_capable = true, + .align = SZ_64K, + }; +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index 0ddeef70726dd..06571d806ab31 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -1988,6 +1988,7 @@ static int tegra_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, + } + + static const struct pci_epc_features tegra_pcie_epc_features = { ++ DWC_EPC_COMMON_FEATURES, + .linkup_notifier = true, + .msi_capable = true, + .bar[BAR_0] = { .type = BAR_FIXED, .fixed_size = SZ_1M, +diff --git a/drivers/pci/controller/dwc/pcie-uniphier-ep.c b/drivers/pci/controller/dwc/pcie-uniphier-ep.c +index d6e73811216e2..d52753060970f 100644 +--- a/drivers/pci/controller/dwc/pcie-uniphier-ep.c ++++ b/drivers/pci/controller/dwc/pcie-uniphier-ep.c +@@ -420,6 +420,7 @@ static const struct uniphier_pcie_ep_soc_data uniphier_pro5_data = { + .init = uniphier_pcie_pro5_init_ep, + .wait = NULL, + .features = { ++ DWC_EPC_COMMON_FEATURES, + .linkup_notifier = false, + .msi_capable = true, + .msix_capable = false, +@@ -438,6 +439,7 @@ static const struct uniphier_pcie_ep_soc_data uniphier_nx1_data = { + .init = uniphier_pcie_nx1_init_ep, + .wait = uniphier_pcie_nx1_wait_ep, + .features = { ++ DWC_EPC_COMMON_FEATURES, + .linkup_notifier = false, + .msi_capable = true, + .msix_capable = false, +-- +2.51.0 + diff --git a/queue-6.19/pci-dwc-ep-add-per-pf-bar-and-inbound-atu-mapping-su.patch b/queue-6.19/pci-dwc-ep-add-per-pf-bar-and-inbound-atu-mapping-su.patch new file mode 100644 index 0000000000..a4ed3facfa --- /dev/null +++ b/queue-6.19/pci-dwc-ep-add-per-pf-bar-and-inbound-atu-mapping-su.patch @@ -0,0 +1,310 @@ +From 78d3dcdcc5b86acf4d7cbd666deb24bc707764db Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 17:25:15 +0530 +Subject: PCI: dwc: ep: Add per-PF BAR and inbound ATU mapping support + +From: Aksh Garg + +[ Upstream commit 72cb5ed2a5c6d87f71a409347f7d3b228fee6bee ] + +The commit 24ede430fa49 ("PCI: designware-ep: Add multiple PFs support +for DWC") added support for multiple PFs in the DWC driver, but the +implementation was incomplete. It did not properly support MSI/MSI-X, +as well as BAR and inbound ATU mapping for multiple PFs. The MSI/MSI-X +issue was later fixed by commit 47a062609a30 ("PCI: designware-ep: +Modify MSI and MSIX CAP way of finding") by introducing a per-PF +struct dw_pcie_ep_func. + +However, even with both commits, the multiple PF support in the driver +remains broken because BAR configuration and ATU mappings are managed +globally in struct dw_pcie_ep, meaning all PFs share the same BAR-to-ATU +mapping table. This causes one PF's EPF to overwrite the address +translation of another PF's EPF in the internal ATU region, +creating conflicts when multiple physical functions attempt to +configure their BARs independently. + +The commit cfbc98dbf44d ("PCI: dwc: ep: Support BAR subrange inbound +mapping via Address Match Mode iATU") later introduced Address Match +Mode support, which suffers from the same multi-PF conflict issue. + +Fix this by moving the required members from struct dw_pcie_ep to +struct dw_pcie_ep_func, similar to what commit 47a062609a30 +("PCI: designware-ep: Modify MSI and MSIX CAP way of finding") did for +MSI/MSI-X capability support, to allow proper multi-function endpoint +operation, where each PF can configure its BARs and corresponding +internal ATU region without interfering with other PFs. + +Fixes: 24ede430fa49 ("PCI: designware-ep: Add multiple PFs support for DWC") +Fixes: cc839bef7727 ("PCI: dwc: ep: Support BAR subrange inbound mapping via Address Match Mode iATU") +Signed-off-by: Aksh Garg +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Reviewed-by: Niklas Cassel +Link: https://patch.msgid.link/20260130115516.515082-3-a-garg7@ti.com +Signed-off-by: Sasha Levin +--- + .../pci/controller/dwc/pcie-designware-ep.c | 79 +++++++++++-------- + drivers/pci/controller/dwc/pcie-designware.h | 12 +-- + 2 files changed, 54 insertions(+), 37 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c +index 1cc2985bab03d..6d3c35dd280f3 100644 +--- a/drivers/pci/controller/dwc/pcie-designware-ep.c ++++ b/drivers/pci/controller/dwc/pcie-designware-ep.c +@@ -115,11 +115,15 @@ static int dw_pcie_ep_ib_atu_bar(struct dw_pcie_ep *ep, u8 func_no, int type, + int ret; + u32 free_win; + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); ++ struct dw_pcie_ep_func *ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); + +- if (!ep->bar_to_atu[bar]) ++ if (!ep_func) ++ return -EINVAL; ++ ++ if (!ep_func->bar_to_atu[bar]) + free_win = find_first_zero_bit(ep->ib_window_map, pci->num_ib_windows); + else +- free_win = ep->bar_to_atu[bar] - 1; ++ free_win = ep_func->bar_to_atu[bar] - 1; + + if (free_win >= pci->num_ib_windows) { + dev_err(pci->dev, "No free inbound window\n"); +@@ -137,33 +141,37 @@ static int dw_pcie_ep_ib_atu_bar(struct dw_pcie_ep *ep, u8 func_no, int type, + * Always increment free_win before assignment, since value 0 is used to identify + * unallocated mapping. + */ +- ep->bar_to_atu[bar] = free_win + 1; ++ ep_func->bar_to_atu[bar] = free_win + 1; + set_bit(free_win, ep->ib_window_map); + + return 0; + } + +-static void dw_pcie_ep_clear_ib_maps(struct dw_pcie_ep *ep, enum pci_barno bar) ++static void dw_pcie_ep_clear_ib_maps(struct dw_pcie_ep *ep, u8 func_no, enum pci_barno bar) + { ++ struct dw_pcie_ep_func *ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + struct device *dev = pci->dev; + unsigned int i, num; + u32 atu_index; + u32 *indexes; + ++ if (!ep_func) ++ return; ++ + /* Tear down the BAR Match Mode mapping, if any. */ +- if (ep->bar_to_atu[bar]) { +- atu_index = ep->bar_to_atu[bar] - 1; ++ if (ep_func->bar_to_atu[bar]) { ++ atu_index = ep_func->bar_to_atu[bar] - 1; + dw_pcie_disable_atu(pci, PCIE_ATU_REGION_DIR_IB, atu_index); + clear_bit(atu_index, ep->ib_window_map); +- ep->bar_to_atu[bar] = 0; ++ ep_func->bar_to_atu[bar] = 0; + } + + /* Tear down all Address Match Mode mappings, if any. */ +- indexes = ep->ib_atu_indexes[bar]; +- num = ep->num_ib_atu_indexes[bar]; +- ep->ib_atu_indexes[bar] = NULL; +- ep->num_ib_atu_indexes[bar] = 0; ++ indexes = ep_func->ib_atu_indexes[bar]; ++ num = ep_func->num_ib_atu_indexes[bar]; ++ ep_func->ib_atu_indexes[bar] = NULL; ++ ep_func->num_ib_atu_indexes[bar] = 0; + if (!indexes) + return; + for (i = 0; i < num; i++) { +@@ -248,6 +256,7 @@ static int dw_pcie_ep_validate_submap(struct dw_pcie_ep *ep, + static int dw_pcie_ep_ib_atu_addr(struct dw_pcie_ep *ep, u8 func_no, int type, + const struct pci_epf_bar *epf_bar) + { ++ struct dw_pcie_ep_func *ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); + const struct pci_epf_bar_submap *submap = epf_bar->submap; + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + enum pci_barno bar = epf_bar->barno; +@@ -258,7 +267,7 @@ static int dw_pcie_ep_ib_atu_addr(struct dw_pcie_ep *ep, u8 func_no, int type, + unsigned int i; + u32 *indexes; + +- if (!epf_bar->num_submap || !submap || !epf_bar->size) ++ if (!ep_func || !epf_bar->num_submap || !submap || !epf_bar->size) + return -EINVAL; + + ret = dw_pcie_ep_validate_submap(ep, submap, epf_bar->num_submap, +@@ -279,8 +288,8 @@ static int dw_pcie_ep_ib_atu_addr(struct dw_pcie_ep *ep, u8 func_no, int type, + if (!indexes) + return -ENOMEM; + +- ep->ib_atu_indexes[bar] = indexes; +- ep->num_ib_atu_indexes[bar] = 0; ++ ep_func->ib_atu_indexes[bar] = indexes; ++ ep_func->num_ib_atu_indexes[bar] = 0; + + for (i = 0; i < epf_bar->num_submap; i++) { + size = submap[i].size; +@@ -308,11 +317,11 @@ static int dw_pcie_ep_ib_atu_addr(struct dw_pcie_ep *ep, u8 func_no, int type, + + set_bit(free_win, ep->ib_window_map); + indexes[i] = free_win; +- ep->num_ib_atu_indexes[bar] = i + 1; ++ ep_func->num_ib_atu_indexes[bar] = i + 1; + } + return 0; + err: +- dw_pcie_ep_clear_ib_maps(ep, bar); ++ dw_pcie_ep_clear_ib_maps(ep, func_no, bar); + return ret; + } + +@@ -346,15 +355,16 @@ static void dw_pcie_ep_clear_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no, + struct dw_pcie_ep *ep = epc_get_drvdata(epc); + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + enum pci_barno bar = epf_bar->barno; ++ struct dw_pcie_ep_func *ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); + +- if (!ep->epf_bar[bar]) ++ if (!ep_func || !ep_func->epf_bar[bar]) + return; + + __dw_pcie_ep_reset_bar(pci, func_no, bar, epf_bar->flags); + +- dw_pcie_ep_clear_ib_maps(ep, bar); ++ dw_pcie_ep_clear_ib_maps(ep, func_no, bar); + +- ep->epf_bar[bar] = NULL; ++ ep_func->epf_bar[bar] = NULL; + } + + static unsigned int dw_pcie_ep_get_rebar_offset(struct dw_pcie_ep *ep, u8 func_no, +@@ -481,12 +491,16 @@ static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no, + { + struct dw_pcie_ep *ep = epc_get_drvdata(epc); + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); ++ struct dw_pcie_ep_func *ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); + enum pci_barno bar = epf_bar->barno; + size_t size = epf_bar->size; + enum pci_epc_bar_type bar_type; + int flags = epf_bar->flags; + int ret, type; + ++ if (!ep_func) ++ return -EINVAL; ++ + /* + * DWC does not allow BAR pairs to overlap, e.g. you cannot combine BARs + * 1 and 2 to form a 64-bit BAR. +@@ -500,22 +514,22 @@ static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no, + * calling clear_bar() would clear the BAR's PCI address assigned by the + * host). + */ +- if (ep->epf_bar[bar]) { ++ if (ep_func->epf_bar[bar]) { + /* + * We can only dynamically change a BAR if the new BAR size and + * BAR flags do not differ from the existing configuration. + */ +- if (ep->epf_bar[bar]->barno != bar || +- ep->epf_bar[bar]->size != size || +- ep->epf_bar[bar]->flags != flags) ++ if (ep_func->epf_bar[bar]->barno != bar || ++ ep_func->epf_bar[bar]->size != size || ++ ep_func->epf_bar[bar]->flags != flags) + return -EINVAL; + + /* + * When dynamically changing a BAR, tear down any existing + * mappings before re-programming. + */ +- if (ep->epf_bar[bar]->num_submap || epf_bar->num_submap) +- dw_pcie_ep_clear_ib_maps(ep, bar); ++ if (ep_func->epf_bar[bar]->num_submap || epf_bar->num_submap) ++ dw_pcie_ep_clear_ib_maps(ep, func_no, bar); + + /* + * When dynamically changing a BAR, skip writing the BAR reg, as +@@ -574,7 +588,7 @@ static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no, + if (ret) + return ret; + +- ep->epf_bar[bar] = epf_bar; ++ ep_func->epf_bar[bar] = epf_bar; + + return 0; + } +@@ -969,7 +983,7 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, + bir = FIELD_GET(PCI_MSIX_TABLE_BIR, tbl_offset); + tbl_offset &= PCI_MSIX_TABLE_OFFSET; + +- msix_tbl = ep->epf_bar[bir]->addr + tbl_offset; ++ msix_tbl = ep_func->epf_bar[bir]->addr + tbl_offset; + msg_addr = msix_tbl[(interrupt_num - 1)].msg_addr; + msg_data = msix_tbl[(interrupt_num - 1)].msg_data; + vec_ctrl = msix_tbl[(interrupt_num - 1)].vector_ctrl; +@@ -1032,11 +1046,14 @@ EXPORT_SYMBOL_GPL(dw_pcie_ep_deinit); + + static void dw_pcie_ep_init_rebar_registers(struct dw_pcie_ep *ep, u8 func_no) + { +- unsigned int offset; +- unsigned int nbars; ++ struct dw_pcie_ep_func *ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); ++ unsigned int offset, nbars; + enum pci_barno bar; + u32 reg, i, val; + ++ if (!ep_func) ++ return; ++ + offset = dw_pcie_ep_find_ext_capability(ep, func_no, PCI_EXT_CAP_ID_REBAR); + + if (offset) { +@@ -1063,8 +1080,8 @@ static void dw_pcie_ep_init_rebar_registers(struct dw_pcie_ep *ep, u8 func_no) + */ + val = dw_pcie_ep_readl_dbi(ep, func_no, offset + PCI_REBAR_CTRL); + bar = FIELD_GET(PCI_REBAR_CTRL_BAR_IDX, val); +- if (ep->epf_bar[bar]) +- pci_epc_bar_size_to_rebar_cap(ep->epf_bar[bar]->size, &val); ++ if (ep_func->epf_bar[bar]) ++ pci_epc_bar_size_to_rebar_cap(ep_func->epf_bar[bar]->size, &val); + else + val = BIT(4); + +diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h +index 3c4220027415e..5c429b62cb086 100644 +--- a/drivers/pci/controller/dwc/pcie-designware.h ++++ b/drivers/pci/controller/dwc/pcie-designware.h +@@ -467,6 +467,12 @@ struct dw_pcie_ep_func { + u8 func_no; + u8 msi_cap; /* MSI capability offset */ + u8 msix_cap; /* MSI-X capability offset */ ++ u8 bar_to_atu[PCI_STD_NUM_BARS]; ++ struct pci_epf_bar *epf_bar[PCI_STD_NUM_BARS]; ++ ++ /* Only for Address Match Mode inbound iATU */ ++ u32 *ib_atu_indexes[PCI_STD_NUM_BARS]; ++ unsigned int num_ib_atu_indexes[PCI_STD_NUM_BARS]; + }; + + struct dw_pcie_ep { +@@ -476,17 +482,11 @@ struct dw_pcie_ep { + phys_addr_t phys_base; + size_t addr_size; + size_t page_size; +- u8 bar_to_atu[PCI_STD_NUM_BARS]; + phys_addr_t *outbound_addr; + unsigned long *ib_window_map; + unsigned long *ob_window_map; + void __iomem *msi_mem; + phys_addr_t msi_mem_phys; +- struct pci_epf_bar *epf_bar[PCI_STD_NUM_BARS]; +- +- /* Only for Address Match Mode inbound iATU */ +- u32 *ib_atu_indexes[PCI_STD_NUM_BARS]; +- unsigned int num_ib_atu_indexes[PCI_STD_NUM_BARS]; + + /* MSI outbound iATU state */ + bool msi_iatu_mapped; +-- +2.51.0 + diff --git a/queue-6.19/pci-dwc-ep-cache-msi-outbound-iatu-mapping.patch b/queue-6.19/pci-dwc-ep-cache-msi-outbound-iatu-mapping.patch new file mode 100644 index 0000000000..87ed5f2010 --- /dev/null +++ b/queue-6.19/pci-dwc-ep-cache-msi-outbound-iatu-mapping.patch @@ -0,0 +1,151 @@ +From 7fd8e04e4a999d173528138774bf5dc1b45ff068 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 22 Dec 2025 12:01:44 +0100 +Subject: PCI: dwc: ep: Cache MSI outbound iATU mapping + +From: Koichiro Den + +[ Upstream commit 8719c64e76bf258cc8f44109740c854f2e2ead2e ] + +dw_pcie_ep_raise_msi_irq() currently programs an outbound iATU window +for the MSI target address on every interrupt and tears it down again +via dw_pcie_ep_unmap_addr(). + +On systems that heavily use the AXI bridge interface (for example when +the integrated eDMA engine is active), this means the outbound iATU +registers are updated while traffic is in flight. The DesignWare +endpoint databook 5.40a - "3.10.6.1 iATU Outbound Programming Overview" +warns that updating iATU registers in this situation is not supported, +and the behavior is undefined. + +Under high MSI and eDMA load this pattern results in occasional bogus +outbound transactions and IOMMU faults, on the RC side, such as: + + ipmmu-vmsa eed40000.iommu: Unhandled fault: status 0x00001502 iova 0xfe000000 + +followed by the system becoming unresponsive. This is the actual output +observed on Renesas R-Car S4, with its ipmmu_hc used with PCIe ch0. + +There is no need to reprogram the iATU region used for MSI on every +interrupt. The host-provided MSI address is stable while MSI is enabled, +and the endpoint driver already dedicates a scratch buffer for MSI +generation. + +Cache the aligned MSI address and map size, program the outbound iATU +once, and keep the window enabled. Subsequent interrupts only perform a +write to the MSI scratch buffer, avoiding dynamic iATU reprogramming in +the hot path and fixing the lockups seen under load. + +dw_pcie_ep_raise_msix_irq() is not modified, as each vector can have a +different msg_addr, and because the msg_addr is allowed to be changed +while the vector is masked. Neither problem is easy to solve with the +current design. Instead, the plan is for the DWC vendor drivers to +transition to dw_pcie_ep_raise_msix_irq_doorbell(), which does not rely +on the iATU. + +Signed-off-by: Koichiro Den +[cassel: improve commit message] +Signed-off-by: Niklas Cassel +Signed-off-by: Manivannan Sadhasivam +Link: https://patch.msgid.link/20251222110144.3299523-2-cassel@kernel.org +Stable-dep-of: 72cb5ed2a5c6 ("PCI: dwc: ep: Add per-PF BAR and inbound ATU mapping support") +Signed-off-by: Sasha Levin +--- + .../pci/controller/dwc/pcie-designware-ep.c | 48 ++++++++++++++++--- + drivers/pci/controller/dwc/pcie-designware.h | 5 ++ + 2 files changed, 47 insertions(+), 6 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c +index f6c54625486e2..1195d401df19e 100644 +--- a/drivers/pci/controller/dwc/pcie-designware-ep.c ++++ b/drivers/pci/controller/dwc/pcie-designware-ep.c +@@ -601,6 +601,16 @@ static void dw_pcie_ep_stop(struct pci_epc *epc) + struct dw_pcie_ep *ep = epc_get_drvdata(epc); + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + ++ /* ++ * Tear down the dedicated outbound window used for MSI ++ * generation. This avoids leaking an iATU window across ++ * endpoint stop/start cycles. ++ */ ++ if (ep->msi_iatu_mapped) { ++ dw_pcie_ep_unmap_addr(epc, 0, 0, ep->msi_mem_phys); ++ ep->msi_iatu_mapped = false; ++ } ++ + dw_pcie_stop_link(pci); + } + +@@ -702,14 +712,37 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, + msg_addr = ((u64)msg_addr_upper) << 32 | msg_addr_lower; + + msg_addr = dw_pcie_ep_align_addr(epc, msg_addr, &map_size, &offset); +- ret = dw_pcie_ep_map_addr(epc, func_no, 0, ep->msi_mem_phys, msg_addr, +- map_size); +- if (ret) +- return ret; + +- writel(msg_data | (interrupt_num - 1), ep->msi_mem + offset); ++ /* ++ * Program the outbound iATU once and keep it enabled. ++ * ++ * The spec warns that updating iATU registers while there are ++ * operations in flight on the AXI bridge interface is not ++ * supported, so we avoid reprogramming the region on every MSI, ++ * specifically unmapping immediately after writel(). ++ */ ++ if (!ep->msi_iatu_mapped) { ++ ret = dw_pcie_ep_map_addr(epc, func_no, 0, ++ ep->msi_mem_phys, msg_addr, ++ map_size); ++ if (ret) ++ return ret; ++ ++ ep->msi_iatu_mapped = true; ++ ep->msi_msg_addr = msg_addr; ++ ep->msi_map_size = map_size; ++ } else if (WARN_ON_ONCE(ep->msi_msg_addr != msg_addr || ++ ep->msi_map_size != map_size)) { ++ /* ++ * The host changed the MSI target address or the required ++ * mapping size changed. Reprogramming the iATU at runtime is ++ * unsafe on this controller, so bail out instead of trying to ++ * update the existing region. ++ */ ++ return -EINVAL; ++ } + +- dw_pcie_ep_unmap_addr(epc, func_no, 0, ep->msi_mem_phys); ++ writel(msg_data | (interrupt_num - 1), ep->msi_mem + offset); + + return 0; + } +@@ -1087,6 +1120,9 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) + struct device *dev = pci->dev; + + INIT_LIST_HEAD(&ep->func_list); ++ ep->msi_iatu_mapped = false; ++ ep->msi_msg_addr = 0; ++ ep->msi_map_size = 0; + + epc = devm_pci_epc_create(dev, &epc_ops); + if (IS_ERR(epc)) { +diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h +index aec4af5194b51..f9e2eaa3571e0 100644 +--- a/drivers/pci/controller/dwc/pcie-designware.h ++++ b/drivers/pci/controller/dwc/pcie-designware.h +@@ -479,6 +479,11 @@ struct dw_pcie_ep { + void __iomem *msi_mem; + phys_addr_t msi_mem_phys; + struct pci_epf_bar *epf_bar[PCI_STD_NUM_BARS]; ++ ++ /* MSI outbound iATU state */ ++ bool msi_iatu_mapped; ++ u64 msi_msg_addr; ++ size_t msi_map_size; + }; + + struct dw_pcie_ops { +-- +2.51.0 + diff --git a/queue-6.19/pci-dwc-ep-fix-resizable-bar-support-for-multi-pf-co.patch b/queue-6.19/pci-dwc-ep-fix-resizable-bar-support-for-multi-pf-co.patch new file mode 100644 index 0000000000..3f65a2f172 --- /dev/null +++ b/queue-6.19/pci-dwc-ep-fix-resizable-bar-support-for-multi-pf-co.patch @@ -0,0 +1,173 @@ +From 4bfb706c6f112f007b0416287efa7e47fbcdb3ad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 17:25:14 +0530 +Subject: PCI: dwc: ep: Fix resizable BAR support for multi-PF configurations + +From: Aksh Garg + +[ Upstream commit 43d67ec26b329f8aea34ba9dff23d69b84a8e564 ] + +The resizable BAR support added by the commit 3a3d4cabe681 ("PCI: dwc: ep: +Allow EPF drivers to configure the size of Resizable BARs") incorrectly +configures the resizable BARs only for the first Physical Function (PF0) +in EP mode. + +The resizable BAR configuration functions use generic dw_pcie_*_dbi() +operations instead of physical function specific dw_pcie_ep_*_dbi() +operations. This causes resizable BAR configuration to always target +PF0 regardless of the requested function number. + +Additionally, dw_pcie_ep_init_non_sticky_registers() only initializes +resizable BAR registers for PF0, leaving other PFs unconfigured during +the execution of this function. + +Fix this by using physical function specific configuration space access +operations throughout the resizable BAR code path and initializing +registers for all the physical functions that support resizable BARs. + +Fixes: 3a3d4cabe681 ("PCI: dwc: ep: Allow EPF drivers to configure the size of Resizable BARs") +Signed-off-by: Aksh Garg +[mani: added stable tag] +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Reviewed-by: Niklas Cassel +Cc: stable@vger.kernel.org +Link: https://patch.msgid.link/20260130115516.515082-2-a-garg7@ti.com +Stable-dep-of: 72cb5ed2a5c6 ("PCI: dwc: ep: Add per-PF BAR and inbound ATU mapping support") +Signed-off-by: Sasha Levin +--- + .../pci/controller/dwc/pcie-designware-ep.c | 48 ++++++++++++------- + 1 file changed, 32 insertions(+), 16 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c +index 855b2e58c3380..1cc2985bab03d 100644 +--- a/drivers/pci/controller/dwc/pcie-designware-ep.c ++++ b/drivers/pci/controller/dwc/pcie-designware-ep.c +@@ -75,6 +75,13 @@ static u8 dw_pcie_ep_find_capability(struct dw_pcie_ep *ep, u8 func_no, u8 cap) + cap, NULL, ep, func_no); + } + ++static u16 dw_pcie_ep_find_ext_capability(struct dw_pcie_ep *ep, ++ u8 func_no, u8 cap) ++{ ++ return PCI_FIND_NEXT_EXT_CAP(dw_pcie_ep_read_cfg, 0, ++ cap, NULL, ep, func_no); ++} ++ + static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no, u8 vfunc_no, + struct pci_epf_header *hdr) + { +@@ -350,22 +357,22 @@ static void dw_pcie_ep_clear_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no, + ep->epf_bar[bar] = NULL; + } + +-static unsigned int dw_pcie_ep_get_rebar_offset(struct dw_pcie *pci, ++static unsigned int dw_pcie_ep_get_rebar_offset(struct dw_pcie_ep *ep, u8 func_no, + enum pci_barno bar) + { + u32 reg, bar_index; + unsigned int offset, nbars; + int i; + +- offset = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_REBAR); ++ offset = dw_pcie_ep_find_ext_capability(ep, func_no, PCI_EXT_CAP_ID_REBAR); + if (!offset) + return offset; + +- reg = dw_pcie_readl_dbi(pci, offset + PCI_REBAR_CTRL); ++ reg = dw_pcie_ep_readl_dbi(ep, func_no, offset + PCI_REBAR_CTRL); + nbars = FIELD_GET(PCI_REBAR_CTRL_NBAR_MASK, reg); + + for (i = 0; i < nbars; i++, offset += PCI_REBAR_CTRL) { +- reg = dw_pcie_readl_dbi(pci, offset + PCI_REBAR_CTRL); ++ reg = dw_pcie_ep_readl_dbi(ep, func_no, offset + PCI_REBAR_CTRL); + bar_index = FIELD_GET(PCI_REBAR_CTRL_BAR_IDX, reg); + if (bar_index == bar) + return offset; +@@ -386,7 +393,7 @@ static int dw_pcie_ep_set_bar_resizable(struct dw_pcie_ep *ep, u8 func_no, + u32 rebar_cap, rebar_ctrl; + int ret; + +- rebar_offset = dw_pcie_ep_get_rebar_offset(pci, bar); ++ rebar_offset = dw_pcie_ep_get_rebar_offset(ep, func_no, bar); + if (!rebar_offset) + return -EINVAL; + +@@ -416,16 +423,16 @@ static int dw_pcie_ep_set_bar_resizable(struct dw_pcie_ep *ep, u8 func_no, + * 1 MB to 128 TB. Bits 31:16 in PCI_REBAR_CTRL define "supported sizes" + * bits for sizes 256 TB to 8 EB. Disallow sizes 256 TB to 8 EB. + */ +- rebar_ctrl = dw_pcie_readl_dbi(pci, rebar_offset + PCI_REBAR_CTRL); ++ rebar_ctrl = dw_pcie_ep_readl_dbi(ep, func_no, rebar_offset + PCI_REBAR_CTRL); + rebar_ctrl &= ~GENMASK(31, 16); +- dw_pcie_writel_dbi(pci, rebar_offset + PCI_REBAR_CTRL, rebar_ctrl); ++ dw_pcie_ep_writel_dbi(ep, func_no, rebar_offset + PCI_REBAR_CTRL, rebar_ctrl); + + /* + * The "selected size" (bits 13:8) in PCI_REBAR_CTRL are automatically + * updated when writing PCI_REBAR_CAP, see "Figure 3-26 Resizable BAR + * Example for 32-bit Memory BAR0" in DWC EP databook 5.96a. + */ +- dw_pcie_writel_dbi(pci, rebar_offset + PCI_REBAR_CAP, rebar_cap); ++ dw_pcie_ep_writel_dbi(ep, func_no, rebar_offset + PCI_REBAR_CAP, rebar_cap); + + dw_pcie_dbi_ro_wr_dis(pci); + +@@ -1023,20 +1030,17 @@ void dw_pcie_ep_deinit(struct dw_pcie_ep *ep) + } + EXPORT_SYMBOL_GPL(dw_pcie_ep_deinit); + +-static void dw_pcie_ep_init_non_sticky_registers(struct dw_pcie *pci) ++static void dw_pcie_ep_init_rebar_registers(struct dw_pcie_ep *ep, u8 func_no) + { +- struct dw_pcie_ep *ep = &pci->ep; + unsigned int offset; + unsigned int nbars; + enum pci_barno bar; + u32 reg, i, val; + +- offset = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_REBAR); +- +- dw_pcie_dbi_ro_wr_en(pci); ++ offset = dw_pcie_ep_find_ext_capability(ep, func_no, PCI_EXT_CAP_ID_REBAR); + + if (offset) { +- reg = dw_pcie_readl_dbi(pci, offset + PCI_REBAR_CTRL); ++ reg = dw_pcie_ep_readl_dbi(ep, func_no, offset + PCI_REBAR_CTRL); + nbars = FIELD_GET(PCI_REBAR_CTRL_NBAR_MASK, reg); + + /* +@@ -1057,16 +1061,28 @@ static void dw_pcie_ep_init_non_sticky_registers(struct dw_pcie *pci) + * the controller when RESBAR_CAP_REG is written, which + * is why RESBAR_CAP_REG is written here. + */ +- val = dw_pcie_readl_dbi(pci, offset + PCI_REBAR_CTRL); ++ val = dw_pcie_ep_readl_dbi(ep, func_no, offset + PCI_REBAR_CTRL); + bar = FIELD_GET(PCI_REBAR_CTRL_BAR_IDX, val); + if (ep->epf_bar[bar]) + pci_epc_bar_size_to_rebar_cap(ep->epf_bar[bar]->size, &val); + else + val = BIT(4); + +- dw_pcie_writel_dbi(pci, offset + PCI_REBAR_CAP, val); ++ dw_pcie_ep_writel_dbi(ep, func_no, offset + PCI_REBAR_CAP, val); + } + } ++} ++ ++static void dw_pcie_ep_init_non_sticky_registers(struct dw_pcie *pci) ++{ ++ struct dw_pcie_ep *ep = &pci->ep; ++ u8 funcs = ep->epc->max_functions; ++ u8 func_no; ++ ++ dw_pcie_dbi_ro_wr_en(pci); ++ ++ for (func_no = 0; func_no < funcs; func_no++) ++ dw_pcie_ep_init_rebar_registers(ep, func_no); + + dw_pcie_setup(pci); + dw_pcie_dbi_ro_wr_dis(pci); +-- +2.51.0 + diff --git a/queue-6.19/pci-dwc-ep-support-bar-subrange-inbound-mapping-via-.patch b/queue-6.19/pci-dwc-ep-support-bar-subrange-inbound-mapping-via-.patch new file mode 100644 index 0000000000..f1fe3cc7d4 --- /dev/null +++ b/queue-6.19/pci-dwc-ep-support-bar-subrange-inbound-mapping-via-.patch @@ -0,0 +1,337 @@ +From ad97aaf34840ebf1503c214531e2da1ccae164f3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 24 Jan 2026 23:50:08 +0900 +Subject: PCI: dwc: ep: Support BAR subrange inbound mapping via Address Match + Mode iATU + +From: Koichiro Den + +[ Upstream commit cc839bef7727043a66004bba563492957ca3e531 ] + +Extend dw_pcie_ep_set_bar() to support inbound mappings for BAR +subranges using Address Match Mode IB iATU when pci_epf_bar.num_submap +is non-zero. + +Rename the existing BAR-match helper into dw_pcie_ep_ib_atu_bar() and +introduce dw_pcie_ep_ib_atu_addr() for Address Match Mode. When +num_submap is non-zero, read the assigned BAR base address and program +one inbound iATU window per subrange. Validate the submap array before +programming: +- each subrange is aligned to pci->region_align +- subranges cover the whole BAR (no gaps and no overlaps) + +Track Address Match Mode mappings and tear them down on clear_bar() and +on set_bar() error paths to avoid leaving half-programmed state or +untranslated BAR holes. + +Advertise this capability by extending the common feature bit +initializer macro (DWC_EPC_COMMON_FEATURES). + +This enables multiple inbound windows within a single BAR, which is +useful on platforms where usable BARs are scarce but EPFs need multiple +inbound regions. + +Signed-off-by: Koichiro Den +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Reviewed-by: Frank Li +Reviewed-by: Niklas Cassel +Link: https://patch.msgid.link/20260124145012.2794108-5-den@valinux.co.jp +Stable-dep-of: 72cb5ed2a5c6 ("PCI: dwc: ep: Add per-PF BAR and inbound ATU mapping support") +Signed-off-by: Sasha Levin +--- + .../pci/controller/dwc/pcie-designware-ep.c | 213 +++++++++++++++++- + drivers/pci/controller/dwc/pcie-designware.h | 7 +- + 2 files changed, 209 insertions(+), 11 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c +index cfd59899c7b85..855b2e58c3380 100644 +--- a/drivers/pci/controller/dwc/pcie-designware-ep.c ++++ b/drivers/pci/controller/dwc/pcie-designware-ep.c +@@ -100,9 +100,10 @@ static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no, u8 vfunc_no, + return 0; + } + +-static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, u8 func_no, int type, +- dma_addr_t parent_bus_addr, enum pci_barno bar, +- size_t size) ++/* BAR Match Mode inbound iATU mapping */ ++static int dw_pcie_ep_ib_atu_bar(struct dw_pcie_ep *ep, u8 func_no, int type, ++ dma_addr_t parent_bus_addr, enum pci_barno bar, ++ size_t size) + { + int ret; + u32 free_win; +@@ -135,6 +136,179 @@ static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, u8 func_no, int type, + return 0; + } + ++static void dw_pcie_ep_clear_ib_maps(struct dw_pcie_ep *ep, enum pci_barno bar) ++{ ++ struct dw_pcie *pci = to_dw_pcie_from_ep(ep); ++ struct device *dev = pci->dev; ++ unsigned int i, num; ++ u32 atu_index; ++ u32 *indexes; ++ ++ /* Tear down the BAR Match Mode mapping, if any. */ ++ if (ep->bar_to_atu[bar]) { ++ atu_index = ep->bar_to_atu[bar] - 1; ++ dw_pcie_disable_atu(pci, PCIE_ATU_REGION_DIR_IB, atu_index); ++ clear_bit(atu_index, ep->ib_window_map); ++ ep->bar_to_atu[bar] = 0; ++ } ++ ++ /* Tear down all Address Match Mode mappings, if any. */ ++ indexes = ep->ib_atu_indexes[bar]; ++ num = ep->num_ib_atu_indexes[bar]; ++ ep->ib_atu_indexes[bar] = NULL; ++ ep->num_ib_atu_indexes[bar] = 0; ++ if (!indexes) ++ return; ++ for (i = 0; i < num; i++) { ++ dw_pcie_disable_atu(pci, PCIE_ATU_REGION_DIR_IB, indexes[i]); ++ clear_bit(indexes[i], ep->ib_window_map); ++ } ++ devm_kfree(dev, indexes); ++} ++ ++static u64 dw_pcie_ep_read_bar_assigned(struct dw_pcie_ep *ep, u8 func_no, ++ enum pci_barno bar, int flags) ++{ ++ u32 reg = PCI_BASE_ADDRESS_0 + (4 * bar); ++ u32 lo, hi; ++ u64 addr; ++ ++ lo = dw_pcie_ep_readl_dbi(ep, func_no, reg); ++ ++ if (flags & PCI_BASE_ADDRESS_SPACE) ++ return lo & PCI_BASE_ADDRESS_IO_MASK; ++ ++ addr = lo & PCI_BASE_ADDRESS_MEM_MASK; ++ if (!(flags & PCI_BASE_ADDRESS_MEM_TYPE_64)) ++ return addr; ++ ++ hi = dw_pcie_ep_readl_dbi(ep, func_no, reg + 4); ++ return addr | ((u64)hi << 32); ++} ++ ++static int dw_pcie_ep_validate_submap(struct dw_pcie_ep *ep, ++ const struct pci_epf_bar_submap *submap, ++ unsigned int num_submap, size_t bar_size) ++{ ++ struct dw_pcie *pci = to_dw_pcie_from_ep(ep); ++ u32 align = pci->region_align; ++ size_t off = 0; ++ unsigned int i; ++ size_t size; ++ ++ if (!align || !IS_ALIGNED(bar_size, align)) ++ return -EINVAL; ++ ++ /* ++ * The submap array order defines the BAR layout (submap[0] starts ++ * at offset 0 and each entry immediately follows the previous ++ * one). Here, validate that it forms a strict, gapless ++ * decomposition of the BAR: ++ * - each entry has a non-zero size ++ * - sizes, implicit offsets and phys_addr are aligned to ++ * pci->region_align ++ * - each entry lies within the BAR range ++ * - the entries exactly cover the whole BAR ++ * ++ * Note: dw_pcie_prog_inbound_atu() also checks alignment for the ++ * PCI address and the target phys_addr, but validating up-front ++ * avoids partially programming iATU windows in vain. ++ */ ++ for (i = 0; i < num_submap; i++) { ++ size = submap[i].size; ++ ++ if (!size) ++ return -EINVAL; ++ ++ if (!IS_ALIGNED(size, align) || !IS_ALIGNED(off, align)) ++ return -EINVAL; ++ ++ if (!IS_ALIGNED(submap[i].phys_addr, align)) ++ return -EINVAL; ++ ++ if (off > bar_size || size > bar_size - off) ++ return -EINVAL; ++ ++ off += size; ++ } ++ if (off != bar_size) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++/* Address Match Mode inbound iATU mapping */ ++static int dw_pcie_ep_ib_atu_addr(struct dw_pcie_ep *ep, u8 func_no, int type, ++ const struct pci_epf_bar *epf_bar) ++{ ++ const struct pci_epf_bar_submap *submap = epf_bar->submap; ++ struct dw_pcie *pci = to_dw_pcie_from_ep(ep); ++ enum pci_barno bar = epf_bar->barno; ++ struct device *dev = pci->dev; ++ u64 pci_addr, parent_bus_addr; ++ u64 size, base, off = 0; ++ int free_win, ret; ++ unsigned int i; ++ u32 *indexes; ++ ++ if (!epf_bar->num_submap || !submap || !epf_bar->size) ++ return -EINVAL; ++ ++ ret = dw_pcie_ep_validate_submap(ep, submap, epf_bar->num_submap, ++ epf_bar->size); ++ if (ret) ++ return ret; ++ ++ base = dw_pcie_ep_read_bar_assigned(ep, func_no, bar, epf_bar->flags); ++ if (!base) { ++ dev_err(dev, ++ "BAR%u not assigned, cannot set up sub-range mappings\n", ++ bar); ++ return -EINVAL; ++ } ++ ++ indexes = devm_kcalloc(dev, epf_bar->num_submap, sizeof(*indexes), ++ GFP_KERNEL); ++ if (!indexes) ++ return -ENOMEM; ++ ++ ep->ib_atu_indexes[bar] = indexes; ++ ep->num_ib_atu_indexes[bar] = 0; ++ ++ for (i = 0; i < epf_bar->num_submap; i++) { ++ size = submap[i].size; ++ parent_bus_addr = submap[i].phys_addr; ++ ++ if (off > (~0ULL) - base) { ++ ret = -EINVAL; ++ goto err; ++ } ++ ++ pci_addr = base + off; ++ off += size; ++ ++ free_win = find_first_zero_bit(ep->ib_window_map, ++ pci->num_ib_windows); ++ if (free_win >= pci->num_ib_windows) { ++ ret = -ENOSPC; ++ goto err; ++ } ++ ++ ret = dw_pcie_prog_inbound_atu(pci, free_win, type, ++ parent_bus_addr, pci_addr, size); ++ if (ret) ++ goto err; ++ ++ set_bit(free_win, ep->ib_window_map); ++ indexes[i] = free_win; ++ ep->num_ib_atu_indexes[bar] = i + 1; ++ } ++ return 0; ++err: ++ dw_pcie_ep_clear_ib_maps(ep, bar); ++ return ret; ++} ++ + static int dw_pcie_ep_outbound_atu(struct dw_pcie_ep *ep, + struct dw_pcie_ob_atu_cfg *atu) + { +@@ -165,17 +339,15 @@ static void dw_pcie_ep_clear_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no, + struct dw_pcie_ep *ep = epc_get_drvdata(epc); + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + enum pci_barno bar = epf_bar->barno; +- u32 atu_index = ep->bar_to_atu[bar] - 1; + +- if (!ep->bar_to_atu[bar]) ++ if (!ep->epf_bar[bar]) + return; + + __dw_pcie_ep_reset_bar(pci, func_no, bar, epf_bar->flags); + +- dw_pcie_disable_atu(pci, PCIE_ATU_REGION_DIR_IB, atu_index); +- clear_bit(atu_index, ep->ib_window_map); ++ dw_pcie_ep_clear_ib_maps(ep, bar); ++ + ep->epf_bar[bar] = NULL; +- ep->bar_to_atu[bar] = 0; + } + + static unsigned int dw_pcie_ep_get_rebar_offset(struct dw_pcie *pci, +@@ -331,11 +503,28 @@ static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no, + ep->epf_bar[bar]->flags != flags) + return -EINVAL; + ++ /* ++ * When dynamically changing a BAR, tear down any existing ++ * mappings before re-programming. ++ */ ++ if (ep->epf_bar[bar]->num_submap || epf_bar->num_submap) ++ dw_pcie_ep_clear_ib_maps(ep, bar); ++ + /* + * When dynamically changing a BAR, skip writing the BAR reg, as + * that would clear the BAR's PCI address assigned by the host. + */ + goto config_atu; ++ } else { ++ /* ++ * Subrange mapping is an update-only operation. The BAR ++ * must have been configured once without submaps so that ++ * subsequent set_bar() calls can update inbound mappings ++ * without touching the BAR register (and clobbering the ++ * host-assigned address). ++ */ ++ if (epf_bar->num_submap) ++ return -EINVAL; + } + + bar_type = dw_pcie_ep_get_bar_type(ep, bar); +@@ -369,8 +558,12 @@ static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no, + else + type = PCIE_ATU_TYPE_IO; + +- ret = dw_pcie_ep_inbound_atu(ep, func_no, type, epf_bar->phys_addr, bar, +- size); ++ if (epf_bar->num_submap) ++ ret = dw_pcie_ep_ib_atu_addr(ep, func_no, type, epf_bar); ++ else ++ ret = dw_pcie_ep_ib_atu_bar(ep, func_no, type, ++ epf_bar->phys_addr, bar, size); ++ + if (ret) + return ret; + +diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h +index 205fb55fca8c0..3c4220027415e 100644 +--- a/drivers/pci/controller/dwc/pcie-designware.h ++++ b/drivers/pci/controller/dwc/pcie-designware.h +@@ -306,7 +306,8 @@ + #define DMA_LLP_MEM_SIZE PAGE_SIZE + + /* Common struct pci_epc_feature bits among DWC EP glue drivers */ +-#define DWC_EPC_COMMON_FEATURES .dynamic_inbound_mapping = true ++#define DWC_EPC_COMMON_FEATURES .dynamic_inbound_mapping = true, \ ++ .subrange_mapping = true + + struct dw_pcie; + struct dw_pcie_rp; +@@ -483,6 +484,10 @@ struct dw_pcie_ep { + phys_addr_t msi_mem_phys; + struct pci_epf_bar *epf_bar[PCI_STD_NUM_BARS]; + ++ /* Only for Address Match Mode inbound iATU */ ++ u32 *ib_atu_indexes[PCI_STD_NUM_BARS]; ++ unsigned int num_ib_atu_indexes[PCI_STD_NUM_BARS]; ++ + /* MSI outbound iATU state */ + bool msi_iatu_mapped; + u64 msi_msg_addr; +-- +2.51.0 + diff --git a/queue-6.19/pci-dwc-remove-duplicate-dw_pcie_ep_hide_ext_capabil.patch b/queue-6.19/pci-dwc-remove-duplicate-dw_pcie_ep_hide_ext_capabil.patch new file mode 100644 index 0000000000..cf8e9a23b9 --- /dev/null +++ b/queue-6.19/pci-dwc-remove-duplicate-dw_pcie_ep_hide_ext_capabil.patch @@ -0,0 +1,121 @@ +From 3580be83fb9a453fd1325f665f9fd06cc20d6496 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Dec 2025 02:10:46 -0800 +Subject: PCI: dwc: Remove duplicate dw_pcie_ep_hide_ext_capability() function + +From: Qiang Yu + +[ Upstream commit 86291f774fe8524178446cb2c792939640b4970c ] + +Remove dw_pcie_ep_hide_ext_capability() and replace its usage with +dw_pcie_remove_ext_capability(). Both functions serve the same purpose +of hiding PCIe extended capabilities, but dw_pcie_remove_ext_capability() +provides a cleaner API that doesn't require the caller to specify the +previous capability ID. + +Suggested-by: Niklas Cassel +Signed-off-by: Qiang Yu +Signed-off-by: Manivannan Sadhasivam +Tested-by: Niklas Cassel +Link: https://patch.msgid.link/20251224-remove_dw_pcie_ep_hide_ext_capability-v1-1-4302c9cdc316@oss.qualcomm.com +Stable-dep-of: 72cb5ed2a5c6 ("PCI: dwc: ep: Add per-PF BAR and inbound ATU mapping support") +Signed-off-by: Sasha Levin +--- + .../pci/controller/dwc/pcie-designware-ep.c | 39 ------------------- + drivers/pci/controller/dwc/pcie-designware.h | 7 ---- + drivers/pci/controller/dwc/pcie-dw-rockchip.c | 4 +- + 3 files changed, 1 insertion(+), 49 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c +index 1195d401df19e..cfd59899c7b85 100644 +--- a/drivers/pci/controller/dwc/pcie-designware-ep.c ++++ b/drivers/pci/controller/dwc/pcie-designware-ep.c +@@ -75,45 +75,6 @@ static u8 dw_pcie_ep_find_capability(struct dw_pcie_ep *ep, u8 func_no, u8 cap) + cap, NULL, ep, func_no); + } + +-/** +- * dw_pcie_ep_hide_ext_capability - Hide a capability from the linked list +- * @pci: DWC PCI device +- * @prev_cap: Capability preceding the capability that should be hidden +- * @cap: Capability that should be hidden +- * +- * Return: 0 if success, errno otherwise. +- */ +-int dw_pcie_ep_hide_ext_capability(struct dw_pcie *pci, u8 prev_cap, u8 cap) +-{ +- u16 prev_cap_offset, cap_offset; +- u32 prev_cap_header, cap_header; +- +- prev_cap_offset = dw_pcie_find_ext_capability(pci, prev_cap); +- if (!prev_cap_offset) +- return -EINVAL; +- +- prev_cap_header = dw_pcie_readl_dbi(pci, prev_cap_offset); +- cap_offset = PCI_EXT_CAP_NEXT(prev_cap_header); +- cap_header = dw_pcie_readl_dbi(pci, cap_offset); +- +- /* cap must immediately follow prev_cap. */ +- if (PCI_EXT_CAP_ID(cap_header) != cap) +- return -EINVAL; +- +- /* Clear next ptr. */ +- prev_cap_header &= ~GENMASK(31, 20); +- +- /* Set next ptr to next ptr of cap. */ +- prev_cap_header |= cap_header & GENMASK(31, 20); +- +- dw_pcie_dbi_ro_wr_en(pci); +- dw_pcie_writel_dbi(pci, prev_cap_offset, prev_cap_header); +- dw_pcie_dbi_ro_wr_dis(pci); +- +- return 0; +-} +-EXPORT_SYMBOL_GPL(dw_pcie_ep_hide_ext_capability); +- + static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no, u8 vfunc_no, + struct pci_epf_header *hdr) + { +diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h +index f9e2eaa3571e0..8a99a9c393f53 100644 +--- a/drivers/pci/controller/dwc/pcie-designware.h ++++ b/drivers/pci/controller/dwc/pcie-designware.h +@@ -906,7 +906,6 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, + int dw_pcie_ep_raise_msix_irq_doorbell(struct dw_pcie_ep *ep, u8 func_no, + u16 interrupt_num); + void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar); +-int dw_pcie_ep_hide_ext_capability(struct dw_pcie *pci, u8 prev_cap, u8 cap); + struct dw_pcie_ep_func * + dw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, u8 func_no); + #else +@@ -964,12 +963,6 @@ static inline void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar) + { + } + +-static inline int dw_pcie_ep_hide_ext_capability(struct dw_pcie *pci, +- u8 prev_cap, u8 cap) +-{ +- return 0; +-} +- + static inline struct dw_pcie_ep_func * + dw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, u8 func_no) + { +diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c +index f8605fe61a415..2f865f67a10a7 100644 +--- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c ++++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c +@@ -327,9 +327,7 @@ static void rockchip_pcie_ep_hide_broken_ats_cap_rk3588(struct dw_pcie_ep *ep) + if (!of_device_is_compatible(dev->of_node, "rockchip,rk3588-pcie-ep")) + return; + +- if (dw_pcie_ep_hide_ext_capability(pci, PCI_EXT_CAP_ID_SECPCI, +- PCI_EXT_CAP_ID_ATS)) +- dev_err(dev, "failed to hide ATS capability\n"); ++ dw_pcie_remove_ext_capability(pci, PCI_EXT_CAP_ID_ATS); + } + + static void rockchip_pcie_ep_init(struct dw_pcie_ep *ep) +-- +2.51.0 + diff --git a/queue-6.19/pci-endpoint-add-bar-subrange-mapping-support.patch b/queue-6.19/pci-endpoint-add-bar-subrange-mapping-support.patch new file mode 100644 index 0000000000..3468a64ca4 --- /dev/null +++ b/queue-6.19/pci-endpoint-add-bar-subrange-mapping-support.patch @@ -0,0 +1,135 @@ +From ca9df79429d478cc0f562264daeacd18b668559f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 24 Jan 2026 23:50:06 +0900 +Subject: PCI: endpoint: Add BAR subrange mapping support + +From: Koichiro Den + +[ Upstream commit 31fb95400451040050361e22ff480476964280f0 ] + +Some endpoint platforms have only a small number of usable BARs. At the +same time, EPF drivers (e.g. vNTB) may need multiple independent inbound +regions (control/scratchpad, one or more memory windows, and optionally +MSI or other feature-related regions). Subrange mapping allows these to +share a single BAR without consuming additional BARs that may not be +available, or forcing a fragile layout by aggressively packing into a +single contiguous memory range. + +Extend the PCI endpoint core to support mapping subranges within a BAR. +Add an optional 'submap' field in struct pci_epf_bar so an endpoint +function driver can request inbound mappings that fully cover the BAR. + +Introduce a new EPC feature bit, subrange_mapping, and reject submap +requests from pci_epc_set_bar() unless the controller advertises both +subrange_mapping and dynamic_inbound_mapping features. + +The submap array describes the complete BAR layout (no overlaps and no +gaps are allowed to avoid exposing untranslated address ranges). This +provides the generic infrastructure needed to map multiple logical +regions into a single BAR at different offsets, without assuming a +controller-specific inbound address translation mechanism. + +Signed-off-by: Koichiro Den +Signed-off-by: Manivannan Sadhasivam +Reviewed-by: Niklas Cassel +Link: https://patch.msgid.link/20260124145012.2794108-3-den@valinux.co.jp +Stable-dep-of: 72cb5ed2a5c6 ("PCI: dwc: ep: Add per-PF BAR and inbound ATU mapping support") +Signed-off-by: Sasha Levin +--- + drivers/pci/endpoint/pci-epc-core.c | 8 ++++++++ + include/linux/pci-epc.h | 4 ++++ + include/linux/pci-epf.h | 23 +++++++++++++++++++++++ + 3 files changed, 35 insertions(+) + +diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c +index ca7f19cc973a4..068155819c575 100644 +--- a/drivers/pci/endpoint/pci-epc-core.c ++++ b/drivers/pci/endpoint/pci-epc-core.c +@@ -596,6 +596,14 @@ int pci_epc_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no, + if (!epc_features) + return -EINVAL; + ++ if (epf_bar->num_submap && !epf_bar->submap) ++ return -EINVAL; ++ ++ if (epf_bar->num_submap && ++ !(epc_features->dynamic_inbound_mapping && ++ epc_features->subrange_mapping)) ++ return -EINVAL; ++ + if (epc_features->bar[bar].type == BAR_RESIZABLE && + (epf_bar->size < SZ_1M || (u64)epf_bar->size > (SZ_128G * 1024))) + return -EINVAL; +diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h +index 4c8516756c568..c021c7af175fd 100644 +--- a/include/linux/pci-epc.h ++++ b/include/linux/pci-epc.h +@@ -227,6 +227,9 @@ struct pci_epc_bar_desc { + * inbound mappings for an already configured BAR + * (i.e. allow calling pci_epc_set_bar() again + * without first calling pci_epc_clear_bar()) ++ * @subrange_mapping: indicate if the EPC device can map inbound subranges for a ++ * BAR. This feature depends on @dynamic_inbound_mapping ++ * feature. + * @msi_capable: indicate if the endpoint function has MSI capability + * @msix_capable: indicate if the endpoint function has MSI-X capability + * @intx_capable: indicate if the endpoint can raise INTx interrupts +@@ -236,6 +239,7 @@ struct pci_epc_bar_desc { + struct pci_epc_features { + unsigned int linkup_notifier : 1; + unsigned int dynamic_inbound_mapping : 1; ++ unsigned int subrange_mapping : 1; + unsigned int msi_capable : 1; + unsigned int msix_capable : 1; + unsigned int intx_capable : 1; +diff --git a/include/linux/pci-epf.h b/include/linux/pci-epf.h +index 48f68c4dcfa5e..7737a7c03260d 100644 +--- a/include/linux/pci-epf.h ++++ b/include/linux/pci-epf.h +@@ -110,6 +110,22 @@ struct pci_epf_driver { + + #define to_pci_epf_driver(drv) container_of_const((drv), struct pci_epf_driver, driver) + ++/** ++ * struct pci_epf_bar_submap - BAR subrange for inbound mapping ++ * @phys_addr: target physical/DMA address for this subrange ++ * @size: the size of the subrange to be mapped ++ * ++ * When pci_epf_bar.num_submap is >0, pci_epf_bar.submap describes the ++ * complete BAR layout. This allows an EPC driver to program multiple ++ * inbound translation windows for a single BAR when supported by the ++ * controller. The array order defines the BAR layout (submap[0] at offset ++ * 0, and each immediately follows the previous one). ++ */ ++struct pci_epf_bar_submap { ++ dma_addr_t phys_addr; ++ size_t size; ++}; ++ + /** + * struct pci_epf_bar - represents the BAR of EPF device + * @phys_addr: physical address that should be mapped to the BAR +@@ -119,6 +135,9 @@ struct pci_epf_driver { + * requirement + * @barno: BAR number + * @flags: flags that are set for the BAR ++ * @num_submap: number of entries in @submap ++ * @submap: array of subrange descriptors allocated by the caller. See ++ * struct pci_epf_bar_submap for the semantics in detail. + */ + struct pci_epf_bar { + dma_addr_t phys_addr; +@@ -127,6 +146,10 @@ struct pci_epf_bar { + size_t mem_size; + enum pci_barno barno; + int flags; ++ ++ /* Optional sub-range mapping */ ++ unsigned int num_submap; ++ struct pci_epf_bar_submap *submap; + }; + + /** +-- +2.51.0 + diff --git a/queue-6.19/pci-endpoint-add-dynamic_inbound_mapping-epc-feature.patch b/queue-6.19/pci-endpoint-add-dynamic_inbound_mapping-epc-feature.patch new file mode 100644 index 0000000000..e3514590ba --- /dev/null +++ b/queue-6.19/pci-endpoint-add-dynamic_inbound_mapping-epc-feature.patch @@ -0,0 +1,56 @@ +From c66f1c0e25a68a218f8a2523fb7fc92e847c7690 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 24 Jan 2026 23:50:05 +0900 +Subject: PCI: endpoint: Add dynamic_inbound_mapping EPC feature + +From: Koichiro Den + +[ Upstream commit 06a81c5940e46cc7bddee28f16bdd29a12a76344 ] + +Introduce a new EPC feature bit (dynamic_inbound_mapping) that indicates +whether an Endpoint Controller can update the inbound address +translation for a BAR without requiring the EPF driver to clear/reset +the BAR first. + +Endpoint Function drivers (e.g. vNTB) can use this information to decide +whether it really is safe to call pci_epc_set_bar() multiple times to +update inbound mappings for the BAR. + +Suggested-by: Niklas Cassel +Signed-off-by: Koichiro Den +Signed-off-by: Manivannan Sadhasivam +Reviewed-by: Niklas Cassel +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260124145012.2794108-2-den@valinux.co.jp +Stable-dep-of: 72cb5ed2a5c6 ("PCI: dwc: ep: Add per-PF BAR and inbound ATU mapping support") +Signed-off-by: Sasha Levin +--- + include/linux/pci-epc.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h +index 4286bfdbfdfad..4c8516756c568 100644 +--- a/include/linux/pci-epc.h ++++ b/include/linux/pci-epc.h +@@ -223,6 +223,10 @@ struct pci_epc_bar_desc { + /** + * struct pci_epc_features - features supported by a EPC device per function + * @linkup_notifier: indicate if the EPC device can notify EPF driver on link up ++ * @dynamic_inbound_mapping: indicate if the EPC device supports updating ++ * inbound mappings for an already configured BAR ++ * (i.e. allow calling pci_epc_set_bar() again ++ * without first calling pci_epc_clear_bar()) + * @msi_capable: indicate if the endpoint function has MSI capability + * @msix_capable: indicate if the endpoint function has MSI-X capability + * @intx_capable: indicate if the endpoint can raise INTx interrupts +@@ -231,6 +235,7 @@ struct pci_epc_bar_desc { + */ + struct pci_epc_features { + unsigned int linkup_notifier : 1; ++ unsigned int dynamic_inbound_mapping : 1; + unsigned int msi_capable : 1; + unsigned int msix_capable : 1; + unsigned int intx_capable : 1; +-- +2.51.0 + diff --git a/queue-6.19/pci-endpoint-add-missing-null-check-for-alloc_workqu.patch b/queue-6.19/pci-endpoint-add-missing-null-check-for-alloc_workqu.patch new file mode 100644 index 0000000000..da4cb8df1c --- /dev/null +++ b/queue-6.19/pci-endpoint-add-missing-null-check-for-alloc_workqu.patch @@ -0,0 +1,65 @@ +From 596b54ab0d02ed2cb8f4eaad224a492d26e6f11e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 10 Nov 2025 12:04:46 +0800 +Subject: PCI: endpoint: Add missing NULL check for alloc_workqueue() + +From: Haotian Zhang + +[ Upstream commit 03f336a869b3a3f119d3ae52ac9723739c7fb7b6 ] + +alloc_workqueue() can return NULL on memory allocation failure. Without +proper error checking, this may lead to a NULL pointer dereference when +queue_work() is later called with the NULL workqueue pointer in +epf_ntb_epc_init(). + +Add a NULL check immediately after alloc_workqueue() and return -ENOMEM on +failure to prevent the driver from loading with an invalid workqueue +pointer. + +Fixes: e35f56bb0330 ("PCI: endpoint: Support NTB transfer between RC and EP") +Fixes: 8b821cf76150 ("PCI: endpoint: Add EP function driver to provide NTB functionality") +Signed-off-by: Haotian Zhang +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20251110040446.2065-1-vulab@iscas.ac.cn +Signed-off-by: Sasha Levin +--- + drivers/pci/endpoint/functions/pci-epf-ntb.c | 5 +++++ + drivers/pci/endpoint/functions/pci-epf-vntb.c | 5 +++++ + 2 files changed, 10 insertions(+) + +diff --git a/drivers/pci/endpoint/functions/pci-epf-ntb.c b/drivers/pci/endpoint/functions/pci-epf-ntb.c +index 9ea8b57d69d79..a3a588e522e71 100644 +--- a/drivers/pci/endpoint/functions/pci-epf-ntb.c ++++ b/drivers/pci/endpoint/functions/pci-epf-ntb.c +@@ -2126,6 +2126,11 @@ static int __init epf_ntb_init(void) + + kpcintb_workqueue = alloc_workqueue("kpcintb", + WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_PERCPU, 0); ++ if (!kpcintb_workqueue) { ++ pr_err("Failed to allocate kpcintb workqueue\n"); ++ return -ENOMEM; ++ } ++ + ret = pci_epf_register_driver(&epf_ntb_driver); + if (ret) { + destroy_workqueue(kpcintb_workqueue); +diff --git a/drivers/pci/endpoint/functions/pci-epf-vntb.c b/drivers/pci/endpoint/functions/pci-epf-vntb.c +index a098727f784bd..20a400e834392 100644 +--- a/drivers/pci/endpoint/functions/pci-epf-vntb.c ++++ b/drivers/pci/endpoint/functions/pci-epf-vntb.c +@@ -1653,6 +1653,11 @@ static int __init epf_ntb_init(void) + + kpcintb_workqueue = alloc_workqueue("kpcintb", + WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_PERCPU, 0); ++ if (!kpcintb_workqueue) { ++ pr_err("Failed to allocate kpcintb workqueue\n"); ++ return -ENOMEM; ++ } ++ + ret = pci_epf_register_driver(&epf_ntb_driver); + if (ret) { + destroy_workqueue(kpcintb_workqueue); +-- +2.51.0 + diff --git a/queue-6.19/pci-initialize-rcb-from-pci_configure_device.patch b/queue-6.19/pci-initialize-rcb-from-pci_configure_device.patch new file mode 100644 index 0000000000..fbc4857eb6 --- /dev/null +++ b/queue-6.19/pci-initialize-rcb-from-pci_configure_device.patch @@ -0,0 +1,90 @@ +From fbf41928622ee12b23e2247b35ad99809a176a1c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 18:52:32 +0100 +Subject: PCI: Initialize RCB from pci_configure_device() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: HÃ¥kon Bugge + +[ Upstream commit 1a6845aaa6de81f95959b380b45de8f10d6a8502 ] + +Commit e42010d8207f ("PCI: Set Read Completion Boundary to 128 iff Root +Port supports it (_HPX)") worked around a bogus _HPX type 2 record, which +caused program_hpx_type2() to set the RCB in an endpoint even though the +Root Port did not have the RCB bit set. + +e42010d8207f fixed that by setting the RCB in the endpoint only when it was +set in the Root Port. + +In retrospect, program_hpx_type2() is intended for AER-related settings, +and the RCB should be configured elsewhere so it doesn't depend on the +presence or contents of an _HPX record. + +Explicitly program the RCB from pci_configure_device() so it matches the +Root Port's RCB. The Root Port may not be visible to virtualized guests; +in that case, leave RCB alone. + +Fixes: e42010d8207f ("PCI: Set Read Completion Boundary to 128 iff Root Port supports it (_HPX)") +Signed-off-by: HÃ¥kon Bugge +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260129175237.727059-2-haakon.bugge@oracle.com +Signed-off-by: Sasha Levin +--- + drivers/pci/probe.c | 32 ++++++++++++++++++++++++++++++++ + 1 file changed, 32 insertions(+) + +diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c +index 86665658d7047..c791bca2891f6 100644 +--- a/drivers/pci/probe.c ++++ b/drivers/pci/probe.c +@@ -2411,6 +2411,37 @@ static void pci_configure_serr(struct pci_dev *dev) + } + } + ++static void pci_configure_rcb(struct pci_dev *dev) ++{ ++ struct pci_dev *rp; ++ u16 rp_lnkctl; ++ ++ /* ++ * Per PCIe r7.0, sec 7.5.3.7, RCB is only meaningful in Root Ports ++ * (where it is read-only), Endpoints, and Bridges. It may only be ++ * set for Endpoints and Bridges if it is set in the Root Port. For ++ * Endpoints, it is 'RsvdP' for Virtual Functions. ++ */ ++ if (!pci_is_pcie(dev) || ++ pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT || ++ pci_pcie_type(dev) == PCI_EXP_TYPE_UPSTREAM || ++ pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM || ++ pci_pcie_type(dev) == PCI_EXP_TYPE_RC_EC || ++ dev->is_virtfn) ++ return; ++ ++ /* Root Port often not visible to virtualized guests */ ++ rp = pcie_find_root_port(dev); ++ if (!rp) ++ return; ++ ++ pcie_capability_read_word(rp, PCI_EXP_LNKCTL, &rp_lnkctl); ++ pcie_capability_clear_and_set_word(dev, PCI_EXP_LNKCTL, ++ PCI_EXP_LNKCTL_RCB, ++ (rp_lnkctl & PCI_EXP_LNKCTL_RCB) ? ++ PCI_EXP_LNKCTL_RCB : 0); ++} ++ + static void pci_configure_device(struct pci_dev *dev) + { + pci_configure_mps(dev); +@@ -2420,6 +2451,7 @@ static void pci_configure_device(struct pci_dev *dev) + pci_configure_aspm_l1ss(dev); + pci_configure_eetlp_prefix(dev); + pci_configure_serr(dev); ++ pci_configure_rcb(dev); + + pci_acpi_program_hp_params(dev); + } +-- +2.51.0 + diff --git a/queue-6.19/pci-mark-3ware-9650sa-root-port-extended-tags-as-bro.patch b/queue-6.19/pci-mark-3ware-9650sa-root-port-extended-tags-as-bro.patch new file mode 100644 index 0000000000..85dc42c302 --- /dev/null +++ b/queue-6.19/pci-mark-3ware-9650sa-root-port-extended-tags-as-bro.patch @@ -0,0 +1,56 @@ +From eb319c77b988ad84db3a05375ce63e1edbf8cb0d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 15:31:10 +0100 +Subject: PCI: Mark 3ware-9650SA Root Port Extended Tags as broken +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jörg Wedekind + +[ Upstream commit 959ac08a2c2811305be8c2779779e8b0932e5a99 ] + +Per PCIe r7.0, sec 2.2.6.2.1 and 7.5.3.4, a Requester may not use 8-bit Tags +unless its Extended Tag Field Enable is set, but all Receivers/Completers +must handle 8-bit Tags correctly regardless of their Extended Tag Field +Enable. + +Some devices do not handle 8-bit Tags as Completers, so add a quirk for +them. If we find such a device, we disable Extended Tags for the entire +hierarchy to make peer-to-peer DMA possible. + +The 3ware 9650SA seems to have issues with handling 8-bit tags. Mark it as +broken. + +This fixes PCI Parity Errors like : + + 3w-9xxx: scsi0: ERROR: (0x06:0x000C): PCI Parity Error: clearing. + 3w-9xxx: scsi0: ERROR: (0x06:0x000D): PCI Abort: clearing. + 3w-9xxx: scsi0: ERROR: (0x06:0x000E): Controller Queue Error: clearing. + 3w-9xxx: scsi0: ERROR: (0x06:0x0010): Microcontroller Error: clearing. + +Fixes: 60db3a4d8cc9 ("PCI: Enable PCIe Extended Tags if supported") +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=202425 +Signed-off-by: Jörg Wedekind +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260119143114.21948-1-joerg@wedekind.de +Signed-off-by: Sasha Levin +--- + drivers/pci/quirks.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index 280cd50d693bd..211b7f72d103e 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -5581,6 +5581,7 @@ static void quirk_no_ext_tags(struct pci_dev *pdev) + pci_walk_bus(bridge->bus, pci_configure_extended_tags, NULL); + } + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_3WARE, 0x1004, quirk_no_ext_tags); ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_3WARE, 0x1005, quirk_no_ext_tags); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0132, quirk_no_ext_tags); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0140, quirk_no_ext_tags); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0141, quirk_no_ext_tags); +-- +2.51.0 + diff --git a/queue-6.19/pci-mediatek-fix-irq-domain-leak-when-msi-allocation.patch b/queue-6.19/pci-mediatek-fix-irq-domain-leak-when-msi-allocation.patch new file mode 100644 index 0000000000..f23926f3c9 --- /dev/null +++ b/queue-6.19/pci-mediatek-fix-irq-domain-leak-when-msi-allocation.patch @@ -0,0 +1,45 @@ +From c7299e422cbac2fafd4fbd6be84cb86e24dbadd8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 19 Nov 2025 10:33:08 +0800 +Subject: PCI: mediatek: Fix IRQ domain leak when MSI allocation fails + +From: Haotian Zhang + +[ Upstream commit 7f0cdcddf8bef1c8c18f9be6708073fd3790a20f ] + +In mtk_pcie_init_irq_domain(), if mtk_pcie_allocate_msi_domains() +fails after port->irq_domain has been successfully created via +irq_domain_create_linear(), the function returns directly without +cleaning up the allocated IRQ domain, resulting in a resource leak. + +Add irq_domain_remove() call in the error path to properly release the +INTx IRQ domain before returning the error. + +Fixes: 43e6409db64d ("PCI: mediatek: Add MSI support for MT2712 and MT7622") +Signed-off-by: Haotian Zhang +Signed-off-by: Manivannan Sadhasivam +Link: https://patch.msgid.link/20251119023308.476-1-vulab@iscas.ac.cn +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/pcie-mediatek.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c +index 4b78b6528f9fd..5defa5cc4c2bd 100644 +--- a/drivers/pci/controller/pcie-mediatek.c ++++ b/drivers/pci/controller/pcie-mediatek.c +@@ -585,8 +585,10 @@ static int mtk_pcie_init_irq_domain(struct mtk_pcie_port *port, + + if (IS_ENABLED(CONFIG_PCI_MSI)) { + ret = mtk_pcie_allocate_msi_domains(port); +- if (ret) ++ if (ret) { ++ irq_domain_remove(port->irq_domain); + return ret; ++ } + } + + return 0; +-- +2.51.0 + diff --git a/queue-6.19/pci-p2pdma-fix-p2pmem_alloc_mmap-warning-condition.patch b/queue-6.19/pci-p2pdma-fix-p2pmem_alloc_mmap-warning-condition.patch new file mode 100644 index 0000000000..f4c0481c8d --- /dev/null +++ b/queue-6.19/pci-p2pdma-fix-p2pmem_alloc_mmap-warning-condition.patch @@ -0,0 +1,52 @@ +From ed9b4dd9b81ab8876b18204a1649121a2b7a4f51 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 12:04:35 +0800 +Subject: PCI/P2PDMA: Fix p2pmem_alloc_mmap() warning condition + +From: Hou Tao + +[ Upstream commit cb500023a75246f60b79af9f7321d6e75330c5b5 ] + +Commit b7e282378773 has already changed the initial page refcount of +p2pdma page from one to zero, however, in p2pmem_alloc_mmap() it uses +"VM_WARN_ON_ONCE_PAGE(!page_ref_count(page))" to assert the initial page +refcount should not be zero and the following will be reported when +CONFIG_DEBUG_VM is enabled: + + page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x380400000 + flags: 0x20000000002000(reserved|node=0|zone=4) + raw: 0020000000002000 ff1100015e3ab440 0000000000000000 0000000000000000 + raw: 0000000000000000 0000000000000000 00000000ffffffff 0000000000000000 + page dumped because: VM_WARN_ON_ONCE_PAGE(!page_ref_count(page)) + ------------[ cut here ]------------ + WARNING: CPU: 5 PID: 449 at drivers/pci/p2pdma.c:240 p2pmem_alloc_mmap+0x83a/0xa60 + +Fix by using "page_ref_count(page)" as the assertion condition. + +Fixes: b7e282378773 ("mm/mm_init: move p2pdma page refcount initialisation to p2pdma") +Signed-off-by: Hou Tao +Signed-off-by: Bjorn Helgaas +Reviewed-by: Logan Gunthorpe +Reviewed-by: Alistair Popple +Link: https://patch.msgid.link/20251220040446.274991-3-houtao@huaweicloud.com +Signed-off-by: Sasha Levin +--- + drivers/pci/p2pdma.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c +index 218c1f5252b66..dd64ec830fdd4 100644 +--- a/drivers/pci/p2pdma.c ++++ b/drivers/pci/p2pdma.c +@@ -147,7 +147,7 @@ static int p2pmem_alloc_mmap(struct file *filp, struct kobject *kobj, + * we have just allocated the page no one else should be + * using it. + */ +- VM_WARN_ON_ONCE_PAGE(!page_ref_count(page), page); ++ VM_WARN_ON_ONCE_PAGE(page_ref_count(page), page); + set_page_count(page, 1); + ret = vm_insert_page(vma, vaddr, page); + if (ret) { +-- +2.51.0 + diff --git a/queue-6.19/pci-p2pdma-release-per-cpu-pgmap-ref-when-vm_insert_.patch b/queue-6.19/pci-p2pdma-release-per-cpu-pgmap-ref-when-vm_insert_.patch new file mode 100644 index 0000000000..828a76e8f6 --- /dev/null +++ b/queue-6.19/pci-p2pdma-release-per-cpu-pgmap-ref-when-vm_insert_.patch @@ -0,0 +1,42 @@ +From ec01550542b437dd47cf51c03c119df269dc4708 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 12:04:34 +0800 +Subject: PCI/P2PDMA: Release per-CPU pgmap ref when vm_insert_page() fails + +From: Hou Tao + +[ Upstream commit 6220694c52a5a04102b48109e4f24e958b559bd3 ] + +When vm_insert_page() fails in p2pmem_alloc_mmap(), p2pmem_alloc_mmap() +doesn't invoke percpu_ref_put() to free the per-CPU ref of pgmap acquired +after gen_pool_alloc_owner(), and memunmap_pages() will hang forever when +trying to remove the PCI device. + +Fix it by adding the missed percpu_ref_put(). + +Fixes: 7e9c7ef83d78 ("PCI/P2PDMA: Allow userspace VMA allocations through sysfs") +Signed-off-by: Hou Tao +Signed-off-by: Bjorn Helgaas +Reviewed-by: Logan Gunthorpe +Reviewed-by: Alistair Popple +Link: https://patch.msgid.link/20251220040446.274991-2-houtao@huaweicloud.com +Signed-off-by: Sasha Levin +--- + drivers/pci/p2pdma.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c +index 4a2fc7ab42c34..218c1f5252b66 100644 +--- a/drivers/pci/p2pdma.c ++++ b/drivers/pci/p2pdma.c +@@ -152,6 +152,7 @@ static int p2pmem_alloc_mmap(struct file *filp, struct kobject *kobj, + ret = vm_insert_page(vma, vaddr, page); + if (ret) { + gen_pool_free(p2pdma->pool, (uintptr_t)kaddr, len); ++ percpu_ref_put(ref); + return ret; + } + percpu_ref_get(ref); +-- +2.51.0 + diff --git a/queue-6.19/pci-p2pdma-reset-page-reference-count-when-page-mapp.patch b/queue-6.19/pci-p2pdma-reset-page-reference-count-when-page-mapp.patch new file mode 100644 index 0000000000..1549b51121 --- /dev/null +++ b/queue-6.19/pci-p2pdma-reset-page-reference-count-when-page-mapp.patch @@ -0,0 +1,57 @@ +From f20ccdba09e0fac426e91f6cdaa10fa62a9c0431 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 11:54:40 +1100 +Subject: PCI/P2PDMA: Reset page reference count when page mapping fails + +From: Alistair Popple + +[ Upstream commit 83014d82a1100abc89f7712ad67c3e5accaddc43 ] + +When mapping a p2pdma page the page reference count is initialised to 1 +prior to calling vm_insert_page(). This is to avoid vm_insert_page() +warning if the page refcount is zero. Prior to setting the page count there +is a check to ensure the page is currently free (ie. has a zero reference +count). + +However vm_insert_page() can fail. In this case the pages are freed back to +the genalloc pool, but that does not reset the page refcount. So a future +allocation of the same page will see the elevated page refcount from the +previous set_page_count() call triggering the VM_WARN_ON_ONCE_PAGE checking +that the page is free. + +Fix this by resetting the page refcount to zero using set_page_count(). +Note that put_page() is not used because that would result in freeing the +page twice due to implicitly calling p2pdma_folio_free(). + +Fixes: b7e282378773 ("mm/mm_init: move p2pdma page refcount initialisation to p2pdma") +Signed-off-by: Alistair Popple +Signed-off-by: Bjorn Helgaas +Reviewed-by: Logan Gunthorpe +Acked-by: Balbir Singh +Link: https://patch.msgid.link/20260112005440.998543-1-apopple@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/p2pdma.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c +index dd64ec830fdd4..79a414fd6623b 100644 +--- a/drivers/pci/p2pdma.c ++++ b/drivers/pci/p2pdma.c +@@ -152,6 +152,13 @@ static int p2pmem_alloc_mmap(struct file *filp, struct kobject *kobj, + ret = vm_insert_page(vma, vaddr, page); + if (ret) { + gen_pool_free(p2pdma->pool, (uintptr_t)kaddr, len); ++ ++ /* ++ * Reset the page count. We don't use put_page() ++ * because we don't want to trigger the ++ * p2pdma_folio_free() path. ++ */ ++ set_page_count(page, 0); + percpu_ref_put(ref); + return ret; + } +-- +2.51.0 + diff --git a/queue-6.19/pci-pm-avoid-redundant-delays-on-d3hot-d3cold.patch b/queue-6.19/pci-pm-avoid-redundant-delays-on-d3hot-d3cold.patch new file mode 100644 index 0000000000..2d9fd8310e --- /dev/null +++ b/queue-6.19/pci-pm-avoid-redundant-delays-on-d3hot-d3cold.patch @@ -0,0 +1,56 @@ +From fac835b44f62eb338465abc77cb06504e92c1e51 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Oct 2025 15:40:09 -0700 +Subject: PCI/PM: Avoid redundant delays on D3hot->D3cold + +From: Brian Norris + +[ Upstream commit 4d982084507d663df160546c4c48066a8887ed89 ] + +When transitioning to D3cold, __pci_set_power_state() first transitions to +D3hot. If the device was already in D3hot, this adds excess work: + + (a) read/modify/write PMCSR; and + (b) excess delay (pci_dev_d3_sleep()). + +For (b), we already performed the necessary delay on the previous D3hot +entry; this was extra noticeable when evaluating runtime PM transition +latency. + +Check whether we're already in the target state before continuing. + +Note that __pci_set_power_state() already does this same check for other +state transitions, but D3cold is special because __pci_set_power_state() +converts it to D3hot for the purposes of PMCSR. + +This seems to be an oversight in commit 0aacdc957401 ("PCI/PM: Clean up +pci_set_low_power_state()"). + +Fixes: 0aacdc957401 ("PCI/PM: Clean up pci_set_low_power_state()") +Signed-off-by: Brian Norris +Signed-off-by: Brian Norris +[bhelgaas: reverse test to match other "dev->current_state == state" cases] +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20251003154008.1.I7a21c240b30062c66471329567a96dceb6274358@changeid +Signed-off-by: Sasha Levin +--- + drivers/pci/pci.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c +index 13dbb405dc31f..86ccbd0efb495 100644 +--- a/drivers/pci/pci.c ++++ b/drivers/pci/pci.c +@@ -1488,6 +1488,9 @@ static int pci_set_low_power_state(struct pci_dev *dev, pci_power_t state, bool + || (state == PCI_D2 && !dev->d2_support)) + return -EIO; + ++ if (dev->current_state == state) ++ return 0; ++ + pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr); + if (PCI_POSSIBLE_ERROR(pmcsr)) { + pci_err(dev, "Unable to change power state from %s to %s, device inaccessible\n", +-- +2.51.0 + diff --git a/queue-6.19/pci-portdrv-fix-potential-resource-leak.patch b/queue-6.19/pci-portdrv-fix-potential-resource-leak.patch new file mode 100644 index 0000000000..5a88c0b9b2 --- /dev/null +++ b/queue-6.19/pci-portdrv-fix-potential-resource-leak.patch @@ -0,0 +1,48 @@ +From a22f69d4bd1f31068322a468460d25838cd6791d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Dec 2025 16:13:49 +0100 +Subject: PCI/portdrv: Fix potential resource leak +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Uwe Kleine-König + +[ Upstream commit 01464a3fdf91c041a381d93a1b6fefbdb819a46f ] + +pcie_port_probe_service() unconditionally calls get_device() (unless it +fails). So drop that reference also unconditionally as it's fine for a +PCIe driver to not have a remove callback. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Uwe Kleine-König +Signed-off-by: Bjorn Helgaas +Reviewed-by: Ilpo Järvinen +Reviewed-by: Jonathan Cameron +Link: https://patch.msgid.link/e1c68c3b3f1af8427e98ca5e2c79f8bf0ebe2ce4.1764688034.git.u.kleine-koenig@baylibre.com +Signed-off-by: Sasha Levin +--- + drivers/pci/pcie/portdrv.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/pci/pcie/portdrv.c b/drivers/pci/pcie/portdrv.c +index 38a41ccf79b9a..a0991da482136 100644 +--- a/drivers/pci/pcie/portdrv.c ++++ b/drivers/pci/pcie/portdrv.c +@@ -557,10 +557,10 @@ static int pcie_port_remove_service(struct device *dev) + + pciedev = to_pcie_device(dev); + driver = to_service_driver(dev->driver); +- if (driver && driver->remove) { ++ if (driver && driver->remove) + driver->remove(pciedev); +- put_device(dev); +- } ++ ++ put_device(dev); + return 0; + } + +-- +2.51.0 + diff --git a/queue-6.19/pci-ptm-fix-pcie_ptm_create_debugfs-memory-leak.patch b/queue-6.19/pci-ptm-fix-pcie_ptm_create_debugfs-memory-leak.patch new file mode 100644 index 0000000000..9cf7d4b614 --- /dev/null +++ b/queue-6.19/pci-ptm-fix-pcie_ptm_create_debugfs-memory-leak.patch @@ -0,0 +1,55 @@ +From 3aeb930e59ea3d7553e0285812a626749a9c62f3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 11 Jan 2026 22:06:50 +0530 +Subject: PCI/PTM: Fix pcie_ptm_create_debugfs() memory leak + +From: Aadityarangan Shridhar Iyengar + +[ Upstream commit 62171369cf17794ddd88f602c2c84d008ecafcff ] + +In pcie_ptm_create_debugfs(), if devm_kasprintf() fails after successfully +allocating ptm_debugfs with kzalloc(), the function returns without freeing +the allocated memory, resulting in a memory leak. + +Free ptm_debugfs before returning in the devm_kasprintf() error path and in +pcie_ptm_destroy_debugfs(). + +Fixes: 132833405e61 ("PCI: Add debugfs support for exposing PTM context") +Signed-off-by: Aadityarangan Shridhar Iyengar +[bhelgaas: squash additional fix from Mani: +https://lore.kernel.org/r/pdp4xc4d5ee3e547mmdro5riui3mclduqdl7j6iclfbozo2a4c@7m3qdm6yrhuv] +Signed-off-by: Bjorn Helgaas +Reviewed-by: Manivannan Sadhasivam +Link: https://patch.msgid.link/20260111163650.33168-1-adiyenga@cisco.com +Signed-off-by: Sasha Levin +--- + drivers/pci/pcie/ptm.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/pci/pcie/ptm.c b/drivers/pci/pcie/ptm.c +index ed0f9691e7d16..c7c61869bc9cf 100644 +--- a/drivers/pci/pcie/ptm.c ++++ b/drivers/pci/pcie/ptm.c +@@ -542,8 +542,10 @@ struct pci_ptm_debugfs *pcie_ptm_create_debugfs(struct device *dev, void *pdata, + return NULL; + + dirname = devm_kasprintf(dev, GFP_KERNEL, "pcie_ptm_%s", dev_name(dev)); +- if (!dirname) ++ if (!dirname) { ++ kfree(ptm_debugfs); + return NULL; ++ } + + ptm_debugfs->debugfs = debugfs_create_dir(dirname, NULL); + ptm_debugfs->pdata = pdata; +@@ -574,6 +576,7 @@ void pcie_ptm_destroy_debugfs(struct pci_ptm_debugfs *ptm_debugfs) + + mutex_destroy(&ptm_debugfs->lock); + debugfs_remove_recursive(ptm_debugfs->debugfs); ++ kfree(ptm_debugfs); + } + EXPORT_SYMBOL_GPL(pcie_ptm_destroy_debugfs); + #endif +-- +2.51.0 + diff --git a/queue-6.19/pci-pwrctrl-tc9563-use-put_device-instead-of-i2c_put.patch b/queue-6.19/pci-pwrctrl-tc9563-use-put_device-instead-of-i2c_put.patch new file mode 100644 index 0000000000..88909c2021 --- /dev/null +++ b/queue-6.19/pci-pwrctrl-tc9563-use-put_device-instead-of-i2c_put.patch @@ -0,0 +1,57 @@ +From 72a81e7aba5912272ecb0073985a26d4277d9edf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 12:58:55 +0530 +Subject: PCI/pwrctrl: tc9563: Use put_device() instead of i2c_put_adapter() + +From: Manivannan Sadhasivam + +[ Upstream commit 99ee5837c63d1000f9ce7508591486a7bd8bdedb ] + +The API comment for of_find_i2c_adapter_by_node() recommends using +put_device() to drop the reference count of I2C adapter instead of using +i2c_put_adapter(). So replace i2c_put_adapter() with put_device(). + +Fixes: 4c9c7be47310 ("PCI: pwrctrl: Add power control driver for TC9563") +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Reviewed-by: Bartosz Golaszewski +Link: https://patch.msgid.link/20260115-pci-pwrctrl-rework-v5-3-9d26da3ce903@oss.qualcomm.com +Signed-off-by: Sasha Levin +--- + drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c b/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c +index ec423432ac655..0a63add84d095 100644 +--- a/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c ++++ b/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c +@@ -533,7 +533,7 @@ static int tc9563_pwrctrl_probe(struct platform_device *pdev) + ctx->client = i2c_new_dummy_device(ctx->adapter, addr); + if (IS_ERR(ctx->client)) { + dev_err(dev, "Failed to create I2C client\n"); +- i2c_put_adapter(ctx->adapter); ++ put_device(&ctx->adapter->dev); + return PTR_ERR(ctx->client); + } + +@@ -613,7 +613,7 @@ static int tc9563_pwrctrl_probe(struct platform_device *pdev) + tc9563_pwrctrl_power_off(ctx); + remove_i2c: + i2c_unregister_device(ctx->client); +- i2c_put_adapter(ctx->adapter); ++ put_device(&ctx->adapter->dev); + return ret; + } + +@@ -623,7 +623,7 @@ static void tc9563_pwrctrl_remove(struct platform_device *pdev) + + tc9563_pwrctrl_power_off(ctx); + i2c_unregister_device(ctx->client); +- i2c_put_adapter(ctx->adapter); ++ put_device(&ctx->adapter->dev); + } + + static const struct of_device_id tc9563_pwrctrl_of_match[] = { +-- +2.51.0 + diff --git a/queue-6.19/pci-remove-old_size-limit-from-bridge-window-sizing.patch b/queue-6.19/pci-remove-old_size-limit-from-bridge-window-sizing.patch new file mode 100644 index 0000000000..925752648c --- /dev/null +++ b/queue-6.19/pci-remove-old_size-limit-from-bridge-window-sizing.patch @@ -0,0 +1,117 @@ +From 62cd1f200777edcb6ca2861ac4ccd749dc481415 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 19 Dec 2025 19:40:18 +0200 +Subject: PCI: Remove old_size limit from bridge window sizing +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ilpo Järvinen + +[ Upstream commit f909e3ee3ed1a44202f09ac7e637a0f9ec372225 ] + +calculate_memsize() applies lower bound to the resource size before +aligning the resource size making it impossible to shrink bridge window +resources. I've not found any justification for this lower bound and +nothing indicated it was to work around some HW issue. + +Prior to the commit 3baeae36039a ("PCI: Use pci_release_resource() instead +of release_resource()"), releasing a bridge window during BAR resize +resulted in clearing start and end address of the resource. Clearing +addresses destroys the resource size as a side-effect, therefore nullifying +the effect of the old size lower bound. + +After the commit 3baeae36039a ("PCI: Use pci_release_resource() instead of +release_resource()"), BAR resize uses the aligned old size, which results +in exceeding what fits into the parent window in some cases: + + xe 0030:03:00.0: [drm] Attempting to resize bar from 256MiB -> 16384MiB + xe 0030:03:00.0: BAR 0 [mem 0x620c000000000-0x620c000ffffff 64bit]: releasing + xe 0030:03:00.0: BAR 2 [mem 0x6200000000000-0x620000fffffff 64bit pref]: releasing + pci 0030:02:01.0: bridge window [mem 0x6200000000000-0x620001fffffff 64bit pref]: releasing + pci 0030:01:00.0: bridge window [mem 0x6200000000000-0x6203fbff0ffff 64bit pref]: releasing + pci 0030:00:00.0: bridge window [mem 0x6200000000000-0x6203fbff0ffff 64bit pref]: was not released (still contains assigned resources) + pci 0030:00:00.0: Assigned bridge window [mem 0x6200000000000-0x6203fbff0ffff 64bit pref] to [bus 01-04] free space at [mem 0x6200400000000-0x62007ffffffff 64bit pref] + pci 0030:00:00.0: Assigned bridge window [mem 0x6200000000000-0x6203fbff0ffff 64bit pref] to [bus 01-04] cannot fit 0x4000000000 required for 0030:01:00.0 bridging to [bus 02-04] + +The old size of 0x6200000000000-0x6203fbff0ffff resource was used as the +lower bound which results in 0x4000000000 size request due to alignment. +That exceeds what can fit into the parent window. + +Since the lower bound never even was enforced fully because the resource +addresses were cleared when the bridge window is released, remove the +old_size lower bound entirely and trust the calculated bridge window size +is enough. + +This same problem may occur on io window side but seems less likely to +cause issues due to general difference in alignment. Removing the lower +bound may have other unforeseen consequences in case of io window so it's +better to leave it as -next material if no problem is reported related to +io window sizing (BAR resize shouldn't touch io windows anyway). + +Fixes: 3baeae36039a ("PCI: Use pci_release_resource() instead of release_resource()") +Reported-by: Simon Richter +Link: https://lore.kernel.org/r/f9a8c975-f5d3-4dd2-988e-4371a1433a60@hogyros.de/ +Signed-off-by: Ilpo Järvinen +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20251219174036.16738-6-ilpo.jarvinen@linux.intel.com +Signed-off-by: Sasha Levin +--- + drivers/pci/setup-bus.c | 11 +++-------- + 1 file changed, 3 insertions(+), 8 deletions(-) + +diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c +index ed23778659114..902fdae73c232 100644 +--- a/drivers/pci/setup-bus.c ++++ b/drivers/pci/setup-bus.c +@@ -1070,16 +1070,13 @@ static resource_size_t calculate_memsize(resource_size_t size, + resource_size_t min_size, + resource_size_t add_size, + resource_size_t children_add_size, +- resource_size_t old_size, + resource_size_t align) + { + if (size < min_size) + size = min_size; +- if (old_size == 1) +- old_size = 0; + + size = max(size, add_size) + children_add_size; +- return ALIGN(max(size, old_size), align); ++ return ALIGN(size, align); + } + + resource_size_t __weak pcibios_window_alignment(struct pci_bus *bus, +@@ -1297,7 +1294,6 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type, + resource_size_t children_add_size = 0; + resource_size_t children_add_align = 0; + resource_size_t add_align = 0; +- resource_size_t old_size; + + if (!b_res) + return; +@@ -1363,11 +1359,10 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type, + } + } + +- old_size = resource_size(b_res); + win_align = window_alignment(bus, b_res->flags); + min_align = calculate_head_align(aligns, max_order); + min_align = max(min_align, win_align); +- size0 = calculate_memsize(size, min_size, 0, 0, old_size, win_align); ++ size0 = calculate_memsize(size, min_size, 0, 0, win_align); + + if (size0) { + resource_set_range(b_res, min_align, size0); +@@ -1377,7 +1372,7 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type, + if (realloc_head && (add_size > 0 || children_add_size > 0)) { + add_align = max(min_align, add_align); + size1 = calculate_memsize(size, min_size, add_size, children_add_size, +- old_size, win_align); ++ win_align); + } + + if (!size0 && !size1) { +-- +2.51.0 + diff --git a/queue-6.19/pci-rewrite-bridge-window-head-alignment-function.patch b/queue-6.19/pci-rewrite-bridge-window-head-alignment-function.patch new file mode 100644 index 0000000000..32db5e66c5 --- /dev/null +++ b/queue-6.19/pci-rewrite-bridge-window-head-alignment-function.patch @@ -0,0 +1,174 @@ +From 6e1c4837991c20963896b79de459aeb0da2e3726 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 19 Dec 2025 19:40:15 +0200 +Subject: PCI: Rewrite bridge window head alignment function +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ilpo Järvinen + +[ Upstream commit bc75c8e5071120e919beb39e69f0979cccfdf219 ] + +The calculation of bridge window head alignment is done by +calculate_mem_align() [*]. With the default bridge window alignment, it +is used for both head and tail alignment. + +The selected head alignment does not always result in tight-fitting +resources (gap at d4f00000-d4ffffff): + + d4800000-dbffffff : PCI Bus 0000:06 + d4800000-d48fffff : PCI Bus 0000:07 + d4800000-d4803fff : 0000:07:00.0 + d4800000-d4803fff : nvme + d4900000-d49fffff : PCI Bus 0000:0a + d4900000-d490ffff : 0000:0a:00.0 + d4900000-d490ffff : r8169 + d4910000-d4913fff : 0000:0a:00.0 + d4a00000-d4cfffff : PCI Bus 0000:0b + d4a00000-d4bfffff : 0000:0b:00.0 + d4a00000-d4bfffff : 0000:0b:00.0 + d4c00000-d4c07fff : 0000:0b:00.0 + d4d00000-d4dfffff : PCI Bus 0000:15 + d4d00000-d4d07fff : 0000:15:00.0 + d4d00000-d4d07fff : xhci-hcd + d4e00000-d4efffff : PCI Bus 0000:16 + d4e00000-d4e7ffff : 0000:16:00.0 + d4e80000-d4e803ff : 0000:16:00.0 + d4e80000-d4e803ff : ahci + d5000000-dbffffff : PCI Bus 0000:0c + +This has not caused problems (for years) with the default bridge window +tail alignment that grossly over-estimates the required tail alignment +leaving more tail room than necessary. With the introduction of relaxed +tail alignment that leaves no extra tail room whatsoever, any gaps will +immediately turn into assignment failures. + +Introduce head alignment calculation that ensures no gaps are left and +apply the new approach when using relaxed alignment. We may want to +consider using it for the normal alignment eventually, but as the first +step, solve only the problem with the relaxed tail alignment. + +([*] I don't understand the algorithm in calculate_mem_align().) + +Link: https://git.kernel.org/history/history/c/5d0a8965aea9 ("[PATCH] 2.5.14: New PCI allocation code (alpha, arm, parisc) [2/2]") +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220775 +Reported-by: Malte Schröder +Signed-off-by: Ilpo Järvinen +Signed-off-by: Bjorn Helgaas +Tested-by: Malte Schröder +Cc: stable@vger.kernel.org +Link: https://patch.msgid.link/20251219174036.16738-3-ilpo.jarvinen@linux.intel.com +Stable-dep-of: f909e3ee3ed1 ("PCI: Remove old_size limit from bridge window sizing") +Signed-off-by: Sasha Levin +--- + drivers/pci/setup-bus.c | 53 ++++++++++++++++++++++++++++++++++------- + 1 file changed, 44 insertions(+), 9 deletions(-) + +diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c +index a61d38777cdc4..99086980e102e 100644 +--- a/drivers/pci/setup-bus.c ++++ b/drivers/pci/setup-bus.c +@@ -1227,6 +1227,45 @@ static inline resource_size_t calculate_mem_align(resource_size_t *aligns, + return min_align; + } + ++/* ++ * Calculate bridge window head alignment that leaves no gaps in between ++ * resources. ++ */ ++static resource_size_t calculate_head_align(resource_size_t *aligns, ++ int max_order) ++{ ++ resource_size_t head_align = 1; ++ resource_size_t remainder = 0; ++ int order; ++ ++ /* Take the largest alignment as the starting point. */ ++ head_align <<= max_order + __ffs(SZ_1M); ++ ++ for (order = max_order - 1; order >= 0; order--) { ++ resource_size_t align1 = 1; ++ ++ align1 <<= order + __ffs(SZ_1M); ++ ++ /* ++ * Account smaller resources with alignment < max_order that ++ * could be used to fill head room if alignment less than ++ * max_order is used. ++ */ ++ remainder += aligns[order]; ++ ++ /* ++ * Test if head fill is enough to satisfy the alignment of ++ * the larger resources after reducing the alignment. ++ */ ++ while ((head_align > align1) && (remainder >= head_align / 2)) { ++ head_align /= 2; ++ remainder -= head_align; ++ } ++ } ++ ++ return head_align; ++} ++ + /** + * pbus_upstream_space_available - Check no upstream resource limits allocation + * @bus: The bus +@@ -1314,13 +1353,13 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type, + { + struct pci_dev *dev; + resource_size_t min_align, win_align, align, size, size0, size1 = 0; +- resource_size_t aligns[28]; /* Alignments from 1MB to 128TB */ ++ resource_size_t aligns[28] = {}; /* Alignments from 1MB to 128TB */ ++ resource_size_t aligns2[28] = {};/* Alignments from 1MB to 128TB */ + int order, max_order; + struct resource *b_res = pbus_select_window_for_type(bus, type); + resource_size_t children_add_size = 0; + resource_size_t children_add_align = 0; + resource_size_t add_align = 0; +- resource_size_t relaxed_align; + resource_size_t old_size; + + if (!b_res) +@@ -1330,7 +1369,6 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type, + if (b_res->parent) + return; + +- memset(aligns, 0, sizeof(aligns)); + max_order = 0; + size = 0; + +@@ -1381,6 +1419,7 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type, + */ + if (r_size <= align) + aligns[order] += align; ++ aligns2[order] += align; + if (order > max_order) + max_order = order; + +@@ -1405,9 +1444,7 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type, + + if (bus->self && size0 && + !pbus_upstream_space_available(bus, b_res, size0, min_align)) { +- relaxed_align = 1ULL << (max_order + __ffs(SZ_1M)); +- relaxed_align = max(relaxed_align, win_align); +- min_align = min(min_align, relaxed_align); ++ min_align = calculate_head_align(aligns2, max_order); + size0 = calculate_memsize(size, min_size, 0, 0, old_size, win_align); + resource_set_range(b_res, min_align, size0); + pci_info(bus->self, "bridge window %pR to %pR requires relaxed alignment rules\n", +@@ -1421,9 +1458,7 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type, + + if (bus->self && size1 && + !pbus_upstream_space_available(bus, b_res, size1, add_align)) { +- relaxed_align = 1ULL << (max_order + __ffs(SZ_1M)); +- relaxed_align = max(relaxed_align, win_align); +- min_align = min(min_align, relaxed_align); ++ min_align = calculate_head_align(aligns2, max_order); + size1 = calculate_memsize(size, min_size, add_size, children_add_size, + old_size, win_align); + pci_info(bus->self, +-- +2.51.0 + diff --git a/queue-6.19/pci-rzg3s-host-fix-device-node-reference-leak-in-rzg.patch b/queue-6.19/pci-rzg3s-host-fix-device-node-reference-leak-in-rzg.patch new file mode 100644 index 0000000000..a6969166bc --- /dev/null +++ b/queue-6.19/pci-rzg3s-host-fix-device-node-reference-leak-in-rzg.patch @@ -0,0 +1,47 @@ +From ea10f9866b78d9ab13bf710f3c11e85ff87d629e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 00:46:24 +0800 +Subject: PCI: rzg3s-host: Fix device node reference leak in + rzg3s_pcie_host_parse_port() + +From: Felix Gu + +[ Upstream commit e43e2aa557040bbcc5de0eaa1c59ee3ae9e31793 ] + +In rzg3s_pcie_host_parse_port(), of_get_next_child() returns a device node +with an incremented reference count that must be released with +of_node_put(). The current code fails to call of_node_put() which causes a +reference leak. + +Use the __free(device_node) attribute to ensure automatic cleanup when the +variable goes out of scope. + +Fixes: 7ef502fb35b2 ("PCI: Add Renesas RZ/G3S host controller driver") +Signed-off-by: Felix Gu +Signed-off-by: Bjorn Helgaas +Tested-by: Claudiu Beznea +Reviewed-by: Claudiu Beznea +Acked-by: Manivannan Sadhasivam +Link: https://patch.msgid.link/20260204-rzg3s-v1-1-142bc81c3312@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/pcie-rzg3s-host.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/pci/controller/pcie-rzg3s-host.c b/drivers/pci/controller/pcie-rzg3s-host.c +index ae6d9c7dc2c12..1bea8360f8944 100644 +--- a/drivers/pci/controller/pcie-rzg3s-host.c ++++ b/drivers/pci/controller/pcie-rzg3s-host.c +@@ -1143,7 +1143,8 @@ static int rzg3s_pcie_resets_prepare_and_get(struct rzg3s_pcie_host *host) + + static int rzg3s_pcie_host_parse_port(struct rzg3s_pcie_host *host) + { +- struct device_node *of_port = of_get_next_child(host->dev->of_node, NULL); ++ struct device_node *of_port __free(device_node) = ++ of_get_next_child(host->dev->of_node, NULL); + struct rzg3s_pcie_port *port = &host->port; + int ret; + +-- +2.51.0 + diff --git a/queue-6.19/pci-rzg3s-host-use-pci_generic_config_write-for-the-.patch b/queue-6.19/pci-rzg3s-host-use-pci_generic_config_write-for-the-.patch new file mode 100644 index 0000000000..620145a8dd --- /dev/null +++ b/queue-6.19/pci-rzg3s-host-use-pci_generic_config_write-for-the-.patch @@ -0,0 +1,92 @@ +From 12f1771f354eb013df66a304ddc76d089540e51b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 17 Dec 2025 13:15:09 +0200 +Subject: PCI: rzg3s-host: Use pci_generic_config_write() for the root bus + +From: Claudiu Beznea + +[ Upstream commit 4b86eff47e205819eb862097493ec20e25ac8f56 ] + +The Renesas RZ/G3S host controller allows writing to read-only PCIe +configuration registers when the RZG3S_PCI_PERM_CFG_HWINIT_EN bit is set in +the RZG3S_PCI_PERM register. However, callers of struct pci_ops::write +expect the semantics defined by the PCIe specification, meaning that writes +to read-only registers must not be allowed. + +The previous custom struct pci_ops::write implementation for the root bus +temporarily enabled write access before calling pci_generic_config_write(). +This breaks the expected semantics. + +Remove the custom implementation and simply use pci_generic_config_write(). + +Along with this change, the updates of the PCI_PRIMARY_BUS, +PCI_SECONDARY_BUS, and PCI_SUBORDINATE_BUS registers were moved so that +they no longer depends on the RZG3S_PCI_PERM_CFG_HWINIT_EN bit in the +RZG3S_PCI_PERM_CFG register, since these registers are R/W. + +Fixes: 7ef502fb35b2 ("PCI: Add Renesas RZ/G3S host controller driver") +Suggested-by: Bjorn Helgaas +Signed-off-by: Claudiu Beznea +Signed-off-by: Manivannan Sadhasivam +Tested-by: Wolfram Sang +Link: https://patch.msgid.link/20251217111510.138848-2-claudiu.beznea.uj@bp.renesas.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/pcie-rzg3s-host.c | 27 ++++-------------------- + 1 file changed, 4 insertions(+), 23 deletions(-) + +diff --git a/drivers/pci/controller/pcie-rzg3s-host.c b/drivers/pci/controller/pcie-rzg3s-host.c +index 83ec66a708236..ae6d9c7dc2c12 100644 +--- a/drivers/pci/controller/pcie-rzg3s-host.c ++++ b/drivers/pci/controller/pcie-rzg3s-host.c +@@ -439,28 +439,9 @@ static void __iomem *rzg3s_pcie_root_map_bus(struct pci_bus *bus, + return host->pcie + where; + } + +-/* Serialized by 'pci_lock' */ +-static int rzg3s_pcie_root_write(struct pci_bus *bus, unsigned int devfn, +- int where, int size, u32 val) +-{ +- struct rzg3s_pcie_host *host = bus->sysdata; +- int ret; +- +- /* Enable access control to the CFGU */ +- writel_relaxed(RZG3S_PCI_PERM_CFG_HWINIT_EN, +- host->axi + RZG3S_PCI_PERM); +- +- ret = pci_generic_config_write(bus, devfn, where, size, val); +- +- /* Disable access control to the CFGU */ +- writel_relaxed(0, host->axi + RZG3S_PCI_PERM); +- +- return ret; +-} +- + static struct pci_ops rzg3s_pcie_root_ops = { + .read = pci_generic_config_read, +- .write = rzg3s_pcie_root_write, ++ .write = pci_generic_config_write, + .map_bus = rzg3s_pcie_root_map_bus, + }; + +@@ -1065,14 +1046,14 @@ static int rzg3s_pcie_config_init(struct rzg3s_pcie_host *host) + writel_relaxed(0xffffffff, host->pcie + RZG3S_PCI_CFG_BARMSK00L); + writel_relaxed(0xffffffff, host->pcie + RZG3S_PCI_CFG_BARMSK00U); + ++ /* Disable access control to the CFGU */ ++ writel_relaxed(0, host->axi + RZG3S_PCI_PERM); ++ + /* Update bus info */ + writeb_relaxed(primary_bus, host->pcie + PCI_PRIMARY_BUS); + writeb_relaxed(secondary_bus, host->pcie + PCI_SECONDARY_BUS); + writeb_relaxed(subordinate_bus, host->pcie + PCI_SUBORDINATE_BUS); + +- /* Disable access control to the CFGU */ +- writel_relaxed(0, host->axi + RZG3S_PCI_PERM); +- + return 0; + } + +-- +2.51.0 + diff --git a/queue-6.19/pci-s32g-skip-root-port-removal-during-success.patch b/queue-6.19/pci-s32g-skip-root-port-removal-during-success.patch new file mode 100644 index 0000000000..7aa2cafec0 --- /dev/null +++ b/queue-6.19/pci-s32g-skip-root-port-removal-during-success.patch @@ -0,0 +1,49 @@ +From ebe03482c40bb995d0ff68a57e20fd6e612cc466 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 16:10:50 +0100 +Subject: PCI: s32g: Skip Root Port removal during success + +From: Vincent Guittot + +[ Upstream commit b79e0875fe8144fcb09e4fc1cf386cb3b2262480 ] + +Currently, s32g_pcie_parse_ports() exercises the 'err_port' path even +during the success case. This results in ports getting deleted after +successful parsing of Root Ports. + +Hence, skip the removal of Root Ports during success. + +Fixes: 5cbc7d3e316e ("PCI: s32g: Add NXP S32G PCIe controller driver (RC)") +Signed-off-by: Vincent Guittot +[mani: reworded subject and description] +Signed-off-by: Manivannan Sadhasivam +Link: https://patch.msgid.link/20260202151050.1446165-1-vincent.guittot@linaro.org +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-nxp-s32g.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-nxp-s32g.c b/drivers/pci/controller/dwc/pcie-nxp-s32g.c +index 47745749f75c3..b3ec38099fa38 100644 +--- a/drivers/pci/controller/dwc/pcie-nxp-s32g.c ++++ b/drivers/pci/controller/dwc/pcie-nxp-s32g.c +@@ -282,12 +282,12 @@ static int s32g_pcie_parse_ports(struct device *dev, struct s32g_pcie *s32g_pp) + + ret = s32g_pcie_parse_port(s32g_pp, of_port); + if (ret) +- goto err_port; ++ break; + } + +-err_port: +- list_for_each_entry_safe(port, tmp, &s32g_pp->ports, list) +- list_del(&port->list); ++ if (ret) ++ list_for_each_entry_safe(port, tmp, &s32g_pp->ports, list) ++ list_del(&port->list); + + return ret; + } +-- +2.51.0 + diff --git a/queue-6.19/pci-sophgo-disable-l0s-and-l1-on-sophgo-2044-pcie-ro.patch b/queue-6.19/pci-sophgo-disable-l0s-and-l1-on-sophgo-2044-pcie-ro.patch new file mode 100644 index 0000000000..0cc5bed29f --- /dev/null +++ b/queue-6.19/pci-sophgo-disable-l0s-and-l1-on-sophgo-2044-pcie-ro.patch @@ -0,0 +1,68 @@ +From 7c5822e6ea70dad05952a59cfb1e52e7e08f358f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 12:07:53 +0800 +Subject: PCI: sophgo: Disable L0s and L1 on Sophgo 2044 PCIe Root Ports + +From: Inochi Amaoto + +[ Upstream commit 613f3255a35a95f52575dd8c60b7ac9d711639ce ] + +Sophgo 2044 Root Ports advertise L0 and L1 capabilities without supporting +them. Since commit f3ac2ff14834 ("PCI/ASPM: Enable all ClockPM and ASPM +states for devicetree platforms") force enabled ASPM on all device tree +platforms, the issue became evident and the SG2044 Root Port started +breaking. + +Hence, disable the L0s and L1 capabilities in the LINKCAP register for the +SG2044 Root Ports, so that these states won't get enabled. + +Fixes: 467d9c0348d6 ("PCI: dwc: Add Sophgo SG2044 PCIe controller driver in Root Complex mode") +Signed-off-by: Inochi Amaoto +[mani: reworded description and corrected fixes tag] +Signed-off-by: Manivannan Sadhasivam +Tested-by: Han Gao +Link: https://patch.msgid.link/20260109040756.731169-1-inochiama@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-sophgo.c | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/drivers/pci/controller/dwc/pcie-sophgo.c b/drivers/pci/controller/dwc/pcie-sophgo.c +index ad4baaa34ffa1..044088898819e 100644 +--- a/drivers/pci/controller/dwc/pcie-sophgo.c ++++ b/drivers/pci/controller/dwc/pcie-sophgo.c +@@ -161,6 +161,22 @@ static void sophgo_pcie_msi_enable(struct dw_pcie_rp *pp) + raw_spin_unlock_irqrestore(&pp->lock, flags); + } + ++static void sophgo_pcie_disable_l0s_l1(struct dw_pcie_rp *pp) ++{ ++ struct dw_pcie *pci = to_dw_pcie_from_pp(pp); ++ u32 offset, val; ++ ++ offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); ++ ++ dw_pcie_dbi_ro_wr_en(pci); ++ ++ val = dw_pcie_readl_dbi(pci, PCI_EXP_LNKCAP + offset); ++ val &= ~(PCI_EXP_LNKCAP_ASPM_L0S | PCI_EXP_LNKCAP_ASPM_L1); ++ dw_pcie_writel_dbi(pci, PCI_EXP_LNKCAP + offset, val); ++ ++ dw_pcie_dbi_ro_wr_dis(pci); ++} ++ + static int sophgo_pcie_host_init(struct dw_pcie_rp *pp) + { + int irq; +@@ -171,6 +187,8 @@ static int sophgo_pcie_host_init(struct dw_pcie_rp *pp) + + irq_set_chained_handler_and_data(irq, sophgo_pcie_intx_handler, pp); + ++ sophgo_pcie_disable_l0s_l1(pp); ++ + sophgo_pcie_msi_enable(pp); + + return 0; +-- +2.51.0 + diff --git a/queue-6.19/pci-stop-over-estimating-bridge-window-size.patch b/queue-6.19/pci-stop-over-estimating-bridge-window-size.patch new file mode 100644 index 0000000000..03d7ccf296 --- /dev/null +++ b/queue-6.19/pci-stop-over-estimating-bridge-window-size.patch @@ -0,0 +1,173 @@ +From 351bf52d2a7b4a7d41af3aa902b5d459f87ba29c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 19 Dec 2025 19:40:16 +0200 +Subject: PCI: Stop over-estimating bridge window size +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ilpo Järvinen + +[ Upstream commit 3958bf16e2fe1b1c95467e58694102122c951a31 ] + +New way to calculate the bridge window head alignment produces tight-fit, +that is, it does not leave any gaps between the resources. Similarly, +relaxed tail alignment does not leave extra tail room. + +Start to use bridge window calculation that does not over-estimate the size +of the required window. + +pbus_upstream_space_available() can be removed. + +Signed-off-by: Ilpo Järvinen +Signed-off-by: Bjorn Helgaas +Tested-by: Malte Schröder +Link: https://patch.msgid.link/20251219174036.16738-4-ilpo.jarvinen@linux.intel.com +Stable-dep-of: f909e3ee3ed1 ("PCI: Remove old_size limit from bridge window sizing") +Signed-off-by: Sasha Levin +--- + drivers/pci/setup-bus.c | 97 +++-------------------------------------- + 1 file changed, 5 insertions(+), 92 deletions(-) + +diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c +index 99086980e102e..ed23778659114 100644 +--- a/drivers/pci/setup-bus.c ++++ b/drivers/pci/setup-bus.c +@@ -1266,68 +1266,6 @@ static resource_size_t calculate_head_align(resource_size_t *aligns, + return head_align; + } + +-/** +- * pbus_upstream_space_available - Check no upstream resource limits allocation +- * @bus: The bus +- * @res: The resource to help select the correct bridge window +- * @size: The size required from the bridge window +- * @align: Required alignment for the resource +- * +- * Check that @size can fit inside the upstream bridge resources that are +- * already assigned. Select the upstream bridge window based on the type of +- * @res. +- * +- * Return: %true if enough space is available on all assigned upstream +- * resources. +- */ +-static bool pbus_upstream_space_available(struct pci_bus *bus, +- struct resource *res, +- resource_size_t size, +- resource_size_t align) +-{ +- struct resource_constraint constraint = { +- .max = RESOURCE_SIZE_MAX, +- .align = align, +- }; +- struct pci_bus *downstream = bus; +- +- while ((bus = bus->parent)) { +- if (pci_is_root_bus(bus)) +- break; +- +- res = pbus_select_window(bus, res); +- if (!res) +- return false; +- if (!res->parent) +- continue; +- +- if (resource_size(res) >= size) { +- struct resource gap = {}; +- +- if (find_resource_space(res, &gap, size, &constraint) == 0) { +- gap.flags = res->flags; +- pci_dbg(bus->self, +- "Assigned bridge window %pR to %pR free space at %pR\n", +- res, &bus->busn_res, &gap); +- return true; +- } +- } +- +- if (bus->self) { +- pci_info(bus->self, +- "Assigned bridge window %pR to %pR cannot fit 0x%llx required for %s bridging to %pR\n", +- res, &bus->busn_res, +- (unsigned long long)size, +- pci_name(downstream->self), +- &downstream->busn_res); +- } +- +- return false; +- } +- +- return true; +-} +- + /** + * pbus_size_mem() - Size the memory window of a given bus + * +@@ -1354,7 +1292,6 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type, + struct pci_dev *dev; + resource_size_t min_align, win_align, align, size, size0, size1 = 0; + resource_size_t aligns[28] = {}; /* Alignments from 1MB to 128TB */ +- resource_size_t aligns2[28] = {};/* Alignments from 1MB to 128TB */ + int order, max_order; + struct resource *b_res = pbus_select_window_for_type(bus, type); + resource_size_t children_add_size = 0; +@@ -1413,13 +1350,8 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type, + continue; + } + size += max(r_size, align); +- /* +- * Exclude ranges with size > align from calculation of +- * the alignment. +- */ +- if (r_size <= align) +- aligns[order] += align; +- aligns2[order] += align; ++ ++ aligns[order] += align; + if (order > max_order) + max_order = order; + +@@ -1433,38 +1365,19 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type, + + old_size = resource_size(b_res); + win_align = window_alignment(bus, b_res->flags); +- min_align = calculate_mem_align(aligns, max_order); ++ min_align = calculate_head_align(aligns, max_order); + min_align = max(min_align, win_align); +- size0 = calculate_memsize(size, min_size, 0, 0, old_size, min_align); ++ size0 = calculate_memsize(size, min_size, 0, 0, old_size, win_align); + + if (size0) { + resource_set_range(b_res, min_align, size0); + b_res->flags &= ~IORESOURCE_DISABLED; + } + +- if (bus->self && size0 && +- !pbus_upstream_space_available(bus, b_res, size0, min_align)) { +- min_align = calculate_head_align(aligns2, max_order); +- size0 = calculate_memsize(size, min_size, 0, 0, old_size, win_align); +- resource_set_range(b_res, min_align, size0); +- pci_info(bus->self, "bridge window %pR to %pR requires relaxed alignment rules\n", +- b_res, &bus->busn_res); +- } +- + if (realloc_head && (add_size > 0 || children_add_size > 0)) { + add_align = max(min_align, add_align); + size1 = calculate_memsize(size, min_size, add_size, children_add_size, +- old_size, add_align); +- +- if (bus->self && size1 && +- !pbus_upstream_space_available(bus, b_res, size1, add_align)) { +- min_align = calculate_head_align(aligns2, max_order); +- size1 = calculate_memsize(size, min_size, add_size, children_add_size, +- old_size, win_align); +- pci_info(bus->self, +- "bridge window %pR to %pR requires relaxed alignment rules\n", +- b_res, &bus->busn_res); +- } ++ old_size, win_align); + } + + if (!size0 && !size1) { +-- +2.51.0 + diff --git a/queue-6.19/pci-xilinx-fix-intx-irq-domain-leak-in-error-paths.patch b/queue-6.19/pci-xilinx-fix-intx-irq-domain-leak-in-error-paths.patch new file mode 100644 index 0000000000..fa64387787 --- /dev/null +++ b/queue-6.19/pci-xilinx-fix-intx-irq-domain-leak-in-error-paths.patch @@ -0,0 +1,70 @@ +From 7c90ff737c2300715f3dffe638a4a029f6fab35b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 19 Dec 2025 10:16:15 +0800 +Subject: PCI: xilinx: Fix INTx IRQ domain leak in error paths + +From: Haotian Zhang + +[ Upstream commit f42b3c053b1554d66af6fe45bb1ef357464c0456 ] + +In xilinx_pcie_init_irq_domain(), if xilinx_allocate_msi_domains() fails +after pcie->leg_domain has been successfully created via +irq_domain_create_linear(), the function returns directly without cleaning +up the allocated IRQ domain, resulting in a resource leak. In +xilinx_free_msi_domains(), pcie->leg_domain is also neglected. + +Add irq_domain_remove() call in the error path to properly release the +IRQ domain before returning the error. Also rename +xilinx_free_msi_domains() to xilinx_free_irq_domains() and add the release +of pcie->leg_domain to it. + +Fixes: 313b64c3ae52 ("PCI: xilinx: Convert to MSI domains") +Suggested-by: Manivannan Sadhasivam +Signed-off-by: Haotian Zhang +Signed-off-by: Manivannan Sadhasivam +Link: https://patch.msgid.link/20251219021615.965-1-vulab@iscas.ac.cn +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/pcie-xilinx.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/drivers/pci/controller/pcie-xilinx.c b/drivers/pci/controller/pcie-xilinx.c +index 937ea6ae1ac48..4aa139abac16e 100644 +--- a/drivers/pci/controller/pcie-xilinx.c ++++ b/drivers/pci/controller/pcie-xilinx.c +@@ -302,9 +302,10 @@ static int xilinx_allocate_msi_domains(struct xilinx_pcie *pcie) + return 0; + } + +-static void xilinx_free_msi_domains(struct xilinx_pcie *pcie) ++static void xilinx_free_irq_domains(struct xilinx_pcie *pcie) + { + irq_domain_remove(pcie->msi_domain); ++ irq_domain_remove(pcie->leg_domain); + } + + /* INTx Functions */ +@@ -480,8 +481,10 @@ static int xilinx_pcie_init_irq_domain(struct xilinx_pcie *pcie) + phys_addr_t pa = ALIGN_DOWN(virt_to_phys(pcie), SZ_4K); + + ret = xilinx_allocate_msi_domains(pcie); +- if (ret) ++ if (ret) { ++ irq_domain_remove(pcie->leg_domain); + return ret; ++ } + + pcie_write(pcie, upper_32_bits(pa), XILINX_PCIE_REG_MSIBASE1); + pcie_write(pcie, lower_32_bits(pa), XILINX_PCIE_REG_MSIBASE2); +@@ -600,7 +603,7 @@ static int xilinx_pcie_probe(struct platform_device *pdev) + + err = pci_host_probe(bridge); + if (err) +- xilinx_free_msi_domains(pcie); ++ xilinx_free_irq_domains(pcie); + + return err; + } +-- +2.51.0 + diff --git a/queue-6.19/perf-arm_spe-properly-set-hw.state-on-failures.patch b/queue-6.19/perf-arm_spe-properly-set-hw.state-on-failures.patch new file mode 100644 index 0000000000..b3ffdaa3f6 --- /dev/null +++ b/queue-6.19/perf-arm_spe-properly-set-hw.state-on-failures.patch @@ -0,0 +1,108 @@ +From 8023fa3e2bc1967b0bb222cfc6056fd36d3fb490 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 14:40:43 +0000 +Subject: perf: arm_spe: Properly set hw.state on failures + +From: Leo Yan + +[ Upstream commit 283182c1c239f6873d1a50e9e710c1a699f2256b ] + +When arm_spe_pmu_next_off() fails to calculate a valid limit, it returns +zero to indicate that tracing should not start. However, the caller +arm_spe_perf_aux_output_begin() does not propagate this failure by +updating hwc->state, cause the error to be silently ignored by upper +layers. + +Because hwc->state remains zero after a failure, arm_spe_pmu_start() +continues to programs filter registers unnecessarily. The driver +still reports success to the perf core, so the core assumes the SPE +event was enabled and proceeds to enable other events. This breaks +event group semantics: SPE is already stopped while other events in the +same group are enabled. + +Fix this by updating arm_spe_perf_aux_output_begin() to return a status +code indicating success (0) or failure (-EIO). Both the interrupt +handler and arm_spe_pmu_start() check the return value and call +arm_spe_pmu_stop() to set PERF_HES_STOPPED in hwc->state. + +In the interrupt handler, the period (e.g., period_left) needs to be +updated, so PERF_EF_UPDATE is passed to arm_spe_pmu_stop(). When the +error occurs during event start, the trace unit is not yet enabled, so +a flag '0' is used to drain buffer and update state only. + +Fixes: d5d9696b0380 ("drivers/perf: Add support for ARMv8.2 Statistical Profiling Extension") +Signed-off-by: Leo Yan +Signed-off-by: Will Deacon +Signed-off-by: Sasha Levin +--- + drivers/perf/arm_spe_pmu.c | 18 ++++++++++++------ + 1 file changed, 12 insertions(+), 6 deletions(-) + +diff --git a/drivers/perf/arm_spe_pmu.c b/drivers/perf/arm_spe_pmu.c +index 4801115f2b540..5410fb7428d0e 100644 +--- a/drivers/perf/arm_spe_pmu.c ++++ b/drivers/perf/arm_spe_pmu.c +@@ -106,6 +106,8 @@ struct arm_spe_pmu { + /* Keep track of our dynamic hotplug state */ + static enum cpuhp_state arm_spe_pmu_online; + ++static void arm_spe_pmu_stop(struct perf_event *event, int flags); ++ + enum arm_spe_pmu_buf_fault_action { + SPE_PMU_BUF_FAULT_ACT_SPURIOUS, + SPE_PMU_BUF_FAULT_ACT_FATAL, +@@ -607,8 +609,8 @@ static u64 arm_spe_pmu_next_off(struct perf_output_handle *handle) + return limit; + } + +-static void arm_spe_perf_aux_output_begin(struct perf_output_handle *handle, +- struct perf_event *event) ++static int arm_spe_perf_aux_output_begin(struct perf_output_handle *handle, ++ struct perf_event *event) + { + u64 base, limit; + struct arm_spe_pmu_buf *buf; +@@ -622,7 +624,6 @@ static void arm_spe_perf_aux_output_begin(struct perf_output_handle *handle, + /* Start a new aux session */ + buf = perf_aux_output_begin(handle, event); + if (!buf) { +- event->hw.state |= PERF_HES_STOPPED; + /* + * We still need to clear the limit pointer, since the + * profiler might only be disabled by virtue of a fault. +@@ -642,6 +643,7 @@ static void arm_spe_perf_aux_output_begin(struct perf_output_handle *handle, + + out_write_limit: + write_sysreg_s(limit, SYS_PMBLIMITR_EL1); ++ return (limit & PMBLIMITR_EL1_E) ? 0 : -EIO; + } + + static void arm_spe_perf_aux_output_end(struct perf_output_handle *handle) +@@ -781,7 +783,10 @@ static irqreturn_t arm_spe_pmu_irq_handler(int irq, void *dev) + * when we get to it. + */ + if (!(handle->aux_flags & PERF_AUX_FLAG_TRUNCATED)) { +- arm_spe_perf_aux_output_begin(handle, event); ++ if (arm_spe_perf_aux_output_begin(handle, event)) { ++ arm_spe_pmu_stop(event, PERF_EF_UPDATE); ++ break; ++ } + isb(); + } + break; +@@ -880,9 +885,10 @@ static void arm_spe_pmu_start(struct perf_event *event, int flags) + struct perf_output_handle *handle = this_cpu_ptr(spe_pmu->handle); + + hwc->state = 0; +- arm_spe_perf_aux_output_begin(handle, event); +- if (hwc->state) ++ if (arm_spe_perf_aux_output_begin(handle, event)) { ++ arm_spe_pmu_stop(event, 0); + return; ++ } + + reg = arm_spe_event_to_pmsfcr(event); + write_sysreg_s(reg, SYS_PMSFCR_EL1); +-- +2.51.0 + diff --git a/queue-6.19/perf-x86-core-do-not-set-bit-width-for-unavailable-c.patch b/queue-6.19/perf-x86-core-do-not-set-bit-width-for-unavailable-c.patch new file mode 100644 index 0000000000..d4fbe89ba8 --- /dev/null +++ b/queue-6.19/perf-x86-core-do-not-set-bit-width-for-unavailable-c.patch @@ -0,0 +1,46 @@ +From 77bd7749e7c9afd8c091dbb4a9ad31f7fd1cc04f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Dec 2025 16:16:46 -0800 +Subject: perf/x86/core: Do not set bit width for unavailable counters + +From: Sandipan Das + +[ Upstream commit b456a6ba5756b6fb7e651775343e713bd08418e7 ] + +Not all x86 processors have fixed counters. It may also be the case that +a processor has only fixed counters and no general-purpose counters. Set +the bit widths corresponding to each counter type only if such counters +are available. + +Fixes: b3d9468a8bd2 ("perf, x86: Expose perf capability to other modules") +Signed-off-by: Sandipan Das +Co-developed-by: Dapeng Mi +Signed-off-by: Dapeng Mi +Signed-off-by: Mingwei Zhang +Signed-off-by: Sean Christopherson +Signed-off-by: Peter Zijlstra (Intel) +Tested-by: Xudong Hao +Link: https://patch.msgid.link/20251206001720.468579-11-seanjc@google.com +Signed-off-by: Sasha Levin +--- + arch/x86/events/core.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c +index 576baa9a52c5b..af1329ae9f82a 100644 +--- a/arch/x86/events/core.c ++++ b/arch/x86/events/core.c +@@ -3073,8 +3073,8 @@ void perf_get_x86_pmu_capability(struct x86_pmu_capability *cap) + cap->version = x86_pmu.version; + cap->num_counters_gp = x86_pmu_num_counters(NULL); + cap->num_counters_fixed = x86_pmu_num_counters_fixed(NULL); +- cap->bit_width_gp = x86_pmu.cntval_bits; +- cap->bit_width_fixed = x86_pmu.cntval_bits; ++ cap->bit_width_gp = cap->num_counters_gp ? x86_pmu.cntval_bits : 0; ++ cap->bit_width_fixed = cap->num_counters_fixed ? x86_pmu.cntval_bits : 0; + cap->events_mask = (unsigned int)x86_pmu.events_maskl; + cap->events_mask_len = x86_pmu.events_mask_len; + cap->pebs_ept = x86_pmu.pebs_ept; +-- +2.51.0 + diff --git a/queue-6.19/phy-freescale-imx8qm-hsio-fix-null-pointer-dereferen.patch b/queue-6.19/phy-freescale-imx8qm-hsio-fix-null-pointer-dereferen.patch new file mode 100644 index 0000000000..8f7230b5ed --- /dev/null +++ b/queue-6.19/phy-freescale-imx8qm-hsio-fix-null-pointer-dereferen.patch @@ -0,0 +1,41 @@ +From 3bc8c904a7b1b63945c95bbf6e8bc1a83d5958b0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 17:50:23 +0100 +Subject: phy: freescale: imx8qm-hsio: fix NULL pointer dereference + +From: Thomas Richard + +[ Upstream commit 4dd5d4c0361af0a3fd24f45c815996abf4429770 ] + +During the probe the refclk_pad pointer is set to NULL if the +'fsl,refclk-pad-mode' property is not defined in the devicetree node. But +in imx_hsio_configure_clk_pad() this pointer is unconditionally used which +could result in a NULL pointer dereference. So check the pointer before to +use it. + +Fixes: 82c56b6dd24f ("phy: freescale: imx8qm-hsio: Add i.MX8QM HSIO PHY driver support") +Signed-off-by: Thomas Richard +Reviewed-by: Richard Zhu +Link: https://patch.msgid.link/20260114-phy-fsl-imx8qm-hsio-fix-null-pointer-dereference-v1-1-730e941be464@bootlin.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/phy/freescale/phy-fsl-imx8qm-hsio.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/phy/freescale/phy-fsl-imx8qm-hsio.c b/drivers/phy/freescale/phy-fsl-imx8qm-hsio.c +index 977d21d753a59..279b8ac7822df 100644 +--- a/drivers/phy/freescale/phy-fsl-imx8qm-hsio.c ++++ b/drivers/phy/freescale/phy-fsl-imx8qm-hsio.c +@@ -251,7 +251,7 @@ static void imx_hsio_configure_clk_pad(struct phy *phy) + struct imx_hsio_lane *lane = phy_get_drvdata(phy); + struct imx_hsio_priv *priv = lane->priv; + +- if (strncmp(priv->refclk_pad, "output", 6) == 0) { ++ if (priv->refclk_pad && strncmp(priv->refclk_pad, "output", 6) == 0) { + pll = true; + regmap_update_bits(priv->misc, HSIO_CTRL0, + HSIO_IOB_A_0_TXOE | HSIO_IOB_A_0_M1M0_MASK, +-- +2.51.0 + diff --git a/queue-6.19/phy-rockchip-samsung-hdptx-pre-compute-hdmi-pll-conf.patch b/queue-6.19/phy-rockchip-samsung-hdptx-pre-compute-hdmi-pll-conf.patch new file mode 100644 index 0000000000..d094c47021 --- /dev/null +++ b/queue-6.19/phy-rockchip-samsung-hdptx-pre-compute-hdmi-pll-conf.patch @@ -0,0 +1,62 @@ +From 63e8fc99642bdd8f7bea55524f96c975aaeaca1e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 21 Dec 2025 12:36:23 +0200 +Subject: phy: rockchip: samsung-hdptx: Pre-compute HDMI PLL config for + 461.10125 MHz output + +From: Cristian Ciocaltea + +[ Upstream commit f2daf0c67a1767ff6536aa3e96599afb42ca42e7 ] + +Attempting to make use of a 1080p@120Hz display mode with 10 bpc RGB on +my Acer XV275K P3 monitor results in a blank image. A similar behavior +has been reported on Philips 279M1RV. + +The faulty modeline is created by drm_gtf_mode_complex() based on the +following EDID entry from the Standard Timings block: + + GTF: 1920x1080 119.999987 Hz 16:9 138.840 kHz 368.759000 MHz + +It's worth noting the computed pixel clock ends up being slightly higher +at 368.881000 MHz. Nevertheless, this seems to work consistently fine +with 8 bpc RGB. + +After switching to 10 bpc, the TMDS character rate expected for the mode +increases to 461.101250 MHz, as per drm_hdmi_compute_mode_clock(). + +Since there is no entry for this rate in the ropll_tmds_cfg table, the +necessary HDMI PLL configuration parameters are calculated dynamically +by rk_hdptx_phy_clk_pll_calc(). However, the resulting output rate is +not quite a perfect match, i.e. 461.100000 MHz. That proved to be the +actual root cause of the problem. + +Add a new entry to the TMDS configuration table and provide the +necessary frequency division coefficients for the PHY PLL to generate +the expected 461.101250 MHz output. + +Fixes: 9d0ec51d7c22 ("phy: rockchip: samsung-hdptx: Add high color depth management") +Tested-by: Derek Foreman +Signed-off-by: Cristian Ciocaltea +Link: https://patch.msgid.link/20251221-phy-hdptx-pll-fix-v2-1-ae4abf7f75a1@collabora.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c +index 29de2f7bdae8a..cafa618d70fdc 100644 +--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c ++++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c +@@ -414,6 +414,8 @@ struct rk_hdptx_phy { + static const struct ropll_config ropll_tmds_cfg[] = { + { 594000000ULL, 124, 124, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, ++ { 461101250ULL, 97, 97, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 71, 1, 53, 2, 6, ++ 35, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 371250000ULL, 155, 155, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 297000000ULL, 124, 124, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, +-- +2.51.0 + diff --git a/queue-6.19/pidfs-return-eremote-when-pidfd_get_info-is-called-o.patch b/queue-6.19/pidfs-return-eremote-when-pidfd_get_info-is-called-o.patch new file mode 100644 index 0000000000..e5fe1effe3 --- /dev/null +++ b/queue-6.19/pidfs-return-eremote-when-pidfd_get_info-is-called-o.patch @@ -0,0 +1,47 @@ +From 55f539e07bdf79762022ee5ac79dd9f33c43bf10 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 22:51:37 +0000 +Subject: pidfs: return -EREMOTE when PIDFD_GET_INFO is called on another ns + +From: Luca Boccassi + +[ Upstream commit ab89060fbc92edd6e852bf0f533f29140afabe0e ] + +Currently it is not possible to distinguish between the case where a +process has already exited and the case where a process is in a +different namespace, as both return -ESRCH. +glibc's pidfd_getpid() procfs-based implementation returns -EREMOTE +in the latter, so that distinguishing the two is possible, as the +fdinfo in procfs will list '0' as the PID in that case: + +https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/pidfd_getpid.c;h=860829cf07da2267484299ccb02861822c0d07b4;hb=HEAD#l121 + +Change the error code so that the kernel also returns -EREMOTE in +that case. + +Fixes: 7477d7dce48a ("pidfs: allow to retrieve exit information") + +Signed-off-by: Luca Boccassi +Link: https://patch.msgid.link/20260127225209.2293342-1-luca.boccassi@gmail.com +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/pidfs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/pidfs.c b/fs/pidfs.c +index 1e20e36e0ed55..d18c51513f6c5 100644 +--- a/fs/pidfs.c ++++ b/fs/pidfs.c +@@ -329,7 +329,7 @@ static long pidfd_info(struct file *file, unsigned int cmd, unsigned long arg) + * namespace hierarchy. + */ + if (!pid_in_current_pidns(pid)) +- return -ESRCH; ++ return -EREMOTE; + + attr = READ_ONCE(pid->attr); + if (mask & PIDFD_INFO_EXIT) { +-- +2.51.0 + diff --git a/queue-6.19/pinctrl-canaan-k230-fix-null-pointer-dereference-whe.patch b/queue-6.19/pinctrl-canaan-k230-fix-null-pointer-dereference-whe.patch new file mode 100644 index 0000000000..ffdcca32d6 --- /dev/null +++ b/queue-6.19/pinctrl-canaan-k230-fix-null-pointer-dereference-whe.patch @@ -0,0 +1,76 @@ +From 4fde5294db1315c93ca81c76d7b86f7ac2fd6eb0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 28 Dec 2025 23:49:47 +0800 +Subject: pinctrl: canaan: k230: Fix NULL pointer dereference when parsing + devicetree + +From: Jiayu Du + +[ Upstream commit d8c128fb6c2277d95f3f6a4ce28b82c8370031f6 ] + +When probing the k230 pinctrl driver, the kernel triggers a NULL pointer +dereference. The crash trace showed: +[ 0.732084] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000068 +[ 0.740737] ... +[ 0.776296] epc : k230_pinctrl_probe+0x1be/0x4fc + +In k230_pinctrl_parse_functions(), we attempt to retrieve the device +pointer via info->pctl_dev->dev, but info->pctl_dev is only initialized +after k230_pinctrl_parse_dt() completes. + +At the time of DT parsing, info->pctl_dev is still NULL, leading to +the invalid dereference of info->pctl_dev->dev. + +Use the already available device pointer from platform_device +instead of accessing through uninitialized pctl_dev. + +Fixes: d94a32ac688f ("pinctrl: canaan: k230: Fix order of DT parse and pinctrl register") +Signed-off-by: Jiayu Du +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-k230.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/pinctrl/pinctrl-k230.c b/drivers/pinctrl/pinctrl-k230.c +index d716f23d837f7..20f7c0f70eb77 100644 +--- a/drivers/pinctrl/pinctrl-k230.c ++++ b/drivers/pinctrl/pinctrl-k230.c +@@ -65,6 +65,7 @@ struct k230_pmx_func { + }; + + struct k230_pinctrl { ++ struct device *dev; + struct pinctrl_desc pctl; + struct pinctrl_dev *pctl_dev; + struct regmap *regmap_base; +@@ -470,7 +471,7 @@ static int k230_pinctrl_parse_groups(struct device_node *np, + struct k230_pinctrl *info, + unsigned int index) + { +- struct device *dev = info->pctl_dev->dev; ++ struct device *dev = info->dev; + const __be32 *list; + int size, i, ret; + +@@ -511,7 +512,7 @@ static int k230_pinctrl_parse_functions(struct device_node *np, + struct k230_pinctrl *info, + unsigned int index) + { +- struct device *dev = info->pctl_dev->dev; ++ struct device *dev = info->dev; + struct k230_pmx_func *func; + struct k230_pin_group *grp; + static unsigned int idx, i; +@@ -596,6 +597,8 @@ static int k230_pinctrl_probe(struct platform_device *pdev) + if (!info) + return -ENOMEM; + ++ info->dev = dev; ++ + pctl = &info->pctl; + + pctl->name = "k230-pinctrl"; +-- +2.51.0 + diff --git a/queue-6.19/pinctrl-equilibrium-fix-device-node-reference-leak-i.patch b/queue-6.19/pinctrl-equilibrium-fix-device-node-reference-leak-i.patch new file mode 100644 index 0000000000..7ea750ddb3 --- /dev/null +++ b/queue-6.19/pinctrl-equilibrium-fix-device-node-reference-leak-i.patch @@ -0,0 +1,44 @@ +From 6b6f5b78e042f4680816f20f38e145f42be56925 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 01:30:07 +0800 +Subject: pinctrl: equilibrium: Fix device node reference leak in + pinbank_init() + +From: Felix Gu + +[ Upstream commit c0b4a4feeb43305a754893d8d9c6b2b5a52d45ac ] + +When calling of_parse_phandle_with_fixed_args(), the caller is +responsible to call of_node_put() to release the reference of device +node. + +In pinbank_init(), the reference of the node obtained from the +"gpio-ranges" property is never released, resulting in a reference +count leak. + +Add the missing of_node_put() call to fix the leak. + +Fixes: 1948d5c51dba ("pinctrl: Add pinmux & GPIO controller driver for a new SoC") +Signed-off-by: Felix Gu +Acked-by: Andy Shevchenko +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-equilibrium.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/pinctrl/pinctrl-equilibrium.c b/drivers/pinctrl/pinctrl-equilibrium.c +index 2d04829b29c99..48b55c5bf8d4f 100644 +--- a/drivers/pinctrl/pinctrl-equilibrium.c ++++ b/drivers/pinctrl/pinctrl-equilibrium.c +@@ -846,6 +846,7 @@ static int pinbank_init(struct device_node *np, + + bank->pin_base = spec.args[1]; + bank->nr_pins = spec.args[2]; ++ of_node_put(spec.np); + + bank->aval_pinmap = readl(bank->membase + REG_AVAIL); + bank->id = id; +-- +2.51.0 + diff --git a/queue-6.19/pinctrl-meson-amlogic-a4-fix-device-node-reference-l.patch b/queue-6.19/pinctrl-meson-amlogic-a4-fix-device-node-reference-l.patch new file mode 100644 index 0000000000..a5be15175c --- /dev/null +++ b/queue-6.19/pinctrl-meson-amlogic-a4-fix-device-node-reference-l.patch @@ -0,0 +1,57 @@ +From cd808a196f004bb6dd6422cc894ad577483dd826 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 02:23:12 +0800 +Subject: pinctrl: meson: amlogic-a4: Fix device node reference leak in bank + helpers + +From: Felix Gu + +[ Upstream commit e56aa18eba32fb68ac5e19e44670010095bb189c ] + +of_parse_phandle_with_fixed_args() increments the reference count of the +returned device node, so it must be explicitly released using +of_node_put() after use. + +Fix the reference leak in aml_bank_pins() and aml_bank_number() by +adding the missing of_node_put() calls. + +Fixes: 6e9be3abb78c ("pinctrl: Add driver support for Amlogic SoCs") +Signed-off-by: Felix Gu +Reviewed-by: Xianwei Zhao +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/meson/pinctrl-amlogic-a4.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/drivers/pinctrl/meson/pinctrl-amlogic-a4.c b/drivers/pinctrl/meson/pinctrl-amlogic-a4.c +index d9e3a8d5932a8..f05d8261624a4 100644 +--- a/drivers/pinctrl/meson/pinctrl-amlogic-a4.c ++++ b/drivers/pinctrl/meson/pinctrl-amlogic-a4.c +@@ -725,8 +725,9 @@ static u32 aml_bank_pins(struct device_node *np) + if (of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, + 0, &of_args)) + return 0; +- else +- return of_args.args[2]; ++ ++ of_node_put(of_args.np); ++ return of_args.args[2]; + } + + static int aml_bank_number(struct device_node *np) +@@ -736,8 +737,9 @@ static int aml_bank_number(struct device_node *np) + if (of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, + 0, &of_args)) + return -EINVAL; +- else +- return of_args.args[1] >> 8; ++ ++ of_node_put(of_args.np); ++ return of_args.args[1] >> 8; + } + + static unsigned int aml_count_pins(struct device_node *np) +-- +2.51.0 + diff --git a/queue-6.19/pinctrl-qcom-sm8250-lpass-lpi-fix-i2s2_data_groups-d.patch b/queue-6.19/pinctrl-qcom-sm8250-lpass-lpi-fix-i2s2_data_groups-d.patch new file mode 100644 index 0000000000..9a76735020 --- /dev/null +++ b/queue-6.19/pinctrl-qcom-sm8250-lpass-lpi-fix-i2s2_data_groups-d.patch @@ -0,0 +1,38 @@ +From cab5dd86ab3e0bb1adf8b102b2acbf67b391a994 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 12:22:28 +0100 +Subject: pinctrl: qcom: sm8250-lpass-lpi: Fix i2s2_data_groups definition + +From: Luca Weiss + +[ Upstream commit eabf273c8466af3f033473c2d2267a6ea7946d57 ] + +The i2s2_data function is available on both gpio12 and gpio13. Fix the +groups definition. + +Fixes: 6e261d1090d6 ("pinctrl: qcom: Add sm8250 lpass lpi pinctrl driver") +Signed-off-by: Luca Weiss +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c +index 64494a86490e2..c27452eece3e6 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c ++++ b/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c +@@ -73,7 +73,7 @@ static const char * const i2s1_ws_groups[] = { "gpio7" }; + static const char * const i2s1_data_groups[] = { "gpio8", "gpio9" }; + static const char * const wsa_swr_clk_groups[] = { "gpio10" }; + static const char * const wsa_swr_data_groups[] = { "gpio11" }; +-static const char * const i2s2_data_groups[] = { "gpio12", "gpio12" }; ++static const char * const i2s2_data_groups[] = { "gpio12", "gpio13" }; + + static const struct lpi_pingroup sm8250_groups[] = { + LPI_PINGROUP(0, 0, swr_tx_clk, qua_mi2s_sclk, _, _), +-- +2.51.0 + diff --git a/queue-6.19/pinctrl-single-fix-refcount-leak-in-pcs_add_gpio_fun.patch b/queue-6.19/pinctrl-single-fix-refcount-leak-in-pcs_add_gpio_fun.patch new file mode 100644 index 0000000000..d3996cf493 --- /dev/null +++ b/queue-6.19/pinctrl-single-fix-refcount-leak-in-pcs_add_gpio_fun.patch @@ -0,0 +1,50 @@ +From 8f60cb18f555fb77ad9347298350c5362a01a4a2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 08:07:35 +0000 +Subject: pinctrl: single: fix refcount leak in pcs_add_gpio_func() + +From: Wei Li + +[ Upstream commit 353353309b0f7afa407df29e455f9d15b5acc296 ] + +of_parse_phandle_with_args() returns a device_node pointer with refcount +incremented in gpiospec.np. The loop iterates through all phandles but +never releases the reference, causing a refcount leak on each iteration. + +Add of_node_put() calls to release the reference after extracting the +needed arguments and on the error path when devm_kzalloc() fails. + +This bug was detected by our static analysis tool and verified by my +code review. + +Fixes: a1a277eb76b3 ("pinctrl: single: create new gpio function range") +Signed-off-by: Wei Li +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-single.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c +index 998f23d6c3179..d85e6c1f63218 100644 +--- a/drivers/pinctrl/pinctrl-single.c ++++ b/drivers/pinctrl/pinctrl-single.c +@@ -1359,6 +1359,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) + } + range = devm_kzalloc(pcs->dev, sizeof(*range), GFP_KERNEL); + if (!range) { ++ of_node_put(gpiospec.np); + ret = -ENOMEM; + break; + } +@@ -1368,6 +1369,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) + mutex_lock(&pcs->mutex); + list_add_tail(&range->node, &pcs->gpiofuncs); + mutex_unlock(&pcs->mutex); ++ of_node_put(gpiospec.np); + } + return ret; + } +-- +2.51.0 + diff --git a/queue-6.19/platform-chrome-cros_ec_lightbar-fix-response-size-i.patch b/queue-6.19/platform-chrome-cros_ec_lightbar-fix-response-size-i.patch new file mode 100644 index 0000000000..9fbd229e6a --- /dev/null +++ b/queue-6.19/platform-chrome-cros_ec_lightbar-fix-response-size-i.patch @@ -0,0 +1,43 @@ +From c4683eea2c4905d100e385a29f410987de02a89e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 04:03:35 +0000 +Subject: platform/chrome: cros_ec_lightbar: Fix response size initialization + +From: Tzung-Bi Shih + +[ Upstream commit ec0dd36dbf8b0b209e63d0cd795451fa2203c736 ] + +Commit 1e7913ff5f9f ("platform/chrome: cros_ec_lightbar: Reduce +ligthbar get version command") meant to set smaller values for both +request and response sizes. + +However, it incorrectly assigned the response size to the `result` field +instead of `insize`. Fix it. + +Reported-by: Gwendal Grignou +Closes: https://lore.kernel.org/chrome-platform/CAMHSBOVrrYaB=1nEqZk09VkczCrj=6B-P8Fe29TpPdSDgT2CCQ@mail.gmail.com +Fixes: 1e7913ff5f9f ("platform/chrome: cros_ec_lightbar: Reduce ligthbar get version command") +Link: https://lore.kernel.org/r/20260130040335.361997-1-tzungbi@kernel.org +Reviewed-by: Gwendal Grignou +Signed-off-by: Tzung-Bi Shih +Signed-off-by: Sasha Levin +--- + drivers/platform/chrome/cros_ec_lightbar.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/platform/chrome/cros_ec_lightbar.c b/drivers/platform/chrome/cros_ec_lightbar.c +index 8352e97327911..3702baff5d4f1 100644 +--- a/drivers/platform/chrome/cros_ec_lightbar.c ++++ b/drivers/platform/chrome/cros_ec_lightbar.c +@@ -126,7 +126,7 @@ static int get_lightbar_version(struct cros_ec_dev *ec, + param = (struct ec_params_lightbar *)msg->data; + param->cmd = LIGHTBAR_CMD_VERSION; + msg->outsize = sizeof(param->cmd); +- msg->result = sizeof(resp->version); ++ msg->insize = sizeof(resp->version); + ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg); + if (ret < 0 && ret != -EINVAL) { + ret = 0; +-- +2.51.0 + diff --git a/queue-6.19/platform-chrome-cros_typec_switch-don-t-touch-struct.patch b/queue-6.19/platform-chrome-cros_typec_switch-don-t-touch-struct.patch new file mode 100644 index 0000000000..f2600e16da --- /dev/null +++ b/queue-6.19/platform-chrome-cros_typec_switch-don-t-touch-struct.patch @@ -0,0 +1,54 @@ +From 7793d90b0d01834a206ab00c056b5ef7823fd8e6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 14:12:30 +0100 +Subject: platform/chrome: cros_typec_switch: Don't touch struct + fwnode_handle::dev + +From: Andy Shevchenko + +[ Upstream commit e1adf48853bc715f4deea074932aa1c44eb7abea ] + +The 'dev' field in struct fwnode is special and related to device links, +There no driver should use it for printing messages. Fix incorrect use +of private field. + +Fixes: affc804c44c8 ("platform/chrome: cros_typec_switch: Add switch driver") +Signed-off-by: Andy Shevchenko +Link: https://lore.kernel.org/r/20260120131413.1697891-2-andriy.shevchenko@linux.intel.com +Signed-off-by: Tzung-Bi Shih +Signed-off-by: Sasha Levin +--- + drivers/platform/chrome/cros_typec_switch.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/platform/chrome/cros_typec_switch.c b/drivers/platform/chrome/cros_typec_switch.c +index 8d7c34abb0a12..d8a28d4e51a85 100644 +--- a/drivers/platform/chrome/cros_typec_switch.c ++++ b/drivers/platform/chrome/cros_typec_switch.c +@@ -230,20 +230,20 @@ static int cros_typec_register_switches(struct cros_typec_switch_data *sdata) + + adev = to_acpi_device_node(fwnode); + if (!adev) { +- dev_err(fwnode->dev, "Couldn't get ACPI device handle\n"); ++ dev_err(dev, "Couldn't get ACPI device handle for %pfwP\n", fwnode); + ret = -ENODEV; + goto err_switch; + } + + ret = acpi_evaluate_integer(adev->handle, "_ADR", NULL, &index); + if (ACPI_FAILURE(ret)) { +- dev_err(fwnode->dev, "_ADR wasn't evaluated\n"); ++ dev_err(dev, "_ADR wasn't evaluated for %pfwP\n", fwnode); + ret = -ENODATA; + goto err_switch; + } + + if (index >= EC_USB_PD_MAX_PORTS) { +- dev_err(fwnode->dev, "Invalid port index number: %llu\n", index); ++ dev_err(dev, "%pfwP: Invalid port index number: %llu\n", fwnode, index); + ret = -EINVAL; + goto err_switch; + } +-- +2.51.0 + diff --git a/queue-6.19/platform-x86-amd-pmf-prevent-tee-errors-after-hibern.patch b/queue-6.19/platform-x86-amd-pmf-prevent-tee-errors-after-hibern.patch new file mode 100644 index 0000000000..7872997382 --- /dev/null +++ b/queue-6.19/platform-x86-amd-pmf-prevent-tee-errors-after-hibern.patch @@ -0,0 +1,193 @@ +From dd90f14b49dd94ea39815f3aac85b4b531720328 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 22:11:28 -0600 +Subject: platform/x86/amd/pmf: Prevent TEE errors after hibernate +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Shyam Sundar S K + +[ Upstream commit 48d229c7047128dd52eaf863881bb3e62b5896e5 ] + +After resuming from hibernate, TEE commands can time out and cause PSP +disables. Fix this by reinitializing the Trusted Application (TA) and +cancelling the pb workqueue in the hibernate callbacks to avoid these +errors. + +ccp 0000:c4:00.2: tee: command 0x5 timed out, disabling PSP +amd-pmf AMDI0107:00: TEE enact cmd failed. err: ffff000e, ret:0 +amd-pmf AMDI0107:00: TEE enact cmd failed. err: ffff000e, ret:0 +amd-pmf AMDI0107:00: TEE enact cmd failed. err: ffff000e, ret:0 + +Fixes: ae82cef7d9c5 ("platform/x86/amd/pmf: Add support for PMF-TA interaction") +Reported-by: Lars Francke +Closes: https://lore.kernel.org/platform-driver-x86/CAD-Ua_gfJnQSo8ucS_7ZwzuhoBRJ14zXP7s8b-zX3ZcxcyWePw@mail.gmail.com/ +Tested-by: Yijun Shen +Co-developed-by: Patil Rajesh Reddy +Signed-off-by: Patil Rajesh Reddy +Signed-off-by: Shyam Sundar S K +[ML: Add more tags] +Signed-off-by: Mario Limonciello (AMD) +Link: https://patch.msgid.link/20260116041132.153674-2-superm1@kernel.org +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/amd/pmf/core.c | 62 ++++++++++++++++++++++++++- + drivers/platform/x86/amd/pmf/pmf.h | 10 +++++ + drivers/platform/x86/amd/pmf/tee-if.c | 12 ++---- + 3 files changed, 74 insertions(+), 10 deletions(-) + +diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c +index 8fc293c9c5380..15c27edfb6d85 100644 +--- a/drivers/platform/x86/amd/pmf/core.c ++++ b/drivers/platform/x86/amd/pmf/core.c +@@ -314,6 +314,61 @@ int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev) + return 0; + } + ++static int amd_pmf_reinit_ta(struct amd_pmf_dev *pdev) ++{ ++ bool status; ++ int ret, i; ++ ++ for (i = 0; i < ARRAY_SIZE(amd_pmf_ta_uuid); i++) { ++ ret = amd_pmf_tee_init(pdev, &amd_pmf_ta_uuid[i]); ++ if (ret) { ++ dev_err(pdev->dev, "TEE init failed for UUID[%d] ret: %d\n", i, ret); ++ return ret; ++ } ++ ++ ret = amd_pmf_start_policy_engine(pdev); ++ dev_dbg(pdev->dev, "start policy engine ret: %d (UUID idx: %d)\n", ret, i); ++ status = ret == TA_PMF_TYPE_SUCCESS; ++ if (status) ++ break; ++ amd_pmf_tee_deinit(pdev); ++ } ++ ++ return 0; ++} ++ ++static int amd_pmf_restore_handler(struct device *dev) ++{ ++ struct amd_pmf_dev *pdev = dev_get_drvdata(dev); ++ int ret; ++ ++ if (pdev->buf) { ++ ret = amd_pmf_set_dram_addr(pdev, false); ++ if (ret) ++ return ret; ++ } ++ ++ if (pdev->smart_pc_enabled) ++ amd_pmf_reinit_ta(pdev); ++ ++ return 0; ++} ++ ++static int amd_pmf_freeze_handler(struct device *dev) ++{ ++ struct amd_pmf_dev *pdev = dev_get_drvdata(dev); ++ ++ if (!pdev->smart_pc_enabled) ++ return 0; ++ ++ cancel_delayed_work_sync(&pdev->pb_work); ++ /* Clear all TEE resources */ ++ amd_pmf_tee_deinit(pdev); ++ pdev->session_id = 0; ++ ++ return 0; ++} ++ + static int amd_pmf_suspend_handler(struct device *dev) + { + struct amd_pmf_dev *pdev = dev_get_drvdata(dev); +@@ -347,7 +402,12 @@ static int amd_pmf_resume_handler(struct device *dev) + return 0; + } + +-static DEFINE_SIMPLE_DEV_PM_OPS(amd_pmf_pm, amd_pmf_suspend_handler, amd_pmf_resume_handler); ++static const struct dev_pm_ops amd_pmf_pm = { ++ .suspend = amd_pmf_suspend_handler, ++ .resume = amd_pmf_resume_handler, ++ .freeze = amd_pmf_freeze_handler, ++ .restore = amd_pmf_restore_handler, ++}; + + static void amd_pmf_init_features(struct amd_pmf_dev *dev) + { +diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h +index 9144c8c3bbaf2..513a6309ce130 100644 +--- a/drivers/platform/x86/amd/pmf/pmf.h ++++ b/drivers/platform/x86/amd/pmf/pmf.h +@@ -129,6 +129,12 @@ struct cookie_header { + + typedef void (*apmf_event_handler_t)(acpi_handle handle, u32 event, void *data); + ++static const uuid_t amd_pmf_ta_uuid[] __used = { UUID_INIT(0xd9b39bf2, 0x66bd, 0x4154, 0xaf, 0xb8, ++ 0x8a, 0xcc, 0x2b, 0x2b, 0x60, 0xd6), ++ UUID_INIT(0x6fd93b77, 0x3fb8, 0x524d, 0xb1, 0x2d, ++ 0xc5, 0x29, 0xb1, 0x3d, 0x85, 0x43), ++ }; ++ + /* APTS PMF BIOS Interface */ + struct amd_pmf_apts_output { + u16 table_version; +@@ -895,4 +901,8 @@ void amd_pmf_populate_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_tab + void amd_pmf_dump_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in); + int amd_pmf_invoke_cmd_enact(struct amd_pmf_dev *dev); + ++int amd_pmf_tee_init(struct amd_pmf_dev *dev, const uuid_t *uuid); ++void amd_pmf_tee_deinit(struct amd_pmf_dev *dev); ++int amd_pmf_start_policy_engine(struct amd_pmf_dev *dev); ++ + #endif /* PMF_H */ +diff --git a/drivers/platform/x86/amd/pmf/tee-if.c b/drivers/platform/x86/amd/pmf/tee-if.c +index 0abce76f89ffe..95ceb906a5f39 100644 +--- a/drivers/platform/x86/amd/pmf/tee-if.c ++++ b/drivers/platform/x86/amd/pmf/tee-if.c +@@ -27,12 +27,6 @@ module_param(pb_side_load, bool, 0444); + MODULE_PARM_DESC(pb_side_load, "Sideload policy binaries debug policy failures"); + #endif + +-static const uuid_t amd_pmf_ta_uuid[] = { UUID_INIT(0xd9b39bf2, 0x66bd, 0x4154, 0xaf, 0xb8, 0x8a, +- 0xcc, 0x2b, 0x2b, 0x60, 0xd6), +- UUID_INIT(0x6fd93b77, 0x3fb8, 0x524d, 0xb1, 0x2d, 0xc5, +- 0x29, 0xb1, 0x3d, 0x85, 0x43), +- }; +- + static const char *amd_pmf_uevent_as_str(unsigned int state) + { + switch (state) { +@@ -324,7 +318,7 @@ static void amd_pmf_invoke_cmd(struct work_struct *work) + schedule_delayed_work(&dev->pb_work, msecs_to_jiffies(pb_actions_ms)); + } + +-static int amd_pmf_start_policy_engine(struct amd_pmf_dev *dev) ++int amd_pmf_start_policy_engine(struct amd_pmf_dev *dev) + { + struct cookie_header *header; + int res; +@@ -480,7 +474,7 @@ static int amd_pmf_register_input_device(struct amd_pmf_dev *dev) + return 0; + } + +-static int amd_pmf_tee_init(struct amd_pmf_dev *dev, const uuid_t *uuid) ++int amd_pmf_tee_init(struct amd_pmf_dev *dev, const uuid_t *uuid) + { + u32 size; + int ret; +@@ -528,7 +522,7 @@ static int amd_pmf_tee_init(struct amd_pmf_dev *dev, const uuid_t *uuid) + return ret; + } + +-static void amd_pmf_tee_deinit(struct amd_pmf_dev *dev) ++void amd_pmf_tee_deinit(struct amd_pmf_dev *dev) + { + if (!dev->tee_ctx) + return; +-- +2.51.0 + diff --git a/queue-6.19/platform-x86-hp-wmi-fix-platform-profile-values-for-.patch b/queue-6.19/platform-x86-hp-wmi-fix-platform-profile-values-for-.patch new file mode 100644 index 0000000000..a95a69fc44 --- /dev/null +++ b/queue-6.19/platform-x86-hp-wmi-fix-platform-profile-values-for-.patch @@ -0,0 +1,306 @@ +From 6b90d8e3c1d1072036db925493e43d73df1e37a0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Jan 2026 23:56:03 +0530 +Subject: platform/x86: hp-wmi: fix platform profile values for Omen 16-wf1xxx +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Krishna Chomal + +[ Upstream commit 8ca7515d3c76a8b629f703ff8301a75f503bcc50 ] + +HP Omen 16-wf1xxx (board ID 8C78) currently sends the incorrect +Victus-specific thermal profile values via WMI, leading to a logical +inconsistency when switching between platform profiles. + +The driver currently uses Victus S values: +0x00 => Balanced / Low-Power +0x01 => Performance + +However, Omen Gaming Hub logs / EC register inspection on Windows shows +that this board is intended to use: +0x30 => Balanced / Low-Power +0x31 => Performance + +This patch corrects the thermal profile command values to match the +values observed from Omen Gaming Hub logs. The performance benchmarks +and peak power draw (from both CPU and GPU) show no observable change +with this correction (suggesting that the firmware is currently tolerant +of the incorrect values). However sending the correct values prevents +potential regressions after future firmware updates. + +Refactor victus_s_thermal_profile_boards from a list of strings to a +dmi_system_id table and move the lookup to module init. The new struct +thermal_profile_params is used to store board-specific WMI parameters, +allowing the driver to cache these values in a static pointer. This +avoids repeated DMI string comparisons and allows marking of DMI table as +__initconst. + +Testing on HP Omen 16-wf1xxx (board 8C78) confirmed WMI codes 0x30/0x31 +are now sent, resolving the logical inconsistency and ensuring the value +visible in EC registers match the Windows state for this profile. + +Fixes: fb146a38cb11 ("platform/x86: hp-wmi: Add Omen 16-wf1xxx fan support") +Signed-off-by: Krishna Chomal +Link: https://patch.msgid.link/20260113182604.115211-2-krishna.chomal108@gmail.com +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/hp/hp-wmi.c | 179 ++++++++++++++++++++++--------- + 1 file changed, 127 insertions(+), 52 deletions(-) + +diff --git a/drivers/platform/x86/hp/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c +index f4ea1ea05997b..24d065ddfc6ae 100644 +--- a/drivers/platform/x86/hp/hp-wmi.c ++++ b/drivers/platform/x86/hp/hp-wmi.c +@@ -53,6 +53,66 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45E9-BE91-3D44E2C707E4"); + + #define zero_if_sup(tmp) (zero_insize_support?0:sizeof(tmp)) // use when zero insize is required + ++enum hp_thermal_profile_omen_v0 { ++ HP_OMEN_V0_THERMAL_PROFILE_DEFAULT = 0x00, ++ HP_OMEN_V0_THERMAL_PROFILE_PERFORMANCE = 0x01, ++ HP_OMEN_V0_THERMAL_PROFILE_COOL = 0x02, ++}; ++ ++enum hp_thermal_profile_omen_v1 { ++ HP_OMEN_V1_THERMAL_PROFILE_DEFAULT = 0x30, ++ HP_OMEN_V1_THERMAL_PROFILE_PERFORMANCE = 0x31, ++ HP_OMEN_V1_THERMAL_PROFILE_COOL = 0x50, ++}; ++ ++enum hp_thermal_profile_omen_flags { ++ HP_OMEN_EC_FLAGS_TURBO = 0x04, ++ HP_OMEN_EC_FLAGS_NOTIMER = 0x02, ++ HP_OMEN_EC_FLAGS_JUSTSET = 0x01, ++}; ++ ++enum hp_thermal_profile_victus { ++ HP_VICTUS_THERMAL_PROFILE_DEFAULT = 0x00, ++ HP_VICTUS_THERMAL_PROFILE_PERFORMANCE = 0x01, ++ HP_VICTUS_THERMAL_PROFILE_QUIET = 0x03, ++}; ++ ++enum hp_thermal_profile_victus_s { ++ HP_VICTUS_S_THERMAL_PROFILE_DEFAULT = 0x00, ++ HP_VICTUS_S_THERMAL_PROFILE_PERFORMANCE = 0x01, ++}; ++ ++enum hp_thermal_profile { ++ HP_THERMAL_PROFILE_PERFORMANCE = 0x00, ++ HP_THERMAL_PROFILE_DEFAULT = 0x01, ++ HP_THERMAL_PROFILE_COOL = 0x02, ++ HP_THERMAL_PROFILE_QUIET = 0x03, ++}; ++ ++struct thermal_profile_params { ++ u8 performance; ++ u8 balanced; ++ u8 low_power; ++}; ++ ++static const struct thermal_profile_params victus_s_thermal_params = { ++ .performance = HP_VICTUS_S_THERMAL_PROFILE_PERFORMANCE, ++ .balanced = HP_VICTUS_S_THERMAL_PROFILE_DEFAULT, ++ .low_power = HP_VICTUS_S_THERMAL_PROFILE_DEFAULT, ++}; ++ ++static const struct thermal_profile_params omen_v1_thermal_params = { ++ .performance = HP_OMEN_V1_THERMAL_PROFILE_PERFORMANCE, ++ .balanced = HP_OMEN_V1_THERMAL_PROFILE_DEFAULT, ++ .low_power = HP_OMEN_V1_THERMAL_PROFILE_DEFAULT, ++}; ++ ++/* ++ * A generic pointer for the currently-active board's thermal profile ++ * parameters. ++ */ ++static struct thermal_profile_params *active_thermal_profile_params; ++ + /* DMI board names of devices that should use the omen specific path for + * thermal profiles. + * This was obtained by taking a look in the windows omen command center +@@ -99,12 +159,40 @@ static const char * const victus_thermal_profile_boards[] = { + }; + + /* DMI Board names of Victus 16-r and Victus 16-s laptops */ +-static const char * const victus_s_thermal_profile_boards[] = { +- "8BBE", "8BD4", "8BD5", +- "8C78", "8C99", "8C9C", +- "8D41", ++static const struct dmi_system_id victus_s_thermal_profile_boards[] __initconst = { ++ { ++ .matches = { DMI_MATCH(DMI_BOARD_NAME, "8BBE") }, ++ .driver_data = (void *)&victus_s_thermal_params, ++ }, ++ { ++ .matches = { DMI_MATCH(DMI_BOARD_NAME, "8BD4") }, ++ .driver_data = (void *)&victus_s_thermal_params, ++ }, ++ { ++ .matches = { DMI_MATCH(DMI_BOARD_NAME, "8BD5") }, ++ .driver_data = (void *)&victus_s_thermal_params, ++ }, ++ { ++ .matches = { DMI_MATCH(DMI_BOARD_NAME, "8C78") }, ++ .driver_data = (void *)&omen_v1_thermal_params, ++ }, ++ { ++ .matches = { DMI_MATCH(DMI_BOARD_NAME, "8C99") }, ++ .driver_data = (void *)&victus_s_thermal_params, ++ }, ++ { ++ .matches = { DMI_MATCH(DMI_BOARD_NAME, "8C9C") }, ++ .driver_data = (void *)&victus_s_thermal_params, ++ }, ++ { ++ .matches = { DMI_MATCH(DMI_BOARD_NAME, "8D41") }, ++ .driver_data = (void *)&victus_s_thermal_params, ++ }, ++ {}, + }; + ++static bool is_victus_s_board; ++ + enum hp_wmi_radio { + HPWMI_WIFI = 0x0, + HPWMI_BLUETOOTH = 0x1, +@@ -225,42 +313,6 @@ enum hp_wireless2_bits { + HPWMI_POWER_FW_OR_HW = HPWMI_POWER_BIOS | HPWMI_POWER_HARD, + }; + +-enum hp_thermal_profile_omen_v0 { +- HP_OMEN_V0_THERMAL_PROFILE_DEFAULT = 0x00, +- HP_OMEN_V0_THERMAL_PROFILE_PERFORMANCE = 0x01, +- HP_OMEN_V0_THERMAL_PROFILE_COOL = 0x02, +-}; +- +-enum hp_thermal_profile_omen_v1 { +- HP_OMEN_V1_THERMAL_PROFILE_DEFAULT = 0x30, +- HP_OMEN_V1_THERMAL_PROFILE_PERFORMANCE = 0x31, +- HP_OMEN_V1_THERMAL_PROFILE_COOL = 0x50, +-}; +- +-enum hp_thermal_profile_omen_flags { +- HP_OMEN_EC_FLAGS_TURBO = 0x04, +- HP_OMEN_EC_FLAGS_NOTIMER = 0x02, +- HP_OMEN_EC_FLAGS_JUSTSET = 0x01, +-}; +- +-enum hp_thermal_profile_victus { +- HP_VICTUS_THERMAL_PROFILE_DEFAULT = 0x00, +- HP_VICTUS_THERMAL_PROFILE_PERFORMANCE = 0x01, +- HP_VICTUS_THERMAL_PROFILE_QUIET = 0x03, +-}; +- +-enum hp_thermal_profile_victus_s { +- HP_VICTUS_S_THERMAL_PROFILE_DEFAULT = 0x00, +- HP_VICTUS_S_THERMAL_PROFILE_PERFORMANCE = 0x01, +-}; +- +-enum hp_thermal_profile { +- HP_THERMAL_PROFILE_PERFORMANCE = 0x00, +- HP_THERMAL_PROFILE_DEFAULT = 0x01, +- HP_THERMAL_PROFILE_COOL = 0x02, +- HP_THERMAL_PROFILE_QUIET = 0x03, +-}; +- + #define IS_HWBLOCKED(x) ((x & HPWMI_POWER_FW_OR_HW) != HPWMI_POWER_FW_OR_HW) + #define IS_SWBLOCKED(x) !(x & HPWMI_POWER_SOFT) + +@@ -1581,15 +1633,8 @@ static int platform_profile_victus_set_ec(enum platform_profile_option profile) + + static bool is_victus_s_thermal_profile(void) + { +- const char *board_name; +- +- board_name = dmi_get_system_info(DMI_BOARD_NAME); +- if (!board_name) +- return false; +- +- return match_string(victus_s_thermal_profile_boards, +- ARRAY_SIZE(victus_s_thermal_profile_boards), +- board_name) >= 0; ++ /* Initialised in driver init, hence safe to use here */ ++ return is_victus_s_board; + } + + static int victus_s_gpu_thermal_profile_get(bool *ctgp_enable, +@@ -1672,25 +1717,30 @@ static int victus_s_set_cpu_pl1_pl2(u8 pl1, u8 pl2) + + static int platform_profile_victus_s_set_ec(enum platform_profile_option profile) + { ++ struct thermal_profile_params *params; + bool gpu_ctgp_enable, gpu_ppab_enable; + u8 gpu_dstate; /* Test shows 1 = 100%, 2 = 50%, 3 = 25%, 4 = 12.5% */ + int err, tp; + ++ params = active_thermal_profile_params; ++ if (!params) ++ return -ENODEV; ++ + switch (profile) { + case PLATFORM_PROFILE_PERFORMANCE: +- tp = HP_VICTUS_S_THERMAL_PROFILE_PERFORMANCE; ++ tp = params->performance; + gpu_ctgp_enable = true; + gpu_ppab_enable = true; + gpu_dstate = 1; + break; + case PLATFORM_PROFILE_BALANCED: +- tp = HP_VICTUS_S_THERMAL_PROFILE_DEFAULT; ++ tp = params->balanced; + gpu_ctgp_enable = false; + gpu_ppab_enable = true; + gpu_dstate = 1; + break; + case PLATFORM_PROFILE_LOW_POWER: +- tp = HP_VICTUS_S_THERMAL_PROFILE_DEFAULT; ++ tp = params->low_power; + gpu_ctgp_enable = false; + gpu_ppab_enable = false; + gpu_dstate = 1; +@@ -2227,6 +2277,26 @@ static int hp_wmi_hwmon_init(void) + return 0; + } + ++static void __init setup_active_thermal_profile_params(void) ++{ ++ const struct dmi_system_id *id; ++ ++ /* ++ * Currently only victus_s devices use the ++ * active_thermal_profile_params ++ */ ++ id = dmi_first_match(victus_s_thermal_profile_boards); ++ if (id) { ++ /* ++ * Marking this boolean is required to ensure that ++ * is_victus_s_thermal_profile() behaves like a valid ++ * wrapper. ++ */ ++ is_victus_s_board = true; ++ active_thermal_profile_params = id->driver_data; ++ } ++} ++ + static int __init hp_wmi_init(void) + { + int event_capable = wmi_has_guid(HPWMI_EVENT_GUID); +@@ -2254,6 +2324,11 @@ static int __init hp_wmi_init(void) + goto err_destroy_input; + } + ++ /* ++ * Setup active board's thermal profile parameters before ++ * starting platform driver probe. ++ */ ++ setup_active_thermal_profile_params(); + err = platform_driver_probe(&hp_wmi_driver, hp_wmi_bios_setup); + if (err) + goto err_unregister_device; +-- +2.51.0 + diff --git a/queue-6.19/platform-x86-int0002-remove-irqf_oneshot-from-reques.patch b/queue-6.19/platform-x86-int0002-remove-irqf_oneshot-from-reques.patch new file mode 100644 index 0000000000..b5bff40ff0 --- /dev/null +++ b/queue-6.19/platform-x86-int0002-remove-irqf_oneshot-from-reques.patch @@ -0,0 +1,57 @@ +From 95d881087e3d5e2bc145f68c5cced50f570ee78e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:55:22 +0100 +Subject: platform/x86: int0002: Remove IRQF_ONESHOT from request_irq() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Sebastian Andrzej Siewior + +[ Upstream commit f6bc712877f24dc89bdfd7bdbf1a32f3b9960b34 ] + +Passing IRQF_ONESHOT ensures that the interrupt source is masked until the +secondary (threaded) handler is done. If only a primary handler is used +then the flag makes no sense because the interrupt cannot fire (again) +while its handler is running. + +The flag also prevents force-threading of the primary handler and the +irq-core will warn about this. + +The flag was added to match the flag on the shared handler which uses a +threaded handler and therefore IRQF_ONESHOT. This is no longer needed +because devm_request_irq() now passes IRQF_COND_ONESHOT for this case. + +Revert adding IRQF_ONESHOT to irqflags. + +Fixes: 8f812373d1958 ("platform/x86: intel: int0002_vgpio: Pass IRQF_ONESHOT to request_irq()") +Reported-by: Borah, Chaitanya Kumar +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Reviewed-by: Hans de Goede +Acked-by: Ilpo Järvinen +Link: https://patch.msgid.link/20260128095540.863589-3-bigeasy@linutronix.de +Closes: https://lore.kernel.org/all/555f1c56-0f74-41bf-8bd2-6217e0aab0c6@intel.com +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/intel/int0002_vgpio.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/platform/x86/intel/int0002_vgpio.c b/drivers/platform/x86/intel/int0002_vgpio.c +index 6f5629dc3f8db..562e880256436 100644 +--- a/drivers/platform/x86/intel/int0002_vgpio.c ++++ b/drivers/platform/x86/intel/int0002_vgpio.c +@@ -206,8 +206,8 @@ static int int0002_probe(struct platform_device *pdev) + * FIXME: augment this if we managed to pull handling of shared + * IRQs into gpiolib. + */ +- ret = devm_request_irq(dev, irq, int0002_irq, +- IRQF_ONESHOT | IRQF_SHARED, "INT0002", chip); ++ ret = devm_request_irq(dev, irq, int0002_irq, IRQF_SHARED, "INT0002", ++ chip); + if (ret) { + dev_err(dev, "Error requesting IRQ %d: %d\n", irq, ret); + return ret; +-- +2.51.0 + diff --git a/queue-6.19/pm-sleep-wakeirq-harden-dev_pm_clear_wake_irq-agains.patch b/queue-6.19/pm-sleep-wakeirq-harden-dev_pm_clear_wake_irq-agains.patch new file mode 100644 index 0000000000..c807b7f577 --- /dev/null +++ b/queue-6.19/pm-sleep-wakeirq-harden-dev_pm_clear_wake_irq-agains.patch @@ -0,0 +1,65 @@ +From 45d45b57dae146014f108361e22c913dbd0206be Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 11:19:43 +0800 +Subject: PM: sleep: wakeirq: harden dev_pm_clear_wake_irq() against races + +From: Gui-Dong Han + +[ Upstream commit 5c9ecd8e6437cd55a38ea4f1e1d19cee8e226cb8 ] + +dev_pm_clear_wake_irq() currently uses a dangerous pattern where +dev->power.wakeirq is read and checked for NULL outside the lock. +If two callers invoke this function concurrently, both might see +a valid pointer and proceed. This could result in a double-free +when the second caller acquires the lock and tries to release the +same object. + +Address this by removing the lockless check of dev->power.wakeirq. +Instead, acquire dev->power.lock immediately to ensure the check and +the subsequent operations are atomic. If dev->power.wakeirq is NULL +under the lock, simply unlock and return. This guarantees that +concurrent calls cannot race to free the same object. + +Based on a quick scan of current users, I did not find an actual bug as +drivers seem to rely on their own synchronization. However, since +asynchronous usage patterns exist (e.g., in +drivers/net/wireless/ti/wlcore), I believe a race is theoretically +possible if the API is used less carefully in the future. This change +hardens the API to be robust against such cases. + +Fixes: 4990d4fe327b ("PM / Wakeirq: Add automated device wake IRQ handling") +Signed-off-by: Gui-Dong Han +Link: https://patch.msgid.link/20260203031943.1924-1-hanguidong02@gmail.com +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/base/power/wakeirq.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/drivers/base/power/wakeirq.c b/drivers/base/power/wakeirq.c +index 8aa28c08b2891..c0809d18fc540 100644 +--- a/drivers/base/power/wakeirq.c ++++ b/drivers/base/power/wakeirq.c +@@ -83,13 +83,16 @@ EXPORT_SYMBOL_GPL(dev_pm_set_wake_irq); + */ + void dev_pm_clear_wake_irq(struct device *dev) + { +- struct wake_irq *wirq = dev->power.wakeirq; ++ struct wake_irq *wirq; + unsigned long flags; + +- if (!wirq) ++ spin_lock_irqsave(&dev->power.lock, flags); ++ wirq = dev->power.wakeirq; ++ if (!wirq) { ++ spin_unlock_irqrestore(&dev->power.lock, flags); + return; ++ } + +- spin_lock_irqsave(&dev->power.lock, flags); + device_wakeup_detach_irq(dev); + dev->power.wakeirq = NULL; + spin_unlock_irqrestore(&dev->power.lock, flags); +-- +2.51.0 + diff --git a/queue-6.19/pm-wakeup-handle-empty-list-in-wakeup_sources_walk_s.patch b/queue-6.19/pm-wakeup-handle-empty-list-in-wakeup_sources_walk_s.patch new file mode 100644 index 0000000000..ef7d7c212d --- /dev/null +++ b/queue-6.19/pm-wakeup-handle-empty-list-in-wakeup_sources_walk_s.patch @@ -0,0 +1,44 @@ +From d59cdce2ac6647766c39bff91d1dbdf8e830d2b6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 17:21:29 -0800 +Subject: PM: wakeup: Handle empty list in wakeup_sources_walk_start() + +From: Samuel Wu + +[ Upstream commit 75ce02f4bc9a8b8350b6b1b01872467b0cc960cc ] + +In the case of an empty wakeup_sources list, wakeup_sources_walk_start() +will return an invalid but non-NULL address. This also affects wrappers +of the aforementioned function, like for_each_wakeup_source(). + +Update wakeup_sources_walk_start() to return NULL in case of an empty +list. + +Fixes: b4941adb24c0 ("PM: wakeup: Add routine to help fetch wakeup source object.") +Signed-off-by: Samuel Wu +[ rjw: Subject and changelog edits ] +Link: https://patch.msgid.link/20260124012133.2451708-2-wusamuel@google.com +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/base/power/wakeup.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c +index 1e1a0e7eeac5f..e69033d16fba0 100644 +--- a/drivers/base/power/wakeup.c ++++ b/drivers/base/power/wakeup.c +@@ -275,9 +275,7 @@ EXPORT_SYMBOL_GPL(wakeup_sources_read_unlock); + */ + struct wakeup_source *wakeup_sources_walk_start(void) + { +- struct list_head *ws_head = &wakeup_sources; +- +- return list_entry_rcu(ws_head->next, struct wakeup_source, entry); ++ return list_first_or_null_rcu(&wakeup_sources, struct wakeup_source, entry); + } + EXPORT_SYMBOL_GPL(wakeup_sources_walk_start); + +-- +2.51.0 + diff --git a/queue-6.19/pnfs-fix-a-missing-wake-up-while-waiting-on-nfs_layo.patch b/queue-6.19/pnfs-fix-a-missing-wake-up-while-waiting-on-nfs_layo.patch new file mode 100644 index 0000000000..3890f19f44 --- /dev/null +++ b/queue-6.19/pnfs-fix-a-missing-wake-up-while-waiting-on-nfs_layo.patch @@ -0,0 +1,61 @@ +From aea87eed8d847aab6b0a6e01d63a2c4a16761253 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 14:15:39 -0500 +Subject: pNFS: fix a missing wake up while waiting on NFS_LAYOUT_DRAIN + +From: Olga Kornievskaia + +[ Upstream commit 5248d8474e594d156bee1ed10339cc16e207a28b ] + +It is possible to have a task get stuck on waiting on the +NFS_LAYOUT_DRAIN in the following scenario + +1. cpu a: waiter test NFS_LAYOUT_DRAIN (1) and plh_outstanding (1) +2. cpu b: atomic_dec_and_test() -> clear bit -> wake up +3. cpu c: sets NFS_LAYOUT_DRAIN again +4. cpu a: calls wait_on_bit() sleeps forever. + +To expand on this we have say 2 outstanding pnfs write IO that get +ESTALE which causes both to call pnfs_destroy_layout() and set the +NFS_LAYOUT_DRAIN bit but the 1st one doesn't call the +pnfs_put_layout_hdr() yet (as that would prevent the 2nd ESTALE write +from trying to call pnfs_destroy_layout()). If the 1st ESTALE write +is the one that initially sets the NFS_LAYOUT_DRAIN so that new IO +on this file initiates new LAYOUTGET. Another new write would find +NFS_LAYOUT_DRAIN set and phl_outstanding>0 (step 1) and would +wait_on_bit(). LAYOUTGET completes doing step 2. Now, the 2nd of +ESTALE writes is calling pnfs_destory_layout() and set the +NFS_LAYOUT_DRAIN bit (step 3). Finally, the waiting write wakes up +to check the bit and goes back to sleep. + +The problem revolves around the fact that if NFS_LAYOUT_INVALID_STID +was already set, it should not do the work of +pnfs_mark_layout_stateid_invalid(), thus NFS_LAYOUT_DRAIN will not +be set more than once for an invalid layout. + +Suggested-by: Trond Myklebust +Fixes: 880265c77ac4 ("pNFS: Avoid a live lock condition in pnfs_update_layout()") +Signed-off-by: Olga Kornievskaia +Signed-off-by: Anna Schumaker +Signed-off-by: Sasha Levin +--- + fs/nfs/pnfs.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c +index cff225721d1ce..ff8483d3373a8 100644 +--- a/fs/nfs/pnfs.c ++++ b/fs/nfs/pnfs.c +@@ -463,7 +463,8 @@ pnfs_mark_layout_stateid_invalid(struct pnfs_layout_hdr *lo, + }; + struct pnfs_layout_segment *lseg, *next; + +- set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags); ++ if (test_and_set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags)) ++ return !list_empty(&lo->plh_segs); + clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(lo->plh_inode)->flags); + list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list) + pnfs_clear_lseg_state(lseg, lseg_list); +-- +2.51.0 + diff --git a/queue-6.19/power-reset-nvmem-reboot-mode-respect-cell-size-for-.patch b/queue-6.19/power-reset-nvmem-reboot-mode-respect-cell-size-for-.patch new file mode 100644 index 0000000000..7f6cf24c74 --- /dev/null +++ b/queue-6.19/power-reset-nvmem-reboot-mode-respect-cell-size-for-.patch @@ -0,0 +1,64 @@ +From b7b8b88a4d9e5dd82058b50df9596424ed2a91a7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 14 Dec 2025 19:16:18 +0000 +Subject: power: reset: nvmem-reboot-mode: respect cell size for + nvmem_cell_write + +From: Alexander Koskovich + +[ Upstream commit 36b05629226413836cfbb3fbe6689cd188bca156 ] + +Some platforms expose reboot mode cells that are smaller than an +unsigned int, in which cases lead to write failures. Read the cell +first to determine actual size and only write the number of bytes the +cell can hold. + +Fixes: 7a78a7f7695b ("power: reset: nvmem-reboot-mode: use NVMEM as reboot mode write interface") +Signed-off-by: Alexander Koskovich +Link: https://patch.msgid.link/20251214191529.2470580-1-akoskovich@pm.me +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/reset/nvmem-reboot-mode.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +diff --git a/drivers/power/reset/nvmem-reboot-mode.c b/drivers/power/reset/nvmem-reboot-mode.c +index 41530b70cfc48..d260715fccf67 100644 +--- a/drivers/power/reset/nvmem-reboot-mode.c ++++ b/drivers/power/reset/nvmem-reboot-mode.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + + struct nvmem_reboot_mode { + struct reboot_mode_driver reboot; +@@ -19,12 +20,22 @@ struct nvmem_reboot_mode { + static int nvmem_reboot_mode_write(struct reboot_mode_driver *reboot, + unsigned int magic) + { +- int ret; + struct nvmem_reboot_mode *nvmem_rbm; ++ size_t buf_len; ++ void *buf; ++ int ret; + + nvmem_rbm = container_of(reboot, struct nvmem_reboot_mode, reboot); + +- ret = nvmem_cell_write(nvmem_rbm->cell, &magic, sizeof(magic)); ++ buf = nvmem_cell_read(nvmem_rbm->cell, &buf_len); ++ if (IS_ERR(buf)) ++ return PTR_ERR(buf); ++ kfree(buf); ++ ++ if (buf_len > sizeof(magic)) ++ return -EINVAL; ++ ++ ret = nvmem_cell_write(nvmem_rbm->cell, &magic, buf_len); + if (ret < 0) + dev_err(reboot->dev, "update reboot mode bits failed\n"); + +-- +2.51.0 + diff --git a/queue-6.19/power-supply-ab8500-fix-use-after-free-in-power_supp.patch b/queue-6.19/power-supply-ab8500-fix-use-after-free-in-power_supp.patch new file mode 100644 index 0000000000..7fc49a02dd --- /dev/null +++ b/queue-6.19/power-supply-ab8500-fix-use-after-free-in-power_supp.patch @@ -0,0 +1,104 @@ +From 0c7317e1023ecb29d58d9ece33cafed574328143 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:35:58 +0100 +Subject: power: supply: ab8500: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit c4af8a98bb52825a5331ae1d0604c0ea6956ba4b ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Commit 1c1f13a006ed ("power: supply: ab8500: Move to componentized +binding") introduced this issue during a refactorization. Fix this racy +use-after-free by making sure the IRQ is requested _after_ the +registration of the `power_supply` handle. + +Fixes: 1c1f13a006ed ("power: supply: ab8500: Move to componentized binding") +Signed-off-by: Waqar Hameed +Reviewed-by: Linus Walleij +Link: https://patch.msgid.link/ccf83a09942cb8dda3dff70b2682f2c2e9cb97f2.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/ab8500_charger.c | 40 +++++++++++++-------------- + 1 file changed, 20 insertions(+), 20 deletions(-) + +diff --git a/drivers/power/supply/ab8500_charger.c b/drivers/power/supply/ab8500_charger.c +index 5f4537766e5b9..1813fbdfa1c1f 100644 +--- a/drivers/power/supply/ab8500_charger.c ++++ b/drivers/power/supply/ab8500_charger.c +@@ -3466,26 +3466,6 @@ static int ab8500_charger_probe(struct platform_device *pdev) + return ret; + } + +- /* Request interrupts */ +- for (i = 0; i < ARRAY_SIZE(ab8500_charger_irq); i++) { +- irq = platform_get_irq_byname(pdev, ab8500_charger_irq[i].name); +- if (irq < 0) +- return irq; +- +- ret = devm_request_threaded_irq(dev, +- irq, NULL, ab8500_charger_irq[i].isr, +- IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT, +- ab8500_charger_irq[i].name, di); +- +- if (ret != 0) { +- dev_err(dev, "failed to request %s IRQ %d: %d\n" +- , ab8500_charger_irq[i].name, irq, ret); +- return ret; +- } +- dev_dbg(dev, "Requested %s IRQ %d: %d\n", +- ab8500_charger_irq[i].name, irq, ret); +- } +- + /* initialize lock */ + spin_lock_init(&di->usb_state.usb_lock); + mutex_init(&di->usb_ipt_crnt_lock); +@@ -3614,6 +3594,26 @@ static int ab8500_charger_probe(struct platform_device *pdev) + return PTR_ERR(di->usb_chg.psy); + } + ++ /* Request interrupts */ ++ for (i = 0; i < ARRAY_SIZE(ab8500_charger_irq); i++) { ++ irq = platform_get_irq_byname(pdev, ab8500_charger_irq[i].name); ++ if (irq < 0) ++ return irq; ++ ++ ret = devm_request_threaded_irq(dev, ++ irq, NULL, ab8500_charger_irq[i].isr, ++ IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT, ++ ab8500_charger_irq[i].name, di); ++ ++ if (ret != 0) { ++ dev_err(dev, "failed to request %s IRQ %d: %d\n" ++ , ab8500_charger_irq[i].name, irq, ret); ++ return ret; ++ } ++ dev_dbg(dev, "Requested %s IRQ %d: %d\n", ++ ab8500_charger_irq[i].name, irq, ret); ++ } ++ + /* + * Check what battery we have, since we always have the USB + * psy, use that as a handle. +-- +2.51.0 + diff --git a/queue-6.19/power-supply-act8945a-fix-use-after-free-in-power_su.patch b/queue-6.19/power-supply-act8945a-fix-use-after-free-in-power_su.patch new file mode 100644 index 0000000000..6574f21515 --- /dev/null +++ b/queue-6.19/power-supply-act8945a-fix-use-after-free-in-power_su.patch @@ -0,0 +1,77 @@ +From 77e909ea288bbe85d4987ce6a0f839b0f4af0d10 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:35:59 +0100 +Subject: power: supply: act8945a: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 3291c51d4684d048dd2eb91b5b65fcfdaf72141f ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: a09209acd6a8 ("power: supply: act8945a_charger: Add status change update support") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/bcf3a23b5187df0bba54a8c8fe09f8b8a0031dee.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/act8945a_charger.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/drivers/power/supply/act8945a_charger.c b/drivers/power/supply/act8945a_charger.c +index 3901a02f326a5..9dec4486b1439 100644 +--- a/drivers/power/supply/act8945a_charger.c ++++ b/drivers/power/supply/act8945a_charger.c +@@ -597,14 +597,6 @@ static int act8945a_charger_probe(struct platform_device *pdev) + return irq ?: -ENXIO; + } + +- ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, +- IRQF_TRIGGER_FALLING, "act8945a_interrupt", +- charger); +- if (ret) { +- dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); +- return ret; +- } +- + charger->desc.name = "act8945a-charger"; + charger->desc.get_property = act8945a_charger_get_property; + charger->desc.properties = act8945a_charger_props; +@@ -625,6 +617,14 @@ static int act8945a_charger_probe(struct platform_device *pdev) + return PTR_ERR(charger->psy); + } + ++ ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, ++ IRQF_TRIGGER_FALLING, "act8945a_interrupt", ++ charger); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); ++ return ret; ++ } ++ + platform_set_drvdata(pdev, charger); + + INIT_WORK(&charger->work, act8945a_work); +-- +2.51.0 + diff --git a/queue-6.19/power-supply-bq256xx-fix-use-after-free-in-power_sup.patch b/queue-6.19/power-supply-bq256xx-fix-use-after-free-in-power_sup.patch new file mode 100644 index 0000000000..1f5af5a903 --- /dev/null +++ b/queue-6.19/power-supply-bq256xx-fix-use-after-free-in-power_sup.patch @@ -0,0 +1,73 @@ +From c39c990b1329d651a470e8d54346d7ae23d55b03 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:35:59 +0100 +Subject: power: supply: bq256xx: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 8005843369723d9c8975b7c4202d1b85d6125302 ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: 32e4978bb920 ("power: supply: bq256xx: Introduce the BQ256XX charger driver") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/39da6da8cc060fa0382ca859f65071e791cb6119.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/bq256xx_charger.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/power/supply/bq256xx_charger.c b/drivers/power/supply/bq256xx_charger.c +index ae14162f017a9..d3de4f8b80db1 100644 +--- a/drivers/power/supply/bq256xx_charger.c ++++ b/drivers/power/supply/bq256xx_charger.c +@@ -1741,6 +1741,12 @@ static int bq256xx_probe(struct i2c_client *client) + usb_register_notifier(bq->usb3_phy, &bq->usb_nb); + } + ++ ret = bq256xx_power_supply_init(bq, &psy_cfg, dev); ++ if (ret) { ++ dev_err(dev, "Failed to register power supply\n"); ++ return ret; ++ } ++ + if (client->irq) { + ret = devm_request_threaded_irq(dev, client->irq, NULL, + bq256xx_irq_handler_thread, +@@ -1753,12 +1759,6 @@ static int bq256xx_probe(struct i2c_client *client) + } + } + +- ret = bq256xx_power_supply_init(bq, &psy_cfg, dev); +- if (ret) { +- dev_err(dev, "Failed to register power supply\n"); +- return ret; +- } +- + ret = bq256xx_hw_init(bq); + if (ret) { + dev_err(dev, "Cannot initialize the chip.\n"); +-- +2.51.0 + diff --git a/queue-6.19/power-supply-bq25980-fix-use-after-free-in-power_sup.patch b/queue-6.19/power-supply-bq25980-fix-use-after-free-in-power_sup.patch new file mode 100644 index 0000000000..670972b858 --- /dev/null +++ b/queue-6.19/power-supply-bq25980-fix-use-after-free-in-power_sup.patch @@ -0,0 +1,73 @@ +From 124a69d5ac0eb2df1a4f5cabf15ecbc015c78331 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:35:59 +0100 +Subject: power: supply: bq25980: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 5f0b1cb41906e86b64bf69f5ededb83b0d757c27 ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: 5069185fc18e ("power: supply: bq25980: Add support for the BQ259xx family") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/8763035cadb959e14787b3837f2d3db61f6e1c34.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/bq25980_charger.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/power/supply/bq25980_charger.c b/drivers/power/supply/bq25980_charger.c +index 723858d62d141..73f06f09f134c 100644 +--- a/drivers/power/supply/bq25980_charger.c ++++ b/drivers/power/supply/bq25980_charger.c +@@ -1241,6 +1241,12 @@ static int bq25980_probe(struct i2c_client *client) + return ret; + } + ++ ret = bq25980_power_supply_init(bq, dev); ++ if (ret) { ++ dev_err(dev, "Failed to register power supply\n"); ++ return ret; ++ } ++ + if (client->irq) { + ret = devm_request_threaded_irq(dev, client->irq, NULL, + bq25980_irq_handler_thread, +@@ -1251,12 +1257,6 @@ static int bq25980_probe(struct i2c_client *client) + return ret; + } + +- ret = bq25980_power_supply_init(bq, dev); +- if (ret) { +- dev_err(dev, "Failed to register power supply\n"); +- return ret; +- } +- + ret = bq25980_hw_init(bq); + if (ret) { + dev_err(dev, "Cannot initialize the chip.\n"); +-- +2.51.0 + diff --git a/queue-6.19/power-supply-bq27xxx-fix-wrong-errno-when-bus-ops-ar.patch b/queue-6.19/power-supply-bq27xxx-fix-wrong-errno-when-bus-ops-ar.patch new file mode 100644 index 0000000000..428a8491d2 --- /dev/null +++ b/queue-6.19/power-supply-bq27xxx-fix-wrong-errno-when-bus-ops-ar.patch @@ -0,0 +1,61 @@ +From 8a5cef258a17452ac491a0b088292516cbc2917c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Dec 2025 16:34:36 +0800 +Subject: power: supply: bq27xxx: fix wrong errno when bus ops are unsupported + +From: Haotian Zhang + +[ Upstream commit 688364a11647dc09ba1e4429313e0008066ec790 ] + +bq27xxx_write(), bq27xxx_read_block(), and bq27xxx_write_block() +return -EPERM when the bus callback pointer is NULL. A NULL callback +indicates the operation is not supported by the bus/driver, +not that permission is denied. + +Return -EOPNOTSUPP instead of -EPERM when di->bus.write/ +read_bulk/write_bulk is NULL. + +Fixes: 14073f6614f6 ("power: supply: bq27xxx: Add bulk transfer bus methods") +Signed-off-by: Haotian Zhang +Reviewed-by: Matt Ranostay +Link: https://patch.msgid.link/20251204083436.1367-1-vulab@iscas.ac.cn +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/bq27xxx_battery.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c +index 19445e39651c7..45f0e39b8c2dd 100644 +--- a/drivers/power/supply/bq27xxx_battery.c ++++ b/drivers/power/supply/bq27xxx_battery.c +@@ -1172,7 +1172,7 @@ static inline int bq27xxx_write(struct bq27xxx_device_info *di, int reg_index, + return -EINVAL; + + if (!di->bus.write) +- return -EPERM; ++ return -EOPNOTSUPP; + + ret = di->bus.write(di, di->regs[reg_index], value, single); + if (ret < 0) +@@ -1191,7 +1191,7 @@ static inline int bq27xxx_read_block(struct bq27xxx_device_info *di, int reg_ind + return -EINVAL; + + if (!di->bus.read_bulk) +- return -EPERM; ++ return -EOPNOTSUPP; + + ret = di->bus.read_bulk(di, di->regs[reg_index], data, len); + if (ret < 0) +@@ -1210,7 +1210,7 @@ static inline int bq27xxx_write_block(struct bq27xxx_device_info *di, int reg_in + return -EINVAL; + + if (!di->bus.write_bulk) +- return -EPERM; ++ return -EOPNOTSUPP; + + ret = di->bus.write_bulk(di, di->regs[reg_index], data, len); + if (ret < 0) +-- +2.51.0 + diff --git a/queue-6.19/power-supply-cpcap-battery-fix-use-after-free-in-pow.patch b/queue-6.19/power-supply-cpcap-battery-fix-use-after-free-in-pow.patch new file mode 100644 index 0000000000..6ef4337ef8 --- /dev/null +++ b/queue-6.19/power-supply-cpcap-battery-fix-use-after-free-in-pow.patch @@ -0,0 +1,70 @@ +From 8ef81becc7bdff7b0c43a1767279cec926e754f7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:36:00 +0100 +Subject: power: supply: cpcap-battery: Fix use-after-free in + power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 642f33e34b969eedec334738fd5df95d2dc42742 ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: 874b2adbed12 ("power: supply: cpcap-battery: Add a battery driver") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/81db58d610c9a51a68184f856cd431a934cccee2.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/cpcap-battery.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/power/supply/cpcap-battery.c b/drivers/power/supply/cpcap-battery.c +index 8106d1edcbc26..507fdc1c866d5 100644 +--- a/drivers/power/supply/cpcap-battery.c ++++ b/drivers/power/supply/cpcap-battery.c +@@ -1122,10 +1122,6 @@ static int cpcap_battery_probe(struct platform_device *pdev) + + platform_set_drvdata(pdev, ddata); + +- error = cpcap_battery_init_interrupts(pdev, ddata); +- if (error) +- return error; +- + error = cpcap_battery_init_iio(ddata); + if (error) + return error; +@@ -1142,6 +1138,10 @@ static int cpcap_battery_probe(struct platform_device *pdev) + return error; + } + ++ error = cpcap_battery_init_interrupts(pdev, ddata); ++ if (error) ++ return error; ++ + atomic_set(&ddata->active, 1); + + error = cpcap_battery_calibrate(ddata); +-- +2.51.0 + diff --git a/queue-6.19/power-supply-goldfish-fix-use-after-free-in-power_su.patch b/queue-6.19/power-supply-goldfish-fix-use-after-free-in-power_su.patch new file mode 100644 index 0000000000..11a8ca3eb6 --- /dev/null +++ b/queue-6.19/power-supply-goldfish-fix-use-after-free-in-power_su.patch @@ -0,0 +1,73 @@ +From 8a5a8c2c66d368a3d9f5fd0c94fc5c0ad0a41742 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:36:00 +0100 +Subject: power: supply: goldfish: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit b2ce982e2e0c888dc55c888ad0e20ea04daf2e6b ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: 84d7b7687489 ("power: Add battery driver for goldfish emulator") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/500a606bb6fb6f2bb8d797e19a00cea9dd7b03c1.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/goldfish_battery.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/power/supply/goldfish_battery.c b/drivers/power/supply/goldfish_battery.c +index 479195e35d734..5aa24e4dc4455 100644 +--- a/drivers/power/supply/goldfish_battery.c ++++ b/drivers/power/supply/goldfish_battery.c +@@ -224,12 +224,6 @@ static int goldfish_battery_probe(struct platform_device *pdev) + if (data->irq < 0) + return -ENODEV; + +- ret = devm_request_irq(&pdev->dev, data->irq, +- goldfish_battery_interrupt, +- IRQF_SHARED, pdev->name, data); +- if (ret) +- return ret; +- + psy_cfg.drv_data = data; + + data->ac = devm_power_supply_register(&pdev->dev, +@@ -244,6 +238,12 @@ static int goldfish_battery_probe(struct platform_device *pdev) + if (IS_ERR(data->battery)) + return PTR_ERR(data->battery); + ++ ret = devm_request_irq(&pdev->dev, data->irq, ++ goldfish_battery_interrupt, ++ IRQF_SHARED, pdev->name, data); ++ if (ret) ++ return ret; ++ + GOLDFISH_BATTERY_WRITE(data, BATTERY_INT_ENABLE, BATTERY_INT_MASK); + return 0; + } +-- +2.51.0 + diff --git a/queue-6.19/power-supply-pf1550-fix-use-after-free-in-power_supp.patch b/queue-6.19/power-supply-pf1550-fix-use-after-free-in-power_supp.patch new file mode 100644 index 0000000000..74d74fbc07 --- /dev/null +++ b/queue-6.19/power-supply-pf1550-fix-use-after-free-in-power_supp.patch @@ -0,0 +1,94 @@ +From a02c2d873715218ea15ccfa439a010b6412dc78a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:36:01 +0100 +Subject: power: supply: pf1550: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 838767f5074700552d3f006d867caed65edc7328 ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: 4b6b6433a97d ("power: supply: pf1550: add battery charger support") +Signed-off-by: Waqar Hameed +Reviewed-by: Samuel Kayode +Link: https://patch.msgid.link/ae5a71b7e4dd2967d8fdcc531065cc71b17c86f5.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/pf1550-charger.c | 32 +++++++++++++-------------- + 1 file changed, 16 insertions(+), 16 deletions(-) + +diff --git a/drivers/power/supply/pf1550-charger.c b/drivers/power/supply/pf1550-charger.c +index 98f1ee8eca3bc..a457862ef4610 100644 +--- a/drivers/power/supply/pf1550-charger.c ++++ b/drivers/power/supply/pf1550-charger.c +@@ -584,22 +584,6 @@ static int pf1550_charger_probe(struct platform_device *pdev) + return dev_err_probe(chg->dev, ret, + "failed to add battery sense work\n"); + +- for (i = 0; i < PF1550_CHARGER_IRQ_NR; i++) { +- irq = platform_get_irq(pdev, i); +- if (irq < 0) +- return irq; +- +- chg->virqs[i] = irq; +- +- ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, +- pf1550_charger_irq_handler, +- IRQF_NO_SUSPEND, +- "pf1550-charger", chg); +- if (ret) +- return dev_err_probe(&pdev->dev, ret, +- "failed irq request\n"); +- } +- + psy_cfg.drv_data = chg; + + chg->charger = devm_power_supply_register(&pdev->dev, +@@ -616,6 +600,22 @@ static int pf1550_charger_probe(struct platform_device *pdev) + return dev_err_probe(&pdev->dev, PTR_ERR(chg->battery), + "failed: power supply register\n"); + ++ for (i = 0; i < PF1550_CHARGER_IRQ_NR; i++) { ++ irq = platform_get_irq(pdev, i); ++ if (irq < 0) ++ return irq; ++ ++ chg->virqs[i] = irq; ++ ++ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, ++ pf1550_charger_irq_handler, ++ IRQF_NO_SUSPEND, ++ "pf1550-charger", chg); ++ if (ret) ++ return dev_err_probe(&pdev->dev, ret, ++ "failed irq request\n"); ++ } ++ + pf1550_dt_parse_dev_info(chg); + + return pf1550_reg_init(chg); +-- +2.51.0 + diff --git a/queue-6.19/power-supply-pm8916_bms_vm-fix-use-after-free-in-pow.patch b/queue-6.19/power-supply-pm8916_bms_vm-fix-use-after-free-in-pow.patch new file mode 100644 index 0000000000..c1d923b65f --- /dev/null +++ b/queue-6.19/power-supply-pm8916_bms_vm-fix-use-after-free-in-pow.patch @@ -0,0 +1,81 @@ +From 530e673e420648062e17849955c2b17de74c9a0d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:36:01 +0100 +Subject: power: supply: pm8916_bms_vm: Fix use-after-free in + power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 62914959b35e9a1e29cc0f64cb8cfc5075a5366f ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: 098bce1838e0 ("power: supply: Add pm8916 VM-BMS support") +Signed-off-by: Waqar Hameed +Reviewed-by: Nikita Travkin +Link: https://patch.msgid.link/2749c09ff81fcac87ae48147e216135450d8c067.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/pm8916_bms_vm.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/drivers/power/supply/pm8916_bms_vm.c b/drivers/power/supply/pm8916_bms_vm.c +index 5120be086e6ff..de5d571c03e21 100644 +--- a/drivers/power/supply/pm8916_bms_vm.c ++++ b/drivers/power/supply/pm8916_bms_vm.c +@@ -167,15 +167,6 @@ static int pm8916_bms_vm_battery_probe(struct platform_device *pdev) + if (ret < 0) + return -EINVAL; + +- irq = platform_get_irq_byname(pdev, "fifo"); +- if (irq < 0) +- return irq; +- +- ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_bms_vm_fifo_update_done_irq, +- IRQF_ONESHOT, "pm8916_vm_bms", bat); +- if (ret) +- return ret; +- + ret = regmap_bulk_read(bat->regmap, bat->reg + PM8916_PERPH_TYPE, &tmp, 2); + if (ret) + goto comm_error; +@@ -220,6 +211,15 @@ static int pm8916_bms_vm_battery_probe(struct platform_device *pdev) + if (ret) + return dev_err_probe(dev, ret, "Unable to get battery info\n"); + ++ irq = platform_get_irq_byname(pdev, "fifo"); ++ if (irq < 0) ++ return irq; ++ ++ ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_bms_vm_fifo_update_done_irq, ++ IRQF_ONESHOT, "pm8916_vm_bms", bat); ++ if (ret) ++ return ret; ++ + platform_set_drvdata(pdev, bat); + + return 0; +-- +2.51.0 + diff --git a/queue-6.19/power-supply-pm8916_lbc-fix-use-after-free-for-extco.patch b/queue-6.19/power-supply-pm8916_lbc-fix-use-after-free-for-extco.patch new file mode 100644 index 0000000000..39b98547ae --- /dev/null +++ b/queue-6.19/power-supply-pm8916_lbc-fix-use-after-free-for-extco.patch @@ -0,0 +1,67 @@ +From 3131a81f105af2704b5d7708d3e979e6ee5e6376 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 11:24:20 +0100 +Subject: power: supply: pm8916_lbc: Fix use-after-free for extcon in IRQ + handler + +From: Waqar Hameed + +[ Upstream commit 23067259919663580c6f81801847cfc7bd54fd1f ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `extcon` handle, means that the +`extcon` handle will be deallocated/unregistered _before_ the interrupt +handler (since `devm_` naturally deallocates in reverse allocation +order). This means that during removal, there is a race condition where +an interrupt can fire just _after_ the `extcon` handle has been +freed, *but* just _before_ the corresponding unregistration of the IRQ +handler has run. + +This will lead to the IRQ handler calling `extcon_set_state_sync()` with +a freed `extcon` handle. Which usually crashes the system or otherwise +silently corrupts the memory... + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `extcon` handle. + +Fixes: f8d7a3d21160 ("power: supply: Add driver for pm8916 lbc") +Signed-off-by: Waqar Hameed +Reviewed-by: Nikita Travkin +Link: https://patch.msgid.link/e2a4cd2fcd42b6cd97d856c17c097289a2aed393.1769163273.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/pm8916_lbc.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/power/supply/pm8916_lbc.c b/drivers/power/supply/pm8916_lbc.c +index 3ca717d84aade..6b631012a7959 100644 +--- a/drivers/power/supply/pm8916_lbc.c ++++ b/drivers/power/supply/pm8916_lbc.c +@@ -327,11 +327,6 @@ static int pm8916_lbc_charger_probe(struct platform_device *pdev) + if (irq < 0) + return irq; + +- ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_lbc_charger_state_changed_irq, +- IRQF_ONESHOT, "pm8916_lbc", chg); +- if (ret) +- return ret; +- + chg->edev = devm_extcon_dev_allocate(dev, pm8916_lbc_charger_cable); + if (IS_ERR(chg->edev)) + return PTR_ERR(chg->edev); +@@ -340,6 +335,11 @@ static int pm8916_lbc_charger_probe(struct platform_device *pdev) + if (ret < 0) + return dev_err_probe(dev, ret, "failed to register extcon device\n"); + ++ ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_lbc_charger_state_changed_irq, ++ IRQF_ONESHOT, "pm8916_lbc", chg); ++ if (ret) ++ return ret; ++ + ret = regmap_read(chg->regmap, chg->reg[LBC_USB] + PM8916_INT_RT_STS, &tmp); + if (ret) + goto comm_error; +-- +2.51.0 + diff --git a/queue-6.19/power-supply-pm8916_lbc-fix-use-after-free-in-power_.patch b/queue-6.19/power-supply-pm8916_lbc-fix-use-after-free-in-power_.patch new file mode 100644 index 0000000000..43e2d9918d --- /dev/null +++ b/queue-6.19/power-supply-pm8916_lbc-fix-use-after-free-in-power_.patch @@ -0,0 +1,81 @@ +From 528375176ba0b11b0add886ba1ceef740a55f185 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:36:01 +0100 +Subject: power: supply: pm8916_lbc: Fix use-after-free in + power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit b7508129978ae1e2ed9b0410396abc05def9c4eb ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: f8d7a3d21160 ("power: supply: Add driver for pm8916 lbc") +Signed-off-by: Waqar Hameed +Reviewed-by: Nikita Travkin +Link: https://patch.msgid.link/64d8dd3675a4e59fa32c3e0ef451f12d1f7ed18f.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/pm8916_lbc.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/drivers/power/supply/pm8916_lbc.c b/drivers/power/supply/pm8916_lbc.c +index c74b75b1b2676..3ca717d84aade 100644 +--- a/drivers/power/supply/pm8916_lbc.c ++++ b/drivers/power/supply/pm8916_lbc.c +@@ -274,15 +274,6 @@ static int pm8916_lbc_charger_probe(struct platform_device *pdev) + return dev_err_probe(dev, -EINVAL, + "Wrong amount of reg values: %d (4 expected)\n", len); + +- irq = platform_get_irq_byname(pdev, "usb_vbus"); +- if (irq < 0) +- return irq; +- +- ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_lbc_charger_state_changed_irq, +- IRQF_ONESHOT, "pm8916_lbc", chg); +- if (ret) +- return ret; +- + ret = device_property_read_u32_array(dev, "reg", chg->reg, len); + if (ret) + return ret; +@@ -332,6 +323,15 @@ static int pm8916_lbc_charger_probe(struct platform_device *pdev) + if (ret) + return dev_err_probe(dev, ret, "Unable to get battery info\n"); + ++ irq = platform_get_irq_byname(pdev, "usb_vbus"); ++ if (irq < 0) ++ return irq; ++ ++ ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_lbc_charger_state_changed_irq, ++ IRQF_ONESHOT, "pm8916_lbc", chg); ++ if (ret) ++ return ret; ++ + chg->edev = devm_extcon_dev_allocate(dev, pm8916_lbc_charger_cable); + if (IS_ERR(chg->edev)) + return PTR_ERR(chg->edev); +-- +2.51.0 + diff --git a/queue-6.19/power-supply-qcom_battmgr-recognize-lip-as-lithium-p.patch b/queue-6.19/power-supply-qcom_battmgr-recognize-lip-as-lithium-p.patch new file mode 100644 index 0000000000..aa39c9b911 --- /dev/null +++ b/queue-6.19/power-supply-qcom_battmgr-recognize-lip-as-lithium-p.patch @@ -0,0 +1,42 @@ +From 87527a478555ddd00a1bf09bfeac3d0f78b43c3b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 20:57:58 -0300 +Subject: power: supply: qcom_battmgr: Recognize "LiP" as lithium-polymer + +From: Val Packett + +[ Upstream commit c655f45480637aee326b5bd96488d35ab90db2b0 ] + +On the Dell Latitude 7455, the firmware uses "LiP" with a lowercase 'i' +for the battery chemistry type, but only all-uppercase "LIP" was being +recognized. Add the CamelCase variant to the check to fix the "Unknown +battery technology" warning. + +Fixes: 202ac22b8e2e ("power: supply: qcom_battmgr: Add lithium-polymer entry") +Signed-off-by: Val Packett +Reviewed-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Link: https://patch.msgid.link/20260120235831.479038-1-val@packett.cool +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/qcom_battmgr.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/power/supply/qcom_battmgr.c b/drivers/power/supply/qcom_battmgr.c +index c8028606bba00..80572ee945b4f 100644 +--- a/drivers/power/supply/qcom_battmgr.c ++++ b/drivers/power/supply/qcom_battmgr.c +@@ -1240,7 +1240,8 @@ static unsigned int qcom_battmgr_sc8280xp_parse_technology(const char *chemistry + if ((!strncmp(chemistry, "LIO", BATTMGR_CHEMISTRY_LEN)) || + (!strncmp(chemistry, "OOI", BATTMGR_CHEMISTRY_LEN))) + return POWER_SUPPLY_TECHNOLOGY_LION; +- if (!strncmp(chemistry, "LIP", BATTMGR_CHEMISTRY_LEN)) ++ if (!strncmp(chemistry, "LIP", BATTMGR_CHEMISTRY_LEN) || ++ !strncmp(chemistry, "LiP", BATTMGR_CHEMISTRY_LEN)) + return POWER_SUPPLY_TECHNOLOGY_LIPO; + + pr_err("Unknown battery technology '%s'\n", chemistry); +-- +2.51.0 + diff --git a/queue-6.19/power-supply-rt9455-fix-use-after-free-in-power_supp.patch b/queue-6.19/power-supply-rt9455-fix-use-after-free-in-power_supp.patch new file mode 100644 index 0000000000..855f2d8fe7 --- /dev/null +++ b/queue-6.19/power-supply-rt9455-fix-use-after-free-in-power_supp.patch @@ -0,0 +1,78 @@ +From 9ceefbf8f3b2c076976c3dc7076c6e24d80c95a4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:36:02 +0100 +Subject: power: supply: rt9455: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit e2febe375e5ea5afed92f4cd9711bde8f24ee6d2 ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: e86d69dd786e ("power_supply: Add support for Richtek RT9455 battery charger") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/1567d831e04c3e2fcb9e18dd36b7bcba4634581a.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/rt9455_charger.c | 17 +++++++++-------- + 1 file changed, 9 insertions(+), 8 deletions(-) + +diff --git a/drivers/power/supply/rt9455_charger.c b/drivers/power/supply/rt9455_charger.c +index 1ffe7f02932f6..5130d2395e88f 100644 +--- a/drivers/power/supply/rt9455_charger.c ++++ b/drivers/power/supply/rt9455_charger.c +@@ -1663,6 +1663,15 @@ static int rt9455_probe(struct i2c_client *client) + rt9455_charger_config.supplied_to = rt9455_charger_supplied_to; + rt9455_charger_config.num_supplicants = + ARRAY_SIZE(rt9455_charger_supplied_to); ++ ++ info->charger = devm_power_supply_register(dev, &rt9455_charger_desc, ++ &rt9455_charger_config); ++ if (IS_ERR(info->charger)) { ++ dev_err(dev, "Failed to register charger\n"); ++ ret = PTR_ERR(info->charger); ++ goto put_usb_notifier; ++ } ++ + ret = devm_request_threaded_irq(dev, client->irq, NULL, + rt9455_irq_handler_thread, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, +@@ -1678,14 +1687,6 @@ static int rt9455_probe(struct i2c_client *client) + goto put_usb_notifier; + } + +- info->charger = devm_power_supply_register(dev, &rt9455_charger_desc, +- &rt9455_charger_config); +- if (IS_ERR(info->charger)) { +- dev_err(dev, "Failed to register charger\n"); +- ret = PTR_ERR(info->charger); +- goto put_usb_notifier; +- } +- + return 0; + + put_usb_notifier: +-- +2.51.0 + diff --git a/queue-6.19/power-supply-sbs-battery-fix-use-after-free-in-power.patch b/queue-6.19/power-supply-sbs-battery-fix-use-after-free-in-power.patch new file mode 100644 index 0000000000..3575abb5f2 --- /dev/null +++ b/queue-6.19/power-supply-sbs-battery-fix-use-after-free-in-power.patch @@ -0,0 +1,101 @@ +From cde93254fb5ddf7ea0a4f1a2641fd6842c5ae911 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:36:02 +0100 +Subject: power: supply: sbs-battery: Fix use-after-free in + power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 8d59cf3887fbabacef53bfba473e33e8a8d9d07b ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. Keep the old behavior of +just printing a warning in case of any failures during the IRQ request +and finishing the probe successfully. + +Fixes: d2cec82c2880 ("power: sbs-battery: Request threaded irq and fix dev callback cookie") +Signed-off-by: Waqar Hameed +Reviewed-by: Phil Reid +Link: https://patch.msgid.link/0ef896e002495e615157b482d18a437af19ddcd0.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/sbs-battery.c | 36 +++++++++++++++--------------- + 1 file changed, 18 insertions(+), 18 deletions(-) + +diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c +index 943c82ee978f4..43c48196c1674 100644 +--- a/drivers/power/supply/sbs-battery.c ++++ b/drivers/power/supply/sbs-battery.c +@@ -1174,24 +1174,6 @@ static int sbs_probe(struct i2c_client *client) + + i2c_set_clientdata(client, chip); + +- if (!chip->gpio_detect) +- goto skip_gpio; +- +- irq = gpiod_to_irq(chip->gpio_detect); +- if (irq <= 0) { +- dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq); +- goto skip_gpio; +- } +- +- rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq, +- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, +- dev_name(&client->dev), chip); +- if (rc) { +- dev_warn(&client->dev, "Failed to request irq: %d\n", rc); +- goto skip_gpio; +- } +- +-skip_gpio: + /* + * Before we register, we might need to make sure we can actually talk + * to the battery. +@@ -1217,6 +1199,24 @@ static int sbs_probe(struct i2c_client *client) + return dev_err_probe(&client->dev, PTR_ERR(chip->power_supply), + "Failed to register power supply\n"); + ++ if (!chip->gpio_detect) ++ goto out; ++ ++ irq = gpiod_to_irq(chip->gpio_detect); ++ if (irq <= 0) { ++ dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq); ++ goto out; ++ } ++ ++ rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq, ++ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, ++ dev_name(&client->dev), chip); ++ if (rc) { ++ dev_warn(&client->dev, "Failed to request irq: %d\n", rc); ++ goto out; ++ } ++ ++out: + dev_info(&client->dev, + "%s: battery gas gauge device registered\n", client->name); + +-- +2.51.0 + diff --git a/queue-6.19/power-supply-wm97xx-fix-null-pointer-dereference-in-.patch b/queue-6.19/power-supply-wm97xx-fix-null-pointer-dereference-in-.patch new file mode 100644 index 0000000000..eb3fc33507 --- /dev/null +++ b/queue-6.19/power-supply-wm97xx-fix-null-pointer-dereference-in-.patch @@ -0,0 +1,98 @@ +From 0cd8d09f7a2ceb2732618e1a88811c9b333d449f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:46:24 +0100 +Subject: power: supply: wm97xx: Fix NULL pointer dereference in + power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 39fe0eac6d755ef215026518985fcf8de9360e9e ] + +In `probe()`, `request_irq()` is called before allocating/registering a +`power_supply` handle. If an interrupt is fired between the call to +`request_irq()` and `power_supply_register()`, the `power_supply` handle +will be used uninitialized in `power_supply_changed()` in +`wm97xx_bat_update()` (triggered from the interrupt handler). This will +lead to a `NULL` pointer dereference since + +Fix this racy `NULL` pointer dereference by making sure the IRQ is +requested _after_ the registration of the `power_supply` handle. Since +the IRQ is the last thing requests in the `probe()` now, remove the +error path for freeing it. Instead add one for unregistering the +`power_supply` handle when IRQ request fails. + +Fixes: 7c87942aef52 ("wm97xx_battery: Use irq to detect charger state") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/97b55f0479a932eea7213844bf66f28a974e27a2.1766270196.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/wm97xx_battery.c | 34 +++++++++++++++------------ + 1 file changed, 19 insertions(+), 15 deletions(-) + +diff --git a/drivers/power/supply/wm97xx_battery.c b/drivers/power/supply/wm97xx_battery.c +index b3b0c37a9dd2d..f00722c88c6fe 100644 +--- a/drivers/power/supply/wm97xx_battery.c ++++ b/drivers/power/supply/wm97xx_battery.c +@@ -178,12 +178,6 @@ static int wm97xx_bat_probe(struct platform_device *dev) + "failed to get charge GPIO\n"); + if (charge_gpiod) { + gpiod_set_consumer_name(charge_gpiod, "BATT CHRG"); +- ret = request_irq(gpiod_to_irq(charge_gpiod), +- wm97xx_chrg_irq, 0, +- "AC Detect", dev); +- if (ret) +- return dev_err_probe(&dev->dev, ret, +- "failed to request GPIO irq\n"); + props++; /* POWER_SUPPLY_PROP_STATUS */ + } + +@@ -199,10 +193,8 @@ static int wm97xx_bat_probe(struct platform_device *dev) + props++; /* POWER_SUPPLY_PROP_VOLTAGE_MIN */ + + prop = kcalloc(props, sizeof(*prop), GFP_KERNEL); +- if (!prop) { +- ret = -ENOMEM; +- goto err3; +- } ++ if (!prop) ++ return -ENOMEM; + + prop[i++] = POWER_SUPPLY_PROP_PRESENT; + if (charge_gpiod) +@@ -236,15 +228,27 @@ static int wm97xx_bat_probe(struct platform_device *dev) + schedule_work(&bat_work); + } else { + ret = PTR_ERR(bat_psy); +- goto err4; ++ goto free; ++ } ++ ++ if (charge_gpiod) { ++ ret = request_irq(gpiod_to_irq(charge_gpiod), wm97xx_chrg_irq, ++ 0, "AC Detect", dev); ++ if (ret) { ++ dev_err_probe(&dev->dev, ret, ++ "failed to request GPIO irq\n"); ++ goto unregister; ++ } + } + + return 0; +-err4: ++ ++unregister: ++ power_supply_unregister(bat_psy); ++ ++free: + kfree(prop); +-err3: +- if (charge_gpiod) +- free_irq(gpiod_to_irq(charge_gpiod), dev); ++ + return ret; + } + +-- +2.51.0 + diff --git a/queue-6.19/powerpc-eeh-fix-recursive-pci_lock_rescan_remove-loc.patch b/queue-6.19/powerpc-eeh-fix-recursive-pci_lock_rescan_remove-loc.patch new file mode 100644 index 0000000000..1125a41d79 --- /dev/null +++ b/queue-6.19/powerpc-eeh-fix-recursive-pci_lock_rescan_remove-loc.patch @@ -0,0 +1,275 @@ +From e84f14c0b1ead94ac1cba258f7d33efcbf8d946f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 10 Dec 2025 08:25:59 -0600 +Subject: powerpc/eeh: fix recursive pci_lock_rescan_remove locking in EEH + event handling +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Narayana Murty N + +[ Upstream commit 815a8d2feb5615ae7f0b5befd206af0b0160614c ] + +The recent commit 1010b4c012b0 ("powerpc/eeh: Make EEH driver device +hotplug safe") restructured the EEH driver to improve synchronization +with the PCI hotplug layer. + +However, it inadvertently moved pci_lock_rescan_remove() outside its +intended scope in eeh_handle_normal_event(), leading to broken PCI +error reporting and improper EEH event triggering. Specifically, +eeh_handle_normal_event() acquired pci_lock_rescan_remove() before +calling eeh_pe_bus_get(), but eeh_pe_bus_get() itself attempts to +acquire the same lock internally, causing nested locking and disrupting +normal EEH event handling paths. + +This patch adds a boolean parameter do_lock to _eeh_pe_bus_get(), +with two public wrappers: + eeh_pe_bus_get() with locking enabled. + eeh_pe_bus_get_nolock() that skips locking. + +Callers that already hold pci_lock_rescan_remove() now use +eeh_pe_bus_get_nolock() to avoid recursive lock acquisition. + +Additionally, pci_lock_rescan_remove() calls are restored to the correct +position—after eeh_pe_bus_get() and immediately before iterating affected +PEs and devices. This ensures EEH-triggered PCI removes occur under proper +bus rescan locking without recursive lock contention. + +The eeh_pe_loc_get() function has been split into two functions: + eeh_pe_loc_get(struct eeh_pe *pe) which retrieves the loc for given PE. + eeh_pe_loc_get_bus(struct pci_bus *bus) which retrieves the location + code for given bus. + +This resolves lockdep warnings such as: + +[ 84.964298] [ T928] ============================================ +[ 84.964304] [ T928] WARNING: possible recursive locking detected +[ 84.964311] [ T928] 6.18.0-rc3 #51 Not tainted +[ 84.964315] [ T928] -------------------------------------------- +[ 84.964320] [ T928] eehd/928 is trying to acquire lock: +[ 84.964324] [ T928] c000000003b29d58 (pci_rescan_remove_lock){+.+.}-{3:3}, at: pci_lock_rescan_remove+0x28/0x40 +[ 84.964342] [ T928] + but task is already holding lock: +[ 84.964347] [ T928] c000000003b29d58 (pci_rescan_remove_lock){+.+.}-{3:3}, at: pci_lock_rescan_remove+0x28/0x40 +[ 84.964357] [ T928] + other info that might help us debug this: +[ 84.964363] [ T928] Possible unsafe locking scenario: + +[ 84.964367] [ T928] CPU0 +[ 84.964370] [ T928] ---- +[ 84.964373] [ T928] lock(pci_rescan_remove_lock); +[ 84.964378] [ T928] lock(pci_rescan_remove_lock); +[ 84.964383] [ T928] + *** DEADLOCK *** + +[ 84.964388] [ T928] May be due to missing lock nesting notation + +[ 84.964393] [ T928] 1 lock held by eehd/928: +[ 84.964397] [ T928] #0: c000000003b29d58 (pci_rescan_remove_lock){+.+.}-{3:3}, at: pci_lock_rescan_remove+0x28/0x40 +[ 84.964408] [ T928] + stack backtrace: +[ 84.964414] [ T928] CPU: 2 UID: 0 PID: 928 Comm: eehd Not tainted 6.18.0-rc3 #51 VOLUNTARY +[ 84.964417] [ T928] Hardware name: IBM,9080-HEX POWER10 (architected) 0x800200 0xf000006 of:IBM,FW1060.00 (NH1060_022) hv:phyp pSeries +[ 84.964419] [ T928] Call Trace: +[ 84.964420] [ T928] [c0000011a7157990] [c000000001705de4] dump_stack_lvl+0xc8/0x130 (unreliable) +[ 84.964424] [ T928] [c0000011a71579d0] [c0000000002f66e0] print_deadlock_bug+0x430/0x440 +[ 84.964428] [ T928] [c0000011a7157a70] [c0000000002fd0c0] __lock_acquire+0x1530/0x2d80 +[ 84.964431] [ T928] [c0000011a7157ba0] [c0000000002fea54] lock_acquire+0x144/0x410 +[ 84.964433] [ T928] [c0000011a7157cb0] [c0000011a7157cb0] __mutex_lock+0xf4/0x1050 +[ 84.964436] [ T928] [c0000011a7157e00] [c000000000de21d8] pci_lock_rescan_remove+0x28/0x40 +[ 84.964439] [ T928] [c0000011a7157e20] [c00000000004ed98] eeh_pe_bus_get+0x48/0xc0 +[ 84.964442] [ T928] [c0000011a7157e50] [c000000000050434] eeh_handle_normal_event+0x64/0xa60 +[ 84.964446] [ T928] [c0000011a7157f30] [c000000000051de8] eeh_event_handler+0xf8/0x190 +[ 84.964450] [ T928] [c0000011a7157f90] [c0000000002747ac] kthread+0x16c/0x180 +[ 84.964453] [ T928] [c0000011a7157fe0] [c00000000000ded8] start_kernel_thread+0x14/0x18 + + +Fixes: 1010b4c012b0 ("powerpc/eeh: Make EEH driver device hotplug safe") +Signed-off-by: Narayana Murty N +Reviewed-by: Sourabh Jain +Reviewed-by: Mahesh Salgaonkar +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/20251210142559.8874-1-nnmlinux@linux.ibm.com +Signed-off-by: Sasha Levin +--- + arch/powerpc/include/asm/eeh.h | 2 + + arch/powerpc/kernel/eeh_driver.c | 11 ++--- + arch/powerpc/kernel/eeh_pe.c | 74 ++++++++++++++++++++++++++++++-- + 3 files changed, 78 insertions(+), 9 deletions(-) + +diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h +index 5e34611de9ef4..b7ebb4ac2c710 100644 +--- a/arch/powerpc/include/asm/eeh.h ++++ b/arch/powerpc/include/asm/eeh.h +@@ -289,6 +289,8 @@ void eeh_pe_dev_traverse(struct eeh_pe *root, + void eeh_pe_restore_bars(struct eeh_pe *pe); + const char *eeh_pe_loc_get(struct eeh_pe *pe); + struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe); ++const char *eeh_pe_loc_get_bus(struct pci_bus *bus); ++struct pci_bus *eeh_pe_bus_get_nolock(struct eeh_pe *pe); + + void eeh_show_enabled(void); + int __init eeh_init(struct eeh_ops *ops); +diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c +index ef78ff77cf8f2..028f691585323 100644 +--- a/arch/powerpc/kernel/eeh_driver.c ++++ b/arch/powerpc/kernel/eeh_driver.c +@@ -846,7 +846,7 @@ void eeh_handle_normal_event(struct eeh_pe *pe) + + pci_lock_rescan_remove(); + +- bus = eeh_pe_bus_get(pe); ++ bus = eeh_pe_bus_get_nolock(pe); + if (!bus) { + pr_err("%s: Cannot find PCI bus for PHB#%x-PE#%x\n", + __func__, pe->phb->global_number, pe->addr); +@@ -886,14 +886,15 @@ void eeh_handle_normal_event(struct eeh_pe *pe) + /* Log the event */ + if (pe->type & EEH_PE_PHB) { + pr_err("EEH: Recovering PHB#%x, location: %s\n", +- pe->phb->global_number, eeh_pe_loc_get(pe)); ++ pe->phb->global_number, eeh_pe_loc_get_bus(bus)); + } else { + struct eeh_pe *phb_pe = eeh_phb_pe_get(pe->phb); + + pr_err("EEH: Recovering PHB#%x-PE#%x\n", + pe->phb->global_number, pe->addr); + pr_err("EEH: PE location: %s, PHB location: %s\n", +- eeh_pe_loc_get(pe), eeh_pe_loc_get(phb_pe)); ++ eeh_pe_loc_get_bus(bus), ++ eeh_pe_loc_get_bus(eeh_pe_bus_get_nolock(phb_pe))); + } + + #ifdef CONFIG_STACKTRACE +@@ -1098,7 +1099,7 @@ void eeh_handle_normal_event(struct eeh_pe *pe) + eeh_pe_state_clear(pe, EEH_PE_PRI_BUS, true); + eeh_pe_dev_mode_mark(pe, EEH_DEV_REMOVED); + +- bus = eeh_pe_bus_get(pe); ++ bus = eeh_pe_bus_get_nolock(pe); + if (bus) + pci_hp_remove_devices(bus); + else +@@ -1222,7 +1223,7 @@ void eeh_handle_special_event(void) + (phb_pe->state & EEH_PE_RECOVERING)) + continue; + +- bus = eeh_pe_bus_get(phb_pe); ++ bus = eeh_pe_bus_get_nolock(phb_pe); + if (!bus) { + pr_err("%s: Cannot find PCI bus for " + "PHB#%x-PE#%x\n", +diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c +index e740101fadf3b..040e8f69a4aa8 100644 +--- a/arch/powerpc/kernel/eeh_pe.c ++++ b/arch/powerpc/kernel/eeh_pe.c +@@ -812,6 +812,24 @@ void eeh_pe_restore_bars(struct eeh_pe *pe) + const char *eeh_pe_loc_get(struct eeh_pe *pe) + { + struct pci_bus *bus = eeh_pe_bus_get(pe); ++ return eeh_pe_loc_get_bus(bus); ++} ++ ++/** ++ * eeh_pe_loc_get_bus - Retrieve location code binding to the given PCI bus ++ * @bus: PCI bus ++ * ++ * Retrieve the location code associated with the given PCI bus. If the bus ++ * is a root bus, the location code is fetched from the PHB device tree node ++ * or root port. Otherwise, the location code is obtained from the device ++ * tree node of the upstream bridge of the bus. The function walks up the ++ * bus hierarchy if necessary, checking each node for the appropriate ++ * location code property ("ibm,io-base-loc-code" for root buses, ++ * "ibm,slot-location-code" for others). If no location code is found, ++ * returns "N/A". ++ */ ++const char *eeh_pe_loc_get_bus(struct pci_bus *bus) ++{ + struct device_node *dn; + const char *loc = NULL; + +@@ -838,8 +856,9 @@ const char *eeh_pe_loc_get(struct eeh_pe *pe) + } + + /** +- * eeh_pe_bus_get - Retrieve PCI bus according to the given PE ++ * _eeh_pe_bus_get - Retrieve PCI bus according to the given PE + * @pe: EEH PE ++ * @do_lock: Is the caller already held the pci_lock_rescan_remove? + * + * Retrieve the PCI bus according to the given PE. Basically, + * there're 3 types of PEs: PHB/Bus/Device. For PHB PE, the +@@ -847,7 +866,7 @@ const char *eeh_pe_loc_get(struct eeh_pe *pe) + * returned for BUS PE. However, we don't have associated PCI + * bus for DEVICE PE. + */ +-struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe) ++static struct pci_bus *_eeh_pe_bus_get(struct eeh_pe *pe, bool do_lock) + { + struct eeh_dev *edev; + struct pci_dev *pdev; +@@ -862,11 +881,58 @@ struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe) + + /* Retrieve the parent PCI bus of first (top) PCI device */ + edev = list_first_entry_or_null(&pe->edevs, struct eeh_dev, entry); +- pci_lock_rescan_remove(); ++ if (do_lock) ++ pci_lock_rescan_remove(); + pdev = eeh_dev_to_pci_dev(edev); + if (pdev) + bus = pdev->bus; +- pci_unlock_rescan_remove(); ++ if (do_lock) ++ pci_unlock_rescan_remove(); + + return bus; + } ++ ++/** ++ * eeh_pe_bus_get - Retrieve PCI bus associated with the given EEH PE, locking ++ * if needed ++ * @pe: Pointer to the EEH PE ++ * ++ * This function is a wrapper around _eeh_pe_bus_get(), which retrieves the PCI ++ * bus associated with the provided EEH PE structure. It acquires the PCI ++ * rescans lock to ensure safe access to shared data during the retrieval ++ * process. This function should be used when the caller requires the PCI bus ++ * while holding the rescan/remove lock, typically during operations that modify ++ * or inspect PCIe device state in a safe manner. ++ * ++ * RETURNS: ++ * A pointer to the PCI bus associated with the EEH PE, or NULL if none found. ++ */ ++ ++struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe) ++{ ++ return _eeh_pe_bus_get(pe, true); ++} ++ ++/** ++ * eeh_pe_bus_get_nolock - Retrieve PCI bus associated with the given EEH PE ++ * without locking ++ * @pe: Pointer to the EEH PE ++ * ++ * This function is a variant of _eeh_pe_bus_get() that retrieves the PCI bus ++ * associated with the specified EEH PE without acquiring the ++ * pci_lock_rescan_remove lock. It should only be used when the caller can ++ * guarantee safe access to PE structures without the need for that lock, ++ * typically in contexts where the lock is already held locking is otherwise ++ * managed. ++ * ++ * RETURNS: ++ * pointer to the PCI bus associated with the EEH PE, or NULL if none is found. ++ * ++ * NOTE: ++ * Use this function carefully to avoid race conditions and data corruption. ++ */ ++ ++struct pci_bus *eeh_pe_bus_get_nolock(struct eeh_pe *pe) ++{ ++ return _eeh_pe_bus_get(pe, false); ++} +-- +2.51.0 + diff --git a/queue-6.19/powerpc-uaccess-move-barrier_nospec-out-of-allow_rea.patch b/queue-6.19/powerpc-uaccess-move-barrier_nospec-out-of-allow_rea.patch new file mode 100644 index 0000000000..14e76f8f5d --- /dev/null +++ b/queue-6.19/powerpc-uaccess-move-barrier_nospec-out-of-allow_rea.patch @@ -0,0 +1,98 @@ +From f498eb5ea5e29951547fdc1cd139fd601f1779c1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Dec 2025 12:20:49 +0100 +Subject: powerpc/uaccess: Move barrier_nospec() out of + allow_read_{from/write}_user() + +From: Christophe Leroy + +[ Upstream commit 5fbc09eb0b4f4b1a4b33abebacbeee0d29f195e9 ] + +Commit 74e19ef0ff80 ("uaccess: Add speculation barrier to +copy_from_user()") added a redundant barrier_nospec() in +copy_from_user(), because powerpc is already calling +barrier_nospec() in allow_read_from_user() and +allow_read_write_user(). But on other architectures that +call to barrier_nospec() was missing. So change powerpc +instead of reverting the above commit and having to fix +other architectures one by one. This is now possible +because barrier_nospec() has also been added in +copy_from_user_iter(). + +Move barrier_nospec() out of allow_read_from_user() and +allow_read_write_user(). This will also allow reuse of those +functions when implementing masked user access which doesn't +require barrier_nospec(). + +Don't add it back in raw_copy_from_user() as it is already called +by copy_from_user() and copy_from_user_iter(). + +Fixes: 74e19ef0ff80 ("uaccess: Add speculation barrier to copy_from_user()") +Signed-off-by: Christophe Leroy +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/f29612105c5fcbc8ceb7303808ddc1a781f0f6b5.1766574657.git.chleroy@kernel.org +Signed-off-by: Sasha Levin +--- + arch/powerpc/include/asm/kup.h | 2 -- + arch/powerpc/include/asm/uaccess.h | 4 ++++ + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/arch/powerpc/include/asm/kup.h b/arch/powerpc/include/asm/kup.h +index dab63b82a8d4f..f2009d7c8cfa7 100644 +--- a/arch/powerpc/include/asm/kup.h ++++ b/arch/powerpc/include/asm/kup.h +@@ -134,7 +134,6 @@ static __always_inline void kuap_assert_locked(void) + + static __always_inline void allow_read_from_user(const void __user *from, unsigned long size) + { +- barrier_nospec(); + allow_user_access(NULL, from, size, KUAP_READ); + } + +@@ -146,7 +145,6 @@ static __always_inline void allow_write_to_user(void __user *to, unsigned long s + static __always_inline void allow_read_write_user(void __user *to, const void __user *from, + unsigned long size) + { +- barrier_nospec(); + allow_user_access(to, from, size, KUAP_READ_WRITE); + } + +diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h +index 784a00e681fa3..3e622e647d622 100644 +--- a/arch/powerpc/include/asm/uaccess.h ++++ b/arch/powerpc/include/asm/uaccess.h +@@ -301,6 +301,7 @@ do { \ + __typeof__(sizeof(*(ptr))) __gu_size = sizeof(*(ptr)); \ + \ + might_fault(); \ ++ barrier_nospec(); \ + allow_read_from_user(__gu_addr, __gu_size); \ + __get_user_size_allowed(__gu_val, __gu_addr, __gu_size, __gu_err); \ + prevent_read_from_user(__gu_addr, __gu_size); \ +@@ -329,6 +330,7 @@ raw_copy_in_user(void __user *to, const void __user *from, unsigned long n) + { + unsigned long ret; + ++ barrier_nospec(); + allow_read_write_user(to, from, n); + ret = __copy_tofrom_user(to, from, n); + prevent_read_write_user(to, from, n); +@@ -415,6 +417,7 @@ static __must_check __always_inline bool user_access_begin(const void __user *pt + + might_fault(); + ++ barrier_nospec(); + allow_read_write_user((void __user *)ptr, ptr, len); + return true; + } +@@ -431,6 +434,7 @@ user_read_access_begin(const void __user *ptr, size_t len) + + might_fault(); + ++ barrier_nospec(); + allow_read_from_user(ptr, len); + return true; + } +-- +2.51.0 + diff --git a/queue-6.19/printk-vt-fbcon-remove-console_conditional_schedule.patch b/queue-6.19/printk-vt-fbcon-remove-console_conditional_schedule.patch new file mode 100644 index 0000000000..44c0ce15a5 --- /dev/null +++ b/queue-6.19/printk-vt-fbcon-remove-console_conditional_schedule.patch @@ -0,0 +1,176 @@ +From fa53eabe488d48c2752e37735ff6db38d4e9956f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 19:08:36 +0100 +Subject: printk, vt, fbcon: Remove console_conditional_schedule() + +From: Sebastian Andrzej Siewior + +[ Upstream commit 8e9bf8b9e8c0a3e1ef16dd48260a113f65ed01d2 ] + +do_con_write(), fbcon_redraw.*() invoke console_conditional_schedule() +which is a conditional scheduling point based on printk's internal +variables console_may_schedule. It may only be used if the console lock +is acquired for instance via console_lock() or console_trylock(). + +Prinkt sets the internal variable to 1 (and allows to schedule) +if the console lock has been acquired via console_lock(). The trylock +does not allow it. + +The console_conditional_schedule() invocation in do_con_write() is +invoked shortly before console_unlock(). +The console_conditional_schedule() invocation in fbcon_redraw.*() +original from fbcon_scroll() / vt's con_scroll() which originate from a +line feed. + +In console_unlock() the variable is set to 0 (forbids to schedule) and +it tries to schedule while making progress printing. This is brand new +compared to when console_conditional_schedule() was added in v2.4.9.11. + +In v2.6.38-rc3, console_unlock() (started its existence) iterated over +all consoles and flushed them with disabled interrupts. A scheduling +attempt here was not possible, it relied that a long print scheduled +before console_unlock(). + +Since commit 8d91f8b15361d ("printk: do cond_resched() between lines +while outputting to consoles"), which appeared in v4.5-rc1, +console_unlock() attempts to schedule if it was allowed to schedule +while during console_lock(). Each record is idealy one line so after +every line feed. + +This console_conditional_schedule() is also only relevant on +PREEMPT_NONE and PREEMPT_VOLUNTARY builds. In other configurations +cond_resched() becomes a nop and has no impact. + +I'm bringing this all up just proof that it is not required anymore. It +becomes a problem on a PREEMPT_RT build with debug code enabled because +that might_sleep() in cond_resched() remains and triggers a warnings. +This is due to + + legacy_kthread_func-> console_flush_one_record -> vt_console_print-> lf + -> con_scroll -> fbcon_scroll + +and vt_console_print() acquires a spinlock_t which does not allow a +voluntary schedule. There is no need to fb_scroll() to schedule since +console_flush_one_record() attempts to schedule after each line. +!PREEMPT_RT is not affected because the legacy printing thread is only +enabled on PREEMPT_RT builds. + +Therefore I suggest to remove console_conditional_schedule(). + +Cc: Simona Vetter +Cc: Helge Deller +Cc: linux-fbdev@vger.kernel.org +Cc: dri-devel@lists.freedesktop.org +Fixes: 5f53ca3ff83b4 ("printk: Implement legacy printer kthread for PREEMPT_RT") +Signed-off-by: Sebastian Andrzej Siewior +Acked-by: Greg Kroah-Hartman +Acked-by: Petr Mladek # from printk() POV +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/tty/vt/vt.c | 1 - + drivers/video/fbdev/core/fbcon.c | 6 ------ + include/linux/console.h | 1 - + kernel/printk/printk.c | 16 ---------------- + 4 files changed, 24 deletions(-) + +diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c +index 59b4b5e126ba1..53daf7614b1af 100644 +--- a/drivers/tty/vt/vt.c ++++ b/drivers/tty/vt/vt.c +@@ -3236,7 +3236,6 @@ static int do_con_write(struct tty_struct *tty, const u8 *buf, int count) + goto rescan_last_byte; + } + con_flush(vc, &draw); +- console_conditional_schedule(); + notify_update(vc); + + return n; +diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c +index 7be9e865325d9..36dd9d4a46ae0 100644 +--- a/drivers/video/fbdev/core/fbcon.c ++++ b/drivers/video/fbdev/core/fbcon.c +@@ -1607,12 +1607,10 @@ static void fbcon_redraw_move(struct vc_data *vc, struct fbcon_display *p, + start = s; + } + } +- console_conditional_schedule(); + s++; + } while (s < le); + if (s > start) + fbcon_putcs(vc, start, s - start, dy, x); +- console_conditional_schedule(); + dy++; + } + } +@@ -1648,14 +1646,12 @@ static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info, + } + + scr_writew(c, d); +- console_conditional_schedule(); + s++; + d++; + } while (s < le); + if (s > start) + par->bitops->bmove(vc, info, line + ycount, x, line, x, 1, + s - start); +- console_conditional_schedule(); + if (ycount > 0) + line++; + else { +@@ -1703,13 +1699,11 @@ static void fbcon_redraw(struct vc_data *vc, int line, int count, int offset) + } + } + scr_writew(c, d); +- console_conditional_schedule(); + s++; + d++; + } while (s < le); + if (s > start) + fbcon_putcs(vc, start, s - start, line, x); +- console_conditional_schedule(); + if (offset > 0) + line++; + else { +diff --git a/include/linux/console.h b/include/linux/console.h +index fc9f5c5c1b04c..ec506d3501965 100644 +--- a/include/linux/console.h ++++ b/include/linux/console.h +@@ -697,7 +697,6 @@ extern int unregister_console(struct console *); + extern void console_lock(void); + extern int console_trylock(void); + extern void console_unlock(void); +-extern void console_conditional_schedule(void); + extern void console_unblank(void); + extern void console_flush_on_panic(enum con_flush_mode mode); + extern struct tty_driver *console_device(int *); +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index 1d765ad242b82..9296bf41aa49d 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -3362,22 +3362,6 @@ void console_unlock(void) + } + EXPORT_SYMBOL(console_unlock); + +-/** +- * console_conditional_schedule - yield the CPU if required +- * +- * If the console code is currently allowed to sleep, and +- * if this CPU should yield the CPU to another task, do +- * so here. +- * +- * Must be called within console_lock();. +- */ +-void __sched console_conditional_schedule(void) +-{ +- if (console_may_schedule) +- cond_resched(); +-} +-EXPORT_SYMBOL(console_conditional_schedule); +- + void console_unblank(void) + { + bool found_unblank = false; +-- +2.51.0 + diff --git a/queue-6.19/procfs-fix-missing-rcu-protection-when-reading-real_.patch b/queue-6.19/procfs-fix-missing-rcu-protection-when-reading-real_.patch new file mode 100644 index 0000000000..9a5f96565c --- /dev/null +++ b/queue-6.19/procfs-fix-missing-rcu-protection-when-reading-real_.patch @@ -0,0 +1,59 @@ +From 2a91970dd68d8a6ef4de951b679f76c0ec2abb8e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 16:30:07 +0800 +Subject: procfs: fix missing RCU protection when reading real_parent in + do_task_stat() + +From: Jinliang Zheng + +[ Upstream commit 76149d53502cf17ef3ae454ff384551236fba867 ] + +When reading /proc/[pid]/stat, do_task_stat() accesses task->real_parent +without proper RCU protection, which leads to: + + cpu 0 cpu 1 + ----- ----- + do_task_stat + var = task->real_parent + release_task + call_rcu(delayed_put_task_struct) + task_tgid_nr_ns(var) + rcu_read_lock <--- Too late to protect task->real_parent! + task_pid_ptr <--- UAF! + rcu_read_unlock + +This patch uses task_ppid_nr_ns() instead of task_tgid_nr_ns() to add +proper RCU protection for accessing task->real_parent. + +Link: https://lkml.kernel.org/r/20260128083007.3173016-1-alexjlzheng@tencent.com +Fixes: 06fffb1267c9 ("do_task_stat: don't take rcu_read_lock()") +Signed-off-by: Jinliang Zheng +Acked-by: Oleg Nesterov +Cc: David Hildenbrand +Cc: Ingo Molnar +Cc: Lorenzo Stoakes +Cc: Mateusz Guzik +Cc: ruippan +Cc: Usama Arif +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/proc/array.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/proc/array.c b/fs/proc/array.c +index 42932f88141a9..5571177e0435d 100644 +--- a/fs/proc/array.c ++++ b/fs/proc/array.c +@@ -528,7 +528,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, + } + + sid = task_session_nr_ns(task, ns); +- ppid = task_tgid_nr_ns(task->real_parent, ns); ++ ppid = task_ppid_nr_ns(task, ns); + pgid = task_pgrp_nr_ns(task, ns); + + unlock_task_sighand(task, &flags); +-- +2.51.0 + diff --git a/queue-6.19/pstore-ram-fix-buffer-overflow-in-persistent_ram_sav.patch b/queue-6.19/pstore-ram-fix-buffer-overflow-in-persistent_ram_sav.patch new file mode 100644 index 0000000000..a49b497818 --- /dev/null +++ b/queue-6.19/pstore-ram-fix-buffer-overflow-in-persistent_ram_sav.patch @@ -0,0 +1,92 @@ +From 66f1a44295438838dfa9b7bc1ec2f14fd5be35da Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 1 Feb 2026 13:22:40 +0000 +Subject: pstore/ram: fix buffer overflow in persistent_ram_save_old() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Sai Ritvik Tanksalkar + +[ Upstream commit 5669645c052f235726a85f443769b6fc02f66762 ] + +persistent_ram_save_old() can be called multiple times for the same +persistent_ram_zone (e.g., via ramoops_pstore_read -> ramoops_get_next_prz +for PSTORE_TYPE_DMESG records). + +Currently, the function only allocates prz->old_log when it is NULL, +but it unconditionally updates prz->old_log_size to the current buffer +size and then performs memcpy_fromio() using this new size. If the +buffer size has grown since the first allocation (which can happen +across different kernel boot cycles), this leads to: + +1. A heap buffer overflow (OOB write) in the memcpy_fromio() calls +2. A subsequent OOB read when ramoops_pstore_read() accesses the buffer + using the incorrect (larger) old_log_size + +The KASAN splat would look similar to: + BUG: KASAN: slab-out-of-bounds in ramoops_pstore_read+0x... + Read of size N at addr ... by task ... + +The conditions are likely extremely hard to hit: + + 0. Crash with a ramoops write of less-than-record-max-size bytes. + 1. Reboot: ramoops registers, pstore_get_records(0) reads old crash, + allocates old_log with size X + 2. Crash handler registered, timer started (if pstore_update_ms >= 0) + 3. Oops happens (non-fatal, system continues) + 4. pstore_dump() writes oops via ramoops_pstore_write() size Y (>X) + 5. pstore_new_entry = 1, pstore_timer_kick() called + 6. System continues running (not a panic oops) + 7. Timer fires after pstore_update_ms milliseconds + 8. pstore_timefunc() → schedule_work() → pstore_dowork() → pstore_get_records(1) + 9. ramoops_get_next_prz() → persistent_ram_save_old() + 10. buffer_size() returns Y, but old_log is X bytes + 11. Y > X: memcpy_fromio() overflows heap + + Requirements: + - a prior crash record exists that did not fill the record size + (almost impossible since the crash handler writes as much as it + can possibly fit into the record, capped by max record size and + the kmsg buffer almost always exceeds the max record size) + - pstore_update_ms >= 0 (disabled by default) + - Non-fatal oops (system survives) + +Free and reallocate the buffer when the new size differs from the +previously allocated size. This ensures old_log always has sufficient +space for the data being copied. + +Fixes: 201e4aca5aa1 ("pstore/ram: Should update old dmesg buffer before reading") +Signed-off-by: Sai Ritvik Tanksalkar +Link: https://patch.msgid.link/20260201132240.2948732-1-stanksal@purdue.edu +Signed-off-by: Kees Cook +Signed-off-by: Sasha Levin +--- + fs/pstore/ram_core.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c +index f1848cdd6d348..c9eaacdec37e4 100644 +--- a/fs/pstore/ram_core.c ++++ b/fs/pstore/ram_core.c +@@ -298,6 +298,17 @@ void persistent_ram_save_old(struct persistent_ram_zone *prz) + if (!size) + return; + ++ /* ++ * If the existing buffer is differently sized, free it so a new ++ * one is allocated. This can happen when persistent_ram_save_old() ++ * is called early in boot and later for a timer-triggered ++ * survivable crash when the crash dumps don't match in size ++ * (which would be extremely unlikely given kmsg buffers usually ++ * exceed prz buffer sizes). ++ */ ++ if (prz->old_log && prz->old_log_size != size) ++ persistent_ram_free_old(prz); ++ + if (!prz->old_log) { + persistent_ram_ecc_old(prz); + prz->old_log = kvzalloc(size, GFP_KERNEL); +-- +2.51.0 + diff --git a/queue-6.19/pwm-tiehrpwm-enable-pwmchip-s-parent-device-before-s.patch b/queue-6.19/pwm-tiehrpwm-enable-pwmchip-s-parent-device-before-s.patch new file mode 100644 index 0000000000..3f97a03752 --- /dev/null +++ b/queue-6.19/pwm-tiehrpwm-enable-pwmchip-s-parent-device-before-s.patch @@ -0,0 +1,69 @@ +From 6975eda655c6944f48cb53f0ae7b828d87276b83 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 11:41:34 +0530 +Subject: pwm: tiehrpwm: Enable pwmchip's parent device before setting + configuration +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Gokul Praveen + +[ Upstream commit 75e7ed52ac7c1da90f304dcda2906636404df921 ] + +The period and duty cycle configurations on J7200 and J784S4 SoCs +does not get reflected after setting them using sysfs nodes. +This is because at the end of ehrpwm_pwm_config function, +the put_sync function is called which resets the hardware. + +Hold the PWM controller out of low-power mode during .apply() to +make sure it accepts the writes to its registers. + +This renders the calls to pm_runtime_get_sync() and +pm_runtime_put_sync() in ehrpwm_pwm_config() into no-ops, so +these can be dropped. + +Fixes: 5f027d9b83db ("pwm: tiehrpwm: Implement .apply() callback") +Signed-off-by: Gokul Praveen +Suggested-by: Uwe Kleine-König +Link: https://patch.msgid.link/20260121061134.15466-1-g-praveen@ti.com +Signed-off-by: Uwe Kleine-König +Signed-off-by: Sasha Levin +--- + drivers/pwm/pwm-tiehrpwm.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c +index 7a86cb090f76f..2533c95b0ba9d 100644 +--- a/drivers/pwm/pwm-tiehrpwm.c ++++ b/drivers/pwm/pwm-tiehrpwm.c +@@ -237,8 +237,6 @@ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, + if (period_cycles < 1) + period_cycles = 1; + +- pm_runtime_get_sync(pwmchip_parent(chip)); +- + /* Update clock prescaler values */ + ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_CLKDIV_MASK, tb_divval); + +@@ -290,8 +288,6 @@ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, + if (!(duty_cycles > period_cycles)) + ehrpwm_write(pc->mmio_base, cmp_reg, duty_cycles); + +- pm_runtime_put_sync(pwmchip_parent(chip)); +- + return 0; + } + +@@ -378,6 +374,8 @@ static int ehrpwm_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + int err; + bool enabled = pwm->state.enabled; + ++ guard(pm_runtime_active)(pwmchip_parent(chip)); ++ + if (state->polarity != pwm->state.polarity) { + if (enabled) { + ehrpwm_pwm_disable(chip, pwm); +-- +2.51.0 + diff --git a/queue-6.19/quota-fix-livelock-between-quotactl-and-freeze_super.patch b/queue-6.19/quota-fix-livelock-between-quotactl-and-freeze_super.patch new file mode 100644 index 0000000000..9ac7f8172d --- /dev/null +++ b/queue-6.19/quota-fix-livelock-between-quotactl-and-freeze_super.patch @@ -0,0 +1,73 @@ +From 3e3ab66ddbb695d16c0854f624133577ba45b37d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 21:31:03 +0000 +Subject: quota: fix livelock between quotactl and freeze_super + +From: Abhishek Bapat + +[ Upstream commit 77449e453dfc006ad738dec55374c4cbc056fd39 ] + +When a filesystem is frozen, quotactl_block() enters a retry loop +waiting for the filesystem to thaw. It acquires s_umount, checks the +freeze state, drops s_umount and uses sb_start_write() - sb_end_write() +pair to wait for the unfreeze. + +However, this retry loop can trigger a livelock issue, specifically on +kernels with preemption disabled. + +The mechanism is as follows: +1. freeze_super() sets SB_FREEZE_WRITE and calls sb_wait_write(). +2. sb_wait_write() calls percpu_down_write(), which initiates + synchronize_rcu(). +3. Simultaneously, quotactl_block() spins in its retry loop, immediately + executing the sb_start_write() - sb_end_write() pair. +4. Because the kernel is non-preemptible and the loop contains no + scheduling points, quotactl_block() never yields the CPU. This + prevents that CPU from reaching an RCU quiescent state. +5. synchronize_rcu() in the freezer thread waits indefinitely for the + quotactl_block() CPU to report a quiescent state. +6. quotactl_block() spins indefinitely waiting for the freezer to + advance, which it cannot do as it is blocked on the RCU sync. + +This results in a hang of the freezer process and 100% CPU usage by the +quota process. + +While this can occur intermittently on multi-core systems, it is +reliably reproducing on a node with the following script, running both +the freezer and the quota toggle on the same CPU: + + # mkfs.ext4 -O quota /dev/sda 2g && mkdir a_mount + # mount /dev/sda -o quota,usrquota,grpquota a_mount + # taskset -c 3 bash -c "while true; do xfs_freeze -f a_mount; \ + xfs_freeze -u a_mount; done" & + # taskset -c 3 bash -c "while true; do quotaon a_mount; \ + quotaoff a_mount; done" & + +Adding cond_resched() to the retry loop fixes the issue. It acts as an +RCU quiescent state, allowing synchronize_rcu() in percpu_down_write() +to complete. + +Fixes: 576215cffdef ("fs: Drop wait_unfrozen wait queue") +Signed-off-by: Abhishek Bapat +Link: https://patch.msgid.link/20260115213103.1089129-1-abhishekbapat@google.com +Signed-off-by: Jan Kara +Signed-off-by: Sasha Levin +--- + fs/quota/quota.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/quota/quota.c b/fs/quota/quota.c +index 7c2b75a444852..de4379a9c7920 100644 +--- a/fs/quota/quota.c ++++ b/fs/quota/quota.c +@@ -899,6 +899,7 @@ static struct super_block *quotactl_block(const char __user *special, int cmd) + sb_start_write(sb); + sb_end_write(sb); + put_super(sb); ++ cond_resched(); + goto retry; + } + return sb; +-- +2.51.0 + diff --git a/queue-6.19/rcu-fix-rcu_read_unlock-deadloop-due-to-softirq.patch b/queue-6.19/rcu-fix-rcu_read_unlock-deadloop-due-to-softirq.patch new file mode 100644 index 0000000000..901a5d11b7 --- /dev/null +++ b/queue-6.19/rcu-fix-rcu_read_unlock-deadloop-due-to-softirq.patch @@ -0,0 +1,168 @@ +From f9cc05f218849f063b99a9c8fd50e9badaad4e29 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 1 Jan 2026 11:34:10 -0500 +Subject: rcu: Fix rcu_read_unlock() deadloop due to softirq + +From: Yao Kai + +[ Upstream commit d41e37f26b3157b3f1d10223863519a943aa239b ] + +Commit 5f5fa7ea89dc ("rcu: Don't use negative nesting depth in +__rcu_read_unlock()") removes the recursion-protection code from +__rcu_read_unlock(). Therefore, we could invoke the deadloop in +raise_softirq_irqoff() with ftrace enabled as follows: + +WARNING: CPU: 0 PID: 0 at kernel/trace/trace.c:3021 __ftrace_trace_stack.constprop.0+0x172/0x180 +Modules linked in: my_irq_work(O) +CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Tainted: G O 6.18.0-rc7-dirty #23 PREEMPT(full) +Tainted: [O]=OOT_MODULE +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014 +RIP: 0010:__ftrace_trace_stack.constprop.0+0x172/0x180 +RSP: 0018:ffffc900000034a8 EFLAGS: 00010002 +RAX: 0000000000000000 RBX: 0000000000000004 RCX: 0000000000000000 +RDX: 0000000000000003 RSI: ffffffff826d7b87 RDI: ffffffff826e9329 +RBP: 0000000000090009 R08: 0000000000000005 R09: ffffffff82afbc4c +R10: 0000000000000008 R11: 0000000000011d7a R12: 0000000000000000 +R13: ffff888003874100 R14: 0000000000000003 R15: ffff8880038c1054 +FS: 0000000000000000(0000) GS:ffff8880fa8ea000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 000055b31fa7f540 CR3: 00000000078f4005 CR4: 0000000000770ef0 +PKRU: 55555554 +Call Trace: + + trace_buffer_unlock_commit_regs+0x6d/0x220 + trace_event_buffer_commit+0x5c/0x260 + trace_event_raw_event_softirq+0x47/0x80 + raise_softirq_irqoff+0x6e/0xa0 + rcu_read_unlock_special+0xb1/0x160 + unwind_next_frame+0x203/0x9b0 + __unwind_start+0x15d/0x1c0 + arch_stack_walk+0x62/0xf0 + stack_trace_save+0x48/0x70 + __ftrace_trace_stack.constprop.0+0x144/0x180 + trace_buffer_unlock_commit_regs+0x6d/0x220 + trace_event_buffer_commit+0x5c/0x260 + trace_event_raw_event_softirq+0x47/0x80 + raise_softirq_irqoff+0x6e/0xa0 + rcu_read_unlock_special+0xb1/0x160 + unwind_next_frame+0x203/0x9b0 + __unwind_start+0x15d/0x1c0 + arch_stack_walk+0x62/0xf0 + stack_trace_save+0x48/0x70 + __ftrace_trace_stack.constprop.0+0x144/0x180 + trace_buffer_unlock_commit_regs+0x6d/0x220 + trace_event_buffer_commit+0x5c/0x260 + trace_event_raw_event_softirq+0x47/0x80 + raise_softirq_irqoff+0x6e/0xa0 + rcu_read_unlock_special+0xb1/0x160 + unwind_next_frame+0x203/0x9b0 + __unwind_start+0x15d/0x1c0 + arch_stack_walk+0x62/0xf0 + stack_trace_save+0x48/0x70 + __ftrace_trace_stack.constprop.0+0x144/0x180 + trace_buffer_unlock_commit_regs+0x6d/0x220 + trace_event_buffer_commit+0x5c/0x260 + trace_event_raw_event_softirq+0x47/0x80 + raise_softirq_irqoff+0x6e/0xa0 + rcu_read_unlock_special+0xb1/0x160 + __is_insn_slot_addr+0x54/0x70 + kernel_text_address+0x48/0xc0 + __kernel_text_address+0xd/0x40 + unwind_get_return_address+0x1e/0x40 + arch_stack_walk+0x9c/0xf0 + stack_trace_save+0x48/0x70 + __ftrace_trace_stack.constprop.0+0x144/0x180 + trace_buffer_unlock_commit_regs+0x6d/0x220 + trace_event_buffer_commit+0x5c/0x260 + trace_event_raw_event_softirq+0x47/0x80 + __raise_softirq_irqoff+0x61/0x80 + __flush_smp_call_function_queue+0x115/0x420 + __sysvec_call_function_single+0x17/0xb0 + sysvec_call_function_single+0x8c/0xc0 + + +Commit b41642c87716 ("rcu: Fix rcu_read_unlock() deadloop due to IRQ work") +fixed the infinite loop in rcu_read_unlock_special() for IRQ work by +setting a flag before calling irq_work_queue_on(). We fix this issue by +setting the same flag before calling raise_softirq_irqoff() and rename the +flag to defer_qs_pending for more common. + +Fixes: 5f5fa7ea89dc ("rcu: Don't use negative nesting depth in __rcu_read_unlock()") +Reported-by: Tengda Wu +Signed-off-by: Yao Kai +Reviewed-by: Joel Fernandes +Tested-by: Paul E. McKenney +Signed-off-by: Joel Fernandes +Signed-off-by: Boqun Feng +Signed-off-by: Sasha Levin +--- + kernel/rcu/tree.h | 2 +- + kernel/rcu/tree_plugin.h | 15 +++++++++------ + 2 files changed, 10 insertions(+), 7 deletions(-) + +diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h +index b8bbe7960cda7..2265b9c2906e1 100644 +--- a/kernel/rcu/tree.h ++++ b/kernel/rcu/tree.h +@@ -203,7 +203,7 @@ struct rcu_data { + /* during and after the last grace */ + /* period it is aware of. */ + struct irq_work defer_qs_iw; /* Obtain later scheduler attention. */ +- int defer_qs_iw_pending; /* Scheduler attention pending? */ ++ int defer_qs_pending; /* irqwork or softirq pending? */ + struct work_struct strict_work; /* Schedule readers for strict GPs. */ + + /* 2) batch handling */ +diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h +index dbe2d02be824a..95ad967adcf3c 100644 +--- a/kernel/rcu/tree_plugin.h ++++ b/kernel/rcu/tree_plugin.h +@@ -487,8 +487,8 @@ rcu_preempt_deferred_qs_irqrestore(struct task_struct *t, unsigned long flags) + union rcu_special special; + + rdp = this_cpu_ptr(&rcu_data); +- if (rdp->defer_qs_iw_pending == DEFER_QS_PENDING) +- rdp->defer_qs_iw_pending = DEFER_QS_IDLE; ++ if (rdp->defer_qs_pending == DEFER_QS_PENDING) ++ rdp->defer_qs_pending = DEFER_QS_IDLE; + + /* + * If RCU core is waiting for this CPU to exit its critical section, +@@ -645,7 +645,7 @@ static void rcu_preempt_deferred_qs_handler(struct irq_work *iwp) + * 5. Deferred QS reporting does not happen. + */ + if (rcu_preempt_depth() > 0) +- WRITE_ONCE(rdp->defer_qs_iw_pending, DEFER_QS_IDLE); ++ WRITE_ONCE(rdp->defer_qs_pending, DEFER_QS_IDLE); + } + + /* +@@ -747,7 +747,10 @@ static void rcu_read_unlock_special(struct task_struct *t) + // Using softirq, safe to awaken, and either the + // wakeup is free or there is either an expedited + // GP in flight or a potential need to deboost. +- raise_softirq_irqoff(RCU_SOFTIRQ); ++ if (rdp->defer_qs_pending != DEFER_QS_PENDING) { ++ rdp->defer_qs_pending = DEFER_QS_PENDING; ++ raise_softirq_irqoff(RCU_SOFTIRQ); ++ } + } else { + // Enabling BH or preempt does reschedule, so... + // Also if no expediting and no possible deboosting, +@@ -755,11 +758,11 @@ static void rcu_read_unlock_special(struct task_struct *t) + // tick enabled. + set_need_resched_current(); + if (IS_ENABLED(CONFIG_IRQ_WORK) && irqs_were_disabled && +- needs_exp && rdp->defer_qs_iw_pending != DEFER_QS_PENDING && ++ needs_exp && rdp->defer_qs_pending != DEFER_QS_PENDING && + cpu_online(rdp->cpu)) { + // Get scheduler to re-evaluate and call hooks. + // If !IRQ_WORK, FQS scan will eventually IPI. +- rdp->defer_qs_iw_pending = DEFER_QS_PENDING; ++ rdp->defer_qs_pending = DEFER_QS_PENDING; + irq_work_queue_on(&rdp->defer_qs_iw, rdp->cpu); + } + } +-- +2.51.0 + diff --git a/queue-6.19/rcutorture-correctly-compute-probability-to-invoke-e.patch b/queue-6.19/rcutorture-correctly-compute-probability-to-invoke-e.patch new file mode 100644 index 0000000000..58cdd5ac63 --- /dev/null +++ b/queue-6.19/rcutorture-correctly-compute-probability-to-invoke-e.patch @@ -0,0 +1,49 @@ +From a045412fe2b58bc6041bfc1dade5bfdb2ff9622c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Dec 2025 11:16:16 -0800 +Subject: rcutorture: Correctly compute probability to invoke ->exp_current() + +From: Paul E. McKenney + +[ Upstream commit 37d9b475077b5096d41ebdc416a9019bd4fcfdb9 ] + +Lack of parentheses causes the ->exp_current() function, for example, +srcu_expedite_current(), to be called only once in four billion times +instead of the intended once in 256 times. This commit therefore adds +the needed parentheses. + +Reported-by: Chris Mason +Reported-by: Joel Fernandes +Fixes: 950063c6e897 ("rcutorture: Test srcu_expedite_current()") +Signed-off-by: Paul E. McKenney +Signed-off-by: Boqun Feng +Signed-off-by: Sasha Levin +--- + kernel/rcu/rcutorture.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c +index 07e51974b06bc..83934402a287b 100644 +--- a/kernel/rcu/rcutorture.c ++++ b/kernel/rcu/rcutorture.c +@@ -1750,7 +1750,7 @@ rcu_torture_writer(void *arg) + ulo[i] = cur_ops->get_comp_state(); + gp_snap = cur_ops->start_gp_poll(); + rcu_torture_writer_state = RTWS_POLL_WAIT; +- if (cur_ops->exp_current && !torture_random(&rand) % 0xff) ++ if (cur_ops->exp_current && !(torture_random(&rand) & 0xff)) + cur_ops->exp_current(); + while (!cur_ops->poll_gp_state(gp_snap)) { + gp_snap1 = cur_ops->get_gp_state(); +@@ -1772,7 +1772,7 @@ rcu_torture_writer(void *arg) + cur_ops->get_comp_state_full(&rgo[i]); + cur_ops->start_gp_poll_full(&gp_snap_full); + rcu_torture_writer_state = RTWS_POLL_WAIT_FULL; +- if (cur_ops->exp_current && !torture_random(&rand) % 0xff) ++ if (cur_ops->exp_current && !(torture_random(&rand) & 0xff)) + cur_ops->exp_current(); + while (!cur_ops->poll_gp_state_full(&gp_snap_full)) { + cur_ops->get_gp_state_full(&gp_snap1_full); +-- +2.51.0 + diff --git a/queue-6.19/rdma-core-add-rdma_rw_max_sge-helper-for-sq-sizing.patch b/queue-6.19/rdma-core-add-rdma_rw_max_sge-helper-for-sq-sizing.patch new file mode 100644 index 0000000000..310ef42835 --- /dev/null +++ b/queue-6.19/rdma-core-add-rdma_rw_max_sge-helper-for-sq-sizing.patch @@ -0,0 +1,159 @@ +From eee7c712ea2d76343295d6a8545ebee2eea3295e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 19:53:59 -0500 +Subject: RDMA/core: add rdma_rw_max_sge() helper for SQ sizing + +From: Chuck Lever + +[ Upstream commit afcae7d7b8a278a6c29e064f99e5bafd4ac1fb37 ] + +svc_rdma_accept() computes sc_sq_depth as the sum of rq_depth and the +number of rdma_rw contexts (ctxts). This value is used to allocate the +Send CQ and to initialize the sc_sq_avail credit pool. + +However, when the device uses memory registration for RDMA operations, +rdma_rw_init_qp() inflates the QP's max_send_wr by a factor of three +per context to account for REG and INV work requests. The Send CQ and +credit pool remain sized for only one work request per context, +causing Send Queue exhaustion under heavy NFS WRITE workloads. + +Introduce rdma_rw_max_sge() to compute the actual number of Send Queue +entries required for a given number of rdma_rw contexts. Upper layer +protocols call this helper before creating a Queue Pair so that their +Send CQs and credit accounting match the QP's true capacity. + +Update svc_rdma_accept() to use rdma_rw_max_sge() when computing +sc_sq_depth, ensuring the credit pool reflects the work requests +that rdma_rw_init_qp() will reserve. + +Reviewed-by: Christoph Hellwig +Fixes: 00bd1439f464 ("RDMA/rw: Support threshold for registration vs scattering to local pages") +Signed-off-by: Chuck Lever +Link: https://patch.msgid.link/20260128005400.25147-5-cel@kernel.org +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/rw.c | 53 +++++++++++++++++------- + include/rdma/rw.h | 2 + + net/sunrpc/xprtrdma/svc_rdma_transport.c | 8 +++- + 3 files changed, 46 insertions(+), 17 deletions(-) + +diff --git a/drivers/infiniband/core/rw.c b/drivers/infiniband/core/rw.c +index 6354ddf2a274c..2522ff1cc462c 100644 +--- a/drivers/infiniband/core/rw.c ++++ b/drivers/infiniband/core/rw.c +@@ -651,34 +651,57 @@ unsigned int rdma_rw_mr_factor(struct ib_device *device, u32 port_num, + } + EXPORT_SYMBOL(rdma_rw_mr_factor); + ++/** ++ * rdma_rw_max_send_wr - compute max Send WRs needed for RDMA R/W contexts ++ * @dev: RDMA device ++ * @port_num: port number ++ * @max_rdma_ctxs: number of rdma_rw_ctx structures ++ * @create_flags: QP create flags (pass IB_QP_CREATE_INTEGRITY_EN if ++ * data integrity will be enabled on the QP) ++ * ++ * Returns the total number of Send Queue entries needed for ++ * @max_rdma_ctxs. The result accounts for memory registration and ++ * invalidation work requests when the device requires them. ++ * ++ * ULPs use this to size Send Queues and Send CQs before creating a ++ * Queue Pair. ++ */ ++unsigned int rdma_rw_max_send_wr(struct ib_device *dev, u32 port_num, ++ unsigned int max_rdma_ctxs, u32 create_flags) ++{ ++ unsigned int factor = 1; ++ unsigned int result; ++ ++ if (create_flags & IB_QP_CREATE_INTEGRITY_EN || ++ rdma_rw_can_use_mr(dev, port_num)) ++ factor += 2; /* reg + inv */ ++ ++ if (check_mul_overflow(factor, max_rdma_ctxs, &result)) ++ return UINT_MAX; ++ return result; ++} ++EXPORT_SYMBOL(rdma_rw_max_send_wr); ++ + void rdma_rw_init_qp(struct ib_device *dev, struct ib_qp_init_attr *attr) + { +- u32 factor; ++ unsigned int factor = 1; + + WARN_ON_ONCE(attr->port_num == 0); + + /* +- * Each context needs at least one RDMA READ or WRITE WR. +- * +- * For some hardware we might need more, eventually we should ask the +- * HCA driver for a multiplier here. +- */ +- factor = 1; +- +- /* +- * If the device needs MRs to perform RDMA READ or WRITE operations, +- * we'll need two additional MRs for the registrations and the +- * invalidation. ++ * If the device uses MRs to perform RDMA READ or WRITE operations, ++ * or if data integrity is enabled, account for registration and ++ * invalidation work requests. + */ + if (attr->create_flags & IB_QP_CREATE_INTEGRITY_EN || + rdma_rw_can_use_mr(dev, attr->port_num)) +- factor += 2; /* inv + reg */ ++ factor += 2; /* reg + inv */ + + attr->cap.max_send_wr += factor * attr->cap.max_rdma_ctxs; + + /* +- * But maybe we were just too high in the sky and the device doesn't +- * even support all we need, and we'll have to live with what we get.. ++ * The device might not support all we need, and we'll have to ++ * live with what we get. + */ + attr->cap.max_send_wr = + min_t(u32, attr->cap.max_send_wr, dev->attrs.max_qp_wr); +diff --git a/include/rdma/rw.h b/include/rdma/rw.h +index d606cac482338..9a8f4b76ce588 100644 +--- a/include/rdma/rw.h ++++ b/include/rdma/rw.h +@@ -66,6 +66,8 @@ int rdma_rw_ctx_post(struct rdma_rw_ctx *ctx, struct ib_qp *qp, u32 port_num, + + unsigned int rdma_rw_mr_factor(struct ib_device *device, u32 port_num, + unsigned int maxpages); ++unsigned int rdma_rw_max_send_wr(struct ib_device *dev, u32 port_num, ++ unsigned int max_rdma_ctxs, u32 create_flags); + void rdma_rw_init_qp(struct ib_device *dev, struct ib_qp_init_attr *attr); + int rdma_rw_init_mrs(struct ib_qp *qp, struct ib_qp_init_attr *attr); + void rdma_rw_cleanup_mrs(struct ib_qp *qp); +diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c +index b7b318ad25c42..9b623849723ed 100644 +--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c ++++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c +@@ -462,7 +462,10 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + newxprt->sc_max_bc_requests = 2; + } + +- /* Arbitrary estimate of the needed number of rdma_rw contexts. ++ /* Estimate the needed number of rdma_rw contexts. The maximum ++ * Read and Write chunks have one segment each. Each request ++ * can involve one Read chunk and either a Write chunk or Reply ++ * chunk; thus a factor of three. + */ + maxpayload = min(xprt->xpt_server->sv_max_payload, + RPCSVC_MAXPAYLOAD_RDMA); +@@ -470,7 +473,8 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + rdma_rw_mr_factor(dev, newxprt->sc_port_num, + maxpayload >> PAGE_SHIFT); + +- newxprt->sc_sq_depth = rq_depth + ctxts; ++ newxprt->sc_sq_depth = rq_depth + ++ rdma_rw_max_send_wr(dev, newxprt->sc_port_num, ctxts, 0); + if (newxprt->sc_sq_depth > dev->attrs.max_qp_wr) + newxprt->sc_sq_depth = dev->attrs.max_qp_wr; + atomic_set(&newxprt->sc_sq_avail, newxprt->sc_sq_depth); +-- +2.51.0 + diff --git a/queue-6.19/rdma-hns-fix-rocev1-failure-due-to-dscp.patch b/queue-6.19/rdma-hns-fix-rocev1-failure-due-to-dscp.patch new file mode 100644 index 0000000000..63b53eb047 --- /dev/null +++ b/queue-6.19/rdma-hns-fix-rocev1-failure-due-to-dscp.patch @@ -0,0 +1,112 @@ +From d07ec6802e7cae5cd67494c5120f04f9ad3e6986 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 4 Jan 2026 14:40:56 +0800 +Subject: RDMA/hns: Fix RoCEv1 failure due to DSCP + +From: Junxian Huang + +[ Upstream commit 84bd5d60f0a2b9c763c5e6d0b3d8f4f61f6c5470 ] + +DSCP is not supported in RoCEv1, but get_dscp() is still called. If +get_dscp() returns an error, it'll eventually cause create_ah to fail +even when using RoCEv1. + +Correct the return value and avoid calling get_dscp() when using +RoCEv1. + +Fixes: ee20cc17e9d8 ("RDMA/hns: Support DSCP") +Signed-off-by: Junxian Huang +Link: https://patch.msgid.link/20260104064057.1582216-4-huangjunxian6@hisilicon.com +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/hw/hns/hns_roce_ah.c | 23 +++++++++--------- + drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 28 ++++++++++++---------- + 2 files changed, 26 insertions(+), 25 deletions(-) + +diff --git a/drivers/infiniband/hw/hns/hns_roce_ah.c b/drivers/infiniband/hw/hns/hns_roce_ah.c +index 0c1c32d23c884..8a605da8a93c9 100644 +--- a/drivers/infiniband/hw/hns/hns_roce_ah.c ++++ b/drivers/infiniband/hw/hns/hns_roce_ah.c +@@ -60,7 +60,7 @@ int hns_roce_create_ah(struct ib_ah *ibah, struct rdma_ah_init_attr *init_attr, + u8 tclass = get_tclass(grh); + u8 priority = 0; + u8 tc_mode = 0; +- int ret; ++ int ret = 0; + + if (hr_dev->pci_dev->revision == PCI_REVISION_ID_HIP08 && udata) { + ret = -EOPNOTSUPP; +@@ -77,19 +77,18 @@ int hns_roce_create_ah(struct ib_ah *ibah, struct rdma_ah_init_attr *init_attr, + ah->av.flowlabel = grh->flow_label; + ah->av.udp_sport = get_ah_udp_sport(ah_attr); + ah->av.tclass = tclass; ++ ah->av.sl = rdma_ah_get_sl(ah_attr); + +- ret = hr_dev->hw->get_dscp(hr_dev, tclass, &tc_mode, &priority); +- if (ret == -EOPNOTSUPP) +- ret = 0; +- +- if (ret && grh->sgid_attr->gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) +- goto err_out; ++ if (grh->sgid_attr->gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) { ++ ret = hr_dev->hw->get_dscp(hr_dev, tclass, &tc_mode, &priority); ++ if (ret == -EOPNOTSUPP) ++ ret = 0; ++ else if (ret) ++ goto err_out; + +- if (tc_mode == HNAE3_TC_MAP_MODE_DSCP && +- grh->sgid_attr->gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) +- ah->av.sl = priority; +- else +- ah->av.sl = rdma_ah_get_sl(ah_attr); ++ if (tc_mode == HNAE3_TC_MAP_MODE_DSCP) ++ ah->av.sl = priority; ++ } + + if (!check_sl_valid(hr_dev, ah->av.sl)) { + ret = -EINVAL; +diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +index f95442798ddb3..1f37d74b466b5 100644 +--- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c ++++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +@@ -5053,20 +5053,22 @@ static int hns_roce_set_sl(struct ib_qp *ibqp, + struct ib_device *ibdev = &hr_dev->ib_dev; + int ret; + +- ret = hns_roce_hw_v2_get_dscp(hr_dev, get_tclass(&attr->ah_attr.grh), +- &hr_qp->tc_mode, &hr_qp->priority); +- if (ret && ret != -EOPNOTSUPP && +- grh->sgid_attr->gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) { +- ibdev_err_ratelimited(ibdev, +- "failed to get dscp, ret = %d.\n", ret); +- return ret; +- } ++ hr_qp->sl = rdma_ah_get_sl(&attr->ah_attr); + +- if (hr_qp->tc_mode == HNAE3_TC_MAP_MODE_DSCP && +- grh->sgid_attr->gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) +- hr_qp->sl = hr_qp->priority; +- else +- hr_qp->sl = rdma_ah_get_sl(&attr->ah_attr); ++ if (grh->sgid_attr->gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) { ++ ret = hns_roce_hw_v2_get_dscp(hr_dev, ++ get_tclass(&attr->ah_attr.grh), ++ &hr_qp->tc_mode, &hr_qp->priority); ++ if (ret && ret != -EOPNOTSUPP) { ++ ibdev_err_ratelimited(ibdev, ++ "failed to get dscp, ret = %d.\n", ++ ret); ++ return ret; ++ } ++ ++ if (hr_qp->tc_mode == HNAE3_TC_MAP_MODE_DSCP) ++ hr_qp->sl = hr_qp->priority; ++ } + + if (!check_sl_valid(hr_dev, hr_qp->sl)) + return -EINVAL; +-- +2.51.0 + diff --git a/queue-6.19/rdma-hns-fix-wq_mem_reclaim-warning.patch b/queue-6.19/rdma-hns-fix-wq_mem_reclaim-warning.patch new file mode 100644 index 0000000000..fca97c582f --- /dev/null +++ b/queue-6.19/rdma-hns-fix-wq_mem_reclaim-warning.patch @@ -0,0 +1,62 @@ +From 7c212fce8451a472e99aba46a23f9aa50f24f5b7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 4 Jan 2026 14:40:54 +0800 +Subject: RDMA/hns: Fix WQ_MEM_RECLAIM warning + +From: Chengchang Tang + +[ Upstream commit c0a26bbd3f99b7b03f072e3409aff4e6ec8af6f6 ] + +When sunrpc is used, if a reset triggered, our wq may lead the +following trace: + +workqueue: WQ_MEM_RECLAIM xprtiod:xprt_rdma_connect_worker [rpcrdma] +is flushing !WQ_MEM_RECLAIM hns_roce_irq_workq:flush_work_handle +[hns_roce_hw_v2] +WARNING: CPU: 0 PID: 8250 at kernel/workqueue.c:2644 check_flush_dependency+0xe0/0x144 +Call trace: + check_flush_dependency+0xe0/0x144 + start_flush_work.constprop.0+0x1d0/0x2f0 + __flush_work.isra.0+0x40/0xb0 + flush_work+0x14/0x30 + hns_roce_v2_destroy_qp+0xac/0x1e0 [hns_roce_hw_v2] + ib_destroy_qp_user+0x9c/0x2b4 + rdma_destroy_qp+0x34/0xb0 + rpcrdma_ep_destroy+0x28/0xcc [rpcrdma] + rpcrdma_ep_put+0x74/0xb4 [rpcrdma] + rpcrdma_xprt_disconnect+0x1d8/0x260 [rpcrdma] + xprt_rdma_connect_worker+0xc0/0x120 [rpcrdma] + process_one_work+0x1cc/0x4d0 + worker_thread+0x154/0x414 + kthread+0x104/0x144 + ret_from_fork+0x10/0x18 + +Since QP destruction frees memory, this wq should have the WQ_MEM_RECLAIM. + +Fixes: ffd541d45726 ("RDMA/hns: Add the workqueue framework for flush cqe handler") +Signed-off-by: Chengchang Tang +Signed-off-by: Junxian Huang +Link: https://patch.msgid.link/20260104064057.1582216-2-huangjunxian6@hisilicon.com +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +index 2d6ae89e525b8..f95442798ddb3 100644 +--- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c ++++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +@@ -6956,7 +6956,8 @@ static int hns_roce_v2_init_eq_table(struct hns_roce_dev *hr_dev) + + INIT_WORK(&hr_dev->ecc_work, fmea_ram_ecc_work); + +- hr_dev->irq_workq = alloc_ordered_workqueue("hns_roce_irq_workq", 0); ++ hr_dev->irq_workq = alloc_ordered_workqueue("hns_roce_irq_workq", ++ WQ_MEM_RECLAIM); + if (!hr_dev->irq_workq) { + dev_err(dev, "failed to create irq workqueue.\n"); + ret = -ENOMEM; +-- +2.51.0 + diff --git a/queue-6.19/rdma-hns-notify-ulp-of-remaining-soft-wcs-during-res.patch b/queue-6.19/rdma-hns-notify-ulp-of-remaining-soft-wcs-during-res.patch new file mode 100644 index 0000000000..0aa037499c --- /dev/null +++ b/queue-6.19/rdma-hns-notify-ulp-of-remaining-soft-wcs-during-res.patch @@ -0,0 +1,70 @@ +From e4fcd5bd17e820480efc1606959b78f01d930706 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 4 Jan 2026 14:40:57 +0800 +Subject: RDMA/hns: Notify ULP of remaining soft-WCs during reset + +From: Chengchang Tang + +[ Upstream commit 0789f929900d85b80b343c5f04f8b9444e991384 ] + +During a reset, software-generated WCs cannot be reported via +interrupts. This may cause the ULP to miss some WCs. + +To avoid this, add check in the CQ arm process: if a hardware reset +has occurred and there are still unreported soft-WCs, notify the ULP +to handle the remaining WCs, thereby preventing any loss of completions. + +Fixes: 626903e9355b ("RDMA/hns: Add support for reporting wc as software mode") +Signed-off-by: Chengchang Tang +Signed-off-by: Junxian Huang +Link: https://patch.msgid.link/20260104064057.1582216-5-huangjunxian6@hisilicon.com +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 23 ++++++++++++++++++++++ + 1 file changed, 23 insertions(+) + +diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +index 1f37d74b466b5..a2ae4f33e459f 100644 +--- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c ++++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +@@ -3739,6 +3739,23 @@ static void hns_roce_v2_write_cqc(struct hns_roce_dev *hr_dev, + HNS_ROCE_V2_CQ_DEFAULT_INTERVAL); + } + ++static bool left_sw_wc(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq) ++{ ++ struct hns_roce_qp *hr_qp; ++ ++ list_for_each_entry(hr_qp, &hr_cq->sq_list, sq_node) { ++ if (hr_qp->sq.head != hr_qp->sq.tail) ++ return true; ++ } ++ ++ list_for_each_entry(hr_qp, &hr_cq->rq_list, rq_node) { ++ if (hr_qp->rq.head != hr_qp->rq.tail) ++ return true; ++ } ++ ++ return false; ++} ++ + static int hns_roce_v2_req_notify_cq(struct ib_cq *ibcq, + enum ib_cq_notify_flags flags) + { +@@ -3747,6 +3764,12 @@ static int hns_roce_v2_req_notify_cq(struct ib_cq *ibcq, + struct hns_roce_v2_db cq_db = {}; + u32 notify_flag; + ++ if (hr_dev->state >= HNS_ROCE_DEVICE_STATE_RST_DOWN) { ++ if ((flags & IB_CQ_REPORT_MISSED_EVENTS) && ++ left_sw_wc(hr_dev, hr_cq)) ++ return 1; ++ return 0; ++ } + /* + * flags = 0, then notify_flag : next + * flags = 1, then notify flag : solocited +-- +2.51.0 + diff --git a/queue-6.19/rdma-hns-return-actual-error-code-instead-of-fixed-e.patch b/queue-6.19/rdma-hns-return-actual-error-code-instead-of-fixed-e.patch new file mode 100644 index 0000000000..f957fb572f --- /dev/null +++ b/queue-6.19/rdma-hns-return-actual-error-code-instead-of-fixed-e.patch @@ -0,0 +1,47 @@ +From 5f00f95624ed06f3c4aa7e157694036ce97ed62b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 4 Jan 2026 14:40:55 +0800 +Subject: RDMA/hns: Return actual error code instead of fixed EINVAL + +From: Junxian Huang + +[ Upstream commit 8cda8acbb1f8c6c0fec45b7166bb558b5af59da8 ] + +query_cqc() and query_mpt() may return various error codes in +different cases. Return actual error code instead of fixed EINVAL. + +Fixes: f2b070f36d1b ("RDMA/hns: Support CQ's restrack raw ops for hns driver") +Fixes: 3d67e7e236ad ("RDMA/hns: Support MR's restrack raw ops for hns driver") +Signed-off-by: Junxian Huang +Link: https://patch.msgid.link/20260104064057.1582216-3-huangjunxian6@hisilicon.com +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/hw/hns/hns_roce_restrack.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/infiniband/hw/hns/hns_roce_restrack.c b/drivers/infiniband/hw/hns/hns_roce_restrack.c +index 230187dda6a07..085791cc617c4 100644 +--- a/drivers/infiniband/hw/hns/hns_roce_restrack.c ++++ b/drivers/infiniband/hw/hns/hns_roce_restrack.c +@@ -51,7 +51,7 @@ int hns_roce_fill_res_cq_entry_raw(struct sk_buff *msg, struct ib_cq *ib_cq) + + ret = hr_dev->hw->query_cqc(hr_dev, hr_cq->cqn, &context); + if (ret) +- return -EINVAL; ++ return ret; + + ret = nla_put(msg, RDMA_NLDEV_ATTR_RES_RAW, sizeof(context), &context); + +@@ -177,7 +177,7 @@ int hns_roce_fill_res_mr_entry_raw(struct sk_buff *msg, struct ib_mr *ib_mr) + + ret = hr_dev->hw->query_mpt(hr_dev, hr_mr->key, &context); + if (ret) +- return -EINVAL; ++ return ret; + + ret = nla_put(msg, RDMA_NLDEV_ATTR_RES_RAW, sizeof(context), &context); + +-- +2.51.0 + diff --git a/queue-6.19/rdma-iwcm-fix-workqueue-list-corruption-by-removing-.patch b/queue-6.19/rdma-iwcm-fix-workqueue-list-corruption-by-removing-.patch new file mode 100644 index 0000000000..2aa3cfd559 --- /dev/null +++ b/queue-6.19/rdma-iwcm-fix-workqueue-list-corruption-by-removing-.patch @@ -0,0 +1,206 @@ +From dd87817de086e325975bb4b51132a6ab773fef5a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 02:00:06 +0000 +Subject: RDMA/iwcm: Fix workqueue list corruption by removing work_list + +From: Jacob Moroni + +[ Upstream commit 7874eeacfa42177565c01d5198726671acf7adf2 ] + +The commit e1168f0 ("RDMA/iwcm: Simplify cm_event_handler()") +changed the work submission logic to unconditionally call +queue_work() with the expectation that queue_work() would +have no effect if work was already pending. The problem is +that a free list of struct iwcm_work is used (for which +struct work_struct is embedded), so each call to queue_work() +is basically unique and therefore does indeed queue the work. + +This causes a problem in the work handler which walks the work_list +until it's empty to process entries. This means that a single +run of the work handler could process item N+1 and release it +back to the free list while the actual workqueue entry is still +queued. It could then get reused (INIT_WORK...) and lead to +list corruption in the workqueue logic. + +Fix this by just removing the work_list. The workqueue already +does this for us. + +This fixes the following error that was observed when stress +testing with ucmatose on an Intel E830 in iWARP mode: + +[ 151.465780] list_del corruption. next->prev should be ffff9f0915c69c08, but was ffff9f0a1116be08. (next=ffff9f0a15b11c08) +[ 151.466639] ------------[ cut here ]------------ +[ 151.466986] kernel BUG at lib/list_debug.c:67! +[ 151.467349] Oops: invalid opcode: 0000 [#1] SMP NOPTI +[ 151.467753] CPU: 14 UID: 0 PID: 2306 Comm: kworker/u64:18 Not tainted 6.19.0-rc4+ #1 PREEMPT(voluntary) +[ 151.468466] Hardware name: QEMU Ubuntu 24.04 PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 +[ 151.469192] Workqueue: 0x0 (iw_cm_wq) +[ 151.469478] RIP: 0010:__list_del_entry_valid_or_report+0xf0/0x100 +[ 151.469942] Code: c7 58 5f 4c b2 e8 10 50 aa ff 0f 0b 48 89 ef e8 36 57 cb ff 48 8b 55 08 48 89 e9 48 89 de 48 c7 c7 a8 5f 4c b2 e8 f0 4f aa ff <0f> 0b 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 90 90 90 90 90 90 +[ 151.471323] RSP: 0000:ffffb15644e7bd68 EFLAGS: 00010046 +[ 151.471712] RAX: 000000000000006d RBX: ffff9f0915c69c08 RCX: 0000000000000027 +[ 151.472243] RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff9f0a37d9c600 +[ 151.472768] RBP: ffff9f0a15b11c08 R08: 0000000000000000 R09: c0000000ffff7fff +[ 151.473294] R10: 0000000000000001 R11: ffffb15644e7bba8 R12: ffff9f092339ee68 +[ 151.473817] R13: ffff9f0900059c28 R14: ffff9f092339ee78 R15: 0000000000000000 +[ 151.474344] FS: 0000000000000000(0000) GS:ffff9f0a847b5000(0000) knlGS:0000000000000000 +[ 151.474934] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 151.475362] CR2: 0000559e233a9088 CR3: 000000020296b004 CR4: 0000000000770ef0 +[ 151.475895] PKRU: 55555554 +[ 151.476118] Call Trace: +[ 151.476331] +[ 151.476497] move_linked_works+0x49/0xa0 +[ 151.476792] __pwq_activate_work.isra.46+0x2f/0xa0 +[ 151.477151] pwq_dec_nr_in_flight+0x1e0/0x2f0 +[ 151.477479] process_scheduled_works+0x1c8/0x410 +[ 151.477823] worker_thread+0x125/0x260 +[ 151.478108] ? __pfx_worker_thread+0x10/0x10 +[ 151.478430] kthread+0xfe/0x240 +[ 151.478671] ? __pfx_kthread+0x10/0x10 +[ 151.478955] ? __pfx_kthread+0x10/0x10 +[ 151.479240] ret_from_fork+0x208/0x270 +[ 151.479523] ? __pfx_kthread+0x10/0x10 +[ 151.479806] ret_from_fork_asm+0x1a/0x30 +[ 151.480103] + +Fixes: e1168f09b331 ("RDMA/iwcm: Simplify cm_event_handler()") +Signed-off-by: Jacob Moroni +Link: https://patch.msgid.link/20260112020006.1352438-1-jmoroni@google.com +Reviewed-by: Bart Van Assche +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/iwcm.c | 56 +++++++++++++--------------------- + drivers/infiniband/core/iwcm.h | 1 - + 2 files changed, 21 insertions(+), 36 deletions(-) + +diff --git a/drivers/infiniband/core/iwcm.c b/drivers/infiniband/core/iwcm.c +index 62410578dec37..eb942ab9c4055 100644 +--- a/drivers/infiniband/core/iwcm.c ++++ b/drivers/infiniband/core/iwcm.c +@@ -95,7 +95,6 @@ static struct workqueue_struct *iwcm_wq; + struct iwcm_work { + struct work_struct work; + struct iwcm_id_private *cm_id; +- struct list_head list; + struct iw_cm_event event; + struct list_head free_list; + }; +@@ -178,7 +177,6 @@ static int alloc_work_entries(struct iwcm_id_private *cm_id_priv, int count) + return -ENOMEM; + } + work->cm_id = cm_id_priv; +- INIT_LIST_HEAD(&work->list); + put_work(work); + } + return 0; +@@ -213,7 +211,6 @@ static void free_cm_id(struct iwcm_id_private *cm_id_priv) + static bool iwcm_deref_id(struct iwcm_id_private *cm_id_priv) + { + if (refcount_dec_and_test(&cm_id_priv->refcount)) { +- BUG_ON(!list_empty(&cm_id_priv->work_list)); + free_cm_id(cm_id_priv); + return true; + } +@@ -260,7 +257,6 @@ struct iw_cm_id *iw_create_cm_id(struct ib_device *device, + refcount_set(&cm_id_priv->refcount, 1); + init_waitqueue_head(&cm_id_priv->connect_wait); + init_completion(&cm_id_priv->destroy_comp); +- INIT_LIST_HEAD(&cm_id_priv->work_list); + INIT_LIST_HEAD(&cm_id_priv->work_free_list); + + return &cm_id_priv->id; +@@ -1007,13 +1003,13 @@ static int process_event(struct iwcm_id_private *cm_id_priv, + } + + /* +- * Process events on the work_list for the cm_id. If the callback +- * function requests that the cm_id be deleted, a flag is set in the +- * cm_id flags to indicate that when the last reference is +- * removed, the cm_id is to be destroyed. This is necessary to +- * distinguish between an object that will be destroyed by the app +- * thread asleep on the destroy_comp list vs. an object destroyed +- * here synchronously when the last reference is removed. ++ * Process events for the cm_id. If the callback function requests ++ * that the cm_id be deleted, a flag is set in the cm_id flags to ++ * indicate that when the last reference is removed, the cm_id is ++ * to be destroyed. This is necessary to distinguish between an ++ * object that will be destroyed by the app thread asleep on the ++ * destroy_comp list vs. an object destroyed here synchronously ++ * when the last reference is removed. + */ + static void cm_work_handler(struct work_struct *_work) + { +@@ -1024,35 +1020,26 @@ static void cm_work_handler(struct work_struct *_work) + int ret = 0; + + spin_lock_irqsave(&cm_id_priv->lock, flags); +- while (!list_empty(&cm_id_priv->work_list)) { +- work = list_first_entry(&cm_id_priv->work_list, +- struct iwcm_work, list); +- list_del_init(&work->list); +- levent = work->event; +- put_work(work); +- spin_unlock_irqrestore(&cm_id_priv->lock, flags); +- +- if (!test_bit(IWCM_F_DROP_EVENTS, &cm_id_priv->flags)) { +- ret = process_event(cm_id_priv, &levent); +- if (ret) { +- destroy_cm_id(&cm_id_priv->id); +- WARN_ON_ONCE(iwcm_deref_id(cm_id_priv)); +- } +- } else +- pr_debug("dropping event %d\n", levent.event); +- if (iwcm_deref_id(cm_id_priv)) +- return; +- spin_lock_irqsave(&cm_id_priv->lock, flags); +- } ++ levent = work->event; ++ put_work(work); + spin_unlock_irqrestore(&cm_id_priv->lock, flags); ++ ++ if (!test_bit(IWCM_F_DROP_EVENTS, &cm_id_priv->flags)) { ++ ret = process_event(cm_id_priv, &levent); ++ if (ret) { ++ destroy_cm_id(&cm_id_priv->id); ++ WARN_ON_ONCE(iwcm_deref_id(cm_id_priv)); ++ } ++ } else ++ pr_debug("dropping event %d\n", levent.event); ++ if (iwcm_deref_id(cm_id_priv)) ++ return; + } + + /* + * This function is called on interrupt context. Schedule events on + * the iwcm_wq thread to allow callback functions to downcall into +- * the CM and/or block. Events are queued to a per-CM_ID +- * work_list. If this is the first event on the work_list, the work +- * element is also queued on the iwcm_wq thread. ++ * the CM and/or block. + * + * Each event holds a reference on the cm_id. Until the last posted + * event has been delivered and processed, the cm_id cannot be +@@ -1094,7 +1081,6 @@ static int cm_event_handler(struct iw_cm_id *cm_id, + } + + refcount_inc(&cm_id_priv->refcount); +- list_add_tail(&work->list, &cm_id_priv->work_list); + queue_work(iwcm_wq, &work->work); + out: + spin_unlock_irqrestore(&cm_id_priv->lock, flags); +diff --git a/drivers/infiniband/core/iwcm.h b/drivers/infiniband/core/iwcm.h +index bf74639be1287..b56fb12edece4 100644 +--- a/drivers/infiniband/core/iwcm.h ++++ b/drivers/infiniband/core/iwcm.h +@@ -50,7 +50,6 @@ struct iwcm_id_private { + struct ib_qp *qp; + struct completion destroy_comp; + wait_queue_head_t connect_wait; +- struct list_head work_list; + spinlock_t lock; + refcount_t refcount; + struct list_head work_free_list; +-- +2.51.0 + diff --git a/queue-6.19/rdma-mlx5-fix-memory-leak-in-get_data_direct_sysfs_p.patch b/queue-6.19/rdma-mlx5-fix-memory-leak-in-get_data_direct_sysfs_p.patch new file mode 100644 index 0000000000..486fa255d3 --- /dev/null +++ b/queue-6.19/rdma-mlx5-fix-memory-leak-in-get_data_direct_sysfs_p.patch @@ -0,0 +1,57 @@ +From 94c601fc559394c81c97ef7bc5a5e00c3a6463b7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 07:48:01 +0000 +Subject: RDMA/mlx5: Fix memory leak in GET_DATA_DIRECT_SYSFS_PATH handler + +From: Zilin Guan + +[ Upstream commit 9b9d253908478f504297ac283c514e5953ddafa6 ] + +The UVERBS_HANDLER(MLX5_IB_METHOD_GET_DATA_DIRECT_SYSFS_PATH) function +allocates memory for the device path using kobject_get_path(). If the +length of the device path exceeds the output buffer length, the function +returns -ENOSPC but does not free the allocated memory, resulting in a +memory leak. + +Add a kfree() call to the error path to ensure the allocated memory is +properly freed. + +Compile tested only. Issue found using a prototype static analysis tool +and code review. + +Fixes: ec7ad6530909 ("RDMA/mlx5: Introduce GET_DATA_DIRECT_SYSFS_PATH ioctl") +Signed-off-by: Zilin Guan +Link: https://patch.msgid.link/20260126074801.627898-1-zilin@seu.edu.cn +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/hw/mlx5/std_types.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/infiniband/hw/mlx5/std_types.c b/drivers/infiniband/hw/mlx5/std_types.c +index 2fcf553044e15..1ee31611b4b3f 100644 +--- a/drivers/infiniband/hw/mlx5/std_types.c ++++ b/drivers/infiniband/hw/mlx5/std_types.c +@@ -195,7 +195,7 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_GET_DATA_DIRECT_SYSFS_PATH)( + int out_len = uverbs_attr_get_len(attrs, + MLX5_IB_ATTR_GET_DATA_DIRECT_SYSFS_PATH); + u32 dev_path_len; +- char *dev_path; ++ char *dev_path = NULL; + int ret; + + c = to_mucontext(ib_uverbs_get_ucontext(attrs)); +@@ -223,9 +223,9 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_GET_DATA_DIRECT_SYSFS_PATH)( + + ret = uverbs_copy_to(attrs, MLX5_IB_ATTR_GET_DATA_DIRECT_SYSFS_PATH, dev_path, + dev_path_len); +- kfree(dev_path); + + end: ++ kfree(dev_path); + mutex_unlock(&dev->data_direct_lock); + return ret; + } +-- +2.51.0 + diff --git a/queue-6.19/rdma-mlx5-fix-ucaps-init-error-flow.patch b/queue-6.19/rdma-mlx5-fix-ucaps-init-error-flow.patch new file mode 100644 index 0000000000..c68fc3bb43 --- /dev/null +++ b/queue-6.19/rdma-mlx5-fix-ucaps-init-error-flow.patch @@ -0,0 +1,52 @@ +From 30cd40a4a5a0f048f8f5d64e131eb5c74817f884 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 4 Jan 2026 15:51:35 +0200 +Subject: RDMA/mlx5: Fix ucaps init error flow + +From: Maher Sanalla + +[ Upstream commit 6dc78c53de99e4ed9868d4f0fc6da6e46f52fe4d ] + +In mlx5_ib_stage_caps_init(), if mlx5_ib_init_ucaps() fails after +mlx5_ib_init_var_table() succeeds, the VAR bitmap is leaked since +the function returns without cleanup. + +Thus, cleanup the var table bitmap in case of error of initializing +ucaps before exiting, preventing the leak above. + +Fixes: cf7174e8982f ("RDMA/mlx5: Create UCAP char devices for supported device capabilities") +Signed-off-by: Maher Sanalla +Reviewed-by: Yishai Hadas +Link: https://patch.msgid.link/20260104-ib-core-misc-v1-3-00367f77f3a8@nvidia.com +Reviewed-by: Kalesh AP +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/hw/mlx5/main.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c +index 40284bbb45d6d..8d515d266125e 100644 +--- a/drivers/infiniband/hw/mlx5/main.c ++++ b/drivers/infiniband/hw/mlx5/main.c +@@ -4466,12 +4466,16 @@ static int mlx5_ib_stage_caps_init(struct mlx5_ib_dev *dev) + MLX5_HCA_CAP_2_GENERAL_OBJECT_TYPES_RDMA_CTRL) { + err = mlx5_ib_init_ucaps(dev); + if (err) +- return err; ++ goto err_ucaps; + } + + dev->ib_dev.use_cq_dim = true; + + return 0; ++ ++err_ucaps: ++ bitmap_free(dev->var_table.bitmap); ++ return err; + } + + static const struct ib_device_ops mlx5_ib_dev_port_ops = { +-- +2.51.0 + diff --git a/queue-6.19/rdma-mlx5-fix-umr-hang-in-lag-error-state-unload.patch b/queue-6.19/rdma-mlx5-fix-umr-hang-in-lag-error-state-unload.patch new file mode 100644 index 0000000000..744a001043 --- /dev/null +++ b/queue-6.19/rdma-mlx5-fix-umr-hang-in-lag-error-state-unload.patch @@ -0,0 +1,220 @@ +From ca4ee33d6b649d0f638c95f8aa5ff7fd26cbc23d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Jan 2026 15:37:10 +0200 +Subject: RDMA/mlx5: Fix UMR hang in LAG error state unload + +From: Chiara Meiohas + +[ Upstream commit ebc2164a4cd4314503f1a0c8e7aaf76d7e5fa211 ] + +During firmware reset in LAG mode, a race condition causes the driver +to hang indefinitely while waiting for UMR completion during device +unload. See [1]. + +In LAG mode the bond device is only registered on the master, so it +never sees sys_error events from the slave. +During firmware reset this causes UMR waits to hang forever on unload +as the slave is dead but the master hasn't entered error state yet, so +UMR posts succeed but completions never arrive. + +Fix this by adding a sys_error notifier that gets registered before +MLX5_IB_STAGE_IB_REG and stays alive until after ib_unregister_device(). +This ensures error events reach the bond device throughout teardown. + +[1] +Call Trace: + __schedule+0x2bd/0x760 + schedule+0x37/0xa0 + schedule_preempt_disabled+0xa/0x10 + __mutex_lock.isra.6+0x2b5/0x4a0 + __mlx5_ib_dereg_mr+0x606/0x870 [mlx5_ib] + ? __xa_erase+0x4a/0xa0 + ? _cond_resched+0x15/0x30 + ? wait_for_completion+0x31/0x100 + ib_dereg_mr_user+0x48/0xc0 [ib_core] + ? rdmacg_uncharge_hierarchy+0xa0/0x100 + destroy_hw_idr_uobject+0x20/0x50 [ib_uverbs] + uverbs_destroy_uobject+0x37/0x150 [ib_uverbs] + __uverbs_cleanup_ufile+0xda/0x140 [ib_uverbs] + uverbs_destroy_ufile_hw+0x3a/0xf0 [ib_uverbs] + ib_uverbs_remove_one+0xc3/0x140 [ib_uverbs] + remove_client_context+0x8b/0xd0 [ib_core] + disable_device+0x8c/0x130 [ib_core] + __ib_unregister_device+0x10d/0x180 [ib_core] + ib_unregister_device+0x21/0x30 [ib_core] + __mlx5_ib_remove+0x1e4/0x1f0 [mlx5_ib] + auxiliary_bus_remove+0x1e/0x30 + device_release_driver_internal+0x103/0x1f0 + bus_remove_device+0xf7/0x170 + device_del+0x181/0x410 + mlx5_rescan_drivers_locked.part.10+0xa9/0x1d0 [mlx5_core] + mlx5_disable_lag+0x253/0x260 [mlx5_core] + mlx5_lag_disable_change+0x89/0xc0 [mlx5_core] + mlx5_eswitch_disable+0x67/0xa0 [mlx5_core] + mlx5_unload+0x15/0xd0 [mlx5_core] + mlx5_unload_one+0x71/0xc0 [mlx5_core] + mlx5_sync_reset_reload_work+0x83/0x100 [mlx5_core] + process_one_work+0x1a7/0x360 + worker_thread+0x30/0x390 + ? create_worker+0x1a0/0x1a0 + kthread+0x116/0x130 + ? kthread_flush_work_fn+0x10/0x10 + ret_from_fork+0x22/0x40 + +Fixes: ede132a5cf55 ("RDMA/mlx5: Move events notifier registration to be after device registration") +Signed-off-by: Chiara Meiohas +Signed-off-by: Maher Sanalla +Reviewed-by: Mark Bloch +Signed-off-by: Edward Srouji +Link: https://patch.msgid.link/20260113-umr-hand-lag-fix-v1-1-3dc476e00cd9@nvidia.com +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/hw/mlx5/main.c | 75 ++++++++++++++++++++++++---- + drivers/infiniband/hw/mlx5/mlx5_ib.h | 2 + + 2 files changed, 68 insertions(+), 9 deletions(-) + +diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c +index 8d515d266125e..3485a9a3d75e0 100644 +--- a/drivers/infiniband/hw/mlx5/main.c ++++ b/drivers/infiniband/hw/mlx5/main.c +@@ -2878,7 +2878,6 @@ static void mlx5_ib_handle_event(struct work_struct *_work) + container_of(_work, struct mlx5_ib_event_work, work); + struct mlx5_ib_dev *ibdev; + struct ib_event ibev; +- bool fatal = false; + + if (work->is_slave) { + ibdev = mlx5_ib_get_ibdev_from_mpi(work->mpi); +@@ -2889,12 +2888,6 @@ static void mlx5_ib_handle_event(struct work_struct *_work) + } + + switch (work->event) { +- case MLX5_DEV_EVENT_SYS_ERROR: +- ibev.event = IB_EVENT_DEVICE_FATAL; +- mlx5_ib_handle_internal_error(ibdev); +- ibev.element.port_num = (u8)(unsigned long)work->param; +- fatal = true; +- break; + case MLX5_EVENT_TYPE_PORT_CHANGE: + if (handle_port_change(ibdev, work->param, &ibev)) + goto out; +@@ -2916,8 +2909,6 @@ static void mlx5_ib_handle_event(struct work_struct *_work) + if (ibdev->ib_active) + ib_dispatch_event(&ibev); + +- if (fatal) +- ibdev->ib_active = false; + out: + kfree(work); + } +@@ -2961,6 +2952,66 @@ static int mlx5_ib_event_slave_port(struct notifier_block *nb, + return NOTIFY_OK; + } + ++static void mlx5_ib_handle_sys_error_event(struct work_struct *_work) ++{ ++ struct mlx5_ib_event_work *work = ++ container_of(_work, struct mlx5_ib_event_work, work); ++ struct mlx5_ib_dev *ibdev = work->dev; ++ struct ib_event ibev; ++ ++ ibev.event = IB_EVENT_DEVICE_FATAL; ++ mlx5_ib_handle_internal_error(ibdev); ++ ibev.element.port_num = (u8)(unsigned long)work->param; ++ ibev.device = &ibdev->ib_dev; ++ ++ if (!rdma_is_port_valid(&ibdev->ib_dev, ibev.element.port_num)) { ++ mlx5_ib_warn(ibdev, "warning: event on port %d\n", ibev.element.port_num); ++ goto out; ++ } ++ ++ if (ibdev->ib_active) ++ ib_dispatch_event(&ibev); ++ ++ ibdev->ib_active = false; ++out: ++ kfree(work); ++} ++ ++static int mlx5_ib_sys_error_event(struct notifier_block *nb, ++ unsigned long event, void *param) ++{ ++ struct mlx5_ib_event_work *work; ++ ++ if (event != MLX5_DEV_EVENT_SYS_ERROR) ++ return NOTIFY_DONE; ++ ++ work = kmalloc(sizeof(*work), GFP_ATOMIC); ++ if (!work) ++ return NOTIFY_DONE; ++ ++ INIT_WORK(&work->work, mlx5_ib_handle_sys_error_event); ++ work->dev = container_of(nb, struct mlx5_ib_dev, sys_error_events); ++ work->is_slave = false; ++ work->param = param; ++ work->event = event; ++ ++ queue_work(mlx5_ib_event_wq, &work->work); ++ ++ return NOTIFY_OK; ++} ++ ++static int mlx5_ib_stage_sys_error_notifier_init(struct mlx5_ib_dev *dev) ++{ ++ dev->sys_error_events.notifier_call = mlx5_ib_sys_error_event; ++ mlx5_notifier_register(dev->mdev, &dev->sys_error_events); ++ return 0; ++} ++ ++static void mlx5_ib_stage_sys_error_notifier_cleanup(struct mlx5_ib_dev *dev) ++{ ++ mlx5_notifier_unregister(dev->mdev, &dev->sys_error_events); ++} ++ + static int mlx5_ib_get_plane_num(struct mlx5_core_dev *mdev, u8 *num_plane) + { + struct mlx5_hca_vport_context vport_ctx; +@@ -4811,6 +4862,9 @@ static const struct mlx5_ib_profile pf_profile = { + STAGE_CREATE(MLX5_IB_STAGE_WHITELIST_UID, + mlx5_ib_devx_init, + mlx5_ib_devx_cleanup), ++ STAGE_CREATE(MLX5_IB_STAGE_SYS_ERROR_NOTIFIER, ++ mlx5_ib_stage_sys_error_notifier_init, ++ mlx5_ib_stage_sys_error_notifier_cleanup), + STAGE_CREATE(MLX5_IB_STAGE_IB_REG, + mlx5_ib_stage_ib_reg_init, + mlx5_ib_stage_ib_reg_cleanup), +@@ -4868,6 +4922,9 @@ const struct mlx5_ib_profile raw_eth_profile = { + STAGE_CREATE(MLX5_IB_STAGE_WHITELIST_UID, + mlx5_ib_devx_init, + mlx5_ib_devx_cleanup), ++ STAGE_CREATE(MLX5_IB_STAGE_SYS_ERROR_NOTIFIER, ++ mlx5_ib_stage_sys_error_notifier_init, ++ mlx5_ib_stage_sys_error_notifier_cleanup), + STAGE_CREATE(MLX5_IB_STAGE_IB_REG, + mlx5_ib_stage_ib_reg_init, + mlx5_ib_stage_ib_reg_cleanup), +diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h +index 09d82d5f95e35..fbccb0362590b 100644 +--- a/drivers/infiniband/hw/mlx5/mlx5_ib.h ++++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h +@@ -1007,6 +1007,7 @@ enum mlx5_ib_stages { + MLX5_IB_STAGE_BFREG, + MLX5_IB_STAGE_PRE_IB_REG_UMR, + MLX5_IB_STAGE_WHITELIST_UID, ++ MLX5_IB_STAGE_SYS_ERROR_NOTIFIER, + MLX5_IB_STAGE_IB_REG, + MLX5_IB_STAGE_DEVICE_NOTIFIER, + MLX5_IB_STAGE_POST_IB_REG_UMR, +@@ -1165,6 +1166,7 @@ struct mlx5_ib_dev { + /* protect accessing data_direct_dev */ + struct mutex data_direct_lock; + struct notifier_block mdev_events; ++ struct notifier_block sys_error_events; + struct notifier_block lag_events; + int num_ports; + /* serialize update of capability mask +-- +2.51.0 + diff --git a/queue-6.19/rdma-rtrs-server-remove-dead-code.patch b/queue-6.19/rdma-rtrs-server-remove-dead-code.patch new file mode 100644 index 0000000000..afca925cda --- /dev/null +++ b/queue-6.19/rdma-rtrs-server-remove-dead-code.patch @@ -0,0 +1,57 @@ +From 61a0cfb8387e561e2d1e91c1f6f1d12be9d32411 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Dec 2025 10:38:19 +0800 +Subject: RDMA/rtrs: server: remove dead code + +From: Honggang LI + +[ Upstream commit a3572bdc3a028ca47f77d7166ac95b719cf77d50 ] + +As rkey had been initialized to zero, the WARN_ON_ONCE should never been +triggered. Remove it. + +Fixes: 9cb837480424 ("RDMA/rtrs: server: main functionality") +Signed-off-by: Honggang LI +Link: https://patch.msgid.link/20251224023819.138846-1-honggangli@163.com +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/ulp/rtrs/rtrs-srv.c | 8 +------- + 1 file changed, 1 insertion(+), 7 deletions(-) + +diff --git a/drivers/infiniband/ulp/rtrs/rtrs-srv.c b/drivers/infiniband/ulp/rtrs/rtrs-srv.c +index 9ecc6343455d6..7a402eb8e0bf0 100644 +--- a/drivers/infiniband/ulp/rtrs/rtrs-srv.c ++++ b/drivers/infiniband/ulp/rtrs/rtrs-srv.c +@@ -208,7 +208,6 @@ static int rdma_write_sg(struct rtrs_srv_op *id) + size_t sg_cnt; + int err, offset; + bool need_inval; +- u32 rkey = 0; + struct ib_reg_wr rwr; + struct ib_sge *plist; + struct ib_sge list; +@@ -240,11 +239,6 @@ static int rdma_write_sg(struct rtrs_srv_op *id) + wr->wr.num_sge = 1; + wr->remote_addr = le64_to_cpu(id->rd_msg->desc[0].addr); + wr->rkey = le32_to_cpu(id->rd_msg->desc[0].key); +- if (rkey == 0) +- rkey = wr->rkey; +- else +- /* Only one key is actually used */ +- WARN_ON_ONCE(rkey != wr->rkey); + + wr->wr.opcode = IB_WR_RDMA_WRITE; + wr->wr.wr_cqe = &io_comp_cqe; +@@ -277,7 +271,7 @@ static int rdma_write_sg(struct rtrs_srv_op *id) + inv_wr.opcode = IB_WR_SEND_WITH_INV; + inv_wr.wr_cqe = &io_comp_cqe; + inv_wr.send_flags = 0; +- inv_wr.ex.invalidate_rkey = rkey; ++ inv_wr.ex.invalidate_rkey = wr->rkey; + } + + imm_wr.wr.next = NULL; +-- +2.51.0 + diff --git a/queue-6.19/rdma-rtrs-srv-fix-sg-mapping.patch b/queue-6.19/rdma-rtrs-srv-fix-sg-mapping.patch new file mode 100644 index 0000000000..bbac22cbbe --- /dev/null +++ b/queue-6.19/rdma-rtrs-srv-fix-sg-mapping.patch @@ -0,0 +1,85 @@ +From 1df8d63eacbdca338ab694bcab37a9b4432fc559 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 17:15:08 +0100 +Subject: RDMA/rtrs-srv: fix SG mapping + +From: Roman Penyaev + +[ Upstream commit 83835f7c07b523c7ca2a5ad0a511670b5810539e ] + +This fixes the following error on the server side: + + RTRS server session allocation failed: -EINVAL + +caused by the caller of the `ib_dma_map_sg()`, which does not expect +less mapped entries, than requested, which is in the order of things +and can be easily reproduced on the machine with enabled IOMMU. + +The fix is to treat any positive number of mapped sg entries as a +successful mapping and cache DMA addresses by traversing modified +SG table. + +Fixes: 9cb837480424 ("RDMA/rtrs: server: main functionality") +Signed-off-by: Roman Penyaev +Signed-off-by: Jack Wang +Signed-off-by: Grzegorz Prajsner +Link: https://patch.msgid.link/20260107161517.56357-2-haris.iqbal@ionos.com +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/ulp/rtrs/rtrs-srv.c | 25 ++++++++++++++++++++----- + 1 file changed, 20 insertions(+), 5 deletions(-) + +diff --git a/drivers/infiniband/ulp/rtrs/rtrs-srv.c b/drivers/infiniband/ulp/rtrs/rtrs-srv.c +index 7a402eb8e0bf0..adb798e2a54ae 100644 +--- a/drivers/infiniband/ulp/rtrs/rtrs-srv.c ++++ b/drivers/infiniband/ulp/rtrs/rtrs-srv.c +@@ -595,7 +595,7 @@ static int map_cont_bufs(struct rtrs_srv_path *srv_path) + srv_path->mrs_num++) { + struct rtrs_srv_mr *srv_mr = &srv_path->mrs[srv_path->mrs_num]; + struct scatterlist *s; +- int nr, nr_sgt, chunks; ++ int nr, nr_sgt, chunks, ind; + + sgt = &srv_mr->sgt; + chunks = chunks_per_mr * srv_path->mrs_num; +@@ -625,7 +625,7 @@ static int map_cont_bufs(struct rtrs_srv_path *srv_path) + } + nr = ib_map_mr_sg(mr, sgt->sgl, nr_sgt, + NULL, max_chunk_size); +- if (nr != nr_sgt) { ++ if (nr < nr_sgt) { + err = nr < 0 ? nr : -EINVAL; + goto dereg_mr; + } +@@ -641,9 +641,24 @@ static int map_cont_bufs(struct rtrs_srv_path *srv_path) + goto dereg_mr; + } + } +- /* Eventually dma addr for each chunk can be cached */ +- for_each_sg(sgt->sgl, s, nr_sgt, i) +- srv_path->dma_addr[chunks + i] = sg_dma_address(s); ++ ++ /* ++ * Cache DMA addresses by traversing sg entries. If ++ * regions were merged, an inner loop is required to ++ * populate the DMA address array by traversing larger ++ * regions. ++ */ ++ ind = chunks; ++ for_each_sg(sgt->sgl, s, nr_sgt, i) { ++ unsigned int dma_len = sg_dma_len(s); ++ u64 dma_addr = sg_dma_address(s); ++ u64 dma_addr_end = dma_addr + dma_len; ++ ++ do { ++ srv_path->dma_addr[ind++] = dma_addr; ++ dma_addr += max_chunk_size; ++ } while (dma_addr < dma_addr_end); ++ } + + ib_update_fast_reg_key(mr, ib_inc_rkey(mr->rkey)); + srv_mr->mr = mr; +-- +2.51.0 + diff --git a/queue-6.19/rdma-rxe-fix-double-free-in-rxe_srq_from_init.patch b/queue-6.19/rdma-rxe-fix-double-free-in-rxe_srq_from_init.patch new file mode 100644 index 0000000000..78a14c0b7a --- /dev/null +++ b/queue-6.19/rdma-rxe-fix-double-free-in-rxe_srq_from_init.patch @@ -0,0 +1,67 @@ +From 00d80dc95908c8ed662853fddc5ec7fc68f02cbc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 01:54:12 +0000 +Subject: RDMA/rxe: Fix double free in rxe_srq_from_init + +From: Jiasheng Jiang + +[ Upstream commit 0beefd0e15d962f497aad750b2d5e9c3570b66d1 ] + +In rxe_srq_from_init(), the queue pointer 'q' is assigned to +'srq->rq.queue' before copying the SRQ number to user space. +If copy_to_user() fails, the function calls rxe_queue_cleanup() +to free the queue, but leaves the now-invalid pointer in +'srq->rq.queue'. + +The caller of rxe_srq_from_init() (rxe_create_srq) eventually +calls rxe_srq_cleanup() upon receiving the error, which triggers +a second rxe_queue_cleanup() on the same memory, leading to a +double free. + +The call trace looks like this: + kmem_cache_free+0x.../0x... + rxe_queue_cleanup+0x1a/0x30 [rdma_rxe] + rxe_srq_cleanup+0x42/0x60 [rdma_rxe] + rxe_elem_release+0x31/0x70 [rdma_rxe] + rxe_create_srq+0x12b/0x1a0 [rdma_rxe] + ib_create_srq_user+0x9a/0x150 [ib_core] + +Fix this by moving 'srq->rq.queue = q' after copy_to_user. + +Fixes: aae0484e15f0 ("IB/rxe: avoid srq memory leak") +Signed-off-by: Jiasheng Jiang +Link: https://patch.msgid.link/20260112015412.29458-1-jiashengjiangcool@gmail.com +Reviewed-by: Zhu Yanjun +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/sw/rxe/rxe_srq.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/infiniband/sw/rxe/rxe_srq.c b/drivers/infiniband/sw/rxe/rxe_srq.c +index 2a234f26ac104..c9a7cd38953d3 100644 +--- a/drivers/infiniband/sw/rxe/rxe_srq.c ++++ b/drivers/infiniband/sw/rxe/rxe_srq.c +@@ -77,9 +77,6 @@ int rxe_srq_from_init(struct rxe_dev *rxe, struct rxe_srq *srq, + goto err_free; + } + +- srq->rq.queue = q; +- init->attr.max_wr = srq->rq.max_wr; +- + if (uresp) { + if (copy_to_user(&uresp->srq_num, &srq->srq_num, + sizeof(uresp->srq_num))) { +@@ -88,6 +85,9 @@ int rxe_srq_from_init(struct rxe_dev *rxe, struct rxe_srq *srq, + } + } + ++ srq->rq.queue = q; ++ init->attr.max_wr = srq->rq.max_wr; ++ + return 0; + + err_free: +-- +2.51.0 + diff --git a/queue-6.19/rdma-rxe-fix-iova-to-va-conversion-for-mr-page-sizes.patch b/queue-6.19/rdma-rxe-fix-iova-to-va-conversion-for-mr-page-sizes.patch new file mode 100644 index 0000000000..277a0779e2 --- /dev/null +++ b/queue-6.19/rdma-rxe-fix-iova-to-va-conversion-for-mr-page-sizes.patch @@ -0,0 +1,553 @@ +From a50ac040ee051d2a1cefc791bef156c891d907e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 11:27:53 +0800 +Subject: RDMA/rxe: Fix iova-to-va conversion for MR page sizes != PAGE_SIZE + +From: Li Zhijian + +[ Upstream commit 12985e5915a0b8354796efadaaeb201eed115377 ] + +The current implementation incorrectly handles memory regions (MRs) with +page sizes different from the system PAGE_SIZE. The core issue is that +rxe_set_page() is called with mr->page_size step increments, but the +page_list stores individual struct page pointers, each representing +PAGE_SIZE of memory. + +ib_sg_to_page() has ensured that when i>=1 either +a) SG[i-1].dma_end and SG[i].dma_addr are contiguous +or +b) SG[i-1].dma_end and SG[i].dma_addr are mr->page_size aligned. + +This leads to incorrect iova-to-va conversion in scenarios: + +1) page_size < PAGE_SIZE (e.g., MR: 4K, system: 64K): + ibmr->iova = 0x181800 + sg[0]: dma_addr=0x181800, len=0x800 + sg[1]: dma_addr=0x173000, len=0x1000 + + Access iova = 0x181800 + 0x810 = 0x182010 + Expected VA: 0x173010 (second SG, offset 0x10) + Before fix: + - index = (0x182010 >> 12) - (0x181800 >> 12) = 1 + - page_offset = 0x182010 & 0xFFF = 0x10 + - xarray[1] stores system page base 0x170000 + - Resulting VA: 0x170000 + 0x10 = 0x170010 (wrong) + +2) page_size > PAGE_SIZE (e.g., MR: 64K, system: 4K): + ibmr->iova = 0x18f800 + sg[0]: dma_addr=0x18f800, len=0x800 + sg[1]: dma_addr=0x170000, len=0x1000 + + Access iova = 0x18f800 + 0x810 = 0x190010 + Expected VA: 0x170010 (second SG, offset 0x10) + Before fix: + - index = (0x190010 >> 16) - (0x18f800 >> 16) = 1 + - page_offset = 0x190010 & 0xFFFF = 0x10 + - xarray[1] stores system page for dma_addr 0x170000 + - Resulting VA: system page of 0x170000 + 0x10 = 0x170010 (wrong) + +Yi Zhang reported a kernel panic[1] years ago related to this defect. + +Solution: +1. Replace xarray with pre-allocated rxe_mr_page array for sequential + indexing (all MR page indices are contiguous) +2. Each rxe_mr_page stores both struct page* and offset within the + system page +3. Handle MR page_size != PAGE_SIZE relationships: + - page_size > PAGE_SIZE: Split MR pages into multiple system pages + - page_size <= PAGE_SIZE: Store offset within system page +4. Add boundary checks and compatibility validation + +This ensures correct iova-to-va conversion regardless of MR page size +and system PAGE_SIZE relationship, while improving performance through +array-based sequential access. + +Tests on 4K and 64K PAGE_SIZE hosts: +- rdma-core/pytests + $ ./build/bin/run_tests.py --dev eth0_rxe +- blktest: + $ TIMEOUT=30 QUICK_RUN=1 USE_RXE=1 NVMET_TRTYPES=rdma ./check nvme srp rnbd + +[1] https://lore.kernel.org/all/CAHj4cs9XRqE25jyVw9rj9YugffLn5+f=1znaBEnu1usLOciD+g@mail.gmail.com/T/ + +Fixes: 592627ccbdff ("RDMA/rxe: Replace rxe_map and rxe_phys_buf by xarray") +Signed-off-by: Li Zhijian +Link: https://patch.msgid.link/20260116032753.2574363-1-lizhijian@fujitsu.com +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/sw/rxe/rxe_mr.c | 281 +++++++++++++++++--------- + drivers/infiniband/sw/rxe/rxe_verbs.h | 10 +- + 2 files changed, 194 insertions(+), 97 deletions(-) + +diff --git a/drivers/infiniband/sw/rxe/rxe_mr.c b/drivers/infiniband/sw/rxe/rxe_mr.c +index b1df052388488..8116cf0fa6da3 100644 +--- a/drivers/infiniband/sw/rxe/rxe_mr.c ++++ b/drivers/infiniband/sw/rxe/rxe_mr.c +@@ -72,14 +72,46 @@ void rxe_mr_init_dma(int access, struct rxe_mr *mr) + mr->ibmr.type = IB_MR_TYPE_DMA; + } + ++/* ++ * Convert iova to page_info index. The page_info stores pages of size ++ * PAGE_SIZE, but MRs can have different page sizes. This function ++ * handles the conversion for all cases: ++ * ++ * 1. mr->page_size > PAGE_SIZE: ++ * The MR's iova may not be aligned to mr->page_size. We use the ++ * aligned base (iova & page_mask) as reference, then calculate ++ * which PAGE_SIZE sub-page the iova falls into. ++ * ++ * 2. mr->page_size <= PAGE_SIZE: ++ * Use simple shift arithmetic since each page_info entry corresponds ++ * to one or more MR pages. ++ */ + static unsigned long rxe_mr_iova_to_index(struct rxe_mr *mr, u64 iova) + { +- return (iova >> mr->page_shift) - (mr->ibmr.iova >> mr->page_shift); ++ int idx; ++ ++ if (mr_page_size(mr) > PAGE_SIZE) ++ idx = (iova - (mr->ibmr.iova & mr->page_mask)) >> PAGE_SHIFT; ++ else ++ idx = (iova >> mr->page_shift) - ++ (mr->ibmr.iova >> mr->page_shift); ++ ++ WARN_ON(idx >= mr->nbuf); ++ return idx; + } + ++/* ++ * Convert iova to offset within the page_info entry. ++ * ++ * For mr_page_size > PAGE_SIZE, the offset is within the system page. ++ * For mr_page_size <= PAGE_SIZE, the offset is within the MR page size. ++ */ + static unsigned long rxe_mr_iova_to_page_offset(struct rxe_mr *mr, u64 iova) + { +- return iova & (mr_page_size(mr) - 1); ++ if (mr_page_size(mr) > PAGE_SIZE) ++ return iova & (PAGE_SIZE - 1); ++ else ++ return iova & (mr_page_size(mr) - 1); + } + + static bool is_pmem_page(struct page *pg) +@@ -93,37 +125,69 @@ static bool is_pmem_page(struct page *pg) + + static int rxe_mr_fill_pages_from_sgt(struct rxe_mr *mr, struct sg_table *sgt) + { +- XA_STATE(xas, &mr->page_list, 0); + struct sg_page_iter sg_iter; + struct page *page; + bool persistent = !!(mr->access & IB_ACCESS_FLUSH_PERSISTENT); + ++ WARN_ON(mr_page_size(mr) != PAGE_SIZE); ++ + __sg_page_iter_start(&sg_iter, sgt->sgl, sgt->orig_nents, 0); + if (!__sg_page_iter_next(&sg_iter)) + return 0; + +- do { +- xas_lock(&xas); +- while (true) { +- page = sg_page_iter_page(&sg_iter); +- +- if (persistent && !is_pmem_page(page)) { +- rxe_dbg_mr(mr, "Page can't be persistent\n"); +- xas_set_err(&xas, -EINVAL); +- break; +- } ++ while (true) { ++ page = sg_page_iter_page(&sg_iter); + +- xas_store(&xas, page); +- if (xas_error(&xas)) +- break; +- xas_next(&xas); +- if (!__sg_page_iter_next(&sg_iter)) +- break; ++ if (persistent && !is_pmem_page(page)) { ++ rxe_dbg_mr(mr, "Page can't be persistent\n"); ++ return -EINVAL; + } +- xas_unlock(&xas); +- } while (xas_nomem(&xas, GFP_KERNEL)); + +- return xas_error(&xas); ++ mr->page_info[mr->nbuf].page = page; ++ mr->page_info[mr->nbuf].offset = 0; ++ mr->nbuf++; ++ ++ if (!__sg_page_iter_next(&sg_iter)) ++ break; ++ } ++ ++ return 0; ++} ++ ++static int __alloc_mr_page_info(struct rxe_mr *mr, int num_pages) ++{ ++ mr->page_info = kcalloc(num_pages, sizeof(struct rxe_mr_page), ++ GFP_KERNEL); ++ if (!mr->page_info) ++ return -ENOMEM; ++ ++ mr->max_allowed_buf = num_pages; ++ mr->nbuf = 0; ++ ++ return 0; ++} ++ ++static int alloc_mr_page_info(struct rxe_mr *mr, int num_pages) ++{ ++ int ret; ++ ++ WARN_ON(mr->num_buf); ++ ret = __alloc_mr_page_info(mr, num_pages); ++ if (ret) ++ return ret; ++ ++ mr->num_buf = num_pages; ++ ++ return 0; ++} ++ ++static void free_mr_page_info(struct rxe_mr *mr) ++{ ++ if (!mr->page_info) ++ return; ++ ++ kfree(mr->page_info); ++ mr->page_info = NULL; + } + + int rxe_mr_init_user(struct rxe_dev *rxe, u64 start, u64 length, +@@ -134,8 +198,6 @@ int rxe_mr_init_user(struct rxe_dev *rxe, u64 start, u64 length, + + rxe_mr_init(access, mr); + +- xa_init(&mr->page_list); +- + umem = ib_umem_get(&rxe->ib_dev, start, length, access); + if (IS_ERR(umem)) { + rxe_dbg_mr(mr, "Unable to pin memory region err = %d\n", +@@ -143,46 +205,24 @@ int rxe_mr_init_user(struct rxe_dev *rxe, u64 start, u64 length, + return PTR_ERR(umem); + } + ++ err = alloc_mr_page_info(mr, ib_umem_num_pages(umem)); ++ if (err) ++ goto err2; ++ + err = rxe_mr_fill_pages_from_sgt(mr, &umem->sgt_append.sgt); +- if (err) { +- ib_umem_release(umem); +- return err; +- } ++ if (err) ++ goto err1; + + mr->umem = umem; + mr->ibmr.type = IB_MR_TYPE_USER; + mr->state = RXE_MR_STATE_VALID; + + return 0; +-} +- +-static int rxe_mr_alloc(struct rxe_mr *mr, int num_buf) +-{ +- XA_STATE(xas, &mr->page_list, 0); +- int i = 0; +- int err; +- +- xa_init(&mr->page_list); +- +- do { +- xas_lock(&xas); +- while (i != num_buf) { +- xas_store(&xas, XA_ZERO_ENTRY); +- if (xas_error(&xas)) +- break; +- xas_next(&xas); +- i++; +- } +- xas_unlock(&xas); +- } while (xas_nomem(&xas, GFP_KERNEL)); +- +- err = xas_error(&xas); +- if (err) +- return err; +- +- mr->num_buf = num_buf; +- +- return 0; ++err1: ++ free_mr_page_info(mr); ++err2: ++ ib_umem_release(umem); ++ return err; + } + + int rxe_mr_init_fast(int max_pages, struct rxe_mr *mr) +@@ -192,7 +232,7 @@ int rxe_mr_init_fast(int max_pages, struct rxe_mr *mr) + /* always allow remote access for FMRs */ + rxe_mr_init(RXE_ACCESS_REMOTE, mr); + +- err = rxe_mr_alloc(mr, max_pages); ++ err = alloc_mr_page_info(mr, max_pages); + if (err) + goto err1; + +@@ -205,26 +245,43 @@ int rxe_mr_init_fast(int max_pages, struct rxe_mr *mr) + return err; + } + ++/* ++ * I) MRs with page_size >= PAGE_SIZE, ++ * Split a large MR page (mr->page_size) into multiple PAGE_SIZE ++ * sub-pages and store them in page_info, offset is always 0. ++ * ++ * Called when mr->page_size > PAGE_SIZE. Each call to rxe_set_page() ++ * represents one mr->page_size region, which we must split into ++ * (mr->page_size >> PAGE_SHIFT) individual pages. ++ * ++ * II) MRs with page_size < PAGE_SIZE, ++ * Save each PAGE_SIZE page and its offset within the system page in page_info. ++ */ + static int rxe_set_page(struct ib_mr *ibmr, u64 dma_addr) + { + struct rxe_mr *mr = to_rmr(ibmr); +- struct page *page = ib_virt_dma_to_page(dma_addr); + bool persistent = !!(mr->access & IB_ACCESS_FLUSH_PERSISTENT); +- int err; ++ u32 i, pages_per_mr = mr_page_size(mr) >> PAGE_SHIFT; + +- if (persistent && !is_pmem_page(page)) { +- rxe_dbg_mr(mr, "Page cannot be persistent\n"); +- return -EINVAL; +- } ++ pages_per_mr = MAX(1, pages_per_mr); + +- if (unlikely(mr->nbuf == mr->num_buf)) +- return -ENOMEM; ++ for (i = 0; i < pages_per_mr; i++) { ++ u64 addr = dma_addr + i * PAGE_SIZE; ++ struct page *sub_page = ib_virt_dma_to_page(addr); + +- err = xa_err(xa_store(&mr->page_list, mr->nbuf, page, GFP_KERNEL)); +- if (err) +- return err; ++ if (unlikely(mr->nbuf >= mr->max_allowed_buf)) ++ return -ENOMEM; ++ ++ if (persistent && !is_pmem_page(sub_page)) { ++ rxe_dbg_mr(mr, "Page cannot be persistent\n"); ++ return -EINVAL; ++ } ++ ++ mr->page_info[mr->nbuf].page = sub_page; ++ mr->page_info[mr->nbuf].offset = addr & (PAGE_SIZE - 1); ++ mr->nbuf++; ++ } + +- mr->nbuf++; + return 0; + } + +@@ -234,6 +291,31 @@ int rxe_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sgl, + struct rxe_mr *mr = to_rmr(ibmr); + unsigned int page_size = mr_page_size(mr); + ++ /* ++ * Ensure page_size and PAGE_SIZE are compatible for mapping. ++ * We require one to be a multiple of the other for correct ++ * iova-to-page conversion. ++ */ ++ if (!IS_ALIGNED(page_size, PAGE_SIZE) && ++ !IS_ALIGNED(PAGE_SIZE, page_size)) { ++ rxe_dbg_mr(mr, "MR page size %u must be compatible with PAGE_SIZE %lu\n", ++ page_size, PAGE_SIZE); ++ return -EINVAL; ++ } ++ ++ if (mr_page_size(mr) > PAGE_SIZE) { ++ /* resize page_info if needed */ ++ u32 map_mr_pages = (page_size >> PAGE_SHIFT) * mr->num_buf; ++ ++ if (map_mr_pages > mr->max_allowed_buf) { ++ rxe_dbg_mr(mr, "requested pages %u exceed max %u\n", ++ map_mr_pages, mr->max_allowed_buf); ++ free_mr_page_info(mr); ++ if (__alloc_mr_page_info(mr, map_mr_pages)) ++ return -ENOMEM; ++ } ++ } ++ + mr->nbuf = 0; + mr->page_shift = ilog2(page_size); + mr->page_mask = ~((u64)page_size - 1); +@@ -245,30 +327,30 @@ int rxe_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sgl, + static int rxe_mr_copy_xarray(struct rxe_mr *mr, u64 iova, void *addr, + unsigned int length, enum rxe_mr_copy_dir dir) + { +- unsigned int page_offset = rxe_mr_iova_to_page_offset(mr, iova); +- unsigned long index = rxe_mr_iova_to_index(mr, iova); + unsigned int bytes; +- struct page *page; +- void *va; ++ u8 *va; + + while (length) { +- page = xa_load(&mr->page_list, index); +- if (!page) ++ unsigned long index = rxe_mr_iova_to_index(mr, iova); ++ struct rxe_mr_page *info = &mr->page_info[index]; ++ unsigned int page_offset = rxe_mr_iova_to_page_offset(mr, iova); ++ ++ if (!info->page) + return -EFAULT; + +- bytes = min_t(unsigned int, length, +- mr_page_size(mr) - page_offset); +- va = kmap_local_page(page); ++ page_offset += info->offset; ++ bytes = min_t(unsigned int, length, PAGE_SIZE - page_offset); ++ va = kmap_local_page(info->page); ++ + if (dir == RXE_FROM_MR_OBJ) + memcpy(addr, va + page_offset, bytes); + else + memcpy(va + page_offset, addr, bytes); + kunmap_local(va); + +- page_offset = 0; + addr += bytes; ++ iova += bytes; + length -= bytes; +- index++; + } + + return 0; +@@ -426,9 +508,6 @@ int copy_data( + + static int rxe_mr_flush_pmem_iova(struct rxe_mr *mr, u64 iova, unsigned int length) + { +- unsigned int page_offset; +- unsigned long index; +- struct page *page; + unsigned int bytes; + int err; + u8 *va; +@@ -438,15 +517,17 @@ static int rxe_mr_flush_pmem_iova(struct rxe_mr *mr, u64 iova, unsigned int leng + return err; + + while (length > 0) { +- index = rxe_mr_iova_to_index(mr, iova); +- page = xa_load(&mr->page_list, index); +- page_offset = rxe_mr_iova_to_page_offset(mr, iova); +- if (!page) ++ unsigned long index = rxe_mr_iova_to_index(mr, iova); ++ struct rxe_mr_page *info = &mr->page_info[index]; ++ unsigned int page_offset = rxe_mr_iova_to_page_offset(mr, iova); ++ ++ if (!info->page) + return -EFAULT; +- bytes = min_t(unsigned int, length, +- mr_page_size(mr) - page_offset); + +- va = kmap_local_page(page); ++ page_offset += info->offset; ++ bytes = min_t(unsigned int, length, PAGE_SIZE - page_offset); ++ ++ va = kmap_local_page(info->page); + arch_wb_cache_pmem(va + page_offset, bytes); + kunmap_local(va); + +@@ -501,6 +582,7 @@ enum resp_states rxe_mr_do_atomic_op(struct rxe_mr *mr, u64 iova, int opcode, + } else { + unsigned long index; + int err; ++ struct rxe_mr_page *info; + + err = mr_check_range(mr, iova, sizeof(value)); + if (err) { +@@ -509,9 +591,12 @@ enum resp_states rxe_mr_do_atomic_op(struct rxe_mr *mr, u64 iova, int opcode, + } + page_offset = rxe_mr_iova_to_page_offset(mr, iova); + index = rxe_mr_iova_to_index(mr, iova); +- page = xa_load(&mr->page_list, index); +- if (!page) ++ info = &mr->page_info[index]; ++ if (!info->page) + return RESPST_ERR_RKEY_VIOLATION; ++ ++ page_offset += info->offset; ++ page = info->page; + } + + if (unlikely(page_offset & 0x7)) { +@@ -550,6 +635,7 @@ enum resp_states rxe_mr_do_atomic_write(struct rxe_mr *mr, u64 iova, u64 value) + } else { + unsigned long index; + int err; ++ struct rxe_mr_page *info; + + /* See IBA oA19-28 */ + err = mr_check_range(mr, iova, sizeof(value)); +@@ -559,9 +645,12 @@ enum resp_states rxe_mr_do_atomic_write(struct rxe_mr *mr, u64 iova, u64 value) + } + page_offset = rxe_mr_iova_to_page_offset(mr, iova); + index = rxe_mr_iova_to_index(mr, iova); +- page = xa_load(&mr->page_list, index); +- if (!page) ++ info = &mr->page_info[index]; ++ if (!info->page) + return RESPST_ERR_RKEY_VIOLATION; ++ ++ page_offset += info->offset; ++ page = info->page; + } + + /* See IBA A19.4.2 */ +@@ -725,5 +814,5 @@ void rxe_mr_cleanup(struct rxe_pool_elem *elem) + ib_umem_release(mr->umem); + + if (mr->ibmr.type != IB_MR_TYPE_DMA) +- xa_destroy(&mr->page_list); ++ free_mr_page_info(mr); + } +diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.h b/drivers/infiniband/sw/rxe/rxe_verbs.h +index fd48075810dd1..1b8ed1031bd57 100644 +--- a/drivers/infiniband/sw/rxe/rxe_verbs.h ++++ b/drivers/infiniband/sw/rxe/rxe_verbs.h +@@ -335,6 +335,11 @@ static inline int rkey_is_mw(u32 rkey) + return (index >= RXE_MIN_MW_INDEX) && (index <= RXE_MAX_MW_INDEX); + } + ++struct rxe_mr_page { ++ struct page *page; ++ unsigned int offset; /* offset in system page */ ++}; ++ + struct rxe_mr { + struct rxe_pool_elem elem; + struct ib_mr ibmr; +@@ -351,10 +356,13 @@ struct rxe_mr { + unsigned int page_shift; + u64 page_mask; + ++ /* size of page_info when mr allocated */ + u32 num_buf; ++ /* real size of page_info */ ++ u32 max_allowed_buf; + u32 nbuf; + +- struct xarray page_list; ++ struct rxe_mr_page *page_info; + }; + + static inline unsigned int mr_page_size(struct rxe_mr *mr) +-- +2.51.0 + diff --git a/queue-6.19/rdma-rxe-fix-race-condition-in-qp-timer-handlers.patch b/queue-6.19/rdma-rxe-fix-race-condition-in-qp-timer-handlers.patch new file mode 100644 index 0000000000..7bf1e73fbf --- /dev/null +++ b/queue-6.19/rdma-rxe-fix-race-condition-in-qp-timer-handlers.patch @@ -0,0 +1,116 @@ +From 64f6f161c431c46f19a261f5c40344508164f129 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 15:44:37 +0800 +Subject: RDMA/rxe: Fix race condition in QP timer handlers + +From: Li Zhijian + +[ Upstream commit 87bf646921430e303176edc4eb07c30160361b73 ] + +I encontered the following warning: + WARNING: drivers/infiniband/sw/rxe/rxe_task.c:249 at rxe_sched_task+0x1c8/0x238 [rdma_rxe], CPU#0: swapper/0/0 +... + libsha1 [last unloaded: ip6_udp_tunnel] + CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Tainted: G C 6.19.0-rc5-64k-v8+ #37 PREEMPT + Tainted: [C]=CRAP + Hardware name: Raspberry Pi 4 Model B Rev 1.2 + Call trace: + rxe_sched_task+0x1c8/0x238 [rdma_rxe] (P) + retransmit_timer+0x130/0x188 [rdma_rxe] + call_timer_fn+0x68/0x4d0 + __run_timers+0x630/0x888 +... + WARNING: drivers/infiniband/sw/rxe/rxe_task.c:38 at rxe_sched_task+0x1c0/0x238 [rdma_rxe], CPU#0: swapper/0/0 +... + WARNING: drivers/infiniband/sw/rxe/rxe_task.c:111 at do_work+0x488/0x5c8 [rdma_rxe], CPU#3: kworker/u17:4/93400 +... + refcount_t: underflow; use-after-free. + WARNING: lib/refcount.c:28 at refcount_warn_saturate+0x138/0x1a0, CPU#3: kworker/u17:4/93400 + +The issue is caused by a race condition between retransmit_timer() and +rxe_destroy_qp, leading to the Queue Pair's (QP) reference count dropping +to zero during timer handler execution. + +It seems this warning is harmless because rxe_qp_do_cleanup() will flush +all pending timers and requests. + +Example of flow causing the issue: + +CPU0 CPU1 +retransmit_timer() { + spin_lock_irqsave + rxe_destroy_qp() + __rxe_cleanup() + __rxe_put() // qp->ref_count decrease to 0 + rxe_qp_do_cleanup() { + if (qp->valid) { + rxe_sched_task() { + WARN_ON(rxe_read(task->qp) <= 0); + } + } + spin_unlock_irqrestore +} + spin_lock_irqsave + qp->valid = 0 + spin_unlock_irqrestore + } + +Ensure the QP's reference count is maintained and its validity is checked +within the timer callbacks by adding calls to rxe_get(qp) and corresponding +rxe_put(qp) after use. + +Signed-off-by: Li Zhijian +Fixes: d94671632572 ("RDMA/rxe: Rewrite rxe_task.c") +Link: https://patch.msgid.link/20260120074437.623018-1-lizhijian@fujitsu.com +Reviewed-by: Zhu Yanjun +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/sw/rxe/rxe_comp.c | 3 +++ + drivers/infiniband/sw/rxe/rxe_req.c | 3 +++ + 2 files changed, 6 insertions(+) + +diff --git a/drivers/infiniband/sw/rxe/rxe_comp.c b/drivers/infiniband/sw/rxe/rxe_comp.c +index a5b2b62f596b0..1390e861bd1d7 100644 +--- a/drivers/infiniband/sw/rxe/rxe_comp.c ++++ b/drivers/infiniband/sw/rxe/rxe_comp.c +@@ -119,12 +119,15 @@ void retransmit_timer(struct timer_list *t) + + rxe_dbg_qp(qp, "retransmit timer fired\n"); + ++ if (!rxe_get(qp)) ++ return; + spin_lock_irqsave(&qp->state_lock, flags); + if (qp->valid) { + qp->comp.timeout = 1; + rxe_sched_task(&qp->send_task); + } + spin_unlock_irqrestore(&qp->state_lock, flags); ++ rxe_put(qp); + } + + void rxe_comp_queue_pkt(struct rxe_qp *qp, struct sk_buff *skb) +diff --git a/drivers/infiniband/sw/rxe/rxe_req.c b/drivers/infiniband/sw/rxe/rxe_req.c +index 373b03f223beb..12d03f390b097 100644 +--- a/drivers/infiniband/sw/rxe/rxe_req.c ++++ b/drivers/infiniband/sw/rxe/rxe_req.c +@@ -102,6 +102,8 @@ void rnr_nak_timer(struct timer_list *t) + + rxe_dbg_qp(qp, "nak timer fired\n"); + ++ if (!rxe_get(qp)) ++ return; + spin_lock_irqsave(&qp->state_lock, flags); + if (qp->valid) { + /* request a send queue retry */ +@@ -110,6 +112,7 @@ void rnr_nak_timer(struct timer_list *t) + rxe_sched_task(&qp->send_task); + } + spin_unlock_irqrestore(&qp->state_lock, flags); ++ rxe_put(qp); + } + + static void req_check_sq_drain_done(struct rxe_qp *qp) +-- +2.51.0 + diff --git a/queue-6.19/rdma-uverbs-add-__gfp_nowarn-to-ib_uverbs_unmarshall.patch b/queue-6.19/rdma-uverbs-add-__gfp_nowarn-to-ib_uverbs_unmarshall.patch new file mode 100644 index 0000000000..405629806e --- /dev/null +++ b/queue-6.19/rdma-uverbs-add-__gfp_nowarn-to-ib_uverbs_unmarshall.patch @@ -0,0 +1,39 @@ +From 30cad3fef3bbae397ac3444d66d573de8b19275f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 17:49:00 +0800 +Subject: RDMA/uverbs: Add __GFP_NOWARN to ib_uverbs_unmarshall_recv() kmalloc + +From: Yi Liu + +[ Upstream commit 58b604dfc7bb753f91bc0ccd3fa705e14e6edfb4 ] + +Since wqe_size in ib_uverbs_unmarshall_recv() is user-provided and already +validated, but can still be large, add __GFP_NOWARN to suppress memory +allocation warnings for large sizes, consistent with the similar fix in +ib_uverbs_post_send(). + +Fixes: 67cdb40ca444 ("[IB] uverbs: Implement more commands") +Signed-off-by: Yi Liu +Link: https://patch.msgid.link/20260129094900.3517706-1-liuy22@mails.tsinghua.edu.cn +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/uverbs_cmd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c +index 3259e9848cc79..f4616deeca545 100644 +--- a/drivers/infiniband/core/uverbs_cmd.c ++++ b/drivers/infiniband/core/uverbs_cmd.c +@@ -2242,7 +2242,7 @@ ib_uverbs_unmarshall_recv(struct uverbs_req_iter *iter, u32 wr_count, + if (ret) + return ERR_PTR(ret); + +- user_wr = kmalloc(wqe_size, GFP_KERNEL); ++ user_wr = kmalloc(wqe_size, GFP_KERNEL | __GFP_NOWARN); + if (!user_wr) + return ERR_PTR(-ENOMEM); + +-- +2.51.0 + diff --git a/queue-6.19/rdma-uverbs-validate-wqe_size-before-using-it-in-ib_.patch b/queue-6.19/rdma-uverbs-validate-wqe_size-before-using-it-in-ib_.patch new file mode 100644 index 0000000000..aa884a7aa5 --- /dev/null +++ b/queue-6.19/rdma-uverbs-validate-wqe_size-before-using-it-in-ib_.patch @@ -0,0 +1,57 @@ +From eb3e2fb1eb726146cda2155483c6a830eb7c243a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 22:29:00 +0800 +Subject: RDMA/uverbs: Validate wqe_size before using it in ib_uverbs_post_send + +From: Yi Liu + +[ Upstream commit 1956f0a74ccf5dc9c3ef717f2985c3ed3400aab0 ] + +ib_uverbs_post_send() uses cmd.wqe_size from userspace without any +validation before passing it to kmalloc() and using the allocated +buffer as struct ib_uverbs_send_wr. + +If a user provides a small wqe_size value (e.g., 1), kmalloc() will +succeed, but subsequent accesses to user_wr->opcode, user_wr->num_sge, +and other fields will read beyond the allocated buffer, resulting in +an out-of-bounds read from kernel heap memory. This could potentially +leak sensitive kernel information to userspace. + +Additionally, providing an excessively large wqe_size can trigger a +WARNING in the memory allocation path, as reported by syzkaller. + +This is inconsistent with ib_uverbs_unmarshall_recv() which properly +validates that wqe_size >= sizeof(struct ib_uverbs_recv_wr) before +proceeding. + +Add the same validation for ib_uverbs_post_send() to ensure wqe_size +is at least sizeof(struct ib_uverbs_send_wr). + +Fixes: c3bea3d2dc53 ("RDMA/uverbs: Use the iterator for ib_uverbs_unmarshall_recv()") +Signed-off-by: Yi Liu +Link: https://patch.msgid.link/20260122142900.2356276-2-liuy22@mails.tsinghua.edu.cn +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/uverbs_cmd.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c +index ce16404cdfb8c..3259e9848cc79 100644 +--- a/drivers/infiniband/core/uverbs_cmd.c ++++ b/drivers/infiniband/core/uverbs_cmd.c +@@ -2049,7 +2049,10 @@ static int ib_uverbs_post_send(struct uverbs_attr_bundle *attrs) + if (ret) + return ret; + +- user_wr = kmalloc(cmd.wqe_size, GFP_KERNEL); ++ if (cmd.wqe_size < sizeof(struct ib_uverbs_send_wr)) ++ return -EINVAL; ++ ++ user_wr = kmalloc(cmd.wqe_size, GFP_KERNEL | __GFP_NOWARN); + if (!user_wr) + return -ENOMEM; + +-- +2.51.0 + diff --git a/queue-6.19/regulator-core-don-t-ignore-errors-from-event-forwar.patch b/queue-6.19/regulator-core-don-t-ignore-errors-from-event-forwar.patch new file mode 100644 index 0000000000..161a14e431 --- /dev/null +++ b/queue-6.19/regulator-core-don-t-ignore-errors-from-event-forwar.patch @@ -0,0 +1,58 @@ +From 04c54c89bf5ad46d13991cd9637a98b35861e16b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 08:38:42 +0000 +Subject: regulator: core: don't ignore errors from event forwarding setup +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: André Draszik + +[ Upstream commit e23c0a59dabae9166bbea26fc05d08e7d9e900b7 ] + +Receiving and forwarding critical supply events seems like they're +important information and we shouldn't ignore errors occurring during +registration for such events. + +With this change the supply is unset on event registration failure, +allowing us to potentially retry another time. + +Fixes: 433e294c3c5b ("regulator: core: forward undervoltage events downstream by default") +Signed-off-by: André Draszik +Link: https://patch.msgid.link/20260109-regulators-defer-v2-6-1a25dc968e60@linaro.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/regulator/core.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c +index d0140227fcbdb..8ee33b777f6ce 100644 +--- a/drivers/regulator/core.c ++++ b/drivers/regulator/core.c +@@ -2273,10 +2273,21 @@ static int regulator_resolve_supply(struct regulator_dev *rdev) + * under-voltage. + */ + ret = register_regulator_event_forwarding(rdev); +- if (ret < 0) ++ if (ret < 0) { ++ struct regulator *supply; ++ + rdev_warn(rdev, "Failed to register event forwarding: %pe\n", + ERR_PTR(ret)); + ++ supply = rdev->supply; ++ rdev->supply = NULL; ++ ++ regulator_unlock_two(rdev, supply->rdev, &ww_ctx); ++ ++ regulator_put(supply); ++ goto out; ++ } ++ + regulator_unlock_two(rdev, r, &ww_ctx); + + /* rdev->supply was created in set_supply() */ +-- +2.51.0 + diff --git a/queue-6.19/regulator-core-fix-locking-in-regulator_resolve_supp.patch b/queue-6.19/regulator-core-fix-locking-in-regulator_resolve_supp.patch new file mode 100644 index 0000000000..1dea2bdccd --- /dev/null +++ b/queue-6.19/regulator-core-fix-locking-in-regulator_resolve_supp.patch @@ -0,0 +1,70 @@ +From 453ed84068a9d83865c210bdd7d7530d38f9077a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 08:38:38 +0000 +Subject: regulator: core: fix locking in regulator_resolve_supply() error path +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: André Draszik + +[ Upstream commit 497330b203d2c59c5ff3fa4c34d14494d7203bc3 ] + +If late enabling of a supply regulator fails in +regulator_resolve_supply(), the code currently triggers a lockdep +warning: + + WARNING: drivers/regulator/core.c:2649 at _regulator_put+0x80/0xa0, CPU#6: kworker/u32:4/596 + ... + Call trace: + _regulator_put+0x80/0xa0 (P) + regulator_resolve_supply+0x7cc/0xbe0 + regulator_register_resolve_supply+0x28/0xb8 + +as the regulator_list_mutex must be held when calling _regulator_put(). + +To solve this, simply switch to using regulator_put(). + +While at it, we should also make sure that no concurrent access happens +to our rdev while we clear out the supply pointer. Add appropriate +locking to ensure that. + +While the code in question will be removed altogether in a follow-up +commit, I believe it is still beneficial to have this corrected before +removal for future reference. + +Fixes: 36a1f1b6ddc6 ("regulator: core: Fix memory leak in regulator_resolve_supply()") +Fixes: 8e5356a73604 ("regulator: core: Clear the supply pointer if enabling fails") +Signed-off-by: André Draszik +Link: https://patch.msgid.link/20260109-regulators-defer-v2-2-1a25dc968e60@linaro.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/regulator/core.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c +index 4b6182cde859a..b2dcd1acd0ece 100644 +--- a/drivers/regulator/core.c ++++ b/drivers/regulator/core.c +@@ -2285,8 +2285,16 @@ static int regulator_resolve_supply(struct regulator_dev *rdev) + if (rdev->use_count) { + ret = regulator_enable(rdev->supply); + if (ret < 0) { +- _regulator_put(rdev->supply); ++ struct regulator *supply; ++ ++ regulator_lock_two(rdev, rdev->supply->rdev, &ww_ctx); ++ ++ supply = rdev->supply; + rdev->supply = NULL; ++ ++ regulator_unlock_two(rdev, supply->rdev, &ww_ctx); ++ ++ regulator_put(supply); + goto out; + } + } +-- +2.51.0 + diff --git a/queue-6.19/regulator-core-move-supply-check-earlier-in-set_mach.patch b/queue-6.19/regulator-core-move-supply-check-earlier-in-set_mach.patch new file mode 100644 index 0000000000..2a235406d7 --- /dev/null +++ b/queue-6.19/regulator-core-move-supply-check-earlier-in-set_mach.patch @@ -0,0 +1,121 @@ +From a9fc70b6eb5f9ea9d6a7316d11eeb82e30842d31 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 08:38:39 +0000 +Subject: regulator: core: move supply check earlier in + set_machine_constraints() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: André Draszik + +[ Upstream commit 86a8eeb0e913f4b6a55dabba5122098d4e805e55 ] + +Since commit 98e48cd9283d ("regulator: core: resolve supply for +boot-on/always-on regulators"), set_machine_constraints() can return +-EPROBE_DEFER very late, after it has done a lot of work and +configuration of the regulator. + +This means that configuration will happen multiple times for no +benefit in that case. Furthermore, this can lead to timing-dependent +voltage glitches as mentioned e.g. in commit 8a866d527ac0 ("regulator: +core: Resolve supply name earlier to prevent double-init"). + +We can know that it's going to fail very early, in particular before +going through the complete regulator configuration by moving some code +around a little. + +Do so to avoid re-configuring the regulator multiple times, also +avoiding the voltage glitches if we can. + +Fixes: 98e48cd9283d ("regulator: core: resolve supply for boot-on/always-on regulators") +Signed-off-by: André Draszik +Link: https://patch.msgid.link/20260109-regulators-defer-v2-3-1a25dc968e60@linaro.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/regulator/core.c | 55 ++++++++++++++++++++++------------------ + 1 file changed, 30 insertions(+), 25 deletions(-) + +diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c +index b2dcd1acd0ece..d0140227fcbdb 100644 +--- a/drivers/regulator/core.c ++++ b/drivers/regulator/core.c +@@ -1444,6 +1444,33 @@ static int set_machine_constraints(struct regulator_dev *rdev) + int ret = 0; + const struct regulator_ops *ops = rdev->desc->ops; + ++ /* ++ * If there is no mechanism for controlling the regulator then ++ * flag it as always_on so we don't end up duplicating checks ++ * for this so much. Note that we could control the state of ++ * a supply to control the output on a regulator that has no ++ * direct control. ++ */ ++ if (!rdev->ena_pin && !ops->enable) { ++ if (rdev->supply_name && !rdev->supply) ++ return -EPROBE_DEFER; ++ ++ if (rdev->supply) ++ rdev->constraints->always_on = ++ rdev->supply->rdev->constraints->always_on; ++ else ++ rdev->constraints->always_on = true; ++ } ++ ++ /* ++ * If we want to enable this regulator, make sure that we know the ++ * supplying regulator. ++ */ ++ if (rdev->constraints->always_on || rdev->constraints->boot_on) { ++ if (rdev->supply_name && !rdev->supply) ++ return -EPROBE_DEFER; ++ } ++ + ret = machine_constraints_voltage(rdev, rdev->constraints); + if (ret != 0) + return ret; +@@ -1609,37 +1636,15 @@ static int set_machine_constraints(struct regulator_dev *rdev) + } + } + +- /* +- * If there is no mechanism for controlling the regulator then +- * flag it as always_on so we don't end up duplicating checks +- * for this so much. Note that we could control the state of +- * a supply to control the output on a regulator that has no +- * direct control. +- */ +- if (!rdev->ena_pin && !ops->enable) { +- if (rdev->supply_name && !rdev->supply) +- return -EPROBE_DEFER; +- +- if (rdev->supply) +- rdev->constraints->always_on = +- rdev->supply->rdev->constraints->always_on; +- else +- rdev->constraints->always_on = true; +- } +- + /* If the constraints say the regulator should be on at this point + * and we have control then make sure it is enabled. + */ + if (rdev->constraints->always_on || rdev->constraints->boot_on) { + bool supply_enabled = false; + +- /* If we want to enable this regulator, make sure that we know +- * the supplying regulator. +- */ +- if (rdev->supply_name && !rdev->supply) +- return -EPROBE_DEFER; +- +- /* If supplying regulator has already been enabled, ++ /* We have ensured a potential supply has been resolved above. ++ * ++ * If supplying regulator has already been enabled, + * it's not intended to have use_count increment + * when rdev is only boot-on. + */ +-- +2.51.0 + diff --git a/queue-6.19/remoteproc-imx_dsp_rproc-fix-multiple-start-stop-ope.patch b/queue-6.19/remoteproc-imx_dsp_rproc-fix-multiple-start-stop-ope.patch new file mode 100644 index 0000000000..2e627e1587 --- /dev/null +++ b/queue-6.19/remoteproc-imx_dsp_rproc-fix-multiple-start-stop-ope.patch @@ -0,0 +1,128 @@ +From 13aa72a724f8d87559f16408aebc0c664e4ccd8b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 10 Dec 2025 17:49:06 +0200 +Subject: remoteproc: imx_dsp_rproc: Fix multiple start/stop operations + +From: Daniel Baluta + +[ Upstream commit a84a1e21c0678032f1185173f816cbb500a87877 ] + +After commit 67a7bc7f0358 ("remoteproc: Use of reserved_mem_region_* +functions for "memory-region"") following commands with +imx-dsp-rproc started to fail: + +$ echo zephyr.elf > /sys/class/remoteproc/remoteproc0/firmware +$ echo start > /sys/class/remoteproc/remoteproc0/state +$ echo stop > /sys/class/remoteproc/remoteproc0/state +$ echo start > /sys/class/remoteproc/remoteproc0/state #! This fails +-sh: echo: write error: Device or resource busy + +This happens because aforementioned commit replaced devm_ioremap_wc with +devm_ioremap_resource_wc which will "reserve" the memory region with the +first start and then will fail at the second start if the memory +region is already reserved. + +Even partially reverting the faulty commit won't fix the +underlying issue because we map the address in prepare() but we never +unmap it at unprepare(), so we will keep leaking memory regions. + +So, lets use alloc() and release() callbacks for memory carveout +handling. This will nicely map() the memory region at prepare() time +and unmap() it at unprepare(). + +Fixes: 67a7bc7f0358 ("remoteproc: Use of_reserved_mem_region_* functions for "memory-region"") +Signed-off-by: Daniel Baluta +Link: https://lore.kernel.org/r/20251210154906.99210-1-daniel.baluta@nxp.com +Signed-off-by: Mathieu Poirier +Signed-off-by: Sasha Levin +--- + drivers/remoteproc/imx_dsp_rproc.c | 50 ++++++++++++++++++++---------- + 1 file changed, 33 insertions(+), 17 deletions(-) + +diff --git a/drivers/remoteproc/imx_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c +index 5130a35214c92..83468558e634e 100644 +--- a/drivers/remoteproc/imx_dsp_rproc.c ++++ b/drivers/remoteproc/imx_dsp_rproc.c +@@ -644,6 +644,32 @@ static void imx_dsp_rproc_free_mbox(struct imx_dsp_rproc *priv) + mbox_free_channel(priv->rxdb_ch); + } + ++static int imx_dsp_rproc_mem_alloc(struct rproc *rproc, ++ struct rproc_mem_entry *mem) ++{ ++ struct device *dev = rproc->dev.parent; ++ void *va; ++ ++ va = ioremap_wc(mem->dma, mem->len); ++ if (!va) { ++ dev_err(dev, "Unable to map memory region: %pa+%zx\n", ++ &mem->dma, mem->len); ++ return -ENOMEM; ++ } ++ ++ mem->va = va; ++ ++ return 0; ++} ++ ++static int imx_dsp_rproc_mem_release(struct rproc *rproc, ++ struct rproc_mem_entry *mem) ++{ ++ iounmap(mem->va); ++ ++ return 0; ++} ++ + /** + * imx_dsp_rproc_add_carveout() - request mailbox channels + * @priv: private data pointer +@@ -659,7 +685,6 @@ static int imx_dsp_rproc_add_carveout(struct imx_dsp_rproc *priv) + struct device *dev = rproc->dev.parent; + struct device_node *np = dev->of_node; + struct rproc_mem_entry *mem; +- void __iomem *cpu_addr; + int a, i = 0; + u64 da; + +@@ -673,15 +698,10 @@ static int imx_dsp_rproc_add_carveout(struct imx_dsp_rproc *priv) + if (imx_dsp_rproc_sys_to_da(priv, att->sa, att->size, &da)) + return -EINVAL; + +- cpu_addr = devm_ioremap_wc(dev, att->sa, att->size); +- if (!cpu_addr) { +- dev_err(dev, "failed to map memory %p\n", &att->sa); +- return -ENOMEM; +- } +- + /* Register memory region */ +- mem = rproc_mem_entry_init(dev, (void __force *)cpu_addr, (dma_addr_t)att->sa, +- att->size, da, NULL, NULL, "dsp_mem"); ++ mem = rproc_mem_entry_init(dev, NULL, (dma_addr_t)att->sa, ++ att->size, da, imx_dsp_rproc_mem_alloc, ++ imx_dsp_rproc_mem_release, "dsp_mem"); + + if (mem) + rproc_coredump_add_segment(rproc, da, att->size); +@@ -709,15 +729,11 @@ static int imx_dsp_rproc_add_carveout(struct imx_dsp_rproc *priv) + if (imx_dsp_rproc_sys_to_da(priv, res.start, resource_size(&res), &da)) + return -EINVAL; + +- cpu_addr = devm_ioremap_resource_wc(dev, &res); +- if (IS_ERR(cpu_addr)) { +- dev_err(dev, "failed to map memory %pR\n", &res); +- return PTR_ERR(cpu_addr); +- } +- + /* Register memory region */ +- mem = rproc_mem_entry_init(dev, (void __force *)cpu_addr, (dma_addr_t)res.start, +- resource_size(&res), da, NULL, NULL, ++ mem = rproc_mem_entry_init(dev, NULL, (dma_addr_t)res.start, ++ resource_size(&res), da, ++ imx_dsp_rproc_mem_alloc, ++ imx_dsp_rproc_mem_release, + "%.*s", strchrnul(res.name, '@') - res.name, res.name); + if (!mem) + return -ENOMEM; +-- +2.51.0 + diff --git a/queue-6.19/remoteproc-imx_dsp_rproc-only-reset-carveout-memory-.patch b/queue-6.19/remoteproc-imx_dsp_rproc-only-reset-carveout-memory-.patch new file mode 100644 index 0000000000..a7ce563e22 --- /dev/null +++ b/queue-6.19/remoteproc-imx_dsp_rproc-only-reset-carveout-memory-.patch @@ -0,0 +1,47 @@ +From bf588a1cbf9ff10c097fc72fdacfeb65bc1b04c5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 15:17:50 +0800 +Subject: remoteproc: imx_dsp_rproc: Only reset carveout memory at + RPROC_OFFLINE state + +From: Shengjiu Wang + +[ Upstream commit b490ddf27be28e64a39c08ae643d7b22561beaf6 ] + +Do not reset memory at suspend and resume stage, because some +memory is used to save the software state for resume, if it is cleared, +the resume operation can fail. + +Fixes: c4c432dfb00f ("remoteproc: imx_dsp_rproc: Add support of recovery and coredump process") +Signed-off-by: Shengjiu Wang +Reviewed-by: Daniel Baluta +Reviewed-by: Iuliana Prodan +Link: https://lore.kernel.org/r/20251218071750.2692132-1-shengjiu.wang@nxp.com +Signed-off-by: Mathieu Poirier +Signed-off-by: Sasha Levin +--- + drivers/remoteproc/imx_dsp_rproc.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/remoteproc/imx_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c +index 83468558e634e..5a9a8fa031f6d 100644 +--- a/drivers/remoteproc/imx_dsp_rproc.c ++++ b/drivers/remoteproc/imx_dsp_rproc.c +@@ -1000,9 +1000,11 @@ static int imx_dsp_rproc_load(struct rproc *rproc, const struct firmware *fw) + * Clear buffers after pm rumtime for internal ocram is not + * accessible if power and clock are not enabled. + */ +- list_for_each_entry(carveout, &rproc->carveouts, node) { +- if (carveout->va) +- memset(carveout->va, 0, carveout->len); ++ if (rproc->state == RPROC_OFFLINE) { ++ list_for_each_entry(carveout, &rproc->carveouts, node) { ++ if (carveout->va) ++ memset(carveout->va, 0, carveout->len); ++ } + } + + ret = imx_dsp_rproc_elf_load_segments(rproc, fw); +-- +2.51.0 + diff --git a/queue-6.19/remoteproc-imx_rproc-use-strstarts-for-rsc-table-che.patch b/queue-6.19/remoteproc-imx_rproc-use-strstarts-for-rsc-table-che.patch new file mode 100644 index 0000000000..c67545beba --- /dev/null +++ b/queue-6.19/remoteproc-imx_rproc-use-strstarts-for-rsc-table-che.patch @@ -0,0 +1,44 @@ +From 9e11a3dc405a5c52bfcaaf22232dbba1ea5a5613 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Dec 2025 17:33:02 -0600 +Subject: remoteproc: imx_rproc: Use strstarts for "rsc-table" check + +From: Shenwei Wang + +[ Upstream commit 93f51b9182a107cf5f5e8a7802cd90df0c9a7154 ] + +The resource name may include an address suffix, for example: +rsc-table@1fff8000. + +To handle such cases, use strstarts() instead of strcmp() when checking +for "rsc-table". + +Signed-off-by: Shenwei Wang +Reviewed-by: Daniel Baluta +Reviewed-by: Frank Li +Reviewed-by: Zhongqiu Han +Reviewed-by: Peng Fan +Fixes: 67a7bc7f0358 ("remoteproc: Use of_reserved_mem_region_* functions for "memory-region"") +Link: https://lore.kernel.org/r/20251208233302.684139-1-shenwei.wang@nxp.com +Signed-off-by: Mathieu Poirier +Signed-off-by: Sasha Levin +--- + drivers/remoteproc/imx_rproc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c +index 3be8790c14a2c..33f21ab24c921 100644 +--- a/drivers/remoteproc/imx_rproc.c ++++ b/drivers/remoteproc/imx_rproc.c +@@ -694,7 +694,7 @@ static int imx_rproc_addr_init(struct imx_rproc *priv, + } + priv->mem[b].sys_addr = res.start; + priv->mem[b].size = resource_size(&res); +- if (!strcmp(res.name, "rsc-table")) ++ if (strstarts(res.name, "rsc-table")) + priv->rsc_table = priv->mem[b].cpu_addr; + b++; + } +-- +2.51.0 + diff --git a/queue-6.19/reset-canaan-k230-drop-of-dependency-and-enable-by-d.patch b/queue-6.19/reset-canaan-k230-drop-of-dependency-and-enable-by-d.patch new file mode 100644 index 0000000000..ec13c927c4 --- /dev/null +++ b/queue-6.19/reset-canaan-k230-drop-of-dependency-and-enable-by-d.patch @@ -0,0 +1,36 @@ +From 14211cf65895ddb3735f7358de9e02caa9437e44 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 17 Jan 2026 18:06:22 +0800 +Subject: reset: canaan: k230: drop OF dependency and enable by default + +From: Junhui Liu + +[ Upstream commit c7a5e01e229d21e0560d78bd645b4f7398667ce4 ] + +The driver doesn't use any symbols depending on CONFIG_OF, so drop the +dependency. Also, enable it by default when ARCH_CANAAN is selected. + +Fixes: 360a7a647759 ("reset: canaan: add reset driver for Kendryte K230") +Signed-off-by: Junhui Liu +Signed-off-by: Philipp Zabel +Signed-off-by: Sasha Levin +--- + drivers/reset/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig +index 6e5d6deffa7d3..52ee102621eef 100644 +--- a/drivers/reset/Kconfig ++++ b/drivers/reset/Kconfig +@@ -161,7 +161,7 @@ config RESET_K210 + config RESET_K230 + tristate "Reset controller driver for Canaan Kendryte K230 SoC" + depends on ARCH_CANAAN || COMPILE_TEST +- depends on OF ++ default ARCH_CANAAN + help + Support for the Canaan Kendryte K230 RISC-V SoC reset controller. + Say Y if you want to control reset signals provided by this +-- +2.51.0 + diff --git a/queue-6.19/revert-hwmon-ibmpex-fix-use-after-free-in-high-low-s.patch b/queue-6.19/revert-hwmon-ibmpex-fix-use-after-free-in-high-low-s.patch new file mode 100644 index 0000000000..241e30bf15 --- /dev/null +++ b/queue-6.19/revert-hwmon-ibmpex-fix-use-after-free-in-high-low-s.patch @@ -0,0 +1,89 @@ +From 411906da9a7be514ec3b84228cf1bdcabe1ad572 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Feb 2026 08:12:25 -0800 +Subject: Revert "hwmon: (ibmpex) fix use-after-free in high/low store" + +From: Guenter Roeck + +[ Upstream commit 8bde3e395a85017f12af2b0ba5c3684f5af9c006 ] + +This reverts commit 6946c726c3f4c36f0f049e6f97e88c510b15f65d. + +Jean Delvare points out that the patch does not completely +fix the reported problem, that it in fact introduces a +(new) race condition, and that it may actually not be needed in +the first place. + +Various AI reviews agree. Specific and relevant AI feedback: + +" +This reordering sets the driver data to NULL before removing the sensor +attributes in the loop below. + +ibmpex_show_sensor() retrieves this driver data via dev_get_drvdata() but +does not check if it is NULL before dereferencing it to access +data->sensors[]. + +If a userspace process reads a sensor file (like temp1_input) while this +delete function is running, could it race with the dev_set_drvdata(..., +NULL) call here and crash in ibmpex_show_sensor()? + +Would it be safer to keep the original order where device_remove_file() is +called before clearing the driver data? device_remove_file() should wait +for any active sysfs callbacks to complete, which might already prevent the +use-after-free this patch intends to fix. +" + +Revert the offending patch. If it can be shown that the originally reported +alleged race condition does indeed exist, it can always be re-introduced +with a complete fix. + +Reported-by: Jean Delvare +Closes: https://lore.kernel.org/linux-hwmon/20260121095342.73e723cb@endymion/ +Cc: Jean Delvare +Cc: Junrui Luo +Fixes: 6946c726c3f4 ("hwmon: (ibmpex) fix use-after-free in high/low store") +Reviewed-by: Jean Delvare +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + drivers/hwmon/ibmpex.c | 9 ++------- + 1 file changed, 2 insertions(+), 7 deletions(-) + +diff --git a/drivers/hwmon/ibmpex.c b/drivers/hwmon/ibmpex.c +index 129f3a9e8fe96..228c5f6c6f383 100644 +--- a/drivers/hwmon/ibmpex.c ++++ b/drivers/hwmon/ibmpex.c +@@ -277,9 +277,6 @@ static ssize_t ibmpex_high_low_store(struct device *dev, + { + struct ibmpex_bmc_data *data = dev_get_drvdata(dev); + +- if (!data) +- return -ENODEV; +- + ibmpex_reset_high_low_data(data); + + return count; +@@ -511,9 +508,6 @@ static void ibmpex_bmc_delete(struct ibmpex_bmc_data *data) + { + int i, j; + +- hwmon_device_unregister(data->hwmon_dev); +- dev_set_drvdata(data->bmc_device, NULL); +- + device_remove_file(data->bmc_device, + &sensor_dev_attr_reset_high_low.dev_attr); + device_remove_file(data->bmc_device, &dev_attr_name.attr); +@@ -527,7 +521,8 @@ static void ibmpex_bmc_delete(struct ibmpex_bmc_data *data) + } + + list_del(&data->list); +- ++ dev_set_drvdata(data->bmc_device, NULL); ++ hwmon_device_unregister(data->hwmon_dev); + ipmi_destroy_user(data->user); + kfree(data->sensors); + kfree(data); +-- +2.51.0 + diff --git a/queue-6.19/revert-mailbox-pcc-support-mailbox-management-of-the.patch b/queue-6.19/revert-mailbox-pcc-support-mailbox-management-of-the.patch new file mode 100644 index 0000000000..197b1ccd49 --- /dev/null +++ b/queue-6.19/revert-mailbox-pcc-support-mailbox-management-of-the.patch @@ -0,0 +1,254 @@ +From 2a6697eeb152ea0b4aa901461764bc795b52a970 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Oct 2025 20:08:15 +0100 +Subject: Revert "mailbox/pcc: support mailbox management of the shared buffer" + +From: Sudeep Holla + +[ Upstream commit f82c3e62b6b8c31d8c56415bf38658f306fda4cb ] + +This reverts commit 5378bdf6a611a32500fccf13d14156f219bb0c85. + +Commit 5378bdf6a611 ("mailbox/pcc: support mailbox management of the shared buffer") +attempted to introduce generic helpers for managing the PCC shared memory, +but it largely duplicates functionality already provided by the mailbox +core and leaves gaps: + +1. TX preparation: The mailbox framework already supports this via + ->tx_prepare callback for mailbox clients. The patch adds + pcc_write_to_buffer() and expects clients to toggle pchan->chan.manage_writes, + but no drivers set manage_writes, so pcc_write_to_buffer() has no users. + +2. RX handling: Data reception is already delivered through + mbox_chan_received_data() and client ->rx_callback. The patch adds an + optional pchan->chan.rx_alloc, which again has no users and duplicates + the existing path. + +3. Completion handling: While adding last_tx_done is directionally useful, + the implementation only covers Type 3/4 and fails to handle the absence + of a command_complete register, so it is incomplete for other types. + +Given the duplication and incomplete coverage, revert this change. Any new +requirements should be addressed in focused follow-ups rather than bundling +multiple behavioral changes together. + +Fixes: 5378bdf6a611 ("mailbox/pcc: support mailbox management of the shared buffer") +Signed-off-by: Sudeep Holla +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/pcc.c | 102 ++---------------------------------------- + include/acpi/pcc.h | 29 ------------ + 2 files changed, 4 insertions(+), 127 deletions(-) + +diff --git a/drivers/mailbox/pcc.c b/drivers/mailbox/pcc.c +index ff292b9e0be9e..0e0a66359d4c3 100644 +--- a/drivers/mailbox/pcc.c ++++ b/drivers/mailbox/pcc.c +@@ -305,22 +305,6 @@ static void pcc_chan_acknowledge(struct pcc_chan_info *pchan) + pcc_chan_reg_read_modify_write(&pchan->db); + } + +-static void *write_response(struct pcc_chan_info *pchan) +-{ +- struct pcc_header pcc_header; +- void *buffer; +- int data_len; +- +- memcpy_fromio(&pcc_header, pchan->chan.shmem, +- sizeof(pcc_header)); +- data_len = pcc_header.length - sizeof(u32) + sizeof(struct pcc_header); +- +- buffer = pchan->chan.rx_alloc(pchan->chan.mchan->cl, data_len); +- if (buffer != NULL) +- memcpy_fromio(buffer, pchan->chan.shmem, data_len); +- return buffer; +-} +- + /** + * pcc_mbox_irq - PCC mailbox interrupt handler + * @irq: interrupt number +@@ -332,8 +316,6 @@ static irqreturn_t pcc_mbox_irq(int irq, void *p) + { + struct pcc_chan_info *pchan; + struct mbox_chan *chan = p; +- struct pcc_header *pcc_header = chan->active_req; +- void *handle = NULL; + + pchan = chan->con_priv; + +@@ -357,17 +339,7 @@ static irqreturn_t pcc_mbox_irq(int irq, void *p) + * required to avoid any possible race in updatation of this flag. + */ + pchan->chan_in_use = false; +- +- if (pchan->chan.rx_alloc) +- handle = write_response(pchan); +- +- if (chan->active_req) { +- pcc_header = chan->active_req; +- if (pcc_header->flags & PCC_CMD_COMPLETION_NOTIFY) +- mbox_chan_txdone(chan, 0); +- } +- +- mbox_chan_received_data(chan, handle); ++ mbox_chan_received_data(chan, NULL); + + pcc_chan_acknowledge(pchan); + +@@ -411,24 +383,9 @@ pcc_mbox_request_channel(struct mbox_client *cl, int subspace_id) + pcc_mchan = &pchan->chan; + pcc_mchan->shmem = acpi_os_ioremap(pcc_mchan->shmem_base_addr, + pcc_mchan->shmem_size); +- if (!pcc_mchan->shmem) +- goto err; +- +- pcc_mchan->manage_writes = false; +- +- /* This indicates that the channel is ready to accept messages. +- * This needs to happen after the channel has registered +- * its callback. There is no access point to do that in +- * the mailbox API. That implies that the mailbox client must +- * have set the allocate callback function prior to +- * sending any messages. +- */ +- if (pchan->type == ACPI_PCCT_TYPE_EXT_PCC_SLAVE_SUBSPACE) +- pcc_chan_reg_read_modify_write(&pchan->cmd_update); +- +- return pcc_mchan; ++ if (pcc_mchan->shmem) ++ return pcc_mchan; + +-err: + mbox_free_channel(chan); + return ERR_PTR(-ENXIO); + } +@@ -459,38 +416,8 @@ void pcc_mbox_free_channel(struct pcc_mbox_chan *pchan) + } + EXPORT_SYMBOL_GPL(pcc_mbox_free_channel); + +-static int pcc_write_to_buffer(struct mbox_chan *chan, void *data) +-{ +- struct pcc_chan_info *pchan = chan->con_priv; +- struct pcc_mbox_chan *pcc_mbox_chan = &pchan->chan; +- struct pcc_header *pcc_header = data; +- +- if (!pchan->chan.manage_writes) +- return 0; +- +- /* The PCC header length includes the command field +- * but not the other values from the header. +- */ +- int len = pcc_header->length - sizeof(u32) + sizeof(struct pcc_header); +- u64 val; +- +- pcc_chan_reg_read(&pchan->cmd_complete, &val); +- if (!val) { +- pr_info("%s pchan->cmd_complete not set", __func__); +- return -1; +- } +- memcpy_toio(pcc_mbox_chan->shmem, data, len); +- return 0; +-} +- +- + /** +- * pcc_send_data - Called from Mailbox Controller code. If +- * pchan->chan.rx_alloc is set, then the command complete +- * flag is checked and the data is written to the shared +- * buffer io memory. +- * +- * If pchan->chan.rx_alloc is not set, then it is used ++ * pcc_send_data - Called from Mailbox Controller code. Used + * here only to ring the channel doorbell. The PCC client + * specific read/write is done in the client driver in + * order to maintain atomicity over PCC channel once +@@ -506,37 +433,17 @@ static int pcc_send_data(struct mbox_chan *chan, void *data) + int ret; + struct pcc_chan_info *pchan = chan->con_priv; + +- ret = pcc_write_to_buffer(chan, data); +- if (ret) +- return ret; +- + ret = pcc_chan_reg_read_modify_write(&pchan->cmd_update); + if (ret) + return ret; + + ret = pcc_chan_reg_read_modify_write(&pchan->db); +- + if (!ret && pchan->plat_irq > 0) + pchan->chan_in_use = true; + + return ret; + } + +- +-static bool pcc_last_tx_done(struct mbox_chan *chan) +-{ +- struct pcc_chan_info *pchan = chan->con_priv; +- u64 val; +- +- pcc_chan_reg_read(&pchan->cmd_complete, &val); +- if (!val) +- return false; +- else +- return true; +-} +- +- +- + /** + * pcc_startup - Called from Mailbox Controller code. Used here + * to request the interrupt. +@@ -582,7 +489,6 @@ static const struct mbox_chan_ops pcc_chan_ops = { + .send_data = pcc_send_data, + .startup = pcc_startup, + .shutdown = pcc_shutdown, +- .last_tx_done = pcc_last_tx_done, + }; + + /** +diff --git a/include/acpi/pcc.h b/include/acpi/pcc.h +index 9af3b502f8395..840bfc95bae33 100644 +--- a/include/acpi/pcc.h ++++ b/include/acpi/pcc.h +@@ -17,35 +17,6 @@ struct pcc_mbox_chan { + u32 latency; + u32 max_access_rate; + u16 min_turnaround_time; +- +- /* Set to true to indicate that the mailbox should manage +- * writing the dat to the shared buffer. This differs from +- * the case where the drivesr are writing to the buffer and +- * using send_data only to ring the doorbell. If this flag +- * is set, then the void * data parameter of send_data must +- * point to a kernel-memory buffer formatted in accordance with +- * the PCC specification. +- * +- * The active buffer management will include reading the +- * notify_on_completion flag, and will then +- * call mbox_chan_txdone when the acknowledgment interrupt is +- * received. +- */ +- bool manage_writes; +- +- /* Optional callback that allows the driver +- * to allocate the memory used for receiving +- * messages. The return value is the location +- * inside the buffer where the mailbox should write the data. +- */ +- void *(*rx_alloc)(struct mbox_client *cl, int size); +-}; +- +-struct pcc_header { +- u32 signature; +- u32 flags; +- u32 length; +- u32 command; + }; + + /* Generic Communications Channel Shared Memory Region */ +-- +2.51.0 + diff --git a/queue-6.19/revert-mmc-rtsx_pci_sdmmc-increase-power-on-settling.patch b/queue-6.19/revert-mmc-rtsx_pci_sdmmc-increase-power-on-settling.patch new file mode 100644 index 0000000000..2683af2617 --- /dev/null +++ b/queue-6.19/revert-mmc-rtsx_pci_sdmmc-increase-power-on-settling.patch @@ -0,0 +1,39 @@ +From 8a6be073c80e53d8da728ab8ce35d8f615b7fcd0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 15:49:31 +0100 +Subject: Revert "mmc: rtsx_pci_sdmmc: increase power-on settling delay to 5ms" + +From: Greg Kroah-Hartman + +[ Upstream commit ff112f1ecd10b72004eac05bae395e1c65f0c63c ] + +This reverts commit aced969e9bf3701dc75cfca57c78c031b7875b9d. + +It was determined that this was not the correct "fix", so should be +reverted. + +Fixes: aced969e9bf3 ("mmc: rtsx_pci_sdmmc: increase power-on settling delay to 5ms") +Cc: Matthew Schwartz +Cc: Ulf Hansson +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/mmc/host/rtsx_pci_sdmmc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c +index b6cf1803c7d27..4db3328f46dfb 100644 +--- a/drivers/mmc/host/rtsx_pci_sdmmc.c ++++ b/drivers/mmc/host/rtsx_pci_sdmmc.c +@@ -937,7 +937,7 @@ static int sd_power_on(struct realtek_pci_sdmmc *host, unsigned char power_mode) + if (err < 0) + return err; + +- mdelay(5); ++ mdelay(1); + + err = rtsx_pci_write_register(pcr, CARD_OE, SD_OUTPUT_EN, SD_OUTPUT_EN); + if (err < 0) +-- +2.51.0 + diff --git a/queue-6.19/revert-net-smc-introduce-tcp-ulp-support.patch b/queue-6.19/revert-net-smc-introduce-tcp-ulp-support.patch new file mode 100644 index 0000000000..6092a9ea6e --- /dev/null +++ b/queue-6.19/revert-net-smc-introduce-tcp-ulp-support.patch @@ -0,0 +1,195 @@ +From bbd1ae27d75feb4d077632d369f7db24c344363f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 13:54:52 +0800 +Subject: Revert "net/smc: Introduce TCP ULP support" + +From: D. Wythe + +[ Upstream commit df31a6b0a3057e66994ad6ccf5d95b9b9514f033 ] + +This reverts commit d7cd421da9da2cc7b4d25b8537f66db5c8331c40. + +As reported by Al Viro, the TCP ULP support for SMC is fundamentally +broken. The implementation attempts to convert an active TCP socket +into an SMC socket by modifying the underlying `struct file`, dentry, +and inode in-place, which violates core VFS invariants that assume +these structures are immutable for an open file, creating a risk of +use after free errors and general system instability. + +Given the severity of this design flaw and the fact that cleaner +alternatives (e.g., LD_PRELOAD, BPF) exist for legacy application +transparency, the correct course of action is to remove this feature +entirely. + +Fixes: d7cd421da9da ("net/smc: Introduce TCP ULP support") +Link: https://lore.kernel.org/netdev/Yus1SycZxcd+wHwz@ZenIV/ +Reported-by: Al Viro +Signed-off-by: D. Wythe +Reviewed-by: Tony Lu +Reviewed-by: Dust Li +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260128055452.98251-1-alibuda@linux.alibaba.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/smc/af_smc.c | 91 +++--------------------------------------------- + 1 file changed, 4 insertions(+), 87 deletions(-) + +diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c +index f97f77b041d97..d8201eb3ac5f3 100644 +--- a/net/smc/af_smc.c ++++ b/net/smc/af_smc.c +@@ -3357,11 +3357,10 @@ int smc_create_clcsk(struct net *net, struct sock *sk, int family) + return 0; + } + +-static int __smc_create(struct net *net, struct socket *sock, int protocol, +- int kern, struct socket *clcsock) ++static int smc_create(struct net *net, struct socket *sock, int protocol, ++ int kern) + { + int family = (protocol == SMCPROTO_SMC6) ? PF_INET6 : PF_INET; +- struct smc_sock *smc; + struct sock *sk; + int rc; + +@@ -3380,15 +3379,7 @@ static int __smc_create(struct net *net, struct socket *sock, int protocol, + if (!sk) + goto out; + +- /* create internal TCP socket for CLC handshake and fallback */ +- smc = smc_sk(sk); +- +- rc = 0; +- if (clcsock) +- smc->clcsock = clcsock; +- else +- rc = smc_create_clcsk(net, sk, family); +- ++ rc = smc_create_clcsk(net, sk, family); + if (rc) { + sk_common_release(sk); + sock->sk = NULL; +@@ -3397,76 +3388,12 @@ static int __smc_create(struct net *net, struct socket *sock, int protocol, + return rc; + } + +-static int smc_create(struct net *net, struct socket *sock, int protocol, +- int kern) +-{ +- return __smc_create(net, sock, protocol, kern, NULL); +-} +- + static const struct net_proto_family smc_sock_family_ops = { + .family = PF_SMC, + .owner = THIS_MODULE, + .create = smc_create, + }; + +-static int smc_ulp_init(struct sock *sk) +-{ +- struct socket *tcp = sk->sk_socket; +- struct net *net = sock_net(sk); +- struct socket *smcsock; +- int protocol, ret; +- +- /* only TCP can be replaced */ +- if (tcp->type != SOCK_STREAM || sk->sk_protocol != IPPROTO_TCP || +- (sk->sk_family != AF_INET && sk->sk_family != AF_INET6)) +- return -ESOCKTNOSUPPORT; +- /* don't handle wq now */ +- if (tcp->state != SS_UNCONNECTED || !tcp->file || tcp->wq.fasync_list) +- return -ENOTCONN; +- +- if (sk->sk_family == AF_INET) +- protocol = SMCPROTO_SMC; +- else +- protocol = SMCPROTO_SMC6; +- +- smcsock = sock_alloc(); +- if (!smcsock) +- return -ENFILE; +- +- smcsock->type = SOCK_STREAM; +- __module_get(THIS_MODULE); /* tried in __tcp_ulp_find_autoload */ +- ret = __smc_create(net, smcsock, protocol, 1, tcp); +- if (ret) { +- sock_release(smcsock); /* module_put() which ops won't be NULL */ +- return ret; +- } +- +- /* replace tcp socket to smc */ +- smcsock->file = tcp->file; +- smcsock->file->private_data = smcsock; +- smcsock->file->f_inode = SOCK_INODE(smcsock); /* replace inode when sock_close */ +- smcsock->file->f_path.dentry->d_inode = SOCK_INODE(smcsock); /* dput() in __fput */ +- tcp->file = NULL; +- +- return ret; +-} +- +-static void smc_ulp_clone(const struct request_sock *req, struct sock *newsk, +- const gfp_t priority) +-{ +- struct inet_connection_sock *icsk = inet_csk(newsk); +- +- /* don't inherit ulp ops to child when listen */ +- icsk->icsk_ulp_ops = NULL; +-} +- +-static struct tcp_ulp_ops smc_ulp_ops __read_mostly = { +- .name = "smc", +- .owner = THIS_MODULE, +- .init = smc_ulp_init, +- .clone = smc_ulp_clone, +-}; +- + unsigned int smc_net_id; + + static __net_init int smc_net_init(struct net *net) +@@ -3589,16 +3516,10 @@ static int __init smc_init(void) + pr_err("%s: ib_register fails with %d\n", __func__, rc); + goto out_sock; + } +- +- rc = tcp_register_ulp(&smc_ulp_ops); +- if (rc) { +- pr_err("%s: tcp_ulp_register fails with %d\n", __func__, rc); +- goto out_ib; +- } + rc = smc_inet_init(); + if (rc) { + pr_err("%s: smc_inet_init fails with %d\n", __func__, rc); +- goto out_ulp; ++ goto out_ib; + } + rc = bpf_smc_hs_ctrl_init(); + if (rc) { +@@ -3610,8 +3531,6 @@ static int __init smc_init(void) + return 0; + out_inet: + smc_inet_exit(); +-out_ulp: +- tcp_unregister_ulp(&smc_ulp_ops); + out_ib: + smc_ib_unregister_client(); + out_sock: +@@ -3647,7 +3566,6 @@ static void __exit smc_exit(void) + { + static_branch_disable(&tcp_have_smc); + smc_inet_exit(); +- tcp_unregister_ulp(&smc_ulp_ops); + sock_unregister(PF_SMC); + smc_core_exit(); + smc_ib_unregister_client(); +@@ -3672,7 +3590,6 @@ MODULE_AUTHOR("Ursula Braun "); + MODULE_DESCRIPTION("smc socket address family"); + MODULE_LICENSE("GPL"); + MODULE_ALIAS_NETPROTO(PF_SMC); +-MODULE_ALIAS_TCP_ULP("smc"); + /* 256 for IPPROTO_SMC and 1 for SOCK_STREAM */ + MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET, 256, 1); + #if IS_ENABLED(CONFIG_IPV6) +-- +2.51.0 + diff --git a/queue-6.19/riscv-dts-sophgo-cv180x-fix-usb-dwc2-fifo-sizes.patch b/queue-6.19/riscv-dts-sophgo-cv180x-fix-usb-dwc2-fifo-sizes.patch new file mode 100644 index 0000000000..91e269313a --- /dev/null +++ b/queue-6.19/riscv-dts-sophgo-cv180x-fix-usb-dwc2-fifo-sizes.patch @@ -0,0 +1,51 @@ +From 2da02fa4a62d4eed65cb97a12b1879cbee3d3048 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 26 Nov 2025 21:21:16 +0400 +Subject: riscv: dts: sophgo: cv180x: fix USB dwc2 FIFO sizes + +From: Anton D. Stavinskii + +[ Upstream commit 03ea8676919af21b99bea01f18ef1a271d19f92f ] + +I've tested the current dwc2 FIFO configuration and found that USB +device mode breaks in ECM mode when transmitting frames larger than +128 bytes. For example, large ICMP packets or iperf3 traffic cause +the USB link to hang and eventually disconnect without any messages in +dmesg. + +After switching to more conservative FIFO sizes, ECM becomes stable +and no longer drops the connection. iperf3 now shows ~130 Mbit/s RX +and ~100 Mbit/s TX on SG2002 (MilkV Duo 256M). + +Fix the FIFO sizes accordingly. + +Signed-off-by: Anton D. Stavinskii +Reviewed-by: Inochi Amaoto +Fixes: e307248a3c2d ("riscv: dts: sophgo: Add USB support for cv18xx") +Link: https://lore.kernel.org/r/20251126172115.1894190-2-stavinsky@gmail.com +Signed-off-by: Inochi Amaoto +Signed-off-by: Chen Wang +Signed-off-by: Chen Wang +Signed-off-by: Sasha Levin +--- + arch/riscv/boot/dts/sophgo/cv180x.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/riscv/boot/dts/sophgo/cv180x.dtsi b/arch/riscv/boot/dts/sophgo/cv180x.dtsi +index 1b2b1969a6484..06b0ce5a2db7a 100644 +--- a/arch/riscv/boot/dts/sophgo/cv180x.dtsi ++++ b/arch/riscv/boot/dts/sophgo/cv180x.dtsi +@@ -438,8 +438,8 @@ usb: usb@4340000 { + clocks = <&clk CLK_AXI4_USB>, <&clk CLK_APB_USB>; + clock-names = "otg", "utmi"; + g-np-tx-fifo-size = <32>; +- g-rx-fifo-size = <536>; +- g-tx-fifo-size = <768 512 512 384 128 128>; ++ g-rx-fifo-size = <1536>; ++ g-tx-fifo-size = <128 128 64 64 64 64 32 32>; + interrupts = ; + phys = <&usbphy>; + phy-names = "usb2-phy"; +-- +2.51.0 + diff --git a/queue-6.19/rnbd-srv-fix-server-side-setting-of-bi_size-for-spec.patch b/queue-6.19/rnbd-srv-fix-server-side-setting-of-bi_size-for-spec.patch new file mode 100644 index 0000000000..62d368e8f6 --- /dev/null +++ b/queue-6.19/rnbd-srv-fix-server-side-setting-of-bi_size-for-spec.patch @@ -0,0 +1,80 @@ +From 866f4c4705cc3b5288561a48ffd52f1fa2ba3199 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Dec 2025 13:47:32 +0100 +Subject: rnbd-srv: Fix server side setting of bi_size for special IOs + +From: Florian-Ewald Mueller + +[ Upstream commit 4ac9690d4b9456ca1d5276d86547fa2e7cd47684 ] + +On rnbd-srv, the bi_size of the bio is set during the bio_add_page +function, to which datalen is passed. But for special IOs like DISCARD +and WRITE_ZEROES, datalen is 0, since there is no data to write. For +these special IOs, use the bi_size of the rnbd_msg_io. + +Fixes: f6f84be089c9 ("block/rnbd-srv: Add sanity check and remove redundant assignment") +Signed-off-by: Florian-Ewald Mueller +Signed-off-by: Md Haris Iqbal +Signed-off-by: Grzegorz Prajsner +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/block/rnbd/rnbd-srv.c | 33 +++++++++++++++++++++++---------- + 1 file changed, 23 insertions(+), 10 deletions(-) + +diff --git a/drivers/block/rnbd/rnbd-srv.c b/drivers/block/rnbd/rnbd-srv.c +index 2df8941a6b146..9b3fdc202e152 100644 +--- a/drivers/block/rnbd/rnbd-srv.c ++++ b/drivers/block/rnbd/rnbd-srv.c +@@ -145,18 +145,30 @@ static int process_rdma(struct rnbd_srv_session *srv_sess, + priv->sess_dev = sess_dev; + priv->id = id; + +- bio = bio_alloc(file_bdev(sess_dev->bdev_file), 1, ++ bio = bio_alloc(file_bdev(sess_dev->bdev_file), !!datalen, + rnbd_to_bio_flags(le32_to_cpu(msg->rw)), GFP_KERNEL); +- bio_add_virt_nofail(bio, data, datalen); +- +- bio->bi_opf = rnbd_to_bio_flags(le32_to_cpu(msg->rw)); +- if (bio_has_data(bio) && +- bio->bi_iter.bi_size != le32_to_cpu(msg->bi_size)) { +- rnbd_srv_err_rl(sess_dev, "Datalen mismatch: bio bi_size (%u), bi_size (%u)\n", +- bio->bi_iter.bi_size, msg->bi_size); +- err = -EINVAL; +- goto bio_put; ++ if (unlikely(!bio)) { ++ err = -ENOMEM; ++ goto put_sess_dev; + } ++ ++ if (!datalen) { ++ /* ++ * For special requests like DISCARD and WRITE_ZEROES, the datalen is zero. ++ */ ++ bio->bi_iter.bi_size = le32_to_cpu(msg->bi_size); ++ } else { ++ bio_add_virt_nofail(bio, data, datalen); ++ bio->bi_opf = rnbd_to_bio_flags(le32_to_cpu(msg->rw)); ++ if (bio->bi_iter.bi_size != le32_to_cpu(msg->bi_size)) { ++ rnbd_srv_err_rl(sess_dev, ++ "Datalen mismatch: bio bi_size (%u), bi_size (%u)\n", ++ bio->bi_iter.bi_size, msg->bi_size); ++ err = -EINVAL; ++ goto bio_put; ++ } ++ } ++ + bio->bi_end_io = rnbd_dev_bi_end_io; + bio->bi_private = priv; + bio->bi_iter.bi_sector = le64_to_cpu(msg->sector); +@@ -170,6 +182,7 @@ static int process_rdma(struct rnbd_srv_session *srv_sess, + + bio_put: + bio_put(bio); ++put_sess_dev: + rnbd_put_sess_dev(sess_dev); + err: + kfree(priv); +-- +2.51.0 + diff --git a/queue-6.19/rqspinlock-fix-tas-fallback-lock-entry-creation.patch b/queue-6.19/rqspinlock-fix-tas-fallback-lock-entry-creation.patch new file mode 100644 index 0000000000..68548e09d4 --- /dev/null +++ b/queue-6.19/rqspinlock-fix-tas-fallback-lock-entry-creation.patch @@ -0,0 +1,67 @@ +From c819a3a6f84735142bcd375e352d7926ee22fbe5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 03:59:11 -0800 +Subject: rqspinlock: Fix TAS fallback lock entry creation + +From: Kumar Kartikeya Dwivedi + +[ Upstream commit 82f3b142c99cf44c7b1e70b7720169c646b9760f ] + +The TAS fallback can be invoked directly when queued spin locks are +disabled, and through the slow path when paravirt is enabled for queued +spin locks. In the latter case, the res_spin_lock macro will attempt the +fast path and already hold the entry when entering the slow path. This +will lead to creation of extraneous entries that are not released, which +may cause false positives for deadlock detection. + +Fix this by always preceding invocation of the TAS fallback in every +case with the grabbing of the held lock entry, and add a comment to make +note of this. + +Fixes: c9102a68c070 ("rqspinlock: Add a test-and-set fallback") +Reported-by: Amery Hung +Signed-off-by: Kumar Kartikeya Dwivedi +Tested-by: Amery Hung +Link: https://lore.kernel.org/r/20260122115911.3668985-1-memxor@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + include/asm-generic/rqspinlock.h | 2 +- + kernel/bpf/rqspinlock.c | 7 ++++--- + 2 files changed, 5 insertions(+), 4 deletions(-) + +diff --git a/include/asm-generic/rqspinlock.h b/include/asm-generic/rqspinlock.h +index 0f2dcbbfee2f0..5c5cf2f7fc395 100644 +--- a/include/asm-generic/rqspinlock.h ++++ b/include/asm-generic/rqspinlock.h +@@ -191,7 +191,7 @@ static __always_inline int res_spin_lock(rqspinlock_t *lock) + + #else + +-#define res_spin_lock(lock) resilient_tas_spin_lock(lock) ++#define res_spin_lock(lock) ({ grab_held_lock_entry(lock); resilient_tas_spin_lock(lock); }) + + #endif /* CONFIG_QUEUED_SPINLOCKS */ + +diff --git a/kernel/bpf/rqspinlock.c b/kernel/bpf/rqspinlock.c +index f7d0c8d4644ed..2fdfa828e3d35 100644 +--- a/kernel/bpf/rqspinlock.c ++++ b/kernel/bpf/rqspinlock.c +@@ -265,10 +265,11 @@ int __lockfunc resilient_tas_spin_lock(rqspinlock_t *lock) + + RES_INIT_TIMEOUT(ts); + /* +- * The fast path is not invoked for the TAS fallback, so we must grab +- * the deadlock detection entry here. ++ * We are either called directly from res_spin_lock after grabbing the ++ * deadlock detection entry when queued spinlocks are disabled, or from ++ * resilient_queued_spin_lock_slowpath after grabbing the deadlock ++ * detection entry. No need to obtain it here. + */ +- grab_held_lock_entry(lock); + + /* + * Since the waiting loop's time is dependent on the amount of +-- +2.51.0 + diff --git a/queue-6.19/rtc-amlogic-a4-remove-irqf_oneshot.patch b/queue-6.19/rtc-amlogic-a4-remove-irqf_oneshot.patch new file mode 100644 index 0000000000..8f71406b39 --- /dev/null +++ b/queue-6.19/rtc-amlogic-a4-remove-irqf_oneshot.patch @@ -0,0 +1,45 @@ +From 712b6673ca392aa369ccb0e29c98a101304fb4f2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:55:32 +0100 +Subject: rtc: amlogic-a4: Remove IRQF_ONESHOT + +From: Sebastian Andrzej Siewior + +[ Upstream commit 18d28446231390e4ea3634fb16200865df2c6506 ] + +Passing IRQF_ONESHOT ensures that the interrupt source is masked until +the secondary (threaded) handler is done. If only a primary handler is +used then the flag makes no sense because the interrupt can not fire +(again) while its handler is running. + +The flag also prevents force-threading of the primary handler and the +irq-core will warn about this. + +Remove IRQF_ONESHOT from irqflags. + +Fixes: c89ac9182ee29 ("rtc: support for the Amlogic on-chip RTC") +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Reviewed-by: Xianwei Zhao +Link: https://patch.msgid.link/20260128095540.863589-13-bigeasy@linutronix.de +Signed-off-by: Sasha Levin +--- + drivers/rtc/rtc-amlogic-a4.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/rtc/rtc-amlogic-a4.c b/drivers/rtc/rtc-amlogic-a4.c +index 123fb372fc9fe..50938c35af36a 100644 +--- a/drivers/rtc/rtc-amlogic-a4.c ++++ b/drivers/rtc/rtc-amlogic-a4.c +@@ -369,7 +369,7 @@ static int aml_rtc_probe(struct platform_device *pdev) + return PTR_ERR(rtc->rtc_dev); + + ret = devm_request_irq(dev, rtc->irq, aml_rtc_handler, +- IRQF_ONESHOT, "aml-rtc alarm", rtc); ++ 0, "aml-rtc alarm", rtc); + if (ret) { + dev_err_probe(dev, ret, "IRQ%d request failed, ret = %d\n", + rtc->irq, ret); +-- +2.51.0 + diff --git a/queue-6.19/rust-devres-fix-race-condition-due-to-nesting.patch b/queue-6.19/rust-devres-fix-race-condition-due-to-nesting.patch new file mode 100644 index 0000000000..05b79d0745 --- /dev/null +++ b/queue-6.19/rust-devres-fix-race-condition-due-to-nesting.patch @@ -0,0 +1,304 @@ +From 248eb55a8ce4c0d9fec7c5c05702d7fecfcdb73e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 23:25:15 +0100 +Subject: rust: devres: fix race condition due to nesting + +From: Danilo Krummrich + +[ Upstream commit ba268514ea14b44570030e8ed2aef92a38679e85 ] + +Commit f5d3ef25d238 ("rust: devres: get rid of Devres' inner Arc") did +attempt to optimize away the internal reference count of Devres. + +However, without an internal reference count, we can't support cases +where Devres is indirectly nested, resulting into a deadlock. + +Such indirect nesting easily happens in the following way: + +A registration object (which is guarded by devres) hold a reference +count of an object that holds a device resource guarded by devres +itself. + +For instance a drm::Registration holds a reference of a drm::Device. The +drm::Device itself holds a device resource in its private data. + +When the drm::Registration is dropped by devres, and it happens that it +did hold the last reference count of the drm::Device, it also drops the +device resource, which is guarded by devres itself. + +Thus, resulting into a deadlock in the Devres destructor of the device +resource, as in the following backtrace. + + sysrq: Show Blocked State + task:rmmod state:D stack:0 pid:1331 tgid:1331 ppid:1330 task_flags:0x400100 flags:0x00000010 + Call trace: + __switch_to+0x190/0x294 (T) + __schedule+0x878/0xf10 + schedule+0x4c/0xcc + schedule_timeout+0x44/0x118 + wait_for_common+0xc0/0x18c + wait_for_completion+0x18/0x24 + _RINvNtCs4gKlGRWyJ5S_4core3ptr13drop_in_placeINtNtNtCsgzhNYVB7wSz_6kernel4sync3arc3ArcINtNtBN_6devres6DevresmEEECsRdyc7Hyps3_15rust_driver_pci+0x68/0xe8 [rust_driver_pci] + _RINvNvNtCsgzhNYVB7wSz_6kernel6devres16register_foreign8callbackINtNtCs4gKlGRWyJ5S_4core3pin3PinINtNtNtB6_5alloc4kbox3BoxINtNtNtB6_4sync3arc3ArcINtB4_6DevresmEENtNtB1A_9allocator7KmallocEEECsRdyc7Hyps3_15rust_driver_pci+0x34/0xc8 [rust_driver_pci] + devm_action_release+0x14/0x20 + devres_release_all+0xb8/0x118 + device_release_driver_internal+0x1c4/0x28c + driver_detach+0x94/0xd4 + bus_remove_driver+0xdc/0x11c + driver_unregister+0x34/0x58 + pci_unregister_driver+0x20/0x80 + __arm64_sys_delete_module+0x1d8/0x254 + invoke_syscall+0x40/0xcc + el0_svc_common+0x8c/0xd8 + do_el0_svc+0x1c/0x28 + el0_svc+0x54/0x1d4 + el0t_64_sync_handler+0x84/0x12c + el0t_64_sync+0x198/0x19c + +In order to fix this, re-introduce the internal reference count. + +Reported-by: Boris Brezillon +Closes: https://rust-for-linux.zulipchat.com/#narrow/channel/288089-General/topic/.E2.9C.94.20Deadlock.20caused.20by.20nested.20Devres/with/571242651 +Reported-by: Markus Probst +Closes: https://rust-for-linux.zulipchat.com/#narrow/channel/288089-General/topic/.E2.9C.94.20Devres.20inside.20Devres.20stuck.20on.20cleanup/with/571239721 +Reported-by: Alice Ryhl +Closes: https://gitlab.freedesktop.org/panfrost/linux/-/merge_requests/56#note_3282757 +Fixes: f5d3ef25d238 ("rust: devres: get rid of Devres' inner Arc") +Reviewed-by: Greg Kroah-Hartman +Reviewed-by: Alice Ryhl +Tested-by: Boris Brezillon +Link: https://patch.msgid.link/20260205222529.91465-1-dakr@kernel.org +[ Call clone() prior to devm_add_action(). - Danilo ] +Signed-off-by: Danilo Krummrich +Signed-off-by: Sasha Levin +--- + rust/kernel/devres.rs | 149 ++++++++++++------------------------------ + 1 file changed, 40 insertions(+), 109 deletions(-) + +diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs +index db02f8b1788d4..a9917ce71ded4 100644 +--- a/rust/kernel/devres.rs ++++ b/rust/kernel/devres.rs +@@ -21,30 +21,11 @@ + sync::{ + aref::ARef, + rcu, +- Completion, // +- }, +- types::{ +- ForeignOwnable, +- Opaque, +- ScopeGuard, // ++ Arc, // + }, ++ types::ForeignOwnable, + }; + +-use pin_init::Wrapper; +- +-/// [`Devres`] inner data accessed from [`Devres::callback`]. +-#[pin_data] +-struct Inner { +- #[pin] +- data: Revocable, +- /// Tracks whether [`Devres::callback`] has been completed. +- #[pin] +- devm: Completion, +- /// Tracks whether revoking [`Self::data`] has been completed. +- #[pin] +- revoke: Completion, +-} +- + /// This abstraction is meant to be used by subsystems to containerize [`Device`] bound resources to + /// manage their lifetime. + /// +@@ -118,18 +99,13 @@ struct Inner { + /// # fn no_run(dev: &Device) -> Result<(), Error> { + /// // SAFETY: Invalid usage for example purposes. + /// let iomem = unsafe { IoMem::<{ core::mem::size_of::() }>::new(0xBAAAAAAD)? }; +-/// let devres = KBox::pin_init(Devres::new(dev, iomem), GFP_KERNEL)?; ++/// let devres = Devres::new(dev, iomem)?; + /// + /// let res = devres.try_access().ok_or(ENXIO)?; + /// res.write8(0x42, 0x0); + /// # Ok(()) + /// # } + /// ``` +-/// +-/// # Invariants +-/// +-/// `Self::inner` is guaranteed to be initialized and is always accessed read-only. +-#[pin_data(PinnedDrop)] + pub struct Devres { + dev: ARef, + /// Pointer to [`Self::devres_callback`]. +@@ -137,14 +113,7 @@ pub struct Devres { + /// Has to be stored, since Rust does not guarantee to always return the same address for a + /// function. However, the C API uses the address as a key. + callback: unsafe extern "C" fn(*mut c_void), +- /// Contains all the fields shared with [`Self::callback`]. +- // TODO: Replace with `UnsafePinned`, once available. +- // +- // Subsequently, the `drop_in_place()` in `Devres::drop` and `Devres::new` as well as the +- // explicit `Send` and `Sync' impls can be removed. +- #[pin] +- inner: Opaque>, +- _add_action: (), ++ data: Arc>, + } + + impl Devres { +@@ -152,74 +121,48 @@ impl Devres { + /// + /// The `data` encapsulated within the returned `Devres` instance' `data` will be + /// (revoked)[`Revocable`] once the device is detached. +- pub fn new<'a, E>( +- dev: &'a Device, +- data: impl PinInit + 'a, +- ) -> impl PinInit + 'a ++ pub fn new(dev: &Device, data: impl PinInit) -> Result + where +- T: 'a, + Error: From, + { +- try_pin_init!(&this in Self { +- dev: dev.into(), +- callback: Self::devres_callback, +- // INVARIANT: `inner` is properly initialized. +- inner <- Opaque::pin_init(try_pin_init!(Inner { +- devm <- Completion::new(), +- revoke <- Completion::new(), +- data <- Revocable::new(data), +- })), +- // TODO: Replace with "initializer code blocks" [1] once available. +- // +- // [1] https://github.com/Rust-for-Linux/pin-init/pull/69 +- _add_action: { +- // SAFETY: `this` is a valid pointer to uninitialized memory. +- let inner = unsafe { &raw mut (*this.as_ptr()).inner }; ++ let callback = Self::devres_callback; ++ let data = Arc::pin_init(Revocable::new(data), GFP_KERNEL)?; ++ let devres_data = data.clone(); + +- // SAFETY: +- // - `dev.as_raw()` is a pointer to a valid bound device. +- // - `inner` is guaranteed to be a valid for the duration of the lifetime of `Self`. +- // - `devm_add_action()` is guaranteed not to call `callback` until `this` has been +- // properly initialized, because we require `dev` (i.e. the *bound* device) to +- // live at least as long as the returned `impl PinInit`. +- to_result(unsafe { +- bindings::devm_add_action(dev.as_raw(), Some(*callback), inner.cast()) +- }).inspect_err(|_| { +- let inner = Opaque::cast_into(inner); ++ // SAFETY: ++ // - `dev.as_raw()` is a pointer to a valid bound device. ++ // - `data` is guaranteed to be a valid for the duration of the lifetime of `Self`. ++ // - `devm_add_action()` is guaranteed not to call `callback` for the entire lifetime of ++ // `dev`. ++ to_result(unsafe { ++ bindings::devm_add_action( ++ dev.as_raw(), ++ Some(callback), ++ Arc::as_ptr(&data).cast_mut().cast(), ++ ) ++ })?; + +- // SAFETY: `inner` is a valid pointer to an `Inner` and valid for both reads +- // and writes. +- unsafe { core::ptr::drop_in_place(inner) }; +- })?; +- }, +- }) +- } ++ // `devm_add_action()` was successful and has consumed the reference count. ++ core::mem::forget(devres_data); + +- fn inner(&self) -> &Inner { +- // SAFETY: By the type invairants of `Self`, `inner` is properly initialized and always +- // accessed read-only. +- unsafe { &*self.inner.get() } ++ Ok(Self { ++ dev: dev.into(), ++ callback, ++ data, ++ }) + } + + fn data(&self) -> &Revocable { +- &self.inner().data ++ &self.data + } + + #[allow(clippy::missing_safety_doc)] + unsafe extern "C" fn devres_callback(ptr: *mut kernel::ffi::c_void) { +- // SAFETY: In `Self::new` we've passed a valid pointer to `Inner` to `devm_add_action()`, +- // hence `ptr` must be a valid pointer to `Inner`. +- let inner = unsafe { &*ptr.cast::>() }; ++ // SAFETY: In `Self::new` we've passed a valid pointer of `Revocable` to ++ // `devm_add_action()`, hence `ptr` must be a valid pointer to `Revocable`. ++ let data = unsafe { Arc::from_raw(ptr.cast::>()) }; + +- // Ensure that `inner` can't be used anymore after we signal completion of this callback. +- let inner = ScopeGuard::new_with_data(inner, |inner| inner.devm.complete_all()); +- +- if !inner.data.revoke() { +- // If `revoke()` returns false, it means that `Devres::drop` already started revoking +- // `data` for us. Hence we have to wait until `Devres::drop` signals that it +- // completed revoking `data`. +- inner.revoke.wait_for_completion(); +- } ++ data.revoke(); + } + + fn remove_action(&self) -> bool { +@@ -231,7 +174,7 @@ fn remove_action(&self) -> bool { + bindings::devm_remove_action_nowarn( + self.dev.as_raw(), + Some(self.callback), +- core::ptr::from_ref(self.inner()).cast_mut().cast(), ++ core::ptr::from_ref(self.data()).cast_mut().cast(), + ) + } == 0) + } +@@ -302,31 +245,19 @@ unsafe impl Send for Devres {} + // SAFETY: `Devres` can be shared with any task, if `T: Sync`. + unsafe impl Sync for Devres {} + +-#[pinned_drop] +-impl PinnedDrop for Devres { +- fn drop(self: Pin<&mut Self>) { ++impl Drop for Devres { ++ fn drop(&mut self) { + // SAFETY: When `drop` runs, it is guaranteed that nobody is accessing the revocable data + // anymore, hence it is safe not to wait for the grace period to finish. + if unsafe { self.data().revoke_nosync() } { + // We revoked `self.data` before the devres action did, hence try to remove it. +- if !self.remove_action() { +- // We could not remove the devres action, which means that it now runs concurrently, +- // hence signal that `self.data` has been revoked by us successfully. +- self.inner().revoke.complete_all(); +- +- // Wait for `Self::devres_callback` to be done using this object. +- self.inner().devm.wait_for_completion(); ++ if self.remove_action() { ++ // SAFETY: In `Self::new` we have taken an additional reference count of `self.data` ++ // for `devm_add_action()`. Since `remove_action()` was successful, we have to drop ++ // this additional reference count. ++ drop(unsafe { Arc::from_raw(Arc::as_ptr(&self.data)) }); + } +- } else { +- // `Self::devres_callback` revokes `self.data` for us, hence wait for it to be done +- // using this object. +- self.inner().devm.wait_for_completion(); + } +- +- // INVARIANT: At this point it is guaranteed that `inner` can't be accessed any more. +- // +- // SAFETY: `inner` is valid for dropping. +- unsafe { core::ptr::drop_in_place(self.inner.get()) }; + } + } + +-- +2.51.0 + diff --git a/queue-6.19/rust-driver-core-use-kernel-vertical-style-for-impor.patch b/queue-6.19/rust-driver-core-use-kernel-vertical-style-for-impor.patch new file mode 100644 index 0000000000..0256326f11 --- /dev/null +++ b/queue-6.19/rust-driver-core-use-kernel-vertical-style-for-impor.patch @@ -0,0 +1,119 @@ +From 495d4d95441055321ba1e67e452d32546c90e217 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Jan 2026 15:19:44 +0100 +Subject: rust: driver-core: use "kernel vertical" style for imports + +From: Danilo Krummrich + +[ Upstream commit 52563c665b0b0b39f319bee40ecc5e8f25b9050a ] + +Convert all imports to use "kernel vertical" style. + +With this, subsequent patches neither introduce unrelated changes nor +leave an inconsistent import pattern. + +While at it, drop unnecessary imports covered by prelude::*. + +Link: https://docs.kernel.org/rust/coding-guidelines.html#imports +Reviewed-by: Greg Kroah-Hartman +Link: https://patch.msgid.link/20260105142123.95030-3-dakr@kernel.org +Signed-off-by: Danilo Krummrich +Stable-dep-of: ba268514ea14 ("rust: devres: fix race condition due to nesting") +Signed-off-by: Sasha Levin +--- + rust/kernel/device.rs | 14 +++++++++++--- + rust/kernel/devres.rs | 25 +++++++++++++++++++------ + rust/kernel/driver.rs | 12 ++++++++---- + 3 files changed, 38 insertions(+), 13 deletions(-) + +diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs +index 031720bf5d8ca..7b950b01f16d4 100644 +--- a/rust/kernel/device.rs ++++ b/rust/kernel/device.rs +@@ -5,12 +5,20 @@ + //! C header: [`include/linux/device.h`](srctree/include/linux/device.h) + + use crate::{ +- bindings, fmt, ++ bindings, ++ fmt, + prelude::*, + sync::aref::ARef, +- types::{ForeignOwnable, Opaque}, ++ types::{ ++ ForeignOwnable, ++ Opaque, // ++ }, // ++}; ++use core::{ ++ any::TypeId, ++ marker::PhantomData, ++ ptr, // + }; +-use core::{any::TypeId, marker::PhantomData, ptr}; + + #[cfg(CONFIG_PRINTK)] + use crate::c_str; +diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs +index 835d9c11948e7..db02f8b1788d4 100644 +--- a/rust/kernel/devres.rs ++++ b/rust/kernel/devres.rs +@@ -8,13 +8,26 @@ + use crate::{ + alloc::Flags, + bindings, +- device::{Bound, Device}, +- error::{to_result, Error, Result}, +- ffi::c_void, ++ device::{ ++ Bound, ++ Device, // ++ }, ++ error::to_result, + prelude::*, +- revocable::{Revocable, RevocableGuard}, +- sync::{aref::ARef, rcu, Completion}, +- types::{ForeignOwnable, Opaque, ScopeGuard}, ++ revocable::{ ++ Revocable, ++ RevocableGuard, // ++ }, ++ sync::{ ++ aref::ARef, ++ rcu, ++ Completion, // ++ }, ++ types::{ ++ ForeignOwnable, ++ Opaque, ++ ScopeGuard, // ++ }, + }; + + use pin_init::Wrapper; +diff --git a/rust/kernel/driver.rs b/rust/kernel/driver.rs +index bee3ae21a27b2..36de8098754d0 100644 +--- a/rust/kernel/driver.rs ++++ b/rust/kernel/driver.rs +@@ -94,10 +94,14 @@ + //! [`device_id`]: kernel::device_id + //! [`module_driver`]: kernel::module_driver + +-use crate::error::{Error, Result}; +-use crate::{acpi, device, of, str::CStr, try_pin_init, types::Opaque, ThisModule}; +-use core::pin::Pin; +-use pin_init::{pin_data, pinned_drop, PinInit}; ++use crate::{ ++ acpi, ++ device, ++ of, ++ prelude::*, ++ types::Opaque, ++ ThisModule, // ++}; + + /// Trait describing the layout of a specific device driver. + /// +-- +2.51.0 + diff --git a/queue-6.19/rust-pwm-fix-potential-memory-leak-on-init-error.patch b/queue-6.19/rust-pwm-fix-potential-memory-leak-on-init-error.patch new file mode 100644 index 0000000000..e34bcbac41 --- /dev/null +++ b/queue-6.19/rust-pwm-fix-potential-memory-leak-on-init-error.patch @@ -0,0 +1,48 @@ +From 05002960640c2e6ca28566e9e12832b6450f372f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 2 Jan 2026 09:51:41 +0200 +Subject: rust: pwm: Fix potential memory leak on init error +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Kari Argillander + +[ Upstream commit a2633dc243c35754a0c2270131d8a199c987c9bf ] + +When initializing a PWM chip using pwmchip_alloc(), the allocated device +owns an initial reference that must be released on all error paths. + +If __pinned_init() were to fail, the allocated pwm_chip would currently +leak because the error path returns without calling pwmchip_put(). + +Fixes: 7b3dce814a15 ("rust: pwm: Add Kconfig and basic data structures") +Signed-off-by: Kari Argillander +Acked-by: Michal Wilczynski +Link: https://patch.msgid.link/20260102-pwm-rust-v2-1-2702ce57d571@gmail.com +Signed-off-by: Uwe Kleine-König +Signed-off-by: Sasha Levin +--- + rust/kernel/pwm.rs | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/rust/kernel/pwm.rs b/rust/kernel/pwm.rs +index cb00f8a8765c8..2ba9cfd02bfdb 100644 +--- a/rust/kernel/pwm.rs ++++ b/rust/kernel/pwm.rs +@@ -601,7 +601,11 @@ pub fn new( + let drvdata_ptr = unsafe { bindings::pwmchip_get_drvdata(c_chip_ptr) }; + + // SAFETY: We construct the `T` object in-place in the allocated private memory. +- unsafe { data.__pinned_init(drvdata_ptr.cast())? }; ++ unsafe { data.__pinned_init(drvdata_ptr.cast()) }.inspect_err(|_| { ++ // SAFETY: It is safe to call `pwmchip_put()` with a valid pointer obtained ++ // from `pwmchip_alloc()`. We will not use pointer after this. ++ unsafe { bindings::pwmchip_put(c_chip_ptr) } ++ })?; + + // SAFETY: `c_chip_ptr` points to a valid chip. + unsafe { +-- +2.51.0 + diff --git a/queue-6.19/rust-task-restrict-task-group_leader-to-current.patch b/queue-6.19/rust-task-restrict-task-group_leader-to-current.patch new file mode 100644 index 0000000000..6a28c7cf01 --- /dev/null +++ b/queue-6.19/rust-task-restrict-task-group_leader-to-current.patch @@ -0,0 +1,102 @@ +From bafde4c2cc2b23d6e7500ff50ac75605e1f2c5d1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 08:28:46 +0000 +Subject: rust: task: restrict Task::group_leader() to current +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Alice Ryhl + +[ Upstream commit 105ddfb2d2b3acec7a7d9695463df48733d91e6c ] + +The Task::group_leader() method currently allows you to access the +group_leader() of any task, for example one you hold a refcount to. But +this is not safe in general since the group leader could change when a +task exits. See for example commit a15f37a40145c ("kernel/sys.c: fix the +racy usage of task_lock(tsk->group_leader) in sys_prlimit64() paths"). + +All existing users of Task::group_leader() call this method on current, +which is guaranteed running, so there's not an actual issue in Rust code +today. But to prevent code in the future from making this mistake, +restrict Task::group_leader() so that it can only be called on current. + +There are some other cases where accessing task->group_leader is okay. +For example it can be safe if you hold tasklist_lock or rcu_read_lock(). +However, only supporting current->group_leader is sufficient for all +in-tree Rust users of group_leader right now. Safe Rust functionality for +accessing it under rcu or while holding tasklist_lock may be added in the +future if required by any future Rust module. + +This patch is a bugfix in that it prevents users of this API from writing +incorrect code. It doesn't change behavior of correct code. + +Link: https://lkml.kernel.org/r/20260107-task-group-leader-v2-1-8fbf816f2a2f@google.com +Signed-off-by: Alice Ryhl +Fixes: 313c4281bc9d ("rust: add basic `Task`") +Reported-by: Oleg Nesterov +Closes: https://lore.kernel.org/all/aTLnV-5jlgfk1aRK@redhat.com/ +Reviewed-by: Boqun Feng +Reviewed-by: Gary Guo +Cc: Andreas Hindborg +Cc: Benno Lossin +Cc: "Björn Roy Baron" +Cc: Björn Roy Baron +Cc: Christian Brauner +Cc: Danilo Krummrich +Cc: FUJITA Tomonori +Cc: Miguel Ojeda +Cc: Panagiotis Foliadis +Cc: Shankari Anand +Cc: Trevor Gross +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + rust/kernel/task.rs | 24 ++++++++++++------------ + 1 file changed, 12 insertions(+), 12 deletions(-) + +diff --git a/rust/kernel/task.rs b/rust/kernel/task.rs +index 49fad6de06740..cc907fb531bce 100644 +--- a/rust/kernel/task.rs ++++ b/rust/kernel/task.rs +@@ -204,18 +204,6 @@ pub fn as_ptr(&self) -> *mut bindings::task_struct { + self.0.get() + } + +- /// Returns the group leader of the given task. +- pub fn group_leader(&self) -> &Task { +- // SAFETY: The group leader of a task never changes after initialization, so reading this +- // field is not a data race. +- let ptr = unsafe { *ptr::addr_of!((*self.as_ptr()).group_leader) }; +- +- // SAFETY: The lifetime of the returned task reference is tied to the lifetime of `self`, +- // and given that a task has a reference to its group leader, we know it must be valid for +- // the lifetime of the returned task reference. +- unsafe { &*ptr.cast() } +- } +- + /// Returns the PID of the given task. + pub fn pid(&self) -> Pid { + // SAFETY: The pid of a task never changes after initialization, so reading this field is +@@ -345,6 +333,18 @@ pub fn active_pid_ns(&self) -> Option<&PidNamespace> { + // `release_task()` call. + Some(unsafe { PidNamespace::from_ptr(active_ns) }) + } ++ ++ /// Returns the group leader of the current task. ++ pub fn group_leader(&self) -> &Task { ++ // SAFETY: The group leader of a task never changes while the task is running, and `self` ++ // is the current task, which is guaranteed running. ++ let ptr = unsafe { (*self.as_ptr()).group_leader }; ++ ++ // SAFETY: `current->group_leader` stays valid for at least the duration in which `current` ++ // is running, and the signature of this function ensures that the returned `&Task` can ++ // only be used while `current` is still valid, thus still running. ++ unsafe { &*ptr.cast() } ++ } + } + + // SAFETY: The type invariants guarantee that `Task` is always refcounted. +-- +2.51.0 + diff --git a/queue-6.19/s390-cio-fix-device-lifecycle-handling-in-css_alloc_.patch b/queue-6.19/s390-cio-fix-device-lifecycle-handling-in-css_alloc_.patch new file mode 100644 index 0000000000..6eeae8ed9d --- /dev/null +++ b/queue-6.19/s390-cio-fix-device-lifecycle-handling-in-css_alloc_.patch @@ -0,0 +1,49 @@ +From 8265b8931f681a2989c4f5944b23d006731ad7f7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 21:47:59 +0100 +Subject: s390/cio: Fix device lifecycle handling in css_alloc_subchannel() + +From: Salah Triki + +[ Upstream commit f65c75b0b9b5a390bc3beadcde0a6fbc3ad118f7 ] + +`css_alloc_subchannel()` calls `device_initialize()` before setting up +the DMA masks. If `dma_set_coherent_mask()` or `dma_set_mask()` fails, +the error path frees the subchannel structure directly, bypassing +the device model reference counting. + +Once `device_initialize()` has been called, the embedded struct device +must be released via `put_device()`, allowing the release callback to +free the container structure. + +Fix the error path by dropping the initial device reference with +`put_device()` instead of calling `kfree()` directly. + +This ensures correct device lifetime handling and avoids potential +use-after-free or double-free issues. + +Fixes: e5dcf0025d7af ("s390/css: move subchannel lock allocation") +Signed-off-by: Salah Triki +Reviewed-by: Vineeth Vijayan +Signed-off-by: Heiko Carstens +Signed-off-by: Sasha Levin +--- + drivers/s390/cio/css.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c +index 4c85df7a548ef..ac24e019020e8 100644 +--- a/drivers/s390/cio/css.c ++++ b/drivers/s390/cio/css.c +@@ -235,7 +235,7 @@ struct subchannel *css_alloc_subchannel(struct subchannel_id schid, + return sch; + + err: +- kfree(sch); ++ put_device(&sch->dev); + return ERR_PTR(ret); + } + +-- +2.51.0 + diff --git a/queue-6.19/sched-deadline-clear-the-defer-params.patch b/queue-6.19/sched-deadline-clear-the-defer-params.patch new file mode 100644 index 0000000000..94512ec9d2 --- /dev/null +++ b/queue-6.19/sched-deadline-clear-the-defer-params.patch @@ -0,0 +1,43 @@ +From 03e57c44e0abc79027c1870b5a1fa3c0638a71ec Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 10:58:59 +0100 +Subject: sched/deadline: Clear the defer params + +From: Joel Fernandes + +[ Upstream commit 3cb3b27693bf30defb16aa096158a3b24583b8d2 ] + +The defer params were not cleared in __dl_clear_params. Clear them. + +Without this is some of my test cases are flaking and the DL timer is +not starting correctly AFAICS. + +Fixes: a110a81c52a9 ("sched/deadline: Deferrable dl server") +Signed-off-by: Joel Fernandes +Signed-off-by: Peter Zijlstra (Intel) +Reviewed-by: Andrea Righi +Acked-by: Juri Lelli +Tested-by: Christian Loehle +Link: https://patch.msgid.link/20260126100050.3854740-2-arighi@nvidia.com +Signed-off-by: Sasha Levin +--- + kernel/sched/deadline.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c +index 7bcde7114f1b6..e3a6b8ed1d6db 100644 +--- a/kernel/sched/deadline.c ++++ b/kernel/sched/deadline.c +@@ -3656,6 +3656,9 @@ static void __dl_clear_params(struct sched_dl_entity *dl_se) + dl_se->dl_non_contending = 0; + dl_se->dl_overrun = 0; + dl_se->dl_server = 0; ++ dl_se->dl_defer = 0; ++ dl_se->dl_defer_running = 0; ++ dl_se->dl_defer_armed = 0; + + #ifdef CONFIG_RT_MUTEXES + dl_se->pi_se = dl_se; +-- +2.51.0 + diff --git a/queue-6.19/sched-export-hidden-tracepoints-to-modules.patch b/queue-6.19/sched-export-hidden-tracepoints-to-modules.patch new file mode 100644 index 0000000000..caec958a37 --- /dev/null +++ b/queue-6.19/sched-export-hidden-tracepoints-to-modules.patch @@ -0,0 +1,48 @@ +From df0ffe12e5bb0b27fccf64fd0db1fca85a75fabc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Dec 2025 14:16:16 +0100 +Subject: sched: Export hidden tracepoints to modules + +From: Gabriele Monaco + +[ Upstream commit 6c125b85f3c87b4bf7dba91af6f27d9600b9dba0 ] + +The tracepoints sched_entry, sched_exit and sched_set_need_resched +are not exported to tracefs as trace events, this allows only kernel +code to access them. Helper modules like [1] can be used to still have +the tracepoints available to ftrace for debugging purposes, but they do +rely on the tracepoints being exported. + +Export the 3 not exported tracepoints. +Note that sched_set_state is already exported as the macro is called +from modules. + +[1] - https://github.com/qais-yousef/sched_tp.git + +Fixes: adcc3bfa8806 ("sched: Adapt sched tracepoints for RV task model") +Signed-off-by: Gabriele Monaco +Signed-off-by: Peter Zijlstra (Intel) +Reviewed-by: Phil Auld +Link: https://patch.msgid.link/20251205131621.135513-9-gmonaco@redhat.com +Signed-off-by: Sasha Levin +--- + kernel/sched/core.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/kernel/sched/core.c b/kernel/sched/core.c +index 61c2d65156b50..2df7c1e2aed80 100644 +--- a/kernel/sched/core.c ++++ b/kernel/sched/core.c +@@ -119,6 +119,9 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(sched_util_est_cfs_tp); + EXPORT_TRACEPOINT_SYMBOL_GPL(sched_util_est_se_tp); + EXPORT_TRACEPOINT_SYMBOL_GPL(sched_update_nr_running_tp); + EXPORT_TRACEPOINT_SYMBOL_GPL(sched_compute_energy_tp); ++EXPORT_TRACEPOINT_SYMBOL_GPL(sched_entry_tp); ++EXPORT_TRACEPOINT_SYMBOL_GPL(sched_exit_tp); ++EXPORT_TRACEPOINT_SYMBOL_GPL(sched_set_need_resched_tp); + + DEFINE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues); + DEFINE_PER_CPU(struct rnd_state, sched_rnd_state); +-- +2.51.0 + diff --git a/queue-6.19/sched-fix-build-for-modules-using-set_tsk_need_resch.patch b/queue-6.19/sched-fix-build-for-modules-using-set_tsk_need_resch.patch new file mode 100644 index 0000000000..9a8a2af30f --- /dev/null +++ b/queue-6.19/sched-fix-build-for-modules-using-set_tsk_need_resch.patch @@ -0,0 +1,44 @@ +From 59d3c7b68a5a22c738d483027ecd3866ade95cfa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 15:04:13 +0100 +Subject: sched: Fix build for modules using set_tsk_need_resched() + +From: Gabriele Monaco + +[ Upstream commit 8d737320166bd145af70a3133a9964b00ca81cba ] + +Commit adcc3bfa8806 ("sched: Adapt sched tracepoints for RV task model") +added a tracepoint to the need_resched action that can be triggered also +by set_tsk_need_resched. +This function was previously accessible from out-of-tree modules but +it's no longer available because the __trace_set_need_resched() symbol +is not exported (together with the tracepoint itself, which was exported +in a separate patch) and building such modules fails. + +Export __trace_set_need_resched to modules to fix those build issues. + +Fixes: adcc3bfa8806 ("sched: Adapt sched tracepoints for RV task model") +Signed-off-by: Gabriele Monaco +Signed-off-by: Peter Zijlstra (Intel) +Reviewed-by: Phil Auld +Link: https://patch.msgid.link/20260112140413.362202-1-gmonaco@redhat.com +Signed-off-by: Sasha Levin +--- + kernel/sched/core.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/kernel/sched/core.c b/kernel/sched/core.c +index 2df7c1e2aed80..c3b6e123fa00e 100644 +--- a/kernel/sched/core.c ++++ b/kernel/sched/core.c +@@ -1139,6 +1139,7 @@ void __trace_set_need_resched(struct task_struct *curr, int tif) + { + trace_sched_set_need_resched_tp(curr, smp_processor_id(), tif); + } ++EXPORT_SYMBOL_GPL(__trace_set_need_resched); + + void resched_curr(struct rq *rq) + { +-- +2.51.0 + diff --git a/queue-6.19/sched-re-evaluate-scheduling-when-migrating-queued-t.patch b/queue-6.19/sched-re-evaluate-scheduling-when-migrating-queued-t.patch new file mode 100644 index 0000000000..0ef3c3290e --- /dev/null +++ b/queue-6.19/sched-re-evaluate-scheduling-when-migrating-queued-t.patch @@ -0,0 +1,93 @@ +From 46de6af923f53869626342e34f7aebdf47a52893 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 08:34:38 +0000 +Subject: sched: Re-evaluate scheduling when migrating queued tasks out of + throttled cgroups + +From: Zicheng Qu + +[ Upstream commit e34881c84c255bc300f24d9fe685324be20da3d1 ] + +Consider the following sequence on a CPU configured with nohz_full: + +1) A task P runs in cgroup A, and cgroup A becomes throttled due to CFS + bandwidth control. The gse (cgroup A) where the task P attached is +dequeued and the CPU switches to idle. + +2) Before cgroup A is unthrottled, task P is migrated from cgroup A to + another cgroup B (not throttled). + + During sched_move_task(), the task P is observed as queued but not +running, and therefore no resched_curr() is triggered. + +3) Since the CPU is nohz_full, it remains in do_idle() waiting for an + explicit scheduling event, i.e., resched_curr(). + +4) For kernel <= 5.10: Later, cgroup A is unthrottled. However, the task + P has already been migrated out of cgroup A, so unthrottle_cfs_rq() +may observe load_weight == 0 and return early without resched_curr() +called. For kernel >= 6.6: The unthrottling path normally triggers +`resched_curr()` almost cases even when no runnable tasks remain in the +unthrottled cgroup, preventing the idle stall described above. However, +if cgroup A is removed before it gets unthrottled, the unthrottling path +for cgroup A is never executed. In a result, no `resched_curr()` can be +called. + +5) At this point, the task P is runnable in cgroup B (not throttled), but +the CPU remains in do_idle() with no pending reschedule point. The +system stays in this state until an unrelated event (e.g. a new task +wakeup or any cases) that can trigger a resched_curr() breaks the +nohz_full idle state, and then the task P finally gets scheduled. + +The root cause is that sched_move_task() may classify the task as only +queued, not running, and therefore fails to trigger a resched_curr(), +while the later unthrottling path no longer has visibility of the +migrated task. + +Preserve the existing behavior for running tasks by issuing +resched_curr(), and explicitly invoke check_preempt_curr() for tasks +that were queued at the time of migration. This ensures that runnable +tasks are reconsidered for scheduling even when nohz_full suppresses +periodic ticks. + +Fixes: 29f59db3a74b ("sched: group-scheduler core") +Signed-off-by: Zicheng Qu +Signed-off-by: Peter Zijlstra (Intel) +Reviewed-by: K Prateek Nayak +Reviewed-by: Aaron Lu +Tested-by: Aaron Lu +Link: https://patch.msgid.link/20260130083438.1122457-1-quzicheng@huawei.com +Signed-off-by: Sasha Levin +--- + kernel/sched/core.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/kernel/sched/core.c b/kernel/sched/core.c +index c3b6e123fa00e..dbf4e32a063f7 100644 +--- a/kernel/sched/core.c ++++ b/kernel/sched/core.c +@@ -9115,6 +9115,7 @@ void sched_move_task(struct task_struct *tsk, bool for_autogroup) + { + unsigned int queue_flags = DEQUEUE_SAVE | DEQUEUE_MOVE; + bool resched = false; ++ bool queued = false; + struct rq *rq; + + CLASS(task_rq_lock, rq_guard)(tsk); +@@ -9126,10 +9127,13 @@ void sched_move_task(struct task_struct *tsk, bool for_autogroup) + scx_cgroup_move_task(tsk); + if (scope->running) + resched = true; ++ queued = scope->queued; + } + + if (resched) + resched_curr(rq); ++ else if (queued) ++ wakeup_preempt(rq, tsk, 0); + + __balance_callbacks(rq, &rq_guard.rf); + } +-- +2.51.0 + diff --git a/queue-6.19/sched-rt-skip-currently-executing-cpu-in-rto_next_cp.patch b/queue-6.19/sched-rt-skip-currently-executing-cpu-in-rto_next_cp.patch new file mode 100644 index 0000000000..0d4e61798c --- /dev/null +++ b/queue-6.19/sched-rt-skip-currently-executing-cpu-in-rto_next_cp.patch @@ -0,0 +1,87 @@ +From c3ac88050b98ca5b1091862d3987a83f76b4753f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 01:25:33 +0000 +Subject: sched/rt: Skip currently executing CPU in rto_next_cpu() + +From: Chen Jinghuang + +[ Upstream commit 94894c9c477e53bcea052e075c53f89df3d2a33e ] + +CPU0 becomes overloaded when hosting a CPU-bound RT task, a non-CPU-bound +RT task, and a CFS task stuck in kernel space. When other CPUs switch from +RT to non-RT tasks, RT load balancing (LB) is triggered; with +HAVE_RT_PUSH_IPI enabled, they send IPIs to CPU0 to drive the execution +of rto_push_irq_work_func. During push_rt_task on CPU0, +if next_task->prio < rq->donor->prio, resched_curr() sets NEED_RESCHED +and after the push operation completes, CPU0 calls rto_next_cpu(). +Since only CPU0 is overloaded in this scenario, rto_next_cpu() should +ideally return -1 (no further IPI needed). + +However, multiple CPUs invoking tell_cpu_to_push() during LB increments +rd->rto_loop_next. Even when rd->rto_cpu is set to -1, the mismatch between +rd->rto_loop and rd->rto_loop_next forces rto_next_cpu() to restart its +search from -1. With CPU0 remaining overloaded (satisfying rt_nr_migratory +&& rt_nr_total > 1), it gets reselected, causing CPU0 to queue irq_work to +itself and send self-IPIs repeatedly. As long as CPU0 stays overloaded and +other CPUs run pull_rt_tasks(), it falls into an infinite self-IPI loop, +which triggers a CPU hardlockup due to continuous self-interrupts. + +The trigging scenario is as follows: + + cpu0 cpu1 cpu2 + pull_rt_task + tell_cpu_to_push + <------------irq_work_queue_on +rto_push_irq_work_func + push_rt_task + resched_curr(rq) pull_rt_task + rto_next_cpu tell_cpu_to_push + <-------------------------- atomic_inc(rto_loop_next) +rd->rto_loop != next + rto_next_cpu + irq_work_queue_on +rto_push_irq_work_func + +Fix redundant self-IPI by filtering the initiating CPU in rto_next_cpu(). +This solution has been verified to effectively eliminate spurious self-IPIs +and prevent CPU hardlockup scenarios. + +Fixes: 4bdced5c9a29 ("sched/rt: Simplify the IPI based RT balancing logic") +Suggested-by: Steven Rostedt (Google) +Suggested-by: K Prateek Nayak +Signed-off-by: Chen Jinghuang +Signed-off-by: Peter Zijlstra (Intel) +Reviewed-by: Steven Rostedt (Google) +Reviewed-by: Valentin Schneider +Link: https://patch.msgid.link/20260122012533.673768-1-chenjinghuang2@huawei.com +Signed-off-by: Sasha Levin +--- + kernel/sched/rt.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c +index f1867fe8e5c53..e0ff909050190 100644 +--- a/kernel/sched/rt.c ++++ b/kernel/sched/rt.c +@@ -2100,6 +2100,7 @@ static void push_rt_tasks(struct rq *rq) + */ + static int rto_next_cpu(struct root_domain *rd) + { ++ int this_cpu = smp_processor_id(); + int next; + int cpu; + +@@ -2123,6 +2124,10 @@ static int rto_next_cpu(struct root_domain *rd) + + rd->rto_cpu = cpu; + ++ /* Do not send IPI to self */ ++ if (cpu == this_cpu) ++ continue; ++ + if (cpu < nr_cpu_ids) + return cpu; + +-- +2.51.0 + diff --git a/queue-6.19/scsi-csiostor-fix-dereference-of-null-pointer-rn.patch b/queue-6.19/scsi-csiostor-fix-dereference-of-null-pointer-rn.patch new file mode 100644 index 0000000000..b91bcb45cf --- /dev/null +++ b/queue-6.19/scsi-csiostor-fix-dereference-of-null-pointer-rn.patch @@ -0,0 +1,46 @@ +From b54ae1d73b1ce3fcfe19fd272dff316772380114 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 15:53:32 +0000 +Subject: scsi: csiostor: Fix dereference of null pointer rn + +From: Colin Ian King + +[ Upstream commit 1982257570b84dc33753d536dd969fd357a014e9 ] + +The error exit path when rn is NULL ends up deferencing the null pointer rn +via the use of the macro CSIO_INC_STATS. Fix this by adding a new error +return path label after the use of the macro to avoid the deference. + +Fixes: a3667aaed569 ("[SCSI] csiostor: Chelsio FCoE offload driver") +Signed-off-by: Colin Ian King +Link: https://patch.msgid.link/20260129155332.196338-1-colin.i.king@gmail.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/csiostor/csio_scsi.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/scsi/csiostor/csio_scsi.c b/drivers/scsi/csiostor/csio_scsi.c +index 34bde6650fae0..356a7c577ec3e 100644 +--- a/drivers/scsi/csiostor/csio_scsi.c ++++ b/drivers/scsi/csiostor/csio_scsi.c +@@ -2074,7 +2074,7 @@ csio_eh_lun_reset_handler(struct scsi_cmnd *cmnd) + struct csio_scsi_level_data sld; + + if (!rn) +- goto fail; ++ goto fail_ret; + + csio_dbg(hw, "Request to reset LUN:%llu (ssni:0x%x tgtid:%d)\n", + cmnd->device->lun, rn->flowid, rn->scsi_id); +@@ -2220,6 +2220,7 @@ csio_eh_lun_reset_handler(struct scsi_cmnd *cmnd) + csio_put_scsi_ioreq_lock(hw, scsim, ioreq); + fail: + CSIO_INC_STATS(rn, n_lun_rst_fail); ++fail_ret: + return FAILED; + } + +-- +2.51.0 + diff --git a/queue-6.19/scsi-efct-use-irqf_oneshot-and-default-primary-handl.patch b/queue-6.19/scsi-efct-use-irqf_oneshot-and-default-primary-handl.patch new file mode 100644 index 0000000000..5950847751 --- /dev/null +++ b/queue-6.19/scsi-efct-use-irqf_oneshot-and-default-primary-handl.patch @@ -0,0 +1,59 @@ +From c3a119f4f7fe290fb6b00104cbe1595c8f50b911 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:55:27 +0100 +Subject: scsi: efct: Use IRQF_ONESHOT and default primary handler + +From: Sebastian Andrzej Siewior + +[ Upstream commit bd81f07e9a27c341cd7e72be95eb0b7cf3910926 ] + +There is no added value in efct_intr_msix() compared to +irq_default_primary_handler(). + +Using a threaded interrupt without a dedicated primary handler mandates +the IRQF_ONESHOT flag to mask the interrupt source while the threaded +handler is active. Otherwise the interrupt can fire again before the +threaded handler had a chance to run. + +Use the default primary interrupt handler by specifying NULL and set +IRQF_ONESHOT so the interrupt source is masked until the secondary +handler is done. + +Fixes: 4df84e8466242 ("scsi: elx: efct: Driver initialization routines") +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260128095540.863589-8-bigeasy@linutronix.de +Signed-off-by: Sasha Levin +--- + drivers/scsi/elx/efct/efct_driver.c | 8 +------- + 1 file changed, 1 insertion(+), 7 deletions(-) + +diff --git a/drivers/scsi/elx/efct/efct_driver.c b/drivers/scsi/elx/efct/efct_driver.c +index 1bd42f7db1773..528399f725d42 100644 +--- a/drivers/scsi/elx/efct/efct_driver.c ++++ b/drivers/scsi/elx/efct/efct_driver.c +@@ -415,12 +415,6 @@ efct_intr_thread(int irq, void *handle) + return IRQ_HANDLED; + } + +-static irqreturn_t +-efct_intr_msix(int irq, void *handle) +-{ +- return IRQ_WAKE_THREAD; +-} +- + static int + efct_setup_msix(struct efct *efct, u32 num_intrs) + { +@@ -450,7 +444,7 @@ efct_setup_msix(struct efct *efct, u32 num_intrs) + intr_ctx->index = i; + + rc = request_threaded_irq(pci_irq_vector(efct->pci, i), +- efct_intr_msix, efct_intr_thread, 0, ++ NULL, efct_intr_thread, IRQF_ONESHOT, + EFCT_DRIVER_NAME, intr_ctx); + if (rc) { + dev_err(&efct->pci->dev, +-- +2.51.0 + diff --git a/queue-6.19/scsi-smartpqi-fix-memory-leak-in-pqi_report_phys_lun.patch b/queue-6.19/scsi-smartpqi-fix-memory-leak-in-pqi_report_phys_lun.patch new file mode 100644 index 0000000000..61a9eca50a --- /dev/null +++ b/queue-6.19/scsi-smartpqi-fix-memory-leak-in-pqi_report_phys_lun.patch @@ -0,0 +1,72 @@ +From 94282d384f987654ae1b6bf89c88e3796e8c07a4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Jan 2026 09:36:41 +0000 +Subject: scsi: smartpqi: Fix memory leak in pqi_report_phys_luns() + +From: Zilin Guan + +[ Upstream commit 41b37312bd9722af77ec7817ccf22d7a4880c289 ] + +pqi_report_phys_luns() fails to release the rpl_list buffer when +encountering an unsupported data format or when the allocation for +rpl_16byte_wwid_list fails. These early returns bypass the cleanup logic, +leading to memory leaks. + +Consolidate the error handling by adding an out_free_rpl_list label and use +goto statements to ensure rpl_list is consistently freed on failure. + +Compile tested only. Issue found using a prototype static analysis tool and +code review. + +Fixes: 28ca6d876c5a ("scsi: smartpqi: Add extended report physical LUNs") +Signed-off-by: Zilin Guan +Tested-by: Don Brace +Acked-by: Don Brace +Link: https://patch.msgid.link/20260131093641.1008117-1-zilin@seu.edu.cn +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/smartpqi/smartpqi_init.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c +index fe549e2b7c940..c829d9590558d 100644 +--- a/drivers/scsi/smartpqi/smartpqi_init.c ++++ b/drivers/scsi/smartpqi/smartpqi_init.c +@@ -1241,7 +1241,8 @@ static inline int pqi_report_phys_luns(struct pqi_ctrl_info *ctrl_info, void **b + dev_err(&ctrl_info->pci_dev->dev, + "RPL returned unsupported data format %u\n", + rpl_response_format); +- return -EINVAL; ++ rc = -EINVAL; ++ goto out_free_rpl_list; + } else { + dev_warn(&ctrl_info->pci_dev->dev, + "RPL returned extended format 2 instead of 4\n"); +@@ -1253,8 +1254,10 @@ static inline int pqi_report_phys_luns(struct pqi_ctrl_info *ctrl_info, void **b + + rpl_16byte_wwid_list = kmalloc(struct_size(rpl_16byte_wwid_list, lun_entries, + num_physicals), GFP_KERNEL); +- if (!rpl_16byte_wwid_list) +- return -ENOMEM; ++ if (!rpl_16byte_wwid_list) { ++ rc = -ENOMEM; ++ goto out_free_rpl_list; ++ } + + put_unaligned_be32(num_physicals * sizeof(struct report_phys_lun_16byte_wwid), + &rpl_16byte_wwid_list->header.list_length); +@@ -1275,6 +1278,10 @@ static inline int pqi_report_phys_luns(struct pqi_ctrl_info *ctrl_info, void **b + *buffer = rpl_16byte_wwid_list; + + return 0; ++ ++out_free_rpl_list: ++ kfree(rpl_list); ++ return rc; + } + + static inline int pqi_report_logical_luns(struct pqi_ctrl_info *ctrl_info, void **buffer) +-- +2.51.0 + diff --git a/queue-6.19/scsi-ufs-host-mediatek-require-config_pm.patch b/queue-6.19/scsi-ufs-host-mediatek-require-config_pm.patch new file mode 100644 index 0000000000..d8b70232d1 --- /dev/null +++ b/queue-6.19/scsi-ufs-host-mediatek-require-config_pm.patch @@ -0,0 +1,116 @@ +From 52c1a3d9e5330f7c571f10a5a7736ef5544a2a07 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 10:50:18 +0100 +Subject: scsi: ufs: host: mediatek: Require CONFIG_PM + +From: Arnd Bergmann + +[ Upstream commit bbb8d98fb4536594cb104fd630ea0f7dce3771d6 ] + +The added print statement from a recent fix causes the driver to fail +building when CONFIG_PM is disabled: + +drivers/ufs/host/ufs-mediatek.c: In function 'ufs_mtk_resume': +drivers/ufs/host/ufs-mediatek.c:1890:40: error: 'struct dev_pm_info' has no member named 'request' + 1890 | hba->dev->power.request, + +It seems unlikely that the driver can work at all without CONFIG_PM, so +just add a dependency and remove the existing ifdef checks, rather than +adding another ifdef. + +Fixes: 15ef3f5aa822 ("scsi: ufs: host: mediatek: Enhance recovery on resume failure") +Signed-off-by: Arnd Bergmann +Reviewed-by: AngeloGioacchino Del Regno +Link: https://patch.msgid.link/20260202095052.1232703-1-arnd@kernel.org +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/ufs/host/Kconfig | 1 + + drivers/ufs/host/ufs-mediatek.c | 12 +++--------- + include/ufs/ufshcd.h | 4 ---- + 3 files changed, 4 insertions(+), 13 deletions(-) + +diff --git a/drivers/ufs/host/Kconfig b/drivers/ufs/host/Kconfig +index 7d5117b2dab4a..964ae70e7390d 100644 +--- a/drivers/ufs/host/Kconfig ++++ b/drivers/ufs/host/Kconfig +@@ -72,6 +72,7 @@ config SCSI_UFS_QCOM + config SCSI_UFS_MEDIATEK + tristate "Mediatek specific hooks to UFS controller platform driver" + depends on SCSI_UFSHCD_PLATFORM && ARCH_MEDIATEK ++ depends on PM + depends on RESET_CONTROLLER + select PHY_MTK_UFS + select RESET_TI_SYSCON +diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c +index 66b11cc0703bd..b3daaa07e9252 100644 +--- a/drivers/ufs/host/ufs-mediatek.c ++++ b/drivers/ufs/host/ufs-mediatek.c +@@ -2437,7 +2437,6 @@ static void ufs_mtk_remove(struct platform_device *pdev) + ufshcd_pltfrm_remove(pdev); + } + +-#ifdef CONFIG_PM_SLEEP + static int ufs_mtk_system_suspend(struct device *dev) + { + struct ufs_hba *hba = dev_get_drvdata(dev); +@@ -2484,9 +2483,7 @@ static int ufs_mtk_system_resume(struct device *dev) + + return ret; + } +-#endif + +-#ifdef CONFIG_PM + static int ufs_mtk_runtime_suspend(struct device *dev) + { + struct ufs_hba *hba = dev_get_drvdata(dev); +@@ -2525,13 +2522,10 @@ static int ufs_mtk_runtime_resume(struct device *dev) + + return ufshcd_runtime_resume(dev); + } +-#endif + + static const struct dev_pm_ops ufs_mtk_pm_ops = { +- SET_SYSTEM_SLEEP_PM_OPS(ufs_mtk_system_suspend, +- ufs_mtk_system_resume) +- SET_RUNTIME_PM_OPS(ufs_mtk_runtime_suspend, +- ufs_mtk_runtime_resume, NULL) ++ SYSTEM_SLEEP_PM_OPS(ufs_mtk_system_suspend, ufs_mtk_system_resume) ++ RUNTIME_PM_OPS(ufs_mtk_runtime_suspend, ufs_mtk_runtime_resume, NULL) + .prepare = ufshcd_suspend_prepare, + .complete = ufshcd_resume_complete, + }; +@@ -2541,7 +2535,7 @@ static struct platform_driver ufs_mtk_pltform = { + .remove = ufs_mtk_remove, + .driver = { + .name = "ufshcd-mtk", +- .pm = &ufs_mtk_pm_ops, ++ .pm = pm_ptr(&ufs_mtk_pm_ops), + .of_match_table = ufs_mtk_of_match, + }, + }; +diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h +index 19154228780b2..8e15c3a70ed41 100644 +--- a/include/ufs/ufshcd.h ++++ b/include/ufs/ufshcd.h +@@ -1342,17 +1342,13 @@ static inline void *ufshcd_get_variant(struct ufs_hba *hba) + return hba->priv; + } + +-#ifdef CONFIG_PM + extern int ufshcd_runtime_suspend(struct device *dev); + extern int ufshcd_runtime_resume(struct device *dev); +-#endif +-#ifdef CONFIG_PM_SLEEP + extern int ufshcd_system_suspend(struct device *dev); + extern int ufshcd_system_resume(struct device *dev); + extern int ufshcd_system_freeze(struct device *dev); + extern int ufshcd_system_thaw(struct device *dev); + extern int ufshcd_system_restore(struct device *dev); +-#endif + + extern int ufshcd_dme_reset(struct ufs_hba *hba); + extern int ufshcd_dme_enable(struct ufs_hba *hba); +-- +2.51.0 + diff --git a/queue-6.19/selftests-bpf-fix-kprobe-multi-stacktrace_ips-test.patch b/queue-6.19/selftests-bpf-fix-kprobe-multi-stacktrace_ips-test.patch new file mode 100644 index 0000000000..466357776a --- /dev/null +++ b/queue-6.19/selftests-bpf-fix-kprobe-multi-stacktrace_ips-test.patch @@ -0,0 +1,54 @@ +From 319bad385b061d4ae7cf84ad852e21ed412757ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 22:18:34 +0100 +Subject: selftests/bpf: Fix kprobe multi stacktrace_ips test + +From: Jiri Olsa + +[ Upstream commit 0207f94971e72a13380e28022c86da147e8e090f ] + +We now include the attached function in the stack trace, +fixing the test accordingly. + +Fixes: c9e208fa93cd ("selftests/bpf: Add stacktrace ips test for kprobe_multi/kretprobe_multi") +Signed-off-by: Jiri Olsa +Signed-off-by: Andrii Nakryiko +Link: https://lore.kernel.org/bpf/20260126211837.472802-4-jolsa@kernel.org +Signed-off-by: Sasha Levin +--- + .../selftests/bpf/prog_tests/stacktrace_ips.c | 19 ++++++++++++++----- + 1 file changed, 14 insertions(+), 5 deletions(-) + +diff --git a/tools/testing/selftests/bpf/prog_tests/stacktrace_ips.c b/tools/testing/selftests/bpf/prog_tests/stacktrace_ips.c +index c9efdd2a5b18a..c93718dafd9b6 100644 +--- a/tools/testing/selftests/bpf/prog_tests/stacktrace_ips.c ++++ b/tools/testing/selftests/bpf/prog_tests/stacktrace_ips.c +@@ -74,11 +74,20 @@ static void test_stacktrace_ips_kprobe_multi(bool retprobe) + + load_kallsyms(); + +- check_stacktrace_ips(bpf_map__fd(skel->maps.stackmap), skel->bss->stack_key, 4, +- ksym_get_addr("bpf_testmod_stacktrace_test_3"), +- ksym_get_addr("bpf_testmod_stacktrace_test_2"), +- ksym_get_addr("bpf_testmod_stacktrace_test_1"), +- ksym_get_addr("bpf_testmod_test_read")); ++ if (retprobe) { ++ check_stacktrace_ips(bpf_map__fd(skel->maps.stackmap), skel->bss->stack_key, 4, ++ ksym_get_addr("bpf_testmod_stacktrace_test_3"), ++ ksym_get_addr("bpf_testmod_stacktrace_test_2"), ++ ksym_get_addr("bpf_testmod_stacktrace_test_1"), ++ ksym_get_addr("bpf_testmod_test_read")); ++ } else { ++ check_stacktrace_ips(bpf_map__fd(skel->maps.stackmap), skel->bss->stack_key, 5, ++ ksym_get_addr("bpf_testmod_stacktrace_test"), ++ ksym_get_addr("bpf_testmod_stacktrace_test_3"), ++ ksym_get_addr("bpf_testmod_stacktrace_test_2"), ++ ksym_get_addr("bpf_testmod_stacktrace_test_1"), ++ ksym_get_addr("bpf_testmod_test_read")); ++ } + + cleanup: + stacktrace_ips__destroy(skel); +-- +2.51.0 + diff --git a/queue-6.19/selftests-bpf-fix-resource-leak-in-serial_test_wq-on.patch b/queue-6.19/selftests-bpf-fix-resource-leak-in-serial_test_wq-on.patch new file mode 100644 index 0000000000..6bb95d7a28 --- /dev/null +++ b/queue-6.19/selftests-bpf-fix-resource-leak-in-serial_test_wq-on.patch @@ -0,0 +1,60 @@ +From 12b7c9eb52c6227cd0cf6fb01d8ef5a846d297c8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 17:41:16 +0800 +Subject: selftests/bpf: Fix resource leak in serial_test_wq on attach failure + +From: Kery Qi + +[ Upstream commit a32ae2658471dd87a2f7a438388ed7d9a5767212 ] + +When wq__attach() fails, serial_test_wq() returns early without calling +wq__destroy(), leaking the skeleton resources allocated by +wq__open_and_load(). This causes ASAN leak reports in selftests runs. + +Fix this by jumping to a common clean_up label that calls wq__destroy() +on all exit paths after successful open_and_load. + +Note that the early return after wq__open_and_load() failure is correct +and doesn't need fixing, since that function returns NULL on failure +(after internally cleaning up any partial allocations). + +Fixes: 8290dba51910 ("selftests/bpf: wq: add bpf_wq_start() checks") +Signed-off-by: Kery Qi +Signed-off-by: Andrii Nakryiko +Acked-by: Yonghong Song +Link: https://lore.kernel.org/bpf/20260121094114.1801-3-qikeyu2017@gmail.com +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/bpf/prog_tests/wq.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/tools/testing/selftests/bpf/prog_tests/wq.c b/tools/testing/selftests/bpf/prog_tests/wq.c +index 15c67d23128b2..84831eecc935b 100644 +--- a/tools/testing/selftests/bpf/prog_tests/wq.c ++++ b/tools/testing/selftests/bpf/prog_tests/wq.c +@@ -16,12 +16,12 @@ void serial_test_wq(void) + /* re-run the success test to check if the timer was actually executed */ + + wq_skel = wq__open_and_load(); +- if (!ASSERT_OK_PTR(wq_skel, "wq_skel_load")) ++ if (!ASSERT_OK_PTR(wq_skel, "wq__open_and_load")) + return; + + err = wq__attach(wq_skel); + if (!ASSERT_OK(err, "wq_attach")) +- return; ++ goto clean_up; + + prog_fd = bpf_program__fd(wq_skel->progs.test_syscall_array_sleepable); + err = bpf_prog_test_run_opts(prog_fd, &topts); +@@ -31,6 +31,7 @@ void serial_test_wq(void) + usleep(50); /* 10 usecs should be enough, but give it extra */ + + ASSERT_EQ(wq_skel->bss->ok_sleepable, (1 << 1), "ok_sleepable"); ++clean_up: + wq__destroy(wq_skel); + } + +-- +2.51.0 + diff --git a/queue-6.19/selftests-bpf-veristat-fix-printing-order-in-output_.patch b/queue-6.19/selftests-bpf-veristat-fix-printing-order-in-output_.patch new file mode 100644 index 0000000000..7a7599b975 --- /dev/null +++ b/queue-6.19/selftests-bpf-veristat-fix-printing-order-in-output_.patch @@ -0,0 +1,46 @@ +From df128d9267181068cc50537b9f3f6412cc7e0011 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 31 Dec 2025 14:10:50 -0800 +Subject: selftests/bpf: veristat: fix printing order in output_stats() + +From: Puranjay Mohan + +[ Upstream commit c286e7e9d1f1f3d90ad11c37e896f582b02d19c4 ] + +The order of the variables in the printf() doesn't match the text and +therefore veristat prints something like this: + +Done. Processed 24 files, 0 programs. Skipped 62 files, 0 programs. + +When it should print: + +Done. Processed 24 files, 62 programs. Skipped 0 files, 0 programs. + +Fix the order of variables in the printf() call. + +Fixes: 518fee8bfaf2 ("selftests/bpf: make veristat skip non-BPF and failing-to-open BPF objects") +Tested-by: Eduard Zingerman +Signed-off-by: Puranjay Mohan +Link: https://lore.kernel.org/r/20251231221052.759396-1-puranjay@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/bpf/veristat.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/testing/selftests/bpf/veristat.c b/tools/testing/selftests/bpf/veristat.c +index e962f133250c7..1be1e353d40a7 100644 +--- a/tools/testing/selftests/bpf/veristat.c ++++ b/tools/testing/selftests/bpf/veristat.c +@@ -2580,7 +2580,7 @@ static void output_stats(const struct verif_stats *s, enum resfmt fmt, bool last + if (last && fmt == RESFMT_TABLE) { + output_header_underlines(); + printf("Done. Processed %d files, %d programs. Skipped %d files, %d programs.\n", +- env.files_processed, env.files_skipped, env.progs_processed, env.progs_skipped); ++ env.files_processed, env.progs_processed, env.files_skipped, env.progs_skipped); + } + } + +-- +2.51.0 + diff --git a/queue-6.19/selftests-mm-fix-faulting-in-code-in-pagemap_ioctl-t.patch b/queue-6.19/selftests-mm-fix-faulting-in-code-in-pagemap_ioctl-t.patch new file mode 100644 index 0000000000..d20b93e3cb --- /dev/null +++ b/queue-6.19/selftests-mm-fix-faulting-in-code-in-pagemap_ioctl-t.patch @@ -0,0 +1,80 @@ +From 365e2de33bfca616a389a0342f7e6fa3f8b75a06 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 17:02:22 +0000 +Subject: selftests/mm: fix faulting-in code in pagemap_ioctl test + +From: Kevin Brodsky + +[ Upstream commit 7e938f00b00319510ae097e20b7487dfa578d53f ] + +One of the pagemap_ioctl tests attempts to fault in pages by memcpy()'ing +them to an unused buffer. This probably worked originally, but since +commit 46036188ea1f ("selftests/mm: build with -O2") the compiler is free +to optimise away that unused buffer and the memcpy() with it. As a result +there might not be any resident page in the mapping and the test may fail. + +We don't need to copy all that memory anyway. Just fault in every page. + +While at it also make sure to compute the number of pages once using +simple integer arithmetic instead of ceilf() and implicit conversions. + +Link: https://lkml.kernel.org/r/20260122170224.4056513-8-kevin.brodsky@arm.com +Fixes: 46036188ea1f ("selftests/mm: build with -O2") +Signed-off-by: Kevin Brodsky +Acked-by: David Hildenbrand (Red Hat) +Reviewed-by: Dev Jain +Reviewed-by: Muhammad Usama Anjum +Cc: Jason Gunthorpe +Cc: John Hubbard +Cc: Lorenzo Stoakes +Cc: Mark Brown +Cc: Paolo Abeni +Cc: Ryan Roberts +Cc: SeongJae Park +Cc: Shuah Khan +Cc: wang lian +Cc: Yunsheng Lin +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/mm/pagemap_ioctl.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/tools/testing/selftests/mm/pagemap_ioctl.c b/tools/testing/selftests/mm/pagemap_ioctl.c +index 2cb5441f29c72..1896c7d4f72ee 100644 +--- a/tools/testing/selftests/mm/pagemap_ioctl.c ++++ b/tools/testing/selftests/mm/pagemap_ioctl.c +@@ -1052,11 +1052,10 @@ static void test_simple(void) + int sanity_tests(void) + { + unsigned long long mem_size, vec_size; +- long ret, fd, i, buf_size; ++ long ret, fd, i, buf_size, nr_pages; + struct page_region *vec; + char *mem, *fmem; + struct stat sbuf; +- char *tmp_buf; + + /* 1. wrong operation */ + mem_size = 10 * page_size; +@@ -1167,14 +1166,14 @@ int sanity_tests(void) + if (fmem == MAP_FAILED) + ksft_exit_fail_msg("error nomem %d %s\n", errno, strerror(errno)); + +- tmp_buf = malloc(sbuf.st_size); +- memcpy(tmp_buf, fmem, sbuf.st_size); ++ nr_pages = (sbuf.st_size + page_size - 1) / page_size; ++ force_read_pages(fmem, nr_pages, page_size); + + ret = pagemap_ioctl(fmem, sbuf.st_size, vec, vec_size, 0, 0, + 0, PAGEMAP_NON_WRITTEN_BITS, 0, PAGEMAP_NON_WRITTEN_BITS); + + ksft_test_result(ret >= 0 && vec[0].start == (uintptr_t)fmem && +- LEN(vec[0]) == ceilf((float)sbuf.st_size/page_size) && ++ LEN(vec[0]) == nr_pages && + (vec[0].categories & PAGE_IS_FILE), + "%s Memory mapped file\n", __func__); + +-- +2.51.0 + diff --git a/queue-6.19/selftests-mm-fix-usage-of-force_read-in-cow-tests.patch b/queue-6.19/selftests-mm-fix-usage-of-force_read-in-cow-tests.patch new file mode 100644 index 0000000000..1a2cd882fd --- /dev/null +++ b/queue-6.19/selftests-mm-fix-usage-of-force_read-in-cow-tests.patch @@ -0,0 +1,96 @@ +From c138df2bb6c66ec8c95846ec19968585ffd926cc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 17:02:19 +0000 +Subject: selftests/mm: fix usage of FORCE_READ() in cow tests + +From: Kevin Brodsky + +[ Upstream commit bce1dabd310e87fefe0645fec9ba98b84d37e418 ] + +Commit 5bbc2b785e63 ("selftests/mm: fix FORCE_READ to read input value +correctly") modified FORCE_READ() to take a value instead of a pointer. +It also changed most of the call sites accordingly, but missed many of +them in cow.c. In those cases, we ended up with the pointer itself being +read, not the memory it points to. + +No failure occurred as a result, so it looks like the tests work just fine +without faulting in. However, the huge_zeropage tests explicitly check +that pages are populated, so those became skipped. + +Convert all the remaining FORCE_READ() to fault in the mapped page, as was +originally intended. This allows the huge_zeropage tests to run again (3 +tests in total). + +Link: https://lkml.kernel.org/r/20260122170224.4056513-5-kevin.brodsky@arm.com +Fixes: 5bbc2b785e63 ("selftests/mm: fix FORCE_READ to read input value correctly") +Signed-off-by: Kevin Brodsky +Acked-by: SeongJae Park +Reviewed-by: wang lian +Acked-by: David Hildenbrand (Red Hat) +Reviewed-by: Dev Jain +Cc: Jason Gunthorpe +Cc: John Hubbard +Cc: Lorenzo Stoakes +Cc: Mark Brown +Cc: Paolo Abeni +Cc: Ryan Roberts +Cc: Shuah Khan +Cc: Usama Anjum +Cc: Yunsheng Lin +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/mm/cow.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/tools/testing/selftests/mm/cow.c b/tools/testing/selftests/mm/cow.c +index accfd198dbda8..83b3563be26b6 100644 +--- a/tools/testing/selftests/mm/cow.c ++++ b/tools/testing/selftests/mm/cow.c +@@ -1612,8 +1612,8 @@ static void run_with_huge_zeropage(non_anon_test_fn fn, const char *desc) + * the first sub-page and test if we get another sub-page populated + * automatically. + */ +- FORCE_READ(mem); +- FORCE_READ(smem); ++ FORCE_READ(*mem); ++ FORCE_READ(*smem); + if (!pagemap_is_populated(pagemap_fd, mem + pagesize) || + !pagemap_is_populated(pagemap_fd, smem + pagesize)) { + ksft_test_result_skip("Did not get THPs populated\n"); +@@ -1663,8 +1663,8 @@ static void run_with_memfd(non_anon_test_fn fn, const char *desc) + } + + /* Fault the page in. */ +- FORCE_READ(mem); +- FORCE_READ(smem); ++ FORCE_READ(*mem); ++ FORCE_READ(*smem); + + fn(mem, smem, pagesize); + munmap: +@@ -1719,8 +1719,8 @@ static void run_with_tmpfile(non_anon_test_fn fn, const char *desc) + } + + /* Fault the page in. */ +- FORCE_READ(mem); +- FORCE_READ(smem); ++ FORCE_READ(*mem); ++ FORCE_READ(*smem); + + fn(mem, smem, pagesize); + munmap: +@@ -1773,8 +1773,8 @@ static void run_with_memfd_hugetlb(non_anon_test_fn fn, const char *desc, + } + + /* Fault the page in. */ +- FORCE_READ(mem); +- FORCE_READ(smem); ++ FORCE_READ(*mem); ++ FORCE_READ(*smem); + + fn(mem, smem, hugetlbsize); + munmap: +-- +2.51.0 + diff --git a/queue-6.19/selftests-resctrl-fix-a-division-by-zero-error-on-hy.patch b/queue-6.19/selftests-resctrl-fix-a-division-by-zero-error-on-hy.patch new file mode 100644 index 0000000000..e2269ff711 --- /dev/null +++ b/queue-6.19/selftests-resctrl-fix-a-division-by-zero-error-on-hy.patch @@ -0,0 +1,67 @@ +From 313ebf0fda7655e9bf4b3dab59b6b2e040057ace Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 17 Dec 2025 11:04:53 +0800 +Subject: selftests/resctrl: Fix a division by zero error on Hygon + +From: Xiaochen Shen + +[ Upstream commit 671ef08d9455f5754d1fc96f5a14e357d6b80936 ] + +Change to adjust effective L3 cache size with SNC enabled change +introduced the snc_nodes_per_l3_cache() function to detect the Intel +Sub-NUMA Clustering (SNC) feature by comparing #CPUs in node0 with #CPUs +sharing LLC with CPU0. The function was designed to return: + (1) >1: SNC mode is enabled. + (2) 1: SNC mode is not enabled or not supported. + +However, on certain Hygon CPUs, #CPUs sharing LLC with CPU0 is actually +less than #CPUs in node0. This results in snc_nodes_per_l3_cache() +returning 0 (calculated as cache_cpus / node_cpus). + +This leads to a division by zero error in get_cache_size(): + *cache_size /= snc_nodes_per_l3_cache(); + +Causing the resctrl selftest to fail with: + "Floating point exception (core dumped)" + +Fix the issue by ensuring snc_nodes_per_l3_cache() returns 1 when SNC +mode is not supported on the platform. + +Updated commit log to fix commit has issues: +Shuah Khan + +Link: https://lore.kernel.org/r/20251217030456.3834956-2-shenxiaochen@open-hieco.net +Fixes: a1cd99e700ec ("selftests/resctrl: Adjust effective L3 cache size with SNC enabled") +Signed-off-by: Xiaochen Shen +Reviewed-by: Reinette Chatre +Reviewed-by: Fenghua Yu +Signed-off-by: Shuah Khan +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/resctrl/resctrlfs.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/tools/testing/selftests/resctrl/resctrlfs.c b/tools/testing/selftests/resctrl/resctrlfs.c +index 195f04c4d1586..b9c1bfb6cc029 100644 +--- a/tools/testing/selftests/resctrl/resctrlfs.c ++++ b/tools/testing/selftests/resctrl/resctrlfs.c +@@ -243,6 +243,16 @@ int snc_nodes_per_l3_cache(void) + } + snc_mode = cache_cpus / node_cpus; + ++ /* ++ * On some platforms (e.g. Hygon), ++ * cache_cpus < node_cpus, the calculated snc_mode is 0. ++ * ++ * Set snc_mode = 1 to indicate that SNC mode is not ++ * supported on the platform. ++ */ ++ if (!snc_mode) ++ snc_mode = 1; ++ + if (snc_mode > 1) + ksft_print_msg("SNC-%d mode discovered.\n", snc_mode); + } +-- +2.51.0 + diff --git a/queue-6.19/selftests-xsk-fix-number-of-tx-frags-in-invalid-pack.patch b/queue-6.19/selftests-xsk-fix-number-of-tx-frags-in-invalid-pack.patch new file mode 100644 index 0000000000..b23900aa78 --- /dev/null +++ b/queue-6.19/selftests-xsk-fix-number-of-tx-frags-in-invalid-pack.patch @@ -0,0 +1,59 @@ +From 10d400fe3603bb452a01a662452a0d40a21f25c7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 16:50:58 +0100 +Subject: selftests/xsk: fix number of Tx frags in invalid packet + +From: Larysa Zaremba + +[ Upstream commit 88af9fefed412e4bea9a1a771cbe6fe347fa3507 ] + +The issue occurs in TOO_MANY_FRAGS test case when xdp_zc_max_segs is set to +an odd number. + +TOO_MANY_FRAGS test case contains an invalid packet consisting of +(xdp_zc_max_segs) frags. Every frag, even the last one has XDP_PKT_CONTD +flag set. This packet is expected to be dropped. After that, there is a +valid linear packet, which is expected to be received back. + +Once (xdp_zc_max_segs) is an odd number, the last packet cannot be +received, if packet forwarding between Rx and Tx interfaces relies on +the ethernet header, e.g. checks for ETH_P_LOOPBACK. Packet is malformed, +if all traffic is looped. + +Turns out, sending function processes multiple invalid frags as if they +were in 2-frag packets. So once the invalid mbuf packet contains an odd +number of those, the valid packet after gets paired with the previous +invalid descriptor, and hence does not get an ethernet header generated, so +it is either dropped or malformed. + +Make invalid packets in verbatim mode always have only a single frag. For +such packets, number of frags is otherwise meaningless, as descriptor flags +are pre-configured in verbatim mode and packet data is not generated for +invalid descriptors. + +Fixes: 697604492b64 ("selftests/xsk: add invalid descriptor test for multi-buffer") +Reviewed-by: Aleksandr Loktionov +Signed-off-by: Larysa Zaremba +Link: https://lore.kernel.org/r/20260203155103.2305816-3-larysa.zaremba@intel.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/bpf/prog_tests/test_xsk.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/testing/selftests/bpf/prog_tests/test_xsk.c b/tools/testing/selftests/bpf/prog_tests/test_xsk.c +index 69a5a9a5189b0..bab4a31621c75 100644 +--- a/tools/testing/selftests/bpf/prog_tests/test_xsk.c ++++ b/tools/testing/selftests/bpf/prog_tests/test_xsk.c +@@ -433,7 +433,7 @@ static u32 pkt_nb_frags(u32 frame_size, struct pkt_stream *pkt_stream, struct pk + } + + /* Search for the end of the packet in verbatim mode */ +- if (!pkt_continues(pkt->options)) ++ if (!pkt_continues(pkt->options) || !pkt->valid) + return nb_frags; + + next_frag = pkt_stream->current_pkt_nb; +-- +2.51.0 + diff --git a/queue-6.19/selftests-xsk-properly-handle-batch-ending-in-the-mi.patch b/queue-6.19/selftests-xsk-properly-handle-batch-ending-in-the-mi.patch new file mode 100644 index 0000000000..436dfa474a --- /dev/null +++ b/queue-6.19/selftests-xsk-properly-handle-batch-ending-in-the-mi.patch @@ -0,0 +1,43 @@ +From 43edb856ef2253b4192f30a7f0e3d56b6d2ecc3f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 16:50:57 +0100 +Subject: selftests/xsk: properly handle batch ending in the middle of a packet + +From: Larysa Zaremba + +[ Upstream commit 42e41b2a0afa04ca49ee2725aadf90ccb058ed28 ] + +Referenced commit reduced the scope of the variable pkt, so now it has to +be reinitialized via pkt_stream_get_next_rx_pkt(), which also increments +some counters. When the packet is interrupted by the batch ending, pkt +stream therefore proceeds to the next packet, while xsk ring still contains +the previous one, this results in a pkt_nb mismatch. + +Decrement the affected counters when packet is interrupted. + +Fixes: 8913e653e9b8 ("selftests/xsk: Iterate over all the sockets in the receive pkts function") +Reviewed-by: Aleksandr Loktionov +Signed-off-by: Larysa Zaremba +Link: https://lore.kernel.org/r/20260203155103.2305816-2-larysa.zaremba@intel.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/bpf/prog_tests/test_xsk.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/tools/testing/selftests/bpf/prog_tests/test_xsk.c b/tools/testing/selftests/bpf/prog_tests/test_xsk.c +index 5af28f359cfda..69a5a9a5189b0 100644 +--- a/tools/testing/selftests/bpf/prog_tests/test_xsk.c ++++ b/tools/testing/selftests/bpf/prog_tests/test_xsk.c +@@ -1090,6 +1090,8 @@ static int __receive_pkts(struct test_spec *test, struct xsk_socket_info *xsk) + xsk_ring_prod__cancel(&umem->fq, nb_frags); + } + frags_processed -= nb_frags; ++ pkt_stream_cancel(pkt_stream); ++ pkts_sent--; + } + + if (ifobj->use_fill_ring) +-- +2.51.0 + diff --git a/queue-6.19/seqlock-fix-scoped_seqlock_read-kernel-doc.patch b/queue-6.19/seqlock-fix-scoped_seqlock_read-kernel-doc.patch new file mode 100644 index 0000000000..d2803bd6ea --- /dev/null +++ b/queue-6.19/seqlock-fix-scoped_seqlock_read-kernel-doc.patch @@ -0,0 +1,64 @@ +From 96ad8c6c07c0a6a40108d2268e5973fb051e665f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 10:37:49 -0800 +Subject: seqlock: fix scoped_seqlock_read kernel-doc + +From: Randy Dunlap + +[ Upstream commit f88a31308db6a856229150039b0f56d59696ed31 ] + +Eliminate all kernel-doc warnings in seqlock.h: + +- correct the macro to have "()" immediately following the macro name +- don't include the macro parameters in the short description (first line) +- make the parameter names in the comments match the actual macro + parameter names. +- use "::" for the Example + +WARNING: include/linux/seqlock.h:1341 This comment starts with '/**', but isn't a kernel-doc comment. + * scoped_seqlock_read (lock, ss_state) - execute the read side critical +Documentation/locking/seqlock:242: include/linux/seqlock.h:1351: WARNING: + Definition list ends without a blank line; unexpected unindent. [docutils] +Warning: include/linux/seqlock.h:1357 function parameter '_seqlock' not described in 'scoped_seqlock_read' +Warning: include/linux/seqlock.h:1357 function parameter '_target' not described in 'scoped_seqlock_read' + +Fixes: cc39f3872c08 ("seqlock: Introduce scoped_seqlock_read()") +Signed-off-by: Randy Dunlap +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260123183749.3997533-1-rdunlap@infradead.org +Signed-off-by: Sasha Levin +--- + include/linux/seqlock.h | 17 ++++++++--------- + 1 file changed, 8 insertions(+), 9 deletions(-) + +diff --git a/include/linux/seqlock.h b/include/linux/seqlock.h +index 221123660e710..f827cc3cb1460 100644 +--- a/include/linux/seqlock.h ++++ b/include/linux/seqlock.h +@@ -1303,15 +1303,14 @@ __scoped_seqlock_next(struct ss_tmp *sst, seqlock_t *lock, enum ss_state target) + __scoped_seqlock_next(&_s, _seqlock, _target)) + + /** +- * scoped_seqlock_read (lock, ss_state) - execute the read side critical +- * section without manual sequence +- * counter handling or calls to other +- * helpers +- * @lock: pointer to seqlock_t protecting the data +- * @ss_state: one of {ss_lock, ss_lock_irqsave, ss_lockless} indicating +- * the type of critical read section +- * +- * Example: ++ * scoped_seqlock_read() - execute the read-side critical section ++ * without manual sequence counter handling ++ * or calls to other helpers ++ * @_seqlock: pointer to seqlock_t protecting the data ++ * @_target: an enum ss_state: one of {ss_lock, ss_lock_irqsave, ss_lockless} ++ * indicating the type of critical read section ++ * ++ * Example:: + * + * scoped_seqlock_read (&lock, ss_lock) { + * // read-side critical section +-- +2.51.0 + diff --git a/queue-6.19/serial-caif-fix-use-after-free-in-caif_serial-ldisc_.patch b/queue-6.19/serial-caif-fix-use-after-free-in-caif_serial-ldisc_.patch new file mode 100644 index 0000000000..8e0fd62dae --- /dev/null +++ b/queue-6.19/serial-caif-fix-use-after-free-in-caif_serial-ldisc_.patch @@ -0,0 +1,152 @@ +From c8ed145312f8f68c20259fc95402c9fb7676f895 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 15:44:44 +0800 +Subject: serial: caif: fix use-after-free in caif_serial ldisc_close() + +From: Jiayuan Chen + +[ Upstream commit 308e7e4d0a846359685f40aade023aee7b27284c ] + +There is a use-after-free bug in caif_serial where handle_tx() may +access ser->tty after the tty has been freed. + +The race condition occurs between ldisc_close() and packet transmission: + + CPU 0 (close) CPU 1 (xmit) + ------------- ------------ + ldisc_close() + tty_kref_put(ser->tty) + [tty may be freed here] + <-- race window --> + caif_xmit() + handle_tx() + tty = ser->tty // dangling ptr + tty->ops->write() // UAF! + schedule_work() + ser_release() + unregister_netdevice() + +The root cause is that tty_kref_put() is called in ldisc_close() while +the network device is still active and can receive packets. + +Since ser and tty have a 1:1 binding relationship with consistent +lifecycles (ser is allocated in ldisc_open and freed in ser_release +via unregister_netdevice, and each ser binds exactly one tty), we can +safely defer the tty reference release to ser_release() where the +network device is unregistered. + +Fix this by moving tty_kref_put() from ldisc_close() to ser_release(), +after unregister_netdevice(). This ensures the tty reference is held +as long as the network device exists, preventing the UAF. + +Note: We save ser->tty before unregister_netdevice() because ser is +embedded in netdev's private data and will be freed along with netdev +(needs_free_netdev = true). + +How to reproduce: Add mdelay(500) at the beginning of ldisc_close() +to widen the race window, then run the reproducer program [1]. + +Note: There is a separate deadloop issue in handle_tx() when using +PORT_UNKNOWN serial ports (e.g., /dev/ttyS3 in QEMU without proper +serial backend). This deadloop exists even without this patch, +and is likely caused by inconsistency between uart_write_room() and +uart_write() in serial core. It has been addressed in a separate +patch [2]. + +KASAN report: + +================================================================== +BUG: KASAN: slab-use-after-free in handle_tx+0x5d1/0x620 +Read of size 1 at addr ffff8881131e1490 by task caif_uaf_trigge/9929 + +Call Trace: + + dump_stack_lvl+0x10e/0x1f0 + print_report+0xd0/0x630 + kasan_report+0xe4/0x120 + handle_tx+0x5d1/0x620 + dev_hard_start_xmit+0x9d/0x6c0 + __dev_queue_xmit+0x6e2/0x4410 + packet_xmit+0x243/0x360 + packet_sendmsg+0x26cf/0x5500 + __sys_sendto+0x4a3/0x520 + __x64_sys_sendto+0xe0/0x1c0 + do_syscall_64+0xc9/0xf80 + entry_SYSCALL_64_after_hwframe+0x77/0x7f +RIP: 0033:0x7f615df2c0d7 + +Allocated by task 9930: + +Freed by task 64: + +Last potentially related work creation: + +The buggy address belongs to the object at ffff8881131e1000 + which belongs to the cache kmalloc-cg-2k of size 2048 +The buggy address is located 1168 bytes inside of + freed 2048-byte region [ffff8881131e1000, ffff8881131e1800) + +The buggy address belongs to the physical page: +page_owner tracks the page as allocated +page last free pid 9778 tgid 9778 stack trace: + +Memory state around the buggy address: + ffff8881131e1380: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb + ffff8881131e1400: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb +>ffff8881131e1480: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb + ^ + ffff8881131e1500: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb + ffff8881131e1580: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb +================================================================== +[1]: https://gist.github.com/mrpre/f683f244544f7b11e7fa87df9e6c2eeb +[2]: https://lore.kernel.org/linux-serial/20260204074327.226165-1-jiayuan.chen@linux.dev/T/#u + +Reported-by: syzbot+827272712bd6d12c79a4@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/000000000000a4a7550611e234f5@google.com/T/ +Fixes: 56e0ef527b18 ("drivers/net: caif: fix wrong rtnl_is_locked() usage") +Reviewed-by: Greg Kroah-Hartman +Signed-off-by: Jiayuan Chen +Reviewed-by: Jijie Shao +Link: https://patch.msgid.link/20260206074450.154267-1-jiayuan.chen@linux.dev +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/caif/caif_serial.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c +index c398ac42eae90..b90890030751f 100644 +--- a/drivers/net/caif/caif_serial.c ++++ b/drivers/net/caif/caif_serial.c +@@ -284,6 +284,7 @@ static void ser_release(struct work_struct *work) + { + struct list_head list; + struct ser_device *ser, *tmp; ++ struct tty_struct *tty; + + spin_lock(&ser_lock); + list_replace_init(&ser_release_list, &list); +@@ -292,9 +293,11 @@ static void ser_release(struct work_struct *work) + if (!list_empty(&list)) { + rtnl_lock(); + list_for_each_entry_safe(ser, tmp, &list, node) { ++ tty = ser->tty; + dev_close(ser->dev); + unregister_netdevice(ser->dev); + debugfs_deinit(ser); ++ tty_kref_put(tty); + } + rtnl_unlock(); + } +@@ -355,8 +358,6 @@ static void ldisc_close(struct tty_struct *tty) + { + struct ser_device *ser = tty->disc_data; + +- tty_kref_put(ser->tty); +- + spin_lock(&ser_lock); + list_move(&ser->node, &ser_release_list); + spin_unlock(&ser_lock); +-- +2.51.0 + diff --git a/queue-6.19/serial-imx-change-serial_imx_console-to-bool.patch b/queue-6.19/serial-imx-change-serial_imx_console-to-bool.patch new file mode 100644 index 0000000000..dcd9029cc8 --- /dev/null +++ b/queue-6.19/serial-imx-change-serial_imx_console-to-bool.patch @@ -0,0 +1,50 @@ +From 30deb473fe9bc7356583315ef4d8f33714468b57 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 10 Jan 2026 15:26:40 -0800 +Subject: serial: imx: change SERIAL_IMX_CONSOLE to bool + +From: Randy Dunlap + +[ Upstream commit 79527d86ba91c2d9354832d19fd12b3baa66bd10 ] + +SERIAL_IMX_CONSOLE is a build option for the imx driver (SERIAL_IMX). +It does not build a separate console driver file, so it can't be built +as a module since it isn't built at all. + +Change the Kconfig symbol from tristate to bool and update the help +text accordingly. + +Fixes: 0db4f9b91c86 ("tty: serial: imx: enable imx serial console port as module") +Signed-off-by: Randy Dunlap +Link: https://patch.msgid.link/20260110232643.3533351-2-rdunlap@infradead.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/Kconfig | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig +index 59221cce0028f..98a946096be3c 100644 +--- a/drivers/tty/serial/Kconfig ++++ b/drivers/tty/serial/Kconfig +@@ -486,14 +486,14 @@ config SERIAL_IMX + can enable its onboard serial port by enabling this option. + + config SERIAL_IMX_CONSOLE +- tristate "Console on IMX serial port" ++ bool "Console on IMX serial port" + depends on SERIAL_IMX + select SERIAL_CORE_CONSOLE + help + If you have enabled the serial port on the Freescale IMX +- CPU you can make it the console by answering Y/M to this option. ++ CPU you can make it the console by answering Y to this option. + +- Even if you say Y/M here, the currently visible virtual console ++ Even if you say Y here, the currently visible virtual console + (/dev/tty0) will still be used as the system console by default, but + you can alter that using a kernel command line option such as + "console=ttymxc0". (Try "man bootparam" or see the documentation of +-- +2.51.0 + diff --git a/queue-6.19/serial-sh_sci-improve-dma-support-prompt.patch b/queue-6.19/serial-sh_sci-improve-dma-support-prompt.patch new file mode 100644 index 0000000000..37e8979073 --- /dev/null +++ b/queue-6.19/serial-sh_sci-improve-dma-support-prompt.patch @@ -0,0 +1,39 @@ +From d050011c5be48c11893cd102307f01ef115e2db9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 10 Jan 2026 15:26:43 -0800 +Subject: serial: SH_SCI: improve "DMA support" prompt + +From: Randy Dunlap + +[ Upstream commit 93bb95a11238d66a4c9aa6eabf9774b073a5895c ] + +Having a prompt of "DMA support" suddenly appear during a +"make oldconfig" can be confusing. Add a little helpful text to +the prompt message. + +Fixes: 73a19e4c0301 ("serial: sh-sci: Add DMA support.") +Signed-off-by: Randy Dunlap +Reviewed-by: Geert Uytterhoeven +Link: https://patch.msgid.link/20260110232643.3533351-5-rdunlap@infradead.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig +index 98a946096be3c..3d06c65c2f491 100644 +--- a/drivers/tty/serial/Kconfig ++++ b/drivers/tty/serial/Kconfig +@@ -671,7 +671,7 @@ config SERIAL_SH_SCI_EARLYCON + default ARCH_RENESAS + + config SERIAL_SH_SCI_DMA +- bool "DMA support" if EXPERT ++ bool "Support for DMA on SuperH SCI(F)" if EXPERT + depends on SERIAL_SH_SCI && DMA_ENGINE + default ARCH_RENESAS + +-- +2.51.0 + diff --git a/queue-6.19/series b/queue-6.19/series index 0b63edc9fd..7d3cfa9a1e 100644 --- a/queue-6.19/series +++ b/queue-6.19/series @@ -1,2 +1,617 @@ rdma-siw-fix-potential-null-pointer-dereference-in-header-processing.patch rdma-umad-reject-negative-data_len-in-ib_umad_write.patch +auxdisplay-arm-charlcd-fix-release_mem_region-size.patch +hfsplus-return-error-when-node-already-exists-in-hfs.patch +rcutorture-correctly-compute-probability-to-invoke-e.patch +rcu-fix-rcu_read_unlock-deadloop-due-to-softirq.patch +audit-move-the-compat_xxx_class-extern-declarations-.patch +selftests-resctrl-fix-a-division-by-zero-error-on-hy.patch +i3c-move-device-name-assignment-after-i3c_bus_init.patch +device_cgroup-remove-branch-hint-after-code-refactor.patch +fs-move-initializing-f_mode-before-file_ref_init.patch +fs-add-linux-init_task.h-for-init_fs.patch +i3c-master-update-hot-join-flag-only-on-success.patch +erofs-use-pe-format-specifier-for-error-pointers.patch +erofs-avoid-noisy-messages-for-transient-enomem.patch +gfs2-retries-missing-in-gfs2_-rename-exchange.patch +gfs2-rename-gfs2_log_submit_-bio-write.patch +gfs2-initialize-bio-bi_opf-early.patch +gfs2-fix-slab-use-after-free-in-qd_put.patch +iomap-fix-invalid-folio-access-after-folio_end_read.patch +gfs2-fix-use-after-free-in-iomap-inline-data-write-p.patch +i3c-dw-initialize-spinlock-to-avoid-upsetting-lockde.patch +i3c-dw-fix-memory-leak-in-dw_i3c_master_i2c_xfers.patch +tpm-tpm_i2c_infineon-fix-locality-leak-on-get_burstc.patch +tpm-st33zp24-fix-missing-cleanup-on-get_burstcount-e.patch +erofs-handle-end-of-filesystem-properly-for-file-bac.patch +btrfs-zoned-don-t-zone-append-to-conventional-zone.patch +btrfs-qgroup-return-correct-error-when-deleting-qgro.patch +btrfs-fix-block_group_tree-dirty_list-corruption.patch +btrfs-fix-eexist-abort-due-to-non-consecutive-gaps-i.patch +gfs2-fix-memory-leaks-in-gfs2_fill_super-error-path.patch +erofs-fix-inline-data-read-failure-for-ztailpacking-.patch +smb-client-fix-potential-uaf-and-double-free-in-smb2.patch +netfs-avoid-double-increment-of-retry_count-in-subre.patch +tools-nolibc-always-use-64-bit-mode-for-s390-header-.patch +rnbd-srv-fix-server-side-setting-of-bi_size-for-spec.patch +docs-find-unused-docs.sh-fixup-directory-usage.patch +acpi-processor-update-cpuidle-driver-check-in-__acpi.patch +xen-virtio-don-t-use-grant-dma-ops-when-running-as-d.patch +io_uring-use-release-acquire-ordering-for-ioring_set.patch +acpica-fix-null-pointer-dereference-in-acpi_ev_addre.patch +io_uring-eventfd-remove-unused-ctx-evfd_last_cq_tail.patch +io_uring-sync-validate-passed-in-offset.patch +cpuidle-governors-menu-always-check-timers-with-tick.patch +thermal-intel-x86_pkg_temp_thermal-handle-invalid-te.patch +md-raid5-fix-raid5_run-to-return-error-when-log_init.patch +md-raid10-fix-any_working-flag-handling-in-raid10_sy.patch +md-raid5-fix-io-hang-with-degraded-array-with-llbitm.patch +md-md-llbitmap-fix-percpu_ref-not-resurrected-on-sus.patch +opp-return-correct-value-in-dev_pm_opp_get_level.patch +cpufreq-scmi-correct-scmi-explanation.patch +cpufreq-scmi-fix-device_node-reference-leak-in-scmi_.patch +iomap-fix-submission-side-handling-of-completion-sid.patch +thermal-of-fix-reference-leak-in-thermal_of_cm_looku.patch +ublk-restore-auto-buf-unregister-refcount-optimizati.patch +ublk-validate-sqe128-flag-before-accessing-the-cmd.patch +ublk-use-read_once-to-read-struct-ublksrv_ctrl_cmd.patch +partial-revert-x86-xen-fix-balloon-target-initializa.patch +md-raid1-fix-memory-leak-in-raid1_run.patch +md-fix-return-value-of-mddev_trylock.patch +pm-wakeup-handle-empty-list-in-wakeup_sources_walk_s.patch +arm64-gcs-fix-error-handling-in-arch_set_shadow_stac.patch +block-don-t-use-strcpy-to-copy-blockdev-name.patch +perf-arm_spe-properly-set-hw.state-on-failures.patch +cpufreq-intel_pstate-enable-asym-capacity-only-when-.patch +pm-sleep-wakeirq-harden-dev_pm_clear_wake_irq-agains.patch +s390-cio-fix-device-lifecycle-handling-in-css_alloc_.patch +io_uring-kbuf-fix-memory-leak-if-io_buffer_add_list-.patch +x86-cpu-amd-correct-the-microcode-table-for-zenbleed.patch +perf-x86-core-do-not-set-bit-width-for-unavailable-c.patch +crypto-qat-fix-parameter-order-used-in-icp_qat_fw_co.patch +crypto-qat-fix-warning-on-adf_pfvf_pf_proto.c.patch +bpf-bpf_scc_visit-instance-and-backedges-accumulatio.patch +selftests-bpf-veristat-fix-printing-order-in-output_.patch +libbpf-fix-oob-read-in-btf_dump_get_bitfield_value.patch +sched-export-hidden-tracepoints-to-modules.patch +arm-vdso-patch-out-__vdso_clock_getres-if-unavailabl.patch +time-sched_clock-use-access_private-to-evaluate-hrti.patch +bpf-return-proper-address-for-non-zero-offsets-in-in.patch +sched-fix-build-for-modules-using-set_tsk_need_resch.patch +crypto-cavium-fix-dma_free_coherent-size.patch +crypto-octeontx-fix-dma_free_coherent-size.patch +crypto-hisilicon-zip-adjust-the-way-to-obtain-the-re.patch +crypto-hisilicon-sec-move-backlog-management-to-qp-a.patch +crypto-hisilicon-hpre-extend-tag-field-to-64-bits-fo.patch +crypto-hisilicon-qm-enhance-the-configuration-of-req.patch +crypto-hisilicon-qm-centralize-the-sending-locks-of-.patch +crypto-hisilicon-zip-support-fallback-for-zip.patch +crypto-hisilicon-consolidate-qp-creation-and-start-i.patch +crypto-hisilicon-hpre-support-the-hpre-algorithm-fal.patch +crypto-hisilicon-sec2-support-skcipher-aead-fallback.patch +crypto-hisilicon-sgl-fix-inconsistent-map-unmap-dire.patch +bpf-preserve-id-of-register-in-sync_linked_regs.patch +clocksource-drivers-timer-sp804-fix-an-oops-when-rea.patch +bpf-fix-memory-access-flags-in-helper-prototypes.patch +selftests-bpf-fix-resource-leak-in-serial_test_wq-on.patch +hrtimer-fix-trace-oddity.patch +crypto-inside-secure-eip93-fix-kernel-panic-in-drive.patch +crypto-ccp-fix-a-case-where-snp_shutdown-is-missed.patch +crypto-ccp-narrow-scope-of-snp_range_list.patch +hwrng-airoha-set-rng-quality-to-900.patch +rqspinlock-fix-tas-fallback-lock-entry-creation.patch +bpf-sockmap-fix-incorrect-copied_seq-calculation.patch +bpf-sockmap-fix-fionread-for-sockmap.patch +bpf-fix-tcx-netkit-detach-permissions-when-prog-fd-i.patch +seqlock-fix-scoped_seqlock_read-kernel-doc.patch +x86-hyperv-fix-smp_ops-build-failure-on-up-kernels.patch +ftrace-bpf-remove-ftrace_ops_fl_jmp-ftrace_ops-flag.patch +bpf-fix-verifier_bug_if-to-account-for-bpf_call.patch +crypto-ccp-fix-a-crash-due-to-incorrect-cleanup-usag.patch +crypto-inside-secure-eip93-unregister-only-available.patch +x86-fgraph-fix-return_to_handler-regs.rsp-value.patch +x86-fgraph-bpf-switch-kprobe_multi-program-stack-unw.patch +selftests-bpf-fix-kprobe-multi-stacktrace_ips-test.patch +crypto-hisilicon-trng-support-tfms-sharing-the-devic.patch +crypto-caam-fix-netdev-memory-leak-in-dpaa2_caam_pro.patch +bpf-fix-bpf_xdp_store_bytes-proto-for-read-only-arg.patch +genirq-set-irqf_cond_oneshot-in-devm_request_irq.patch +platform-x86-int0002-remove-irqf_oneshot-from-reques.patch +iommu-amd-use-core-s-primary-handler-and-set-irqf_on.patch +bluetooth-btintel_pcie-use-irqf_oneshot-and-default-.patch +scsi-efct-use-irqf_oneshot-and-default-primary-handl.patch +edac-altera-remove-irqf_oneshot.patch +usb-typec-fusb302-remove-irqf_oneshot.patch +rtc-amlogic-a4-remove-irqf_oneshot.patch +mfd-wm8350-core-use-irqf_oneshot.patch +media-pci-mg4b-use-irqf_no_thread.patch +sched-deadline-clear-the-defer-params.patch +sched-rt-skip-currently-executing-cpu-in-rto_next_cp.patch +sched-re-evaluate-scheduling-when-migrating-queued-t.patch +fs-tests-exec-drop-duplicate-bprm_stack_limits-test-.patch +irqchip-sifive-plic-handle-number-of-hardware-interr.patch +bpf-limit-bpf-program-signature-size.patch +bpf-require-frozen-map-for-calculating-map-hash.patch +crypto-starfive-fix-memory-leak-in-starfive_aes_aead.patch +hwrng-core-use-rcu-and-work_struct-to-fix-race-condi.patch +selftests-xsk-properly-handle-batch-ending-in-the-mi.patch +selftests-xsk-fix-number-of-tx-frags-in-invalid-pack.patch +pstore-ram-fix-buffer-overflow-in-persistent_ram_sav.patch +arm64-dts-ti-k3-am69-aquila-dev-fix-usb-c-sink-pdo.patch +arm64-dts-ti-k3-am69-aquila-clover-fix-usb-c-sink-pd.patch +soc-qcom-smem-handle-enomem-error-during-probe.patch +edac-i5000-fix-snprintf-size-calculation-in-calculat.patch +edac-i5400-fix-snprintf-limit-calculation-in-calcula.patch +firmware-arm_ffa-correct-32-bit-response-handling-in.patch +riscv-dts-sophgo-cv180x-fix-usb-dwc2-fifo-sizes.patch +arm64-dts-tqma8mpql-mba8mpxl-fix-hdmi-cec-pad-contro.patch +arm64-dts-tqma8mpql-mba8mp-ras314-fix-hdmi-cec-pad-c.patch +edac-amd64-avoid-a-wformat-security-warning.patch +clk-qcom-return-correct-error-code-in-qcom_cc_probe_.patch +arm64-dts-qcom-sdm630-fix-gpu_speed_bin-size.patch +arm64-dts-qcom-sm8150-hdk-mtp-specify-zap-firmware-n.patch +arm64-dts-qcom-sm8250-hdk-specify-zap-firmware-name.patch +arm64-dts-qcom-sdm850-huawei-matebook-e-2019-remove-.patch +arm64-dts-qcom-sdm850-huawei-matebook-e-2019-correct.patch +arm64-dts-qcom-sdm845-oneplus-don-t-mark-ts-supply-b.patch +arm64-dts-qcom-sdm845-oneplus-don-t-keep-panel-regul.patch +arm64-dts-qcom-sdm845-oneplus-mark-l14a-regulator-as.patch +arm64-dts-qcom-x1e80100-fix-usb-combo-phys-ss1-and-s.patch +arm64-dts-renesas-r9a09g047e57-smarc-remove-duplicat.patch +arm64-dts-qcom-msm8994-octagon-fix-analog-devices-ve.patch +arm-dts-allwinner-sun5i-a13-utoo-p66-delete-power-gp.patch +powerpc-uaccess-move-barrier_nospec-out-of-allow_rea.patch +soc-qcom-cmd-db-use-devm_memremap-to-fix-memory-leak.patch +soc-mediatek-svs-fix-memory-leak-in-svs_enable_debug.patch +powerpc-eeh-fix-recursive-pci_lock_rescan_remove-loc.patch +arm64-dts-renesas-rzt2h-n2h-evk-common-use-gpio-for-.patch +arm-dts-lpc32xx-add-clocks-property-to-motor-control.patch +arm64-dts-mediatek-mt8183-jacuzzi-pico6-fix-typo-in-.patch +arm64-dts-amlogic-s4-assign-mmc-b-clock-to-24mhz.patch +arm64-dts-amlogic-s4-fix-mmc-clock-assignment.patch +arm64-dts-ti-k3-j784s4-main.dtsi-move-c71_3-node-to-.patch +arm64-dts-ti-k3-j784s4-j742s2-main-common.dtsi-refac.patch +soc-qcom-ubwc-add-missing-include.patch +hwspinlock-omap-handle-devm_pm_runtime_enable-errors.patch +arm64-dts-amlogic-c3-assign-the-mmc-signal-clocks.patch +arm64-dts-amlogic-axg-assign-the-mmc-signal-clocks.patch +arm64-dts-amlogic-gx-assign-the-mmc-signal-clocks.patch +arm64-dts-amlogic-g12-assign-the-mmc-b-and-c-signal-.patch +arm64-dts-amlogic-g12-assign-the-mmc-a-signal-clock.patch +arm64-dts-qcom-qrb4210-rb2-fix-uart3-wakeup-irq-stor.patch +arm64-dts-qcom-sdm845-db845c-drop-cs-from-spio0.patch +arm64-dts-qcom-sdm845-db845c-specify-power-for-wifi-.patch +arm64-dts-ti-k3-am67a-kontron-sa67-base-fix-cma-node.patch +arm64-dts-ti-k3-am67a-kontron-sa67-base-fix-sd-card-.patch +arm64-dts-qcom-x1e-bus-is-40-bits-fix-64gb-models.patch +arm64-dts-imx95-use-gpu_cgc-as-core-clock-for-gpu.patch +arm64-dts-qcom-talos-drop-opp-shared-from-qup-opp-ta.patch +arm64-dts-amlogic-meson-sm1-odroid-eliminate-odroid-.patch +arm64-dts-qcom-agatti-add-cx_mem-dbgc-gpu-regions.patch +arm64-dts-qcom-sm6115-add-cx_mem-dbgc-gpu-regions.patch +reset-canaan-k230-drop-of-dependency-and-enable-by-d.patch +drm-xe-pf-fix-.bulk_profile-sched_priority-descripti.patch +drm-panthor-recover-from-panthor_gpu_flush_caches-fa.patch +drm-panthor-fix-the-full_tick-check.patch +drm-panthor-fix-the-group-priority-rotation-logic.patch +drm-panthor-fix-immediate-ticking-on-a-disabled-tick.patch +drm-panthor-fix-the-logic-that-decides-when-to-stop-.patch +drm-panthor-make-sure-we-resume-the-tick-when-new-jo.patch +drm-panthor-remove-redundant-call-to-disable-the-mcu.patch +drm-panthor-fix-queue_reset_timeout_locked.patch +workqueue-process-rescuer-work-items-one-by-one-usin.patch +drm-amdgpu-don-t-attach-the-tlb-fence-for-si.patch +drm-panthor-fix-panthor_gpu_coherency_set.patch +accel-amdxdna-fix-race-condition-when-checking-rpm_o.patch +accel-amdxdna-fix-cu_idx-being-cleared-by-memset-dur.patch +drm-plane-fix-is_err-vs-null-bug-drm_plane_create_co.patch +accel-amdxdna-fix-race-where-send-ring-appears-full-.patch +firmware-cs_dsp-remove-__free-from-cs_dsp_debugfs_st.patch +firmware-cs_dsp-don-t-use-__free-in-cs_dsp_load-and-.patch +spi-cadence-qspi-remove-redundant-pm_runtime_mark_la.patch +accel-amdxdna-fix-potential-null-pointer-dereference.patch +drm-panel-sw43408-remove-manual-invocation-of-unprep.patch +alsa-compress_offload-relax-__free-variable-declarat.patch +alsa-control-relax-__free-variable-declarations.patch +alsa-pcm-relax-__free-variable-declarations.patch +alsa-oss-relax-__free-variable-declarations.patch +alsa-seq-oss-relax-__free-variable-declarations.patch +alsa-seq-relax-__free-variable-declarations.patch +alsa-timer-relax-__free-variable-declarations.patch +alsa-vmaster-relax-__free-variable-declarations.patch +alsa-hda-relax-__free-variable-declarations.patch +alsa-usx2y-relax-__free-variable-declarations.patch +alsa-usb-audio-relax-__free-variable-declarations.patch +asoc-sdca-allow-sample-width-wild-cards-in-set_usage.patch +drm-panthor-fix-null-pointer-dereference-on-panthor_.patch +drm-i915-colorop-do-not-include-headers-from-headers.patch +drm-panthor-evict-groups-before-vm-termination.patch +drm-display-dp_mst-add-protection-against-0-vcpi.patch +drm-atomic-convert-drm_atomic_get_-old-new-_colorop_.patch +ima-fix-stack-out-of-bounds-in-is_bprm_creds_for_exe.patch +smack-smack-doi-must-be-0.patch +smack-smack-doi-accept-previously-used-values.patch +asoc-nau8821-fixup-nau8821_enable_jack_detect.patch +asoc-nau8821-cancel-delayed-work-on-component-remove.patch +asoc-nau8821-cancel-pending-work-before-suspend.patch +media-chips-media-wave5-fix-memory-leak-on-codec_inf.patch +drm-amd-display-don-t-use-kernel-doc-comment-in-dc_r.patch +drm-amdgpu-describe-amd_ip_block_type_ras-in-amd_ip_.patch +drm-amd-drop-amdgpu-kernel-modesetting-enabled-messa.patch +drm-amdkfd-fix-signal_eviction_fence-bool-return-val.patch +drm-amdgpu-use-explicit-vcn-instance-0-in-sr-iov-ini.patch +drm-amd-display-remove-unused-encoder-types.patch +drm-amd-display-use-local-variable-for-analog_engine.patch +drm-amd-display-pass-proper-dac-encoder-id-to-vbios.patch +drm-amd-display-update-dc_connection_dac_load-to-dc_.patch +drm-amd-display-don-t-repeat-dac-load-detection.patch +drm-msm-disp-dpu-add-merge3d-support-for-sc7280.patch +drm-msm-dpu-set-vsync-source-irrespective-of-mdp-top.patch +drm-msm-dpu-fix-wd-timer-handling-on-dpu-8.x.patch +drm-msm-dp-update-msm_dp_controller-ids-for-sa8775p.patch +alsa-hda-fix-function-names-missing-function-paramet.patch +mei-late_bind-fix-struct-intel_lb_component_ops-kern.patch +spi-microchip-core-use-xor-instead-of-andnot-to-fix-.patch +regulator-core-fix-locking-in-regulator_resolve_supp.patch +regulator-core-move-supply-check-earlier-in-set_mach.patch +regulator-core-don-t-ignore-errors-from-event-forwar.patch +hid-playstation-add-missing-check-for-input_ff_creat.patch +drm-amdgpu-ttm-pin-4k-mmio_remap-singleton-bo-at-ini.patch +drm-amdgpu-drop-mmio_remap-domain-bit-and-keep-it-in.patch +gpu-nova-core-check-for-overflow-to-dmatrfbase1.patch +drm-msm-disp-set-num_planes-to-1-for-interleaved-yuv.patch +drm-msm-dpu-drop-intr_start-from-dpu-3.x-catalog-fil.patch +drm-msm-dpu-fix-cmd-panels-on-dpu-1.x-3.x.patch +drm-msm-dsi_phy_14nm-convert-from-divider_round_rate.patch +accel-amdxdna-fix-notifier_wq-flushing-warning.patch +drm-msm-fix-x2-85-tpl1_dbg_eco_cntl1.patch +drm-msm-fix-gmem_base-for-gen8.patch +media-ccs-accommodate-c-phy-into-the-calculation.patch +drm-msm-a2xx-fix-pixel-shader-start-on-a225.patch +drm-buddy-release-free_trees-array-on-buddy-mm-teard.patch +drm-hisilicon-hibmc-fix-dp-probabilistical-detect-er.patch +drm-hisilicon-hibmc-add-dp-mode-valid-check.patch +drm-hisilicon-hibmc-fix-no-showing-problem-with-load.patch +drm-hisilicon-hibmc-adding-reset-colorbar-cfg-in-dp-.patch +drm-rockchip-dw_hdmi_qp-fix-rk3576-hpd-interrupt-han.patch +rust-pwm-fix-potential-memory-leak-on-init-error.patch +drm-amd-pm-fix-unneeded-semicolon-warning.patch +drm-msm-mdss-correct-hbb-programmed-on-ubwc-5.x-and-.patch +drm-msm-dpu-offset-hbb-values-written-to-dpu-by-13.patch +drm-msm-dpu-program-correct-register-for-ubwc-config.patch +drm-msm-dpu-fix-sspp_ubwc_static_ctrl-programming-on.patch +drm-msm-dp-avoid-division-by-zero-in-msm_dp_ctrl_con.patch +platform-chrome-cros_typec_switch-don-t-touch-struct.patch +pwm-tiehrpwm-enable-pwmchip-s-parent-device-before-s.patch +drm-amd-pm-return-eopnotsupp-when-can-t-read-power-l.patch +media-uvcvideo-fix-allocation-for-small-frame-sizes.patch +evm-use-ordered-xattrs-list-to-calculate-hmac-in-evm.patch +drm-xe-ptl-disable-dcc-on-ptl.patch +drm-xe-unregister-drm-device-on-probe-error.patch +mm-slab-fix-false-lockdep-warning-in-__kfree_rcu_she.patch +asoc-tegra-add-ahub-writeable_reg-for-rx-holes.patch +platform-chrome-cros_ec_lightbar-fix-response-size-i.patch +accel-amdxdna-hold-mm-structure-across-iommu_sva_unb.patch +accel-amdxdna-stop-job-scheduling-across-aie2_releas.patch +accel-amdxdna-fix-memory-leak-in-amdxdna_ubuf_map.patch +drm-i915-display-fix-the-pixel-normalization-handlin.patch +hid-intel-ish-hid-fix-null-ptr-deref-in-ishtp_bus_re.patch +hid-intel-thc-hid-intel-thc-fix-wrong-register-field.patch +accel-amdxdna-enable-temporal-sharing-only-mode.patch +accel-amdxdna-remove-hardware-context-status.patch +accel-amdxdna-fix-incorrect-error-code-returned-for-.patch +asoc-sdca-remove-outdated-todo-comment.patch +asoc-sdca-handle-volatile-controls-correctly.patch +asoc-sdca-factor-out-jack-handling-into-new-c-file.patch +asoc-sdca-add-ability-to-connect-sdca-jacks-to-asoc-.patch +asoc-sdca-still-process-most-of-the-jack-detect-if-c.patch +accel-amdxdna-fix-incorrect-dpm-level-after-suspend-.patch +accel-amdxdna-move-rpm-resume-into-job-run-function.patch +asoc-cs4271-fix-resource-leak-in-cs4271_soc_resume.patch +vsnprintf-drop-__printf-attributes-on-binary-printin.patch +alsa-oss-delete-self-assignment.patch +spi-tools-add-include-folder-to-.gitignore.patch +revert-hwmon-ibmpex-fix-use-after-free-in-high-low-s.patch +hwmon-pmbus-mpq8785-fix-vout_mode-mismatch-during-id.patch +pci-mediatek-fix-irq-domain-leak-when-msi-allocation.patch +wifi-rtw89-correct-use-sequence-of-driver_data-in-sk.patch +pci-xilinx-fix-intx-irq-domain-leak-in-error-paths.patch +documentation-pci-endpoint-fix-ntb-vntb-copy-paste-e.patch +pci-add-wq_percpu-to-alloc_workqueue-users.patch +pci-endpoint-add-missing-null-check-for-alloc_workqu.patch +pci-rzg3s-host-use-pci_generic_config_write-for-the-.patch +pci-pm-avoid-redundant-delays-on-d3hot-d3cold.patch +wifi-cfg80211-fix-use_for-flag-update-on-bss-refresh.patch +pci-p2pdma-release-per-cpu-pgmap-ref-when-vm_insert_.patch +pci-p2pdma-fix-p2pmem_alloc_mmap-warning-condition.patch +documentation-tracing-add-pci-tracepoint-documentati.patch +pci-do-not-attempt-to-set-exttag-for-vfs.patch +pci-sophgo-disable-l0s-and-l1-on-sophgo-2044-pcie-ro.patch +pci-portdrv-fix-potential-resource-leak.patch +dm-fix-unlocked-test-for-dm_suspended_md.patch +dm-use-read_once-in-dm_blk_report_zones.patch +pci-ptm-fix-pcie_ptm_create_debugfs-memory-leak.patch +pci-p2pdma-reset-page-reference-count-when-page-mapp.patch +wifi-ath9k-debug.h-fix-kernel-doc-bad-lines-and-stru.patch +wifi-ath9k-fix-kernel-doc-warnings-in-common-debug.h.patch +wifi-ath9k-add-of-dependency-to-ahb.patch +wifi-ath12k-do-wow-offloads-only-on-primary-link.patch +quota-fix-livelock-between-quotactl-and-freeze_super.patch +pci-pwrctrl-tc9563-use-put_device-instead-of-i2c_put.patch +net-mctp-i2c-fix-duplicate-reception-of-old-data.patch +mctp-i2c-initialise-event-handler-read-bytes.patch +wifi-cfg80211-stop-nan-and-p2p-in-cfg80211_leave.patch +iommupt-do-not-set-c-bit-on-mmio-backed-ptes.patch +ext4-fast-commit-make-s_fc_lock-reclaim-safe.patch +netfilter-nf_tables-reset-table-validation-state-on-.patch +netfilter-nf_conncount-increase-the-connection-clean.patch +netfilter-nft_compat-add-more-restrictions-on-netlin.patch +netfilter-nf_conncount-fix-tracking-of-connections-f.patch +kallsyms-bpf-rename-__bpf_address_lookup-to-bpf_addr.patch +module-add-helper-function-for-reading-module_buildi.patch +kallsyms-ftrace-set-module-buildid-in-ftrace_mod_add.patch +pci-mark-3ware-9650sa-root-port-extended-tags-as-bro.patch +wifi-rtw89-debug-fix-memory-leak-in-__print_txpwr_ma.patch +iommu-vt-d-flush-cache-for-pasid-table-before-using-.patch +iommu-vt-d-clear-present-bit-before-tearing-down-pas.patch +iommu-vt-d-clear-present-bit-before-tearing-down-con.patch +iommu-vt-d-fix-race-condition-during-pasid-entry-rep.patch +dm-use-bio_clone_blkg_association.patch +xdrgen-fix-struct-prefix-for-typedef-types-in-progra.patch +nfs-nfserr_inval-is-not-defined-by-nfsv2.patch +xdrgen-initialize-data-pointer-for-zero-length-items.patch +xdrgen-remove-inclusion-of-nlm4.h-header.patch +nfsd-never-defer-requests-during-idmap-lookup.patch +lib-kstrtox-fix-kstrtobool-docstring-to-mention-enab.patch +lib-kconfig.debug-fix-bootparam_hung_task_panic-comm.patch +rust-task-restrict-task-group_leader-to-current.patch +fat-avoid-parent-link-count-underflow-in-rmdir.patch +pci-rewrite-bridge-window-head-alignment-function.patch +pci-stop-over-estimating-bridge-window-size.patch +pci-remove-old_size-limit-from-bridge-window-sizing.patch +tcp-tcp_tx_timestamp-must-look-at-the-rtx-queue.patch +bluetooth-hci_conn-fix-using-conn-le_-tx-rx-_phy-as-.patch +pci-check-parent-for-null-in-of_pci_bus_release_doma.patch +wifi-ath10k-sdio-add-missing-lock-protection-in-ath1.patch +wifi-ath11k-add-usecase-firmware-handling-based-on-d.patch +wifi-ath12k-fix-index-decrement-when-array_len-is-ze.patch +wifi-ath12k-clear-stale-link-mapping-of-ahvif-links_.patch +pci-initialize-rcb-from-pci_configure_device.patch +pci-acpi-restrict-program_hpx_type2-to-aer-bits.patch +revert-net-smc-introduce-tcp-ulp-support.patch +selftests-mm-fix-usage-of-force_read-in-cow-tests.patch +selftests-mm-fix-faulting-in-code-in-pagemap_ioctl-t.patch +ipc-don-t-audit-capability-check-in-ipc_permissions.patch +ucount-check-for-cap_sys_resource-using-ns_capable_n.patch +jfs-avoid-wtautological-constant-out-of-range-compar.patch +pci-s32g-skip-root-port-removal-during-success.patch +tcp-ect_1_negotiation-and-needs_accecn-identifiers.patch +tcp-disable-rfc3168-fallback-identifier-for-cc-modul.patch +tcp-accecn-handle-unexpected-accecn-negotiation-feed.patch +pci-add-preceding-capability-position-support-in-pci.patch +pci-dwc-add-new-apis-to-remove-standard-and-extended.patch +pci-dwc-ep-cache-msi-outbound-iatu-mapping.patch +pci-dwc-remove-duplicate-dw_pcie_ep_hide_ext_capabil.patch +pci-endpoint-add-dynamic_inbound_mapping-epc-feature.patch +pci-endpoint-add-bar-subrange-mapping-support.patch +pci-dwc-advertise-dynamic-inbound-mapping-support.patch +pci-dwc-ep-support-bar-subrange-inbound-mapping-via-.patch +pci-dwc-ep-fix-resizable-bar-support-for-multi-pf-co.patch +pci-dwc-ep-add-per-pf-bar-and-inbound-atu-mapping-su.patch +of-unittest-fix-possible-null-pointer-dereferences-i.patch +mptcp-do-not-account-for-ooo-in-mptcp_rcvbuf_grow.patch +mptcp-fix-receive-space-timestamp-initialization.patch +octeontx2-af-fix-pf-driver-crash-with-kexec-kernel-b.patch +bonding-only-set-speed-duplex-to-unknown-if-getting-.patch +inet-raw-sockets-using-ipproto_raw-must-drop-incomin.patch +nfc-hci-shdlc-stop-timers-and-work-before-freeing-co.patch +amd-xgbe-do-not-select-net_selftests-when-inet-is-di.patch +netfilter-nfnetlink_queue-optimize-verdict-lookup-wi.patch +netfilter-nfnetlink_queue-do-shared-unconfirmed-chec.patch +netfilter-nft_set_hash-fix-get-operation-on-big-endi.patch +netfilter-nft_counter-fix-reset-of-counters-on-32bit.patch +netfilter-nft_set_rbtree-fix-bogus-eexist-with-nlm_f.patch +netfilter-nft_set_rbtree-check-for-partial-overlaps-.patch +netfilter-nft_set_rbtree-translate-rbtree-to-array-f.patch +netfilter-nft_set_rbtree-use-binary-search-array-in-.patch +netfilter-nft_set_rbtree-remove-seqcount_rwlock_t.patch +netfilter-nft_set_rbtree-don-t-gc-elements-on-insert.patch +netfilter-nft_set_rbtree-validate-element-belonging-.patch +netfilter-nft_set_rbtree-validate-open-interval-over.patch +pci-rzg3s-host-fix-device-node-reference-leak-in-rzg.patch +pci-add-acs-quirk-for-pericom-pi7c9x2g404-switches-1.patch +rust-driver-core-use-kernel-vertical-style-for-impor.patch +rust-devres-fix-race-condition-due-to-nesting.patch +dpll-zl3073x-fix-output-pin-phase-adjustment-sign.patch +net-hns3-fix-double-free-issue-for-tx-spare-buffer.patch +procfs-fix-missing-rcu-protection-when-reading-real_.patch +smb-client-correct-value-for-smbd_max_fragmented_rec.patch +net-atm-fix-crash-due-to-unvalidated-vcc-pointer-in-.patch +net-sunhme-fix-sbus-regression.patch +xfrm-fix-ip_rt_bug-race-in-icmp_route_lookup-reverse.patch +serial-caif-fix-use-after-free-in-caif_serial-ldisc_.patch +octeon_ep-disable-per-ring-interrupts.patch +octeon_ep-ensure-dbell-baddr-updation.patch +octeon_ep_vf-ensure-dbell-baddr-updation.patch +ionic-rate-limit-unknown-xcvr-type-messages.patch +net-renesas-rswitch-fix-forwarding-offload-statemach.patch +octeontx2-pf-unregister-devlink-on-probe-failure.patch +af_unix-fix-memleak-of-newsk-in-unix_stream_connect.patch +rdma-rtrs-server-remove-dead-code.patch +ib-cache-update-gid-cache-on-client-reregister-event.patch +rdma-hns-fix-wq_mem_reclaim-warning.patch +rdma-hns-return-actual-error-code-instead-of-fixed-e.patch +rdma-hns-fix-rocev1-failure-due-to-dscp.patch +rdma-hns-notify-ulp-of-remaining-soft-wcs-during-res.patch +rdma-mlx5-fix-ucaps-init-error-flow.patch +cxl-mem-fix-devm_cxl_memdev_edac_release-confusion.patch +power-supply-ab8500-fix-use-after-free-in-power_supp.patch +power-supply-act8945a-fix-use-after-free-in-power_su.patch +power-supply-bq256xx-fix-use-after-free-in-power_sup.patch +power-supply-bq25980-fix-use-after-free-in-power_sup.patch +power-supply-cpcap-battery-fix-use-after-free-in-pow.patch +power-supply-goldfish-fix-use-after-free-in-power_su.patch +power-supply-pf1550-fix-use-after-free-in-power_supp.patch +power-supply-pm8916_bms_vm-fix-use-after-free-in-pow.patch +power-supply-pm8916_lbc-fix-use-after-free-in-power_.patch +power-supply-rt9455-fix-use-after-free-in-power_supp.patch +power-supply-sbs-battery-fix-use-after-free-in-power.patch +power-reset-nvmem-reboot-mode-respect-cell-size-for-.patch +power-supply-bq27xxx-fix-wrong-errno-when-bus-ops-ar.patch +power-supply-wm97xx-fix-null-pointer-dereference-in-.patch +rdma-rtrs-srv-fix-sg-mapping.patch +rdma-rxe-fix-double-free-in-rxe_srq_from_init.patch +rdma-iwcm-fix-workqueue-list-corruption-by-removing-.patch +platform-x86-hp-wmi-fix-platform-profile-values-for-.patch +tools-power-x86-intel-speed-select-fix-file-descript.patch +rdma-mlx5-fix-umr-hang-in-lag-error-state-unload.patch +ib-mlx5-fix-port-speed-query-for-representors.patch +mtd-rawnand-cadence-fix-return-type-of-cdma-send-and.patch +mtd-intel-dg-fix-accessing-regions-before-setting-nr.patch +vfio-pci-lock-upstream-bridge-for-vfio_pci_core_disa.patch +platform-x86-amd-pmf-prevent-tee-errors-after-hibern.patch +crypto-ccp-declare-psp-dead-if-psp_cmd_tee_ring_init.patch +crypto-ccp-add-an-s4-restore-flow.patch +crypto-ccp-factor-out-ring-destroy-handling-to-a-hel.patch +crypto-ccp-send-psp_cmd_tee_ring_destroy-when-psp_cm.patch +mtd-parsers-fix-memory-leak-in-mtd_parser_tplink_saf.patch +nfs-localio-handle-short-writes-by-retrying.patch +nfs-localio-prevent-direct-reclaim-recursion-into-nf.patch +nfs-localio-use-gfp_noio-and-non-memreclaim-workqueu.patch +nfs-localio-remove-eagain-handling-in-nfs_local_doio.patch +cxl-hdm-fix-newline-character-in-dev_err-messages.patch +cxl-core-fix-cxl_dport-debugfs-einj-entries.patch +rdma-rxe-fix-iova-to-va-conversion-for-mr-page-sizes.patch +ata-libata-add-ata_quirk_max_sec-and-convert-all-dev.patch +ata-libata-core-quirk-intel-ssdsc2kg480g8-max_sector.patch +rdma-uverbs-validate-wqe_size-before-using-it-in-ib_.patch +rdma-mlx5-fix-memory-leak-in-get_data_direct_sysfs_p.patch +rdma-rxe-fix-race-condition-in-qp-timer-handlers.patch +rdma-core-add-rdma_rw_max_sge-helper-for-sq-sizing.patch +cxl-fix-premature-commit_end-increment-on-decoder-co.patch +mtd-parsers-ofpart-fix-of-node-refcount-leak-in-pars.patch +mtd-spinand-fix-kernel-doc.patch +hisi_acc_vfio_pci-fix-vf-reset-timeout-issue.patch +power-supply-pm8916_lbc-fix-use-after-free-for-extco.patch +power-supply-qcom_battmgr-recognize-lip-as-lithium-p.patch +rdma-uverbs-add-__gfp_nowarn-to-ib_uverbs_unmarshall.patch +pnfs-fix-a-missing-wake-up-while-waiting-on-nfs_layo.patch +scsi-smartpqi-fix-memory-leak-in-pqi_report_phys_lun.patch +scsi-ufs-host-mediatek-require-config_pm.patch +scsi-csiostor-fix-dereference-of-null-pointer-rn.patch +nvdimm-virtio_pmem-serialize-flush-requests.patch +fs-nfs-fix-readdir-slow-start-regression.patch +tracing-properly-process-error-handling-in-event_his.patch +tracing-remove-duplicate-enable_event_str-and-disabl.patch +remoteproc-imx_rproc-use-strstarts-for-rsc-table-che.patch +remoteproc-imx_dsp_rproc-fix-multiple-start-stop-ope.patch +remoteproc-imx_dsp_rproc-only-reset-carveout-memory-.patch +revert-mailbox-pcc-support-mailbox-management-of-the.patch +printk-vt-fbcon-remove-console_conditional_schedule.patch +fbdev-of_display_timing-fix-device-node-reference-le.patch +fbdev-au1200fb-fix-a-memory-leak-in-au1200fb_drv_pro.patch +clk-thead-th1520-ap-poll-for-pll-lock-and-wait-for-s.patch +clk-spacemit-respect-kconfig-setting-when-building-m.patch +clk-qcom-gcc-sm8550-use-floor-ops-for-sdcc-rcgs.patch +clk-qcom-gcc-sm8650-use-floor-ops-for-sdcc-rcgs.patch +clk-qcom-rcg2-compute-2d-using-duty-fraction-directl.patch +clk-meson-gxbb-limit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch +clk-meson-g12a-limit-the-hdmi-pll-od-to-4.patch +clk-qcom-gcc-sm8450-update-the-sdcc-rcgs-to-use-shar.patch +clk-qcom-gcc-sm8750-update-the-sdcc-rcgs-to-use-shar.patch +clk-qcom-gcc-sm4450-update-the-sdcc-rcgs-to-use-shar.patch +clk-qcom-gcc-sdx75-update-the-sdcc-rcgs-to-use-share.patch +clk-qcom-gcc-milos-update-the-sdcc-rcgs-to-use-share.patch +clk-qcom-gcc-x1e80100-update-the-sdcc-rcgs-to-use-sh.patch +clk-qcom-gcc-qdu1000-update-the-sdcc-rcgs-to-use-sha.patch +clk-qcom-gcc-glymur-update-the-sdcc-rcgs-to-use-shar.patch +clk-qcom-gcc-msm8953-remove-always_on-flag-from-cpp_.patch +clk-qcom-gcc-msm8917-remove-always_on-flag-from-cpp_.patch +clk-qcom-gcc-ipq5018-flag-sleep-clock-as-critical.patch +clk-qcom-alpha-pll-convert-from-divider_round_rate-t.patch +clk-rockchip-fix-error-pointer-check-after-rockchip_.patch +clk-microchip-core-remove-duplicate-determine_rate-o.patch +input-adp5589-remove-a-leftover-header-file.patch +clk-move-clk_-save-restore-_context-to-common_clk-se.patch +clk-qcom-regmap-divider-convert-from-divider_ro_roun.patch +clk-qcom-regmap-divider-convert-from-divider_round_r.patch +clk-qcom-dispcc-sdm845-enable-parents-for-pixel-cloc.patch +clk-qcom-dispcc-sm7150-fix-dispcc_mdss_pclk1_clk_src.patch +clk-qcom-gfx3d-add-parent-to-parent-request-map.patch +clk-actions-owl-composite-convert-from-owl_divider_h.patch +clk-actions-owl-divider-convert-from-divider_round_r.patch +clk-bm1880-convert-from-divider_round_rate-to-divide.patch +clk-hisilicon-clkdivider-hi6220-convert-from-divider.patch +clk-loongson1-convert-from-divider_round_rate-to-div.patch +clk-milbeaut-convert-from-divider_round_rate-to-divi.patch +clk-nuvoton-ma35d1-divider-convert-from-divider_roun.patch +clk-nxp-lpc32xx-convert-from-divider_round_rate-to-d.patch +clk-sophgo-sg2042-clkgen-convert-from-divider_round_.patch +clk-sprd-div-convert-from-divider_round_rate-to-divi.patch +clk-stm32-stm32-core-convert-from-divider_ro_round_r.patch +clk-stm32-stm32-core-convert-from-divider_round_rate.patch +clk-versaclock3-convert-from-divider_round_rate-to-d.patch +clk-x86-cgu-convert-from-divider_round_rate-to-divid.patch +clk-zynqmp-divider-convert-from-divider_round_rate-t.patch +clk-mediatek-drop-__initconst-from-gates.patch +clk-respect-clk_ops_parent_enable-during-recalc.patch +clk-mediatek-add-mfg_eb-as-parent-to-mt8196-mfgpll-c.patch +clk-mediatek-fix-error-handling-in-runtime-pm-setup.patch +clk-zynqmp-divider-fix-zynqmp_clk_divider_determine_.patch +clk-zynqmp-pll-fix-zynqmp_clk_divider_determine_rate.patch +interconnect-mediatek-don-t-hijack-parent-device.patch +interconnect-mediatek-aggregate-bandwidth-with-satur.patch +dmaengine-mediatek-uart-apdma-fix-above-4g-addressin.patch +dma-dma-axi-dmac-fix-sw-cyclic-transfers.patch +dma-dma-axi-dmac-fix-hw-scatter-gather-not-looking-a.patch +phy-rockchip-samsung-hdptx-pre-compute-hdmi-pll-conf.patch +char-misc-use-is_err-for-filp_open-return-value.patch +soundwire-intel_ace2x-add-snd_hda_core-dependency.patch +iio-test-drop-dangling-symbol-in-gain-time-scale-hel.patch +usb-typec-ucsi-drop-an-unused-kconfig-symbol.patch +staging-greybus-lights-avoid-null-deref.patch +serial-imx-change-serial_imx_console-to-bool.patch +serial-sh_sci-improve-dma-support-prompt.patch +gpib-fix-error-code-in-ibonline.patch +gpib-fix-error-code-in-ni_usb_write_registers.patch +gpib-fix-memory-leak-in-ni_usb_init.patch +stm-class-kconfig-correct-symbol-name.patch +mmc-rtsx_pci_sdmmc-increase-power-on-settling-delay-.patch +iio-pressure-mprls0025pa-fix-spi_transfer-struct-ini.patch +iio-pressure-mprls0025pa-fix-spi-cs-delay-violation.patch +iio-pressure-mprls0025pa-fix-interrupt-flag.patch +iio-pressure-mprls0025pa-fix-scan_type-struct.patch +iio-pressure-mprls0025pa-fix-pressure-calculation.patch +watchdog-starfive-wdt-fix-pm-reference-leak-in-probe.patch +coresight-etm3x-fix-cpulocked-warning-on-cpuhp.patch +backlight-aw99706-fix-build-errors-caused-by-wrong-g.patch +phy-freescale-imx8qm-hsio-fix-null-pointer-dereferen.patch +interconnect-qcom-qcs8300-fix-the-num_links-for-nsp-.patch +coresight-tmc-etr-fix-race-condition-between-sysfs-a.patch +revert-mmc-rtsx_pci_sdmmc-increase-power-on-settling.patch +mfd-arizona-fix-regulator-resource-leak-on-wm5102_cl.patch +mfd-simple-mfd-i2c-add-delta-tn48m-cpld-support.patch +mfd-sec-fix-irq-domain-names-duplication.patch +drivers-iio-mpu3050-use-dev_err_probe-for-regulator-.patch +usb-bdc-fix-sleep-during-atomic.patch +nvmem-an8855-drop-an-unused-kconfig-symbol.patch +mcb-fix-incorrect-sanity-check.patch +pinctrl-equilibrium-fix-device-node-reference-leak-i.patch +ovl-fix-uninit-value-in-ovl_fill_real.patch +nfsd-do-not-allow-exporting-of-special-kernel-filesy.patch +iio-sca3000-fix-a-resource-leak-in-sca3000_probe.patch +mips-loongson32-drop-a-dangling-kconfig-symbol.patch +pidfs-return-eremote-when-pidfd_get_info-is-called-o.patch +pinctrl-qcom-sm8250-lpass-lpi-fix-i2s2_data_groups-d.patch +pinctrl-meson-amlogic-a4-fix-device-node-reference-l.patch +pinctrl-single-fix-refcount-leak-in-pcs_add_gpio_fun.patch +pinctrl-canaan-k230-fix-null-pointer-dereference-whe.patch +leds-expresswire-fix-chip-state-breakage.patch +leds-qcom-lpg-check-the-return-value-of-regmap_bulk_.patch +backlight-qcom-wled-support-ovp-values-for-pmi8994.patch +backlight-qcom-wled-change-pm8950-wled-configuration.patch +dmaengine-fsl-edma-don-t-explicitly-disable-clocks-i.patch +drbd-always-set-blk_feat_stable_writes.patch +block-allow-ioc_pr_read_-ioctls-with-blk_open_read.patch +io_uring-delay-sqarray-static-branch-disablement.patch +io_uring-cancel-de-unionize-file-and-user_data-in-st.patch diff --git a/queue-6.19/smack-smack-doi-accept-previously-used-values.patch b/queue-6.19/smack-smack-doi-accept-previously-used-values.patch new file mode 100644 index 0000000000..3ff9275aef --- /dev/null +++ b/queue-6.19/smack-smack-doi-accept-previously-used-values.patch @@ -0,0 +1,233 @@ +From 3a4634872408acb3d2f96cda3f7e9f58ddc4fc94 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Sep 2025 15:31:53 +0300 +Subject: smack: /smack/doi: accept previously used values +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Konstantin Andreev + +[ Upstream commit 33d589ed60ae433b483761987b85e0d24e54584e ] + +Writing to /smack/doi a value that has ever been +written there in the past disables networking for +non-ambient labels. +E.g. + + # cat /smack/doi + 3 + # netlabelctl -p cipso list + Configured CIPSO mappings (1) + DOI value : 3 + mapping type : PASS_THROUGH + # netlabelctl -p map list + Configured NetLabel domain mappings (3) + domain: "_" (IPv4) + protocol: UNLABELED + domain: DEFAULT (IPv4) + protocol: CIPSO, DOI = 3 + domain: DEFAULT (IPv6) + protocol: UNLABELED + + # cat /smack/ambient + _ + # cat /proc/$$/attr/smack/current + _ + # ping -c1 10.1.95.12 + 64 bytes from 10.1.95.12: icmp_seq=1 ttl=64 time=0.964 ms + # echo foo >/proc/$$/attr/smack/current + # ping -c1 10.1.95.12 + 64 bytes from 10.1.95.12: icmp_seq=1 ttl=64 time=0.956 ms + unknown option 86 + + # echo 4 >/smack/doi + # echo 3 >/smack/doi +!> [ 214.050395] smk_cipso_doi:691 cipso add rc = -17 + # echo 3 >/smack/doi +!> [ 249.402261] smk_cipso_doi:678 remove rc = -2 +!> [ 249.402261] smk_cipso_doi:691 cipso add rc = -17 + + # ping -c1 10.1.95.12 +!!> ping: 10.1.95.12: Address family for hostname not supported + + # echo _ >/proc/$$/attr/smack/current + # ping -c1 10.1.95.12 + 64 bytes from 10.1.95.12: icmp_seq=1 ttl=64 time=0.617 ms + +This happens because Smack keeps decommissioned DOIs, +fails to re-add them, and consequently refuses to add +the “default” domain map: + + # netlabelctl -p cipso list + Configured CIPSO mappings (2) + DOI value : 3 + mapping type : PASS_THROUGH + DOI value : 4 + mapping type : PASS_THROUGH + # netlabelctl -p map list + Configured NetLabel domain mappings (2) + domain: "_" (IPv4) + protocol: UNLABELED +!> (no ipv4 map for default domain here) + domain: DEFAULT (IPv6) + protocol: UNLABELED + +Fix by clearing decommissioned DOI definitions and +serializing concurrent DOI updates with a new lock. + +Also: +- allow /smack/doi to live unconfigured, since + adding a map (netlbl_cfg_cipsov4_map_add) may fail. + CIPSO_V4_DOI_UNKNOWN(0) indicates the unconfigured DOI +- add new DOI before removing the old default map, + so the old map remains if the add fails + +(2008-02-04, Casey Schaufler) +Fixes: e114e473771c ("Smack: Simplified Mandatory Access Control Kernel") + +Signed-off-by: Konstantin Andreev +Signed-off-by: Casey Schaufler +Signed-off-by: Sasha Levin +--- + security/smack/smackfs.c | 71 +++++++++++++++++++++++++--------------- + 1 file changed, 45 insertions(+), 26 deletions(-) + +diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c +index e611e0fb56209..8919e330d2f60 100644 +--- a/security/smack/smackfs.c ++++ b/security/smack/smackfs.c +@@ -70,6 +70,7 @@ enum smk_inos { + static DEFINE_MUTEX(smack_cipso_lock); + static DEFINE_MUTEX(smack_ambient_lock); + static DEFINE_MUTEX(smk_net4addr_lock); ++static DEFINE_MUTEX(smk_cipso_doi_lock); + #if IS_ENABLED(CONFIG_IPV6) + static DEFINE_MUTEX(smk_net6addr_lock); + #endif /* CONFIG_IPV6 */ +@@ -141,7 +142,7 @@ struct smack_parsed_rule { + int smk_access2; + }; + +-static u32 smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; ++static u32 smk_cipso_doi_value = CIPSO_V4_DOI_UNKNOWN; + + /* + * Values for parsing cipso rules +@@ -663,43 +664,60 @@ static const struct file_operations smk_load_ops = { + }; + + /** +- * smk_cipso_doi - initialize the CIPSO domain ++ * smk_cipso_doi - set netlabel maps ++ * @ndoi: new value for our CIPSO DOI ++ * @gfp_flags: kmalloc allocation context + */ +-static void smk_cipso_doi(void) ++static int ++smk_cipso_doi(u32 ndoi, gfp_t gfp_flags) + { +- int rc; ++ int rc = 0; + struct cipso_v4_doi *doip; + struct netlbl_audit nai; + +- smk_netlabel_audit_set(&nai); ++ mutex_lock(&smk_cipso_doi_lock); + +- rc = netlbl_cfg_map_del(NULL, PF_INET, NULL, NULL, &nai); +- if (rc != 0) +- printk(KERN_WARNING "%s:%d remove rc = %d\n", +- __func__, __LINE__, rc); ++ if (smk_cipso_doi_value == ndoi) ++ goto clr_doi_lock; ++ ++ smk_netlabel_audit_set(&nai); + +- doip = kmalloc(sizeof(struct cipso_v4_doi), GFP_KERNEL | __GFP_NOFAIL); ++ doip = kmalloc(sizeof(struct cipso_v4_doi), gfp_flags); ++ if (!doip) { ++ rc = -ENOMEM; ++ goto clr_doi_lock; ++ } + doip->map.std = NULL; +- doip->doi = smk_cipso_doi_value; ++ doip->doi = ndoi; + doip->type = CIPSO_V4_MAP_PASS; + doip->tags[0] = CIPSO_V4_TAG_RBITMAP; + for (rc = 1; rc < CIPSO_V4_TAG_MAXCNT; rc++) + doip->tags[rc] = CIPSO_V4_TAG_INVALID; + + rc = netlbl_cfg_cipsov4_add(doip, &nai); +- if (rc != 0) { +- printk(KERN_WARNING "%s:%d cipso add rc = %d\n", +- __func__, __LINE__, rc); ++ if (rc) { + kfree(doip); +- return; ++ goto clr_doi_lock; + } +- rc = netlbl_cfg_cipsov4_map_add(doip->doi, NULL, NULL, NULL, &nai); +- if (rc != 0) { +- printk(KERN_WARNING "%s:%d map add rc = %d\n", +- __func__, __LINE__, rc); +- netlbl_cfg_cipsov4_del(doip->doi, &nai); +- return; ++ ++ if (smk_cipso_doi_value != CIPSO_V4_DOI_UNKNOWN) { ++ rc = netlbl_cfg_map_del(NULL, PF_INET, NULL, NULL, &nai); ++ if (rc && rc != -ENOENT) ++ goto clr_ndoi_def; ++ ++ netlbl_cfg_cipsov4_del(smk_cipso_doi_value, &nai); + } ++ ++ rc = netlbl_cfg_cipsov4_map_add(ndoi, NULL, NULL, NULL, &nai); ++ if (rc) { ++ smk_cipso_doi_value = CIPSO_V4_DOI_UNKNOWN; // no default map ++clr_ndoi_def: netlbl_cfg_cipsov4_del(ndoi, &nai); ++ } else ++ smk_cipso_doi_value = ndoi; ++ ++clr_doi_lock: ++ mutex_unlock(&smk_cipso_doi_lock); ++ return rc; + } + + /** +@@ -1599,11 +1617,8 @@ static ssize_t smk_write_doi(struct file *file, const char __user *buf, + + if (u == CIPSO_V4_DOI_UNKNOWN || u > U32_MAX) + return -EINVAL; +- smk_cipso_doi_value = u; +- +- smk_cipso_doi(); + +- return count; ++ return smk_cipso_doi(u, GFP_KERNEL) ? : count; + } + + static const struct file_operations smk_doi_ops = { +@@ -2984,6 +2999,7 @@ int __init init_smk_fs(void) + { + int err; + int rc; ++ struct netlbl_audit nai; + + if (smack_enabled == 0) + return 0; +@@ -3002,7 +3018,10 @@ int __init init_smk_fs(void) + } + } + +- smk_cipso_doi(); ++ smk_netlabel_audit_set(&nai); ++ (void) netlbl_cfg_map_del(NULL, PF_INET, NULL, NULL, &nai); ++ (void) smk_cipso_doi(SMACK_CIPSO_DOI_DEFAULT, ++ GFP_KERNEL | __GFP_NOFAIL); + smk_unlbl_ambient(NULL); + + rc = smack_populate_secattr(&smack_known_floor); +-- +2.51.0 + diff --git a/queue-6.19/smack-smack-doi-must-be-0.patch b/queue-6.19/smack-smack-doi-must-be-0.patch new file mode 100644 index 0000000000..a2c51c66a2 --- /dev/null +++ b/queue-6.19/smack-smack-doi-must-be-0.patch @@ -0,0 +1,71 @@ +From e3bbb206860d35e14bd7979554c2326dce4047fd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Sep 2025 15:16:02 +0300 +Subject: smack: /smack/doi must be > 0 + +From: Konstantin Andreev + +[ Upstream commit 19c013e1551bf51e1493da1270841d60e4fd3f15 ] + +/smack/doi allows writing and keeping negative doi values. +Correct values are 0 < doi <= (max 32-bit positive integer) + +(2008-02-04, Casey Schaufler) +Fixes: e114e473771c ("Smack: Simplified Mandatory Access Control Kernel") + +Signed-off-by: Konstantin Andreev +Signed-off-by: Casey Schaufler +Signed-off-by: Sasha Levin +--- + security/smack/smackfs.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c +index 2a9d3f2ebbe13..e611e0fb56209 100644 +--- a/security/smack/smackfs.c ++++ b/security/smack/smackfs.c +@@ -141,7 +141,7 @@ struct smack_parsed_rule { + int smk_access2; + }; + +-static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; ++static u32 smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; + + /* + * Values for parsing cipso rules +@@ -1562,7 +1562,7 @@ static ssize_t smk_read_doi(struct file *filp, char __user *buf, + if (*ppos != 0) + return 0; + +- sprintf(temp, "%d", smk_cipso_doi_value); ++ sprintf(temp, "%lu", (unsigned long)smk_cipso_doi_value); + rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp)); + + return rc; +@@ -1581,7 +1581,7 @@ static ssize_t smk_write_doi(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) + { + char temp[80]; +- int i; ++ unsigned long u; + + if (!smack_privileged(CAP_MAC_ADMIN)) + return -EPERM; +@@ -1594,10 +1594,12 @@ static ssize_t smk_write_doi(struct file *file, const char __user *buf, + + temp[count] = '\0'; + +- if (sscanf(temp, "%d", &i) != 1) ++ if (kstrtoul(temp, 10, &u)) + return -EINVAL; + +- smk_cipso_doi_value = i; ++ if (u == CIPSO_V4_DOI_UNKNOWN || u > U32_MAX) ++ return -EINVAL; ++ smk_cipso_doi_value = u; + + smk_cipso_doi(); + +-- +2.51.0 + diff --git a/queue-6.19/smb-client-correct-value-for-smbd_max_fragmented_rec.patch b/queue-6.19/smb-client-correct-value-for-smbd_max_fragmented_rec.patch new file mode 100644 index 0000000000..4a1bf2a007 --- /dev/null +++ b/queue-6.19/smb-client-correct-value-for-smbd_max_fragmented_rec.patch @@ -0,0 +1,78 @@ +From 5c610b53e1479b6509ba8e477c548ba3e3b158e9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 17:14:14 +0100 +Subject: smb: client: correct value for smbd_max_fragmented_recv_size + +From: Stefan Metzmacher + +[ Upstream commit 4a93d1ee2d0206970b6eb13fbffe07938cd95948 ] + +When we download a file without rdma offload or get +a large directly enumeration from the server, +the server might want to send up to smbd_max_fragmented_recv_size +bytes, but if it is too large all our recv buffers +might already be moved to the recv_io.reassembly.list +and we're no longer able to grant recv credits. + +The maximum fragmented upper-layer payload receive size supported + +Assume max_payload_per_credit is +smbd_max_receive_size - 24 = 1340 + +The maximum number would be +smbd_receive_credit_max * max_payload_per_credit + + 1340 * 255 = 341700 (0x536C4) + +The minimum value from the spec is 131072 (0x20000) + +For now we use the logic we used in ksmbd before: + (1364 * 255) / 2 = 173910 (0x2A756) + +Fixes: 03bee01d6215 ("CIFS: SMBD: Add SMB Direct protocol initial values and constants") +Cc: Steve French +Cc: Tom Talpey +Cc: Long Li +Cc: Namjae Jeon +Cc: linux-cifs@vger.kernel.org +Cc: samba-technical@lists.samba.org +Signed-off-by: Stefan Metzmacher +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/client/smbdirect.c | 19 +++++++++++++++++-- + 1 file changed, 17 insertions(+), 2 deletions(-) + +diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c +index 01d55bcc6d0f9..c8cef098d4806 100644 +--- a/fs/smb/client/smbdirect.c ++++ b/fs/smb/client/smbdirect.c +@@ -101,8 +101,23 @@ int smbd_send_credit_target = 255; + /* The maximum single message size can be sent to remote peer */ + int smbd_max_send_size = 1364; + +-/* The maximum fragmented upper-layer payload receive size supported */ +-int smbd_max_fragmented_recv_size = 1024 * 1024; ++/* ++ * The maximum fragmented upper-layer payload receive size supported ++ * ++ * Assume max_payload_per_credit is ++ * smbd_max_receive_size - 24 = 1340 ++ * ++ * The maximum number would be ++ * smbd_receive_credit_max * max_payload_per_credit ++ * ++ * 1340 * 255 = 341700 (0x536C4) ++ * ++ * The minimum value from the spec is 131072 (0x20000) ++ * ++ * For now we use the logic we used in ksmbd before: ++ * (1364 * 255) / 2 = 173910 (0x2A756) ++ */ ++int smbd_max_fragmented_recv_size = (1364 * 255) / 2; + + /* The maximum single-message size which can be received */ + int smbd_max_receive_size = 1364; +-- +2.51.0 + diff --git a/queue-6.19/smb-client-fix-potential-uaf-and-double-free-in-smb2.patch b/queue-6.19/smb-client-fix-potential-uaf-and-double-free-in-smb2.patch new file mode 100644 index 0000000000..1b29c51605 --- /dev/null +++ b/queue-6.19/smb-client-fix-potential-uaf-and-double-free-in-smb2.patch @@ -0,0 +1,41 @@ +From 8497d4dc0e171a9eb2014402e2953b78a4e69279 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 13:19:52 -0300 +Subject: smb: client: fix potential UAF and double free in smb2_open_file() + +From: Paulo Alcantara + +[ Upstream commit ebbbc4bfad4cb355d17c671223d0814ee3ef4eda ] + +Zero out @err_iov and @err_buftype before retrying SMB2_open() to +prevent an UAF bug if @data != NULL, otherwise a double free. + +Fixes: e3a43633023e ("smb/client: fix memory leak in smb2_open_file()") +Reported-by: David Howells +Closes: https://lore.kernel.org/r/2892312.1770306653@warthog.procyon.org.uk +Signed-off-by: Paulo Alcantara (Red Hat) +Reviewed-by: David Howells +Reviewed-by: ChenXiaoSong +Cc: linux-cifs@vger.kernel.org +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/client/smb2file.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/fs/smb/client/smb2file.c b/fs/smb/client/smb2file.c +index 2dd08388ea873..1f7f284a78449 100644 +--- a/fs/smb/client/smb2file.c ++++ b/fs/smb/client/smb2file.c +@@ -179,6 +179,8 @@ int smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, + &err_buftype); + if (rc == -EACCES && retry_without_read_attributes) { + free_rsp_buf(err_buftype, err_iov.iov_base); ++ memset(&err_iov, 0, sizeof(err_iov)); ++ err_buftype = CIFS_NO_BUFFER; + oparms->desired_access &= ~FILE_READ_ATTRIBUTES; + rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, smb2_data, NULL, &err_iov, + &err_buftype); +-- +2.51.0 + diff --git a/queue-6.19/soc-mediatek-svs-fix-memory-leak-in-svs_enable_debug.patch b/queue-6.19/soc-mediatek-svs-fix-memory-leak-in-svs_enable_debug.patch new file mode 100644 index 0000000000..386ffcc711 --- /dev/null +++ b/queue-6.19/soc-mediatek-svs-fix-memory-leak-in-svs_enable_debug.patch @@ -0,0 +1,59 @@ +From 384646409b657986434b41908cd9a84d5474ced2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 28 Dec 2025 16:26:36 +0000 +Subject: soc: mediatek: svs: Fix memory leak in svs_enable_debug_write() + +From: Zilin Guan + +[ Upstream commit 6259094ee806fb813ca95894c65fb80e2ec98bf1 ] + +In svs_enable_debug_write(), the buf allocated by memdup_user_nul() +is leaked if kstrtoint() fails. + +Fix this by using __free(kfree) to automatically free buf, eliminating +the need for explicit kfree() calls and preventing leaks. + +Fixes: 13f1bbcfb582 ("soc: mediatek: SVS: add debug commands") +Co-developed-by: Jianhao Xu +Signed-off-by: Jianhao Xu +Signed-off-by: Zilin Guan +[Angelo: Added missing cleanup.h inclusion] +Signed-off-by: AngeloGioacchino Del Regno +Signed-off-by: Sasha Levin +--- + drivers/soc/mediatek/mtk-svs.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/soc/mediatek/mtk-svs.c b/drivers/soc/mediatek/mtk-svs.c +index f45537546553e..99edecb204f25 100644 +--- a/drivers/soc/mediatek/mtk-svs.c ++++ b/drivers/soc/mediatek/mtk-svs.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -789,7 +790,7 @@ static ssize_t svs_enable_debug_write(struct file *filp, + struct svs_bank *svsb = file_inode(filp)->i_private; + struct svs_platform *svsp = dev_get_drvdata(svsb->dev); + int enabled, ret; +- char *buf = NULL; ++ char *buf __free(kfree) = NULL; + + if (count >= PAGE_SIZE) + return -EINVAL; +@@ -807,8 +808,6 @@ static ssize_t svs_enable_debug_write(struct file *filp, + svsb->mode_support = SVSB_MODE_ALL_DISABLE; + } + +- kfree(buf); +- + return count; + } + +-- +2.51.0 + diff --git a/queue-6.19/soc-qcom-cmd-db-use-devm_memremap-to-fix-memory-leak.patch b/queue-6.19/soc-qcom-cmd-db-use-devm_memremap-to-fix-memory-leak.patch new file mode 100644 index 0000000000..f50797b76c --- /dev/null +++ b/queue-6.19/soc-qcom-cmd-db-use-devm_memremap-to-fix-memory-leak.patch @@ -0,0 +1,53 @@ +From 5bd1609d83ed7e47f88866c61d7527d7cc8a6875 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Dec 2025 09:39:32 +0800 +Subject: soc: qcom: cmd-db: Use devm_memremap() to fix memory leak in + cmd_db_dev_probe + +From: Haotian Zhang + +[ Upstream commit 0da7824734d8d83e6a844dd0207f071cb0c50cf4 ] + +If cmd_db_magic_matches() fails after memremap() succeeds, the function +returns -EINVAL without unmapping the memory region, causing a +potential resource leak. + +Switch to devm_memremap to automatically manage the map resource. + +Fixes: 312416d9171a ("drivers: qcom: add command DB driver") +Suggested-by: Dmitry Baryshkov +Signed-off-by: Haotian Zhang +Link: https://lore.kernel.org/r/20251216013933.773-1-vulab@iscas.ac.cn +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/cmd-db.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/soc/qcom/cmd-db.c b/drivers/soc/qcom/cmd-db.c +index ae66c2623d250..84a75d8c4b702 100644 +--- a/drivers/soc/qcom/cmd-db.c ++++ b/drivers/soc/qcom/cmd-db.c +@@ -349,15 +349,16 @@ static int cmd_db_dev_probe(struct platform_device *pdev) + return -EINVAL; + } + +- cmd_db_header = memremap(rmem->base, rmem->size, MEMREMAP_WC); +- if (!cmd_db_header) { +- ret = -ENOMEM; ++ cmd_db_header = devm_memremap(&pdev->dev, rmem->base, rmem->size, MEMREMAP_WC); ++ if (IS_ERR(cmd_db_header)) { ++ ret = PTR_ERR(cmd_db_header); + cmd_db_header = NULL; + return ret; + } + + if (!cmd_db_magic_matches(cmd_db_header)) { + dev_err(&pdev->dev, "Invalid Command DB Magic\n"); ++ cmd_db_header = NULL; + return -EINVAL; + } + +-- +2.51.0 + diff --git a/queue-6.19/soc-qcom-smem-handle-enomem-error-during-probe.patch b/queue-6.19/soc-qcom-smem-handle-enomem-error-during-probe.patch new file mode 100644 index 0000000000..ae63609e95 --- /dev/null +++ b/queue-6.19/soc-qcom-smem-handle-enomem-error-during-probe.patch @@ -0,0 +1,39 @@ +From b49b8334d19de4e52dff48650d834b24cb4f7103 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 08:45:37 +0100 +Subject: soc: qcom: smem: handle ENOMEM error during probe + +From: Jorge Ramirez-Ortiz + +[ Upstream commit 0fe01a7955f4fef97e7cc6d14bfc5931c660402b ] + +Fail the driver probe if the region can't be mapped + +Signed-off-by: Jorge Ramirez-Ortiz +Fixes: 20bb6c9de1b7 ("soc: qcom: smem: map only partitions used by local HOST") +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20251209074610.3751781-1-jorge.ramirez@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/smem.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c +index c18a0c946f762..d5c94b47f431f 100644 +--- a/drivers/soc/qcom/smem.c ++++ b/drivers/soc/qcom/smem.c +@@ -1219,7 +1219,9 @@ static int qcom_smem_probe(struct platform_device *pdev) + smem->item_count = qcom_smem_get_item_count(smem); + break; + case SMEM_GLOBAL_HEAP_VERSION: +- qcom_smem_map_global(smem, size); ++ ret = qcom_smem_map_global(smem, size); ++ if (ret < 0) ++ return ret; + smem->item_count = SMEM_ITEM_COUNT; + break; + default: +-- +2.51.0 + diff --git a/queue-6.19/soc-qcom-ubwc-add-missing-include.patch b/queue-6.19/soc-qcom-ubwc-add-missing-include.patch new file mode 100644 index 0000000000..42462ec0ac --- /dev/null +++ b/queue-6.19/soc-qcom-ubwc-add-missing-include.patch @@ -0,0 +1,37 @@ +From ccc5e4f40170612ef4334557216c853447c305fd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 10 Jan 2026 21:37:53 +0200 +Subject: soc: qcom: ubwc: add missing include + +From: Dmitry Baryshkov + +[ Upstream commit ccef4b2703ff5b0de0b1bda30a0de3026d52eb19 ] + +The header has a function which calls pr_err(). Don't require users of +the header to include and include it here. + +Fixes: 87cfc79dcd60 ("drm/msm/a6xx: Resolve the meaning of UBWC_MODE") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Bryan O'Donoghue +Link: https://lore.kernel.org/r/20260110-iris-ubwc-v1-1-dd70494dcd7b@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + include/linux/soc/qcom/ubwc.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/include/linux/soc/qcom/ubwc.h b/include/linux/soc/qcom/ubwc.h +index 0a4edfe3d96d4..f052e241736c4 100644 +--- a/include/linux/soc/qcom/ubwc.h ++++ b/include/linux/soc/qcom/ubwc.h +@@ -8,6 +8,7 @@ + #define __QCOM_UBWC_H__ + + #include ++#include + #include + + struct qcom_ubwc_cfg_data { +-- +2.51.0 + diff --git a/queue-6.19/soundwire-intel_ace2x-add-snd_hda_core-dependency.patch b/queue-6.19/soundwire-intel_ace2x-add-snd_hda_core-dependency.patch new file mode 100644 index 0000000000..a9df416329 --- /dev/null +++ b/queue-6.19/soundwire-intel_ace2x-add-snd_hda_core-dependency.patch @@ -0,0 +1,45 @@ +From 34952f20be086ba91f3d982957d6529aa69ebafb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 23 Dec 2025 22:50:01 +0100 +Subject: soundwire: intel_ace2x: add SND_HDA_CORE dependency + +From: Arnd Bergmann + +[ Upstream commit dc3a6a942e9ee3f18560bfcb16c06bb94f37fabf ] + +The ace2x driver can optionally use the HDA infrastructure, but can still +build without that. However, with SND_HDA_CORE=m and SND_HDA_ALIGNED_MMIO=y, +it fails to link as built-in: + +aarch64-linux-ld: drivers/soundwire/intel_ace2x.o: in function `intel_shim_wake': +intel_ace2x.c:(.text+0x2518): undefined reference to `snd_hdac_aligned_read' +aarch64-linux-ld: intel_ace2x.c:(.text+0x25d4): undefined reference to `snd_hdac_aligned_read' +aarch64-linux-ld: intel_ace2x.c:(.text+0x268c): undefined reference to `snd_hdac_aligned_write' + +Add a Kconfig dependency that forces the soundwire driver to be a loadable +module if necessary. + +Fixes: 79e7123c078d ("soundwire: intel_ace2x: fix wakeup handling") +Signed-off-by: Arnd Bergmann +Link: https://patch.msgid.link/20251223215014.534756-1-arnd@kernel.org +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/soundwire/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/soundwire/Kconfig b/drivers/soundwire/Kconfig +index ad56393e4c93b..196a7daaabdb8 100644 +--- a/drivers/soundwire/Kconfig ++++ b/drivers/soundwire/Kconfig +@@ -40,6 +40,7 @@ config SOUNDWIRE_INTEL + select AUXILIARY_BUS + depends on ACPI && SND_SOC + depends on SND_SOC_SOF_HDA_MLINK || !SND_SOC_SOF_HDA_MLINK ++ depends on SND_HDA_CORE || !SND_HDA_ALIGNED_MMIO + help + SoundWire Intel Master driver. + If you have an Intel platform which has a SoundWire Master then +-- +2.51.0 + diff --git a/queue-6.19/spi-cadence-qspi-remove-redundant-pm_runtime_mark_la.patch b/queue-6.19/spi-cadence-qspi-remove-redundant-pm_runtime_mark_la.patch new file mode 100644 index 0000000000..0e6733e36f --- /dev/null +++ b/queue-6.19/spi-cadence-qspi-remove-redundant-pm_runtime_mark_la.patch @@ -0,0 +1,47 @@ +From 14ba93f167f69a898a6e5660fdce64f3e2dea7ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Dec 2025 23:19:21 +0500 +Subject: spi: cadence-qspi: Remove redundant pm_runtime_mark_last_busy call + +From: Akif Ejaz + +[ Upstream commit 28d21dfcea0121afec04451733a6c553fd319c8e ] + +The pm_runtime_mark_last_busy() call is redundant in probe function +as pm_runtime_put_autosuspend() already calls pm_runtime_mark_last_busy() +internally to update the last access time of the device before queuing +autosuspend. + +Remove the pm_runtime_mark_last_busy() call from the probe function. + +Tested on StarFive VisionFive 2 v1.2A board. + +Fixes: e1f2e77624db ("spi: cadence-qspi: Fix runtime PM imbalance in probe") + +Signed-off-by: Akif Ejaz +Link: https://patch.msgid.link/20251203181921.97171-1-akifejaz40@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-cadence-quadspi.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c +index 965b4cea3388a..b9a560c75c5cd 100644 +--- a/drivers/spi/spi-cadence-quadspi.c ++++ b/drivers/spi/spi-cadence-quadspi.c +@@ -2012,10 +2012,8 @@ static int cqspi_probe(struct platform_device *pdev) + goto probe_setup_failed; + } + +- if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) { +- pm_runtime_mark_last_busy(dev); ++ if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) + pm_runtime_put_autosuspend(dev); +- } + + return 0; + probe_setup_failed: +-- +2.51.0 + diff --git a/queue-6.19/spi-microchip-core-use-xor-instead-of-andnot-to-fix-.patch b/queue-6.19/spi-microchip-core-use-xor-instead-of-andnot-to-fix-.patch new file mode 100644 index 0000000000..b7201aced8 --- /dev/null +++ b/queue-6.19/spi-microchip-core-use-xor-instead-of-andnot-to-fix-.patch @@ -0,0 +1,46 @@ +From 529501e7032fcc108102cd35dfd7fbc4df33337e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 18:49:40 +0100 +Subject: spi: microchip-core: use XOR instead of ANDNOT to fix the logic + +From: Andy Shevchenko + +[ Upstream commit 19a4505a7a5d4eea70f1a42d601c25d730922fdf ] + +Use XOR instead of ANDNOT to fix the logic. The current approach with +(foo & BAR & ~baz) is harder to process, and it proved to be wrong, +than more usual pattern for the comparing misconfiguration using +((foo ^ baz) & BAR) which can be read as "find all different bits +between foo and baz that are related to BAR (mask)". Besides that +it makes the binary code shorter. + +Function old new delta +mchp_corespi_setup 103 99 -4 + +Fixes: 059f545832be ("spi: add support for microchip "soft" spi controller") +Reviewed-by: Conor Dooley +Tested-by: Prajna Rajendra Kumar +Signed-off-by: Andy Shevchenko +Link: https://patch.msgid.link/20260108175100.3535306-1-andriy.shevchenko@linux.intel.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-microchip-core-spi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/spi/spi-microchip-core-spi.c b/drivers/spi/spi-microchip-core-spi.c +index 89e40fc45d73a..c8ebb58e0369a 100644 +--- a/drivers/spi/spi-microchip-core-spi.c ++++ b/drivers/spi/spi-microchip-core-spi.c +@@ -161,7 +161,7 @@ static int mchp_corespi_setup(struct spi_device *spi) + return -EOPNOTSUPP; + } + +- if (spi->mode & SPI_MODE_X_MASK & ~spi->controller->mode_bits) { ++ if ((spi->mode ^ spi->controller->mode_bits) & SPI_MODE_X_MASK) { + dev_err(&spi->dev, "incompatible CPOL/CPHA, must match controller's Motorola mode\n"); + return -EINVAL; + } +-- +2.51.0 + diff --git a/queue-6.19/spi-tools-add-include-folder-to-.gitignore.patch b/queue-6.19/spi-tools-add-include-folder-to-.gitignore.patch new file mode 100644 index 0000000000..71f0627f4f --- /dev/null +++ b/queue-6.19/spi-tools-add-include-folder-to-.gitignore.patch @@ -0,0 +1,35 @@ +From 67cb453cc156744241520937f81afbfee6a7dd46 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 10:50:01 +0100 +Subject: spi: tools: Add include folder to .gitignore + +From: Francesco Lavra + +[ Upstream commit 5af56f30c4fcbade4a92f94dadfea517d1db9703 ] + +The Makefile for the SPI tools creates an include/linux/spi folder and some +symlinks inside it. After running `make -C spi/tools`, this folder shows up +as untracked in the git status. +Add the above folder to the .gitignore file. + +Fixes: f325b73dc4db ("spi: tools: move to tools buildsystem") +Signed-off-by: Francesco Lavra +Link: https://patch.msgid.link/20260209095001.556495-1-flavra@baylibre.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + tools/spi/.gitignore | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/tools/spi/.gitignore b/tools/spi/.gitignore +index 14ddba3d21957..038261b34ed83 100644 +--- a/tools/spi/.gitignore ++++ b/tools/spi/.gitignore +@@ -1,3 +1,4 @@ + # SPDX-License-Identifier: GPL-2.0-only + spidev_fdx + spidev_test ++include/ +-- +2.51.0 + diff --git a/queue-6.19/staging-greybus-lights-avoid-null-deref.patch b/queue-6.19/staging-greybus-lights-avoid-null-deref.patch new file mode 100644 index 0000000000..03e65dd977 --- /dev/null +++ b/queue-6.19/staging-greybus-lights-avoid-null-deref.patch @@ -0,0 +1,55 @@ +From 65ae8af6f00c0cfd79f37305e69fc472295bf787 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 20:42:54 +0530 +Subject: staging: greybus: lights: avoid NULL deref + +From: Chaitanya Mishra + +[ Upstream commit efcffd9a6ad8d190651498d5eda53bfc7cf683a7 ] + +gb_lights_light_config() stores channel_count before allocating the +channels array. If kcalloc() fails, gb_lights_release() iterates the +non-zero count and dereferences light->channels, which is NULL. + +Allocate channels first and only then publish channels_count so the +cleanup path can't walk a NULL pointer. + +Fixes: 2870b52bae4c ("greybus: lights: add lights implementation") +Link: https://lore.kernel.org/all/20260108103700.15384-1-chaitanyamishra.ai@gmail.com/ +Reviewed-by: Rui Miguel Silva +Signed-off-by: Chaitanya Mishra +Link: https://patch.msgid.link/20260108151254.81553-1-chaitanyamishra.ai@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/staging/greybus/light.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/drivers/staging/greybus/light.c b/drivers/staging/greybus/light.c +index e509fdc715dbb..38c233a706c48 100644 +--- a/drivers/staging/greybus/light.c ++++ b/drivers/staging/greybus/light.c +@@ -1008,14 +1008,18 @@ static int gb_lights_light_config(struct gb_lights *glights, u8 id) + if (!strlen(conf.name)) + return -EINVAL; + +- light->channels_count = conf.channel_count; + light->name = kstrndup(conf.name, NAMES_MAX, GFP_KERNEL); + if (!light->name) + return -ENOMEM; +- light->channels = kcalloc(light->channels_count, ++ light->channels = kcalloc(conf.channel_count, + sizeof(struct gb_channel), GFP_KERNEL); + if (!light->channels) + return -ENOMEM; ++ /* ++ * Publish channels_count only after channels allocation so cleanup ++ * doesn't walk a NULL channels pointer on allocation failure. ++ */ ++ light->channels_count = conf.channel_count; + + /* First we collect all the configurations for all channels */ + for (i = 0; i < light->channels_count; i++) { +-- +2.51.0 + diff --git a/queue-6.19/stm-class-kconfig-correct-symbol-name.patch b/queue-6.19/stm-class-kconfig-correct-symbol-name.patch new file mode 100644 index 0000000000..e5682ffd3c --- /dev/null +++ b/queue-6.19/stm-class-kconfig-correct-symbol-name.patch @@ -0,0 +1,48 @@ +From c42c2d01beafbca84bf999284b2abc0d921d1230 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 28 Dec 2025 11:05:02 -0800 +Subject: stm class: Kconfig: correct symbol name + +From: Randy Dunlap + +[ Upstream commit ed1613fc18834b5ec38d3534e96e4bc990289aa2 ] + +Drop the leading "CONFIG_" when referring to Kconfig symbols-- +it is supplied by the kconfig software. +This make the default values work as (apparently) expected. + +Fixes: a02509f301c6 ("stm class: Factor out default framing protocol") +Fixes: d69d5e83110f ("stm class: Add MIPI SyS-T protocol support") +Signed-off-by: Randy Dunlap +Link: https://patch.msgid.link/20251228190502.2480758-1-rdunlap@infradead.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/hwtracing/stm/Kconfig | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/hwtracing/stm/Kconfig b/drivers/hwtracing/stm/Kconfig +index eda6b11d40a1f..cd7f0b0f3fbeb 100644 +--- a/drivers/hwtracing/stm/Kconfig ++++ b/drivers/hwtracing/stm/Kconfig +@@ -13,7 +13,7 @@ if STM + + config STM_PROTO_BASIC + tristate "Basic STM framing protocol driver" +- default CONFIG_STM ++ default STM + help + This is a simple framing protocol for sending data over STM + devices. This was the protocol that the STM framework used +@@ -28,7 +28,7 @@ config STM_PROTO_BASIC + + config STM_PROTO_SYS_T + tristate "MIPI SyS-T STM framing protocol driver" +- default CONFIG_STM ++ default STM + help + This is an implementation of MIPI SyS-T protocol to be used + over the STP transport. In addition to the data payload, it +-- +2.51.0 + diff --git a/queue-6.19/tcp-accecn-handle-unexpected-accecn-negotiation-feed.patch b/queue-6.19/tcp-accecn-handle-unexpected-accecn-negotiation-feed.patch new file mode 100644 index 0000000000..844fffdaba --- /dev/null +++ b/queue-6.19/tcp-accecn-handle-unexpected-accecn-negotiation-feed.patch @@ -0,0 +1,117 @@ +From f89251b534839dc2ee7b33f127b03a982a316e7c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Jan 2026 23:25:06 +0100 +Subject: tcp: accecn: handle unexpected AccECN negotiation feedback + +From: Chia-Yu Chang + +[ Upstream commit c5ff6b83715919767f181f13e992b5055812a194 ] + +According to Sections 3.1.2 and 3.1.3 of AccECN spec (RFC9768). + +In Section 3.1.2, it says an AccECN implementation has no need to +recognize or support the Server response labelled 'Nonce' or ECN-nonce +feedback more generally, as RFC 3540 has been reclassified as Historic. +AccECN is compatible with alternative ECN feedback integrity approaches +to the nonce. The SYN/ACK labelled 'Nonce' with (AE,CWR,ECE) = (1,0,1) +is reserved for future use. A TCP Client (A) that receives such a SYN/ACK +follows the procedure for forward compatibility given in Section 3.1.3. + +Then in Section 3.1.3, it says if a TCP Client has sent a SYN requesting +AccECN feedback with (AE,CWR,ECE) = (1,1,1) then receives a SYN/ACK with +the currently reserved combination (AE,CWR,ECE) = (1,0,1) but it does not +have logic specific to such a combination, the Client MUST enable AccECN +mode as if the SYN/ACK onfirmed that the Server supported AccECN and as +if it fed back that the IP-ECN field on the SYN had arrived unchanged. + +Fixes: 3cae34274c79 ("tcp: accecn: AccECN negotiation"). +Signed-off-by: Chia-Yu Chang +Acked-by: Paolo Abeni +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260131222515.8485-7-chia-yu.chang@nokia-bell-labs.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + include/net/tcp_ecn.h | 44 ++++++++++++++++++++++++++++++------------- + 1 file changed, 31 insertions(+), 13 deletions(-) + +diff --git a/include/net/tcp_ecn.h b/include/net/tcp_ecn.h +index 2e1637edf1d3c..a709fb1756eb7 100644 +--- a/include/net/tcp_ecn.h ++++ b/include/net/tcp_ecn.h +@@ -473,6 +473,26 @@ static inline u8 tcp_accecn_option_init(const struct sk_buff *skb, + return TCP_ACCECN_OPT_COUNTER_SEEN; + } + ++static inline void tcp_ecn_rcv_synack_accecn(struct sock *sk, ++ const struct sk_buff *skb, u8 dsf) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ tcp_ecn_mode_set(tp, TCP_ECN_MODE_ACCECN); ++ tp->syn_ect_rcv = dsf & INET_ECN_MASK; ++ /* Demand Accurate ECN option in response to the SYN on the SYN/ACK ++ * and the TCP server will try to send one more packet with an AccECN ++ * Option at a later point during the connection. ++ */ ++ if (tp->rx_opt.accecn && ++ tp->saw_accecn_opt < TCP_ACCECN_OPT_COUNTER_SEEN) { ++ u8 saw_opt = tcp_accecn_option_init(skb, tp->rx_opt.accecn); ++ ++ tcp_accecn_saw_opt_fail_recv(tp, saw_opt); ++ tp->accecn_opt_demand = 2; ++ } ++} ++ + /* See Table 2 of the AccECN draft */ + static inline void tcp_ecn_rcv_synack(struct sock *sk, const struct sk_buff *skb, + const struct tcphdr *th, u8 ip_dsfield) +@@ -495,13 +515,11 @@ static inline void tcp_ecn_rcv_synack(struct sock *sk, const struct sk_buff *skb + tcp_ecn_mode_set(tp, TCP_ECN_DISABLED); + break; + case 0x1: +- case 0x5: + /* +========+========+============+=============+ + * | A | B | SYN/ACK | Feedback | + * | | | B->A | Mode of A | + * | | | AE CWR ECE | | + * +========+========+============+=============+ +- * | AccECN | Nonce | 1 0 1 | (Reserved) | + * | AccECN | ECN | 0 0 1 | Classic ECN | + * | Nonce | AccECN | 0 0 1 | Classic ECN | + * | ECN | AccECN | 0 0 1 | Classic ECN | +@@ -509,20 +527,20 @@ static inline void tcp_ecn_rcv_synack(struct sock *sk, const struct sk_buff *skb + */ + if (tcp_ca_no_fallback_rfc3168(sk)) + tcp_ecn_mode_set(tp, TCP_ECN_DISABLED); +- else if (tcp_ecn_mode_pending(tp)) +- /* Downgrade from AccECN, or requested initially */ ++ else + tcp_ecn_mode_set(tp, TCP_ECN_MODE_RFC3168); + break; +- default: +- tcp_ecn_mode_set(tp, TCP_ECN_MODE_ACCECN); +- tp->syn_ect_rcv = ip_dsfield & INET_ECN_MASK; +- if (tp->rx_opt.accecn && +- tp->saw_accecn_opt < TCP_ACCECN_OPT_COUNTER_SEEN) { +- u8 saw_opt = tcp_accecn_option_init(skb, tp->rx_opt.accecn); +- +- tcp_accecn_saw_opt_fail_recv(tp, saw_opt); +- tp->accecn_opt_demand = 2; ++ case 0x5: ++ if (tcp_ecn_mode_pending(tp)) { ++ tcp_ecn_rcv_synack_accecn(sk, skb, ip_dsfield); ++ if (INET_ECN_is_ce(ip_dsfield)) { ++ tp->received_ce++; ++ tp->received_ce_pending++; ++ } + } ++ break; ++ default: ++ tcp_ecn_rcv_synack_accecn(sk, skb, ip_dsfield); + if (INET_ECN_is_ce(ip_dsfield) && + tcp_accecn_validate_syn_feedback(sk, ace, + tp->syn_ect_snt)) { +-- +2.51.0 + diff --git a/queue-6.19/tcp-disable-rfc3168-fallback-identifier-for-cc-modul.patch b/queue-6.19/tcp-disable-rfc3168-fallback-identifier-for-cc-modul.patch new file mode 100644 index 0000000000..62ce45451e --- /dev/null +++ b/queue-6.19/tcp-disable-rfc3168-fallback-identifier-for-cc-modul.patch @@ -0,0 +1,135 @@ +From 0256d80f774983a68708e686b2e5dec7c9f88dcd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Jan 2026 23:25:05 +0100 +Subject: tcp: disable RFC3168 fallback identifier for CC modules + +From: Chia-Yu Chang + +[ Upstream commit e68c28f22f46ecfdec3656ae785dd8ccbb4d557d ] + +When AccECN is not successfully negociated for a TCP flow, it defaults +fallback to classic ECN (RFC3168). However, L4S service will fallback +to non-ECN. + +This patch enables congestion control module to control whether it +should not fallback to classic ECN after unsuccessful AccECN negotiation. +A new CA module flag (TCP_CONG_NO_FALLBACK_RFC3168) identifies this +behavior expected by the CA. + +Signed-off-by: Chia-Yu Chang +Acked-by: Paolo Abeni +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260131222515.8485-6-chia-yu.chang@nokia-bell-labs.com +Signed-off-by: Paolo Abeni +Stable-dep-of: c5ff6b837159 ("tcp: accecn: handle unexpected AccECN negotiation feedback") +Signed-off-by: Sasha Levin +--- + include/net/tcp.h | 12 +++++++++++- + include/net/tcp_ecn.h | 11 ++++++++--- + net/ipv4/tcp_input.c | 2 +- + net/ipv4/tcp_minisocks.c | 7 ++++--- + 4 files changed, 24 insertions(+), 8 deletions(-) + +diff --git a/include/net/tcp.h b/include/net/tcp.h +index c4c25f2e0c0dd..e0a5cf2f78181 100644 +--- a/include/net/tcp.h ++++ b/include/net/tcp.h +@@ -1207,8 +1207,11 @@ enum tcp_ca_ack_event_flags { + #define TCP_CONG_NEEDS_ACCECN BIT(2) + /* Use ECT(1) instead of ECT(0) while the CA is uninitialized */ + #define TCP_CONG_ECT_1_NEGOTIATION BIT(3) ++/* Cannot fallback to RFC3168 during AccECN negotiation */ ++#define TCP_CONG_NO_FALLBACK_RFC3168 BIT(4) + #define TCP_CONG_MASK (TCP_CONG_NON_RESTRICTED | TCP_CONG_NEEDS_ECN | \ +- TCP_CONG_NEEDS_ACCECN | TCP_CONG_ECT_1_NEGOTIATION) ++ TCP_CONG_NEEDS_ACCECN | TCP_CONG_ECT_1_NEGOTIATION | \ ++ TCP_CONG_NO_FALLBACK_RFC3168) + + union tcp_cc_info; + +@@ -1354,6 +1357,13 @@ static inline bool tcp_ca_ect_1_negotiation(const struct sock *sk) + return icsk->icsk_ca_ops->flags & TCP_CONG_ECT_1_NEGOTIATION; + } + ++static inline bool tcp_ca_no_fallback_rfc3168(const struct sock *sk) ++{ ++ const struct inet_connection_sock *icsk = inet_csk(sk); ++ ++ return icsk->icsk_ca_ops->flags & TCP_CONG_NO_FALLBACK_RFC3168; ++} ++ + static inline void tcp_ca_event(struct sock *sk, const enum tcp_ca_event event) + { + const struct inet_connection_sock *icsk = inet_csk(sk); +diff --git a/include/net/tcp_ecn.h b/include/net/tcp_ecn.h +index fdde1c342b35c..2e1637edf1d3c 100644 +--- a/include/net/tcp_ecn.h ++++ b/include/net/tcp_ecn.h +@@ -507,7 +507,9 @@ static inline void tcp_ecn_rcv_synack(struct sock *sk, const struct sk_buff *skb + * | ECN | AccECN | 0 0 1 | Classic ECN | + * +========+========+============+=============+ + */ +- if (tcp_ecn_mode_pending(tp)) ++ if (tcp_ca_no_fallback_rfc3168(sk)) ++ tcp_ecn_mode_set(tp, TCP_ECN_DISABLED); ++ else if (tcp_ecn_mode_pending(tp)) + /* Downgrade from AccECN, or requested initially */ + tcp_ecn_mode_set(tp, TCP_ECN_MODE_RFC3168); + break; +@@ -531,9 +533,11 @@ static inline void tcp_ecn_rcv_synack(struct sock *sk, const struct sk_buff *skb + } + } + +-static inline void tcp_ecn_rcv_syn(struct tcp_sock *tp, const struct tcphdr *th, ++static inline void tcp_ecn_rcv_syn(struct sock *sk, const struct tcphdr *th, + const struct sk_buff *skb) + { ++ struct tcp_sock *tp = tcp_sk(sk); ++ + if (tcp_ecn_mode_pending(tp)) { + if (!tcp_accecn_syn_requested(th)) { + /* Downgrade to classic ECN feedback */ +@@ -545,7 +549,8 @@ static inline void tcp_ecn_rcv_syn(struct tcp_sock *tp, const struct tcphdr *th, + tcp_ecn_mode_set(tp, TCP_ECN_MODE_ACCECN); + } + } +- if (tcp_ecn_mode_rfc3168(tp) && (!th->ece || !th->cwr)) ++ if (tcp_ecn_mode_rfc3168(tp) && ++ (!th->ece || !th->cwr || tcp_ca_no_fallback_rfc3168(sk))) + tcp_ecn_mode_set(tp, TCP_ECN_DISABLED); + } + +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index 736f8f55ab5a6..0d080a3e27d6f 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -6843,7 +6843,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, + tp->snd_wl1 = TCP_SKB_CB(skb)->seq; + tp->max_window = tp->snd_wnd; + +- tcp_ecn_rcv_syn(tp, th, skb); ++ tcp_ecn_rcv_syn(sk, th, skb); + + tcp_mtup_init(sk); + tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); +diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c +index bd5462154f970..9776c921d1bb4 100644 +--- a/net/ipv4/tcp_minisocks.c ++++ b/net/ipv4/tcp_minisocks.c +@@ -485,9 +485,10 @@ static void tcp_ecn_openreq_child(struct sock *sk, + tp->accecn_opt_demand = 1; + tcp_ecn_received_counters_payload(sk, skb); + } else { +- tcp_ecn_mode_set(tp, inet_rsk(req)->ecn_ok ? +- TCP_ECN_MODE_RFC3168 : +- TCP_ECN_DISABLED); ++ if (inet_rsk(req)->ecn_ok && !tcp_ca_no_fallback_rfc3168(sk)) ++ tcp_ecn_mode_set(tp, TCP_ECN_MODE_RFC3168); ++ else ++ tcp_ecn_mode_set(tp, TCP_ECN_DISABLED); + } + } + +-- +2.51.0 + diff --git a/queue-6.19/tcp-ect_1_negotiation-and-needs_accecn-identifiers.patch b/queue-6.19/tcp-ect_1_negotiation-and-needs_accecn-identifiers.patch new file mode 100644 index 0000000000..a8dc8d382b --- /dev/null +++ b/queue-6.19/tcp-ect_1_negotiation-and-needs_accecn-identifiers.patch @@ -0,0 +1,207 @@ +From 9d7355d516c7a9279216a4b1a0ae7c84dd4c4fad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Jan 2026 23:25:04 +0100 +Subject: tcp: ECT_1_NEGOTIATION and NEEDS_ACCECN identifiers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Chia-Yu Chang + +[ Upstream commit 100f946b8d44b64bc0b8a8c30d283105031c0a77 ] + +Two flags for congestion control (CC) module are added in this patch +related to AccECN negotiation. First, a new flag (TCP_CONG_NEEDS_ACCECN) +defines that the CC expects to negotiate AccECN functionality using the +ECE, CWR and AE flags in the TCP header. + +Second, during ECN negotiation, ECT(0) in the IP header is used. This +patch enables CC to control whether ECT(0) or ECT(1) should be used on +a per-segment basis. A new flag (TCP_CONG_ECT_1_NEGOTIATION) defines the +expected ECT value in the IP header by the CA when not-yet initialized +for the connection. + +The detailed AccECN negotiaotn can be found in IETF RFC9768. + +Co-developed-by: Olivier Tilmans +Signed-off-by: Olivier Tilmans +Signed-off-by: Ilpo Järvinen +Signed-off-by: Chia-Yu Chang +Acked-by: Paolo Abeni +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260131222515.8485-5-chia-yu.chang@nokia-bell-labs.com +Signed-off-by: Paolo Abeni +Stable-dep-of: c5ff6b837159 ("tcp: accecn: handle unexpected AccECN negotiation feedback") +Signed-off-by: Sasha Levin +--- + include/net/inet_ecn.h | 20 +++++++++++++++++--- + include/net/tcp.h | 21 ++++++++++++++++++++- + include/net/tcp_ecn.h | 13 ++++++++++--- + net/ipv4/tcp_cong.c | 5 +++-- + net/ipv4/tcp_input.c | 3 ++- + 5 files changed, 52 insertions(+), 10 deletions(-) + +diff --git a/include/net/inet_ecn.h b/include/net/inet_ecn.h +index ea32393464a29..827b87a95dab3 100644 +--- a/include/net/inet_ecn.h ++++ b/include/net/inet_ecn.h +@@ -51,11 +51,25 @@ static inline __u8 INET_ECN_encapsulate(__u8 outer, __u8 inner) + return outer; + } + ++/* Apply either ECT(0) or ECT(1) */ ++static inline void __INET_ECN_xmit(struct sock *sk, bool use_ect_1) ++{ ++ __u8 ect = use_ect_1 ? INET_ECN_ECT_1 : INET_ECN_ECT_0; ++ ++ /* Mask the complete byte in case the connection alternates between ++ * ECT(0) and ECT(1). ++ */ ++ inet_sk(sk)->tos &= ~INET_ECN_MASK; ++ inet_sk(sk)->tos |= ect; ++ if (inet6_sk(sk)) { ++ inet6_sk(sk)->tclass &= ~INET_ECN_MASK; ++ inet6_sk(sk)->tclass |= ect; ++ } ++} ++ + static inline void INET_ECN_xmit(struct sock *sk) + { +- inet_sk(sk)->tos |= INET_ECN_ECT_0; +- if (inet6_sk(sk) != NULL) +- inet6_sk(sk)->tclass |= INET_ECN_ECT_0; ++ __INET_ECN_xmit(sk, false); + } + + static inline void INET_ECN_dontxmit(struct sock *sk) +diff --git a/include/net/tcp.h b/include/net/tcp.h +index 0deb5e9dd9114..c4c25f2e0c0dd 100644 +--- a/include/net/tcp.h ++++ b/include/net/tcp.h +@@ -1203,7 +1203,12 @@ enum tcp_ca_ack_event_flags { + #define TCP_CONG_NON_RESTRICTED BIT(0) + /* Requires ECN/ECT set on all packets */ + #define TCP_CONG_NEEDS_ECN BIT(1) +-#define TCP_CONG_MASK (TCP_CONG_NON_RESTRICTED | TCP_CONG_NEEDS_ECN) ++/* Require successfully negotiated AccECN capability */ ++#define TCP_CONG_NEEDS_ACCECN BIT(2) ++/* Use ECT(1) instead of ECT(0) while the CA is uninitialized */ ++#define TCP_CONG_ECT_1_NEGOTIATION BIT(3) ++#define TCP_CONG_MASK (TCP_CONG_NON_RESTRICTED | TCP_CONG_NEEDS_ECN | \ ++ TCP_CONG_NEEDS_ACCECN | TCP_CONG_ECT_1_NEGOTIATION) + + union tcp_cc_info; + +@@ -1335,6 +1340,20 @@ static inline bool tcp_ca_needs_ecn(const struct sock *sk) + return icsk->icsk_ca_ops->flags & TCP_CONG_NEEDS_ECN; + } + ++static inline bool tcp_ca_needs_accecn(const struct sock *sk) ++{ ++ const struct inet_connection_sock *icsk = inet_csk(sk); ++ ++ return icsk->icsk_ca_ops->flags & TCP_CONG_NEEDS_ACCECN; ++} ++ ++static inline bool tcp_ca_ect_1_negotiation(const struct sock *sk) ++{ ++ const struct inet_connection_sock *icsk = inet_csk(sk); ++ ++ return icsk->icsk_ca_ops->flags & TCP_CONG_ECT_1_NEGOTIATION; ++} ++ + static inline void tcp_ca_event(struct sock *sk, const enum tcp_ca_event event) + { + const struct inet_connection_sock *icsk = inet_csk(sk); +diff --git a/include/net/tcp_ecn.h b/include/net/tcp_ecn.h +index f13e5cd2b1ac3..fdde1c342b35c 100644 +--- a/include/net/tcp_ecn.h ++++ b/include/net/tcp_ecn.h +@@ -31,6 +31,12 @@ enum tcp_accecn_option { + TCP_ACCECN_OPTION_FULL = 2, + }; + ++/* Apply either ECT(0) or ECT(1) based on TCP_CONG_ECT_1_NEGOTIATION flag */ ++static inline void INET_ECN_xmit_ect_1_negotiation(struct sock *sk) ++{ ++ __INET_ECN_xmit(sk, tcp_ca_ect_1_negotiation(sk)); ++} ++ + static inline void tcp_ecn_queue_cwr(struct tcp_sock *tp) + { + /* Do not set CWR if in AccECN mode! */ +@@ -561,7 +567,7 @@ static inline void tcp_ecn_send_synack(struct sock *sk, struct sk_buff *skb) + TCP_SKB_CB(skb)->tcp_flags &= ~TCPHDR_ECE; + else if (tcp_ca_needs_ecn(sk) || + tcp_bpf_ca_needs_ecn(sk)) +- INET_ECN_xmit(sk); ++ INET_ECN_xmit_ect_1_negotiation(sk); + + if (tp->ecn_flags & TCP_ECN_MODE_ACCECN) { + TCP_SKB_CB(skb)->tcp_flags &= ~TCPHDR_ACE; +@@ -579,7 +585,8 @@ static inline void tcp_ecn_send_syn(struct sock *sk, struct sk_buff *skb) + bool use_ecn, use_accecn; + u8 tcp_ecn = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_ecn); + +- use_accecn = tcp_ecn == TCP_ECN_IN_ACCECN_OUT_ACCECN; ++ use_accecn = tcp_ecn == TCP_ECN_IN_ACCECN_OUT_ACCECN || ++ tcp_ca_needs_accecn(sk); + use_ecn = tcp_ecn == TCP_ECN_IN_ECN_OUT_ECN || + tcp_ecn == TCP_ECN_IN_ACCECN_OUT_ECN || + tcp_ca_needs_ecn(sk) || bpf_needs_ecn || use_accecn; +@@ -595,7 +602,7 @@ static inline void tcp_ecn_send_syn(struct sock *sk, struct sk_buff *skb) + + if (use_ecn) { + if (tcp_ca_needs_ecn(sk) || bpf_needs_ecn) +- INET_ECN_xmit(sk); ++ INET_ECN_xmit_ect_1_negotiation(sk); + + TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_ECE | TCPHDR_CWR; + if (use_accecn) { +diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c +index df758adbb445f..e9f6c77e06316 100644 +--- a/net/ipv4/tcp_cong.c ++++ b/net/ipv4/tcp_cong.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + #include + + static DEFINE_SPINLOCK(tcp_cong_list_lock); +@@ -227,7 +228,7 @@ void tcp_assign_congestion_control(struct sock *sk) + + memset(icsk->icsk_ca_priv, 0, sizeof(icsk->icsk_ca_priv)); + if (ca->flags & TCP_CONG_NEEDS_ECN) +- INET_ECN_xmit(sk); ++ INET_ECN_xmit_ect_1_negotiation(sk); + else + INET_ECN_dontxmit(sk); + } +@@ -257,7 +258,7 @@ static void tcp_reinit_congestion_control(struct sock *sk, + memset(icsk->icsk_ca_priv, 0, sizeof(icsk->icsk_ca_priv)); + + if (ca->flags & TCP_CONG_NEEDS_ECN) +- INET_ECN_xmit(sk); ++ INET_ECN_xmit_ect_1_negotiation(sk); + else + INET_ECN_dontxmit(sk); + +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index 198f8a0d37be0..736f8f55ab5a6 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -7248,7 +7248,8 @@ static void tcp_ecn_create_request(struct request_sock *req, + u32 ecn_ok_dst; + + if (tcp_accecn_syn_requested(th) && +- READ_ONCE(net->ipv4.sysctl_tcp_ecn) >= 3) { ++ (READ_ONCE(net->ipv4.sysctl_tcp_ecn) >= 3 || ++ tcp_ca_needs_accecn(listen_sk))) { + inet_rsk(req)->ecn_ok = 1; + tcp_rsk(req)->accecn_ok = 1; + tcp_rsk(req)->syn_ect_rcv = TCP_SKB_CB(skb)->ip_dsfield & +-- +2.51.0 + diff --git a/queue-6.19/tcp-tcp_tx_timestamp-must-look-at-the-rtx-queue.patch b/queue-6.19/tcp-tcp_tx_timestamp-must-look-at-the-rtx-queue.patch new file mode 100644 index 0000000000..e1354cbe35 --- /dev/null +++ b/queue-6.19/tcp-tcp_tx_timestamp-must-look-at-the-rtx-queue.patch @@ -0,0 +1,44 @@ +From 1c7682a09cf795b780df69e3c42039593b6ad636 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 12:38:27 +0000 +Subject: tcp: tcp_tx_timestamp() must look at the rtx queue + +From: Eric Dumazet + +[ Upstream commit 838eb9687691d29915797a885b861fd09353386e ] + +tcp_tx_timestamp() is only called at the end of tcp_sendmsg_locked() +before the final tcp_push(). + +By the time it is called, it is possible all the copied data +has been sent already (transmit queue is empty). + +If this is the case, use the last skb in the rtx queue. + +Fixes: 75c119afe14f ("tcp: implement rb-tree based retransmit queue") +Signed-off-by: Eric Dumazet +Reviewed-by: Jason Xing +Link: https://patch.msgid.link/20260127123828.4098577-2-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index d5319ebe24525..81666571ecfb5 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -501,6 +501,9 @@ static void tcp_tx_timestamp(struct sock *sk, struct sockcm_cookie *sockc) + struct sk_buff *skb = tcp_write_queue_tail(sk); + u32 tsflags = sockc->tsflags; + ++ if (unlikely(!skb)) ++ skb = skb_rb_last(&sk->tcp_rtx_queue); ++ + if (tsflags && skb) { + struct skb_shared_info *shinfo = skb_shinfo(skb); + struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); +-- +2.51.0 + diff --git a/queue-6.19/thermal-intel-x86_pkg_temp_thermal-handle-invalid-te.patch b/queue-6.19/thermal-intel-x86_pkg_temp_thermal-handle-invalid-te.patch new file mode 100644 index 0000000000..29ad88266f --- /dev/null +++ b/queue-6.19/thermal-intel-x86_pkg_temp_thermal-handle-invalid-te.patch @@ -0,0 +1,43 @@ +From f396c9ac54e79c307e45423031aaad1fdb836b73 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 16:23:41 +0100 +Subject: thermal: intel: x86_pkg_temp_thermal: Handle invalid temperature + +From: Rafael J. Wysocki + +[ Upstream commit 9635c586a559ba0e45b2bfbff79c937ddbaf1a62 ] + +After commit be0a3600aa1e ("thermal: sysfs: Rework the handling of trip +point updates"), THERMAL_TEMP_INVALID can be passed to sys_set_trip_temp() +and it is treated as a regular temperature value there, so the sysfs +write fails even though it is expected to succeed and disable the given +trip point. + +Address this by making sys_set_trip_temp() clear its temp variable when +it is equal to THERMAL_TEMP_INVALID. + +Fixes: be0a3600aa1e ("thermal: sysfs: Rework the handling of trip point updates") +Signed-off-by: Rafael J. Wysocki +Link: https://patch.msgid.link/2815400.mvXUDI8C0e@rafael.j.wysocki +Signed-off-by: Sasha Levin +--- + drivers/thermal/intel/x86_pkg_temp_thermal.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/thermal/intel/x86_pkg_temp_thermal.c b/drivers/thermal/intel/x86_pkg_temp_thermal.c +index 3fc679b6f11b1..aab5f9fca9c33 100644 +--- a/drivers/thermal/intel/x86_pkg_temp_thermal.c ++++ b/drivers/thermal/intel/x86_pkg_temp_thermal.c +@@ -128,6 +128,9 @@ sys_set_trip_temp(struct thermal_zone_device *tzd, + u32 l, h, mask, shift, intr; + int tj_max, val, ret; + ++ if (temp == THERMAL_TEMP_INVALID) ++ temp = 0; ++ + tj_max = intel_tcc_get_tjmax(zonedev->cpu); + if (tj_max < 0) + return tj_max; +-- +2.51.0 + diff --git a/queue-6.19/thermal-of-fix-reference-leak-in-thermal_of_cm_looku.patch b/queue-6.19/thermal-of-fix-reference-leak-in-thermal_of_cm_looku.patch new file mode 100644 index 0000000000..571e29e8f5 --- /dev/null +++ b/queue-6.19/thermal-of-fix-reference-leak-in-thermal_of_cm_looku.patch @@ -0,0 +1,46 @@ +From 5086152b71e0f71373837b9fdbdb3d886973577e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 24 Jan 2026 03:06:40 +0800 +Subject: thermal/of: Fix reference leak in thermal_of_cm_lookup() + +From: Felix Gu + +[ Upstream commit a1fe789a96fe47733c133134fd264cb7ca832395 ] + +In thermal_of_cm_lookup(), tr_np is obtained via of_parse_phandle(), but +never released. + +Use the __free(device_node) cleanup attribute to automatically release +the node and fix the leak. + +Fixes: 423de5b5bc5b ("thermal/of: Fix cdev lookup in thermal_of_should_bind()") +Signed-off-by: Felix Gu +Reviewed-by: Lukasz Luba +[ rjw: Changelog edits ] +Link: https://patch.msgid.link/20260124-thermal_of-v1-1-54d3416948cf@gmail.com +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/thermal/thermal_of.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/thermal/thermal_of.c b/drivers/thermal/thermal_of.c +index 1a51a4d240ff6..b6d0c92f5522b 100644 +--- a/drivers/thermal/thermal_of.c ++++ b/drivers/thermal/thermal_of.c +@@ -280,10 +280,10 @@ static bool thermal_of_cm_lookup(struct device_node *cm_np, + struct cooling_spec *c) + { + for_each_child_of_node_scoped(cm_np, child) { +- struct device_node *tr_np; + int count, i; + +- tr_np = of_parse_phandle(child, "trip", 0); ++ struct device_node *tr_np __free(device_node) = ++ of_parse_phandle(child, "trip", 0); + if (tr_np != trip->priv) + continue; + +-- +2.51.0 + diff --git a/queue-6.19/time-sched_clock-use-access_private-to-evaluate-hrti.patch b/queue-6.19/time-sched_clock-use-access_private-to-evaluate-hrti.patch new file mode 100644 index 0000000000..7b968e453e --- /dev/null +++ b/queue-6.19/time-sched_clock-use-access_private-to-evaluate-hrti.patch @@ -0,0 +1,38 @@ +From 7793bdce7ad21d0aa2cc501d8fe1f33ebcac12a8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Jan 2026 17:47:37 +0100 +Subject: time/sched_clock: Use ACCESS_PRIVATE() to evaluate hrtimer::function + +From: Thomas Gleixner + +[ Upstream commit 3db5306b0bd562ac0fe7eddad26c60ebb6f5fdd4 ] + +This dereference of sched_clock_timer::function was missed when the +hrtimer callback function pointer was marked private. + +Fixes: 04257da0c99c ("hrtimers: Make callback function pointer private") +Reported-by: kernel test robot +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/875x95jw7q.ffs@tglx +Closes: https://lore.kernel.org/oe-kbuild-all/202601131713.KsxhXQ0M-lkp@intel.com/ +Signed-off-by: Sasha Levin +--- + kernel/time/sched_clock.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/time/sched_clock.c b/kernel/time/sched_clock.c +index f39111830ca36..f3aaef695b8cd 100644 +--- a/kernel/time/sched_clock.c ++++ b/kernel/time/sched_clock.c +@@ -215,7 +215,7 @@ void sched_clock_register(u64 (*read)(void), int bits, unsigned long rate) + + update_clock_read_data(&rd); + +- if (sched_clock_timer.function != NULL) { ++ if (ACCESS_PRIVATE(&sched_clock_timer, function) != NULL) { + /* update timeout for clock wrap */ + hrtimer_start(&sched_clock_timer, cd.wrap_kt, + HRTIMER_MODE_REL_HARD); +-- +2.51.0 + diff --git a/queue-6.19/tools-nolibc-always-use-64-bit-mode-for-s390-header-.patch b/queue-6.19/tools-nolibc-always-use-64-bit-mode-for-s390-header-.patch new file mode 100644 index 0000000000..93c9fa4610 --- /dev/null +++ b/queue-6.19/tools-nolibc-always-use-64-bit-mode-for-s390-header-.patch @@ -0,0 +1,48 @@ +From 21c103208ddbcfcee16507cbee9a69621e46ddda Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Dec 2025 20:08:00 +0100 +Subject: tools/nolibc: always use 64-bit mode for s390 header checks +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh + +[ Upstream commit cc6809f6728456c03db6750fcc94ed8b581a2cf8 ] + +32-bit s390 support was recently removed from nolibc. +If the compiler defaults to 32-bit during the header checks, they fail. + +Make sure to always use 64-bit mode for s390 heafer checks. + +Fixes: 169ebcbb9082 ("tools: Remove s390 compat support") +Acked-by: Willy Tarreau +Acked-by: Heiko Carstens +Link: https://patch.msgid.link/20251203-nolibc-headers-check-s390-v1-1-5d35e52a83ba@weissschuh.net +Signed-off-by: Thomas Weißschuh +Signed-off-by: Sasha Levin +--- + tools/include/nolibc/Makefile | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/tools/include/nolibc/Makefile b/tools/include/nolibc/Makefile +index 8118e22844f19..afb6a20ac1336 100644 +--- a/tools/include/nolibc/Makefile ++++ b/tools/include/nolibc/Makefile +@@ -103,9 +103,12 @@ headers_standalone: headers + $(Q)$(MAKE) -C $(srctree) headers + $(Q)$(MAKE) -C $(srctree) headers_install INSTALL_HDR_PATH=$(OUTPUT)sysroot + ++CFLAGS_s390 := -m64 ++CFLAGS := $(CFLAGS_$(ARCH)) ++ + headers_check: headers_standalone + $(Q)for header in $(filter-out crt.h std.h,$(all_files)); do \ +- $(CC) $(CLANG_CROSS_FLAGS) -Wall -Werror -nostdinc -fsyntax-only -x c /dev/null \ ++ $(CC) $(CFLAGS) $(CLANG_CROSS_FLAGS) -Wall -Werror -nostdinc -fsyntax-only -x c /dev/null \ + -I$(or $(objtree),$(srctree))/usr/include -include $$header -include $$header || exit 1; \ + done + +-- +2.51.0 + diff --git a/queue-6.19/tools-power-x86-intel-speed-select-fix-file-descript.patch b/queue-6.19/tools-power-x86-intel-speed-select-fix-file-descript.patch new file mode 100644 index 0000000000..2bcddb1b1a --- /dev/null +++ b/queue-6.19/tools-power-x86-intel-speed-select-fix-file-descript.patch @@ -0,0 +1,50 @@ +From 41493b969f3a91cd26b4e80266c83f846b23641b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 15:33:33 +0530 +Subject: tools/power/x86/intel-speed-select: Fix file descriptor leak in + isolate_cpus() + +From: Malaya Kumar Rout + +[ Upstream commit 56c17ee151c6e1a73d77e15b82a8e2130cd8dd16 ] + +The file descriptor opened in isolate_cpus() when (!level) is true was +not being closed before returning, causing a file descriptor leak in +both the error path and the success path. + +When write() fails at line 950, the function returns at line 953 without +closing the file descriptor. Similarly, on success, the function returns +at line 956 without closing the file descriptor. + +Add close(fd) calls before both return statements to fix the resource +leak. This follows the same pattern used elsewhere in the same function +where file descriptors are properly closed before returning (see lines +1005 and 1027). + +Fixes: 997074df658e ("tools/power/x86/intel-speed-select: Use cgroup v2 isolation") +Signed-off-by: Malaya Kumar Rout +Signed-off-by: Srinivas Pandruvada +Signed-off-by: Sasha Levin +--- + tools/power/x86/intel-speed-select/isst-config.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/tools/power/x86/intel-speed-select/isst-config.c b/tools/power/x86/intel-speed-select/isst-config.c +index 558138eea75e9..d00d15490a98c 100644 +--- a/tools/power/x86/intel-speed-select/isst-config.c ++++ b/tools/power/x86/intel-speed-select/isst-config.c +@@ -950,9 +950,11 @@ int isolate_cpus(struct isst_id *id, int mask_size, cpu_set_t *cpu_mask, int lev + ret = write(fd, "member", strlen("member")); + if (ret == -1) { + printf("Can't update to member\n"); ++ close(fd); + return ret; + } + ++ close(fd); + return 0; + } + +-- +2.51.0 + diff --git a/queue-6.19/tpm-st33zp24-fix-missing-cleanup-on-get_burstcount-e.patch b/queue-6.19/tpm-st33zp24-fix-missing-cleanup-on-get_burstcount-e.patch new file mode 100644 index 0000000000..f52df18c2e --- /dev/null +++ b/queue-6.19/tpm-st33zp24-fix-missing-cleanup-on-get_burstcount-e.patch @@ -0,0 +1,43 @@ +From b711fc4ae1da3e27b237b526632bfbb03b55a33a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Dec 2025 15:09:27 +0300 +Subject: tpm: st33zp24: Fix missing cleanup on get_burstcount() error + +From: Alper Ak + +[ Upstream commit 3e91b44c93ad2871f89fc2a98c5e4fe6ca5db3d9 ] + +get_burstcount() can return -EBUSY on timeout. When this happens, +st33zp24_send() returns directly without releasing the locality +acquired earlier. + +Use goto out_err to ensure proper cleanup when get_burstcount() fails. + +Fixes: bf38b8710892 ("tpm/tpm_i2c_stm_st33: Split tpm_i2c_tpm_st33 in 2 layers (core + phy)") +Signed-off-by: Alper Ak +Signed-off-by: Jarkko Sakkinen +Signed-off-by: Sasha Levin +--- + drivers/char/tpm/st33zp24/st33zp24.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/char/tpm/st33zp24/st33zp24.c b/drivers/char/tpm/st33zp24/st33zp24.c +index 2ed7815e4899b..e2b7451ea7ccd 100644 +--- a/drivers/char/tpm/st33zp24/st33zp24.c ++++ b/drivers/char/tpm/st33zp24/st33zp24.c +@@ -328,8 +328,10 @@ static int st33zp24_send(struct tpm_chip *chip, unsigned char *buf, + + for (i = 0; i < len - 1;) { + burstcnt = get_burstcount(chip); +- if (burstcnt < 0) +- return burstcnt; ++ if (burstcnt < 0) { ++ ret = burstcnt; ++ goto out_err; ++ } + size = min_t(int, len - i - 1, burstcnt); + ret = tpm_dev->ops->send(tpm_dev->phy_id, TPM_DATA_FIFO, + buf + i, size); +-- +2.51.0 + diff --git a/queue-6.19/tpm-tpm_i2c_infineon-fix-locality-leak-on-get_burstc.patch b/queue-6.19/tpm-tpm_i2c_infineon-fix-locality-leak-on-get_burstc.patch new file mode 100644 index 0000000000..a81e573ccd --- /dev/null +++ b/queue-6.19/tpm-tpm_i2c_infineon-fix-locality-leak-on-get_burstc.patch @@ -0,0 +1,44 @@ +From a09f750e6114e541daddf92844d180ecbcdcdc0c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Dec 2025 13:23:38 +0300 +Subject: tpm: tpm_i2c_infineon: Fix locality leak on get_burstcount() failure + +From: Alper Ak + +[ Upstream commit bbd6e97c836cbeb9606d7b7e5dcf8a1d89525713 ] + +get_burstcount() can return -EBUSY on timeout. When this happens, the +function returns directly without releasing the locality that was +acquired at the beginning of tpm_tis_i2c_send(). + +Use goto out_err to ensure proper cleanup when get_burstcount() fails. + +Fixes: aad628c1d91a ("char/tpm: Add new driver for Infineon I2C TIS TPM") +Signed-off-by: Alper Ak +Reviewed-by: Jarkko Sakkinen +Signed-off-by: Jarkko Sakkinen +Signed-off-by: Sasha Levin +--- + drivers/char/tpm/tpm_i2c_infineon.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c +index bdf1f329a6794..8b7d32de0b2ef 100644 +--- a/drivers/char/tpm/tpm_i2c_infineon.c ++++ b/drivers/char/tpm/tpm_i2c_infineon.c +@@ -544,8 +544,10 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t bufsiz, + burstcnt = get_burstcount(chip); + + /* burstcnt < 0 = TPM is busy */ +- if (burstcnt < 0) +- return burstcnt; ++ if (burstcnt < 0) { ++ rc = burstcnt; ++ goto out_err; ++ } + + if (burstcnt > (len - 1 - count)) + burstcnt = len - 1 - count; +-- +2.51.0 + diff --git a/queue-6.19/tracing-properly-process-error-handling-in-event_his.patch b/queue-6.19/tracing-properly-process-error-handling-in-event_his.patch new file mode 100644 index 0000000000..be75b014c9 --- /dev/null +++ b/queue-6.19/tracing-properly-process-error-handling-in-event_his.patch @@ -0,0 +1,51 @@ +From 64e6c25a7162a2bd297b01f343408f4c0228cfef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 11 Dec 2025 14:00:58 +0400 +Subject: tracing: Properly process error handling in + event_hist_trigger_parse() + +From: Miaoqian Lin + +[ Upstream commit 0550069cc25f513ce1f109c88f7c1f01d63297db ] + +Memory allocated with trigger_data_alloc() requires trigger_data_free() +for proper cleanup. + +Replace kfree() with trigger_data_free() to fix this. + +Found via static analysis and code review. + +This isn't a real bug due to the current code basically being an open +coded version of trigger_data_free() without the synchronization. The +synchronization isn't needed as this is the error path of creation and +there's nothing to synchronize against yet. Replace the kfree() to be +consistent with the allocation. + +Cc: Masami Hiramatsu +Cc: Mathieu Desnoyers +Cc: Tom Zanussi +Link: https://patch.msgid.link/20251211100058.2381268-1-linmq006@gmail.com +Fixes: e1f187d09e11 ("tracing: Have existing event_command.parse() implementations use helpers") +Signed-off-by: Miaoqian Lin +Signed-off-by: Steven Rostedt (Google) +Signed-off-by: Sasha Levin +--- + kernel/trace/trace_events_hist.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c +index c97bb2fda5c02..7e50df8b800b1 100644 +--- a/kernel/trace/trace_events_hist.c ++++ b/kernel/trace/trace_events_hist.c +@@ -6911,7 +6911,7 @@ static int event_hist_trigger_parse(struct event_command *cmd_ops, + + remove_hist_vars(hist_data); + +- kfree(trigger_data); ++ trigger_data_free(trigger_data); + + destroy_hist_data(hist_data); + goto out; +-- +2.51.0 + diff --git a/queue-6.19/tracing-remove-duplicate-enable_event_str-and-disabl.patch b/queue-6.19/tracing-remove-duplicate-enable_event_str-and-disabl.patch new file mode 100644 index 0000000000..a72f5d3b10 --- /dev/null +++ b/queue-6.19/tracing-remove-duplicate-enable_event_str-and-disabl.patch @@ -0,0 +1,44 @@ +From 7ad23d314febf24c92c55f7157828ca9d7da6fb1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 13:00:37 -0500 +Subject: tracing: Remove duplicate ENABLE_EVENT_STR and DISABLE_EVENT_STR + macros + +From: Steven Rostedt + +[ Upstream commit 9df0e49c5b9b8d051529be9994e4f92f2d20be6f ] + +The macros ENABLE_EVENT_STR and DISABLE_EVENT_STR were added to trace.h so +that more than one file can have access to them, but was never removed +from their original location. Remove the duplicates. + +Cc: Masami Hiramatsu +Cc: Mathieu Desnoyers +Cc: Tom Zanussi +Link: https://patch.msgid.link/20260126130037.4ba201f9@gandalf.local.home +Fixes: d0bad49bb0a09 ("tracing: Add enable_hist/disable_hist triggers") +Signed-off-by: Steven Rostedt (Google) +Signed-off-by: Sasha Levin +--- + kernel/trace/trace_events.c | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c +index 137b4d9bb116d..2c6d3e33b9fb4 100644 +--- a/kernel/trace/trace_events.c ++++ b/kernel/trace/trace_events.c +@@ -3963,11 +3963,6 @@ void trace_put_event_file(struct trace_event_file *file) + EXPORT_SYMBOL_GPL(trace_put_event_file); + + #ifdef CONFIG_DYNAMIC_FTRACE +- +-/* Avoid typos */ +-#define ENABLE_EVENT_STR "enable_event" +-#define DISABLE_EVENT_STR "disable_event" +- + struct event_probe_data { + struct trace_event_file *file; + unsigned long count; +-- +2.51.0 + diff --git a/queue-6.19/ublk-restore-auto-buf-unregister-refcount-optimizati.patch b/queue-6.19/ublk-restore-auto-buf-unregister-refcount-optimizati.patch new file mode 100644 index 0000000000..89bfc2ab5a --- /dev/null +++ b/queue-6.19/ublk-restore-auto-buf-unregister-refcount-optimizati.patch @@ -0,0 +1,52 @@ +From 517ac9d9d86fd394ab19c16718e628fa2f065b11 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 13:56:34 -0700 +Subject: ublk: restore auto buf unregister refcount optimization + +From: Caleb Sander Mateos + +[ Upstream commit ad5f2e2908c9b79a86529281a48e94d644d43dc7 ] + +Commit 1ceeedb59749 ("ublk: optimize UBLK_IO_UNREGISTER_IO_BUF on daemon +task") optimized ublk request buffer unregistration to use a non-atomic +reference count decrement when performed on the ublk_io's daemon task. +The optimization applied to auto buffer unregistration, which happens as +part of handling UBLK_IO_COMMIT_AND_FETCH_REQ on the daemon task. +However, commit b749965edda8 ("ublk: remove ublk_commit_and_fetch()") +reordered the ublk_sub_req_ref() for the completed request before the +io_buffer_unregister_bvec() call. As a result, task_registered_buffers +is already 0 when io_buffer_unregister_bvec() calls ublk_io_release() +and the non-atomic refcount optimization doesn't apply. +Move the io_buffer_unregister_bvec() call back to before +ublk_need_complete_req() to restore the reference counting optimization. + +Signed-off-by: Caleb Sander Mateos +Fixes: b749965edda8 ("ublk: remove ublk_commit_and_fetch()") +Reviewed-by: Ming Lei +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/block/ublk_drv.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c +index cd1e84653002d..6000517645e12 100644 +--- a/drivers/block/ublk_drv.c ++++ b/drivers/block/ublk_drv.c +@@ -2462,11 +2462,11 @@ static int ublk_ch_uring_cmd_local(struct io_uring_cmd *cmd, + io->res = result; + req = ublk_fill_io_cmd(io, cmd); + ret = ublk_config_io_buf(ub, io, cmd, addr, &buf_idx); ++ if (buf_idx != UBLK_INVALID_BUF_IDX) ++ io_buffer_unregister_bvec(cmd, buf_idx, issue_flags); + compl = ublk_need_complete_req(ub, io); + + /* can't touch 'ublk_io' any more */ +- if (buf_idx != UBLK_INVALID_BUF_IDX) +- io_buffer_unregister_bvec(cmd, buf_idx, issue_flags); + if (req_op(req) == REQ_OP_ZONE_APPEND) + req->__sector = addr; + if (compl) +-- +2.51.0 + diff --git a/queue-6.19/ublk-use-read_once-to-read-struct-ublksrv_ctrl_cmd.patch b/queue-6.19/ublk-use-read_once-to-read-struct-ublksrv_ctrl_cmd.patch new file mode 100644 index 0000000000..a29525f899 --- /dev/null +++ b/queue-6.19/ublk-use-read_once-to-read-struct-ublksrv_ctrl_cmd.patch @@ -0,0 +1,194 @@ +From 1a2e7eb0b0eca0adedde1efba341bbcd2045a72e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 10:14:13 -0700 +Subject: ublk: use READ_ONCE() to read struct ublksrv_ctrl_cmd + +From: Caleb Sander Mateos + +[ Upstream commit ed9f54cc1e335096733aed03c2a46de3d58922ed ] + +struct ublksrv_ctrl_cmd is part of the io_uring_sqe, which may lie in +userspace-mapped memory. It's racy to access its fields with normal +loads, as userspace may write to them concurrently. Use READ_ONCE() to +copy the ublksrv_ctrl_cmd from the io_uring_sqe to the stack. Use the +local copy in place of the one in the io_uring_sqe. + +Fixes: 87213b0d847c ("ublk: allow non-blocking ctrl cmds in IO_URING_F_NONBLOCK issue") +Signed-off-by: Caleb Sander Mateos +Reviewed-by: Ming Lei +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/block/ublk_drv.c | 56 ++++++++++++++++++++++------------------ + 1 file changed, 31 insertions(+), 25 deletions(-) + +diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c +index 0ce0e537fb850..06e0790150d1d 100644 +--- a/drivers/block/ublk_drv.c ++++ b/drivers/block/ublk_drv.c +@@ -3311,12 +3311,11 @@ static int ublk_ctrl_del_dev(struct ublk_device **p_ub, bool wait) + return 0; + } + +-static inline void ublk_ctrl_cmd_dump(struct io_uring_cmd *cmd) ++static inline void ublk_ctrl_cmd_dump(u32 cmd_op, ++ const struct ublksrv_ctrl_cmd *header) + { +- const struct ublksrv_ctrl_cmd *header = io_uring_sqe_cmd(cmd->sqe); +- + pr_devel("%s: cmd_op %x, dev id %d qid %d data %llx buf %llx len %u\n", +- __func__, cmd->cmd_op, header->dev_id, header->queue_id, ++ __func__, cmd_op, header->dev_id, header->queue_id, + header->data[0], header->addr, header->len); + } + +@@ -3685,9 +3684,8 @@ static int ublk_char_dev_permission(struct ublk_device *ub, + } + + static int ublk_ctrl_uring_cmd_permission(struct ublk_device *ub, +- struct io_uring_cmd *cmd) ++ u32 cmd_op, struct ublksrv_ctrl_cmd *header) + { +- struct ublksrv_ctrl_cmd *header = (struct ublksrv_ctrl_cmd *)io_uring_sqe_cmd(cmd->sqe); + bool unprivileged = ub->dev_info.flags & UBLK_F_UNPRIVILEGED_DEV; + void __user *argp = (void __user *)(unsigned long)header->addr; + char *dev_path = NULL; +@@ -3703,7 +3701,7 @@ static int ublk_ctrl_uring_cmd_permission(struct ublk_device *ub, + * know if the specified device is created as unprivileged + * mode. + */ +- if (_IOC_NR(cmd->cmd_op) != UBLK_CMD_GET_DEV_INFO2) ++ if (_IOC_NR(cmd_op) != UBLK_CMD_GET_DEV_INFO2) + return 0; + } + +@@ -3724,7 +3722,7 @@ static int ublk_ctrl_uring_cmd_permission(struct ublk_device *ub, + return PTR_ERR(dev_path); + + ret = -EINVAL; +- switch (_IOC_NR(cmd->cmd_op)) { ++ switch (_IOC_NR(cmd_op)) { + case UBLK_CMD_GET_DEV_INFO: + case UBLK_CMD_GET_DEV_INFO2: + case UBLK_CMD_GET_QUEUE_AFFINITY: +@@ -3753,7 +3751,7 @@ static int ublk_ctrl_uring_cmd_permission(struct ublk_device *ub, + header->addr += header->dev_path_len; + } + pr_devel("%s: dev id %d cmd_op %x uid %d gid %d path %s ret %d\n", +- __func__, ub->ub_number, cmd->cmd_op, ++ __func__, ub->ub_number, cmd_op, + ub->dev_info.owner_uid, ub->dev_info.owner_gid, + dev_path, ret); + exit: +@@ -3777,7 +3775,9 @@ static bool ublk_ctrl_uring_cmd_may_sleep(u32 cmd_op) + static int ublk_ctrl_uring_cmd(struct io_uring_cmd *cmd, + unsigned int issue_flags) + { +- const struct ublksrv_ctrl_cmd *header = io_uring_sqe_cmd(cmd->sqe); ++ /* May point to userspace-mapped memory */ ++ const struct ublksrv_ctrl_cmd *ub_src = io_uring_sqe_cmd(cmd->sqe); ++ struct ublksrv_ctrl_cmd header; + struct ublk_device *ub = NULL; + u32 cmd_op = cmd->cmd_op; + int ret = -EINVAL; +@@ -3789,41 +3789,47 @@ static int ublk_ctrl_uring_cmd(struct io_uring_cmd *cmd, + if (!(issue_flags & IO_URING_F_SQE128)) + return -EINVAL; + +- ublk_ctrl_cmd_dump(cmd); ++ header.dev_id = READ_ONCE(ub_src->dev_id); ++ header.queue_id = READ_ONCE(ub_src->queue_id); ++ header.len = READ_ONCE(ub_src->len); ++ header.addr = READ_ONCE(ub_src->addr); ++ header.data[0] = READ_ONCE(ub_src->data[0]); ++ header.dev_path_len = READ_ONCE(ub_src->dev_path_len); ++ ublk_ctrl_cmd_dump(cmd_op, &header); + + ret = ublk_check_cmd_op(cmd_op); + if (ret) + goto out; + + if (cmd_op == UBLK_U_CMD_GET_FEATURES) { +- ret = ublk_ctrl_get_features(header); ++ ret = ublk_ctrl_get_features(&header); + goto out; + } + + if (_IOC_NR(cmd_op) != UBLK_CMD_ADD_DEV) { + ret = -ENODEV; +- ub = ublk_get_device_from_id(header->dev_id); ++ ub = ublk_get_device_from_id(header.dev_id); + if (!ub) + goto out; + +- ret = ublk_ctrl_uring_cmd_permission(ub, cmd); ++ ret = ublk_ctrl_uring_cmd_permission(ub, cmd_op, &header); + if (ret) + goto put_dev; + } + + switch (_IOC_NR(cmd_op)) { + case UBLK_CMD_START_DEV: +- ret = ublk_ctrl_start_dev(ub, header); ++ ret = ublk_ctrl_start_dev(ub, &header); + break; + case UBLK_CMD_STOP_DEV: + ret = ublk_ctrl_stop_dev(ub); + break; + case UBLK_CMD_GET_DEV_INFO: + case UBLK_CMD_GET_DEV_INFO2: +- ret = ublk_ctrl_get_dev_info(ub, header); ++ ret = ublk_ctrl_get_dev_info(ub, &header); + break; + case UBLK_CMD_ADD_DEV: +- ret = ublk_ctrl_add_dev(header); ++ ret = ublk_ctrl_add_dev(&header); + break; + case UBLK_CMD_DEL_DEV: + ret = ublk_ctrl_del_dev(&ub, true); +@@ -3832,26 +3838,26 @@ static int ublk_ctrl_uring_cmd(struct io_uring_cmd *cmd, + ret = ublk_ctrl_del_dev(&ub, false); + break; + case UBLK_CMD_GET_QUEUE_AFFINITY: +- ret = ublk_ctrl_get_queue_affinity(ub, header); ++ ret = ublk_ctrl_get_queue_affinity(ub, &header); + break; + case UBLK_CMD_GET_PARAMS: +- ret = ublk_ctrl_get_params(ub, header); ++ ret = ublk_ctrl_get_params(ub, &header); + break; + case UBLK_CMD_SET_PARAMS: +- ret = ublk_ctrl_set_params(ub, header); ++ ret = ublk_ctrl_set_params(ub, &header); + break; + case UBLK_CMD_START_USER_RECOVERY: +- ret = ublk_ctrl_start_recovery(ub, header); ++ ret = ublk_ctrl_start_recovery(ub, &header); + break; + case UBLK_CMD_END_USER_RECOVERY: +- ret = ublk_ctrl_end_recovery(ub, header); ++ ret = ublk_ctrl_end_recovery(ub, &header); + break; + case UBLK_CMD_UPDATE_SIZE: +- ublk_ctrl_set_size(ub, header); ++ ublk_ctrl_set_size(ub, &header); + ret = 0; + break; + case UBLK_CMD_QUIESCE_DEV: +- ret = ublk_ctrl_quiesce_dev(ub, header); ++ ret = ublk_ctrl_quiesce_dev(ub, &header); + break; + default: + ret = -EOPNOTSUPP; +@@ -3863,7 +3869,7 @@ static int ublk_ctrl_uring_cmd(struct io_uring_cmd *cmd, + ublk_put_device(ub); + out: + pr_devel("%s: cmd done ret %d cmd_op %x, dev id %d qid %d\n", +- __func__, ret, cmd->cmd_op, header->dev_id, header->queue_id); ++ __func__, ret, cmd_op, header.dev_id, header.queue_id); + return ret; + } + +-- +2.51.0 + diff --git a/queue-6.19/ublk-validate-sqe128-flag-before-accessing-the-cmd.patch b/queue-6.19/ublk-validate-sqe128-flag-before-accessing-the-cmd.patch new file mode 100644 index 0000000000..e451534e0f --- /dev/null +++ b/queue-6.19/ublk-validate-sqe128-flag-before-accessing-the-cmd.patch @@ -0,0 +1,47 @@ +From 334158a0b9235fb7841a72cbbb51fb5a208cb2d5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 10:14:12 -0700 +Subject: ublk: Validate SQE128 flag before accessing the cmd + +From: Govindarajulu Varadarajan + +[ Upstream commit da7e4b75e50c087d2031a92f6646eb90f7045a67 ] + +ublk_ctrl_cmd_dump() accesses (header *)sqe->cmd before +IO_URING_F_SQE128 flag check. This could cause out of boundary memory +access. + +Move the SQE128 flag check earlier in ublk_ctrl_uring_cmd() to return +-EINVAL immediately if the flag is not set. + +Fixes: 71f28f3136af ("ublk_drv: add io_uring based userspace block driver") +Signed-off-by: Govindarajulu Varadarajan +Reviewed-by: Caleb Sander Mateos +Reviewed-by: Ming Lei +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/block/ublk_drv.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c +index 6000517645e12..0ce0e537fb850 100644 +--- a/drivers/block/ublk_drv.c ++++ b/drivers/block/ublk_drv.c +@@ -3786,10 +3786,10 @@ static int ublk_ctrl_uring_cmd(struct io_uring_cmd *cmd, + issue_flags & IO_URING_F_NONBLOCK) + return -EAGAIN; + +- ublk_ctrl_cmd_dump(cmd); +- + if (!(issue_flags & IO_URING_F_SQE128)) +- goto out; ++ return -EINVAL; ++ ++ ublk_ctrl_cmd_dump(cmd); + + ret = ublk_check_cmd_op(cmd_op); + if (ret) +-- +2.51.0 + diff --git a/queue-6.19/ucount-check-for-cap_sys_resource-using-ns_capable_n.patch b/queue-6.19/ucount-check-for-cap_sys_resource-using-ns_capable_n.patch new file mode 100644 index 0000000000..e7cf5345de --- /dev/null +++ b/queue-6.19/ucount-check-for-cap_sys_resource-using-ns_capable_n.patch @@ -0,0 +1,51 @@ +From 685823a46f715b75e83b7f46a4bf24e74b42e49c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 15:07:45 +0100 +Subject: ucount: check for CAP_SYS_RESOURCE using ns_capable_noaudit() + +From: Ondrej Mosnacek + +[ Upstream commit 0895a000e4fff9e950a7894210db45973e485c35 ] + +The user.* sysctls implement the ctl_table_root::permissions hook and they +override the file access mode based on the CAP_SYS_RESOURCE capability (at +most rwx if capable, at most r-- if not). The capability is being checked +unconditionally, so if an LSM denies the capability, an audit record may +be logged even when access is in fact granted. + +Given the logic in the set_permissions() function in kernel/ucount.c and +the unfortunate way the permission checking is implemented, it doesn't +seem viable to avoid false positive denials by deferring the capability +check. Thus, do the same as in net_ctl_permissions() (net/sysctl_net.c) - +switch from ns_capable() to ns_capable_noaudit(), so that the check never +logs an audit record. + +Link: https://lkml.kernel.org/r/20260122140745.239428-1-omosnace@redhat.com +Fixes: dbec28460a89 ("userns: Add per user namespace sysctls.") +Signed-off-by: Ondrej Mosnacek +Reviewed-by: Paul Moore +Acked-by: Serge Hallyn +Cc: Eric Biederman +Cc: Alexey Gladkov +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + kernel/ucount.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/ucount.c b/kernel/ucount.c +index 586af49fc03e4..fc4a8f2d30965 100644 +--- a/kernel/ucount.c ++++ b/kernel/ucount.c +@@ -47,7 +47,7 @@ static int set_permissions(struct ctl_table_header *head, + int mode; + + /* Allow users with CAP_SYS_RESOURCE unrestrained access */ +- if (ns_capable(user_ns, CAP_SYS_RESOURCE)) ++ if (ns_capable_noaudit(user_ns, CAP_SYS_RESOURCE)) + mode = (table->mode & S_IRWXU) >> 6; + else + /* Allow all others at most read-only access */ +-- +2.51.0 + diff --git a/queue-6.19/usb-bdc-fix-sleep-during-atomic.patch b/queue-6.19/usb-bdc-fix-sleep-during-atomic.patch new file mode 100644 index 0000000000..fba7f383e3 --- /dev/null +++ b/queue-6.19/usb-bdc-fix-sleep-during-atomic.patch @@ -0,0 +1,41 @@ +From 1435fac026741acf458bc5134a8854073dee0aeb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 12:07:54 -0800 +Subject: usb: bdc: fix sleep during atomic + +From: Justin Chen + +[ Upstream commit f1195ca3b4bbd001d3f1264dce91f83dec7777f5 ] + +bdc_run() can be ran during atomic context leading to a sleep during +atomic warning. Fix this by replacing read_poll_timeout() with +read_poll_timeout_atomic(). + +Fixes: 75ae051efc9b ("usb: gadget: bdc: use readl_poll_timeout() to simplify code") +Signed-off-by: Justin Chen +Reviewed-by: Florian Fainelli +Link: https://patch.msgid.link/20260120200754.2488765-1-justin.chen@broadcom.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/gadget/udc/bdc/bdc_core.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/usb/gadget/udc/bdc/bdc_core.c b/drivers/usb/gadget/udc/bdc/bdc_core.c +index 5c3d8b64c0e76..f47aac078f6be 100644 +--- a/drivers/usb/gadget/udc/bdc/bdc_core.c ++++ b/drivers/usb/gadget/udc/bdc/bdc_core.c +@@ -35,8 +35,8 @@ static int poll_oip(struct bdc *bdc, u32 usec) + u32 status; + int ret; + +- ret = readl_poll_timeout(bdc->regs + BDC_BDCSC, status, +- (BDC_CSTS(status) != BDC_OIP), 10, usec); ++ ret = readl_poll_timeout_atomic(bdc->regs + BDC_BDCSC, status, ++ (BDC_CSTS(status) != BDC_OIP), 10, usec); + if (ret) + dev_err(bdc->dev, "operation timedout BDCSC: 0x%08x\n", status); + else +-- +2.51.0 + diff --git a/queue-6.19/usb-typec-fusb302-remove-irqf_oneshot.patch b/queue-6.19/usb-typec-fusb302-remove-irqf_oneshot.patch new file mode 100644 index 0000000000..8072de4b12 --- /dev/null +++ b/queue-6.19/usb-typec-fusb302-remove-irqf_oneshot.patch @@ -0,0 +1,47 @@ +From 9fa527ff9efc5626e3c565a60a2034ed27198c6b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:55:31 +0100 +Subject: usb: typec: fusb302: Remove IRQF_ONESHOT + +From: Sebastian Andrzej Siewior + +[ Upstream commit a7fb84ea70aae9a92a842932206e70ed1b3c7007 ] + +Passing IRQF_ONESHOT ensures that the interrupt source is masked until +the secondary (threaded) handler is done. If only a primary handler is +used then the flag makes no sense because the interrupt can not fire +(again) while its handler is running. + +The flag also prevents force-threading of the primary handler and the +irq-core will warn about this. + +Remove IRQF_ONESHOT from irqflags. + +Fixes: 309b6341d5570 ("usb: typec: fusb302: Revert incorrect threaded irq fix") +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Acked-by: Greg Kroah-Hartman +Acked-by: Heikki Krogerus +Link: https://patch.msgid.link/20260128095540.863589-12-bigeasy@linutronix.de +Signed-off-by: Sasha Levin +--- + drivers/usb/typec/tcpm/fusb302.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c +index 870a71f953f6c..19ff8217818e7 100644 +--- a/drivers/usb/typec/tcpm/fusb302.c ++++ b/drivers/usb/typec/tcpm/fusb302.c +@@ -1756,8 +1756,7 @@ static int fusb302_probe(struct i2c_client *client) + } + + ret = request_irq(chip->gpio_int_n_irq, fusb302_irq_intn, +- IRQF_ONESHOT | IRQF_TRIGGER_LOW, +- "fsc_interrupt_int_n", chip); ++ IRQF_TRIGGER_LOW, "fsc_interrupt_int_n", chip); + if (ret < 0) { + dev_err(dev, "cannot request IRQ for GPIO Int_N, ret=%d", ret); + goto tcpm_unregister_port; +-- +2.51.0 + diff --git a/queue-6.19/usb-typec-ucsi-drop-an-unused-kconfig-symbol.patch b/queue-6.19/usb-typec-ucsi-drop-an-unused-kconfig-symbol.patch new file mode 100644 index 0000000000..afee58d593 --- /dev/null +++ b/queue-6.19/usb-typec-ucsi-drop-an-unused-kconfig-symbol.patch @@ -0,0 +1,40 @@ +From f880dbc414a3636a4616ab15a5fa05e6d0af619f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 28 Dec 2025 11:06:03 -0800 +Subject: usb: typec: ucsi: drop an unused Kconfig symbol + +From: Randy Dunlap + +[ Upstream commit c5177144b561dd4037a6a225d444b3604afbfbf2 ] + +EXTCON_TCSS_CROS_EC isn't used anywhere else in the kernel tree, +so drop it from this Kconfig file. + +(unless it should be EXTCON_USBC_CROS_EC ?) + +Fixes: f1a2241778d9 ("usb: typec: ucsi: Implement ChromeOS UCSI driver") +Signed-off-by: Randy Dunlap +Reviewed-by: Abhishek Pandit-Subedi +Reviewed-by: Benson Leung +Link: https://patch.msgid.link/20251228190604.2484082-1-rdunlap@infradead.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/typec/ucsi/Kconfig | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/usb/typec/ucsi/Kconfig b/drivers/usb/typec/ucsi/Kconfig +index b812be4d0e674..87dd992a4b9e9 100644 +--- a/drivers/usb/typec/ucsi/Kconfig ++++ b/drivers/usb/typec/ucsi/Kconfig +@@ -73,7 +73,6 @@ config CROS_EC_UCSI + tristate "UCSI Driver for ChromeOS EC" + depends on MFD_CROS_EC_DEV + depends on CROS_USBPD_NOTIFY +- depends on !EXTCON_TCSS_CROS_EC + default MFD_CROS_EC_DEV + help + This driver enables UCSI support for a ChromeOS EC. The EC is +-- +2.51.0 + diff --git a/queue-6.19/vfio-pci-lock-upstream-bridge-for-vfio_pci_core_disa.patch b/queue-6.19/vfio-pci-lock-upstream-bridge-for-vfio_pci_core_disa.patch new file mode 100644 index 0000000000..69dffbd782 --- /dev/null +++ b/queue-6.19/vfio-pci-lock-upstream-bridge-for-vfio_pci_core_disa.patch @@ -0,0 +1,74 @@ +From cbb46a75de583b4ce335361c6135e7a4b09c8f99 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 15:31:26 +0000 +Subject: vfio/pci: Lock upstream bridge for vfio_pci_core_disable() + +From: Anthony Pighin (Nokia) + +[ Upstream commit 962ae6892d8bd208b2d1e2b358f07551ddc8d32f ] + +The commit 7e89efc6e9e4 ("Lock upstream bridge for pci_reset_function()") +added locking of the upstream bridge to the reset function. To catch +paths that are not properly locked, the commit 920f6468924f ("Warn on +missing cfg_access_lock during secondary bus reset") added a warning +if the PCI configuration space was not locked during a secondary bus reset +request. + +When a VFIO PCI device is released from userspace ownership, an attempt +to reset the PCI device function may be made. If so, and the upstream bridge +is not locked, the release request results in a warning: + + pcieport 0000:00:00.0: unlocked secondary bus reset via: + pci_reset_bus_function+0x188/0x1b8 + +Add missing upstream bridge locking to vfio_pci_core_disable(). + +Fixes: 7e89efc6e9e4 ("PCI: Lock upstream bridge for pci_reset_function()") +Signed-off-by: Anthony Pighin +Link: https://lore.kernel.org/r/BN0PR08MB695171D3AB759C65B6438B5D838DA@BN0PR08MB6951.namprd08.prod.outlook.com +Signed-off-by: Alex Williamson +Signed-off-by: Sasha Levin +--- + drivers/vfio/pci/vfio_pci_core.c | 17 +++++++++++++---- + 1 file changed, 13 insertions(+), 4 deletions(-) + +diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c +index 3a11e6f450f70..72c33b399800e 100644 +--- a/drivers/vfio/pci/vfio_pci_core.c ++++ b/drivers/vfio/pci/vfio_pci_core.c +@@ -588,6 +588,7 @@ EXPORT_SYMBOL_GPL(vfio_pci_core_enable); + + void vfio_pci_core_disable(struct vfio_pci_core_device *vdev) + { ++ struct pci_dev *bridge; + struct pci_dev *pdev = vdev->pdev; + struct vfio_pci_dummy_resource *dummy_res, *tmp; + struct vfio_pci_ioeventfd *ioeventfd, *ioeventfd_tmp; +@@ -694,12 +695,20 @@ void vfio_pci_core_disable(struct vfio_pci_core_device *vdev) + * We can not use the "try" reset interface here, which will + * overwrite the previously restored configuration information. + */ +- if (vdev->reset_works && pci_dev_trylock(pdev)) { +- if (!__pci_reset_function_locked(pdev)) +- vdev->needs_reset = false; +- pci_dev_unlock(pdev); ++ if (vdev->reset_works) { ++ bridge = pci_upstream_bridge(pdev); ++ if (bridge && !pci_dev_trylock(bridge)) ++ goto out_restore_state; ++ if (pci_dev_trylock(pdev)) { ++ if (!__pci_reset_function_locked(pdev)) ++ vdev->needs_reset = false; ++ pci_dev_unlock(pdev); ++ } ++ if (bridge) ++ pci_dev_unlock(bridge); + } + ++out_restore_state: + pci_restore_state(pdev); + out: + pci_disable_device(pdev); +-- +2.51.0 + diff --git a/queue-6.19/vsnprintf-drop-__printf-attributes-on-binary-printin.patch b/queue-6.19/vsnprintf-drop-__printf-attributes-on-binary-printin.patch new file mode 100644 index 0000000000..6a6e0e73ed --- /dev/null +++ b/queue-6.19/vsnprintf-drop-__printf-attributes-on-binary-printin.patch @@ -0,0 +1,77 @@ +From cb71209404a567d463df76162764356ca03ca73e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 14:26:23 +0100 +Subject: vsnprintf: drop __printf() attributes on binary printing functions + +From: Arnd Bergmann + +[ Upstream commit b07829d546c83134629591f02c5348d57cea0c1e ] + +The printf() format attributes are applied inconsistently for the binary +printf helpers, which causes warnings for the bpf_trace code using +them from functions that pass down format strings: + + kernel/trace/bpf_trace.c: In function '____bpf_trace_printk': + kernel/trace/bpf_trace.c:377:9: error: function '____bpf_trace_printk' might be a candidate for 'gnu_printf' format attribute [-Werror=suggest-attribute=format] + 377 | ret = bstr_printf(data.buf, MAX_BPRINTF_BUF, fmt, data.bin_args); + | ^~~ + +This can be addressed either by annotating all five callers in bpf code, +or by removing the annotations on the callees that were added by Andy +Shevchenko last year. + +As Alexei Starovoitov points out, there are no callers in C code that +would benefit from the __printf attributes, the only users are in BPF +code or in the do_trace_printk() helper that already checks the arguments. + +Drop all three of these annotations, reverting the earlierl commits that +added these, in order to get a clean build with -Wsuggest-attribute=format. + +Fixes: 6b2c1e30ad68 ("seq_file: Mark binary printing functions with __printf() attribute") +Fixes: 7bf819aa992f ("vsnprintf: Mark binary printing functions with __printf() attribute") +Link: https://lore.kernel.org/all/CAADnVQK3eZp3yp35OUx8j1UBsQFhgsn5-4VReqAJ=68PaaKYmg@mail.gmail.com/ +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202512061640.9hKTnB8p-lkp@intel.com/ +Suggested-by: Alexei Starovoitov +Acked-by: Alexei Starovoitov +Signed-off-by: Arnd Bergmann +Acked-by: Petr Mladek +Acked-by: Andy Shevchenko +Link: https://patch.msgid.link/20260204132643.1302967-1-arnd@kernel.org +Signed-off-by: Petr Mladek +Signed-off-by: Sasha Levin +--- + include/linux/seq_file.h | 1 - + include/linux/string.h | 4 ++-- + 2 files changed, 2 insertions(+), 3 deletions(-) + +diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h +index d6ebf0596510c..2fb266ea69fa4 100644 +--- a/include/linux/seq_file.h ++++ b/include/linux/seq_file.h +@@ -181,7 +181,6 @@ int seq_open_private(struct file *, const struct seq_operations *, int); + int seq_release_private(struct inode *, struct file *); + + #ifdef CONFIG_BINARY_PRINTF +-__printf(2, 0) + void seq_bprintf(struct seq_file *m, const char *f, const u32 *binary); + #endif + +diff --git a/include/linux/string.h b/include/linux/string.h +index 1b564c36d721b..b850bd91b3d88 100644 +--- a/include/linux/string.h ++++ b/include/linux/string.h +@@ -336,8 +336,8 @@ int __sysfs_match_string(const char * const *array, size_t n, const char *s); + #define sysfs_match_string(_a, _s) __sysfs_match_string(_a, ARRAY_SIZE(_a), _s) + + #ifdef CONFIG_BINARY_PRINTF +-__printf(3, 0) int vbin_printf(u32 *bin_buf, size_t size, const char *fmt, va_list args); +-__printf(3, 0) int bstr_printf(char *buf, size_t size, const char *fmt, const u32 *bin_buf); ++int vbin_printf(u32 *bin_buf, size_t size, const char *fmt, va_list args); ++int bstr_printf(char *buf, size_t size, const char *fmt, const u32 *bin_buf); + #endif + + extern ssize_t memory_read_from_buffer(void *to, size_t count, loff_t *ppos, +-- +2.51.0 + diff --git a/queue-6.19/watchdog-starfive-wdt-fix-pm-reference-leak-in-probe.patch b/queue-6.19/watchdog-starfive-wdt-fix-pm-reference-leak-in-probe.patch new file mode 100644 index 0000000000..023394030a --- /dev/null +++ b/queue-6.19/watchdog-starfive-wdt-fix-pm-reference-leak-in-probe.patch @@ -0,0 +1,45 @@ +From f671811dbfef50d5284d9467444a6bd0753ec7bf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 01:29:15 +0800 +Subject: watchdog: starfive-wdt: Fix PM reference leak in probe error path + +From: Kery Qi + +[ Upstream commit 3f2d8d79cceb05a8b8dd200fa81c0dffc59ec46f ] + +The PM reference count is not expected to be incremented on return in +functions starfive_wdt_probe. + +However, pm_runtime_get_sync will increment pm usage counter +even failed. Forgetting to putting operation will result in a +reference leak here. + +Replace it with pm_runtime_resume_and_get to keep usage +counter balanced. + +Fixes: db728ea9c7be ("drivers: watchdog: Add StarFive Watchdog driver") +Signed-off-by: Kery Qi +Reviewed-by: Guenter Roeck +Signed-off-by: Guenter Roeck +Signed-off-by: Wim Van Sebroeck +Signed-off-by: Sasha Levin +--- + drivers/watchdog/starfive-wdt.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/watchdog/starfive-wdt.c b/drivers/watchdog/starfive-wdt.c +index ed71d3960a0f2..af55adc4a3c69 100644 +--- a/drivers/watchdog/starfive-wdt.c ++++ b/drivers/watchdog/starfive-wdt.c +@@ -446,7 +446,7 @@ static int starfive_wdt_probe(struct platform_device *pdev) + platform_set_drvdata(pdev, wdt); + pm_runtime_enable(&pdev->dev); + if (pm_runtime_enabled(&pdev->dev)) { +- ret = pm_runtime_get_sync(&pdev->dev); ++ ret = pm_runtime_resume_and_get(&pdev->dev); + if (ret < 0) + return ret; + } else { +-- +2.51.0 + diff --git a/queue-6.19/wifi-ath10k-sdio-add-missing-lock-protection-in-ath1.patch b/queue-6.19/wifi-ath10k-sdio-add-missing-lock-protection-in-ath1.patch new file mode 100644 index 0000000000..b7ddc84ed6 --- /dev/null +++ b/queue-6.19/wifi-ath10k-sdio-add-missing-lock-protection-in-ath1.patch @@ -0,0 +1,62 @@ +From 63c9e0d14a25fe4aac66e40cea3f4b741c56f1e5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 04:58:22 +0000 +Subject: wifi: ath10k: sdio: add missing lock protection in + ath10k_sdio_fw_crashed_dump() + +From: Ziyi Guo + +[ Upstream commit e55ac348089e579fc224569c7bd90340bf2439f9 ] + +ath10k_sdio_fw_crashed_dump() calls ath10k_coredump_new() which requires +ar->dump_mutex to be held, as indicated by lockdep_assert_held() in that +function. However, the SDIO implementation does not acquire this lock, +unlike the PCI and SNOC implementations which properly hold the mutex. + +Additionally, ar->stats.fw_crash_counter is documented as protected by +ar->data_lock in core.h, but the SDIO implementation modifies it without +holding this spinlock. + +Add the missing mutex_lock()/mutex_unlock() around the coredump +operations, and add spin_lock_bh()/spin_unlock_bh() around the +fw_crash_counter increment, following the pattern used in +ath10k_pci_fw_dump_work() and ath10k_snoc_fw_crashed_dump(). + +Fixes: 3c45f21af84e ("ath10k: sdio: add firmware coredump support") +Signed-off-by: Ziyi Guo +Reviewed-by: Baochen Qiang +Link: https://patch.msgid.link/20260123045822.2221549-1-n7l8m4@u.northwestern.edu +Signed-off-by: Jeff Johnson +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/ath/ath10k/sdio.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c +index c06d50db40b81..00d0556dafefd 100644 +--- a/drivers/net/wireless/ath/ath10k/sdio.c ++++ b/drivers/net/wireless/ath/ath10k/sdio.c +@@ -2487,7 +2487,11 @@ void ath10k_sdio_fw_crashed_dump(struct ath10k *ar) + if (fast_dump) + ath10k_bmi_start(ar); + ++ mutex_lock(&ar->dump_mutex); ++ ++ spin_lock_bh(&ar->data_lock); + ar->stats.fw_crash_counter++; ++ spin_unlock_bh(&ar->data_lock); + + ath10k_sdio_disable_intrs(ar); + +@@ -2505,6 +2509,8 @@ void ath10k_sdio_fw_crashed_dump(struct ath10k *ar) + + ath10k_sdio_enable_intrs(ar); + ++ mutex_unlock(&ar->dump_mutex); ++ + ath10k_core_start_recovery(ar); + } + +-- +2.51.0 + diff --git a/queue-6.19/wifi-ath11k-add-usecase-firmware-handling-based-on-d.patch b/queue-6.19/wifi-ath11k-add-usecase-firmware-handling-based-on-d.patch new file mode 100644 index 0000000000..fcd04b8ffb --- /dev/null +++ b/queue-6.19/wifi-ath11k-add-usecase-firmware-handling-based-on-d.patch @@ -0,0 +1,101 @@ +From 124531625306924e67fb2dcd31fefc2abea2f0c6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 17:50:54 +0800 +Subject: wifi: ath11k: add usecase firmware handling based on device + compatible + +From: Miaoqing Pan + +[ Upstream commit c386a2b1068910538e87ef1cf2fc938ebf7e218f ] + +For M.2 WLAN chips, there is no suitable DTS node to specify the +firmware-name property. In addition, assigning firmware for the +M.2 PCIe interface causes chips that do not use usecase specific +firmware to fail. Therefore, abandoning the approach of specifying +firmware in DTS. As an alternative, propose a static lookup table +mapping device compatible to firmware names. Currently, only WCN6855 +HW2.1 requires this. + +However, support for the firmware-name property is retained to keep +the ABI backwards compatible. + +For details on usecase specific firmware, see: +https://lore.kernel.org/all/20250522013444.1301330-3-miaoqing.pan@oss.qualcomm.com/. + +Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-04685-QCAHSPSWPL_V1_V2_SILICONZ_IOE-1 + +Fixes: edbbc647c4f3 ("wifi: ath11k: support usercase-specific firmware overrides") +Signed-off-by: Miaoqing Pan +Reviewed-by: Vasanthakumar Thiagarajan +Reviewed-by: Baochen Qiang +Link: https://patch.msgid.link/20260121095055.3683957-2-miaoqing.pan@oss.qualcomm.com +Signed-off-by: Jeff Johnson +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/ath/ath11k/core.c | 27 ++++++++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/core.h | 4 ++++ + 2 files changed, 31 insertions(+) + +diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c +index 812686173ac8a..06b4df2370e95 100644 +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -997,6 +997,33 @@ static const struct dmi_system_id ath11k_pm_quirk_table[] = { + {} + }; + ++static const struct __ath11k_core_usecase_firmware_table { ++ u32 hw_rev; ++ const char *compatible; ++ const char *firmware_name; ++} ath11k_core_usecase_firmware_table[] = { ++ { ATH11K_HW_WCN6855_HW21, "qcom,lemans-evk", "nfa765"}, ++ { ATH11K_HW_WCN6855_HW21, "qcom,monaco-evk", "nfa765"}, ++ { ATH11K_HW_WCN6855_HW21, "qcom,hamoa-iot-evk", "nfa765"}, ++ { /* Sentinel */ } ++}; ++ ++const char *ath11k_core_get_usecase_firmware(struct ath11k_base *ab) ++{ ++ const struct __ath11k_core_usecase_firmware_table *entry = NULL; ++ ++ entry = ath11k_core_usecase_firmware_table; ++ while (entry->compatible) { ++ if (ab->hw_rev == entry->hw_rev && ++ of_machine_is_compatible(entry->compatible)) ++ return entry->firmware_name; ++ entry++; ++ } ++ ++ return NULL; ++} ++EXPORT_SYMBOL(ath11k_core_get_usecase_firmware); ++ + void ath11k_fw_stats_pdevs_free(struct list_head *head) + { + struct ath11k_fw_stats_pdev *i, *tmp; +diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h +index e8780b05ce11e..834988dad591c 100644 +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -1275,6 +1275,7 @@ bool ath11k_core_coldboot_cal_support(struct ath11k_base *ab); + + const struct firmware *ath11k_core_firmware_request(struct ath11k_base *ab, + const char *filename); ++const char *ath11k_core_get_usecase_firmware(struct ath11k_base *ab); + + static inline const char *ath11k_scan_state_str(enum ath11k_scan_state state) + { +@@ -1329,6 +1330,9 @@ static inline void ath11k_core_create_firmware_path(struct ath11k_base *ab, + + of_property_read_string(ab->dev->of_node, "firmware-name", &fw_name); + ++ if (!fw_name) ++ fw_name = ath11k_core_get_usecase_firmware(ab); ++ + if (fw_name && strncmp(filename, "board", 5)) + snprintf(buf, buf_len, "%s/%s/%s/%s", ATH11K_FW_DIR, + ab->hw_params.fw.dir, fw_name, filename); +-- +2.51.0 + diff --git a/queue-6.19/wifi-ath12k-clear-stale-link-mapping-of-ahvif-links_.patch b/queue-6.19/wifi-ath12k-clear-stale-link-mapping-of-ahvif-links_.patch new file mode 100644 index 0000000000..b29d278a4e --- /dev/null +++ b/queue-6.19/wifi-ath12k-clear-stale-link-mapping-of-ahvif-links_.patch @@ -0,0 +1,68 @@ +From 46bb3281f5d9c6d92f64626c72114c7519a6b50e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 09:04:00 +0530 +Subject: wifi: ath12k: clear stale link mapping of ahvif->links_map + +From: Aaradhana Sahu + +[ Upstream commit 2c1ba9c2adf0fda96eaaebd8799268a7506a8fc9 ] + +When an arvif is initialized in non-AP STA mode but MLO connection +preparation fails before the arvif is created +(arvif->is_created remains false), the error path attempts to delete all +links. However, link deletion only executes when arvif->is_created is true. +As a result, ahvif retains a stale entry of arvif that is initialized but +not created. + +When a new arvif is initialized with the same link id, this stale mapping +triggers the following WARN_ON. + +WARNING: drivers/net/wireless/ath/ath12k/mac.c:4271 at ath12k_mac_op_change_vif_links+0x140/0x180 [ath12k], CPU#3: wpa_supplicant/275 + +Call trace: + ath12k_mac_op_change_vif_links+0x140/0x180 [ath12k] (P) + drv_change_vif_links+0xbc/0x1a4 [mac80211] + ieee80211_vif_update_links+0x54c/0x6a0 [mac80211] + ieee80211_vif_set_links+0x40/0x70 [mac80211] + ieee80211_prep_connection+0x84/0x450 [mac80211] + ieee80211_mgd_auth+0x200/0x480 [mac80211] + ieee80211_auth+0x14/0x20 [mac80211] + cfg80211_mlme_auth+0x90/0xf0 [cfg80211] + nl80211_authenticate+0x32c/0x380 [cfg80211] + genl_family_rcv_msg_doit+0xc8/0x134 + +Fix this issue by unassigning the link vif and clearing ahvif->links_map +if arvif is only initialized but not created. + +Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.5-01651-QCAHKSWPL_SILICONZ-1 + +Fixes: 81e4be30544e ("wifi: ath12k: handle link removal in change_vif_links()") +Signed-off-by: Aaradhana Sahu +Reviewed-by: Vasanthakumar Thiagarajan +Reviewed-by: Baochen Qiang +Link: https://patch.msgid.link/20260127033400.1721220-1-aaradhana.sahu@oss.qualcomm.com +Signed-off-by: Jeff Johnson +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/ath/ath12k/mac.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c +index e0e49f782bf8d..63684ff9332d4 100644 +--- a/drivers/net/wireless/ath/ath12k/mac.c ++++ b/drivers/net/wireless/ath/ath12k/mac.c +@@ -4175,8 +4175,10 @@ ath12k_mac_op_change_vif_links(struct ieee80211_hw *hw, + if (WARN_ON(!arvif)) + return -EINVAL; + +- if (!arvif->is_created) ++ if (!arvif->is_created) { ++ ath12k_mac_unassign_link_vif(arvif); + continue; ++ } + + if (WARN_ON(!arvif->ar)) + return -EINVAL; +-- +2.51.0 + diff --git a/queue-6.19/wifi-ath12k-do-wow-offloads-only-on-primary-link.patch b/queue-6.19/wifi-ath12k-do-wow-offloads-only-on-primary-link.patch new file mode 100644 index 0000000000..87fca6af27 --- /dev/null +++ b/queue-6.19/wifi-ath12k-do-wow-offloads-only-on-primary-link.patch @@ -0,0 +1,86 @@ +From aeb197d109b119348baf4bcbcc7a8d56c7f54add Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 3 Nov 2025 10:44:49 +0800 +Subject: wifi: ath12k: do WoW offloads only on primary link + +From: Baochen Qiang + +[ Upstream commit e62102ac9b773bdb08475aa9ca24dea61ae98708 ] + +In case of multi-link connection, WCN7850 firmware crashes due to WoW +offloads enabled on both primary and secondary links. + +Change to do it only on primary link to fix it. + +Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00284-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1 + +Fixes: 32f7b19668bd ("wifi: ath12k: support MLO as well if single_chip_mlo_support flag is set") +Signed-off-by: Baochen Qiang +Reviewed-by: Vasanthakumar Thiagarajan +Link: https://patch.msgid.link/20251103-ath12-primary-link-wow-v1-1-3cf523dc09f0@oss.qualcomm.com +Signed-off-by: Jeff Johnson +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/ath/ath12k/wow.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/drivers/net/wireless/ath/ath12k/wow.c b/drivers/net/wireless/ath/ath12k/wow.c +index e8481626f1940..c78aa95d49791 100644 +--- a/drivers/net/wireless/ath/ath12k/wow.c ++++ b/drivers/net/wireless/ath/ath12k/wow.c +@@ -135,6 +135,9 @@ static int ath12k_wow_cleanup(struct ath12k *ar) + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); + + list_for_each_entry(arvif, &ar->arvifs, list) { ++ if (arvif != &arvif->ahvif->deflink) ++ continue; ++ + ret = ath12k_wow_vif_cleanup(arvif); + if (ret) { + ath12k_warn(ar->ab, "failed to clean wow wakeups on vdev %i: %d\n", +@@ -479,8 +482,12 @@ static int ath12k_wow_set_wakeups(struct ath12k *ar, + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); + + list_for_each_entry(arvif, &ar->arvifs, list) { ++ if (arvif != &arvif->ahvif->deflink) ++ continue; ++ + if (ath12k_wow_is_p2p_vdev(arvif->ahvif)) + continue; ++ + ret = ath12k_wow_vif_set_wakeups(arvif, wowlan); + if (ret) { + ath12k_warn(ar->ab, "failed to set wow wakeups on vdev %i: %d\n", +@@ -538,6 +545,9 @@ static int ath12k_wow_nlo_cleanup(struct ath12k *ar) + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); + + list_for_each_entry(arvif, &ar->arvifs, list) { ++ if (arvif != &arvif->ahvif->deflink) ++ continue; ++ + if (ath12k_wow_is_p2p_vdev(arvif->ahvif)) + continue; + +@@ -745,6 +755,9 @@ static int ath12k_wow_arp_ns_offload(struct ath12k *ar, bool enable) + list_for_each_entry(arvif, &ar->arvifs, list) { + ahvif = arvif->ahvif; + ++ if (arvif != &ahvif->deflink) ++ continue; ++ + if (ahvif->vdev_type != WMI_VDEV_TYPE_STA) + continue; + +@@ -776,6 +789,9 @@ static int ath12k_gtk_rekey_offload(struct ath12k *ar, bool enable) + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); + + list_for_each_entry(arvif, &ar->arvifs, list) { ++ if (arvif != &arvif->ahvif->deflink) ++ continue; ++ + if (arvif->ahvif->vdev_type != WMI_VDEV_TYPE_STA || + !arvif->is_up || + !arvif->rekey_data.enable_offload) +-- +2.51.0 + diff --git a/queue-6.19/wifi-ath12k-fix-index-decrement-when-array_len-is-ze.patch b/queue-6.19/wifi-ath12k-fix-index-decrement-when-array_len-is-ze.patch new file mode 100644 index 0000000000..7824adeb20 --- /dev/null +++ b/queue-6.19/wifi-ath12k-fix-index-decrement-when-array_len-is-ze.patch @@ -0,0 +1,56 @@ +From 497c3dce5ade86d923133864d35e4a9c0015a77f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 12:42:51 +0530 +Subject: wifi: ath12k: Fix index decrement when array_len is zero + +From: Aaradhana Sahu + +[ Upstream commit e4763898bb1325dbb3792961b6d607b5c6452d64 ] + +Currently, print_array_to_buf_index() decrements index unconditionally. +This may lead to invalid buffer access when array_len is zero. + +Fix this by decrementing index only when array_len is non-zero. + +Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.5-01651-QCAHKSWPL_SILICONZ-1 +Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00302-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.115823.3 + +Fixes: adf6df963c03 ("wifi: ath12k: Add support to parse requested stats_type") +Signed-off-by: Aaradhana Sahu +Reviewed-by: Baochen Qiang +Link: https://patch.msgid.link/20260123071253.2202644-2-aaradhana.sahu@oss.qualcomm.com +Signed-off-by: Jeff Johnson +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c +index 48b010a1b7566..4f749d473d0e1 100644 +--- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c ++++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c +@@ -1,7 +1,7 @@ + // SPDX-License-Identifier: BSD-3-Clause-Clear + /* + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. +- * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved. ++ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + + #include +@@ -29,8 +29,10 @@ print_array_to_buf_index(u8 *buf, u32 offset, const char *header, u32 stats_inde + " %u:%u,", stats_index++, le32_to_cpu(array[i])); + } + /* To overwrite the last trailing comma */ +- index--; +- *(buf + offset + index) = '\0'; ++ if (array_len > 0) { ++ index--; ++ *(buf + offset + index) = '\0'; ++ } + + if (footer) { + index += scnprintf(buf + offset + index, +-- +2.51.0 + diff --git a/queue-6.19/wifi-ath9k-add-of-dependency-to-ahb.patch b/queue-6.19/wifi-ath9k-add-of-dependency-to-ahb.patch new file mode 100644 index 0000000000..a061c55854 --- /dev/null +++ b/queue-6.19/wifi-ath9k-add-of-dependency-to-ahb.patch @@ -0,0 +1,40 @@ +From 2f3ca109b16046dae3a28efb39b7c870cdb4ca8d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 1 Aug 2025 17:04:32 -0700 +Subject: wifi: ath9k: add OF dependency to AHB +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Rosen Penev + +[ Upstream commit 125e7b31f041cc0a4ede1e42bef69915f0a63a35 ] + +The conversion to OF missed adding a Kconfig dependency. + +Fixes: 2fa490c0d759 ("wifi: ath9k: ahb: replace id_table with of") +Signed-off-by: Rosen Penev +Acked-by: Toke Høiland-Jørgensen +Link: https://patch.msgid.link/20250802000432.3079550-1-rosenp@gmail.com +Signed-off-by: Jeff Johnson +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/ath/ath9k/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig +index 0c47be06c153b..47d570a5ca6a1 100644 +--- a/drivers/net/wireless/ath/ath9k/Kconfig ++++ b/drivers/net/wireless/ath/ath9k/Kconfig +@@ -47,7 +47,7 @@ config ATH9K_PCI + + config ATH9K_AHB + bool "Atheros ath9k AHB bus support" +- depends on ATH9K ++ depends on ATH9K && OF + default n + help + This option enables the AHB bus support in ath9k. +-- +2.51.0 + diff --git a/queue-6.19/wifi-ath9k-debug.h-fix-kernel-doc-bad-lines-and-stru.patch b/queue-6.19/wifi-ath9k-debug.h-fix-kernel-doc-bad-lines-and-stru.patch new file mode 100644 index 0000000000..b063590270 --- /dev/null +++ b/queue-6.19/wifi-ath9k-debug.h-fix-kernel-doc-bad-lines-and-stru.patch @@ -0,0 +1,88 @@ +From ef15d375e1c6356df9f6c238ce8d0f7f84768898 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 16 Nov 2025 18:03:03 -0800 +Subject: wifi: ath9k: debug.h: fix kernel-doc bad lines and struct + ath_tx_stats +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Randy Dunlap + +[ Upstream commit c6131765a2c0052b2c5a2310ff92191ff33aec8b ] + +Repair "bad line" warnings by starting each line with " *". +Add or correct kernel-doc entries for missing struct members in +struct ath_tx_stats. + +Warning: ../drivers/net/wireless/ath/ath9k/debug.h:144 bad line: + may have had errors. +Warning: ../drivers/net/wireless/ath/ath9k/debug.h:146 bad line: + may have had errors. +Warning: ../drivers/net/wireless/ath/ath9k/debug.h:156 bad line: + Valid only for: +Warning: ../drivers/net/wireless/ath/ath9k/debug.h:157 bad line: + - non-aggregate condition. +Warning: ../drivers/net/wireless/ath/ath9k/debug.h:158 bad line: + - first packet of aggregate. +Warning: drivers/net/wireless/ath/ath9k/debug.h:191 struct member + 'xretries' not described in 'ath_tx_stats' +Warning: drivers/net/wireless/ath/ath9k/debug.h:191 struct member + 'data_underrun' not described in 'ath_tx_stats' +Warning: drivers/net/wireless/ath/ath9k/debug.h:191 struct member + 'delim_underrun' not described in 'ath_tx_stats' + +Fixes: 99c15bf575b1 ("ath9k: Report total tx/rx bytes and packets in debugfs.") +Fixes: fec247c0d5bf ("ath9k: Add debug counters for TX") +Fixes: 5a6f78afdabe ("ath9k: show excessive-retry MPDUs in debugfs") +Signed-off-by: Randy Dunlap +Acked-by: Toke Høiland-Jørgensen +Link: https://patch.msgid.link/20251117020304.448687-1-rdunlap@infradead.org +Signed-off-by: Jeff Johnson +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/ath/ath9k/debug.h | 15 ++++++++------- + 1 file changed, 8 insertions(+), 7 deletions(-) + +diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h +index cb3e75969875a..804e2a0a0c20f 100644 +--- a/drivers/net/wireless/ath/ath9k/debug.h ++++ b/drivers/net/wireless/ath/ath9k/debug.h +@@ -142,11 +142,12 @@ struct ath_interrupt_stats { + /** + * struct ath_tx_stats - Statistics about TX + * @tx_pkts_all: No. of total frames transmitted, including ones that +- may have had errors. ++ * may have had errors. + * @tx_bytes_all: No. of total bytes transmitted, including ones that +- may have had errors. ++ * may have had errors. + * @queued: Total MPDUs (non-aggr) queued + * @completed: Total MPDUs (non-aggr) completed ++ * @xretries: Total MPDUs with xretries + * @a_aggr: Total no. of aggregates queued + * @a_queued_hw: Total AMPDUs queued to hardware + * @a_completed: Total AMPDUs completed +@@ -154,14 +155,14 @@ struct ath_interrupt_stats { + * @a_xretries: No. of AMPDUs dropped due to xretries + * @txerr_filtered: No. of frames with TXERR_FILT flag set. + * @fifo_underrun: FIFO underrun occurrences +- Valid only for: +- - non-aggregate condition. +- - first packet of aggregate. ++ * Valid only for: ++ * - non-aggregate condition. ++ * - first packet of aggregate. + * @xtxop: No. of frames filtered because of TXOP limit + * @timer_exp: Transmit timer expiry + * @desc_cfg_err: Descriptor configuration errors +- * @data_urn: TX data underrun errors +- * @delim_urn: TX delimiter underrun errors ++ * @data_underrun: TX data underrun errors ++ * @delim_underrun: TX delimiter underrun errors + * @puttxbuf: Number of times hardware was given txbuf to write. + * @txstart: Number of times hardware was told to start tx. + * @txprocdesc: Number of times tx descriptor was processed +-- +2.51.0 + diff --git a/queue-6.19/wifi-ath9k-fix-kernel-doc-warnings-in-common-debug.h.patch b/queue-6.19/wifi-ath9k-fix-kernel-doc-warnings-in-common-debug.h.patch new file mode 100644 index 0000000000..3198a1e56e --- /dev/null +++ b/queue-6.19/wifi-ath9k-fix-kernel-doc-warnings-in-common-debug.h.patch @@ -0,0 +1,60 @@ +From 7c8b6d0d00babe182474ce732fb12a6752c0053d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 16 Nov 2025 18:02:50 -0800 +Subject: wifi: ath9k: fix kernel-doc warnings in common-debug.h +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Randy Dunlap + +[ Upstream commit b9909c19965dc9e5a3a898fef09b437fcc3a9494 ] + +Modify kernel-doc comments in common-debug.h to avoid warnings: + +Warning: drivers/net/wireless/ath/ath9k/common-debug.h:21 bad line: + may have had errors. +Warning: ../drivers/net/wireless/ath/ath9k/common-debug.h:23 bad line: + may have had errors. +Warning: ../drivers/net/wireless/ath/ath9k/common-debug.h:26 bad line: + decryption process completed +Warning: ../drivers/net/wireless/ath/ath9k/common-debug.h:28 bad line: + encountered an error + +Fixes: 99c15bf575b1 ("ath9k: Report total tx/rx bytes and packets in debugfs.") +Fixes: 1395d3f00a41 ("ath9k: Add debugfs file for RX errors") +Signed-off-by: Randy Dunlap +Acked-by: Toke Høiland-Jørgensen +Link: https://patch.msgid.link/20251117020251.447692-1-rdunlap@infradead.org +Signed-off-by: Jeff Johnson +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/ath/ath9k/common-debug.h | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/wireless/ath/ath9k/common-debug.h b/drivers/net/wireless/ath/ath9k/common-debug.h +index 2938b5b96b074..97948af97682b 100644 +--- a/drivers/net/wireless/ath/ath9k/common-debug.h ++++ b/drivers/net/wireless/ath/ath9k/common-debug.h +@@ -19,14 +19,14 @@ + /** + * struct ath_rx_stats - RX Statistics + * @rx_pkts_all: No. of total frames received, including ones that +- may have had errors. ++ * may have had errors. + * @rx_bytes_all: No. of total bytes received, including ones that +- may have had errors. ++ * may have had errors. + * @crc_err: No. of frames with incorrect CRC value + * @decrypt_crc_err: No. of frames whose CRC check failed after +- decryption process completed ++ * decryption process completed + * @phy_err: No. of frames whose reception failed because the PHY +- encountered an error ++ * encountered an error + * @mic_err: No. of frames with incorrect TKIP MIC verification failure + * @pre_delim_crc_err: Pre-Frame delimiter CRC error detections + * @post_delim_crc_err: Post-Frame delimiter CRC error detections +-- +2.51.0 + diff --git a/queue-6.19/wifi-cfg80211-fix-use_for-flag-update-on-bss-refresh.patch b/queue-6.19/wifi-cfg80211-fix-use_for-flag-update-on-bss-refresh.patch new file mode 100644 index 0000000000..7bc22f6b60 --- /dev/null +++ b/queue-6.19/wifi-cfg80211-fix-use_for-flag-update-on-bss-refresh.patch @@ -0,0 +1,54 @@ +From e9d42ffbe1efc7550006a4fb60693b5b3cb9f36c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 08:27:33 +0530 +Subject: wifi: cfg80211: Fix use_for flag update on BSS refresh +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Huang Chenming + +[ Upstream commit 4073ea516106e5f98ed0476f89cdede8baa98d37 ] + +Userspace may fail to connect to certain BSS that were initially +marked as unusable due to regulatory restrictions (use_for = 0, +e.g., 6 GHz power type mismatch). Even after these restrictions +are removed and the BSS becomes usable, connection attempts still +fail. + +The issue occurs in cfg80211_update_known_bss() where the use_for +flag is updated using bitwise AND (&=) instead of direct assignment. +Once a BSS is marked with use_for = 0, the AND operation masks out +any subsequent non-zero values, permanently keeping the flag at 0. +This causes __cfg80211_get_bss(), invoked by nl80211_assoc_bss(), to +fail the check "(bss->pub.use_for & use_for) != use_for", thereby +blocking association. + +Replace the bitwise AND operation with direct assignment so the use_for +flag accurately reflects the current BSS state. + +Fixes: d02a12b8e4bb ("wifi: cfg80211: add BSS usage reporting") +Signed-off-by: Huang Chenming +Link: https://patch.msgid.link/20251209025733.2098456-1-chenming.huang@oss.qualcomm.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/wireless/scan.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/wireless/scan.c b/net/wireless/scan.c +index 7546647752fd8..eb0e77813d466 100644 +--- a/net/wireless/scan.c ++++ b/net/wireless/scan.c +@@ -1959,7 +1959,7 @@ cfg80211_update_known_bss(struct cfg80211_registered_device *rdev, + ether_addr_copy(known->parent_bssid, new->parent_bssid); + known->pub.max_bssid_indicator = new->pub.max_bssid_indicator; + known->pub.bssid_index = new->pub.bssid_index; +- known->pub.use_for &= new->pub.use_for; ++ known->pub.use_for = new->pub.use_for; + known->pub.cannot_use_reasons = new->pub.cannot_use_reasons; + known->bss_source = new->bss_source; + +-- +2.51.0 + diff --git a/queue-6.19/wifi-cfg80211-stop-nan-and-p2p-in-cfg80211_leave.patch b/queue-6.19/wifi-cfg80211-stop-nan-and-p2p-in-cfg80211_leave.patch new file mode 100644 index 0000000000..b8b29e210a --- /dev/null +++ b/queue-6.19/wifi-cfg80211-stop-nan-and-p2p-in-cfg80211_leave.patch @@ -0,0 +1,47 @@ +From 7f83ba71784291bce557427048612401c973390e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 14:04:51 +0200 +Subject: wifi: cfg80211: stop NAN and P2P in cfg80211_leave + +From: Miri Korenblit + +[ Upstream commit e1696c8bd0056bc1a5f7766f58ac333adc203e8a ] + +Seems that there is an assumption that this function should be called +only for netdev interfaces, but it can also be called in suspend, or +from nl80211_netlink_notify (indirectly). +Note that the documentation of NL80211_ATTR_SOCKET_OWNER explicitly +says that NAN interfaces would be destroyed as well in the +nl80211_netlink_notify case. + +Fix this by also stopping P2P and NAN. + +Fixes: cb3b7d87652a ("cfg80211: add start / stop NAN commands") +Reviewed-by: Johannes Berg +Signed-off-by: Miri Korenblit +Link: https://patch.msgid.link/20260107140430.dab142cbef0b.I290cc47836d56dd7e35012ce06bec36c6da688cd@changeid +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/wireless/core.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/net/wireless/core.c b/net/wireless/core.c +index 9a420d627d3ce..a04f96dc9a1d7 100644 +--- a/net/wireless/core.c ++++ b/net/wireless/core.c +@@ -1415,8 +1415,10 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev, + cfg80211_leave_ocb(rdev, dev); + break; + case NL80211_IFTYPE_P2P_DEVICE: ++ cfg80211_stop_p2p_device(rdev, wdev); ++ break; + case NL80211_IFTYPE_NAN: +- /* cannot happen, has no netdev */ ++ cfg80211_stop_nan(rdev, wdev); + break; + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_MONITOR: +-- +2.51.0 + diff --git a/queue-6.19/wifi-rtw89-correct-use-sequence-of-driver_data-in-sk.patch b/queue-6.19/wifi-rtw89-correct-use-sequence-of-driver_data-in-sk.patch new file mode 100644 index 0000000000..9109db8773 --- /dev/null +++ b/queue-6.19/wifi-rtw89-correct-use-sequence-of-driver_data-in-sk.patch @@ -0,0 +1,75 @@ +From 46420a99c6b64c2712676ef981352875072359cc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 17 Dec 2025 15:26:46 +0800 +Subject: wifi: rtw89: correct use sequence of driver_data in skb->info + +From: Ping-Ke Shih + +[ Upstream commit d3a9e132a4c6273a5254e743da14887502e928c8 ] + +As ieee80211_tx_info is used to assist filling TX descriptor, and layout of +IEEE80211_SKB_CB(skb)->driver_data (accessing by RTW89_TX_SKB_CB()) is +union, so driver_data must be used by/after rtw89_hci_tx_write() or just +before calling rtw89_hci_tx_write(). Otherwise, ieee80211_tx_info::control +data is overwritten. + +Found this by using injected packets which uses ieee80211_tx_info::control, +but always sending incorrect data rate. + +Cc: Fedor Pchelkin +Fixes: d5da3d9fb05f ("wifi: rtw89: process TX wait skbs for USB via C2H handler") +Signed-off-by: Ping-Ke Shih +Tested-by: Fedor Pchelkin +Link: https://patch.msgid.link/20251217072646.43209-1-pkshih@realtek.com +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtw89/core.c | 6 ++++-- + drivers/net/wireless/realtek/rtw89/core.h | 2 ++ + 2 files changed, 6 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c +index 0824940c91aee..53d32f3137ebe 100644 +--- a/drivers/net/wireless/realtek/rtw89/core.c ++++ b/drivers/net/wireless/realtek/rtw89/core.c +@@ -1207,7 +1207,7 @@ rtw89_core_tx_update_desc_info(struct rtw89_dev *rtwdev, + if (addr_cam->valid && desc_info->mlo) + upd_wlan_hdr = true; + +- if (rtw89_is_tx_rpt_skb(rtwdev, tx_req->skb)) ++ if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS || tx_req->with_wait) + rtw89_tx_rpt_init(rtwdev, tx_req); + + is_bmc = (is_broadcast_ether_addr(hdr->addr1) || +@@ -1342,13 +1342,15 @@ static int rtw89_core_tx_write_link(struct rtw89_dev *rtwdev, + tx_req.rtwvif_link = rtwvif_link; + tx_req.rtwsta_link = rtwsta_link; + tx_req.desc_info.sw_mld = sw_mld; +- rcu_assign_pointer(skb_data->wait, wait); ++ tx_req.with_wait = !!wait; + + rtw89_traffic_stats_accu(rtwdev, rtwvif, skb, true, true); + rtw89_wow_parse_akm(rtwdev, skb); + rtw89_core_tx_update_desc_info(rtwdev, &tx_req); + rtw89_core_tx_wake(rtwdev, &tx_req); + ++ rcu_assign_pointer(skb_data->wait, wait); ++ + ret = rtw89_hci_tx_write(rtwdev, &tx_req); + if (ret) { + rtw89_err(rtwdev, "failed to transmit skb to HCI\n"); +diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h +index a9cb47ea0b935..92636cfc5ca58 100644 +--- a/drivers/net/wireless/realtek/rtw89/core.h ++++ b/drivers/net/wireless/realtek/rtw89/core.h +@@ -1211,6 +1211,8 @@ struct rtw89_core_tx_request { + struct rtw89_vif_link *rtwvif_link; + struct rtw89_sta_link *rtwsta_link; + struct rtw89_tx_desc_info desc_info; ++ ++ bool with_wait; + }; + + struct rtw89_txq { +-- +2.51.0 + diff --git a/queue-6.19/wifi-rtw89-debug-fix-memory-leak-in-__print_txpwr_ma.patch b/queue-6.19/wifi-rtw89-debug-fix-memory-leak-in-__print_txpwr_ma.patch new file mode 100644 index 0000000000..1889aa5a83 --- /dev/null +++ b/queue-6.19/wifi-rtw89-debug-fix-memory-leak-in-__print_txpwr_ma.patch @@ -0,0 +1,59 @@ +From 0b8b82418277e6c391985631909c582c00a04fbb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 13:08:34 +0000 +Subject: wifi: rtw89: debug: Fix memory leak in __print_txpwr_map() + +From: Zilin Guan + +[ Upstream commit 6070a44051b1c35714fa130de7726cfe91ca5559 ] + +In __print_txpwr_map(), memory is allocated to bufp via vzalloc(). +If max_valid_addr is 0, the function returns -EOPNOTSUPP immediately +without freeing bufp, leading to a memory leak. + +Since the validation of max_valid_addr does not depend on the allocated +memory, fix this by moving the vzalloc() call after the check. + +Compile tested only. Issue found using a prototype static analysis tool +and code review. + +Fixes: 036042e15770 ("wifi: rtw89: debug: txpwr table supports Wi-Fi 7 chips") +Suggested-by: Zong-Zhe Yang +Signed-off-by: Zilin Guan +Reviewed-by: Zong-Zhe Yang +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/20260116130834.1413924-1-zilin@seu.edu.cn +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtw89/debug.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/wireless/realtek/rtw89/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c +index 1264c2f82600b..987eef8170f2b 100644 +--- a/drivers/net/wireless/realtek/rtw89/debug.c ++++ b/drivers/net/wireless/realtek/rtw89/debug.c +@@ -825,10 +825,6 @@ static ssize_t __print_txpwr_map(struct rtw89_dev *rtwdev, char *buf, size_t buf + s8 *bufp, tmp; + int ret; + +- bufp = vzalloc(map->addr_to - map->addr_from + 4); +- if (!bufp) +- return -ENOMEM; +- + if (path_num == 1) + max_valid_addr = map->addr_to_1ss; + else +@@ -837,6 +833,10 @@ static ssize_t __print_txpwr_map(struct rtw89_dev *rtwdev, char *buf, size_t buf + if (max_valid_addr == 0) + return -EOPNOTSUPP; + ++ bufp = vzalloc(map->addr_to - map->addr_from + 4); ++ if (!bufp) ++ return -ENOMEM; ++ + for (addr = map->addr_from; addr <= max_valid_addr; addr += 4) { + ret = rtw89_mac_txpwr_read32(rtwdev, RTW89_PHY_0, addr, &val); + if (ret) +-- +2.51.0 + diff --git a/queue-6.19/workqueue-process-rescuer-work-items-one-by-one-usin.patch b/queue-6.19/workqueue-process-rescuer-work-items-one-by-one-usin.patch new file mode 100644 index 0000000000..cf38408336 --- /dev/null +++ b/queue-6.19/workqueue-process-rescuer-work-items-one-by-one-usin.patch @@ -0,0 +1,202 @@ +From 0d00f1cede11f07e975779898059fc34db10f1da Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Dec 2025 21:25:18 +0800 +Subject: workqueue: Process rescuer work items one-by-one using a cursor + +From: Lai Jiangshan + +[ Upstream commit e5a30c303b07a4d6083e0f7f051b53add6d93c5d ] + +Previously, the rescuer scanned for all matching work items at once and +processed them within a single rescuer thread, which could cause one +blocking work item to stall all others. + +Make the rescuer process work items one-by-one instead of slurping all +matches in a single pass. + +Break the rescuer loop after finding and processing the first matching +work item, then restart the search to pick up the next. This gives +normal worker threads a chance to process other items which gives them +the opportunity to be processed instead of waiting on the rescuer's +queue and prevents a blocking work item from stalling the rest once +memory pressure is relieved. + +Introduce a dummy cursor work item to avoid potentially O(N^2) +rescans of the work list. The marker records the resume position for +the next scan, eliminating redundant traversals. + +Also introduce RESCUER_BATCH to control the maximum number of work items +the rescuer processes in each turn, and move on to other PWQs when the +limit is reached. + +Cc: ying chen +Reported-by: ying chen +Fixes: e22bee782b3b ("workqueue: implement concurrency managed dynamic worker pool") +Signed-off-by: Lai Jiangshan +Signed-off-by: Tejun Heo +Signed-off-by: Sasha Levin +--- + kernel/workqueue.c | 75 ++++++++++++++++++++++++++++++++++++---------- + 1 file changed, 59 insertions(+), 16 deletions(-) + +diff --git a/kernel/workqueue.c b/kernel/workqueue.c +index 253311af47c6d..2909c19540ed1 100644 +--- a/kernel/workqueue.c ++++ b/kernel/workqueue.c +@@ -117,6 +117,8 @@ enum wq_internal_consts { + MAYDAY_INTERVAL = HZ / 10, /* and then every 100ms */ + CREATE_COOLDOWN = HZ, /* time to breath after fail */ + ++ RESCUER_BATCH = 16, /* process items per turn */ ++ + /* + * Rescue workers are used only on emergencies and shared by + * all cpus. Give MIN_NICE. +@@ -286,6 +288,7 @@ struct pool_workqueue { + struct list_head pending_node; /* LN: node on wq_node_nr_active->pending_pwqs */ + struct list_head pwqs_node; /* WR: node on wq->pwqs */ + struct list_head mayday_node; /* MD: node on wq->maydays */ ++ struct work_struct mayday_cursor; /* L: cursor on pool->worklist */ + + u64 stats[PWQ_NR_STATS]; + +@@ -1120,6 +1123,12 @@ static struct worker *find_worker_executing_work(struct worker_pool *pool, + return NULL; + } + ++static void mayday_cursor_func(struct work_struct *work) ++{ ++ /* should not be processed, only for marking position */ ++ BUG(); ++} ++ + /** + * move_linked_works - move linked works to a list + * @work: start of series of works to be scheduled +@@ -1182,6 +1191,16 @@ static bool assign_work(struct work_struct *work, struct worker *worker, + + lockdep_assert_held(&pool->lock); + ++ /* The cursor work should not be processed */ ++ if (unlikely(work->func == mayday_cursor_func)) { ++ /* only worker_thread() can possibly take this branch */ ++ WARN_ON_ONCE(worker->rescue_wq); ++ if (nextp) ++ *nextp = list_next_entry(work, entry); ++ list_del_init(&work->entry); ++ return false; ++ } ++ + /* + * A single work shouldn't be executed concurrently by multiple workers. + * __queue_work() ensures that @work doesn't jump to a different pool +@@ -3440,22 +3459,30 @@ static int worker_thread(void *__worker) + static bool assign_rescuer_work(struct pool_workqueue *pwq, struct worker *rescuer) + { + struct worker_pool *pool = pwq->pool; ++ struct work_struct *cursor = &pwq->mayday_cursor; + struct work_struct *work, *n; + + /* need rescue? */ + if (!pwq->nr_active || !need_to_create_worker(pool)) + return false; + +- /* +- * Slurp in all works issued via this workqueue and +- * process'em. +- */ +- list_for_each_entry_safe(work, n, &pool->worklist, entry) { +- if (get_work_pwq(work) == pwq && assign_work(work, rescuer, &n)) ++ /* search from the start or cursor if available */ ++ if (list_empty(&cursor->entry)) ++ work = list_first_entry(&pool->worklist, struct work_struct, entry); ++ else ++ work = list_next_entry(cursor, entry); ++ ++ /* find the next work item to rescue */ ++ list_for_each_entry_safe_from(work, n, &pool->worklist, entry) { ++ if (get_work_pwq(work) == pwq && assign_work(work, rescuer, &n)) { + pwq->stats[PWQ_STAT_RESCUED]++; ++ /* put the cursor for next search */ ++ list_move_tail(&cursor->entry, &n->entry); ++ return true; ++ } + } + +- return !list_empty(&rescuer->scheduled); ++ return false; + } + + /** +@@ -3512,6 +3539,7 @@ static int rescuer_thread(void *__rescuer) + struct pool_workqueue *pwq = list_first_entry(&wq->maydays, + struct pool_workqueue, mayday_node); + struct worker_pool *pool = pwq->pool; ++ unsigned int count = 0; + + __set_current_state(TASK_RUNNING); + list_del_init(&pwq->mayday_node); +@@ -3524,19 +3552,16 @@ static int rescuer_thread(void *__rescuer) + + WARN_ON_ONCE(!list_empty(&rescuer->scheduled)); + +- if (assign_rescuer_work(pwq, rescuer)) { ++ while (assign_rescuer_work(pwq, rescuer)) { + process_scheduled_works(rescuer); + + /* +- * The above execution of rescued work items could +- * have created more to rescue through +- * pwq_activate_first_inactive() or chained +- * queueing. Let's put @pwq back on mayday list so +- * that such back-to-back work items, which may be +- * being used to relieve memory pressure, don't +- * incur MAYDAY_INTERVAL delay inbetween. ++ * If the per-turn work item limit is reached and other ++ * PWQs are in mayday, requeue mayday for this PWQ and ++ * let the rescuer handle the other PWQs first. + */ +- if (pwq->nr_active && need_to_create_worker(pool)) { ++ if (++count > RESCUER_BATCH && !list_empty(&pwq->wq->maydays) && ++ pwq->nr_active && need_to_create_worker(pool)) { + raw_spin_lock(&wq_mayday_lock); + /* + * Queue iff somebody else hasn't queued it already. +@@ -3546,9 +3571,14 @@ static int rescuer_thread(void *__rescuer) + list_add_tail(&pwq->mayday_node, &wq->maydays); + } + raw_spin_unlock(&wq_mayday_lock); ++ break; + } + } + ++ /* The cursor can not be left behind without the rescuer watching it. */ ++ if (!list_empty(&pwq->mayday_cursor.entry) && list_empty(&pwq->mayday_node)) ++ list_del_init(&pwq->mayday_cursor.entry); ++ + /* + * Leave this pool. Notify regular workers; otherwise, we end up + * with 0 concurrency and stalling the execution. +@@ -5167,6 +5197,19 @@ static void init_pwq(struct pool_workqueue *pwq, struct workqueue_struct *wq, + INIT_LIST_HEAD(&pwq->pwqs_node); + INIT_LIST_HEAD(&pwq->mayday_node); + kthread_init_work(&pwq->release_work, pwq_release_workfn); ++ ++ /* ++ * Set the dummy cursor work with valid function and get_work_pwq(). ++ * ++ * The cursor work should only be in the pwq->pool->worklist, and ++ * should not be treated as a processable work item. ++ * ++ * WORK_STRUCT_PENDING and WORK_STRUCT_INACTIVE just make it less ++ * surprise for kernel debugging tools and reviewers. ++ */ ++ INIT_WORK(&pwq->mayday_cursor, mayday_cursor_func); ++ atomic_long_set(&pwq->mayday_cursor.data, (unsigned long)pwq | ++ WORK_STRUCT_PENDING | WORK_STRUCT_PWQ | WORK_STRUCT_INACTIVE); + } + + /* sync @pwq with the current state of its associated wq and link it */ +-- +2.51.0 + diff --git a/queue-6.19/x86-cpu-amd-correct-the-microcode-table-for-zenbleed.patch b/queue-6.19/x86-cpu-amd-correct-the-microcode-table-for-zenbleed.patch new file mode 100644 index 0000000000..394fd870bd --- /dev/null +++ b/queue-6.19/x86-cpu-amd-correct-the-microcode-table-for-zenbleed.patch @@ -0,0 +1,84 @@ +From 109f55f00a732c903a337fcacdb72fa9a29e79b5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 26 Nov 2025 13:03:52 +0000 +Subject: x86/cpu/amd: Correct the microcode table for Zenbleed + +From: Andrew Cooper + +[ Upstream commit fb7bfa31b8e8569f154f2fe0ea6c2f03c0f087aa ] + +The good revisions are tied to exact steppings, meaning it's not valid to +match on model number alone, let alone a range. + +This is probably only a latent issue. From public microcode archives, the +following CPUs exist 17-30-00, 17-60-00, 17-70-00 and would be captured by the +model ranges. They're likely pre-production steppings, and likely didn't get +Zenbleed microcode, but it's still incorrect to compare them to a different +steppings revision. + +Either way, convert the logic to use x86_match_min_microcode_rev(), which is +the preferred mechanism. + +Fixes: 522b1d69219d ("x86/cpu/amd: Add a Zenbleed fix") +Signed-off-by: Andrew Cooper +Signed-off-by: Ingo Molnar +Cc: Borislav Petkov +Cc: Mario Limonciello +Cc: x86@kernel.org +Link: https://patch.msgid.link/20251126130352.880424-1-andrew.cooper3@citrix.com +Signed-off-by: Sasha Levin +--- + arch/x86/kernel/cpu/amd.c | 30 +++++++++--------------------- + 1 file changed, 9 insertions(+), 21 deletions(-) + +diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c +index bc94ff1e250ad..86059f2c0fcd4 100644 +--- a/arch/x86/kernel/cpu/amd.c ++++ b/arch/x86/kernel/cpu/amd.c +@@ -951,26 +951,14 @@ static void init_amd_zen1(struct cpuinfo_x86 *c) + } + } + +-static bool cpu_has_zenbleed_microcode(void) +-{ +- u32 good_rev = 0; +- +- switch (boot_cpu_data.x86_model) { +- case 0x30 ... 0x3f: good_rev = 0x0830107b; break; +- case 0x60 ... 0x67: good_rev = 0x0860010c; break; +- case 0x68 ... 0x6f: good_rev = 0x08608107; break; +- case 0x70 ... 0x7f: good_rev = 0x08701033; break; +- case 0xa0 ... 0xaf: good_rev = 0x08a00009; break; +- +- default: +- return false; +- } +- +- if (boot_cpu_data.microcode < good_rev) +- return false; +- +- return true; +-} ++static const struct x86_cpu_id amd_zenbleed_microcode[] = { ++ ZEN_MODEL_STEP_UCODE(0x17, 0x31, 0x0, 0x0830107b), ++ ZEN_MODEL_STEP_UCODE(0x17, 0x60, 0x1, 0x0860010c), ++ ZEN_MODEL_STEP_UCODE(0x17, 0x68, 0x1, 0x08608107), ++ ZEN_MODEL_STEP_UCODE(0x17, 0x71, 0x0, 0x08701033), ++ ZEN_MODEL_STEP_UCODE(0x17, 0xa0, 0x0, 0x08a00009), ++ {} ++}; + + static void zen2_zenbleed_check(struct cpuinfo_x86 *c) + { +@@ -980,7 +968,7 @@ static void zen2_zenbleed_check(struct cpuinfo_x86 *c) + if (!cpu_has(c, X86_FEATURE_AVX)) + return; + +- if (!cpu_has_zenbleed_microcode()) { ++ if (!x86_match_min_microcode_rev(amd_zenbleed_microcode)) { + pr_notice_once("Zenbleed: please update your microcode for the most optimal fix\n"); + msr_set_bit(MSR_AMD64_DE_CFG, MSR_AMD64_DE_CFG_ZEN2_FP_BACKUP_FIX_BIT); + } else { +-- +2.51.0 + diff --git a/queue-6.19/x86-fgraph-bpf-switch-kprobe_multi-program-stack-unw.patch b/queue-6.19/x86-fgraph-bpf-switch-kprobe_multi-program-stack-unw.patch new file mode 100644 index 0000000000..cfc677f6d2 --- /dev/null +++ b/queue-6.19/x86-fgraph-bpf-switch-kprobe_multi-program-stack-unw.patch @@ -0,0 +1,111 @@ +From fce715d38d81343af7defe6ff01cdf3fc40dcf5a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 22:18:33 +0100 +Subject: x86/fgraph,bpf: Switch kprobe_multi program stack unwind to hw_regs + path +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jiri Olsa + +[ Upstream commit aea251799998aa1b78eacdfb308f18ea114ea5b3 ] + +Mahe reported missing function from stack trace on top of kprobe +multi program. The missing function is the very first one in the +stacktrace, the one that the bpf program is attached to. + + # bpftrace -e 'kprobe:__x64_sys_newuname* { print(kstack)}' + Attaching 1 probe... + + do_syscall_64+134 + entry_SYSCALL_64_after_hwframe+118 + + ('*' is used for kprobe_multi attachment) + +The reason is that the previous change (the Fixes commit) fixed +stack unwind for tracepoint, but removed attached function address +from the stack trace on top of kprobe multi programs, which I also +overlooked in the related test (check following patch). + +The tracepoint and kprobe_multi have different stack setup, but use +same unwind path. I think it's better to keep the previous change, +which fixed tracepoint unwind and instead change the kprobe multi +unwind as explained below. + +The bpf program stack unwind calls perf_callchain_kernel for kernel +portion and it follows two unwind paths based on X86_EFLAGS_FIXED +bit in pt_regs.flags. + +When the bit set we unwind from stack represented by pt_regs argument, +otherwise we unwind currently executed stack up to 'first_frame' +boundary. + +The 'first_frame' value is taken from regs.rsp value, but ftrace_caller +and ftrace_regs_caller (ftrace trampoline) functions set the regs.rsp +to the previous stack frame, so we skip the attached function entry. + +If we switch kprobe_multi unwind to use the X86_EFLAGS_FIXED bit, +we set the start of the unwind to the attached function address. +As another benefit we also cut extra unwind cycles needed to reach +the 'first_frame' boundary. + +The speedup can be measured with trigger bench for kprobe_multi +program and stacktrace support. + +- trigger bench with stacktrace on current code: + + kprobe-multi : 0.810 ± 0.001M/s + kretprobe-multi: 0.808 ± 0.001M/s + +- and with the fix: + + kprobe-multi : 1.264 ± 0.001M/s + kretprobe-multi: 1.401 ± 0.002M/s + +With the fix, the entry probe stacktrace: + + # bpftrace -e 'kprobe:__x64_sys_newuname* { print(kstack)}' + Attaching 1 probe... + + __x64_sys_newuname+9 + do_syscall_64+134 + entry_SYSCALL_64_after_hwframe+118 + +The return probe skips the attached function, because it's no longer +on the stack at the point of the unwind and this way is the same how +standard kretprobe works. + + # bpftrace -e 'kretprobe:__x64_sys_newuname* { print(kstack)}' + Attaching 1 probe... + + do_syscall_64+134 + entry_SYSCALL_64_after_hwframe+118 + +Fixes: 6d08340d1e35 ("Revert "perf/x86: Always store regs->ip in perf_callchain_kernel()"") +Reported-by: Mahe Tardy +Signed-off-by: Jiri Olsa +Signed-off-by: Andrii Nakryiko +Acked-by: Steven Rostedt (Google) +Link: https://lore.kernel.org/bpf/20260126211837.472802-3-jolsa@kernel.org +Signed-off-by: Sasha Levin +--- + arch/x86/include/asm/ftrace.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h +index b08c95872eed9..c56e1e63b8932 100644 +--- a/arch/x86/include/asm/ftrace.h ++++ b/arch/x86/include/asm/ftrace.h +@@ -57,7 +57,7 @@ arch_ftrace_get_regs(struct ftrace_regs *fregs) + } + + #define arch_ftrace_partial_regs(regs) do { \ +- regs->flags &= ~X86_EFLAGS_FIXED; \ ++ regs->flags |= X86_EFLAGS_FIXED; \ + regs->cs = __KERNEL_CS; \ + } while (0) + +-- +2.51.0 + diff --git a/queue-6.19/x86-fgraph-fix-return_to_handler-regs.rsp-value.patch b/queue-6.19/x86-fgraph-fix-return_to_handler-regs.rsp-value.patch new file mode 100644 index 0000000000..013b4dafbf --- /dev/null +++ b/queue-6.19/x86-fgraph-fix-return_to_handler-regs.rsp-value.patch @@ -0,0 +1,66 @@ +From 4fa37fe51d15a6d1291fd9d7c26fad0e10c7e4b8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 22:18:32 +0100 +Subject: x86/fgraph: Fix return_to_handler regs.rsp value + +From: Jiri Olsa + +[ Upstream commit 8bc11700e0d23d4fdb7d8d5a73b2e95de427cabc ] + +The previous change (Fixes commit) messed up the rsp register value, +which is wrong because it's already adjusted with FRAME_SIZE, we need +the original rsp value. + +This change does not affect fprobe current kernel unwind, the !perf_hw_regs +path perf_callchain_kernel: + + if (perf_hw_regs(regs)) { + if (perf_callchain_store(entry, regs->ip)) + return; + unwind_start(&state, current, regs, NULL); + } else { + unwind_start(&state, current, NULL, (void *)regs->sp); + } + +which uses pt_regs.sp as first_frame boundary (FRAME_SIZE shift makes +no difference, unwind stil stops at the right frame). + +This change fixes the other path when we want to unwind directly from +pt_regs sp/fp/ip state, which is coming in following change. + +Fixes: 20a0bc10272f ("x86/fgraph,bpf: Fix stack ORC unwind from kprobe_multi return probe") +Signed-off-by: Jiri Olsa +Signed-off-by: Andrii Nakryiko +Reviewed-by: Steven Rostedt (Google) +Link: https://lore.kernel.org/bpf/20260126211837.472802-2-jolsa@kernel.org +Signed-off-by: Sasha Levin +--- + arch/x86/kernel/ftrace_64.S | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/arch/x86/kernel/ftrace_64.S b/arch/x86/kernel/ftrace_64.S +index a132608265f6c..62c1c93aa1c6a 100644 +--- a/arch/x86/kernel/ftrace_64.S ++++ b/arch/x86/kernel/ftrace_64.S +@@ -364,6 +364,9 @@ SYM_CODE_START(return_to_handler) + UNWIND_HINT_UNDEFINED + ANNOTATE_NOENDBR + ++ /* Store original rsp for pt_regs.sp value. */ ++ movq %rsp, %rdi ++ + /* Restore return_to_handler value that got eaten by previous ret instruction. */ + subq $8, %rsp + UNWIND_HINT_FUNC +@@ -374,7 +377,7 @@ SYM_CODE_START(return_to_handler) + movq %rax, RAX(%rsp) + movq %rdx, RDX(%rsp) + movq %rbp, RBP(%rsp) +- movq %rsp, RSP(%rsp) ++ movq %rdi, RSP(%rsp) + movq %rsp, %rdi + + call ftrace_return_to_handler +-- +2.51.0 + diff --git a/queue-6.19/x86-hyperv-fix-smp_ops-build-failure-on-up-kernels.patch b/queue-6.19/x86-hyperv-fix-smp_ops-build-failure-on-up-kernels.patch new file mode 100644 index 0000000000..d82eea8ac1 --- /dev/null +++ b/queue-6.19/x86-hyperv-fix-smp_ops-build-failure-on-up-kernels.patch @@ -0,0 +1,57 @@ +From b54aef86c6c9ef654da8ba6c06bfc049ced6af0b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 11:35:20 +0100 +Subject: x86/hyperv: Fix smp_ops build failure on UP kernels +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ingo Molnar + +[ Upstream commit ac059ae422d7d05ed9d62970a30fa3b95870b967 ] + +CI testing found this build failure: + + arch/x86/hyperv/hv_crash.c:631:9: error: ‘smp_ops’ undeclared (first use in this function) + +And I bisected it back to the initial commit that enabled this feature: + + 77c860d2dbb72d1f3c6a2e882a07d19eca399db5 is the first bad commit + commit 77c860d2dbb72d1f3c6a2e882a07d19eca399db5 (HEAD) + Author: Mukesh Rathor + Date: Mon Oct 6 15:42:08 2025 -0700 + + x86/hyperv: Enable build of hypervisor crashdump collection files + +Hyperv should probably be limited to SMP kernels, as nobody +appears to be testing it on UP kernels. + +Until then, fix the smp_ops assumption. Build tested only. + +Fixes: 77c860d2dbb72 ("x86/hyperv: Enable build of hypervisor crashdump collection files") +Cc: Mukesh Rathor +Cc: Wei Liu +Cc: linux-kernel@vger.kernel.org +Signed-off-by: Ingo Molnar +Signed-off-by: Sasha Levin +--- + arch/x86/hyperv/hv_crash.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/x86/hyperv/hv_crash.c b/arch/x86/hyperv/hv_crash.c +index c0e22921ace1a..a78e4fed57203 100644 +--- a/arch/x86/hyperv/hv_crash.c ++++ b/arch/x86/hyperv/hv_crash.c +@@ -628,7 +628,9 @@ void hv_root_crash_init(void) + if (rc) + goto err_out; + ++#ifdef CONFIG_SMP + smp_ops.crash_stop_other_cpus = hv_crash_stop_other_cpus; ++#endif + + crash_kexec_post_notifiers = true; + hv_crash_enabled = true; +-- +2.51.0 + diff --git a/queue-6.19/xdrgen-fix-struct-prefix-for-typedef-types-in-progra.patch b/queue-6.19/xdrgen-fix-struct-prefix-for-typedef-types-in-progra.patch new file mode 100644 index 0000000000..f9c4905db3 --- /dev/null +++ b/queue-6.19/xdrgen-fix-struct-prefix-for-typedef-types-in-progra.patch @@ -0,0 +1,83 @@ +From 832235ba57ae5d885a50aa52514d924cb6eda3fc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Dec 2025 11:15:32 -0500 +Subject: xdrgen: Fix struct prefix for typedef types in program wrappers + +From: Chuck Lever + +[ Upstream commit bf0fe9ad3d597d8e1378dc9953ca96dfc3addb2b ] + +The program templates for decoder/argument.j2 and encoder/result.j2 +unconditionally add 'struct' prefix to all types. This is incorrect +when an RPC protocol specification lists a typedef'd basic type or +an enum as a procedure argument or result (e.g., NFSv2's fhandle or +stat), resulting in compiler errors when building generated C code. + +Fixes: 4b132aacb076 ("tools: Add xdrgen") +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + tools/net/sunrpc/xdrgen/generators/__init__.py | 3 ++- + .../sunrpc/xdrgen/templates/C/program/decoder/argument.j2 | 4 ++++ + .../net/sunrpc/xdrgen/templates/C/program/encoder/result.j2 | 6 ++++++ + 3 files changed, 12 insertions(+), 1 deletion(-) + +diff --git a/tools/net/sunrpc/xdrgen/generators/__init__.py b/tools/net/sunrpc/xdrgen/generators/__init__.py +index e22632cf38fbe..1d577a986c6cf 100644 +--- a/tools/net/sunrpc/xdrgen/generators/__init__.py ++++ b/tools/net/sunrpc/xdrgen/generators/__init__.py +@@ -6,7 +6,7 @@ from pathlib import Path + from jinja2 import Environment, FileSystemLoader, Template + + from xdr_ast import _XdrAst, Specification, _RpcProgram, _XdrTypeSpecifier +-from xdr_ast import public_apis, pass_by_reference, get_header_name ++from xdr_ast import public_apis, pass_by_reference, structs, get_header_name + from xdr_parse import get_xdr_annotate + + +@@ -25,6 +25,7 @@ def create_jinja2_environment(language: str, xdr_type: str) -> Environment: + environment.globals["annotate"] = get_xdr_annotate() + environment.globals["public_apis"] = public_apis + environment.globals["pass_by_reference"] = pass_by_reference ++ environment.globals["structs"] = structs + return environment + case _: + raise NotImplementedError("Language not supported") +diff --git a/tools/net/sunrpc/xdrgen/templates/C/program/decoder/argument.j2 b/tools/net/sunrpc/xdrgen/templates/C/program/decoder/argument.j2 +index 0b1709cca0d4a..19b219dd276d3 100644 +--- a/tools/net/sunrpc/xdrgen/templates/C/program/decoder/argument.j2 ++++ b/tools/net/sunrpc/xdrgen/templates/C/program/decoder/argument.j2 +@@ -14,7 +14,11 @@ bool {{ program }}_svc_decode_{{ argument }}(struct svc_rqst *rqstp, struct xdr_ + {% if argument == 'void' %} + return xdrgen_decode_void(xdr); + {% else %} ++{% if argument in structs %} + struct {{ argument }} *argp = rqstp->rq_argp; ++{% else %} ++ {{ argument }} *argp = rqstp->rq_argp; ++{% endif %} + + return xdrgen_decode_{{ argument }}(xdr, argp); + {% endif %} +diff --git a/tools/net/sunrpc/xdrgen/templates/C/program/encoder/result.j2 b/tools/net/sunrpc/xdrgen/templates/C/program/encoder/result.j2 +index 6fc61a5d47b7f..746592cfda562 100644 +--- a/tools/net/sunrpc/xdrgen/templates/C/program/encoder/result.j2 ++++ b/tools/net/sunrpc/xdrgen/templates/C/program/encoder/result.j2 +@@ -14,8 +14,14 @@ bool {{ program }}_svc_encode_{{ result }}(struct svc_rqst *rqstp, struct xdr_st + {% if result == 'void' %} + return xdrgen_encode_void(xdr); + {% else %} ++{% if result in structs %} + struct {{ result }} *resp = rqstp->rq_resp; + + return xdrgen_encode_{{ result }}(xdr, resp); ++{% else %} ++ {{ result }} *resp = rqstp->rq_resp; ++ ++ return xdrgen_encode_{{ result }}(xdr, *resp); ++{% endif %} + {% endif %} + } +-- +2.51.0 + diff --git a/queue-6.19/xdrgen-initialize-data-pointer-for-zero-length-items.patch b/queue-6.19/xdrgen-initialize-data-pointer-for-zero-length-items.patch new file mode 100644 index 0000000000..b6d2dfe2ef --- /dev/null +++ b/queue-6.19/xdrgen-initialize-data-pointer-for-zero-length-items.patch @@ -0,0 +1,70 @@ +From 42a5f1575512474d7322a1f4c14b3000ea6beccf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 10:41:09 -0500 +Subject: xdrgen: Initialize data pointer for zero-length items + +From: Chuck Lever + +[ Upstream commit 27b0fcae8f535fb882b1876227a935dcfdf576aa ] + +The xdrgen decoders for strings and opaque data had an +optimization that skipped calling xdr_inline_decode() when the +item length was zero. This left the data pointer uninitialized, +which could lead to unpredictable behavior when callers access +it. + +Remove the zero-length check and always call xdr_inline_decode(). +When passed a length of zero, xdr_inline_decode() returns the +current buffer position, which is valid and matches the behavior +of hand-coded XDR decoders throughout the kernel. + +Fixes: 4b132aacb076 ("tools: Add xdrgen") +Reviewed-by: Jeff Layton +Reviewed-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + include/linux/sunrpc/xdrgen/_builtins.h | 20 ++++++++------------ + 1 file changed, 8 insertions(+), 12 deletions(-) + +diff --git a/include/linux/sunrpc/xdrgen/_builtins.h b/include/linux/sunrpc/xdrgen/_builtins.h +index 66ca3ece951ab..a5ab75d2db044 100644 +--- a/include/linux/sunrpc/xdrgen/_builtins.h ++++ b/include/linux/sunrpc/xdrgen/_builtins.h +@@ -188,12 +188,10 @@ xdrgen_decode_string(struct xdr_stream *xdr, string *ptr, u32 maxlen) + return false; + if (unlikely(maxlen && len > maxlen)) + return false; +- if (len != 0) { +- p = xdr_inline_decode(xdr, len); +- if (unlikely(!p)) +- return false; +- ptr->data = (unsigned char *)p; +- } ++ p = xdr_inline_decode(xdr, len); ++ if (unlikely(!p)) ++ return false; ++ ptr->data = (unsigned char *)p; + ptr->len = len; + return true; + } +@@ -219,12 +217,10 @@ xdrgen_decode_opaque(struct xdr_stream *xdr, opaque *ptr, u32 maxlen) + return false; + if (unlikely(maxlen && len > maxlen)) + return false; +- if (len != 0) { +- p = xdr_inline_decode(xdr, len); +- if (unlikely(!p)) +- return false; +- ptr->data = (u8 *)p; +- } ++ p = xdr_inline_decode(xdr, len); ++ if (unlikely(!p)) ++ return false; ++ ptr->data = (u8 *)p; + ptr->len = len; + return true; + } +-- +2.51.0 + diff --git a/queue-6.19/xdrgen-remove-inclusion-of-nlm4.h-header.patch b/queue-6.19/xdrgen-remove-inclusion-of-nlm4.h-header.patch new file mode 100644 index 0000000000..8ffa0371f0 --- /dev/null +++ b/queue-6.19/xdrgen-remove-inclusion-of-nlm4.h-header.patch @@ -0,0 +1,35 @@ +From 511d366357da949d4337cae6ecb022a2a1c82406 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 22 Dec 2025 09:44:29 -0500 +Subject: xdrgen: Remove inclusion of nlm4.h header + +From: Chuck Lever + +[ Upstream commit eb1f3b55ac6202a013daf14ed508066947cdafa8 ] + +The client-side source code template mistakenly includes the +nlm4.h header file, which is specific to the NLM protocol and +should not be present in the generic template that generates +client stubs for all XDR-based protocols. + +Fixes: 903a7d37d9ea ("xdrgen: Update the files included in client-side source code") +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + tools/net/sunrpc/xdrgen/templates/C/source_top/client.j2 | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/tools/net/sunrpc/xdrgen/templates/C/source_top/client.j2 b/tools/net/sunrpc/xdrgen/templates/C/source_top/client.j2 +index c5518c519854a..df3598c38b2c2 100644 +--- a/tools/net/sunrpc/xdrgen/templates/C/source_top/client.j2 ++++ b/tools/net/sunrpc/xdrgen/templates/C/source_top/client.j2 +@@ -8,6 +8,5 @@ + #include + #include + #include +-#include + + #include +-- +2.51.0 + diff --git a/queue-6.19/xen-virtio-don-t-use-grant-dma-ops-when-running-as-d.patch b/queue-6.19/xen-virtio-don-t-use-grant-dma-ops-when-running-as-d.patch new file mode 100644 index 0000000000..c44eb7070f --- /dev/null +++ b/queue-6.19/xen-virtio-don-t-use-grant-dma-ops-when-running-as-d.patch @@ -0,0 +1,45 @@ +From e7ab57317ad6e47072ee8e6200b1eaaa79ea84ed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Jan 2026 17:36:50 +0000 +Subject: xen/virtio: Don't use grant-dma-ops when running as Dom0 + +From: Teddy Astie + +[ Upstream commit dc8ea8714311e549ee93a2b0bdd5487d20bfadbf ] + +Dom0 inherit devices from the machine and is usually in PV mode. +If we are running in a virtual that has virtio devices, these devices +would be considered as using grants with Dom0 as backend, while being +the said Dom0 itself, while we want to use these devices like regular +PCI devices. + +Fix this by preventing grant-dma-ops from being used when running as Dom0 +(initial domain). We still keep the device-tree logic as-is. + +Signed-off-by: Teddy Astie +Fixes: 61367688f1fb0 ("xen/virtio: enable grant based virtio on x86") +Reviewed-by: Juergen Gross +Signed-off-by: Juergen Gross +Message-ID: <6698564dd2270a9f7377b78ebfb20cb425cabbe8.1767720955.git.teddy.astie@vates.tech> +Signed-off-by: Sasha Levin +--- + drivers/xen/grant-dma-ops.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/xen/grant-dma-ops.c b/drivers/xen/grant-dma-ops.c +index 14077d23f2a19..c2603e7001786 100644 +--- a/drivers/xen/grant-dma-ops.c ++++ b/drivers/xen/grant-dma-ops.c +@@ -366,7 +366,8 @@ static int xen_grant_init_backend_domid(struct device *dev, + if (np) { + ret = xen_dt_grant_init_backend_domid(dev, np, backend_domid); + of_node_put(np); +- } else if (IS_ENABLED(CONFIG_XEN_VIRTIO_FORCE_GRANT) || xen_pv_domain()) { ++ } else if (!xen_initial_domain() && ++ (IS_ENABLED(CONFIG_XEN_VIRTIO_FORCE_GRANT) || xen_pv_domain())) { + dev_info(dev, "Using dom0 as backend\n"); + *backend_domid = 0; + ret = 0; +-- +2.51.0 + diff --git a/queue-6.19/xfrm-fix-ip_rt_bug-race-in-icmp_route_lookup-reverse.patch b/queue-6.19/xfrm-fix-ip_rt_bug-race-in-icmp_route_lookup-reverse.patch new file mode 100644 index 0000000000..521e6522c6 --- /dev/null +++ b/queue-6.19/xfrm-fix-ip_rt_bug-race-in-icmp_route_lookup-reverse.patch @@ -0,0 +1,100 @@ +From 3e3125a949bcb80c8bcdd0c31ecaf8d5f2aec39d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 13:02:19 +0800 +Subject: xfrm: fix ip_rt_bug race in icmp_route_lookup reverse path + +From: Jiayuan Chen + +[ Upstream commit 81b84de32bb27ae1ae2eb9acf0420e9d0d14bf00 ] + +icmp_route_lookup() performs multiple route lookups to find a suitable +route for sending ICMP error messages, with special handling for XFRM +(IPsec) policies. + +The lookup sequence is: +1. First, lookup output route for ICMP reply (dst = original src) +2. Pass through xfrm_lookup() for policy check +3. If blocked (-EPERM) or dst is not local, enter "reverse path" +4. In reverse path, call xfrm_decode_session_reverse() to get fl4_dec + which reverses the original packet's flow (saddr<->daddr swapped) +5. If fl4_dec.saddr is local (we are the original destination), use + __ip_route_output_key() for output route lookup +6. If fl4_dec.saddr is NOT local (we are a forwarding node), use + ip_route_input() to simulate the reverse packet's input path +7. Finally, pass rt2 through xfrm_lookup() with XFRM_LOOKUP_ICMP flag + +The bug occurs in step 6: ip_route_input() is called with fl4_dec.daddr +(original packet's source) as destination. If this address becomes local +between the initial check and ip_route_input() call (e.g., due to +concurrent "ip addr add"), ip_route_input() returns a LOCAL route with +dst.output set to ip_rt_bug. + +This route is then used for ICMP output, causing dst_output() to call +ip_rt_bug(), triggering a WARN_ON: + + ------------[ cut here ]------------ + WARNING: net/ipv4/route.c:1275 at ip_rt_bug+0x21/0x30, CPU#1 + Call Trace: + + ip_push_pending_frames+0x202/0x240 + icmp_push_reply+0x30d/0x430 + __icmp_send+0x1149/0x24f0 + ip_options_compile+0xa2/0xd0 + ip_rcv_finish_core+0x829/0x1950 + ip_rcv+0x2d7/0x420 + __netif_receive_skb_one_core+0x185/0x1f0 + netif_receive_skb+0x90/0x450 + tun_get_user+0x3413/0x3fb0 + tun_chr_write_iter+0xe4/0x220 + ... + +Fix this by checking rt2->rt_type after ip_route_input(). If it's +RTN_LOCAL, the route cannot be used for output, so treat it as an error. + +The reproducer requires kernel modification to widen the race window, +making it unsuitable as a selftest. It is available at: + + https://gist.github.com/mrpre/eae853b72ac6a750f5d45d64ddac1e81 + +Reported-by: syzbot+e738404dcd14b620923c@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/000000000000b1060905eada8881@google.com/T/ +Closes: https://lore.kernel.org/r/20260128090523.356953-1-jiayuan.chen@linux.dev +Fixes: 8b7817f3a959 ("[IPSEC]: Add ICMP host relookup support") +Signed-off-by: Jiayuan Chen +Signed-off-by: Jiayuan Chen +Link: https://patch.msgid.link/20260206050220.59642-1-jiayuan.chen@linux.dev +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/ipv4/icmp.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c +index 4acbbc703e798..a2cff16668d72 100644 +--- a/net/ipv4/icmp.c ++++ b/net/ipv4/icmp.c +@@ -554,6 +554,21 @@ static struct rtable *icmp_route_lookup(struct net *net, struct flowi4 *fl4, + /* steal dst entry from skb_in, don't drop refcnt */ + skb_dstref_steal(skb_in); + skb_dstref_restore(skb_in, orefdst); ++ ++ /* ++ * At this point, fl4_dec.daddr should NOT be local (we ++ * checked fl4_dec.saddr above). However, a race condition ++ * may occur if the address is added to the interface ++ * concurrently. In that case, ip_route_input() returns a ++ * LOCAL route with dst.output=ip_rt_bug, which must not ++ * be used for output. ++ */ ++ if (!err && rt2 && rt2->rt_type == RTN_LOCAL) { ++ net_warn_ratelimited("detected local route for %pI4 during ICMP sending, src %pI4\n", ++ &fl4_dec.daddr, &fl4_dec.saddr); ++ dst_release(&rt2->dst); ++ err = -EINVAL; ++ } + } + + if (err) +-- +2.51.0 + diff --git a/queue-6.6/acpica-fix-null-pointer-dereference-in-acpi_ev_addre.patch b/queue-6.6/acpica-fix-null-pointer-dereference-in-acpi_ev_addre.patch new file mode 100644 index 0000000000..5cc7118046 --- /dev/null +++ b/queue-6.6/acpica-fix-null-pointer-dereference-in-acpi_ev_addre.patch @@ -0,0 +1,40 @@ +From 174b4941304e45a5121fef5b3acbb94962d5fcb9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 13:20:17 +0100 +Subject: ACPICA: Fix NULL pointer dereference in + acpi_ev_address_space_dispatch() + +From: Alexey Simakov + +[ Upstream commit f851e03bce968ff9b3faad1b616062e1244fd38d ] + +Cover a missed execution path with a new check. + +Fixes: 0acf24ad7e10 ("ACPICA: Add support for PCC Opregion special context data") +Link: https://github.com/acpica/acpica/commit/f421dd9dd897 +Signed-off-by: Alexey Simakov +Signed-off-by: Rafael J. Wysocki +Link: https://patch.msgid.link/3030574.e9J7NaK4W3@rafael.j.wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/acpica/evregion.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c +index cf53b9535f18e..7788c27ccf461 100644 +--- a/drivers/acpi/acpica/evregion.c ++++ b/drivers/acpi/acpica/evregion.c +@@ -163,7 +163,9 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, + return_ACPI_STATUS(AE_NOT_EXIST); + } + +- if (region_obj->region.space_id == ACPI_ADR_SPACE_PLATFORM_COMM) { ++ if (field_obj ++ && region_obj->region.space_id == ++ ACPI_ADR_SPACE_PLATFORM_COMM) { + struct acpi_pcc_info *ctx = + handler_desc->address_space.context; + +-- +2.51.0 + diff --git a/queue-6.6/arm-dts-allwinner-sun5i-a13-utoo-p66-delete-power-gp.patch b/queue-6.6/arm-dts-allwinner-sun5i-a13-utoo-p66-delete-power-gp.patch new file mode 100644 index 0000000000..00dee7065c --- /dev/null +++ b/queue-6.6/arm-dts-allwinner-sun5i-a13-utoo-p66-delete-power-gp.patch @@ -0,0 +1,46 @@ +From 6b54974026a9b6b6199c20b4792ba36115717bc9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 25 Dec 2025 18:36:14 +0800 +Subject: ARM: dts: allwinner: sun5i-a13-utoo-p66: delete "power-gpios" + property + +From: Chen-Yu Tsai + +[ Upstream commit 0b2761eb1287bd9f62367cccf6626eb3107cef6f ] + +The P66's device tree includes the reference design dtsi files, which +defines a node and properties for the touchpanel in the common design. +The P66 dts file then overrides all the properties to match its own +design, but as the touchpanel model is different, a different schema +is matched. This other schema uses a different name for the GPIO. + +The original submission added the correct GPIO property, but did not +delete the one inherited from the reference design, causing validation +errors. + +Explicitly delete the incorrect GPIO property. + +Fixes: 2a53aff27236 ("ARM: dts: sun5i: Enable touchscreen on Utoo P66") +Reviewed-by: Jernej Skrabec +Link: https://patch.msgid.link/20251225103616.3203473-4-wens@kernel.org +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Sasha Levin +--- + arch/arm/boot/dts/allwinner/sun5i-a13-utoo-p66.dts | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/boot/dts/allwinner/sun5i-a13-utoo-p66.dts b/arch/arm/boot/dts/allwinner/sun5i-a13-utoo-p66.dts +index be486d28d04fa..428cab5a0e906 100644 +--- a/arch/arm/boot/dts/allwinner/sun5i-a13-utoo-p66.dts ++++ b/arch/arm/boot/dts/allwinner/sun5i-a13-utoo-p66.dts +@@ -102,6 +102,7 @@ &touchscreen { + /* The P66 uses a different EINT then the reference design */ + interrupts = <6 9 IRQ_TYPE_EDGE_FALLING>; /* EINT9 (PG9) */ + /* The icn8318 binding expects wake-gpios instead of power-gpios */ ++ /delete-property/ power-gpios; + wake-gpios = <&pio 1 3 GPIO_ACTIVE_HIGH>; /* PB3 */ + touchscreen-size-x = <800>; + touchscreen-size-y = <480>; +-- +2.51.0 + diff --git a/queue-6.6/arm-dts-lpc32xx-add-clocks-property-to-motor-control.patch b/queue-6.6/arm-dts-lpc32xx-add-clocks-property-to-motor-control.patch new file mode 100644 index 0000000000..05bed2b852 --- /dev/null +++ b/queue-6.6/arm-dts-lpc32xx-add-clocks-property-to-motor-control.patch @@ -0,0 +1,35 @@ +From 22b49db63c0447aba883e8eb8d6fbdd7ecb05db8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Dec 2025 00:49:07 +0200 +Subject: arm: dts: lpc32xx: add clocks property to Motor Control PWM device + tree node + +From: Vladimir Zapolskiy + +[ Upstream commit 71630e581a0e34c03757f5c1706f57c853b92555 ] + +Motor Control PWM depends on its own supply clock, the clock gate control +is present in TIMCLK_CTRL1 register. + +Fixes: b7d41c937ed7 ("ARM: LPC32xx: Add the motor PWM to base dts file") +Signed-off-by: Vladimir Zapolskiy +Signed-off-by: Sasha Levin +--- + arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi +index 770e85b8268f3..7503074d2877c 100644 +--- a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi ++++ b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi +@@ -301,6 +301,7 @@ i2c2: i2c@400a8000 { + mpwm: mpwm@400e8000 { + compatible = "nxp,lpc3220-motor-pwm"; + reg = <0x400e8000 0x78>; ++ clocks = <&clk LPC32XX_CLK_MCPWM>; + #pwm-cells = <3>; + status = "disabled"; + }; +-- +2.51.0 + diff --git a/queue-6.6/arm-dts-lpc32xx-set-motor-pwm-pwm-cells-property-val.patch b/queue-6.6/arm-dts-lpc32xx-set-motor-pwm-pwm-cells-property-val.patch new file mode 100644 index 0000000000..f906e53eaf --- /dev/null +++ b/queue-6.6/arm-dts-lpc32xx-set-motor-pwm-pwm-cells-property-val.patch @@ -0,0 +1,47 @@ +From fcc9f614c715f52f1043b03126f44256c7de7722 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Sep 2025 21:46:42 +0300 +Subject: ARM: dts: lpc32xx: Set motor PWM #pwm-cells property value to 3 cells +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Vladimir Zapolskiy + +[ Upstream commit 65ae9ea77e1f2a20ad2866f99596df7ccdbd3b95 ] + +Since commit 4cd2f417a0ac ("dt-bindings: pwm: Convert lpc32xx-pwm.txt +to yaml format") both types of PWM controlles on NXP LPC32xx SoC +fairly gained 3 cells, reflect it in the platform dtsi file. + +The change removes a dt binding checker warning: + + mpwm@400e8000: #pwm-cells:0:0: 3 was expected + +Cc: Uwe Kleine-König +Acked-by: Uwe Kleine-König +Reviewed-by: Frank Li +Signed-off-by: Vladimir Zapolskiy +Stable-dep-of: 71630e581a0e ("arm: dts: lpc32xx: add clocks property to Motor Control PWM device tree node") +Signed-off-by: Sasha Levin +--- + arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi +index 974410918f35b..770e85b8268f3 100644 +--- a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi ++++ b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi +@@ -301,8 +301,8 @@ i2c2: i2c@400a8000 { + mpwm: mpwm@400e8000 { + compatible = "nxp,lpc3220-motor-pwm"; + reg = <0x400e8000 0x78>; ++ #pwm-cells = <3>; + status = "disabled"; +- #pwm-cells = <2>; + }; + }; + +-- +2.51.0 + diff --git a/queue-6.6/arm-vdso-patch-out-__vdso_clock_getres-if-unavailabl.patch b/queue-6.6/arm-vdso-patch-out-__vdso_clock_getres-if-unavailabl.patch new file mode 100644 index 0000000000..ddfa276e53 --- /dev/null +++ b/queue-6.6/arm-vdso-patch-out-__vdso_clock_getres-if-unavailabl.patch @@ -0,0 +1,39 @@ +From 595af5e00c84847bd255cd09707e2edf0630da9a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 23 Dec 2025 07:59:17 +0100 +Subject: ARM: VDSO: Patch out __vdso_clock_getres() if unavailable +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh + +[ Upstream commit b9fecf0dddfc55cd7d02b0011494da3c613f7cde ] + +The vDSO code hides symbols which are non-functional. +__vdso_clock_getres() was not added to this list when it got introduced. + +Fixes: 052e76a31b4a ("ARM: 8931/1: Add clock_getres entry point") +Signed-off-by: Thomas Weißschuh +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20251223-vdso-compat-time32-v1-6-97ea7a06a543@linutronix.de +Signed-off-by: Sasha Levin +--- + arch/arm/kernel/vdso.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/kernel/vdso.c b/arch/arm/kernel/vdso.c +index f297d66a8a762..32b6683b45956 100644 +--- a/arch/arm/kernel/vdso.c ++++ b/arch/arm/kernel/vdso.c +@@ -176,6 +176,7 @@ static void __init patch_vdso(void *ehdr) + vdso_nullpatch_one(&einfo, "__vdso_gettimeofday"); + vdso_nullpatch_one(&einfo, "__vdso_clock_gettime"); + vdso_nullpatch_one(&einfo, "__vdso_clock_gettime64"); ++ vdso_nullpatch_one(&einfo, "__vdso_clock_getres"); + } + } + +-- +2.51.0 + diff --git a/queue-6.6/arm64-dts-amlogic-axg-assign-the-mmc-signal-clocks.patch b/queue-6.6/arm64-dts-amlogic-axg-assign-the-mmc-signal-clocks.patch new file mode 100644 index 0000000000..e037d403b9 --- /dev/null +++ b/queue-6.6/arm64-dts-amlogic-axg-assign-the-mmc-signal-clocks.patch @@ -0,0 +1,52 @@ +From fcd163887a283b7ec9770ecb3b8a64f7a324b400 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:08:50 +0100 +Subject: arm64: dts: amlogic: axg: assign the MMC signal clocks + +From: Jerome Brunet + +[ Upstream commit 13d3fe2318ef6e46d6fcfe13bc373827fdf2aeac ] + +The amlogic MMC driver operate with the assumption that MMC clock +is configured to provide 24MHz. It uses this path for low +rates such as 400kHz. + +Assign the clocks to make sure they are properly configured + +Fixes: 221cf34bac54 ("ARM64: dts: meson-axg: enable the eMMC controller") +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Link: https://patch.msgid.link/20260114-amlogic-mmc-clocks-followup-v1-3-a999fafbe0aa@baylibre.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-axg.dtsi | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi +index 768d0ed78dbe6..16af71d84a132 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi +@@ -1894,6 +1894,9 @@ sd_emmc_b: mmc@5000 { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_B>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_B_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + sd_emmc_c: mmc@7000 { +@@ -1906,6 +1909,9 @@ sd_emmc_c: mmc@7000 { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_C>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_C_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + usb2_phy1: phy@9020 { +-- +2.51.0 + diff --git a/queue-6.6/arm64-dts-amlogic-g12-assign-the-mmc-a-signal-clock.patch b/queue-6.6/arm64-dts-amlogic-g12-assign-the-mmc-a-signal-clock.patch new file mode 100644 index 0000000000..fc555f3dd2 --- /dev/null +++ b/queue-6.6/arm64-dts-amlogic-g12-assign-the-mmc-a-signal-clock.patch @@ -0,0 +1,42 @@ +From 76173ce2354775149d237cdb9413c98885596597 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:08:53 +0100 +Subject: arm64: dts: amlogic: g12: assign the MMC A signal clock + +From: Jerome Brunet + +[ Upstream commit 3c941feaa363f1573a501452391ddf513394c84b ] + +The amlogic MMC driver operate with the assumption that MMC clock +is configured to provide 24MHz. It uses this path for low +rates such as 400kHz. + +Assign the clock to make sure it is properly configured + +Fixes: 8a6b3ca2d361 ("arm64: dts: meson: g12a: add SDIO controller") +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Link: https://patch.msgid.link/20260114-amlogic-mmc-clocks-followup-v1-6-a999fafbe0aa@baylibre.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +index cf2d073154f43..c5848363df37a 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +@@ -2341,6 +2341,9 @@ sd_emmc_a: mmc@ffe03000 { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_A>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_A_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + sd_emmc_b: mmc@ffe05000 { +-- +2.51.0 + diff --git a/queue-6.6/arm64-dts-amlogic-g12-assign-the-mmc-b-and-c-signal-.patch b/queue-6.6/arm64-dts-amlogic-g12-assign-the-mmc-b-and-c-signal-.patch new file mode 100644 index 0000000000..f1e190048d --- /dev/null +++ b/queue-6.6/arm64-dts-amlogic-g12-assign-the-mmc-b-and-c-signal-.patch @@ -0,0 +1,52 @@ +From 6ca5aa823b357baa1edc38f7dc910fddf3de199d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:08:52 +0100 +Subject: arm64: dts: amlogic: g12: assign the MMC B and C signal clocks + +From: Jerome Brunet + +[ Upstream commit be2ff5fdb0e83e32d4ec4e68a69875cec0d14621 ] + +The amlogic MMC driver operate with the assumption that MMC clock +is configured to provide 24MHz. It uses this path for low +rates such as 400kHz. + +Assign the clocks to make sure they are properly configured + +Fixes: 4759fd87b928 ("arm64: dts: meson: g12a: add mmc nodes") +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Link: https://patch.msgid.link/20260114-amlogic-mmc-clocks-followup-v1-5-a999fafbe0aa@baylibre.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +index 0ff0d090548d0..cf2d073154f43 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +@@ -2353,6 +2353,9 @@ sd_emmc_b: mmc@ffe05000 { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_B>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_B_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + sd_emmc_c: mmc@ffe07000 { +@@ -2365,6 +2368,9 @@ sd_emmc_c: mmc@ffe07000 { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_C>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_C_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + usb: usb@ffe09000 { +-- +2.51.0 + diff --git a/queue-6.6/arm64-dts-amlogic-gx-assign-the-mmc-signal-clocks.patch b/queue-6.6/arm64-dts-amlogic-gx-assign-the-mmc-signal-clocks.patch new file mode 100644 index 0000000000..0dda222d23 --- /dev/null +++ b/queue-6.6/arm64-dts-amlogic-gx-assign-the-mmc-signal-clocks.patch @@ -0,0 +1,97 @@ +From 79fda9f7ee1192d1117f27bf4b96caa83e520cf7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:08:51 +0100 +Subject: arm64: dts: amlogic: gx: assign the MMC signal clocks + +From: Jerome Brunet + +[ Upstream commit 406706559046eebc09a31e8ae5e78620bfd746fe ] + +The amlogic MMC driver operate with the assumption that MMC clock +is configured to provide 24MHz. It uses this path for low +rates such as 400kHz. + +Assign the clocks to make sure they are properly configured + +Fixes: 50662499f911 ("ARM64: dts: meson-gx: Use correct mmc clock source 0") +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Link: https://patch.msgid.link/20260114-amlogic-mmc-clocks-followup-v1-4-a999fafbe0aa@baylibre.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 9 +++++++++ + arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 9 +++++++++ + 2 files changed, 18 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi +index ed00e67e6923a..851ae89dd17fa 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi +@@ -799,6 +799,9 @@ &sd_emmc_a { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_A>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_A_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &sd_emmc_b { +@@ -807,6 +810,9 @@ &sd_emmc_b { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_B>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_B_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &sd_emmc_c { +@@ -815,6 +821,9 @@ &sd_emmc_c { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_C>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_C_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &simplefb_hdmi { +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi +index f58d1790de1cb..f7fafebafd809 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi +@@ -869,6 +869,9 @@ &sd_emmc_a { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_A>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_A_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &sd_emmc_b { +@@ -877,6 +880,9 @@ &sd_emmc_b { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_B>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_B_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &sd_emmc_c { +@@ -885,6 +891,9 @@ &sd_emmc_c { + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + resets = <&reset RESET_SD_EMMC_C>; ++ ++ assigned-clocks = <&clkc CLKID_SD_EMMC_C_CLK0>; ++ assigned-clock-rates = <24000000>; + }; + + &simplefb_hdmi { +-- +2.51.0 + diff --git a/queue-6.6/arm64-dts-qcom-sdm630-fix-gpu_speed_bin-size.patch b/queue-6.6/arm64-dts-qcom-sdm630-fix-gpu_speed_bin-size.patch new file mode 100644 index 0000000000..1ac92c0c1e --- /dev/null +++ b/queue-6.6/arm64-dts-qcom-sdm630-fix-gpu_speed_bin-size.patch @@ -0,0 +1,49 @@ +From 270ed6d5d06800c8d369d4906465afa5a3475945 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 11 Dec 2025 03:27:45 +0200 +Subject: arm64: dts: qcom: sdm630: fix gpu_speed_bin size + +From: Dmitry Baryshkov + +[ Upstream commit e814796dfcae8905682ac3ac2dd57f512a9f6726 ] + +Historically sdm630.dtsi has used 1 byte length for the gpu_speed_bin +cell, although it spans two bytes (offset 5, size 7 bits). It was being +accepted by the kernel because before the commit 7a06ef751077 ("nvmem: +core: fix bit offsets of more than one byte") the kernel didn't have +length check. After this commit nvmem core rejects QFPROM on sdm630 / +sdm660, making GPU and USB unusable on those platforms. + +Set the size of the gpu_speed_bin cell to 2 bytes, fixing the parsing +error. While we are at it, update the length to 8 bits as pointed out by +Alexey Minnekhanov. + +Fixes: b190fb010664 ("arm64: dts: qcom: sdm630: Add sdm630 dts file") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Reviewed-by: Alexey Minnekhanov +Link: https://lore.kernel.org/r/20251211-sdm630-fix-gpu-v2-1-92f0e736dba0@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm630.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/sdm630.dtsi b/arch/arm64/boot/dts/qcom/sdm630.dtsi +index 0f3f57fb860ec..74b36cb8bffa8 100644 +--- a/arch/arm64/boot/dts/qcom/sdm630.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm630.dtsi +@@ -589,8 +589,8 @@ qusb2_hstx_trim: hstx-trim@240 { + }; + + gpu_speed_bin: gpu-speed-bin@41a0 { +- reg = <0x41a2 0x1>; +- bits = <5 7>; ++ reg = <0x41a2 0x2>; ++ bits = <5 8>; + }; + }; + +-- +2.51.0 + diff --git a/queue-6.6/arm64-dts-qcom-sdm845-db845c-drop-cs-from-spio0.patch b/queue-6.6/arm64-dts-qcom-sdm845-db845c-drop-cs-from-spio0.patch new file mode 100644 index 0000000000..a4d7b1bfea --- /dev/null +++ b/queue-6.6/arm64-dts-qcom-sdm845-db845c-drop-cs-from-spio0.patch @@ -0,0 +1,40 @@ +From 0b5d7a9b7a2942e478da00d035951510b5abc97c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Jan 2026 03:01:17 +0200 +Subject: arm64: dts: qcom: sdm845-db845c: drop CS from SPIO0 + +From: Dmitry Baryshkov + +[ Upstream commit 8bfb696ccdc5bcfad7a45b84c2c8a36757070e19 ] + +On SDM845 SPI uses hardware-provided chip select, while specifying +cs-gpio makes the driver request GPIO pin, which on DB845c conflicts +with the normal host controllers pinctrl entry. + +Drop the cs-gpios property to restore SPI functionality. + +Fixes: cb29e7106d4e ("arm64: dts: qcom: db845c: Add support for MCP2517FD") +Reviewed-by: Konrad Dybcio +Signed-off-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260106-wcn3990-pwrctl-v2-7-0386204328be@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm845-db845c.dts | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts +index 0a891a0122446..d2924abd91d22 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts ++++ b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts +@@ -852,7 +852,6 @@ &spi0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&qup_spi0_default>; +- cs-gpios = <&tlmm 3 GPIO_ACTIVE_LOW>; + + can@0 { + compatible = "microchip,mcp2517fd"; +-- +2.51.0 + diff --git a/queue-6.6/arm64-dts-qcom-sdm845-db845c-specify-power-for-wifi-.patch b/queue-6.6/arm64-dts-qcom-sdm845-db845c-specify-power-for-wifi-.patch new file mode 100644 index 0000000000..eeaa9757cb --- /dev/null +++ b/queue-6.6/arm64-dts-qcom-sdm845-db845c-specify-power-for-wifi-.patch @@ -0,0 +1,50 @@ +From 49bc43aa16b3db506ee7527f2f32c02424048437 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Jan 2026 03:01:18 +0200 +Subject: arm64: dts: qcom: sdm845-db845c: specify power for WiFi CH1 + +From: Dmitry Baryshkov + +[ Upstream commit c303e89f7f17c29981d09f8beaaf60937ae8b1f2 ] + +Specify power supply for the second chain / antenna output of the +onboard WiFi chip. + +Fixes: 3f72e2d3e682 ("arm64: dts: qcom: Add Dragonboard 845c") +Reviewed-by: Konrad Dybcio +Signed-off-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260106-wcn3990-pwrctl-v2-8-0386204328be@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm845-db845c.dts | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts +index d2924abd91d22..1164f2cf5bc96 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts ++++ b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts +@@ -372,6 +372,12 @@ vreg_l21a_2p95: ldo21 { + regulator-initial-mode = ; + }; + ++ vreg_l23a_3p3: ldo23 { ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3312000>; ++ regulator-initial-mode = ; ++ }; ++ + vreg_l24a_3p075: ldo24 { + regulator-min-microvolt = <3088000>; + regulator-max-microvolt = <3088000>; +@@ -1157,6 +1163,7 @@ &wifi { + vdd-1.8-xo-supply = <&vreg_l7a_1p8>; + vdd-1.3-rfa-supply = <&vreg_l17a_1p3>; + vdd-3.3-ch0-supply = <&vreg_l25a_3p3>; ++ vdd-3.3-ch1-supply = <&vreg_l23a_3p3>; + + qcom,snoc-host-cap-8bit-quirk; + qcom,ath10k-calibration-variant = "Thundercomm_DB845C"; +-- +2.51.0 + diff --git a/queue-6.6/arm64-dts-qcom-sdm845-oneplus-don-t-keep-panel-regul.patch b/queue-6.6/arm64-dts-qcom-sdm845-oneplus-don-t-keep-panel-regul.patch new file mode 100644 index 0000000000..3afd48ddd3 --- /dev/null +++ b/queue-6.6/arm64-dts-qcom-sdm845-oneplus-don-t-keep-panel-regul.patch @@ -0,0 +1,39 @@ +From 7e1c4fad3d094dbf15e8a6207ad599797f637aee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 18 Nov 2025 15:52:26 +0100 +Subject: arm64: dts: qcom: sdm845-oneplus: Don't keep panel regulator always + on + +From: Casey Connolly + +[ Upstream commit 45d1f42d3e84b5880cf9fab1eb24a7818320eeb7 ] + +The panel regulator doesn't need to be always on, so remove this +property. + +Fixes: 288ef8a42612 ("arm64: dts: sdm845: add oneplus6/6t devices") +Signed-off-by: Casey Connolly +Signed-off-by: David Heidelberg +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251118-dts-oneplus-regulators-v2-2-3e67cea1e4e7@ixit.cz +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +index c50d335e0761f..4e335c9fd8185 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +@@ -251,7 +251,6 @@ vreg_l14a_1p88: ldo14 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; +- regulator-always-on; + }; + + vreg_l17a_1p3: ldo17 { +-- +2.51.0 + diff --git a/queue-6.6/arm64-dts-qcom-sdm845-oneplus-don-t-mark-ts-supply-b.patch b/queue-6.6/arm64-dts-qcom-sdm845-oneplus-don-t-mark-ts-supply-b.patch new file mode 100644 index 0000000000..c6c00ad754 --- /dev/null +++ b/queue-6.6/arm64-dts-qcom-sdm845-oneplus-don-t-mark-ts-supply-b.patch @@ -0,0 +1,39 @@ +From e073e1fec4866459c8230e585a6107fd921abba8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 18 Nov 2025 15:52:25 +0100 +Subject: arm64: dts: qcom: sdm845-oneplus: Don't mark ts supply boot-on + +From: Casey Connolly + +[ Upstream commit c9b98b9dad9749bf2eb7336a6fca31a6af1039d7 ] + +The touchscreen isn't enabled by bootloader and doesn't need to be +enabled at boot, only when the driver probes, thus remove the +regulator-boot-on property. + +Fixes: 288ef8a42612 ("arm64: dts: sdm845: add oneplus6/6t devices") +Signed-off-by: Casey Connolly +Signed-off-by: David Heidelberg +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251118-dts-oneplus-regulators-v2-1-3e67cea1e4e7@ixit.cz +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +index bccc52e01da38..c50d335e0761f 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +@@ -155,7 +155,6 @@ ts_1p8_supply: ts-1p8-regulator { + + gpio = <&tlmm 88 0>; + enable-active-high; +- regulator-boot-on; + }; + }; + +-- +2.51.0 + diff --git a/queue-6.6/arm64-dts-qcom-sdm845-oneplus-mark-l14a-regulator-as.patch b/queue-6.6/arm64-dts-qcom-sdm845-oneplus-mark-l14a-regulator-as.patch new file mode 100644 index 0000000000..6f1b472a8a --- /dev/null +++ b/queue-6.6/arm64-dts-qcom-sdm845-oneplus-mark-l14a-regulator-as.patch @@ -0,0 +1,38 @@ +From 2dd5d9f372bc12626546c9ccde3da6d9a1925fe9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 18 Nov 2025 15:52:27 +0100 +Subject: arm64: dts: qcom: sdm845-oneplus: Mark l14a regulator as boot-on + +From: Casey Connolly + +[ Upstream commit ad33ee060be46794a03d033894c9db3a9d6c1a0f ] + +This regulator is used only for the display, which is enabled by the +bootloader and left on for continuous splash. Mark it as such. + +Fixes: 288ef8a42612 ("arm64: dts: sdm845: add oneplus6/6t devices") +Signed-off-by: Casey Connolly +Signed-off-by: David Heidelberg +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251118-dts-oneplus-regulators-v2-3-3e67cea1e4e7@ixit.cz +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +index 4e335c9fd8185..894fd3395189a 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +@@ -251,6 +251,7 @@ vreg_l14a_1p88: ldo14 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; ++ regulator-boot-on; + }; + + vreg_l17a_1p3: ldo17 { +-- +2.51.0 + diff --git a/queue-6.6/arm64-dts-qcom-sm6115-add-cx_mem-dbgc-gpu-regions.patch b/queue-6.6/arm64-dts-qcom-sm6115-add-cx_mem-dbgc-gpu-regions.patch new file mode 100644 index 0000000000..c1e5b0cebe --- /dev/null +++ b/queue-6.6/arm64-dts-qcom-sm6115-add-cx_mem-dbgc-gpu-regions.patch @@ -0,0 +1,49 @@ +From bf0157baec8ebfb9ffaa7aa5bc1638a71469a1c0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Dec 2025 21:47:41 +0100 +Subject: arm64: dts: qcom: sm6115: Add CX_MEM/DBGC GPU regions + +From: Konrad Dybcio + +[ Upstream commit 78c13dac18cf0e6f6cbc6ea85d4f967e6cca9562 ] + +Describe the GPU register regions, with the former existing but not +being used much if at all on this silicon, and the latter containing +various debugging levers generally related to dumping the state of +the IP upon a crash. + +Fixes: 11750af256f8 ("arm64: dts: qcom: sm6115: Add GPU nodes") +Reported-by: Krzysztof Kozlowski +Closes: https://lore.kernel.org/linux-arm-msm/8a64f70b-8034-45e7-86a3-0015cf357132@oss.qualcomm.com/T/#m404f1425c36b61467760f058b696b8910340a063 +Signed-off-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Akhil P Oommen +Link: https://lore.kernel.org/r/20251229-topic-6115_2290_gpu_dbgc-v1-3-4a24d196389c@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm6115.dtsi | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm6115.dtsi b/arch/arm64/boot/dts/qcom/sm6115.dtsi +index 5c6fcf725473c..4c6d30404ff13 100644 +--- a/arch/arm64/boot/dts/qcom/sm6115.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm6115.dtsi +@@ -1336,8 +1336,12 @@ usb_dwc3: usb@4e00000 { + + gpu: gpu@5900000 { + compatible = "qcom,adreno-610.0", "qcom,adreno"; +- reg = <0x0 0x05900000 0x0 0x40000>; +- reg-names = "kgsl_3d0_reg_memory"; ++ reg = <0x0 0x05900000 0x0 0x40000>, ++ <0x0 0x0599e000 0x0 0x1000>, ++ <0x0 0x05961000 0x0 0x800>; ++ reg-names = "kgsl_3d0_reg_memory", ++ "cx_mem", ++ "cx_dbgc"; + + /* There's no (real) GMU, so we have to handle quite a bunch of clocks! */ + clocks = <&gpucc GPU_CC_GX_GFX3D_CLK>, +-- +2.51.0 + diff --git a/queue-6.6/arm64-dts-tqma8mpql-mba8mpxl-fix-hdmi-cec-pad-contro.patch b/queue-6.6/arm64-dts-tqma8mpql-mba8mpxl-fix-hdmi-cec-pad-contro.patch new file mode 100644 index 0000000000..14a663e619 --- /dev/null +++ b/queue-6.6/arm64-dts-tqma8mpql-mba8mpxl-fix-hdmi-cec-pad-contro.patch @@ -0,0 +1,36 @@ +From ad12362e9320fc80ce1f26f410d3d1993bf2f6e1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 11:53:09 +0100 +Subject: arm64: dts: tqma8mpql-mba8mpxl: Fix HDMI CEC pad control settings + +From: Alexander Stein + +[ Upstream commit 8401527abb5e3a00c867b6597b8e1b29c80c9824 ] + +As per datasheet of the HDMI protection IC the CEC_IC pin has been +configured as open-drain. + +Fixes: 418d1d840e42 ("arm64: dts: freescale: add initial device tree for TQMa8MPQL with i.MX8MP") +Signed-off-by: Alexander Stein +Signed-off-by: Shawn Guo +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts +index 258e90cc16ff3..5430b62a3b282 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts +@@ -810,7 +810,7 @@ pinctrl_hdmi: hdmigrp { + fsl,pins = , + , + , +- ; ++ ; + }; + + pinctrl_hoggpio2: hoggpio2grp { +-- +2.51.0 + diff --git a/queue-6.6/asoc-nau8821-avoid-unnecessary-blocking-in-irq-handl.patch b/queue-6.6/asoc-nau8821-avoid-unnecessary-blocking-in-irq-handl.patch new file mode 100644 index 0000000000..e9c16bc3aa --- /dev/null +++ b/queue-6.6/asoc-nau8821-avoid-unnecessary-blocking-in-irq-handl.patch @@ -0,0 +1,121 @@ +From b50a8ee68a0c9797b47b2e7315705e4fba98d297 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Oct 2025 21:03:27 +0300 +Subject: ASoC: nau8821: Avoid unnecessary blocking in IRQ handler + +From: Cristian Ciocaltea + +[ Upstream commit ee70bacef1c6050e4836409927294d744dbcfa72 ] + +The interrupt handler offloads the microphone detection logic to +nau8821_jdet_work(), which implies a sleep operation. However, before +being able to process any subsequent hotplug event, the interrupt +handler needs to wait for any prior scheduled work to complete. + +Move the sleep out of jdet_work by converting it to a delayed work. +This eliminates the undesired blocking in the interrupt handler when +attempting to cancel a recently scheduled work item and should help +reducing transient input reports that might confuse user-space. + +Signed-off-by: Cristian Ciocaltea +Link: https://patch.msgid.link/20251003-nau8821-jdet-fixes-v1-5-f7b0e2543f09@collabora.com +Signed-off-by: Mark Brown +Stable-dep-of: 70237853edf0 ("ASoC: nau8821: Fixup nau8821_enable_jack_detect()") +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/nau8821.c | 22 ++++++++++++---------- + sound/soc/codecs/nau8821.h | 2 +- + 2 files changed, 13 insertions(+), 11 deletions(-) + +diff --git a/sound/soc/codecs/nau8821.c b/sound/soc/codecs/nau8821.c +index 585884a087ecc..7b84939602985 100644 +--- a/sound/soc/codecs/nau8821.c ++++ b/sound/soc/codecs/nau8821.c +@@ -1113,16 +1113,12 @@ static void nau8821_eject_jack(struct nau8821 *nau8821) + static void nau8821_jdet_work(struct work_struct *work) + { + struct nau8821 *nau8821 = +- container_of(work, struct nau8821, jdet_work); ++ container_of(work, struct nau8821, jdet_work.work); + struct snd_soc_dapm_context *dapm = nau8821->dapm; + struct snd_soc_component *component = snd_soc_dapm_to_component(dapm); + struct regmap *regmap = nau8821->regmap; + int jack_status_reg, mic_detected, event = 0, event_mask = 0; + +- snd_soc_component_force_enable_pin(component, "MICBIAS"); +- snd_soc_dapm_sync(dapm); +- msleep(20); +- + regmap_read(regmap, NAU8821_R58_I2C_DEVICE_ID, &jack_status_reg); + mic_detected = !(jack_status_reg & NAU8821_KEYDET); + if (mic_detected) { +@@ -1152,6 +1148,7 @@ static void nau8821_jdet_work(struct work_struct *work) + snd_soc_component_disable_pin(component, "MICBIAS"); + snd_soc_dapm_sync(dapm); + } ++ + event_mask |= SND_JACK_HEADSET; + snd_soc_jack_report(nau8821->jack, event, event_mask); + } +@@ -1200,6 +1197,7 @@ static irqreturn_t nau8821_interrupt(int irq, void *data) + { + struct nau8821 *nau8821 = (struct nau8821 *)data; + struct regmap *regmap = nau8821->regmap; ++ struct snd_soc_component *component; + int active_irq, event = 0, event_mask = 0; + + if (regmap_read(regmap, NAU8821_R10_IRQ_STATUS, &active_irq)) { +@@ -1211,7 +1209,7 @@ static irqreturn_t nau8821_interrupt(int irq, void *data) + + if ((active_irq & NAU8821_JACK_EJECT_IRQ_MASK) == + NAU8821_JACK_EJECT_DETECTED) { +- cancel_work_sync(&nau8821->jdet_work); ++ cancel_delayed_work_sync(&nau8821->jdet_work); + regmap_update_bits(regmap, NAU8821_R71_ANALOG_ADC_1, + NAU8821_MICDET_MASK, NAU8821_MICDET_DIS); + nau8821_eject_jack(nau8821); +@@ -1225,12 +1223,15 @@ static irqreturn_t nau8821_interrupt(int irq, void *data) + nau8821_irq_status_clear(regmap, NAU8821_KEY_RELEASE_IRQ); + } else if ((active_irq & NAU8821_JACK_INSERT_IRQ_MASK) == + NAU8821_JACK_INSERT_DETECTED) { +- cancel_work_sync(&nau8821->jdet_work); ++ cancel_delayed_work_sync(&nau8821->jdet_work); + regmap_update_bits(regmap, NAU8821_R71_ANALOG_ADC_1, + NAU8821_MICDET_MASK, NAU8821_MICDET_EN); + if (nau8821_is_jack_inserted(regmap)) { +- /* detect microphone and jack type */ +- schedule_work(&nau8821->jdet_work); ++ /* Detect microphone and jack type */ ++ component = snd_soc_dapm_to_component(nau8821->dapm); ++ snd_soc_component_force_enable_pin(component, "MICBIAS"); ++ snd_soc_dapm_sync(nau8821->dapm); ++ schedule_delayed_work(&nau8821->jdet_work, msecs_to_jiffies(20)); + /* Turn off insertion interruption at manual mode */ + nau8821_setup_inserted_irq(nau8821); + } else { +@@ -1667,7 +1668,8 @@ int nau8821_enable_jack_detect(struct snd_soc_component *component, + + nau8821->jack = jack; + /* Initiate jack detection work queue */ +- INIT_WORK(&nau8821->jdet_work, nau8821_jdet_work); ++ INIT_DELAYED_WORK(&nau8821->jdet_work, nau8821_jdet_work); ++ + ret = devm_request_threaded_irq(nau8821->dev, nau8821->irq, NULL, + nau8821_interrupt, IRQF_TRIGGER_LOW | IRQF_ONESHOT, + "nau8821", nau8821); +diff --git a/sound/soc/codecs/nau8821.h b/sound/soc/codecs/nau8821.h +index 00a888ed07ceb..5abb91b087a12 100644 +--- a/sound/soc/codecs/nau8821.h ++++ b/sound/soc/codecs/nau8821.h +@@ -559,7 +559,7 @@ struct nau8821 { + struct regmap *regmap; + struct snd_soc_dapm_context *dapm; + struct snd_soc_jack *jack; +- struct work_struct jdet_work; ++ struct delayed_work jdet_work; + int irq; + int clk_id; + int micbias_voltage; +-- +2.51.0 + diff --git a/queue-6.6/asoc-nau8821-consistently-clear-interrupts-before-un.patch b/queue-6.6/asoc-nau8821-consistently-clear-interrupts-before-un.patch new file mode 100644 index 0000000000..c154d70fbd --- /dev/null +++ b/queue-6.6/asoc-nau8821-consistently-clear-interrupts-before-un.patch @@ -0,0 +1,169 @@ +From bbca586ed902f760c79d003e813410ebdc6531e2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Oct 2025 21:03:25 +0300 +Subject: ASoC: nau8821: Consistently clear interrupts before unmasking + +From: Cristian Ciocaltea + +[ Upstream commit a698679fe8b0fec41d1fb9547a53127a85c1be92 ] + +The interrupt handler attempts to perform some IRQ status clear +operations *after* rather than *before* unmasking and enabling +interrupts. This is a rather fragile approach since it may generally +lead to missing IRQ requests or causing spurious interrupts. + +Make use of the nau8821_irq_status_clear() helper instead of +manipulating the related register directly and ensure any interrupt +clearing is performed *after* the target interrupts are disabled/masked +and *before* proceeding with additional interrupt unmasking/enablement +operations. + +This also implicitly drops the redundant clear operation of the ejection +IRQ in the interrupt handler, since nau8821_eject_jack() has been +already responsible for clearing all active interrupts. + +Fixes: aab1ad11d69f ("ASoC: nau8821: new driver") +Fixes: 2551b6e89936 ("ASoC: nau8821: Add headset button detection") +Signed-off-by: Cristian Ciocaltea +Link: https://patch.msgid.link/20251003-nau8821-jdet-fixes-v1-3-f7b0e2543f09@collabora.com +Signed-off-by: Mark Brown +Stable-dep-of: 70237853edf0 ("ASoC: nau8821: Fixup nau8821_enable_jack_detect()") +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/nau8821.c | 58 ++++++++++++++++++++------------------ + 1 file changed, 30 insertions(+), 28 deletions(-) + +diff --git a/sound/soc/codecs/nau8821.c b/sound/soc/codecs/nau8821.c +index 48ed75c3a7db2..585884a087ecc 100644 +--- a/sound/soc/codecs/nau8821.c ++++ b/sound/soc/codecs/nau8821.c +@@ -1067,20 +1067,24 @@ static void nau8821_eject_jack(struct nau8821 *nau8821) + snd_soc_component_disable_pin(component, "MICBIAS"); + snd_soc_dapm_sync(dapm); + ++ /* Disable & mask both insertion & ejection IRQs */ ++ regmap_update_bits(regmap, NAU8821_R12_INTERRUPT_DIS_CTRL, ++ NAU8821_IRQ_INSERT_DIS | NAU8821_IRQ_EJECT_DIS, ++ NAU8821_IRQ_INSERT_DIS | NAU8821_IRQ_EJECT_DIS); ++ regmap_update_bits(regmap, NAU8821_R0F_INTERRUPT_MASK, ++ NAU8821_IRQ_INSERT_EN | NAU8821_IRQ_EJECT_EN, ++ NAU8821_IRQ_INSERT_EN | NAU8821_IRQ_EJECT_EN); ++ + /* Clear all interruption status */ + nau8821_irq_status_clear(regmap, 0); + +- /* Enable the insertion interruption, disable the ejection inter- +- * ruption, and then bypass de-bounce circuit. +- */ ++ /* Enable & unmask the insertion IRQ */ + regmap_update_bits(regmap, NAU8821_R12_INTERRUPT_DIS_CTRL, +- NAU8821_IRQ_EJECT_DIS | NAU8821_IRQ_INSERT_DIS, +- NAU8821_IRQ_EJECT_DIS); +- /* Mask unneeded IRQs: 1 - disable, 0 - enable */ ++ NAU8821_IRQ_INSERT_DIS, 0); + regmap_update_bits(regmap, NAU8821_R0F_INTERRUPT_MASK, +- NAU8821_IRQ_EJECT_EN | NAU8821_IRQ_INSERT_EN, +- NAU8821_IRQ_EJECT_EN); ++ NAU8821_IRQ_INSERT_EN, 0); + ++ /* Bypass de-bounce circuit */ + regmap_update_bits(regmap, NAU8821_R0D_JACK_DET_CTRL, + NAU8821_JACK_DET_DB_BYPASS, NAU8821_JACK_DET_DB_BYPASS); + +@@ -1104,7 +1108,6 @@ static void nau8821_eject_jack(struct nau8821 *nau8821) + NAU8821_IRQ_KEY_RELEASE_DIS | + NAU8821_IRQ_KEY_PRESS_DIS); + } +- + } + + static void nau8821_jdet_work(struct work_struct *work) +@@ -1158,6 +1161,15 @@ static void nau8821_setup_inserted_irq(struct nau8821 *nau8821) + { + struct regmap *regmap = nau8821->regmap; + ++ /* Disable & mask insertion IRQ */ ++ regmap_update_bits(regmap, NAU8821_R12_INTERRUPT_DIS_CTRL, ++ NAU8821_IRQ_INSERT_DIS, NAU8821_IRQ_INSERT_DIS); ++ regmap_update_bits(regmap, NAU8821_R0F_INTERRUPT_MASK, ++ NAU8821_IRQ_INSERT_EN, NAU8821_IRQ_INSERT_EN); ++ ++ /* Clear insert IRQ status */ ++ nau8821_irq_status_clear(regmap, NAU8821_JACK_INSERT_DETECTED); ++ + /* Enable internal VCO needed for interruptions */ + if (nau8821->dapm->bias_level < SND_SOC_BIAS_PREPARE) + nau8821_configure_sysclk(nau8821, NAU8821_CLK_INTERNAL, 0); +@@ -1177,17 +1189,18 @@ static void nau8821_setup_inserted_irq(struct nau8821 *nau8821) + regmap_update_bits(regmap, NAU8821_R0D_JACK_DET_CTRL, + NAU8821_JACK_DET_DB_BYPASS, 0); + ++ /* Unmask & enable the ejection IRQs */ + regmap_update_bits(regmap, NAU8821_R0F_INTERRUPT_MASK, +- NAU8821_IRQ_EJECT_EN, 0); ++ NAU8821_IRQ_EJECT_EN, 0); + regmap_update_bits(regmap, NAU8821_R12_INTERRUPT_DIS_CTRL, +- NAU8821_IRQ_EJECT_DIS, 0); ++ NAU8821_IRQ_EJECT_DIS, 0); + } + + static irqreturn_t nau8821_interrupt(int irq, void *data) + { + struct nau8821 *nau8821 = (struct nau8821 *)data; + struct regmap *regmap = nau8821->regmap; +- int active_irq, clear_irq = 0, event = 0, event_mask = 0; ++ int active_irq, event = 0, event_mask = 0; + + if (regmap_read(regmap, NAU8821_R10_IRQ_STATUS, &active_irq)) { + dev_err(nau8821->dev, "failed to read irq status\n"); +@@ -1203,14 +1216,13 @@ static irqreturn_t nau8821_interrupt(int irq, void *data) + NAU8821_MICDET_MASK, NAU8821_MICDET_DIS); + nau8821_eject_jack(nau8821); + event_mask |= SND_JACK_HEADSET; +- clear_irq = NAU8821_JACK_EJECT_IRQ_MASK; + } else if (active_irq & NAU8821_KEY_SHORT_PRESS_IRQ) { + event |= NAU8821_BUTTON; + event_mask |= NAU8821_BUTTON; +- clear_irq = NAU8821_KEY_SHORT_PRESS_IRQ; ++ nau8821_irq_status_clear(regmap, NAU8821_KEY_SHORT_PRESS_IRQ); + } else if (active_irq & NAU8821_KEY_RELEASE_IRQ) { + event_mask = NAU8821_BUTTON; +- clear_irq = NAU8821_KEY_RELEASE_IRQ; ++ nau8821_irq_status_clear(regmap, NAU8821_KEY_RELEASE_IRQ); + } else if ((active_irq & NAU8821_JACK_INSERT_IRQ_MASK) == + NAU8821_JACK_INSERT_DETECTED) { + cancel_work_sync(&nau8821->jdet_work); +@@ -1220,27 +1232,17 @@ static irqreturn_t nau8821_interrupt(int irq, void *data) + /* detect microphone and jack type */ + schedule_work(&nau8821->jdet_work); + /* Turn off insertion interruption at manual mode */ +- regmap_update_bits(regmap, +- NAU8821_R12_INTERRUPT_DIS_CTRL, +- NAU8821_IRQ_INSERT_DIS, +- NAU8821_IRQ_INSERT_DIS); +- regmap_update_bits(regmap, +- NAU8821_R0F_INTERRUPT_MASK, +- NAU8821_IRQ_INSERT_EN, +- NAU8821_IRQ_INSERT_EN); + nau8821_setup_inserted_irq(nau8821); + } else { + dev_warn(nau8821->dev, + "Inserted IRQ fired but not connected\n"); + nau8821_eject_jack(nau8821); + } ++ } else { ++ /* Clear the rightmost interrupt */ ++ nau8821_irq_status_clear(regmap, active_irq); + } + +- if (!clear_irq) +- clear_irq = active_irq; +- /* clears the rightmost interruption */ +- regmap_write(regmap, NAU8821_R11_INT_CLR_KEY_STATUS, clear_irq); +- + if (event_mask) + snd_soc_jack_report(nau8821->jack, event, event_mask); + +-- +2.51.0 + diff --git a/queue-6.6/asoc-nau8821-fixup-nau8821_enable_jack_detect.patch b/queue-6.6/asoc-nau8821-fixup-nau8821_enable_jack_detect.patch new file mode 100644 index 0000000000..348a3dce3d --- /dev/null +++ b/queue-6.6/asoc-nau8821-fixup-nau8821_enable_jack_detect.patch @@ -0,0 +1,84 @@ +From bdee9c54bdb1805a61f1857d0042924e638bca2a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 31 Dec 2025 22:04:15 +0200 +Subject: ASoC: nau8821: Fixup nau8821_enable_jack_detect() + +From: Cristian Ciocaltea + +[ Upstream commit 70237853edf0a69773a7370eb74ea2a44dfe3050 ] + +The nau8821_enable_jack_detect() function was supposed to allow enabling +or disabling jack events reporting. However, once enabled, any +subsequent invocation would fail and the following splat is shown: + +[ 3136.996771] Hardware name: Valve Jupiter/Jupiter, BIOS F7A0131 01/30/2024 +[ 3136.996773] Workqueue: events_unbound deferred_probe_work_func +[ 3136.996780] Call Trace: +[ 3136.996782] +[ 3136.996787] dump_stack_lvl+0x6e/0xa0 +[ 3136.996796] __setup_irq.cold+0x9c/0xce +[ 3136.996803] ? __pfx_irq_default_primary_handler+0x10/0x10 +[ 3136.996812] ? __pfx_nau8821_interrupt+0x10/0x10 [snd_soc_nau8821] +[ 3136.996825] request_threaded_irq+0xd9/0x160 +[ 3136.996853] devm_request_threaded_irq+0x71/0xd0 +[ 3136.996859] ? __pfx_nau8821_interrupt+0x10/0x10 [snd_soc_nau8821] +[ 3136.996882] nau8821_enable_jack_detect+0xa5/0xc0 [snd_soc_nau8821] +[ 3136.996901] acp5x_8821_init+0x8d/0xa0 [snd_soc_acp5x_mach] +[ 3136.996917] snd_soc_link_init+0x25/0x50 [snd_soc_core] +[ 3136.996958] snd_soc_bind_card+0x615/0xd00 [snd_soc_core] +[ 3136.997026] snd_soc_register_card+0x1b2/0x1c0 [snd_soc_core] +[ 3136.997064] devm_snd_soc_register_card+0x47/0x90 [snd_soc_core] +[ 3136.997108] acp5x_probe+0x72/0xb0 [snd_soc_acp5x_mach] +[...] +[ 3136.997508] nau8821 i2c-NVTN2020:00: Cannot request irq 58 (-16) + +Introduce jdet_active flag to driver data structure and use it to +provide one-time initialization of the jack detection work queue and +related interrupt line. + +Note this is also a prerequisite for additional fixes around module +unloading and suspend handling. + +Fixes: aab1ad11d69f ("ASoC: nau8821: new driver") +Signed-off-by: Cristian Ciocaltea +Link: https://patch.msgid.link/20251231-nau8821-cleanup-v1-1-6b0b76cbbb64@collabora.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/nau8821.c | 5 +++++ + sound/soc/codecs/nau8821.h | 1 + + 2 files changed, 6 insertions(+) + +diff --git a/sound/soc/codecs/nau8821.c b/sound/soc/codecs/nau8821.c +index 7b84939602985..3cf531258911b 100644 +--- a/sound/soc/codecs/nau8821.c ++++ b/sound/soc/codecs/nau8821.c +@@ -1667,8 +1667,13 @@ int nau8821_enable_jack_detect(struct snd_soc_component *component, + int ret; + + nau8821->jack = jack; ++ ++ if (nau8821->jdet_active) ++ return 0; ++ + /* Initiate jack detection work queue */ + INIT_DELAYED_WORK(&nau8821->jdet_work, nau8821_jdet_work); ++ nau8821->jdet_active = true; + + ret = devm_request_threaded_irq(nau8821->dev, nau8821->irq, NULL, + nau8821_interrupt, IRQF_TRIGGER_LOW | IRQF_ONESHOT, +diff --git a/sound/soc/codecs/nau8821.h b/sound/soc/codecs/nau8821.h +index 5abb91b087a12..ce0880cdd1899 100644 +--- a/sound/soc/codecs/nau8821.h ++++ b/sound/soc/codecs/nau8821.h +@@ -560,6 +560,7 @@ struct nau8821 { + struct snd_soc_dapm_context *dapm; + struct snd_soc_jack *jack; + struct delayed_work jdet_work; ++ bool jdet_active; + int irq; + int clk_id; + int micbias_voltage; +-- +2.51.0 + diff --git a/queue-6.6/audit-move-the-compat_xxx_class-extern-declarations-.patch b/queue-6.6/audit-move-the-compat_xxx_class-extern-declarations-.patch new file mode 100644 index 0000000000..72a514ec09 --- /dev/null +++ b/queue-6.6/audit-move-the-compat_xxx_class-extern-declarations-.patch @@ -0,0 +1,77 @@ +From bc19f3fbc267aa3da7e8b4b8a2c0a4384dd2edeb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 13:39:38 +0000 +Subject: audit: move the compat_xxx_class[] extern declarations to + audit_arch.h + +From: Ben Dooks + +[ Upstream commit 76489955c6d4a065ca69dc88faf7a50a59b66f35 ] + +The comapt_xxx_class symbols aren't declared in anything that +lib/comapt_audit.c is including (arm64 build) which is causing +the following sparse warnings: + +lib/compat_audit.c:7:10: warning: symbol 'compat_dir_class' + was not declared. Should it be static? +lib/compat_audit.c:12:10: warning: symbol 'compat_read_class' + was not declared. Should it be static? +lib/compat_audit.c:17:10: warning: symbol 'compat_write_class' + was not declared. Should it be static? +lib/compat_audit.c:22:10: warning: symbol 'compat_chattr_class' + was not declared. Should it be static? +lib/compat_audit.c:27:10: warning: symbol 'compat_signal_class' + was not declared. Should it be static? + +Trying to fix this by chaning compat_audit.c to inclde +does not work on arm64 due to compile errors with the extra includes +that changing this header makes. The simpler thing would be just to +move the definitons of these symbols out of into + which is included. + +Fixes: 4b58841149dca ("audit: Add generic compat syscall support") +Signed-off-by: Ben Dooks +[PM: rewrite subject line, fixed line length in description] +Signed-off-by: Paul Moore +Signed-off-by: Sasha Levin +--- + include/linux/audit.h | 6 ------ + include/linux/audit_arch.h | 7 +++++++ + 2 files changed, 7 insertions(+), 6 deletions(-) + +diff --git a/include/linux/audit.h b/include/linux/audit.h +index 7ca75f8873799..517c665da2597 100644 +--- a/include/linux/audit.h ++++ b/include/linux/audit.h +@@ -125,12 +125,6 @@ enum audit_nfcfgop { + extern int __init audit_register_class(int class, unsigned *list); + extern int audit_classify_syscall(int abi, unsigned syscall); + extern int audit_classify_arch(int arch); +-/* only for compat system calls */ +-extern unsigned compat_write_class[]; +-extern unsigned compat_read_class[]; +-extern unsigned compat_dir_class[]; +-extern unsigned compat_chattr_class[]; +-extern unsigned compat_signal_class[]; + + /* audit_names->type values */ + #define AUDIT_TYPE_UNKNOWN 0 /* we don't know yet */ +diff --git a/include/linux/audit_arch.h b/include/linux/audit_arch.h +index 0e34d673ef171..2b8153791e6a5 100644 +--- a/include/linux/audit_arch.h ++++ b/include/linux/audit_arch.h +@@ -23,4 +23,11 @@ enum auditsc_class_t { + + extern int audit_classify_compat_syscall(int abi, unsigned syscall); + ++/* only for compat system calls */ ++extern unsigned compat_write_class[]; ++extern unsigned compat_read_class[]; ++extern unsigned compat_dir_class[]; ++extern unsigned compat_chattr_class[]; ++extern unsigned compat_signal_class[]; ++ + #endif +-- +2.51.0 + diff --git a/queue-6.6/auxdisplay-arm-charlcd-fix-release_mem_region-size.patch b/queue-6.6/auxdisplay-arm-charlcd-fix-release_mem_region-size.patch new file mode 100644 index 0000000000..de9b4e5e04 --- /dev/null +++ b/queue-6.6/auxdisplay-arm-charlcd-fix-release_mem_region-size.patch @@ -0,0 +1,39 @@ +From 3c4193c01ff8df622c958eee5f69ed3874f126d9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Dec 2025 18:47:13 +0100 +Subject: auxdisplay: arm-charlcd: fix release_mem_region() size + +From: Thomas Fourier + +[ Upstream commit b5c23a4d291d2ac1dfdd574a68a3a68c8da3069e ] + +It seems like, after the request_mem_region(), the corresponding +release_mem_region() must take the same size. This was done +in (now removed due to previous refactoring) charlcd_remove() +but not in the error path in charlcd_probe(). + +Fixes: ce8962455e90 ("ARM: 6214/2: driver for the character LCD found in ARM refdesigns") +Signed-off-by: Thomas Fourier +Reviewed-by: Geert Uytterhoeven +Signed-off-by: Andy Shevchenko +Signed-off-by: Sasha Levin +--- + drivers/auxdisplay/arm-charlcd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/auxdisplay/arm-charlcd.c b/drivers/auxdisplay/arm-charlcd.c +index 0b1c99cca7334..f418b133ee752 100644 +--- a/drivers/auxdisplay/arm-charlcd.c ++++ b/drivers/auxdisplay/arm-charlcd.c +@@ -323,7 +323,7 @@ static int __init charlcd_probe(struct platform_device *pdev) + out_no_irq: + iounmap(lcd->virtbase); + out_no_memregion: +- release_mem_region(lcd->phybase, SZ_4K); ++ release_mem_region(lcd->phybase, lcd->physize); + out_no_resource: + kfree(lcd); + return ret; +-- +2.51.0 + diff --git a/queue-6.6/backlight-qcom-wled-change-pm8950-wled-configuration.patch b/queue-6.6/backlight-qcom-wled-change-pm8950-wled-configuration.patch new file mode 100644 index 0000000000..82ca6052a5 --- /dev/null +++ b/queue-6.6/backlight-qcom-wled-change-pm8950-wled-configuration.patch @@ -0,0 +1,42 @@ +From fcaa87fcce00607a070c4163102e2bd1d6d6caa6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 08:07:36 +0100 +Subject: backlight: qcom-wled: Change PM8950 WLED configurations +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Czémán + +[ Upstream commit 83333aa97441ba7ce32b91e8a007c72d316a1c67 ] + +PMI8950 WLED needs same configurations as PMI8994 WLED. + +Fixes: 10258bf4534b ("backlight: qcom-wled: Add PMI8950 compatible") +Signed-off-by: Barnabás Czémán +Reviewed-by: Konrad Dybcio +Reviewed-by: Daniel Thompson (RISCstar) +Link: https://patch.msgid.link/20260116-pmi8950-wled-v3-4-e6c93de84079@mainlining.org +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/video/backlight/qcom-wled.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c +index 79337e84069fb..0d55818f554ec 100644 +--- a/drivers/video/backlight/qcom-wled.c ++++ b/drivers/video/backlight/qcom-wled.c +@@ -1455,7 +1455,8 @@ static int wled_configure(struct wled *wled) + break; + + case 4: +- if (of_device_is_compatible(dev->of_node, "qcom,pmi8994-wled")) { ++ if (of_device_is_compatible(dev->of_node, "qcom,pmi8950-wled") || ++ of_device_is_compatible(dev->of_node, "qcom,pmi8994-wled")) { + u32_opts = pmi8994_wled_opts; + size = ARRAY_SIZE(pmi8994_wled_opts); + } else { +-- +2.51.0 + diff --git a/queue-6.6/backlight-qcom-wled-support-ovp-values-for-pmi8994.patch b/queue-6.6/backlight-qcom-wled-support-ovp-values-for-pmi8994.patch new file mode 100644 index 0000000000..7c54f926da --- /dev/null +++ b/queue-6.6/backlight-qcom-wled-support-ovp-values-for-pmi8994.patch @@ -0,0 +1,94 @@ +From 3ca9484beab88bb67f4e96a5ab89b103ddf9a8f1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 08:07:34 +0100 +Subject: backlight: qcom-wled: Support ovp values for PMI8994 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Czémán + +[ Upstream commit f29f972a6e7e3f187ea4d89b98a76c1981ca4d53 ] + +WLED4 found in PMI8994 supports different ovp values. + +Fixes: 6fc632d3e3e0 ("video: backlight: qcom-wled: Add PMI8994 compatible") +Signed-off-by: Barnabás Czémán +Reviewed-by: Konrad Dybcio +Reviewed-by: Daniel Thompson (RISCstar) +Link: https://patch.msgid.link/20260116-pmi8950-wled-v3-2-e6c93de84079@mainlining.org +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/video/backlight/qcom-wled.c | 41 +++++++++++++++++++++++++++-- + 1 file changed, 39 insertions(+), 2 deletions(-) + +diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c +index b19e5f73de8bb..79337e84069fb 100644 +--- a/drivers/video/backlight/qcom-wled.c ++++ b/drivers/video/backlight/qcom-wled.c +@@ -1244,6 +1244,15 @@ static const struct wled_var_cfg wled4_ovp_cfg = { + .size = ARRAY_SIZE(wled4_ovp_values), + }; + ++static const u32 pmi8994_wled_ovp_values[] = { ++ 31000, 29500, 19400, 17800, ++}; ++ ++static const struct wled_var_cfg pmi8994_wled_ovp_cfg = { ++ .values = pmi8994_wled_ovp_values, ++ .size = ARRAY_SIZE(pmi8994_wled_ovp_values), ++}; ++ + static inline u32 wled5_ovp_values_fn(u32 idx) + { + /* +@@ -1357,6 +1366,29 @@ static int wled_configure(struct wled *wled) + }, + }; + ++ const struct wled_u32_opts pmi8994_wled_opts[] = { ++ { ++ .name = "qcom,current-boost-limit", ++ .val_ptr = &cfg->boost_i_limit, ++ .cfg = &wled4_boost_i_limit_cfg, ++ }, ++ { ++ .name = "qcom,current-limit-microamp", ++ .val_ptr = &cfg->string_i_limit, ++ .cfg = &wled4_string_i_limit_cfg, ++ }, ++ { ++ .name = "qcom,ovp-millivolt", ++ .val_ptr = &cfg->ovp, ++ .cfg = &pmi8994_wled_ovp_cfg, ++ }, ++ { ++ .name = "qcom,switching-freq", ++ .val_ptr = &cfg->switch_freq, ++ .cfg = &wled3_switch_freq_cfg, ++ }, ++ }; ++ + const struct wled_u32_opts wled5_opts[] = { + { + .name = "qcom,current-boost-limit", +@@ -1423,8 +1455,13 @@ static int wled_configure(struct wled *wled) + break; + + case 4: +- u32_opts = wled4_opts; +- size = ARRAY_SIZE(wled4_opts); ++ if (of_device_is_compatible(dev->of_node, "qcom,pmi8994-wled")) { ++ u32_opts = pmi8994_wled_opts; ++ size = ARRAY_SIZE(pmi8994_wled_opts); ++ } else { ++ u32_opts = wled4_opts; ++ size = ARRAY_SIZE(wled4_opts); ++ } + *cfg = wled4_config_defaults; + wled->wled_set_brightness = wled4_set_brightness; + wled->wled_sync_toggle = wled3_sync_toggle; +-- +2.51.0 + diff --git a/queue-6.6/bonding-only-set-speed-duplex-to-unknown-if-getting-.patch b/queue-6.6/bonding-only-set-speed-duplex-to-unknown-if-getting-.patch new file mode 100644 index 0000000000..3fac2e38a0 --- /dev/null +++ b/queue-6.6/bonding-only-set-speed-duplex-to-unknown-if-getting-.patch @@ -0,0 +1,74 @@ +From 94f15c486d906e3ff4bad20ffdacf955529aa51d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 15:11:52 +0100 +Subject: bonding: only set speed/duplex to unknown, if getting speed failed + +From: Thomas Bogendoerfer + +[ Upstream commit 48dec8d88af96039a4a17b8c2f148f2a4066e195 ] + +bond_update_speed_duplex() first set speed/duplex to unknown and +then asks slave driver for current speed/duplex. Since getting +speed/duplex might take longer there is a race, where this false state +is visible by /proc/net/bonding. With commit 691b2bf14946 ("bonding: + update port speed when getting bond speed") this race gets more visible, +if user space is calling ethtool on a regular base. + +Fix this by only setting speed/duplex to unknown, if link speed is +really unknown/unusable. + +Fixes: 98f41f694f46 ("bonding:update speed/duplex for NETDEV_CHANGE") +Signed-off-by: Thomas Bogendoerfer +Acked-by: Jay Vosburgh +Reviewed-by: Nikolay Aleksandrov +Reviewed-by: Hangbin Liu +Link: https://patch.msgid.link/20260203141153.51581-1-tbogendoerfer@suse.de +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/bonding/bond_main.c | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c +index 4373e300879d9..4f8a59b4ba985 100644 +--- a/drivers/net/bonding/bond_main.c ++++ b/drivers/net/bonding/bond_main.c +@@ -727,26 +727,29 @@ static int bond_update_speed_duplex(struct slave *slave) + struct ethtool_link_ksettings ecmd; + int res; + +- slave->speed = SPEED_UNKNOWN; +- slave->duplex = DUPLEX_UNKNOWN; +- + res = __ethtool_get_link_ksettings(slave_dev, &ecmd); + if (res < 0) +- return 1; ++ goto speed_duplex_unknown; + if (ecmd.base.speed == 0 || ecmd.base.speed == ((__u32)-1)) +- return 1; ++ goto speed_duplex_unknown; + switch (ecmd.base.duplex) { + case DUPLEX_FULL: + case DUPLEX_HALF: + break; + default: +- return 1; ++ goto speed_duplex_unknown; + } + + slave->speed = ecmd.base.speed; + slave->duplex = ecmd.base.duplex; + + return 0; ++ ++speed_duplex_unknown: ++ slave->speed = SPEED_UNKNOWN; ++ slave->duplex = DUPLEX_UNKNOWN; ++ ++ return 1; + } + + const char *bond_slave_link_status(s8 link) +-- +2.51.0 + diff --git a/queue-6.6/bpf-fix-bpf_xdp_store_bytes-proto-for-read-only-arg.patch b/queue-6.6/bpf-fix-bpf_xdp_store_bytes-proto-for-read-only-arg.patch new file mode 100644 index 0000000000..80842ac697 --- /dev/null +++ b/queue-6.6/bpf-fix-bpf_xdp_store_bytes-proto-for-read-only-arg.patch @@ -0,0 +1,60 @@ +From 378f7faa31e0b293e03aa76b864a34c7b141bdad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Jan 2026 17:08:37 +0100 +Subject: bpf: Fix bpf_xdp_store_bytes proto for read-only arg + +From: Paul Chaignon + +[ Upstream commit 6557f1565d779851c4db9c488c49c05a47a6e72f ] + +While making some maps in Cilium read-only from the BPF side, we noticed +that the bpf_xdp_store_bytes proto is incorrect. In particular, the +verifier was throwing the following error: + + ; ret = ctx_store_bytes(ctx, l3_off + offsetof(struct iphdr, saddr), + &nat->address, 4, 0); + 635: (79) r1 = *(u64 *)(r10 -144) ; R1=ctx() R10=fp0 fp-144=ctx() + 636: (b4) w2 = 26 ; R2=26 + 637: (b4) w4 = 4 ; R4=4 + 638: (b4) w5 = 0 ; R5=0 + 639: (85) call bpf_xdp_store_bytes#190 + write into map forbidden, value_size=6 off=0 size=4 + +nat comes from a BPF_F_RDONLY_PROG map, so R3 is a PTR_TO_MAP_VALUE. +The verifier checks the helper's memory access to R3 in +check_mem_size_reg, as it reaches ARG_CONST_SIZE argument. The third +argument has expected type ARG_PTR_TO_UNINIT_MEM, which includes the +MEM_WRITE flag. The verifier thus checks for a BPF_WRITE access on R3. +Given R3 points to a read-only map, the check fails. + +Conversely, ARG_PTR_TO_UNINIT_MEM can also lead to the helper reading +from uninitialized memory. + +This patch simply fixes the expected argument type to match that of +bpf_skb_store_bytes. + +Fixes: 3f364222d032 ("net: xdp: introduce bpf_xdp_pointer utility routine") +Signed-off-by: Paul Chaignon +Link: https://lore.kernel.org/r/9fa3c9f72d806e82541071c4df88b8cba28ad6a9.1769875479.git.paul.chaignon@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + net/core/filter.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/core/filter.c b/net/core/filter.c +index ddb6d3dd34deb..e5dc1f699297b 100644 +--- a/net/core/filter.c ++++ b/net/core/filter.c +@@ -4118,7 +4118,7 @@ static const struct bpf_func_proto bpf_xdp_store_bytes_proto = { + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_CTX, + .arg2_type = ARG_ANYTHING, +- .arg3_type = ARG_PTR_TO_UNINIT_MEM, ++ .arg3_type = ARG_PTR_TO_MEM | MEM_RDONLY, + .arg4_type = ARG_CONST_SIZE, + }; + +-- +2.51.0 + diff --git a/queue-6.6/bpf-sockmap-fix-fionread-for-sockmap.patch b/queue-6.6/bpf-sockmap-fix-fionread-for-sockmap.patch new file mode 100644 index 0000000000..5152eb6a06 --- /dev/null +++ b/queue-6.6/bpf-sockmap-fix-fionread-for-sockmap.patch @@ -0,0 +1,293 @@ +From 2fdba7d83466f1895b858e716967620c5d137616 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 24 Jan 2026 19:32:44 +0800 +Subject: bpf, sockmap: Fix FIONREAD for sockmap + +From: Jiayuan Chen + +[ Upstream commit 929e30f9312514902133c45e51c79088421ab084 ] + +A socket using sockmap has its own independent receive queue: ingress_msg. +This queue may contain data from its own protocol stack or from other +sockets. + +Therefore, for sockmap, relying solely on copied_seq and rcv_nxt to +calculate FIONREAD is not enough. + +This patch adds a new msg_tot_len field in the psock structure to record +the data length in ingress_msg. Additionally, we implement new ioctl +interfaces for TCP and UDP to intercept FIONREAD operations. + +Note that we intentionally do not include sk_receive_queue data in the +FIONREAD result. Data in sk_receive_queue has not yet been processed by +the BPF verdict program, and may be redirected to other sockets or +dropped. Including it would create semantic ambiguity since this data +may never be readable by the user. + +Unix and VSOCK sockets have similar issues, but fixing them is outside +the scope of this patch as it would require more intrusive changes. + +Previous work by John Fastabend made some efforts towards FIONREAD support: +commit e5c6de5fa025 ("bpf, sockmap: Incorrectly handling copied_seq") +Although the current patch is based on the previous work by John Fastabend, +it is acceptable for our Fixes tag to point to the same commit. + + FD1:read() + -- FD1->copied_seq++ + | [read data] + | + [enqueue data] v + [sockmap] -> ingress to self -> ingress_msg queue +FD1 native stack ------> ^ +-- FD1->rcv_nxt++ -> redirect to other | [enqueue data] + | | + | ingress to FD1 + v ^ + ... | [sockmap] + FD2 native stack + +Fixes: 04919bed948dc ("tcp: Introduce tcp_read_skb()") +Signed-off-by: Jiayuan Chen +Reviewed-by: Jakub Sitnicki +Link: https://lore.kernel.org/r/20260124113314.113584-3-jiayuan.chen@linux.dev +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + include/linux/skmsg.h | 68 +++++++++++++++++++++++++++++++++++++++++-- + net/core/skmsg.c | 3 ++ + net/ipv4/tcp_bpf.c | 20 +++++++++++++ + net/ipv4/udp_bpf.c | 23 ++++++++++++--- + 4 files changed, 108 insertions(+), 6 deletions(-) + +diff --git a/include/linux/skmsg.h b/include/linux/skmsg.h +index 5c5a2d65184c3..e923f1c24ce4b 100644 +--- a/include/linux/skmsg.h ++++ b/include/linux/skmsg.h +@@ -93,6 +93,8 @@ struct sk_psock { + struct sk_buff_head ingress_skb; + struct list_head ingress_msg; + spinlock_t ingress_lock; ++ /** @msg_tot_len: Total bytes queued in ingress_msg list. */ ++ u32 msg_tot_len; + unsigned long state; + struct list_head link; + spinlock_t link_lock; +@@ -312,6 +314,27 @@ static inline void sock_drop(struct sock *sk, struct sk_buff *skb) + kfree_skb(skb); + } + ++static inline u32 sk_psock_get_msg_len_nolock(struct sk_psock *psock) ++{ ++ /* Used by ioctl to read msg_tot_len only; lock-free for performance */ ++ return READ_ONCE(psock->msg_tot_len); ++} ++ ++static inline void sk_psock_msg_len_add_locked(struct sk_psock *psock, int diff) ++{ ++ /* Use WRITE_ONCE to ensure correct read in sk_psock_get_msg_len_nolock(). ++ * ingress_lock should be held to prevent concurrent updates to msg_tot_len ++ */ ++ WRITE_ONCE(psock->msg_tot_len, psock->msg_tot_len + diff); ++} ++ ++static inline void sk_psock_msg_len_add(struct sk_psock *psock, int diff) ++{ ++ spin_lock_bh(&psock->ingress_lock); ++ sk_psock_msg_len_add_locked(psock, diff); ++ spin_unlock_bh(&psock->ingress_lock); ++} ++ + static inline bool sk_psock_queue_msg(struct sk_psock *psock, + struct sk_msg *msg) + { +@@ -320,6 +343,7 @@ static inline bool sk_psock_queue_msg(struct sk_psock *psock, + spin_lock_bh(&psock->ingress_lock); + if (sk_psock_test_state(psock, SK_PSOCK_TX_ENABLED)) { + list_add_tail(&msg->list, &psock->ingress_msg); ++ sk_psock_msg_len_add_locked(psock, msg->sg.size); + ret = true; + } else { + sk_msg_free(psock->sk, msg); +@@ -336,18 +360,25 @@ static inline struct sk_msg *sk_psock_dequeue_msg(struct sk_psock *psock) + + spin_lock_bh(&psock->ingress_lock); + msg = list_first_entry_or_null(&psock->ingress_msg, struct sk_msg, list); +- if (msg) ++ if (msg) { + list_del(&msg->list); ++ sk_psock_msg_len_add_locked(psock, -msg->sg.size); ++ } + spin_unlock_bh(&psock->ingress_lock); + return msg; + } + ++static inline struct sk_msg *sk_psock_peek_msg_locked(struct sk_psock *psock) ++{ ++ return list_first_entry_or_null(&psock->ingress_msg, struct sk_msg, list); ++} ++ + static inline struct sk_msg *sk_psock_peek_msg(struct sk_psock *psock) + { + struct sk_msg *msg; + + spin_lock_bh(&psock->ingress_lock); +- msg = list_first_entry_or_null(&psock->ingress_msg, struct sk_msg, list); ++ msg = sk_psock_peek_msg_locked(psock); + spin_unlock_bh(&psock->ingress_lock); + return msg; + } +@@ -511,6 +542,39 @@ static inline bool sk_psock_strp_enabled(struct sk_psock *psock) + return !!psock->saved_data_ready; + } + ++/* for tcp only, sk is locked */ ++static inline ssize_t sk_psock_msg_inq(struct sock *sk) ++{ ++ struct sk_psock *psock; ++ ssize_t inq = 0; ++ ++ psock = sk_psock_get(sk); ++ if (likely(psock)) { ++ inq = sk_psock_get_msg_len_nolock(psock); ++ sk_psock_put(sk, psock); ++ } ++ return inq; ++} ++ ++/* for udp only, sk is not locked */ ++static inline ssize_t sk_msg_first_len(struct sock *sk) ++{ ++ struct sk_psock *psock; ++ struct sk_msg *msg; ++ ssize_t inq = 0; ++ ++ psock = sk_psock_get(sk); ++ if (likely(psock)) { ++ spin_lock_bh(&psock->ingress_lock); ++ msg = sk_psock_peek_msg_locked(psock); ++ if (msg) ++ inq = msg->sg.size; ++ spin_unlock_bh(&psock->ingress_lock); ++ sk_psock_put(sk, psock); ++ } ++ return inq; ++} ++ + #if IS_ENABLED(CONFIG_NET_SOCK_MSG) + + #define BPF_F_STRPARSER (1UL << 1) +diff --git a/net/core/skmsg.c b/net/core/skmsg.c +index 9f522835bfafe..5d557ba9c0cb4 100644 +--- a/net/core/skmsg.c ++++ b/net/core/skmsg.c +@@ -457,6 +457,7 @@ int __sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg + atomic_sub(copy, &sk->sk_rmem_alloc); + } + msg_rx->sg.size -= copy; ++ sk_psock_msg_len_add(psock, -copy); + + if (!sge->length) { + sk_msg_iter_var_next(i); +@@ -820,9 +821,11 @@ static void __sk_psock_purge_ingress_msg(struct sk_psock *psock) + list_del(&msg->list); + if (!msg->skb) + atomic_sub(msg->sg.size, &psock->sk->sk_rmem_alloc); ++ sk_psock_msg_len_add(psock, -msg->sg.size); + sk_msg_free(psock->sk, msg); + kfree(msg); + } ++ WARN_ON_ONCE(psock->msg_tot_len); + } + + static void __sk_psock_zap_ingress(struct sk_psock *psock) +diff --git a/net/ipv4/tcp_bpf.c b/net/ipv4/tcp_bpf.c +index 5ff5faa2adde0..06a185bb1e35c 100644 +--- a/net/ipv4/tcp_bpf.c ++++ b/net/ipv4/tcp_bpf.c +@@ -10,6 +10,7 @@ + + #include + #include ++#include + + void tcp_eat_skb(struct sock *sk, struct sk_buff *skb) + { +@@ -332,6 +333,24 @@ static int tcp_bpf_recvmsg_parser(struct sock *sk, + return copied; + } + ++static int tcp_bpf_ioctl(struct sock *sk, int cmd, int *karg) ++{ ++ bool slow; ++ ++ if (cmd != SIOCINQ) ++ return tcp_ioctl(sk, cmd, karg); ++ ++ /* works similar as tcp_ioctl */ ++ if (sk->sk_state == TCP_LISTEN) ++ return -EINVAL; ++ ++ slow = lock_sock_fast(sk); ++ *karg = sk_psock_msg_inq(sk); ++ unlock_sock_fast(sk, slow); ++ ++ return 0; ++} ++ + static int tcp_bpf_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, + int flags, int *addr_len) + { +@@ -610,6 +629,7 @@ static void tcp_bpf_rebuild_protos(struct proto prot[TCP_BPF_NUM_CFGS], + prot[TCP_BPF_BASE].close = sock_map_close; + prot[TCP_BPF_BASE].recvmsg = tcp_bpf_recvmsg; + prot[TCP_BPF_BASE].sock_is_readable = sk_msg_is_readable; ++ prot[TCP_BPF_BASE].ioctl = tcp_bpf_ioctl; + + prot[TCP_BPF_TX] = prot[TCP_BPF_BASE]; + prot[TCP_BPF_TX].sendmsg = tcp_bpf_sendmsg; +diff --git a/net/ipv4/udp_bpf.c b/net/ipv4/udp_bpf.c +index 0735d820e413f..91233e37cd97a 100644 +--- a/net/ipv4/udp_bpf.c ++++ b/net/ipv4/udp_bpf.c +@@ -5,6 +5,7 @@ + #include + #include + #include ++#include + + #include "udp_impl.h" + +@@ -111,12 +112,26 @@ enum { + static DEFINE_SPINLOCK(udpv6_prot_lock); + static struct proto udp_bpf_prots[UDP_BPF_NUM_PROTS]; + ++static int udp_bpf_ioctl(struct sock *sk, int cmd, int *karg) ++{ ++ if (cmd != SIOCINQ) ++ return udp_ioctl(sk, cmd, karg); ++ ++ /* Since we don't hold a lock, sk_receive_queue may contain data. ++ * BPF might only be processing this data at the moment. We only ++ * care about the data in the ingress_msg here. ++ */ ++ *karg = sk_msg_first_len(sk); ++ return 0; ++} ++ + static void udp_bpf_rebuild_protos(struct proto *prot, const struct proto *base) + { +- *prot = *base; +- prot->close = sock_map_close; +- prot->recvmsg = udp_bpf_recvmsg; +- prot->sock_is_readable = sk_msg_is_readable; ++ *prot = *base; ++ prot->close = sock_map_close; ++ prot->recvmsg = udp_bpf_recvmsg; ++ prot->sock_is_readable = sk_msg_is_readable; ++ prot->ioctl = udp_bpf_ioctl; + } + + static void udp_bpf_check_v6_needs_rebuild(struct proto *ops) +-- +2.51.0 + diff --git a/queue-6.6/bpf-sockmap-fix-incorrect-copied_seq-calculation.patch b/queue-6.6/bpf-sockmap-fix-incorrect-copied_seq-calculation.patch new file mode 100644 index 0000000000..a13752ba79 --- /dev/null +++ b/queue-6.6/bpf-sockmap-fix-incorrect-copied_seq-calculation.patch @@ -0,0 +1,178 @@ +From cf48b09c84b3ffa0df1c57431952eb3848c3035a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 24 Jan 2026 19:32:43 +0800 +Subject: bpf, sockmap: Fix incorrect copied_seq calculation + +From: Jiayuan Chen + +[ Upstream commit b40cc5adaa80e1471095a62d78233b611d7a558c ] + +A socket using sockmap has its own independent receive queue: ingress_msg. +This queue may contain data from its own protocol stack or from other +sockets. + +The issue is that when reading from ingress_msg, we update tp->copied_seq +by default. However, if the data is not from its own protocol stack, +tcp->rcv_nxt is not increased. Later, if we convert this socket to a +native socket, reading from this socket may fail because copied_seq might +be significantly larger than rcv_nxt. + +This fix also addresses the syzkaller-reported bug referenced in the +Closes tag. + +This patch marks the skmsg objects in ingress_msg. When reading, we update +copied_seq only if the data is from its own protocol stack. + + FD1:read() + -- FD1->copied_seq++ + | [read data] + | + [enqueue data] v + [sockmap] -> ingress to self -> ingress_msg queue +FD1 native stack ------> ^ +-- FD1->rcv_nxt++ -> redirect to other | [enqueue data] + | | + | ingress to FD1 + v ^ + ... | [sockmap] + FD2 native stack + +Closes: https://syzkaller.appspot.com/bug?extid=06dbd397158ec0ea4983 +Fixes: 04919bed948dc ("tcp: Introduce tcp_read_skb()") +Reviewed-by: Jakub Sitnicki +Reviewed-by: John Fastabend +Signed-off-by: Jiayuan Chen +Link: https://lore.kernel.org/r/20260124113314.113584-2-jiayuan.chen@linux.dev +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + include/linux/skmsg.h | 2 ++ + net/core/skmsg.c | 27 ++++++++++++++++++++++++--- + net/ipv4/tcp_bpf.c | 5 +++-- + 3 files changed, 29 insertions(+), 5 deletions(-) + +diff --git a/include/linux/skmsg.h b/include/linux/skmsg.h +index 32bbebf5b71e3..5c5a2d65184c3 100644 +--- a/include/linux/skmsg.h ++++ b/include/linux/skmsg.h +@@ -132,6 +132,8 @@ int sk_msg_memcopy_from_iter(struct sock *sk, struct iov_iter *from, + struct sk_msg *msg, u32 bytes); + int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, + int len, int flags); ++int __sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, ++ int len, int flags, int *copied_from_self); + bool sk_msg_is_readable(struct sock *sk); + + static inline void sk_msg_check_to_free(struct sk_msg *msg, u32 i, u32 bytes) +diff --git a/net/core/skmsg.c b/net/core/skmsg.c +index 6225547808a6b..9f522835bfafe 100644 +--- a/net/core/skmsg.c ++++ b/net/core/skmsg.c +@@ -408,22 +408,26 @@ int sk_msg_memcopy_from_iter(struct sock *sk, struct iov_iter *from, + } + EXPORT_SYMBOL_GPL(sk_msg_memcopy_from_iter); + +-/* Receive sk_msg from psock->ingress_msg to @msg. */ +-int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, +- int len, int flags) ++int __sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, ++ int len, int flags, int *copied_from_self) + { + struct iov_iter *iter = &msg->msg_iter; + int peek = flags & MSG_PEEK; + struct sk_msg *msg_rx; + int i, copied = 0; ++ bool from_self; + + msg_rx = sk_psock_peek_msg(psock); ++ if (copied_from_self) ++ *copied_from_self = 0; ++ + while (copied != len) { + struct scatterlist *sge; + + if (unlikely(!msg_rx)) + break; + ++ from_self = msg_rx->sk == sk; + i = msg_rx->sg.start; + do { + struct page *page; +@@ -442,6 +446,9 @@ int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, + } + + copied += copy; ++ if (from_self && copied_from_self) ++ *copied_from_self += copy; ++ + if (likely(!peek)) { + sge->offset += copy; + sge->length -= copy; +@@ -486,6 +493,13 @@ int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, + out: + return copied; + } ++ ++/* Receive sk_msg from psock->ingress_msg to @msg. */ ++int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, ++ int len, int flags) ++{ ++ return __sk_msg_recvmsg(sk, psock, msg, len, flags, NULL); ++} + EXPORT_SYMBOL_GPL(sk_msg_recvmsg); + + bool sk_msg_is_readable(struct sock *sk) +@@ -615,6 +629,12 @@ static int sk_psock_skb_ingress_self(struct sk_psock *psock, struct sk_buff *skb + if (unlikely(!msg)) + return -EAGAIN; + skb_set_owner_r(skb, sk); ++ ++ /* This is used in tcp_bpf_recvmsg_parser() to determine whether the ++ * data originates from the socket's own protocol stack. No need to ++ * refcount sk because msg's lifetime is bound to sk via the ingress_msg. ++ */ ++ msg->sk = sk; + err = sk_psock_skb_ingress_enqueue(skb, off, len, psock, sk, msg, take_ref); + if (err < 0) + kfree(msg); +@@ -908,6 +928,7 @@ int sk_psock_msg_verdict(struct sock *sk, struct sk_psock *psock, + sk_msg_compute_data_pointers(msg); + msg->sk = sk; + ret = bpf_prog_run_pin_on_cpu(prog, msg); ++ msg->sk = NULL; + ret = sk_psock_map_verd(ret, msg->sk_redir); + psock->apply_bytes = msg->apply_bytes; + if (ret == __SK_REDIRECT) { +diff --git a/net/ipv4/tcp_bpf.c b/net/ipv4/tcp_bpf.c +index 7518d2af63088..5ff5faa2adde0 100644 +--- a/net/ipv4/tcp_bpf.c ++++ b/net/ipv4/tcp_bpf.c +@@ -226,6 +226,7 @@ static int tcp_bpf_recvmsg_parser(struct sock *sk, + int peek = flags & MSG_PEEK; + struct sk_psock *psock; + struct tcp_sock *tcp; ++ int copied_from_self = 0; + int copied = 0; + u32 seq; + +@@ -262,7 +263,7 @@ static int tcp_bpf_recvmsg_parser(struct sock *sk, + } + + msg_bytes_ready: +- copied = sk_msg_recvmsg(sk, psock, msg, len, flags); ++ copied = __sk_msg_recvmsg(sk, psock, msg, len, flags, &copied_from_self); + /* The typical case for EFAULT is the socket was gracefully + * shutdown with a FIN pkt. So check here the other case is + * some error on copy_page_to_iter which would be unexpected. +@@ -277,7 +278,7 @@ static int tcp_bpf_recvmsg_parser(struct sock *sk, + goto out; + } + } +- seq += copied; ++ seq += copied_from_self; + if (!copied) { + long timeo; + int data; +-- +2.51.0 + diff --git a/queue-6.6/btrfs-fix-block_group_tree-dirty_list-corruption.patch b/queue-6.6/btrfs-fix-block_group_tree-dirty_list-corruption.patch new file mode 100644 index 0000000000..650717f90e --- /dev/null +++ b/queue-6.6/btrfs-fix-block_group_tree-dirty_list-corruption.patch @@ -0,0 +1,150 @@ +From b13221cccbc9f2bda91ef0631a1c98bdbfbe4e2e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 22 Dec 2025 16:15:44 -0800 +Subject: btrfs: fix block_group_tree dirty_list corruption + +From: Boris Burkov + +[ Upstream commit 3a1f4264daed4b419c325a7fe35e756cada3cf82 ] + +When the incompat flag EXTENT_TREE_V2 is set, we unconditionally add the +block group tree to the switch_commits list before calling +switch_commit_roots, as we do for the tree root and the chunk root. +However, the block group tree uses normal root dirty tracking and in any +transaction that does an allocation and dirties a block group, the block +group root will already be linked to a list by the dirty_list field and +this use of list_add_tail() is invalid and corrupts the prev/next +members of block_group_root->dirty_list. + +This is apparent on a subsequent list_del on the prev if we enable +CONFIG_DEBUG_LIST: + + [32.1571] ------------[ cut here ]------------ + [32.1572] list_del corruption. next->prev should beffff958890202538, but was ffff9588992bd538. (next=ffff958890201538) + [32.1575] WARNING: lib/list_debug.c:65 at 0x0, CPU#3: sync/607 + [32.1583] CPU: 3 UID: 0 PID: 607 Comm: sync Not tainted 6.18.0 #24PREEMPT(none) + [32.1585] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS1.17.0-4.fc41 04/01/2014 + [32.1587] RIP: 0010:__list_del_entry_valid_or_report+0x108/0x120 + [32.1593] RSP: 0018:ffffaa288287fdd0 EFLAGS: 00010202 + [32.1594] RAX: 0000000000000001 RBX: ffff95889326e800 RCX:ffff958890201538 + [32.1596] RDX: ffff9588992bd538 RSI: ffff958890202538 RDI:ffffffff82a41e00 + [32.1597] RBP: ffff958890202538 R08: ffffffff828fc1e8 R09:00000000ffffefff + [32.1599] R10: ffffffff8288c200 R11: ffffffff828e4200 R12:ffff958890201538 + [32.1601] R13: ffff95889326e958 R14: ffff958895c24000 R15:ffff958890202538 + [32.1603] FS: 00007f0c28eb5740(0000) GS:ffff958af2bd2000(0000)knlGS:0000000000000000 + [32.1605] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + [32.1607] CR2: 00007f0c28e8a3cc CR3: 0000000109942005 CR4:0000000000370ef0 + [32.1609] Call Trace: + [32.1610] + [32.1611] switch_commit_roots+0x82/0x1d0 [btrfs] + [32.1615] btrfs_commit_transaction+0x968/0x1550 [btrfs] + [32.1618] ? btrfs_attach_transaction_barrier+0x23/0x60 [btrfs] + [32.1621] __iterate_supers+0xe8/0x190 + [32.1622] ? __pfx_sync_fs_one_sb+0x10/0x10 + [32.1623] ksys_sync+0x63/0xb0 + [32.1624] __do_sys_sync+0xe/0x20 + [32.1625] do_syscall_64+0x73/0x450 + [32.1626] entry_SYSCALL_64_after_hwframe+0x76/0x7e + [32.1627] RIP: 0033:0x7f0c28d05d2b + [32.1632] RSP: 002b:00007ffc9d988048 EFLAGS: 00000246 ORIG_RAX:00000000000000a2 + [32.1634] RAX: ffffffffffffffda RBX: 00007ffc9d988228 RCX:00007f0c28d05d2b + [32.1636] RDX: 00007f0c28e02301 RSI: 00007ffc9d989b21 RDI:00007f0c28dba90d + [32.1637] RBP: 0000000000000001 R08: 0000000000000001 R09:0000000000000000 + [32.1639] R10: 0000000000000000 R11: 0000000000000246 R12:000055b96572cb80 + [32.1641] R13: 000055b96572b19f R14: 00007f0c28dfa434 R15:000055b96572b034 + [32.1643] + [32.1644] irq event stamp: 0 + [32.1644] hardirqs last enabled at (0): [<0000000000000000>] 0x0 + [32.1646] hardirqs last disabled at (0): []copy_process+0xb37/0x2260 + [32.1648] softirqs last enabled at (0): []copy_process+0xb37/0x2260 + [32.1650] softirqs last disabled at (0): [<0000000000000000>] 0x0 + [32.1652] ---[ end trace 0000000000000000 ]--- + +Furthermore, this list corruption eventually (when we happen to add a +new block group) results in getting the switch_commits and +dirty_cowonly_roots lists mixed up and attempting to call update_root +on the tree root which can't be found in the tree root, resulting in a +transaction abort: + + [87.8269] BTRFS critical (device nvme1n1): unable to find root key (1 0 0) in tree 1 + [87.8272] ------------[ cut here ]------------ + [87.8274] BTRFS: Transaction aborted (error -117) + [87.8275] WARNING: fs/btrfs/root-tree.c:153 at 0x0, CPU#4: sync/703 + [87.8285] CPU: 4 UID: 0 PID: 703 Comm: sync Not tainted 6.18.0 #25 PREEMPT(none) + [87.8287] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.17.0-4.fc41 04/01/2014 + [87.8289] RIP: 0010:btrfs_update_root+0x296/0x790 [btrfs] + [87.8295] RSP: 0018:ffffa58d035dfd60 EFLAGS: 00010282 + [87.8297] RAX: ffff9a59126ddb68 RBX: ffff9a59126dc000 RCX: 0000000000000000 + [87.8299] RDX: 0000000000000000 RSI: 00000000ffffff8b RDI: ffffffffc0b28270 + [87.8301] RBP: ffff9a5904aec000 R08: 0000000000000000 R09: 00000000ffffefff + [87.8303] R10: ffffffff9ac8c200 R11: ffffffff9ace4200 R12: 0000000000000001 + [87.8305] R13: ffff9a59041740e8 R14: ffff9a5904aec1f7 R15: ffff9a590fdefaf0 + [87.8307] FS: 00007f54cde6b740(0000) GS:ffff9a5b5a81c000(0000) knlGS:0000000000000000 + [87.8309] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + [87.8310] CR2: 00007f54cde403cc CR3: 0000000112902004 CR4: 0000000000370ef0 + [87.8312] Call Trace: + [87.8313] + [87.8314] ? _raw_spin_unlock+0x23/0x40 + [87.8315] commit_cowonly_roots+0x1ad/0x250 [btrfs] + [87.8317] ? btrfs_commit_transaction+0x79b/0x1560 [btrfs] + [87.8320] btrfs_commit_transaction+0x8aa/0x1560 [btrfs] + [87.8322] ? btrfs_attach_transaction_barrier+0x23/0x60 [btrfs] + [87.8325] __iterate_supers+0xf1/0x170 + [87.8326] ? __pfx_sync_fs_one_sb+0x10/0x10 + [87.8327] ksys_sync+0x63/0xb0 + [87.8328] __do_sys_sync+0xe/0x20 + [87.8329] do_syscall_64+0x73/0x450 + [87.8330] entry_SYSCALL_64_after_hwframe+0x76/0x7e + [87.8331] RIP: 0033:0x7f54cdd05d2b + [87.8336] RSP: 002b:00007fff1b58ff78 EFLAGS: 00000246 ORIG_RAX: 00000000000000a2 + [87.8338] RAX: ffffffffffffffda RBX: 00007fff1b590158 RCX: 00007f54cdd05d2b + [87.8340] RDX: 00007f54cde02301 RSI: 00007fff1b592b66 RDI: 00007f54cddba90d + [87.8342] RBP: 0000000000000001 R08: 0000000000000001 R09: 0000000000000000 + [87.8344] R10: 0000000000000000 R11: 0000000000000246 R12: 000055e07ca96b80 + [87.8346] R13: 000055e07ca9519f R14: 00007f54cddfa434 R15: 000055e07ca95034 + [87.8348] + [87.8348] irq event stamp: 0 + [87.8349] hardirqs last enabled at (0): [<0000000000000000>] 0x0 + [87.8351] hardirqs last disabled at (0): [] copy_process+0xb37/0x21e0 + [87.8353] softirqs last enabled at (0): [] copy_process+0xb37/0x21e0 + [87.8355] softirqs last disabled at (0): [<0000000000000000>] 0x0 + [87.8357] ---[ end trace 0000000000000000 ]--- + [87.8358] BTRFS: error (device nvme1n1 state A) in btrfs_update_root:153: errno=-117 Filesystem corrupted + [87.8360] BTRFS info (device nvme1n1 state EA): forced readonly + [87.8362] BTRFS warning (device nvme1n1 state EA): Skipping commit of aborted transaction. + [87.8364] BTRFS: error (device nvme1n1 state EA) in cleanup_transaction:2037: errno=-117 Filesystem corrupted + +Since the block group tree was pulled out of the extent tree and uses +normal root dirty tracking, remove the offending extra list_add. This +fixes the list corruption and the resulting fs corruption. + +Fixes: 14033b08a029 ("btrfs: don't save block group root into super block") +Reviewed-by: Filipe Manana +Signed-off-by: Boris Burkov +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/transaction.c | 7 ------- + 1 file changed, 7 deletions(-) + +diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c +index ce1e5b5dae3a0..6dbbb03be562f 100644 +--- a/fs/btrfs/transaction.c ++++ b/fs/btrfs/transaction.c +@@ -2457,13 +2457,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans) + list_add_tail(&fs_info->chunk_root->dirty_list, + &cur_trans->switch_commits); + +- if (btrfs_fs_incompat(fs_info, EXTENT_TREE_V2)) { +- btrfs_set_root_node(&fs_info->block_group_root->root_item, +- fs_info->block_group_root->node); +- list_add_tail(&fs_info->block_group_root->dirty_list, +- &cur_trans->switch_commits); +- } +- + switch_commit_roots(trans); + + ASSERT(list_empty(&cur_trans->dirty_bgs)); +-- +2.51.0 + diff --git a/queue-6.6/btrfs-qgroup-return-correct-error-when-deleting-qgro.patch b/queue-6.6/btrfs-qgroup-return-correct-error-when-deleting-qgro.patch new file mode 100644 index 0000000000..5e73013be5 --- /dev/null +++ b/queue-6.6/btrfs-qgroup-return-correct-error-when-deleting-qgro.patch @@ -0,0 +1,43 @@ +From e64e0edca1ecd962c93c2ddab908cec4b683eeea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 19:35:23 +0000 +Subject: btrfs: qgroup: return correct error when deleting qgroup relation + item + +From: Filipe Manana + +[ Upstream commit 51b1fcf71c88c3c89e7dcf07869c5de837b1f428 ] + +If we fail to delete the second qgroup relation item, we end up returning +success or -ENOENT in case the first item does not exist, instead of +returning the error from the second item deletion. + +Fixes: 73798c465b66 ("btrfs: qgroup: Try our best to delete qgroup relations") +Reviewed-by: Johannes Thumshirn +Signed-off-by: Filipe Manana +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/qgroup.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c +index c46ea2ecf1881..d27b9e0fa229a 100644 +--- a/fs/btrfs/qgroup.c ++++ b/fs/btrfs/qgroup.c +@@ -1601,8 +1601,10 @@ static int __del_qgroup_relation(struct btrfs_trans_handle *trans, u64 src, + if (ret < 0 && ret != -ENOENT) + goto out; + ret2 = del_qgroup_relation_item(trans, dst, src); +- if (ret2 < 0 && ret2 != -ENOENT) ++ if (ret2 < 0 && ret2 != -ENOENT) { ++ ret = ret2; + goto out; ++ } + + /* At least one deletion succeeded, return 0 */ + if (!ret || !ret2) +-- +2.51.0 + diff --git a/queue-6.6/clk-mediatek-fix-error-handling-in-runtime-pm-setup.patch b/queue-6.6/clk-mediatek-fix-error-handling-in-runtime-pm-setup.patch new file mode 100644 index 0000000000..ceb5362310 --- /dev/null +++ b/queue-6.6/clk-mediatek-fix-error-handling-in-runtime-pm-setup.patch @@ -0,0 +1,66 @@ +From 4463da5e8d38e309f91a084a9bab9de29f7c9c4a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 23 Nov 2025 23:43:15 +0800 +Subject: clk: mediatek: Fix error handling in runtime PM setup + +From: Haotian Zhang + +[ Upstream commit aa2ad19210a6a444111bce55e8b69579f29318fb ] + +devm_pm_runtime_enable() can fail due to memory allocation. The current +code ignores its return value, and when pm_runtime_resume_and_get() fails, +it returns directly without unmapping the shared_io region. + +Add error handling for devm_pm_runtime_enable(). Reorder cleanup labels +to properly unmap shared_io on pm_runtime_resume_and_get() failure. + +Fixes: 2f7b1d8b5505 ("clk: mediatek: Do a runtime PM get on controllers during probe") +Signed-off-by: Haotian Zhang +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + drivers/clk/mediatek/clk-mtk.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c +index ba1d1c495bc2b..644e5a854f2b6 100644 +--- a/drivers/clk/mediatek/clk-mtk.c ++++ b/drivers/clk/mediatek/clk-mtk.c +@@ -497,14 +497,16 @@ static int __mtk_clk_simple_probe(struct platform_device *pdev, + + + if (mcd->need_runtime_pm) { +- devm_pm_runtime_enable(&pdev->dev); ++ r = devm_pm_runtime_enable(&pdev->dev); ++ if (r) ++ goto unmap_io; + /* + * Do a pm_runtime_resume_and_get() to workaround a possible + * deadlock between clk_register() and the genpd framework. + */ + r = pm_runtime_resume_and_get(&pdev->dev); + if (r) +- return r; ++ goto unmap_io; + } + + /* Calculate how many clk_hw_onecell_data entries to allocate */ +@@ -618,11 +620,11 @@ static int __mtk_clk_simple_probe(struct platform_device *pdev, + free_data: + mtk_free_clk_data(clk_data); + free_base: +- if (mcd->shared_io && base) +- iounmap(base); +- + if (mcd->need_runtime_pm) + pm_runtime_put(&pdev->dev); ++unmap_io: ++ if (mcd->shared_io && base) ++ iounmap(base); + return r; + } + +-- +2.51.0 + diff --git a/queue-6.6/clk-meson-gxbb-limit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch b/queue-6.6/clk-meson-gxbb-limit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch new file mode 100644 index 0000000000..49e9ac3817 --- /dev/null +++ b/queue-6.6/clk-meson-gxbb-limit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch @@ -0,0 +1,87 @@ +From b65072ca34bc7909dc73bbf9f2c6ae4fc93a8ddb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Jan 2026 21:47:08 +0100 +Subject: clk: meson: gxbb: Limit the HDMI PLL OD to /4 on GXL/GXM SoCs + +From: Martin Blumenstingl + +[ Upstream commit 5b1a43950fd3162af0ce52b13c14a2d29b179d4f ] + +GXBB has the HDMI PLL OD in the HHI_HDMI_PLL_CNTL2 register while for +GXL/GXM the OD has moved to HHI_HDMI_PLL_CNTL3. At first glance the rest +of the OD setup seems identical. + +However, looking at the downstream kernel sources as well as testing +shows that GXL only supports three OD values: +- register value 0 means: divide by 1 +- register value 1 means: divide by 2 +- register value 2 means: divide by 4 + +Using register value 3 (which on GXBB means: divide by 8) still divides +by 4 as verified using meson-clk-measure. Downstream sources are also +only using OD register values 0, 1 and 2 for GXL (while for GXBB the +downstream kernel sources are also using value 3). + +Add clk_div_table and have it replace the CLK_DIVIDER_POWER_OF_TWO flag +to make the kernel's view of this register match with how the hardware +actually works. + +Fixes: 69d92293274b ("clk: meson: add the gxl hdmi pll") +Signed-off-by: Martin Blumenstingl +Link: https://lore.kernel.org/r/20260105204710.447779-2-martin.blumenstingl@googlemail.com +Signed-off-by: Jerome Brunet +Signed-off-by: Sasha Levin +--- + drivers/clk/meson/gxbb.c | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c +index a133013356b64..00eaca92b388a 100644 +--- a/drivers/clk/meson/gxbb.c ++++ b/drivers/clk/meson/gxbb.c +@@ -318,12 +318,23 @@ static struct clk_regmap gxbb_hdmi_pll = { + }, + }; + ++/* ++ * GXL hdmi OD dividers are POWER_OF_TWO dividers but limited to /4. ++ * A divider value of 3 should map to /8 but instead map /4 so ignore it. ++ */ ++static const struct clk_div_table gxl_hdmi_pll_od_div_table[] = { ++ { .val = 0, .div = 1 }, ++ { .val = 1, .div = 2 }, ++ { .val = 2, .div = 4 }, ++ { /* sentinel */ } ++}; ++ + static struct clk_regmap gxl_hdmi_pll_od = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL + 8, + .shift = 21, + .width = 2, +- .flags = CLK_DIVIDER_POWER_OF_TWO, ++ .table = gxl_hdmi_pll_od_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od", +@@ -341,7 +352,7 @@ static struct clk_regmap gxl_hdmi_pll_od2 = { + .offset = HHI_HDMI_PLL_CNTL + 8, + .shift = 23, + .width = 2, +- .flags = CLK_DIVIDER_POWER_OF_TWO, ++ .table = gxl_hdmi_pll_od_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od2", +@@ -359,7 +370,7 @@ static struct clk_regmap gxl_hdmi_pll = { + .offset = HHI_HDMI_PLL_CNTL + 8, + .shift = 19, + .width = 2, +- .flags = CLK_DIVIDER_POWER_OF_TWO, ++ .table = gxl_hdmi_pll_od_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll", +-- +2.51.0 + diff --git a/queue-6.6/clk-move-clk_-save-restore-_context-to-common_clk-se.patch b/queue-6.6/clk-move-clk_-save-restore-_context-to-common_clk-se.patch new file mode 100644 index 0000000000..e92cec3a1d --- /dev/null +++ b/queue-6.6/clk-move-clk_-save-restore-_context-to-common_clk-se.patch @@ -0,0 +1,117 @@ +From b8629ef1c4ea6c6119e5082851537e02f55e4452 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Dec 2025 10:42:26 +0100 +Subject: clk: Move clk_{save,restore}_context() to COMMON_CLK section + +From: Geert Uytterhoeven + +[ Upstream commit f47c1b77d0a2a9c0d49ec14302e74f933398d1a3 ] + +The clk_save_context() and clk_restore_context() helpers are only +implemented by the Common Clock Framework. They are not available when +using legacy clock frameworks. Dummy implementations are provided, but +only if no clock support is available at all. + +Hence when CONFIG_HAVE_CLK=y, but CONFIG_COMMON_CLK is not enabled: + + m68k-linux-gnu-ld: drivers/net/phy/air_en8811h.o: in function `en8811h_resume': + air_en8811h.c:(.text+0x83e): undefined reference to `clk_restore_context' + m68k-linux-gnu-ld: drivers/net/phy/air_en8811h.o: in function `en8811h_suspend': + air_en8811h.c:(.text+0x856): undefined reference to `clk_save_context' + +Fix this by moving forward declarations and dummy implementions from the +HAVE_CLK to the COMMON_CLK section. + +Fixes: 8b95d1ce3300c411 ("clk: Add functions to save/restore clock context en-masse") +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202511301553.eaEz1nEW-lkp@intel.com/ +Signed-off-by: Geert Uytterhoeven +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + include/linux/clk.h | 48 ++++++++++++++++++++++----------------------- + 1 file changed, 24 insertions(+), 24 deletions(-) + +diff --git a/include/linux/clk.h b/include/linux/clk.h +index 06f1b292f8a00..862ef29ee5f0e 100644 +--- a/include/linux/clk.h ++++ b/include/linux/clk.h +@@ -216,6 +216,23 @@ int clk_rate_exclusive_get(struct clk *clk); + */ + void clk_rate_exclusive_put(struct clk *clk); + ++/** ++ * clk_save_context - save clock context for poweroff ++ * ++ * Saves the context of the clock register for powerstates in which the ++ * contents of the registers will be lost. Occurs deep within the suspend ++ * code so locking is not necessary. ++ */ ++int clk_save_context(void); ++ ++/** ++ * clk_restore_context - restore clock context after poweroff ++ * ++ * This occurs with all clocks enabled. Occurs deep within the resume code ++ * so locking is not necessary. ++ */ ++void clk_restore_context(void); ++ + #else + + static inline int clk_notifier_register(struct clk *clk, +@@ -276,6 +293,13 @@ static inline int clk_rate_exclusive_get(struct clk *clk) + + static inline void clk_rate_exclusive_put(struct clk *clk) {} + ++static inline int clk_save_context(void) ++{ ++ return 0; ++} ++ ++static inline void clk_restore_context(void) {} ++ + #endif + + #ifdef CONFIG_HAVE_CLK_PREPARE +@@ -872,23 +896,6 @@ struct clk *clk_get_parent(struct clk *clk); + */ + struct clk *clk_get_sys(const char *dev_id, const char *con_id); + +-/** +- * clk_save_context - save clock context for poweroff +- * +- * Saves the context of the clock register for powerstates in which the +- * contents of the registers will be lost. Occurs deep within the suspend +- * code so locking is not necessary. +- */ +-int clk_save_context(void); +- +-/** +- * clk_restore_context - restore clock context after poweroff +- * +- * This occurs with all clocks enabled. Occurs deep within the resume code +- * so locking is not necessary. +- */ +-void clk_restore_context(void); +- + #else /* !CONFIG_HAVE_CLK */ + + static inline struct clk *clk_get(struct device *dev, const char *id) +@@ -1055,13 +1062,6 @@ static inline struct clk *clk_get_sys(const char *dev_id, const char *con_id) + return NULL; + } + +-static inline int clk_save_context(void) +-{ +- return 0; +-} +- +-static inline void clk_restore_context(void) {} +- + #endif + + /* clk_prepare_enable helps cases using clk_enable in non-atomic context. */ +-- +2.51.0 + diff --git a/queue-6.6/clk-qcom-dispcc-sdm845-enable-parents-for-pixel-cloc.patch b/queue-6.6/clk-qcom-dispcc-sdm845-enable-parents-for-pixel-cloc.patch new file mode 100644 index 0000000000..9a74b2ad66 --- /dev/null +++ b/queue-6.6/clk-qcom-dispcc-sdm845-enable-parents-for-pixel-cloc.patch @@ -0,0 +1,49 @@ +From 5d2afe2b18f19f4f63a347b901f4dc3a2430224c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 12:44:43 +0100 +Subject: clk: qcom: dispcc-sdm845: Enable parents for pixel clocks + +From: Petr Hodina + +[ Upstream commit a1d63493634e98360140027fef49d82b1ff0a267 ] + +Add CLK_OPS_PARENT_ENABLE to MDSS pixel clock sources to ensure parent +clocks are enabled during clock operations, preventing potential +stability issues during display configuration. + +Fixes: 81351776c9fb ("clk: qcom: Add display clock controller driver for SDM845") +Signed-off-by: Petr Hodina +Reviewed-by: Dmitry Baryshkov +Reviewed-by: David Heidelberg +Link: https://lore.kernel.org/r/20260107-stability-discussion-v2-1-ef7717b435ff@protonmail.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sdm845.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/dispcc-sdm845.c b/drivers/clk/qcom/dispcc-sdm845.c +index e792e0b130d33..eae6dcff18da5 100644 +--- a/drivers/clk/qcom/dispcc-sdm845.c ++++ b/drivers/clk/qcom/dispcc-sdm845.c +@@ -280,7 +280,7 @@ static struct clk_rcg2 disp_cc_mdss_pclk0_clk_src = { + .name = "disp_cc_mdss_pclk0_clk_src", + .parent_data = disp_cc_parent_data_4, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_4), +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .ops = &clk_pixel_ops, + }, + }; +@@ -295,7 +295,7 @@ static struct clk_rcg2 disp_cc_mdss_pclk1_clk_src = { + .name = "disp_cc_mdss_pclk1_clk_src", + .parent_data = disp_cc_parent_data_4, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_4), +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .ops = &clk_pixel_ops, + }, + }; +-- +2.51.0 + diff --git a/queue-6.6/clk-qcom-gcc-ipq5018-flag-sleep-clock-as-critical.patch b/queue-6.6/clk-qcom-gcc-ipq5018-flag-sleep-clock-as-critical.patch new file mode 100644 index 0000000000..03a9d52899 --- /dev/null +++ b/queue-6.6/clk-qcom-gcc-ipq5018-flag-sleep-clock-as-critical.patch @@ -0,0 +1,37 @@ +From faed4abdb1f92d3d2897156d8508469ef06f42ab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 15:03:19 +0400 +Subject: clk: qcom: gcc-ipq5018: flag sleep clock as critical + +From: George Moussalem + +[ Upstream commit 04c4dc1f541135708d90a9b4632af51136f93ac3 ] + +The sleep clock never be disabled. To avoid the kernel trying to disable +it and keep it always on, flag it as critical. + +Fixes: e3fdbef1bab8 ("clk: qcom: Add Global Clock controller (GCC) driver for IPQ5018") +Signed-off-by: George Moussalem +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251128-ipq5018-sleep-clk-fix-v1-1-6f4b75ec336c@outlook.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-ipq5018.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/clk/qcom/gcc-ipq5018.c b/drivers/clk/qcom/gcc-ipq5018.c +index 915e84db3c97d..292eaa154737f 100644 +--- a/drivers/clk/qcom/gcc-ipq5018.c ++++ b/drivers/clk/qcom/gcc-ipq5018.c +@@ -1339,6 +1339,7 @@ static struct clk_branch gcc_sleep_clk_src = { + .name = "gcc_sleep_clk_src", + .parent_data = gcc_sleep_clk_data, + .num_parents = ARRAY_SIZE(gcc_sleep_clk_data), ++ .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +-- +2.51.0 + diff --git a/queue-6.6/clk-qcom-gcc-msm8917-remove-always_on-flag-from-cpp_.patch b/queue-6.6/clk-qcom-gcc-msm8917-remove-always_on-flag-from-cpp_.patch new file mode 100644 index 0000000000..a0e27d8571 --- /dev/null +++ b/queue-6.6/clk-qcom-gcc-msm8917-remove-always_on-flag-from-cpp_.patch @@ -0,0 +1,39 @@ +From cab634be0a9e0841aae5f61d15ac19ed0325598a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 17 Nov 2025 18:58:48 +0100 +Subject: clk: qcom: gcc-msm8917: Remove ALWAYS_ON flag from cpp_gdsc +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Czémán + +[ Upstream commit e4eb42f290aecac0ba355b1f8d7243be6de11f32 ] + +cpp_gdsc should not be always on, ALWAYS_ON flag was set accidentally. + +Fixes: 33cc27a47d3a ("clk: qcom: Add global clock controller driver for MSM8917") +Signed-off-by: Barnabás Czémán +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251117-fix-gdsc-cpp-msm8917-msm8953-v1-2-db33adcff28a@mainlining.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-msm8917.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/clk/qcom/gcc-msm8917.c b/drivers/clk/qcom/gcc-msm8917.c +index f2dd132e2fb1c..0be62cb7a6228 100644 +--- a/drivers/clk/qcom/gcc-msm8917.c ++++ b/drivers/clk/qcom/gcc-msm8917.c +@@ -3034,7 +3034,6 @@ static struct gdsc cpp_gdsc = { + .pd = { + .name = "cpp_gdsc", + }, +- .flags = ALWAYS_ON, + .pwrsts = PWRSTS_OFF_ON, + }; + +-- +2.51.0 + diff --git a/queue-6.6/clk-qcom-gcc-msm8953-remove-always_on-flag-from-cpp_.patch b/queue-6.6/clk-qcom-gcc-msm8953-remove-always_on-flag-from-cpp_.patch new file mode 100644 index 0000000000..58508f2a3c --- /dev/null +++ b/queue-6.6/clk-qcom-gcc-msm8953-remove-always_on-flag-from-cpp_.patch @@ -0,0 +1,39 @@ +From 91d1551a19b72a11faf1b794674a1d9049512220 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 17 Nov 2025 18:58:47 +0100 +Subject: clk: qcom: gcc-msm8953: Remove ALWAYS_ON flag from cpp_gdsc +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Czémán + +[ Upstream commit 5f613e7034187179a9d088ff5fd02b1089d0cf20 ] + +cpp_gdsc should not be always on, ALWAYS_ON flag was set accidentally. + +Fixes: 9bb6cfc3c77e ("clk: qcom: Add Global Clock Controller driver for MSM8953") +Signed-off-by: Barnabás Czémán +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251117-fix-gdsc-cpp-msm8917-msm8953-v1-1-db33adcff28a@mainlining.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-msm8953.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/clk/qcom/gcc-msm8953.c b/drivers/clk/qcom/gcc-msm8953.c +index e6e2ab1380f20..1689f08814063 100644 +--- a/drivers/clk/qcom/gcc-msm8953.c ++++ b/drivers/clk/qcom/gcc-msm8953.c +@@ -3946,7 +3946,6 @@ static struct gdsc cpp_gdsc = { + .pd = { + .name = "cpp_gdsc", + }, +- .flags = ALWAYS_ON, + .pwrsts = PWRSTS_OFF_ON, + }; + +-- +2.51.0 + diff --git a/queue-6.6/clk-qcom-gcc-qdu1000-update-the-sdcc-rcgs-to-use-sha.patch b/queue-6.6/clk-qcom-gcc-qdu1000-update-the-sdcc-rcgs-to-use-sha.patch new file mode 100644 index 0000000000..d32ce24427 --- /dev/null +++ b/queue-6.6/clk-qcom-gcc-qdu1000-update-the-sdcc-rcgs-to-use-sha.patch @@ -0,0 +1,51 @@ +From 3b45f3469c63fd5a8567627b5ce90e14da9950b3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Nov 2025 23:27:42 +0530 +Subject: clk: qcom: gcc-qdu1000: Update the SDCC RCGs to use shared_floor_ops + +From: Jagadeesh Kona + +[ Upstream commit 947c4b326c1f4dc64aed42170b39c2cf551ba8ca ] + +Use shared_floor_ops for the SDCC RCGs so the RCG is safely parked +during disable and the new parent configuration is programmed in +hardware only when the new parent is enabled, avoiding cases where +the RCG configuration fails to update. + +Fixes: baa316580013 ("clk: qcom: gcc-qdu1000: Update the SDCC clock RCG ops") +Signed-off-by: Jagadeesh Kona +Reviewed-by: Imran Shaik +Reviewed-by: Taniya Das +Reviewed-by: Vladimir Zapolskiy +Link: https://lore.kernel.org/r/20251127-sdcc_shared_floor_ops-v2-7-473afc86589c@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-qdu1000.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-qdu1000.c b/drivers/clk/qcom/gcc-qdu1000.c +index 9f42d2601464e..84643f9ffb02d 100644 +--- a/drivers/clk/qcom/gcc-qdu1000.c ++++ b/drivers/clk/qcom/gcc-qdu1000.c +@@ -904,7 +904,7 @@ static struct clk_rcg2 gcc_sdcc5_apps_clk_src = { + .name = "gcc_sdcc5_apps_clk_src", + .parent_data = gcc_parent_data_8, + .num_parents = ARRAY_SIZE(gcc_parent_data_8), +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +@@ -923,7 +923,7 @@ static struct clk_rcg2 gcc_sdcc5_ice_core_clk_src = { + .name = "gcc_sdcc5_ice_core_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = ARRAY_SIZE(gcc_parent_data_2), +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +-- +2.51.0 + diff --git a/queue-6.6/clk-qcom-gcc-sdx75-update-the-sdcc-rcgs-to-use-share.patch b/queue-6.6/clk-qcom-gcc-sdx75-update-the-sdcc-rcgs-to-use-share.patch new file mode 100644 index 0000000000..936737c5e8 --- /dev/null +++ b/queue-6.6/clk-qcom-gcc-sdx75-update-the-sdcc-rcgs-to-use-share.patch @@ -0,0 +1,52 @@ +From 9fdc01bb5e35c933fcb35f65c6ff92a327f27741 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Nov 2025 23:27:39 +0530 +Subject: clk: qcom: gcc-sdx75: Update the SDCC RCGs to use shared_floor_ops + +From: Jagadeesh Kona + +[ Upstream commit 4b057462bb61a6571608ba393e6e018c9da9c9c3 ] + +Use shared_floor_ops for the SDCC RCGs so the RCG is safely parked +during disable and the new parent configuration is programmed in +hardware only when the new parent is enabled, avoiding cases where +the RCG configuration fails to update. + +Fixes: 108cdc09b2de ("clk: qcom: Add GCC driver support for SDX75") +Reviewed-by: Taniya Das +Reviewed-by: Imran Shaik +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Vladimir Zapolskiy +Signed-off-by: Jagadeesh Kona +Link: https://lore.kernel.org/r/20251127-sdcc_shared_floor_ops-v2-4-473afc86589c@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-sdx75.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-sdx75.c b/drivers/clk/qcom/gcc-sdx75.c +index 573af17bd24ca..314bacd03374b 100644 +--- a/drivers/clk/qcom/gcc-sdx75.c ++++ b/drivers/clk/qcom/gcc-sdx75.c +@@ -1033,7 +1033,7 @@ static struct clk_rcg2 gcc_sdcc1_apps_clk_src = { + .name = "gcc_sdcc1_apps_clk_src", + .parent_data = gcc_parent_data_17, + .num_parents = ARRAY_SIZE(gcc_parent_data_17), +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +@@ -1057,7 +1057,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .name = "gcc_sdcc2_apps_clk_src", + .parent_data = gcc_parent_data_18, + .num_parents = ARRAY_SIZE(gcc_parent_data_18), +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +-- +2.51.0 + diff --git a/queue-6.6/clk-qcom-gcc-sm8450-update-the-sdcc-rcgs-to-use-shar.patch b/queue-6.6/clk-qcom-gcc-sm8450-update-the-sdcc-rcgs-to-use-shar.patch new file mode 100644 index 0000000000..92a4ada0c8 --- /dev/null +++ b/queue-6.6/clk-qcom-gcc-sm8450-update-the-sdcc-rcgs-to-use-shar.patch @@ -0,0 +1,52 @@ +From 47cd5ac24cd33da0ef2080256fec5d17df57e970 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Nov 2025 23:27:36 +0530 +Subject: clk: qcom: gcc-sm8450: Update the SDCC RCGs to use shared_floor_ops + +From: Jagadeesh Kona + +[ Upstream commit 89428516f99572a9c37ebbb7859595881e7025a0 ] + +Use shared_floor_ops for the SDCC RCGs so the RCG is safely parked +during disable and the new parent configuration is programmed in +hardware only when the new parent is enabled, avoiding cases where +the RCG configuration fails to update. + +Fixes: a27ac3806b0a ("clk: qcom: gcc-sm8450: Use floor ops for SDCC RCGs") +Reviewed-by: Taniya Das +Reviewed-by: Imran Shaik +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Vladimir Zapolskiy +Signed-off-by: Jagadeesh Kona +Link: https://lore.kernel.org/r/20251127-sdcc_shared_floor_ops-v2-1-473afc86589c@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-sm8450.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-sm8450.c b/drivers/clk/qcom/gcc-sm8450.c +index 4c55df89ddca7..ef02d1003cb4a 100644 +--- a/drivers/clk/qcom/gcc-sm8450.c ++++ b/drivers/clk/qcom/gcc-sm8450.c +@@ -936,7 +936,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .parent_data = gcc_parent_data_7, + .num_parents = ARRAY_SIZE(gcc_parent_data_7), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +@@ -959,7 +959,7 @@ static struct clk_rcg2 gcc_sdcc4_apps_clk_src = { + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_floor_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +-- +2.51.0 + diff --git a/queue-6.6/clk-qcom-gcc-sm8550-use-floor-ops-for-sdcc-rcgs.patch b/queue-6.6/clk-qcom-gcc-sm8550-use-floor-ops-for-sdcc-rcgs.patch new file mode 100644 index 0000000000..9a2b317eb9 --- /dev/null +++ b/queue-6.6/clk-qcom-gcc-sm8550-use-floor-ops-for-sdcc-rcgs.patch @@ -0,0 +1,55 @@ +From 52a59763d19bbb70451fcd07b54d2c051150fead Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 24 Nov 2025 23:20:11 +0200 +Subject: clk: qcom: gcc-sm8550: Use floor ops for SDCC RCGs + +From: Vladimir Zapolskiy + +[ Upstream commit 1c06e3956054fb5a0930f07b02726b1774b6c700 ] + +In line with commit a27ac3806b0a ("clk: qcom: gcc-sm8450: Use floor ops +for SDCC RCGs") done to fix issues with overclocked SD cards on SM8450 +powered boards set floor clock operations for SDCC RCGs on SM8550. + +This change fixes initialization of some SD cards, where the problem +is manifested by the SDHC driver: + + mmc0: Card appears overclocked; req 50000000 Hz, actual 100000000 Hz + mmc0: error -110 whilst initialising SD card + +Fixes: 955f2ea3b9e9 ("clk: qcom: Add GCC driver for SM8550") +Signed-off-by: Vladimir Zapolskiy +Reviewed-by: Neil Armstrong +Reviewed-by: Taniya Das +Link: https://lore.kernel.org/r/20251124212012.3660189-2-vladimir.zapolskiy@linaro.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-sm8550.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-sm8550.c b/drivers/clk/qcom/gcc-sm8550.c +index b30ece62216f7..3e5ce6fa68058 100644 +--- a/drivers/clk/qcom/gcc-sm8550.c ++++ b/drivers/clk/qcom/gcc-sm8550.c +@@ -1025,7 +1025,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .parent_data = gcc_parent_data_9, + .num_parents = ARRAY_SIZE(gcc_parent_data_9), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_shared_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +@@ -1048,7 +1048,7 @@ static struct clk_rcg2 gcc_sdcc4_apps_clk_src = { + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_shared_ops, ++ .ops = &clk_rcg2_shared_floor_ops, + }, + }; + +-- +2.51.0 + diff --git a/queue-6.6/clk-qcom-gfx3d-add-parent-to-parent-request-map.patch b/queue-6.6/clk-qcom-gfx3d-add-parent-to-parent-request-map.patch new file mode 100644 index 0000000000..5afcbc0722 --- /dev/null +++ b/queue-6.6/clk-qcom-gfx3d-add-parent-to-parent-request-map.patch @@ -0,0 +1,67 @@ +From e8484605845baf73fcee80b172c6b34879888305 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 17 Jan 2026 05:54:47 +0200 +Subject: clk: qcom: gfx3d: add parent to parent request map + +From: Dmitry Baryshkov + +[ Upstream commit 2583cb925ca1ce450aa5d74a05a67448db970193 ] + +After commit d228ece36345 ("clk: divider: remove round_rate() in favor +of determine_rate()") determining GFX3D clock rate crashes, because the +passed parent map doesn't provide the expected best_parent_hw clock +(with the roundd_rate path before the offending commit the +best_parent_hw was ignored). + +Set the field in parent_req in addition to setting it in the req, +fixing the crash. + + clk_hw_round_rate (drivers/clk/clk.c:1764) (P) + clk_divider_bestdiv (drivers/clk/clk-divider.c:336) + divider_determine_rate (drivers/clk/clk-divider.c:358) + clk_alpha_pll_postdiv_determine_rate (drivers/clk/qcom/clk-alpha-pll.c:1275) + clk_core_determine_round_nolock (drivers/clk/clk.c:1606) + clk_core_round_rate_nolock (drivers/clk/clk.c:1701) + __clk_determine_rate (drivers/clk/clk.c:1741) + clk_gfx3d_determine_rate (drivers/clk/qcom/clk-rcg2.c:1268) + clk_core_determine_round_nolock (drivers/clk/clk.c:1606) + clk_core_round_rate_nolock (drivers/clk/clk.c:1701) + clk_core_round_rate_nolock (drivers/clk/clk.c:1710) + clk_round_rate (drivers/clk/clk.c:1804) + dev_pm_opp_set_rate (drivers/opp/core.c:1440 (discriminator 1)) + msm_devfreq_target (drivers/gpu/drm/msm/msm_gpu_devfreq.c:51) + devfreq_set_target (drivers/devfreq/devfreq.c:360) + devfreq_update_target (drivers/devfreq/devfreq.c:426) + devfreq_monitor (drivers/devfreq/devfreq.c:458) + process_one_work (arch/arm64/include/asm/jump_label.h:36 include/trace/events/workqueue.h:110 kernel/workqueue.c:3284) + worker_thread (kernel/workqueue.c:3356 (discriminator 2) kernel/workqueue.c:3443 (discriminator 2)) + kthread (kernel/kthread.c:467) + ret_from_fork (arch/arm64/kernel/entry.S:861) + +Fixes: 55213e1acec9 ("clk: qcom: Add gfx3d ping-pong PLL frequency switching") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Abel Vesa +Reviewed-by: Konrad Dybcio +Reviewed-by: Brian Masney +Link: https://lore.kernel.org/r/20260117-db820-fix-gfx3d-v1-1-0f8894d71d63@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/clk-rcg2.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c +index 658d2ee7aacff..20bb72565f0ed 100644 +--- a/drivers/clk/qcom/clk-rcg2.c ++++ b/drivers/clk/qcom/clk-rcg2.c +@@ -918,6 +918,7 @@ static int clk_gfx3d_determine_rate(struct clk_hw *hw, + if (req->max_rate < parent_req.max_rate) + parent_req.max_rate = req->max_rate; + ++ parent_req.best_parent_hw = req->best_parent_hw; + ret = __clk_determine_rate(req->best_parent_hw, &parent_req); + if (ret) + return ret; +-- +2.51.0 + diff --git a/queue-6.6/clk-qcom-rcg2-compute-2d-using-duty-fraction-directl.patch b/queue-6.6/clk-qcom-rcg2-compute-2d-using-duty-fraction-directl.patch new file mode 100644 index 0000000000..0353da53f9 --- /dev/null +++ b/queue-6.6/clk-qcom-rcg2-compute-2d-using-duty-fraction-directl.patch @@ -0,0 +1,71 @@ +From 961caf27256a1b7b4f8a4a32da55fe0f0dad00b0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Jan 2026 16:09:50 +0530 +Subject: clk: qcom: rcg2: compute 2d using duty fraction directly +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Taniya Das + +[ Upstream commit d6205a1878dd4cc9664c4b4829b68a29c0426efc ] + +The duty-cycle calculation in clk_rcg2_set_duty_cycle() currently +derives an intermediate percentage `duty_per = (num * 100) / den` and +then computes: + + d = DIV_ROUND_CLOSEST(n * duty_per * 2, 100); + +This introduces integer truncation at the percentage step (division by +`den`) and a redundant scaling by 100, which can reduce precision for +large `den` and skew the final rounding. + +Compute `2d` directly from the duty fraction to preserve precision and +avoid the unnecessary scaling: + + d = DIV_ROUND_CLOSEST(n * duty->num * 2, duty->den); + +This keeps the intended formula `d ≈ n * 2 * (num/den)` while performing +a single, final rounded division, improving accuracy especially for small +duty cycles or large denominators. It also removes the unused `duty_per` +variable, simplifying the code. + +There is no functional changes beyond improved numerical accuracy. + +Fixes: 7f891faf596ed ("clk: qcom: clk-rcg2: Add support for duty-cycle for RCG") +Signed-off-by: Taniya Das +Link: https://lore.kernel.org/r/20260105-duty_cycle_precision-v2-1-d1d466a6330a@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/clk-rcg2.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c +index fae1c07982aba..658d2ee7aacff 100644 +--- a/drivers/clk/qcom/clk-rcg2.c ++++ b/drivers/clk/qcom/clk-rcg2.c +@@ -434,7 +434,7 @@ static int clk_rcg2_get_duty_cycle(struct clk_hw *hw, struct clk_duty *duty) + static int clk_rcg2_set_duty_cycle(struct clk_hw *hw, struct clk_duty *duty) + { + struct clk_rcg2 *rcg = to_clk_rcg2(hw); +- u32 notn_m, n, m, d, not2d, mask, duty_per, cfg; ++ u32 notn_m, n, m, d, not2d, mask, cfg; + int ret; + + /* Duty-cycle cannot be modified for non-MND RCGs */ +@@ -453,10 +453,8 @@ static int clk_rcg2_set_duty_cycle(struct clk_hw *hw, struct clk_duty *duty) + + n = (~(notn_m) + m) & mask; + +- duty_per = (duty->num * 100) / duty->den; +- + /* Calculate 2d value */ +- d = DIV_ROUND_CLOSEST(n * duty_per * 2, 100); ++ d = DIV_ROUND_CLOSEST(n * duty->num * 2, duty->den); + + /* + * Check bit widths of 2d. If D is too big reduce duty cycle. +-- +2.51.0 + diff --git a/queue-6.6/clk-qcom-return-correct-error-code-in-qcom_cc_probe_.patch b/queue-6.6/clk-qcom-return-correct-error-code-in-qcom_cc_probe_.patch new file mode 100644 index 0000000000..3d354c3448 --- /dev/null +++ b/queue-6.6/clk-qcom-return-correct-error-code-in-qcom_cc_probe_.patch @@ -0,0 +1,42 @@ +From 16bc090f066f25519367860132d429256a430a75 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 17 Dec 2025 12:13:38 +0800 +Subject: clk: qcom: Return correct error code in qcom_cc_probe_by_index() + +From: Haotian Zhang + +[ Upstream commit 1e07ebe744fb522983bd52a4a6148601675330c7 ] + +When devm_platform_ioremap_resource() fails, it returns various +error codes. Returning a hardcoded -ENOMEM masks the actual +failure reason. + +Use PTR_ERR() to propagate the actual error code returned by +devm_platform_ioremap_resource() instead of -ENOMEM. + +Fixes: 75e0a1e30191 ("clk: qcom: define probe by index API as common API") +Signed-off-by: Haotian Zhang +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20251217041338.2432-1-vulab@iscas.ac.cn +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/common.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c +index 35bd987f2e52a..3d6e87872ddc3 100644 +--- a/drivers/clk/qcom/common.c ++++ b/drivers/clk/qcom/common.c +@@ -325,7 +325,7 @@ int qcom_cc_probe_by_index(struct platform_device *pdev, int index, + + base = devm_platform_ioremap_resource(pdev, index); + if (IS_ERR(base)) +- return -ENOMEM; ++ return PTR_ERR(base); + + regmap = devm_regmap_init_mmio(&pdev->dev, base, desc->config); + if (IS_ERR(regmap)) +-- +2.51.0 + diff --git a/queue-6.6/coresight-etm3x-fix-cpulocked-warning-on-cpuhp.patch b/queue-6.6/coresight-etm3x-fix-cpulocked-warning-on-cpuhp.patch new file mode 100644 index 0000000000..80ae7da5f4 --- /dev/null +++ b/queue-6.6/coresight-etm3x-fix-cpulocked-warning-on-cpuhp.patch @@ -0,0 +1,67 @@ +From eb5a3aa058f574242dd3c0e2fedea6a0a64bae0b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 16:24:27 +0100 +Subject: coresight: etm3x: Fix cpulocked warning on cpuhp + +From: Antonio Borneo + +[ Upstream commit 1feb0377b9b816f89a04fc381eb19fc6bac9f4a4 ] + +When changes [1] and [2] have been applied to the driver etm4x, the +same modifications have been also collapsed in [3] and applied in +one shot to the driver etm3x. +While doing this, the driver etm3x has not been aligned to etm4x on +the use of non cpuslocked version of cpuhp callback setup APIs. + +The current code triggers two run-time warnings when the kernel is +compiled with CONFIG_PROVE_LOCKING=y. + +Use non cpuslocked version of cpuhp callback setup APIs in driver +etm3x, aligning it to the driver etm4x. + +[1] commit 2d1a8bfb61ec ("coresight: etm4x: Fix etm4_count race by + moving cpuhp callbacks to init") +[2] commit 22a550a306ad ("coresight: etm4x: Allow etm4x to be built + as a module") +[3] commit 97fe626ce64c ("coresight: etm3x: Allow etm3x to be built + as a module") + +Fixes: 97fe626ce64c ("coresight: etm3x: Allow etm3x to be built as a module") +Signed-off-by: Antonio Borneo +Signed-off-by: Suzuki K Poulose +Link: https://lore.kernel.org/r/20260108152427.357379-1-antonio.borneo@foss.st.com +Signed-off-by: Sasha Levin +--- + drivers/hwtracing/coresight/coresight-etm3x-core.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c +index 116a91d90ac20..4cef1023f0290 100644 +--- a/drivers/hwtracing/coresight/coresight-etm3x-core.c ++++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c +@@ -814,16 +814,16 @@ static int __init etm_hp_setup(void) + { + int ret; + +- ret = cpuhp_setup_state_nocalls_cpuslocked(CPUHP_AP_ARM_CORESIGHT_STARTING, +- "arm/coresight:starting", +- etm_starting_cpu, etm_dying_cpu); ++ ret = cpuhp_setup_state_nocalls(CPUHP_AP_ARM_CORESIGHT_STARTING, ++ "arm/coresight:starting", ++ etm_starting_cpu, etm_dying_cpu); + + if (ret) + return ret; + +- ret = cpuhp_setup_state_nocalls_cpuslocked(CPUHP_AP_ONLINE_DYN, +- "arm/coresight:online", +- etm_online_cpu, NULL); ++ ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, ++ "arm/coresight:online", ++ etm_online_cpu, NULL); + + /* HP dyn state ID returned in ret on success */ + if (ret > 0) { +-- +2.51.0 + diff --git a/queue-6.6/cpufreq-scmi-correct-scmi-explanation.patch b/queue-6.6/cpufreq-scmi-correct-scmi-explanation.patch new file mode 100644 index 0000000000..eb9e8b476e --- /dev/null +++ b/queue-6.6/cpufreq-scmi-correct-scmi-explanation.patch @@ -0,0 +1,37 @@ +From a06b0fbb259a6128cc8b2e1ce562215fb1eaa16f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Jan 2026 22:33:30 +0300 +Subject: cpufreq: scmi: correct SCMI explanation + +From: Sergey Shtylyov + +[ Upstream commit 8c376f337a7e31c42949247e24eaad9a30d6c62c ] + +SCMI stands for System Control and Management Interface, not System Control +and Power Interface -- apparently, Sudeep Holla copied this line from his +SCPI driver and then just forgot to update the acronym explanation... :-) + +Fixes: 99d6bdf33877 ("cpufreq: add support for CPU DVFS based on SCMI message protocol") +Signed-off-by: Sergey Shtylyov +Reviewed-by: Sudeep Holla +Signed-off-by: Viresh Kumar +Signed-off-by: Sasha Levin +--- + drivers/cpufreq/scmi-cpufreq.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c +index 68325ebd56fe3..39d0ef66dd42f 100644 +--- a/drivers/cpufreq/scmi-cpufreq.c ++++ b/drivers/cpufreq/scmi-cpufreq.c +@@ -1,6 +1,6 @@ + // SPDX-License-Identifier: GPL-2.0 + /* +- * System Control and Power Interface (SCMI) based CPUFreq Interface driver ++ * System Control and Management Interface (SCMI) based CPUFreq Interface driver + * + * Copyright (C) 2018-2021 ARM Ltd. + * Sudeep Holla +-- +2.51.0 + diff --git a/queue-6.6/cpuidle-governors-menu-always-check-timers-with-tick.patch b/queue-6.6/cpuidle-governors-menu-always-check-timers-with-tick.patch new file mode 100644 index 0000000000..8db2b26cc5 --- /dev/null +++ b/queue-6.6/cpuidle-governors-menu-always-check-timers-with-tick.patch @@ -0,0 +1,88 @@ +From eb23ff446d13612972128fe289c1ecda7f9f73a0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 16:26:14 +0100 +Subject: cpuidle: governors: menu: Always check timers with tick stopped + +From: Rafael J. Wysocki + +[ Upstream commit 80606f4eb8d7484ab7f7d6f0fd30d71e6fbcf328 ] + +After commit 5484e31bbbff ("cpuidle: menu: Skip tick_nohz_get_sleep_length() +call in some cases"), if the return value of get_typical_interval() +multiplied by NSEC_PER_USEC is not greater than RESIDENCY_THRESHOLD_NS, +the menu governor will skip computing the time till the closest timer. +If that happens when the tick has been stopped already, the selected +idle state may be too deep due to the subsequent check comparing +predicted_ns with TICK_NSEC and causing its value to be replaced with +the expected time till the closest timer, which is KTIME_MAX in that +case. That will cause the deepest enabled idle state to be selected, +but the time till the closest timer very well may be shorter than the +target residency of that state, in which case a shallower state should +be used. + +Address this by making menu_select() always compute the time till the +closest timer when the tick has been stopped. + +Also move the predicted_ns check mentioned above into the branch in +which the time till the closest timer is determined because it only +needs to be done in that case. + +Fixes: 5484e31bbbff ("cpuidle: menu: Skip tick_nohz_get_sleep_length() call in some cases") +Signed-off-by: Rafael J. Wysocki +Reviewed-by: Christian Loehle +Link: https://patch.msgid.link/5959091.DvuYhMxLoT@rafael.j.wysocki +Signed-off-by: Sasha Levin +--- + drivers/cpuidle/governors/menu.c | 22 +++++++++++----------- + 1 file changed, 11 insertions(+), 11 deletions(-) + +diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c +index 864a7be7ba485..bedf6c4b8d1b5 100644 +--- a/drivers/cpuidle/governors/menu.c ++++ b/drivers/cpuidle/governors/menu.c +@@ -269,7 +269,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, + + /* Find the shortest expected idle interval. */ + predicted_ns = get_typical_interval(data) * NSEC_PER_USEC; +- if (predicted_ns > RESIDENCY_THRESHOLD_NS) { ++ if (predicted_ns > RESIDENCY_THRESHOLD_NS || tick_nohz_tick_stopped()) { + unsigned int timer_us; + + /* Determine the time till the closest timer. */ +@@ -289,6 +289,16 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, + RESOLUTION * DECAY * NSEC_PER_USEC); + /* Use the lowest expected idle interval to pick the idle state. */ + predicted_ns = min((u64)timer_us * NSEC_PER_USEC, predicted_ns); ++ /* ++ * If the tick is already stopped, the cost of possible short ++ * idle duration misprediction is much higher, because the CPU ++ * may be stuck in a shallow idle state for a long time as a ++ * result of it. In that case, say we might mispredict and use ++ * the known time till the closest timer event for the idle ++ * state selection. ++ */ ++ if (tick_nohz_tick_stopped() && predicted_ns < TICK_NSEC) ++ predicted_ns = data->next_timer_ns; + } else { + /* + * Because the next timer event is not going to be determined +@@ -314,16 +324,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, + return 0; + } + +- /* +- * If the tick is already stopped, the cost of possible short idle +- * duration misprediction is much higher, because the CPU may be stuck +- * in a shallow idle state for a long time as a result of it. In that +- * case, say we might mispredict and use the known time till the closest +- * timer event for the idle state selection. +- */ +- if (tick_nohz_tick_stopped() && predicted_ns < TICK_NSEC) +- predicted_ns = data->next_timer_ns; +- + /* + * Find the idle state with the lowest power while satisfying + * our constraints. +-- +2.51.0 + diff --git a/queue-6.6/cpuidle-menu-cleanup-after-loadavg-removal.patch b/queue-6.6/cpuidle-menu-cleanup-after-loadavg-removal.patch new file mode 100644 index 0000000000..508d8e8415 --- /dev/null +++ b/queue-6.6/cpuidle-menu-cleanup-after-loadavg-removal.patch @@ -0,0 +1,60 @@ +From 2e1d25c5584a8da25593c8f897293158d519a272 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Jun 2024 11:55:29 +0100 +Subject: cpuidle: menu: Cleanup after loadavg removal + +From: Christian Loehle + +[ Upstream commit bf183113842b0fcf4b6f977a97fa9cf8e2b21625 ] + +The performance impact of loadavg was removed with commit a7fe5190c03f +("cpuidle: menu: Remove get_loadavg() from the performance multiplier") +With only iowait remaining the description can be simplified, remove +also the no longer needed includes. + +Signed-off-by: Christian Loehle +Signed-off-by: Rafael J. Wysocki +Stable-dep-of: 80606f4eb8d7 ("cpuidle: governors: menu: Always check timers with tick stopped") +Signed-off-by: Sasha Levin +--- + drivers/cpuidle/governors/menu.c | 17 +++++------------ + 1 file changed, 5 insertions(+), 12 deletions(-) + +diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c +index 27010eee6d1bc..864a7be7ba485 100644 +--- a/drivers/cpuidle/governors/menu.c ++++ b/drivers/cpuidle/governors/menu.c +@@ -14,8 +14,6 @@ + #include + #include + #include +-#include +-#include + #include + #include + +@@ -94,16 +92,11 @@ + * state, and thus the less likely a busy CPU will hit such a deep + * C state. + * +- * Two factors are used in determing this multiplier: +- * a value of 10 is added for each point of "per cpu load average" we have. +- * a value of 5 points is added for each process that is waiting for +- * IO on this CPU. +- * (these values are experimentally determined) +- * +- * The load average factor gives a longer term (few seconds) input to the +- * decision, while the iowait value gives a cpu local instantanious input. +- * The iowait factor may look low, but realize that this is also already +- * represented in the system load average. ++ * Currently there is only one value determining the factor: ++ * 10 points are added for each process that is waiting for IO on this CPU. ++ * (This value was experimentally determined.) ++ * Utilization is no longer a factor as it was shown that it never contributed ++ * significantly to the performance multiplier in the first place. + * + */ + +-- +2.51.0 + diff --git a/queue-6.6/crypto-cavium-fix-dma_free_coherent-size.patch b/queue-6.6/crypto-cavium-fix-dma_free_coherent-size.patch new file mode 100644 index 0000000000..218d9e3219 --- /dev/null +++ b/queue-6.6/crypto-cavium-fix-dma_free_coherent-size.patch @@ -0,0 +1,38 @@ +From 409b68fddf5e64cf96f49811d8e1e34c77f66f66 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 10:56:45 +0100 +Subject: crypto: cavium - fix dma_free_coherent() size + +From: Thomas Fourier + +[ Upstream commit 941676c30ba5b40a01bed92448f457ce62fd1f07 ] + +The size of the buffer in alloc_command_queues() is +curr->size + CPT_NEXT_CHUNK_PTR_SIZE, so used that length for +dma_free_coherent(). + +Fixes: c694b233295b ("crypto: cavium - Add the Virtual Function driver for CPT") +Signed-off-by: Thomas Fourier +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/cavium/cpt/cptvf_main.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/crypto/cavium/cpt/cptvf_main.c b/drivers/crypto/cavium/cpt/cptvf_main.c +index c246920e6f540..bccd680c7f7ee 100644 +--- a/drivers/crypto/cavium/cpt/cptvf_main.c ++++ b/drivers/crypto/cavium/cpt/cptvf_main.c +@@ -180,7 +180,8 @@ static void free_command_queues(struct cpt_vf *cptvf, + + hlist_for_each_entry_safe(chunk, node, &cqinfo->queue[i].chead, + nextchunk) { +- dma_free_coherent(&pdev->dev, chunk->size, ++ dma_free_coherent(&pdev->dev, ++ chunk->size + CPT_NEXT_CHUNK_PTR_SIZE, + chunk->head, + chunk->dma_addr); + chunk->head = NULL; +-- +2.51.0 + diff --git a/queue-6.6/crypto-ccp-add-an-s4-restore-flow.patch b/queue-6.6/crypto-ccp-add-an-s4-restore-flow.patch new file mode 100644 index 0000000000..cbf4e23fb6 --- /dev/null +++ b/queue-6.6/crypto-ccp-add-an-s4-restore-flow.patch @@ -0,0 +1,168 @@ +From 5b72a1ae84d0eaf311b40250f2bb4e05ca9ad048 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 22:11:30 -0600 +Subject: crypto: ccp - Add an S4 restore flow +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Mario Limonciello (AMD) + +[ Upstream commit 0ba2035026d0ab6c7c7e65ad8b418dc73d5700d9 ] + +The system will have lost power during S4. The ring used for TEE +communications needs to be initialized before use. + +Fixes: f892a21f51162 ("crypto: ccp - use generic power management") +Reported-by: Lars Francke +Closes: https://lore.kernel.org/platform-driver-x86/CAD-Ua_gfJnQSo8ucS_7ZwzuhoBRJ14zXP7s8b-zX3ZcxcyWePw@mail.gmail.com/ +Tested-by: Yijun Shen +Signed-off-by: Mario Limonciello (AMD) +Reviewed-by: Shyam Sundar S K +Reviewed-by: Tom Lendacky +Link: https://patch.msgid.link/20260116041132.153674-4-superm1@kernel.org +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/crypto/ccp/psp-dev.c | 11 +++++++++++ + drivers/crypto/ccp/sp-dev.c | 12 ++++++++++++ + drivers/crypto/ccp/sp-dev.h | 3 +++ + drivers/crypto/ccp/sp-pci.c | 16 +++++++++++++++- + drivers/crypto/ccp/tee-dev.c | 5 +++++ + drivers/crypto/ccp/tee-dev.h | 1 + + 6 files changed, 47 insertions(+), 1 deletion(-) + +diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c +index d42d7bc623523..d001abc350cd2 100644 +--- a/drivers/crypto/ccp/psp-dev.c ++++ b/drivers/crypto/ccp/psp-dev.c +@@ -253,6 +253,17 @@ struct psp_device *psp_get_master_device(void) + return sp ? sp->psp_data : NULL; + } + ++int psp_restore(struct sp_device *sp) ++{ ++ struct psp_device *psp = sp->psp_data; ++ int ret = 0; ++ ++ if (psp->tee_data) ++ ret = tee_restore(psp); ++ ++ return ret; ++} ++ + void psp_pci_init(void) + { + psp_master = psp_get_master_device(); +diff --git a/drivers/crypto/ccp/sp-dev.c b/drivers/crypto/ccp/sp-dev.c +index 7eb3e46682860..ccbe009ad6e58 100644 +--- a/drivers/crypto/ccp/sp-dev.c ++++ b/drivers/crypto/ccp/sp-dev.c +@@ -229,6 +229,18 @@ int sp_resume(struct sp_device *sp) + return 0; + } + ++int sp_restore(struct sp_device *sp) ++{ ++ if (sp->psp_data) { ++ int ret = psp_restore(sp); ++ ++ if (ret) ++ return ret; ++ } ++ ++ return sp_resume(sp); ++} ++ + struct sp_device *sp_get_psp_master_device(void) + { + struct sp_device *i, *ret = NULL; +diff --git a/drivers/crypto/ccp/sp-dev.h b/drivers/crypto/ccp/sp-dev.h +index 2329ad524b494..8bbef2426acd4 100644 +--- a/drivers/crypto/ccp/sp-dev.h ++++ b/drivers/crypto/ccp/sp-dev.h +@@ -138,6 +138,7 @@ struct sp_device *sp_get_master(void); + + int sp_suspend(struct sp_device *sp); + int sp_resume(struct sp_device *sp); ++int sp_restore(struct sp_device *sp); + int sp_request_ccp_irq(struct sp_device *sp, irq_handler_t handler, + const char *name, void *data); + void sp_free_ccp_irq(struct sp_device *sp, void *data); +@@ -171,6 +172,7 @@ int psp_dev_init(struct sp_device *sp); + void psp_pci_init(void); + void psp_dev_destroy(struct sp_device *sp); + void psp_pci_exit(void); ++int psp_restore(struct sp_device *sp); + + #else /* !CONFIG_CRYPTO_DEV_SP_PSP */ + +@@ -178,6 +180,7 @@ static inline int psp_dev_init(struct sp_device *sp) { return 0; } + static inline void psp_pci_init(void) { } + static inline void psp_dev_destroy(struct sp_device *sp) { } + static inline void psp_pci_exit(void) { } ++static inline int psp_restore(struct sp_device *sp) { return 0; } + + #endif /* CONFIG_CRYPTO_DEV_SP_PSP */ + +diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c +index b1e60542351a6..8f1b032f7e633 100644 +--- a/drivers/crypto/ccp/sp-pci.c ++++ b/drivers/crypto/ccp/sp-pci.c +@@ -407,6 +407,13 @@ static int __maybe_unused sp_pci_resume(struct device *dev) + return sp_resume(sp); + } + ++static int __maybe_unused sp_pci_restore(struct device *dev) ++{ ++ struct sp_device *sp = dev_get_drvdata(dev); ++ ++ return sp_restore(sp); ++} ++ + #ifdef CONFIG_CRYPTO_DEV_SP_PSP + static const struct sev_vdata sevv1 = { + .cmdresp_reg = 0x10580, /* C2PMSG_32 */ +@@ -585,7 +592,14 @@ static const struct pci_device_id sp_pci_table[] = { + }; + MODULE_DEVICE_TABLE(pci, sp_pci_table); + +-static SIMPLE_DEV_PM_OPS(sp_pci_pm_ops, sp_pci_suspend, sp_pci_resume); ++static const struct dev_pm_ops sp_pci_pm_ops = { ++ .suspend = pm_sleep_ptr(sp_pci_suspend), ++ .resume = pm_sleep_ptr(sp_pci_resume), ++ .freeze = pm_sleep_ptr(sp_pci_suspend), ++ .thaw = pm_sleep_ptr(sp_pci_resume), ++ .poweroff = pm_sleep_ptr(sp_pci_suspend), ++ .restore_early = pm_sleep_ptr(sp_pci_restore), ++}; + + static struct pci_driver sp_pci_driver = { + .name = "ccp", +diff --git a/drivers/crypto/ccp/tee-dev.c b/drivers/crypto/ccp/tee-dev.c +index 5560bf8329a12..9c02706e94948 100644 +--- a/drivers/crypto/ccp/tee-dev.c ++++ b/drivers/crypto/ccp/tee-dev.c +@@ -395,3 +395,8 @@ int psp_check_tee_status(void) + return 0; + } + EXPORT_SYMBOL(psp_check_tee_status); ++ ++int tee_restore(struct psp_device *psp) ++{ ++ return tee_init_ring(psp->tee_data); ++} +diff --git a/drivers/crypto/ccp/tee-dev.h b/drivers/crypto/ccp/tee-dev.h +index 49d26158b71e3..b0bf1de94ea6f 100644 +--- a/drivers/crypto/ccp/tee-dev.h ++++ b/drivers/crypto/ccp/tee-dev.h +@@ -122,5 +122,6 @@ struct tee_ring_cmd { + + int tee_dev_init(struct psp_device *psp); + void tee_dev_destroy(struct psp_device *psp); ++int tee_restore(struct psp_device *psp); + + #endif /* __TEE_DEV_H__ */ +-- +2.51.0 + diff --git a/queue-6.6/crypto-ccp-factor-out-ring-destroy-handling-to-a-hel.patch b/queue-6.6/crypto-ccp-factor-out-ring-destroy-handling-to-a-hel.patch new file mode 100644 index 0000000000..01a28d0ad2 --- /dev/null +++ b/queue-6.6/crypto-ccp-factor-out-ring-destroy-handling-to-a-hel.patch @@ -0,0 +1,90 @@ +From 0db279066a35e63e00e30015c7d92d729016110f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 22:11:31 -0600 +Subject: crypto: ccp - Factor out ring destroy handling to a helper +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Mario Limonciello (AMD) + +[ Upstream commit d95f87a65bce5f2f2a02ca6094ca4841d4073df3 ] + +The ring destroy command needs to be used in multiple places. Split +out the code to a helper. + +Tested-by: Yijun Shen +Signed-off-by: Mario Limonciello (AMD) +Acked-by: Tom Lendacky +Reviewed-by: Shyam Sundar S K +Link: https://patch.msgid.link/20260116041132.153674-5-superm1@kernel.org +Signed-off-by: Ilpo Järvinen +Stable-dep-of: 7b85137caf11 ("crypto: ccp - Send PSP_CMD_TEE_RING_DESTROY when PSP_CMD_TEE_RING_INIT fails") +Signed-off-by: Sasha Levin +--- + drivers/crypto/ccp/tee-dev.c | 36 ++++++++++++++++++++++++------------ + 1 file changed, 24 insertions(+), 12 deletions(-) + +diff --git a/drivers/crypto/ccp/tee-dev.c b/drivers/crypto/ccp/tee-dev.c +index 0ccd0e29b0380..09b54bd9b3e3c 100644 +--- a/drivers/crypto/ccp/tee-dev.c ++++ b/drivers/crypto/ccp/tee-dev.c +@@ -86,6 +86,29 @@ static inline void tee_free_cmd_buffer(struct tee_init_ring_cmd *cmd) + kfree(cmd); + } + ++static bool tee_send_destroy_cmd(struct psp_tee_device *tee) ++{ ++ unsigned int reg; ++ int ret; ++ ++ ret = psp_mailbox_command(tee->psp, PSP_CMD_TEE_RING_DESTROY, NULL, ++ TEE_DEFAULT_CMD_TIMEOUT, ®); ++ if (ret) { ++ dev_err(tee->dev, "tee: ring destroy command timed out, disabling TEE support\n"); ++ psp_dead = true; ++ return false; ++ } ++ ++ if (FIELD_GET(PSP_CMDRESP_STS, reg)) { ++ dev_err(tee->dev, "tee: ring destroy command failed (%#010lx)\n", ++ FIELD_GET(PSP_CMDRESP_STS, reg)); ++ psp_dead = true; ++ return false; ++ } ++ ++ return true; ++} ++ + static int tee_init_ring(struct psp_tee_device *tee) + { + int ring_size = MAX_RING_BUFFER_ENTRIES * sizeof(struct tee_ring_cmd); +@@ -136,24 +159,13 @@ static int tee_init_ring(struct psp_tee_device *tee) + + static void tee_destroy_ring(struct psp_tee_device *tee) + { +- unsigned int reg; +- int ret; +- + if (!tee->rb_mgr.ring_start) + return; + + if (psp_dead) + goto free_ring; + +- ret = psp_mailbox_command(tee->psp, PSP_CMD_TEE_RING_DESTROY, NULL, +- TEE_DEFAULT_CMD_TIMEOUT, ®); +- if (ret) { +- dev_err(tee->dev, "tee: ring destroy command timed out, disabling TEE support\n"); +- psp_dead = true; +- } else if (FIELD_GET(PSP_CMDRESP_STS, reg)) { +- dev_err(tee->dev, "tee: ring destroy command failed (%#010lx)\n", +- FIELD_GET(PSP_CMDRESP_STS, reg)); +- } ++ tee_send_destroy_cmd(tee); + + free_ring: + tee_free_ring(tee); +-- +2.51.0 + diff --git a/queue-6.6/crypto-ccp-move-direct-access-to-some-psp-registers-.patch b/queue-6.6/crypto-ccp-move-direct-access-to-some-psp-registers-.patch new file mode 100644 index 0000000000..fffce2d4bf --- /dev/null +++ b/queue-6.6/crypto-ccp-move-direct-access-to-some-psp-registers-.patch @@ -0,0 +1,357 @@ +From 8ad13eaa39c0a4b3d7129a43d1d36dafef4f51dd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 7 Sep 2023 13:48:42 -0500 +Subject: crypto: ccp - Move direct access to some PSP registers out of TEE + +From: Tom Lendacky + +[ Upstream commit 949a0c8dd3c257730ef7205be759e4bc6cf49cea ] + +With the PSP mailbox registers supporting more than just TEE, access to +them must be maintained and serialized by the PSP device support. Remove +TEE support direct access and create an interface in the PSP support +where the register access can be controlled/serialized. + +Signed-off-by: Tom Lendacky +Signed-off-by: Mario Limonciello +Reviewed-by: Rijo Thomas +Tested-by: Rijo Thomas +Signed-off-by: Herbert Xu +Stable-dep-of: 7b85137caf11 ("crypto: ccp - Send PSP_CMD_TEE_RING_DESTROY when PSP_CMD_TEE_RING_INIT fails") +Signed-off-by: Sasha Levin +--- + drivers/crypto/ccp/psp-dev.c | 60 ++++++++++++++++++++++++++++++++++++ + drivers/crypto/ccp/psp-dev.h | 18 +++++++++++ + drivers/crypto/ccp/sp-dev.h | 3 ++ + drivers/crypto/ccp/sp-pci.c | 18 +++++++---- + drivers/crypto/ccp/tee-dev.c | 48 ++++++----------------------- + drivers/crypto/ccp/tee-dev.h | 15 ++------- + 6 files changed, 104 insertions(+), 58 deletions(-) + +diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c +index d001abc350cd2..5f591bce09521 100644 +--- a/drivers/crypto/ccp/psp-dev.c ++++ b/drivers/crypto/ccp/psp-dev.c +@@ -9,6 +9,9 @@ + + #include + #include ++#include ++#include ++#include + + #include "sp-dev.h" + #include "psp-dev.h" +@@ -19,6 +22,62 @@ + + struct psp_device *psp_master; + ++#define PSP_C2PMSG_17_CMDRESP_CMD GENMASK(19, 16) ++ ++static int psp_mailbox_poll(const void __iomem *cmdresp_reg, unsigned int *cmdresp, ++ unsigned int timeout_msecs) ++{ ++ while (true) { ++ *cmdresp = ioread32(cmdresp_reg); ++ if (FIELD_GET(PSP_CMDRESP_RESP, *cmdresp)) ++ return 0; ++ ++ if (!timeout_msecs--) ++ break; ++ ++ usleep_range(1000, 1100); ++ } ++ ++ return -ETIMEDOUT; ++} ++ ++int psp_mailbox_command(struct psp_device *psp, enum psp_cmd cmd, void *cmdbuff, ++ unsigned int timeout_msecs, unsigned int *cmdresp) ++{ ++ void __iomem *cmdresp_reg, *cmdbuff_lo_reg, *cmdbuff_hi_reg; ++ int ret; ++ ++ if (!psp || !psp->vdata || !psp->vdata->cmdresp_reg || ++ !psp->vdata->cmdbuff_addr_lo_reg || !psp->vdata->cmdbuff_addr_hi_reg) ++ return -ENODEV; ++ ++ cmdresp_reg = psp->io_regs + psp->vdata->cmdresp_reg; ++ cmdbuff_lo_reg = psp->io_regs + psp->vdata->cmdbuff_addr_lo_reg; ++ cmdbuff_hi_reg = psp->io_regs + psp->vdata->cmdbuff_addr_hi_reg; ++ ++ mutex_lock(&psp->mailbox_mutex); ++ ++ /* Ensure mailbox is ready for a command */ ++ ret = -EBUSY; ++ if (psp_mailbox_poll(cmdresp_reg, cmdresp, 0)) ++ goto unlock; ++ ++ if (cmdbuff) { ++ iowrite32(lower_32_bits(__psp_pa(cmdbuff)), cmdbuff_lo_reg); ++ iowrite32(upper_32_bits(__psp_pa(cmdbuff)), cmdbuff_hi_reg); ++ } ++ ++ *cmdresp = FIELD_PREP(PSP_C2PMSG_17_CMDRESP_CMD, cmd); ++ iowrite32(*cmdresp, cmdresp_reg); ++ ++ ret = psp_mailbox_poll(cmdresp_reg, cmdresp, timeout_msecs); ++ ++unlock: ++ mutex_unlock(&psp->mailbox_mutex); ++ ++ return ret; ++} ++ + static struct psp_device *psp_alloc_struct(struct sp_device *sp) + { + struct device *dev = sp->dev; +@@ -164,6 +223,7 @@ int psp_dev_init(struct sp_device *sp) + } + + psp->io_regs = sp->io_map; ++ mutex_init(&psp->mailbox_mutex); + + ret = psp_get_capability(psp); + if (ret) +diff --git a/drivers/crypto/ccp/psp-dev.h b/drivers/crypto/ccp/psp-dev.h +index 8a4de69399c59..d917657c6085a 100644 +--- a/drivers/crypto/ccp/psp-dev.h ++++ b/drivers/crypto/ccp/psp-dev.h +@@ -14,6 +14,8 @@ + #include + #include + #include ++#include ++#include + + #include "sp-dev.h" + +@@ -33,6 +35,7 @@ struct psp_device { + struct sp_device *sp; + + void __iomem *io_regs; ++ struct mutex mailbox_mutex; + + psp_irq_handler_t sev_irq_handler; + void *sev_irq_data; +@@ -71,4 +74,19 @@ struct psp_device *psp_get_master_device(void); + #define PSP_SECURITY_HSP_TPM_AVAILABLE BIT(10) + #define PSP_SECURITY_ROM_ARMOR_ENFORCED BIT(11) + ++/** ++ * enum psp_cmd - PSP mailbox commands ++ * @PSP_CMD_TEE_RING_INIT: Initialize TEE ring buffer ++ * @PSP_CMD_TEE_RING_DESTROY: Destroy TEE ring buffer ++ * @PSP_CMD_MAX: Maximum command id ++ */ ++enum psp_cmd { ++ PSP_CMD_TEE_RING_INIT = 1, ++ PSP_CMD_TEE_RING_DESTROY = 2, ++ PSP_CMD_MAX = 15, ++}; ++ ++int psp_mailbox_command(struct psp_device *psp, enum psp_cmd cmd, void *cmdbuff, ++ unsigned int timeout_msecs, unsigned int *cmdresp); ++ + #endif /* __PSP_DEV_H */ +diff --git a/drivers/crypto/ccp/sp-dev.h b/drivers/crypto/ccp/sp-dev.h +index 8bbef2426acd4..2efe4a6ef544f 100644 +--- a/drivers/crypto/ccp/sp-dev.h ++++ b/drivers/crypto/ccp/sp-dev.h +@@ -71,6 +71,9 @@ struct psp_vdata { + const struct sev_vdata *sev; + const struct tee_vdata *tee; + const struct platform_access_vdata *platform_access; ++ const unsigned int cmdresp_reg; ++ const unsigned int cmdbuff_addr_lo_reg; ++ const unsigned int cmdbuff_addr_hi_reg; + const unsigned int feature_reg; + const unsigned int inten_reg; + const unsigned int intsts_reg; +diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c +index 8f1b032f7e633..86517bb4c1952 100644 +--- a/drivers/crypto/ccp/sp-pci.c ++++ b/drivers/crypto/ccp/sp-pci.c +@@ -428,18 +428,12 @@ static const struct sev_vdata sevv2 = { + }; + + static const struct tee_vdata teev1 = { +- .cmdresp_reg = 0x10544, /* C2PMSG_17 */ +- .cmdbuff_addr_lo_reg = 0x10548, /* C2PMSG_18 */ +- .cmdbuff_addr_hi_reg = 0x1054c, /* C2PMSG_19 */ + .ring_wptr_reg = 0x10550, /* C2PMSG_20 */ + .ring_rptr_reg = 0x10554, /* C2PMSG_21 */ + .info_reg = 0x109e8, /* C2PMSG_58 */ + }; + + static const struct tee_vdata teev2 = { +- .cmdresp_reg = 0x10944, /* C2PMSG_17 */ +- .cmdbuff_addr_lo_reg = 0x10948, /* C2PMSG_18 */ +- .cmdbuff_addr_hi_reg = 0x1094c, /* C2PMSG_19 */ + .ring_wptr_reg = 0x10950, /* C2PMSG_20 */ + .ring_rptr_reg = 0x10954, /* C2PMSG_21 */ + }; +@@ -476,6 +470,9 @@ static const struct psp_vdata pspv2 = { + static const struct psp_vdata pspv3 = { + .tee = &teev1, + .platform_access = &pa_v1, ++ .cmdresp_reg = 0x10544, /* C2PMSG_17 */ ++ .cmdbuff_addr_lo_reg = 0x10548, /* C2PMSG_18 */ ++ .cmdbuff_addr_hi_reg = 0x1054c, /* C2PMSG_19 */ + .bootloader_info_reg = 0x109ec, /* C2PMSG_59 */ + .feature_reg = 0x109fc, /* C2PMSG_63 */ + .inten_reg = 0x10690, /* P2CMSG_INTEN */ +@@ -486,6 +483,9 @@ static const struct psp_vdata pspv3 = { + static const struct psp_vdata pspv4 = { + .sev = &sevv2, + .tee = &teev1, ++ .cmdresp_reg = 0x10544, /* C2PMSG_17 */ ++ .cmdbuff_addr_lo_reg = 0x10548, /* C2PMSG_18 */ ++ .cmdbuff_addr_hi_reg = 0x1054c, /* C2PMSG_19 */ + .bootloader_info_reg = 0x109ec, /* C2PMSG_59 */ + .feature_reg = 0x109fc, /* C2PMSG_63 */ + .inten_reg = 0x10690, /* P2CMSG_INTEN */ +@@ -495,6 +495,9 @@ static const struct psp_vdata pspv4 = { + static const struct psp_vdata pspv5 = { + .tee = &teev2, + .platform_access = &pa_v2, ++ .cmdresp_reg = 0x10944, /* C2PMSG_17 */ ++ .cmdbuff_addr_lo_reg = 0x10948, /* C2PMSG_18 */ ++ .cmdbuff_addr_hi_reg = 0x1094c, /* C2PMSG_19 */ + .feature_reg = 0x109fc, /* C2PMSG_63 */ + .inten_reg = 0x10510, /* P2CMSG_INTEN */ + .intsts_reg = 0x10514, /* P2CMSG_INTSTS */ +@@ -503,6 +506,9 @@ static const struct psp_vdata pspv5 = { + static const struct psp_vdata pspv6 = { + .sev = &sevv2, + .tee = &teev2, ++ .cmdresp_reg = 0x10944, /* C2PMSG_17 */ ++ .cmdbuff_addr_lo_reg = 0x10948, /* C2PMSG_18 */ ++ .cmdbuff_addr_hi_reg = 0x1094c, /* C2PMSG_19 */ + .feature_reg = 0x109fc, /* C2PMSG_63 */ + .inten_reg = 0x10510, /* P2CMSG_INTEN */ + .intsts_reg = 0x10514, /* P2CMSG_INTSTS */ +diff --git a/drivers/crypto/ccp/tee-dev.c b/drivers/crypto/ccp/tee-dev.c +index 9c02706e94948..0ccd0e29b0380 100644 +--- a/drivers/crypto/ccp/tee-dev.c ++++ b/drivers/crypto/ccp/tee-dev.c +@@ -62,26 +62,6 @@ static void tee_free_ring(struct psp_tee_device *tee) + mutex_destroy(&rb_mgr->mutex); + } + +-static int tee_wait_cmd_poll(struct psp_tee_device *tee, unsigned int timeout, +- unsigned int *reg) +-{ +- /* ~10ms sleep per loop => nloop = timeout * 100 */ +- int nloop = timeout * 100; +- +- while (--nloop) { +- *reg = ioread32(tee->io_regs + tee->vdata->cmdresp_reg); +- if (FIELD_GET(PSP_CMDRESP_RESP, *reg)) +- return 0; +- +- usleep_range(10000, 10100); +- } +- +- dev_err(tee->dev, "tee: command timed out, disabling PSP\n"); +- psp_dead = true; +- +- return -ETIMEDOUT; +-} +- + static + struct tee_init_ring_cmd *tee_alloc_cmd_buffer(struct psp_tee_device *tee) + { +@@ -110,7 +90,6 @@ static int tee_init_ring(struct psp_tee_device *tee) + { + int ring_size = MAX_RING_BUFFER_ENTRIES * sizeof(struct tee_ring_cmd); + struct tee_init_ring_cmd *cmd; +- phys_addr_t cmd_buffer; + unsigned int reg; + int ret; + +@@ -130,23 +109,15 @@ static int tee_init_ring(struct psp_tee_device *tee) + return -ENOMEM; + } + +- cmd_buffer = __psp_pa((void *)cmd); +- + /* Send command buffer details to Trusted OS by writing to + * CPU-PSP message registers + */ +- +- iowrite32(lower_32_bits(cmd_buffer), +- tee->io_regs + tee->vdata->cmdbuff_addr_lo_reg); +- iowrite32(upper_32_bits(cmd_buffer), +- tee->io_regs + tee->vdata->cmdbuff_addr_hi_reg); +- iowrite32(TEE_RING_INIT_CMD, +- tee->io_regs + tee->vdata->cmdresp_reg); +- +- ret = tee_wait_cmd_poll(tee, TEE_DEFAULT_TIMEOUT, ®); ++ ret = psp_mailbox_command(tee->psp, PSP_CMD_TEE_RING_INIT, cmd, ++ TEE_DEFAULT_CMD_TIMEOUT, ®); + if (ret) { +- dev_err(tee->dev, "tee: ring init command timed out\n"); ++ dev_err(tee->dev, "tee: ring init command timed out, disabling TEE support\n"); + tee_free_ring(tee); ++ psp_dead = true; + goto free_buf; + } + +@@ -174,12 +145,11 @@ static void tee_destroy_ring(struct psp_tee_device *tee) + if (psp_dead) + goto free_ring; + +- iowrite32(TEE_RING_DESTROY_CMD, +- tee->io_regs + tee->vdata->cmdresp_reg); +- +- ret = tee_wait_cmd_poll(tee, TEE_DEFAULT_TIMEOUT, ®); ++ ret = psp_mailbox_command(tee->psp, PSP_CMD_TEE_RING_DESTROY, NULL, ++ TEE_DEFAULT_CMD_TIMEOUT, ®); + if (ret) { +- dev_err(tee->dev, "tee: ring destroy command timed out\n"); ++ dev_err(tee->dev, "tee: ring destroy command timed out, disabling TEE support\n"); ++ psp_dead = true; + } else if (FIELD_GET(PSP_CMDRESP_STS, reg)) { + dev_err(tee->dev, "tee: ring destroy command failed (%#010lx)\n", + FIELD_GET(PSP_CMDRESP_STS, reg)); +@@ -370,7 +340,7 @@ int psp_tee_process_cmd(enum tee_cmd_id cmd_id, void *buf, size_t len, + if (ret) + return ret; + +- ret = tee_wait_cmd_completion(tee, resp, TEE_DEFAULT_TIMEOUT); ++ ret = tee_wait_cmd_completion(tee, resp, TEE_DEFAULT_RING_TIMEOUT); + if (ret) { + resp->flag = CMD_RESPONSE_TIMEDOUT; + return ret; +diff --git a/drivers/crypto/ccp/tee-dev.h b/drivers/crypto/ccp/tee-dev.h +index b0bf1de94ea6f..c23416cb7bb37 100644 +--- a/drivers/crypto/ccp/tee-dev.h ++++ b/drivers/crypto/ccp/tee-dev.h +@@ -17,21 +17,10 @@ + #include + #include + +-#define TEE_DEFAULT_TIMEOUT 10 ++#define TEE_DEFAULT_CMD_TIMEOUT (10 * MSEC_PER_SEC) ++#define TEE_DEFAULT_RING_TIMEOUT 10 + #define MAX_BUFFER_SIZE 988 + +-/** +- * enum tee_ring_cmd_id - TEE interface commands for ring buffer configuration +- * @TEE_RING_INIT_CMD: Initialize ring buffer +- * @TEE_RING_DESTROY_CMD: Destroy ring buffer +- * @TEE_RING_MAX_CMD: Maximum command id +- */ +-enum tee_ring_cmd_id { +- TEE_RING_INIT_CMD = 0x00010000, +- TEE_RING_DESTROY_CMD = 0x00020000, +- TEE_RING_MAX_CMD = 0x000F0000, +-}; +- + /** + * struct tee_init_ring_cmd - Command to init TEE ring buffer + * @low_addr: bits [31:0] of the physical address of ring buffer +-- +2.51.0 + diff --git a/queue-6.6/crypto-ccp-send-psp_cmd_tee_ring_destroy-when-psp_cm.patch b/queue-6.6/crypto-ccp-send-psp_cmd_tee_ring_destroy-when-psp_cm.patch new file mode 100644 index 0000000000..2e29ca9542 --- /dev/null +++ b/queue-6.6/crypto-ccp-send-psp_cmd_tee_ring_destroy-when-psp_cm.patch @@ -0,0 +1,113 @@ +From d026eec7da15a9439d88343d863df13b001b9345 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 22:11:32 -0600 +Subject: crypto: ccp - Send PSP_CMD_TEE_RING_DESTROY when + PSP_CMD_TEE_RING_INIT fails +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Mario Limonciello (AMD) + +[ Upstream commit 7b85137caf110a09a4a18f00f730de4709f9afc8 ] + +The hibernate resume sequence involves loading a resume kernel that is just +used for loading the hibernate image before shifting back to the existing +kernel. + +During that hibernate resume sequence the resume kernel may have loaded +the ccp driver. If this happens the resume kernel will also have called +PSP_CMD_TEE_RING_INIT but it will never have called +PSP_CMD_TEE_RING_DESTROY. + +This is problematic because the existing kernel needs to re-initialize the +ring. One could argue that the existing kernel should call destroy +as part of restore() but there is no guarantee that the resume kernel did +or didn't load the ccp driver. There is also no callback opportunity for +the resume kernel to destroy before handing back control to the existing +kernel. + +Similar problems could potentially exist with the use of kdump and +crash handling. I actually reproduced this issue like this: + +1) rmmod ccp +2) hibernate the system +3) resume the system +4) modprobe ccp + +The resume kernel will have loaded ccp but never destroyed and then when +I try to modprobe it fails. + +Because of these possible cases add a flow that checks the error code from +the PSP_CMD_TEE_RING_INIT call and tries to call PSP_CMD_TEE_RING_DESTROY +if it failed. If this succeeds then call PSP_CMD_TEE_RING_INIT again. + +Fixes: f892a21f51162 ("crypto: ccp - use generic power management") +Reported-by: Lars Francke +Closes: https://lore.kernel.org/platform-driver-x86/CAD-Ua_gfJnQSo8ucS_7ZwzuhoBRJ14zXP7s8b-zX3ZcxcyWePw@mail.gmail.com/ +Tested-by: Yijun Shen +Signed-off-by: Mario Limonciello (AMD) +Reviewed-by: Shyam Sundar S K +Acked-by: Tom Lendacky +Link: https://patch.msgid.link/20260116041132.153674-6-superm1@kernel.org +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/crypto/ccp/tee-dev.c | 14 ++++++++++++++ + include/linux/psp.h | 1 + + 2 files changed, 15 insertions(+) + +diff --git a/drivers/crypto/ccp/tee-dev.c b/drivers/crypto/ccp/tee-dev.c +index 09b54bd9b3e3c..01d7dcb9cfee1 100644 +--- a/drivers/crypto/ccp/tee-dev.c ++++ b/drivers/crypto/ccp/tee-dev.c +@@ -113,6 +113,7 @@ static int tee_init_ring(struct psp_tee_device *tee) + { + int ring_size = MAX_RING_BUFFER_ENTRIES * sizeof(struct tee_ring_cmd); + struct tee_init_ring_cmd *cmd; ++ bool retry = false; + unsigned int reg; + int ret; + +@@ -135,6 +136,7 @@ static int tee_init_ring(struct psp_tee_device *tee) + /* Send command buffer details to Trusted OS by writing to + * CPU-PSP message registers + */ ++retry_init: + ret = psp_mailbox_command(tee->psp, PSP_CMD_TEE_RING_INIT, cmd, + TEE_DEFAULT_CMD_TIMEOUT, ®); + if (ret) { +@@ -145,6 +147,18 @@ static int tee_init_ring(struct psp_tee_device *tee) + } + + if (FIELD_GET(PSP_CMDRESP_STS, reg)) { ++ /* ++ * During the hibernate resume sequence driver may have gotten loaded ++ * but the ring not properly destroyed. If the ring doesn't work, try ++ * to destroy and re-init once. ++ */ ++ if (!retry && FIELD_GET(PSP_CMDRESP_STS, reg) == PSP_TEE_STS_RING_BUSY) { ++ dev_info(tee->dev, "tee: ring init command failed with busy status, retrying\n"); ++ if (tee_send_destroy_cmd(tee)) { ++ retry = true; ++ goto retry_init; ++ } ++ } + dev_err(tee->dev, "tee: ring init command failed (%#010lx)\n", + FIELD_GET(PSP_CMDRESP_STS, reg)); + tee_free_ring(tee); +diff --git a/include/linux/psp.h b/include/linux/psp.h +index 92e60aeef21e1..b337dcce1e991 100644 +--- a/include/linux/psp.h ++++ b/include/linux/psp.h +@@ -18,6 +18,7 @@ + * and should include an appropriate local definition in their source file. + */ + #define PSP_CMDRESP_STS GENMASK(15, 0) ++#define PSP_TEE_STS_RING_BUSY 0x0000000d /* Ring already initialized */ + #define PSP_CMDRESP_CMD GENMASK(23, 16) + #define PSP_CMDRESP_RESERVED GENMASK(29, 24) + #define PSP_CMDRESP_RECOVERY BIT(30) +-- +2.51.0 + diff --git a/queue-6.6/crypto-hisilicon-sec2-support-skcipher-aead-fallback.patch b/queue-6.6/crypto-hisilicon-sec2-support-skcipher-aead-fallback.patch new file mode 100644 index 0000000000..7ac9eea56b --- /dev/null +++ b/queue-6.6/crypto-hisilicon-sec2-support-skcipher-aead-fallback.patch @@ -0,0 +1,220 @@ +From 66edbc7c8c3f8c69e40166a5c4017fe0c9fa6ba4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 21:44:52 +0800 +Subject: crypto: hisilicon/sec2 - support skcipher/aead fallback for hardware + queue unavailable + +From: Qi Tao + +[ Upstream commit e7507439628052363500d717caffb5c2241854dc ] + +When all hardware queues are busy and no shareable queue, +new processes fail to apply for queues. To avoid affecting +tasks, support fallback mechanism when hardware queues are +unavailable. + +Fixes: c16a70c1f253 ("crypto: hisilicon/sec - add new algorithm mode for AEAD") +Signed-off-by: Qi Tao +Signed-off-by: Chenghai Huang +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/sec2/sec_crypto.c | 62 ++++++++++++++++------ + 1 file changed, 47 insertions(+), 15 deletions(-) + +diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.c b/drivers/crypto/hisilicon/sec2/sec_crypto.c +index d6727b8ff582b..8db3d2990816e 100644 +--- a/drivers/crypto/hisilicon/sec2/sec_crypto.c ++++ b/drivers/crypto/hisilicon/sec2/sec_crypto.c +@@ -590,10 +590,8 @@ static int sec_ctx_base_init(struct sec_ctx *ctx) + int i, ret; + + ctx->qps = sec_create_qps(); +- if (!ctx->qps) { +- pr_err("Can not create sec qps!\n"); ++ if (!ctx->qps) + return -ENODEV; +- } + + sec = container_of(ctx->qps[0]->qm, struct sec_dev, qm); + ctx->sec = sec; +@@ -632,6 +630,9 @@ static void sec_ctx_base_uninit(struct sec_ctx *ctx) + { + int i; + ++ if (!ctx->qps) ++ return; ++ + for (i = 0; i < ctx->sec->ctx_q_num; i++) + sec_release_qp_ctx(ctx, &ctx->qp_ctx[i]); + +@@ -643,6 +644,9 @@ static int sec_cipher_init(struct sec_ctx *ctx) + { + struct sec_cipher_ctx *c_ctx = &ctx->c_ctx; + ++ if (!ctx->qps) ++ return 0; ++ + c_ctx->c_key = dma_alloc_coherent(ctx->dev, SEC_MAX_KEY_SIZE, + &c_ctx->c_key_dma, GFP_KERNEL); + if (!c_ctx->c_key) +@@ -655,6 +659,9 @@ static void sec_cipher_uninit(struct sec_ctx *ctx) + { + struct sec_cipher_ctx *c_ctx = &ctx->c_ctx; + ++ if (!ctx->qps) ++ return; ++ + memzero_explicit(c_ctx->c_key, SEC_MAX_KEY_SIZE); + dma_free_coherent(ctx->dev, SEC_MAX_KEY_SIZE, + c_ctx->c_key, c_ctx->c_key_dma); +@@ -676,6 +683,9 @@ static void sec_auth_uninit(struct sec_ctx *ctx) + { + struct sec_auth_ctx *a_ctx = &ctx->a_ctx; + ++ if (!ctx->qps) ++ return; ++ + memzero_explicit(a_ctx->a_key, SEC_MAX_AKEY_SIZE); + dma_free_coherent(ctx->dev, SEC_MAX_AKEY_SIZE, + a_ctx->a_key, a_ctx->a_key_dma); +@@ -713,7 +723,7 @@ static int sec_skcipher_init(struct crypto_skcipher *tfm) + } + + ret = sec_ctx_base_init(ctx); +- if (ret) ++ if (ret && ret != -ENODEV) + return ret; + + ret = sec_cipher_init(ctx); +@@ -824,6 +834,9 @@ static int sec_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key, + struct device *dev = ctx->dev; + int ret; + ++ if (!ctx->qps) ++ goto set_soft_key; ++ + if (c_mode == SEC_CMODE_XTS) { + ret = xts_verify_key(tfm, key, keylen); + if (ret) { +@@ -854,13 +867,14 @@ static int sec_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key, + } + + memcpy(c_ctx->c_key, key, keylen); +- if (c_ctx->fbtfm) { +- ret = crypto_sync_skcipher_setkey(c_ctx->fbtfm, key, keylen); +- if (ret) { +- dev_err(dev, "failed to set fallback skcipher key!\n"); +- return ret; +- } ++ ++set_soft_key: ++ ret = crypto_sync_skcipher_setkey(c_ctx->fbtfm, key, keylen); ++ if (ret) { ++ dev_err(dev, "failed to set fallback skcipher key!\n"); ++ return ret; + } ++ + return 0; + } + +@@ -1139,6 +1153,9 @@ static int sec_aead_setkey(struct crypto_aead *tfm, const u8 *key, + struct crypto_authenc_keys keys; + int ret; + ++ if (!ctx->qps) ++ return sec_aead_fallback_setkey(a_ctx, tfm, key, keylen); ++ + ctx->a_ctx.a_alg = a_alg; + ctx->c_ctx.c_alg = c_alg; + c_ctx->c_mode = c_mode; +@@ -1833,6 +1850,9 @@ static int sec_skcipher_ctx_init(struct crypto_skcipher *tfm) + if (ret) + return ret; + ++ if (!ctx->qps) ++ return 0; ++ + if (ctx->sec->qm.ver < QM_HW_V3) { + ctx->type_supported = SEC_BD_TYPE2; + ctx->req_op = &sec_skcipher_req_ops; +@@ -1841,7 +1861,7 @@ static int sec_skcipher_ctx_init(struct crypto_skcipher *tfm) + ctx->req_op = &sec_skcipher_req_ops_v3; + } + +- return ret; ++ return 0; + } + + static void sec_skcipher_ctx_exit(struct crypto_skcipher *tfm) +@@ -1909,7 +1929,7 @@ static int sec_aead_ctx_init(struct crypto_aead *tfm, const char *hash_name) + int ret; + + ret = sec_aead_init(tfm); +- if (ret) { ++ if (ret && ret != -ENODEV) { + pr_err("hisi_sec2: aead init error!\n"); + return ret; + } +@@ -1951,7 +1971,7 @@ static int sec_aead_xcm_ctx_init(struct crypto_aead *tfm) + int ret; + + ret = sec_aead_init(tfm); +- if (ret) { ++ if (ret && ret != -ENODEV) { + dev_err(ctx->dev, "hisi_sec2: aead xcm init error!\n"); + return ret; + } +@@ -2098,6 +2118,9 @@ static int sec_skcipher_crypto(struct skcipher_request *sk_req, bool encrypt) + bool need_fallback = false; + int ret; + ++ if (!ctx->qps) ++ goto soft_crypto; ++ + if (!sk_req->cryptlen) { + if (ctx->c_ctx.c_mode == SEC_CMODE_XTS) + return -EINVAL; +@@ -2114,9 +2137,12 @@ static int sec_skcipher_crypto(struct skcipher_request *sk_req, bool encrypt) + return -EINVAL; + + if (unlikely(ctx->c_ctx.fallback || need_fallback)) +- return sec_skcipher_soft_crypto(ctx, sk_req, encrypt); ++ goto soft_crypto; + + return ctx->req_op->process(ctx, req); ++ ++soft_crypto: ++ return sec_skcipher_soft_crypto(ctx, sk_req, encrypt); + } + + static int sec_skcipher_encrypt(struct skcipher_request *sk_req) +@@ -2346,6 +2372,9 @@ static int sec_aead_crypto(struct aead_request *a_req, bool encrypt) + bool need_fallback = false; + int ret; + ++ if (!ctx->qps) ++ goto soft_crypto; ++ + req->flag = a_req->base.flags; + req->aead_req.aead_req = a_req; + req->c_req.encrypt = encrypt; +@@ -2355,11 +2384,14 @@ static int sec_aead_crypto(struct aead_request *a_req, bool encrypt) + ret = sec_aead_param_check(ctx, req, &need_fallback); + if (unlikely(ret)) { + if (need_fallback) +- return sec_aead_soft_crypto(ctx, a_req, encrypt); ++ goto soft_crypto; + return -EINVAL; + } + + return ctx->req_op->process(ctx, req); ++ ++soft_crypto: ++ return sec_aead_soft_crypto(ctx, a_req, encrypt); + } + + static int sec_aead_encrypt(struct aead_request *a_req) +-- +2.51.0 + diff --git a/queue-6.6/crypto-hisilicon-trng-modifying-the-order-of-header-.patch b/queue-6.6/crypto-hisilicon-trng-modifying-the-order-of-header-.patch new file mode 100644 index 0000000000..e7ab990e43 --- /dev/null +++ b/queue-6.6/crypto-hisilicon-trng-modifying-the-order-of-header-.patch @@ -0,0 +1,56 @@ +From 3819a617e01fcc9eb16e1f1d452c6bebc550df5b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Aug 2024 17:50:09 +0800 +Subject: crypto: hisilicon/trng - modifying the order of header files + +From: Chenghai Huang + +[ Upstream commit f5dd7c43022799ac5c4e3a0d445f9c293a198413 ] + +Header files is included Order-ref: standard library headers, +OS library headers, and project-specific headers. This patch +modifies the order of header files according to suggestions. + +In addition, use %u to print unsigned int variables to prevent +overflow. + +Signed-off-by: Chenghai Huang +Signed-off-by: Herbert Xu +Stable-dep-of: 3d3135057ff5 ("crypto: hisilicon/trng - support tfms sharing the device") +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/trng/trng.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/crypto/hisilicon/trng/trng.c b/drivers/crypto/hisilicon/trng/trng.c +index 97e500db0a825..ec1eaed32d3bc 100644 +--- a/drivers/crypto/hisilicon/trng/trng.c ++++ b/drivers/crypto/hisilicon/trng/trng.c +@@ -1,6 +1,7 @@ + // SPDX-License-Identifier: GPL-2.0 + /* Copyright (c) 2019 HiSilicon Limited. */ + ++#include + #include + #include + #include +@@ -13,7 +14,6 @@ + #include + #include + #include +-#include + + #define HISI_TRNG_REG 0x00F0 + #define HISI_TRNG_BYTES 4 +@@ -121,7 +121,7 @@ static int hisi_trng_generate(struct crypto_rng *tfm, const u8 *src, + u32 i; + + if (dlen > SW_DRBG_BLOCKS_NUM * SW_DRBG_BYTES || dlen == 0) { +- pr_err("dlen(%d) exceeds limit(%d)!\n", dlen, ++ pr_err("dlen(%u) exceeds limit(%d)!\n", dlen, + SW_DRBG_BLOCKS_NUM * SW_DRBG_BYTES); + return -EINVAL; + } +-- +2.51.0 + diff --git a/queue-6.6/crypto-hisilicon-trng-support-tfms-sharing-the-devic.patch b/queue-6.6/crypto-hisilicon-trng-support-tfms-sharing-the-devic.patch new file mode 100644 index 0000000000..92d74b3cbf --- /dev/null +++ b/queue-6.6/crypto-hisilicon-trng-support-tfms-sharing-the-devic.patch @@ -0,0 +1,258 @@ +From ee7d9d4b6cbc7608d6ba5f8e9eefd7dbc1d5aa95 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 17 Jan 2026 15:18:21 +0800 +Subject: crypto: hisilicon/trng - support tfms sharing the device + +From: Weili Qian + +[ Upstream commit 3d3135057ff567d5c09fff4c9ef6391a684e8042 ] + +Since the number of devices is limited, and the number +of tfms may exceed the number of devices, to ensure that +tfms can be successfully allocated, support tfms +sharing the same device. + +Fixes: e4d9d10ef4be ("crypto: hisilicon/trng - add support for PRNG") +Signed-off-by: Weili Qian +Signed-off-by: Chenghai Huang +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/trng/trng.c | 121 +++++++++++++++++++-------- + 1 file changed, 86 insertions(+), 35 deletions(-) + +diff --git a/drivers/crypto/hisilicon/trng/trng.c b/drivers/crypto/hisilicon/trng/trng.c +index ec1eaed32d3bc..b2d9b5310b784 100644 +--- a/drivers/crypto/hisilicon/trng/trng.c ++++ b/drivers/crypto/hisilicon/trng/trng.c +@@ -40,6 +40,7 @@ + #define SEED_SHIFT_24 24 + #define SEED_SHIFT_16 16 + #define SEED_SHIFT_8 8 ++#define SW_MAX_RANDOM_BYTES 65520 + + struct hisi_trng_list { + struct mutex lock; +@@ -53,8 +54,10 @@ struct hisi_trng { + struct list_head list; + struct hwrng rng; + u32 ver; +- bool is_used; +- struct mutex mutex; ++ u32 ctx_num; ++ /* The bytes of the random number generated since the last seeding. */ ++ u32 random_bytes; ++ struct mutex lock; + }; + + struct hisi_trng_ctx { +@@ -63,10 +66,14 @@ struct hisi_trng_ctx { + + static atomic_t trng_active_devs; + static struct hisi_trng_list trng_devices; ++static int hisi_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait); + +-static void hisi_trng_set_seed(struct hisi_trng *trng, const u8 *seed) ++static int hisi_trng_set_seed(struct hisi_trng *trng, const u8 *seed) + { + u32 val, seed_reg, i; ++ int ret; ++ ++ writel(0x0, trng->base + SW_DRBG_BLOCKS); + + for (i = 0; i < SW_DRBG_SEED_SIZE; + i += SW_DRBG_SEED_SIZE / SW_DRBG_SEED_REGS_NUM) { +@@ -78,6 +85,20 @@ static void hisi_trng_set_seed(struct hisi_trng *trng, const u8 *seed) + seed_reg = (i >> SW_DRBG_NUM_SHIFT) % SW_DRBG_SEED_REGS_NUM; + writel(val, trng->base + SW_DRBG_SEED(seed_reg)); + } ++ ++ writel(SW_DRBG_BLOCKS_NUM | (0x1 << SW_DRBG_ENABLE_SHIFT), ++ trng->base + SW_DRBG_BLOCKS); ++ writel(0x1, trng->base + SW_DRBG_INIT); ++ ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS, ++ val, val & BIT(0), SLEEP_US, TIMEOUT_US); ++ if (ret) { ++ pr_err("failed to init trng(%d)\n", ret); ++ return -EIO; ++ } ++ ++ trng->random_bytes = 0; ++ ++ return 0; + } + + static int hisi_trng_seed(struct crypto_rng *tfm, const u8 *seed, +@@ -85,8 +106,7 @@ static int hisi_trng_seed(struct crypto_rng *tfm, const u8 *seed, + { + struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm); + struct hisi_trng *trng = ctx->trng; +- u32 val = 0; +- int ret = 0; ++ int ret; + + if (slen < SW_DRBG_SEED_SIZE) { + pr_err("slen(%u) is not matched with trng(%d)\n", slen, +@@ -94,43 +114,45 @@ static int hisi_trng_seed(struct crypto_rng *tfm, const u8 *seed, + return -EINVAL; + } + +- writel(0x0, trng->base + SW_DRBG_BLOCKS); +- hisi_trng_set_seed(trng, seed); ++ mutex_lock(&trng->lock); ++ ret = hisi_trng_set_seed(trng, seed); ++ mutex_unlock(&trng->lock); + +- writel(SW_DRBG_BLOCKS_NUM | (0x1 << SW_DRBG_ENABLE_SHIFT), +- trng->base + SW_DRBG_BLOCKS); +- writel(0x1, trng->base + SW_DRBG_INIT); ++ return ret; ++} + +- ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS, +- val, val & BIT(0), SLEEP_US, TIMEOUT_US); +- if (ret) +- pr_err("fail to init trng(%d)\n", ret); ++static int hisi_trng_reseed(struct hisi_trng *trng) ++{ ++ u8 seed[SW_DRBG_SEED_SIZE]; ++ int size; + +- return ret; ++ if (!trng->random_bytes) ++ return 0; ++ ++ size = hisi_trng_read(&trng->rng, seed, SW_DRBG_SEED_SIZE, false); ++ if (size != SW_DRBG_SEED_SIZE) ++ return -EIO; ++ ++ return hisi_trng_set_seed(trng, seed); + } + +-static int hisi_trng_generate(struct crypto_rng *tfm, const u8 *src, +- unsigned int slen, u8 *dstn, unsigned int dlen) ++static int hisi_trng_get_bytes(struct hisi_trng *trng, u8 *dstn, unsigned int dlen) + { +- struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm); +- struct hisi_trng *trng = ctx->trng; + u32 data[SW_DRBG_DATA_NUM]; + u32 currsize = 0; + u32 val = 0; + int ret; + u32 i; + +- if (dlen > SW_DRBG_BLOCKS_NUM * SW_DRBG_BYTES || dlen == 0) { +- pr_err("dlen(%u) exceeds limit(%d)!\n", dlen, +- SW_DRBG_BLOCKS_NUM * SW_DRBG_BYTES); +- return -EINVAL; +- } ++ ret = hisi_trng_reseed(trng); ++ if (ret) ++ return ret; + + do { + ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS, +- val, val & BIT(1), SLEEP_US, TIMEOUT_US); ++ val, val & BIT(1), SLEEP_US, TIMEOUT_US); + if (ret) { +- pr_err("fail to generate random number(%d)!\n", ret); ++ pr_err("failed to generate random number(%d)!\n", ret); + break; + } + +@@ -145,30 +167,57 @@ static int hisi_trng_generate(struct crypto_rng *tfm, const u8 *src, + currsize = dlen; + } + ++ trng->random_bytes += SW_DRBG_BYTES; + writel(0x1, trng->base + SW_DRBG_GEN); + } while (currsize < dlen); + + return ret; + } + ++static int hisi_trng_generate(struct crypto_rng *tfm, const u8 *src, ++ unsigned int slen, u8 *dstn, unsigned int dlen) ++{ ++ struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm); ++ struct hisi_trng *trng = ctx->trng; ++ unsigned int currsize = 0; ++ unsigned int block_size; ++ int ret; ++ ++ if (!dstn || !dlen) { ++ pr_err("output is error, dlen %u!\n", dlen); ++ return -EINVAL; ++ } ++ ++ do { ++ block_size = min_t(unsigned int, dlen - currsize, SW_MAX_RANDOM_BYTES); ++ mutex_lock(&trng->lock); ++ ret = hisi_trng_get_bytes(trng, dstn + currsize, block_size); ++ mutex_unlock(&trng->lock); ++ if (ret) ++ return ret; ++ currsize += block_size; ++ } while (currsize < dlen); ++ ++ return 0; ++} ++ + static int hisi_trng_init(struct crypto_tfm *tfm) + { + struct hisi_trng_ctx *ctx = crypto_tfm_ctx(tfm); + struct hisi_trng *trng; +- int ret = -EBUSY; ++ u32 ctx_num = ~0; + + mutex_lock(&trng_devices.lock); + list_for_each_entry(trng, &trng_devices.list, list) { +- if (!trng->is_used) { +- trng->is_used = true; ++ if (trng->ctx_num < ctx_num) { ++ ctx_num = trng->ctx_num; + ctx->trng = trng; +- ret = 0; +- break; + } + } ++ ctx->trng->ctx_num++; + mutex_unlock(&trng_devices.lock); + +- return ret; ++ return 0; + } + + static void hisi_trng_exit(struct crypto_tfm *tfm) +@@ -176,7 +225,7 @@ static void hisi_trng_exit(struct crypto_tfm *tfm) + struct hisi_trng_ctx *ctx = crypto_tfm_ctx(tfm); + + mutex_lock(&trng_devices.lock); +- ctx->trng->is_used = false; ++ ctx->trng->ctx_num--; + mutex_unlock(&trng_devices.lock); + } + +@@ -238,7 +287,7 @@ static int hisi_trng_del_from_list(struct hisi_trng *trng) + int ret = -EBUSY; + + mutex_lock(&trng_devices.lock); +- if (!trng->is_used) { ++ if (!trng->ctx_num) { + list_del(&trng->list); + ret = 0; + } +@@ -262,7 +311,9 @@ static int hisi_trng_probe(struct platform_device *pdev) + if (IS_ERR(trng->base)) + return PTR_ERR(trng->base); + +- trng->is_used = false; ++ trng->ctx_num = 0; ++ trng->random_bytes = SW_MAX_RANDOM_BYTES; ++ mutex_init(&trng->lock); + trng->ver = readl(trng->base + HISI_TRNG_VERSION); + if (!trng_devices.is_init) { + INIT_LIST_HEAD(&trng_devices.list); +-- +2.51.0 + diff --git a/queue-6.6/crypto-hisilicon-zip-adjust-the-way-to-obtain-the-re.patch b/queue-6.6/crypto-hisilicon-zip-adjust-the-way-to-obtain-the-re.patch new file mode 100644 index 0000000000..eaaa54ac9c --- /dev/null +++ b/queue-6.6/crypto-hisilicon-zip-adjust-the-way-to-obtain-the-re.patch @@ -0,0 +1,128 @@ +From a1f7d9dd787d77f5834009dd33b4ca5eff8b43d2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 21:44:42 +0800 +Subject: crypto: hisilicon/zip - adjust the way to obtain the req in the + callback function + +From: Chenghai Huang + +[ Upstream commit 19c2475ce1984cf675ebfbbeaa5509b2fb1887d6 ] + +In the shared queue design, multiple tfms use same qp, and one qp +need to corresponds to multiple qp_ctx. So use tag to obtain the +req virtual address. Build a one-to-one relationship between tfm +and qp_ctx. finaly remove the old get_tag operation. + +Fixes: 2bcf36348ce5 ("crypto: hisilicon/zip - initialize operations about 'sqe' in 'acomp_alg.init'") +Signed-off-by: Chenghai Huang +Signed-off-by: Weili Qian +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/zip/zip_crypto.c | 24 +++++++++-------------- + 1 file changed, 9 insertions(+), 15 deletions(-) + +diff --git a/drivers/crypto/hisilicon/zip/zip_crypto.c b/drivers/crypto/hisilicon/zip/zip_crypto.c +index 636ac794ebb75..d21ce4094d7db 100644 +--- a/drivers/crypto/hisilicon/zip/zip_crypto.c ++++ b/drivers/crypto/hisilicon/zip/zip_crypto.c +@@ -36,6 +36,7 @@ enum { + HZIP_CTX_Q_NUM + }; + ++#define GET_REQ_FROM_SQE(sqe) ((u64)(sqe)->dw26 | (u64)(sqe)->dw27 << 32) + #define COMP_NAME_TO_TYPE(alg_name) \ + (!strcmp((alg_name), "deflate") ? HZIP_ALG_TYPE_DEFLATE : 0) + +@@ -45,6 +46,7 @@ struct hisi_zip_req { + struct hisi_acc_hw_sgl *hw_dst; + dma_addr_t dma_src; + dma_addr_t dma_dst; ++ struct hisi_zip_qp_ctx *qp_ctx; + u16 req_id; + }; + +@@ -71,7 +73,6 @@ struct hisi_zip_sqe_ops { + void (*fill_req_type)(struct hisi_zip_sqe *sqe, u8 req_type); + void (*fill_tag)(struct hisi_zip_sqe *sqe, struct hisi_zip_req *req); + void (*fill_sqe_type)(struct hisi_zip_sqe *sqe, u8 sqe_type); +- u32 (*get_tag)(struct hisi_zip_sqe *sqe); + u32 (*get_status)(struct hisi_zip_sqe *sqe); + u32 (*get_dstlen)(struct hisi_zip_sqe *sqe); + }; +@@ -128,6 +129,7 @@ static struct hisi_zip_req *hisi_zip_create_req(struct hisi_zip_qp_ctx *qp_ctx, + req_cache = q + req_id; + req_cache->req_id = req_id; + req_cache->req = req; ++ req_cache->qp_ctx = qp_ctx; + + return req_cache; + } +@@ -178,7 +180,8 @@ static void hisi_zip_fill_req_type(struct hisi_zip_sqe *sqe, u8 req_type) + + static void hisi_zip_fill_tag(struct hisi_zip_sqe *sqe, struct hisi_zip_req *req) + { +- sqe->dw26 = req->req_id; ++ sqe->dw26 = lower_32_bits((u64)req); ++ sqe->dw27 = upper_32_bits((u64)req); + } + + static void hisi_zip_fill_sqe_type(struct hisi_zip_sqe *sqe, u8 sqe_type) +@@ -232,7 +235,7 @@ static int hisi_zip_do_work(struct hisi_zip_qp_ctx *qp_ctx, + &req->dma_dst); + if (IS_ERR(req->hw_dst)) { + ret = PTR_ERR(req->hw_dst); +- dev_err(dev, "failed to map the dst buffer to hw slg (%d)!\n", ++ dev_err(dev, "failed to map the dst buffer to hw sgl (%d)!\n", + ret); + goto err_unmap_input; + } +@@ -258,11 +261,6 @@ static int hisi_zip_do_work(struct hisi_zip_qp_ctx *qp_ctx, + return ret; + } + +-static u32 hisi_zip_get_tag(struct hisi_zip_sqe *sqe) +-{ +- return sqe->dw26; +-} +- + static u32 hisi_zip_get_status(struct hisi_zip_sqe *sqe) + { + return sqe->dw3 & HZIP_BD_STATUS_M; +@@ -275,14 +273,12 @@ static u32 hisi_zip_get_dstlen(struct hisi_zip_sqe *sqe) + + static void hisi_zip_acomp_cb(struct hisi_qp *qp, void *data) + { +- struct hisi_zip_qp_ctx *qp_ctx = qp->qp_ctx; ++ struct hisi_zip_sqe *sqe = data; ++ struct hisi_zip_req *req = (struct hisi_zip_req *)GET_REQ_FROM_SQE(sqe); ++ struct hisi_zip_qp_ctx *qp_ctx = req->qp_ctx; + const struct hisi_zip_sqe_ops *ops = qp_ctx->ctx->ops; + struct hisi_zip_dfx *dfx = &qp_ctx->zip_dev->dfx; +- struct hisi_zip_req_q *req_q = &qp_ctx->req_q; + struct device *dev = &qp->qm->pdev->dev; +- struct hisi_zip_sqe *sqe = data; +- u32 tag = ops->get_tag(sqe); +- struct hisi_zip_req *req = req_q->q + tag; + struct acomp_req *acomp_req = req->req; + int err = 0; + u32 status; +@@ -386,7 +382,6 @@ static const struct hisi_zip_sqe_ops hisi_zip_ops = { + .fill_req_type = hisi_zip_fill_req_type, + .fill_tag = hisi_zip_fill_tag, + .fill_sqe_type = hisi_zip_fill_sqe_type, +- .get_tag = hisi_zip_get_tag, + .get_status = hisi_zip_get_status, + .get_dstlen = hisi_zip_get_dstlen, + }; +@@ -574,7 +569,6 @@ static void hisi_zip_acomp_exit(struct crypto_acomp *tfm) + { + struct hisi_zip_ctx *ctx = crypto_tfm_ctx(&tfm->base); + +- hisi_zip_set_acomp_cb(ctx, NULL); + hisi_zip_release_sgl_pool(ctx); + hisi_zip_release_req_q(ctx); + hisi_zip_ctx_exit(ctx); +-- +2.51.0 + diff --git a/queue-6.6/crypto-hisilicon-zip-remove-zlib-and-gzip.patch b/queue-6.6/crypto-hisilicon-zip-remove-zlib-and-gzip.patch new file mode 100644 index 0000000000..6bc2fc76ec --- /dev/null +++ b/queue-6.6/crypto-hisilicon-zip-remove-zlib-and-gzip.patch @@ -0,0 +1,489 @@ +From ed60b06991d23bfeeb5f2732928ba92e2cb7d52e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 14 Sep 2023 17:09:08 +0800 +Subject: crypto: hisilicon/zip - remove zlib and gzip + +From: Yang Shen + +[ Upstream commit 1a9e6f59caeea35d157f91b452ae75f251d8255b ] + +Remove the support of zlib-deflate and gzip. + +Signed-off-by: Yang Shen +Reviewed-by: Longfang Liu +Signed-off-by: Herbert Xu +Stable-dep-of: 19c2475ce198 ("crypto: hisilicon/zip - adjust the way to obtain the req in the callback function") +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/zip/zip_crypto.c | 308 ++-------------------- + drivers/crypto/hisilicon/zip/zip_main.c | 2 +- + 2 files changed, 22 insertions(+), 288 deletions(-) + +diff --git a/drivers/crypto/hisilicon/zip/zip_crypto.c b/drivers/crypto/hisilicon/zip/zip_crypto.c +index 09f60f7867795..636ac794ebb75 100644 +--- a/drivers/crypto/hisilicon/zip/zip_crypto.c ++++ b/drivers/crypto/hisilicon/zip/zip_crypto.c +@@ -17,38 +17,14 @@ + /* hisi_zip_sqe dw9 */ + #define HZIP_REQ_TYPE_M GENMASK(7, 0) + #define HZIP_ALG_TYPE_DEFLATE 0x01 +-#define HZIP_ALG_TYPE_ZLIB 0x02 +-#define HZIP_ALG_TYPE_GZIP 0x03 + #define HZIP_BUF_TYPE_M GENMASK(11, 8) +-#define HZIP_PBUFFER 0x0 + #define HZIP_SGL 0x1 + +-#define HZIP_ZLIB_HEAD_SIZE 2 +-#define HZIP_GZIP_HEAD_SIZE 10 +- +-#define GZIP_HEAD_FHCRC_BIT BIT(1) +-#define GZIP_HEAD_FEXTRA_BIT BIT(2) +-#define GZIP_HEAD_FNAME_BIT BIT(3) +-#define GZIP_HEAD_FCOMMENT_BIT BIT(4) +- +-#define GZIP_HEAD_FLG_SHIFT 3 +-#define GZIP_HEAD_FEXTRA_SHIFT 10 +-#define GZIP_HEAD_FEXTRA_XLEN 2UL +-#define GZIP_HEAD_FHCRC_SIZE 2 +- +-#define HZIP_GZIP_HEAD_BUF 256 + #define HZIP_ALG_PRIORITY 300 + #define HZIP_SGL_SGE_NR 10 + +-#define HZIP_ALG_ZLIB GENMASK(1, 0) +-#define HZIP_ALG_GZIP GENMASK(3, 2) + #define HZIP_ALG_DEFLATE GENMASK(5, 4) + +-static const u8 zlib_head[HZIP_ZLIB_HEAD_SIZE] = {0x78, 0x9c}; +-static const u8 gzip_head[HZIP_GZIP_HEAD_SIZE] = { +- 0x1f, 0x8b, 0x08, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x03 +-}; +- + enum hisi_zip_alg_type { + HZIP_ALG_TYPE_COMP = 0, + HZIP_ALG_TYPE_DECOMP = 1, +@@ -61,22 +37,10 @@ enum { + }; + + #define COMP_NAME_TO_TYPE(alg_name) \ +- (!strcmp((alg_name), "deflate") ? HZIP_ALG_TYPE_DEFLATE : \ +- (!strcmp((alg_name), "zlib-deflate") ? HZIP_ALG_TYPE_ZLIB : \ +- !strcmp((alg_name), "gzip") ? HZIP_ALG_TYPE_GZIP : 0)) \ +- +-#define TO_HEAD_SIZE(req_type) \ +- (((req_type) == HZIP_ALG_TYPE_ZLIB) ? sizeof(zlib_head) : \ +- ((req_type) == HZIP_ALG_TYPE_GZIP) ? sizeof(gzip_head) : 0) \ +- +-#define TO_HEAD(req_type) \ +- (((req_type) == HZIP_ALG_TYPE_ZLIB) ? zlib_head : \ +- ((req_type) == HZIP_ALG_TYPE_GZIP) ? gzip_head : NULL) \ ++ (!strcmp((alg_name), "deflate") ? HZIP_ALG_TYPE_DEFLATE : 0) + + struct hisi_zip_req { + struct acomp_req *req; +- u32 sskip; +- u32 dskip; + struct hisi_acc_hw_sgl *hw_src; + struct hisi_acc_hw_sgl *hw_dst; + dma_addr_t dma_src; +@@ -141,85 +105,8 @@ static u16 sgl_sge_nr = HZIP_SGL_SGE_NR; + module_param_cb(sgl_sge_nr, &sgl_sge_nr_ops, &sgl_sge_nr, 0444); + MODULE_PARM_DESC(sgl_sge_nr, "Number of sge in sgl(1-255)"); + +-static u32 get_extra_field_size(const u8 *start) +-{ +- return *((u16 *)start) + GZIP_HEAD_FEXTRA_XLEN; +-} +- +-static u32 get_name_field_size(const u8 *start) +-{ +- return strlen(start) + 1; +-} +- +-static u32 get_comment_field_size(const u8 *start) +-{ +- return strlen(start) + 1; +-} +- +-static u32 __get_gzip_head_size(const u8 *src) +-{ +- u8 head_flg = *(src + GZIP_HEAD_FLG_SHIFT); +- u32 size = GZIP_HEAD_FEXTRA_SHIFT; +- +- if (head_flg & GZIP_HEAD_FEXTRA_BIT) +- size += get_extra_field_size(src + size); +- if (head_flg & GZIP_HEAD_FNAME_BIT) +- size += get_name_field_size(src + size); +- if (head_flg & GZIP_HEAD_FCOMMENT_BIT) +- size += get_comment_field_size(src + size); +- if (head_flg & GZIP_HEAD_FHCRC_BIT) +- size += GZIP_HEAD_FHCRC_SIZE; +- +- return size; +-} +- +-static u32 __maybe_unused get_gzip_head_size(struct scatterlist *sgl) +-{ +- char buf[HZIP_GZIP_HEAD_BUF]; +- +- sg_copy_to_buffer(sgl, sg_nents(sgl), buf, sizeof(buf)); +- +- return __get_gzip_head_size(buf); +-} +- +-static int add_comp_head(struct scatterlist *dst, u8 req_type) +-{ +- int head_size = TO_HEAD_SIZE(req_type); +- const u8 *head = TO_HEAD(req_type); +- int ret; +- +- ret = sg_copy_from_buffer(dst, sg_nents(dst), head, head_size); +- if (unlikely(ret != head_size)) { +- pr_err("the head size of buffer is wrong (%d)!\n", ret); +- return -ENOMEM; +- } +- +- return head_size; +-} +- +-static int get_comp_head_size(struct acomp_req *acomp_req, u8 req_type) +-{ +- if (unlikely(!acomp_req->src || !acomp_req->slen)) +- return -EINVAL; +- +- if (unlikely(req_type == HZIP_ALG_TYPE_GZIP && +- acomp_req->slen < GZIP_HEAD_FEXTRA_SHIFT)) +- return -EINVAL; +- +- switch (req_type) { +- case HZIP_ALG_TYPE_ZLIB: +- return TO_HEAD_SIZE(HZIP_ALG_TYPE_ZLIB); +- case HZIP_ALG_TYPE_GZIP: +- return TO_HEAD_SIZE(HZIP_ALG_TYPE_GZIP); +- default: +- pr_err("request type does not support!\n"); +- return -EINVAL; +- } +-} +- +-static struct hisi_zip_req *hisi_zip_create_req(struct acomp_req *req, +- struct hisi_zip_qp_ctx *qp_ctx, +- size_t head_size, bool is_comp) ++static struct hisi_zip_req *hisi_zip_create_req(struct hisi_zip_qp_ctx *qp_ctx, ++ struct acomp_req *req) + { + struct hisi_zip_req_q *req_q = &qp_ctx->req_q; + struct hisi_zip_req *q = req_q->q; +@@ -242,14 +129,6 @@ static struct hisi_zip_req *hisi_zip_create_req(struct acomp_req *req, + req_cache->req_id = req_id; + req_cache->req = req; + +- if (is_comp) { +- req_cache->sskip = 0; +- req_cache->dskip = head_size; +- } else { +- req_cache->sskip = head_size; +- req_cache->dskip = 0; +- } +- + return req_cache; + } + +@@ -275,10 +154,8 @@ static void hisi_zip_fill_buf_size(struct hisi_zip_sqe *sqe, struct hisi_zip_req + { + struct acomp_req *a_req = req->req; + +- sqe->input_data_length = a_req->slen - req->sskip; +- sqe->dest_avail_out = a_req->dlen - req->dskip; +- sqe->dw7 = FIELD_PREP(HZIP_IN_SGE_DATA_OFFSET_M, req->sskip); +- sqe->dw8 = FIELD_PREP(HZIP_OUT_SGE_DATA_OFFSET_M, req->dskip); ++ sqe->input_data_length = a_req->slen; ++ sqe->dest_avail_out = a_req->dlen; + } + + static void hisi_zip_fill_buf_type(struct hisi_zip_sqe *sqe, u8 buf_type) +@@ -299,12 +176,7 @@ static void hisi_zip_fill_req_type(struct hisi_zip_sqe *sqe, u8 req_type) + sqe->dw9 = val; + } + +-static void hisi_zip_fill_tag_v1(struct hisi_zip_sqe *sqe, struct hisi_zip_req *req) +-{ +- sqe->dw13 = req->req_id; +-} +- +-static void hisi_zip_fill_tag_v2(struct hisi_zip_sqe *sqe, struct hisi_zip_req *req) ++static void hisi_zip_fill_tag(struct hisi_zip_sqe *sqe, struct hisi_zip_req *req) + { + sqe->dw26 = req->req_id; + } +@@ -333,8 +205,8 @@ static void hisi_zip_fill_sqe(struct hisi_zip_ctx *ctx, struct hisi_zip_sqe *sqe + ops->fill_sqe_type(sqe, ops->sqe_type); + } + +-static int hisi_zip_do_work(struct hisi_zip_req *req, +- struct hisi_zip_qp_ctx *qp_ctx) ++static int hisi_zip_do_work(struct hisi_zip_qp_ctx *qp_ctx, ++ struct hisi_zip_req *req) + { + struct hisi_acc_sgl_pool *pool = qp_ctx->sgl_pool; + struct hisi_zip_dfx *dfx = &qp_ctx->zip_dev->dfx; +@@ -386,12 +258,7 @@ static int hisi_zip_do_work(struct hisi_zip_req *req, + return ret; + } + +-static u32 hisi_zip_get_tag_v1(struct hisi_zip_sqe *sqe) +-{ +- return sqe->dw13; +-} +- +-static u32 hisi_zip_get_tag_v2(struct hisi_zip_sqe *sqe) ++static u32 hisi_zip_get_tag(struct hisi_zip_sqe *sqe) + { + return sqe->dw26; + } +@@ -417,8 +284,8 @@ static void hisi_zip_acomp_cb(struct hisi_qp *qp, void *data) + u32 tag = ops->get_tag(sqe); + struct hisi_zip_req *req = req_q->q + tag; + struct acomp_req *acomp_req = req->req; +- u32 status, dlen, head_size; + int err = 0; ++ u32 status; + + atomic64_inc(&dfx->recv_cnt); + status = ops->get_status(sqe); +@@ -430,13 +297,10 @@ static void hisi_zip_acomp_cb(struct hisi_qp *qp, void *data) + err = -EIO; + } + +- dlen = ops->get_dstlen(sqe); +- + hisi_acc_sg_buf_unmap(dev, acomp_req->src, req->hw_src); + hisi_acc_sg_buf_unmap(dev, acomp_req->dst, req->hw_dst); + +- head_size = (qp->alg_type == 0) ? TO_HEAD_SIZE(qp->req_type) : 0; +- acomp_req->dlen = dlen + head_size; ++ acomp_req->dlen = ops->get_dstlen(sqe); + + if (acomp_req->base.complete) + acomp_request_complete(acomp_req, err); +@@ -450,24 +314,13 @@ static int hisi_zip_acompress(struct acomp_req *acomp_req) + struct hisi_zip_qp_ctx *qp_ctx = &ctx->qp_ctx[HZIP_QPC_COMP]; + struct device *dev = &qp_ctx->qp->qm->pdev->dev; + struct hisi_zip_req *req; +- int head_size = 0; + int ret; + +- /* let's output compression head now */ +- if (qp_ctx->qp->req_type != HZIP_ALG_TYPE_DEFLATE) { +- head_size = add_comp_head(acomp_req->dst, qp_ctx->qp->req_type); +- if (unlikely(head_size < 0)) { +- dev_err_ratelimited(dev, "failed to add comp head (%d)!\n", +- head_size); +- return head_size; +- } +- } +- +- req = hisi_zip_create_req(acomp_req, qp_ctx, head_size, true); ++ req = hisi_zip_create_req(qp_ctx, acomp_req); + if (IS_ERR(req)) + return PTR_ERR(req); + +- ret = hisi_zip_do_work(req, qp_ctx); ++ ret = hisi_zip_do_work(qp_ctx, req); + if (unlikely(ret != -EINPROGRESS)) { + dev_info_ratelimited(dev, "failed to do compress (%d)!\n", ret); + hisi_zip_remove_req(qp_ctx, req); +@@ -482,22 +335,13 @@ static int hisi_zip_adecompress(struct acomp_req *acomp_req) + struct hisi_zip_qp_ctx *qp_ctx = &ctx->qp_ctx[HZIP_QPC_DECOMP]; + struct device *dev = &qp_ctx->qp->qm->pdev->dev; + struct hisi_zip_req *req; +- int head_size = 0, ret; +- +- if (qp_ctx->qp->req_type != HZIP_ALG_TYPE_DEFLATE) { +- head_size = get_comp_head_size(acomp_req, qp_ctx->qp->req_type); +- if (unlikely(head_size < 0)) { +- dev_err_ratelimited(dev, "failed to get comp head size (%d)!\n", +- head_size); +- return head_size; +- } +- } ++ int ret; + +- req = hisi_zip_create_req(acomp_req, qp_ctx, head_size, false); ++ req = hisi_zip_create_req(qp_ctx, acomp_req); + if (IS_ERR(req)) + return PTR_ERR(req); + +- ret = hisi_zip_do_work(req, qp_ctx); ++ ret = hisi_zip_do_work(qp_ctx, req); + if (unlikely(ret != -EINPROGRESS)) { + dev_info_ratelimited(dev, "failed to do decompress (%d)!\n", + ret); +@@ -534,28 +378,15 @@ static void hisi_zip_release_qp(struct hisi_zip_qp_ctx *qp_ctx) + hisi_qm_free_qps(&qp_ctx->qp, 1); + } + +-static const struct hisi_zip_sqe_ops hisi_zip_ops_v1 = { +- .sqe_type = 0, +- .fill_addr = hisi_zip_fill_addr, +- .fill_buf_size = hisi_zip_fill_buf_size, +- .fill_buf_type = hisi_zip_fill_buf_type, +- .fill_req_type = hisi_zip_fill_req_type, +- .fill_tag = hisi_zip_fill_tag_v1, +- .fill_sqe_type = hisi_zip_fill_sqe_type, +- .get_tag = hisi_zip_get_tag_v1, +- .get_status = hisi_zip_get_status, +- .get_dstlen = hisi_zip_get_dstlen, +-}; +- +-static const struct hisi_zip_sqe_ops hisi_zip_ops_v2 = { ++static const struct hisi_zip_sqe_ops hisi_zip_ops = { + .sqe_type = 0x3, + .fill_addr = hisi_zip_fill_addr, + .fill_buf_size = hisi_zip_fill_buf_size, + .fill_buf_type = hisi_zip_fill_buf_type, + .fill_req_type = hisi_zip_fill_req_type, +- .fill_tag = hisi_zip_fill_tag_v2, ++ .fill_tag = hisi_zip_fill_tag, + .fill_sqe_type = hisi_zip_fill_sqe_type, +- .get_tag = hisi_zip_get_tag_v2, ++ .get_tag = hisi_zip_get_tag, + .get_status = hisi_zip_get_status, + .get_dstlen = hisi_zip_get_dstlen, + }; +@@ -591,10 +422,7 @@ static int hisi_zip_ctx_init(struct hisi_zip_ctx *hisi_zip_ctx, u8 req_type, int + qp_ctx->zip_dev = hisi_zip; + } + +- if (hisi_zip->qm.ver < QM_HW_V3) +- hisi_zip_ctx->ops = &hisi_zip_ops_v1; +- else +- hisi_zip_ctx->ops = &hisi_zip_ops_v2; ++ hisi_zip_ctx->ops = &hisi_zip_ops; + + return 0; + } +@@ -788,106 +616,12 @@ static void hisi_zip_unregister_deflate(struct hisi_qm *qm) + crypto_unregister_acomp(&hisi_zip_acomp_deflate); + } + +-static struct acomp_alg hisi_zip_acomp_zlib = { +- .init = hisi_zip_acomp_init, +- .exit = hisi_zip_acomp_exit, +- .compress = hisi_zip_acompress, +- .decompress = hisi_zip_adecompress, +- .base = { +- .cra_name = "zlib-deflate", +- .cra_driver_name = "hisi-zlib-acomp", +- .cra_module = THIS_MODULE, +- .cra_priority = HZIP_ALG_PRIORITY, +- .cra_ctxsize = sizeof(struct hisi_zip_ctx), +- } +-}; +- +-static int hisi_zip_register_zlib(struct hisi_qm *qm) +-{ +- int ret; +- +- if (!hisi_zip_alg_support(qm, HZIP_ALG_ZLIB)) +- return 0; +- +- ret = crypto_register_acomp(&hisi_zip_acomp_zlib); +- if (ret) +- dev_err(&qm->pdev->dev, "failed to register to zlib (%d)!\n", ret); +- +- return ret; +-} +- +-static void hisi_zip_unregister_zlib(struct hisi_qm *qm) +-{ +- if (!hisi_zip_alg_support(qm, HZIP_ALG_ZLIB)) +- return; +- +- crypto_unregister_acomp(&hisi_zip_acomp_zlib); +-} +- +-static struct acomp_alg hisi_zip_acomp_gzip = { +- .init = hisi_zip_acomp_init, +- .exit = hisi_zip_acomp_exit, +- .compress = hisi_zip_acompress, +- .decompress = hisi_zip_adecompress, +- .base = { +- .cra_name = "gzip", +- .cra_driver_name = "hisi-gzip-acomp", +- .cra_module = THIS_MODULE, +- .cra_priority = HZIP_ALG_PRIORITY, +- .cra_ctxsize = sizeof(struct hisi_zip_ctx), +- } +-}; +- +-static int hisi_zip_register_gzip(struct hisi_qm *qm) +-{ +- int ret; +- +- if (!hisi_zip_alg_support(qm, HZIP_ALG_GZIP)) +- return 0; +- +- ret = crypto_register_acomp(&hisi_zip_acomp_gzip); +- if (ret) +- dev_err(&qm->pdev->dev, "failed to register to gzip (%d)!\n", ret); +- +- return ret; +-} +- +-static void hisi_zip_unregister_gzip(struct hisi_qm *qm) +-{ +- if (!hisi_zip_alg_support(qm, HZIP_ALG_GZIP)) +- return; +- +- crypto_unregister_acomp(&hisi_zip_acomp_gzip); +-} +- + int hisi_zip_register_to_crypto(struct hisi_qm *qm) + { +- int ret = 0; +- +- ret = hisi_zip_register_deflate(qm); +- if (ret) +- return ret; +- +- ret = hisi_zip_register_zlib(qm); +- if (ret) +- goto err_unreg_deflate; +- +- ret = hisi_zip_register_gzip(qm); +- if (ret) +- goto err_unreg_zlib; +- +- return 0; +- +-err_unreg_zlib: +- hisi_zip_unregister_zlib(qm); +-err_unreg_deflate: +- hisi_zip_unregister_deflate(qm); +- return ret; ++ return hisi_zip_register_deflate(qm); + } + + void hisi_zip_unregister_from_crypto(struct hisi_qm *qm) + { + hisi_zip_unregister_deflate(qm); +- hisi_zip_unregister_zlib(qm); +- hisi_zip_unregister_gzip(qm); + } +diff --git a/drivers/crypto/hisilicon/zip/zip_main.c b/drivers/crypto/hisilicon/zip/zip_main.c +index 26a0581e0d393..91212d9584bf5 100644 +--- a/drivers/crypto/hisilicon/zip/zip_main.c ++++ b/drivers/crypto/hisilicon/zip/zip_main.c +@@ -238,7 +238,7 @@ static struct hisi_qm_cap_info zip_basic_cap_info[] = { + {ZIP_CLUSTER_DECOMP_NUM_CAP, 0x313C, 0, GENMASK(7, 0), 0x6, 0x6, 0x3}, + {ZIP_DECOMP_ENABLE_BITMAP, 0x3140, 16, GENMASK(15, 0), 0xFC, 0xFC, 0x1C}, + {ZIP_COMP_ENABLE_BITMAP, 0x3140, 0, GENMASK(15, 0), 0x3, 0x3, 0x3}, +- {ZIP_DRV_ALG_BITMAP, 0x3144, 0, GENMASK(31, 0), 0xF, 0xF, 0x3F}, ++ {ZIP_DRV_ALG_BITMAP, 0x3144, 0, GENMASK(31, 0), 0x0, 0x0, 0x30}, + {ZIP_DEV_ALG_BITMAP, 0x3148, 0, GENMASK(31, 0), 0xF, 0xF, 0x3F}, + {ZIP_CORE1_ALG_BITMAP, 0x314C, 0, GENMASK(31, 0), 0x5, 0x5, 0xD5}, + {ZIP_CORE2_ALG_BITMAP, 0x3150, 0, GENMASK(31, 0), 0x5, 0x5, 0xD5}, +-- +2.51.0 + diff --git a/queue-6.6/crypto-hisilicon-zip-support-deflate-algorithm.patch b/queue-6.6/crypto-hisilicon-zip-support-deflate-algorithm.patch new file mode 100644 index 0000000000..56d7d8ee04 --- /dev/null +++ b/queue-6.6/crypto-hisilicon-zip-support-deflate-algorithm.patch @@ -0,0 +1,192 @@ +From f1f25cc477d70c80ce8daf6faf169b851296a5fb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 14 Sep 2023 17:09:07 +0800 +Subject: crypto: hisilicon/zip - support deflate algorithm + +From: Yang Shen + +[ Upstream commit aa3f80500382ca864b7cfcff4e5ca2fa6a0e977d ] + +Add the deflate algorithm support for hisilicon zip hardware. + +Signed-off-by: Yang Shen +Signed-off-by: Herbert Xu +Stable-dep-of: 19c2475ce198 ("crypto: hisilicon/zip - adjust the way to obtain the req in the callback function") +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/zip/zip_crypto.c | 86 ++++++++++++++++++----- + drivers/crypto/hisilicon/zip/zip_main.c | 4 +- + 2 files changed, 72 insertions(+), 18 deletions(-) + +diff --git a/drivers/crypto/hisilicon/zip/zip_crypto.c b/drivers/crypto/hisilicon/zip/zip_crypto.c +index 6608971d10cdc..09f60f7867795 100644 +--- a/drivers/crypto/hisilicon/zip/zip_crypto.c ++++ b/drivers/crypto/hisilicon/zip/zip_crypto.c +@@ -16,6 +16,7 @@ + #define HZIP_OUT_SGE_DATA_OFFSET_M GENMASK(23, 0) + /* hisi_zip_sqe dw9 */ + #define HZIP_REQ_TYPE_M GENMASK(7, 0) ++#define HZIP_ALG_TYPE_DEFLATE 0x01 + #define HZIP_ALG_TYPE_ZLIB 0x02 + #define HZIP_ALG_TYPE_GZIP 0x03 + #define HZIP_BUF_TYPE_M GENMASK(11, 8) +@@ -41,6 +42,7 @@ + + #define HZIP_ALG_ZLIB GENMASK(1, 0) + #define HZIP_ALG_GZIP GENMASK(3, 2) ++#define HZIP_ALG_DEFLATE GENMASK(5, 4) + + static const u8 zlib_head[HZIP_ZLIB_HEAD_SIZE] = {0x78, 0x9c}; + static const u8 gzip_head[HZIP_GZIP_HEAD_SIZE] = { +@@ -59,8 +61,9 @@ enum { + }; + + #define COMP_NAME_TO_TYPE(alg_name) \ ++ (!strcmp((alg_name), "deflate") ? HZIP_ALG_TYPE_DEFLATE : \ + (!strcmp((alg_name), "zlib-deflate") ? HZIP_ALG_TYPE_ZLIB : \ +- !strcmp((alg_name), "gzip") ? HZIP_ALG_TYPE_GZIP : 0) \ ++ !strcmp((alg_name), "gzip") ? HZIP_ALG_TYPE_GZIP : 0)) \ + + #define TO_HEAD_SIZE(req_type) \ + (((req_type) == HZIP_ALG_TYPE_ZLIB) ? sizeof(zlib_head) : \ +@@ -447,15 +450,17 @@ static int hisi_zip_acompress(struct acomp_req *acomp_req) + struct hisi_zip_qp_ctx *qp_ctx = &ctx->qp_ctx[HZIP_QPC_COMP]; + struct device *dev = &qp_ctx->qp->qm->pdev->dev; + struct hisi_zip_req *req; +- int head_size; ++ int head_size = 0; + int ret; + + /* let's output compression head now */ +- head_size = add_comp_head(acomp_req->dst, qp_ctx->qp->req_type); +- if (unlikely(head_size < 0)) { +- dev_err_ratelimited(dev, "failed to add comp head (%d)!\n", +- head_size); +- return head_size; ++ if (qp_ctx->qp->req_type != HZIP_ALG_TYPE_DEFLATE) { ++ head_size = add_comp_head(acomp_req->dst, qp_ctx->qp->req_type); ++ if (unlikely(head_size < 0)) { ++ dev_err_ratelimited(dev, "failed to add comp head (%d)!\n", ++ head_size); ++ return head_size; ++ } + } + + req = hisi_zip_create_req(acomp_req, qp_ctx, head_size, true); +@@ -477,13 +482,15 @@ static int hisi_zip_adecompress(struct acomp_req *acomp_req) + struct hisi_zip_qp_ctx *qp_ctx = &ctx->qp_ctx[HZIP_QPC_DECOMP]; + struct device *dev = &qp_ctx->qp->qm->pdev->dev; + struct hisi_zip_req *req; +- int head_size, ret; +- +- head_size = get_comp_head_size(acomp_req, qp_ctx->qp->req_type); +- if (unlikely(head_size < 0)) { +- dev_err_ratelimited(dev, "failed to get comp head size (%d)!\n", +- head_size); +- return head_size; ++ int head_size = 0, ret; ++ ++ if (qp_ctx->qp->req_type != HZIP_ALG_TYPE_DEFLATE) { ++ head_size = get_comp_head_size(acomp_req, qp_ctx->qp->req_type); ++ if (unlikely(head_size < 0)) { ++ dev_err_ratelimited(dev, "failed to get comp head size (%d)!\n", ++ head_size); ++ return head_size; ++ } + } + + req = hisi_zip_create_req(acomp_req, qp_ctx, head_size, false); +@@ -745,6 +752,42 @@ static void hisi_zip_acomp_exit(struct crypto_acomp *tfm) + hisi_zip_ctx_exit(ctx); + } + ++static struct acomp_alg hisi_zip_acomp_deflate = { ++ .init = hisi_zip_acomp_init, ++ .exit = hisi_zip_acomp_exit, ++ .compress = hisi_zip_acompress, ++ .decompress = hisi_zip_adecompress, ++ .base = { ++ .cra_name = "deflate", ++ .cra_driver_name = "hisi-deflate-acomp", ++ .cra_module = THIS_MODULE, ++ .cra_priority = HZIP_ALG_PRIORITY, ++ .cra_ctxsize = sizeof(struct hisi_zip_ctx), ++ } ++}; ++ ++static int hisi_zip_register_deflate(struct hisi_qm *qm) ++{ ++ int ret; ++ ++ if (!hisi_zip_alg_support(qm, HZIP_ALG_DEFLATE)) ++ return 0; ++ ++ ret = crypto_register_acomp(&hisi_zip_acomp_deflate); ++ if (ret) ++ dev_err(&qm->pdev->dev, "failed to register to deflate (%d)!\n", ret); ++ ++ return ret; ++} ++ ++static void hisi_zip_unregister_deflate(struct hisi_qm *qm) ++{ ++ if (!hisi_zip_alg_support(qm, HZIP_ALG_DEFLATE)) ++ return; ++ ++ crypto_unregister_acomp(&hisi_zip_acomp_deflate); ++} ++ + static struct acomp_alg hisi_zip_acomp_zlib = { + .init = hisi_zip_acomp_init, + .exit = hisi_zip_acomp_exit, +@@ -821,19 +864,30 @@ int hisi_zip_register_to_crypto(struct hisi_qm *qm) + { + int ret = 0; + +- ret = hisi_zip_register_zlib(qm); ++ ret = hisi_zip_register_deflate(qm); + if (ret) + return ret; + ++ ret = hisi_zip_register_zlib(qm); ++ if (ret) ++ goto err_unreg_deflate; ++ + ret = hisi_zip_register_gzip(qm); + if (ret) +- hisi_zip_unregister_zlib(qm); ++ goto err_unreg_zlib; ++ ++ return 0; + ++err_unreg_zlib: ++ hisi_zip_unregister_zlib(qm); ++err_unreg_deflate: ++ hisi_zip_unregister_deflate(qm); + return ret; + } + + void hisi_zip_unregister_from_crypto(struct hisi_qm *qm) + { ++ hisi_zip_unregister_deflate(qm); + hisi_zip_unregister_zlib(qm); + hisi_zip_unregister_gzip(qm); + } +diff --git a/drivers/crypto/hisilicon/zip/zip_main.c b/drivers/crypto/hisilicon/zip/zip_main.c +index b70aa6032874e..26a0581e0d393 100644 +--- a/drivers/crypto/hisilicon/zip/zip_main.c ++++ b/drivers/crypto/hisilicon/zip/zip_main.c +@@ -238,8 +238,8 @@ static struct hisi_qm_cap_info zip_basic_cap_info[] = { + {ZIP_CLUSTER_DECOMP_NUM_CAP, 0x313C, 0, GENMASK(7, 0), 0x6, 0x6, 0x3}, + {ZIP_DECOMP_ENABLE_BITMAP, 0x3140, 16, GENMASK(15, 0), 0xFC, 0xFC, 0x1C}, + {ZIP_COMP_ENABLE_BITMAP, 0x3140, 0, GENMASK(15, 0), 0x3, 0x3, 0x3}, +- {ZIP_DRV_ALG_BITMAP, 0x3144, 0, GENMASK(31, 0), 0xF, 0xF, 0xF}, +- {ZIP_DEV_ALG_BITMAP, 0x3148, 0, GENMASK(31, 0), 0xF, 0xF, 0xFF}, ++ {ZIP_DRV_ALG_BITMAP, 0x3144, 0, GENMASK(31, 0), 0xF, 0xF, 0x3F}, ++ {ZIP_DEV_ALG_BITMAP, 0x3148, 0, GENMASK(31, 0), 0xF, 0xF, 0x3F}, + {ZIP_CORE1_ALG_BITMAP, 0x314C, 0, GENMASK(31, 0), 0x5, 0x5, 0xD5}, + {ZIP_CORE2_ALG_BITMAP, 0x3150, 0, GENMASK(31, 0), 0x5, 0x5, 0xD5}, + {ZIP_CORE3_ALG_BITMAP, 0x3154, 0, GENMASK(31, 0), 0xA, 0xA, 0x2A}, +-- +2.51.0 + diff --git a/queue-6.6/crypto-octeontx-fix-dma_free_coherent-size.patch b/queue-6.6/crypto-octeontx-fix-dma_free_coherent-size.patch new file mode 100644 index 0000000000..c97126dd0c --- /dev/null +++ b/queue-6.6/crypto-octeontx-fix-dma_free_coherent-size.patch @@ -0,0 +1,38 @@ +From 32998e3a26b52140dd5398adc9d43ce9f7039a29 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 11:12:57 +0100 +Subject: crypto: octeontx - fix dma_free_coherent() size + +From: Thomas Fourier + +[ Upstream commit 624a6760bf8464965c17c8df10b40b557eaa3002 ] + +The size of the buffer in alloc_command_queues() is +curr->size + OTX_CPT_NEXT_CHUNK_PTR_SIZE, so used that length for +dma_free_coherent(). + +Fixes: 10b4f09491bf ("crypto: marvell - add the Virtual Function driver for CPT") +Signed-off-by: Thomas Fourier +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/marvell/octeontx/otx_cptvf_main.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/crypto/marvell/octeontx/otx_cptvf_main.c b/drivers/crypto/marvell/octeontx/otx_cptvf_main.c +index 88a41d1ca5f64..6c0bfb3ea1c9f 100644 +--- a/drivers/crypto/marvell/octeontx/otx_cptvf_main.c ++++ b/drivers/crypto/marvell/octeontx/otx_cptvf_main.c +@@ -168,7 +168,8 @@ static void free_command_queues(struct otx_cptvf *cptvf, + chunk = list_first_entry(&cqinfo->queue[i].chead, + struct otx_cpt_cmd_chunk, nextchunk); + +- dma_free_coherent(&pdev->dev, chunk->size, ++ dma_free_coherent(&pdev->dev, ++ chunk->size + OTX_CPT_NEXT_CHUNK_PTR_SIZE, + chunk->head, + chunk->dma_addr); + chunk->head = NULL; +-- +2.51.0 + diff --git a/queue-6.6/crypto-qat-fix-warning-on-adf_pfvf_pf_proto.c.patch b/queue-6.6/crypto-qat-fix-warning-on-adf_pfvf_pf_proto.c.patch new file mode 100644 index 0000000000..f4adbba7e1 --- /dev/null +++ b/queue-6.6/crypto-qat-fix-warning-on-adf_pfvf_pf_proto.c.patch @@ -0,0 +1,63 @@ +From dd988bd4376dbc995384428ca71d4f1520d61874 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 20 Nov 2025 16:30:46 +0000 +Subject: crypto: qat - fix warning on adf_pfvf_pf_proto.c +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Giovanni Cabiddu + +[ Upstream commit 994689b8f91b02fdb5f64cba2412cde5ef3084b5 ] + +Building the QAT driver with -Wmaybe-uninitialized triggers warnings in +qat_common/adf_pfvf_pf_proto.c. Specifically, the variables blk_type, +blk_byte, and byte_max may be used uninitialized in handle_blkmsg_req(): + + make M=drivers/crypto/intel/qat W=1 C=2 "KCFLAGS=-Werror" \ + KBUILD_CFLAGS_KERNEL=-Wmaybe-uninitialized \ + CFLAGS_MODULE=-Wmaybe-uninitialized + + ... + warning: ‘byte_max’ may be used uninitialized [-Wmaybe-uninitialized] + warning: ‘blk_type’ may be used uninitialized [-Wmaybe-uninitialized] + warning: ‘blk_byte’ may be used uninitialized [-Wmaybe-uninitialized] + +Although the caller of handle_blkmsg_req() always provides a req.type +that is handled by the switch, the compiler cannot guarantee this. + +Add a default case to the switch statement to handle an invalid req.type. + +Fixes: 673184a2a58f ("crypto: qat - introduce support for PFVF block messages") +Signed-off-by: Giovanni Cabiddu +Reviewed-by: Ahsan Atta +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + .../crypto/intel/qat/qat_common/adf_pfvf_pf_proto.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/crypto/intel/qat/qat_common/adf_pfvf_pf_proto.c b/drivers/crypto/intel/qat/qat_common/adf_pfvf_pf_proto.c +index 388e58bcbcaf2..4a1ea3e720329 100644 +--- a/drivers/crypto/intel/qat/qat_common/adf_pfvf_pf_proto.c ++++ b/drivers/crypto/intel/qat/qat_common/adf_pfvf_pf_proto.c +@@ -148,6 +148,16 @@ static struct pfvf_message handle_blkmsg_req(struct adf_accel_vf_info *vf_info, + blk_byte = FIELD_GET(ADF_VF2PF_SMALL_BLOCK_BYTE_MASK, req.data); + byte_max = ADF_VF2PF_SMALL_BLOCK_BYTE_MAX; + break; ++ default: ++ dev_err(&GET_DEV(vf_info->accel_dev), ++ "Invalid BlockMsg type 0x%.4x received from VF%u\n", ++ req.type, vf_info->vf_nr); ++ resp.type = ADF_PF2VF_MSGTYPE_BLKMSG_RESP; ++ resp.data = FIELD_PREP(ADF_PF2VF_BLKMSG_RESP_TYPE_MASK, ++ ADF_PF2VF_BLKMSG_RESP_TYPE_ERROR) | ++ FIELD_PREP(ADF_PF2VF_BLKMSG_RESP_DATA_MASK, ++ ADF_PF2VF_UNSPECIFIED_ERROR); ++ return resp; + } + + /* Is this a request for CRC or data? */ +-- +2.51.0 + diff --git a/queue-6.6/cxl-fix-premature-commit_end-increment-on-decoder-co.patch b/queue-6.6/cxl-fix-premature-commit_end-increment-on-decoder-co.patch new file mode 100644 index 0000000000..5c25f90597 --- /dev/null +++ b/queue-6.6/cxl-fix-premature-commit_end-increment-on-decoder-co.patch @@ -0,0 +1,62 @@ +From 9309ac53cb57cf9563703f65d4e946b93c42be4e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 14:45:52 +0800 +Subject: cxl: Fix premature commit_end increment on decoder commit failure + +From: Yuxiong Wang + +[ Upstream commit 7b6f9d9b1ea05c9c22570126547c780e8c6c3f62 ] + +In cxl_decoder_commit(), commit_end is incremented before verifying +whether the commit succeeded, and the CXL_DECODER_F_ENABLE bit in +cxld->flags is only set after a successful commit. As a result, if the +commit fails, commit_end has been incremented and cxld->reset() has no +effect since the flag is not set, so commit_end remains incorrectly +incremented. The inconsistency between commit_end and CXL_DECODER_F_ENABLE +causes failure during subsequent either commit or reset operations. + +Fix this by incrementing commit_end only after confirming the commit +succeeded. Also, remove the ineffective cxld->reset() call. According to +CXL Spec r4.0 8.2.4.20.12 Committing Decoder Programming, since +cxld_await_commit() has cleared the decoder commit bit on failure, no +additional reset is required. + +[dj: Fixed commit log 80 char wrapping. ] +[dj: Fix "Fixes" tag to correct hash length. ] +[dj: Change spec to r4.0. ] + +Fixes: 176baefb2eb5 ("cxl/hdm: Commit decoder state to hardware") +Signed-off-by: Yuxiong Wang +Acked-by: Huang Ying +Reviewed-by: Dave Jiang +Reviewed-by: Alison Schofield +Link: https://patch.msgid.link/20260129064552.31180-1-yuxiong.wang@linux.alibaba.com +Signed-off-by: Dave Jiang +Signed-off-by: Sasha Levin +--- + drivers/cxl/core/hdm.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c +index 36b20b844b109..f9738c863df0e 100644 +--- a/drivers/cxl/core/hdm.c ++++ b/drivers/cxl/core/hdm.c +@@ -710,14 +710,13 @@ static int cxl_decoder_commit(struct cxl_decoder *cxld) + writel(ctrl, hdm + CXL_HDM_DECODER0_CTRL_OFFSET(id)); + up_read(&cxl_dpa_rwsem); + +- port->commit_end++; + rc = cxld_await_commit(hdm, cxld->id); + if (rc) { + dev_dbg(&port->dev, "%s: error %d committing decoder\n", + dev_name(&cxld->dev), rc); +- cxld->reset(cxld); + return rc; + } ++ port->commit_end++; + cxld->flags |= CXL_DECODER_F_ENABLE; + + return 0; +-- +2.51.0 + diff --git a/queue-6.6/dm-use-bio_clone_blkg_association.patch b/queue-6.6/dm-use-bio_clone_blkg_association.patch new file mode 100644 index 0000000000..dcbbf94597 --- /dev/null +++ b/queue-6.6/dm-use-bio_clone_blkg_association.patch @@ -0,0 +1,44 @@ +From c254ef0eed76fdc7772deaefe3b460b2d0d34f4a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 15:36:22 +0100 +Subject: dm: use bio_clone_blkg_association + +From: Mikulas Patocka + +[ Upstream commit 2df8b310bcfe76827fd71092f58a2493ee6590b0 ] + +The origin bio carries blk-cgroup information which could be set from +foreground(task_css(css) - wbc->wb->blkcg_css), so the blkcg won't +control buffer io since commit ca522482e3eaf ("dm: pass NULL bdev to +bio_alloc_clone"). The synchronous io is still under control by blkcg, +because 'bio->bi_blkg' is set by io submitting task which has been added +into 'cgroup.procs'. + +Fix it by using bio_clone_blkg_association when submitting a cloned bio. + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=220985 +Fixes: ca522482e3eaf ("dm: pass NULL bdev to bio_alloc_clone") +Reported-by: Zhihao Cheng +Signed-off-by: Mikulas Patocka +Tested-by: Zhihao Cheng +Signed-off-by: Sasha Levin +--- + drivers/md/dm.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/md/dm.c b/drivers/md/dm.c +index f0c4c3553c016..1d03536fded00 100644 +--- a/drivers/md/dm.c ++++ b/drivers/md/dm.c +@@ -1363,6 +1363,8 @@ void dm_submit_bio_remap(struct bio *clone, struct bio *tgt_clone) + if (!tgt_clone) + tgt_clone = clone; + ++ bio_clone_blkg_association(tgt_clone, io->orig_bio); ++ + /* + * Account io->origin_bio to DM dev on behalf of target + * that took ownership of IO with DM_MAPIO_SUBMITTED. +-- +2.51.0 + diff --git a/queue-6.6/dma-dma-axi-dmac-fix-sw-cyclic-transfers.patch b/queue-6.6/dma-dma-axi-dmac-fix-sw-cyclic-transfers.patch new file mode 100644 index 0000000000..49f7ee0a06 --- /dev/null +++ b/queue-6.6/dma-dma-axi-dmac-fix-sw-cyclic-transfers.patch @@ -0,0 +1,57 @@ +From 0d6c80c9c62f7779823440818252997db1a93c96 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Nov 2025 16:22:25 +0000 +Subject: dma: dma-axi-dmac: fix SW cyclic transfers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Nuno Sá + +[ Upstream commit 9bd257181fd5c996d922e9991500ad27987cfbf4 ] + +If 'hw_cyclic' is false we should still be able to do cyclic transfers in +"software". That was not working for the case where 'desc->num_sgs' is 1 +because 'chan->next_desc' is never set with the current desc which means +that the cyclic transfer only runs once and in the next SOT interrupt we +do nothing since vchan_next_desc() will return NULL. + +Fix it by setting 'chan->next_desc' as soon as we get a new desc via +vchan_next_desc(). + +Fixes: 0e3b67b348b8 ("dmaengine: Add support for the Analog Devices AXI-DMAC DMA controller") +Signed-off-by: Nuno Sá +base-commit: 398035178503bf662281bbffb4bebce1460a4bc5 +change-id: 20251104-axi-dmac-fixes-and-improvs-e3ad512a329c +Acked-by: Michael Hennerich +Link: https://patch.msgid.link/20251104-axi-dmac-fixes-and-improvs-v1-1-3e6fd9328f72@analog.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/dma/dma-axi-dmac.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c +index 4f426be286884..93e00130400df 100644 +--- a/drivers/dma/dma-axi-dmac.c ++++ b/drivers/dma/dma-axi-dmac.c +@@ -225,6 +225,7 @@ static void axi_dmac_start_transfer(struct axi_dmac_chan *chan) + return; + list_move_tail(&vdesc->node, &chan->active_descs); + desc = to_axi_dmac_desc(vdesc); ++ chan->next_desc = desc; + } + sg = &desc->sg[desc->num_submitted]; + +@@ -242,8 +243,6 @@ static void axi_dmac_start_transfer(struct axi_dmac_chan *chan) + else + chan->next_desc = NULL; + flags |= AXI_DMAC_FLAG_LAST; +- } else { +- chan->next_desc = desc; + } + + sg->id = axi_dmac_read(dmac, AXI_DMAC_REG_TRANSFER_ID); +-- +2.51.0 + diff --git a/queue-6.6/dmaengine-fsl-edma-don-t-explicitly-disable-clocks-i.patch b/queue-6.6/dmaengine-fsl-edma-don-t-explicitly-disable-clocks-i.patch new file mode 100644 index 0000000000..dfe1ca117b --- /dev/null +++ b/queue-6.6/dmaengine-fsl-edma-don-t-explicitly-disable-clocks-i.patch @@ -0,0 +1,61 @@ +From cc8d211424d43900f58d78acbebc66def6c575b9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Jan 2026 11:46:50 -0800 +Subject: dmaengine: fsl-edma: don't explicitly disable clocks in .remove() + +From: Jared Kangas + +[ Upstream commit 666c53e94c1d0bf0bdf14c49505ece9ddbe725bc ] + +The clocks in fsl_edma_engine::muxclk are allocated and enabled with +devm_clk_get_enabled(), which automatically cleans these resources up, +but these clocks are also manually disabled in fsl_edma_remove(). This +causes warnings on driver removal for each clock: + + edma_module already disabled + WARNING: CPU: 0 PID: 418 at drivers/clk/clk.c:1200 clk_core_disable+0x198/0x1c8 + [...] + Call trace: + clk_core_disable+0x198/0x1c8 (P) + clk_disable+0x34/0x58 + fsl_edma_remove+0x74/0xe8 [fsl_edma] + [...] + ---[ end trace 0000000000000000 ]--- + edma_module already unprepared + WARNING: CPU: 0 PID: 418 at drivers/clk/clk.c:1059 clk_core_unprepare+0x1f8/0x220 + [...] + Call trace: + clk_core_unprepare+0x1f8/0x220 (P) + clk_unprepare+0x34/0x58 + fsl_edma_remove+0x7c/0xe8 [fsl_edma] + [...] + ---[ end trace 0000000000000000 ]--- + +Fix these warnings by removing the unnecessary fsl_disable_clocks() call +in fsl_edma_remove(). + +Fixes: a9903de3aa16 ("dmaengine: fsl-edma: refactor using devm_clk_get_enabled") +Signed-off-by: Jared Kangas +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260113-fsl-edma-clock-removal-v1-1-2025b49e7bcc@redhat.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/dma/fsl-edma-main.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/dma/fsl-edma-main.c b/drivers/dma/fsl-edma-main.c +index 7dedd85d74d9b..34b194759d218 100644 +--- a/drivers/dma/fsl-edma-main.c ++++ b/drivers/dma/fsl-edma-main.c +@@ -678,7 +678,6 @@ static void fsl_edma_remove(struct platform_device *pdev) + of_dma_controller_free(np); + dma_async_device_unregister(&fsl_edma->dma_dev); + fsl_edma_cleanup_vchan(&fsl_edma->dma_dev); +- fsl_disable_clocks(fsl_edma, fsl_edma->drvdata->dmamuxs); + } + + static int fsl_edma_suspend_late(struct device *dev) +-- +2.51.0 + diff --git a/queue-6.6/dmaengine-fsl-edma-main-convert-to-platform-remove-c.patch b/queue-6.6/dmaengine-fsl-edma-main-convert-to-platform-remove-c.patch new file mode 100644 index 0000000000..0a2e8a8bc2 --- /dev/null +++ b/queue-6.6/dmaengine-fsl-edma-main-convert-to-platform-remove-c.patch @@ -0,0 +1,68 @@ +From e28c92a1f8305176eb0b2b4039825592dbe3350d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 Sep 2023 15:31:20 +0200 +Subject: dmaengine: fsl-edma-main: Convert to platform remove callback + returning void +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Uwe Kleine-König + +[ Upstream commit fa13c3ef3f45bca5a1474755dac57bfaf28ef61b ] + +The .remove() callback for a platform driver returns an int which makes +many driver authors wrongly assume it's possible to do error handling by +returning an error code. However the value returned is ignored (apart +from emitting a warning) and this typically results in resource leaks. +To improve here there is a quest to make the remove callback return +void. In the first step of this quest all drivers are converted to +.remove_new() which already returns void. Eventually after all drivers +are converted, .remove_new() is renamed to .remove(). + +Trivially convert this driver from always returning zero in the remove +callback to the void returning variant. + +Signed-off-by: Uwe Kleine-König +Link: https://lore.kernel.org/r/20230919133207.1400430-13-u.kleine-koenig@pengutronix.de +Signed-off-by: Vinod Koul +Stable-dep-of: 666c53e94c1d ("dmaengine: fsl-edma: don't explicitly disable clocks in .remove()") +Signed-off-by: Sasha Levin +--- + drivers/dma/fsl-edma-main.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/dma/fsl-edma-main.c b/drivers/dma/fsl-edma-main.c +index eccbcf67951fb..7dedd85d74d9b 100644 +--- a/drivers/dma/fsl-edma-main.c ++++ b/drivers/dma/fsl-edma-main.c +@@ -669,7 +669,7 @@ static int fsl_edma_probe(struct platform_device *pdev) + return 0; + } + +-static int fsl_edma_remove(struct platform_device *pdev) ++static void fsl_edma_remove(struct platform_device *pdev) + { + struct device_node *np = pdev->dev.of_node; + struct fsl_edma_engine *fsl_edma = platform_get_drvdata(pdev); +@@ -679,8 +679,6 @@ static int fsl_edma_remove(struct platform_device *pdev) + dma_async_device_unregister(&fsl_edma->dma_dev); + fsl_edma_cleanup_vchan(&fsl_edma->dma_dev); + fsl_disable_clocks(fsl_edma, fsl_edma->drvdata->dmamuxs); +- +- return 0; + } + + static int fsl_edma_suspend_late(struct device *dev) +@@ -749,7 +747,7 @@ static struct platform_driver fsl_edma_driver = { + .pm = &fsl_edma_pm_ops, + }, + .probe = fsl_edma_probe, +- .remove = fsl_edma_remove, ++ .remove_new = fsl_edma_remove, + }; + + static int __init fsl_edma_init(void) +-- +2.51.0 + diff --git a/queue-6.6/dmaengine-mediatek-uart-apdma-fix-above-4g-addressin.patch b/queue-6.6/dmaengine-mediatek-uart-apdma-fix-above-4g-addressin.patch new file mode 100644 index 0000000000..b53ecd3309 --- /dev/null +++ b/queue-6.6/dmaengine-mediatek-uart-apdma-fix-above-4g-addressin.patch @@ -0,0 +1,83 @@ +From 3b4c7ff67c3ba852ebed43e93df26019b678e064 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 13 Nov 2025 13:22:26 +0100 +Subject: dmaengine: mediatek: uart-apdma: Fix above 4G addressing TX/RX + +From: AngeloGioacchino Del Regno + +[ Upstream commit 58ab9d7b6651d21e1cff1777529f2d3dd0b4e851 ] + +The VFF_4G_SUPPORT register is named differently in datasheets, +and its name is "VFF_ADDR2"; was this named correctly from the +beginning it would've been clearer that there was a mistake in +the programming sequence. + +This register is supposed to hold the high bits to support the +DMA addressing above 4G (so, more than 32 bits) and not a bit +to "enable" the support for VFF 4G. + +Fix the name of this register, and also fix its usage by writing +the upper 32 bits of the dma_addr_t on it when the SoC supports +such feature. + +Fixes: 9135408c3ace ("dmaengine: mediatek: Add MediaTek UART APDMA support") +Signed-off-by: AngeloGioacchino Del Regno +Link: https://patch.msgid.link/20251113122229.23998-6-angelogioacchino.delregno@collabora.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/dma/mediatek/mtk-uart-apdma.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/dma/mediatek/mtk-uart-apdma.c b/drivers/dma/mediatek/mtk-uart-apdma.c +index 06d12ac39144f..aa42a09fde1a6 100644 +--- a/drivers/dma/mediatek/mtk-uart-apdma.c ++++ b/drivers/dma/mediatek/mtk-uart-apdma.c +@@ -41,7 +41,7 @@ + #define VFF_STOP_CLR_B 0 + #define VFF_EN_CLR_B 0 + #define VFF_INT_EN_CLR_B 0 +-#define VFF_4G_SUPPORT_CLR_B 0 ++#define VFF_ADDR2_CLR_B 0 + + /* + * interrupt trigger level for tx +@@ -72,7 +72,7 @@ + /* TX: the buffer size SW can write. RX: the buffer size HW can write. */ + #define VFF_LEFT_SIZE 0x40 + #define VFF_DEBUG_STATUS 0x50 +-#define VFF_4G_SUPPORT 0x54 ++#define VFF_ADDR2 0x54 + + struct mtk_uart_apdmadev { + struct dma_device ddev; +@@ -149,7 +149,7 @@ static void mtk_uart_apdma_start_tx(struct mtk_chan *c) + mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_TX_INT_CLR_B); + + if (mtkd->support_33bits) +- mtk_uart_apdma_write(c, VFF_4G_SUPPORT, VFF_4G_EN_B); ++ mtk_uart_apdma_write(c, VFF_ADDR2, upper_32_bits(d->addr)); + } + + mtk_uart_apdma_write(c, VFF_EN, VFF_EN_B); +@@ -192,7 +192,7 @@ static void mtk_uart_apdma_start_rx(struct mtk_chan *c) + mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_RX_INT_CLR_B); + + if (mtkd->support_33bits) +- mtk_uart_apdma_write(c, VFF_4G_SUPPORT, VFF_4G_EN_B); ++ mtk_uart_apdma_write(c, VFF_ADDR2, upper_32_bits(d->addr)); + } + + mtk_uart_apdma_write(c, VFF_INT_EN, VFF_RX_INT_EN_B); +@@ -298,7 +298,7 @@ static int mtk_uart_apdma_alloc_chan_resources(struct dma_chan *chan) + } + + if (mtkd->support_33bits) +- mtk_uart_apdma_write(c, VFF_4G_SUPPORT, VFF_4G_SUPPORT_CLR_B); ++ mtk_uart_apdma_write(c, VFF_ADDR2, VFF_ADDR2_CLR_B); + + err_pm: + pm_runtime_put_noidle(mtkd->ddev.dev); +-- +2.51.0 + diff --git a/queue-6.6/docs-fix-warning-document-not-included-in-any-toctre.patch b/queue-6.6/docs-fix-warning-document-not-included-in-any-toctre.patch new file mode 100644 index 0000000000..36ca434f99 --- /dev/null +++ b/queue-6.6/docs-fix-warning-document-not-included-in-any-toctre.patch @@ -0,0 +1,36 @@ +From 68617261a33483045c873291e322361d4d452ec3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 3 Oct 2024 01:28:17 +0530 +Subject: docs: fix WARNING document not included in any toctree + +From: SurajSonawane2415 + +[ Upstream commit 998bece1d22bf2cbc819cb3a492148932d4e12a8 ] + +Add debugging.rst to the relevant toctree to fix warning +about missing documentation inclusion in toctree. + +Signed-off-by: SurajSonawane2415 +Signed-off-by: Jonathan Corbet +Link: https://lore.kernel.org/r/20241002195817.22972-1-surajsonawane0215@gmail.com +Stable-dep-of: 8236fc613d44 ("Documentation: tracing: Add PCI tracepoint documentation") +Signed-off-by: Sasha Levin +--- + Documentation/trace/index.rst | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/Documentation/trace/index.rst b/Documentation/trace/index.rst +index 0b300901fd750..2c991dc96ace6 100644 +--- a/Documentation/trace/index.rst ++++ b/Documentation/trace/index.rst +@@ -24,6 +24,7 @@ Linux Tracing Technologies + histogram + histogram-design + boottime-trace ++ debugging + hwlat_detector + osnoise-tracer + timerlat-tracer +-- +2.51.0 + diff --git a/queue-6.6/documentation-pci-endpoint-fix-ntb-vntb-copy-paste-e.patch b/queue-6.6/documentation-pci-endpoint-fix-ntb-vntb-copy-paste-e.patch new file mode 100644 index 0000000000..f80bbdb32b --- /dev/null +++ b/queue-6.6/documentation-pci-endpoint-fix-ntb-vntb-copy-paste-e.patch @@ -0,0 +1,82 @@ +From 3fc53e7f5c01cbcf7b65c2b85ddcadf66fdc1443 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 3 Nov 2025 09:28:30 +0200 +Subject: Documentation: PCI: endpoint: Fix ntb/vntb copy & paste errors + +From: Baruch Siach + +[ Upstream commit ad0c6da5be901f5c181490f683d22b416059bccb ] + +Fix copy & paste errors by changing the references from 'ntb' to 'vntb'. + +Fixes: 4ac8c8e52cd9 ("Documentation: PCI: Add specification for the PCI vNTB function device") +Signed-off-by: Baruch Siach +[mani: squashed the patches and fixed more errors] +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Reviewed-by: Frank Li +Link: https://patch.msgid.link/b51c2a69ffdbfa2c359f5cf33f3ad2acc3db87e4.1762154911.git.baruch@tkos.co.il +Signed-off-by: Sasha Levin +--- + Documentation/PCI/endpoint/pci-vntb-howto.rst | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/Documentation/PCI/endpoint/pci-vntb-howto.rst b/Documentation/PCI/endpoint/pci-vntb-howto.rst +index 70d3bc90893f3..949c0d35694c2 100644 +--- a/Documentation/PCI/endpoint/pci-vntb-howto.rst ++++ b/Documentation/PCI/endpoint/pci-vntb-howto.rst +@@ -52,14 +52,14 @@ pci-epf-vntb device, the following commands can be used:: + # cd /sys/kernel/config/pci_ep/ + # mkdir functions/pci_epf_vntb/func1 + +-The "mkdir func1" above creates the pci-epf-ntb function device that will ++The "mkdir func1" above creates the pci-epf-vntb function device that will + be probed by pci_epf_vntb driver. + + The PCI endpoint framework populates the directory with the following + configurable fields:: + +- # ls functions/pci_epf_ntb/func1 +- baseclass_code deviceid msi_interrupts pci-epf-ntb.0 ++ # ls functions/pci_epf_vntb/func1 ++ baseclass_code deviceid msi_interrupts pci-epf-vntb.0 + progif_code secondary subsys_id vendorid + cache_line_size interrupt_pin msix_interrupts primary + revid subclass_code subsys_vendor_id +@@ -106,13 +106,13 @@ A sample configuration for virtual NTB driver for virtual PCI bus:: + # echo 0x080A > functions/pci_epf_vntb/func1/pci_epf_vntb.0/vntb_pid + # echo 0x10 > functions/pci_epf_vntb/func1/pci_epf_vntb.0/vbus_number + +-Binding pci-epf-ntb Device to EP Controller ++Binding pci-epf-vntb Device to EP Controller + -------------------------------------------- + + NTB function device should be attached to PCI endpoint controllers + connected to the host. + +- # ln -s controllers/5f010000.pcie_ep functions/pci-epf-ntb/func1/primary ++ # ln -s controllers/5f010000.pcie_ep functions/pci_epf_vntb/func1/primary + + Once the above step is completed, the PCI endpoint controllers are ready to + establish a link with the host. +@@ -134,7 +134,7 @@ lspci Output at Host side + ------------------------- + + Note that the devices listed here correspond to the values populated in +-"Creating pci-epf-ntb Device" section above:: ++"Creating pci-epf-vntb Device" section above:: + + # lspci + 00:00.0 PCI bridge: Freescale Semiconductor Inc Device 0000 (rev 01) +@@ -147,7 +147,7 @@ lspci Output at EP Side / Virtual PCI bus + ----------------------------------------- + + Note that the devices listed here correspond to the values populated in +-"Creating pci-epf-ntb Device" section above:: ++"Creating pci-epf-vntb Device" section above:: + + # lspci + 10:00.0 Unassigned class [ffff]: Dawicontrol Computersysteme GmbH Device 1234 (rev ff) +-- +2.51.0 + diff --git a/queue-6.6/documentation-trace-refactor-toctree.patch b/queue-6.6/documentation-trace-refactor-toctree.patch new file mode 100644 index 0000000000..bc0a05f6a7 --- /dev/null +++ b/queue-6.6/documentation-trace-refactor-toctree.patch @@ -0,0 +1,156 @@ +From e536224a8c8f664b05b7c9b0d5fc4ea12eba901a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 16 Apr 2025 09:40:50 +0700 +Subject: Documentation: trace: Refactor toctree + +From: Purva Yeshi + +[ Upstream commit f0ba72e65516d1d86f40c79a49c4ba01c9555592 ] + +Refactor table of contents of kernel tracing subsystem docs to improve +clarity, structure, and organization: + +- Reformat sections and add appropriate headings +- Improve section grouping and refine descriptions for each group +- Add docs intro paragraph + +Signed-off-by: Purva Yeshi +Link: https://lore.kernel.org/r/20250318113230.24950-2-purvayeshi550@gmail.com +[Bagas: massage commit message and address reviews] +Co-developed-by: Bagas Sanjaya +Signed-off-by: Bagas Sanjaya +Acked-by: Steven Rostedt (Google) +Signed-off-by: Jonathan Corbet +Stable-dep-of: 8236fc613d44 ("Documentation: tracing: Add PCI tracepoint documentation") +Signed-off-by: Sasha Levin +--- + Documentation/trace/index.rst | 96 +++++++++++++++++++++++++++++------ + 1 file changed, 80 insertions(+), 16 deletions(-) + +diff --git a/Documentation/trace/index.rst b/Documentation/trace/index.rst +index 2c991dc96ace6..770d3bece22c3 100644 +--- a/Documentation/trace/index.rst ++++ b/Documentation/trace/index.rst +@@ -1,39 +1,103 @@ +-========================== +-Linux Tracing Technologies +-========================== ++================================ ++Linux Tracing Technologies Guide ++================================ ++ ++Tracing in the Linux kernel is a powerful mechanism that allows ++developers and system administrators to analyze and debug system ++behavior. This guide provides documentation on various tracing ++frameworks and tools available in the Linux kernel. ++ ++Introduction to Tracing ++----------------------- ++ ++This section provides an overview of Linux tracing mechanisms ++and debugging approaches. + + .. toctree:: + :maxdepth: 2 + +- ftrace-design ++ debugging ++ tracepoints + tracepoint-analysis ++ ring-buffer-map ++ ++Core Tracing Frameworks ++----------------------- ++ ++The following are the primary tracing frameworks integrated into ++the Linux kernel. ++ ++.. toctree:: ++ :maxdepth: 1 ++ + ftrace ++ ftrace-design + ftrace-uses +- fprobe + kprobes + kprobetrace +- uprobetracer + fprobetrace +- tracepoints ++ fprobe ++ ring-buffer-design ++ ++Event Tracing and Analysis ++-------------------------- ++ ++A detailed explanation of event tracing mechanisms and their ++applications. ++ ++.. toctree:: ++ :maxdepth: 1 ++ + events + events-kmem + events-power + events-nmi + events-msr +- mmiotrace ++ boottime-trace + histogram + histogram-design +- boottime-trace +- debugging +- hwlat_detector +- osnoise-tracer +- timerlat-tracer ++ ++Hardware and Performance Tracing ++-------------------------------- ++ ++This section covers tracing features that monitor hardware ++interactions and system performance. ++ ++.. toctree:: ++ :maxdepth: 1 ++ + intel_th +- ring-buffer-design +- ring-buffer-map + stm + sys-t + coresight/index +- user_events + rv/index + hisi-ptt ++ mmiotrace ++ hwlat_detector ++ osnoise-tracer ++ timerlat-tracer ++ ++User-Space Tracing ++------------------ ++ ++These tools allow tracing user-space applications and ++interactions. ++ ++.. toctree:: ++ :maxdepth: 1 ++ ++ user_events ++ uprobetracer ++ ++Additional Resources ++-------------------- ++ ++For more details, refer to the respective documentation of each ++tracing tool and framework. ++ ++.. only:: subproject and html ++ ++ Indices ++ ======= ++ ++ * :ref:`genindex` +-- +2.51.0 + diff --git a/queue-6.6/documentation-tracing-add-pci-tracepoint-documentati.patch b/queue-6.6/documentation-tracing-add-pci-tracepoint-documentati.patch new file mode 100644 index 0000000000..898fea9089 --- /dev/null +++ b/queue-6.6/documentation-tracing-add-pci-tracepoint-documentati.patch @@ -0,0 +1,125 @@ +From 684151d7910ba1f9d16808e1cef4757a377a35a5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 10 Dec 2025 21:29:07 +0800 +Subject: Documentation: tracing: Add PCI tracepoint documentation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Shuai Xue + +[ Upstream commit 8236fc613d44e59f6736d6c3e9efffaf26ab7f00 ] + +The PCI tracing system provides tracepoints to monitor critical hardware +events that can impact system performance and reliability. Add +documentation about it. + +Signed-off-by: Shuai Xue +[bhelgaas: squash fixes: +https://lore.kernel.org/r/20260108013956.14351-2-bagasdotme@gmail.com +https://lore.kernel.org/r/20260108013956.14351-3-bagasdotme@gmail.com] +Signed-off-by: Bjorn Helgaas +Reviewed-by: Ilpo Järvinen +Link: https://patch.msgid.link/20251210132907.58799-4-xueshuai@linux.alibaba.com +Signed-off-by: Sasha Levin +--- + Documentation/trace/events-pci.rst | 74 ++++++++++++++++++++++++++++++ + Documentation/trace/index.rst | 1 + + 2 files changed, 75 insertions(+) + create mode 100644 Documentation/trace/events-pci.rst + +diff --git a/Documentation/trace/events-pci.rst b/Documentation/trace/events-pci.rst +new file mode 100644 +index 0000000000000..03ff4ad30ddfa +--- /dev/null ++++ b/Documentation/trace/events-pci.rst +@@ -0,0 +1,74 @@ ++.. SPDX-License-Identifier: GPL-2.0 ++ ++=========================== ++Subsystem Trace Points: PCI ++=========================== ++ ++Overview ++======== ++The PCI tracing system provides tracepoints to monitor critical hardware events ++that can impact system performance and reliability. These events normally show ++up here: ++ ++ /sys/kernel/tracing/events/pci ++ ++Cf. include/trace/events/pci.h for the events definitions. ++ ++Available Tracepoints ++===================== ++ ++pci_hp_event ++------------ ++ ++Monitors PCI hotplug events including card insertion/removal and link ++state changes. ++:: ++ ++ pci_hp_event "%s slot:%s, event:%s\n" ++ ++**Event Types**: ++ ++* ``LINK_UP`` - PCIe link established ++* ``LINK_DOWN`` - PCIe link lost ++* ``CARD_PRESENT`` - Card detected in slot ++* ``CARD_NOT_PRESENT`` - Card removed from slot ++ ++**Example Usage**:: ++ ++ # Enable the tracepoint ++ echo 1 > /sys/kernel/debug/tracing/events/pci/pci_hp_event/enable ++ ++ # Monitor events (the following output is generated when a device is hotplugged) ++ cat /sys/kernel/debug/tracing/trace_pipe ++ irq/51-pciehp-88 [001] ..... 1311.177459: pci_hp_event: 0000:00:02.0 slot:10, event:CARD_PRESENT ++ ++ irq/51-pciehp-88 [001] ..... 1311.177566: pci_hp_event: 0000:00:02.0 slot:10, event:LINK_UP ++ ++pcie_link_event ++--------------- ++ ++Monitors PCIe link speed changes and provides detailed link status information. ++:: ++ ++ pcie_link_event "%s type:%d, reason:%d, cur_bus_speed:%d, max_bus_speed:%d, width:%u, flit_mode:%u, status:%s\n" ++ ++**Parameters**: ++ ++* ``type`` - PCIe device type (4=Root Port, etc.) ++* ``reason`` - Reason for link change: ++ ++ - ``0`` - Link retrain ++ - ``1`` - Bus enumeration ++ - ``2`` - Bandwidth notification enable ++ - ``3`` - Bandwidth notification IRQ ++ - ``4`` - Hotplug event ++ ++ ++**Example Usage**:: ++ ++ # Enable the tracepoint ++ echo 1 > /sys/kernel/debug/tracing/events/pci/pcie_link_event/enable ++ ++ # Monitor events (the following output is generated when a device is hotplugged) ++ cat /sys/kernel/debug/tracing/trace_pipe ++ irq/51-pciehp-88 [001] ..... 381.545386: pcie_link_event: 0000:00:02.0 type:4, reason:4, cur_bus_speed:20, max_bus_speed:23, width:1, flit_mode:0, status:DLLLA +diff --git a/Documentation/trace/index.rst b/Documentation/trace/index.rst +index 770d3bece22c3..e9bcb9d9f7f3b 100644 +--- a/Documentation/trace/index.rst ++++ b/Documentation/trace/index.rst +@@ -53,6 +53,7 @@ applications. + events-power + events-nmi + events-msr ++ events-pci + boottime-trace + histogram + histogram-design +-- +2.51.0 + diff --git a/queue-6.6/documentation-tracing-add-ring-buffer-mapping.patch b/queue-6.6/documentation-tracing-add-ring-buffer-mapping.patch new file mode 100644 index 0000000000..b42fcee1ac --- /dev/null +++ b/queue-6.6/documentation-tracing-add-ring-buffer-mapping.patch @@ -0,0 +1,151 @@ +From 0856df37646c2fb5e3b85485aa8aca50fe81547f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 May 2024 15:04:33 +0100 +Subject: Documentation: tracing: Add ring-buffer mapping + +From: Vincent Donnefort + +[ Upstream commit a1e0dd7ce38af3fb1a3bc54a222a7c5e4eaa4202 ] + +It is now possible to mmap() a ring-buffer to stream its content. Add +some documentation and a code example. + +Link: https://lore.kernel.org/linux-trace-kernel/20240510140435.3550353-5-vdonnefort@google.com + +Signed-off-by: Vincent Donnefort +Signed-off-by: Steven Rostedt (Google) +Stable-dep-of: 8236fc613d44 ("Documentation: tracing: Add PCI tracepoint documentation") +Signed-off-by: Sasha Levin +--- + Documentation/trace/index.rst | 1 + + Documentation/trace/ring-buffer-map.rst | 106 ++++++++++++++++++++++++ + 2 files changed, 107 insertions(+) + create mode 100644 Documentation/trace/ring-buffer-map.rst + +diff --git a/Documentation/trace/index.rst b/Documentation/trace/index.rst +index 5092d6c13af5e..0b300901fd750 100644 +--- a/Documentation/trace/index.rst ++++ b/Documentation/trace/index.rst +@@ -29,6 +29,7 @@ Linux Tracing Technologies + timerlat-tracer + intel_th + ring-buffer-design ++ ring-buffer-map + stm + sys-t + coresight/index +diff --git a/Documentation/trace/ring-buffer-map.rst b/Documentation/trace/ring-buffer-map.rst +new file mode 100644 +index 0000000000000..8e296bcc0d7f3 +--- /dev/null ++++ b/Documentation/trace/ring-buffer-map.rst +@@ -0,0 +1,106 @@ ++.. SPDX-License-Identifier: GPL-2.0 ++ ++================================== ++Tracefs ring-buffer memory mapping ++================================== ++ ++:Author: Vincent Donnefort ++ ++Overview ++======== ++Tracefs ring-buffer memory map provides an efficient method to stream data ++as no memory copy is necessary. The application mapping the ring-buffer becomes ++then a consumer for that ring-buffer, in a similar fashion to trace_pipe. ++ ++Memory mapping setup ++==================== ++The mapping works with a mmap() of the trace_pipe_raw interface. ++ ++The first system page of the mapping contains ring-buffer statistics and ++description. It is referred to as the meta-page. One of the most important ++fields of the meta-page is the reader. It contains the sub-buffer ID which can ++be safely read by the mapper (see ring-buffer-design.rst). ++ ++The meta-page is followed by all the sub-buffers, ordered by ascending ID. It is ++therefore effortless to know where the reader starts in the mapping: ++ ++.. code-block:: c ++ ++ reader_id = meta->reader->id; ++ reader_offset = meta->meta_page_size + reader_id * meta->subbuf_size; ++ ++When the application is done with the current reader, it can get a new one using ++the trace_pipe_raw ioctl() TRACE_MMAP_IOCTL_GET_READER. This ioctl also updates ++the meta-page fields. ++ ++Limitations ++=========== ++When a mapping is in place on a Tracefs ring-buffer, it is not possible to ++either resize it (either by increasing the entire size of the ring-buffer or ++each subbuf). It is also not possible to use snapshot and causes splice to copy ++the ring buffer data instead of using the copyless swap from the ring buffer. ++ ++Concurrent readers (either another application mapping that ring-buffer or the ++kernel with trace_pipe) are allowed but not recommended. They will compete for ++the ring-buffer and the output is unpredictable, just like concurrent readers on ++trace_pipe would be. ++ ++Example ++======= ++ ++.. code-block:: c ++ ++ #include ++ #include ++ #include ++ #include ++ ++ #include ++ ++ #include ++ #include ++ ++ #define TRACE_PIPE_RAW "/sys/kernel/tracing/per_cpu/cpu0/trace_pipe_raw" ++ ++ int main(void) ++ { ++ int page_size = getpagesize(), fd, reader_id; ++ unsigned long meta_len, data_len; ++ struct trace_buffer_meta *meta; ++ void *map, *reader, *data; ++ ++ fd = open(TRACE_PIPE_RAW, O_RDONLY | O_NONBLOCK); ++ if (fd < 0) ++ exit(EXIT_FAILURE); ++ ++ map = mmap(NULL, page_size, PROT_READ, MAP_SHARED, fd, 0); ++ if (map == MAP_FAILED) ++ exit(EXIT_FAILURE); ++ ++ meta = (struct trace_buffer_meta *)map; ++ meta_len = meta->meta_page_size; ++ ++ printf("entries: %llu\n", meta->entries); ++ printf("overrun: %llu\n", meta->overrun); ++ printf("read: %llu\n", meta->read); ++ printf("nr_subbufs: %u\n", meta->nr_subbufs); ++ ++ data_len = meta->subbuf_size * meta->nr_subbufs; ++ data = mmap(NULL, data_len, PROT_READ, MAP_SHARED, fd, meta_len); ++ if (data == MAP_FAILED) ++ exit(EXIT_FAILURE); ++ ++ if (ioctl(fd, TRACE_MMAP_IOCTL_GET_READER) < 0) ++ exit(EXIT_FAILURE); ++ ++ reader_id = meta->reader.id; ++ reader = data + meta->subbuf_size * reader_id; ++ ++ printf("Current reader address: %p\n", reader); ++ ++ munmap(data, data_len); ++ munmap(meta, meta_len); ++ close (fd); ++ ++ return 0; ++ } +-- +2.51.0 + diff --git a/queue-6.6/drivers-iio-mpu3050-use-dev_err_probe-for-regulator-.patch b/queue-6.6/drivers-iio-mpu3050-use-dev_err_probe-for-regulator-.patch new file mode 100644 index 0000000000..7167d6d3ea --- /dev/null +++ b/queue-6.6/drivers-iio-mpu3050-use-dev_err_probe-for-regulator-.patch @@ -0,0 +1,42 @@ +From 625ea60070233a476d0c5576df846632242ce5e9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 17:34:25 +0200 +Subject: drivers: iio: mpu3050: use dev_err_probe for regulator request + +From: Svyatoslav Ryhel + +[ Upstream commit b010880b9936da14f8035585ab57577aa05be23a ] + +Regulator requesting may result in deferred probing error which will +abort driver probing. To avoid this just use dev_err_probe which handles +deferred probing. + +Fixes: 3904b28efb2c ("iio: gyro: Add driver for the MPU-3050 gyroscope") +Signed-off-by: Svyatoslav Ryhel +Reviewed-by: Andy Shevchenko +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/gyro/mpu3050-core.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/iio/gyro/mpu3050-core.c b/drivers/iio/gyro/mpu3050-core.c +index a791ba3a693a4..de126561f197d 100644 +--- a/drivers/iio/gyro/mpu3050-core.c ++++ b/drivers/iio/gyro/mpu3050-core.c +@@ -1172,10 +1172,8 @@ int mpu3050_common_probe(struct device *dev, + mpu3050->regs[1].supply = mpu3050_reg_vlogic; + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(mpu3050->regs), + mpu3050->regs); +- if (ret) { +- dev_err(dev, "Cannot get regulators\n"); +- return ret; +- } ++ if (ret) ++ return dev_err_probe(dev, ret, "Cannot get regulators\n"); + + ret = mpu3050_power_up(mpu3050); + if (ret) +-- +2.51.0 + diff --git a/queue-6.6/drm-amdgpu-use-explicit-vcn-instance-0-in-sr-iov-ini.patch b/queue-6.6/drm-amdgpu-use-explicit-vcn-instance-0-in-sr-iov-ini.patch new file mode 100644 index 0000000000..1838829584 --- /dev/null +++ b/queue-6.6/drm-amdgpu-use-explicit-vcn-instance-0-in-sr-iov-ini.patch @@ -0,0 +1,179 @@ +From c73934c477782aa3a55e9db80ca5533de7ac9f62 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 15:25:25 +0530 +Subject: drm/amdgpu: Use explicit VCN instance 0 in SR-IOV init +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Srinivasan Shanmugam + +[ Upstream commit af26fa751c2eef66916acbf0d3c3e9159da56186 ] + +vcn_v2_0_start_sriov() declares a local variable "i" initialized to zero +and uses it only as the instance index in SOC15_REG_OFFSET(UVD, i, ...). +The value is never changed and all other fields are taken from +adev->vcn.inst[0], so this path only ever programs VCN instance 0. + +This triggered a Smatch: +warn: iterator 'i' not incremented + +Replace the dummy iterator with an explicit instance index of 0 in +SOC15_REG_OFFSET() calls. + +Fixes: dd26858a9cd8 ("drm/amdgpu: implement initialization part on VCN2.0 for SRIOV") +Reported by: Dan Carpenter +Cc: darlington Opara +Cc: Jinage Zhao +Cc: Monk Liu +Cc: Emily Deng +Cc: Christian König +Cc: Alex Deucher +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Emily Deng +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c | 45 ++++++++++++++------------- + 1 file changed, 23 insertions(+), 22 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c +index 18794394c5a05..2505951ad06a0 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c +@@ -1862,7 +1862,8 @@ static int vcn_v2_0_start_sriov(struct amdgpu_device *adev) + struct mmsch_v2_0_cmd_end end = { {0} }; + struct mmsch_v2_0_init_header *header; + uint32_t *init_table = adev->virt.mm_table.cpu_addr; +- uint8_t i = 0; ++ ++ /* This path only programs VCN instance 0. */ + + header = (struct mmsch_v2_0_init_header *)init_table; + direct_wt.cmd_header.command_type = MMSCH_COMMAND__DIRECT_REG_WRITE; +@@ -1881,93 +1882,93 @@ static int vcn_v2_0_start_sriov(struct amdgpu_device *adev) + size = AMDGPU_GPU_PAGE_ALIGN(adev->vcn.fw->size + 4); + + MMSCH_V2_0_INSERT_DIRECT_RD_MOD_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_STATUS), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_STATUS), + 0xFFFFFFFF, 0x00000004); + + /* mc resume*/ + if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW), + adev->firmware.ucode[AMDGPU_UCODE_ID_VCN].tmr_mc_addr_lo); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE_64BIT_BAR_HIGH), + adev->firmware.ucode[AMDGPU_UCODE_ID_VCN].tmr_mc_addr_hi); + offset = 0; + } else { + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW), + lower_32_bits(adev->vcn.inst->gpu_addr)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE_64BIT_BAR_HIGH), + upper_32_bits(adev->vcn.inst->gpu_addr)); + offset = size; + } + + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_OFFSET0), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_OFFSET0), + 0); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_SIZE0), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_SIZE0), + size); + + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE1_64BIT_BAR_LOW), + lower_32_bits(adev->vcn.inst->gpu_addr + offset)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE1_64BIT_BAR_HIGH), + upper_32_bits(adev->vcn.inst->gpu_addr + offset)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_OFFSET1), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_OFFSET1), + 0); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_SIZE1), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_SIZE1), + AMDGPU_VCN_STACK_SIZE); + + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE2_64BIT_BAR_LOW), + lower_32_bits(adev->vcn.inst->gpu_addr + offset + + AMDGPU_VCN_STACK_SIZE)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_VCPU_CACHE2_64BIT_BAR_HIGH), + upper_32_bits(adev->vcn.inst->gpu_addr + offset + + AMDGPU_VCN_STACK_SIZE)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_OFFSET2), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_OFFSET2), + 0); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_SIZE2), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_SIZE2), + AMDGPU_VCN_CONTEXT_SIZE); + + for (r = 0; r < adev->vcn.num_enc_rings; ++r) { + ring = &adev->vcn.inst->ring_enc[r]; + ring->wptr = 0; + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_RB_BASE_LO), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_RB_BASE_LO), + lower_32_bits(ring->gpu_addr)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_RB_BASE_HI), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_RB_BASE_HI), + upper_32_bits(ring->gpu_addr)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_RB_SIZE), ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_RB_SIZE), + ring->ring_size / 4); + } + + ring = &adev->vcn.inst->ring_dec; + ring->wptr = 0; + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_RBC_RB_64BIT_BAR_LOW), + lower_32_bits(ring->gpu_addr)); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, ++ SOC15_REG_OFFSET(UVD, 0, + mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH), + upper_32_bits(ring->gpu_addr)); + /* force RBC into idle state */ +@@ -1978,7 +1979,7 @@ static int vcn_v2_0_start_sriov(struct amdgpu_device *adev) + tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1); + tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1); + MMSCH_V2_0_INSERT_DIRECT_WT( +- SOC15_REG_OFFSET(UVD, i, mmUVD_RBC_RB_CNTL), tmp); ++ SOC15_REG_OFFSET(UVD, 0, mmUVD_RBC_RB_CNTL), tmp); + + /* add end packet */ + tmp = sizeof(struct mmsch_v2_0_cmd_end); +-- +2.51.0 + diff --git a/queue-6.6/drm-msm-a2xx-fix-pixel-shader-start-on-a225.patch b/queue-6.6/drm-msm-a2xx-fix-pixel-shader-start-on-a225.patch new file mode 100644 index 0000000000..71fa137b3b --- /dev/null +++ b/queue-6.6/drm-msm-a2xx-fix-pixel-shader-start-on-a225.patch @@ -0,0 +1,42 @@ +From b95d8e73fc9a98b2469e8c61e9575a601968295f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 21 Nov 2025 18:13:03 +0200 +Subject: drm/msm/a2xx: fix pixel shader start on A225 + +From: Dmitry Baryshkov + +[ Upstream commit 6a7b0a670ba4d283285d76d45233cbecc5af5e40 ] + +A225 has a different PixelShader start address, write correct address +while initializing GPU. + +Fixes: 21af872cd8c6 ("drm/msm/adreno: add a2xx") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Patchwork: https://patchwork.freedesktop.org/patch/689906/ +Message-ID: <20251121-a225-v1-1-a1bab651d186@oss.qualcomm.com> +Signed-off-by: Rob Clark +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/adreno/a2xx_gpu.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/msm/adreno/a2xx_gpu.c b/drivers/gpu/drm/msm/adreno/a2xx_gpu.c +index 535c89ce5d62e..0410a1657b15e 100644 +--- a/drivers/gpu/drm/msm/adreno/a2xx_gpu.c ++++ b/drivers/gpu/drm/msm/adreno/a2xx_gpu.c +@@ -77,7 +77,10 @@ static bool a2xx_me_init(struct msm_gpu *gpu) + + /* Vertex and Pixel Shader Start Addresses in instructions + * (3 DWORDS per instruction) */ +- OUT_RING(ring, 0x80000180); ++ if (adreno_is_a225(adreno_gpu)) ++ OUT_RING(ring, 0x80000300); ++ else ++ OUT_RING(ring, 0x80000180); + /* Maximum Contexts */ + OUT_RING(ring, 0x00000001); + /* Write Confirm Interval and The CP will wait the +-- +2.51.0 + diff --git a/queue-6.6/drm-msm-disp-dpu-add-merge3d-support-for-sc7280.patch b/queue-6.6/drm-msm-disp-dpu-add-merge3d-support-for-sc7280.patch new file mode 100644 index 0000000000..4f30e73423 --- /dev/null +++ b/queue-6.6/drm-msm-disp-dpu-add-merge3d-support-for-sc7280.patch @@ -0,0 +1,86 @@ +From 28fe23ce00e816f405d9435480a57718f5cd2ac7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 1 Jan 2026 10:34:38 +0530 +Subject: drm/msm/disp/dpu: add merge3d support for sc7280 + +From: Mahadevan P + +[ Upstream commit 2892de3f4f985fa779c330468e2f341fdb762ccd ] + +On SC7280 targets, display modes with a width greater than the +max_mixer_width (2400) are rejected during mode validation when +merge3d is disabled. This limitation exists because, without a +3D merge block, two layer mixers cannot be combined(non-DSC interface), +preventing large layers from being split across mixers. As a result, +higher resolution modes cannot be supported. + +Enable merge3d support on SC7280 to allow combining streams from +two layer mixers into a single non-DSC interface. This capability +removes the width restriction and enables buffer sizes beyond the +2400-pixel limit. + +Fixes: 591e34a091d1 ("drm/msm/disp/dpu1: add support for display for SC7280 target") +Signed-off-by: Mahadevan P +Reviewed-by: Dmitry Baryshkov +Patchwork: https://patchwork.freedesktop.org/patch/696713/ +Link: https://lore.kernel.org/r/20260101-4k-v2-1-712ae3c1f816@oss.qualcomm.com +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + .../gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h +index 9195cb996f444..cbaca4bf2864a 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h +@@ -14,6 +14,7 @@ static const struct dpu_caps sc7280_dpu_caps = { + .has_dim_layer = true, + .has_idle_pc = true, + .max_linewidth = 2400, ++ .has_3d_merge = true, + .pixel_ram_size = DEFAULT_PIXEL_RAM_SIZE, + }; + +@@ -145,7 +146,7 @@ static const struct dpu_pingpong_cfg sc7280_pp[] = { + .base = 0x6b000, .len = 0, + .features = BIT(DPU_PINGPONG_DITHER), + .sblk = &sc7280_pp_sblk, +- .merge_3d = 0, ++ .merge_3d = MERGE_3D_1, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 10), + .intr_rdptr = -1, + }, { +@@ -153,12 +154,19 @@ static const struct dpu_pingpong_cfg sc7280_pp[] = { + .base = 0x6c000, .len = 0, + .features = BIT(DPU_PINGPONG_DITHER), + .sblk = &sc7280_pp_sblk, +- .merge_3d = 0, ++ .merge_3d = MERGE_3D_1, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 11), + .intr_rdptr = -1, + }, + }; + ++static const struct dpu_merge_3d_cfg sc7280_merge_3d[] = { ++ { ++ .name = "merge_3d_1", .id = MERGE_3D_1, ++ .base = 0x4f000, .len = 0x8, ++ }, ++}; ++ + /* NOTE: sc7280 only has one DSC hard slice encoder */ + static const struct dpu_dsc_cfg sc7280_dsc[] = { + { +@@ -265,6 +273,8 @@ const struct dpu_mdss_cfg dpu_sc7280_cfg = { + .mixer = sc7280_lm, + .pingpong_count = ARRAY_SIZE(sc7280_pp), + .pingpong = sc7280_pp, ++ .merge_3d_count = ARRAY_SIZE(sc7280_merge_3d), ++ .merge_3d = sc7280_merge_3d, + .dsc_count = ARRAY_SIZE(sc7280_dsc), + .dsc = sc7280_dsc, + .wb_count = ARRAY_SIZE(sc7280_wb), +-- +2.51.0 + diff --git a/queue-6.6/drm-msm-dpu-fix-cmd-panels-on-dpu-1.x-3.x.patch b/queue-6.6/drm-msm-dpu-fix-cmd-panels-on-dpu-1.x-3.x.patch new file mode 100644 index 0000000000..6caa9007db --- /dev/null +++ b/queue-6.6/drm-msm-dpu-fix-cmd-panels-on-dpu-1.x-3.x.patch @@ -0,0 +1,48 @@ +From aa9d59d99ac1ccae1d584ad44a777adc795822b8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 28 Dec 2025 06:02:28 +0200 +Subject: drm/msm/dpu: fix CMD panels on DPU 1.x - 3.x + +From: Dmitry Baryshkov + +[ Upstream commit 59ca3d11f5311d9167015fe4f431701614ae0048 ] + +DPU units before 4.x don't have a separate CTL_START IRQ to mark the +begin of the data transfer. In such a case, wait for the frame transfer +to complete rather than trying to wait for the CTL_START interrupt (and +obviously hitting the timeout). + +Fixes: 050770cbbd26 ("drm/msm/dpu: Fix timeout issues on command mode panels") +Reported-by: Alexey Minnekhanov +Closes: https://lore.kernel.org/r/8e1d33ff-d902-4ae9-9162-e00d17a5e6d1@postmarketos.org +Patchwork: https://patchwork.freedesktop.org/patch/696490/ +Link: https://lore.kernel.org/r/20251228-mdp5-drop-dpu3-v4-2-7497c3d39179@oss.qualcomm.com +Tested-by: Alexey Minnekhanov +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c +index 83a804ebf8d7e..fd2400c4665d2 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c +@@ -675,10 +675,11 @@ static int dpu_encoder_phys_cmd_wait_for_commit_done( + if (!dpu_encoder_phys_cmd_is_master(phys_enc)) + return 0; + +- if (phys_enc->hw_ctl->ops.is_started(phys_enc->hw_ctl)) +- return dpu_encoder_phys_cmd_wait_for_tx_complete(phys_enc); ++ if (phys_enc->irq[INTR_IDX_CTL_START] && ++ !phys_enc->hw_ctl->ops.is_started(phys_enc->hw_ctl)) ++ return _dpu_encoder_phys_cmd_wait_for_ctl_start(phys_enc); + +- return _dpu_encoder_phys_cmd_wait_for_ctl_start(phys_enc); ++ return dpu_encoder_phys_cmd_wait_for_tx_complete(phys_enc); + } + + static void dpu_encoder_phys_cmd_handle_post_kickoff( +-- +2.51.0 + diff --git a/queue-6.6/edac-altera-remove-irqf_oneshot.patch b/queue-6.6/edac-altera-remove-irqf_oneshot.patch new file mode 100644 index 0000000000..6b2d1a4a10 --- /dev/null +++ b/queue-6.6/edac-altera-remove-irqf_oneshot.patch @@ -0,0 +1,74 @@ +From 83c14bd08b9cb96e0de0e3d506a05b3bc4b33457 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:55:30 +0100 +Subject: EDAC/altera: Remove IRQF_ONESHOT + +From: Sebastian Andrzej Siewior + +[ Upstream commit 5c858d6c66304b4c7579582ec5235f02d43578ea ] + +Passing IRQF_ONESHOT ensures that the interrupt source is masked until +the secondary (threaded) handler is done. If only a primary handler is +used then the flag makes no sense because the interrupt can not fire +(again) while its handler is running. + +The flag also prevents force-threading of the primary handler and the +irq-core will warn about this. + +Remove IRQF_ONESHOT from irqflags. + +Fixes: a29d64a45eed1 ("EDAC, altera: Add IRQ Flags to disable IRQ while handling") +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260128095540.863589-11-bigeasy@linutronix.de +Signed-off-by: Sasha Levin +--- + drivers/edac/altera_edac.c | 11 ++++------- + 1 file changed, 4 insertions(+), 7 deletions(-) + +diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c +index 4f8f87207b67b..dc1915ffc3cbe 100644 +--- a/drivers/edac/altera_edac.c ++++ b/drivers/edac/altera_edac.c +@@ -1573,8 +1573,7 @@ static int altr_portb_setup(struct altr_edac_device_dev *device) + goto err_release_group_1; + } + rc = devm_request_irq(&altdev->ddev, altdev->sb_irq, +- prv->ecc_irq_handler, +- IRQF_ONESHOT | IRQF_TRIGGER_HIGH, ++ prv->ecc_irq_handler, IRQF_TRIGGER_HIGH, + ecc_name, altdev); + if (rc) { + edac_printk(KERN_ERR, EDAC_DEVICE, "PortB SBERR IRQ error\n"); +@@ -1597,8 +1596,7 @@ static int altr_portb_setup(struct altr_edac_device_dev *device) + goto err_release_group_1; + } + rc = devm_request_irq(&altdev->ddev, altdev->db_irq, +- prv->ecc_irq_handler, +- IRQF_ONESHOT | IRQF_TRIGGER_HIGH, ++ prv->ecc_irq_handler, IRQF_TRIGGER_HIGH, + ecc_name, altdev); + if (rc) { + edac_printk(KERN_ERR, EDAC_DEVICE, "PortB DBERR IRQ error\n"); +@@ -1981,8 +1979,7 @@ static int altr_edac_a10_device_add(struct altr_arria10_edac *edac, + goto err_release_group1; + } + rc = devm_request_irq(edac->dev, altdev->sb_irq, prv->ecc_irq_handler, +- IRQF_ONESHOT | IRQF_TRIGGER_HIGH, +- ecc_name, altdev); ++ IRQF_TRIGGER_HIGH, ecc_name, altdev); + if (rc) { + edac_printk(KERN_ERR, EDAC_DEVICE, "No SBERR IRQ resource\n"); + goto err_release_group1; +@@ -2004,7 +2001,7 @@ static int altr_edac_a10_device_add(struct altr_arria10_edac *edac, + goto err_release_group1; + } + rc = devm_request_irq(edac->dev, altdev->db_irq, prv->ecc_irq_handler, +- IRQF_ONESHOT | IRQF_TRIGGER_HIGH, ++ IRQF_TRIGGER_HIGH, + ecc_name, altdev); + if (rc) { + edac_printk(KERN_ERR, EDAC_DEVICE, "No DBERR IRQ resource\n"); +-- +2.51.0 + diff --git a/queue-6.6/edac-i5000-fix-snprintf-size-calculation-in-calculat.patch b/queue-6.6/edac-i5000-fix-snprintf-size-calculation-in-calculat.patch new file mode 100644 index 0000000000..2436bff159 --- /dev/null +++ b/queue-6.6/edac-i5000-fix-snprintf-size-calculation-in-calculat.patch @@ -0,0 +1,40 @@ +From 86649afb39943c71c91848866cc5174d9d3036b7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 17:36:59 +0300 +Subject: EDAC/i5000: Fix snprintf() size calculation in calculate_dimm_size() + +From: Dan Carpenter + +[ Upstream commit 7b5c7e83ac405ff9ecbdd92b37a477f4288f8814 ] + +The snprintf() can't really overflow because we're writing a max of 42 +bytes to a PAGE_SIZE buffer. But the limit calculation doesn't take +the first 11 bytes that we wrote into consideration so the limit is +not correct. Just fix it for correctness even though it doesn't +affect runtime. + +Fixes: 64e1fdaf55d6 ("i5000_edac: Fix the logic that retrieves memory information") +Signed-off-by: Dan Carpenter +Signed-off-by: Tony Luck +Reviewed-by: Qiuxu Zhuo +Link: https://patch.msgid.link/07cd652c51e77aad5a8350e1a7cd9407e5bbe373.1765290801.git.dan.carpenter@linaro.org +Signed-off-by: Sasha Levin +--- + drivers/edac/i5000_edac.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c +index 4b5a71f8739d9..8c6a291e01f6a 100644 +--- a/drivers/edac/i5000_edac.c ++++ b/drivers/edac/i5000_edac.c +@@ -1111,6 +1111,7 @@ static void calculate_dimm_size(struct i5000_pvt *pvt) + + n = snprintf(p, space, " "); + p += n; ++ space -= n; + for (branch = 0; branch < MAX_BRANCHES; branch++) { + n = snprintf(p, space, " branch %d | ", branch); + p += n; +-- +2.51.0 + diff --git a/queue-6.6/edac-i5400-fix-snprintf-limit-calculation-in-calcula.patch b/queue-6.6/edac-i5400-fix-snprintf-limit-calculation-in-calcula.patch new file mode 100644 index 0000000000..af555615b5 --- /dev/null +++ b/queue-6.6/edac-i5400-fix-snprintf-limit-calculation-in-calcula.patch @@ -0,0 +1,49 @@ +From 525fa2d8f66712d3267dc2f48fc59214cea8c0aa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 17:37:04 +0300 +Subject: EDAC/i5400: Fix snprintf() limit calculation in calculate_dimm_size() + +From: Dan Carpenter + +[ Upstream commit 72f12683611344853ab030fe7d19b23970ed2bd8 ] + +The snprintf() can't really overflow because we're writing a max of 42 +bytes to a PAGE_SIZE buffer. But my static checker complains because +the limit calculation doesn't take the first 11 space characters that +we wrote into the buffer into consideration. Fix this for the sake of +correctness even though it doesn't affect runtime. + +Also delete an earlier "space -= n;" which was not used. + +Fixes: 68d086f89b80 ("i5400_edac: improve debug messages to better represent the filled memory") +Signed-off-by: Dan Carpenter +Signed-off-by: Tony Luck +Reviewed-by: Qiuxu Zhuo +Link: https://patch.msgid.link/ccd06b91748e7ed8e33eeb2ff1e7b98700879304.1765290801.git.dan.carpenter@linaro.org +Signed-off-by: Sasha Levin +--- + drivers/edac/i5400_edac.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/edac/i5400_edac.c b/drivers/edac/i5400_edac.c +index 49b4499269fb7..68afb3bb8e290 100644 +--- a/drivers/edac/i5400_edac.c ++++ b/drivers/edac/i5400_edac.c +@@ -1025,13 +1025,13 @@ static void calculate_dimm_size(struct i5400_pvt *pvt) + space -= n; + } + +- space -= n; + edac_dbg(2, "%s\n", mem_buffer); + p = mem_buffer; + space = PAGE_SIZE; + + n = snprintf(p, space, " "); + p += n; ++ space -= n; + for (branch = 0; branch < MAX_BRANCHES; branch++) { + n = snprintf(p, space, " branch %d | ", branch); + p += n; +-- +2.51.0 + diff --git a/queue-6.6/fat-avoid-parent-link-count-underflow-in-rmdir.patch b/queue-6.6/fat-avoid-parent-link-count-underflow-in-rmdir.patch new file mode 100644 index 0000000000..6b1be04faa --- /dev/null +++ b/queue-6.6/fat-avoid-parent-link-count-underflow-in-rmdir.patch @@ -0,0 +1,74 @@ +From 7f77db3522213ff19ad1d51db6e35a229d5bbe73 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 1 Jan 2026 19:11:48 +0800 +Subject: fat: avoid parent link count underflow in rmdir + +From: Zhiyu Zhang + +[ Upstream commit 8cafcb881364af5ef3a8b9fed4db254054033d8a ] + +Corrupted FAT images can leave a directory inode with an incorrect +i_nlink (e.g. 2 even though subdirectories exist). rmdir then +unconditionally calls drop_nlink(dir) and can drive i_nlink to 0, +triggering the WARN_ON in drop_nlink(). + +Add a sanity check in vfat_rmdir() and msdos_rmdir(): only drop the +parent link count when it is at least 3, otherwise report a filesystem +error. + +Link: https://lkml.kernel.org/r/20260101111148.1437-1-zhiyuzhang999@gmail.com +Fixes: 9a53c3a783c2 ("[PATCH] r/o bind mounts: unlink: monitor i_nlink") +Signed-off-by: Zhiyu Zhang +Reported-by: Zhiyu Zhang +Closes: https://lore.kernel.org/linux-fsdevel/aVN06OKsKxZe6-Kv@casper.infradead.org/T/#t +Tested-by: Zhiyu Zhang +Acked-by: OGAWA Hirofumi +Cc: Al Viro +Cc: Christian Brauner +Cc: Jan Kara +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/fat/namei_msdos.c | 7 ++++++- + fs/fat/namei_vfat.c | 7 ++++++- + 2 files changed, 12 insertions(+), 2 deletions(-) + +diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c +index 2116c486843b7..e189fbf95fcac 100644 +--- a/fs/fat/namei_msdos.c ++++ b/fs/fat/namei_msdos.c +@@ -325,7 +325,12 @@ static int msdos_rmdir(struct inode *dir, struct dentry *dentry) + err = fat_remove_entries(dir, &sinfo); /* and releases bh */ + if (err) + goto out; +- drop_nlink(dir); ++ if (dir->i_nlink >= 3) ++ drop_nlink(dir); ++ else { ++ fat_fs_error(sb, "parent dir link count too low (%u)", ++ dir->i_nlink); ++ } + + clear_nlink(inode); + fat_truncate_time(inode, NULL, S_CTIME); +diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c +index 3cf22a6727f1b..7d7ac30c6eff8 100644 +--- a/fs/fat/namei_vfat.c ++++ b/fs/fat/namei_vfat.c +@@ -806,7 +806,12 @@ static int vfat_rmdir(struct inode *dir, struct dentry *dentry) + err = fat_remove_entries(dir, &sinfo); /* and releases bh */ + if (err) + goto out; +- drop_nlink(dir); ++ if (dir->i_nlink >= 3) ++ drop_nlink(dir); ++ else { ++ fat_fs_error(sb, "parent dir link count too low (%u)", ++ dir->i_nlink); ++ } + + clear_nlink(inode); + fat_truncate_time(inode, NULL, S_ATIME|S_MTIME); +-- +2.51.0 + diff --git a/queue-6.6/fbdev-au1200fb-fix-a-memory-leak-in-au1200fb_drv_pro.patch b/queue-6.6/fbdev-au1200fb-fix-a-memory-leak-in-au1200fb_drv_pro.patch new file mode 100644 index 0000000000..99658ac024 --- /dev/null +++ b/queue-6.6/fbdev-au1200fb-fix-a-memory-leak-in-au1200fb_drv_pro.patch @@ -0,0 +1,43 @@ +From 77b3f4d3148c368379084eaf0749441ef113bf13 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 20:14:58 +0800 +Subject: fbdev: au1200fb: Fix a memory leak in au1200fb_drv_probe() + +From: Felix Gu + +[ Upstream commit ce4e25198a6aaaaf36248edf8daf3d744ec8e309 ] + +In au1200fb_drv_probe(), when platform_get_irq fails(), it directly +returns from the function with an error code, which causes a memory +leak. + +Replace it with a goto label to ensure proper cleanup. + +Fixes: 4e88761f5f8c ("fbdev: au1200fb: Fix missing IRQ check in au1200fb_drv_probe") +Signed-off-by: Felix Gu +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/au1200fb.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/video/fbdev/au1200fb.c b/drivers/video/fbdev/au1200fb.c +index c137d6afe4840..1b05dfbd5195e 100644 +--- a/drivers/video/fbdev/au1200fb.c ++++ b/drivers/video/fbdev/au1200fb.c +@@ -1732,8 +1732,10 @@ static int au1200fb_drv_probe(struct platform_device *dev) + + /* Now hook interrupt too */ + irq = platform_get_irq(dev, 0); +- if (irq < 0) +- return irq; ++ if (irq < 0) { ++ ret = irq; ++ goto failed; ++ } + + ret = request_irq(irq, au1200fb_handle_irq, + IRQF_SHARED, "lcd", (void *)dev); +-- +2.51.0 + diff --git a/queue-6.6/fbdev-of_display_timing-fix-device-node-reference-le.patch b/queue-6.6/fbdev-of_display_timing-fix-device-node-reference-le.patch new file mode 100644 index 0000000000..f4e4869407 --- /dev/null +++ b/queue-6.6/fbdev-of_display_timing-fix-device-node-reference-le.patch @@ -0,0 +1,56 @@ +From 1088ce6fb2fa4887fc0fe4772e8101b60db1c506 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Jan 2026 20:48:33 +0800 +Subject: fbdev: of_display_timing: Fix device node reference leak in + of_get_display_timings() + +From: Felix Gu + +[ Upstream commit c39ee2d264f98efa14aa46c9942114cb03c7baa6 ] + +Use for_each_child_of_node_scoped instead of for_each_child_of_node +to ensure automatic of_node_put on early exit paths, preventing +device node reference leak. + +Fixes: cc3f414cf2e4 ("video: add of helper for display timings/videomode") +Signed-off-by: Felix Gu +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/of_display_timing.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/video/of_display_timing.c b/drivers/video/of_display_timing.c +index bebd371c6b93e..a4cd446ac5a59 100644 +--- a/drivers/video/of_display_timing.c ++++ b/drivers/video/of_display_timing.c +@@ -195,7 +195,7 @@ struct display_timings *of_get_display_timings(const struct device_node *np) + disp->num_timings = 0; + disp->native_mode = 0; + +- for_each_child_of_node(timings_np, entry) { ++ for_each_child_of_node_scoped(timings_np, child) { + struct display_timing *dt; + int r; + +@@ -206,7 +206,7 @@ struct display_timings *of_get_display_timings(const struct device_node *np) + goto timingfail; + } + +- r = of_parse_display_timing(entry, dt); ++ r = of_parse_display_timing(child, dt); + if (r) { + /* + * to not encourage wrong devicetrees, fail in case of +@@ -218,7 +218,7 @@ struct display_timings *of_get_display_timings(const struct device_node *np) + goto timingfail; + } + +- if (native_mode == entry) ++ if (native_mode == child) + disp->native_mode = disp->num_timings; + + disp->timings[disp->num_timings] = dt; +-- +2.51.0 + diff --git a/queue-6.6/fs-add-linux-init_task.h-for-init_fs.patch b/queue-6.6/fs-add-linux-init_task.h-for-init_fs.patch new file mode 100644 index 0000000000..94b56afacc --- /dev/null +++ b/queue-6.6/fs-add-linux-init_task.h-for-init_fs.patch @@ -0,0 +1,40 @@ +From e69b2d2af729f6b8105efe4bcbe7373998466884 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 11:58:56 +0000 +Subject: fs: add for 'init_fs' + +From: Ben Dooks + +[ Upstream commit 589cff4975afe1a4eaaa1d961652f50b1628d78d ] + +The init_fs symbol is defined in but was +not included in fs/fs_struct.c so fix by adding the include. + +Fixes the following sparse warning: +fs/fs_struct.c:150:18: warning: symbol 'init_fs' was not declared. Should it be static? + +Fixes: 3e93cd671813e ("Take fs_struct handling to new file") +Signed-off-by: Ben Dooks +Link: https://patch.msgid.link/20260108115856.238027-1-ben.dooks@codethink.co.uk +Reviewed-by: Jan Kara +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/fs_struct.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/fs_struct.c b/fs/fs_struct.c +index 64c2d0814ed68..100bd3474476b 100644 +--- a/fs/fs_struct.c ++++ b/fs/fs_struct.c +@@ -6,6 +6,7 @@ + #include + #include + #include ++#include + #include "internal.h" + + /* +-- +2.51.0 + diff --git a/queue-6.6/fs-nfs-fix-readdir-slow-start-regression.patch b/queue-6.6/fs-nfs-fix-readdir-slow-start-regression.patch new file mode 100644 index 0000000000..433ac433db --- /dev/null +++ b/queue-6.6/fs-nfs-fix-readdir-slow-start-regression.patch @@ -0,0 +1,54 @@ +From e4c360e0d20a446888ebfdad1ff0c99c6c84c94c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 27 Dec 2025 12:46:29 +0200 +Subject: fs/nfs: Fix readdir slow-start regression + +From: Sagi Grimberg + +[ Upstream commit 42e7c876b182da65723700f6bc507a8aecb10d3b ] + +Commit 580f236737d1 ("NFS: Adjust the amount of readahead +performed by NFS readdir") reduces the amount of readahead names +caching done by the client. + +The downside of this approach is READDIR now may suffer from +a slow-start issue, where initially it will fetch names that fit +in a single page, then in 2, 4, 8 until the maximum supported +transfer size (usually 1M). + +This patch tries to take a balanced approach between mitigating +the slow-start issue still maintaining some efficiency gains. + +Fixes: 580f236737d1 ("NFS: Adjust the amount of readahead performed by NFS readdir") +Signed-off-by: Sagi Grimberg +Signed-off-by: Anna Schumaker +Signed-off-by: Sasha Levin +--- + fs/nfs/dir.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c +index 32e922a20d0d4..46f53f40b741a 100644 +--- a/fs/nfs/dir.c ++++ b/fs/nfs/dir.c +@@ -70,7 +70,7 @@ const struct address_space_operations nfs_dir_aops = { + .free_folio = nfs_readdir_clear_array, + }; + +-#define NFS_INIT_DTSIZE PAGE_SIZE ++#define NFS_INIT_DTSIZE SZ_64K + + static struct nfs_open_dir_context * + alloc_nfs_open_dir_context(struct inode *dir) +@@ -81,7 +81,7 @@ alloc_nfs_open_dir_context(struct inode *dir) + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL_ACCOUNT); + if (ctx != NULL) { + ctx->attr_gencount = nfsi->attr_gencount; +- ctx->dtsize = NFS_INIT_DTSIZE; ++ ctx->dtsize = min(NFS_SERVER(dir)->dtsize, NFS_INIT_DTSIZE); + spin_lock(&dir->i_lock); + if (list_empty(&nfsi->open_files) && + (nfsi->cache_validity & NFS_INO_DATA_INVAL_DEFER)) +-- +2.51.0 + diff --git a/queue-6.6/gfs2-add-metapath_dibh-helper.patch b/queue-6.6/gfs2-add-metapath_dibh-helper.patch new file mode 100644 index 0000000000..844e08ba47 --- /dev/null +++ b/queue-6.6/gfs2-add-metapath_dibh-helper.patch @@ -0,0 +1,48 @@ +From f9a17afb84920bbf7eae167873a56e4d2f88c4fe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Oct 2023 01:32:15 +0200 +Subject: gfs2: Add metapath_dibh helper + +From: Andreas Gruenbacher + +[ Upstream commit 92099f0c92270c8c7a79e6bc6e0312ad248ea331 ] + +Add a metapath_dibh() helper for extracting the inode's buffer head from +a metapath. + +Signed-off-by: Andreas Gruenbacher +Stable-dep-of: faddeb848305 ("gfs2: Fix use-after-free in iomap inline data write path") +Signed-off-by: Sasha Levin +--- + fs/gfs2/bmap.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c +index 7ed276a8f599d..b837a2c2dd571 100644 +--- a/fs/gfs2/bmap.c ++++ b/fs/gfs2/bmap.c +@@ -317,6 +317,12 @@ static void gfs2_metapath_ra(struct gfs2_glock *gl, __be64 *start, __be64 *end) + } + } + ++static inline struct buffer_head * ++metapath_dibh(struct metapath *mp) ++{ ++ return mp->mp_bh[0]; ++} ++ + static int __fillup_metapath(struct gfs2_inode *ip, struct metapath *mp, + unsigned int x, unsigned int h) + { +@@ -660,7 +666,7 @@ static int __gfs2_iomap_alloc(struct inode *inode, struct iomap *iomap, + { + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); +- struct buffer_head *dibh = mp->mp_bh[0]; ++ struct buffer_head *dibh = metapath_dibh(mp); + u64 bn; + unsigned n, i, blks, alloced = 0, iblks = 0, branch_start = 0; + size_t dblks = iomap->length >> inode->i_blkbits; +-- +2.51.0 + diff --git a/queue-6.6/gfs2-fix-slab-use-after-free-in-qd_put.patch b/queue-6.6/gfs2-fix-slab-use-after-free-in-qd_put.patch new file mode 100644 index 0000000000..9cb441c84d --- /dev/null +++ b/queue-6.6/gfs2-fix-slab-use-after-free-in-qd_put.patch @@ -0,0 +1,45 @@ +From 3d5a984e1acdf1adffa29a8c005e4a3bf2cc9f7a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 14 Dec 2025 16:47:34 +0000 +Subject: gfs2: Fix slab-use-after-free in qd_put + +From: Andreas Gruenbacher + +[ Upstream commit 22150a7d401d9e9169b9b68e05bed95f7f49bf69 ] + +Commit a475c5dd16e5 ("gfs2: Free quota data objects synchronously") +started freeing quota data objects during filesystem shutdown instead of +putting them back onto the LRU list, but it failed to remove these +objects from the LRU list, causing LRU list corruption. This caused +use-after-free when the shrinker (gfs2_qd_shrink_scan) tried to access +already-freed objects on the LRU list. + +Fix this by removing qd objects from the LRU list before freeing them in +qd_put(). + +Initial fix from Deepanshu Kartikey . + +Fixes: a475c5dd16e5 ("gfs2: Free quota data objects synchronously") +Reported-by: syzbot+046b605f01802054bff0@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=046b605f01802054bff0 +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Sasha Levin +--- + fs/gfs2/quota.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c +index c537e1d02cf3a..5b06240a67367 100644 +--- a/fs/gfs2/quota.c ++++ b/fs/gfs2/quota.c +@@ -323,6 +323,7 @@ static void qd_put(struct gfs2_quota_data *qd) + lockref_mark_dead(&qd->qd_lockref); + spin_unlock(&qd->qd_lockref.lock); + ++ list_lru_del_obj(&gfs2_qd_lru, &qd->qd_lru); + gfs2_qd_dispose(qd); + return; + } +-- +2.51.0 + diff --git a/queue-6.6/gfs2-fix-use-after-free-in-iomap-inline-data-write-p.patch b/queue-6.6/gfs2-fix-use-after-free-in-iomap-inline-data-write-p.patch new file mode 100644 index 0000000000..887ce423c9 --- /dev/null +++ b/queue-6.6/gfs2-fix-use-after-free-in-iomap-inline-data-write-p.patch @@ -0,0 +1,84 @@ +From 3a2f88833b951d8748df7618de6e836b91e017bc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 14:51:34 +0530 +Subject: gfs2: Fix use-after-free in iomap inline data write path + +From: Deepanshu Kartikey + +[ Upstream commit faddeb848305e79db89ee0479bb0e33380656321 ] + +The inline data buffer head (dibh) is being released prematurely in +gfs2_iomap_begin() via release_metapath() while iomap->inline_data +still points to dibh->b_data. This causes a use-after-free when +iomap_write_end_inline() later attempts to write to the inline data +area. + +The bug sequence: +1. gfs2_iomap_begin() calls gfs2_meta_inode_buffer() to read inode + metadata into dibh +2. Sets iomap->inline_data = dibh->b_data + sizeof(struct gfs2_dinode) +3. Calls release_metapath() which calls brelse(dibh), dropping refcount + to 0 +4. kswapd reclaims the page (~39ms later in the syzbot report) +5. iomap_write_end_inline() tries to memcpy() to iomap->inline_data +6. KASAN detects use-after-free write to freed memory + +Fix by storing dibh in iomap->private and incrementing its refcount +with get_bh() in gfs2_iomap_begin(). The buffer is then properly +released in gfs2_iomap_end() after the inline write completes, +ensuring the page stays alive for the entire iomap operation. + +Note: A C reproducer is not available for this issue. The fix is based +on analysis of the KASAN report and code review showing the buffer head +is freed before use. + +[agruenba: Take buffer head reference in gfs2_iomap_begin() to avoid +leaks in gfs2_iomap_get() and gfs2_iomap_alloc().] + +Reported-by: syzbot+ea1cd4aa4d1e98458a55@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=ea1cd4aa4d1e98458a55 +Fixes: d0a22a4b03b8 ("gfs2: Fix iomap write page reclaim deadlock") +Signed-off-by: Deepanshu Kartikey +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Sasha Levin +--- + fs/gfs2/bmap.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c +index b837a2c2dd571..bc0f7023adcf3 100644 +--- a/fs/gfs2/bmap.c ++++ b/fs/gfs2/bmap.c +@@ -1126,10 +1126,18 @@ static int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length, + goto out_unlock; + break; + default: +- goto out_unlock; ++ goto out; + } + + ret = gfs2_iomap_begin_write(inode, pos, length, flags, iomap, &mp); ++ if (ret) ++ goto out_unlock; ++ ++out: ++ if (iomap->type == IOMAP_INLINE) { ++ iomap->private = metapath_dibh(&mp); ++ get_bh(iomap->private); ++ } + + out_unlock: + release_metapath(&mp); +@@ -1143,6 +1151,9 @@ static int gfs2_iomap_end(struct inode *inode, loff_t pos, loff_t length, + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); + ++ if (iomap->private) ++ brelse(iomap->private); ++ + switch (flags & (IOMAP_WRITE | IOMAP_ZERO)) { + case IOMAP_WRITE: + if (flags & IOMAP_DIRECT) +-- +2.51.0 + diff --git a/queue-6.6/gfs2-retries-missing-in-gfs2_-rename-exchange.patch b/queue-6.6/gfs2-retries-missing-in-gfs2_-rename-exchange.patch new file mode 100644 index 0000000000..ff3d2f1441 --- /dev/null +++ b/queue-6.6/gfs2-retries-missing-in-gfs2_-rename-exchange.patch @@ -0,0 +1,178 @@ +From 05de50a353417ab5db1b94fc86aee0bd59d317ab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 22:59:12 +0000 +Subject: gfs2: Retries missing in gfs2_{rename,exchange} + +From: Andreas Gruenbacher + +[ Upstream commit 11d763f0b0afc2cf5f92f4adae5dbbbbef712f8f ] + +Fix a bug in gfs2's asynchronous glock handling for rename and exchange +operations. The original async implementation from commit ad26967b9afa +("gfs2: Use async glocks for rename") mentioned that retries were needed +but never implemented them, causing operations to fail with -ESTALE +instead of retrying on timeout. + +Also makes the waiting interruptible. + +In addition, the timeouts used were too high for situations in which +timing out is a rare but expected scenario. Switch to shorter timeouts +with randomization and exponentional backoff. + +Fixes: ad26967b9afa ("gfs2: Use async glocks for rename") +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Sasha Levin +--- + fs/gfs2/glock.c | 36 +++++++++++++++++++++++++++--------- + fs/gfs2/glock.h | 3 ++- + fs/gfs2/inode.c | 18 ++++++++++++++---- + 3 files changed, 43 insertions(+), 14 deletions(-) + +diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c +index c4bc86c3535ba..9265262807f09 100644 +--- a/fs/gfs2/glock.c ++++ b/fs/gfs2/glock.c +@@ -1396,31 +1396,45 @@ static int glocks_pending(unsigned int num_gh, struct gfs2_holder *ghs) + * gfs2_glock_async_wait - wait on multiple asynchronous glock acquisitions + * @num_gh: the number of holders in the array + * @ghs: the glock holder array ++ * @retries: number of retries attempted so far + * + * Returns: 0 on success, meaning all glocks have been granted and are held. + * -ESTALE if the request timed out, meaning all glocks were released, + * and the caller should retry the operation. + */ + +-int gfs2_glock_async_wait(unsigned int num_gh, struct gfs2_holder *ghs) ++int gfs2_glock_async_wait(unsigned int num_gh, struct gfs2_holder *ghs, ++ unsigned int retries) + { + struct gfs2_sbd *sdp = ghs[0].gh_gl->gl_name.ln_sbd; +- int i, ret = 0, timeout = 0; + unsigned long start_time = jiffies; ++ int i, ret = 0; ++ long timeout; + + might_sleep(); +- /* +- * Total up the (minimum hold time * 2) of all glocks and use that to +- * determine the max amount of time we should wait. +- */ +- for (i = 0; i < num_gh; i++) +- timeout += ghs[i].gh_gl->gl_hold_time << 1; + +- if (!wait_event_timeout(sdp->sd_async_glock_wait, ++ timeout = GL_GLOCK_MIN_HOLD; ++ if (retries) { ++ unsigned int max_shift; ++ long incr; ++ ++ /* Add a random delay and increase the timeout exponentially. */ ++ max_shift = BITS_PER_LONG - 2 - __fls(GL_GLOCK_HOLD_INCR); ++ incr = min(GL_GLOCK_HOLD_INCR << min(retries - 1, max_shift), ++ 10 * HZ - GL_GLOCK_MIN_HOLD); ++ schedule_timeout_interruptible(get_random_long() % (incr / 3)); ++ if (signal_pending(current)) ++ goto interrupted; ++ timeout += (incr / 3) + get_random_long() % (incr / 3); ++ } ++ ++ if (!wait_event_interruptible_timeout(sdp->sd_async_glock_wait, + !glocks_pending(num_gh, ghs), timeout)) { + ret = -ESTALE; /* request timed out. */ + goto out; + } ++ if (signal_pending(current)) ++ goto interrupted; + + for (i = 0; i < num_gh; i++) { + struct gfs2_holder *gh = &ghs[i]; +@@ -1444,6 +1458,10 @@ int gfs2_glock_async_wait(unsigned int num_gh, struct gfs2_holder *ghs) + } + } + return ret; ++ ++interrupted: ++ ret = -EINTR; ++ goto out; + } + + /** +diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h +index aae9fabbb76cc..e86dccdd61332 100644 +--- a/fs/gfs2/glock.h ++++ b/fs/gfs2/glock.h +@@ -204,7 +204,8 @@ int gfs2_glock_poll(struct gfs2_holder *gh); + int gfs2_instantiate(struct gfs2_holder *gh); + int gfs2_glock_holder_ready(struct gfs2_holder *gh); + int gfs2_glock_wait(struct gfs2_holder *gh); +-int gfs2_glock_async_wait(unsigned int num_gh, struct gfs2_holder *ghs); ++int gfs2_glock_async_wait(unsigned int num_gh, struct gfs2_holder *ghs, ++ unsigned int retries); + void gfs2_glock_dq(struct gfs2_holder *gh); + void gfs2_glock_dq_wait(struct gfs2_holder *gh); + void gfs2_glock_dq_uninit(struct gfs2_holder *gh); +diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c +index 1cb5ce63fbf69..b65444bc1b5f2 100644 +--- a/fs/gfs2/inode.c ++++ b/fs/gfs2/inode.c +@@ -1408,7 +1408,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, + unsigned int num_gh; + int dir_rename = 0; + struct gfs2_diradd da = { .nr_blocks = 0, .save_loc = 0, }; +- unsigned int x; ++ unsigned int retries = 0, x; + int error; + + gfs2_holder_mark_uninitialized(&r_gh); +@@ -1458,12 +1458,17 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, + num_gh++; + } + ++again: + for (x = 0; x < num_gh; x++) { + error = gfs2_glock_nq(ghs + x); + if (error) + goto out_gunlock; + } +- error = gfs2_glock_async_wait(num_gh, ghs); ++ error = gfs2_glock_async_wait(num_gh, ghs, retries); ++ if (error == -ESTALE) { ++ retries++; ++ goto again; ++ } + if (error) + goto out_gunlock; + +@@ -1652,7 +1657,7 @@ static int gfs2_exchange(struct inode *odir, struct dentry *odentry, + struct gfs2_sbd *sdp = GFS2_SB(odir); + struct gfs2_holder ghs[4], r_gh; + unsigned int num_gh; +- unsigned int x; ++ unsigned int retries = 0, x; + umode_t old_mode = oip->i_inode.i_mode; + umode_t new_mode = nip->i_inode.i_mode; + int error; +@@ -1696,13 +1701,18 @@ static int gfs2_exchange(struct inode *odir, struct dentry *odentry, + gfs2_holder_init(nip->i_gl, LM_ST_EXCLUSIVE, GL_ASYNC, ghs + num_gh); + num_gh++; + ++again: + for (x = 0; x < num_gh; x++) { + error = gfs2_glock_nq(ghs + x); + if (error) + goto out_gunlock; + } + +- error = gfs2_glock_async_wait(num_gh, ghs); ++ error = gfs2_glock_async_wait(num_gh, ghs, retries); ++ if (error == -ESTALE) { ++ retries++; ++ goto again; ++ } + if (error) + goto out_gunlock; + +-- +2.51.0 + diff --git a/queue-6.6/hfsplus-return-error-when-node-already-exists-in-hfs.patch b/queue-6.6/hfsplus-return-error-when-node-already-exists-in-hfs.patch new file mode 100644 index 0000000000..e3c811b041 --- /dev/null +++ b/queue-6.6/hfsplus-return-error-when-node-already-exists-in-hfs.patch @@ -0,0 +1,58 @@ +From fb5b230a774e385471d754c967587918a7cfe008 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Dec 2025 02:19:38 +0530 +Subject: hfsplus: return error when node already exists in hfs_bnode_create + +From: Shardul Bankar + +[ Upstream commit d8a73cc46c8462a969a7516131feb3096f4c49d3 ] + +When hfs_bnode_create() finds that a node is already hashed (which should +not happen in normal operation), it currently returns the existing node +without incrementing its reference count. This causes a reference count +inconsistency that leads to a kernel panic when the node is later freed +in hfs_bnode_put(): + + kernel BUG at fs/hfsplus/bnode.c:676! + BUG_ON(!atomic_read(&node->refcnt)) + +This scenario can occur when hfs_bmap_alloc() attempts to allocate a node +that is already in use (e.g., when node 0's bitmap bit is incorrectly +unset), or due to filesystem corruption. + +Returning an existing node from a create path is not normal operation. + +Fix this by returning ERR_PTR(-EEXIST) instead of the node when it's +already hashed. This properly signals the error condition to callers, +which already check for IS_ERR() return values. + +Reported-by: syzbot+1c8ff72d0cd8a50dfeaa@syzkaller.appspotmail.com +Link: https://syzkaller.appspot.com/bug?extid=1c8ff72d0cd8a50dfeaa +Link: https://lore.kernel.org/all/784415834694f39902088fa8946850fc1779a318.camel@ibm.com/ +Fixes: 634725a92938 ("[PATCH] hfs: cleanup HFS+ prints") +Signed-off-by: Shardul Bankar +Reviewed-by: Viacheslav Dubeyko +Signed-off-by: Viacheslav Dubeyko +Link: https://lore.kernel.org/r/20251229204938.1907089-1-shardul.b@mpiricsoftware.com +Signed-off-by: Viacheslav Dubeyko +Signed-off-by: Sasha Levin +--- + fs/hfsplus/bnode.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/hfsplus/bnode.c b/fs/hfsplus/bnode.c +index c0089849be50e..fb437598e2625 100644 +--- a/fs/hfsplus/bnode.c ++++ b/fs/hfsplus/bnode.c +@@ -629,7 +629,7 @@ struct hfs_bnode *hfs_bnode_create(struct hfs_btree *tree, u32 num) + if (node) { + pr_crit("new node %u already hashed?\n", num); + WARN_ON(1); +- return node; ++ return ERR_PTR(-EEXIST); + } + node = __hfs_bnode_create(tree, num); + if (!node) +-- +2.51.0 + diff --git a/queue-6.6/hid-playstation-add-missing-check-for-input_ff_creat.patch b/queue-6.6/hid-playstation-add-missing-check-for-input_ff_creat.patch new file mode 100644 index 0000000000..8a50443db5 --- /dev/null +++ b/queue-6.6/hid-playstation-add-missing-check-for-input_ff_creat.patch @@ -0,0 +1,41 @@ +From 4436693dd3fa109938628d081569a1014e571b76 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 17 Nov 2025 16:28:08 +0800 +Subject: HID: playstation: Add missing check for input_ff_create_memless + +From: Haotian Zhang + +[ Upstream commit e6807641ac94e832988655a1c0e60ccc806b76dc ] + +The ps_gamepad_create() function calls input_ff_create_memless() +without verifying its return value, which can lead to incorrect +behavior or potential crashes when FF effects are triggered. + +Add a check for the return value of input_ff_create_memless(). + +Fixes: 51151098d7ab ("HID: playstation: add DualSense classic rumble support.") +Signed-off-by: Haotian Zhang +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-playstation.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c +index 32f65c45fdc8a..199f76988bae8 100644 +--- a/drivers/hid/hid-playstation.c ++++ b/drivers/hid/hid-playstation.c +@@ -732,7 +732,9 @@ static struct input_dev *ps_gamepad_create(struct hid_device *hdev, + #if IS_ENABLED(CONFIG_PLAYSTATION_FF) + if (play_effect) { + input_set_capability(gamepad, EV_FF, FF_RUMBLE); +- input_ff_create_memless(gamepad, NULL, play_effect); ++ ret = input_ff_create_memless(gamepad, NULL, play_effect); ++ if (ret) ++ return ERR_PTR(ret); + } + #endif + +-- +2.51.0 + diff --git a/queue-6.6/hrtimer-fix-trace-oddity.patch b/queue-6.6/hrtimer-fix-trace-oddity.patch new file mode 100644 index 0000000000..c667080827 --- /dev/null +++ b/queue-6.6/hrtimer-fix-trace-oddity.patch @@ -0,0 +1,43 @@ +From 14888473f5105a66c4d34c169c1551509dc5e3bd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 11:38:34 +0100 +Subject: hrtimer: Fix trace oddity + +From: Thomas Gleixner + +[ Upstream commit 5d6446f409da00e5a389125ddb5ce09f5bc404c9 ] + +It turns out that __run_hrtimer() will trace like: + + -0 [032] d.h2. 20705.474563: hrtimer_cancel: hrtimer=0xff2db8f77f8226e8 + -0 [032] d.h1. 20705.474563: hrtimer_expire_entry: hrtimer=0xff2db8f77f8226e8 now=20699452001850 function=tick_nohz_handler/0x0 + +Which is a bit nonsensical, the timer doesn't get canceled on +expiration. The cause is the use of the incorrect debug helper. + +Fixes: c6a2a1770245 ("hrtimer: Add tracepoint for hrtimers") +Reported-by: Peter Zijlstra (Intel) +Signed-off-by: Thomas Gleixner +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260121143208.219595606@infradead.org +Signed-off-by: Sasha Levin +--- + kernel/time/hrtimer.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c +index 0320f49bd1f4a..03f488f93cddf 100644 +--- a/kernel/time/hrtimer.c ++++ b/kernel/time/hrtimer.c +@@ -1715,7 +1715,7 @@ static void __run_hrtimer(struct hrtimer_cpu_base *cpu_base, + + lockdep_assert_held(&cpu_base->lock); + +- debug_deactivate(timer); ++ debug_hrtimer_deactivate(timer); + base->running = timer; + + /* +-- +2.51.0 + diff --git a/queue-6.6/i3c-dw-initialize-spinlock-to-avoid-upsetting-lockde.patch b/queue-6.6/i3c-dw-initialize-spinlock-to-avoid-upsetting-lockde.patch new file mode 100644 index 0000000000..d4e4432f7f --- /dev/null +++ b/queue-6.6/i3c-dw-initialize-spinlock-to-avoid-upsetting-lockde.patch @@ -0,0 +1,39 @@ +From 645a7776e6ac70703b45e9af26df7b61b739a0b3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 15:29:42 +0100 +Subject: i3c: dw: Initialize spinlock to avoid upsetting lockdep + +From: Fredrik Markstrom + +[ Upstream commit b58eaa4761ab02fc38c39d674a6bcdd55e00f388 ] + +The devs_lock spinlock introduced when adding support for ibi:s was +never initialized. + +Fixes: e389b1d72a624 ("i3c: dw: Add support for in-band interrupts") +Suggested-by: Jani Nurminen +Signed-off-by: Fredrik Markstrom +Reviewed-by: Ivar Holmqvist +Link: https://patch.msgid.link/20260116-i3c_dw_initialize_spinlock-v3-1-cf707b6ed75f@est.tech +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master/dw-i3c-master.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c +index 030127525672e..cee2805fccd0f 100644 +--- a/drivers/i3c/master/dw-i3c-master.c ++++ b/drivers/i3c/master/dw-i3c-master.c +@@ -1483,6 +1483,8 @@ int dw_i3c_common_probe(struct dw_i3c_master *master, + spin_lock_init(&master->xferqueue.lock); + INIT_LIST_HEAD(&master->xferqueue.list); + ++ spin_lock_init(&master->devs_lock); ++ + writel(INTR_ALL, master->regs + INTR_STATUS); + irq = platform_get_irq(pdev, 0); + ret = devm_request_irq(&pdev->dev, irq, +-- +2.51.0 + diff --git a/queue-6.6/i3c-master-update-hot-join-flag-only-on-success.patch b/queue-6.6/i3c-master-update-hot-join-flag-only-on-success.patch new file mode 100644 index 0000000000..93a58be4b5 --- /dev/null +++ b/queue-6.6/i3c-master-update-hot-join-flag-only-on-success.patch @@ -0,0 +1,39 @@ +From 1a3ff2d17f63d47a756ef94cca9c252895cc268d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Jan 2026 09:26:44 +0200 +Subject: i3c: master: Update hot-join flag only on success + +From: Adrian Hunter + +[ Upstream commit f0775157b9f9a28ae3eabc8d05b0bc52e8056c80 ] + +To prevent inconsistent state when an error occurs, ensure the hot-join +flag is updated only when enabling or disabling hot-join succeeds. + +Fixes: 317bacf960a48 ("i3c: master: add enable(disable) hot join in sys entry") +Signed-off-by: Adrian Hunter +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260113072702.16268-4-adrian.hunter@intel.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c +index 0c3434e357e26..f74ef65d257d7 100644 +--- a/drivers/i3c/master.c ++++ b/drivers/i3c/master.c +@@ -586,7 +586,8 @@ static int i3c_set_hotjoin(struct i3c_master_controller *master, bool enable) + else + ret = master->ops->disable_hotjoin(master); + +- master->hotjoin = enable; ++ if (!ret) ++ master->hotjoin = enable; + + i3c_bus_normaluse_unlock(&master->bus); + +-- +2.51.0 + diff --git a/queue-6.6/i3c-move-device-name-assignment-after-i3c_bus_init.patch b/queue-6.6/i3c-move-device-name-assignment-after-i3c_bus_init.patch new file mode 100644 index 0000000000..fc97a7fd54 --- /dev/null +++ b/queue-6.6/i3c-move-device-name-assignment-after-i3c_bus_init.patch @@ -0,0 +1,46 @@ +From 2ff971b6e62b1cdf6fd8ceae04f5f7fffabd8c69 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 14:07:22 +0800 +Subject: i3c: Move device name assignment after i3c_bus_init + +From: Billy Tsai + +[ Upstream commit 3502cea99c7ceb331458cbd34ef6792c83144687 ] + +Move device name initialization to occur after i3c_bus_init() +so that i3cbus->id is guaranteed to be assigned before it is used. + +Fixes: 9d4f219807d5 ("i3c: fix refcount inconsistency in i3c_master_register") +Signed-off-by: Billy Tsai +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260112-upstream_i3c_fix-v1-1-cbbf2cb71809@aspeedtech.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c +index 060f70e4d52d7..0c3434e357e26 100644 +--- a/drivers/i3c/master.c ++++ b/drivers/i3c/master.c +@@ -2769,7 +2769,6 @@ int i3c_master_register(struct i3c_master_controller *master, + INIT_LIST_HEAD(&master->boardinfo.i3c); + + device_initialize(&master->dev); +- dev_set_name(&master->dev, "i3c-%d", i3cbus->id); + + master->dev.dma_mask = parent->dma_mask; + master->dev.coherent_dma_mask = parent->coherent_dma_mask; +@@ -2779,6 +2778,8 @@ int i3c_master_register(struct i3c_master_controller *master, + if (ret) + goto err_put_dev; + ++ dev_set_name(&master->dev, "i3c-%d", i3cbus->id); ++ + ret = of_populate_i3c_bus(master); + if (ret) + goto err_put_dev; +-- +2.51.0 + diff --git a/queue-6.6/ib-cache-update-gid-cache-on-client-reregister-event.patch b/queue-6.6/ib-cache-update-gid-cache-on-client-reregister-event.patch new file mode 100644 index 0000000000..2dcc9717db --- /dev/null +++ b/queue-6.6/ib-cache-update-gid-cache-on-client-reregister-event.patch @@ -0,0 +1,54 @@ +From 9b654fba17b6377b1960e2ea4fb602e501a6acde Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 31 Dec 2025 14:07:45 +0100 +Subject: IB/cache: update gid cache on client reregister event +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Etienne AUJAMES + +[ Upstream commit ddd6c8c873e912cb1ead79def54de5e24ff71c80 ] + +Some HCAs (e.g: ConnectX4) do not trigger a IB_EVENT_GID_CHANGE on +subnet prefix update from SM (PortInfo). + +Since the commit d58c23c92548 ("IB/core: Only update PKEY and GID caches +on respective events"), the GID cache is updated exclusively on +IB_EVENT_GID_CHANGE. If this event is not emitted, the subnet prefix in the +IPoIB interface’s hardware address remains set to its default value +(0xfe80000000000000). + +Then rdma_bind_addr() failed because it relies on hardware address to +find the port GID (subnet_prefix + port GUID). + +This patch fixes this issue by updating the GID cache on +IB_EVENT_CLIENT_REREGISTER event (emitted on PortInfo::ClientReregister=1). + +Fixes: d58c23c92548 ("IB/core: Only update PKEY and GID caches on respective events") +Signed-off-by: Etienne AUJAMES +Link: https://patch.msgid.link/aVUfsO58QIDn5bGX@eaujamesFR0130 +Reviewed-by: Parav Pandit +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/cache.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c +index 77c0b89259911..7ed9915f7893e 100644 +--- a/drivers/infiniband/core/cache.c ++++ b/drivers/infiniband/core/cache.c +@@ -1566,7 +1566,8 @@ static void ib_cache_event_task(struct work_struct *_work) + * the cache. + */ + ret = ib_cache_update(work->event.device, work->event.element.port_num, +- work->event.event == IB_EVENT_GID_CHANGE, ++ work->event.event == IB_EVENT_GID_CHANGE || ++ work->event.event == IB_EVENT_CLIENT_REREGISTER, + work->event.event == IB_EVENT_PKEY_CHANGE, + work->enforce_security); + +-- +2.51.0 + diff --git a/queue-6.6/iio-pressure-mprls0025pa-fix-scan_type-struct.patch b/queue-6.6/iio-pressure-mprls0025pa-fix-scan_type-struct.patch new file mode 100644 index 0000000000..b6efdf4ea7 --- /dev/null +++ b/queue-6.6/iio-pressure-mprls0025pa-fix-scan_type-struct.patch @@ -0,0 +1,47 @@ +From 0964f8e7b1b1a7950d40178a4dbe4376f088c349 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 18:55:33 +0200 +Subject: iio: pressure: mprls0025pa: fix scan_type struct + +From: Petre Rodan + +[ Upstream commit 8a228e036926f7e57421d750c3724e63f11b808a ] + +Fix the scan_type sign and realbits assignment. + +The pressure is a 24bit unsigned int between output_min and output_max. + + transfer function A: 10% to 90% of 2^24 + transfer function B: 2.5% to 22.5% of 2^24 + transfer function C: 20% to 80% of 2^24 +[MPR_FUNCTION_A] = { .output_min = 1677722, .output_max = 15099494 } +[MPR_FUNCTION_B] = { .output_min = 419430, .output_max = 3774874 } +[MPR_FUNCTION_C] = { .output_min = 3355443, .output_max = 13421773 } + +Fixes: 713337d9143e ("iio: pressure: Honeywell mprls0025pa pressure sensor") +Signed-off-by: Petre Rodan +Reviewed-by: Andy Shevchenko +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/pressure/mprls0025pa.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/iio/pressure/mprls0025pa.c b/drivers/iio/pressure/mprls0025pa.c +index 829c472812e49..566c21bf3ea0d 100644 +--- a/drivers/iio/pressure/mprls0025pa.c ++++ b/drivers/iio/pressure/mprls0025pa.c +@@ -132,8 +132,8 @@ static const struct iio_chan_spec mpr_channels[] = { + BIT(IIO_CHAN_INFO_OFFSET), + .scan_index = 0, + .scan_type = { +- .sign = 's', +- .realbits = 32, ++ .sign = 'u', ++ .realbits = 24, + .storagebits = 32, + .endianness = IIO_CPU, + }, +-- +2.51.0 + diff --git a/queue-6.6/iio-sca3000-fix-a-resource-leak-in-sca3000_probe.patch b/queue-6.6/iio-sca3000-fix-a-resource-leak-in-sca3000_probe.patch new file mode 100644 index 0000000000..83a09e5697 --- /dev/null +++ b/queue-6.6/iio-sca3000-fix-a-resource-leak-in-sca3000_probe.patch @@ -0,0 +1,42 @@ +From 135a8cf2ad27ca0cefea7c239ebf64851f4989a9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 22:49:49 -0800 +Subject: iio: sca3000: Fix a resource leak in sca3000_probe() + +From: Harshit Mogalapalli + +[ Upstream commit 62b44ebc1f2c71db3ca2d4737c52e433f6f03038 ] + +spi->irq from request_threaded_irq() not released when +iio_device_register() fails. Add an return value check and jump to a +common error handler when iio_device_register() fails. + +Fixes: 9a4936dc89a3 ("staging:iio:accel:sca3000 Tidy up probe order to avoid a race.") +Signed-off-by: Harshit Mogalapalli +Reviewed-by: Andy Shevchenko +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/accel/sca3000.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/iio/accel/sca3000.c b/drivers/iio/accel/sca3000.c +index 87c54e41f6ccd..2b87f7f5508bb 100644 +--- a/drivers/iio/accel/sca3000.c ++++ b/drivers/iio/accel/sca3000.c +@@ -1496,7 +1496,11 @@ static int sca3000_probe(struct spi_device *spi) + if (ret) + goto error_free_irq; + +- return iio_device_register(indio_dev); ++ ret = iio_device_register(indio_dev); ++ if (ret) ++ goto error_free_irq; ++ ++ return 0; + + error_free_irq: + if (spi->irq) +-- +2.51.0 + diff --git a/queue-6.6/inet-raw-sockets-using-ipproto_raw-must-drop-incomin.patch b/queue-6.6/inet-raw-sockets-using-ipproto_raw-must-drop-incomin.patch new file mode 100644 index 0000000000..ec5cefe6df --- /dev/null +++ b/queue-6.6/inet-raw-sockets-using-ipproto_raw-must-drop-incomin.patch @@ -0,0 +1,94 @@ +From 07e136cd11fd4e2305f0ecd6b0ab72484639f023 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 19:25:09 +0000 +Subject: inet: RAW sockets using IPPROTO_RAW MUST drop incoming ICMP + +From: Eric Dumazet + +[ Upstream commit c89477ad79446867394360b29bb801010fc3ff22 ] + +Yizhou Zhao reported that simply having one RAW socket on protocol +IPPROTO_RAW (255) was dangerous. + + socket(AF_INET, SOCK_RAW, 255); + +A malicious incoming ICMP packet can set the protocol field to 255 +and match this socket, leading to FNHE cache changes. + +inner = IP(src="192.168.2.1", dst="8.8.8.8", proto=255)/Raw("TEST") +pkt = IP(src="192.168.1.1", dst="192.168.2.1")/ICMP(type=3, code=4, nexthopmtu=576)/inner + +"man 7 raw" states: + + A protocol of IPPROTO_RAW implies enabled IP_HDRINCL and is able + to send any IP protocol that is specified in the passed header. + Receiving of all IP protocols via IPPROTO_RAW is not possible + using raw sockets. + +Make sure we drop these malicious packets. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: Yizhou Zhao +Link: https://lore.kernel.org/netdev/20251109134600.292125-1-zhaoyz24@mails.tsinghua.edu.cn/ +Signed-off-by: Eric Dumazet +Reviewed-by: David Ahern +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260203192509.682208-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/icmp.c | 14 ++++++++++---- + net/ipv6/icmp.c | 6 ++++++ + 2 files changed, 16 insertions(+), 4 deletions(-) + +diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c +index b17549c4e5de8..f3cdfc09d7f06 100644 +--- a/net/ipv4/icmp.c ++++ b/net/ipv4/icmp.c +@@ -840,16 +840,22 @@ static void icmp_socket_deliver(struct sk_buff *skb, u32 info) + /* Checkin full IP header plus 8 bytes of protocol to + * avoid additional coding at protocol handlers. + */ +- if (!pskb_may_pull(skb, iph->ihl * 4 + 8)) { +- __ICMP_INC_STATS(dev_net_rcu(skb->dev), ICMP_MIB_INERRORS); +- return; +- } ++ if (!pskb_may_pull(skb, iph->ihl * 4 + 8)) ++ goto out; ++ ++ /* IPPROTO_RAW sockets are not supposed to receive anything. */ ++ if (protocol == IPPROTO_RAW) ++ goto out; + + raw_icmp_error(skb, protocol, info); + + ipprot = rcu_dereference(inet_protos[protocol]); + if (ipprot && ipprot->err_handler) + ipprot->err_handler(skb, info); ++ return; ++ ++out: ++ __ICMP_INC_STATS(dev_net_rcu(skb->dev), ICMP_MIB_INERRORS); + } + + static bool icmp_tag_validation(int proto) +diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c +index c7e815b7ca087..e9e457b7d4eac 100644 +--- a/net/ipv6/icmp.c ++++ b/net/ipv6/icmp.c +@@ -869,6 +869,12 @@ enum skb_drop_reason icmpv6_notify(struct sk_buff *skb, u8 type, + if (reason != SKB_NOT_DROPPED_YET) + goto out; + ++ if (nexthdr == IPPROTO_RAW) { ++ /* Add a more specific reason later ? */ ++ reason = SKB_DROP_REASON_NOT_SPECIFIED; ++ goto out; ++ } ++ + /* BUGGG_FUTURE: we should try to parse exthdrs in this packet. + Without this we will not able f.e. to make source routed + pmtu discovery. +-- +2.51.0 + diff --git a/queue-6.6/io_uring-cancel-de-unionize-file-and-user_data-in-st.patch b/queue-6.6/io_uring-cancel-de-unionize-file-and-user_data-in-st.patch new file mode 100644 index 0000000000..a89ca1ccdc --- /dev/null +++ b/queue-6.6/io_uring-cancel-de-unionize-file-and-user_data-in-st.patch @@ -0,0 +1,45 @@ +From e7d72703987328ab44e017e9efa2a392916db922 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 14:16:27 -0700 +Subject: io_uring/cancel: de-unionize file and user_data in struct + io_cancel_data + +From: Jens Axboe + +[ Upstream commit 22dbb0987bd1e0ec3b1e4ad20756a98f99aa4a08 ] + +By having them share the same space in struct io_cancel_data, it ends up +disallowing IORING_ASYNC_CANCEL_FD|IORING_ASYNC_CANCEL_USERDATA from +working. Eg you cannot match on both a file and user_data for +cancelation purposes. This obviously isn't a common use case as nobody +has reported this, but it does result in -ENOENT potentially being +returned when trying to match on both, rather than actually doing what +the API says it would. + +Fixes: 4bf94615b888 ("io_uring: allow IORING_OP_ASYNC_CANCEL with 'fd' key") +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + io_uring/cancel.h | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/io_uring/cancel.h b/io_uring/cancel.h +index fc98622e6166e..7e6d0fca7db28 100644 +--- a/io_uring/cancel.h ++++ b/io_uring/cancel.h +@@ -4,10 +4,8 @@ + + struct io_cancel_data { + struct io_ring_ctx *ctx; +- union { +- u64 data; +- struct file *file; +- }; ++ u64 data; ++ struct file *file; + u8 opcode; + u32 flags; + int seq; +-- +2.51.0 + diff --git a/queue-6.6/io_uring-sync-validate-passed-in-offset.patch b/queue-6.6/io_uring-sync-validate-passed-in-offset.patch new file mode 100644 index 0000000000..e61fc465b6 --- /dev/null +++ b/queue-6.6/io_uring-sync-validate-passed-in-offset.patch @@ -0,0 +1,36 @@ +From e0c96da0fefd162cbf3f9637c7a0a6777ad9654f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 11:48:56 -0700 +Subject: io_uring/sync: validate passed in offset + +From: Jens Axboe + +[ Upstream commit 649dd18f559891bdafc5532d737c7dfb56060a6d ] + +Check if the passed in offset is negative once cast to sync->off. This +ensures that -EINVAL is returned for that case, like it would be for +sync_file_range(2). + +Fixes: c992fe2925d7 ("io_uring: add fsync support") +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + io_uring/sync.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/io_uring/sync.c b/io_uring/sync.c +index 255f68c37e55c..27bd0a26500bc 100644 +--- a/io_uring/sync.c ++++ b/io_uring/sync.c +@@ -62,6 +62,8 @@ int io_fsync_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) + return -EINVAL; + + sync->off = READ_ONCE(sqe->off); ++ if (sync->off < 0) ++ return -EINVAL; + sync->len = READ_ONCE(sqe->len); + req->flags |= REQ_F_FORCE_ASYNC; + return 0; +-- +2.51.0 + diff --git a/queue-6.6/iomap-fix-submission-side-handling-of-completion-sid.patch b/queue-6.6/iomap-fix-submission-side-handling-of-completion-sid.patch new file mode 100644 index 0000000000..0cbb540428 --- /dev/null +++ b/queue-6.6/iomap-fix-submission-side-handling-of-completion-sid.patch @@ -0,0 +1,49 @@ +From 921f7ed6cc6a19d573b6b3559544ad599cbed1f9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 06:53:38 +0100 +Subject: iomap: fix submission side handling of completion side errors + +From: Christoph Hellwig + +[ Upstream commit 4ad357e39b2ecd5da7bcc7e840ee24d179593cd5 ] + +The "if (dio->error)" in iomap_dio_bio_iter exists to stop submitting +more bios when a completion already return an error. Commit cfe057f7db1f +("iomap_dio_actor(): fix iov_iter bugs") made it revert the iov by +"copied", which is very wrong given that we've already consumed that +range and submitted a bio for it. + +Fixes: cfe057f7db1f ("iomap_dio_actor(): fix iov_iter bugs") +Signed-off-by: Christoph Hellwig +Reviewed-by: Damien Le Moal +Reviewed-by: Darrick J. Wong +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + fs/iomap/direct-io.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/fs/iomap/direct-io.c b/fs/iomap/direct-io.c +index 8158ab18e1ae8..ec6b019f087fd 100644 +--- a/fs/iomap/direct-io.c ++++ b/fs/iomap/direct-io.c +@@ -381,9 +381,13 @@ static loff_t iomap_dio_bio_iter(const struct iomap_iter *iter, + nr_pages = bio_iov_vecs_to_alloc(dio->submit.iter, BIO_MAX_VECS); + do { + size_t n; +- if (dio->error) { +- iov_iter_revert(dio->submit.iter, copied); +- copied = ret = 0; ++ ++ /* ++ * If completions already occurred and reported errors, give up now and ++ * don't bother submitting more bios. ++ */ ++ if (unlikely(data_race(dio->error))) { ++ ret = 0; + goto out; + } + +-- +2.51.0 + diff --git a/queue-6.6/iommu-vt-d-flush-cache-for-pasid-table-before-using-.patch b/queue-6.6/iommu-vt-d-flush-cache-for-pasid-table-before-using-.patch new file mode 100644 index 0000000000..93e3898b60 --- /dev/null +++ b/queue-6.6/iommu-vt-d-flush-cache-for-pasid-table-before-using-.patch @@ -0,0 +1,55 @@ +From 79d7b0a23f25bbc258fe6f02e26016e72574d2f4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 09:48:52 +0800 +Subject: iommu/vt-d: Flush cache for PASID table before using it + +From: Dmytro Maluka + +[ Upstream commit 22d169bdd2849fe6bd18c2643742e1c02be6451c ] + +When writing the address of a freshly allocated zero-initialized PASID +table to a PASID directory entry, do that after the CPU cache flush for +this PASID table, not before it, to avoid the time window when this +PASID table may be already used by non-coherent IOMMU hardware while +its contents in RAM is still some random old data, not zero-initialized. + +Fixes: 194b3348bdbb ("iommu/vt-d: Fix PASID directory pointer coherency") +Signed-off-by: Dmytro Maluka +Reviewed-by: Kevin Tian +Link: https://lore.kernel.org/r/20251221123508.37495-1-dmaluka@chromium.org +Signed-off-by: Lu Baolu +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/intel/pasid.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c +index 8faa93cffac45..07c8b0df8e2a8 100644 +--- a/drivers/iommu/intel/pasid.c ++++ b/drivers/iommu/intel/pasid.c +@@ -207,6 +207,9 @@ static struct pasid_entry *intel_pasid_get_entry(struct device *dev, u32 pasid) + if (!entries) + return NULL; + ++ if (!ecap_coherent(info->iommu->ecap)) ++ clflush_cache_range(entries, VTD_PAGE_SIZE); ++ + /* + * The pasid directory table entry won't be freed after + * allocation. No worry about the race with free and +@@ -218,10 +221,8 @@ static struct pasid_entry *intel_pasid_get_entry(struct device *dev, u32 pasid) + free_pgtable_page(entries); + goto retry; + } +- if (!ecap_coherent(info->iommu->ecap)) { +- clflush_cache_range(entries, VTD_PAGE_SIZE); ++ if (!ecap_coherent(info->iommu->ecap)) + clflush_cache_range(&dir[dir_index].val, sizeof(*dir)); +- } + } + + return &entries[index]; +-- +2.51.0 + diff --git a/queue-6.6/ionic-rate-limit-unknown-xcvr-type-messages.patch b/queue-6.6/ionic-rate-limit-unknown-xcvr-type-messages.patch new file mode 100644 index 0000000000..cbf9483a46 --- /dev/null +++ b/queue-6.6/ionic-rate-limit-unknown-xcvr-type-messages.patch @@ -0,0 +1,51 @@ +From 36a33fd205d9574a4fbf0ed6d724ced280466494 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 14:46:51 -0800 +Subject: ionic: Rate limit unknown xcvr type messages + +From: Eric Joyner + +[ Upstream commit cdb1634de3bf197c0d86487d1fb84c128a79cc7c ] + +Running ethtool repeatedly with a transceiver unknown to the driver or +firmware will cause the driver to spam the kernel logs with "unknown +xcvr type" messages which can distract from real issues; and this isn't +interesting information outside of debugging. Fix this by rate limiting +the output so that there are still notifications but not so many that +they flood the log. + +Using dev_dbg_once() would reduce the number of messages further, but +this would miss the case where a different unknown transceiver type is +plugged in, and its status is requested. + +Fixes: 4d03e00a2140 ("ionic: Add initial ethtool support") +Signed-off-by: Eric Joyner +Reviewed-by: Brett Creeley +Link: https://patch.msgid.link/20260206224651.1491-1-eric.joyner@amd.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/pensando/ionic/ionic_ethtool.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c +index d76e63f57ff1e..b07dd56b0c76d 100644 +--- a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c ++++ b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c +@@ -222,9 +222,10 @@ static int ionic_get_link_ksettings(struct net_device *netdev, + /* This means there's no module plugged in */ + break; + default: +- dev_info(lif->ionic->dev, "unknown xcvr type pid=%d / 0x%x\n", +- idev->port_info->status.xcvr.pid, +- idev->port_info->status.xcvr.pid); ++ dev_dbg_ratelimited(lif->ionic->dev, ++ "unknown xcvr type pid=%d / 0x%x\n", ++ idev->port_info->status.xcvr.pid, ++ idev->port_info->status.xcvr.pid); + break; + } + +-- +2.51.0 + diff --git a/queue-6.6/ipc-don-t-audit-capability-check-in-ipc_permissions.patch b/queue-6.6/ipc-don-t-audit-capability-check-in-ipc_permissions.patch new file mode 100644 index 0000000000..c703ed2342 --- /dev/null +++ b/queue-6.6/ipc-don-t-audit-capability-check-in-ipc_permissions.patch @@ -0,0 +1,66 @@ +From a2b79b24edec1fc9d994969d3a5e4edeefaf0e70 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 15:13:03 +0100 +Subject: ipc: don't audit capability check in ipc_permissions() + +From: Ondrej Mosnacek + +[ Upstream commit 071588136007482d70fd2667b827036bc60b1f8f ] + +The IPC sysctls implement the ctl_table_root::permissions hook and +they override the file access mode based on the CAP_CHECKPOINT_RESTORE +capability, which is being checked regardless of whether any access is +actually denied or not, so if an LSM denies the capability, an audit +record may be logged even when access is in fact granted. + +It wouldn't be viable to restructure the sysctl permission logic to only +check the capability when the access would be actually denied if it's +not granted. Thus, do the same as in net_ctl_permissions() +(net/sysctl_net.c) - switch from ns_capable() to ns_capable_noaudit(), +so that the check never emits an audit record. + +Fixes: 0889f44e2810 ("ipc: Check permissions for checkpoint_restart sysctls at open time") +Signed-off-by: Ondrej Mosnacek +Acked-by: Alexey Gladkov +Acked-by: Serge Hallyn +Signed-off-by: Serge Hallyn +Stable-dep-of: 8924336531e2 ("ipc: don't audit capability check in ipc_permissions()") +Signed-off-by: Sasha Levin +--- + include/linux/capability.h | 6 ++++++ + ipc/ipc_sysctl.c | 2 +- + 2 files changed, 7 insertions(+), 1 deletion(-) + +diff --git a/include/linux/capability.h b/include/linux/capability.h +index 0c356a5179917..767c535dbd38e 100644 +--- a/include/linux/capability.h ++++ b/include/linux/capability.h +@@ -208,6 +208,12 @@ static inline bool checkpoint_restore_ns_capable(struct user_namespace *ns) + ns_capable(ns, CAP_SYS_ADMIN); + } + ++static inline bool checkpoint_restore_ns_capable_noaudit(struct user_namespace *ns) ++{ ++ return ns_capable_noaudit(ns, CAP_CHECKPOINT_RESTORE) || ++ ns_capable_noaudit(ns, CAP_SYS_ADMIN); ++} ++ + /* audit system wants to get cap info from files as well */ + int get_vfs_caps_from_disk(struct mnt_idmap *idmap, + const struct dentry *dentry, +diff --git a/ipc/ipc_sysctl.c b/ipc/ipc_sysctl.c +index b2f39a86f4734..22b12a482ba91 100644 +--- a/ipc/ipc_sysctl.c ++++ b/ipc/ipc_sysctl.c +@@ -215,7 +215,7 @@ static int ipc_permissions(struct ctl_table_header *head, struct ctl_table *tabl + if (((table->data == &ns->ids[IPC_SEM_IDS].next_id) || + (table->data == &ns->ids[IPC_MSG_IDS].next_id) || + (table->data == &ns->ids[IPC_SHM_IDS].next_id)) && +- checkpoint_restore_ns_capable(ns->user_ns)) ++ checkpoint_restore_ns_capable_noaudit(ns->user_ns)) + mode = 0666; + else + #endif +-- +2.51.0 + diff --git a/queue-6.6/kallsyms-ftrace-set-module-buildid-in-ftrace_mod_add.patch b/queue-6.6/kallsyms-ftrace-set-module-buildid-in-ftrace_mod_add.patch new file mode 100644 index 0000000000..e9f93f4cdf --- /dev/null +++ b/queue-6.6/kallsyms-ftrace-set-module-buildid-in-ftrace_mod_add.patch @@ -0,0 +1,100 @@ +From 138bf071a777fc813b54847fb476c06e1d16a4c4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 14:59:19 +0100 +Subject: kallsyms/ftrace: set module buildid in ftrace_mod_address_lookup() + +From: Petr Mladek + +[ Upstream commit e8a1e7eaa19d0b757b06a2f913e3eeb4b1c002c6 ] + +__sprint_symbol() might access an invalid pointer when +kallsyms_lookup_buildid() returns a symbol found by +ftrace_mod_address_lookup(). + +The ftrace lookup function must set both @modname and @modbuildid the same +way as module_address_lookup(). + +Link: https://lkml.kernel.org/r/20251128135920.217303-7-pmladek@suse.com +Fixes: 9294523e3768 ("module: add printk formats to add module build ID to stacktraces") +Signed-off-by: Petr Mladek +Reviewed-by: Aaron Tomlin +Acked-by: Steven Rostedt (Google) +Cc: Alexei Starovoitov +Cc: Daniel Borkman +Cc: Daniel Gomez +Cc: John Fastabend +Cc: Kees Cook +Cc: Luis Chamberalin +Cc: Marc Rutland +Cc: "Masami Hiramatsu (Google)" +Cc: Petr Pavlu +Cc: Sami Tolvanen +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + include/linux/ftrace.h | 6 ++++-- + kernel/kallsyms.c | 4 ++-- + kernel/trace/ftrace.c | 5 ++++- + 3 files changed, 10 insertions(+), 5 deletions(-) + +diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h +index e8921871ef9aa..5c3eaf9fc90c4 100644 +--- a/include/linux/ftrace.h ++++ b/include/linux/ftrace.h +@@ -89,11 +89,13 @@ struct ftrace_direct_func; + defined(CONFIG_DYNAMIC_FTRACE) + const char * + ftrace_mod_address_lookup(unsigned long addr, unsigned long *size, +- unsigned long *off, char **modname, char *sym); ++ unsigned long *off, char **modname, ++ const unsigned char **modbuildid, char *sym); + #else + static inline const char * + ftrace_mod_address_lookup(unsigned long addr, unsigned long *size, +- unsigned long *off, char **modname, char *sym) ++ unsigned long *off, char **modname, ++ const unsigned char **modbuildid, char *sym) + { + return NULL; + } +diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c +index 07f33601cac28..cd44e9c427533 100644 +--- a/kernel/kallsyms.c ++++ b/kernel/kallsyms.c +@@ -431,8 +431,8 @@ static const char *kallsyms_lookup_buildid(unsigned long addr, + offset, modname, namebuf); + + if (!ret) +- ret = ftrace_mod_address_lookup(addr, symbolsize, +- offset, modname, namebuf); ++ ret = ftrace_mod_address_lookup(addr, symbolsize, offset, ++ modname, modbuildid, namebuf); + + found: + cleanup_symbol_name(namebuf); +diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c +index 8f2d44e741510..94f7ed57d43e5 100644 +--- a/kernel/trace/ftrace.c ++++ b/kernel/trace/ftrace.c +@@ -7046,7 +7046,8 @@ ftrace_func_address_lookup(struct ftrace_mod_map *mod_map, + + const char * + ftrace_mod_address_lookup(unsigned long addr, unsigned long *size, +- unsigned long *off, char **modname, char *sym) ++ unsigned long *off, char **modname, ++ const unsigned char **modbuildid, char *sym) + { + struct ftrace_mod_map *mod_map; + const char *ret = NULL; +@@ -7058,6 +7059,8 @@ ftrace_mod_address_lookup(unsigned long addr, unsigned long *size, + if (ret) { + if (modname) + *modname = mod_map->mod->name; ++ if (modbuildid) ++ *modbuildid = module_buildid(mod_map->mod); + break; + } + } +-- +2.51.0 + diff --git a/queue-6.6/leds-qcom-lpg-check-the-return-value-of-regmap_bulk_.patch b/queue-6.6/leds-qcom-lpg-check-the-return-value-of-regmap_bulk_.patch new file mode 100644 index 0000000000..f3a56a2cfe --- /dev/null +++ b/queue-6.6/leds-qcom-lpg-check-the-return-value-of-regmap_bulk_.patch @@ -0,0 +1,55 @@ +From 5202f3770c80702c69c10b4fe3af0d99b5329df7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 01:51:33 +0800 +Subject: leds: qcom-lpg: Check the return value of regmap_bulk_write() + +From: Haotian Zhang + +[ Upstream commit f42033b5ce8c79c5db645916c9a72ee3e10cecfa ] + +The lpg_lut_store() function currently ignores the return value of +regmap_bulk_write() and always returns 0. This can cause hardware write +failures to go undetected, leading the caller to believe LUT programming +succeeded when it may have failed. + +Check the return value of regmap_bulk_write() in lpg_lut_store and return +the error to the caller on failure. + +Fixes: 24e2d05d1b68 ("leds: Add driver for Qualcomm LPG") +Signed-off-by: Haotian Zhang +Link: https://patch.msgid.link/20260108175133.638-1-vulab@iscas.ac.cn +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/leds/rgb/leds-qcom-lpg.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/leds/rgb/leds-qcom-lpg.c b/drivers/leds/rgb/leds-qcom-lpg.c +index a41c2b13766dc..9843fe2e5f9eb 100644 +--- a/drivers/leds/rgb/leds-qcom-lpg.c ++++ b/drivers/leds/rgb/leds-qcom-lpg.c +@@ -221,7 +221,7 @@ static int lpg_lut_store(struct lpg *lpg, struct led_pattern *pattern, + { + unsigned int idx; + u16 val; +- int i; ++ int i, ret; + + idx = bitmap_find_next_zero_area(lpg->lut_bitmap, lpg->lut_size, + 0, len, 0); +@@ -231,8 +231,10 @@ static int lpg_lut_store(struct lpg *lpg, struct led_pattern *pattern, + for (i = 0; i < len; i++) { + val = pattern[i].brightness; + +- regmap_bulk_write(lpg->map, lpg->lut_base + LPG_LUT_REG(idx + i), +- &val, sizeof(val)); ++ ret = regmap_bulk_write(lpg->map, lpg->lut_base + LPG_LUT_REG(idx + i), ++ &val, sizeof(val)); ++ if (ret) ++ return ret; + } + + bitmap_set(lpg->lut_bitmap, idx, len); +-- +2.51.0 + diff --git a/queue-6.6/libbpf-fix-oob-read-in-btf_dump_get_bitfield_value.patch b/queue-6.6/libbpf-fix-oob-read-in-btf_dump_get_bitfield_value.patch new file mode 100644 index 0000000000..1a94847b5b --- /dev/null +++ b/queue-6.6/libbpf-fix-oob-read-in-btf_dump_get_bitfield_value.patch @@ -0,0 +1,59 @@ +From 433c41a6ca4d4c32b8ea976b8c206b636442c682 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 05:05:27 +0530 +Subject: libbpf: Fix OOB read in btf_dump_get_bitfield_value + +From: Varun R Mallya + +[ Upstream commit 5714ca8cba5ed736f3733663c446cbee63a10a64 ] + +When dumping bitfield data, btf_dump_get_bitfield_value() reads data +based on the underlying type's size (t->size). However, it does not +verify that the provided data buffer (data_sz) is large enough to +contain these bytes. + +If btf_dump__dump_type_data() is called with a buffer smaller than +the type's size, this leads to an out-of-bounds read. This was +confirmed by AddressSanitizer in the linked issue. + +Fix this by ensuring we do not read past the provided data_sz limit. + +Fixes: a1d3cc3c5eca ("libbpf: Avoid use of __int128 in typed dump display") +Reported-by: Harrison Green +Suggested-by: Alan Maguire +Signed-off-by: Varun R Mallya +Signed-off-by: Andrii Nakryiko +Link: https://lore.kernel.org/bpf/20260106233527.163487-1-varunrmallya@gmail.com + +Closes: https://github.com/libbpf/libbpf/issues/928 +Signed-off-by: Sasha Levin +--- + tools/lib/bpf/btf_dump.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/tools/lib/bpf/btf_dump.c b/tools/lib/bpf/btf_dump.c +index cf4db51b99eb5..beb91c78ca7a4 100644 +--- a/tools/lib/bpf/btf_dump.c ++++ b/tools/lib/bpf/btf_dump.c +@@ -1758,9 +1758,18 @@ static int btf_dump_get_bitfield_value(struct btf_dump *d, + __u16 left_shift_bits, right_shift_bits; + const __u8 *bytes = data; + __u8 nr_copy_bits; ++ __u8 start_bit, nr_bytes; + __u64 num = 0; + int i; + ++ /* Calculate how many bytes cover the bitfield */ ++ start_bit = bits_offset % 8; ++ nr_bytes = (start_bit + bit_sz + 7) / 8; ++ ++ /* Bound check */ ++ if (data + nr_bytes > d->typed_dump->data_end) ++ return -E2BIG; ++ + /* Maximum supported bitfield size is 64 bits */ + if (t->size > 8) { + pr_warn("unexpected bitfield size %d\n", t->size); +-- +2.51.0 + diff --git a/queue-6.6/mctp-i2c-initialise-event-handler-read-bytes.patch b/queue-6.6/mctp-i2c-initialise-event-handler-read-bytes.patch new file mode 100644 index 0000000000..53cb4284e6 --- /dev/null +++ b/queue-6.6/mctp-i2c-initialise-event-handler-read-bytes.patch @@ -0,0 +1,43 @@ +From b767c11be0b18b8cc755c5850109372be47fc413 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Jan 2026 17:01:16 +0800 +Subject: mctp i2c: initialise event handler read bytes + +From: Matt Johnston + +[ Upstream commit 2a14e91b6d76639dac70ea170f4384c1ee3cb48d ] + +Set a 0xff value for i2c reads of an mctp-i2c device. Otherwise reads +will return "val" from the i2c bus driver. For i2c-aspeed and +i2c-npcm7xx that is a stack uninitialised u8. + +Tested with "i2ctransfer -y 1 r10@0x34" where 0x34 is a mctp-i2c +instance, now it returns all 0xff. + +Fixes: f5b8abf9fc3d ("mctp i2c: MCTP I2C binding driver") +Signed-off-by: Matt Johnston +Link: https://patch.msgid.link/20260113-mctp-read-fix-v1-1-70c4b59c741c@codeconstruct.com.au +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/mctp/mctp-i2c.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/mctp/mctp-i2c.c b/drivers/net/mctp/mctp-i2c.c +index 079fb7ca97b62..c8c2c5dc46eb7 100644 +--- a/drivers/net/mctp/mctp-i2c.c ++++ b/drivers/net/mctp/mctp-i2c.c +@@ -244,7 +244,10 @@ static int mctp_i2c_slave_cb(struct i2c_client *client, + + switch (event) { + case I2C_SLAVE_READ_REQUESTED: ++ case I2C_SLAVE_READ_PROCESSED: ++ /* MCTP I2C transport only uses writes */ + midev->rx_pos = 0; ++ *val = 0xff; + break; + case I2C_SLAVE_WRITE_RECEIVED: + if (midev->rx_pos < MCTP_I2C_BUFSZ) { +-- +2.51.0 + diff --git a/queue-6.6/md-raid10-fix-any_working-flag-handling-in-raid10_sy.patch b/queue-6.6/md-raid10-fix-any_working-flag-handling-in-raid10_sy.patch new file mode 100644 index 0000000000..9dfa76dd0d --- /dev/null +++ b/queue-6.6/md-raid10-fix-any_working-flag-handling-in-raid10_sy.patch @@ -0,0 +1,47 @@ +From b498cc3ce0c55df53718310e64cffa8d4560c3c4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Jan 2026 19:02:58 +0800 +Subject: md/raid10: fix any_working flag handling in raid10_sync_request + +From: Li Nan + +[ Upstream commit 99582edb3f62e8ee6c34512021368f53f9b091f2 ] + +In raid10_sync_request(), 'any_working' indicates if any IO will +be submitted. When there's only one In_sync disk with badblocks, +'any_working' might be set to 1 but no IO is submitted. Fix it by +setting 'any_working' after badblock checks. + +Link: https://lore.kernel.org/linux-raid/20260105110300.1442509-11-linan666@huaweicloud.com +Fixes: e875ecea266a ("md/raid10 record bad blocks as needed during recovery.") +Signed-off-by: Li Nan +Reviewed-by: Yu Kuai +Signed-off-by: Yu Kuai +Signed-off-by: Sasha Levin +--- + drivers/md/raid10.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c +index a75d090a7fa15..8546ef98bfa7e 100644 +--- a/drivers/md/raid10.c ++++ b/drivers/md/raid10.c +@@ -3533,7 +3533,6 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr, + !test_bit(In_sync, &rdev->flags)) + continue; + /* This is where we read from */ +- any_working = 1; + sector = r10_bio->devs[j].addr; + + if (is_badblock(rdev, sector, max_sync, +@@ -3548,6 +3547,7 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr, + continue; + } + } ++ any_working = 1; + bio = r10_bio->devs[0].bio; + bio->bi_next = biolist; + biolist = bio; +-- +2.51.0 + diff --git a/queue-6.6/media-ccs-accommodate-c-phy-into-the-calculation.patch b/queue-6.6/media-ccs-accommodate-c-phy-into-the-calculation.patch new file mode 100644 index 0000000000..0cc0697811 --- /dev/null +++ b/queue-6.6/media-ccs-accommodate-c-phy-into-the-calculation.patch @@ -0,0 +1,53 @@ +From 007d1a7a67842a04811d7e22264283e65b93c6c2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 18:57:07 +0100 +Subject: media: ccs: Accommodate C-PHY into the calculation + +From: David Heidelberg + +[ Upstream commit 3085977e734dab74adebb1dda195befce25addff ] + +We need to set correct mode for PLL to calculate correct frequency. +Signalling mode is known at this point, so use it for that. + +Fixes: 47b6eaf36eba ("media: ccs-pll: Differentiate between CSI-2 D-PHY and C-PHY") +Reviewed-by: Mehdi Djait +Signed-off-by: David Heidelberg +[Sakari Ailus: Drop extra newline.] +Signed-off-by: Sakari Ailus +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/i2c/ccs/ccs-core.c | 16 +++++++++++++++- + 1 file changed, 15 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c +index 4d31b2bb8f09f..5611db7e1b326 100644 +--- a/drivers/media/i2c/ccs/ccs-core.c ++++ b/drivers/media/i2c/ccs/ccs-core.c +@@ -3530,7 +3530,21 @@ static int ccs_probe(struct i2c_client *client) + sensor->scale_m = CCS_LIM(sensor, SCALER_N_MIN); + + /* prepare PLL configuration input values */ +- sensor->pll.bus_type = CCS_PLL_BUS_TYPE_CSI2_DPHY; ++ switch (sensor->hwcfg.csi_signalling_mode) { ++ case CCS_CSI_SIGNALING_MODE_CSI_2_CPHY: ++ sensor->pll.bus_type = CCS_PLL_BUS_TYPE_CSI2_CPHY; ++ break; ++ case CCS_CSI_SIGNALING_MODE_CSI_2_DPHY: ++ case SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK: ++ case SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_STROBE: ++ sensor->pll.bus_type = CCS_PLL_BUS_TYPE_CSI2_DPHY; ++ break; ++ default: ++ dev_err(&client->dev, "unsupported signalling mode %u\n", ++ sensor->hwcfg.csi_signalling_mode); ++ rval = -EINVAL; ++ goto out_cleanup; ++ } + sensor->pll.csi2.lanes = sensor->hwcfg.lanes; + if (CCS_LIM(sensor, CLOCK_CALCULATION) & + CCS_CLOCK_CALCULATION_LANE_SPEED) { +-- +2.51.0 + diff --git a/queue-6.6/media-uvcvideo-fix-allocation-for-small-frame-sizes.patch b/queue-6.6/media-uvcvideo-fix-allocation-for-small-frame-sizes.patch new file mode 100644 index 0000000000..2d8ff178bf --- /dev/null +++ b/queue-6.6/media-uvcvideo-fix-allocation-for-small-frame-sizes.patch @@ -0,0 +1,57 @@ +From 004fde95f2f8951a48fa1f78e99feb3322844792 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jan 2026 10:32:13 +0000 +Subject: media: uvcvideo: Fix allocation for small frame sizes + +From: Ricardo Ribalda + +[ Upstream commit 40d3ac25c11310bfaa50ed7614846ef75cb69a1e ] + +If a frame has size of less or equal than one packet size +uvc_alloc_urb_buffers() is unable to allocate memory for it due to a +off-by-one error. + +Fix the off-by-one-error and now that we are at it, make sure that +stream->urb_size has always a valid value when we return from the +function, even when an error happens. + +Fixes: efdc8a9585ce ("V4L/DVB (10295): uvcvideo: Retry URB buffers allocation when the system is low on memory.") +Reported-by: Itay Chamiel +Closes: https://lore.kernel.org/linux-media/CANiDSCsSoZf2LsCCoWAUbCg6tJT-ypXR1B85aa6rAdMVYr2iBQ@mail.gmail.com/T/#t +Co-developed-by: Itay Chamiel +Signed-off-by: Itay Chamiel +Signed-off-by: Ricardo Ribalda +Reviewed-by: Laurent Pinchart +Tested-by: Itay Chamiel +Link: https://patch.msgid.link/20260114-uvc-alloc-urb-v1-1-cedf3fb66711@chromium.org +Signed-off-by: Laurent Pinchart +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/usb/uvc/uvc_video.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c +index a9f880eb518ad..ea7d91b19079e 100644 +--- a/drivers/media/usb/uvc/uvc_video.c ++++ b/drivers/media/usb/uvc/uvc_video.c +@@ -1819,7 +1819,7 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream, + npackets = UVC_MAX_PACKETS; + + /* Retry allocations until one succeed. */ +- for (; npackets > 1; npackets /= 2) { ++ for (; npackets > 0; npackets /= 2) { + stream->urb_size = psize * npackets; + + for (i = 0; i < UVC_URBS; ++i) { +@@ -1844,6 +1844,7 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream, + uvc_dbg(stream->dev, VIDEO, + "Failed to allocate URB buffers (%u bytes per packet)\n", + psize); ++ stream->urb_size = 0; + return 0; + } + +-- +2.51.0 + diff --git a/queue-6.6/mfd-arizona-fix-regulator-resource-leak-on-wm5102_cl.patch b/queue-6.6/mfd-arizona-fix-regulator-resource-leak-on-wm5102_cl.patch new file mode 100644 index 0000000000..a66d06fbd6 --- /dev/null +++ b/queue-6.6/mfd-arizona-fix-regulator-resource-leak-on-wm5102_cl.patch @@ -0,0 +1,43 @@ +From 97585906bda2ad1d23d6b32bfb12d67c6f57db4a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 14 Dec 2025 22:58:03 +0800 +Subject: mfd: arizona: Fix regulator resource leak on + wm5102_clear_write_sequencer() failure + +From: Haotian Zhang + +[ Upstream commit 4feb753ba6e5e5bbaba868b841a2db41c21e56fa ] + +The wm5102_clear_write_sequencer() helper may return an error +and just return, bypassing the cleanup sequence and causing +regulators to remain enabled, leading to a resource leak. + +Change the direct return to jump to the err_reset label to +properly free the resources. + +Fixes: 1c1c6bba57f5 ("mfd: wm5102: Ensure we always boot the device fully") +Signed-off-by: Haotian Zhang +Reviewed-by: Charles Keepax +Link: https://patch.msgid.link/20251214145804.2037-1-vulab@iscas.ac.cn +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/mfd/arizona-core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c +index 19a0adf8ce3db..35f516d934c8b 100644 +--- a/drivers/mfd/arizona-core.c ++++ b/drivers/mfd/arizona-core.c +@@ -1100,7 +1100,7 @@ int arizona_dev_init(struct arizona *arizona) + } else if (val & 0x01) { + ret = wm5102_clear_write_sequencer(arizona); + if (ret) +- return ret; ++ goto err_reset; + } + break; + default: +-- +2.51.0 + diff --git a/queue-6.6/mfd-simple-mfd-i2c-add-compatible-strings-for-layers.patch b/queue-6.6/mfd-simple-mfd-i2c-add-compatible-strings-for-layers.patch new file mode 100644 index 0000000000..58637abb71 --- /dev/null +++ b/queue-6.6/mfd-simple-mfd-i2c-add-compatible-strings-for-layers.patch @@ -0,0 +1,40 @@ +From 1d738bdc37374dc29e0de9eba294a98239e9f561 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 7 Jul 2025 18:31:20 +0300 +Subject: mfd: simple-mfd-i2c: Add compatible strings for Layerscape QIXIS FPGA + +From: Ioana Ciornei + +[ Upstream commit 81a2c31257411296862487aaade98b7d9e25dc72 ] + +The QIXIS FPGA found on Layerscape boards such as LX2160AQDS, LS1028AQDS +etc deals with power-on-reset timing, muxing etc. Use the simple-mfd-i2c +as its core driver by adding its compatible string (already found in +some dt files). By using the simple-mfd-i2c driver, any child device +will have access to the i2c regmap created by it. + +Signed-off-by: Ioana Ciornei +Link: https://lore.kernel.org/r/20250707153120.1371719-1-ioana.ciornei@nxp.com +Signed-off-by: Lee Jones +Stable-dep-of: 8f34c1a64c53 ("mfd: simple-mfd-i2c: Add Delta TN48M CPLD support") +Signed-off-by: Sasha Levin +--- + drivers/mfd/simple-mfd-i2c.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/mfd/simple-mfd-i2c.c b/drivers/mfd/simple-mfd-i2c.c +index 22159913bea03..f7798bd922224 100644 +--- a/drivers/mfd/simple-mfd-i2c.c ++++ b/drivers/mfd/simple-mfd-i2c.c +@@ -99,6 +99,8 @@ static const struct of_device_id simple_mfd_i2c_of_match[] = { + { .compatible = "maxim,max5970", .data = &maxim_max5970}, + { .compatible = "maxim,max5978", .data = &maxim_max5970}, + { .compatible = "maxim,max77705-battery", .data = &maxim_mon_max77705}, ++ { .compatible = "fsl,lx2160aqds-fpga" }, ++ { .compatible = "fsl,ls1028aqds-fpga" }, + {} + }; + MODULE_DEVICE_TABLE(of, simple_mfd_i2c_of_match); +-- +2.51.0 + diff --git a/queue-6.6/mfd-simple-mfd-i2c-add-delta-tn48m-cpld-support.patch b/queue-6.6/mfd-simple-mfd-i2c-add-delta-tn48m-cpld-support.patch new file mode 100644 index 0000000000..63951c5def --- /dev/null +++ b/queue-6.6/mfd-simple-mfd-i2c-add-delta-tn48m-cpld-support.patch @@ -0,0 +1,67 @@ +From 38ad2de8dfc9a670fd65e3002c18e691220b1f75 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 17:14:52 +0100 +Subject: mfd: simple-mfd-i2c: Add Delta TN48M CPLD support + +From: Robert Marko + +[ Upstream commit 8f34c1a64c5394d2b51d3fba197947dc4b0b48a0 ] + +Delta TN48M switches have a Lattice CPLD that serves +multiple purposes including being a GPIO expander. + +So, lets use the simple I2C MFD driver to provide the MFD core. + +Also add a virtual symbol which pulls in the simple-mfd-i2c driver and +provide a common symbol on which the subdevice drivers can depend on. + +Fixes: b3dcb5de6209 ("gpio: Add Delta TN48M CPLD GPIO driver") +Signed-off-by: Robert Marko +Link: https://lore.kernel.org/20220131133049.77780-2-robert.marko@sartura.hr +Link: https://lore.kernel.org/linux-gpio/20260112064950.3837737-1-rdunlap@infradead.org/ +Signed-off-by: Linus Walleij +Link: https://patch.msgid.link/20260112-mfd-tn48m-v11-1-00c798d8cd2a@kernel.org +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/mfd/Kconfig | 11 +++++++++++ + drivers/mfd/simple-mfd-i2c.c | 1 + + 2 files changed, 12 insertions(+) + +diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig +index 45e0447d3b414..cfb22fb7b238b 100644 +--- a/drivers/mfd/Kconfig ++++ b/drivers/mfd/Kconfig +@@ -335,6 +335,17 @@ config MFD_CS47L92 + help + Support for Cirrus Logic CS42L92, CS47L92 and CS47L93 Smart Codecs + ++config MFD_TN48M_CPLD ++ tristate "Delta Networks TN48M switch CPLD driver" ++ depends on I2C ++ depends on ARCH_MVEBU || COMPILE_TEST ++ select MFD_SIMPLE_MFD_I2C ++ help ++ Select this option to enable support for Delta Networks TN48M switch ++ CPLD. It consists of reset and GPIO drivers. CPLD provides GPIOS-s ++ for the SFP slots as well as power supply related information. ++ SFP support depends on the GPIO driver being selected. ++ + config PMIC_DA903X + bool "Dialog Semiconductor DA9030/DA9034 PMIC Support" + depends on I2C=y +diff --git a/drivers/mfd/simple-mfd-i2c.c b/drivers/mfd/simple-mfd-i2c.c +index 0cca7a9044cd4..908eae338fee0 100644 +--- a/drivers/mfd/simple-mfd-i2c.c ++++ b/drivers/mfd/simple-mfd-i2c.c +@@ -110,6 +110,7 @@ static const struct simple_mfd_data spacemit_p1 = { + }; + + static const struct of_device_id simple_mfd_i2c_of_match[] = { ++ { .compatible = "delta,tn48m-cpld" }, + { .compatible = "fsl,ls1028aqds-fpga" }, + { .compatible = "fsl,lx2160aqds-fpga" }, + { .compatible = "kontron,sl28cpld" }, +-- +2.51.0 + diff --git a/queue-6.6/mfd-simple-mfd-i2c-add-max77705-support.patch b/queue-6.6/mfd-simple-mfd-i2c-add-max77705-support.patch new file mode 100644 index 0000000000..ddb93a0f90 --- /dev/null +++ b/queue-6.6/mfd-simple-mfd-i2c-add-max77705-support.patch @@ -0,0 +1,52 @@ +From 5fa1b8c53066b4010eb4555790612a09f0ba6787 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Jan 2025 18:04:29 +0300 +Subject: mfd: simple-mfd-i2c: Add MAX77705 support + +From: Dzmitry Sankouski + +[ Upstream commit 7b591ef98b3fc1ce20c3ccb86715429b72e2e6f0 ] + +Add MAX77705 support - fuel gauge and hwmon devices. +Hwmon provides charger input and system bus measurements. + +Signed-off-by: Dzmitry Sankouski +Reviewed-by: Krzysztof Kozlowski +Link: https://lore.kernel.org/r/20250123-starqltechn_integration_upstream-v17-4-8b06685b6612@gmail.com +Signed-off-by: Lee Jones +Stable-dep-of: 8f34c1a64c53 ("mfd: simple-mfd-i2c: Add Delta TN48M CPLD support") +Signed-off-by: Sasha Levin +--- + drivers/mfd/simple-mfd-i2c.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/drivers/mfd/simple-mfd-i2c.c b/drivers/mfd/simple-mfd-i2c.c +index 6eda79533208a..22159913bea03 100644 +--- a/drivers/mfd/simple-mfd-i2c.c ++++ b/drivers/mfd/simple-mfd-i2c.c +@@ -83,11 +83,22 @@ static const struct simple_mfd_data maxim_max5970 = { + .mfd_cell_size = ARRAY_SIZE(max5970_cells), + }; + ++static const struct mfd_cell max77705_sensor_cells[] = { ++ { .name = "max77705-battery" }, ++ { .name = "max77705-hwmon", }, ++}; ++ ++static const struct simple_mfd_data maxim_mon_max77705 = { ++ .mfd_cell = max77705_sensor_cells, ++ .mfd_cell_size = ARRAY_SIZE(max77705_sensor_cells), ++}; ++ + static const struct of_device_id simple_mfd_i2c_of_match[] = { + { .compatible = "kontron,sl28cpld" }, + { .compatible = "silergy,sy7636a", .data = &silergy_sy7636a}, + { .compatible = "maxim,max5970", .data = &maxim_max5970}, + { .compatible = "maxim,max5978", .data = &maxim_max5970}, ++ { .compatible = "maxim,max77705-battery", .data = &maxim_mon_max77705}, + {} + }; + MODULE_DEVICE_TABLE(of, simple_mfd_i2c_of_match); +-- +2.51.0 + diff --git a/queue-6.6/mfd-simple-mfd-i2c-add-spacemit-p1-support.patch b/queue-6.6/mfd-simple-mfd-i2c-add-spacemit-p1-support.patch new file mode 100644 index 0000000000..2427b2dc73 --- /dev/null +++ b/queue-6.6/mfd-simple-mfd-i2c-add-spacemit-p1-support.patch @@ -0,0 +1,89 @@ +From bd98a1b6f3129361219ea871c891013d75480c0d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Aug 2025 12:20:51 -0500 +Subject: mfd: simple-mfd-i2c: Add SpacemiT P1 support + +From: Alex Elder + +[ Upstream commit 6fc5d415c10e98ac1b31dd1d5653443e691cdcff ] + +Enable support for the RTC and regulators found in the SpacemiT P1 +PMIC. Support is implemented by the simple I2C MFD driver. + +The P1 PMIC is normally implemented with the SpacemiT K1 SoC. This +PMIC provides 6 buck converters and 12 LDO regulators. It also +implements a switch, watchdog timer, real-time clock, and more. +Initially its RTC and regulators are supported. + +Signed-off-by: Alex Elder +Link: https://lore.kernel.org/r/20250825172057.163883-3-elder@riscstar.com +Signed-off-by: Lee Jones +Stable-dep-of: 8f34c1a64c53 ("mfd: simple-mfd-i2c: Add Delta TN48M CPLD support") +Signed-off-by: Sasha Levin +--- + drivers/mfd/Kconfig | 13 +++++++++++++ + drivers/mfd/simple-mfd-i2c.c | 17 +++++++++++++++++ + 2 files changed, 30 insertions(+) + +diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig +index 68d71b4b55bd3..45e0447d3b414 100644 +--- a/drivers/mfd/Kconfig ++++ b/drivers/mfd/Kconfig +@@ -1137,6 +1137,19 @@ config MFD_QCOM_RPM + Say M here if you want to include support for the Qualcomm RPM as a + module. This will build a module called "qcom_rpm". + ++config MFD_SPACEMIT_P1 ++ tristate "SpacemiT P1 PMIC" ++ depends on ARCH_SPACEMIT || COMPILE_TEST ++ depends on I2C ++ select I2C_K1 ++ select MFD_SIMPLE_MFD_I2C ++ help ++ This option supports the I2C-based SpacemiT P1 PMIC, which ++ contains regulators, a power switch, GPIOs, an RTC, and more. ++ This option is selected when any of the supported sub-devices ++ is configured. The basic functionality is implemented by the ++ simple MFD I2C driver. ++ + config MFD_SPMI_PMIC + tristate "Qualcomm SPMI PMICs" + depends on ARCH_QCOM || COMPILE_TEST +diff --git a/drivers/mfd/simple-mfd-i2c.c b/drivers/mfd/simple-mfd-i2c.c +index f7798bd922224..63ac263888606 100644 +--- a/drivers/mfd/simple-mfd-i2c.c ++++ b/drivers/mfd/simple-mfd-i2c.c +@@ -93,6 +93,22 @@ static const struct simple_mfd_data maxim_mon_max77705 = { + .mfd_cell_size = ARRAY_SIZE(max77705_sensor_cells), + }; + ++static const struct regmap_config spacemit_p1_regmap_config = { ++ .reg_bits = 8, ++ .val_bits = 8, ++}; ++ ++static const struct mfd_cell spacemit_p1_cells[] = { ++ { .name = "spacemit-p1-regulator", }, ++ { .name = "spacemit-p1-rtc", }, ++}; ++ ++static const struct simple_mfd_data spacemit_p1 = { ++ .regmap_config = &spacemit_p1_regmap_config, ++ .mfd_cell = spacemit_p1_cells, ++ .mfd_cell_size = ARRAY_SIZE(spacemit_p1_cells), ++}; ++ + static const struct of_device_id simple_mfd_i2c_of_match[] = { + { .compatible = "kontron,sl28cpld" }, + { .compatible = "silergy,sy7636a", .data = &silergy_sy7636a}, +@@ -101,6 +117,7 @@ static const struct of_device_id simple_mfd_i2c_of_match[] = { + { .compatible = "maxim,max77705-battery", .data = &maxim_mon_max77705}, + { .compatible = "fsl,lx2160aqds-fpga" }, + { .compatible = "fsl,ls1028aqds-fpga" }, ++ { .compatible = "spacemit,p1", .data = &spacemit_p1, }, + {} + }; + MODULE_DEVICE_TABLE(of, simple_mfd_i2c_of_match); +-- +2.51.0 + diff --git a/queue-6.6/mfd-simple-mfd-i2c-keep-compatible-strings-in-alphab.patch b/queue-6.6/mfd-simple-mfd-i2c-keep-compatible-strings-in-alphab.patch new file mode 100644 index 0000000000..366e18c0ef --- /dev/null +++ b/queue-6.6/mfd-simple-mfd-i2c-keep-compatible-strings-in-alphab.patch @@ -0,0 +1,44 @@ +From b199b5535602ea017dcad1fd7ff69da618981eb2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 22 Sep 2025 17:24:19 +0300 +Subject: mfd: simple-mfd-i2c: Keep compatible strings in alphabetical order + +From: Ioana Ciornei + +[ Upstream commit 3ed50d77924ff2e35918739df145dd429cee0ce4 ] + +Reorder the of_device_id structures so that they are in alphabetical +order. + +Signed-off-by: Ioana Ciornei +Signed-off-by: Lee Jones +Stable-dep-of: 8f34c1a64c53 ("mfd: simple-mfd-i2c: Add Delta TN48M CPLD support") +Signed-off-by: Sasha Levin +--- + drivers/mfd/simple-mfd-i2c.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/mfd/simple-mfd-i2c.c b/drivers/mfd/simple-mfd-i2c.c +index 63ac263888606..0cca7a9044cd4 100644 +--- a/drivers/mfd/simple-mfd-i2c.c ++++ b/drivers/mfd/simple-mfd-i2c.c +@@ -110,13 +110,13 @@ static const struct simple_mfd_data spacemit_p1 = { + }; + + static const struct of_device_id simple_mfd_i2c_of_match[] = { ++ { .compatible = "fsl,ls1028aqds-fpga" }, ++ { .compatible = "fsl,lx2160aqds-fpga" }, + { .compatible = "kontron,sl28cpld" }, +- { .compatible = "silergy,sy7636a", .data = &silergy_sy7636a}, + { .compatible = "maxim,max5970", .data = &maxim_max5970}, + { .compatible = "maxim,max5978", .data = &maxim_max5970}, + { .compatible = "maxim,max77705-battery", .data = &maxim_mon_max77705}, +- { .compatible = "fsl,lx2160aqds-fpga" }, +- { .compatible = "fsl,ls1028aqds-fpga" }, ++ { .compatible = "silergy,sy7636a", .data = &silergy_sy7636a}, + { .compatible = "spacemit,p1", .data = &spacemit_p1, }, + {} + }; +-- +2.51.0 + diff --git a/queue-6.6/mfd-wm8350-core-use-irqf_oneshot.patch b/queue-6.6/mfd-wm8350-core-use-irqf_oneshot.patch new file mode 100644 index 0000000000..0fa4d2cd60 --- /dev/null +++ b/queue-6.6/mfd-wm8350-core-use-irqf_oneshot.patch @@ -0,0 +1,48 @@ +From 4e70ae5fc62fc8d70242cb7767a837ce5d79a10f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:55:35 +0100 +Subject: mfd: wm8350-core: Use IRQF_ONESHOT + +From: Sebastian Andrzej Siewior + +[ Upstream commit 553b4999cbe231b5011cb8db05a3092dec168aca ] + +Using a threaded interrupt without a dedicated primary handler mandates +the IRQF_ONESHOT flag to mask the interrupt source while the threaded +handler is active. Otherwise the interrupt can fire again before the +threaded handler had a chance to run. + +Mark explained that this should not happen with this hardware since it +is a slow irqchip which is behind an I2C/ SPI bus but the IRQ-core will +refuse to accept such a handler. + +Set IRQF_ONESHOT so the interrupt source is masked until the secondary +handler is done. + +Fixes: 1c6c69525b40e ("genirq: Reject bogus threaded irq requests") +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Reviewed-by: Charles Keepax +Reviewed-by: Andy Shevchenko +Link: https://patch.msgid.link/20260128095540.863589-16-bigeasy@linutronix.de +Signed-off-by: Sasha Levin +--- + include/linux/mfd/wm8350/core.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/linux/mfd/wm8350/core.h b/include/linux/mfd/wm8350/core.h +index a3241e4d75486..4816d4f472101 100644 +--- a/include/linux/mfd/wm8350/core.h ++++ b/include/linux/mfd/wm8350/core.h +@@ -663,7 +663,7 @@ static inline int wm8350_register_irq(struct wm8350 *wm8350, int irq, + return -ENODEV; + + return request_threaded_irq(irq + wm8350->irq_base, NULL, +- handler, flags, name, data); ++ handler, flags | IRQF_ONESHOT, name, data); + } + + static inline void wm8350_free_irq(struct wm8350 *wm8350, int irq, void *data) +-- +2.51.0 + diff --git a/queue-6.6/mm-list_lru-update-kernel-documentation-to-follow-th.patch b/queue-6.6/mm-list_lru-update-kernel-documentation-to-follow-th.patch new file mode 100644 index 0000000000..0ce426074c --- /dev/null +++ b/queue-6.6/mm-list_lru-update-kernel-documentation-to-follow-th.patch @@ -0,0 +1,145 @@ +From 60d51bd2b9ea17138ce9886fe3388fa91f126096 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Nov 2023 19:23:17 +0200 +Subject: mm: list_lru: Update kernel documentation to follow the requirements + +From: Andy Shevchenko + +[ Upstream commit 7679e14098c9c3c8118a7130d6e1e9cfe2565c04 ] + +kernel-doc is not happy about documentation in list_lru.h: + +list_lru.h:90: warning: Function parameter or member 'lru' not described in 'list_lru_add' +list_lru.h:90: warning: Excess function parameter 'list_lru' description in 'list_lru_add' +list_lru.h:90: warning: No description found for return value of 'list_lru_add' +list_lru.h:103: warning: Function parameter or member 'lru' not described in 'list_lru_del' +list_lru.h:103: warning: Excess function parameter 'list_lru' description in 'list_lru_del' +list_lru.h:103: warning: No description found for return value of 'list_lru_del' +list_lru.h:116: warning: No description found for return value of 'list_lru_count_one' +list_lru.h:168: warning: No description found for return value of 'list_lru_walk_one' +list_lru.h:185: warning: No description found for return value of 'list_lru_walk_one_irq' + +Fix the documentation accordingly. + +While at it, fix the references to the parameters in functions +inside the long descriptions, on which the above script is not +complaining (yet?). + +Link: https://lkml.kernel.org/r/20231123172320.2434780-1-andriy.shevchenko@linux.intel.com +Signed-off-by: Andy Shevchenko +Cc: Rasmus Villemoes +Signed-off-by: Andrew Morton +Stable-dep-of: 22150a7d401d ("gfs2: Fix slab-use-after-free in qd_put") +Signed-off-by: Sasha Levin +--- + include/linux/list_lru.h | 36 +++++++++++++++++++----------------- + 1 file changed, 19 insertions(+), 17 deletions(-) + +diff --git a/include/linux/list_lru.h b/include/linux/list_lru.h +index b35968ee9fb50..db86ad78d428a 100644 +--- a/include/linux/list_lru.h ++++ b/include/linux/list_lru.h +@@ -73,7 +73,7 @@ void memcg_reparent_list_lrus(struct mem_cgroup *memcg, struct mem_cgroup *paren + + /** + * list_lru_add: add an element to the lru list's tail +- * @list_lru: the lru pointer ++ * @lru: the lru pointer + * @item: the item to be added. + * + * If the element is already part of a list, this function returns doing +@@ -83,22 +83,22 @@ void memcg_reparent_list_lrus(struct mem_cgroup *memcg, struct mem_cgroup *paren + * the caller organize itself in a way that elements can be in more than + * one type of list, it is up to the caller to fully remove the item from + * the previous list (with list_lru_del() for instance) before moving it +- * to @list_lru ++ * to @lru. + * +- * Return value: true if the list was updated, false otherwise ++ * Return: true if the list was updated, false otherwise + */ + bool list_lru_add(struct list_lru *lru, struct list_head *item); + + /** + * list_lru_del: delete an element to the lru list +- * @list_lru: the lru pointer ++ * @lru: the lru pointer + * @item: the item to be deleted. + * +- * This function works analogously as list_lru_add in terms of list ++ * This function works analogously as list_lru_add() in terms of list + * manipulation. The comments about an element already pertaining to +- * a list are also valid for list_lru_del. ++ * a list are also valid for list_lru_del(). + * +- * Return value: true if the list was updated, false otherwise ++ * Return: true if the list was updated, false otherwise + */ + bool list_lru_del(struct list_lru *lru, struct list_head *item); + +@@ -108,9 +108,11 @@ bool list_lru_del(struct list_lru *lru, struct list_head *item); + * @nid: the node id to count from. + * @memcg: the cgroup to count from. + * +- * Always return a non-negative number, 0 for empty lists. There is no +- * guarantee that the list is not updated while the count is being computed. +- * Callers that want such a guarantee need to provide an outer lock. ++ * There is no guarantee that the list is not updated while the count is being ++ * computed. Callers that want such a guarantee need to provide an outer lock. ++ * ++ * Return: 0 for empty lists, otherwise the number of objects ++ * currently held by @lru. + */ + unsigned long list_lru_count_one(struct list_lru *lru, + int nid, struct mem_cgroup *memcg); +@@ -141,7 +143,7 @@ typedef enum lru_status (*list_lru_walk_cb)(struct list_head *item, + struct list_lru_one *list, spinlock_t *lock, void *cb_arg); + + /** +- * list_lru_walk_one: walk a list_lru, isolating and disposing freeable items. ++ * list_lru_walk_one: walk a @lru, isolating and disposing freeable items. + * @lru: the lru pointer. + * @nid: the node id to scan from. + * @memcg: the cgroup to scan from. +@@ -150,24 +152,24 @@ typedef enum lru_status (*list_lru_walk_cb)(struct list_head *item, + * @cb_arg: opaque type that will be passed to @isolate + * @nr_to_walk: how many items to scan. + * +- * This function will scan all elements in a particular list_lru, calling the ++ * This function will scan all elements in a particular @lru, calling the + * @isolate callback for each of those items, along with the current list + * spinlock and a caller-provided opaque. The @isolate callback can choose to + * drop the lock internally, but *must* return with the lock held. The callback +- * will return an enum lru_status telling the list_lru infrastructure what to ++ * will return an enum lru_status telling the @lru infrastructure what to + * do with the object being scanned. + * +- * Please note that nr_to_walk does not mean how many objects will be freed, ++ * Please note that @nr_to_walk does not mean how many objects will be freed, + * just how many objects will be scanned. + * +- * Return value: the number of objects effectively removed from the LRU. ++ * Return: the number of objects effectively removed from the LRU. + */ + unsigned long list_lru_walk_one(struct list_lru *lru, + int nid, struct mem_cgroup *memcg, + list_lru_walk_cb isolate, void *cb_arg, + unsigned long *nr_to_walk); + /** +- * list_lru_walk_one_irq: walk a list_lru, isolating and disposing freeable items. ++ * list_lru_walk_one_irq: walk a @lru, isolating and disposing freeable items. + * @lru: the lru pointer. + * @nid: the node id to scan from. + * @memcg: the cgroup to scan from. +@@ -176,7 +178,7 @@ unsigned long list_lru_walk_one(struct list_lru *lru, + * @cb_arg: opaque type that will be passed to @isolate + * @nr_to_walk: how many items to scan. + * +- * Same as @list_lru_walk_one except that the spinlock is acquired with ++ * Same as list_lru_walk_one() except that the spinlock is acquired with + * spin_lock_irq(). + */ + unsigned long list_lru_walk_one_irq(struct list_lru *lru, +-- +2.51.0 + diff --git a/queue-6.6/mmc-rtsx_pci_sdmmc-increase-power-on-settling-delay-.patch b/queue-6.6/mmc-rtsx_pci_sdmmc-increase-power-on-settling-delay-.patch new file mode 100644 index 0000000000..5788173e3a --- /dev/null +++ b/queue-6.6/mmc-rtsx_pci_sdmmc-increase-power-on-settling-delay-.patch @@ -0,0 +1,40 @@ +From ee90a2e7368895a7248ce1ae82e67a1ef06ea498 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 4 Jan 2026 22:02:36 -0800 +Subject: mmc: rtsx_pci_sdmmc: increase power-on settling delay to 5ms + +From: Matthew Schwartz + +[ Upstream commit aced969e9bf3701dc75cfca57c78c031b7875b9d ] + +The existing 1ms delay in sd_power_on is insufficient and causes resume +errors around 4% of the time. + +Increasing the delay to 5ms resolves this issue after testing 300 +s2idle cycles. + +Fixes: 1f311c94aabd ("mmc: rtsx: add 74 Clocks in power on flow") +Signed-off-by: Matthew Schwartz +Link: https://patch.msgid.link/20260105060236.400366-3-matthew.schwartz@linux.dev +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/mmc/host/rtsx_pci_sdmmc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c +index 195cd25c2e055..4931ee387f3cf 100644 +--- a/drivers/mmc/host/rtsx_pci_sdmmc.c ++++ b/drivers/mmc/host/rtsx_pci_sdmmc.c +@@ -938,7 +938,7 @@ static int sd_power_on(struct realtek_pci_sdmmc *host, unsigned char power_mode) + if (err < 0) + return err; + +- mdelay(1); ++ mdelay(5); + + err = rtsx_pci_write_register(pcr, CARD_OE, SD_OUTPUT_EN, SD_OUTPUT_EN); + if (err < 0) +-- +2.51.0 + diff --git a/queue-6.6/module-add-helper-function-for-reading-module_buildi.patch b/queue-6.6/module-add-helper-function-for-reading-module_buildi.patch new file mode 100644 index 0000000000..727438bce7 --- /dev/null +++ b/queue-6.6/module-add-helper-function-for-reading-module_buildi.patch @@ -0,0 +1,80 @@ +From b43f14104e313bdd474baa2b0f1105e873012f33 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 14:59:16 +0100 +Subject: module: add helper function for reading module_buildid() + +From: Petr Mladek + +[ Upstream commit acfdbb4ab2910ff6f03becb569c23ac7b2223913 ] + +Add a helper function for reading the optional "build_id" member of struct +module. It is going to be used also in ftrace_mod_address_lookup(). + +Use "#ifdef" instead of "#if IS_ENABLED()" to match the declaration of the +optional field in struct module. + +Link: https://lkml.kernel.org/r/20251128135920.217303-4-pmladek@suse.com +Signed-off-by: Petr Mladek +Reviewed-by: Daniel Gomez +Reviewed-by: Petr Pavlu +Cc: Aaron Tomlin +Cc: Alexei Starovoitov +Cc: Daniel Borkman +Cc: John Fastabend +Cc: Kees Cook +Cc: Luis Chamberalin +Cc: Marc Rutland +Cc: "Masami Hiramatsu (Google)" +Cc: Sami Tolvanen +Cc: Steven Rostedt (Google) +Signed-off-by: Andrew Morton +Stable-dep-of: e8a1e7eaa19d ("kallsyms/ftrace: set module buildid in ftrace_mod_address_lookup()") +Signed-off-by: Sasha Levin +--- + include/linux/module.h | 9 +++++++++ + kernel/module/kallsyms.c | 9 ++------- + 2 files changed, 11 insertions(+), 7 deletions(-) + +diff --git a/include/linux/module.h b/include/linux/module.h +index f58d1eb260fa9..10603f725cae5 100644 +--- a/include/linux/module.h ++++ b/include/linux/module.h +@@ -735,6 +735,15 @@ static inline void __module_get(struct module *module) + __mod ? __mod->name : "kernel"; \ + }) + ++static inline const unsigned char *module_buildid(struct module *mod) ++{ ++#ifdef CONFIG_STACKTRACE_BUILD_ID ++ return mod->build_id; ++#else ++ return NULL; ++#endif ++} ++ + /* Dereference module function descriptor */ + void *dereference_module_function_descriptor(struct module *mod, void *ptr); + +diff --git a/kernel/module/kallsyms.c b/kernel/module/kallsyms.c +index ef73ae7c89094..8428089791133 100644 +--- a/kernel/module/kallsyms.c ++++ b/kernel/module/kallsyms.c +@@ -336,13 +336,8 @@ const char *module_address_lookup(unsigned long addr, + if (mod) { + if (modname) + *modname = mod->name; +- if (modbuildid) { +-#if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID) +- *modbuildid = mod->build_id; +-#else +- *modbuildid = NULL; +-#endif +- } ++ if (modbuildid) ++ *modbuildid = module_buildid(mod); + + ret = find_kallsyms_symbol(mod, addr, size, offset); + } +-- +2.51.0 + diff --git a/queue-6.6/mptcp-fix-receive-space-timestamp-initialization.patch b/queue-6.6/mptcp-fix-receive-space-timestamp-initialization.patch new file mode 100644 index 0000000000..afea67e287 --- /dev/null +++ b/queue-6.6/mptcp-fix-receive-space-timestamp-initialization.patch @@ -0,0 +1,92 @@ +From 8c609772cd64b7898dac69cb2300cf8651aff1d9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 19:41:18 +0100 +Subject: mptcp: fix receive space timestamp initialization + +From: Paolo Abeni + +[ Upstream commit 70274765fef555af92a1532d5bd5450c691fca9d ] + +MPTCP initialize the receive buffer stamp in mptcp_rcv_space_init(), +using the provided subflow stamp. Such helper is invoked in several +places; for passive sockets, space init happened at clone time. + +In such scenario, MPTCP ends-up accesses the subflow stamp before +its initialization, leading to quite randomic timing for the first +receive buffer auto-tune event, as the timestamp for newly created +subflow is not refreshed there. + +Fix the issue moving the stamp initialization out of the mentioned helper, +at the data transfer start, and always using a fresh timestamp. + +Fixes: 013e3179dbd2 ("mptcp: fix rcv space initialization") +Reviewed-by: Mat Martineau +Signed-off-by: Paolo Abeni +Signed-off-by: Matthieu Baerts (NGI0) +Link: https://patch.msgid.link/20260203-net-next-mptcp-misc-feat-6-20-v1-2-31ec8bfc56d1@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/mptcp/protocol.c | 8 ++++---- + net/mptcp/protocol.h | 5 +++++ + 2 files changed, 9 insertions(+), 4 deletions(-) + +diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c +index f3856856aa446..85ef9042873be 100644 +--- a/net/mptcp/protocol.c ++++ b/net/mptcp/protocol.c +@@ -2048,8 +2048,8 @@ static void mptcp_rcv_space_adjust(struct mptcp_sock *msk, int copied) + + msk->rcvq_space.copied += copied; + +- mstamp = div_u64(tcp_clock_ns(), NSEC_PER_USEC); +- time = tcp_stamp_us_delta(mstamp, msk->rcvq_space.time); ++ mstamp = mptcp_stamp(); ++ time = tcp_stamp_us_delta(mstamp, READ_ONCE(msk->rcvq_space.time)); + + rtt_us = msk->rcvq_space.rtt_us; + if (rtt_us && time < (rtt_us >> 3)) +@@ -3451,6 +3451,7 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk, + __mptcp_propagate_sndbuf(nsk, ssk); + + mptcp_rcv_space_init(msk, ssk); ++ msk->rcvq_space.time = mptcp_stamp(); + + if (mp_opt->suboptions & OPTION_MPTCP_MPC_ACK) + __mptcp_subflow_fully_established(msk, subflow, mp_opt); +@@ -3468,8 +3469,6 @@ void mptcp_rcv_space_init(struct mptcp_sock *msk, const struct sock *ssk) + msk->rcvq_space.copied = 0; + msk->rcvq_space.rtt_us = 0; + +- msk->rcvq_space.time = tp->tcp_mstamp; +- + /* initial rcv_space offering made to peer */ + msk->rcvq_space.space = min_t(u32, tp->rcv_wnd, + TCP_INIT_CWND * tp->advmss); +@@ -3688,6 +3687,7 @@ void mptcp_finish_connect(struct sock *ssk) + * accessing the field below + */ + WRITE_ONCE(msk->local_key, subflow->local_key); ++ WRITE_ONCE(msk->rcvq_space.time, mptcp_stamp()); + + mptcp_pm_new_connection(msk, ssk, 0); + } +diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h +index 0fbc1f13bd2d4..58805fbf1f961 100644 +--- a/net/mptcp/protocol.h ++++ b/net/mptcp/protocol.h +@@ -786,6 +786,11 @@ static inline bool mptcp_is_fully_established(struct sock *sk) + READ_ONCE(mptcp_sk(sk)->fully_established); + } + ++static inline u64 mptcp_stamp(void) ++{ ++ return div_u64(tcp_clock_ns(), NSEC_PER_USEC); ++} ++ + void mptcp_rcv_space_init(struct mptcp_sock *msk, const struct sock *ssk); + void mptcp_data_ready(struct sock *sk, struct sock *ssk); + bool mptcp_finish_join(struct sock *sk); +-- +2.51.0 + diff --git a/queue-6.6/mtd-parsers-fix-memory-leak-in-mtd_parser_tplink_saf.patch b/queue-6.6/mtd-parsers-fix-memory-leak-in-mtd_parser_tplink_saf.patch new file mode 100644 index 0000000000..ff64e5cc2f --- /dev/null +++ b/queue-6.6/mtd-parsers-fix-memory-leak-in-mtd_parser_tplink_saf.patch @@ -0,0 +1,42 @@ +From c2cc81ab78b49cbef8258f3aaef79e96cff55561 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 13:09:50 +0000 +Subject: mtd: parsers: Fix memory leak in mtd_parser_tplink_safeloader_parse() + +From: Zilin Guan + +[ Upstream commit 980ce2b02dd06a4fdf5fee38b2e14becf9cf7b8b ] + +The function mtd_parser_tplink_safeloader_parse() allocates buf via +mtd_parser_tplink_safeloader_read_table(). If the allocation for +parts[idx].name fails inside the loop, the code jumps to the err_free +label without freeing buf, leading to a memory leak. + +Fix this by freeing the temporary buffer buf in the err_free label. + +Compile tested only. Issue found using a prototype static analysis tool +and code review. + +Fixes: 00a3588084be ("mtd: parsers: add TP-Link SafeLoader partitions table parser") +Signed-off-by: Zilin Guan +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/parsers/tplink_safeloader.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/mtd/parsers/tplink_safeloader.c b/drivers/mtd/parsers/tplink_safeloader.c +index 1c689dafca2ae..3580c79e3277e 100644 +--- a/drivers/mtd/parsers/tplink_safeloader.c ++++ b/drivers/mtd/parsers/tplink_safeloader.c +@@ -116,6 +116,7 @@ static int mtd_parser_tplink_safeloader_parse(struct mtd_info *mtd, + return idx; + + err_free: ++ kfree(buf); + for (idx -= 1; idx >= 0; idx--) + kfree(parts[idx].name); + err_free_parts: +-- +2.51.0 + diff --git a/queue-6.6/mtd-parsers-ofpart-fix-of-node-refcount-leak-in-pars.patch b/queue-6.6/mtd-parsers-ofpart-fix-of-node-refcount-leak-in-pars.patch new file mode 100644 index 0000000000..ba3bb2b622 --- /dev/null +++ b/queue-6.6/mtd-parsers-ofpart-fix-of-node-refcount-leak-in-pars.patch @@ -0,0 +1,84 @@ +From 1a78080512dd8217032f7fb43f6ee3aeab74bc55 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 05:26:08 +0000 +Subject: mtd: parsers: ofpart: fix OF node refcount leak in + parse_fixed_partitions() + +From: Weigang He + +[ Upstream commit 7cce81df7d26d44123bd7620715c8349d96793d7 ] + +of_get_child_by_name() returns a node pointer with refcount incremented, +which must be released with of_node_put() when done. However, in +parse_fixed_partitions(), when dedicated is true (i.e., a "partitions" +subnode was found), the ofpart_node obtained from of_get_child_by_name() +is never released on any code path. + +Add of_node_put(ofpart_node) calls on all exit paths when dedicated is +true to fix the reference count leak. + +This bug was detected by our static analysis tool. + +Fixes: 562b4e91d3b2 ("mtd: parsers: ofpart: fix parsing subpartitions") +Signed-off-by: Weigang He +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/parsers/ofpart_core.c | 16 ++++++++++++++-- + 1 file changed, 14 insertions(+), 2 deletions(-) + +diff --git a/drivers/mtd/parsers/ofpart_core.c b/drivers/mtd/parsers/ofpart_core.c +index e7b8e9d0a9103..3cf75b56d5a2e 100644 +--- a/drivers/mtd/parsers/ofpart_core.c ++++ b/drivers/mtd/parsers/ofpart_core.c +@@ -77,6 +77,7 @@ static int parse_fixed_partitions(struct mtd_info *master, + of_id = of_match_node(parse_ofpart_match_table, ofpart_node); + if (dedicated && !of_id) { + /* The 'partitions' subnode might be used by another parser */ ++ of_node_put(ofpart_node); + return 0; + } + +@@ -91,12 +92,18 @@ static int parse_fixed_partitions(struct mtd_info *master, + nr_parts++; + } + +- if (nr_parts == 0) ++ if (nr_parts == 0) { ++ if (dedicated) ++ of_node_put(ofpart_node); + return 0; ++ } + + parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL); +- if (!parts) ++ if (!parts) { ++ if (dedicated) ++ of_node_put(ofpart_node); + return -ENOMEM; ++ } + + i = 0; + for_each_child_of_node(ofpart_node, pp) { +@@ -175,6 +182,9 @@ static int parse_fixed_partitions(struct mtd_info *master, + if (quirks && quirks->post_parse) + quirks->post_parse(master, parts, nr_parts); + ++ if (dedicated) ++ of_node_put(ofpart_node); ++ + *pparts = parts; + return nr_parts; + +@@ -183,6 +193,8 @@ static int parse_fixed_partitions(struct mtd_info *master, + master->name, pp, mtd_node); + ret = -EINVAL; + ofpart_none: ++ if (dedicated) ++ of_node_put(ofpart_node); + of_node_put(pp); + kfree(parts); + return ret; +-- +2.51.0 + diff --git a/queue-6.6/mtd-rawnand-cadence-fix-return-type-of-cdma-send-and.patch b/queue-6.6/mtd-rawnand-cadence-fix-return-type-of-cdma-send-and.patch new file mode 100644 index 0000000000..b374ff69f5 --- /dev/null +++ b/queue-6.6/mtd-rawnand-cadence-fix-return-type-of-cdma-send-and.patch @@ -0,0 +1,40 @@ +From bc13305342190382c01561a95c32ad054055b0f1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 19 Dec 2025 03:09:30 -0800 +Subject: mtd: rawnand: cadence: Fix return type of CDMA send-and-wait helper + +From: Alok Tiwari + +[ Upstream commit 6d8226cbbf124bb5613b532216b74c886a4361b7 ] + +cadence_nand_cdma_send_and_wait() propagates negative errno values +from cadence_nand_cdma_send(), returns -ETIMEDOUT on failure and -EIO +when the CDMA engine reports a command failure. + +However, it is declared as u32, causing error codes to wrap. +Change the return type to int to correctly propagate errors. + +Fixes: ec4ba01e894d ("mtd: rawnand: Add new Cadence NAND driver to MTD subsystem") +Signed-off-by: Alok Tiwari +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/nand/raw/cadence-nand-controller.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/nand/raw/cadence-nand-controller.c b/drivers/mtd/nand/raw/cadence-nand-controller.c +index 202b4fc064fa3..0831feb58e13d 100644 +--- a/drivers/mtd/nand/raw/cadence-nand-controller.c ++++ b/drivers/mtd/nand/raw/cadence-nand-controller.c +@@ -1018,7 +1018,7 @@ static int cadence_nand_cdma_send(struct cdns_nand_ctrl *cdns_ctrl, + } + + /* Send SDMA command and wait for finish. */ +-static u32 ++static int + cadence_nand_cdma_send_and_wait(struct cdns_nand_ctrl *cdns_ctrl, + u8 thread) + { +-- +2.51.0 + diff --git a/queue-6.6/mtd-spinand-fix-kernel-doc.patch b/queue-6.6/mtd-spinand-fix-kernel-doc.patch new file mode 100644 index 0000000000..0d34bdcade --- /dev/null +++ b/queue-6.6/mtd-spinand-fix-kernel-doc.patch @@ -0,0 +1,36 @@ +From 67a570ff90a5672a69bc4a9d89909d969c679c6c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 18:18:02 +0100 +Subject: mtd: spinand: Fix kernel doc + +From: Miquel Raynal + +[ Upstream commit a57b1f07d2d35843a7ada30c8cf9a215c0931868 ] + +The @data buffer is 5 bytes, not 4, it has been extended for the need of +devices with an extra ID bytes. + +Fixes: 34a956739d29 ("mtd: spinand: Add support for 5-byte IDs") +Reviewed-by: Tudor Ambarus +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + include/linux/mtd/spinand.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h +index 5c2ccc6494529..980e1fdf67eda 100644 +--- a/include/linux/mtd/spinand.h ++++ b/include/linux/mtd/spinand.h +@@ -195,7 +195,7 @@ struct spinand_device; + + /** + * struct spinand_id - SPI NAND id structure +- * @data: buffer containing the id bytes. Currently 4 bytes large, but can ++ * @data: buffer containing the id bytes. Currently 5 bytes large, but can + * be extended if required + * @len: ID length + */ +-- +2.51.0 + diff --git a/queue-6.6/net-add-skb_dstref_steal-and-skb_dstref_restore.patch b/queue-6.6/net-add-skb_dstref_steal-and-skb_dstref_restore.patch new file mode 100644 index 0000000000..9bf0424d68 --- /dev/null +++ b/queue-6.6/net-add-skb_dstref_steal-and-skb_dstref_restore.patch @@ -0,0 +1,73 @@ +From 6d1f70c0739c8a887afde56fdcc71e881d2886ed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 18 Aug 2025 08:40:26 -0700 +Subject: net: Add skb_dstref_steal and skb_dstref_restore + +From: Stanislav Fomichev + +[ Upstream commit c3f0c02997c7f8489fec259e28e0e04e9811edac ] + +Going forward skb_dst_set will assert that skb dst_entry +is empty during skb_dst_set to prevent potential leaks. There +are few places that still manually manage dst_entry not using +the helpers. Convert them to the following new helpers: +- skb_dstref_steal that resets dst_entry and returns previous dst_entry + value +- skb_dstref_restore that restores dst_entry previously reset via + skb_dstref_steal + +Signed-off-by: Stanislav Fomichev +Link: https://patch.msgid.link/20250818154032.3173645-2-sdf@fomichev.me +Signed-off-by: Jakub Kicinski +Stable-dep-of: 81b84de32bb2 ("xfrm: fix ip_rt_bug race in icmp_route_lookup reverse path") +Signed-off-by: Sasha Levin +--- + include/linux/skbuff.h | 32 ++++++++++++++++++++++++++++++++ + 1 file changed, 32 insertions(+) + +diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h +index 69b392dc10aa3..1a91645fa2497 100644 +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -1122,6 +1122,38 @@ static inline struct dst_entry *skb_dst(const struct sk_buff *skb) + return (struct dst_entry *)(skb->_skb_refdst & SKB_DST_PTRMASK); + } + ++/** ++ * skb_dstref_steal() - return current dst_entry value and clear it ++ * @skb: buffer ++ * ++ * Resets skb dst_entry without adjusting its reference count. Useful in ++ * cases where dst_entry needs to be temporarily reset and restored. ++ * Note that the returned value cannot be used directly because it ++ * might contain SKB_DST_NOREF bit. ++ * ++ * When in doubt, prefer skb_dst_drop() over skb_dstref_steal() to correctly ++ * handle dst_entry reference counting. ++ * ++ * Returns: original skb dst_entry. ++ */ ++static inline unsigned long skb_dstref_steal(struct sk_buff *skb) ++{ ++ unsigned long refdst = skb->_skb_refdst; ++ ++ skb->_skb_refdst = 0; ++ return refdst; ++} ++ ++/** ++ * skb_dstref_restore() - restore skb dst_entry removed via skb_dstref_steal() ++ * @skb: buffer ++ * @refdst: dst entry from a call to skb_dstref_steal() ++ */ ++static inline void skb_dstref_restore(struct sk_buff *skb, unsigned long refdst) ++{ ++ skb->_skb_refdst = refdst; ++} ++ + /** + * skb_dst_set - sets skb dst + * @skb: buffer +-- +2.51.0 + diff --git a/queue-6.6/net-atm-fix-crash-due-to-unvalidated-vcc-pointer-in-.patch b/queue-6.6/net-atm-fix-crash-due-to-unvalidated-vcc-pointer-in-.patch new file mode 100644 index 0000000000..74020bdda3 --- /dev/null +++ b/queue-6.6/net-atm-fix-crash-due-to-unvalidated-vcc-pointer-in-.patch @@ -0,0 +1,154 @@ +From 1028611c067a0ee4c17f31d6c19e48bebe363d7d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 17:54:51 +0800 +Subject: net: atm: fix crash due to unvalidated vcc pointer in sigd_send() + +From: Jiayuan Chen + +[ Upstream commit ae88a5d2f29b69819dc7b04086734439d074a643 ] + +Reproducer available at [1]. + +The ATM send path (sendmsg -> vcc_sendmsg -> sigd_send) reads the vcc +pointer from msg->vcc and uses it directly without any validation. This +pointer comes from userspace via sendmsg() and can be arbitrarily forged: + + int fd = socket(AF_ATMSVC, SOCK_DGRAM, 0); + ioctl(fd, ATMSIGD_CTRL); // become ATM signaling daemon + struct msghdr msg = { .msg_iov = &iov, ... }; + *(unsigned long *)(buf + 4) = 0xdeadbeef; // fake vcc pointer + sendmsg(fd, &msg, 0); // kernel dereferences 0xdeadbeef + +In normal operation, the kernel sends the vcc pointer to the signaling +daemon via sigd_enq() when processing operations like connect(), bind(), +or listen(). The daemon is expected to return the same pointer when +responding. However, a malicious daemon can send arbitrary pointer values. + +Fix this by introducing find_get_vcc() which validates the pointer by +searching through vcc_hash (similar to how sigd_close() iterates over +all VCCs), and acquires a reference via sock_hold() if found. + +Since struct atm_vcc embeds struct sock as its first member, they share +the same lifetime. Therefore using sock_hold/sock_put is sufficient to +keep the vcc alive while it is being used. + +Note that there may be a race with sigd_close() which could mark the vcc +with various flags (e.g., ATM_VF_RELEASED) after find_get_vcc() returns. +However, sock_hold() guarantees the memory remains valid, so this race +only affects the logical state, not memory safety. + +[1]: https://gist.github.com/mrpre/1ba5949c45529c511152e2f4c755b0f3 +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: syzbot+1f22cb1769f249df9fa0@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/69039850.a70a0220.5b2ed.005d.GAE@google.com/T/ +Signed-off-by: Jiayuan Chen +Link: https://patch.msgid.link/20260205095501.131890-1-jiayuan.chen@linux.dev +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/atm/signaling.c | 56 +++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 54 insertions(+), 2 deletions(-) + +diff --git a/net/atm/signaling.c b/net/atm/signaling.c +index e70ae2c113f95..358fbe5e4d1d0 100644 +--- a/net/atm/signaling.c ++++ b/net/atm/signaling.c +@@ -22,6 +22,36 @@ + + struct atm_vcc *sigd = NULL; + ++/* ++ * find_get_vcc - validate and get a reference to a vcc pointer ++ * @vcc: the vcc pointer to validate ++ * ++ * This function validates that @vcc points to a registered VCC in vcc_hash. ++ * If found, it increments the socket reference count and returns the vcc. ++ * The caller must call sock_put(sk_atm(vcc)) when done. ++ * ++ * Returns the vcc pointer if valid, NULL otherwise. ++ */ ++static struct atm_vcc *find_get_vcc(struct atm_vcc *vcc) ++{ ++ int i; ++ ++ read_lock(&vcc_sklist_lock); ++ for (i = 0; i < VCC_HTABLE_SIZE; i++) { ++ struct sock *s; ++ ++ sk_for_each(s, &vcc_hash[i]) { ++ if (atm_sk(s) == vcc) { ++ sock_hold(s); ++ read_unlock(&vcc_sklist_lock); ++ return vcc; ++ } ++ } ++ } ++ read_unlock(&vcc_sklist_lock); ++ return NULL; ++} ++ + static void sigd_put_skb(struct sk_buff *skb) + { + if (!sigd) { +@@ -69,7 +99,14 @@ static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb) + + msg = (struct atmsvc_msg *) skb->data; + WARN_ON(refcount_sub_and_test(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc)); +- vcc = *(struct atm_vcc **) &msg->vcc; ++ ++ vcc = find_get_vcc(*(struct atm_vcc **)&msg->vcc); ++ if (!vcc) { ++ pr_debug("invalid vcc pointer in msg\n"); ++ dev_kfree_skb(skb); ++ return -EINVAL; ++ } ++ + pr_debug("%d (0x%lx)\n", (int)msg->type, (unsigned long)vcc); + sk = sk_atm(vcc); + +@@ -100,7 +137,16 @@ static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb) + clear_bit(ATM_VF_WAITING, &vcc->flags); + break; + case as_indicate: +- vcc = *(struct atm_vcc **)&msg->listen_vcc; ++ /* Release the reference from msg->vcc, we'll use msg->listen_vcc instead */ ++ sock_put(sk); ++ ++ vcc = find_get_vcc(*(struct atm_vcc **)&msg->listen_vcc); ++ if (!vcc) { ++ pr_debug("invalid listen_vcc pointer in msg\n"); ++ dev_kfree_skb(skb); ++ return -EINVAL; ++ } ++ + sk = sk_atm(vcc); + pr_debug("as_indicate!!!\n"); + lock_sock(sk); +@@ -115,6 +161,8 @@ static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb) + sk->sk_state_change(sk); + as_indicate_complete: + release_sock(sk); ++ /* Paired with find_get_vcc(msg->listen_vcc) above */ ++ sock_put(sk); + return 0; + case as_close: + set_bit(ATM_VF_RELEASED, &vcc->flags); +@@ -131,11 +179,15 @@ static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb) + break; + default: + pr_alert("bad message type %d\n", (int)msg->type); ++ /* Paired with find_get_vcc(msg->vcc) above */ ++ sock_put(sk); + return -EINVAL; + } + sk->sk_state_change(sk); + out: + dev_kfree_skb(skb); ++ /* Paired with find_get_vcc(msg->vcc) above */ ++ sock_put(sk); + return 0; + } + +-- +2.51.0 + diff --git a/queue-6.6/net-hns3-fix-double-free-issue-for-tx-spare-buffer.patch b/queue-6.6/net-hns3-fix-double-free-issue-for-tx-spare-buffer.patch new file mode 100644 index 0000000000..c0a9e6a675 --- /dev/null +++ b/queue-6.6/net-hns3-fix-double-free-issue-for-tx-spare-buffer.patch @@ -0,0 +1,74 @@ +From 06645ce94efdbc592623be8726f1c9690f3d6743 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 20:17:19 +0800 +Subject: net: hns3: fix double free issue for tx spare buffer + +From: Jian Shen + +[ Upstream commit 6d2f142b1e4b203387a92519d9d2e34752a79dbb ] + +In hns3_set_ringparam(), a temporary copy (tmp_rings) of the ring structure +is created for rollback. However, the tx_spare pointer in the original +ring handle is incorrectly left pointing to the old backup memory. + +Later, if memory allocation fails in hns3_init_all_ring() during the setup, +the error path attempts to free all newly allocated rings. Since tx_spare +contains a stale (non-NULL) pointer from the backup, it is mistaken for +a newly allocated buffer and is erroneously freed, leading to a double-free +of the backup memory. + +The root cause is that the tx_spare field was not cleared after its value +was saved in tmp_rings, leaving a dangling pointer. + +Fix this by setting tx_spare to NULL in the original ring structure +when the creation of the new `tx_spare` fails. This ensures the +error cleanup path only frees genuinely newly allocated buffers. + +Fixes: 907676b130711 ("net: hns3: use tx bounce buffer for small packets") +Signed-off-by: Jian Shen +Signed-off-by: Jijie Shao +Reviewed-by: Jacob Keller +Link: https://patch.msgid.link/20260205121719.3285730-1-shaojijie@huawei.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +index 34627de2e311e..107e692e8c87a 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +@@ -1048,13 +1048,13 @@ static void hns3_init_tx_spare_buffer(struct hns3_enet_ring *ring) + int order; + + if (!alloc_size) +- return; ++ goto not_init; + + order = get_order(alloc_size); + if (order > MAX_ORDER) { + if (net_ratelimit()) + dev_warn(ring_to_dev(ring), "failed to allocate tx spare buffer, exceed to max order\n"); +- return; ++ goto not_init; + } + + tx_spare = devm_kzalloc(ring_to_dev(ring), sizeof(*tx_spare), +@@ -1092,6 +1092,13 @@ static void hns3_init_tx_spare_buffer(struct hns3_enet_ring *ring) + devm_kfree(ring_to_dev(ring), tx_spare); + devm_kzalloc_error: + ring->tqp->handle->kinfo.tx_spare_buf_size = 0; ++not_init: ++ /* When driver init or reset_init, the ring->tx_spare is always NULL; ++ * but when called from hns3_set_ringparam, it's usually not NULL, and ++ * will be restored if hns3_init_all_ring() failed. So it's safe to set ++ * ring->tx_spare to NULL here. ++ */ ++ ring->tx_spare = NULL; + } + + /* Use hns3_tx_spare_space() to make sure there is enough buffer +-- +2.51.0 + diff --git a/queue-6.6/net-mctp-i2c-fix-duplicate-reception-of-old-data.patch b/queue-6.6/net-mctp-i2c-fix-duplicate-reception-of-old-data.patch new file mode 100644 index 0000000000..7a731cbfff --- /dev/null +++ b/queue-6.6/net-mctp-i2c-fix-duplicate-reception-of-old-data.patch @@ -0,0 +1,49 @@ +From 3d6558db240cc2f734798e708759c2477de51c44 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 18:18:29 +0800 +Subject: net: mctp-i2c: fix duplicate reception of old data + +From: Jian Zhang + +[ Upstream commit ae4744e173fadd092c43eda4ca92dcb74645225a ] + +The MCTP I2C slave callback did not handle I2C_SLAVE_READ_REQUESTED +events. As a result, i2c read event will trigger repeated reception of +old data, reset rx_pos when a read request is received. + +Signed-off-by: Jian Zhang +Link: https://patch.msgid.link/20260108101829.1140448-1-zhangjian.3032@bytedance.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 2a14e91b6d76 ("mctp i2c: initialise event handler read bytes") +Signed-off-by: Sasha Levin +--- + drivers/net/mctp/mctp-i2c.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/mctp/mctp-i2c.c b/drivers/net/mctp/mctp-i2c.c +index fbe8483a07b58..079fb7ca97b62 100644 +--- a/drivers/net/mctp/mctp-i2c.c ++++ b/drivers/net/mctp/mctp-i2c.c +@@ -243,6 +243,9 @@ static int mctp_i2c_slave_cb(struct i2c_client *client, + return 0; + + switch (event) { ++ case I2C_SLAVE_READ_REQUESTED: ++ midev->rx_pos = 0; ++ break; + case I2C_SLAVE_WRITE_RECEIVED: + if (midev->rx_pos < MCTP_I2C_BUFSZ) { + midev->rx_buffer[midev->rx_pos] = *val; +@@ -280,6 +283,9 @@ static int mctp_i2c_recv(struct mctp_i2c_dev *midev) + size_t recvlen; + int status; + ++ if (midev->rx_pos == 0) ++ return 0; ++ + /* + 1 for the PEC */ + if (midev->rx_pos < MCTP_I2C_MINLEN + 1) { + ndev->stats.rx_length_errors++; +-- +2.51.0 + diff --git a/queue-6.6/net-sunhme-fix-sbus-regression.patch b/queue-6.6/net-sunhme-fix-sbus-regression.patch new file mode 100644 index 0000000000..b6ed17bbb2 --- /dev/null +++ b/queue-6.6/net-sunhme-fix-sbus-regression.patch @@ -0,0 +1,73 @@ +From db176b8624eb6271da6e660d83a7be2da48cd13c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 17:09:59 +0100 +Subject: net: sunhme: Fix sbus regression +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: René Rebe + +[ Upstream commit 8c5d17834ec104d0abd1bda52fbc04e647fab274 ] + +Commit cc216e4b44ce ("net: sunhme: Switch SBUS to devres") changed +explicit sized of_ioremap with BMAC_REG_SIZEs to +devm_platform_ioremap_resource mapping all the resource. However, +this does not work on my Sun Ultra 2 with SBUS HMEs: + +hme f0072f38: error -EBUSY: can't request region for resource [mem 0x1ffe8c07000-0x1ffe8c0701f] +hme f0072f38: Cannot map TCVR registers. +hme f0072f38: probe with driver hme failed with error -16 +hme f007ab44: error -EBUSY: can't request region for resource [mem 0x1ff28c07000-0x1ff28c0701f] +hme f007ab44: Cannot map TCVR registers. +hme f007ab44: probe with driver hme failed with error -16 + +Turns out the open-firmware resources overlap, at least on this +machines and PROM version: + +hexdump /proc/device-tree/sbus@1f,0/SUNW,hme@2,8c00000/reg: +00 00 00 02 08 c0 00 00 00 00 01 08 +00 00 00 02 08 c0 20 00 00 00 20 00 +00 00 00 02 08 c0 40 00 00 00 20 00 +00 00 00 02 08 c0 60 00 00 00 20 00 +00 00 00 02 08 c0 70 00 00 00 00 20 + +And the driver previously explicitly mapped way smaller mmio regions: + +/proc/iomem: +1ff28c00000-1ff28c00107 : HME Global Regs +1ff28c02000-1ff28c02033 : HME TX Regs +1ff28c04000-1ff28c0401f : HME RX Regs +1ff28c06000-1ff28c0635f : HME BIGMAC Regs +1ff28c07000-1ff28c0701f : HME Tranceiver Regs + +Quirk this specific issue by truncating the previous resource to not +overlap into the TCVR registers. + +Fixes: cc216e4b44ce ("net: sunhme: Switch SBUS to devres") +Signed-off-by: René Rebe +Reviewed-by: Sean Anderson +Link: https://patch.msgid.link/20260205.170959.89574674688839340.rene@exactco.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/sun/sunhme.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/ethernet/sun/sunhme.c b/drivers/net/ethernet/sun/sunhme.c +index b983b9c23be68..61ca7377b612c 100644 +--- a/drivers/net/ethernet/sun/sunhme.c ++++ b/drivers/net/ethernet/sun/sunhme.c +@@ -2551,6 +2551,9 @@ static int happy_meal_sbus_probe_one(struct platform_device *op, int is_qfe) + goto err_out_clear_quattro; + } + ++ /* BIGMAC may have bogus sizes */ ++ if ((op->resource[3].end - op->resource[3].start) >= BMAC_REG_SIZE) ++ op->resource[3].end = op->resource[3].start + BMAC_REG_SIZE - 1; + hp->bigmacregs = devm_platform_ioremap_resource(op, 3); + if (IS_ERR(hp->bigmacregs)) { + dev_err(&op->dev, "Cannot map BIGMAC registers.\n"); +-- +2.51.0 + diff --git a/queue-6.6/net-switch-to-skb_dstref_steal-skb_dstref_restore-fo.patch b/queue-6.6/net-switch-to-skb_dstref_steal-skb_dstref_restore-fo.patch new file mode 100644 index 0000000000..6015627832 --- /dev/null +++ b/queue-6.6/net-switch-to-skb_dstref_steal-skb_dstref_restore-fo.patch @@ -0,0 +1,75 @@ +From c90bd7271f3f071371cc0a3529c8c2ef7904fdb9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 18 Aug 2025 08:40:29 -0700 +Subject: net: Switch to skb_dstref_steal/skb_dstref_restore for ip_route_input + callers + +From: Stanislav Fomichev + +[ Upstream commit e97e6a1830ddb5885ba312e56b6fa3aa39b5f47e ] + +Going forward skb_dst_set will assert that skb dst_entry +is empty during skb_dst_set. skb_dstref_steal is added to reset +existing entry without doing refcnt. skb_dstref_restore should +be used to restore the previous entry. Convert icmp_route_lookup +and ip_options_rcv_srr to these helpers. Add extra call to +skb_dstref_reset to icmp_route_lookup to clear the ip_route_input +entry. + +Signed-off-by: Stanislav Fomichev +Link: https://patch.msgid.link/20250818154032.3173645-5-sdf@fomichev.me +Signed-off-by: Jakub Kicinski +Stable-dep-of: 81b84de32bb2 ("xfrm: fix ip_rt_bug race in icmp_route_lookup reverse path") +Signed-off-by: Sasha Levin +--- + net/ipv4/icmp.c | 7 ++++--- + net/ipv4/ip_options.c | 5 ++--- + 2 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c +index f3cdfc09d7f06..efa589a1e7a38 100644 +--- a/net/ipv4/icmp.c ++++ b/net/ipv4/icmp.c +@@ -546,14 +546,15 @@ static struct rtable *icmp_route_lookup(struct net *net, struct flowi4 *fl4, + goto relookup_failed; + } + /* Ugh! */ +- orefdst = skb_in->_skb_refdst; /* save old refdst */ +- skb_dst_set(skb_in, NULL); ++ orefdst = skb_dstref_steal(skb_in); + err = ip_route_input(skb_in, fl4_dec.daddr, fl4_dec.saddr, + dscp, rt2->dst.dev); + + dst_release(&rt2->dst); + rt2 = skb_rtable(skb_in); +- skb_in->_skb_refdst = orefdst; /* restore old refdst */ ++ /* steal dst entry from skb_in, don't drop refcnt */ ++ skb_dstref_steal(skb_in); ++ skb_dstref_restore(skb_in, orefdst); + } + + if (err) +diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c +index b4c59708fc095..d898e1523a453 100644 +--- a/net/ipv4/ip_options.c ++++ b/net/ipv4/ip_options.c +@@ -615,14 +615,13 @@ int ip_options_rcv_srr(struct sk_buff *skb, struct net_device *dev) + } + memcpy(&nexthop, &optptr[srrptr-1], 4); + +- orefdst = skb->_skb_refdst; +- skb_dst_set(skb, NULL); ++ orefdst = skb_dstref_steal(skb); + err = ip_route_input(skb, nexthop, iph->saddr, ip4h_dscp(iph), + dev); + rt2 = skb_rtable(skb); + if (err || (rt2->rt_type != RTN_UNICAST && rt2->rt_type != RTN_LOCAL)) { + skb_dst_drop(skb); +- skb->_skb_refdst = orefdst; ++ skb_dstref_restore(skb, orefdst); + return -EINVAL; + } + refdst_drop(orefdst); +-- +2.51.0 + diff --git a/queue-6.6/netfilter-nf_conncount-fix-tracking-of-connections-f.patch b/queue-6.6/netfilter-nf_conncount-fix-tracking-of-connections-f.patch new file mode 100644 index 0000000000..b1efcffa49 --- /dev/null +++ b/queue-6.6/netfilter-nf_conncount-fix-tracking-of-connections-f.patch @@ -0,0 +1,69 @@ +From 9d67a84a90e1299e1bc3c81fa097897f7d60bc10 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 21:35:46 +0100 +Subject: netfilter: nf_conncount: fix tracking of connections from localhost + +From: Fernando Fernandez Mancera + +[ Upstream commit de8a70cefcb26cdceaafdc5ac144712681419c29 ] + +Since commit be102eb6a0e7 ("netfilter: nf_conncount: rework API to use +sk_buff directly"), we skip the adding and trigger a GC when the ct is +confirmed. For connections originated from local to local it doesn't +work because the connection is confirmed on POSTROUTING, therefore +tracking on the INPUT hook is always skipped. + +In order to fix this, we check whether skb input ifindex is set to +loopback ifindex. If it is then we fallback on a GC plus track operation +skipping the optimization. This fallback is necessary to avoid +duplicated tracking of a packet train e.g 10 UDP datagrams sent on a +burst when initiating the connection. + +Tested with xt_connlimit/nft_connlimit and OVS limit and with a HTTP +server and iperf3 on UDP mode. + +Fixes: be102eb6a0e7 ("netfilter: nf_conncount: rework API to use sk_buff directly") +Reported-by: Michal Slabihoudek +Closes: https://lore.kernel.org/netfilter/6989BD9F-8C24-4397-9AD7-4613B28BF0DB@gooddata.com/ +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_conncount.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +diff --git a/net/netfilter/nf_conncount.c b/net/netfilter/nf_conncount.c +index 47bdd8d121bb5..ae9ad439449fa 100644 +--- a/net/netfilter/nf_conncount.c ++++ b/net/netfilter/nf_conncount.c +@@ -179,14 +179,25 @@ static int __nf_conncount_add(struct net *net, + return -ENOENT; + + if (ct && nf_ct_is_confirmed(ct)) { +- err = -EEXIST; +- goto out_put; ++ /* local connections are confirmed in postrouting so confirmation ++ * might have happened before hitting connlimit ++ */ ++ if (skb->skb_iif != LOOPBACK_IFINDEX) { ++ err = -EEXIST; ++ goto out_put; ++ } ++ ++ /* this is likely a local connection, skip optimization to avoid ++ * adding duplicates from a 'packet train' ++ */ ++ goto check_connections; + } + + if ((u32)jiffies == list->last_gc && + (list->count - list->last_gc_count) < CONNCOUNT_GC_MAX_COLLECT) + goto add_new_node; + ++check_connections: + /* check the saved connections */ + list_for_each_entry_safe(conn, conn_n, &list->head, node) { + if (collect > CONNCOUNT_GC_MAX_COLLECT) +-- +2.51.0 + diff --git a/queue-6.6/netfilter-nf_conncount-increase-the-connection-clean.patch b/queue-6.6/netfilter-nf_conncount-increase-the-connection-clean.patch new file mode 100644 index 0000000000..bf81a11af3 --- /dev/null +++ b/queue-6.6/netfilter-nf_conncount-increase-the-connection-clean.patch @@ -0,0 +1,123 @@ +From 886cc838c44b6401892f9176bee89bf783238777 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 17 Dec 2025 15:46:41 +0100 +Subject: netfilter: nf_conncount: increase the connection clean up limit to 64 + +From: Fernando Fernandez Mancera + +[ Upstream commit 21d033e472735ecec677f1ae46d6740b5e47a4f3 ] + +After the optimization to only perform one GC per jiffy, a new problem +was introduced. If more than 8 new connections are tracked per jiffy the +list won't be cleaned up fast enough possibly reaching the limit +wrongly. + +In order to prevent this issue, only skip the GC if it was already +triggered during the same jiffy and the increment is lower than the +clean up limit. In addition, increase the clean up limit to 64 +connections to avoid triggering GC too often and do more effective GCs. + +This has been tested using a HTTP server and several +performance tools while having nft_connlimit/xt_connlimit or OVS limit +configured. + +Output of slowhttptest + OVS limit at 52000 connections: + + slow HTTP test status on 340th second: + initializing: 0 + pending: 432 + connected: 51998 + error: 0 + closed: 0 + service available: YES + +Fixes: d265929930e2 ("netfilter: nf_conncount: reduce unnecessary GC") +Reported-by: Aleksandra Rukomoinikova +Closes: https://lore.kernel.org/netfilter/b2064e7b-0776-4e14-adb6-c68080987471@k2.cloud/ +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + include/net/netfilter/nf_conntrack_count.h | 1 + + net/netfilter/nf_conncount.c | 15 ++++++++++----- + 2 files changed, 11 insertions(+), 5 deletions(-) + +diff --git a/include/net/netfilter/nf_conntrack_count.h b/include/net/netfilter/nf_conntrack_count.h +index 115bb7e572f7d..bf22661925b81 100644 +--- a/include/net/netfilter/nf_conntrack_count.h ++++ b/include/net/netfilter/nf_conntrack_count.h +@@ -13,6 +13,7 @@ struct nf_conncount_list { + u32 last_gc; /* jiffies at most recent gc */ + struct list_head head; /* connections with the same filtering key */ + unsigned int count; /* length of list */ ++ unsigned int last_gc_count; /* length of list at most recent gc */ + }; + + struct nf_conncount_data *nf_conncount_init(struct net *net, unsigned int family, +diff --git a/net/netfilter/nf_conncount.c b/net/netfilter/nf_conncount.c +index 70e9662fe1777..47bdd8d121bb5 100644 +--- a/net/netfilter/nf_conncount.c ++++ b/net/netfilter/nf_conncount.c +@@ -34,8 +34,9 @@ + + #define CONNCOUNT_SLOTS 256U + +-#define CONNCOUNT_GC_MAX_NODES 8 +-#define MAX_KEYLEN 5 ++#define CONNCOUNT_GC_MAX_NODES 8 ++#define CONNCOUNT_GC_MAX_COLLECT 64 ++#define MAX_KEYLEN 5 + + /* we will save the tuples of all connections we care about */ + struct nf_conncount_tuple { +@@ -182,12 +183,13 @@ static int __nf_conncount_add(struct net *net, + goto out_put; + } + +- if ((u32)jiffies == list->last_gc) ++ if ((u32)jiffies == list->last_gc && ++ (list->count - list->last_gc_count) < CONNCOUNT_GC_MAX_COLLECT) + goto add_new_node; + + /* check the saved connections */ + list_for_each_entry_safe(conn, conn_n, &list->head, node) { +- if (collect > CONNCOUNT_GC_MAX_NODES) ++ if (collect > CONNCOUNT_GC_MAX_COLLECT) + break; + + found = find_or_evict(net, list, conn); +@@ -230,6 +232,7 @@ static int __nf_conncount_add(struct net *net, + nf_ct_put(found_ct); + } + list->last_gc = (u32)jiffies; ++ list->last_gc_count = list->count; + + add_new_node: + if (WARN_ON_ONCE(list->count > INT_MAX)) { +@@ -277,6 +280,7 @@ void nf_conncount_list_init(struct nf_conncount_list *list) + spin_lock_init(&list->list_lock); + INIT_LIST_HEAD(&list->head); + list->count = 0; ++ list->last_gc_count = 0; + list->last_gc = (u32)jiffies; + } + EXPORT_SYMBOL_GPL(nf_conncount_list_init); +@@ -316,13 +320,14 @@ static bool __nf_conncount_gc_list(struct net *net, + } + + nf_ct_put(found_ct); +- if (collected > CONNCOUNT_GC_MAX_NODES) ++ if (collected > CONNCOUNT_GC_MAX_COLLECT) + break; + } + + if (!list->count) + ret = true; + list->last_gc = (u32)jiffies; ++ list->last_gc_count = list->count; + + return ret; + } +-- +2.51.0 + diff --git a/queue-6.6/netfilter-nf_conncount-make-nf_conncount_gc_list-to-.patch b/queue-6.6/netfilter-nf_conncount-make-nf_conncount_gc_list-to-.patch new file mode 100644 index 0000000000..8b326070eb --- /dev/null +++ b/queue-6.6/netfilter-nf_conncount-make-nf_conncount_gc_list-to-.patch @@ -0,0 +1,93 @@ +From 7efc9adf85b8d0cc62ca3ad03997f41633059a75 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 21 Nov 2025 01:14:31 +0100 +Subject: netfilter: nf_conncount: make nf_conncount_gc_list() to disable BH + +From: Fernando Fernandez Mancera + +[ Upstream commit c0362b5748282e22fa1592a8d3474f726ad964c2 ] + +For convenience when performing GC over the connection list, make +nf_conncount_gc_list() to disable BH. This unifies the behavior with +nf_conncount_add() and nf_conncount_count(). + +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: 21d033e47273 ("netfilter: nf_conncount: increase the connection clean up limit to 64") +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_conncount.c | 24 +++++++++++++++++------- + net/netfilter/nft_connlimit.c | 7 +------ + 2 files changed, 18 insertions(+), 13 deletions(-) + +diff --git a/net/netfilter/nf_conncount.c b/net/netfilter/nf_conncount.c +index a2c5a7ba0c6fc..70e9662fe1777 100644 +--- a/net/netfilter/nf_conncount.c ++++ b/net/netfilter/nf_conncount.c +@@ -282,8 +282,8 @@ void nf_conncount_list_init(struct nf_conncount_list *list) + EXPORT_SYMBOL_GPL(nf_conncount_list_init); + + /* Return true if the list is empty. Must be called with BH disabled. */ +-bool nf_conncount_gc_list(struct net *net, +- struct nf_conncount_list *list) ++static bool __nf_conncount_gc_list(struct net *net, ++ struct nf_conncount_list *list) + { + const struct nf_conntrack_tuple_hash *found; + struct nf_conncount_tuple *conn, *conn_n; +@@ -295,10 +295,6 @@ bool nf_conncount_gc_list(struct net *net, + if ((u32)jiffies == READ_ONCE(list->last_gc)) + return false; + +- /* don't bother if other cpu is already doing GC */ +- if (!spin_trylock(&list->list_lock)) +- return false; +- + list_for_each_entry_safe(conn, conn_n, &list->head, node) { + found = find_or_evict(net, list, conn); + if (IS_ERR(found)) { +@@ -327,7 +323,21 @@ bool nf_conncount_gc_list(struct net *net, + if (!list->count) + ret = true; + list->last_gc = (u32)jiffies; +- spin_unlock(&list->list_lock); ++ ++ return ret; ++} ++ ++bool nf_conncount_gc_list(struct net *net, ++ struct nf_conncount_list *list) ++{ ++ bool ret; ++ ++ /* don't bother if other cpu is already doing GC */ ++ if (!spin_trylock_bh(&list->list_lock)) ++ return false; ++ ++ ret = __nf_conncount_gc_list(net, list); ++ spin_unlock_bh(&list->list_lock); + + return ret; + } +diff --git a/net/netfilter/nft_connlimit.c b/net/netfilter/nft_connlimit.c +index 83a7d5769396c..5dd50b3ab5a45 100644 +--- a/net/netfilter/nft_connlimit.c ++++ b/net/netfilter/nft_connlimit.c +@@ -232,13 +232,8 @@ static void nft_connlimit_destroy_clone(const struct nft_ctx *ctx, + static bool nft_connlimit_gc(struct net *net, const struct nft_expr *expr) + { + struct nft_connlimit *priv = nft_expr_priv(expr); +- bool ret; + +- local_bh_disable(); +- ret = nf_conncount_gc_list(net, priv->list); +- local_bh_enable(); +- +- return ret; ++ return nf_conncount_gc_list(net, priv->list); + } + + static struct nft_expr_type nft_connlimit_type; +-- +2.51.0 + diff --git a/queue-6.6/netfilter-nf_tables-reset-table-validation-state-on-.patch b/queue-6.6/netfilter-nf_tables-reset-table-validation-state-on-.patch new file mode 100644 index 0000000000..1919ce60f4 --- /dev/null +++ b/queue-6.6/netfilter-nf_tables-reset-table-validation-state-on-.patch @@ -0,0 +1,59 @@ +From ba22bc043a4b12ebba9edb29bd192eb972a6cddf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 12:26:54 +0100 +Subject: netfilter: nf_tables: reset table validation state on abort + +From: Florian Westphal + +[ Upstream commit 6f93616a7323d646d18db9c09f147e453b40fdd7 ] + +If a transaction fails the final validation in the commit hook, the table +validation state is changed to NFT_VALIDATE_DO and a replay of the batch is +performed. Every rule insert will then do a graph validation. + +This is much slower, but provides better error reporting to the user +because we can point at the rule that introduces the validation issue. + +Without this reset the affected table(s) remain in full validation mode, +i.e. on next transaction we start with slow-mode. + +This makes the next transaction after a failed incremental update very slow: + + # time iptables-restore < /tmp/ruleset + real 0m0.496s [..] + # time iptables -A CALLEE -j CALLER + iptables v1.8.11 (nf_tables): RULE_APPEND failed (Too many links): rule in chain CALLEE + real 0m0.022s [..] + # time iptables-restore < /tmp/ruleset + real 1m22.355s [..] + +After this patch, 2nd iptables-restore is back to ~0.5s. + +Fixes: 9a32e9850686 ("netfilter: nf_tables: don't write table validation state without mutex") +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_tables_api.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c +index a0a5d19fa8506..8532d832aad6a 100644 +--- a/net/netfilter/nf_tables_api.c ++++ b/net/netfilter/nf_tables_api.c +@@ -10824,6 +10824,13 @@ static int nf_tables_abort(struct net *net, struct sk_buff *skb, + ret = __nf_tables_abort(net, action); + nft_gc_seq_end(nft_net, gc_seq); + ++ if (action == NFNL_ABORT_NONE) { ++ struct nft_table *table; ++ ++ list_for_each_entry(table, &nft_net->tables, list) ++ table->validate_state = NFT_VALIDATE_SKIP; ++ } ++ + WARN_ON_ONCE(!list_empty(&nft_net->commit_list)); + + /* module autoload needs to happen after GC sequence update because it +-- +2.51.0 + diff --git a/queue-6.6/netfilter-nft_compat-add-more-restrictions-on-netlin.patch b/queue-6.6/netfilter-nft_compat-add-more-restrictions-on-netlin.patch new file mode 100644 index 0000000000..f6c8b9d0f1 --- /dev/null +++ b/queue-6.6/netfilter-nft_compat-add-more-restrictions-on-netlin.patch @@ -0,0 +1,71 @@ +From d742fdb1cda1d30a67a7e188c3217b04f7181bf5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 19 Aug 2022 16:16:07 +0200 +Subject: netfilter: nft_compat: add more restrictions on netlink attributes + +From: Florian Westphal + +[ Upstream commit cda26c645946b08f070f20c166d4736767e4a805 ] + +As far as I can see nothing bad can happen when NFTA_TARGET/MATCH_NAME +are too large because this calls x_tables helpers which check for the +length, but it seems better to already reject it during netlink parsing. + +Rest of the changes avoid silent u8/u16 truncations. + +For _TYPE, its expected to be only 1 or 0. In x_tables world, this +variable is set by kernel, for IPT_SO_GET_REVISION_TARGET its 1, for +all others its set to 0. + +As older versions of nf_tables permitted any value except 1 to mean 'match', +keep this as-is but sanitize the value for consistency. + +Fixes: 0ca743a55991 ("netfilter: nf_tables: add compatibility layer for x_tables") +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_compat.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/net/netfilter/nft_compat.c b/net/netfilter/nft_compat.c +index 7ca4f0d21fe2a..1e8142e64e808 100644 +--- a/net/netfilter/nft_compat.c ++++ b/net/netfilter/nft_compat.c +@@ -134,7 +134,8 @@ static void nft_target_eval_bridge(const struct nft_expr *expr, + } + + static const struct nla_policy nft_target_policy[NFTA_TARGET_MAX + 1] = { +- [NFTA_TARGET_NAME] = { .type = NLA_NUL_STRING }, ++ [NFTA_TARGET_NAME] = { .type = NLA_NUL_STRING, ++ .len = XT_EXTENSION_MAXNAMELEN, }, + [NFTA_TARGET_REV] = NLA_POLICY_MAX(NLA_BE32, 255), + [NFTA_TARGET_INFO] = { .type = NLA_BINARY }, + }; +@@ -434,7 +435,8 @@ static void nft_match_eval(const struct nft_expr *expr, + } + + static const struct nla_policy nft_match_policy[NFTA_MATCH_MAX + 1] = { +- [NFTA_MATCH_NAME] = { .type = NLA_NUL_STRING }, ++ [NFTA_MATCH_NAME] = { .type = NLA_NUL_STRING, ++ .len = XT_EXTENSION_MAXNAMELEN }, + [NFTA_MATCH_REV] = NLA_POLICY_MAX(NLA_BE32, 255), + [NFTA_MATCH_INFO] = { .type = NLA_BINARY }, + }; +@@ -693,7 +695,12 @@ static int nfnl_compat_get_rcu(struct sk_buff *skb, + + name = nla_data(tb[NFTA_COMPAT_NAME]); + rev = ntohl(nla_get_be32(tb[NFTA_COMPAT_REV])); +- target = ntohl(nla_get_be32(tb[NFTA_COMPAT_TYPE])); ++ /* x_tables api checks for 'target == 1' to mean target, ++ * everything else means 'match'. ++ * In x_tables world, the number is set by kernel, not ++ * userspace. ++ */ ++ target = nla_get_be32(tb[NFTA_COMPAT_TYPE]) == htonl(1); + + switch(family) { + case AF_INET: +-- +2.51.0 + diff --git a/queue-6.6/netfilter-nft_counter-fix-reset-of-counters-on-32bit.patch b/queue-6.6/netfilter-nft_counter-fix-reset-of-counters-on-32bit.patch new file mode 100644 index 0000000000..c5ac2ddcef --- /dev/null +++ b/queue-6.6/netfilter-nft_counter-fix-reset-of-counters-on-32bit.patch @@ -0,0 +1,75 @@ +From e2c27d10c60d34c54b668f7f14bfc5f0b2f95b2e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 14:48:30 +0100 +Subject: netfilter: nft_counter: fix reset of counters on 32bit archs + +From: Anders Grahn + +[ Upstream commit 1e13f27e0675552161ab1778be9a23a636dde8a7 ] + +nft_counter_reset() calls u64_stats_add() with a negative value to reset +the counter. This will work on 64bit archs, hence the negative value +added will wrap as a 64bit value which then can wrap the stat counter as +well. + +On 32bit archs, the added negative value will wrap as a 32bit value and +_not_ wrapping the stat counter properly. In most cases, this would just +lead to a very large 32bit value being added to the stat counter. + +Fix by introducing u64_stats_sub(). + +Fixes: 4a1d3acd6ea8 ("netfilter: nft_counter: Use u64_stats_t for statistic.") +Signed-off-by: Anders Grahn +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + include/linux/u64_stats_sync.h | 10 ++++++++++ + net/netfilter/nft_counter.c | 4 ++-- + 2 files changed, 12 insertions(+), 2 deletions(-) + +diff --git a/include/linux/u64_stats_sync.h b/include/linux/u64_stats_sync.h +index 457879938fc19..3366090a86bd2 100644 +--- a/include/linux/u64_stats_sync.h ++++ b/include/linux/u64_stats_sync.h +@@ -89,6 +89,11 @@ static inline void u64_stats_add(u64_stats_t *p, unsigned long val) + local64_add(val, &p->v); + } + ++static inline void u64_stats_sub(u64_stats_t *p, s64 val) ++{ ++ local64_sub(val, &p->v); ++} ++ + static inline void u64_stats_inc(u64_stats_t *p) + { + local64_inc(&p->v); +@@ -130,6 +135,11 @@ static inline void u64_stats_add(u64_stats_t *p, unsigned long val) + p->v += val; + } + ++static inline void u64_stats_sub(u64_stats_t *p, s64 val) ++{ ++ p->v -= val; ++} ++ + static inline void u64_stats_inc(u64_stats_t *p) + { + p->v++; +diff --git a/net/netfilter/nft_counter.c b/net/netfilter/nft_counter.c +index cc73253294963..0d70325280cc5 100644 +--- a/net/netfilter/nft_counter.c ++++ b/net/netfilter/nft_counter.c +@@ -117,8 +117,8 @@ static void nft_counter_reset(struct nft_counter_percpu_priv *priv, + nft_sync = this_cpu_ptr(&nft_counter_sync); + + u64_stats_update_begin(nft_sync); +- u64_stats_add(&this_cpu->packets, -total->packets); +- u64_stats_add(&this_cpu->bytes, -total->bytes); ++ u64_stats_sub(&this_cpu->packets, total->packets); ++ u64_stats_sub(&this_cpu->bytes, total->bytes); + u64_stats_update_end(nft_sync); + + local_bh_enable(); +-- +2.51.0 + diff --git a/queue-6.6/netfilter-nft_set_hash-fix-get-operation-on-big-endi.patch b/queue-6.6/netfilter-nft_set_hash-fix-get-operation-on-big-endi.patch new file mode 100644 index 0000000000..f7645fd2d7 --- /dev/null +++ b/queue-6.6/netfilter-nft_set_hash-fix-get-operation-on-big-endi.patch @@ -0,0 +1,57 @@ +From 31a26343a786f15902010d187fb1f47d63c77b51 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 20:13:45 +0100 +Subject: netfilter: nft_set_hash: fix get operation on big endian + +From: Florian Westphal + +[ Upstream commit 2f635adbe2642d398a0be3ab245accd2987be0c3 ] + +tests/shell/testcases/packetpath/set_match_nomatch_hash_fast +fails on big endian with: + +Error: Could not process rule: No such file or directory +reset element ip test s { 244.147.90.126 } +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Fatal: Cannot fetch element "244.147.90.126" + +... because the wrong bucket is searched, jhash() and jhash1_word are +not interchangeable on big endian. + +Fixes: 3b02b0adc242 ("netfilter: nft_set_hash: fix lookups with fixed size hash on big endian") +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_set_hash.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/net/netfilter/nft_set_hash.c b/net/netfilter/nft_set_hash.c +index 2f1012bde1f34..5a74ee4b7dfb3 100644 +--- a/net/netfilter/nft_set_hash.c ++++ b/net/netfilter/nft_set_hash.c +@@ -525,15 +525,20 @@ bool nft_hash_lookup(const struct net *net, const struct nft_set *set, + static void *nft_hash_get(const struct net *net, const struct nft_set *set, + const struct nft_set_elem *elem, unsigned int flags) + { ++ const u32 *key = (const u32 *)&elem->key.val; + struct nft_hash *priv = nft_set_priv(set); + u8 genmask = nft_genmask_cur(net); + struct nft_hash_elem *he; + u32 hash; + +- hash = jhash(elem->key.val.data, set->klen, priv->seed); ++ if (set->klen == 4) ++ hash = jhash_1word(*key, priv->seed); ++ else ++ hash = jhash(key, set->klen, priv->seed); ++ + hash = reciprocal_scale(hash, priv->buckets); + hlist_for_each_entry_rcu(he, &priv->table[hash], node) { +- if (!memcmp(nft_set_ext_key(&he->ext), elem->key.val.data, set->klen) && ++ if (!memcmp(nft_set_ext_key(&he->ext), key, set->klen) && + nft_set_elem_active(&he->ext, genmask)) + return he; + } +-- +2.51.0 + diff --git a/queue-6.6/netfilter-nft_set_rbtree-check-for-partial-overlaps-.patch b/queue-6.6/netfilter-nft_set_rbtree-check-for-partial-overlaps-.patch new file mode 100644 index 0000000000..b6d7a38439 --- /dev/null +++ b/queue-6.6/netfilter-nft_set_rbtree-check-for-partial-overlaps-.patch @@ -0,0 +1,90 @@ +From ec1cdfa53943500891e79ac7306c93646ffa8f2e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 13:33:44 +0100 +Subject: netfilter: nft_set_rbtree: check for partial overlaps in anonymous + sets + +From: Pablo Neira Ayuso + +[ Upstream commit 4780ec142cbb24b794129d3080eee5cac2943ffc ] + +Userspace provides an optimized representation in case intervals are +adjacent, where the end element is omitted. + +The existing partial overlap detection logic skips anonymous set checks +on start elements for this reason. + +However, it is possible to add intervals that overlap to this anonymous +where two start elements with the same, eg. A-B, A-C where C < B. + + start end + A B + start end + A C + +Restore the check on overlapping start elements to report an overlap. + +Fixes: c9e6978e2725 ("netfilter: nft_set_rbtree: Switch to node list walk for overlap detection") +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_set_rbtree.c | 30 +++++++++++++++++++++++++----- + 1 file changed, 25 insertions(+), 5 deletions(-) + +diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c +index 04672238e17dc..9c9b07f2def1b 100644 +--- a/net/netfilter/nft_set_rbtree.c ++++ b/net/netfilter/nft_set_rbtree.c +@@ -305,11 +305,23 @@ static bool nft_rbtree_update_first(const struct nft_set *set, + return false; + } + ++/* Only for anonymous sets which do not allow updates, all element are active. */ ++static struct nft_rbtree_elem *nft_rbtree_prev_active(struct nft_rbtree_elem *rbe) ++{ ++ struct rb_node *node; ++ ++ node = rb_prev(&rbe->node); ++ if (!node) ++ return NULL; ++ ++ return rb_entry(node, struct nft_rbtree_elem, node); ++} ++ + static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set, + struct nft_rbtree_elem *new, + struct nft_set_ext **ext) + { +- struct nft_rbtree_elem *rbe, *rbe_le = NULL, *rbe_ge = NULL; ++ struct nft_rbtree_elem *rbe, *rbe_le = NULL, *rbe_ge = NULL, *rbe_prev; + struct rb_node *node, *next, *parent, **p, *first = NULL; + struct nft_rbtree *priv = nft_set_priv(set); + u8 cur_genmask = nft_genmask_cur(net); +@@ -441,11 +453,19 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set, + /* - new start element with existing closest, less or equal key value + * being a start element: partial overlap, reported as -ENOTEMPTY. + * Anonymous sets allow for two consecutive start element since they +- * are constant, skip them to avoid bogus overlap reports. ++ * are constant, but validate that this new start element does not ++ * sit in between an existing start and end elements: partial overlap, ++ * reported as -ENOTEMPTY. + */ +- if (!nft_set_is_anonymous(set) && rbe_le && +- nft_rbtree_interval_start(rbe_le) && nft_rbtree_interval_start(new)) +- return -ENOTEMPTY; ++ if (rbe_le && ++ nft_rbtree_interval_start(rbe_le) && nft_rbtree_interval_start(new)) { ++ if (!nft_set_is_anonymous(set)) ++ return -ENOTEMPTY; ++ ++ rbe_prev = nft_rbtree_prev_active(rbe_le); ++ if (rbe_prev && nft_rbtree_interval_end(rbe_prev)) ++ return -ENOTEMPTY; ++ } + + /* - new end element with existing closest, less or equal key value + * being a end element: partial overlap, reported as -ENOTEMPTY. +-- +2.51.0 + diff --git a/queue-6.6/nfc-hci-shdlc-stop-timers-and-work-before-freeing-co.patch b/queue-6.6/nfc-hci-shdlc-stop-timers-and-work-before-freeing-co.patch new file mode 100644 index 0000000000..7105f5fcbe --- /dev/null +++ b/queue-6.6/nfc-hci-shdlc-stop-timers-and-work-before-freeing-co.patch @@ -0,0 +1,52 @@ +From 680b04b8a22adf3342e54639bc57f85f50beafe9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 14:31:57 +0300 +Subject: nfc: hci: shdlc: Stop timers and work before freeing context + +From: Votokina Victoria + +[ Upstream commit c9efde1e537baed7648a94022b43836a348a074f ] + +llc_shdlc_deinit() purges SHDLC skb queues and frees the llc_shdlc +structure while its timers and state machine work may still be active. + +Timer callbacks can schedule sm_work, and sm_work accesses SHDLC state +and the skb queues. If teardown happens in parallel with a queued/running +work item, it can lead to UAF and other shutdown races. + +Stop all SHDLC timers and cancel sm_work synchronously before purging the +queues and freeing the context. + +Found by Linux Verification Center (linuxtesting.org) with SVACE. + +Fixes: 4a61cd6687fc ("NFC: Add an shdlc llc module to llc core") +Signed-off-by: Votokina Victoria +Link: https://patch.msgid.link/20260203113158.2008723-1-Victoria.Votokina@kaspersky.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/nfc/hci/llc_shdlc.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/net/nfc/hci/llc_shdlc.c b/net/nfc/hci/llc_shdlc.c +index e90f70385813a..a106f4352356d 100644 +--- a/net/nfc/hci/llc_shdlc.c ++++ b/net/nfc/hci/llc_shdlc.c +@@ -762,6 +762,14 @@ static void llc_shdlc_deinit(struct nfc_llc *llc) + { + struct llc_shdlc *shdlc = nfc_llc_get_data(llc); + ++ timer_shutdown_sync(&shdlc->connect_timer); ++ timer_shutdown_sync(&shdlc->t1_timer); ++ timer_shutdown_sync(&shdlc->t2_timer); ++ shdlc->t1_active = false; ++ shdlc->t2_active = false; ++ ++ cancel_work_sync(&shdlc->sm_work); ++ + skb_queue_purge(&shdlc->rcv_q); + skb_queue_purge(&shdlc->send_q); + skb_queue_purge(&shdlc->ack_pending_q); +-- +2.51.0 + diff --git a/queue-6.6/nfsd-never-defer-requests-during-idmap-lookup.patch b/queue-6.6/nfsd-never-defer-requests-during-idmap-lookup.patch new file mode 100644 index 0000000000..c558b48521 --- /dev/null +++ b/queue-6.6/nfsd-never-defer-requests-during-idmap-lookup.patch @@ -0,0 +1,152 @@ +From c10546427445e29d260a806e731ae66bf967b6af Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 22 Dec 2025 14:30:04 -0500 +Subject: nfsd: never defer requests during idmap lookup + +From: Anthony Iliopoulos + +[ Upstream commit f9c206cdc4266caad6a9a7f46341420a10f03ccb ] + +During v4 request compound arg decoding, some ops (e.g. SETATTR) +can trigger idmap lookup upcalls. When those upcall responses get +delayed beyond the allowed time limit, cache_check() will mark the +request for deferral and cause it to be dropped. + +This prevents nfs4svc_encode_compoundres from being executed, and +thus the session slot flag NFSD4_SLOT_INUSE never gets cleared. +Subsequent client requests will fail with NFSERR_JUKEBOX, given +that the slot will be marked as in-use, making the SEQUENCE op +fail. + +Fix this by making sure that the RQ_USEDEFERRAL flag is always +clear during nfs4svc_decode_compoundargs(), since no v4 request +should ever be deferred. + +Fixes: 2f425878b6a7 ("nfsd: don't use the deferral service, return NFS4ERR_DELAY") +Signed-off-by: Anthony Iliopoulos +Reviewed-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4idmap.c | 48 +++++++++++++++++++++++++++++++++++++++------ + fs/nfsd/nfs4proc.c | 2 -- + fs/nfsd/nfs4xdr.c | 16 +++++++++++++++ + 3 files changed, 58 insertions(+), 8 deletions(-) + +diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c +index 8cca1329f3485..b5b3d45979c9b 100644 +--- a/fs/nfsd/nfs4idmap.c ++++ b/fs/nfsd/nfs4idmap.c +@@ -643,13 +643,31 @@ static __be32 encode_name_from_id(struct xdr_stream *xdr, + return idmap_id_to_name(xdr, rqstp, type, id); + } + +-__be32 +-nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen, +- kuid_t *uid) ++/** ++ * nfsd_map_name_to_uid - Map user@domain to local UID ++ * @rqstp: RPC execution context ++ * @name: user@domain name to be mapped ++ * @namelen: length of name, in bytes ++ * @uid: OUT: mapped local UID value ++ * ++ * Returns nfs_ok on success or an NFSv4 status code on failure. ++ */ ++__be32 nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, ++ size_t namelen, kuid_t *uid) + { + __be32 status; + u32 id = -1; + ++ /* ++ * The idmap lookup below triggers an upcall that invokes ++ * cache_check(). RQ_USEDEFERRAL must be clear to prevent ++ * cache_check() from setting RQ_DROPME via svc_defer(). ++ * NFSv4 servers are not permitted to drop requests. Also ++ * RQ_DROPME will force NFSv4.1 session slot processing to ++ * be skipped. ++ */ ++ WARN_ON_ONCE(test_bit(RQ_USEDEFERRAL, &rqstp->rq_flags)); ++ + if (name == NULL || namelen == 0) + return nfserr_inval; + +@@ -660,13 +678,31 @@ nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen, + return status; + } + +-__be32 +-nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, size_t namelen, +- kgid_t *gid) ++/** ++ * nfsd_map_name_to_gid - Map user@domain to local GID ++ * @rqstp: RPC execution context ++ * @name: user@domain name to be mapped ++ * @namelen: length of name, in bytes ++ * @gid: OUT: mapped local GID value ++ * ++ * Returns nfs_ok on success or an NFSv4 status code on failure. ++ */ ++__be32 nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, ++ size_t namelen, kgid_t *gid) + { + __be32 status; + u32 id = -1; + ++ /* ++ * The idmap lookup below triggers an upcall that invokes ++ * cache_check(). RQ_USEDEFERRAL must be clear to prevent ++ * cache_check() from setting RQ_DROPME via svc_defer(). ++ * NFSv4 servers are not permitted to drop requests. Also ++ * RQ_DROPME will force NFSv4.1 session slot processing to ++ * be skipped. ++ */ ++ WARN_ON_ONCE(test_bit(RQ_USEDEFERRAL, &rqstp->rq_flags)); ++ + if (name == NULL || namelen == 0) + return nfserr_inval; + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index a126fae2df566..5767080362e85 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -2763,8 +2763,6 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) + BUG_ON(cstate->replay_owner); + out: + cstate->status = status; +- /* Reset deferral mechanism for RPC deferrals */ +- set_bit(RQ_USEDEFERRAL, &rqstp->rq_flags); + return rpc_success; + } + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 15189e683e834..d84eaae7cd0b6 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -5492,6 +5492,22 @@ nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + args->ops = args->iops; + args->rqstp = rqstp; + ++ /* ++ * NFSv4 operation decoders can invoke svc cache lookups ++ * that trigger svc_defer() when RQ_USEDEFERRAL is set, ++ * setting RQ_DROPME. This creates two problems: ++ * ++ * 1. Non-idempotency: Compounds make it too hard to avoid ++ * problems if a request is deferred and replayed. ++ * ++ * 2. Session slot leakage (NFSv4.1+): If RQ_DROPME is set ++ * during decode but SEQUENCE executes successfully, the ++ * session slot will be marked INUSE. The request is then ++ * dropped before encoding, so the slot is never released, ++ * rendering it permanently unusable by the client. ++ */ ++ clear_bit(RQ_USEDEFERRAL, &rqstp->rq_flags); ++ + return nfsd4_decode_compound(args); + } + +-- +2.51.0 + diff --git a/queue-6.6/nvdimm-virtio_pmem-serialize-flush-requests.patch b/queue-6.6/nvdimm-virtio_pmem-serialize-flush-requests.patch new file mode 100644 index 0000000000..92864faa9b --- /dev/null +++ b/queue-6.6/nvdimm-virtio_pmem-serialize-flush-requests.patch @@ -0,0 +1,98 @@ +From ef205d701ca6d5691b645c0f7953fb553848d878 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 10:13:51 +0800 +Subject: nvdimm: virtio_pmem: serialize flush requests + +From: Li Chen + +[ Upstream commit a9ba6733c7f1096c4506bf4e34a546e07242df74 ] + +Under heavy concurrent flush traffic, virtio-pmem can overflow its request +virtqueue (req_vq): virtqueue_add_sgs() starts returning -ENOSPC and the +driver logs "no free slots in the virtqueue". Shortly after that the +device enters VIRTIO_CONFIG_S_NEEDS_RESET and flush requests fail with +"virtio pmem device needs a reset". + +Serialize virtio_pmem_flush() with a per-device mutex so only one flush +request is in-flight at a time. This prevents req_vq descriptor overflow +under high concurrency. + +Reproducer (guest with virtio-pmem): + - mkfs.ext4 -F /dev/pmem0 + - mount -t ext4 -o dax,noatime /dev/pmem0 /mnt/bench + - fio: ioengine=io_uring rw=randwrite bs=4k iodepth=64 numjobs=64 + direct=1 fsync=1 runtime=30s time_based=1 + - dmesg: "no free slots in the virtqueue" + "virtio pmem device needs a reset" + +Fixes: 6e84200c0a29 ("virtio-pmem: Add virtio pmem driver") +Signed-off-by: Li Chen +Acked-by: Pankaj Gupta +Acked-by: Michael S. Tsirkin +Link: https://patch.msgid.link/20260203021353.121091-1-me@linux.beauty +Signed-off-by: Ira Weiny +Signed-off-by: Sasha Levin +--- + drivers/nvdimm/nd_virtio.c | 3 ++- + drivers/nvdimm/virtio_pmem.c | 1 + + drivers/nvdimm/virtio_pmem.h | 4 ++++ + 3 files changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/nvdimm/nd_virtio.c b/drivers/nvdimm/nd_virtio.c +index 839f10ca56eac..e5a7b031da2d6 100644 +--- a/drivers/nvdimm/nd_virtio.c ++++ b/drivers/nvdimm/nd_virtio.c +@@ -44,6 +44,8 @@ static int virtio_pmem_flush(struct nd_region *nd_region) + unsigned long flags; + int err, err1; + ++ guard(mutex)(&vpmem->flush_lock); ++ + /* + * Don't bother to submit the request to the device if the device is + * not activated. +@@ -53,7 +55,6 @@ static int virtio_pmem_flush(struct nd_region *nd_region) + return -EIO; + } + +- might_sleep(); + req_data = kmalloc(sizeof(*req_data), GFP_KERNEL); + if (!req_data) + return -ENOMEM; +diff --git a/drivers/nvdimm/virtio_pmem.c b/drivers/nvdimm/virtio_pmem.c +index a92eb172f0e7e..4eebb2ec3cf97 100644 +--- a/drivers/nvdimm/virtio_pmem.c ++++ b/drivers/nvdimm/virtio_pmem.c +@@ -49,6 +49,7 @@ static int virtio_pmem_probe(struct virtio_device *vdev) + goto out_err; + } + ++ mutex_init(&vpmem->flush_lock); + vpmem->vdev = vdev; + vdev->priv = vpmem; + err = init_vq(vpmem); +diff --git a/drivers/nvdimm/virtio_pmem.h b/drivers/nvdimm/virtio_pmem.h +index 0dddefe594c46..f72cf17f9518f 100644 +--- a/drivers/nvdimm/virtio_pmem.h ++++ b/drivers/nvdimm/virtio_pmem.h +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + #include + + struct virtio_pmem_request { +@@ -35,6 +36,9 @@ struct virtio_pmem { + /* Virtio pmem request queue */ + struct virtqueue *req_vq; + ++ /* Serialize flush requests to the device. */ ++ struct mutex flush_lock; ++ + /* nvdimm bus registers virtio pmem device */ + struct nvdimm_bus *nvdimm_bus; + struct nvdimm_bus_descriptor nd_desc; +-- +2.51.0 + diff --git a/queue-6.6/octeon_ep-disable-per-ring-interrupts.patch b/queue-6.6/octeon_ep-disable-per-ring-interrupts.patch new file mode 100644 index 0000000000..a07fc03c24 --- /dev/null +++ b/queue-6.6/octeon_ep-disable-per-ring-interrupts.patch @@ -0,0 +1,119 @@ +From d6b00955f17c7285e852e03d761bd14e473a3902 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 11:15:06 +0000 +Subject: octeon_ep: disable per ring interrupts + +From: Vimlesh Kumar + +[ Upstream commit 73e6ffa37cebee152c07c5f2b8bc70fd2899ea6e ] + +Disable the MSI-X per ring interrupt for every PF ring when PF +netdev goes down. + +Fixes: 1f2c2d0cee023 ("octeon_ep: add hardware configuration APIs") +Signed-off-by: Sathesh Edara +Signed-off-by: Shinas Rasheed +Signed-off-by: Vimlesh Kumar +Link: https://patch.msgid.link/20260206111510.1045092-2-vimleshk@marvell.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + .../ethernet/marvell/octeon_ep/octep_cn9k_pf.c | 18 +++++++++++++++--- + .../ethernet/marvell/octeon_ep/octep_cnxk_pf.c | 18 +++++++++++++++--- + .../marvell/octeon_ep/octep_regs_cn9k_pf.h | 1 + + .../marvell/octeon_ep/octep_regs_cnxk_pf.h | 1 + + 4 files changed, 32 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c b/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c +index d4ee2454675b6..f7156d093cccf 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c +@@ -642,14 +642,26 @@ static void octep_enable_interrupts_cn93_pf(struct octep_device *oct) + /* Disable all interrupts */ + static void octep_disable_interrupts_cn93_pf(struct octep_device *oct) + { +- u64 intr_mask = 0ULL; ++ u64 reg_val, intr_mask = 0ULL; + int srn, num_rings, i; + + srn = CFG_GET_PORTS_PF_SRN(oct->conf); + num_rings = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); + +- for (i = 0; i < num_rings; i++) +- intr_mask |= (0x1ULL << (srn + i)); ++ for (i = 0; i < num_rings; i++) { ++ intr_mask |= BIT_ULL(srn + i); ++ reg_val = octep_read_csr64(oct, ++ CN93_SDP_R_IN_INT_LEVELS(srn + i)); ++ reg_val &= ~CN93_INT_ENA_BIT; ++ octep_write_csr64(oct, ++ CN93_SDP_R_IN_INT_LEVELS(srn + i), reg_val); ++ ++ reg_val = octep_read_csr64(oct, ++ CN93_SDP_R_OUT_INT_LEVELS(srn + i)); ++ reg_val &= ~CN93_INT_ENA_BIT; ++ octep_write_csr64(oct, ++ CN93_SDP_R_OUT_INT_LEVELS(srn + i), reg_val); ++ } + + octep_write_csr64(oct, CN93_SDP_EPF_IRERR_RINT_ENA_W1C, intr_mask); + octep_write_csr64(oct, CN93_SDP_EPF_ORERR_RINT_ENA_W1C, intr_mask); +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c b/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c +index abb03e9119e72..633d39690eec8 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c +@@ -683,14 +683,26 @@ static void octep_enable_interrupts_cnxk_pf(struct octep_device *oct) + /* Disable all interrupts */ + static void octep_disable_interrupts_cnxk_pf(struct octep_device *oct) + { +- u64 intr_mask = 0ULL; ++ u64 reg_val, intr_mask = 0ULL; + int srn, num_rings, i; + + srn = CFG_GET_PORTS_PF_SRN(oct->conf); + num_rings = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); + +- for (i = 0; i < num_rings; i++) +- intr_mask |= (0x1ULL << (srn + i)); ++ for (i = 0; i < num_rings; i++) { ++ intr_mask |= BIT_ULL(srn + i); ++ reg_val = octep_read_csr64(oct, ++ CNXK_SDP_R_IN_INT_LEVELS(srn + i)); ++ reg_val &= ~CNXK_INT_ENA_BIT; ++ octep_write_csr64(oct, ++ CNXK_SDP_R_IN_INT_LEVELS(srn + i), reg_val); ++ ++ reg_val = octep_read_csr64(oct, ++ CNXK_SDP_R_OUT_INT_LEVELS(srn + i)); ++ reg_val &= ~CNXK_INT_ENA_BIT; ++ octep_write_csr64(oct, ++ CNXK_SDP_R_OUT_INT_LEVELS(srn + i), reg_val); ++ } + + octep_write_csr64(oct, CNXK_SDP_EPF_IRERR_RINT_ENA_W1C, intr_mask); + octep_write_csr64(oct, CNXK_SDP_EPF_ORERR_RINT_ENA_W1C, intr_mask); +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cn9k_pf.h b/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cn9k_pf.h +index 0a43983e91015..9ecfbabe3b9c5 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cn9k_pf.h ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cn9k_pf.h +@@ -373,5 +373,6 @@ + #define CN93_PEM_BAR4_INDEX 7 + #define CN93_PEM_BAR4_INDEX_SIZE 0x400000ULL + #define CN93_PEM_BAR4_INDEX_OFFSET (CN93_PEM_BAR4_INDEX * CN93_PEM_BAR4_INDEX_SIZE) ++#define CN93_INT_ENA_BIT BIT_ULL(62) + + #endif /* _OCTEP_REGS_CN9K_PF_H_ */ +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h b/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h +index abe02df8af117..214aab88bb427 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h +@@ -396,5 +396,6 @@ + #define CNXK_PEM_BAR4_INDEX 7 + #define CNXK_PEM_BAR4_INDEX_SIZE 0x400000ULL + #define CNXK_PEM_BAR4_INDEX_OFFSET (CNXK_PEM_BAR4_INDEX * CNXK_PEM_BAR4_INDEX_SIZE) ++#define CNXK_INT_ENA_BIT BIT_ULL(62) + + #endif /* _OCTEP_REGS_CNXK_PF_H_ */ +-- +2.51.0 + diff --git a/queue-6.6/octeon_ep-ensure-dbell-baddr-updation.patch b/queue-6.6/octeon_ep-ensure-dbell-baddr-updation.patch new file mode 100644 index 0000000000..19d3da4d3e --- /dev/null +++ b/queue-6.6/octeon_ep-ensure-dbell-baddr-updation.patch @@ -0,0 +1,186 @@ +From 0b13867df2ddb2fd0a7f2043a685ad81ca7c6206 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 11:15:07 +0000 +Subject: octeon_ep: ensure dbell BADDR updation + +From: Vimlesh Kumar + +[ Upstream commit ce8fe3fc4f99efd872120301c0f72f2e90ab9769 ] + +Make sure the OUT DBELL base address reflects the +latest values written to it. + +Fix: +Add a wait until the OUT DBELL base address register +is updated with the DMA ring descriptor address, +and modify the setup_oq function to properly +handle failures. + +Fixes: 0807dc76f3bf5 ("octeon_ep: support Octeon CN10K devices") +Signed-off-by: Sathesh Edara +Signed-off-by: Shinas Rasheed +Signed-off-by: Vimlesh Kumar +Link: https://patch.msgid.link/20260206111510.1045092-3-vimleshk@marvell.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + .../marvell/octeon_ep/octep_cn9k_pf.c | 3 +- + .../marvell/octeon_ep/octep_cnxk_pf.c | 46 +++++++++++++++---- + .../ethernet/marvell/octeon_ep/octep_main.h | 2 +- + .../net/ethernet/marvell/octeon_ep/octep_rx.c | 8 +++- + 4 files changed, 48 insertions(+), 11 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c b/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c +index f7156d093cccf..0ed07aad066f4 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c +@@ -302,7 +302,7 @@ static void octep_setup_iq_regs_cn93_pf(struct octep_device *oct, int iq_no) + } + + /* Setup registers for a hardware Rx Queue */ +-static void octep_setup_oq_regs_cn93_pf(struct octep_device *oct, int oq_no) ++static int octep_setup_oq_regs_cn93_pf(struct octep_device *oct, int oq_no) + { + u64 reg_val; + u64 oq_ctl = 0ULL; +@@ -350,6 +350,7 @@ static void octep_setup_oq_regs_cn93_pf(struct octep_device *oct, int oq_no) + reg_val = ((u64)time_threshold << 32) | + CFG_GET_OQ_INTR_PKT(oct->conf); + octep_write_csr64(oct, CN93_SDP_R_OUT_INT_LEVELS(oq_no), reg_val); ++ return 0; + } + + /* Setup registers for a PF mailbox */ +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c b/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c +index 38a03cef314e3..b1f7bf6e0f5d0 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + + #include "octep_config.h" + #include "octep_main.h" +@@ -327,12 +328,14 @@ static void octep_setup_iq_regs_cnxk_pf(struct octep_device *oct, int iq_no) + } + + /* Setup registers for a hardware Rx Queue */ +-static void octep_setup_oq_regs_cnxk_pf(struct octep_device *oct, int oq_no) ++static int octep_setup_oq_regs_cnxk_pf(struct octep_device *oct, int oq_no) + { +- u64 reg_val; +- u64 oq_ctl = 0ULL; +- u32 time_threshold = 0; + struct octep_oq *oq = oct->oq[oq_no]; ++ unsigned long t_out_jiffies; ++ u32 time_threshold = 0; ++ u64 oq_ctl = 0ULL; ++ u64 reg_ba_val; ++ u64 reg_val; + + oq_no += CFG_GET_PORTS_PF_SRN(oct->conf); + reg_val = octep_read_csr64(oct, CNXK_SDP_R_OUT_CONTROL(oq_no)); +@@ -343,6 +346,36 @@ static void octep_setup_oq_regs_cnxk_pf(struct octep_device *oct, int oq_no) + reg_val = octep_read_csr64(oct, CNXK_SDP_R_OUT_CONTROL(oq_no)); + } while (!(reg_val & CNXK_R_OUT_CTL_IDLE)); + } ++ octep_write_csr64(oct, CNXK_SDP_R_OUT_WMARK(oq_no), oq->max_count); ++ /* Wait for WMARK to get applied */ ++ usleep_range(10, 15); ++ ++ octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_BADDR(oq_no), ++ oq->desc_ring_dma); ++ octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_RSIZE(oq_no), ++ oq->max_count); ++ reg_ba_val = octep_read_csr64(oct, CNXK_SDP_R_OUT_SLIST_BADDR(oq_no)); ++ ++ if (reg_ba_val != oq->desc_ring_dma) { ++ t_out_jiffies = jiffies + 10 * HZ; ++ do { ++ if (reg_ba_val == ULLONG_MAX) ++ return -EFAULT; ++ octep_write_csr64(oct, ++ CNXK_SDP_R_OUT_SLIST_BADDR(oq_no), ++ oq->desc_ring_dma); ++ octep_write_csr64(oct, ++ CNXK_SDP_R_OUT_SLIST_RSIZE(oq_no), ++ oq->max_count); ++ reg_ba_val = ++ octep_read_csr64(oct, ++ CNXK_SDP_R_OUT_SLIST_BADDR(oq_no)); ++ } while ((reg_ba_val != oq->desc_ring_dma) && ++ time_before(jiffies, t_out_jiffies)); ++ ++ if (reg_ba_val != oq->desc_ring_dma) ++ return -EAGAIN; ++ } + + reg_val &= ~(CNXK_R_OUT_CTL_IMODE); + reg_val &= ~(CNXK_R_OUT_CTL_ROR_P); +@@ -356,10 +389,6 @@ static void octep_setup_oq_regs_cnxk_pf(struct octep_device *oct, int oq_no) + reg_val |= (CNXK_R_OUT_CTL_ES_P); + + octep_write_csr64(oct, CNXK_SDP_R_OUT_CONTROL(oq_no), reg_val); +- octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_BADDR(oq_no), +- oq->desc_ring_dma); +- octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_RSIZE(oq_no), +- oq->max_count); + + oq_ctl = octep_read_csr64(oct, CNXK_SDP_R_OUT_CONTROL(oq_no)); + +@@ -385,6 +414,7 @@ static void octep_setup_oq_regs_cnxk_pf(struct octep_device *oct, int oq_no) + reg_val &= ~0xFFFFFFFFULL; + reg_val |= CFG_GET_OQ_WMARK(oct->conf); + octep_write_csr64(oct, CNXK_SDP_R_OUT_WMARK(oq_no), reg_val); ++ return 0; + } + + /* Setup registers for a PF mailbox */ +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_main.h b/drivers/net/ethernet/marvell/octeon_ep/octep_main.h +index f67bb87901005..ce92a20127894 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_main.h ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_main.h +@@ -67,7 +67,7 @@ struct octep_pci_win_regs { + + struct octep_hw_ops { + void (*setup_iq_regs)(struct octep_device *oct, int q); +- void (*setup_oq_regs)(struct octep_device *oct, int q); ++ int (*setup_oq_regs)(struct octep_device *oct, int q); + void (*setup_mbox_regs)(struct octep_device *oct, int mbox); + + irqreturn_t (*oei_intr_handler)(void *ioq_vector); +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c b/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c +index c7f4e3c058b7f..60afb6bf2f679 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c +@@ -12,6 +12,8 @@ + #include "octep_config.h" + #include "octep_main.h" + ++static void octep_oq_free_ring_buffers(struct octep_oq *oq); ++ + static void octep_oq_reset_indices(struct octep_oq *oq) + { + oq->host_read_idx = 0; +@@ -169,11 +171,15 @@ static int octep_setup_oq(struct octep_device *oct, int q_no) + goto oq_fill_buff_err; + + octep_oq_reset_indices(oq); +- oct->hw_ops.setup_oq_regs(oct, q_no); ++ if (oct->hw_ops.setup_oq_regs(oct, q_no)) ++ goto oq_setup_err; ++ + oct->num_oqs++; + + return 0; + ++oq_setup_err: ++ octep_oq_free_ring_buffers(oq); + oq_fill_buff_err: + vfree(oq->buff_info); + oq->buff_info = NULL; +-- +2.51.0 + diff --git a/queue-6.6/octeon_ep-restructured-interrupt-handlers.patch b/queue-6.6/octeon_ep-restructured-interrupt-handlers.patch new file mode 100644 index 0000000000..7a9bdf3e96 --- /dev/null +++ b/queue-6.6/octeon_ep-restructured-interrupt-handlers.patch @@ -0,0 +1,546 @@ +From 9c0fcde0d1b4bd725e00d008686c132cab10060d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 17 Sep 2023 23:56:21 -0700 +Subject: octeon_ep: restructured interrupt handlers + +From: Shinas Rasheed + +[ Upstream commit 0b8ef824eedef96f3423f61dde2629755707b168 ] + +Separated queue specific interrupts to register to individual msix-vectors +instead of using a single generic interrupt handler on a single +msix-vector. + +Signed-off-by: Shinas Rasheed +Link: https://lore.kernel.org/r/20230918065621.2165449-1-srasheed@marvell.com +Signed-off-by: Paolo Abeni +Stable-dep-of: 73e6ffa37ceb ("octeon_ep: disable per ring interrupts") +Signed-off-by: Sasha Levin +--- + .../marvell/octeon_ep/octep_cn9k_pf.c | 158 ++++++++++---- + .../ethernet/marvell/octeon_ep/octep_main.c | 197 +++++++++++++++++- + .../ethernet/marvell/octeon_ep/octep_main.h | 13 +- + 3 files changed, 323 insertions(+), 45 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c b/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c +index f282cd5b29ea5..d4ee2454675b6 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c +@@ -369,34 +369,40 @@ static void octep_setup_mbox_regs_cn93_pf(struct octep_device *oct, int q_no) + mbox->mbox_read_reg = oct->mmio[0].hw_addr + CN93_SDP_R_MBOX_VF_PF_DATA(q_no); + } + +-/* Process non-ioq interrupts required to keep pf interface running. +- * OEI_RINT is needed for control mailbox +- */ +-static bool octep_poll_non_ioq_interrupts_cn93_pf(struct octep_device *oct) +-{ +- bool handled = false; +- u64 reg0; +- +- /* Check for OEI INTR */ +- reg0 = octep_read_csr64(oct, CN93_SDP_EPF_OEI_RINT); +- if (reg0) { +- dev_info(&oct->pdev->dev, +- "Received OEI_RINT intr: 0x%llx\n", +- reg0); +- octep_write_csr64(oct, CN93_SDP_EPF_OEI_RINT, reg0); +- if (reg0 & CN93_SDP_EPF_OEI_RINT_DATA_BIT_MBOX) ++/* Poll OEI events like heartbeat */ ++static void octep_poll_oei_cn93_pf(struct octep_device *oct) ++{ ++ u64 reg; ++ ++ reg = octep_read_csr64(oct, CN93_SDP_EPF_OEI_RINT); ++ if (reg) { ++ octep_write_csr64(oct, CN93_SDP_EPF_OEI_RINT, reg); ++ if (reg & CN93_SDP_EPF_OEI_RINT_DATA_BIT_MBOX) + queue_work(octep_wq, &oct->ctrl_mbox_task); +- else if (reg0 & CN93_SDP_EPF_OEI_RINT_DATA_BIT_HBEAT) ++ else if (reg & CN93_SDP_EPF_OEI_RINT_DATA_BIT_HBEAT) + atomic_set(&oct->hb_miss_cnt, 0); +- +- handled = true; + } ++} ++ ++/* OEI interrupt handler */ ++static irqreturn_t octep_oei_intr_handler_cn93_pf(void *dev) ++{ ++ struct octep_device *oct = (struct octep_device *)dev; + +- return handled; ++ octep_poll_oei_cn93_pf(oct); ++ return IRQ_HANDLED; ++} ++ ++/* Process non-ioq interrupts required to keep pf interface running. ++ * OEI_RINT is needed for control mailbox ++ */ ++static void octep_poll_non_ioq_interrupts_cn93_pf(struct octep_device *oct) ++{ ++ octep_poll_oei_cn93_pf(oct); + } + +-/* Interrupts handler for all non-queue generic interrupts. */ +-static irqreturn_t octep_non_ioq_intr_handler_cn93_pf(void *dev) ++/* Interrupt handler for input ring error interrupts. */ ++static irqreturn_t octep_ire_intr_handler_cn93_pf(void *dev) + { + struct octep_device *oct = (struct octep_device *)dev; + struct pci_dev *pdev = oct->pdev; +@@ -421,8 +427,17 @@ static irqreturn_t octep_non_ioq_intr_handler_cn93_pf(void *dev) + reg_val); + } + } +- goto irq_handled; + } ++ return IRQ_HANDLED; ++} ++ ++/* Interrupt handler for output ring error interrupts. */ ++static irqreturn_t octep_ore_intr_handler_cn93_pf(void *dev) ++{ ++ struct octep_device *oct = (struct octep_device *)dev; ++ struct pci_dev *pdev = oct->pdev; ++ u64 reg_val = 0; ++ int i = 0; + + /* Check for ORERR INTR */ + reg_val = octep_read_csr64(oct, CN93_SDP_EPF_ORERR_RINT); +@@ -440,9 +455,16 @@ static irqreturn_t octep_non_ioq_intr_handler_cn93_pf(void *dev) + reg_val); + } + } +- +- goto irq_handled; + } ++ return IRQ_HANDLED; ++} ++ ++/* Interrupt handler for vf input ring error interrupts. */ ++static irqreturn_t octep_vfire_intr_handler_cn93_pf(void *dev) ++{ ++ struct octep_device *oct = (struct octep_device *)dev; ++ struct pci_dev *pdev = oct->pdev; ++ u64 reg_val = 0; + + /* Check for VFIRE INTR */ + reg_val = octep_read_csr64(oct, CN93_SDP_EPF_VFIRE_RINT(0)); +@@ -450,8 +472,16 @@ static irqreturn_t octep_non_ioq_intr_handler_cn93_pf(void *dev) + dev_info(&pdev->dev, + "Received VFIRE_RINT intr: 0x%llx\n", reg_val); + octep_write_csr64(oct, CN93_SDP_EPF_VFIRE_RINT(0), reg_val); +- goto irq_handled; + } ++ return IRQ_HANDLED; ++} ++ ++/* Interrupt handler for vf output ring error interrupts. */ ++static irqreturn_t octep_vfore_intr_handler_cn93_pf(void *dev) ++{ ++ struct octep_device *oct = (struct octep_device *)dev; ++ struct pci_dev *pdev = oct->pdev; ++ u64 reg_val = 0; + + /* Check for VFORE INTR */ + reg_val = octep_read_csr64(oct, CN93_SDP_EPF_VFORE_RINT(0)); +@@ -459,19 +489,30 @@ static irqreturn_t octep_non_ioq_intr_handler_cn93_pf(void *dev) + dev_info(&pdev->dev, + "Received VFORE_RINT intr: 0x%llx\n", reg_val); + octep_write_csr64(oct, CN93_SDP_EPF_VFORE_RINT(0), reg_val); +- goto irq_handled; + } ++ return IRQ_HANDLED; ++} + +- /* Check for MBOX INTR and OEI INTR */ +- if (octep_poll_non_ioq_interrupts_cn93_pf(oct)) +- goto irq_handled; ++/* Interrupt handler for dpi dma related interrupts. */ ++static irqreturn_t octep_dma_intr_handler_cn93_pf(void *dev) ++{ ++ struct octep_device *oct = (struct octep_device *)dev; ++ u64 reg_val = 0; + + /* Check for DMA INTR */ + reg_val = octep_read_csr64(oct, CN93_SDP_EPF_DMA_RINT); + if (reg_val) { + octep_write_csr64(oct, CN93_SDP_EPF_DMA_RINT, reg_val); +- goto irq_handled; + } ++ return IRQ_HANDLED; ++} ++ ++/* Interrupt handler for dpi dma transaction error interrupts for VFs */ ++static irqreturn_t octep_dma_vf_intr_handler_cn93_pf(void *dev) ++{ ++ struct octep_device *oct = (struct octep_device *)dev; ++ struct pci_dev *pdev = oct->pdev; ++ u64 reg_val = 0; + + /* Check for DMA VF INTR */ + reg_val = octep_read_csr64(oct, CN93_SDP_EPF_DMA_VF_RINT(0)); +@@ -479,8 +520,16 @@ static irqreturn_t octep_non_ioq_intr_handler_cn93_pf(void *dev) + dev_info(&pdev->dev, + "Received DMA_VF_RINT intr: 0x%llx\n", reg_val); + octep_write_csr64(oct, CN93_SDP_EPF_DMA_VF_RINT(0), reg_val); +- goto irq_handled; + } ++ return IRQ_HANDLED; ++} ++ ++/* Interrupt handler for pp transaction error interrupts for VFs */ ++static irqreturn_t octep_pp_vf_intr_handler_cn93_pf(void *dev) ++{ ++ struct octep_device *oct = (struct octep_device *)dev; ++ struct pci_dev *pdev = oct->pdev; ++ u64 reg_val = 0; + + /* Check for PPVF INTR */ + reg_val = octep_read_csr64(oct, CN93_SDP_EPF_PP_VF_RINT(0)); +@@ -488,8 +537,16 @@ static irqreturn_t octep_non_ioq_intr_handler_cn93_pf(void *dev) + dev_info(&pdev->dev, + "Received PP_VF_RINT intr: 0x%llx\n", reg_val); + octep_write_csr64(oct, CN93_SDP_EPF_PP_VF_RINT(0), reg_val); +- goto irq_handled; + } ++ return IRQ_HANDLED; ++} ++ ++/* Interrupt handler for mac related interrupts. */ ++static irqreturn_t octep_misc_intr_handler_cn93_pf(void *dev) ++{ ++ struct octep_device *oct = (struct octep_device *)dev; ++ struct pci_dev *pdev = oct->pdev; ++ u64 reg_val = 0; + + /* Check for MISC INTR */ + reg_val = octep_read_csr64(oct, CN93_SDP_EPF_MISC_RINT); +@@ -497,11 +554,17 @@ static irqreturn_t octep_non_ioq_intr_handler_cn93_pf(void *dev) + dev_info(&pdev->dev, + "Received MISC_RINT intr: 0x%llx\n", reg_val); + octep_write_csr64(oct, CN93_SDP_EPF_MISC_RINT, reg_val); +- goto irq_handled; + } ++ return IRQ_HANDLED; ++} ++ ++/* Interrupts handler for all reserved interrupts. */ ++static irqreturn_t octep_rsvd_intr_handler_cn93_pf(void *dev) ++{ ++ struct octep_device *oct = (struct octep_device *)dev; ++ struct pci_dev *pdev = oct->pdev; + + dev_info(&pdev->dev, "Reserved interrupts raised; Ignore\n"); +-irq_handled: + return IRQ_HANDLED; + } + +@@ -565,8 +628,15 @@ static void octep_enable_interrupts_cn93_pf(struct octep_device *oct) + octep_write_csr64(oct, CN93_SDP_EPF_IRERR_RINT_ENA_W1S, intr_mask); + octep_write_csr64(oct, CN93_SDP_EPF_ORERR_RINT_ENA_W1S, intr_mask); + octep_write_csr64(oct, CN93_SDP_EPF_OEI_RINT_ENA_W1S, -1ULL); ++ ++ octep_write_csr64(oct, CN93_SDP_EPF_VFIRE_RINT_ENA_W1S(0), -1ULL); ++ octep_write_csr64(oct, CN93_SDP_EPF_VFORE_RINT_ENA_W1S(0), -1ULL); ++ + octep_write_csr64(oct, CN93_SDP_EPF_MISC_RINT_ENA_W1S, intr_mask); + octep_write_csr64(oct, CN93_SDP_EPF_DMA_RINT_ENA_W1S, intr_mask); ++ ++ octep_write_csr64(oct, CN93_SDP_EPF_DMA_VF_RINT_ENA_W1S(0), -1ULL); ++ octep_write_csr64(oct, CN93_SDP_EPF_PP_VF_RINT_ENA_W1S(0), -1ULL); + } + + /* Disable all interrupts */ +@@ -584,8 +654,15 @@ static void octep_disable_interrupts_cn93_pf(struct octep_device *oct) + octep_write_csr64(oct, CN93_SDP_EPF_IRERR_RINT_ENA_W1C, intr_mask); + octep_write_csr64(oct, CN93_SDP_EPF_ORERR_RINT_ENA_W1C, intr_mask); + octep_write_csr64(oct, CN93_SDP_EPF_OEI_RINT_ENA_W1C, -1ULL); ++ ++ octep_write_csr64(oct, CN93_SDP_EPF_VFIRE_RINT_ENA_W1C(0), -1ULL); ++ octep_write_csr64(oct, CN93_SDP_EPF_VFORE_RINT_ENA_W1C(0), -1ULL); ++ + octep_write_csr64(oct, CN93_SDP_EPF_MISC_RINT_ENA_W1C, intr_mask); + octep_write_csr64(oct, CN93_SDP_EPF_DMA_RINT_ENA_W1C, intr_mask); ++ ++ octep_write_csr64(oct, CN93_SDP_EPF_DMA_VF_RINT_ENA_W1C(0), -1ULL); ++ octep_write_csr64(oct, CN93_SDP_EPF_PP_VF_RINT_ENA_W1C(0), -1ULL); + } + + /* Get new Octeon Read Index: index of descriptor that Octeon reads next. */ +@@ -718,7 +795,16 @@ void octep_device_setup_cn93_pf(struct octep_device *oct) + oct->hw_ops.setup_oq_regs = octep_setup_oq_regs_cn93_pf; + oct->hw_ops.setup_mbox_regs = octep_setup_mbox_regs_cn93_pf; + +- oct->hw_ops.non_ioq_intr_handler = octep_non_ioq_intr_handler_cn93_pf; ++ oct->hw_ops.oei_intr_handler = octep_oei_intr_handler_cn93_pf; ++ oct->hw_ops.ire_intr_handler = octep_ire_intr_handler_cn93_pf; ++ oct->hw_ops.ore_intr_handler = octep_ore_intr_handler_cn93_pf; ++ oct->hw_ops.vfire_intr_handler = octep_vfire_intr_handler_cn93_pf; ++ oct->hw_ops.vfore_intr_handler = octep_vfore_intr_handler_cn93_pf; ++ oct->hw_ops.dma_intr_handler = octep_dma_intr_handler_cn93_pf; ++ oct->hw_ops.dma_vf_intr_handler = octep_dma_vf_intr_handler_cn93_pf; ++ oct->hw_ops.pp_vf_intr_handler = octep_pp_vf_intr_handler_cn93_pf; ++ oct->hw_ops.misc_intr_handler = octep_misc_intr_handler_cn93_pf; ++ oct->hw_ops.rsvd_intr_handler = octep_rsvd_intr_handler_cn93_pf; + oct->hw_ops.ioq_intr_handler = octep_ioq_intr_handler_cn93_pf; + oct->hw_ops.soft_reset = octep_soft_reset_cn93_pf; + oct->hw_ops.reinit_regs = octep_reinit_regs_cn93_pf; +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c +index 32740d0a4216a..b19f756e24489 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c +@@ -155,18 +155,153 @@ static void octep_disable_msix(struct octep_device *oct) + } + + /** +- * octep_non_ioq_intr_handler() - common handler for all generic interrupts. ++ * octep_oei_intr_handler() - common handler for output endpoint interrupts. + * + * @irq: Interrupt number. + * @data: interrupt data. + * +- * this is common handler for all non-queue (generic) interrupts. ++ * this is common handler for all output endpoint interrupts. ++ */ ++static irqreturn_t octep_oei_intr_handler(int irq, void *data) ++{ ++ struct octep_device *oct = data; ++ ++ return oct->hw_ops.oei_intr_handler(oct); ++} ++ ++/** ++ * octep_ire_intr_handler() - common handler for input ring error interrupts. ++ * ++ * @irq: Interrupt number. ++ * @data: interrupt data. ++ * ++ * this is common handler for input ring error interrupts. ++ */ ++static irqreturn_t octep_ire_intr_handler(int irq, void *data) ++{ ++ struct octep_device *oct = data; ++ ++ return oct->hw_ops.ire_intr_handler(oct); ++} ++ ++/** ++ * octep_ore_intr_handler() - common handler for output ring error interrupts. ++ * ++ * @irq: Interrupt number. ++ * @data: interrupt data. ++ * ++ * this is common handler for output ring error interrupts. ++ */ ++static irqreturn_t octep_ore_intr_handler(int irq, void *data) ++{ ++ struct octep_device *oct = data; ++ ++ return oct->hw_ops.ore_intr_handler(oct); ++} ++ ++/** ++ * octep_vfire_intr_handler() - common handler for vf input ring error interrupts. ++ * ++ * @irq: Interrupt number. ++ * @data: interrupt data. ++ * ++ * this is common handler for vf input ring error interrupts. ++ */ ++static irqreturn_t octep_vfire_intr_handler(int irq, void *data) ++{ ++ struct octep_device *oct = data; ++ ++ return oct->hw_ops.vfire_intr_handler(oct); ++} ++ ++/** ++ * octep_vfore_intr_handler() - common handler for vf output ring error interrupts. ++ * ++ * @irq: Interrupt number. ++ * @data: interrupt data. ++ * ++ * this is common handler for vf output ring error interrupts. + */ +-static irqreturn_t octep_non_ioq_intr_handler(int irq, void *data) ++static irqreturn_t octep_vfore_intr_handler(int irq, void *data) + { + struct octep_device *oct = data; + +- return oct->hw_ops.non_ioq_intr_handler(oct); ++ return oct->hw_ops.vfore_intr_handler(oct); ++} ++ ++/** ++ * octep_dma_intr_handler() - common handler for dpi dma related interrupts. ++ * ++ * @irq: Interrupt number. ++ * @data: interrupt data. ++ * ++ * this is common handler for dpi dma related interrupts. ++ */ ++static irqreturn_t octep_dma_intr_handler(int irq, void *data) ++{ ++ struct octep_device *oct = data; ++ ++ return oct->hw_ops.dma_intr_handler(oct); ++} ++ ++/** ++ * octep_dma_vf_intr_handler() - common handler for dpi dma transaction error interrupts for VFs. ++ * ++ * @irq: Interrupt number. ++ * @data: interrupt data. ++ * ++ * this is common handler for dpi dma transaction error interrupts for VFs. ++ */ ++static irqreturn_t octep_dma_vf_intr_handler(int irq, void *data) ++{ ++ struct octep_device *oct = data; ++ ++ return oct->hw_ops.dma_vf_intr_handler(oct); ++} ++ ++/** ++ * octep_pp_vf_intr_handler() - common handler for pp transaction error interrupts for VFs. ++ * ++ * @irq: Interrupt number. ++ * @data: interrupt data. ++ * ++ * this is common handler for pp transaction error interrupts for VFs. ++ */ ++static irqreturn_t octep_pp_vf_intr_handler(int irq, void *data) ++{ ++ struct octep_device *oct = data; ++ ++ return oct->hw_ops.pp_vf_intr_handler(oct); ++} ++ ++/** ++ * octep_misc_intr_handler() - common handler for mac related interrupts. ++ * ++ * @irq: Interrupt number. ++ * @data: interrupt data. ++ * ++ * this is common handler for mac related interrupts. ++ */ ++static irqreturn_t octep_misc_intr_handler(int irq, void *data) ++{ ++ struct octep_device *oct = data; ++ ++ return oct->hw_ops.misc_intr_handler(oct); ++} ++ ++/** ++ * octep_rsvd_intr_handler() - common handler for reserved interrupts (future use). ++ * ++ * @irq: Interrupt number. ++ * @data: interrupt data. ++ * ++ * this is common handler for all reserved interrupts. ++ */ ++static irqreturn_t octep_rsvd_intr_handler(int irq, void *data) ++{ ++ struct octep_device *oct = data; ++ ++ return oct->hw_ops.rsvd_intr_handler(oct); + } + + /** +@@ -222,9 +357,57 @@ static int octep_request_irqs(struct octep_device *oct) + + snprintf(irq_name, OCTEP_MSIX_NAME_SIZE, + "%s-%s", netdev->name, non_ioq_msix_names[i]); +- ret = request_irq(msix_entry->vector, +- octep_non_ioq_intr_handler, 0, +- irq_name, oct); ++ if (!strncmp(non_ioq_msix_names[i], "epf_oei_rint", ++ strlen("epf_oei_rint"))) { ++ ret = request_irq(msix_entry->vector, ++ octep_oei_intr_handler, 0, ++ irq_name, oct); ++ } else if (!strncmp(non_ioq_msix_names[i], "epf_ire_rint", ++ strlen("epf_ire_rint"))) { ++ ret = request_irq(msix_entry->vector, ++ octep_ire_intr_handler, 0, ++ irq_name, oct); ++ } else if (!strncmp(non_ioq_msix_names[i], "epf_ore_rint", ++ strlen("epf_ore_rint"))) { ++ ret = request_irq(msix_entry->vector, ++ octep_ore_intr_handler, 0, ++ irq_name, oct); ++ } else if (!strncmp(non_ioq_msix_names[i], "epf_vfire_rint", ++ strlen("epf_vfire_rint"))) { ++ ret = request_irq(msix_entry->vector, ++ octep_vfire_intr_handler, 0, ++ irq_name, oct); ++ } else if (!strncmp(non_ioq_msix_names[i], "epf_vfore_rint", ++ strlen("epf_vfore_rint"))) { ++ ret = request_irq(msix_entry->vector, ++ octep_vfore_intr_handler, 0, ++ irq_name, oct); ++ } else if (!strncmp(non_ioq_msix_names[i], "epf_dma_rint", ++ strlen("epf_dma_rint"))) { ++ ret = request_irq(msix_entry->vector, ++ octep_dma_intr_handler, 0, ++ irq_name, oct); ++ } else if (!strncmp(non_ioq_msix_names[i], "epf_dma_vf_rint", ++ strlen("epf_dma_vf_rint"))) { ++ ret = request_irq(msix_entry->vector, ++ octep_dma_vf_intr_handler, 0, ++ irq_name, oct); ++ } else if (!strncmp(non_ioq_msix_names[i], "epf_pp_vf_rint", ++ strlen("epf_pp_vf_rint"))) { ++ ret = request_irq(msix_entry->vector, ++ octep_pp_vf_intr_handler, 0, ++ irq_name, oct); ++ } else if (!strncmp(non_ioq_msix_names[i], "epf_misc_rint", ++ strlen("epf_misc_rint"))) { ++ ret = request_irq(msix_entry->vector, ++ octep_misc_intr_handler, 0, ++ irq_name, oct); ++ } else { ++ ret = request_irq(msix_entry->vector, ++ octep_rsvd_intr_handler, 0, ++ irq_name, oct); ++ } ++ + if (ret) { + netdev_err(netdev, + "request_irq failed for %s; err=%d", +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_main.h b/drivers/net/ethernet/marvell/octeon_ep/octep_main.h +index e0907a7191330..6df902ebb7f33 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_main.h ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_main.h +@@ -65,7 +65,16 @@ struct octep_hw_ops { + void (*setup_oq_regs)(struct octep_device *oct, int q); + void (*setup_mbox_regs)(struct octep_device *oct, int mbox); + +- irqreturn_t (*non_ioq_intr_handler)(void *ioq_vector); ++ irqreturn_t (*oei_intr_handler)(void *ioq_vector); ++ irqreturn_t (*ire_intr_handler)(void *ioq_vector); ++ irqreturn_t (*ore_intr_handler)(void *ioq_vector); ++ irqreturn_t (*vfire_intr_handler)(void *ioq_vector); ++ irqreturn_t (*vfore_intr_handler)(void *ioq_vector); ++ irqreturn_t (*dma_intr_handler)(void *ioq_vector); ++ irqreturn_t (*dma_vf_intr_handler)(void *ioq_vector); ++ irqreturn_t (*pp_vf_intr_handler)(void *ioq_vector); ++ irqreturn_t (*misc_intr_handler)(void *ioq_vector); ++ irqreturn_t (*rsvd_intr_handler)(void *ioq_vector); + irqreturn_t (*ioq_intr_handler)(void *ioq_vector); + int (*soft_reset)(struct octep_device *oct); + void (*reinit_regs)(struct octep_device *oct); +@@ -73,7 +82,7 @@ struct octep_hw_ops { + + void (*enable_interrupts)(struct octep_device *oct); + void (*disable_interrupts)(struct octep_device *oct); +- bool (*poll_non_ioq_interrupts)(struct octep_device *oct); ++ void (*poll_non_ioq_interrupts)(struct octep_device *oct); + + void (*enable_io_queues)(struct octep_device *oct); + void (*disable_io_queues)(struct octep_device *oct); +-- +2.51.0 + diff --git a/queue-6.6/octeon_ep-set-backpressure-watermark-for-rx-queues.patch b/queue-6.6/octeon_ep-set-backpressure-watermark-for-rx-queues.patch new file mode 100644 index 0000000000..1b679ff0f0 --- /dev/null +++ b/queue-6.6/octeon_ep-set-backpressure-watermark-for-rx-queues.patch @@ -0,0 +1,102 @@ +From 41b2d44f3a48a0ec40ae32d57679847a35e49f76 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Nov 2023 21:31:31 -0800 +Subject: octeon_ep: set backpressure watermark for RX queues + +From: Shinas Rasheed + +[ Upstream commit 15bc81212f593fbd7bda787598418b931842dc14 ] + +Set backpressure watermark for hardware RX queues. Backpressure +gets triggered when the available buffers of a hardware RX queue +falls below the set watermark. This backpressure will propagate +to packet processing pipeline in the OCTEON card, so that the host +receives fewer packets and prevents packet dropping at host. + +Signed-off-by: Shinas Rasheed +Signed-off-by: David S. Miller +Stable-dep-of: ce8fe3fc4f99 ("octeon_ep: ensure dbell BADDR updation") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c | 7 +++++++ + drivers/net/ethernet/marvell/octeon_ep/octep_config.h | 10 ++++++++++ + .../ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h | 3 +++ + 3 files changed, 20 insertions(+) + +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c b/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c +index 633d39690eec8..38a03cef314e3 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c +@@ -258,6 +258,7 @@ static void octep_init_config_cnxk_pf(struct octep_device *oct) + conf->oq.refill_threshold = OCTEP_OQ_REFILL_THRESHOLD; + conf->oq.oq_intr_pkt = OCTEP_OQ_INTR_PKT_THRESHOLD; + conf->oq.oq_intr_time = OCTEP_OQ_INTR_TIME_THRESHOLD; ++ conf->oq.wmark = OCTEP_OQ_WMARK_MIN; + + conf->msix_cfg.non_ioq_msix = CNXK_NUM_NON_IOQ_INTR; + conf->msix_cfg.ioq_msix = conf->pf_ring_cfg.active_io_rings; +@@ -378,6 +379,12 @@ static void octep_setup_oq_regs_cnxk_pf(struct octep_device *oct, int oq_no) + reg_val = ((u64)time_threshold << 32) | + CFG_GET_OQ_INTR_PKT(oct->conf); + octep_write_csr64(oct, CNXK_SDP_R_OUT_INT_LEVELS(oq_no), reg_val); ++ ++ /* set watermark for backpressure */ ++ reg_val = octep_read_csr64(oct, CNXK_SDP_R_OUT_WMARK(oq_no)); ++ reg_val &= ~0xFFFFFFFFULL; ++ reg_val |= CFG_GET_OQ_WMARK(oct->conf); ++ octep_write_csr64(oct, CNXK_SDP_R_OUT_WMARK(oq_no), reg_val); + } + + /* Setup registers for a PF mailbox */ +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_config.h b/drivers/net/ethernet/marvell/octeon_ep/octep_config.h +index 1622a6ebf0362..ecc2947931410 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_config.h ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_config.h +@@ -19,6 +19,9 @@ + /* Packet threshold for Tx queue interrupt */ + #define OCTEP_IQ_INTR_THRESHOLD 0x0 + ++/* Minimum watermark for backpressure */ ++#define OCTEP_OQ_WMARK_MIN 256 ++ + /* Rx Queue: maximum descriptors per ring */ + #define OCTEP_OQ_MAX_DESCRIPTORS 1024 + +@@ -68,6 +71,7 @@ + #define CFG_GET_OQ_REFILL_THRESHOLD(cfg) ((cfg)->oq.refill_threshold) + #define CFG_GET_OQ_INTR_PKT(cfg) ((cfg)->oq.oq_intr_pkt) + #define CFG_GET_OQ_INTR_TIME(cfg) ((cfg)->oq.oq_intr_time) ++#define CFG_GET_OQ_WMARK(cfg) ((cfg)->oq.wmark) + + #define CFG_GET_PORTS_MAX_IO_RINGS(cfg) ((cfg)->pf_ring_cfg.max_io_rings) + #define CFG_GET_PORTS_ACTIVE_IO_RINGS(cfg) ((cfg)->pf_ring_cfg.active_io_rings) +@@ -137,6 +141,12 @@ struct octep_oq_config { + * default. The time is specified in microseconds. + */ + u32 oq_intr_time; ++ ++ /* Water mark for backpressure. ++ * Output queue sends backpressure signal to source when ++ * free buffer count falls below wmark. ++ */ ++ u32 wmark; + }; + + /* Tx/Rx configuration */ +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h b/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h +index 214aab88bb427..f0b3937002b62 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h +@@ -143,6 +143,9 @@ + #define CNXK_SDP_R_OUT_SLIST_DBELL(ring) \ + (CNXK_SDP_R_OUT_SLIST_DBELL_START + ((ring) * CNXK_RING_OFFSET)) + ++#define CNXK_SDP_R_OUT_WMARK(ring) \ ++ (CNXK_SDP_R_OUT_WMARK_START + ((ring) * CNXK_RING_OFFSET)) ++ + #define CNXK_SDP_R_OUT_CNTS(ring) \ + (CNXK_SDP_R_OUT_CNTS_START + ((ring) * CNXK_RING_OFFSET)) + +-- +2.51.0 + diff --git a/queue-6.6/octeon_ep-support-octeon-cn10k-devices.patch b/queue-6.6/octeon_ep-support-octeon-cn10k-devices.patch new file mode 100644 index 0000000000..a468bdcd10 --- /dev/null +++ b/queue-6.6/octeon_ep-support-octeon-cn10k-devices.patch @@ -0,0 +1,1431 @@ +From 2c7b1253faba6b73a428dc0228d295d72a70381f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Nov 2023 02:38:10 -0800 +Subject: octeon_ep: support Octeon CN10K devices + +From: Shinas Rasheed + +[ Upstream commit 0807dc76f3bf500f9a22465eedd2290da7357efb ] + +Add PCI Endpoint NIC support for Octeon CN10K devices. +CN10K devices are part of Octeon 10 family products with +similar PCI NIC characteristics. These include: +- CN10KA +- CNF10KA +- CNF10KB +- CN10KB + +Update supported device list in Documentation + +Signed-off-by: Shinas Rasheed +Link: https://lore.kernel.org/r/20231117103817.2468176-1-srasheed@marvell.com +Signed-off-by: Paolo Abeni +Stable-dep-of: 73e6ffa37ceb ("octeon_ep: disable per ring interrupts") +Signed-off-by: Sasha Levin +--- + .../ethernet/marvell/octeon_ep.rst | 4 + + .../net/ethernet/marvell/octeon_ep/Makefile | 3 +- + .../marvell/octeon_ep/octep_cnxk_pf.c | 886 ++++++++++++++++++ + .../ethernet/marvell/octeon_ep/octep_main.c | 20 + + .../ethernet/marvell/octeon_ep/octep_main.h | 6 + + .../marvell/octeon_ep/octep_regs_cnxk_pf.h | 400 ++++++++ + 6 files changed, 1318 insertions(+), 1 deletion(-) + create mode 100644 drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c + create mode 100644 drivers/net/ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h + +diff --git a/Documentation/networking/device_drivers/ethernet/marvell/octeon_ep.rst b/Documentation/networking/device_drivers/ethernet/marvell/octeon_ep.rst +index cad96c8d1f97d..613a818d5db6e 100644 +--- a/Documentation/networking/device_drivers/ethernet/marvell/octeon_ep.rst ++++ b/Documentation/networking/device_drivers/ethernet/marvell/octeon_ep.rst +@@ -24,6 +24,10 @@ Supported Devices + Currently, this driver support following devices: + * Network controller: Cavium, Inc. Device b200 + * Network controller: Cavium, Inc. Device b400 ++ * Network controller: Cavium, Inc. Device b900 ++ * Network controller: Cavium, Inc. Device ba00 ++ * Network controller: Cavium, Inc. Device bc00 ++ * Network controller: Cavium, Inc. Device bd00 + + Interface Control + ================= +diff --git a/drivers/net/ethernet/marvell/octeon_ep/Makefile b/drivers/net/ethernet/marvell/octeon_ep/Makefile +index 2026c8118158c..02a4a21bc2986 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/Makefile ++++ b/drivers/net/ethernet/marvell/octeon_ep/Makefile +@@ -6,4 +6,5 @@ + obj-$(CONFIG_OCTEON_EP) += octeon_ep.o + + octeon_ep-y := octep_main.o octep_cn9k_pf.o octep_tx.o octep_rx.o \ +- octep_ethtool.o octep_ctrl_mbox.o octep_ctrl_net.o ++ octep_ethtool.o octep_ctrl_mbox.o octep_ctrl_net.o \ ++ octep_cnxk_pf.o +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c b/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c +new file mode 100644 +index 0000000000000..abb03e9119e72 +--- /dev/null ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c +@@ -0,0 +1,886 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Marvell Octeon EP (EndPoint) Ethernet Driver ++ * ++ * Copyright (C) 2020 Marvell. ++ * ++ */ ++ ++#include ++#include ++#include ++ ++#include "octep_config.h" ++#include "octep_main.h" ++#include "octep_regs_cnxk_pf.h" ++ ++/* We will support 128 pf's in control mbox */ ++#define CTRL_MBOX_MAX_PF 128 ++#define CTRL_MBOX_SZ ((size_t)(0x400000 / CTRL_MBOX_MAX_PF)) ++ ++/* Names of Hardware non-queue generic interrupts */ ++static char *cnxk_non_ioq_msix_names[] = { ++ "epf_ire_rint", ++ "epf_ore_rint", ++ "epf_vfire_rint", ++ "epf_rsvd0", ++ "epf_vfore_rint", ++ "epf_rsvd1", ++ "epf_mbox_rint", ++ "epf_rsvd2_0", ++ "epf_rsvd2_1", ++ "epf_dma_rint", ++ "epf_dma_vf_rint", ++ "epf_rsvd3", ++ "epf_pp_vf_rint", ++ "epf_rsvd3", ++ "epf_misc_rint", ++ "epf_rsvd5", ++ /* Next 16 are for OEI_RINT */ ++ "epf_oei_rint0", ++ "epf_oei_rint1", ++ "epf_oei_rint2", ++ "epf_oei_rint3", ++ "epf_oei_rint4", ++ "epf_oei_rint5", ++ "epf_oei_rint6", ++ "epf_oei_rint7", ++ "epf_oei_rint8", ++ "epf_oei_rint9", ++ "epf_oei_rint10", ++ "epf_oei_rint11", ++ "epf_oei_rint12", ++ "epf_oei_rint13", ++ "epf_oei_rint14", ++ "epf_oei_rint15", ++ /* IOQ interrupt */ ++ "octeon_ep" ++}; ++ ++/* Dump useful hardware CSRs for debug purpose */ ++static void cnxk_dump_regs(struct octep_device *oct, int qno) ++{ ++ struct device *dev = &oct->pdev->dev; ++ ++ dev_info(dev, "IQ-%d register dump\n", qno); ++ dev_info(dev, "R[%d]_IN_INSTR_DBELL[0x%llx]: 0x%016llx\n", ++ qno, CNXK_SDP_R_IN_INSTR_DBELL(qno), ++ octep_read_csr64(oct, CNXK_SDP_R_IN_INSTR_DBELL(qno))); ++ dev_info(dev, "R[%d]_IN_CONTROL[0x%llx]: 0x%016llx\n", ++ qno, CNXK_SDP_R_IN_CONTROL(qno), ++ octep_read_csr64(oct, CNXK_SDP_R_IN_CONTROL(qno))); ++ dev_info(dev, "R[%d]_IN_ENABLE[0x%llx]: 0x%016llx\n", ++ qno, CNXK_SDP_R_IN_ENABLE(qno), ++ octep_read_csr64(oct, CNXK_SDP_R_IN_ENABLE(qno))); ++ dev_info(dev, "R[%d]_IN_INSTR_BADDR[0x%llx]: 0x%016llx\n", ++ qno, CNXK_SDP_R_IN_INSTR_BADDR(qno), ++ octep_read_csr64(oct, CNXK_SDP_R_IN_INSTR_BADDR(qno))); ++ dev_info(dev, "R[%d]_IN_INSTR_RSIZE[0x%llx]: 0x%016llx\n", ++ qno, CNXK_SDP_R_IN_INSTR_RSIZE(qno), ++ octep_read_csr64(oct, CNXK_SDP_R_IN_INSTR_RSIZE(qno))); ++ dev_info(dev, "R[%d]_IN_CNTS[0x%llx]: 0x%016llx\n", ++ qno, CNXK_SDP_R_IN_CNTS(qno), ++ octep_read_csr64(oct, CNXK_SDP_R_IN_CNTS(qno))); ++ dev_info(dev, "R[%d]_IN_INT_LEVELS[0x%llx]: 0x%016llx\n", ++ qno, CNXK_SDP_R_IN_INT_LEVELS(qno), ++ octep_read_csr64(oct, CNXK_SDP_R_IN_INT_LEVELS(qno))); ++ dev_info(dev, "R[%d]_IN_PKT_CNT[0x%llx]: 0x%016llx\n", ++ qno, CNXK_SDP_R_IN_PKT_CNT(qno), ++ octep_read_csr64(oct, CNXK_SDP_R_IN_PKT_CNT(qno))); ++ dev_info(dev, "R[%d]_IN_BYTE_CNT[0x%llx]: 0x%016llx\n", ++ qno, CNXK_SDP_R_IN_BYTE_CNT(qno), ++ octep_read_csr64(oct, CNXK_SDP_R_IN_BYTE_CNT(qno))); ++ ++ dev_info(dev, "OQ-%d register dump\n", qno); ++ dev_info(dev, "R[%d]_OUT_SLIST_DBELL[0x%llx]: 0x%016llx\n", ++ qno, CNXK_SDP_R_OUT_SLIST_DBELL(qno), ++ octep_read_csr64(oct, CNXK_SDP_R_OUT_SLIST_DBELL(qno))); ++ dev_info(dev, "R[%d]_OUT_CONTROL[0x%llx]: 0x%016llx\n", ++ qno, CNXK_SDP_R_OUT_CONTROL(qno), ++ octep_read_csr64(oct, CNXK_SDP_R_OUT_CONTROL(qno))); ++ dev_info(dev, "R[%d]_OUT_ENABLE[0x%llx]: 0x%016llx\n", ++ qno, CNXK_SDP_R_OUT_ENABLE(qno), ++ octep_read_csr64(oct, CNXK_SDP_R_OUT_ENABLE(qno))); ++ dev_info(dev, "R[%d]_OUT_SLIST_BADDR[0x%llx]: 0x%016llx\n", ++ qno, CNXK_SDP_R_OUT_SLIST_BADDR(qno), ++ octep_read_csr64(oct, CNXK_SDP_R_OUT_SLIST_BADDR(qno))); ++ dev_info(dev, "R[%d]_OUT_SLIST_RSIZE[0x%llx]: 0x%016llx\n", ++ qno, CNXK_SDP_R_OUT_SLIST_RSIZE(qno), ++ octep_read_csr64(oct, CNXK_SDP_R_OUT_SLIST_RSIZE(qno))); ++ dev_info(dev, "R[%d]_OUT_CNTS[0x%llx]: 0x%016llx\n", ++ qno, CNXK_SDP_R_OUT_CNTS(qno), ++ octep_read_csr64(oct, CNXK_SDP_R_OUT_CNTS(qno))); ++ dev_info(dev, "R[%d]_OUT_INT_LEVELS[0x%llx]: 0x%016llx\n", ++ qno, CNXK_SDP_R_OUT_INT_LEVELS(qno), ++ octep_read_csr64(oct, CNXK_SDP_R_OUT_INT_LEVELS(qno))); ++ dev_info(dev, "R[%d]_OUT_PKT_CNT[0x%llx]: 0x%016llx\n", ++ qno, CNXK_SDP_R_OUT_PKT_CNT(qno), ++ octep_read_csr64(oct, CNXK_SDP_R_OUT_PKT_CNT(qno))); ++ dev_info(dev, "R[%d]_OUT_BYTE_CNT[0x%llx]: 0x%016llx\n", ++ qno, CNXK_SDP_R_OUT_BYTE_CNT(qno), ++ octep_read_csr64(oct, CNXK_SDP_R_OUT_BYTE_CNT(qno))); ++ dev_info(dev, "R[%d]_ERR_TYPE[0x%llx]: 0x%016llx\n", ++ qno, CNXK_SDP_R_ERR_TYPE(qno), ++ octep_read_csr64(oct, CNXK_SDP_R_ERR_TYPE(qno))); ++} ++ ++/* Reset Hardware Tx queue */ ++static int cnxk_reset_iq(struct octep_device *oct, int q_no) ++{ ++ struct octep_config *conf = oct->conf; ++ u64 val = 0ULL; ++ ++ dev_dbg(&oct->pdev->dev, "Reset PF IQ-%d\n", q_no); ++ ++ /* Get absolute queue number */ ++ q_no += conf->pf_ring_cfg.srn; ++ ++ /* Disable the Tx/Instruction Ring */ ++ octep_write_csr64(oct, CNXK_SDP_R_IN_ENABLE(q_no), val); ++ ++ /* clear the Instruction Ring packet/byte counts and doorbell CSRs */ ++ octep_write_csr64(oct, CNXK_SDP_R_IN_CNTS(q_no), val); ++ octep_write_csr64(oct, CNXK_SDP_R_IN_INT_LEVELS(q_no), val); ++ octep_write_csr64(oct, CNXK_SDP_R_IN_PKT_CNT(q_no), val); ++ octep_write_csr64(oct, CNXK_SDP_R_IN_BYTE_CNT(q_no), val); ++ octep_write_csr64(oct, CNXK_SDP_R_IN_INSTR_BADDR(q_no), val); ++ octep_write_csr64(oct, CNXK_SDP_R_IN_INSTR_RSIZE(q_no), val); ++ ++ val = 0xFFFFFFFF; ++ octep_write_csr64(oct, CNXK_SDP_R_IN_INSTR_DBELL(q_no), val); ++ ++ return 0; ++} ++ ++/* Reset Hardware Rx queue */ ++static void cnxk_reset_oq(struct octep_device *oct, int q_no) ++{ ++ u64 val = 0ULL; ++ ++ q_no += CFG_GET_PORTS_PF_SRN(oct->conf); ++ ++ /* Disable Output (Rx) Ring */ ++ octep_write_csr64(oct, CNXK_SDP_R_OUT_ENABLE(q_no), val); ++ octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_BADDR(q_no), val); ++ octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_RSIZE(q_no), val); ++ octep_write_csr64(oct, CNXK_SDP_R_OUT_INT_LEVELS(q_no), val); ++ ++ /* Clear count CSRs */ ++ val = octep_read_csr(oct, CNXK_SDP_R_OUT_CNTS(q_no)); ++ octep_write_csr(oct, CNXK_SDP_R_OUT_CNTS(q_no), val); ++ ++ octep_write_csr64(oct, CNXK_SDP_R_OUT_PKT_CNT(q_no), 0xFFFFFFFFFULL); ++ octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_DBELL(q_no), 0xFFFFFFFF); ++} ++ ++/* Reset all hardware Tx/Rx queues */ ++static void octep_reset_io_queues_cnxk_pf(struct octep_device *oct) ++{ ++ struct pci_dev *pdev = oct->pdev; ++ int q; ++ ++ dev_dbg(&pdev->dev, "Reset OCTEP_CNXK PF IO Queues\n"); ++ ++ for (q = 0; q < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); q++) { ++ cnxk_reset_iq(oct, q); ++ cnxk_reset_oq(oct, q); ++ } ++} ++ ++/* Initialize windowed addresses to access some hardware registers */ ++static void octep_setup_pci_window_regs_cnxk_pf(struct octep_device *oct) ++{ ++ u8 __iomem *bar0_pciaddr = oct->mmio[0].hw_addr; ++ ++ oct->pci_win_regs.pci_win_wr_addr = (u8 __iomem *)(bar0_pciaddr + CNXK_SDP_WIN_WR_ADDR64); ++ oct->pci_win_regs.pci_win_rd_addr = (u8 __iomem *)(bar0_pciaddr + CNXK_SDP_WIN_RD_ADDR64); ++ oct->pci_win_regs.pci_win_wr_data = (u8 __iomem *)(bar0_pciaddr + CNXK_SDP_WIN_WR_DATA64); ++ oct->pci_win_regs.pci_win_rd_data = (u8 __iomem *)(bar0_pciaddr + CNXK_SDP_WIN_RD_DATA64); ++} ++ ++/* Configure Hardware mapping: inform hardware which rings belong to PF. */ ++static void octep_configure_ring_mapping_cnxk_pf(struct octep_device *oct) ++{ ++ struct octep_config *conf = oct->conf; ++ struct pci_dev *pdev = oct->pdev; ++ u64 pf_srn = CFG_GET_PORTS_PF_SRN(oct->conf); ++ int q; ++ ++ for (q = 0; q < CFG_GET_PORTS_ACTIVE_IO_RINGS(conf); q++) { ++ u64 regval = 0; ++ ++ if (oct->pcie_port) ++ regval = 8 << CNXK_SDP_FUNC_SEL_EPF_BIT_POS; ++ ++ octep_write_csr64(oct, CNXK_SDP_EPVF_RING(pf_srn + q), regval); ++ ++ regval = octep_read_csr64(oct, CNXK_SDP_EPVF_RING(pf_srn + q)); ++ dev_dbg(&pdev->dev, "Write SDP_EPVF_RING[0x%llx] = 0x%llx\n", ++ CNXK_SDP_EPVF_RING(pf_srn + q), regval); ++ } ++} ++ ++/* Initialize configuration limits and initial active config */ ++static void octep_init_config_cnxk_pf(struct octep_device *oct) ++{ ++ struct octep_config *conf = oct->conf; ++ struct pci_dev *pdev = oct->pdev; ++ u8 link = 0; ++ u64 val; ++ int pos; ++ ++ /* Read ring configuration: ++ * PF ring count, number of VFs and rings per VF supported ++ */ ++ val = octep_read_csr64(oct, CNXK_SDP_EPF_RINFO); ++ dev_info(&pdev->dev, "SDP_EPF_RINFO[0x%x]:0x%llx\n", CNXK_SDP_EPF_RINFO, val); ++ conf->sriov_cfg.max_rings_per_vf = CNXK_SDP_EPF_RINFO_RPVF(val); ++ conf->sriov_cfg.active_rings_per_vf = conf->sriov_cfg.max_rings_per_vf; ++ conf->sriov_cfg.max_vfs = CNXK_SDP_EPF_RINFO_NVFS(val); ++ conf->sriov_cfg.active_vfs = conf->sriov_cfg.max_vfs; ++ conf->sriov_cfg.vf_srn = CNXK_SDP_EPF_RINFO_SRN(val); ++ ++ val = octep_read_csr64(oct, CNXK_SDP_MAC_PF_RING_CTL(oct->pcie_port)); ++ dev_info(&pdev->dev, "SDP_MAC_PF_RING_CTL[%d]:0x%llx\n", oct->pcie_port, val); ++ conf->pf_ring_cfg.srn = CNXK_SDP_MAC_PF_RING_CTL_SRN(val); ++ conf->pf_ring_cfg.max_io_rings = CNXK_SDP_MAC_PF_RING_CTL_RPPF(val); ++ conf->pf_ring_cfg.active_io_rings = conf->pf_ring_cfg.max_io_rings; ++ dev_info(&pdev->dev, "pf_srn=%u rpvf=%u nvfs=%u rppf=%u\n", ++ conf->pf_ring_cfg.srn, conf->sriov_cfg.active_rings_per_vf, ++ conf->sriov_cfg.active_vfs, conf->pf_ring_cfg.active_io_rings); ++ ++ conf->iq.num_descs = OCTEP_IQ_MAX_DESCRIPTORS; ++ conf->iq.instr_type = OCTEP_64BYTE_INSTR; ++ conf->iq.db_min = OCTEP_DB_MIN; ++ conf->iq.intr_threshold = OCTEP_IQ_INTR_THRESHOLD; ++ ++ conf->oq.num_descs = OCTEP_OQ_MAX_DESCRIPTORS; ++ conf->oq.buf_size = OCTEP_OQ_BUF_SIZE; ++ conf->oq.refill_threshold = OCTEP_OQ_REFILL_THRESHOLD; ++ conf->oq.oq_intr_pkt = OCTEP_OQ_INTR_PKT_THRESHOLD; ++ conf->oq.oq_intr_time = OCTEP_OQ_INTR_TIME_THRESHOLD; ++ ++ conf->msix_cfg.non_ioq_msix = CNXK_NUM_NON_IOQ_INTR; ++ conf->msix_cfg.ioq_msix = conf->pf_ring_cfg.active_io_rings; ++ conf->msix_cfg.non_ioq_msix_names = cnxk_non_ioq_msix_names; ++ ++ pos = pci_find_ext_capability(oct->pdev, PCI_EXT_CAP_ID_SRIOV); ++ if (pos) { ++ pci_read_config_byte(oct->pdev, ++ pos + PCI_SRIOV_FUNC_LINK, ++ &link); ++ link = PCI_DEVFN(PCI_SLOT(oct->pdev->devfn), link); ++ } ++ conf->ctrl_mbox_cfg.barmem_addr = (void __iomem *)oct->mmio[2].hw_addr + ++ CNXK_PEM_BAR4_INDEX_OFFSET + ++ (link * CTRL_MBOX_SZ); ++ ++ conf->fw_info.hb_interval = OCTEP_DEFAULT_FW_HB_INTERVAL; ++ conf->fw_info.hb_miss_count = OCTEP_DEFAULT_FW_HB_MISS_COUNT; ++} ++ ++/* Setup registers for a hardware Tx Queue */ ++static void octep_setup_iq_regs_cnxk_pf(struct octep_device *oct, int iq_no) ++{ ++ struct octep_iq *iq = oct->iq[iq_no]; ++ u32 reset_instr_cnt; ++ u64 reg_val; ++ ++ iq_no += CFG_GET_PORTS_PF_SRN(oct->conf); ++ reg_val = octep_read_csr64(oct, CNXK_SDP_R_IN_CONTROL(iq_no)); ++ ++ /* wait for IDLE to set to 1 */ ++ if (!(reg_val & CNXK_R_IN_CTL_IDLE)) { ++ do { ++ reg_val = octep_read_csr64(oct, CNXK_SDP_R_IN_CONTROL(iq_no)); ++ } while (!(reg_val & CNXK_R_IN_CTL_IDLE)); ++ } ++ ++ reg_val |= CNXK_R_IN_CTL_RDSIZE; ++ reg_val |= CNXK_R_IN_CTL_IS_64B; ++ reg_val |= CNXK_R_IN_CTL_ESR; ++ octep_write_csr64(oct, CNXK_SDP_R_IN_CONTROL(iq_no), reg_val); ++ ++ /* Write the start of the input queue's ring and its size */ ++ octep_write_csr64(oct, CNXK_SDP_R_IN_INSTR_BADDR(iq_no), ++ iq->desc_ring_dma); ++ octep_write_csr64(oct, CNXK_SDP_R_IN_INSTR_RSIZE(iq_no), ++ iq->max_count); ++ ++ /* Remember the doorbell & instruction count register addr ++ * for this queue ++ */ ++ iq->doorbell_reg = oct->mmio[0].hw_addr + ++ CNXK_SDP_R_IN_INSTR_DBELL(iq_no); ++ iq->inst_cnt_reg = oct->mmio[0].hw_addr + ++ CNXK_SDP_R_IN_CNTS(iq_no); ++ iq->intr_lvl_reg = oct->mmio[0].hw_addr + ++ CNXK_SDP_R_IN_INT_LEVELS(iq_no); ++ ++ /* Store the current instruction counter (used in flush_iq calculation) */ ++ reset_instr_cnt = readl(iq->inst_cnt_reg); ++ writel(reset_instr_cnt, iq->inst_cnt_reg); ++ ++ /* INTR_THRESHOLD is set to max(FFFFFFFF) to disable the INTR */ ++ reg_val = CFG_GET_IQ_INTR_THRESHOLD(oct->conf) & 0xffffffff; ++ octep_write_csr64(oct, CNXK_SDP_R_IN_INT_LEVELS(iq_no), reg_val); ++} ++ ++/* Setup registers for a hardware Rx Queue */ ++static void octep_setup_oq_regs_cnxk_pf(struct octep_device *oct, int oq_no) ++{ ++ u64 reg_val; ++ u64 oq_ctl = 0ULL; ++ u32 time_threshold = 0; ++ struct octep_oq *oq = oct->oq[oq_no]; ++ ++ oq_no += CFG_GET_PORTS_PF_SRN(oct->conf); ++ reg_val = octep_read_csr64(oct, CNXK_SDP_R_OUT_CONTROL(oq_no)); ++ ++ /* wait for IDLE to set to 1 */ ++ if (!(reg_val & CNXK_R_OUT_CTL_IDLE)) { ++ do { ++ reg_val = octep_read_csr64(oct, CNXK_SDP_R_OUT_CONTROL(oq_no)); ++ } while (!(reg_val & CNXK_R_OUT_CTL_IDLE)); ++ } ++ ++ reg_val &= ~(CNXK_R_OUT_CTL_IMODE); ++ reg_val &= ~(CNXK_R_OUT_CTL_ROR_P); ++ reg_val &= ~(CNXK_R_OUT_CTL_NSR_P); ++ reg_val &= ~(CNXK_R_OUT_CTL_ROR_I); ++ reg_val &= ~(CNXK_R_OUT_CTL_NSR_I); ++ reg_val &= ~(CNXK_R_OUT_CTL_ES_I); ++ reg_val &= ~(CNXK_R_OUT_CTL_ROR_D); ++ reg_val &= ~(CNXK_R_OUT_CTL_NSR_D); ++ reg_val &= ~(CNXK_R_OUT_CTL_ES_D); ++ reg_val |= (CNXK_R_OUT_CTL_ES_P); ++ ++ octep_write_csr64(oct, CNXK_SDP_R_OUT_CONTROL(oq_no), reg_val); ++ octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_BADDR(oq_no), ++ oq->desc_ring_dma); ++ octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_RSIZE(oq_no), ++ oq->max_count); ++ ++ oq_ctl = octep_read_csr64(oct, CNXK_SDP_R_OUT_CONTROL(oq_no)); ++ ++ /* Clear the ISIZE and BSIZE (22-0) */ ++ oq_ctl &= ~0x7fffffULL; ++ ++ /* Populate the BSIZE (15-0) */ ++ oq_ctl |= (oq->buffer_size & 0xffff); ++ octep_write_csr64(oct, CNXK_SDP_R_OUT_CONTROL(oq_no), oq_ctl); ++ ++ /* Get the mapped address of the pkt_sent and pkts_credit regs */ ++ oq->pkts_sent_reg = oct->mmio[0].hw_addr + CNXK_SDP_R_OUT_CNTS(oq_no); ++ oq->pkts_credit_reg = oct->mmio[0].hw_addr + ++ CNXK_SDP_R_OUT_SLIST_DBELL(oq_no); ++ ++ time_threshold = CFG_GET_OQ_INTR_TIME(oct->conf); ++ reg_val = ((u64)time_threshold << 32) | ++ CFG_GET_OQ_INTR_PKT(oct->conf); ++ octep_write_csr64(oct, CNXK_SDP_R_OUT_INT_LEVELS(oq_no), reg_val); ++} ++ ++/* Setup registers for a PF mailbox */ ++static void octep_setup_mbox_regs_cnxk_pf(struct octep_device *oct, int q_no) ++{ ++ struct octep_mbox *mbox = oct->mbox[q_no]; ++ ++ mbox->q_no = q_no; ++ ++ /* PF mbox interrupt reg */ ++ mbox->mbox_int_reg = oct->mmio[0].hw_addr + CNXK_SDP_EPF_MBOX_RINT(0); ++ ++ /* PF to VF DATA reg. PF writes into this reg */ ++ mbox->mbox_write_reg = oct->mmio[0].hw_addr + CNXK_SDP_R_MBOX_PF_VF_DATA(q_no); ++ ++ /* VF to PF DATA reg. PF reads from this reg */ ++ mbox->mbox_read_reg = oct->mmio[0].hw_addr + CNXK_SDP_R_MBOX_VF_PF_DATA(q_no); ++} ++ ++/* Poll OEI events like heartbeat */ ++static void octep_poll_oei_cnxk_pf(struct octep_device *oct) ++{ ++ u64 reg0; ++ ++ /* Check for OEI INTR */ ++ reg0 = octep_read_csr64(oct, CNXK_SDP_EPF_OEI_RINT); ++ if (reg0) { ++ octep_write_csr64(oct, CNXK_SDP_EPF_OEI_RINT, reg0); ++ if (reg0 & CNXK_SDP_EPF_OEI_RINT_DATA_BIT_MBOX) ++ queue_work(octep_wq, &oct->ctrl_mbox_task); ++ if (reg0 & CNXK_SDP_EPF_OEI_RINT_DATA_BIT_HBEAT) ++ atomic_set(&oct->hb_miss_cnt, 0); ++ } ++} ++ ++/* OEI interrupt handler */ ++static irqreturn_t octep_oei_intr_handler_cnxk_pf(void *dev) ++{ ++ struct octep_device *oct = (struct octep_device *)dev; ++ ++ octep_poll_oei_cnxk_pf(oct); ++ return IRQ_HANDLED; ++} ++ ++/* Process non-ioq interrupts required to keep pf interface running. ++ * OEI_RINT is needed for control mailbox ++ * MBOX_RINT is needed for pfvf mailbox ++ */ ++static void octep_poll_non_ioq_interrupts_cnxk_pf(struct octep_device *oct) ++{ ++ octep_poll_oei_cnxk_pf(oct); ++} ++ ++/* Interrupt handler for input ring error interrupts. */ ++static irqreturn_t octep_ire_intr_handler_cnxk_pf(void *dev) ++{ ++ struct octep_device *oct = (struct octep_device *)dev; ++ struct pci_dev *pdev = oct->pdev; ++ u64 reg_val = 0; ++ int i = 0; ++ ++ /* Check for IRERR INTR */ ++ reg_val = octep_read_csr64(oct, CNXK_SDP_EPF_IRERR_RINT); ++ if (reg_val) { ++ dev_info(&pdev->dev, ++ "received IRERR_RINT intr: 0x%llx\n", reg_val); ++ octep_write_csr64(oct, CNXK_SDP_EPF_IRERR_RINT, reg_val); ++ ++ for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) { ++ reg_val = octep_read_csr64(oct, ++ CNXK_SDP_R_ERR_TYPE(i)); ++ if (reg_val) { ++ dev_info(&pdev->dev, ++ "Received err type on IQ-%d: 0x%llx\n", ++ i, reg_val); ++ octep_write_csr64(oct, CNXK_SDP_R_ERR_TYPE(i), ++ reg_val); ++ } ++ } ++ } ++ return IRQ_HANDLED; ++} ++ ++/* Interrupt handler for output ring error interrupts. */ ++static irqreturn_t octep_ore_intr_handler_cnxk_pf(void *dev) ++{ ++ struct octep_device *oct = (struct octep_device *)dev; ++ struct pci_dev *pdev = oct->pdev; ++ u64 reg_val = 0; ++ int i = 0; ++ ++ /* Check for ORERR INTR */ ++ reg_val = octep_read_csr64(oct, CNXK_SDP_EPF_ORERR_RINT); ++ if (reg_val) { ++ dev_info(&pdev->dev, ++ "Received ORERR_RINT intr: 0x%llx\n", reg_val); ++ octep_write_csr64(oct, CNXK_SDP_EPF_ORERR_RINT, reg_val); ++ for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) { ++ reg_val = octep_read_csr64(oct, CNXK_SDP_R_ERR_TYPE(i)); ++ if (reg_val) { ++ dev_info(&pdev->dev, ++ "Received err type on OQ-%d: 0x%llx\n", ++ i, reg_val); ++ octep_write_csr64(oct, CNXK_SDP_R_ERR_TYPE(i), ++ reg_val); ++ } ++ } ++ } ++ return IRQ_HANDLED; ++} ++ ++/* Interrupt handler for vf input ring error interrupts. */ ++static irqreturn_t octep_vfire_intr_handler_cnxk_pf(void *dev) ++{ ++ struct octep_device *oct = (struct octep_device *)dev; ++ struct pci_dev *pdev = oct->pdev; ++ u64 reg_val = 0; ++ ++ /* Check for VFIRE INTR */ ++ reg_val = octep_read_csr64(oct, CNXK_SDP_EPF_VFIRE_RINT(0)); ++ if (reg_val) { ++ dev_info(&pdev->dev, ++ "Received VFIRE_RINT intr: 0x%llx\n", reg_val); ++ octep_write_csr64(oct, CNXK_SDP_EPF_VFIRE_RINT(0), reg_val); ++ } ++ return IRQ_HANDLED; ++} ++ ++/* Interrupt handler for vf output ring error interrupts. */ ++static irqreturn_t octep_vfore_intr_handler_cnxk_pf(void *dev) ++{ ++ struct octep_device *oct = (struct octep_device *)dev; ++ struct pci_dev *pdev = oct->pdev; ++ u64 reg_val = 0; ++ ++ /* Check for VFORE INTR */ ++ reg_val = octep_read_csr64(oct, CNXK_SDP_EPF_VFORE_RINT(0)); ++ if (reg_val) { ++ dev_info(&pdev->dev, ++ "Received VFORE_RINT intr: 0x%llx\n", reg_val); ++ octep_write_csr64(oct, CNXK_SDP_EPF_VFORE_RINT(0), reg_val); ++ } ++ return IRQ_HANDLED; ++} ++ ++/* Interrupt handler for dpi dma related interrupts. */ ++static irqreturn_t octep_dma_intr_handler_cnxk_pf(void *dev) ++{ ++ struct octep_device *oct = (struct octep_device *)dev; ++ u64 reg_val = 0; ++ ++ /* Check for DMA INTR */ ++ reg_val = octep_read_csr64(oct, CNXK_SDP_EPF_DMA_RINT); ++ if (reg_val) ++ octep_write_csr64(oct, CNXK_SDP_EPF_DMA_RINT, reg_val); ++ ++ return IRQ_HANDLED; ++} ++ ++/* Interrupt handler for dpi dma transaction error interrupts for VFs */ ++static irqreturn_t octep_dma_vf_intr_handler_cnxk_pf(void *dev) ++{ ++ struct octep_device *oct = (struct octep_device *)dev; ++ struct pci_dev *pdev = oct->pdev; ++ u64 reg_val = 0; ++ ++ /* Check for DMA VF INTR */ ++ reg_val = octep_read_csr64(oct, CNXK_SDP_EPF_DMA_VF_RINT(0)); ++ if (reg_val) { ++ dev_info(&pdev->dev, ++ "Received DMA_VF_RINT intr: 0x%llx\n", reg_val); ++ octep_write_csr64(oct, CNXK_SDP_EPF_DMA_VF_RINT(0), reg_val); ++ } ++ return IRQ_HANDLED; ++} ++ ++/* Interrupt handler for pp transaction error interrupts for VFs */ ++static irqreturn_t octep_pp_vf_intr_handler_cnxk_pf(void *dev) ++{ ++ struct octep_device *oct = (struct octep_device *)dev; ++ struct pci_dev *pdev = oct->pdev; ++ u64 reg_val = 0; ++ ++ /* Check for PPVF INTR */ ++ reg_val = octep_read_csr64(oct, CNXK_SDP_EPF_PP_VF_RINT(0)); ++ if (reg_val) { ++ dev_info(&pdev->dev, ++ "Received PP_VF_RINT intr: 0x%llx\n", reg_val); ++ octep_write_csr64(oct, CNXK_SDP_EPF_PP_VF_RINT(0), reg_val); ++ } ++ return IRQ_HANDLED; ++} ++ ++/* Interrupt handler for mac related interrupts. */ ++static irqreturn_t octep_misc_intr_handler_cnxk_pf(void *dev) ++{ ++ struct octep_device *oct = (struct octep_device *)dev; ++ struct pci_dev *pdev = oct->pdev; ++ u64 reg_val = 0; ++ ++ /* Check for MISC INTR */ ++ reg_val = octep_read_csr64(oct, CNXK_SDP_EPF_MISC_RINT); ++ if (reg_val) { ++ dev_info(&pdev->dev, ++ "Received MISC_RINT intr: 0x%llx\n", reg_val); ++ octep_write_csr64(oct, CNXK_SDP_EPF_MISC_RINT, reg_val); ++ } ++ return IRQ_HANDLED; ++} ++ ++/* Interrupts handler for all reserved interrupts. */ ++static irqreturn_t octep_rsvd_intr_handler_cnxk_pf(void *dev) ++{ ++ struct octep_device *oct = (struct octep_device *)dev; ++ struct pci_dev *pdev = oct->pdev; ++ ++ dev_info(&pdev->dev, "Reserved interrupts raised; Ignore\n"); ++ return IRQ_HANDLED; ++} ++ ++/* Tx/Rx queue interrupt handler */ ++static irqreturn_t octep_ioq_intr_handler_cnxk_pf(void *data) ++{ ++ struct octep_ioq_vector *vector = (struct octep_ioq_vector *)data; ++ struct octep_oq *oq = vector->oq; ++ ++ napi_schedule_irqoff(oq->napi); ++ return IRQ_HANDLED; ++} ++ ++/* soft reset */ ++static int octep_soft_reset_cnxk_pf(struct octep_device *oct) ++{ ++ dev_info(&oct->pdev->dev, "CNXKXX: Doing soft reset\n"); ++ ++ octep_write_csr64(oct, CNXK_SDP_WIN_WR_MASK_REG, 0xFF); ++ ++ /* Firmware status CSR is supposed to be cleared by ++ * core domain reset, but due to a hw bug, it is not. ++ * Set it to RUNNING right before reset so that it is not ++ * left in READY (1) state after a reset. This is required ++ * in addition to the early setting to handle the case where ++ * the OcteonTX is unexpectedly reset, reboots, and then ++ * the module is removed. ++ */ ++ OCTEP_PCI_WIN_WRITE(oct, CNXK_PEMX_PFX_CSX_PFCFGX(0, 0, CNXK_PCIEEP_VSECST_CTL), ++ FW_STATUS_RUNNING); ++ ++ /* Set chip domain reset bit */ ++ OCTEP_PCI_WIN_WRITE(oct, CNXK_RST_CHIP_DOMAIN_W1S, 1); ++ /* Wait till Octeon resets. */ ++ mdelay(10); ++ /* restore the reset value */ ++ octep_write_csr64(oct, CNXK_SDP_WIN_WR_MASK_REG, 0xFF); ++ ++ return 0; ++} ++ ++/* Re-initialize Octeon hardware registers */ ++static void octep_reinit_regs_cnxk_pf(struct octep_device *oct) ++{ ++ u32 i; ++ ++ for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) ++ oct->hw_ops.setup_iq_regs(oct, i); ++ ++ for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) ++ oct->hw_ops.setup_oq_regs(oct, i); ++ ++ oct->hw_ops.enable_interrupts(oct); ++ oct->hw_ops.enable_io_queues(oct); ++ ++ for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) ++ writel(oct->oq[i]->max_count, oct->oq[i]->pkts_credit_reg); ++} ++ ++/* Enable all interrupts */ ++static void octep_enable_interrupts_cnxk_pf(struct octep_device *oct) ++{ ++ u64 intr_mask = 0ULL; ++ int srn, num_rings, i; ++ ++ srn = CFG_GET_PORTS_PF_SRN(oct->conf); ++ num_rings = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); ++ ++ for (i = 0; i < num_rings; i++) ++ intr_mask |= (0x1ULL << (srn + i)); ++ ++ octep_write_csr64(oct, CNXK_SDP_EPF_IRERR_RINT_ENA_W1S, intr_mask); ++ octep_write_csr64(oct, CNXK_SDP_EPF_ORERR_RINT_ENA_W1S, intr_mask); ++ octep_write_csr64(oct, CNXK_SDP_EPF_OEI_RINT_ENA_W1S, -1ULL); ++ ++ octep_write_csr64(oct, CNXK_SDP_EPF_VFIRE_RINT_ENA_W1S(0), -1ULL); ++ octep_write_csr64(oct, CNXK_SDP_EPF_VFORE_RINT_ENA_W1S(0), -1ULL); ++ ++ octep_write_csr64(oct, CNXK_SDP_EPF_MISC_RINT_ENA_W1S, intr_mask); ++ octep_write_csr64(oct, CNXK_SDP_EPF_DMA_RINT_ENA_W1S, intr_mask); ++ ++ octep_write_csr64(oct, CNXK_SDP_EPF_DMA_VF_RINT_ENA_W1S(0), -1ULL); ++ octep_write_csr64(oct, CNXK_SDP_EPF_PP_VF_RINT_ENA_W1S(0), -1ULL); ++} ++ ++/* Disable all interrupts */ ++static void octep_disable_interrupts_cnxk_pf(struct octep_device *oct) ++{ ++ u64 intr_mask = 0ULL; ++ int srn, num_rings, i; ++ ++ srn = CFG_GET_PORTS_PF_SRN(oct->conf); ++ num_rings = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); ++ ++ for (i = 0; i < num_rings; i++) ++ intr_mask |= (0x1ULL << (srn + i)); ++ ++ octep_write_csr64(oct, CNXK_SDP_EPF_IRERR_RINT_ENA_W1C, intr_mask); ++ octep_write_csr64(oct, CNXK_SDP_EPF_ORERR_RINT_ENA_W1C, intr_mask); ++ octep_write_csr64(oct, CNXK_SDP_EPF_OEI_RINT_ENA_W1C, -1ULL); ++ ++ octep_write_csr64(oct, CNXK_SDP_EPF_VFIRE_RINT_ENA_W1C(0), -1ULL); ++ octep_write_csr64(oct, CNXK_SDP_EPF_VFORE_RINT_ENA_W1C(0), -1ULL); ++ ++ octep_write_csr64(oct, CNXK_SDP_EPF_MISC_RINT_ENA_W1C, intr_mask); ++ octep_write_csr64(oct, CNXK_SDP_EPF_DMA_RINT_ENA_W1C, intr_mask); ++ ++ octep_write_csr64(oct, CNXK_SDP_EPF_DMA_VF_RINT_ENA_W1C(0), -1ULL); ++ octep_write_csr64(oct, CNXK_SDP_EPF_PP_VF_RINT_ENA_W1C(0), -1ULL); ++} ++ ++/* Get new Octeon Read Index: index of descriptor that Octeon reads next. */ ++static u32 octep_update_iq_read_index_cnxk_pf(struct octep_iq *iq) ++{ ++ u32 pkt_in_done = readl(iq->inst_cnt_reg); ++ u32 last_done, new_idx; ++ ++ last_done = pkt_in_done - iq->pkt_in_done; ++ iq->pkt_in_done = pkt_in_done; ++ ++ new_idx = (iq->octep_read_index + last_done) % iq->max_count; ++ ++ return new_idx; ++} ++ ++/* Enable a hardware Tx Queue */ ++static void octep_enable_iq_cnxk_pf(struct octep_device *oct, int iq_no) ++{ ++ u64 loop = HZ; ++ u64 reg_val; ++ ++ iq_no += CFG_GET_PORTS_PF_SRN(oct->conf); ++ ++ octep_write_csr64(oct, CNXK_SDP_R_IN_INSTR_DBELL(iq_no), 0xFFFFFFFF); ++ ++ while (octep_read_csr64(oct, CNXK_SDP_R_IN_INSTR_DBELL(iq_no)) && ++ loop--) { ++ schedule_timeout_interruptible(1); ++ } ++ ++ reg_val = octep_read_csr64(oct, CNXK_SDP_R_IN_INT_LEVELS(iq_no)); ++ reg_val |= (0x1ULL << 62); ++ octep_write_csr64(oct, CNXK_SDP_R_IN_INT_LEVELS(iq_no), reg_val); ++ ++ reg_val = octep_read_csr64(oct, CNXK_SDP_R_IN_ENABLE(iq_no)); ++ reg_val |= 0x1ULL; ++ octep_write_csr64(oct, CNXK_SDP_R_IN_ENABLE(iq_no), reg_val); ++} ++ ++/* Enable a hardware Rx Queue */ ++static void octep_enable_oq_cnxk_pf(struct octep_device *oct, int oq_no) ++{ ++ u64 reg_val = 0ULL; ++ ++ oq_no += CFG_GET_PORTS_PF_SRN(oct->conf); ++ ++ reg_val = octep_read_csr64(oct, CNXK_SDP_R_OUT_INT_LEVELS(oq_no)); ++ reg_val |= (0x1ULL << 62); ++ octep_write_csr64(oct, CNXK_SDP_R_OUT_INT_LEVELS(oq_no), reg_val); ++ ++ octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_DBELL(oq_no), 0xFFFFFFFF); ++ ++ reg_val = octep_read_csr64(oct, CNXK_SDP_R_OUT_ENABLE(oq_no)); ++ reg_val |= 0x1ULL; ++ octep_write_csr64(oct, CNXK_SDP_R_OUT_ENABLE(oq_no), reg_val); ++} ++ ++/* Enable all hardware Tx/Rx Queues assined to PF */ ++static void octep_enable_io_queues_cnxk_pf(struct octep_device *oct) ++{ ++ u8 q; ++ ++ for (q = 0; q < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); q++) { ++ octep_enable_iq_cnxk_pf(oct, q); ++ octep_enable_oq_cnxk_pf(oct, q); ++ } ++} ++ ++/* Disable a hardware Tx Queue assined to PF */ ++static void octep_disable_iq_cnxk_pf(struct octep_device *oct, int iq_no) ++{ ++ u64 reg_val = 0ULL; ++ ++ iq_no += CFG_GET_PORTS_PF_SRN(oct->conf); ++ ++ reg_val = octep_read_csr64(oct, CNXK_SDP_R_IN_ENABLE(iq_no)); ++ reg_val &= ~0x1ULL; ++ octep_write_csr64(oct, CNXK_SDP_R_IN_ENABLE(iq_no), reg_val); ++} ++ ++/* Disable a hardware Rx Queue assined to PF */ ++static void octep_disable_oq_cnxk_pf(struct octep_device *oct, int oq_no) ++{ ++ u64 reg_val = 0ULL; ++ ++ oq_no += CFG_GET_PORTS_PF_SRN(oct->conf); ++ reg_val = octep_read_csr64(oct, CNXK_SDP_R_OUT_ENABLE(oq_no)); ++ reg_val &= ~0x1ULL; ++ octep_write_csr64(oct, CNXK_SDP_R_OUT_ENABLE(oq_no), reg_val); ++} ++ ++/* Disable all hardware Tx/Rx Queues assined to PF */ ++static void octep_disable_io_queues_cnxk_pf(struct octep_device *oct) ++{ ++ int q = 0; ++ ++ for (q = 0; q < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); q++) { ++ octep_disable_iq_cnxk_pf(oct, q); ++ octep_disable_oq_cnxk_pf(oct, q); ++ } ++} ++ ++/* Dump hardware registers (including Tx/Rx queues) for debugging. */ ++static void octep_dump_registers_cnxk_pf(struct octep_device *oct) ++{ ++ u8 srn, num_rings, q; ++ ++ srn = CFG_GET_PORTS_PF_SRN(oct->conf); ++ num_rings = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); ++ ++ for (q = srn; q < srn + num_rings; q++) ++ cnxk_dump_regs(oct, q); ++} ++ ++/** ++ * octep_device_setup_cnxk_pf() - Setup Octeon device. ++ * ++ * @oct: Octeon device private data structure. ++ * ++ * - initialize hardware operations. ++ * - get target side pcie port number for the device. ++ * - setup window access to hardware registers. ++ * - set initial configuration and max limits. ++ * - setup hardware mapping of rings to the PF device. ++ */ ++void octep_device_setup_cnxk_pf(struct octep_device *oct) ++{ ++ oct->hw_ops.setup_iq_regs = octep_setup_iq_regs_cnxk_pf; ++ oct->hw_ops.setup_oq_regs = octep_setup_oq_regs_cnxk_pf; ++ oct->hw_ops.setup_mbox_regs = octep_setup_mbox_regs_cnxk_pf; ++ ++ oct->hw_ops.oei_intr_handler = octep_oei_intr_handler_cnxk_pf; ++ oct->hw_ops.ire_intr_handler = octep_ire_intr_handler_cnxk_pf; ++ oct->hw_ops.ore_intr_handler = octep_ore_intr_handler_cnxk_pf; ++ oct->hw_ops.vfire_intr_handler = octep_vfire_intr_handler_cnxk_pf; ++ oct->hw_ops.vfore_intr_handler = octep_vfore_intr_handler_cnxk_pf; ++ oct->hw_ops.dma_intr_handler = octep_dma_intr_handler_cnxk_pf; ++ oct->hw_ops.dma_vf_intr_handler = octep_dma_vf_intr_handler_cnxk_pf; ++ oct->hw_ops.pp_vf_intr_handler = octep_pp_vf_intr_handler_cnxk_pf; ++ oct->hw_ops.misc_intr_handler = octep_misc_intr_handler_cnxk_pf; ++ oct->hw_ops.rsvd_intr_handler = octep_rsvd_intr_handler_cnxk_pf; ++ oct->hw_ops.ioq_intr_handler = octep_ioq_intr_handler_cnxk_pf; ++ oct->hw_ops.soft_reset = octep_soft_reset_cnxk_pf; ++ oct->hw_ops.reinit_regs = octep_reinit_regs_cnxk_pf; ++ ++ oct->hw_ops.enable_interrupts = octep_enable_interrupts_cnxk_pf; ++ oct->hw_ops.disable_interrupts = octep_disable_interrupts_cnxk_pf; ++ oct->hw_ops.poll_non_ioq_interrupts = octep_poll_non_ioq_interrupts_cnxk_pf; ++ ++ oct->hw_ops.update_iq_read_idx = octep_update_iq_read_index_cnxk_pf; ++ ++ oct->hw_ops.enable_iq = octep_enable_iq_cnxk_pf; ++ oct->hw_ops.enable_oq = octep_enable_oq_cnxk_pf; ++ oct->hw_ops.enable_io_queues = octep_enable_io_queues_cnxk_pf; ++ ++ oct->hw_ops.disable_iq = octep_disable_iq_cnxk_pf; ++ oct->hw_ops.disable_oq = octep_disable_oq_cnxk_pf; ++ oct->hw_ops.disable_io_queues = octep_disable_io_queues_cnxk_pf; ++ oct->hw_ops.reset_io_queues = octep_reset_io_queues_cnxk_pf; ++ ++ oct->hw_ops.dump_registers = octep_dump_registers_cnxk_pf; ++ ++ octep_setup_pci_window_regs_cnxk_pf(oct); ++ ++ oct->pcie_port = octep_read_csr64(oct, CNXK_SDP_MAC_NUMBER) & 0xff; ++ dev_info(&oct->pdev->dev, ++ "Octeon device using PCIE Port %d\n", oct->pcie_port); ++ ++ octep_init_config_cnxk_pf(oct); ++ octep_configure_ring_mapping_cnxk_pf(oct); ++ ++ /* Firmware status CSR is supposed to be cleared by ++ * core domain reset, but due to IPBUPEM-38842, it is not. ++ * Set it to RUNNING early in boot, so that unexpected resets ++ * leave it in a state that is not READY (1). ++ */ ++ OCTEP_PCI_WIN_WRITE(oct, CNXK_PEMX_PFX_CSX_PFCFGX(0, 0, CNXK_PCIEEP_VSECST_CTL), ++ FW_STATUS_RUNNING); ++} +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c +index b19f756e24489..db24c290a9079 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c +@@ -24,6 +24,10 @@ struct workqueue_struct *octep_wq; + static const struct pci_device_id octep_pci_id_tbl[] = { + {PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CN93_PF)}, + {PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CNF95N_PF)}, ++ {PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CN10KA_PF)}, ++ {PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CNF10KA_PF)}, ++ {PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CNF10KB_PF)}, ++ {PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CN10KB_PF)}, + {0, }, + }; + MODULE_DEVICE_TABLE(pci, octep_pci_id_tbl); +@@ -1126,6 +1130,14 @@ static const char *octep_devid_to_str(struct octep_device *oct) + return "CN93XX"; + case OCTEP_PCI_DEVICE_ID_CNF95N_PF: + return "CNF95N"; ++ case OCTEP_PCI_DEVICE_ID_CN10KA_PF: ++ return "CN10KA"; ++ case OCTEP_PCI_DEVICE_ID_CNF10KA_PF: ++ return "CNF10KA"; ++ case OCTEP_PCI_DEVICE_ID_CNF10KB_PF: ++ return "CNF10KB"; ++ case OCTEP_PCI_DEVICE_ID_CN10KB_PF: ++ return "CN10KB"; + default: + return "Unsupported"; + } +@@ -1171,6 +1183,14 @@ int octep_device_setup(struct octep_device *oct) + OCTEP_MINOR_REV(oct)); + octep_device_setup_cn93_pf(oct); + break; ++ case OCTEP_PCI_DEVICE_ID_CNF10KA_PF: ++ case OCTEP_PCI_DEVICE_ID_CN10KA_PF: ++ case OCTEP_PCI_DEVICE_ID_CNF10KB_PF: ++ case OCTEP_PCI_DEVICE_ID_CN10KB_PF: ++ dev_info(&pdev->dev, "Setting up OCTEON %s PF PASS%d.%d\n", ++ octep_devid_to_str(oct), OCTEP_MAJOR_REV(oct), OCTEP_MINOR_REV(oct)); ++ octep_device_setup_cnxk_pf(oct); ++ break; + default: + dev_err(&pdev->dev, + "%s: unsupported device\n", __func__); +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_main.h b/drivers/net/ethernet/marvell/octeon_ep/octep_main.h +index 6df902ebb7f33..f67bb87901005 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_main.h ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_main.h +@@ -23,6 +23,11 @@ + + #define OCTEP_PCI_DEVICE_ID_CNF95N_PF 0xB400 //95N PF + ++#define OCTEP_PCI_DEVICE_ID_CN10KA_PF 0xB900 //CN10KA PF ++#define OCTEP_PCI_DEVICE_ID_CNF10KA_PF 0xBA00 //CNF10KA PF ++#define OCTEP_PCI_DEVICE_ID_CNF10KB_PF 0xBC00 //CNF10KB PF ++#define OCTEP_PCI_DEVICE_ID_CN10KB_PF 0xBD00 //CN10KB PF ++ + #define OCTEP_MAX_QUEUES 63 + #define OCTEP_MAX_IQ OCTEP_MAX_QUEUES + #define OCTEP_MAX_OQ OCTEP_MAX_QUEUES +@@ -377,6 +382,7 @@ int octep_setup_oqs(struct octep_device *oct); + void octep_free_oqs(struct octep_device *oct); + void octep_oq_dbell_init(struct octep_device *oct); + void octep_device_setup_cn93_pf(struct octep_device *oct); ++void octep_device_setup_cnxk_pf(struct octep_device *oct); + int octep_iq_process_completions(struct octep_iq *iq, u16 budget); + int octep_oq_process_rx(struct octep_oq *oq, int budget); + void octep_set_ethtool_ops(struct net_device *netdev); +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h b/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h +new file mode 100644 +index 0000000000000..abe02df8af117 +--- /dev/null ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h +@@ -0,0 +1,400 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* Marvell Octeon EP (EndPoint) Ethernet Driver ++ * ++ * Copyright (C) 2020 Marvell. ++ * ++ */ ++ ++#ifndef _OCTEP_REGS_CNXK_PF_H_ ++#define _OCTEP_REGS_CNXK_PF_H_ ++ ++/* ############################ RST ######################### */ ++#define CNXK_RST_BOOT 0x000087E006001600ULL ++#define CNXK_RST_CHIP_DOMAIN_W1S 0x000087E006001810ULL ++#define CNXK_RST_CORE_DOMAIN_W1S 0x000087E006001820ULL ++#define CNXK_RST_CORE_DOMAIN_W1C 0x000087E006001828ULL ++ ++#define CNXK_CONFIG_XPANSION_BAR 0x38 ++#define CNXK_CONFIG_PCIE_CAP 0x70 ++#define CNXK_CONFIG_PCIE_DEVCAP 0x74 ++#define CNXK_CONFIG_PCIE_DEVCTL 0x78 ++#define CNXK_CONFIG_PCIE_LINKCAP 0x7C ++#define CNXK_CONFIG_PCIE_LINKCTL 0x80 ++#define CNXK_CONFIG_PCIE_SLOTCAP 0x84 ++#define CNXK_CONFIG_PCIE_SLOTCTL 0x88 ++ ++#define CNXK_PCIE_SRIOV_FDL 0x188 /* 0x98 */ ++#define CNXK_PCIE_SRIOV_FDL_BIT_POS 0x10 ++#define CNXK_PCIE_SRIOV_FDL_MASK 0xFF ++ ++#define CNXK_CONFIG_PCIE_FLTMSK 0x720 ++ ++/* ################# Offsets of RING, EPF, MAC ######################### */ ++#define CNXK_RING_OFFSET (0x1ULL << 17) ++#define CNXK_EPF_OFFSET (0x1ULL << 25) ++#define CNXK_MAC_OFFSET (0x1ULL << 4) ++#define CNXK_BIT_ARRAY_OFFSET (0x1ULL << 4) ++#define CNXK_EPVF_RING_OFFSET (0x1ULL << 4) ++ ++/* ################# Scratch Registers ######################### */ ++#define CNXK_SDP_EPF_SCRATCH 0x209E0 ++ ++/* ################# Window Registers ######################### */ ++#define CNXK_SDP_WIN_WR_ADDR64 0x20000 ++#define CNXK_SDP_WIN_RD_ADDR64 0x20010 ++#define CNXK_SDP_WIN_WR_DATA64 0x20020 ++#define CNXK_SDP_WIN_WR_MASK_REG 0x20030 ++#define CNXK_SDP_WIN_RD_DATA64 0x20040 ++ ++#define CNXK_SDP_MAC_NUMBER 0x2C100 ++ ++/* ################# Global Previliged registers ######################### */ ++#define CNXK_SDP_EPF_RINFO 0x209F0 ++ ++#define CNXK_SDP_EPF_RINFO_SRN(val) ((val) & 0x7F) ++#define CNXK_SDP_EPF_RINFO_RPVF(val) (((val) >> 32) & 0xF) ++#define CNXK_SDP_EPF_RINFO_NVFS(val) (((val) >> 48) & 0x7F) ++ ++/* SDP Function select */ ++#define CNXK_SDP_FUNC_SEL_EPF_BIT_POS 7 ++#define CNXK_SDP_FUNC_SEL_FUNC_BIT_POS 0 ++ ++/* ##### RING IN (Into device from PCI: Tx Ring) REGISTERS #### */ ++#define CNXK_SDP_R_IN_CONTROL_START 0x10000 ++#define CNXK_SDP_R_IN_ENABLE_START 0x10010 ++#define CNXK_SDP_R_IN_INSTR_BADDR_START 0x10020 ++#define CNXK_SDP_R_IN_INSTR_RSIZE_START 0x10030 ++#define CNXK_SDP_R_IN_INSTR_DBELL_START 0x10040 ++#define CNXK_SDP_R_IN_CNTS_START 0x10050 ++#define CNXK_SDP_R_IN_INT_LEVELS_START 0x10060 ++#define CNXK_SDP_R_IN_PKT_CNT_START 0x10080 ++#define CNXK_SDP_R_IN_BYTE_CNT_START 0x10090 ++ ++#define CNXK_SDP_R_IN_CONTROL(ring) \ ++ (CNXK_SDP_R_IN_CONTROL_START + ((ring) * CNXK_RING_OFFSET)) ++ ++#define CNXK_SDP_R_IN_ENABLE(ring) \ ++ (CNXK_SDP_R_IN_ENABLE_START + ((ring) * CNXK_RING_OFFSET)) ++ ++#define CNXK_SDP_R_IN_INSTR_BADDR(ring) \ ++ (CNXK_SDP_R_IN_INSTR_BADDR_START + ((ring) * CNXK_RING_OFFSET)) ++ ++#define CNXK_SDP_R_IN_INSTR_RSIZE(ring) \ ++ (CNXK_SDP_R_IN_INSTR_RSIZE_START + ((ring) * CNXK_RING_OFFSET)) ++ ++#define CNXK_SDP_R_IN_INSTR_DBELL(ring) \ ++ (CNXK_SDP_R_IN_INSTR_DBELL_START + ((ring) * CNXK_RING_OFFSET)) ++ ++#define CNXK_SDP_R_IN_CNTS(ring) \ ++ (CNXK_SDP_R_IN_CNTS_START + ((ring) * CNXK_RING_OFFSET)) ++ ++#define CNXK_SDP_R_IN_INT_LEVELS(ring) \ ++ (CNXK_SDP_R_IN_INT_LEVELS_START + ((ring) * CNXK_RING_OFFSET)) ++ ++#define CNXK_SDP_R_IN_PKT_CNT(ring) \ ++ (CNXK_SDP_R_IN_PKT_CNT_START + ((ring) * CNXK_RING_OFFSET)) ++ ++#define CNXK_SDP_R_IN_BYTE_CNT(ring) \ ++ (CNXK_SDP_R_IN_BYTE_CNT_START + ((ring) * CNXK_RING_OFFSET)) ++ ++/* Rings per Virtual Function */ ++#define CNXK_R_IN_CTL_RPVF_MASK (0xF) ++#define CNXK_R_IN_CTL_RPVF_POS (48) ++ ++/* Number of instructions to be read in one MAC read request. ++ * setting to Max value(4) ++ */ ++#define CNXK_R_IN_CTL_IDLE (0x1ULL << 28) ++#define CNXK_R_IN_CTL_RDSIZE (0x3ULL << 25) ++#define CNXK_R_IN_CTL_IS_64B (0x1ULL << 24) ++#define CNXK_R_IN_CTL_D_NSR (0x1ULL << 8) ++#define CNXK_R_IN_CTL_D_ESR (0x1ULL << 6) ++#define CNXK_R_IN_CTL_D_ROR (0x1ULL << 5) ++#define CNXK_R_IN_CTL_NSR (0x1ULL << 3) ++#define CNXK_R_IN_CTL_ESR (0x1ULL << 1) ++#define CNXK_R_IN_CTL_ROR (0x1ULL << 0) ++ ++#define CNXK_R_IN_CTL_MASK (CNXK_R_IN_CTL_RDSIZE | CNXK_R_IN_CTL_IS_64B) ++ ++/* ##### RING OUT (out from device to PCI host: Rx Ring) REGISTERS #### */ ++#define CNXK_SDP_R_OUT_CNTS_START 0x10100 ++#define CNXK_SDP_R_OUT_INT_LEVELS_START 0x10110 ++#define CNXK_SDP_R_OUT_SLIST_BADDR_START 0x10120 ++#define CNXK_SDP_R_OUT_SLIST_RSIZE_START 0x10130 ++#define CNXK_SDP_R_OUT_SLIST_DBELL_START 0x10140 ++#define CNXK_SDP_R_OUT_CONTROL_START 0x10150 ++#define CNXK_SDP_R_OUT_WMARK_START 0x10160 ++#define CNXK_SDP_R_OUT_ENABLE_START 0x10170 ++#define CNXK_SDP_R_OUT_PKT_CNT_START 0x10180 ++#define CNXK_SDP_R_OUT_BYTE_CNT_START 0x10190 ++ ++#define CNXK_SDP_R_OUT_CONTROL(ring) \ ++ (CNXK_SDP_R_OUT_CONTROL_START + ((ring) * CNXK_RING_OFFSET)) ++ ++#define CNXK_SDP_R_OUT_ENABLE(ring) \ ++ (CNXK_SDP_R_OUT_ENABLE_START + ((ring) * CNXK_RING_OFFSET)) ++ ++#define CNXK_SDP_R_OUT_SLIST_BADDR(ring) \ ++ (CNXK_SDP_R_OUT_SLIST_BADDR_START + ((ring) * CNXK_RING_OFFSET)) ++ ++#define CNXK_SDP_R_OUT_SLIST_RSIZE(ring) \ ++ (CNXK_SDP_R_OUT_SLIST_RSIZE_START + ((ring) * CNXK_RING_OFFSET)) ++ ++#define CNXK_SDP_R_OUT_SLIST_DBELL(ring) \ ++ (CNXK_SDP_R_OUT_SLIST_DBELL_START + ((ring) * CNXK_RING_OFFSET)) ++ ++#define CNXK_SDP_R_OUT_CNTS(ring) \ ++ (CNXK_SDP_R_OUT_CNTS_START + ((ring) * CNXK_RING_OFFSET)) ++ ++#define CNXK_SDP_R_OUT_INT_LEVELS(ring) \ ++ (CNXK_SDP_R_OUT_INT_LEVELS_START + ((ring) * CNXK_RING_OFFSET)) ++ ++#define CNXK_SDP_R_OUT_PKT_CNT(ring) \ ++ (CNXK_SDP_R_OUT_PKT_CNT_START + ((ring) * CNXK_RING_OFFSET)) ++ ++#define CNXK_SDP_R_OUT_BYTE_CNT(ring) \ ++ (CNXK_SDP_R_OUT_BYTE_CNT_START + ((ring) * CNXK_RING_OFFSET)) ++ ++/*------------------ R_OUT Masks ----------------*/ ++#define CNXK_R_OUT_INT_LEVELS_BMODE BIT_ULL(63) ++#define CNXK_R_OUT_INT_LEVELS_TIMET (32) ++ ++#define CNXK_R_OUT_CTL_IDLE BIT_ULL(40) ++#define CNXK_R_OUT_CTL_ES_I BIT_ULL(34) ++#define CNXK_R_OUT_CTL_NSR_I BIT_ULL(33) ++#define CNXK_R_OUT_CTL_ROR_I BIT_ULL(32) ++#define CNXK_R_OUT_CTL_ES_D BIT_ULL(30) ++#define CNXK_R_OUT_CTL_NSR_D BIT_ULL(29) ++#define CNXK_R_OUT_CTL_ROR_D BIT_ULL(28) ++#define CNXK_R_OUT_CTL_ES_P BIT_ULL(26) ++#define CNXK_R_OUT_CTL_NSR_P BIT_ULL(25) ++#define CNXK_R_OUT_CTL_ROR_P BIT_ULL(24) ++#define CNXK_R_OUT_CTL_IMODE BIT_ULL(23) ++ ++/* ############### Interrupt Moderation Registers ############### */ ++#define CNXK_SDP_R_IN_INT_MDRT_CTL0_START 0x10280 ++#define CNXK_SDP_R_IN_INT_MDRT_CTL1_START 0x102A0 ++#define CNXK_SDP_R_IN_INT_MDRT_DBG_START 0x102C0 ++ ++#define CNXK_SDP_R_OUT_INT_MDRT_CTL0_START 0x10380 ++#define CNXK_SDP_R_OUT_INT_MDRT_CTL1_START 0x103A0 ++#define CNXK_SDP_R_OUT_INT_MDRT_DBG_START 0x103C0 ++ ++#define CNXK_SDP_R_OUT_CNTS_ISM_START 0x10510 ++#define CNXK_SDP_R_IN_CNTS_ISM_START 0x10520 ++ ++#define CNXK_SDP_R_IN_INT_MDRT_CTL0(ring) \ ++ (CNXK_SDP_R_IN_INT_MDRT_CTL0_START + ((ring) * CNXK_RING_OFFSET)) ++ ++#define CNXK_SDP_R_IN_INT_MDRT_CTL1(ring) \ ++ (CNXK_SDP_R_IN_INT_MDRT_CTL1_START + ((ring) * CNXK_RING_OFFSET)) ++ ++#define CNXK_SDP_R_IN_INT_MDRT_DBG(ring) \ ++ (CNXK_SDP_R_IN_INT_MDRT_DBG_START + ((ring) * CNXK_RING_OFFSET)) ++ ++#define CNXK_SDP_R_OUT_INT_MDRT_CTL0(ring) \ ++ (CNXK_SDP_R_OUT_INT_MDRT_CTL0_START + ((ring) * CNXK_RING_OFFSET)) ++ ++#define CNXK_SDP_R_OUT_INT_MDRT_CTL1(ring) \ ++ (CNXK_SDP_R_OUT_INT_MDRT_CTL1_START + ((ring) * CNXK_RING_OFFSET)) ++ ++#define CNXK_SDP_R_OUT_INT_MDRT_DBG(ring) \ ++ (CNXK_SDP_R_OUT_INT_MDRT_DBG_START + ((ring) * CNXK_RING_OFFSET)) ++ ++#define CNXK_SDP_R_OUT_CNTS_ISM(ring) \ ++ (CNXK_SDP_R_OUT_CNTS_ISM_START + ((ring) * CNXK_RING_OFFSET)) ++ ++#define CNXK_SDP_R_IN_CNTS_ISM(ring) \ ++ (CNXK_SDP_R_IN_CNTS_ISM_START + ((ring) * CNXK_RING_OFFSET)) ++ ++/* ##################### Mail Box Registers ########################## */ ++/* INT register for VF. when a MBOX write from PF happed to a VF, ++ * corresponding bit will be set in this register as well as in ++ * PF_VF_INT register. ++ * ++ * This is a RO register, the int can be cleared by writing 1 to PF_VF_INT ++ */ ++/* Basically first 3 are from PF to VF. The last one is data from VF to PF */ ++#define CNXK_SDP_R_MBOX_PF_VF_DATA_START 0x10210 ++#define CNXK_SDP_R_MBOX_PF_VF_INT_START 0x10220 ++#define CNXK_SDP_R_MBOX_VF_PF_DATA_START 0x10230 ++ ++#define CNXK_SDP_R_MBOX_PF_VF_DATA(ring) \ ++ (CNXK_SDP_R_MBOX_PF_VF_DATA_START + ((ring) * CNXK_RING_OFFSET)) ++ ++#define CNXK_SDP_R_MBOX_PF_VF_INT(ring) \ ++ (CNXK_SDP_R_MBOX_PF_VF_INT_START + ((ring) * CNXK_RING_OFFSET)) ++ ++#define CNXK_SDP_R_MBOX_VF_PF_DATA(ring) \ ++ (CNXK_SDP_R_MBOX_VF_PF_DATA_START + ((ring) * CNXK_RING_OFFSET)) ++ ++/* ##################### Interrupt Registers ########################## */ ++#define CNXK_SDP_R_ERR_TYPE_START 0x10400 ++ ++#define CNXK_SDP_R_ERR_TYPE(ring) \ ++ (CNXK_SDP_R_ERR_TYPE_START + ((ring) * CNXK_RING_OFFSET)) ++ ++#define CNXK_SDP_R_MBOX_ISM_START 0x10500 ++#define CNXK_SDP_R_OUT_CNTS_ISM_START 0x10510 ++#define CNXK_SDP_R_IN_CNTS_ISM_START 0x10520 ++ ++#define CNXK_SDP_R_MBOX_ISM(ring) \ ++ (CNXK_SDP_R_MBOX_ISM_START + ((ring) * CNXK_RING_OFFSET)) ++ ++#define CNXK_SDP_R_OUT_CNTS_ISM(ring) \ ++ (CNXK_SDP_R_OUT_CNTS_ISM_START + ((ring) * CNXK_RING_OFFSET)) ++ ++#define CNXK_SDP_R_IN_CNTS_ISM(ring) \ ++ (CNXK_SDP_R_IN_CNTS_ISM_START + ((ring) * CNXK_RING_OFFSET)) ++ ++#define CNXK_SDP_EPF_MBOX_RINT_START 0x20100 ++#define CNXK_SDP_EPF_MBOX_RINT_W1S_START 0x20120 ++#define CNXK_SDP_EPF_MBOX_RINT_ENA_W1C_START 0x20140 ++#define CNXK_SDP_EPF_MBOX_RINT_ENA_W1S_START 0x20160 ++ ++#define CNXK_SDP_EPF_VFIRE_RINT_START 0x20180 ++#define CNXK_SDP_EPF_VFIRE_RINT_W1S_START 0x201A0 ++#define CNXK_SDP_EPF_VFIRE_RINT_ENA_W1C_START 0x201C0 ++#define CNXK_SDP_EPF_VFIRE_RINT_ENA_W1S_START 0x201E0 ++ ++#define CNXK_SDP_EPF_IRERR_RINT 0x20200 ++#define CNXK_SDP_EPF_IRERR_RINT_W1S 0x20210 ++#define CNXK_SDP_EPF_IRERR_RINT_ENA_W1C 0x20220 ++#define CNXK_SDP_EPF_IRERR_RINT_ENA_W1S 0x20230 ++ ++#define CNXK_SDP_EPF_VFORE_RINT_START 0x20240 ++#define CNXK_SDP_EPF_VFORE_RINT_W1S_START 0x20260 ++#define CNXK_SDP_EPF_VFORE_RINT_ENA_W1C_START 0x20280 ++#define CNXK_SDP_EPF_VFORE_RINT_ENA_W1S_START 0x202A0 ++ ++#define CNXK_SDP_EPF_ORERR_RINT 0x20320 ++#define CNXK_SDP_EPF_ORERR_RINT_W1S 0x20330 ++#define CNXK_SDP_EPF_ORERR_RINT_ENA_W1C 0x20340 ++#define CNXK_SDP_EPF_ORERR_RINT_ENA_W1S 0x20350 ++ ++#define CNXK_SDP_EPF_OEI_RINT 0x20400 ++#define CNXK_SDP_EPF_OEI_RINT_W1S 0x20500 ++#define CNXK_SDP_EPF_OEI_RINT_ENA_W1C 0x20600 ++#define CNXK_SDP_EPF_OEI_RINT_ENA_W1S 0x20700 ++ ++#define CNXK_SDP_EPF_DMA_RINT 0x20800 ++#define CNXK_SDP_EPF_DMA_RINT_W1S 0x20810 ++#define CNXK_SDP_EPF_DMA_RINT_ENA_W1C 0x20820 ++#define CNXK_SDP_EPF_DMA_RINT_ENA_W1S 0x20830 ++ ++#define CNXK_SDP_EPF_DMA_INT_LEVEL_START 0x20840 ++#define CNXK_SDP_EPF_DMA_CNT_START 0x20860 ++#define CNXK_SDP_EPF_DMA_TIM_START 0x20880 ++ ++#define CNXK_SDP_EPF_MISC_RINT 0x208A0 ++#define CNXK_SDP_EPF_MISC_RINT_W1S 0x208B0 ++#define CNXK_SDP_EPF_MISC_RINT_ENA_W1C 0x208C0 ++#define CNXK_SDP_EPF_MISC_RINT_ENA_W1S 0x208D0 ++ ++#define CNXK_SDP_EPF_DMA_VF_RINT_START 0x208E0 ++#define CNXK_SDP_EPF_DMA_VF_RINT_W1S_START 0x20900 ++#define CNXK_SDP_EPF_DMA_VF_RINT_ENA_W1C_START 0x20920 ++#define CNXK_SDP_EPF_DMA_VF_RINT_ENA_W1S_START 0x20940 ++ ++#define CNXK_SDP_EPF_PP_VF_RINT_START 0x20960 ++#define CNXK_SDP_EPF_PP_VF_RINT_W1S_START 0x20980 ++#define CNXK_SDP_EPF_PP_VF_RINT_ENA_W1C_START 0x209A0 ++#define CNXK_SDP_EPF_PP_VF_RINT_ENA_W1S_START 0x209C0 ++ ++#define CNXK_SDP_EPF_MBOX_RINT(index) \ ++ (CNXK_SDP_EPF_MBOX_RINT_START + ((index) * CNXK_BIT_ARRAY_OFFSET)) ++#define CNXK_SDP_EPF_MBOX_RINT_W1S(index) \ ++ (CNXK_SDP_EPF_MBOX_RINT_W1S_START + ((index) * CNXK_BIT_ARRAY_OFFSET)) ++#define CNXK_SDP_EPF_MBOX_RINT_ENA_W1C(index) \ ++ (CNXK_SDP_EPF_MBOX_RINT_ENA_W1C_START + ((index) * CNXK_BIT_ARRAY_OFFSET)) ++#define CNXK_SDP_EPF_MBOX_RINT_ENA_W1S(index) \ ++ (CNXK_SDP_EPF_MBOX_RINT_ENA_W1S_START + ((index) * CNXK_BIT_ARRAY_OFFSET)) ++ ++#define CNXK_SDP_EPF_VFIRE_RINT(index) \ ++ (CNXK_SDP_EPF_VFIRE_RINT_START + ((index) * CNXK_BIT_ARRAY_OFFSET)) ++#define CNXK_SDP_EPF_VFIRE_RINT_W1S(index) \ ++ (CNXK_SDP_EPF_VFIRE_RINT_W1S_START + ((index) * CNXK_BIT_ARRAY_OFFSET)) ++#define CNXK_SDP_EPF_VFIRE_RINT_ENA_W1C(index) \ ++ (CNXK_SDP_EPF_VFIRE_RINT_ENA_W1C_START + ((index) * CNXK_BIT_ARRAY_OFFSET)) ++#define CNXK_SDP_EPF_VFIRE_RINT_ENA_W1S(index) \ ++ (CNXK_SDP_EPF_VFIRE_RINT_ENA_W1S_START + ((index) * CNXK_BIT_ARRAY_OFFSET)) ++ ++#define CNXK_SDP_EPF_VFORE_RINT(index) \ ++ (CNXK_SDP_EPF_VFORE_RINT_START + ((index) * CNXK_BIT_ARRAY_OFFSET)) ++#define CNXK_SDP_EPF_VFORE_RINT_W1S(index) \ ++ (CNXK_SDP_EPF_VFORE_RINT_W1S_START + ((index) * CNXK_BIT_ARRAY_OFFSET)) ++#define CNXK_SDP_EPF_VFORE_RINT_ENA_W1C(index) \ ++ (CNXK_SDP_EPF_VFORE_RINT_ENA_W1C_START + ((index) * CNXK_BIT_ARRAY_OFFSET)) ++#define CNXK_SDP_EPF_VFORE_RINT_ENA_W1S(index) \ ++ (CNXK_SDP_EPF_VFORE_RINT_ENA_W1S_START + ((index) * CNXK_BIT_ARRAY_OFFSET)) ++ ++#define CNXK_SDP_EPF_DMA_VF_RINT(index) \ ++ (CNXK_SDP_EPF_DMA_VF_RINT_START + ((index) + CNXK_BIT_ARRAY_OFFSET)) ++#define CNXK_SDP_EPF_DMA_VF_RINT_W1S(index) \ ++ (CNXK_SDP_EPF_DMA_VF_RINT_W1S_START + ((index) + CNXK_BIT_ARRAY_OFFSET)) ++#define CNXK_SDP_EPF_DMA_VF_RINT_ENA_W1C(index) \ ++ (CNXK_SDP_EPF_DMA_VF_RINT_ENA_W1C_START + ((index) + CNXK_BIT_ARRAY_OFFSET)) ++#define CNXK_SDP_EPF_DMA_VF_RINT_ENA_W1S(index) \ ++ (CNXK_SDP_EPF_DMA_VF_RINT_ENA_W1S_START + ((index) + CNXK_BIT_ARRAY_OFFSET)) ++ ++#define CNXK_SDP_EPF_PP_VF_RINT(index) \ ++ (CNXK_SDP_EPF_PP_VF_RINT_START + ((index) + CNXK_BIT_ARRAY_OFFSET)) ++#define CNXK_SDP_EPF_PP_VF_RINT_W1S(index) \ ++ (CNXK_SDP_EPF_PP_VF_RINT_W1S_START + ((index) + CNXK_BIT_ARRAY_OFFSET)) ++#define CNXK_SDP_EPF_PP_VF_RINT_ENA_W1C(index) \ ++ (CNXK_SDP_EPF_PP_VF_RINT_ENA_W1C_START + ((index) + CNXK_BIT_ARRAY_OFFSET)) ++#define CNXK_SDP_EPF_PP_VF_RINT_ENA_W1S(index) \ ++ (CNXK_SDP_EPF_PP_VF_RINT_ENA_W1S_START + ((index) + CNXK_BIT_ARRAY_OFFSET)) ++ ++/*------------------ Interrupt Masks ----------------*/ ++#define CNXK_INTR_R_SEND_ISM BIT_ULL(63) ++#define CNXK_INTR_R_OUT_INT BIT_ULL(62) ++#define CNXK_INTR_R_IN_INT BIT_ULL(61) ++#define CNXK_INTR_R_MBOX_INT BIT_ULL(60) ++#define CNXK_INTR_R_RESEND BIT_ULL(59) ++#define CNXK_INTR_R_CLR_TIM BIT_ULL(58) ++ ++/* ####################### Ring Mapping Registers ################################## */ ++#define CNXK_SDP_EPVF_RING_START 0x26000 ++#define CNXK_SDP_IN_RING_TB_MAP_START 0x28000 ++#define CNXK_SDP_IN_RATE_LIMIT_START 0x2A000 ++#define CNXK_SDP_MAC_PF_RING_CTL_START 0x2C000 ++ ++#define CNXK_SDP_EPVF_RING(ring) \ ++ (CNXK_SDP_EPVF_RING_START + ((ring) * CNXK_EPVF_RING_OFFSET)) ++#define CNXK_SDP_IN_RING_TB_MAP(ring) \ ++ (CNXK_SDP_N_RING_TB_MAP_START + ((ring) * CNXK_EPVF_RING_OFFSET)) ++#define CNXK_SDP_IN_RATE_LIMIT(ring) \ ++ (CNXK_SDP_IN_RATE_LIMIT_START + ((ring) * CNXK_EPVF_RING_OFFSET)) ++#define CNXK_SDP_MAC_PF_RING_CTL(mac) \ ++ (CNXK_SDP_MAC_PF_RING_CTL_START + ((mac) * CNXK_MAC_OFFSET)) ++ ++#define CNXK_SDP_MAC_PF_RING_CTL_NPFS(val) ((val) & 0x3) ++#define CNXK_SDP_MAC_PF_RING_CTL_SRN(val) (((val) >> 8) & 0x7F) ++#define CNXK_SDP_MAC_PF_RING_CTL_RPPF(val) (((val) >> 16) & 0x3F) ++ ++/* Number of non-queue interrupts in CNXKxx */ ++#define CNXK_NUM_NON_IOQ_INTR 32 ++ ++/* bit 0 for control mbox interrupt */ ++#define CNXK_SDP_EPF_OEI_RINT_DATA_BIT_MBOX BIT_ULL(0) ++/* bit 1 for firmware heartbeat interrupt */ ++#define CNXK_SDP_EPF_OEI_RINT_DATA_BIT_HBEAT BIT_ULL(1) ++#define FW_STATUS_RUNNING 2ULL ++#define CNXK_PEMX_PFX_CSX_PFCFGX(pem, pf, offset) ({ typeof(offset) _off = (offset); \ ++ ((0x8e0000008000 | \ ++ (uint64_t)(pem) << 36 \ ++ | (pf) << 18 \ ++ | ((_off >> 16) & 1) << 16 \ ++ | (_off >> 3) << 3) \ ++ + (((_off >> 2) & 1) << 2)); \ ++ }) ++ ++/* Register defines for use with CNXK_PEMX_PFX_CSX_PFCFGX */ ++#define CNXK_PCIEEP_VSECST_CTL 0x418 ++ ++#define CNXK_PEM_BAR4_INDEX 7 ++#define CNXK_PEM_BAR4_INDEX_SIZE 0x400000ULL ++#define CNXK_PEM_BAR4_INDEX_OFFSET (CNXK_PEM_BAR4_INDEX * CNXK_PEM_BAR4_INDEX_SIZE) ++ ++#endif /* _OCTEP_REGS_CNXK_PF_H_ */ +-- +2.51.0 + diff --git a/queue-6.6/octeon_ep-support-to-fetch-firmware-info.patch b/queue-6.6/octeon_ep-support-to-fetch-firmware-info.patch new file mode 100644 index 0000000000..b1e49f2525 --- /dev/null +++ b/queue-6.6/octeon_ep-support-to-fetch-firmware-info.patch @@ -0,0 +1,251 @@ +From ddc325b7bb300e8e9a3b838a3fe31a6192bb6da6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 15 Sep 2023 01:16:07 -0700 +Subject: octeon_ep: support to fetch firmware info + +From: Shinas Rasheed + +[ Upstream commit 8d6198a14e2bfb09f190055b387c90b4ac9b49a4 ] + +Add support to fetch firmware info such as heartbeat miss count, +heartbeat interval. This shall be used for heartbeat monitor. + +Signed-off-by: Shinas Rasheed +Signed-off-by: David S. Miller +Stable-dep-of: 73e6ffa37ceb ("octeon_ep: disable per ring interrupts") +Signed-off-by: Sasha Levin +--- + .../marvell/octeon_ep/octep_cn9k_pf.c | 10 +++----- + .../ethernet/marvell/octeon_ep/octep_config.h | 22 +++++++++++++---- + .../marvell/octeon_ep/octep_ctrl_net.c | 24 ++++++++++++++++++- + .../marvell/octeon_ep/octep_ctrl_net.h | 18 ++++++++++++++ + .../ethernet/marvell/octeon_ep/octep_main.c | 16 +++++++++---- + .../marvell/octeon_ep/octep_regs_cn9k_pf.h | 4 ++++ + 6 files changed, 77 insertions(+), 17 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c b/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c +index 90c3a419932d1..f282cd5b29ea5 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c +@@ -16,9 +16,6 @@ + #define CTRL_MBOX_MAX_PF 128 + #define CTRL_MBOX_SZ ((size_t)(0x400000 / CTRL_MBOX_MAX_PF)) + +-#define FW_HB_INTERVAL_IN_SECS 1 +-#define FW_HB_MISS_COUNT 10 +- + /* Names of Hardware non-queue generic interrupts */ + static char *cn93_non_ioq_msix_names[] = { + "epf_ire_rint", +@@ -250,12 +247,11 @@ static void octep_init_config_cn93_pf(struct octep_device *oct) + link = PCI_DEVFN(PCI_SLOT(oct->pdev->devfn), link); + } + conf->ctrl_mbox_cfg.barmem_addr = (void __iomem *)oct->mmio[2].hw_addr + +- (0x400000ull * 7) + ++ CN93_PEM_BAR4_INDEX_OFFSET + + (link * CTRL_MBOX_SZ); + +- conf->hb_interval = FW_HB_INTERVAL_IN_SECS; +- conf->max_hb_miss_cnt = FW_HB_MISS_COUNT; +- ++ conf->fw_info.hb_interval = OCTEP_DEFAULT_FW_HB_INTERVAL; ++ conf->fw_info.hb_miss_count = OCTEP_DEFAULT_FW_HB_MISS_COUNT; + } + + /* Setup registers for a hardware Tx Queue */ +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_config.h b/drivers/net/ethernet/marvell/octeon_ep/octep_config.h +index df7cd39d9fce1..1622a6ebf0362 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_config.h ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_config.h +@@ -49,6 +49,11 @@ + /* Default MTU */ + #define OCTEP_DEFAULT_MTU 1500 + ++/* pf heartbeat interval in milliseconds */ ++#define OCTEP_DEFAULT_FW_HB_INTERVAL 1000 ++/* pf heartbeat miss count */ ++#define OCTEP_DEFAULT_FW_HB_MISS_COUNT 20 ++ + /* Macros to get octeon config params */ + #define CFG_GET_IQ_CFG(cfg) ((cfg)->iq) + #define CFG_GET_IQ_NUM_DESC(cfg) ((cfg)->iq.num_descs) +@@ -181,6 +186,16 @@ struct octep_ctrl_mbox_config { + void __iomem *barmem_addr; + }; + ++/* Info from firmware */ ++struct octep_fw_info { ++ /* interface pkind */ ++ u16 pkind; ++ /* heartbeat interval in milliseconds */ ++ u16 hb_interval; ++ /* heartbeat miss count */ ++ u16 hb_miss_count; ++}; ++ + /* Data Structure to hold configuration limits and active config */ + struct octep_config { + /* Input Queue attributes. */ +@@ -201,10 +216,7 @@ struct octep_config { + /* ctrl mbox config */ + struct octep_ctrl_mbox_config ctrl_mbox_cfg; + +- /* Configured maximum heartbeat miss count */ +- u32 max_hb_miss_cnt; +- +- /* Configured firmware heartbeat interval in secs */ +- u32 hb_interval; ++ /* fw info */ ++ struct octep_fw_info fw_info; + }; + #endif /* _OCTEP_CONFIG_H_ */ +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.c b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.c +index 17bfd5cdf4620..0594607a25854 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.c ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.c +@@ -26,7 +26,7 @@ static atomic_t ctrl_net_msg_id; + + /* Control plane version in which OCTEP_CTRL_NET_H2F_CMD was added */ + static const u32 octep_ctrl_net_h2f_cmd_versions[OCTEP_CTRL_NET_H2F_CMD_MAX] = { +- [OCTEP_CTRL_NET_H2F_CMD_INVALID ... OCTEP_CTRL_NET_H2F_CMD_LINK_INFO] = ++ [OCTEP_CTRL_NET_H2F_CMD_INVALID ... OCTEP_CTRL_NET_H2F_CMD_GET_INFO] = + OCTEP_CP_VERSION(1, 0, 0) + }; + +@@ -353,6 +353,28 @@ void octep_ctrl_net_recv_fw_messages(struct octep_device *oct) + } + } + ++int octep_ctrl_net_get_info(struct octep_device *oct, int vfid, ++ struct octep_fw_info *info) ++{ ++ struct octep_ctrl_net_wait_data d = {0}; ++ struct octep_ctrl_net_h2f_resp *resp; ++ struct octep_ctrl_net_h2f_req *req; ++ int err; ++ ++ req = &d.data.req; ++ init_send_req(&d.msg, req, 0, vfid); ++ req->hdr.s.cmd = OCTEP_CTRL_NET_H2F_CMD_GET_INFO; ++ req->link_info.cmd = OCTEP_CTRL_NET_CMD_GET; ++ err = octep_send_mbox_req(oct, &d, true); ++ if (err < 0) ++ return err; ++ ++ resp = &d.data.resp; ++ memcpy(info, &resp->info.fw_info, sizeof(struct octep_fw_info)); ++ ++ return 0; ++} ++ + int octep_ctrl_net_uninit(struct octep_device *oct) + { + struct octep_ctrl_net_wait_data *pos, *n; +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.h b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.h +index 1c2ef4ee31d91..b330f370131be 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.h ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.h +@@ -41,6 +41,7 @@ enum octep_ctrl_net_h2f_cmd { + OCTEP_CTRL_NET_H2F_CMD_LINK_STATUS, + OCTEP_CTRL_NET_H2F_CMD_RX_STATE, + OCTEP_CTRL_NET_H2F_CMD_LINK_INFO, ++ OCTEP_CTRL_NET_H2F_CMD_GET_INFO, + OCTEP_CTRL_NET_H2F_CMD_MAX + }; + +@@ -161,6 +162,11 @@ struct octep_ctrl_net_h2f_resp_cmd_state { + u16 state; + }; + ++/* get info request */ ++struct octep_ctrl_net_h2f_resp_cmd_get_info { ++ struct octep_fw_info fw_info; ++}; ++ + /* Host to fw response data */ + struct octep_ctrl_net_h2f_resp { + union octep_ctrl_net_resp_hdr hdr; +@@ -171,6 +177,7 @@ struct octep_ctrl_net_h2f_resp { + struct octep_ctrl_net_h2f_resp_cmd_state link; + struct octep_ctrl_net_h2f_resp_cmd_state rx; + struct octep_ctrl_net_link_info link_info; ++ struct octep_ctrl_net_h2f_resp_cmd_get_info info; + }; + } __packed; + +@@ -330,6 +337,17 @@ int octep_ctrl_net_set_link_info(struct octep_device *oct, + */ + void octep_ctrl_net_recv_fw_messages(struct octep_device *oct); + ++/** Get info from firmware. ++ * ++ * @param oct: non-null pointer to struct octep_device. ++ * @param vfid: Index of virtual function. ++ * @param info: non-null pointer to struct octep_fw_info. ++ * ++ * return value: 0 on success, -errno on failure. ++ */ ++int octep_ctrl_net_get_info(struct octep_device *oct, int vfid, ++ struct octep_fw_info *info); ++ + /** Uninitialize data for ctrl net. + * + * @param oct: non-null pointer to struct octep_device. +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c +index c385084546639..32740d0a4216a 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c +@@ -907,9 +907,9 @@ static void octep_hb_timeout_task(struct work_struct *work) + int miss_cnt; + + miss_cnt = atomic_inc_return(&oct->hb_miss_cnt); +- if (miss_cnt < oct->conf->max_hb_miss_cnt) { ++ if (miss_cnt < oct->conf->fw_info.hb_miss_count) { + queue_delayed_work(octep_wq, &oct->hb_task, +- msecs_to_jiffies(oct->conf->hb_interval * 1000)); ++ msecs_to_jiffies(oct->conf->fw_info.hb_interval)); + return; + } + +@@ -1002,8 +1002,7 @@ int octep_device_setup(struct octep_device *oct) + + atomic_set(&oct->hb_miss_cnt, 0); + INIT_DELAYED_WORK(&oct->hb_task, octep_hb_timeout_task); +- queue_delayed_work(octep_wq, &oct->hb_task, +- msecs_to_jiffies(oct->conf->hb_interval * 1000)); ++ + return 0; + + unsupported_dev: +@@ -1133,6 +1132,15 @@ static int octep_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + dev_err(&pdev->dev, "Device setup failed\n"); + goto err_octep_config; + } ++ ++ octep_ctrl_net_get_info(octep_dev, OCTEP_CTRL_NET_INVALID_VFID, ++ &octep_dev->conf->fw_info); ++ dev_info(&octep_dev->pdev->dev, "Heartbeat interval %u msecs Heartbeat miss count %u\n", ++ octep_dev->conf->fw_info.hb_interval, ++ octep_dev->conf->fw_info.hb_miss_count); ++ queue_delayed_work(octep_wq, &octep_dev->hb_task, ++ msecs_to_jiffies(octep_dev->conf->fw_info.hb_interval)); ++ + INIT_WORK(&octep_dev->tx_timeout_task, octep_tx_timeout_task); + INIT_WORK(&octep_dev->ctrl_mbox_task, octep_ctrl_mbox_task); + INIT_DELAYED_WORK(&octep_dev->intr_poll_task, octep_intr_poll_task); +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cn9k_pf.h b/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cn9k_pf.h +index b25c3093dc7b4..0a43983e91015 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cn9k_pf.h ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cn9k_pf.h +@@ -370,4 +370,8 @@ + /* bit 1 for firmware heartbeat interrupt */ + #define CN93_SDP_EPF_OEI_RINT_DATA_BIT_HBEAT BIT_ULL(1) + ++#define CN93_PEM_BAR4_INDEX 7 ++#define CN93_PEM_BAR4_INDEX_SIZE 0x400000ULL ++#define CN93_PEM_BAR4_INDEX_OFFSET (CN93_PEM_BAR4_INDEX * CN93_PEM_BAR4_INDEX_SIZE) ++ + #endif /* _OCTEP_REGS_CN9K_PF_H_ */ +-- +2.51.0 + diff --git a/queue-6.6/octeontx2-af-fix-pf-driver-crash-with-kexec-kernel-b.patch b/queue-6.6/octeontx2-af-fix-pf-driver-crash-with-kexec-kernel-b.patch new file mode 100644 index 0000000000..65f35cf5af --- /dev/null +++ b/queue-6.6/octeontx2-af-fix-pf-driver-crash-with-kexec-kernel-b.patch @@ -0,0 +1,62 @@ +From 98289f50ac9f9e055b26a2f5db8eda932601d29b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 10:37:01 +0530 +Subject: octeontx2-af: Fix PF driver crash with kexec kernel booting + +From: Anshumali Gaur + +[ Upstream commit 2d2d574309e3ae84ee794869a5da8b4c38753a94 ] + +During a kexec reboot the hardware is not power-cycled, so AF state from +the old kernel can persist into the new kernel. When AF and PF drivers +are built as modules, the PF driver may probe before AF reinitializes +the hardware. + +The PF driver treats the RVUM block revision as an indication that AF +initialization is complete. If this value is left uncleared at shutdown, +PF may incorrectly assume AF is ready and access stale hardware state, +leading to a crash. + +Clear the RVUM block revision during AF shutdown to avoid PF +mis-detecting AF readiness after kexec. + +Fixes: 54494aa5d1e6 ("octeontx2-af: Add Marvell OcteonTX2 RVU AF driver") +Signed-off-by: Anshumali Gaur +Reviewed-by: Jacob Keller +Link: https://patch.msgid.link/20260203050701.2616685-1-agaur@marvell.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/octeontx2/af/rvu.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +index 846049b6c4d60..a7fcea9b1ee7e 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +@@ -3444,11 +3444,22 @@ static void rvu_remove(struct pci_dev *pdev) + devm_kfree(&pdev->dev, rvu); + } + ++static void rvu_shutdown(struct pci_dev *pdev) ++{ ++ struct rvu *rvu = pci_get_drvdata(pdev); ++ ++ if (!rvu) ++ return; ++ ++ rvu_clear_rvum_blk_revid(rvu); ++} ++ + static struct pci_driver rvu_driver = { + .name = DRV_NAME, + .id_table = rvu_id_table, + .probe = rvu_probe, + .remove = rvu_remove, ++ .shutdown = rvu_shutdown, + }; + + static int __init rvu_init_module(void) +-- +2.51.0 + diff --git a/queue-6.6/octeontx2-pf-unregister-devlink-on-probe-failure.patch b/queue-6.6/octeontx2-pf-unregister-devlink-on-probe-failure.patch new file mode 100644 index 0000000000..fd85c68b4e --- /dev/null +++ b/queue-6.6/octeontx2-pf-unregister-devlink-on-probe-failure.patch @@ -0,0 +1,36 @@ +From 52c16f7a39918440c02c302b1602110e4a71e88c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 23:56:45 +0530 +Subject: octeontx2-pf: Unregister devlink on probe failure + +From: Hariprasad Kelam + +[ Upstream commit 943f3b8bfbf297cf74392b50a7108ce1fe4cbd8c ] + +When probe fails after devlink registration, the missing devlink unregister +call causing a memory leak. + +Fixes: 2da489432747 ("octeontx2-pf: devlink params support to set mcam entry count") +Signed-off-by: Hariprasad Kelam +Link: https://patch.msgid.link/20260206182645.4032737-1-hkelam@marvell.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +index b4194ec2a1f2d..784130b4b0865 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c ++++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +@@ -3097,6 +3097,7 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id) + return 0; + + err_pf_sriov_init: ++ otx2_unregister_dl(pf); + otx2_shutdown_tc(pf); + err_mcam_flow_del: + otx2_mcam_flow_del(pf); +-- +2.51.0 + diff --git a/queue-6.6/of-unittest-fix-possible-null-pointer-dereferences-i.patch b/queue-6.6/of-unittest-fix-possible-null-pointer-dereferences-i.patch new file mode 100644 index 0000000000..3d32371ba1 --- /dev/null +++ b/queue-6.6/of-unittest-fix-possible-null-pointer-dereferences-i.patch @@ -0,0 +1,49 @@ +From 2c866a793ed9d61a3b11e3e9542617f1de617d4a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Jan 2026 15:14:38 +0800 +Subject: of: unittest: fix possible null-pointer dereferences in + of_unittest_property_copy() + +From: Tuo Li + +[ Upstream commit d289cb7fcefe41a54d8f9c6d0e0947f5f82b15c6 ] + +This function first duplicates p1 and p2 into new, and then checks whether +the duplication succeeds. However, if the duplication fails (e.g., +kzalloc() returns NULL in __of_prop_dup()), new will be NULL but is still +dereferenced in __of_prop_free(). To ensure that the unit test continues to +run even when duplication fails, add a NULL check before calling +__of_prop_free(). + +Fixes: 1c5e3d9bf33b ("of: Add a helper to free property struct") +Signed-off-by: Tuo Li +Link: https://patch.msgid.link/20260105071438.156186-1-islituo@gmail.com +Signed-off-by: Rob Herring (Arm) +Signed-off-by: Sasha Levin +--- + drivers/of/unittest.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c +index aae4e8ef9e365..4b7e663feee3d 100644 +--- a/drivers/of/unittest.c ++++ b/drivers/of/unittest.c +@@ -800,11 +800,13 @@ static void __init of_unittest_property_copy(void) + + new = __of_prop_dup(&p1, GFP_KERNEL); + unittest(new && propcmp(&p1, new), "empty property didn't copy correctly\n"); +- __of_prop_free(new); ++ if (new) ++ __of_prop_free(new); + + new = __of_prop_dup(&p2, GFP_KERNEL); + unittest(new && propcmp(&p2, new), "non-empty property didn't copy correctly\n"); +- __of_prop_free(new); ++ if (new) ++ __of_prop_free(new); + #endif + } + +-- +2.51.0 + diff --git a/queue-6.6/ovl-fix-uninit-value-in-ovl_fill_real.patch b/queue-6.6/ovl-fix-uninit-value-in-ovl_fill_real.patch new file mode 100644 index 0000000000..f68264186f --- /dev/null +++ b/queue-6.6/ovl-fix-uninit-value-in-ovl_fill_real.patch @@ -0,0 +1,58 @@ +From 9056e86f265313b3e769a096ed1f255df3c111c6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 14:24:04 +0100 +Subject: ovl: Fix uninit-value in ovl_fill_real + +From: Qing Wang + +[ Upstream commit 1992330d90dd766fcf1730fd7bf2d6af65370ac4 ] + +Syzbot reported a KMSAN uninit-value issue in ovl_fill_real. + +This iusse's call chain is: +__do_sys_getdents64() + -> iterate_dir() + ... + -> ext4_readdir() + -> fscrypt_fname_alloc_buffer() // alloc + -> fscrypt_fname_disk_to_usr // write without tail '\0' + -> dir_emit() + -> ovl_fill_real() // read by strcmp() + +The string is used to store the decrypted directory entry name for an +encrypted inode. As shown in the call chain, fscrypt_fname_disk_to_usr() +write it without null-terminate. However, ovl_fill_real() uses strcmp() to +compare the name against "..", which assumes a null-terminated string and +may trigger a KMSAN uninit-value warning when the buffer tail contains +uninit data. + +Reported-by: syzbot+d130f98b2c265fae5297@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=d130f98b2c265fae5297 +Fixes: 4edb83bb1041 ("ovl: constant d_ino for non-merge dirs") +Signed-off-by: Qing Wang +Signed-off-by: Amir Goldstein +Link: https://patch.msgid.link/20260128132406.23768-2-amir73il@gmail.com +Acked-by: Miklos Szeredi +Reviewed-by: Eric Biggers +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/overlayfs/readdir.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c +index de39e067ae65a..0d667e9534573 100644 +--- a/fs/overlayfs/readdir.c ++++ b/fs/overlayfs/readdir.c +@@ -659,7 +659,7 @@ static bool ovl_fill_real(struct dir_context *ctx, const char *name, + container_of(ctx, struct ovl_readdir_translate, ctx); + struct dir_context *orig_ctx = rdt->orig_ctx; + +- if (rdt->parent_ino && strcmp(name, "..") == 0) { ++ if (rdt->parent_ino && namelen == 2 && !strncmp(name, "..", 2)) { + ino = rdt->parent_ino; + } else if (rdt->cache) { + struct ovl_cache_entry *p; +-- +2.51.0 + diff --git a/queue-6.6/partial-revert-x86-xen-fix-balloon-target-initializa.patch b/queue-6.6/partial-revert-x86-xen-fix-balloon-target-initializa.patch new file mode 100644 index 0000000000..f21f18656f --- /dev/null +++ b/queue-6.6/partial-revert-x86-xen-fix-balloon-target-initializa.patch @@ -0,0 +1,140 @@ +From 3f988d699ec65ee615c2540805b1be78dbca4ec3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 12:05:08 +0100 +Subject: Partial revert "x86/xen: fix balloon target initialization for PVH + dom0" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Roger Pau Monne + +[ Upstream commit 0949c646d64697428ff6257d52efa5093566868d ] + +This partially reverts commit 87af633689ce16ddb166c80f32b120e50b1295de so +the current memory target for PV guests is still fetched from +start_info->nr_pages, which matches exactly what the toolstack sets the +initial memory target to. + +Using get_num_physpages() is possible on PV also, but needs adjusting to +take into account the ISA hole and the PFN at 0 not considered usable +memory despite being populated, and hence would need extra adjustments. +Instead of carrying those extra adjustments switch back to the previous +code. That leaves Linux with a difference in how current memory target is +obtained for HVM vs PV, but that's better than adding extra logic just for +PV. + +However if switching to start_info->nr_pages for PV domains we need to +differentiate between released pages (freed back to the hypervisor) as +opposed to pages in the physmap which are not populated to start with. +Introduce a new xen_unpopulated_pages to account for papges that have +never been populated, and hence in the PV case don't need subtracting. + +Fixes: 87af633689ce ("x86/xen: fix balloon target initialization for PVH dom0") +Reported-by: James Dingwall +Signed-off-by: Roger Pau Monné +Reviewed-by: Juergen Gross +Signed-off-by: Juergen Gross +Message-ID: <20260128110510.46425-2-roger.pau@citrix.com> +Signed-off-by: Sasha Levin +--- + arch/x86/xen/enlighten.c | 2 +- + drivers/xen/balloon.c | 19 +++++++++++++++---- + drivers/xen/unpopulated-alloc.c | 3 +++ + include/xen/xen.h | 2 ++ + 4 files changed, 21 insertions(+), 5 deletions(-) + +diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c +index 638de313fc4ed..03fb16dc0b926 100644 +--- a/arch/x86/xen/enlighten.c ++++ b/arch/x86/xen/enlighten.c +@@ -480,7 +480,7 @@ int __init arch_xen_unpopulated_init(struct resource **res) + * driver to know how much of the physmap is unpopulated and + * set an accurate initial memory target. + */ +- xen_released_pages += xen_extra_mem[i].n_pfns; ++ xen_unpopulated_pages += xen_extra_mem[i].n_pfns; + /* Zero so region is not also added to the balloon driver. */ + xen_extra_mem[i].n_pfns = 0; + } +diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c +index 204ec1bcbd526..a76d5530533ff 100644 +--- a/drivers/xen/balloon.c ++++ b/drivers/xen/balloon.c +@@ -716,6 +716,7 @@ static int __init balloon_add_regions(void) + static int __init balloon_init(void) + { + struct task_struct *task; ++ unsigned long current_pages; + int rc; + + if (!xen_domain()) +@@ -723,12 +724,18 @@ static int __init balloon_init(void) + + pr_info("Initialising balloon driver\n"); + +- if (xen_released_pages >= get_num_physpages()) { +- WARN(1, "Released pages underflow current target"); +- return -ERANGE; ++ if (xen_pv_domain()) { ++ if (xen_released_pages >= xen_start_info->nr_pages) ++ goto underflow; ++ current_pages = min(xen_start_info->nr_pages - ++ xen_released_pages, max_pfn); ++ } else { ++ if (xen_unpopulated_pages >= get_num_physpages()) ++ goto underflow; ++ current_pages = get_num_physpages() - xen_unpopulated_pages; + } + +- balloon_stats.current_pages = get_num_physpages() - xen_released_pages; ++ balloon_stats.current_pages = current_pages; + balloon_stats.target_pages = balloon_stats.current_pages; + balloon_stats.balloon_low = 0; + balloon_stats.balloon_high = 0; +@@ -759,6 +766,10 @@ static int __init balloon_init(void) + xen_balloon_init(); + + return 0; ++ ++ underflow: ++ WARN(1, "Released pages underflow current target"); ++ return -ERANGE; + } + subsys_initcall(balloon_init); + +diff --git a/drivers/xen/unpopulated-alloc.c b/drivers/xen/unpopulated-alloc.c +index a39f2d36dd9cf..ae46291e99a9d 100644 +--- a/drivers/xen/unpopulated-alloc.c ++++ b/drivers/xen/unpopulated-alloc.c +@@ -18,6 +18,9 @@ static unsigned int list_count; + + static struct resource *target_resource; + ++/* Pages to subtract from the memory count when setting balloon target. */ ++unsigned long xen_unpopulated_pages __initdata; ++ + /* + * If arch is not happy with system "iomem_resource" being used for + * the region allocation it can provide it's own view by creating specific +diff --git a/include/xen/xen.h b/include/xen/xen.h +index a1e5b3f18d69f..86fe96fe51834 100644 +--- a/include/xen/xen.h ++++ b/include/xen/xen.h +@@ -62,11 +62,13 @@ extern u64 xen_saved_max_mem_size; + #endif + + #ifdef CONFIG_XEN_UNPOPULATED_ALLOC ++extern unsigned long xen_unpopulated_pages; + int xen_alloc_unpopulated_pages(unsigned int nr_pages, struct page **pages); + void xen_free_unpopulated_pages(unsigned int nr_pages, struct page **pages); + #include + int arch_xen_unpopulated_init(struct resource **res); + #else ++#define xen_unpopulated_pages 0UL + #include + static inline int xen_alloc_unpopulated_pages(unsigned int nr_pages, + struct page **pages) +-- +2.51.0 + diff --git a/queue-6.6/pci-acpi-restrict-program_hpx_type2-to-aer-bits.patch b/queue-6.6/pci-acpi-restrict-program_hpx_type2-to-aer-bits.patch new file mode 100644 index 0000000000..96dd28ef45 --- /dev/null +++ b/queue-6.6/pci-acpi-restrict-program_hpx_type2-to-aer-bits.patch @@ -0,0 +1,200 @@ +From 661cba37afe5aa9609e62bfaddb9cf251e0a1b58 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 18:52:33 +0100 +Subject: PCI/ACPI: Restrict program_hpx_type2() to AER bits +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: HÃ¥kon Bugge + +[ Upstream commit 9abf79c8d7b40db0e5a34aa8c744ea60ff9a3fcf ] + +Previously program_hpx_type2() applied PCIe settings unconditionally, +which could incorrectly change bits like Extended Tag Field Enable and +Enable Relaxed Ordering. + +When _HPX was added to ACPI r3.0, the intent of the PCIe Setting +Record (Type 2) in sec 6.2.7.3 was to configure AER registers when the +OS does not own the AER Capability: + + The PCI Express setting record contains ... [the AER] Uncorrectable + Error Mask, Uncorrectable Error Severity, Correctable Error Mask + ... to be used when configuring registers in the Advanced Error + Reporting Extended Capability Structure ... + + OSPM [1] will only evaluate _HPX with Setting Record – Type 2 if + OSPM is not controlling the PCI Express Advanced Error Reporting + capability. + +ACPI r3.0b, sec 6.2.7.3, added more AER registers, including registers +in the PCIe Capability with AER-related bits, and the restriction that +the OS use this only when it owns PCIe native hotplug: + + ... when configuring PCI Express registers in the Advanced Error + Reporting Extended Capability Structure *or PCI Express Capability + Structure* ... + + An OS that has assumed ownership of native hot plug but does not + ... have ownership of the AER register set must use ... the Type 2 + record to program the AER registers ... + + However, since the Type 2 record also includes register bits that + have functions other than AER, the OS must ignore values ... that + are not applicable. + +Restrict program_hpx_type2() to only the intended purpose: + + - Apply settings only when OS owns PCIe native hotplug but not AER, + + - Only touch the AER-related bits (Error Reporting Enables) in Device + Control + + - Don't touch Link Control at all, since nothing there seems AER-related, + but log _HPX settings for debugging purposes + +Note that Read Completion Boundary is now configured elsewhere, since it is +unrelated to _HPX. + +[1] Operating System-directed configuration and Power Management + +Fixes: 40abb96c51bb ("[PATCH] pciehp: Fix programming hotplug parameters") +Signed-off-by: HÃ¥kon Bugge +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260129175237.727059-3-haakon.bugge@oracle.com +Signed-off-by: Sasha Levin +--- + drivers/pci/pci-acpi.c | 59 +++++++++++++++++------------------------- + drivers/pci/pci.h | 3 +++ + drivers/pci/pcie/aer.c | 3 --- + 3 files changed, 27 insertions(+), 38 deletions(-) + +diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c +index 61bded8623d21..508873c526e71 100644 +--- a/drivers/pci/pci-acpi.c ++++ b/drivers/pci/pci-acpi.c +@@ -246,21 +246,6 @@ static acpi_status decode_type1_hpx_record(union acpi_object *record, + return AE_OK; + } + +-static bool pcie_root_rcb_set(struct pci_dev *dev) +-{ +- struct pci_dev *rp = pcie_find_root_port(dev); +- u16 lnkctl; +- +- if (!rp) +- return false; +- +- pcie_capability_read_word(rp, PCI_EXP_LNKCTL, &lnkctl); +- if (lnkctl & PCI_EXP_LNKCTL_RCB) +- return true; +- +- return false; +-} +- + /* _HPX PCI Express Setting Record (Type 2) */ + struct hpx_type2 { + u32 revision; +@@ -286,6 +271,7 @@ static void program_hpx_type2(struct pci_dev *dev, struct hpx_type2 *hpx) + { + int pos; + u32 reg32; ++ const struct pci_host_bridge *host; + + if (!hpx) + return; +@@ -293,6 +279,15 @@ static void program_hpx_type2(struct pci_dev *dev, struct hpx_type2 *hpx) + if (!pci_is_pcie(dev)) + return; + ++ host = pci_find_host_bridge(dev->bus); ++ ++ /* ++ * Only do the _HPX Type 2 programming if OS owns PCIe native ++ * hotplug but not AER. ++ */ ++ if (!host->native_pcie_hotplug || host->native_aer) ++ return; ++ + if (hpx->revision > 1) { + pci_warn(dev, "PCIe settings rev %d not supported\n", + hpx->revision); +@@ -300,33 +295,27 @@ static void program_hpx_type2(struct pci_dev *dev, struct hpx_type2 *hpx) + } + + /* +- * Don't allow _HPX to change MPS or MRRS settings. We manage +- * those to make sure they're consistent with the rest of the +- * platform. ++ * We only allow _HPX to program DEVCTL bits related to AER, namely ++ * PCI_EXP_DEVCTL_CERE, PCI_EXP_DEVCTL_NFERE, PCI_EXP_DEVCTL_FERE, ++ * and PCI_EXP_DEVCTL_URRE. ++ * ++ * The rest of DEVCTL is managed by the OS to make sure it's ++ * consistent with the rest of the platform. + */ +- hpx->pci_exp_devctl_and |= PCI_EXP_DEVCTL_PAYLOAD | +- PCI_EXP_DEVCTL_READRQ; +- hpx->pci_exp_devctl_or &= ~(PCI_EXP_DEVCTL_PAYLOAD | +- PCI_EXP_DEVCTL_READRQ); ++ hpx->pci_exp_devctl_and |= ~PCI_EXP_AER_FLAGS; ++ hpx->pci_exp_devctl_or &= PCI_EXP_AER_FLAGS; + + /* Initialize Device Control Register */ + pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL, + ~hpx->pci_exp_devctl_and, hpx->pci_exp_devctl_or); + +- /* Initialize Link Control Register */ ++ /* Log if _HPX attempts to modify Link Control Register */ + if (pcie_cap_has_lnkctl(dev)) { +- +- /* +- * If the Root Port supports Read Completion Boundary of +- * 128, set RCB to 128. Otherwise, clear it. +- */ +- hpx->pci_exp_lnkctl_and |= PCI_EXP_LNKCTL_RCB; +- hpx->pci_exp_lnkctl_or &= ~PCI_EXP_LNKCTL_RCB; +- if (pcie_root_rcb_set(dev)) +- hpx->pci_exp_lnkctl_or |= PCI_EXP_LNKCTL_RCB; +- +- pcie_capability_clear_and_set_word(dev, PCI_EXP_LNKCTL, +- ~hpx->pci_exp_lnkctl_and, hpx->pci_exp_lnkctl_or); ++ if (hpx->pci_exp_lnkctl_and != 0xffff || ++ hpx->pci_exp_lnkctl_or != 0) ++ pci_info(dev, "_HPX attempts Link Control setting (AND %#06x OR %#06x)\n", ++ hpx->pci_exp_lnkctl_and, ++ hpx->pci_exp_lnkctl_or); + } + + /* Find Advanced Error Reporting Enhanced Capability */ +diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h +index d333be3877b2e..24441a26be1e6 100644 +--- a/drivers/pci/pci.h ++++ b/drivers/pci/pci.h +@@ -44,6 +44,9 @@ + #define PCI_BUS_BRIDGE_MEM_WINDOW 1 + #define PCI_BUS_BRIDGE_PREF_MEM_WINDOW 2 + ++#define PCI_EXP_AER_FLAGS (PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE | \ ++ PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE) ++ + extern const unsigned char pcie_link_speed[]; + extern bool pci_early_dump; + +diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c +index 8e700020ee0bc..42a0f86b72fa5 100644 +--- a/drivers/pci/pcie/aer.c ++++ b/drivers/pci/pcie/aer.c +@@ -218,9 +218,6 @@ void pcie_ecrc_get_policy(char *str) + } + #endif /* CONFIG_PCIE_ECRC */ + +-#define PCI_EXP_AER_FLAGS (PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE | \ +- PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE) +- + int pcie_aer_is_native(struct pci_dev *dev) + { + struct pci_host_bridge *host = pci_find_host_bridge(dev->bus); +-- +2.51.0 + diff --git a/queue-6.6/pci-add-acs-quirk-for-pericom-pi7c9x2g404-switches-1.patch b/queue-6.6/pci-add-acs-quirk-for-pericom-pi7c9x2g404-switches-1.patch new file mode 100644 index 0000000000..0c0a966393 --- /dev/null +++ b/queue-6.6/pci-add-acs-quirk-for-pericom-pi7c9x2g404-switches-1.patch @@ -0,0 +1,46 @@ +From 0a9760164efa44d270321038bc38e8f639e55ea3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 17:08:33 +0100 +Subject: PCI: Add ACS quirk for Pericom PI7C9X2G404 switches [12d8:b404] + +From: Nicolas Cavallari + +[ Upstream commit 5907a90551e9f7968781f3a6ab8684458959beb3 ] + +12d8:b404 is apparently another PCI ID for Pericom PI7C9X2G404 (as +identified by the chip silkscreen and lspci). + +It is also affected by the PI7C9X2G errata (e.g. a network card attached +to it fails under load when P2P Redirect Request is enabled), so apply +the same quirk to this PCI ID too. + +PCI bridge [0604]: Pericom Semiconductor PI7C9X2G404 EV/SV PCIe2 4-Port/4-Lane Packet Switch [12d8:b404] (rev 01) + +Fixes: acd61ffb2f16 ("PCI: Add ACS quirk for Pericom PI7C9X2G switches") +Closes: https://lore.kernel.org/all/a1d926f0-4cb5-4877-a4df-617902648d80@green-communications.fr/ +Signed-off-by: Nicolas Cavallari +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260119160915.26456-1-nicolas.cavallari@green-communications.fr +Signed-off-by: Sasha Levin +--- + drivers/pci/quirks.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index cac9a163d7d55..f89070b1379fe 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -6181,6 +6181,10 @@ DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_PERICOM, 0x2303, + pci_fixup_pericom_acs_store_forward); + DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_PERICOM, 0x2303, + pci_fixup_pericom_acs_store_forward); ++DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_PERICOM, 0xb404, ++ pci_fixup_pericom_acs_store_forward); ++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_PERICOM, 0xb404, ++ pci_fixup_pericom_acs_store_forward); + + static void nvidia_ion_ahci_fixup(struct pci_dev *pdev) + { +-- +2.51.0 + diff --git a/queue-6.6/pci-add-defines-for-bridge-window-indexing.patch b/queue-6.6/pci-add-defines-for-bridge-window-indexing.patch new file mode 100644 index 0000000000..424c123e79 --- /dev/null +++ b/queue-6.6/pci-add-defines-for-bridge-window-indexing.patch @@ -0,0 +1,69 @@ +From 8fc37aaeb894c0918e7f85518a0e2252ff071d33 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 Aug 2025 16:11:00 +0300 +Subject: PCI: Add defines for bridge window indexing +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ilpo Järvinen + +[ Upstream commit e4934832c588f72bcc139d3ca0acc490c63a821c ] + +include/linux/pci.h provides PCI_BRIDGE_{IO,MEM,PREF_MEM}_WINDOW defines, +however, they're based on the resource array indexing in the pci_dev +struct. The struct pci_bus also has pointers to those same resources but +they start from zeroth index. + +Add PCI_BUS_BRIDGE_{IO,MEM,PREF_MEM}_WINDOW defines to get rid of literal +indexing. + +Signed-off-by: Ilpo Järvinen +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20250829131113.36754-12-ilpo.jarvinen@linux.intel.com +Stable-dep-of: 9abf79c8d7b4 ("PCI/ACPI: Restrict program_hpx_type2() to AER bits") +Signed-off-by: Sasha Levin +--- + drivers/pci/pci.h | 4 ++++ + drivers/pci/probe.c | 10 +++++++--- + 2 files changed, 11 insertions(+), 3 deletions(-) + +diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h +index 95603147e73c8..d333be3877b2e 100644 +--- a/drivers/pci/pci.h ++++ b/drivers/pci/pci.h +@@ -40,6 +40,10 @@ + #define PCIE_MSG_CODE_DEASSERT_INTC 0x26 + #define PCIE_MSG_CODE_DEASSERT_INTD 0x27 + ++#define PCI_BUS_BRIDGE_IO_WINDOW 0 ++#define PCI_BUS_BRIDGE_MEM_WINDOW 1 ++#define PCI_BUS_BRIDGE_PREF_MEM_WINDOW 2 ++ + extern const unsigned char pcie_link_speed[]; + extern bool pci_early_dump; + +diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c +index 8a2f1e57bee19..cc56bf47c4a3f 100644 +--- a/drivers/pci/probe.c ++++ b/drivers/pci/probe.c +@@ -539,9 +539,13 @@ void pci_read_bridge_bases(struct pci_bus *child) + for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++) + child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i]; + +- pci_read_bridge_io(child->self, child->resource[0], false); +- pci_read_bridge_mmio(child->self, child->resource[1], false); +- pci_read_bridge_mmio_pref(child->self, child->resource[2], false); ++ pci_read_bridge_io(child->self, ++ child->resource[PCI_BUS_BRIDGE_IO_WINDOW], false); ++ pci_read_bridge_mmio(child->self, ++ child->resource[PCI_BUS_BRIDGE_MEM_WINDOW], false); ++ pci_read_bridge_mmio_pref(child->self, ++ child->resource[PCI_BUS_BRIDGE_PREF_MEM_WINDOW], ++ false); + + if (dev->transparent) { + pci_bus_for_each_resource(child->parent, res) { +-- +2.51.0 + diff --git a/queue-6.6/pci-add-pcie_msg_code_assert_intx-message-macros.patch b/queue-6.6/pci-add-pcie_msg_code_assert_intx-message-macros.patch new file mode 100644 index 0000000000..65fb6fde28 --- /dev/null +++ b/queue-6.6/pci-add-pcie_msg_code_assert_intx-message-macros.patch @@ -0,0 +1,62 @@ +From 5bfa4497e010619cecc594255407cc688031b7a7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Apr 2024 12:04:24 -0400 +Subject: PCI: Add PCIE_MSG_CODE_ASSERT_INTx message macros +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yoshihiro Shimoda + +[ Upstream commit 95cb8ff68851ed0d249fb8a1d9657987cd844e08 ] + +Add "Message Routing" and "INTx Mechanism Messages" macros to enable +a PCIe driver to send messages for INTx Interrupt Signaling. + +Values from PCIe r6.1, sec 2.2.8 and 2.2.8.1. + +Link: https://lore.kernel.org/linux-pci/20240418-pme_msg-v8-1-a54265c39742@nxp.com +Signed-off-by: Yoshihiro Shimoda +Signed-off-by: Frank Li +Signed-off-by: Krzysztof Wilczyński +Signed-off-by: Bjorn Helgaas +Reviewed-by: Manivannan Sadhasivam +Reviewed-by: Serge Semin +Stable-dep-of: 9abf79c8d7b4 ("PCI/ACPI: Restrict program_hpx_type2() to AER bits") +Signed-off-by: Sasha Levin +--- + drivers/pci/pci.h | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h +index d69a17947ffce..95603147e73c8 100644 +--- a/drivers/pci/pci.h ++++ b/drivers/pci/pci.h +@@ -22,6 +22,24 @@ + */ + #define PCIE_PME_TO_L2_TIMEOUT_US 10000 + ++/* Message Routing (r[2:0]); PCIe r6.0, sec 2.2.8 */ ++#define PCIE_MSG_TYPE_R_RC 0 ++#define PCIE_MSG_TYPE_R_ADDR 1 ++#define PCIE_MSG_TYPE_R_ID 2 ++#define PCIE_MSG_TYPE_R_BC 3 ++#define PCIE_MSG_TYPE_R_LOCAL 4 ++#define PCIE_MSG_TYPE_R_GATHER 5 ++ ++/* INTx Mechanism Messages; PCIe r6.0, sec 2.2.8.1 */ ++#define PCIE_MSG_CODE_ASSERT_INTA 0x20 ++#define PCIE_MSG_CODE_ASSERT_INTB 0x21 ++#define PCIE_MSG_CODE_ASSERT_INTC 0x22 ++#define PCIE_MSG_CODE_ASSERT_INTD 0x23 ++#define PCIE_MSG_CODE_DEASSERT_INTA 0x24 ++#define PCIE_MSG_CODE_DEASSERT_INTB 0x25 ++#define PCIE_MSG_CODE_DEASSERT_INTC 0x26 ++#define PCIE_MSG_CODE_DEASSERT_INTD 0x27 ++ + extern const unsigned char pcie_link_speed[]; + extern bool pci_early_dump; + +-- +2.51.0 + diff --git a/queue-6.6/pci-do-not-attempt-to-set-exttag-for-vfs.patch b/queue-6.6/pci-do-not-attempt-to-set-exttag-for-vfs.patch new file mode 100644 index 0000000000..18db932132 --- /dev/null +++ b/queue-6.6/pci-do-not-attempt-to-set-exttag-for-vfs.patch @@ -0,0 +1,49 @@ +From 7fa530bc24026291058f03f27e8a10ff921f72db Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 12 Nov 2025 10:54:40 +0100 +Subject: PCI: Do not attempt to set ExtTag for VFs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: HÃ¥kon Bugge + +[ Upstream commit 73711730a1128d91ebca1a6994ceeb18f36cb0cd ] + +The bit for enabling extended tags is Reserved and Preserved (RsvdP) for +VFs, according to PCIe r7.0 section 7.5.3.4 table 7.21. Hence, bail out +early from pci_configure_extended_tags() if the device is a VF. + +Otherwise, we may see incorrect log messages such as: + + kernel: pci 0000:af:00.2: enabling Extended Tags + +(af:00.2 is a VF) + +Fixes: 60db3a4d8cc9 ("PCI: Enable PCIe Extended Tags if supported") +Signed-off-by: HÃ¥kon Bugge +Signed-off-by: Bjorn Helgaas +Reviewed-by: Zhu Yanjun +Link: https://patch.msgid.link/20251112095442.1913258-1-haakon.bugge@oracle.com +Signed-off-by: Sasha Levin +--- + drivers/pci/probe.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c +index 5557290b63dc1..9b277a91d0cb4 100644 +--- a/drivers/pci/probe.c ++++ b/drivers/pci/probe.c +@@ -2101,7 +2101,8 @@ int pci_configure_extended_tags(struct pci_dev *dev, void *ign) + u16 ctl; + int ret; + +- if (!pci_is_pcie(dev)) ++ /* PCI_EXP_DEVCTL_EXT_TAG is RsvdP in VFs */ ++ if (!pci_is_pcie(dev) || dev->is_virtfn) + return 0; + + ret = pcie_capability_read_dword(dev, PCI_EXP_DEVCAP, &cap); +-- +2.51.0 + diff --git a/queue-6.6/pci-initialize-rcb-from-pci_configure_device.patch b/queue-6.6/pci-initialize-rcb-from-pci_configure_device.patch new file mode 100644 index 0000000000..5548fe6577 --- /dev/null +++ b/queue-6.6/pci-initialize-rcb-from-pci_configure_device.patch @@ -0,0 +1,90 @@ +From 54375f0b608e98a0591ba15120897c32deb670e1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 18:52:32 +0100 +Subject: PCI: Initialize RCB from pci_configure_device() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: HÃ¥kon Bugge + +[ Upstream commit 1a6845aaa6de81f95959b380b45de8f10d6a8502 ] + +Commit e42010d8207f ("PCI: Set Read Completion Boundary to 128 iff Root +Port supports it (_HPX)") worked around a bogus _HPX type 2 record, which +caused program_hpx_type2() to set the RCB in an endpoint even though the +Root Port did not have the RCB bit set. + +e42010d8207f fixed that by setting the RCB in the endpoint only when it was +set in the Root Port. + +In retrospect, program_hpx_type2() is intended for AER-related settings, +and the RCB should be configured elsewhere so it doesn't depend on the +presence or contents of an _HPX record. + +Explicitly program the RCB from pci_configure_device() so it matches the +Root Port's RCB. The Root Port may not be visible to virtualized guests; +in that case, leave RCB alone. + +Fixes: e42010d8207f ("PCI: Set Read Completion Boundary to 128 iff Root Port supports it (_HPX)") +Signed-off-by: HÃ¥kon Bugge +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260129175237.727059-2-haakon.bugge@oracle.com +Signed-off-by: Sasha Levin +--- + drivers/pci/probe.c | 32 ++++++++++++++++++++++++++++++++ + 1 file changed, 32 insertions(+) + +diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c +index 9b277a91d0cb4..e51a5c38739a4 100644 +--- a/drivers/pci/probe.c ++++ b/drivers/pci/probe.c +@@ -2288,6 +2288,37 @@ static void pci_configure_serr(struct pci_dev *dev) + } + } + ++static void pci_configure_rcb(struct pci_dev *dev) ++{ ++ struct pci_dev *rp; ++ u16 rp_lnkctl; ++ ++ /* ++ * Per PCIe r7.0, sec 7.5.3.7, RCB is only meaningful in Root Ports ++ * (where it is read-only), Endpoints, and Bridges. It may only be ++ * set for Endpoints and Bridges if it is set in the Root Port. For ++ * Endpoints, it is 'RsvdP' for Virtual Functions. ++ */ ++ if (!pci_is_pcie(dev) || ++ pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT || ++ pci_pcie_type(dev) == PCI_EXP_TYPE_UPSTREAM || ++ pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM || ++ pci_pcie_type(dev) == PCI_EXP_TYPE_RC_EC || ++ dev->is_virtfn) ++ return; ++ ++ /* Root Port often not visible to virtualized guests */ ++ rp = pcie_find_root_port(dev); ++ if (!rp) ++ return; ++ ++ pcie_capability_read_word(rp, PCI_EXP_LNKCTL, &rp_lnkctl); ++ pcie_capability_clear_and_set_word(dev, PCI_EXP_LNKCTL, ++ PCI_EXP_LNKCTL_RCB, ++ (rp_lnkctl & PCI_EXP_LNKCTL_RCB) ? ++ PCI_EXP_LNKCTL_RCB : 0); ++} ++ + static void pci_configure_device(struct pci_dev *dev) + { + pci_configure_mps(dev); +@@ -2296,6 +2327,7 @@ static void pci_configure_device(struct pci_dev *dev) + pci_configure_ltr(dev); + pci_configure_eetlp_prefix(dev); + pci_configure_serr(dev); ++ pci_configure_rcb(dev); + + pci_acpi_program_hp_params(dev); + } +-- +2.51.0 + diff --git a/queue-6.6/pci-log-bridge-info-when-first-enumerating-bridge.patch b/queue-6.6/pci-log-bridge-info-when-first-enumerating-bridge.patch new file mode 100644 index 0000000000..cfafecd239 --- /dev/null +++ b/queue-6.6/pci-log-bridge-info-when-first-enumerating-bridge.patch @@ -0,0 +1,100 @@ +From 7c30c17b47dc8df80d2863d525dc5dcf21420773 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Nov 2023 10:34:07 -0600 +Subject: PCI: Log bridge info when first enumerating bridge + +From: Bjorn Helgaas + +[ Upstream commit 95140c2fbfdf3b6ca98578e5bdbc82d9922f08b9 ] + +Log bridge secondary/subordinate bus and window information at the same +time we log the bridge BARs, just after discovering the bridge and before +scanning the bridge's secondary bus. This logs the bridge and downstream +devices in a more logical order: + + - pci 0000:00:01.0: [8086:1901] type 01 class 0x060400 + - pci 0000:01:00.0: [10de:13b6] type 00 class 0x030200 + - pci 0000:01:00.0: reg 0x10: [mem 0xec000000-0xecffffff] + - pci 0000:00:01.0: PCI bridge to [bus 01] + - pci 0000:00:01.0: bridge window [io 0xe000-0xefff] + + + pci 0000:00:01.0: [8086:1901] type 01 class 0x060400 + + pci 0000:00:01.0: PCI bridge to [bus 01] + + pci 0000:00:01.0: bridge window [io 0xe000-0xefff] + + pci 0000:01:00.0: [10de:13b6] type 00 class 0x030200 + + pci 0000:01:00.0: reg 0x10: [mem 0xec000000-0xecffffff] + +Note that we read the windows into a temporary struct resource that is +thrown away, not into the resources in the struct pci_bus. + +The windows may be adjusted after we know what downstream devices require, +and those adjustments are logged as they are made. + +Signed-off-by: Bjorn Helgaas +Stable-dep-of: 9abf79c8d7b4 ("PCI/ACPI: Restrict program_hpx_type2() to AER bits") +Signed-off-by: Sasha Levin +--- + drivers/pci/probe.c | 23 +++++++++++++++++++---- + 1 file changed, 19 insertions(+), 4 deletions(-) + +diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c +index f7b01cddf5abf..8a2f1e57bee19 100644 +--- a/drivers/pci/probe.c ++++ b/drivers/pci/probe.c +@@ -458,8 +458,17 @@ static void pci_read_bridge_mmio_pref(struct pci_dev *dev, struct resource *res, + + static void pci_read_bridge_windows(struct pci_dev *bridge) + { ++ u32 buses; + u16 io; + u32 pmem, tmp; ++ struct resource res; ++ ++ pci_read_config_dword(bridge, PCI_PRIMARY_BUS, &buses); ++ res.flags = IORESOURCE_BUS; ++ res.start = (buses >> 8) & 0xff; ++ res.end = (buses >> 16) & 0xff; ++ pci_info(bridge, "PCI bridge to %pR%s\n", &res, ++ bridge->transparent ? " (subtractive decode)" : ""); + + pci_read_config_word(bridge, PCI_IO_BASE, &io); + if (!io) { +@@ -467,8 +476,12 @@ static void pci_read_bridge_windows(struct pci_dev *bridge) + pci_read_config_word(bridge, PCI_IO_BASE, &io); + pci_write_config_word(bridge, PCI_IO_BASE, 0x0); + } +- if (io) ++ if (io) { + bridge->io_window = 1; ++ pci_read_bridge_io(bridge, &res, true); ++ } ++ ++ pci_read_bridge_mmio(bridge, &res, true); + + /* + * DECchip 21050 pass 2 errata: the bridge may miss an address +@@ -505,6 +518,8 @@ static void pci_read_bridge_windows(struct pci_dev *bridge) + if (tmp) + bridge->pref_64_window = 1; + } ++ ++ pci_read_bridge_mmio_pref(bridge, &res, true); + } + + void pci_read_bridge_bases(struct pci_bus *child) +@@ -524,9 +539,9 @@ void pci_read_bridge_bases(struct pci_bus *child) + for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++) + child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i]; + +- pci_read_bridge_io(child->self, child->resource[0], true); +- pci_read_bridge_mmio(child->self, child->resource[1], true); +- pci_read_bridge_mmio_pref(child->self, child->resource[2], true); ++ pci_read_bridge_io(child->self, child->resource[0], false); ++ pci_read_bridge_mmio(child->self, child->resource[1], false); ++ pci_read_bridge_mmio_pref(child->self, child->resource[2], false); + + if (dev->transparent) { + pci_bus_for_each_resource(child->parent, res) { +-- +2.51.0 + diff --git a/queue-6.6/pci-log-bridge-windows-conditionally.patch b/queue-6.6/pci-log-bridge-windows-conditionally.patch new file mode 100644 index 0000000000..af10a67a38 --- /dev/null +++ b/queue-6.6/pci-log-bridge-windows-conditionally.patch @@ -0,0 +1,94 @@ +From 331dc387cb589484f3148412dc3f039b1353c7ea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 4 Dec 2023 17:53:32 -0600 +Subject: PCI: Log bridge windows conditionally + +From: Bjorn Helgaas + +[ Upstream commit 63c6ebb294b7c708cc987d621e59499686650683 ] + +Previously pci_read_bridge_io(), pci_read_bridge_mmio(), and +pci_read_bridge_mmio_pref() unconditionally logged the bridge window +resource. A future change will call these functions earlier and more +often. Add a "log" parameter so callers can control whether to generate +the log message. No functional change intended. + +Signed-off-by: Bjorn Helgaas +Stable-dep-of: 9abf79c8d7b4 ("PCI/ACPI: Restrict program_hpx_type2() to AER bits") +Signed-off-by: Sasha Levin +--- + drivers/pci/probe.c | 24 +++++++++++++++--------- + 1 file changed, 15 insertions(+), 9 deletions(-) + +diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c +index a91ac2faf9a90..f7b01cddf5abf 100644 +--- a/drivers/pci/probe.c ++++ b/drivers/pci/probe.c +@@ -344,7 +344,8 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) + } + } + +-static void pci_read_bridge_io(struct pci_dev *dev, struct resource *res) ++static void pci_read_bridge_io(struct pci_dev *dev, struct resource *res, ++ bool log) + { + u8 io_base_lo, io_limit_lo; + unsigned long io_mask, io_granularity, base, limit; +@@ -377,11 +378,13 @@ static void pci_read_bridge_io(struct pci_dev *dev, struct resource *res) + region.start = base; + region.end = limit + io_granularity - 1; + pcibios_bus_to_resource(dev->bus, res, ®ion); +- pci_info(dev, " bridge window %pR\n", res); ++ if (log) ++ pci_info(dev, " bridge window %pR\n", res); + } + } + +-static void pci_read_bridge_mmio(struct pci_dev *dev, struct resource *res) ++static void pci_read_bridge_mmio(struct pci_dev *dev, struct resource *res, ++ bool log) + { + u16 mem_base_lo, mem_limit_lo; + unsigned long base, limit; +@@ -396,11 +399,13 @@ static void pci_read_bridge_mmio(struct pci_dev *dev, struct resource *res) + region.start = base; + region.end = limit + 0xfffff; + pcibios_bus_to_resource(dev->bus, res, ®ion); +- pci_info(dev, " bridge window %pR\n", res); ++ if (log) ++ pci_info(dev, " bridge window %pR\n", res); + } + } + +-static void pci_read_bridge_mmio_pref(struct pci_dev *dev, struct resource *res) ++static void pci_read_bridge_mmio_pref(struct pci_dev *dev, struct resource *res, ++ bool log) + { + u16 mem_base_lo, mem_limit_lo; + u64 base64, limit64; +@@ -446,7 +451,8 @@ static void pci_read_bridge_mmio_pref(struct pci_dev *dev, struct resource *res) + region.start = base; + region.end = limit + 0xfffff; + pcibios_bus_to_resource(dev->bus, res, ®ion); +- pci_info(dev, " bridge window %pR\n", res); ++ if (log) ++ pci_info(dev, " bridge window %pR\n", res); + } + } + +@@ -518,9 +524,9 @@ void pci_read_bridge_bases(struct pci_bus *child) + for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++) + child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i]; + +- pci_read_bridge_io(child->self, child->resource[0]); +- pci_read_bridge_mmio(child->self, child->resource[1]); +- pci_read_bridge_mmio_pref(child->self, child->resource[2]); ++ pci_read_bridge_io(child->self, child->resource[0], true); ++ pci_read_bridge_mmio(child->self, child->resource[1], true); ++ pci_read_bridge_mmio_pref(child->self, child->resource[2], true); + + if (dev->transparent) { + pci_bus_for_each_resource(child->parent, res) { +-- +2.51.0 + diff --git a/queue-6.6/pci-mark-3ware-9650sa-root-port-extended-tags-as-bro.patch b/queue-6.6/pci-mark-3ware-9650sa-root-port-extended-tags-as-bro.patch new file mode 100644 index 0000000000..146e7d3392 --- /dev/null +++ b/queue-6.6/pci-mark-3ware-9650sa-root-port-extended-tags-as-bro.patch @@ -0,0 +1,56 @@ +From 303420153bd60a0973d65d8084887af6ff1b314e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 15:31:10 +0100 +Subject: PCI: Mark 3ware-9650SA Root Port Extended Tags as broken +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jörg Wedekind + +[ Upstream commit 959ac08a2c2811305be8c2779779e8b0932e5a99 ] + +Per PCIe r7.0, sec 2.2.6.2.1 and 7.5.3.4, a Requester may not use 8-bit Tags +unless its Extended Tag Field Enable is set, but all Receivers/Completers +must handle 8-bit Tags correctly regardless of their Extended Tag Field +Enable. + +Some devices do not handle 8-bit Tags as Completers, so add a quirk for +them. If we find such a device, we disable Extended Tags for the entire +hierarchy to make peer-to-peer DMA possible. + +The 3ware 9650SA seems to have issues with handling 8-bit tags. Mark it as +broken. + +This fixes PCI Parity Errors like : + + 3w-9xxx: scsi0: ERROR: (0x06:0x000C): PCI Parity Error: clearing. + 3w-9xxx: scsi0: ERROR: (0x06:0x000D): PCI Abort: clearing. + 3w-9xxx: scsi0: ERROR: (0x06:0x000E): Controller Queue Error: clearing. + 3w-9xxx: scsi0: ERROR: (0x06:0x0010): Microcontroller Error: clearing. + +Fixes: 60db3a4d8cc9 ("PCI: Enable PCIe Extended Tags if supported") +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=202425 +Signed-off-by: Jörg Wedekind +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260119143114.21948-1-joerg@wedekind.de +Signed-off-by: Sasha Levin +--- + drivers/pci/quirks.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index 30a5f809ee798..cac9a163d7d55 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -5573,6 +5573,7 @@ static void quirk_no_ext_tags(struct pci_dev *pdev) + pci_walk_bus(bridge->bus, pci_configure_extended_tags, NULL); + } + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_3WARE, 0x1004, quirk_no_ext_tags); ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_3WARE, 0x1005, quirk_no_ext_tags); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0132, quirk_no_ext_tags); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0140, quirk_no_ext_tags); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0141, quirk_no_ext_tags); +-- +2.51.0 + diff --git a/queue-6.6/pci-mediatek-fix-irq-domain-leak-when-msi-allocation.patch b/queue-6.6/pci-mediatek-fix-irq-domain-leak-when-msi-allocation.patch new file mode 100644 index 0000000000..206ec47245 --- /dev/null +++ b/queue-6.6/pci-mediatek-fix-irq-domain-leak-when-msi-allocation.patch @@ -0,0 +1,45 @@ +From 8f68243cd07b4e775a0a1a01df29b83acd268c21 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 19 Nov 2025 10:33:08 +0800 +Subject: PCI: mediatek: Fix IRQ domain leak when MSI allocation fails + +From: Haotian Zhang + +[ Upstream commit 7f0cdcddf8bef1c8c18f9be6708073fd3790a20f ] + +In mtk_pcie_init_irq_domain(), if mtk_pcie_allocate_msi_domains() +fails after port->irq_domain has been successfully created via +irq_domain_create_linear(), the function returns directly without +cleaning up the allocated IRQ domain, resulting in a resource leak. + +Add irq_domain_remove() call in the error path to properly release the +INTx IRQ domain before returning the error. + +Fixes: 43e6409db64d ("PCI: mediatek: Add MSI support for MT2712 and MT7622") +Signed-off-by: Haotian Zhang +Signed-off-by: Manivannan Sadhasivam +Link: https://patch.msgid.link/20251119023308.476-1-vulab@iscas.ac.cn +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/pcie-mediatek.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c +index 48372013f26d2..82e575e4d3877 100644 +--- a/drivers/pci/controller/pcie-mediatek.c ++++ b/drivers/pci/controller/pcie-mediatek.c +@@ -587,8 +587,10 @@ static int mtk_pcie_init_irq_domain(struct mtk_pcie_port *port, + + if (IS_ENABLED(CONFIG_PCI_MSI)) { + ret = mtk_pcie_allocate_msi_domains(port); +- if (ret) ++ if (ret) { ++ irq_domain_remove(port->irq_domain); + return ret; ++ } + } + + return 0; +-- +2.51.0 + diff --git a/queue-6.6/pci-move-pci_read_bridge_windows-below-individual-wi.patch b/queue-6.6/pci-move-pci_read_bridge_windows-below-individual-wi.patch new file mode 100644 index 0000000000..fe1c944cd5 --- /dev/null +++ b/queue-6.6/pci-move-pci_read_bridge_windows-below-individual-wi.patch @@ -0,0 +1,143 @@ +From c54a99bf803f9d73038f92f89eefc449eaca2044 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 4 Dec 2023 17:39:15 -0600 +Subject: PCI: Move pci_read_bridge_windows() below individual window accessors + +From: Bjorn Helgaas + +[ Upstream commit 6f32099a91720b6d91da961858d48173f01a729d ] + +Move pci_read_bridge_windows() below the functions that read the I/O, +memory, and prefetchable memory windows, so pci_read_bridge_windows() can +use them in the future. No functional change intended. + +Signed-off-by: Bjorn Helgaas +Stable-dep-of: 9abf79c8d7b4 ("PCI/ACPI: Restrict program_hpx_type2() to AER bits") +Signed-off-by: Sasha Levin +--- + drivers/pci/probe.c | 102 ++++++++++++++++++++++---------------------- + 1 file changed, 51 insertions(+), 51 deletions(-) + +diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c +index e51a5c38739a4..a43f9e9352e47 100644 +--- a/drivers/pci/probe.c ++++ b/drivers/pci/probe.c +@@ -344,57 +344,6 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) + } + } + +-static void pci_read_bridge_windows(struct pci_dev *bridge) +-{ +- u16 io; +- u32 pmem, tmp; +- +- pci_read_config_word(bridge, PCI_IO_BASE, &io); +- if (!io) { +- pci_write_config_word(bridge, PCI_IO_BASE, 0xe0f0); +- pci_read_config_word(bridge, PCI_IO_BASE, &io); +- pci_write_config_word(bridge, PCI_IO_BASE, 0x0); +- } +- if (io) +- bridge->io_window = 1; +- +- /* +- * DECchip 21050 pass 2 errata: the bridge may miss an address +- * disconnect boundary by one PCI data phase. Workaround: do not +- * use prefetching on this device. +- */ +- if (bridge->vendor == PCI_VENDOR_ID_DEC && bridge->device == 0x0001) +- return; +- +- pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem); +- if (!pmem) { +- pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, +- 0xffe0fff0); +- pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem); +- pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, 0x0); +- } +- if (!pmem) +- return; +- +- bridge->pref_window = 1; +- +- if ((pmem & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) { +- +- /* +- * Bridge claims to have a 64-bit prefetchable memory +- * window; verify that the upper bits are actually +- * writable. +- */ +- pci_read_config_dword(bridge, PCI_PREF_BASE_UPPER32, &pmem); +- pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, +- 0xffffffff); +- pci_read_config_dword(bridge, PCI_PREF_BASE_UPPER32, &tmp); +- pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, pmem); +- if (tmp) +- bridge->pref_64_window = 1; +- } +-} +- + static void pci_read_bridge_io(struct pci_bus *child) + { + struct pci_dev *dev = child->self; +@@ -510,6 +459,57 @@ static void pci_read_bridge_mmio_pref(struct pci_bus *child) + } + } + ++static void pci_read_bridge_windows(struct pci_dev *bridge) ++{ ++ u16 io; ++ u32 pmem, tmp; ++ ++ pci_read_config_word(bridge, PCI_IO_BASE, &io); ++ if (!io) { ++ pci_write_config_word(bridge, PCI_IO_BASE, 0xe0f0); ++ pci_read_config_word(bridge, PCI_IO_BASE, &io); ++ pci_write_config_word(bridge, PCI_IO_BASE, 0x0); ++ } ++ if (io) ++ bridge->io_window = 1; ++ ++ /* ++ * DECchip 21050 pass 2 errata: the bridge may miss an address ++ * disconnect boundary by one PCI data phase. Workaround: do not ++ * use prefetching on this device. ++ */ ++ if (bridge->vendor == PCI_VENDOR_ID_DEC && bridge->device == 0x0001) ++ return; ++ ++ pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem); ++ if (!pmem) { ++ pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, ++ 0xffe0fff0); ++ pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem); ++ pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, 0x0); ++ } ++ if (!pmem) ++ return; ++ ++ bridge->pref_window = 1; ++ ++ if ((pmem & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) { ++ ++ /* ++ * Bridge claims to have a 64-bit prefetchable memory ++ * window; verify that the upper bits are actually ++ * writable. ++ */ ++ pci_read_config_dword(bridge, PCI_PREF_BASE_UPPER32, &pmem); ++ pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, ++ 0xffffffff); ++ pci_read_config_dword(bridge, PCI_PREF_BASE_UPPER32, &tmp); ++ pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, pmem); ++ if (tmp) ++ bridge->pref_64_window = 1; ++ } ++} ++ + void pci_read_bridge_bases(struct pci_bus *child) + { + struct pci_dev *dev = child->self; +-- +2.51.0 + diff --git a/queue-6.6/pci-p2pdma-release-per-cpu-pgmap-ref-when-vm_insert_.patch b/queue-6.6/pci-p2pdma-release-per-cpu-pgmap-ref-when-vm_insert_.patch new file mode 100644 index 0000000000..0fdf4748b2 --- /dev/null +++ b/queue-6.6/pci-p2pdma-release-per-cpu-pgmap-ref-when-vm_insert_.patch @@ -0,0 +1,42 @@ +From c4c14ec88cbc9f89a5b4ba2929ea3df2735716a8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 12:04:34 +0800 +Subject: PCI/P2PDMA: Release per-CPU pgmap ref when vm_insert_page() fails + +From: Hou Tao + +[ Upstream commit 6220694c52a5a04102b48109e4f24e958b559bd3 ] + +When vm_insert_page() fails in p2pmem_alloc_mmap(), p2pmem_alloc_mmap() +doesn't invoke percpu_ref_put() to free the per-CPU ref of pgmap acquired +after gen_pool_alloc_owner(), and memunmap_pages() will hang forever when +trying to remove the PCI device. + +Fix it by adding the missed percpu_ref_put(). + +Fixes: 7e9c7ef83d78 ("PCI/P2PDMA: Allow userspace VMA allocations through sysfs") +Signed-off-by: Hou Tao +Signed-off-by: Bjorn Helgaas +Reviewed-by: Logan Gunthorpe +Reviewed-by: Alistair Popple +Link: https://patch.msgid.link/20251220040446.274991-2-houtao@huaweicloud.com +Signed-off-by: Sasha Levin +--- + drivers/pci/p2pdma.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c +index 0f1e431bbfc20..f97ac18a8dc8f 100644 +--- a/drivers/pci/p2pdma.c ++++ b/drivers/pci/p2pdma.c +@@ -143,6 +143,7 @@ static int p2pmem_alloc_mmap(struct file *filp, struct kobject *kobj, + ret = vm_insert_page(vma, vaddr, virt_to_page(kaddr)); + if (ret) { + gen_pool_free(p2pdma->pool, (uintptr_t)kaddr, len); ++ percpu_ref_put(ref); + return ret; + } + percpu_ref_get(ref); +-- +2.51.0 + diff --git a/queue-6.6/pci-pm-avoid-redundant-delays-on-d3hot-d3cold.patch b/queue-6.6/pci-pm-avoid-redundant-delays-on-d3hot-d3cold.patch new file mode 100644 index 0000000000..7b67846ae5 --- /dev/null +++ b/queue-6.6/pci-pm-avoid-redundant-delays-on-d3hot-d3cold.patch @@ -0,0 +1,56 @@ +From 5fa73137d6d799f755b71bf78574a7ea6678fef8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Oct 2025 15:40:09 -0700 +Subject: PCI/PM: Avoid redundant delays on D3hot->D3cold + +From: Brian Norris + +[ Upstream commit 4d982084507d663df160546c4c48066a8887ed89 ] + +When transitioning to D3cold, __pci_set_power_state() first transitions to +D3hot. If the device was already in D3hot, this adds excess work: + + (a) read/modify/write PMCSR; and + (b) excess delay (pci_dev_d3_sleep()). + +For (b), we already performed the necessary delay on the previous D3hot +entry; this was extra noticeable when evaluating runtime PM transition +latency. + +Check whether we're already in the target state before continuing. + +Note that __pci_set_power_state() already does this same check for other +state transitions, but D3cold is special because __pci_set_power_state() +converts it to D3hot for the purposes of PMCSR. + +This seems to be an oversight in commit 0aacdc957401 ("PCI/PM: Clean up +pci_set_low_power_state()"). + +Fixes: 0aacdc957401 ("PCI/PM: Clean up pci_set_low_power_state()") +Signed-off-by: Brian Norris +Signed-off-by: Brian Norris +[bhelgaas: reverse test to match other "dev->current_state == state" cases] +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20251003154008.1.I7a21c240b30062c66471329567a96dceb6274358@changeid +Signed-off-by: Sasha Levin +--- + drivers/pci/pci.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c +index 9a3f6bb60eb4d..2f6c5bf2ae2f5 100644 +--- a/drivers/pci/pci.c ++++ b/drivers/pci/pci.c +@@ -1427,6 +1427,9 @@ static int pci_set_low_power_state(struct pci_dev *dev, pci_power_t state, bool + || (state == PCI_D2 && !dev->d2_support)) + return -EIO; + ++ if (dev->current_state == state) ++ return 0; ++ + pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr); + if (PCI_POSSIBLE_ERROR(pmcsr)) { + pci_err(dev, "Unable to change power state from %s to %s, device inaccessible\n", +-- +2.51.0 + diff --git a/queue-6.6/pci-portdrv-fix-potential-resource-leak.patch b/queue-6.6/pci-portdrv-fix-potential-resource-leak.patch new file mode 100644 index 0000000000..4c2e38d960 --- /dev/null +++ b/queue-6.6/pci-portdrv-fix-potential-resource-leak.patch @@ -0,0 +1,48 @@ +From ddbe89a83a9c5277a5ce4e89be0831b5921379c1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Dec 2025 16:13:49 +0100 +Subject: PCI/portdrv: Fix potential resource leak +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Uwe Kleine-König + +[ Upstream commit 01464a3fdf91c041a381d93a1b6fefbdb819a46f ] + +pcie_port_probe_service() unconditionally calls get_device() (unless it +fails). So drop that reference also unconditionally as it's fine for a +PCIe driver to not have a remove callback. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Uwe Kleine-König +Signed-off-by: Bjorn Helgaas +Reviewed-by: Ilpo Järvinen +Reviewed-by: Jonathan Cameron +Link: https://patch.msgid.link/e1c68c3b3f1af8427e98ca5e2c79f8bf0ebe2ce4.1764688034.git.u.kleine-koenig@baylibre.com +Signed-off-by: Sasha Levin +--- + drivers/pci/pcie/portdrv.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/pci/pcie/portdrv.c b/drivers/pci/pcie/portdrv.c +index d6e5fef54c3b8..dac3ba1b2552f 100644 +--- a/drivers/pci/pcie/portdrv.c ++++ b/drivers/pci/pcie/portdrv.c +@@ -554,10 +554,10 @@ static int pcie_port_remove_service(struct device *dev) + + pciedev = to_pcie_device(dev); + driver = to_service_driver(dev->driver); +- if (driver && driver->remove) { ++ if (driver && driver->remove) + driver->remove(pciedev); +- put_device(dev); +- } ++ ++ put_device(dev); + return 0; + } + +-- +2.51.0 + diff --git a/queue-6.6/pci-supply-bridge-device-not-secondary-bus-to-read-w.patch b/queue-6.6/pci-supply-bridge-device-not-secondary-bus-to-read-w.patch new file mode 100644 index 0000000000..f6bf17047f --- /dev/null +++ b/queue-6.6/pci-supply-bridge-device-not-secondary-bus-to-read-w.patch @@ -0,0 +1,119 @@ +From f1994ade4a025637bad5ad8a88da89c36ba96619 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Nov 2023 10:13:03 -0600 +Subject: PCI: Supply bridge device, not secondary bus, to read window details + +From: Bjorn Helgaas + +[ Upstream commit 281e1f137a97dae4fe47a7d30635c5b83def790b ] + +Previously we logged information about devices *below* the bridge before +logging information about the bridge itself, e.g., + + pci 0000:00:01.0: [8086:1901] type 01 class 0x060400 + pci 0000:01:00.0: [10de:13b6] type 00 class 0x030200 + pci 0000:01:00.0: reg 0x10: [mem 0xec000000-0xecffffff] + pci 0000:00:01.0: PCI bridge to [bus 01] + pci 0000:00:01.0: bridge window [io 0xe000-0xefff] + +This is partly because the bridge windows are read in this path: + + pci_scan_child_bus_extend + for (devfn = 0; devfn < 256; devfn += 8) + pci_scan_slot(bus, devfn) # scan below bridge + pcibios_fixup_bus(bus) + pci_read_bridge_bases(bus) # read bridge windows + pci_read_bridge_io(bus) + +Remove the assumption that the secondary (child) pci_bus already exists by +passing in the bridge device (instead of the pci_bus) and a resource +pointer when reading bridge windows. A future change can use this to log +the bridge details before we enumerate the devices below the bridge. + +No functional change intended. + +Signed-off-by: Bjorn Helgaas +Stable-dep-of: 9abf79c8d7b4 ("PCI/ACPI: Restrict program_hpx_type2() to AER bits") +Signed-off-by: Sasha Levin +--- + drivers/pci/probe.c | 21 ++++++--------------- + 1 file changed, 6 insertions(+), 15 deletions(-) + +diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c +index a43f9e9352e47..a91ac2faf9a90 100644 +--- a/drivers/pci/probe.c ++++ b/drivers/pci/probe.c +@@ -344,13 +344,11 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) + } + } + +-static void pci_read_bridge_io(struct pci_bus *child) ++static void pci_read_bridge_io(struct pci_dev *dev, struct resource *res) + { +- struct pci_dev *dev = child->self; + u8 io_base_lo, io_limit_lo; + unsigned long io_mask, io_granularity, base, limit; + struct pci_bus_region region; +- struct resource *res; + + io_mask = PCI_IO_RANGE_MASK; + io_granularity = 0x1000; +@@ -360,7 +358,6 @@ static void pci_read_bridge_io(struct pci_bus *child) + io_granularity = 0x400; + } + +- res = child->resource[0]; + pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo); + pci_read_config_byte(dev, PCI_IO_LIMIT, &io_limit_lo); + base = (io_base_lo & io_mask) << 8; +@@ -384,15 +381,12 @@ static void pci_read_bridge_io(struct pci_bus *child) + } + } + +-static void pci_read_bridge_mmio(struct pci_bus *child) ++static void pci_read_bridge_mmio(struct pci_dev *dev, struct resource *res) + { +- struct pci_dev *dev = child->self; + u16 mem_base_lo, mem_limit_lo; + unsigned long base, limit; + struct pci_bus_region region; +- struct resource *res; + +- res = child->resource[1]; + pci_read_config_word(dev, PCI_MEMORY_BASE, &mem_base_lo); + pci_read_config_word(dev, PCI_MEMORY_LIMIT, &mem_limit_lo); + base = ((unsigned long) mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16; +@@ -406,16 +400,13 @@ static void pci_read_bridge_mmio(struct pci_bus *child) + } + } + +-static void pci_read_bridge_mmio_pref(struct pci_bus *child) ++static void pci_read_bridge_mmio_pref(struct pci_dev *dev, struct resource *res) + { +- struct pci_dev *dev = child->self; + u16 mem_base_lo, mem_limit_lo; + u64 base64, limit64; + pci_bus_addr_t base, limit; + struct pci_bus_region region; +- struct resource *res; + +- res = child->resource[2]; + pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo); + pci_read_config_word(dev, PCI_PREF_MEMORY_LIMIT, &mem_limit_lo); + base64 = (mem_base_lo & PCI_PREF_RANGE_MASK) << 16; +@@ -527,9 +518,9 @@ void pci_read_bridge_bases(struct pci_bus *child) + for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++) + child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i]; + +- pci_read_bridge_io(child); +- pci_read_bridge_mmio(child); +- pci_read_bridge_mmio_pref(child); ++ pci_read_bridge_io(child->self, child->resource[0]); ++ pci_read_bridge_mmio(child->self, child->resource[1]); ++ pci_read_bridge_mmio_pref(child->self, child->resource[2]); + + if (dev->transparent) { + pci_bus_for_each_resource(child->parent, res) { +-- +2.51.0 + diff --git a/queue-6.6/perf-arm_spe-properly-set-hw.state-on-failures.patch b/queue-6.6/perf-arm_spe-properly-set-hw.state-on-failures.patch new file mode 100644 index 0000000000..f5f2049e78 --- /dev/null +++ b/queue-6.6/perf-arm_spe-properly-set-hw.state-on-failures.patch @@ -0,0 +1,108 @@ +From 06fa4780eae47471e0ebc2ed1c15788217714ee7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 14:40:43 +0000 +Subject: perf: arm_spe: Properly set hw.state on failures + +From: Leo Yan + +[ Upstream commit 283182c1c239f6873d1a50e9e710c1a699f2256b ] + +When arm_spe_pmu_next_off() fails to calculate a valid limit, it returns +zero to indicate that tracing should not start. However, the caller +arm_spe_perf_aux_output_begin() does not propagate this failure by +updating hwc->state, cause the error to be silently ignored by upper +layers. + +Because hwc->state remains zero after a failure, arm_spe_pmu_start() +continues to programs filter registers unnecessarily. The driver +still reports success to the perf core, so the core assumes the SPE +event was enabled and proceeds to enable other events. This breaks +event group semantics: SPE is already stopped while other events in the +same group are enabled. + +Fix this by updating arm_spe_perf_aux_output_begin() to return a status +code indicating success (0) or failure (-EIO). Both the interrupt +handler and arm_spe_pmu_start() check the return value and call +arm_spe_pmu_stop() to set PERF_HES_STOPPED in hwc->state. + +In the interrupt handler, the period (e.g., period_left) needs to be +updated, so PERF_EF_UPDATE is passed to arm_spe_pmu_stop(). When the +error occurs during event start, the trace unit is not yet enabled, so +a flag '0' is used to drain buffer and update state only. + +Fixes: d5d9696b0380 ("drivers/perf: Add support for ARMv8.2 Statistical Profiling Extension") +Signed-off-by: Leo Yan +Signed-off-by: Will Deacon +Signed-off-by: Sasha Levin +--- + drivers/perf/arm_spe_pmu.c | 18 ++++++++++++------ + 1 file changed, 12 insertions(+), 6 deletions(-) + +diff --git a/drivers/perf/arm_spe_pmu.c b/drivers/perf/arm_spe_pmu.c +index affa78376b6a8..5164078c06d25 100644 +--- a/drivers/perf/arm_spe_pmu.c ++++ b/drivers/perf/arm_spe_pmu.c +@@ -102,6 +102,8 @@ struct arm_spe_pmu { + /* Keep track of our dynamic hotplug state */ + static enum cpuhp_state arm_spe_pmu_online; + ++static void arm_spe_pmu_stop(struct perf_event *event, int flags); ++ + enum arm_spe_pmu_buf_fault_action { + SPE_PMU_BUF_FAULT_ACT_SPURIOUS, + SPE_PMU_BUF_FAULT_ACT_FATAL, +@@ -519,8 +521,8 @@ static u64 arm_spe_pmu_next_off(struct perf_output_handle *handle) + return limit; + } + +-static void arm_spe_perf_aux_output_begin(struct perf_output_handle *handle, +- struct perf_event *event) ++static int arm_spe_perf_aux_output_begin(struct perf_output_handle *handle, ++ struct perf_event *event) + { + u64 base, limit; + struct arm_spe_pmu_buf *buf; +@@ -528,7 +530,6 @@ static void arm_spe_perf_aux_output_begin(struct perf_output_handle *handle, + /* Start a new aux session */ + buf = perf_aux_output_begin(handle, event); + if (!buf) { +- event->hw.state |= PERF_HES_STOPPED; + /* + * We still need to clear the limit pointer, since the + * profiler might only be disabled by virtue of a fault. +@@ -548,6 +549,7 @@ static void arm_spe_perf_aux_output_begin(struct perf_output_handle *handle, + + out_write_limit: + write_sysreg_s(limit, SYS_PMBLIMITR_EL1); ++ return (limit & PMBLIMITR_EL1_E) ? 0 : -EIO; + } + + static void arm_spe_perf_aux_output_end(struct perf_output_handle *handle) +@@ -687,7 +689,10 @@ static irqreturn_t arm_spe_pmu_irq_handler(int irq, void *dev) + * when we get to it. + */ + if (!(handle->aux_flags & PERF_AUX_FLAG_TRUNCATED)) { +- arm_spe_perf_aux_output_begin(handle, event); ++ if (arm_spe_perf_aux_output_begin(handle, event)) { ++ arm_spe_pmu_stop(event, PERF_EF_UPDATE); ++ break; ++ } + isb(); + } + break; +@@ -782,9 +787,10 @@ static void arm_spe_pmu_start(struct perf_event *event, int flags) + struct perf_output_handle *handle = this_cpu_ptr(spe_pmu->handle); + + hwc->state = 0; +- arm_spe_perf_aux_output_begin(handle, event); +- if (hwc->state) ++ if (arm_spe_perf_aux_output_begin(handle, event)) { ++ arm_spe_pmu_stop(event, 0); + return; ++ } + + reg = arm_spe_event_to_pmsfcr(event); + write_sysreg_s(reg, SYS_PMSFCR_EL1); +-- +2.51.0 + diff --git a/queue-6.6/pinctrl-equilibrium-fix-device-node-reference-leak-i.patch b/queue-6.6/pinctrl-equilibrium-fix-device-node-reference-leak-i.patch new file mode 100644 index 0000000000..818603c3eb --- /dev/null +++ b/queue-6.6/pinctrl-equilibrium-fix-device-node-reference-leak-i.patch @@ -0,0 +1,44 @@ +From cffdc5f93b914df32ec82b1bdb078faab5acb7f7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 01:30:07 +0800 +Subject: pinctrl: equilibrium: Fix device node reference leak in + pinbank_init() + +From: Felix Gu + +[ Upstream commit c0b4a4feeb43305a754893d8d9c6b2b5a52d45ac ] + +When calling of_parse_phandle_with_fixed_args(), the caller is +responsible to call of_node_put() to release the reference of device +node. + +In pinbank_init(), the reference of the node obtained from the +"gpio-ranges" property is never released, resulting in a reference +count leak. + +Add the missing of_node_put() call to fix the leak. + +Fixes: 1948d5c51dba ("pinctrl: Add pinmux & GPIO controller driver for a new SoC") +Signed-off-by: Felix Gu +Acked-by: Andy Shevchenko +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-equilibrium.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/pinctrl/pinctrl-equilibrium.c b/drivers/pinctrl/pinctrl-equilibrium.c +index 5b5ddf7e5d0eb..d7c89c310b373 100644 +--- a/drivers/pinctrl/pinctrl-equilibrium.c ++++ b/drivers/pinctrl/pinctrl-equilibrium.c +@@ -850,6 +850,7 @@ static int pinbank_init(struct device_node *np, + + bank->pin_base = spec.args[1]; + bank->nr_pins = spec.args[2]; ++ of_node_put(spec.np); + + bank->aval_pinmap = readl(bank->membase + REG_AVAIL); + bank->id = id; +-- +2.51.0 + diff --git a/queue-6.6/pinctrl-qcom-sm8250-lpass-lpi-fix-i2s2_data_groups-d.patch b/queue-6.6/pinctrl-qcom-sm8250-lpass-lpi-fix-i2s2_data_groups-d.patch new file mode 100644 index 0000000000..eca7e54a11 --- /dev/null +++ b/queue-6.6/pinctrl-qcom-sm8250-lpass-lpi-fix-i2s2_data_groups-d.patch @@ -0,0 +1,38 @@ +From 5f76a63a12a1d08afc568f117a3c96bfe94363cb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 12:22:28 +0100 +Subject: pinctrl: qcom: sm8250-lpass-lpi: Fix i2s2_data_groups definition + +From: Luca Weiss + +[ Upstream commit eabf273c8466af3f033473c2d2267a6ea7946d57 ] + +The i2s2_data function is available on both gpio12 and gpio13. Fix the +groups definition. + +Fixes: 6e261d1090d6 ("pinctrl: qcom: Add sm8250 lpass lpi pinctrl driver") +Signed-off-by: Luca Weiss +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c +index ddbc6317f2a74..422ef44b86423 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c ++++ b/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c +@@ -88,7 +88,7 @@ static const char * const i2s1_ws_groups[] = { "gpio7" }; + static const char * const i2s1_data_groups[] = { "gpio8", "gpio9" }; + static const char * const wsa_swr_clk_groups[] = { "gpio10" }; + static const char * const wsa_swr_data_groups[] = { "gpio11" }; +-static const char * const i2s2_data_groups[] = { "gpio12", "gpio12" }; ++static const char * const i2s2_data_groups[] = { "gpio12", "gpio13" }; + + static const struct lpi_pingroup sm8250_groups[] = { + LPI_PINGROUP(0, 0, swr_tx_clk, qua_mi2s_sclk, _, _), +-- +2.51.0 + diff --git a/queue-6.6/pinctrl-single-fix-refcount-leak-in-pcs_add_gpio_fun.patch b/queue-6.6/pinctrl-single-fix-refcount-leak-in-pcs_add_gpio_fun.patch new file mode 100644 index 0000000000..bb2228c9b5 --- /dev/null +++ b/queue-6.6/pinctrl-single-fix-refcount-leak-in-pcs_add_gpio_fun.patch @@ -0,0 +1,50 @@ +From 22d1fa0543d476189213a4068c31ae50a2f67dbe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 08:07:35 +0000 +Subject: pinctrl: single: fix refcount leak in pcs_add_gpio_func() + +From: Wei Li + +[ Upstream commit 353353309b0f7afa407df29e455f9d15b5acc296 ] + +of_parse_phandle_with_args() returns a device_node pointer with refcount +incremented in gpiospec.np. The loop iterates through all phandles but +never releases the reference, causing a refcount leak on each iteration. + +Add of_node_put() calls to release the reference after extracting the +needed arguments and on the error path when devm_kzalloc() fails. + +This bug was detected by our static analysis tool and verified by my +code review. + +Fixes: a1a277eb76b3 ("pinctrl: single: create new gpio function range") +Signed-off-by: Wei Li +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-single.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c +index 2ee0ee3b6ed14..4aadafe2c50a5 100644 +--- a/drivers/pinctrl/pinctrl-single.c ++++ b/drivers/pinctrl/pinctrl-single.c +@@ -1363,6 +1363,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) + } + range = devm_kzalloc(pcs->dev, sizeof(*range), GFP_KERNEL); + if (!range) { ++ of_node_put(gpiospec.np); + ret = -ENOMEM; + break; + } +@@ -1372,6 +1373,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) + mutex_lock(&pcs->mutex); + list_add_tail(&range->node, &pcs->gpiofuncs); + mutex_unlock(&pcs->mutex); ++ of_node_put(gpiospec.np); + } + return ret; + } +-- +2.51.0 + diff --git a/queue-6.6/platform-chrome-cros_ec_lightbar-fix-response-size-i.patch b/queue-6.6/platform-chrome-cros_ec_lightbar-fix-response-size-i.patch new file mode 100644 index 0000000000..00d3abcca3 --- /dev/null +++ b/queue-6.6/platform-chrome-cros_ec_lightbar-fix-response-size-i.patch @@ -0,0 +1,43 @@ +From 1c2f9b6eeaa2ad7a2115c75a48aaa0d482286509 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 04:03:35 +0000 +Subject: platform/chrome: cros_ec_lightbar: Fix response size initialization + +From: Tzung-Bi Shih + +[ Upstream commit ec0dd36dbf8b0b209e63d0cd795451fa2203c736 ] + +Commit 1e7913ff5f9f ("platform/chrome: cros_ec_lightbar: Reduce +ligthbar get version command") meant to set smaller values for both +request and response sizes. + +However, it incorrectly assigned the response size to the `result` field +instead of `insize`. Fix it. + +Reported-by: Gwendal Grignou +Closes: https://lore.kernel.org/chrome-platform/CAMHSBOVrrYaB=1nEqZk09VkczCrj=6B-P8Fe29TpPdSDgT2CCQ@mail.gmail.com +Fixes: 1e7913ff5f9f ("platform/chrome: cros_ec_lightbar: Reduce ligthbar get version command") +Link: https://lore.kernel.org/r/20260130040335.361997-1-tzungbi@kernel.org +Reviewed-by: Gwendal Grignou +Signed-off-by: Tzung-Bi Shih +Signed-off-by: Sasha Levin +--- + drivers/platform/chrome/cros_ec_lightbar.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/platform/chrome/cros_ec_lightbar.c b/drivers/platform/chrome/cros_ec_lightbar.c +index 376425bbd8ffb..0f185b4b6f655 100644 +--- a/drivers/platform/chrome/cros_ec_lightbar.c ++++ b/drivers/platform/chrome/cros_ec_lightbar.c +@@ -118,7 +118,7 @@ static int get_lightbar_version(struct cros_ec_dev *ec, + param = (struct ec_params_lightbar *)msg->data; + param->cmd = LIGHTBAR_CMD_VERSION; + msg->outsize = sizeof(param->cmd); +- msg->result = sizeof(resp->version); ++ msg->insize = sizeof(resp->version); + ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg); + if (ret < 0 && ret != -EINVAL) { + ret = 0; +-- +2.51.0 + diff --git a/queue-6.6/platform-chrome-cros_typec_switch-don-t-touch-struct.patch b/queue-6.6/platform-chrome-cros_typec_switch-don-t-touch-struct.patch new file mode 100644 index 0000000000..2f55e97501 --- /dev/null +++ b/queue-6.6/platform-chrome-cros_typec_switch-don-t-touch-struct.patch @@ -0,0 +1,54 @@ +From 893f83f0f2b07d7f479244c2bad564e939b1fd65 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 14:12:30 +0100 +Subject: platform/chrome: cros_typec_switch: Don't touch struct + fwnode_handle::dev + +From: Andy Shevchenko + +[ Upstream commit e1adf48853bc715f4deea074932aa1c44eb7abea ] + +The 'dev' field in struct fwnode is special and related to device links, +There no driver should use it for printing messages. Fix incorrect use +of private field. + +Fixes: affc804c44c8 ("platform/chrome: cros_typec_switch: Add switch driver") +Signed-off-by: Andy Shevchenko +Link: https://lore.kernel.org/r/20260120131413.1697891-2-andriy.shevchenko@linux.intel.com +Signed-off-by: Tzung-Bi Shih +Signed-off-by: Sasha Levin +--- + drivers/platform/chrome/cros_typec_switch.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/platform/chrome/cros_typec_switch.c b/drivers/platform/chrome/cros_typec_switch.c +index 0eefdcf14d63f..28080f48315dc 100644 +--- a/drivers/platform/chrome/cros_typec_switch.c ++++ b/drivers/platform/chrome/cros_typec_switch.c +@@ -230,20 +230,20 @@ static int cros_typec_register_switches(struct cros_typec_switch_data *sdata) + + adev = to_acpi_device_node(fwnode); + if (!adev) { +- dev_err(fwnode->dev, "Couldn't get ACPI device handle\n"); ++ dev_err(dev, "Couldn't get ACPI device handle for %pfwP\n", fwnode); + ret = -ENODEV; + goto err_switch; + } + + ret = acpi_evaluate_integer(adev->handle, "_ADR", NULL, &index); + if (ACPI_FAILURE(ret)) { +- dev_err(fwnode->dev, "_ADR wasn't evaluated\n"); ++ dev_err(dev, "_ADR wasn't evaluated for %pfwP\n", fwnode); + ret = -ENODATA; + goto err_switch; + } + + if (index >= EC_USB_PD_MAX_PORTS) { +- dev_err(fwnode->dev, "Invalid port index number: %llu\n", index); ++ dev_err(dev, "%pfwP: Invalid port index number: %llu\n", fwnode, index); + ret = -EINVAL; + goto err_switch; + } +-- +2.51.0 + diff --git a/queue-6.6/pm-sleep-wakeirq-harden-dev_pm_clear_wake_irq-agains.patch b/queue-6.6/pm-sleep-wakeirq-harden-dev_pm_clear_wake_irq-agains.patch new file mode 100644 index 0000000000..0bc0b94f2c --- /dev/null +++ b/queue-6.6/pm-sleep-wakeirq-harden-dev_pm_clear_wake_irq-agains.patch @@ -0,0 +1,65 @@ +From 53953a78ac8809f58e14a9d16319bc693d0d6efd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 11:19:43 +0800 +Subject: PM: sleep: wakeirq: harden dev_pm_clear_wake_irq() against races + +From: Gui-Dong Han + +[ Upstream commit 5c9ecd8e6437cd55a38ea4f1e1d19cee8e226cb8 ] + +dev_pm_clear_wake_irq() currently uses a dangerous pattern where +dev->power.wakeirq is read and checked for NULL outside the lock. +If two callers invoke this function concurrently, both might see +a valid pointer and proceed. This could result in a double-free +when the second caller acquires the lock and tries to release the +same object. + +Address this by removing the lockless check of dev->power.wakeirq. +Instead, acquire dev->power.lock immediately to ensure the check and +the subsequent operations are atomic. If dev->power.wakeirq is NULL +under the lock, simply unlock and return. This guarantees that +concurrent calls cannot race to free the same object. + +Based on a quick scan of current users, I did not find an actual bug as +drivers seem to rely on their own synchronization. However, since +asynchronous usage patterns exist (e.g., in +drivers/net/wireless/ti/wlcore), I believe a race is theoretically +possible if the API is used less carefully in the future. This change +hardens the API to be robust against such cases. + +Fixes: 4990d4fe327b ("PM / Wakeirq: Add automated device wake IRQ handling") +Signed-off-by: Gui-Dong Han +Link: https://patch.msgid.link/20260203031943.1924-1-hanguidong02@gmail.com +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/base/power/wakeirq.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/drivers/base/power/wakeirq.c b/drivers/base/power/wakeirq.c +index 5a5a9e978e85f..ddbe9cc91d23d 100644 +--- a/drivers/base/power/wakeirq.c ++++ b/drivers/base/power/wakeirq.c +@@ -83,13 +83,16 @@ EXPORT_SYMBOL_GPL(dev_pm_set_wake_irq); + */ + void dev_pm_clear_wake_irq(struct device *dev) + { +- struct wake_irq *wirq = dev->power.wakeirq; ++ struct wake_irq *wirq; + unsigned long flags; + +- if (!wirq) ++ spin_lock_irqsave(&dev->power.lock, flags); ++ wirq = dev->power.wakeirq; ++ if (!wirq) { ++ spin_unlock_irqrestore(&dev->power.lock, flags); + return; ++ } + +- spin_lock_irqsave(&dev->power.lock, flags); + device_wakeup_detach_irq(dev); + dev->power.wakeirq = NULL; + spin_unlock_irqrestore(&dev->power.lock, flags); +-- +2.51.0 + diff --git a/queue-6.6/pm-wakeup-handle-empty-list-in-wakeup_sources_walk_s.patch b/queue-6.6/pm-wakeup-handle-empty-list-in-wakeup_sources_walk_s.patch new file mode 100644 index 0000000000..6e3d7afd27 --- /dev/null +++ b/queue-6.6/pm-wakeup-handle-empty-list-in-wakeup_sources_walk_s.patch @@ -0,0 +1,44 @@ +From 357ba4b94508f74446c775a27b387af80e660f7d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 17:21:29 -0800 +Subject: PM: wakeup: Handle empty list in wakeup_sources_walk_start() + +From: Samuel Wu + +[ Upstream commit 75ce02f4bc9a8b8350b6b1b01872467b0cc960cc ] + +In the case of an empty wakeup_sources list, wakeup_sources_walk_start() +will return an invalid but non-NULL address. This also affects wrappers +of the aforementioned function, like for_each_wakeup_source(). + +Update wakeup_sources_walk_start() to return NULL in case of an empty +list. + +Fixes: b4941adb24c0 ("PM: wakeup: Add routine to help fetch wakeup source object.") +Signed-off-by: Samuel Wu +[ rjw: Subject and changelog edits ] +Link: https://patch.msgid.link/20260124012133.2451708-2-wusamuel@google.com +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/base/power/wakeup.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c +index a917219feea62..eae81def0902a 100644 +--- a/drivers/base/power/wakeup.c ++++ b/drivers/base/power/wakeup.c +@@ -280,9 +280,7 @@ EXPORT_SYMBOL_GPL(wakeup_sources_read_unlock); + */ + struct wakeup_source *wakeup_sources_walk_start(void) + { +- struct list_head *ws_head = &wakeup_sources; +- +- return list_entry_rcu(ws_head->next, struct wakeup_source, entry); ++ return list_first_or_null_rcu(&wakeup_sources, struct wakeup_source, entry); + } + EXPORT_SYMBOL_GPL(wakeup_sources_walk_start); + +-- +2.51.0 + diff --git a/queue-6.6/pnfs-fix-a-missing-wake-up-while-waiting-on-nfs_layo.patch b/queue-6.6/pnfs-fix-a-missing-wake-up-while-waiting-on-nfs_layo.patch new file mode 100644 index 0000000000..2bc201eb63 --- /dev/null +++ b/queue-6.6/pnfs-fix-a-missing-wake-up-while-waiting-on-nfs_layo.patch @@ -0,0 +1,61 @@ +From 6649f5c205dba8bdd52bc94eb0b764ab5317e537 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 14:15:39 -0500 +Subject: pNFS: fix a missing wake up while waiting on NFS_LAYOUT_DRAIN + +From: Olga Kornievskaia + +[ Upstream commit 5248d8474e594d156bee1ed10339cc16e207a28b ] + +It is possible to have a task get stuck on waiting on the +NFS_LAYOUT_DRAIN in the following scenario + +1. cpu a: waiter test NFS_LAYOUT_DRAIN (1) and plh_outstanding (1) +2. cpu b: atomic_dec_and_test() -> clear bit -> wake up +3. cpu c: sets NFS_LAYOUT_DRAIN again +4. cpu a: calls wait_on_bit() sleeps forever. + +To expand on this we have say 2 outstanding pnfs write IO that get +ESTALE which causes both to call pnfs_destroy_layout() and set the +NFS_LAYOUT_DRAIN bit but the 1st one doesn't call the +pnfs_put_layout_hdr() yet (as that would prevent the 2nd ESTALE write +from trying to call pnfs_destroy_layout()). If the 1st ESTALE write +is the one that initially sets the NFS_LAYOUT_DRAIN so that new IO +on this file initiates new LAYOUTGET. Another new write would find +NFS_LAYOUT_DRAIN set and phl_outstanding>0 (step 1) and would +wait_on_bit(). LAYOUTGET completes doing step 2. Now, the 2nd of +ESTALE writes is calling pnfs_destory_layout() and set the +NFS_LAYOUT_DRAIN bit (step 3). Finally, the waiting write wakes up +to check the bit and goes back to sleep. + +The problem revolves around the fact that if NFS_LAYOUT_INVALID_STID +was already set, it should not do the work of +pnfs_mark_layout_stateid_invalid(), thus NFS_LAYOUT_DRAIN will not +be set more than once for an invalid layout. + +Suggested-by: Trond Myklebust +Fixes: 880265c77ac4 ("pNFS: Avoid a live lock condition in pnfs_update_layout()") +Signed-off-by: Olga Kornievskaia +Signed-off-by: Anna Schumaker +Signed-off-by: Sasha Levin +--- + fs/nfs/pnfs.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c +index 0737d9a15d862..7dae2004c65f9 100644 +--- a/fs/nfs/pnfs.c ++++ b/fs/nfs/pnfs.c +@@ -464,7 +464,8 @@ pnfs_mark_layout_stateid_invalid(struct pnfs_layout_hdr *lo, + }; + struct pnfs_layout_segment *lseg, *next; + +- set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags); ++ if (test_and_set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags)) ++ return !list_empty(&lo->plh_segs); + clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(lo->plh_inode)->flags); + list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list) + pnfs_clear_lseg_state(lseg, lseg_list); +-- +2.51.0 + diff --git a/queue-6.6/power-reset-nvmem-reboot-mode-respect-cell-size-for-.patch b/queue-6.6/power-reset-nvmem-reboot-mode-respect-cell-size-for-.patch new file mode 100644 index 0000000000..c402916fba --- /dev/null +++ b/queue-6.6/power-reset-nvmem-reboot-mode-respect-cell-size-for-.patch @@ -0,0 +1,64 @@ +From 3df0e5d5fb46a15ca3ac17ddef65a916cec99f9e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 14 Dec 2025 19:16:18 +0000 +Subject: power: reset: nvmem-reboot-mode: respect cell size for + nvmem_cell_write + +From: Alexander Koskovich + +[ Upstream commit 36b05629226413836cfbb3fbe6689cd188bca156 ] + +Some platforms expose reboot mode cells that are smaller than an +unsigned int, in which cases lead to write failures. Read the cell +first to determine actual size and only write the number of bytes the +cell can hold. + +Fixes: 7a78a7f7695b ("power: reset: nvmem-reboot-mode: use NVMEM as reboot mode write interface") +Signed-off-by: Alexander Koskovich +Link: https://patch.msgid.link/20251214191529.2470580-1-akoskovich@pm.me +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/reset/nvmem-reboot-mode.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +diff --git a/drivers/power/reset/nvmem-reboot-mode.c b/drivers/power/reset/nvmem-reboot-mode.c +index e229308d43e25..819f11bae788b 100644 +--- a/drivers/power/reset/nvmem-reboot-mode.c ++++ b/drivers/power/reset/nvmem-reboot-mode.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + + struct nvmem_reboot_mode { + struct reboot_mode_driver reboot; +@@ -19,12 +20,22 @@ struct nvmem_reboot_mode { + static int nvmem_reboot_mode_write(struct reboot_mode_driver *reboot, + unsigned int magic) + { +- int ret; + struct nvmem_reboot_mode *nvmem_rbm; ++ size_t buf_len; ++ void *buf; ++ int ret; + + nvmem_rbm = container_of(reboot, struct nvmem_reboot_mode, reboot); + +- ret = nvmem_cell_write(nvmem_rbm->cell, &magic, sizeof(magic)); ++ buf = nvmem_cell_read(nvmem_rbm->cell, &buf_len); ++ if (IS_ERR(buf)) ++ return PTR_ERR(buf); ++ kfree(buf); ++ ++ if (buf_len > sizeof(magic)) ++ return -EINVAL; ++ ++ ret = nvmem_cell_write(nvmem_rbm->cell, &magic, buf_len); + if (ret < 0) + dev_err(reboot->dev, "update reboot mode bits failed\n"); + +-- +2.51.0 + diff --git a/queue-6.6/power-supply-ab8500-fix-use-after-free-in-power_supp.patch b/queue-6.6/power-supply-ab8500-fix-use-after-free-in-power_supp.patch new file mode 100644 index 0000000000..d924776f7a --- /dev/null +++ b/queue-6.6/power-supply-ab8500-fix-use-after-free-in-power_supp.patch @@ -0,0 +1,104 @@ +From d70e784c990690f975aaba93222b89bdab7d73d3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:35:58 +0100 +Subject: power: supply: ab8500: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit c4af8a98bb52825a5331ae1d0604c0ea6956ba4b ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Commit 1c1f13a006ed ("power: supply: ab8500: Move to componentized +binding") introduced this issue during a refactorization. Fix this racy +use-after-free by making sure the IRQ is requested _after_ the +registration of the `power_supply` handle. + +Fixes: 1c1f13a006ed ("power: supply: ab8500: Move to componentized binding") +Signed-off-by: Waqar Hameed +Reviewed-by: Linus Walleij +Link: https://patch.msgid.link/ccf83a09942cb8dda3dff70b2682f2c2e9cb97f2.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/ab8500_charger.c | 40 +++++++++++++-------------- + 1 file changed, 20 insertions(+), 20 deletions(-) + +diff --git a/drivers/power/supply/ab8500_charger.c b/drivers/power/supply/ab8500_charger.c +index 308e68545d44d..c6d513953b042 100644 +--- a/drivers/power/supply/ab8500_charger.c ++++ b/drivers/power/supply/ab8500_charger.c +@@ -3456,26 +3456,6 @@ static int ab8500_charger_probe(struct platform_device *pdev) + return ret; + } + +- /* Request interrupts */ +- for (i = 0; i < ARRAY_SIZE(ab8500_charger_irq); i++) { +- irq = platform_get_irq_byname(pdev, ab8500_charger_irq[i].name); +- if (irq < 0) +- return irq; +- +- ret = devm_request_threaded_irq(dev, +- irq, NULL, ab8500_charger_irq[i].isr, +- IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT, +- ab8500_charger_irq[i].name, di); +- +- if (ret != 0) { +- dev_err(dev, "failed to request %s IRQ %d: %d\n" +- , ab8500_charger_irq[i].name, irq, ret); +- return ret; +- } +- dev_dbg(dev, "Requested %s IRQ %d: %d\n", +- ab8500_charger_irq[i].name, irq, ret); +- } +- + /* initialize lock */ + spin_lock_init(&di->usb_state.usb_lock); + mutex_init(&di->usb_ipt_crnt_lock); +@@ -3604,6 +3584,26 @@ static int ab8500_charger_probe(struct platform_device *pdev) + return PTR_ERR(di->usb_chg.psy); + } + ++ /* Request interrupts */ ++ for (i = 0; i < ARRAY_SIZE(ab8500_charger_irq); i++) { ++ irq = platform_get_irq_byname(pdev, ab8500_charger_irq[i].name); ++ if (irq < 0) ++ return irq; ++ ++ ret = devm_request_threaded_irq(dev, ++ irq, NULL, ab8500_charger_irq[i].isr, ++ IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT, ++ ab8500_charger_irq[i].name, di); ++ ++ if (ret != 0) { ++ dev_err(dev, "failed to request %s IRQ %d: %d\n" ++ , ab8500_charger_irq[i].name, irq, ret); ++ return ret; ++ } ++ dev_dbg(dev, "Requested %s IRQ %d: %d\n", ++ ab8500_charger_irq[i].name, irq, ret); ++ } ++ + /* + * Check what battery we have, since we always have the USB + * psy, use that as a handle. +-- +2.51.0 + diff --git a/queue-6.6/power-supply-act8945a-fix-use-after-free-in-power_su.patch b/queue-6.6/power-supply-act8945a-fix-use-after-free-in-power_su.patch new file mode 100644 index 0000000000..e5a9daf0b6 --- /dev/null +++ b/queue-6.6/power-supply-act8945a-fix-use-after-free-in-power_su.patch @@ -0,0 +1,77 @@ +From c3f450e79031a981b9274d393f29e4fb67d3901d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:35:59 +0100 +Subject: power: supply: act8945a: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 3291c51d4684d048dd2eb91b5b65fcfdaf72141f ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: a09209acd6a8 ("power: supply: act8945a_charger: Add status change update support") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/bcf3a23b5187df0bba54a8c8fe09f8b8a0031dee.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/act8945a_charger.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/drivers/power/supply/act8945a_charger.c b/drivers/power/supply/act8945a_charger.c +index e9b5f42837729..e9cb06daecea9 100644 +--- a/drivers/power/supply/act8945a_charger.c ++++ b/drivers/power/supply/act8945a_charger.c +@@ -597,14 +597,6 @@ static int act8945a_charger_probe(struct platform_device *pdev) + return irq ?: -ENXIO; + } + +- ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, +- IRQF_TRIGGER_FALLING, "act8945a_interrupt", +- charger); +- if (ret) { +- dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); +- return ret; +- } +- + charger->desc.name = "act8945a-charger"; + charger->desc.get_property = act8945a_charger_get_property; + charger->desc.properties = act8945a_charger_props; +@@ -625,6 +617,14 @@ static int act8945a_charger_probe(struct platform_device *pdev) + return PTR_ERR(charger->psy); + } + ++ ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, ++ IRQF_TRIGGER_FALLING, "act8945a_interrupt", ++ charger); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); ++ return ret; ++ } ++ + platform_set_drvdata(pdev, charger); + + INIT_WORK(&charger->work, act8945a_work); +-- +2.51.0 + diff --git a/queue-6.6/power-supply-bq256xx-fix-use-after-free-in-power_sup.patch b/queue-6.6/power-supply-bq256xx-fix-use-after-free-in-power_sup.patch new file mode 100644 index 0000000000..d1b330cbc5 --- /dev/null +++ b/queue-6.6/power-supply-bq256xx-fix-use-after-free-in-power_sup.patch @@ -0,0 +1,73 @@ +From 6585b537bf6eef0f037127e1b6bf477670123ac6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:35:59 +0100 +Subject: power: supply: bq256xx: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 8005843369723d9c8975b7c4202d1b85d6125302 ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: 32e4978bb920 ("power: supply: bq256xx: Introduce the BQ256XX charger driver") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/39da6da8cc060fa0382ca859f65071e791cb6119.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/bq256xx_charger.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/power/supply/bq256xx_charger.c b/drivers/power/supply/bq256xx_charger.c +index c8368dae69c71..2b0216d32d5f7 100644 +--- a/drivers/power/supply/bq256xx_charger.c ++++ b/drivers/power/supply/bq256xx_charger.c +@@ -1746,6 +1746,12 @@ static int bq256xx_probe(struct i2c_client *client) + usb_register_notifier(bq->usb3_phy, &bq->usb_nb); + } + ++ ret = bq256xx_power_supply_init(bq, &psy_cfg, dev); ++ if (ret) { ++ dev_err(dev, "Failed to register power supply\n"); ++ return ret; ++ } ++ + if (client->irq) { + ret = devm_request_threaded_irq(dev, client->irq, NULL, + bq256xx_irq_handler_thread, +@@ -1758,12 +1764,6 @@ static int bq256xx_probe(struct i2c_client *client) + } + } + +- ret = bq256xx_power_supply_init(bq, &psy_cfg, dev); +- if (ret) { +- dev_err(dev, "Failed to register power supply\n"); +- return ret; +- } +- + ret = bq256xx_hw_init(bq); + if (ret) { + dev_err(dev, "Cannot initialize the chip.\n"); +-- +2.51.0 + diff --git a/queue-6.6/power-supply-bq25980-fix-use-after-free-in-power_sup.patch b/queue-6.6/power-supply-bq25980-fix-use-after-free-in-power_sup.patch new file mode 100644 index 0000000000..6192792b35 --- /dev/null +++ b/queue-6.6/power-supply-bq25980-fix-use-after-free-in-power_sup.patch @@ -0,0 +1,73 @@ +From 5bbfa8174829d0412c279720346fdb7723b60b8d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:35:59 +0100 +Subject: power: supply: bq25980: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 5f0b1cb41906e86b64bf69f5ededb83b0d757c27 ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: 5069185fc18e ("power: supply: bq25980: Add support for the BQ259xx family") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/8763035cadb959e14787b3837f2d3db61f6e1c34.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/bq25980_charger.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/power/supply/bq25980_charger.c b/drivers/power/supply/bq25980_charger.c +index d8411722266f5..fd00f9e533548 100644 +--- a/drivers/power/supply/bq25980_charger.c ++++ b/drivers/power/supply/bq25980_charger.c +@@ -1241,6 +1241,12 @@ static int bq25980_probe(struct i2c_client *client) + return ret; + } + ++ ret = bq25980_power_supply_init(bq, dev); ++ if (ret) { ++ dev_err(dev, "Failed to register power supply\n"); ++ return ret; ++ } ++ + if (client->irq) { + ret = devm_request_threaded_irq(dev, client->irq, NULL, + bq25980_irq_handler_thread, +@@ -1251,12 +1257,6 @@ static int bq25980_probe(struct i2c_client *client) + return ret; + } + +- ret = bq25980_power_supply_init(bq, dev); +- if (ret) { +- dev_err(dev, "Failed to register power supply\n"); +- return ret; +- } +- + ret = bq25980_hw_init(bq); + if (ret) { + dev_err(dev, "Cannot initialize the chip.\n"); +-- +2.51.0 + diff --git a/queue-6.6/power-supply-bq27xxx-fix-wrong-errno-when-bus-ops-ar.patch b/queue-6.6/power-supply-bq27xxx-fix-wrong-errno-when-bus-ops-ar.patch new file mode 100644 index 0000000000..8569419bd1 --- /dev/null +++ b/queue-6.6/power-supply-bq27xxx-fix-wrong-errno-when-bus-ops-ar.patch @@ -0,0 +1,61 @@ +From 4b95c1f98b43362c7467d3f684811722ae4a7f62 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Dec 2025 16:34:36 +0800 +Subject: power: supply: bq27xxx: fix wrong errno when bus ops are unsupported + +From: Haotian Zhang + +[ Upstream commit 688364a11647dc09ba1e4429313e0008066ec790 ] + +bq27xxx_write(), bq27xxx_read_block(), and bq27xxx_write_block() +return -EPERM when the bus callback pointer is NULL. A NULL callback +indicates the operation is not supported by the bus/driver, +not that permission is denied. + +Return -EOPNOTSUPP instead of -EPERM when di->bus.write/ +read_bulk/write_bulk is NULL. + +Fixes: 14073f6614f6 ("power: supply: bq27xxx: Add bulk transfer bus methods") +Signed-off-by: Haotian Zhang +Reviewed-by: Matt Ranostay +Link: https://patch.msgid.link/20251204083436.1367-1-vulab@iscas.ac.cn +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/bq27xxx_battery.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c +index 1f06dee4b8b4e..ff01d5d850f9a 100644 +--- a/drivers/power/supply/bq27xxx_battery.c ++++ b/drivers/power/supply/bq27xxx_battery.c +@@ -1162,7 +1162,7 @@ static inline int bq27xxx_write(struct bq27xxx_device_info *di, int reg_index, + return -EINVAL; + + if (!di->bus.write) +- return -EPERM; ++ return -EOPNOTSUPP; + + ret = di->bus.write(di, di->regs[reg_index], value, single); + if (ret < 0) +@@ -1181,7 +1181,7 @@ static inline int bq27xxx_read_block(struct bq27xxx_device_info *di, int reg_ind + return -EINVAL; + + if (!di->bus.read_bulk) +- return -EPERM; ++ return -EOPNOTSUPP; + + ret = di->bus.read_bulk(di, di->regs[reg_index], data, len); + if (ret < 0) +@@ -1200,7 +1200,7 @@ static inline int bq27xxx_write_block(struct bq27xxx_device_info *di, int reg_in + return -EINVAL; + + if (!di->bus.write_bulk) +- return -EPERM; ++ return -EOPNOTSUPP; + + ret = di->bus.write_bulk(di, di->regs[reg_index], data, len); + if (ret < 0) +-- +2.51.0 + diff --git a/queue-6.6/power-supply-cpcap-battery-fix-use-after-free-in-pow.patch b/queue-6.6/power-supply-cpcap-battery-fix-use-after-free-in-pow.patch new file mode 100644 index 0000000000..da1ec25030 --- /dev/null +++ b/queue-6.6/power-supply-cpcap-battery-fix-use-after-free-in-pow.patch @@ -0,0 +1,70 @@ +From 7446010c17a51baedf6b965cd2b421b6a7065c51 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:36:00 +0100 +Subject: power: supply: cpcap-battery: Fix use-after-free in + power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 642f33e34b969eedec334738fd5df95d2dc42742 ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: 874b2adbed12 ("power: supply: cpcap-battery: Add a battery driver") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/81db58d610c9a51a68184f856cd431a934cccee2.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/cpcap-battery.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/power/supply/cpcap-battery.c b/drivers/power/supply/cpcap-battery.c +index 5dd76c0ac98da..d84b81e773628 100644 +--- a/drivers/power/supply/cpcap-battery.c ++++ b/drivers/power/supply/cpcap-battery.c +@@ -1122,10 +1122,6 @@ static int cpcap_battery_probe(struct platform_device *pdev) + + platform_set_drvdata(pdev, ddata); + +- error = cpcap_battery_init_interrupts(pdev, ddata); +- if (error) +- return error; +- + error = cpcap_battery_init_iio(ddata); + if (error) + return error; +@@ -1142,6 +1138,10 @@ static int cpcap_battery_probe(struct platform_device *pdev) + return error; + } + ++ error = cpcap_battery_init_interrupts(pdev, ddata); ++ if (error) ++ return error; ++ + atomic_set(&ddata->active, 1); + + error = cpcap_battery_calibrate(ddata); +-- +2.51.0 + diff --git a/queue-6.6/power-supply-goldfish-fix-use-after-free-in-power_su.patch b/queue-6.6/power-supply-goldfish-fix-use-after-free-in-power_su.patch new file mode 100644 index 0000000000..399d1d9635 --- /dev/null +++ b/queue-6.6/power-supply-goldfish-fix-use-after-free-in-power_su.patch @@ -0,0 +1,73 @@ +From 76ce1564121dea211ce8a2354fc386c456b85e83 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:36:00 +0100 +Subject: power: supply: goldfish: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit b2ce982e2e0c888dc55c888ad0e20ea04daf2e6b ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: 84d7b7687489 ("power: Add battery driver for goldfish emulator") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/500a606bb6fb6f2bb8d797e19a00cea9dd7b03c1.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/goldfish_battery.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/power/supply/goldfish_battery.c b/drivers/power/supply/goldfish_battery.c +index a58d713d75ce8..4d204f0e18532 100644 +--- a/drivers/power/supply/goldfish_battery.c ++++ b/drivers/power/supply/goldfish_battery.c +@@ -224,12 +224,6 @@ static int goldfish_battery_probe(struct platform_device *pdev) + if (data->irq < 0) + return -ENODEV; + +- ret = devm_request_irq(&pdev->dev, data->irq, +- goldfish_battery_interrupt, +- IRQF_SHARED, pdev->name, data); +- if (ret) +- return ret; +- + psy_cfg.drv_data = data; + + data->ac = power_supply_register(&pdev->dev, &ac_desc, &psy_cfg); +@@ -245,6 +239,12 @@ static int goldfish_battery_probe(struct platform_device *pdev) + + platform_set_drvdata(pdev, data); + ++ ret = devm_request_irq(&pdev->dev, data->irq, ++ goldfish_battery_interrupt, ++ IRQF_SHARED, pdev->name, data); ++ if (ret) ++ return ret; ++ + GOLDFISH_BATTERY_WRITE(data, BATTERY_INT_ENABLE, BATTERY_INT_MASK); + return 0; + } +-- +2.51.0 + diff --git a/queue-6.6/power-supply-qcom_battmgr-recognize-lip-as-lithium-p.patch b/queue-6.6/power-supply-qcom_battmgr-recognize-lip-as-lithium-p.patch new file mode 100644 index 0000000000..3b6a013e62 --- /dev/null +++ b/queue-6.6/power-supply-qcom_battmgr-recognize-lip-as-lithium-p.patch @@ -0,0 +1,42 @@ +From fbce3429eded7de1cd5e168226579ba2dc70bab9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 20:57:58 -0300 +Subject: power: supply: qcom_battmgr: Recognize "LiP" as lithium-polymer + +From: Val Packett + +[ Upstream commit c655f45480637aee326b5bd96488d35ab90db2b0 ] + +On the Dell Latitude 7455, the firmware uses "LiP" with a lowercase 'i' +for the battery chemistry type, but only all-uppercase "LIP" was being +recognized. Add the CamelCase variant to the check to fix the "Unknown +battery technology" warning. + +Fixes: 202ac22b8e2e ("power: supply: qcom_battmgr: Add lithium-polymer entry") +Signed-off-by: Val Packett +Reviewed-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Link: https://patch.msgid.link/20260120235831.479038-1-val@packett.cool +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/qcom_battmgr.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/power/supply/qcom_battmgr.c b/drivers/power/supply/qcom_battmgr.c +index 0c993780d3ef2..e5eade1328163 100644 +--- a/drivers/power/supply/qcom_battmgr.c ++++ b/drivers/power/supply/qcom_battmgr.c +@@ -981,7 +981,8 @@ static unsigned int qcom_battmgr_sc8280xp_parse_technology(const char *chemistry + if ((!strncmp(chemistry, "LIO", BATTMGR_CHEMISTRY_LEN)) || + (!strncmp(chemistry, "OOI", BATTMGR_CHEMISTRY_LEN))) + return POWER_SUPPLY_TECHNOLOGY_LION; +- if (!strncmp(chemistry, "LIP", BATTMGR_CHEMISTRY_LEN)) ++ if (!strncmp(chemistry, "LIP", BATTMGR_CHEMISTRY_LEN) || ++ !strncmp(chemistry, "LiP", BATTMGR_CHEMISTRY_LEN)) + return POWER_SUPPLY_TECHNOLOGY_LIPO; + + pr_err("Unknown battery technology '%s'\n", chemistry); +-- +2.51.0 + diff --git a/queue-6.6/power-supply-rt9455-fix-use-after-free-in-power_supp.patch b/queue-6.6/power-supply-rt9455-fix-use-after-free-in-power_supp.patch new file mode 100644 index 0000000000..05e5a25b03 --- /dev/null +++ b/queue-6.6/power-supply-rt9455-fix-use-after-free-in-power_supp.patch @@ -0,0 +1,78 @@ +From 085fb28078fa97bac8c48a9919bdead6e35dd60a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:36:02 +0100 +Subject: power: supply: rt9455: Fix use-after-free in power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit e2febe375e5ea5afed92f4cd9711bde8f24ee6d2 ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. + +Fixes: e86d69dd786e ("power_supply: Add support for Richtek RT9455 battery charger") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/1567d831e04c3e2fcb9e18dd36b7bcba4634581a.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/rt9455_charger.c | 17 +++++++++-------- + 1 file changed, 9 insertions(+), 8 deletions(-) + +diff --git a/drivers/power/supply/rt9455_charger.c b/drivers/power/supply/rt9455_charger.c +index e4dbacd50a437..248dc2b5e1f7c 100644 +--- a/drivers/power/supply/rt9455_charger.c ++++ b/drivers/power/supply/rt9455_charger.c +@@ -1663,6 +1663,15 @@ static int rt9455_probe(struct i2c_client *client) + rt9455_charger_config.supplied_to = rt9455_charger_supplied_to; + rt9455_charger_config.num_supplicants = + ARRAY_SIZE(rt9455_charger_supplied_to); ++ ++ info->charger = devm_power_supply_register(dev, &rt9455_charger_desc, ++ &rt9455_charger_config); ++ if (IS_ERR(info->charger)) { ++ dev_err(dev, "Failed to register charger\n"); ++ ret = PTR_ERR(info->charger); ++ goto put_usb_notifier; ++ } ++ + ret = devm_request_threaded_irq(dev, client->irq, NULL, + rt9455_irq_handler_thread, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, +@@ -1678,14 +1687,6 @@ static int rt9455_probe(struct i2c_client *client) + goto put_usb_notifier; + } + +- info->charger = devm_power_supply_register(dev, &rt9455_charger_desc, +- &rt9455_charger_config); +- if (IS_ERR(info->charger)) { +- dev_err(dev, "Failed to register charger\n"); +- ret = PTR_ERR(info->charger); +- goto put_usb_notifier; +- } +- + return 0; + + put_usb_notifier: +-- +2.51.0 + diff --git a/queue-6.6/power-supply-sbs-battery-fix-use-after-free-in-power.patch b/queue-6.6/power-supply-sbs-battery-fix-use-after-free-in-power.patch new file mode 100644 index 0000000000..9a43a3b4f7 --- /dev/null +++ b/queue-6.6/power-supply-sbs-battery-fix-use-after-free-in-power.patch @@ -0,0 +1,101 @@ +From 09d5a946b50403d5a52aa28536f40503fe8ad81d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:36:02 +0100 +Subject: power: supply: sbs-battery: Fix use-after-free in + power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 8d59cf3887fbabacef53bfba473e33e8a8d9d07b ] + +Using the `devm_` variant for requesting IRQ _before_ the `devm_` +variant for allocating/registering the `power_supply` handle, means that +the `power_supply` handle will be deallocated/unregistered _before_ the +interrupt handler (since `devm_` naturally deallocates in reverse +allocation order). This means that during removal, there is a race +condition where an interrupt can fire just _after_ the `power_supply` +handle has been freed, *but* just _before_ the corresponding +unregistration of the IRQ handler has run. + +This will lead to the IRQ handler calling `power_supply_changed()` with +a freed `power_supply` handle. Which usually crashes the system or +otherwise silently corrupts the memory... + +Note that there is a similar situation which can also happen during +`probe()`; the possibility of an interrupt firing _before_ registering +the `power_supply` handle. This would then lead to the nasty situation +of using the `power_supply` handle *uninitialized* in +`power_supply_changed()`. + +Fix this racy use-after-free by making sure the IRQ is requested _after_ +the registration of the `power_supply` handle. Keep the old behavior of +just printing a warning in case of any failures during the IRQ request +and finishing the probe successfully. + +Fixes: d2cec82c2880 ("power: sbs-battery: Request threaded irq and fix dev callback cookie") +Signed-off-by: Waqar Hameed +Reviewed-by: Phil Reid +Link: https://patch.msgid.link/0ef896e002495e615157b482d18a437af19ddcd0.1766268280.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/sbs-battery.c | 36 +++++++++++++++--------------- + 1 file changed, 18 insertions(+), 18 deletions(-) + +diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c +index cdfc8466d129b..f30a542d4716c 100644 +--- a/drivers/power/supply/sbs-battery.c ++++ b/drivers/power/supply/sbs-battery.c +@@ -1173,24 +1173,6 @@ static int sbs_probe(struct i2c_client *client) + + i2c_set_clientdata(client, chip); + +- if (!chip->gpio_detect) +- goto skip_gpio; +- +- irq = gpiod_to_irq(chip->gpio_detect); +- if (irq <= 0) { +- dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq); +- goto skip_gpio; +- } +- +- rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq, +- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, +- dev_name(&client->dev), chip); +- if (rc) { +- dev_warn(&client->dev, "Failed to request irq: %d\n", rc); +- goto skip_gpio; +- } +- +-skip_gpio: + /* + * Before we register, we might need to make sure we can actually talk + * to the battery. +@@ -1216,6 +1198,24 @@ static int sbs_probe(struct i2c_client *client) + return dev_err_probe(&client->dev, PTR_ERR(chip->power_supply), + "Failed to register power supply\n"); + ++ if (!chip->gpio_detect) ++ goto out; ++ ++ irq = gpiod_to_irq(chip->gpio_detect); ++ if (irq <= 0) { ++ dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq); ++ goto out; ++ } ++ ++ rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq, ++ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, ++ dev_name(&client->dev), chip); ++ if (rc) { ++ dev_warn(&client->dev, "Failed to request irq: %d\n", rc); ++ goto out; ++ } ++ ++out: + dev_info(&client->dev, + "%s: battery gas gauge device registered\n", client->name); + +-- +2.51.0 + diff --git a/queue-6.6/power-supply-wm97xx-fix-null-pointer-dereference-in-.patch b/queue-6.6/power-supply-wm97xx-fix-null-pointer-dereference-in-.patch new file mode 100644 index 0000000000..ae2367968c --- /dev/null +++ b/queue-6.6/power-supply-wm97xx-fix-null-pointer-dereference-in-.patch @@ -0,0 +1,98 @@ +From 2b4056371e582f5f80a02881cacd9852f8e89daf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 23:46:24 +0100 +Subject: power: supply: wm97xx: Fix NULL pointer dereference in + power_supply_changed() + +From: Waqar Hameed + +[ Upstream commit 39fe0eac6d755ef215026518985fcf8de9360e9e ] + +In `probe()`, `request_irq()` is called before allocating/registering a +`power_supply` handle. If an interrupt is fired between the call to +`request_irq()` and `power_supply_register()`, the `power_supply` handle +will be used uninitialized in `power_supply_changed()` in +`wm97xx_bat_update()` (triggered from the interrupt handler). This will +lead to a `NULL` pointer dereference since + +Fix this racy `NULL` pointer dereference by making sure the IRQ is +requested _after_ the registration of the `power_supply` handle. Since +the IRQ is the last thing requests in the `probe()` now, remove the +error path for freeing it. Instead add one for unregistering the +`power_supply` handle when IRQ request fails. + +Fixes: 7c87942aef52 ("wm97xx_battery: Use irq to detect charger state") +Signed-off-by: Waqar Hameed +Link: https://patch.msgid.link/97b55f0479a932eea7213844bf66f28a974e27a2.1766270196.git.waqar.hameed@axis.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/wm97xx_battery.c | 34 +++++++++++++++------------ + 1 file changed, 19 insertions(+), 15 deletions(-) + +diff --git a/drivers/power/supply/wm97xx_battery.c b/drivers/power/supply/wm97xx_battery.c +index f4b190adb3359..d3e5c2f7762a6 100644 +--- a/drivers/power/supply/wm97xx_battery.c ++++ b/drivers/power/supply/wm97xx_battery.c +@@ -178,12 +178,6 @@ static int wm97xx_bat_probe(struct platform_device *dev) + "failed to get charge GPIO\n"); + if (charge_gpiod) { + gpiod_set_consumer_name(charge_gpiod, "BATT CHRG"); +- ret = request_irq(gpiod_to_irq(charge_gpiod), +- wm97xx_chrg_irq, 0, +- "AC Detect", dev); +- if (ret) +- return dev_err_probe(&dev->dev, ret, +- "failed to request GPIO irq\n"); + props++; /* POWER_SUPPLY_PROP_STATUS */ + } + +@@ -199,10 +193,8 @@ static int wm97xx_bat_probe(struct platform_device *dev) + props++; /* POWER_SUPPLY_PROP_VOLTAGE_MIN */ + + prop = kcalloc(props, sizeof(*prop), GFP_KERNEL); +- if (!prop) { +- ret = -ENOMEM; +- goto err3; +- } ++ if (!prop) ++ return -ENOMEM; + + prop[i++] = POWER_SUPPLY_PROP_PRESENT; + if (charge_gpiod) +@@ -236,15 +228,27 @@ static int wm97xx_bat_probe(struct platform_device *dev) + schedule_work(&bat_work); + } else { + ret = PTR_ERR(bat_psy); +- goto err4; ++ goto free; ++ } ++ ++ if (charge_gpiod) { ++ ret = request_irq(gpiod_to_irq(charge_gpiod), wm97xx_chrg_irq, ++ 0, "AC Detect", dev); ++ if (ret) { ++ dev_err_probe(&dev->dev, ret, ++ "failed to request GPIO irq\n"); ++ goto unregister; ++ } + } + + return 0; +-err4: ++ ++unregister: ++ power_supply_unregister(bat_psy); ++ ++free: + kfree(prop); +-err3: +- if (charge_gpiod) +- free_irq(gpiod_to_irq(charge_gpiod), dev); ++ + return ret; + } + +-- +2.51.0 + diff --git a/queue-6.6/powerpc-eeh-fix-recursive-pci_lock_rescan_remove-loc.patch b/queue-6.6/powerpc-eeh-fix-recursive-pci_lock_rescan_remove-loc.patch new file mode 100644 index 0000000000..5238b58c18 --- /dev/null +++ b/queue-6.6/powerpc-eeh-fix-recursive-pci_lock_rescan_remove-loc.patch @@ -0,0 +1,275 @@ +From 6f4081e08c67383ee248fd180c3fd88211e88caf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 10 Dec 2025 08:25:59 -0600 +Subject: powerpc/eeh: fix recursive pci_lock_rescan_remove locking in EEH + event handling +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Narayana Murty N + +[ Upstream commit 815a8d2feb5615ae7f0b5befd206af0b0160614c ] + +The recent commit 1010b4c012b0 ("powerpc/eeh: Make EEH driver device +hotplug safe") restructured the EEH driver to improve synchronization +with the PCI hotplug layer. + +However, it inadvertently moved pci_lock_rescan_remove() outside its +intended scope in eeh_handle_normal_event(), leading to broken PCI +error reporting and improper EEH event triggering. Specifically, +eeh_handle_normal_event() acquired pci_lock_rescan_remove() before +calling eeh_pe_bus_get(), but eeh_pe_bus_get() itself attempts to +acquire the same lock internally, causing nested locking and disrupting +normal EEH event handling paths. + +This patch adds a boolean parameter do_lock to _eeh_pe_bus_get(), +with two public wrappers: + eeh_pe_bus_get() with locking enabled. + eeh_pe_bus_get_nolock() that skips locking. + +Callers that already hold pci_lock_rescan_remove() now use +eeh_pe_bus_get_nolock() to avoid recursive lock acquisition. + +Additionally, pci_lock_rescan_remove() calls are restored to the correct +position—after eeh_pe_bus_get() and immediately before iterating affected +PEs and devices. This ensures EEH-triggered PCI removes occur under proper +bus rescan locking without recursive lock contention. + +The eeh_pe_loc_get() function has been split into two functions: + eeh_pe_loc_get(struct eeh_pe *pe) which retrieves the loc for given PE. + eeh_pe_loc_get_bus(struct pci_bus *bus) which retrieves the location + code for given bus. + +This resolves lockdep warnings such as: + +[ 84.964298] [ T928] ============================================ +[ 84.964304] [ T928] WARNING: possible recursive locking detected +[ 84.964311] [ T928] 6.18.0-rc3 #51 Not tainted +[ 84.964315] [ T928] -------------------------------------------- +[ 84.964320] [ T928] eehd/928 is trying to acquire lock: +[ 84.964324] [ T928] c000000003b29d58 (pci_rescan_remove_lock){+.+.}-{3:3}, at: pci_lock_rescan_remove+0x28/0x40 +[ 84.964342] [ T928] + but task is already holding lock: +[ 84.964347] [ T928] c000000003b29d58 (pci_rescan_remove_lock){+.+.}-{3:3}, at: pci_lock_rescan_remove+0x28/0x40 +[ 84.964357] [ T928] + other info that might help us debug this: +[ 84.964363] [ T928] Possible unsafe locking scenario: + +[ 84.964367] [ T928] CPU0 +[ 84.964370] [ T928] ---- +[ 84.964373] [ T928] lock(pci_rescan_remove_lock); +[ 84.964378] [ T928] lock(pci_rescan_remove_lock); +[ 84.964383] [ T928] + *** DEADLOCK *** + +[ 84.964388] [ T928] May be due to missing lock nesting notation + +[ 84.964393] [ T928] 1 lock held by eehd/928: +[ 84.964397] [ T928] #0: c000000003b29d58 (pci_rescan_remove_lock){+.+.}-{3:3}, at: pci_lock_rescan_remove+0x28/0x40 +[ 84.964408] [ T928] + stack backtrace: +[ 84.964414] [ T928] CPU: 2 UID: 0 PID: 928 Comm: eehd Not tainted 6.18.0-rc3 #51 VOLUNTARY +[ 84.964417] [ T928] Hardware name: IBM,9080-HEX POWER10 (architected) 0x800200 0xf000006 of:IBM,FW1060.00 (NH1060_022) hv:phyp pSeries +[ 84.964419] [ T928] Call Trace: +[ 84.964420] [ T928] [c0000011a7157990] [c000000001705de4] dump_stack_lvl+0xc8/0x130 (unreliable) +[ 84.964424] [ T928] [c0000011a71579d0] [c0000000002f66e0] print_deadlock_bug+0x430/0x440 +[ 84.964428] [ T928] [c0000011a7157a70] [c0000000002fd0c0] __lock_acquire+0x1530/0x2d80 +[ 84.964431] [ T928] [c0000011a7157ba0] [c0000000002fea54] lock_acquire+0x144/0x410 +[ 84.964433] [ T928] [c0000011a7157cb0] [c0000011a7157cb0] __mutex_lock+0xf4/0x1050 +[ 84.964436] [ T928] [c0000011a7157e00] [c000000000de21d8] pci_lock_rescan_remove+0x28/0x40 +[ 84.964439] [ T928] [c0000011a7157e20] [c00000000004ed98] eeh_pe_bus_get+0x48/0xc0 +[ 84.964442] [ T928] [c0000011a7157e50] [c000000000050434] eeh_handle_normal_event+0x64/0xa60 +[ 84.964446] [ T928] [c0000011a7157f30] [c000000000051de8] eeh_event_handler+0xf8/0x190 +[ 84.964450] [ T928] [c0000011a7157f90] [c0000000002747ac] kthread+0x16c/0x180 +[ 84.964453] [ T928] [c0000011a7157fe0] [c00000000000ded8] start_kernel_thread+0x14/0x18 + + +Fixes: 1010b4c012b0 ("powerpc/eeh: Make EEH driver device hotplug safe") +Signed-off-by: Narayana Murty N +Reviewed-by: Sourabh Jain +Reviewed-by: Mahesh Salgaonkar +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/20251210142559.8874-1-nnmlinux@linux.ibm.com +Signed-off-by: Sasha Levin +--- + arch/powerpc/include/asm/eeh.h | 2 + + arch/powerpc/kernel/eeh_driver.c | 11 ++--- + arch/powerpc/kernel/eeh_pe.c | 74 ++++++++++++++++++++++++++++++-- + 3 files changed, 78 insertions(+), 9 deletions(-) + +diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h +index 514dd056c2c84..b5709b9aed238 100644 +--- a/arch/powerpc/include/asm/eeh.h ++++ b/arch/powerpc/include/asm/eeh.h +@@ -289,6 +289,8 @@ void eeh_pe_dev_traverse(struct eeh_pe *root, + void eeh_pe_restore_bars(struct eeh_pe *pe); + const char *eeh_pe_loc_get(struct eeh_pe *pe); + struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe); ++const char *eeh_pe_loc_get_bus(struct pci_bus *bus); ++struct pci_bus *eeh_pe_bus_get_nolock(struct eeh_pe *pe); + + void eeh_show_enabled(void); + int __init eeh_init(struct eeh_ops *ops); +diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c +index cc8bedf410ea7..632bf157636ec 100644 +--- a/arch/powerpc/kernel/eeh_driver.c ++++ b/arch/powerpc/kernel/eeh_driver.c +@@ -846,7 +846,7 @@ void eeh_handle_normal_event(struct eeh_pe *pe) + + pci_lock_rescan_remove(); + +- bus = eeh_pe_bus_get(pe); ++ bus = eeh_pe_bus_get_nolock(pe); + if (!bus) { + pr_err("%s: Cannot find PCI bus for PHB#%x-PE#%x\n", + __func__, pe->phb->global_number, pe->addr); +@@ -877,14 +877,15 @@ void eeh_handle_normal_event(struct eeh_pe *pe) + /* Log the event */ + if (pe->type & EEH_PE_PHB) { + pr_err("EEH: Recovering PHB#%x, location: %s\n", +- pe->phb->global_number, eeh_pe_loc_get(pe)); ++ pe->phb->global_number, eeh_pe_loc_get_bus(bus)); + } else { + struct eeh_pe *phb_pe = eeh_phb_pe_get(pe->phb); + + pr_err("EEH: Recovering PHB#%x-PE#%x\n", + pe->phb->global_number, pe->addr); + pr_err("EEH: PE location: %s, PHB location: %s\n", +- eeh_pe_loc_get(pe), eeh_pe_loc_get(phb_pe)); ++ eeh_pe_loc_get_bus(bus), ++ eeh_pe_loc_get_bus(eeh_pe_bus_get_nolock(phb_pe))); + } + + #ifdef CONFIG_STACKTRACE +@@ -1089,7 +1090,7 @@ void eeh_handle_normal_event(struct eeh_pe *pe) + eeh_pe_state_clear(pe, EEH_PE_PRI_BUS, true); + eeh_pe_dev_mode_mark(pe, EEH_DEV_REMOVED); + +- bus = eeh_pe_bus_get(pe); ++ bus = eeh_pe_bus_get_nolock(pe); + if (bus) + pci_hp_remove_devices(bus); + else +@@ -1213,7 +1214,7 @@ void eeh_handle_special_event(void) + (phb_pe->state & EEH_PE_RECOVERING)) + continue; + +- bus = eeh_pe_bus_get(phb_pe); ++ bus = eeh_pe_bus_get_nolock(phb_pe); + if (!bus) { + pr_err("%s: Cannot find PCI bus for " + "PHB#%x-PE#%x\n", +diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c +index 08095aeba5c98..b10fcca520400 100644 +--- a/arch/powerpc/kernel/eeh_pe.c ++++ b/arch/powerpc/kernel/eeh_pe.c +@@ -812,6 +812,24 @@ void eeh_pe_restore_bars(struct eeh_pe *pe) + const char *eeh_pe_loc_get(struct eeh_pe *pe) + { + struct pci_bus *bus = eeh_pe_bus_get(pe); ++ return eeh_pe_loc_get_bus(bus); ++} ++ ++/** ++ * eeh_pe_loc_get_bus - Retrieve location code binding to the given PCI bus ++ * @bus: PCI bus ++ * ++ * Retrieve the location code associated with the given PCI bus. If the bus ++ * is a root bus, the location code is fetched from the PHB device tree node ++ * or root port. Otherwise, the location code is obtained from the device ++ * tree node of the upstream bridge of the bus. The function walks up the ++ * bus hierarchy if necessary, checking each node for the appropriate ++ * location code property ("ibm,io-base-loc-code" for root buses, ++ * "ibm,slot-location-code" for others). If no location code is found, ++ * returns "N/A". ++ */ ++const char *eeh_pe_loc_get_bus(struct pci_bus *bus) ++{ + struct device_node *dn; + const char *loc = NULL; + +@@ -838,8 +856,9 @@ const char *eeh_pe_loc_get(struct eeh_pe *pe) + } + + /** +- * eeh_pe_bus_get - Retrieve PCI bus according to the given PE ++ * _eeh_pe_bus_get - Retrieve PCI bus according to the given PE + * @pe: EEH PE ++ * @do_lock: Is the caller already held the pci_lock_rescan_remove? + * + * Retrieve the PCI bus according to the given PE. Basically, + * there're 3 types of PEs: PHB/Bus/Device. For PHB PE, the +@@ -847,7 +866,7 @@ const char *eeh_pe_loc_get(struct eeh_pe *pe) + * returned for BUS PE. However, we don't have associated PCI + * bus for DEVICE PE. + */ +-struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe) ++static struct pci_bus *_eeh_pe_bus_get(struct eeh_pe *pe, bool do_lock) + { + struct eeh_dev *edev; + struct pci_dev *pdev; +@@ -862,11 +881,58 @@ struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe) + + /* Retrieve the parent PCI bus of first (top) PCI device */ + edev = list_first_entry_or_null(&pe->edevs, struct eeh_dev, entry); +- pci_lock_rescan_remove(); ++ if (do_lock) ++ pci_lock_rescan_remove(); + pdev = eeh_dev_to_pci_dev(edev); + if (pdev) + bus = pdev->bus; +- pci_unlock_rescan_remove(); ++ if (do_lock) ++ pci_unlock_rescan_remove(); + + return bus; + } ++ ++/** ++ * eeh_pe_bus_get - Retrieve PCI bus associated with the given EEH PE, locking ++ * if needed ++ * @pe: Pointer to the EEH PE ++ * ++ * This function is a wrapper around _eeh_pe_bus_get(), which retrieves the PCI ++ * bus associated with the provided EEH PE structure. It acquires the PCI ++ * rescans lock to ensure safe access to shared data during the retrieval ++ * process. This function should be used when the caller requires the PCI bus ++ * while holding the rescan/remove lock, typically during operations that modify ++ * or inspect PCIe device state in a safe manner. ++ * ++ * RETURNS: ++ * A pointer to the PCI bus associated with the EEH PE, or NULL if none found. ++ */ ++ ++struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe) ++{ ++ return _eeh_pe_bus_get(pe, true); ++} ++ ++/** ++ * eeh_pe_bus_get_nolock - Retrieve PCI bus associated with the given EEH PE ++ * without locking ++ * @pe: Pointer to the EEH PE ++ * ++ * This function is a variant of _eeh_pe_bus_get() that retrieves the PCI bus ++ * associated with the specified EEH PE without acquiring the ++ * pci_lock_rescan_remove lock. It should only be used when the caller can ++ * guarantee safe access to PE structures without the need for that lock, ++ * typically in contexts where the lock is already held locking is otherwise ++ * managed. ++ * ++ * RETURNS: ++ * pointer to the PCI bus associated with the EEH PE, or NULL if none is found. ++ * ++ * NOTE: ++ * Use this function carefully to avoid race conditions and data corruption. ++ */ ++ ++struct pci_bus *eeh_pe_bus_get_nolock(struct eeh_pe *pe) ++{ ++ return _eeh_pe_bus_get(pe, false); ++} +-- +2.51.0 + diff --git a/queue-6.6/powerpc-uaccess-move-barrier_nospec-out-of-allow_rea.patch b/queue-6.6/powerpc-uaccess-move-barrier_nospec-out-of-allow_rea.patch new file mode 100644 index 0000000000..50e15a3f84 --- /dev/null +++ b/queue-6.6/powerpc-uaccess-move-barrier_nospec-out-of-allow_rea.patch @@ -0,0 +1,98 @@ +From e938818e12523a76eafb184df9a1496263c35fa0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Dec 2025 12:20:49 +0100 +Subject: powerpc/uaccess: Move barrier_nospec() out of + allow_read_{from/write}_user() + +From: Christophe Leroy + +[ Upstream commit 5fbc09eb0b4f4b1a4b33abebacbeee0d29f195e9 ] + +Commit 74e19ef0ff80 ("uaccess: Add speculation barrier to +copy_from_user()") added a redundant barrier_nospec() in +copy_from_user(), because powerpc is already calling +barrier_nospec() in allow_read_from_user() and +allow_read_write_user(). But on other architectures that +call to barrier_nospec() was missing. So change powerpc +instead of reverting the above commit and having to fix +other architectures one by one. This is now possible +because barrier_nospec() has also been added in +copy_from_user_iter(). + +Move barrier_nospec() out of allow_read_from_user() and +allow_read_write_user(). This will also allow reuse of those +functions when implementing masked user access which doesn't +require barrier_nospec(). + +Don't add it back in raw_copy_from_user() as it is already called +by copy_from_user() and copy_from_user_iter(). + +Fixes: 74e19ef0ff80 ("uaccess: Add speculation barrier to copy_from_user()") +Signed-off-by: Christophe Leroy +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/f29612105c5fcbc8ceb7303808ddc1a781f0f6b5.1766574657.git.chleroy@kernel.org +Signed-off-by: Sasha Levin +--- + arch/powerpc/include/asm/kup.h | 2 -- + arch/powerpc/include/asm/uaccess.h | 4 ++++ + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/arch/powerpc/include/asm/kup.h b/arch/powerpc/include/asm/kup.h +index ad7e8c5aec3f8..63223b7e520f0 100644 +--- a/arch/powerpc/include/asm/kup.h ++++ b/arch/powerpc/include/asm/kup.h +@@ -134,7 +134,6 @@ static __always_inline void kuap_assert_locked(void) + + static __always_inline void allow_read_from_user(const void __user *from, unsigned long size) + { +- barrier_nospec(); + allow_user_access(NULL, from, size, KUAP_READ); + } + +@@ -146,7 +145,6 @@ static __always_inline void allow_write_to_user(void __user *to, unsigned long s + static __always_inline void allow_read_write_user(void __user *to, const void __user *from, + unsigned long size) + { +- barrier_nospec(); + allow_user_access(to, from, size, KUAP_READ_WRITE); + } + +diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h +index a81bd825087cd..ec7f001d03d01 100644 +--- a/arch/powerpc/include/asm/uaccess.h ++++ b/arch/powerpc/include/asm/uaccess.h +@@ -290,6 +290,7 @@ do { \ + __typeof__(sizeof(*(ptr))) __gu_size = sizeof(*(ptr)); \ + \ + might_fault(); \ ++ barrier_nospec(); \ + allow_read_from_user(__gu_addr, __gu_size); \ + __get_user_size_allowed(__gu_val, __gu_addr, __gu_size, __gu_err); \ + prevent_read_from_user(__gu_addr, __gu_size); \ +@@ -318,6 +319,7 @@ raw_copy_in_user(void __user *to, const void __user *from, unsigned long n) + { + unsigned long ret; + ++ barrier_nospec(); + allow_read_write_user(to, from, n); + ret = __copy_tofrom_user(to, from, n); + prevent_read_write_user(to, from, n); +@@ -404,6 +406,7 @@ static __must_check __always_inline bool user_access_begin(const void __user *pt + + might_fault(); + ++ barrier_nospec(); + allow_read_write_user((void __user *)ptr, ptr, len); + return true; + } +@@ -420,6 +423,7 @@ user_read_access_begin(const void __user *ptr, size_t len) + + might_fault(); + ++ barrier_nospec(); + allow_read_from_user(ptr, len); + return true; + } +-- +2.51.0 + diff --git a/queue-6.6/procfs-fix-missing-rcu-protection-when-reading-real_.patch b/queue-6.6/procfs-fix-missing-rcu-protection-when-reading-real_.patch new file mode 100644 index 0000000000..5de6aaccb8 --- /dev/null +++ b/queue-6.6/procfs-fix-missing-rcu-protection-when-reading-real_.patch @@ -0,0 +1,59 @@ +From dcf3692dbdc496dd8434f2108bdb3a31f18bf4bb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 16:30:07 +0800 +Subject: procfs: fix missing RCU protection when reading real_parent in + do_task_stat() + +From: Jinliang Zheng + +[ Upstream commit 76149d53502cf17ef3ae454ff384551236fba867 ] + +When reading /proc/[pid]/stat, do_task_stat() accesses task->real_parent +without proper RCU protection, which leads to: + + cpu 0 cpu 1 + ----- ----- + do_task_stat + var = task->real_parent + release_task + call_rcu(delayed_put_task_struct) + task_tgid_nr_ns(var) + rcu_read_lock <--- Too late to protect task->real_parent! + task_pid_ptr <--- UAF! + rcu_read_unlock + +This patch uses task_ppid_nr_ns() instead of task_tgid_nr_ns() to add +proper RCU protection for accessing task->real_parent. + +Link: https://lkml.kernel.org/r/20260128083007.3173016-1-alexjlzheng@tencent.com +Fixes: 06fffb1267c9 ("do_task_stat: don't take rcu_read_lock()") +Signed-off-by: Jinliang Zheng +Acked-by: Oleg Nesterov +Cc: David Hildenbrand +Cc: Ingo Molnar +Cc: Lorenzo Stoakes +Cc: Mateusz Guzik +Cc: ruippan +Cc: Usama Arif +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/proc/array.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/proc/array.c b/fs/proc/array.c +index 5e4f7b411fbdb..363d9331216b9 100644 +--- a/fs/proc/array.c ++++ b/fs/proc/array.c +@@ -531,7 +531,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, + } + + sid = task_session_nr_ns(task, ns); +- ppid = task_tgid_nr_ns(task->real_parent, ns); ++ ppid = task_ppid_nr_ns(task, ns); + pgid = task_pgrp_nr_ns(task, ns); + + unlock_task_sighand(task, &flags); +-- +2.51.0 + diff --git a/queue-6.6/pstore-ram-fix-buffer-overflow-in-persistent_ram_sav.patch b/queue-6.6/pstore-ram-fix-buffer-overflow-in-persistent_ram_sav.patch new file mode 100644 index 0000000000..3ba9f3f45b --- /dev/null +++ b/queue-6.6/pstore-ram-fix-buffer-overflow-in-persistent_ram_sav.patch @@ -0,0 +1,92 @@ +From 348aec4badff259cc42d151bb24cefd5fc370e4c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 1 Feb 2026 13:22:40 +0000 +Subject: pstore/ram: fix buffer overflow in persistent_ram_save_old() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Sai Ritvik Tanksalkar + +[ Upstream commit 5669645c052f235726a85f443769b6fc02f66762 ] + +persistent_ram_save_old() can be called multiple times for the same +persistent_ram_zone (e.g., via ramoops_pstore_read -> ramoops_get_next_prz +for PSTORE_TYPE_DMESG records). + +Currently, the function only allocates prz->old_log when it is NULL, +but it unconditionally updates prz->old_log_size to the current buffer +size and then performs memcpy_fromio() using this new size. If the +buffer size has grown since the first allocation (which can happen +across different kernel boot cycles), this leads to: + +1. A heap buffer overflow (OOB write) in the memcpy_fromio() calls +2. A subsequent OOB read when ramoops_pstore_read() accesses the buffer + using the incorrect (larger) old_log_size + +The KASAN splat would look similar to: + BUG: KASAN: slab-out-of-bounds in ramoops_pstore_read+0x... + Read of size N at addr ... by task ... + +The conditions are likely extremely hard to hit: + + 0. Crash with a ramoops write of less-than-record-max-size bytes. + 1. Reboot: ramoops registers, pstore_get_records(0) reads old crash, + allocates old_log with size X + 2. Crash handler registered, timer started (if pstore_update_ms >= 0) + 3. Oops happens (non-fatal, system continues) + 4. pstore_dump() writes oops via ramoops_pstore_write() size Y (>X) + 5. pstore_new_entry = 1, pstore_timer_kick() called + 6. System continues running (not a panic oops) + 7. Timer fires after pstore_update_ms milliseconds + 8. pstore_timefunc() → schedule_work() → pstore_dowork() → pstore_get_records(1) + 9. ramoops_get_next_prz() → persistent_ram_save_old() + 10. buffer_size() returns Y, but old_log is X bytes + 11. Y > X: memcpy_fromio() overflows heap + + Requirements: + - a prior crash record exists that did not fill the record size + (almost impossible since the crash handler writes as much as it + can possibly fit into the record, capped by max record size and + the kmsg buffer almost always exceeds the max record size) + - pstore_update_ms >= 0 (disabled by default) + - Non-fatal oops (system survives) + +Free and reallocate the buffer when the new size differs from the +previously allocated size. This ensures old_log always has sufficient +space for the data being copied. + +Fixes: 201e4aca5aa1 ("pstore/ram: Should update old dmesg buffer before reading") +Signed-off-by: Sai Ritvik Tanksalkar +Link: https://patch.msgid.link/20260201132240.2948732-1-stanksal@purdue.edu +Signed-off-by: Kees Cook +Signed-off-by: Sasha Levin +--- + fs/pstore/ram_core.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c +index f1848cdd6d348..c9eaacdec37e4 100644 +--- a/fs/pstore/ram_core.c ++++ b/fs/pstore/ram_core.c +@@ -298,6 +298,17 @@ void persistent_ram_save_old(struct persistent_ram_zone *prz) + if (!size) + return; + ++ /* ++ * If the existing buffer is differently sized, free it so a new ++ * one is allocated. This can happen when persistent_ram_save_old() ++ * is called early in boot and later for a timer-triggered ++ * survivable crash when the crash dumps don't match in size ++ * (which would be extremely unlikely given kmsg buffers usually ++ * exceed prz buffer sizes). ++ */ ++ if (prz->old_log && prz->old_log_size != size) ++ persistent_ram_free_old(prz); ++ + if (!prz->old_log) { + persistent_ram_ecc_old(prz); + prz->old_log = kvzalloc(size, GFP_KERNEL); +-- +2.51.0 + diff --git a/queue-6.6/quota-fix-livelock-between-quotactl-and-freeze_super.patch b/queue-6.6/quota-fix-livelock-between-quotactl-and-freeze_super.patch new file mode 100644 index 0000000000..448ed1974d --- /dev/null +++ b/queue-6.6/quota-fix-livelock-between-quotactl-and-freeze_super.patch @@ -0,0 +1,73 @@ +From 6cf8607097a66cd8448f2edcd1624867db622635 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 21:31:03 +0000 +Subject: quota: fix livelock between quotactl and freeze_super + +From: Abhishek Bapat + +[ Upstream commit 77449e453dfc006ad738dec55374c4cbc056fd39 ] + +When a filesystem is frozen, quotactl_block() enters a retry loop +waiting for the filesystem to thaw. It acquires s_umount, checks the +freeze state, drops s_umount and uses sb_start_write() - sb_end_write() +pair to wait for the unfreeze. + +However, this retry loop can trigger a livelock issue, specifically on +kernels with preemption disabled. + +The mechanism is as follows: +1. freeze_super() sets SB_FREEZE_WRITE and calls sb_wait_write(). +2. sb_wait_write() calls percpu_down_write(), which initiates + synchronize_rcu(). +3. Simultaneously, quotactl_block() spins in its retry loop, immediately + executing the sb_start_write() - sb_end_write() pair. +4. Because the kernel is non-preemptible and the loop contains no + scheduling points, quotactl_block() never yields the CPU. This + prevents that CPU from reaching an RCU quiescent state. +5. synchronize_rcu() in the freezer thread waits indefinitely for the + quotactl_block() CPU to report a quiescent state. +6. quotactl_block() spins indefinitely waiting for the freezer to + advance, which it cannot do as it is blocked on the RCU sync. + +This results in a hang of the freezer process and 100% CPU usage by the +quota process. + +While this can occur intermittently on multi-core systems, it is +reliably reproducing on a node with the following script, running both +the freezer and the quota toggle on the same CPU: + + # mkfs.ext4 -O quota /dev/sda 2g && mkdir a_mount + # mount /dev/sda -o quota,usrquota,grpquota a_mount + # taskset -c 3 bash -c "while true; do xfs_freeze -f a_mount; \ + xfs_freeze -u a_mount; done" & + # taskset -c 3 bash -c "while true; do quotaon a_mount; \ + quotaoff a_mount; done" & + +Adding cond_resched() to the retry loop fixes the issue. It acts as an +RCU quiescent state, allowing synchronize_rcu() in percpu_down_write() +to complete. + +Fixes: 576215cffdef ("fs: Drop wait_unfrozen wait queue") +Signed-off-by: Abhishek Bapat +Link: https://patch.msgid.link/20260115213103.1089129-1-abhishekbapat@google.com +Signed-off-by: Jan Kara +Signed-off-by: Sasha Levin +--- + fs/quota/quota.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/quota/quota.c b/fs/quota/quota.c +index 0e41fb84060f5..5be53cae2c95d 100644 +--- a/fs/quota/quota.c ++++ b/fs/quota/quota.c +@@ -899,6 +899,7 @@ static struct super_block *quotactl_block(const char __user *special, int cmd) + sb_start_write(sb); + sb_end_write(sb); + put_super(sb); ++ cond_resched(); + goto retry; + } + return sb; +-- +2.51.0 + diff --git a/queue-6.6/rcu-exp-move-expedited-kthread-worker-creation-funct.patch b/queue-6.6/rcu-exp-move-expedited-kthread-worker-creation-funct.patch new file mode 100644 index 0000000000..b481f5fa9f --- /dev/null +++ b/queue-6.6/rcu-exp-move-expedited-kthread-worker-creation-funct.patch @@ -0,0 +1,148 @@ +From 6d5640b776a9099c578f7e4b930aeb1eb9508f59 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 12 Jan 2024 16:46:18 +0100 +Subject: rcu/exp: Move expedited kthread worker creation functions above + rcutree_prepare_cpu() + +From: Frederic Weisbecker + +[ Upstream commit c19e5d3b497a3036f800edf751dc7814e3e887e1 ] + +The expedited kthread worker performing the per node initialization is +going to be split into per node kthreads. As such, the future per node +kthread creation will need to be called from CPU hotplug callbacks +instead of an initcall, right beside the per node boost kthread +creation. + +To prepare for that, move the kthread worker creation above +rcutree_prepare_cpu() as a first step to make the review smoother for +the upcoming modifications. + +No intended functional change. + +Signed-off-by: Frederic Weisbecker +Reviewed-by: Paul E. McKenney +Signed-off-by: Boqun Feng +Stable-dep-of: d41e37f26b31 ("rcu: Fix rcu_read_unlock() deadloop due to softirq") +Signed-off-by: Sasha Levin +--- + kernel/rcu/tree.c | 96 +++++++++++++++++++++++------------------------ + 1 file changed, 48 insertions(+), 48 deletions(-) + +diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c +index 43133dff2a04b..81f0a730c54b2 100644 +--- a/kernel/rcu/tree.c ++++ b/kernel/rcu/tree.c +@@ -4379,6 +4379,54 @@ rcu_boot_init_percpu_data(int cpu) + rcu_boot_init_nocb_percpu_data(rdp); + } + ++#ifdef CONFIG_RCU_EXP_KTHREAD ++struct kthread_worker *rcu_exp_gp_kworker; ++struct kthread_worker *rcu_exp_par_gp_kworker; ++ ++static void __init rcu_start_exp_gp_kworkers(void) ++{ ++ const char *par_gp_kworker_name = "rcu_exp_par_gp_kthread_worker"; ++ const char *gp_kworker_name = "rcu_exp_gp_kthread_worker"; ++ struct sched_param param = { .sched_priority = kthread_prio }; ++ ++ rcu_exp_gp_kworker = kthread_create_worker(0, gp_kworker_name); ++ if (IS_ERR_OR_NULL(rcu_exp_gp_kworker)) { ++ pr_err("Failed to create %s!\n", gp_kworker_name); ++ rcu_exp_gp_kworker = NULL; ++ return; ++ } ++ ++ rcu_exp_par_gp_kworker = kthread_create_worker(0, par_gp_kworker_name); ++ if (IS_ERR_OR_NULL(rcu_exp_par_gp_kworker)) { ++ pr_err("Failed to create %s!\n", par_gp_kworker_name); ++ rcu_exp_par_gp_kworker = NULL; ++ kthread_destroy_worker(rcu_exp_gp_kworker); ++ rcu_exp_gp_kworker = NULL; ++ return; ++ } ++ ++ sched_setscheduler_nocheck(rcu_exp_gp_kworker->task, SCHED_FIFO, ¶m); ++ sched_setscheduler_nocheck(rcu_exp_par_gp_kworker->task, SCHED_FIFO, ++ ¶m); ++} ++ ++static inline void rcu_alloc_par_gp_wq(void) ++{ ++} ++#else /* !CONFIG_RCU_EXP_KTHREAD */ ++struct workqueue_struct *rcu_par_gp_wq; ++ ++static void __init rcu_start_exp_gp_kworkers(void) ++{ ++} ++ ++static inline void rcu_alloc_par_gp_wq(void) ++{ ++ rcu_par_gp_wq = alloc_workqueue("rcu_par_gp", WQ_MEM_RECLAIM, 0); ++ WARN_ON(!rcu_par_gp_wq); ++} ++#endif /* CONFIG_RCU_EXP_KTHREAD */ ++ + /* + * Invoked early in the CPU-online process, when pretty much all services + * are available. The incoming CPU is not present. +@@ -4686,54 +4734,6 @@ static int rcu_pm_notify(struct notifier_block *self, + return NOTIFY_OK; + } + +-#ifdef CONFIG_RCU_EXP_KTHREAD +-struct kthread_worker *rcu_exp_gp_kworker; +-struct kthread_worker *rcu_exp_par_gp_kworker; +- +-static void __init rcu_start_exp_gp_kworkers(void) +-{ +- const char *par_gp_kworker_name = "rcu_exp_par_gp_kthread_worker"; +- const char *gp_kworker_name = "rcu_exp_gp_kthread_worker"; +- struct sched_param param = { .sched_priority = kthread_prio }; +- +- rcu_exp_gp_kworker = kthread_create_worker(0, gp_kworker_name); +- if (IS_ERR_OR_NULL(rcu_exp_gp_kworker)) { +- pr_err("Failed to create %s!\n", gp_kworker_name); +- rcu_exp_gp_kworker = NULL; +- return; +- } +- +- rcu_exp_par_gp_kworker = kthread_create_worker(0, par_gp_kworker_name); +- if (IS_ERR_OR_NULL(rcu_exp_par_gp_kworker)) { +- pr_err("Failed to create %s!\n", par_gp_kworker_name); +- rcu_exp_par_gp_kworker = NULL; +- kthread_destroy_worker(rcu_exp_gp_kworker); +- rcu_exp_gp_kworker = NULL; +- return; +- } +- +- sched_setscheduler_nocheck(rcu_exp_gp_kworker->task, SCHED_FIFO, ¶m); +- sched_setscheduler_nocheck(rcu_exp_par_gp_kworker->task, SCHED_FIFO, +- ¶m); +-} +- +-static inline void rcu_alloc_par_gp_wq(void) +-{ +-} +-#else /* !CONFIG_RCU_EXP_KTHREAD */ +-struct workqueue_struct *rcu_par_gp_wq; +- +-static void __init rcu_start_exp_gp_kworkers(void) +-{ +-} +- +-static inline void rcu_alloc_par_gp_wq(void) +-{ +- rcu_par_gp_wq = alloc_workqueue("rcu_par_gp", WQ_MEM_RECLAIM, 0); +- WARN_ON(!rcu_par_gp_wq); +-} +-#endif /* CONFIG_RCU_EXP_KTHREAD */ +- + /* + * Spawn the kthreads that handle RCU's grace periods. + */ +-- +2.51.0 + diff --git a/queue-6.6/rcu-fix-rcu_read_unlock-deadloop-due-to-softirq.patch b/queue-6.6/rcu-fix-rcu_read_unlock-deadloop-due-to-softirq.patch new file mode 100644 index 0000000000..48b07b866c --- /dev/null +++ b/queue-6.6/rcu-fix-rcu_read_unlock-deadloop-due-to-softirq.patch @@ -0,0 +1,168 @@ +From d66f1a4a29483f3f4ec02bed44e2964ee18c88d8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 1 Jan 2026 11:34:10 -0500 +Subject: rcu: Fix rcu_read_unlock() deadloop due to softirq + +From: Yao Kai + +[ Upstream commit d41e37f26b3157b3f1d10223863519a943aa239b ] + +Commit 5f5fa7ea89dc ("rcu: Don't use negative nesting depth in +__rcu_read_unlock()") removes the recursion-protection code from +__rcu_read_unlock(). Therefore, we could invoke the deadloop in +raise_softirq_irqoff() with ftrace enabled as follows: + +WARNING: CPU: 0 PID: 0 at kernel/trace/trace.c:3021 __ftrace_trace_stack.constprop.0+0x172/0x180 +Modules linked in: my_irq_work(O) +CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Tainted: G O 6.18.0-rc7-dirty #23 PREEMPT(full) +Tainted: [O]=OOT_MODULE +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014 +RIP: 0010:__ftrace_trace_stack.constprop.0+0x172/0x180 +RSP: 0018:ffffc900000034a8 EFLAGS: 00010002 +RAX: 0000000000000000 RBX: 0000000000000004 RCX: 0000000000000000 +RDX: 0000000000000003 RSI: ffffffff826d7b87 RDI: ffffffff826e9329 +RBP: 0000000000090009 R08: 0000000000000005 R09: ffffffff82afbc4c +R10: 0000000000000008 R11: 0000000000011d7a R12: 0000000000000000 +R13: ffff888003874100 R14: 0000000000000003 R15: ffff8880038c1054 +FS: 0000000000000000(0000) GS:ffff8880fa8ea000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 000055b31fa7f540 CR3: 00000000078f4005 CR4: 0000000000770ef0 +PKRU: 55555554 +Call Trace: + + trace_buffer_unlock_commit_regs+0x6d/0x220 + trace_event_buffer_commit+0x5c/0x260 + trace_event_raw_event_softirq+0x47/0x80 + raise_softirq_irqoff+0x6e/0xa0 + rcu_read_unlock_special+0xb1/0x160 + unwind_next_frame+0x203/0x9b0 + __unwind_start+0x15d/0x1c0 + arch_stack_walk+0x62/0xf0 + stack_trace_save+0x48/0x70 + __ftrace_trace_stack.constprop.0+0x144/0x180 + trace_buffer_unlock_commit_regs+0x6d/0x220 + trace_event_buffer_commit+0x5c/0x260 + trace_event_raw_event_softirq+0x47/0x80 + raise_softirq_irqoff+0x6e/0xa0 + rcu_read_unlock_special+0xb1/0x160 + unwind_next_frame+0x203/0x9b0 + __unwind_start+0x15d/0x1c0 + arch_stack_walk+0x62/0xf0 + stack_trace_save+0x48/0x70 + __ftrace_trace_stack.constprop.0+0x144/0x180 + trace_buffer_unlock_commit_regs+0x6d/0x220 + trace_event_buffer_commit+0x5c/0x260 + trace_event_raw_event_softirq+0x47/0x80 + raise_softirq_irqoff+0x6e/0xa0 + rcu_read_unlock_special+0xb1/0x160 + unwind_next_frame+0x203/0x9b0 + __unwind_start+0x15d/0x1c0 + arch_stack_walk+0x62/0xf0 + stack_trace_save+0x48/0x70 + __ftrace_trace_stack.constprop.0+0x144/0x180 + trace_buffer_unlock_commit_regs+0x6d/0x220 + trace_event_buffer_commit+0x5c/0x260 + trace_event_raw_event_softirq+0x47/0x80 + raise_softirq_irqoff+0x6e/0xa0 + rcu_read_unlock_special+0xb1/0x160 + __is_insn_slot_addr+0x54/0x70 + kernel_text_address+0x48/0xc0 + __kernel_text_address+0xd/0x40 + unwind_get_return_address+0x1e/0x40 + arch_stack_walk+0x9c/0xf0 + stack_trace_save+0x48/0x70 + __ftrace_trace_stack.constprop.0+0x144/0x180 + trace_buffer_unlock_commit_regs+0x6d/0x220 + trace_event_buffer_commit+0x5c/0x260 + trace_event_raw_event_softirq+0x47/0x80 + __raise_softirq_irqoff+0x61/0x80 + __flush_smp_call_function_queue+0x115/0x420 + __sysvec_call_function_single+0x17/0xb0 + sysvec_call_function_single+0x8c/0xc0 + + +Commit b41642c87716 ("rcu: Fix rcu_read_unlock() deadloop due to IRQ work") +fixed the infinite loop in rcu_read_unlock_special() for IRQ work by +setting a flag before calling irq_work_queue_on(). We fix this issue by +setting the same flag before calling raise_softirq_irqoff() and rename the +flag to defer_qs_pending for more common. + +Fixes: 5f5fa7ea89dc ("rcu: Don't use negative nesting depth in __rcu_read_unlock()") +Reported-by: Tengda Wu +Signed-off-by: Yao Kai +Reviewed-by: Joel Fernandes +Tested-by: Paul E. McKenney +Signed-off-by: Joel Fernandes +Signed-off-by: Boqun Feng +Signed-off-by: Sasha Levin +--- + kernel/rcu/tree.h | 2 +- + kernel/rcu/tree_plugin.h | 15 +++++++++------ + 2 files changed, 10 insertions(+), 7 deletions(-) + +diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h +index f8408e7a5f824..b79599b2059cc 100644 +--- a/kernel/rcu/tree.h ++++ b/kernel/rcu/tree.h +@@ -203,7 +203,7 @@ struct rcu_data { + /* during and after the last grace */ + /* period it is aware of. */ + struct irq_work defer_qs_iw; /* Obtain later scheduler attention. */ +- int defer_qs_iw_pending; /* Scheduler attention pending? */ ++ int defer_qs_pending; /* irqwork or softirq pending? */ + struct work_struct strict_work; /* Schedule readers for strict GPs. */ + + /* 2) batch handling */ +diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h +index 04044b492cc31..8cf1adcd259ba 100644 +--- a/kernel/rcu/tree_plugin.h ++++ b/kernel/rcu/tree_plugin.h +@@ -475,8 +475,8 @@ rcu_preempt_deferred_qs_irqrestore(struct task_struct *t, unsigned long flags) + union rcu_special special; + + rdp = this_cpu_ptr(&rcu_data); +- if (rdp->defer_qs_iw_pending == DEFER_QS_PENDING) +- rdp->defer_qs_iw_pending = DEFER_QS_IDLE; ++ if (rdp->defer_qs_pending == DEFER_QS_PENDING) ++ rdp->defer_qs_pending = DEFER_QS_IDLE; + + /* + * If RCU core is waiting for this CPU to exit its critical section, +@@ -634,7 +634,7 @@ static void rcu_preempt_deferred_qs_handler(struct irq_work *iwp) + * 5. Deferred QS reporting does not happen. + */ + if (rcu_preempt_depth() > 0) +- WRITE_ONCE(rdp->defer_qs_iw_pending, DEFER_QS_IDLE); ++ WRITE_ONCE(rdp->defer_qs_pending, DEFER_QS_IDLE); + } + + /* +@@ -736,7 +736,10 @@ static void rcu_read_unlock_special(struct task_struct *t) + // Using softirq, safe to awaken, and either the + // wakeup is free or there is either an expedited + // GP in flight or a potential need to deboost. +- raise_softirq_irqoff(RCU_SOFTIRQ); ++ if (rdp->defer_qs_pending != DEFER_QS_PENDING) { ++ rdp->defer_qs_pending = DEFER_QS_PENDING; ++ raise_softirq_irqoff(RCU_SOFTIRQ); ++ } + } else { + // Enabling BH or preempt does reschedule, so... + // Also if no expediting and no possible deboosting, +@@ -745,11 +748,11 @@ static void rcu_read_unlock_special(struct task_struct *t) + set_tsk_need_resched(current); + set_preempt_need_resched(); + if (IS_ENABLED(CONFIG_IRQ_WORK) && irqs_were_disabled && +- needs_exp && rdp->defer_qs_iw_pending != DEFER_QS_PENDING && ++ needs_exp && rdp->defer_qs_pending != DEFER_QS_PENDING && + cpu_online(rdp->cpu)) { + // Get scheduler to re-evaluate and call hooks. + // If !IRQ_WORK, FQS scan will eventually IPI. +- rdp->defer_qs_iw_pending = DEFER_QS_PENDING; ++ rdp->defer_qs_pending = DEFER_QS_PENDING; + irq_work_queue_on(&rdp->defer_qs_iw, rdp->cpu); + } + } +-- +2.51.0 + diff --git a/queue-6.6/rcu-refactor-expedited-handling-check-in-rcu_read_un.patch b/queue-6.6/rcu-refactor-expedited-handling-check-in-rcu_read_un.patch new file mode 100644 index 0000000000..940b7fda46 --- /dev/null +++ b/queue-6.6/rcu-refactor-expedited-handling-check-in-rcu_read_un.patch @@ -0,0 +1,139 @@ +From 8883794369d757e0cb39a15a13ee6d95649b8567 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 15 Jul 2025 16:01:52 -0400 +Subject: rcu: Refactor expedited handling check in rcu_read_unlock_special() + +From: Joel Fernandes + +[ Upstream commit 908a97eba8c8b510996bf5d77d1e3070d59caa6d ] + +Extract the complex expedited handling condition in rcu_read_unlock_special() +into a separate function rcu_unlock_needs_exp_handling() with detailed +comments explaining each condition. + +This improves code readability. No functional change intended. + +Reviewed-by: "Paul E. McKenney" +Signed-off-by: Joel Fernandes +Signed-off-by: Neeraj Upadhyay (AMD) +Stable-dep-of: d41e37f26b31 ("rcu: Fix rcu_read_unlock() deadloop due to softirq") +Signed-off-by: Sasha Levin +--- + kernel/rcu/tree_plugin.h | 83 +++++++++++++++++++++++++++++++++++----- + 1 file changed, 74 insertions(+), 9 deletions(-) + +diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h +index f178a8bb83650..18a8fd116fdff 100644 +--- a/kernel/rcu/tree_plugin.h ++++ b/kernel/rcu/tree_plugin.h +@@ -640,6 +640,75 @@ static void rcu_preempt_deferred_qs_handler(struct irq_work *iwp) + local_irq_restore(flags); + } + ++/* ++ * Check if expedited grace period processing during unlock is needed. ++ * ++ * This function determines whether expedited handling is required based on: ++ * 1. Task blocking an expedited grace period (based on a heuristic, could be ++ * false-positive, see below.) ++ * 2. CPU participating in an expedited grace period ++ * 3. Strict grace period mode requiring expedited handling ++ * 4. RCU priority deboosting needs when interrupts were disabled ++ * ++ * @t: The task being checked ++ * @rdp: The per-CPU RCU data ++ * @rnp: The RCU node for this CPU ++ * @irqs_were_disabled: Whether interrupts were disabled before rcu_read_unlock() ++ * ++ * Returns true if expedited processing of the rcu_read_unlock() is needed. ++ */ ++static bool rcu_unlock_needs_exp_handling(struct task_struct *t, ++ struct rcu_data *rdp, ++ struct rcu_node *rnp, ++ bool irqs_were_disabled) ++{ ++ /* ++ * Check if this task is blocking an expedited grace period. If the ++ * task was preempted within an RCU read-side critical section and is ++ * on the expedited grace period blockers list (exp_tasks), we need ++ * expedited handling to unblock the expedited GP. This is not an exact ++ * check because 't' might not be on the exp_tasks list at all - its ++ * just a fast heuristic that can be false-positive sometimes. ++ */ ++ if (t->rcu_blocked_node && READ_ONCE(t->rcu_blocked_node->exp_tasks)) ++ return true; ++ ++ /* ++ * Check if this CPU is participating in an expedited grace period. ++ * The expmask bitmap tracks which CPUs need to check in for the ++ * current expedited GP. If our CPU's bit is set, we need expedited ++ * handling to help complete the expedited GP. ++ */ ++ if (rdp->grpmask & READ_ONCE(rnp->expmask)) ++ return true; ++ ++ /* ++ * In CONFIG_RCU_STRICT_GRACE_PERIOD=y kernels, all grace periods ++ * are treated as short for testing purposes even if that means ++ * disturbing the system more. Check if either: ++ * - This CPU has not yet reported a quiescent state, or ++ * - This task was preempted within an RCU critical section ++ * In either case, require expedited handling for strict GP mode. ++ */ ++ if (IS_ENABLED(CONFIG_RCU_STRICT_GRACE_PERIOD) && ++ ((rdp->grpmask & READ_ONCE(rnp->qsmask)) || t->rcu_blocked_node)) ++ return true; ++ ++ /* ++ * RCU priority boosting case: If a task is subject to RCU priority ++ * boosting and exits an RCU read-side critical section with interrupts ++ * disabled, we need expedited handling to ensure timely deboosting. ++ * Without this, a low-priority task could incorrectly run at high ++ * real-time priority for an extended period degrading real-time ++ * responsiveness. This applies to all CONFIG_RCU_BOOST=y kernels, ++ * not just to PREEMPT_RT. ++ */ ++ if (IS_ENABLED(CONFIG_RCU_BOOST) && irqs_were_disabled && t->rcu_blocked_node) ++ return true; ++ ++ return false; ++} ++ + /* + * Handle special cases during rcu_read_unlock(), such as needing to + * notify RCU core processing or task having blocked during the RCU +@@ -659,18 +728,14 @@ static void rcu_read_unlock_special(struct task_struct *t) + local_irq_save(flags); + irqs_were_disabled = irqs_disabled_flags(flags); + if (preempt_bh_were_disabled || irqs_were_disabled) { +- bool expboost; // Expedited GP in flight or possible boosting. ++ bool needs_exp; // Expedited handling needed. + struct rcu_data *rdp = this_cpu_ptr(&rcu_data); + struct rcu_node *rnp = rdp->mynode; + +- expboost = (t->rcu_blocked_node && READ_ONCE(t->rcu_blocked_node->exp_tasks)) || +- (rdp->grpmask & READ_ONCE(rnp->expmask)) || +- (IS_ENABLED(CONFIG_RCU_STRICT_GRACE_PERIOD) && +- ((rdp->grpmask & READ_ONCE(rnp->qsmask)) || t->rcu_blocked_node)) || +- (IS_ENABLED(CONFIG_RCU_BOOST) && irqs_were_disabled && +- t->rcu_blocked_node); ++ needs_exp = rcu_unlock_needs_exp_handling(t, rdp, rnp, irqs_were_disabled); ++ + // Need to defer quiescent state until everything is enabled. +- if (use_softirq && (in_hardirq() || (expboost && !irqs_were_disabled))) { ++ if (use_softirq && (in_hardirq() || (needs_exp && !irqs_were_disabled))) { + // Using softirq, safe to awaken, and either the + // wakeup is free or there is either an expedited + // GP in flight or a potential need to deboost. +@@ -683,7 +748,7 @@ static void rcu_read_unlock_special(struct task_struct *t) + set_tsk_need_resched(current); + set_preempt_need_resched(); + if (IS_ENABLED(CONFIG_IRQ_WORK) && irqs_were_disabled && +- expboost && rdp->defer_qs_iw_pending != DEFER_QS_PENDING && ++ needs_exp && rdp->defer_qs_iw_pending != DEFER_QS_PENDING && + cpu_online(rdp->cpu)) { + // Get scheduler to re-evaluate and call hooks. + // If !IRQ_WORK, FQS scan will eventually IPI. +-- +2.51.0 + diff --git a/queue-6.6/rcu-remove-local_irq_save-restore-in-rcu_preempt_def.patch b/queue-6.6/rcu-remove-local_irq_save-restore-in-rcu_preempt_def.patch new file mode 100644 index 0000000000..4bbcbb1da4 --- /dev/null +++ b/queue-6.6/rcu-remove-local_irq_save-restore-in-rcu_preempt_def.patch @@ -0,0 +1,55 @@ +From b0262a7c545200a9bcc19e952a841d022d0f9a35 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 Aug 2025 21:30:02 +0800 +Subject: rcu: Remove local_irq_save/restore() in + rcu_preempt_deferred_qs_handler() + +From: Zqiang + +[ Upstream commit 42d590d100f2e47e47d974a902b9ed610e464824 ] + +The per-CPU rcu_data structure's ->defer_qs_iw field is initialized +by IRQ_WORK_INIT_HARD(), which means that the subsequent invocation of +rcu_preempt_deferred_qs_handler() will always be executed with interrupts +disabled. This commit therefore removes the local_irq_save/restore() +operations from rcu_preempt_deferred_qs_handler() and adds a call to +lockdep_assert_irqs_disabled() in order to enable lockdep to diagnose +mistaken invocations of this function from interrupts-enabled code. + +Signed-off-by: Zqiang +Signed-off-by: Paul E. McKenney +Stable-dep-of: d41e37f26b31 ("rcu: Fix rcu_read_unlock() deadloop due to softirq") +Signed-off-by: Sasha Levin +--- + kernel/rcu/tree_plugin.h | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h +index 18a8fd116fdff..04044b492cc31 100644 +--- a/kernel/rcu/tree_plugin.h ++++ b/kernel/rcu/tree_plugin.h +@@ -615,11 +615,10 @@ notrace void rcu_preempt_deferred_qs(struct task_struct *t) + */ + static void rcu_preempt_deferred_qs_handler(struct irq_work *iwp) + { +- unsigned long flags; + struct rcu_data *rdp; + ++ lockdep_assert_irqs_disabled(); + rdp = container_of(iwp, struct rcu_data, defer_qs_iw); +- local_irq_save(flags); + + /* + * If the IRQ work handler happens to run in the middle of RCU read-side +@@ -636,8 +635,6 @@ static void rcu_preempt_deferred_qs_handler(struct irq_work *iwp) + */ + if (rcu_preempt_depth() > 0) + WRITE_ONCE(rdp->defer_qs_iw_pending, DEFER_QS_IDLE); +- +- local_irq_restore(flags); + } + + /* +-- +2.51.0 + diff --git a/queue-6.6/rcu-s-boost_kthread_mutex-kthread_mutex.patch b/queue-6.6/rcu-s-boost_kthread_mutex-kthread_mutex.patch new file mode 100644 index 0000000000..820320ef28 --- /dev/null +++ b/queue-6.6/rcu-s-boost_kthread_mutex-kthread_mutex.patch @@ -0,0 +1,109 @@ +From 2886e111105e3a1f48fe71005385bd6ed8dd7e42 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 12 Jan 2024 16:46:17 +0100 +Subject: rcu: s/boost_kthread_mutex/kthread_mutex + +From: Frederic Weisbecker + +[ Upstream commit 7836b270607676ed1c0c6a4a840a2ede9437a6a1 ] + +This mutex is currently protecting per node boost kthreads creation and +affinity setting across CPU hotplug operations. + +Since the expedited kworkers will soon be split per node as well, they +will be subject to the same concurrency constraints against hotplug. + +Therefore their creation and affinity tuning operations will be grouped +with those of boost kthreads and then rely on the same mutex. + +To prepare for that, generalize its name. + +Signed-off-by: Frederic Weisbecker +Reviewed-by: Paul E. McKenney +Signed-off-by: Boqun Feng +Stable-dep-of: d41e37f26b31 ("rcu: Fix rcu_read_unlock() deadloop due to softirq") +Signed-off-by: Sasha Levin +--- + kernel/rcu/tree.c | 2 +- + kernel/rcu/tree.h | 2 +- + kernel/rcu/tree_plugin.h | 10 +++++----- + 3 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c +index 607b2e68fa4c2..43133dff2a04b 100644 +--- a/kernel/rcu/tree.c ++++ b/kernel/rcu/tree.c +@@ -4874,7 +4874,7 @@ static void __init rcu_init_one(void) + init_waitqueue_head(&rnp->exp_wq[2]); + init_waitqueue_head(&rnp->exp_wq[3]); + spin_lock_init(&rnp->exp_lock); +- mutex_init(&rnp->boost_kthread_mutex); ++ mutex_init(&rnp->kthread_mutex); + raw_spin_lock_init(&rnp->exp_poll_lock); + rnp->exp_seq_poll_rq = RCU_GET_STATE_COMPLETED; + INIT_WORK(&rnp->exp_poll_wq, sync_rcu_do_polled_gp); +diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h +index 71403d22a8465..f8408e7a5f824 100644 +--- a/kernel/rcu/tree.h ++++ b/kernel/rcu/tree.h +@@ -113,7 +113,7 @@ struct rcu_node { + /* side effect, not as a lock. */ + unsigned long boost_time; + /* When to start boosting (jiffies). */ +- struct mutex boost_kthread_mutex; ++ struct mutex kthread_mutex; + /* Exclusion for thread spawning and affinity */ + /* manipulation. */ + struct task_struct *boost_kthread_task; +diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h +index 8707f155afb6d..f178a8bb83650 100644 +--- a/kernel/rcu/tree_plugin.h ++++ b/kernel/rcu/tree_plugin.h +@@ -1229,7 +1229,7 @@ static void rcu_spawn_one_boost_kthread(struct rcu_node *rnp) + struct sched_param sp; + struct task_struct *t; + +- mutex_lock(&rnp->boost_kthread_mutex); ++ mutex_lock(&rnp->kthread_mutex); + if (rnp->boost_kthread_task || !rcu_scheduler_fully_active) + goto out; + +@@ -1246,7 +1246,7 @@ static void rcu_spawn_one_boost_kthread(struct rcu_node *rnp) + wake_up_process(t); /* get to TASK_INTERRUPTIBLE quickly. */ + + out: +- mutex_unlock(&rnp->boost_kthread_mutex); ++ mutex_unlock(&rnp->kthread_mutex); + } + + /* +@@ -1258,7 +1258,7 @@ static void rcu_spawn_one_boost_kthread(struct rcu_node *rnp) + * no outgoing CPU. If there are no CPUs left in the affinity set, + * this function allows the kthread to execute on any CPU. + * +- * Any future concurrent calls are serialized via ->boost_kthread_mutex. ++ * Any future concurrent calls are serialized via ->kthread_mutex. + */ + static void rcu_boost_kthread_setaffinity(struct rcu_node *rnp, int outgoingcpu) + { +@@ -1271,7 +1271,7 @@ static void rcu_boost_kthread_setaffinity(struct rcu_node *rnp, int outgoingcpu) + return; + if (!zalloc_cpumask_var(&cm, GFP_KERNEL)) + return; +- mutex_lock(&rnp->boost_kthread_mutex); ++ mutex_lock(&rnp->kthread_mutex); + mask = rcu_rnp_online_cpus(rnp); + for_each_leaf_node_possible_cpu(rnp, cpu) + if ((mask & leaf_node_cpu_bit(rnp, cpu)) && +@@ -1284,7 +1284,7 @@ static void rcu_boost_kthread_setaffinity(struct rcu_node *rnp, int outgoingcpu) + cpumask_clear_cpu(outgoingcpu, cm); + } + set_cpus_allowed_ptr(t, cm); +- mutex_unlock(&rnp->boost_kthread_mutex); ++ mutex_unlock(&rnp->kthread_mutex); + free_cpumask_var(cm); + } + +-- +2.51.0 + diff --git a/queue-6.6/rdma-core-add-rdma_rw_max_sge-helper-for-sq-sizing.patch b/queue-6.6/rdma-core-add-rdma_rw_max_sge-helper-for-sq-sizing.patch new file mode 100644 index 0000000000..58d1feaa12 --- /dev/null +++ b/queue-6.6/rdma-core-add-rdma_rw_max_sge-helper-for-sq-sizing.patch @@ -0,0 +1,159 @@ +From 6b60ac8cfce6fcb66b2e9daa54aa867ac0eb0cd6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 19:53:59 -0500 +Subject: RDMA/core: add rdma_rw_max_sge() helper for SQ sizing + +From: Chuck Lever + +[ Upstream commit afcae7d7b8a278a6c29e064f99e5bafd4ac1fb37 ] + +svc_rdma_accept() computes sc_sq_depth as the sum of rq_depth and the +number of rdma_rw contexts (ctxts). This value is used to allocate the +Send CQ and to initialize the sc_sq_avail credit pool. + +However, when the device uses memory registration for RDMA operations, +rdma_rw_init_qp() inflates the QP's max_send_wr by a factor of three +per context to account for REG and INV work requests. The Send CQ and +credit pool remain sized for only one work request per context, +causing Send Queue exhaustion under heavy NFS WRITE workloads. + +Introduce rdma_rw_max_sge() to compute the actual number of Send Queue +entries required for a given number of rdma_rw contexts. Upper layer +protocols call this helper before creating a Queue Pair so that their +Send CQs and credit accounting match the QP's true capacity. + +Update svc_rdma_accept() to use rdma_rw_max_sge() when computing +sc_sq_depth, ensuring the credit pool reflects the work requests +that rdma_rw_init_qp() will reserve. + +Reviewed-by: Christoph Hellwig +Fixes: 00bd1439f464 ("RDMA/rw: Support threshold for registration vs scattering to local pages") +Signed-off-by: Chuck Lever +Link: https://patch.msgid.link/20260128005400.25147-5-cel@kernel.org +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/rw.c | 53 +++++++++++++++++------- + include/rdma/rw.h | 2 + + net/sunrpc/xprtrdma/svc_rdma_transport.c | 8 +++- + 3 files changed, 46 insertions(+), 17 deletions(-) + +diff --git a/drivers/infiniband/core/rw.c b/drivers/infiniband/core/rw.c +index 6354ddf2a274c..2522ff1cc462c 100644 +--- a/drivers/infiniband/core/rw.c ++++ b/drivers/infiniband/core/rw.c +@@ -651,34 +651,57 @@ unsigned int rdma_rw_mr_factor(struct ib_device *device, u32 port_num, + } + EXPORT_SYMBOL(rdma_rw_mr_factor); + ++/** ++ * rdma_rw_max_send_wr - compute max Send WRs needed for RDMA R/W contexts ++ * @dev: RDMA device ++ * @port_num: port number ++ * @max_rdma_ctxs: number of rdma_rw_ctx structures ++ * @create_flags: QP create flags (pass IB_QP_CREATE_INTEGRITY_EN if ++ * data integrity will be enabled on the QP) ++ * ++ * Returns the total number of Send Queue entries needed for ++ * @max_rdma_ctxs. The result accounts for memory registration and ++ * invalidation work requests when the device requires them. ++ * ++ * ULPs use this to size Send Queues and Send CQs before creating a ++ * Queue Pair. ++ */ ++unsigned int rdma_rw_max_send_wr(struct ib_device *dev, u32 port_num, ++ unsigned int max_rdma_ctxs, u32 create_flags) ++{ ++ unsigned int factor = 1; ++ unsigned int result; ++ ++ if (create_flags & IB_QP_CREATE_INTEGRITY_EN || ++ rdma_rw_can_use_mr(dev, port_num)) ++ factor += 2; /* reg + inv */ ++ ++ if (check_mul_overflow(factor, max_rdma_ctxs, &result)) ++ return UINT_MAX; ++ return result; ++} ++EXPORT_SYMBOL(rdma_rw_max_send_wr); ++ + void rdma_rw_init_qp(struct ib_device *dev, struct ib_qp_init_attr *attr) + { +- u32 factor; ++ unsigned int factor = 1; + + WARN_ON_ONCE(attr->port_num == 0); + + /* +- * Each context needs at least one RDMA READ or WRITE WR. +- * +- * For some hardware we might need more, eventually we should ask the +- * HCA driver for a multiplier here. +- */ +- factor = 1; +- +- /* +- * If the device needs MRs to perform RDMA READ or WRITE operations, +- * we'll need two additional MRs for the registrations and the +- * invalidation. ++ * If the device uses MRs to perform RDMA READ or WRITE operations, ++ * or if data integrity is enabled, account for registration and ++ * invalidation work requests. + */ + if (attr->create_flags & IB_QP_CREATE_INTEGRITY_EN || + rdma_rw_can_use_mr(dev, attr->port_num)) +- factor += 2; /* inv + reg */ ++ factor += 2; /* reg + inv */ + + attr->cap.max_send_wr += factor * attr->cap.max_rdma_ctxs; + + /* +- * But maybe we were just too high in the sky and the device doesn't +- * even support all we need, and we'll have to live with what we get.. ++ * The device might not support all we need, and we'll have to ++ * live with what we get. + */ + attr->cap.max_send_wr = + min_t(u32, attr->cap.max_send_wr, dev->attrs.max_qp_wr); +diff --git a/include/rdma/rw.h b/include/rdma/rw.h +index d606cac482338..9a8f4b76ce588 100644 +--- a/include/rdma/rw.h ++++ b/include/rdma/rw.h +@@ -66,6 +66,8 @@ int rdma_rw_ctx_post(struct rdma_rw_ctx *ctx, struct ib_qp *qp, u32 port_num, + + unsigned int rdma_rw_mr_factor(struct ib_device *device, u32 port_num, + unsigned int maxpages); ++unsigned int rdma_rw_max_send_wr(struct ib_device *dev, u32 port_num, ++ unsigned int max_rdma_ctxs, u32 create_flags); + void rdma_rw_init_qp(struct ib_device *dev, struct ib_qp_init_attr *attr); + int rdma_rw_init_mrs(struct ib_qp *qp, struct ib_qp_init_attr *attr); + void rdma_rw_cleanup_mrs(struct ib_qp *qp); +diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c +index 7bf4787678f8f..b8d13b522298b 100644 +--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c ++++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c +@@ -416,7 +416,10 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + newxprt->sc_max_bc_requests = 2; + } + +- /* Arbitrary estimate of the needed number of rdma_rw contexts. ++ /* Estimate the needed number of rdma_rw contexts. The maximum ++ * Read and Write chunks have one segment each. Each request ++ * can involve one Read chunk and either a Write chunk or Reply ++ * chunk; thus a factor of three. + */ + maxpayload = min(xprt->xpt_server->sv_max_payload, + RPCSVC_MAXPAYLOAD_RDMA); +@@ -424,7 +427,8 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + rdma_rw_mr_factor(dev, newxprt->sc_port_num, + maxpayload >> PAGE_SHIFT); + +- newxprt->sc_sq_depth = rq_depth + ctxts; ++ newxprt->sc_sq_depth = rq_depth + ++ rdma_rw_max_send_wr(dev, newxprt->sc_port_num, ctxts, 0); + if (newxprt->sc_sq_depth > dev->attrs.max_qp_wr) + newxprt->sc_sq_depth = dev->attrs.max_qp_wr; + atomic_set(&newxprt->sc_sq_avail, newxprt->sc_sq_depth); +-- +2.51.0 + diff --git a/queue-6.6/rdma-core-fix-a-couple-of-obvious-typos-in-comments.patch b/queue-6.6/rdma-core-fix-a-couple-of-obvious-typos-in-comments.patch new file mode 100644 index 0000000000..0f01b2cf9a --- /dev/null +++ b/queue-6.6/rdma-core-fix-a-couple-of-obvious-typos-in-comments.patch @@ -0,0 +1,50 @@ +From 00be165807b830f2299178765994a15c45aaca67 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Oct 2023 11:29:41 -0400 +Subject: RDMA/core: Fix a couple of obvious typos in comments + +From: Chuck Lever + +[ Upstream commit 0aa44595d61ca9e61239f321fec799518884feb3 ] + +Fix typos. + +Signed-off-by: Chuck Lever +Link: https://lore.kernel.org/r/169643338101.8035.6826446669479247727.stgit@manet.1015granger.net +Signed-off-by: Leon Romanovsky +Stable-dep-of: afcae7d7b8a2 ("RDMA/core: add rdma_rw_max_sge() helper for SQ sizing") +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/rw.c | 2 +- + include/rdma/ib_verbs.h | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/infiniband/core/rw.c b/drivers/infiniband/core/rw.c +index 8367974b7998b..6354ddf2a274c 100644 +--- a/drivers/infiniband/core/rw.c ++++ b/drivers/infiniband/core/rw.c +@@ -666,7 +666,7 @@ void rdma_rw_init_qp(struct ib_device *dev, struct ib_qp_init_attr *attr) + factor = 1; + + /* +- * If the devices needs MRs to perform RDMA READ or WRITE operations, ++ * If the device needs MRs to perform RDMA READ or WRITE operations, + * we'll need two additional MRs for the registrations and the + * invalidation. + */ +diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h +index de1d88d41270c..038fa78835bed 100644 +--- a/include/rdma/ib_verbs.h ++++ b/include/rdma/ib_verbs.h +@@ -1096,7 +1096,7 @@ struct ib_qp_cap { + + /* + * Maximum number of rdma_rw_ctx structures in flight at a time. +- * ib_create_qp() will calculate the right amount of neededed WRs ++ * ib_create_qp() will calculate the right amount of needed WRs + * and MRs based on this. + */ + u32 max_rdma_ctxs; +-- +2.51.0 + diff --git a/queue-6.6/rdma-hns-fix-wq_mem_reclaim-warning.patch b/queue-6.6/rdma-hns-fix-wq_mem_reclaim-warning.patch new file mode 100644 index 0000000000..296e8a9990 --- /dev/null +++ b/queue-6.6/rdma-hns-fix-wq_mem_reclaim-warning.patch @@ -0,0 +1,62 @@ +From 9c08731b70912e342f6f6c86cc3911b4dc8cba8a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 4 Jan 2026 14:40:54 +0800 +Subject: RDMA/hns: Fix WQ_MEM_RECLAIM warning + +From: Chengchang Tang + +[ Upstream commit c0a26bbd3f99b7b03f072e3409aff4e6ec8af6f6 ] + +When sunrpc is used, if a reset triggered, our wq may lead the +following trace: + +workqueue: WQ_MEM_RECLAIM xprtiod:xprt_rdma_connect_worker [rpcrdma] +is flushing !WQ_MEM_RECLAIM hns_roce_irq_workq:flush_work_handle +[hns_roce_hw_v2] +WARNING: CPU: 0 PID: 8250 at kernel/workqueue.c:2644 check_flush_dependency+0xe0/0x144 +Call trace: + check_flush_dependency+0xe0/0x144 + start_flush_work.constprop.0+0x1d0/0x2f0 + __flush_work.isra.0+0x40/0xb0 + flush_work+0x14/0x30 + hns_roce_v2_destroy_qp+0xac/0x1e0 [hns_roce_hw_v2] + ib_destroy_qp_user+0x9c/0x2b4 + rdma_destroy_qp+0x34/0xb0 + rpcrdma_ep_destroy+0x28/0xcc [rpcrdma] + rpcrdma_ep_put+0x74/0xb4 [rpcrdma] + rpcrdma_xprt_disconnect+0x1d8/0x260 [rpcrdma] + xprt_rdma_connect_worker+0xc0/0x120 [rpcrdma] + process_one_work+0x1cc/0x4d0 + worker_thread+0x154/0x414 + kthread+0x104/0x144 + ret_from_fork+0x10/0x18 + +Since QP destruction frees memory, this wq should have the WQ_MEM_RECLAIM. + +Fixes: ffd541d45726 ("RDMA/hns: Add the workqueue framework for flush cqe handler") +Signed-off-by: Chengchang Tang +Signed-off-by: Junxian Huang +Link: https://patch.msgid.link/20260104064057.1582216-2-huangjunxian6@hisilicon.com +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +index f1d4494c7d008..2d4b751fc709d 100644 +--- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c ++++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +@@ -6604,7 +6604,8 @@ static int hns_roce_v2_init_eq_table(struct hns_roce_dev *hr_dev) + + INIT_WORK(&hr_dev->ecc_work, fmea_ram_ecc_work); + +- hr_dev->irq_workq = alloc_ordered_workqueue("hns_roce_irq_workq", 0); ++ hr_dev->irq_workq = alloc_ordered_workqueue("hns_roce_irq_workq", ++ WQ_MEM_RECLAIM); + if (!hr_dev->irq_workq) { + dev_err(dev, "failed to create irq workqueue.\n"); + ret = -ENOMEM; +-- +2.51.0 + diff --git a/queue-6.6/rdma-hns-notify-ulp-of-remaining-soft-wcs-during-res.patch b/queue-6.6/rdma-hns-notify-ulp-of-remaining-soft-wcs-during-res.patch new file mode 100644 index 0000000000..e1109899fb --- /dev/null +++ b/queue-6.6/rdma-hns-notify-ulp-of-remaining-soft-wcs-during-res.patch @@ -0,0 +1,70 @@ +From af91e224d5417d2ce32c6806123a1cfe2ee6b742 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 4 Jan 2026 14:40:57 +0800 +Subject: RDMA/hns: Notify ULP of remaining soft-WCs during reset + +From: Chengchang Tang + +[ Upstream commit 0789f929900d85b80b343c5f04f8b9444e991384 ] + +During a reset, software-generated WCs cannot be reported via +interrupts. This may cause the ULP to miss some WCs. + +To avoid this, add check in the CQ arm process: if a hardware reset +has occurred and there are still unreported soft-WCs, notify the ULP +to handle the remaining WCs, thereby preventing any loss of completions. + +Fixes: 626903e9355b ("RDMA/hns: Add support for reporting wc as software mode") +Signed-off-by: Chengchang Tang +Signed-off-by: Junxian Huang +Link: https://patch.msgid.link/20260104064057.1582216-5-huangjunxian6@hisilicon.com +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 23 ++++++++++++++++++++++ + 1 file changed, 23 insertions(+) + +diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +index 2d4b751fc709d..b50529a652741 100644 +--- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c ++++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +@@ -3588,6 +3588,23 @@ static void hns_roce_v2_write_cqc(struct hns_roce_dev *hr_dev, + HNS_ROCE_V2_CQ_DEFAULT_INTERVAL); + } + ++static bool left_sw_wc(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq) ++{ ++ struct hns_roce_qp *hr_qp; ++ ++ list_for_each_entry(hr_qp, &hr_cq->sq_list, sq_node) { ++ if (hr_qp->sq.head != hr_qp->sq.tail) ++ return true; ++ } ++ ++ list_for_each_entry(hr_qp, &hr_cq->rq_list, rq_node) { ++ if (hr_qp->rq.head != hr_qp->rq.tail) ++ return true; ++ } ++ ++ return false; ++} ++ + static int hns_roce_v2_req_notify_cq(struct ib_cq *ibcq, + enum ib_cq_notify_flags flags) + { +@@ -3596,6 +3613,12 @@ static int hns_roce_v2_req_notify_cq(struct ib_cq *ibcq, + struct hns_roce_v2_db cq_db = {}; + u32 notify_flag; + ++ if (hr_dev->state >= HNS_ROCE_DEVICE_STATE_RST_DOWN) { ++ if ((flags & IB_CQ_REPORT_MISSED_EVENTS) && ++ left_sw_wc(hr_dev, hr_cq)) ++ return 1; ++ return 0; ++ } + /* + * flags = 0, then notify_flag : next + * flags = 1, then notify flag : solocited +-- +2.51.0 + diff --git a/queue-6.6/rdma-rtrs-server-remove-dead-code.patch b/queue-6.6/rdma-rtrs-server-remove-dead-code.patch new file mode 100644 index 0000000000..58ace2d262 --- /dev/null +++ b/queue-6.6/rdma-rtrs-server-remove-dead-code.patch @@ -0,0 +1,57 @@ +From bd34492c754fe1273c665045e9aa22d2763b666b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Dec 2025 10:38:19 +0800 +Subject: RDMA/rtrs: server: remove dead code + +From: Honggang LI + +[ Upstream commit a3572bdc3a028ca47f77d7166ac95b719cf77d50 ] + +As rkey had been initialized to zero, the WARN_ON_ONCE should never been +triggered. Remove it. + +Fixes: 9cb837480424 ("RDMA/rtrs: server: main functionality") +Signed-off-by: Honggang LI +Link: https://patch.msgid.link/20251224023819.138846-1-honggangli@163.com +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/ulp/rtrs/rtrs-srv.c | 8 +------- + 1 file changed, 1 insertion(+), 7 deletions(-) + +diff --git a/drivers/infiniband/ulp/rtrs/rtrs-srv.c b/drivers/infiniband/ulp/rtrs/rtrs-srv.c +index 5dbf315630c1a..f0beea7b90f25 100644 +--- a/drivers/infiniband/ulp/rtrs/rtrs-srv.c ++++ b/drivers/infiniband/ulp/rtrs/rtrs-srv.c +@@ -205,7 +205,6 @@ static int rdma_write_sg(struct rtrs_srv_op *id) + size_t sg_cnt; + int err, offset; + bool need_inval; +- u32 rkey = 0; + struct ib_reg_wr rwr; + struct ib_sge *plist; + struct ib_sge list; +@@ -237,11 +236,6 @@ static int rdma_write_sg(struct rtrs_srv_op *id) + wr->wr.num_sge = 1; + wr->remote_addr = le64_to_cpu(id->rd_msg->desc[0].addr); + wr->rkey = le32_to_cpu(id->rd_msg->desc[0].key); +- if (rkey == 0) +- rkey = wr->rkey; +- else +- /* Only one key is actually used */ +- WARN_ON_ONCE(rkey != wr->rkey); + + wr->wr.opcode = IB_WR_RDMA_WRITE; + wr->wr.wr_cqe = &io_comp_cqe; +@@ -274,7 +268,7 @@ static int rdma_write_sg(struct rtrs_srv_op *id) + inv_wr.opcode = IB_WR_SEND_WITH_INV; + inv_wr.wr_cqe = &io_comp_cqe; + inv_wr.send_flags = 0; +- inv_wr.ex.invalidate_rkey = rkey; ++ inv_wr.ex.invalidate_rkey = wr->rkey; + } + + imm_wr.wr.next = NULL; +-- +2.51.0 + diff --git a/queue-6.6/rdma-rtrs-srv-fix-sg-mapping.patch b/queue-6.6/rdma-rtrs-srv-fix-sg-mapping.patch new file mode 100644 index 0000000000..c8796911a8 --- /dev/null +++ b/queue-6.6/rdma-rtrs-srv-fix-sg-mapping.patch @@ -0,0 +1,85 @@ +From 393181c11aaf6ab9f740b8af80916b73efdf1610 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 17:15:08 +0100 +Subject: RDMA/rtrs-srv: fix SG mapping + +From: Roman Penyaev + +[ Upstream commit 83835f7c07b523c7ca2a5ad0a511670b5810539e ] + +This fixes the following error on the server side: + + RTRS server session allocation failed: -EINVAL + +caused by the caller of the `ib_dma_map_sg()`, which does not expect +less mapped entries, than requested, which is in the order of things +and can be easily reproduced on the machine with enabled IOMMU. + +The fix is to treat any positive number of mapped sg entries as a +successful mapping and cache DMA addresses by traversing modified +SG table. + +Fixes: 9cb837480424 ("RDMA/rtrs: server: main functionality") +Signed-off-by: Roman Penyaev +Signed-off-by: Jack Wang +Signed-off-by: Grzegorz Prajsner +Link: https://patch.msgid.link/20260107161517.56357-2-haris.iqbal@ionos.com +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/ulp/rtrs/rtrs-srv.c | 25 ++++++++++++++++++++----- + 1 file changed, 20 insertions(+), 5 deletions(-) + +diff --git a/drivers/infiniband/ulp/rtrs/rtrs-srv.c b/drivers/infiniband/ulp/rtrs/rtrs-srv.c +index f0beea7b90f25..2c3c8b32190f8 100644 +--- a/drivers/infiniband/ulp/rtrs/rtrs-srv.c ++++ b/drivers/infiniband/ulp/rtrs/rtrs-srv.c +@@ -592,7 +592,7 @@ static int map_cont_bufs(struct rtrs_srv_path *srv_path) + srv_path->mrs_num++) { + struct rtrs_srv_mr *srv_mr = &srv_path->mrs[srv_path->mrs_num]; + struct scatterlist *s; +- int nr, nr_sgt, chunks; ++ int nr, nr_sgt, chunks, ind; + + sgt = &srv_mr->sgt; + chunks = chunks_per_mr * srv_path->mrs_num; +@@ -622,7 +622,7 @@ static int map_cont_bufs(struct rtrs_srv_path *srv_path) + } + nr = ib_map_mr_sg(mr, sgt->sgl, nr_sgt, + NULL, max_chunk_size); +- if (nr != nr_sgt) { ++ if (nr < nr_sgt) { + err = nr < 0 ? nr : -EINVAL; + goto dereg_mr; + } +@@ -638,9 +638,24 @@ static int map_cont_bufs(struct rtrs_srv_path *srv_path) + goto dereg_mr; + } + } +- /* Eventually dma addr for each chunk can be cached */ +- for_each_sg(sgt->sgl, s, nr_sgt, i) +- srv_path->dma_addr[chunks + i] = sg_dma_address(s); ++ ++ /* ++ * Cache DMA addresses by traversing sg entries. If ++ * regions were merged, an inner loop is required to ++ * populate the DMA address array by traversing larger ++ * regions. ++ */ ++ ind = chunks; ++ for_each_sg(sgt->sgl, s, nr_sgt, i) { ++ unsigned int dma_len = sg_dma_len(s); ++ u64 dma_addr = sg_dma_address(s); ++ u64 dma_addr_end = dma_addr + dma_len; ++ ++ do { ++ srv_path->dma_addr[ind++] = dma_addr; ++ dma_addr += max_chunk_size; ++ } while (dma_addr < dma_addr_end); ++ } + + ib_update_fast_reg_key(mr, ib_inc_rkey(mr->rkey)); + srv_mr->mr = mr; +-- +2.51.0 + diff --git a/queue-6.6/rdma-rxe-fix-double-free-in-rxe_srq_from_init.patch b/queue-6.6/rdma-rxe-fix-double-free-in-rxe_srq_from_init.patch new file mode 100644 index 0000000000..4eba173da0 --- /dev/null +++ b/queue-6.6/rdma-rxe-fix-double-free-in-rxe_srq_from_init.patch @@ -0,0 +1,67 @@ +From 478f861db3762a842dc780b47cbf5d095b7a5e9f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 01:54:12 +0000 +Subject: RDMA/rxe: Fix double free in rxe_srq_from_init + +From: Jiasheng Jiang + +[ Upstream commit 0beefd0e15d962f497aad750b2d5e9c3570b66d1 ] + +In rxe_srq_from_init(), the queue pointer 'q' is assigned to +'srq->rq.queue' before copying the SRQ number to user space. +If copy_to_user() fails, the function calls rxe_queue_cleanup() +to free the queue, but leaves the now-invalid pointer in +'srq->rq.queue'. + +The caller of rxe_srq_from_init() (rxe_create_srq) eventually +calls rxe_srq_cleanup() upon receiving the error, which triggers +a second rxe_queue_cleanup() on the same memory, leading to a +double free. + +The call trace looks like this: + kmem_cache_free+0x.../0x... + rxe_queue_cleanup+0x1a/0x30 [rdma_rxe] + rxe_srq_cleanup+0x42/0x60 [rdma_rxe] + rxe_elem_release+0x31/0x70 [rdma_rxe] + rxe_create_srq+0x12b/0x1a0 [rdma_rxe] + ib_create_srq_user+0x9a/0x150 [ib_core] + +Fix this by moving 'srq->rq.queue = q' after copy_to_user. + +Fixes: aae0484e15f0 ("IB/rxe: avoid srq memory leak") +Signed-off-by: Jiasheng Jiang +Link: https://patch.msgid.link/20260112015412.29458-1-jiashengjiangcool@gmail.com +Reviewed-by: Zhu Yanjun +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/sw/rxe/rxe_srq.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/infiniband/sw/rxe/rxe_srq.c b/drivers/infiniband/sw/rxe/rxe_srq.c +index 2a234f26ac104..c9a7cd38953d3 100644 +--- a/drivers/infiniband/sw/rxe/rxe_srq.c ++++ b/drivers/infiniband/sw/rxe/rxe_srq.c +@@ -77,9 +77,6 @@ int rxe_srq_from_init(struct rxe_dev *rxe, struct rxe_srq *srq, + goto err_free; + } + +- srq->rq.queue = q; +- init->attr.max_wr = srq->rq.max_wr; +- + if (uresp) { + if (copy_to_user(&uresp->srq_num, &srq->srq_num, + sizeof(uresp->srq_num))) { +@@ -88,6 +85,9 @@ int rxe_srq_from_init(struct rxe_dev *rxe, struct rxe_srq *srq, + } + } + ++ srq->rq.queue = q; ++ init->attr.max_wr = srq->rq.max_wr; ++ + return 0; + + err_free: +-- +2.51.0 + diff --git a/queue-6.6/rdma-rxe-fix-race-condition-in-qp-timer-handlers.patch b/queue-6.6/rdma-rxe-fix-race-condition-in-qp-timer-handlers.patch new file mode 100644 index 0000000000..a06921495d --- /dev/null +++ b/queue-6.6/rdma-rxe-fix-race-condition-in-qp-timer-handlers.patch @@ -0,0 +1,116 @@ +From 80acda7a8b2f476d853c61e25ef5fb02964cac45 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 15:44:37 +0800 +Subject: RDMA/rxe: Fix race condition in QP timer handlers + +From: Li Zhijian + +[ Upstream commit 87bf646921430e303176edc4eb07c30160361b73 ] + +I encontered the following warning: + WARNING: drivers/infiniband/sw/rxe/rxe_task.c:249 at rxe_sched_task+0x1c8/0x238 [rdma_rxe], CPU#0: swapper/0/0 +... + libsha1 [last unloaded: ip6_udp_tunnel] + CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Tainted: G C 6.19.0-rc5-64k-v8+ #37 PREEMPT + Tainted: [C]=CRAP + Hardware name: Raspberry Pi 4 Model B Rev 1.2 + Call trace: + rxe_sched_task+0x1c8/0x238 [rdma_rxe] (P) + retransmit_timer+0x130/0x188 [rdma_rxe] + call_timer_fn+0x68/0x4d0 + __run_timers+0x630/0x888 +... + WARNING: drivers/infiniband/sw/rxe/rxe_task.c:38 at rxe_sched_task+0x1c0/0x238 [rdma_rxe], CPU#0: swapper/0/0 +... + WARNING: drivers/infiniband/sw/rxe/rxe_task.c:111 at do_work+0x488/0x5c8 [rdma_rxe], CPU#3: kworker/u17:4/93400 +... + refcount_t: underflow; use-after-free. + WARNING: lib/refcount.c:28 at refcount_warn_saturate+0x138/0x1a0, CPU#3: kworker/u17:4/93400 + +The issue is caused by a race condition between retransmit_timer() and +rxe_destroy_qp, leading to the Queue Pair's (QP) reference count dropping +to zero during timer handler execution. + +It seems this warning is harmless because rxe_qp_do_cleanup() will flush +all pending timers and requests. + +Example of flow causing the issue: + +CPU0 CPU1 +retransmit_timer() { + spin_lock_irqsave + rxe_destroy_qp() + __rxe_cleanup() + __rxe_put() // qp->ref_count decrease to 0 + rxe_qp_do_cleanup() { + if (qp->valid) { + rxe_sched_task() { + WARN_ON(rxe_read(task->qp) <= 0); + } + } + spin_unlock_irqrestore +} + spin_lock_irqsave + qp->valid = 0 + spin_unlock_irqrestore + } + +Ensure the QP's reference count is maintained and its validity is checked +within the timer callbacks by adding calls to rxe_get(qp) and corresponding +rxe_put(qp) after use. + +Signed-off-by: Li Zhijian +Fixes: d94671632572 ("RDMA/rxe: Rewrite rxe_task.c") +Link: https://patch.msgid.link/20260120074437.623018-1-lizhijian@fujitsu.com +Reviewed-by: Zhu Yanjun +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/sw/rxe/rxe_comp.c | 3 +++ + drivers/infiniband/sw/rxe/rxe_req.c | 3 +++ + 2 files changed, 6 insertions(+) + +diff --git a/drivers/infiniband/sw/rxe/rxe_comp.c b/drivers/infiniband/sw/rxe/rxe_comp.c +index c997b7cbf2a9e..81b645c727a17 100644 +--- a/drivers/infiniband/sw/rxe/rxe_comp.c ++++ b/drivers/infiniband/sw/rxe/rxe_comp.c +@@ -119,12 +119,15 @@ void retransmit_timer(struct timer_list *t) + + rxe_dbg_qp(qp, "retransmit timer fired\n"); + ++ if (!rxe_get(qp)) ++ return; + spin_lock_irqsave(&qp->state_lock, flags); + if (qp->valid) { + qp->comp.timeout = 1; + rxe_sched_task(&qp->comp.task); + } + spin_unlock_irqrestore(&qp->state_lock, flags); ++ rxe_put(qp); + } + + void rxe_comp_queue_pkt(struct rxe_qp *qp, struct sk_buff *skb) +diff --git a/drivers/infiniband/sw/rxe/rxe_req.c b/drivers/infiniband/sw/rxe/rxe_req.c +index 7ff152ffe15b9..4d550ac0dac5a 100644 +--- a/drivers/infiniband/sw/rxe/rxe_req.c ++++ b/drivers/infiniband/sw/rxe/rxe_req.c +@@ -103,6 +103,8 @@ void rnr_nak_timer(struct timer_list *t) + + rxe_dbg_qp(qp, "nak timer fired\n"); + ++ if (!rxe_get(qp)) ++ return; + spin_lock_irqsave(&qp->state_lock, flags); + if (qp->valid) { + /* request a send queue retry */ +@@ -111,6 +113,7 @@ void rnr_nak_timer(struct timer_list *t) + rxe_sched_task(&qp->req.task); + } + spin_unlock_irqrestore(&qp->state_lock, flags); ++ rxe_put(qp); + } + + static void req_check_sq_drain_done(struct rxe_qp *qp) +-- +2.51.0 + diff --git a/queue-6.6/rdma-uverbs-add-__gfp_nowarn-to-ib_uverbs_unmarshall.patch b/queue-6.6/rdma-uverbs-add-__gfp_nowarn-to-ib_uverbs_unmarshall.patch new file mode 100644 index 0000000000..98880a4a78 --- /dev/null +++ b/queue-6.6/rdma-uverbs-add-__gfp_nowarn-to-ib_uverbs_unmarshall.patch @@ -0,0 +1,39 @@ +From ead842ea832996dbee1b14ebe462a9563d18bae4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 17:49:00 +0800 +Subject: RDMA/uverbs: Add __GFP_NOWARN to ib_uverbs_unmarshall_recv() kmalloc + +From: Yi Liu + +[ Upstream commit 58b604dfc7bb753f91bc0ccd3fa705e14e6edfb4 ] + +Since wqe_size in ib_uverbs_unmarshall_recv() is user-provided and already +validated, but can still be large, add __GFP_NOWARN to suppress memory +allocation warnings for large sizes, consistent with the similar fix in +ib_uverbs_post_send(). + +Fixes: 67cdb40ca444 ("[IB] uverbs: Implement more commands") +Signed-off-by: Yi Liu +Link: https://patch.msgid.link/20260129094900.3517706-1-liuy22@mails.tsinghua.edu.cn +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/uverbs_cmd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c +index 2ed51a7df60fd..2e4265ba35b7f 100644 +--- a/drivers/infiniband/core/uverbs_cmd.c ++++ b/drivers/infiniband/core/uverbs_cmd.c +@@ -2223,7 +2223,7 @@ ib_uverbs_unmarshall_recv(struct uverbs_req_iter *iter, u32 wr_count, + if (ret) + return ERR_PTR(ret); + +- user_wr = kmalloc(wqe_size, GFP_KERNEL); ++ user_wr = kmalloc(wqe_size, GFP_KERNEL | __GFP_NOWARN); + if (!user_wr) + return ERR_PTR(-ENOMEM); + +-- +2.51.0 + diff --git a/queue-6.6/rdma-uverbs-validate-wqe_size-before-using-it-in-ib_.patch b/queue-6.6/rdma-uverbs-validate-wqe_size-before-using-it-in-ib_.patch new file mode 100644 index 0000000000..7a61163527 --- /dev/null +++ b/queue-6.6/rdma-uverbs-validate-wqe_size-before-using-it-in-ib_.patch @@ -0,0 +1,57 @@ +From 4176297c81c00e50e49759c03058508713718db6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 22:29:00 +0800 +Subject: RDMA/uverbs: Validate wqe_size before using it in ib_uverbs_post_send + +From: Yi Liu + +[ Upstream commit 1956f0a74ccf5dc9c3ef717f2985c3ed3400aab0 ] + +ib_uverbs_post_send() uses cmd.wqe_size from userspace without any +validation before passing it to kmalloc() and using the allocated +buffer as struct ib_uverbs_send_wr. + +If a user provides a small wqe_size value (e.g., 1), kmalloc() will +succeed, but subsequent accesses to user_wr->opcode, user_wr->num_sge, +and other fields will read beyond the allocated buffer, resulting in +an out-of-bounds read from kernel heap memory. This could potentially +leak sensitive kernel information to userspace. + +Additionally, providing an excessively large wqe_size can trigger a +WARNING in the memory allocation path, as reported by syzkaller. + +This is inconsistent with ib_uverbs_unmarshall_recv() which properly +validates that wqe_size >= sizeof(struct ib_uverbs_recv_wr) before +proceeding. + +Add the same validation for ib_uverbs_post_send() to ensure wqe_size +is at least sizeof(struct ib_uverbs_send_wr). + +Fixes: c3bea3d2dc53 ("RDMA/uverbs: Use the iterator for ib_uverbs_unmarshall_recv()") +Signed-off-by: Yi Liu +Link: https://patch.msgid.link/20260122142900.2356276-2-liuy22@mails.tsinghua.edu.cn +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/uverbs_cmd.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c +index 33e2fe0facd52..2ed51a7df60fd 100644 +--- a/drivers/infiniband/core/uverbs_cmd.c ++++ b/drivers/infiniband/core/uverbs_cmd.c +@@ -2030,7 +2030,10 @@ static int ib_uverbs_post_send(struct uverbs_attr_bundle *attrs) + if (ret) + return ret; + +- user_wr = kmalloc(cmd.wqe_size, GFP_KERNEL); ++ if (cmd.wqe_size < sizeof(struct ib_uverbs_send_wr)) ++ return -EINVAL; ++ ++ user_wr = kmalloc(cmd.wqe_size, GFP_KERNEL | __GFP_NOWARN); + if (!user_wr) + return -ENOMEM; + +-- +2.51.0 + diff --git a/queue-6.6/regulator-core-move-supply-check-earlier-in-set_mach.patch b/queue-6.6/regulator-core-move-supply-check-earlier-in-set_mach.patch new file mode 100644 index 0000000000..5f4a51f0a3 --- /dev/null +++ b/queue-6.6/regulator-core-move-supply-check-earlier-in-set_mach.patch @@ -0,0 +1,121 @@ +From 7076bf1896a9296eb54efbba295b8485b486fa74 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 08:38:39 +0000 +Subject: regulator: core: move supply check earlier in + set_machine_constraints() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: André Draszik + +[ Upstream commit 86a8eeb0e913f4b6a55dabba5122098d4e805e55 ] + +Since commit 98e48cd9283d ("regulator: core: resolve supply for +boot-on/always-on regulators"), set_machine_constraints() can return +-EPROBE_DEFER very late, after it has done a lot of work and +configuration of the regulator. + +This means that configuration will happen multiple times for no +benefit in that case. Furthermore, this can lead to timing-dependent +voltage glitches as mentioned e.g. in commit 8a866d527ac0 ("regulator: +core: Resolve supply name earlier to prevent double-init"). + +We can know that it's going to fail very early, in particular before +going through the complete regulator configuration by moving some code +around a little. + +Do so to avoid re-configuring the regulator multiple times, also +avoiding the voltage glitches if we can. + +Fixes: 98e48cd9283d ("regulator: core: resolve supply for boot-on/always-on regulators") +Signed-off-by: André Draszik +Link: https://patch.msgid.link/20260109-regulators-defer-v2-3-1a25dc968e60@linaro.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/regulator/core.c | 55 ++++++++++++++++++++++------------------ + 1 file changed, 30 insertions(+), 25 deletions(-) + +diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c +index 23cdf220ca7db..a1a26743430c0 100644 +--- a/drivers/regulator/core.c ++++ b/drivers/regulator/core.c +@@ -1466,6 +1466,33 @@ static int set_machine_constraints(struct regulator_dev *rdev) + int ret = 0; + const struct regulator_ops *ops = rdev->desc->ops; + ++ /* ++ * If there is no mechanism for controlling the regulator then ++ * flag it as always_on so we don't end up duplicating checks ++ * for this so much. Note that we could control the state of ++ * a supply to control the output on a regulator that has no ++ * direct control. ++ */ ++ if (!rdev->ena_pin && !ops->enable) { ++ if (rdev->supply_name && !rdev->supply) ++ return -EPROBE_DEFER; ++ ++ if (rdev->supply) ++ rdev->constraints->always_on = ++ rdev->supply->rdev->constraints->always_on; ++ else ++ rdev->constraints->always_on = true; ++ } ++ ++ /* ++ * If we want to enable this regulator, make sure that we know the ++ * supplying regulator. ++ */ ++ if (rdev->constraints->always_on || rdev->constraints->boot_on) { ++ if (rdev->supply_name && !rdev->supply) ++ return -EPROBE_DEFER; ++ } ++ + ret = machine_constraints_voltage(rdev, rdev->constraints); + if (ret != 0) + return ret; +@@ -1631,37 +1658,15 @@ static int set_machine_constraints(struct regulator_dev *rdev) + } + } + +- /* +- * If there is no mechanism for controlling the regulator then +- * flag it as always_on so we don't end up duplicating checks +- * for this so much. Note that we could control the state of +- * a supply to control the output on a regulator that has no +- * direct control. +- */ +- if (!rdev->ena_pin && !ops->enable) { +- if (rdev->supply_name && !rdev->supply) +- return -EPROBE_DEFER; +- +- if (rdev->supply) +- rdev->constraints->always_on = +- rdev->supply->rdev->constraints->always_on; +- else +- rdev->constraints->always_on = true; +- } +- + /* If the constraints say the regulator should be on at this point + * and we have control then make sure it is enabled. + */ + if (rdev->constraints->always_on || rdev->constraints->boot_on) { + bool supply_enabled = false; + +- /* If we want to enable this regulator, make sure that we know +- * the supplying regulator. +- */ +- if (rdev->supply_name && !rdev->supply) +- return -EPROBE_DEFER; +- +- /* If supplying regulator has already been enabled, ++ /* We have ensured a potential supply has been resolved above. ++ * ++ * If supplying regulator has already been enabled, + * it's not intended to have use_count increment + * when rdev is only boot-on. + */ +-- +2.51.0 + diff --git a/queue-6.6/revert-hwmon-ibmpex-fix-use-after-free-in-high-low-s.patch b/queue-6.6/revert-hwmon-ibmpex-fix-use-after-free-in-high-low-s.patch new file mode 100644 index 0000000000..7a07dbd42a --- /dev/null +++ b/queue-6.6/revert-hwmon-ibmpex-fix-use-after-free-in-high-low-s.patch @@ -0,0 +1,89 @@ +From 24ad925b4a72433a9ee2c5cf308ce0ef6090b2a7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Feb 2026 08:12:25 -0800 +Subject: Revert "hwmon: (ibmpex) fix use-after-free in high/low store" + +From: Guenter Roeck + +[ Upstream commit 8bde3e395a85017f12af2b0ba5c3684f5af9c006 ] + +This reverts commit 6946c726c3f4c36f0f049e6f97e88c510b15f65d. + +Jean Delvare points out that the patch does not completely +fix the reported problem, that it in fact introduces a +(new) race condition, and that it may actually not be needed in +the first place. + +Various AI reviews agree. Specific and relevant AI feedback: + +" +This reordering sets the driver data to NULL before removing the sensor +attributes in the loop below. + +ibmpex_show_sensor() retrieves this driver data via dev_get_drvdata() but +does not check if it is NULL before dereferencing it to access +data->sensors[]. + +If a userspace process reads a sensor file (like temp1_input) while this +delete function is running, could it race with the dev_set_drvdata(..., +NULL) call here and crash in ibmpex_show_sensor()? + +Would it be safer to keep the original order where device_remove_file() is +called before clearing the driver data? device_remove_file() should wait +for any active sysfs callbacks to complete, which might already prevent the +use-after-free this patch intends to fix. +" + +Revert the offending patch. If it can be shown that the originally reported +alleged race condition does indeed exist, it can always be re-introduced +with a complete fix. + +Reported-by: Jean Delvare +Closes: https://lore.kernel.org/linux-hwmon/20260121095342.73e723cb@endymion/ +Cc: Jean Delvare +Cc: Junrui Luo +Fixes: 6946c726c3f4 ("hwmon: (ibmpex) fix use-after-free in high/low store") +Reviewed-by: Jean Delvare +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + drivers/hwmon/ibmpex.c | 9 ++------- + 1 file changed, 2 insertions(+), 7 deletions(-) + +diff --git a/drivers/hwmon/ibmpex.c b/drivers/hwmon/ibmpex.c +index 40fff7e95ea1c..db066b3689187 100644 +--- a/drivers/hwmon/ibmpex.c ++++ b/drivers/hwmon/ibmpex.c +@@ -282,9 +282,6 @@ static ssize_t ibmpex_high_low_store(struct device *dev, + { + struct ibmpex_bmc_data *data = dev_get_drvdata(dev); + +- if (!data) +- return -ENODEV; +- + ibmpex_reset_high_low_data(data); + + return count; +@@ -517,9 +514,6 @@ static void ibmpex_bmc_delete(struct ibmpex_bmc_data *data) + { + int i, j; + +- hwmon_device_unregister(data->hwmon_dev); +- dev_set_drvdata(data->bmc_device, NULL); +- + device_remove_file(data->bmc_device, + &sensor_dev_attr_reset_high_low.dev_attr); + device_remove_file(data->bmc_device, &sensor_dev_attr_name.dev_attr); +@@ -533,7 +527,8 @@ static void ibmpex_bmc_delete(struct ibmpex_bmc_data *data) + } + + list_del(&data->list); +- ++ dev_set_drvdata(data->bmc_device, NULL); ++ hwmon_device_unregister(data->hwmon_dev); + ipmi_destroy_user(data->user); + kfree(data->sensors); + kfree(data); +-- +2.51.0 + diff --git a/queue-6.6/revert-mmc-rtsx_pci_sdmmc-increase-power-on-settling.patch b/queue-6.6/revert-mmc-rtsx_pci_sdmmc-increase-power-on-settling.patch new file mode 100644 index 0000000000..f4597ccf05 --- /dev/null +++ b/queue-6.6/revert-mmc-rtsx_pci_sdmmc-increase-power-on-settling.patch @@ -0,0 +1,39 @@ +From fde7a87d3b9214571f06a1f4c2cd36642b8bf0d2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 15:49:31 +0100 +Subject: Revert "mmc: rtsx_pci_sdmmc: increase power-on settling delay to 5ms" + +From: Greg Kroah-Hartman + +[ Upstream commit ff112f1ecd10b72004eac05bae395e1c65f0c63c ] + +This reverts commit aced969e9bf3701dc75cfca57c78c031b7875b9d. + +It was determined that this was not the correct "fix", so should be +reverted. + +Fixes: aced969e9bf3 ("mmc: rtsx_pci_sdmmc: increase power-on settling delay to 5ms") +Cc: Matthew Schwartz +Cc: Ulf Hansson +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/mmc/host/rtsx_pci_sdmmc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c +index 4931ee387f3cf..195cd25c2e055 100644 +--- a/drivers/mmc/host/rtsx_pci_sdmmc.c ++++ b/drivers/mmc/host/rtsx_pci_sdmmc.c +@@ -938,7 +938,7 @@ static int sd_power_on(struct realtek_pci_sdmmc *host, unsigned char power_mode) + if (err < 0) + return err; + +- mdelay(5); ++ mdelay(1); + + err = rtsx_pci_write_register(pcr, CARD_OE, SD_OUTPUT_EN, SD_OUTPUT_EN); + if (err < 0) +-- +2.51.0 + diff --git a/queue-6.6/s390-cio-fix-device-lifecycle-handling-in-css_alloc_.patch b/queue-6.6/s390-cio-fix-device-lifecycle-handling-in-css_alloc_.patch new file mode 100644 index 0000000000..f32b441c46 --- /dev/null +++ b/queue-6.6/s390-cio-fix-device-lifecycle-handling-in-css_alloc_.patch @@ -0,0 +1,49 @@ +From 00c1f047b2e571f6365bb0726d82af626743e4c6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 21:47:59 +0100 +Subject: s390/cio: Fix device lifecycle handling in css_alloc_subchannel() + +From: Salah Triki + +[ Upstream commit f65c75b0b9b5a390bc3beadcde0a6fbc3ad118f7 ] + +`css_alloc_subchannel()` calls `device_initialize()` before setting up +the DMA masks. If `dma_set_coherent_mask()` or `dma_set_mask()` fails, +the error path frees the subchannel structure directly, bypassing +the device model reference counting. + +Once `device_initialize()` has been called, the embedded struct device +must be released via `put_device()`, allowing the release callback to +free the container structure. + +Fix the error path by dropping the initial device reference with +`put_device()` instead of calling `kfree()` directly. + +This ensures correct device lifetime handling and avoids potential +use-after-free or double-free issues. + +Fixes: e5dcf0025d7af ("s390/css: move subchannel lock allocation") +Signed-off-by: Salah Triki +Reviewed-by: Vineeth Vijayan +Signed-off-by: Heiko Carstens +Signed-off-by: Sasha Levin +--- + drivers/s390/cio/css.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c +index 3ff46fc694f85..e50592c3d30ca 100644 +--- a/drivers/s390/cio/css.c ++++ b/drivers/s390/cio/css.c +@@ -247,7 +247,7 @@ struct subchannel *css_alloc_subchannel(struct subchannel_id schid, + err_lock: + kfree(sch->lock); + err: +- kfree(sch); ++ put_device(&sch->dev); + return ERR_PTR(ret); + } + +-- +2.51.0 + diff --git a/queue-6.6/sched-rt-skip-currently-executing-cpu-in-rto_next_cp.patch b/queue-6.6/sched-rt-skip-currently-executing-cpu-in-rto_next_cp.patch new file mode 100644 index 0000000000..19833b904e --- /dev/null +++ b/queue-6.6/sched-rt-skip-currently-executing-cpu-in-rto_next_cp.patch @@ -0,0 +1,87 @@ +From 9164c8e1297dac4b3807ead9c8f8d1d22c2ae806 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 01:25:33 +0000 +Subject: sched/rt: Skip currently executing CPU in rto_next_cpu() + +From: Chen Jinghuang + +[ Upstream commit 94894c9c477e53bcea052e075c53f89df3d2a33e ] + +CPU0 becomes overloaded when hosting a CPU-bound RT task, a non-CPU-bound +RT task, and a CFS task stuck in kernel space. When other CPUs switch from +RT to non-RT tasks, RT load balancing (LB) is triggered; with +HAVE_RT_PUSH_IPI enabled, they send IPIs to CPU0 to drive the execution +of rto_push_irq_work_func. During push_rt_task on CPU0, +if next_task->prio < rq->donor->prio, resched_curr() sets NEED_RESCHED +and after the push operation completes, CPU0 calls rto_next_cpu(). +Since only CPU0 is overloaded in this scenario, rto_next_cpu() should +ideally return -1 (no further IPI needed). + +However, multiple CPUs invoking tell_cpu_to_push() during LB increments +rd->rto_loop_next. Even when rd->rto_cpu is set to -1, the mismatch between +rd->rto_loop and rd->rto_loop_next forces rto_next_cpu() to restart its +search from -1. With CPU0 remaining overloaded (satisfying rt_nr_migratory +&& rt_nr_total > 1), it gets reselected, causing CPU0 to queue irq_work to +itself and send self-IPIs repeatedly. As long as CPU0 stays overloaded and +other CPUs run pull_rt_tasks(), it falls into an infinite self-IPI loop, +which triggers a CPU hardlockup due to continuous self-interrupts. + +The trigging scenario is as follows: + + cpu0 cpu1 cpu2 + pull_rt_task + tell_cpu_to_push + <------------irq_work_queue_on +rto_push_irq_work_func + push_rt_task + resched_curr(rq) pull_rt_task + rto_next_cpu tell_cpu_to_push + <-------------------------- atomic_inc(rto_loop_next) +rd->rto_loop != next + rto_next_cpu + irq_work_queue_on +rto_push_irq_work_func + +Fix redundant self-IPI by filtering the initiating CPU in rto_next_cpu(). +This solution has been verified to effectively eliminate spurious self-IPIs +and prevent CPU hardlockup scenarios. + +Fixes: 4bdced5c9a29 ("sched/rt: Simplify the IPI based RT balancing logic") +Suggested-by: Steven Rostedt (Google) +Suggested-by: K Prateek Nayak +Signed-off-by: Chen Jinghuang +Signed-off-by: Peter Zijlstra (Intel) +Reviewed-by: Steven Rostedt (Google) +Reviewed-by: Valentin Schneider +Link: https://patch.msgid.link/20260122012533.673768-1-chenjinghuang2@huawei.com +Signed-off-by: Sasha Levin +--- + kernel/sched/rt.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c +index 2d0acdd32108a..0b420a65b31dc 100644 +--- a/kernel/sched/rt.c ++++ b/kernel/sched/rt.c +@@ -2219,6 +2219,7 @@ static void push_rt_tasks(struct rq *rq) + */ + static int rto_next_cpu(struct root_domain *rd) + { ++ int this_cpu = smp_processor_id(); + int next; + int cpu; + +@@ -2242,6 +2243,10 @@ static int rto_next_cpu(struct root_domain *rd) + + rd->rto_cpu = cpu; + ++ /* Do not send IPI to self */ ++ if (cpu == this_cpu) ++ continue; ++ + if (cpu < nr_cpu_ids) + return cpu; + +-- +2.51.0 + diff --git a/queue-6.6/scsi-csiostor-fix-dereference-of-null-pointer-rn.patch b/queue-6.6/scsi-csiostor-fix-dereference-of-null-pointer-rn.patch new file mode 100644 index 0000000000..f9530ff687 --- /dev/null +++ b/queue-6.6/scsi-csiostor-fix-dereference-of-null-pointer-rn.patch @@ -0,0 +1,46 @@ +From d0165a5d9c5334262cdd2312e101301edb746242 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 15:53:32 +0000 +Subject: scsi: csiostor: Fix dereference of null pointer rn + +From: Colin Ian King + +[ Upstream commit 1982257570b84dc33753d536dd969fd357a014e9 ] + +The error exit path when rn is NULL ends up deferencing the null pointer rn +via the use of the macro CSIO_INC_STATS. Fix this by adding a new error +return path label after the use of the macro to avoid the deference. + +Fixes: a3667aaed569 ("[SCSI] csiostor: Chelsio FCoE offload driver") +Signed-off-by: Colin Ian King +Link: https://patch.msgid.link/20260129155332.196338-1-colin.i.king@gmail.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/csiostor/csio_scsi.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/scsi/csiostor/csio_scsi.c b/drivers/scsi/csiostor/csio_scsi.c +index 05e1a63e00c3a..ed40ae6b9800c 100644 +--- a/drivers/scsi/csiostor/csio_scsi.c ++++ b/drivers/scsi/csiostor/csio_scsi.c +@@ -2074,7 +2074,7 @@ csio_eh_lun_reset_handler(struct scsi_cmnd *cmnd) + struct csio_scsi_level_data sld; + + if (!rn) +- goto fail; ++ goto fail_ret; + + csio_dbg(hw, "Request to reset LUN:%llu (ssni:0x%x tgtid:%d)\n", + cmnd->device->lun, rn->flowid, rn->scsi_id); +@@ -2220,6 +2220,7 @@ csio_eh_lun_reset_handler(struct scsi_cmnd *cmnd) + csio_put_scsi_ioreq_lock(hw, scsim, ioreq); + fail: + CSIO_INC_STATS(rn, n_lun_rst_fail); ++fail_ret: + return FAILED; + } + +-- +2.51.0 + diff --git a/queue-6.6/scsi-efct-use-irqf_oneshot-and-default-primary-handl.patch b/queue-6.6/scsi-efct-use-irqf_oneshot-and-default-primary-handl.patch new file mode 100644 index 0000000000..dd899285ef --- /dev/null +++ b/queue-6.6/scsi-efct-use-irqf_oneshot-and-default-primary-handl.patch @@ -0,0 +1,59 @@ +From b36567867773ef192ab7f6fb751dc586d7f5d304 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:55:27 +0100 +Subject: scsi: efct: Use IRQF_ONESHOT and default primary handler + +From: Sebastian Andrzej Siewior + +[ Upstream commit bd81f07e9a27c341cd7e72be95eb0b7cf3910926 ] + +There is no added value in efct_intr_msix() compared to +irq_default_primary_handler(). + +Using a threaded interrupt without a dedicated primary handler mandates +the IRQF_ONESHOT flag to mask the interrupt source while the threaded +handler is active. Otherwise the interrupt can fire again before the +threaded handler had a chance to run. + +Use the default primary interrupt handler by specifying NULL and set +IRQF_ONESHOT so the interrupt source is masked until the secondary +handler is done. + +Fixes: 4df84e8466242 ("scsi: elx: efct: Driver initialization routines") +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260128095540.863589-8-bigeasy@linutronix.de +Signed-off-by: Sasha Levin +--- + drivers/scsi/elx/efct/efct_driver.c | 8 +------- + 1 file changed, 1 insertion(+), 7 deletions(-) + +diff --git a/drivers/scsi/elx/efct/efct_driver.c b/drivers/scsi/elx/efct/efct_driver.c +index 49fd2cfed70c7..37aba56e07217 100644 +--- a/drivers/scsi/elx/efct/efct_driver.c ++++ b/drivers/scsi/elx/efct/efct_driver.c +@@ -415,12 +415,6 @@ efct_intr_thread(int irq, void *handle) + return IRQ_HANDLED; + } + +-static irqreturn_t +-efct_intr_msix(int irq, void *handle) +-{ +- return IRQ_WAKE_THREAD; +-} +- + static int + efct_setup_msix(struct efct *efct, u32 num_intrs) + { +@@ -450,7 +444,7 @@ efct_setup_msix(struct efct *efct, u32 num_intrs) + intr_ctx->index = i; + + rc = request_threaded_irq(pci_irq_vector(efct->pci, i), +- efct_intr_msix, efct_intr_thread, 0, ++ NULL, efct_intr_thread, IRQF_ONESHOT, + EFCT_DRIVER_NAME, intr_ctx); + if (rc) { + dev_err(&efct->pci->dev, +-- +2.51.0 + diff --git a/queue-6.6/scsi-smartpqi-fix-memory-leak-in-pqi_report_phys_lun.patch b/queue-6.6/scsi-smartpqi-fix-memory-leak-in-pqi_report_phys_lun.patch new file mode 100644 index 0000000000..f5d4dda703 --- /dev/null +++ b/queue-6.6/scsi-smartpqi-fix-memory-leak-in-pqi_report_phys_lun.patch @@ -0,0 +1,72 @@ +From 25ebb8115303867d107519d54def2d049813350f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Jan 2026 09:36:41 +0000 +Subject: scsi: smartpqi: Fix memory leak in pqi_report_phys_luns() + +From: Zilin Guan + +[ Upstream commit 41b37312bd9722af77ec7817ccf22d7a4880c289 ] + +pqi_report_phys_luns() fails to release the rpl_list buffer when +encountering an unsupported data format or when the allocation for +rpl_16byte_wwid_list fails. These early returns bypass the cleanup logic, +leading to memory leaks. + +Consolidate the error handling by adding an out_free_rpl_list label and use +goto statements to ensure rpl_list is consistently freed on failure. + +Compile tested only. Issue found using a prototype static analysis tool and +code review. + +Fixes: 28ca6d876c5a ("scsi: smartpqi: Add extended report physical LUNs") +Signed-off-by: Zilin Guan +Tested-by: Don Brace +Acked-by: Don Brace +Link: https://patch.msgid.link/20260131093641.1008117-1-zilin@seu.edu.cn +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/smartpqi/smartpqi_init.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c +index 0cdeb7aa55020..dc194c76f38b7 100644 +--- a/drivers/scsi/smartpqi/smartpqi_init.c ++++ b/drivers/scsi/smartpqi/smartpqi_init.c +@@ -1240,7 +1240,8 @@ static inline int pqi_report_phys_luns(struct pqi_ctrl_info *ctrl_info, void **b + dev_err(&ctrl_info->pci_dev->dev, + "RPL returned unsupported data format %u\n", + rpl_response_format); +- return -EINVAL; ++ rc = -EINVAL; ++ goto out_free_rpl_list; + } else { + dev_warn(&ctrl_info->pci_dev->dev, + "RPL returned extended format 2 instead of 4\n"); +@@ -1252,8 +1253,10 @@ static inline int pqi_report_phys_luns(struct pqi_ctrl_info *ctrl_info, void **b + + rpl_16byte_wwid_list = kmalloc(struct_size(rpl_16byte_wwid_list, lun_entries, + num_physicals), GFP_KERNEL); +- if (!rpl_16byte_wwid_list) +- return -ENOMEM; ++ if (!rpl_16byte_wwid_list) { ++ rc = -ENOMEM; ++ goto out_free_rpl_list; ++ } + + put_unaligned_be32(num_physicals * sizeof(struct report_phys_lun_16byte_wwid), + &rpl_16byte_wwid_list->header.list_length); +@@ -1274,6 +1277,10 @@ static inline int pqi_report_phys_luns(struct pqi_ctrl_info *ctrl_info, void **b + *buffer = rpl_16byte_wwid_list; + + return 0; ++ ++out_free_rpl_list: ++ kfree(rpl_list); ++ return rc; + } + + static inline int pqi_report_logical_luns(struct pqi_ctrl_info *ctrl_info, void **buffer) +-- +2.51.0 + diff --git a/queue-6.6/scsi-ufs-host-mediatek-require-config_pm.patch b/queue-6.6/scsi-ufs-host-mediatek-require-config_pm.patch new file mode 100644 index 0000000000..e05ae17fda --- /dev/null +++ b/queue-6.6/scsi-ufs-host-mediatek-require-config_pm.patch @@ -0,0 +1,116 @@ +From 438c8bfa6a929d2ae7fb2329789435bc1921d0d7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 10:50:18 +0100 +Subject: scsi: ufs: host: mediatek: Require CONFIG_PM + +From: Arnd Bergmann + +[ Upstream commit bbb8d98fb4536594cb104fd630ea0f7dce3771d6 ] + +The added print statement from a recent fix causes the driver to fail +building when CONFIG_PM is disabled: + +drivers/ufs/host/ufs-mediatek.c: In function 'ufs_mtk_resume': +drivers/ufs/host/ufs-mediatek.c:1890:40: error: 'struct dev_pm_info' has no member named 'request' + 1890 | hba->dev->power.request, + +It seems unlikely that the driver can work at all without CONFIG_PM, so +just add a dependency and remove the existing ifdef checks, rather than +adding another ifdef. + +Fixes: 15ef3f5aa822 ("scsi: ufs: host: mediatek: Enhance recovery on resume failure") +Signed-off-by: Arnd Bergmann +Reviewed-by: AngeloGioacchino Del Regno +Link: https://patch.msgid.link/20260202095052.1232703-1-arnd@kernel.org +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/ufs/host/Kconfig | 1 + + drivers/ufs/host/ufs-mediatek.c | 12 +++--------- + include/ufs/ufshcd.h | 4 ---- + 3 files changed, 4 insertions(+), 13 deletions(-) + +diff --git a/drivers/ufs/host/Kconfig b/drivers/ufs/host/Kconfig +index 580c8d0bd8bbd..626bb9002f4a1 100644 +--- a/drivers/ufs/host/Kconfig ++++ b/drivers/ufs/host/Kconfig +@@ -72,6 +72,7 @@ config SCSI_UFS_QCOM + config SCSI_UFS_MEDIATEK + tristate "Mediatek specific hooks to UFS controller platform driver" + depends on SCSI_UFSHCD_PLATFORM && ARCH_MEDIATEK ++ depends on PM + depends on RESET_CONTROLLER + select PHY_MTK_UFS + select RESET_TI_SYSCON +diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c +index 8b4a3cc812531..606e90ce8ca70 100644 +--- a/drivers/ufs/host/ufs-mediatek.c ++++ b/drivers/ufs/host/ufs-mediatek.c +@@ -1852,7 +1852,6 @@ static int ufs_mtk_remove(struct platform_device *pdev) + return 0; + } + +-#ifdef CONFIG_PM_SLEEP + static int ufs_mtk_system_suspend(struct device *dev) + { + struct ufs_hba *hba = dev_get_drvdata(dev); +@@ -1875,9 +1874,7 @@ static int ufs_mtk_system_resume(struct device *dev) + + return ufshcd_system_resume(dev); + } +-#endif + +-#ifdef CONFIG_PM + static int ufs_mtk_runtime_suspend(struct device *dev) + { + struct ufs_hba *hba = dev_get_drvdata(dev); +@@ -1900,13 +1897,10 @@ static int ufs_mtk_runtime_resume(struct device *dev) + + return ufshcd_runtime_resume(dev); + } +-#endif + + static const struct dev_pm_ops ufs_mtk_pm_ops = { +- SET_SYSTEM_SLEEP_PM_OPS(ufs_mtk_system_suspend, +- ufs_mtk_system_resume) +- SET_RUNTIME_PM_OPS(ufs_mtk_runtime_suspend, +- ufs_mtk_runtime_resume, NULL) ++ SYSTEM_SLEEP_PM_OPS(ufs_mtk_system_suspend, ufs_mtk_system_resume) ++ RUNTIME_PM_OPS(ufs_mtk_runtime_suspend, ufs_mtk_runtime_resume, NULL) + .prepare = ufshcd_suspend_prepare, + .complete = ufshcd_resume_complete, + }; +@@ -1916,7 +1910,7 @@ static struct platform_driver ufs_mtk_pltform = { + .remove = ufs_mtk_remove, + .driver = { + .name = "ufshcd-mtk", +- .pm = &ufs_mtk_pm_ops, ++ .pm = pm_ptr(&ufs_mtk_pm_ops), + .of_match_table = ufs_mtk_of_match, + }, + }; +diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h +index 78380fc2374ea..8d2efb9e5d664 100644 +--- a/include/ufs/ufshcd.h ++++ b/include/ufs/ufshcd.h +@@ -1329,17 +1329,13 @@ static inline void *ufshcd_get_variant(struct ufs_hba *hba) + return hba->priv; + } + +-#ifdef CONFIG_PM + extern int ufshcd_runtime_suspend(struct device *dev); + extern int ufshcd_runtime_resume(struct device *dev); +-#endif +-#ifdef CONFIG_PM_SLEEP + extern int ufshcd_system_suspend(struct device *dev); + extern int ufshcd_system_resume(struct device *dev); + extern int ufshcd_system_freeze(struct device *dev); + extern int ufshcd_system_thaw(struct device *dev); + extern int ufshcd_system_restore(struct device *dev); +-#endif + + extern int ufshcd_dme_configure_adapt(struct ufs_hba *hba, + int agreed_gear, +-- +2.51.0 + diff --git a/queue-6.6/selftests-bpf-veristat-fix-printing-order-in-output_.patch b/queue-6.6/selftests-bpf-veristat-fix-printing-order-in-output_.patch new file mode 100644 index 0000000000..0ac915f760 --- /dev/null +++ b/queue-6.6/selftests-bpf-veristat-fix-printing-order-in-output_.patch @@ -0,0 +1,46 @@ +From ac17321c259107b3136f88af14e85ac464743ecf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 31 Dec 2025 14:10:50 -0800 +Subject: selftests/bpf: veristat: fix printing order in output_stats() + +From: Puranjay Mohan + +[ Upstream commit c286e7e9d1f1f3d90ad11c37e896f582b02d19c4 ] + +The order of the variables in the printf() doesn't match the text and +therefore veristat prints something like this: + +Done. Processed 24 files, 0 programs. Skipped 62 files, 0 programs. + +When it should print: + +Done. Processed 24 files, 62 programs. Skipped 0 files, 0 programs. + +Fix the order of variables in the printf() call. + +Fixes: 518fee8bfaf2 ("selftests/bpf: make veristat skip non-BPF and failing-to-open BPF objects") +Tested-by: Eduard Zingerman +Signed-off-by: Puranjay Mohan +Link: https://lore.kernel.org/r/20251231221052.759396-1-puranjay@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/bpf/veristat.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/testing/selftests/bpf/veristat.c b/tools/testing/selftests/bpf/veristat.c +index 611b5a0a6f7e3..fab89a84119f8 100644 +--- a/tools/testing/selftests/bpf/veristat.c ++++ b/tools/testing/selftests/bpf/veristat.c +@@ -1372,7 +1372,7 @@ static void output_stats(const struct verif_stats *s, enum resfmt fmt, bool last + if (last && fmt == RESFMT_TABLE) { + output_header_underlines(); + printf("Done. Processed %d files, %d programs. Skipped %d files, %d programs.\n", +- env.files_processed, env.files_skipped, env.progs_processed, env.progs_skipped); ++ env.files_processed, env.progs_processed, env.files_skipped, env.progs_skipped); + } + } + +-- +2.51.0 + diff --git a/queue-6.6/serial-caif-fix-use-after-free-in-caif_serial-ldisc_.patch b/queue-6.6/serial-caif-fix-use-after-free-in-caif_serial-ldisc_.patch new file mode 100644 index 0000000000..e78b606664 --- /dev/null +++ b/queue-6.6/serial-caif-fix-use-after-free-in-caif_serial-ldisc_.patch @@ -0,0 +1,152 @@ +From 83bc65c679b5b82b86fe18bc5e258818e9779f35 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 15:44:44 +0800 +Subject: serial: caif: fix use-after-free in caif_serial ldisc_close() + +From: Jiayuan Chen + +[ Upstream commit 308e7e4d0a846359685f40aade023aee7b27284c ] + +There is a use-after-free bug in caif_serial where handle_tx() may +access ser->tty after the tty has been freed. + +The race condition occurs between ldisc_close() and packet transmission: + + CPU 0 (close) CPU 1 (xmit) + ------------- ------------ + ldisc_close() + tty_kref_put(ser->tty) + [tty may be freed here] + <-- race window --> + caif_xmit() + handle_tx() + tty = ser->tty // dangling ptr + tty->ops->write() // UAF! + schedule_work() + ser_release() + unregister_netdevice() + +The root cause is that tty_kref_put() is called in ldisc_close() while +the network device is still active and can receive packets. + +Since ser and tty have a 1:1 binding relationship with consistent +lifecycles (ser is allocated in ldisc_open and freed in ser_release +via unregister_netdevice, and each ser binds exactly one tty), we can +safely defer the tty reference release to ser_release() where the +network device is unregistered. + +Fix this by moving tty_kref_put() from ldisc_close() to ser_release(), +after unregister_netdevice(). This ensures the tty reference is held +as long as the network device exists, preventing the UAF. + +Note: We save ser->tty before unregister_netdevice() because ser is +embedded in netdev's private data and will be freed along with netdev +(needs_free_netdev = true). + +How to reproduce: Add mdelay(500) at the beginning of ldisc_close() +to widen the race window, then run the reproducer program [1]. + +Note: There is a separate deadloop issue in handle_tx() when using +PORT_UNKNOWN serial ports (e.g., /dev/ttyS3 in QEMU without proper +serial backend). This deadloop exists even without this patch, +and is likely caused by inconsistency between uart_write_room() and +uart_write() in serial core. It has been addressed in a separate +patch [2]. + +KASAN report: + +================================================================== +BUG: KASAN: slab-use-after-free in handle_tx+0x5d1/0x620 +Read of size 1 at addr ffff8881131e1490 by task caif_uaf_trigge/9929 + +Call Trace: + + dump_stack_lvl+0x10e/0x1f0 + print_report+0xd0/0x630 + kasan_report+0xe4/0x120 + handle_tx+0x5d1/0x620 + dev_hard_start_xmit+0x9d/0x6c0 + __dev_queue_xmit+0x6e2/0x4410 + packet_xmit+0x243/0x360 + packet_sendmsg+0x26cf/0x5500 + __sys_sendto+0x4a3/0x520 + __x64_sys_sendto+0xe0/0x1c0 + do_syscall_64+0xc9/0xf80 + entry_SYSCALL_64_after_hwframe+0x77/0x7f +RIP: 0033:0x7f615df2c0d7 + +Allocated by task 9930: + +Freed by task 64: + +Last potentially related work creation: + +The buggy address belongs to the object at ffff8881131e1000 + which belongs to the cache kmalloc-cg-2k of size 2048 +The buggy address is located 1168 bytes inside of + freed 2048-byte region [ffff8881131e1000, ffff8881131e1800) + +The buggy address belongs to the physical page: +page_owner tracks the page as allocated +page last free pid 9778 tgid 9778 stack trace: + +Memory state around the buggy address: + ffff8881131e1380: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb + ffff8881131e1400: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb +>ffff8881131e1480: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb + ^ + ffff8881131e1500: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb + ffff8881131e1580: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb +================================================================== +[1]: https://gist.github.com/mrpre/f683f244544f7b11e7fa87df9e6c2eeb +[2]: https://lore.kernel.org/linux-serial/20260204074327.226165-1-jiayuan.chen@linux.dev/T/#u + +Reported-by: syzbot+827272712bd6d12c79a4@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/000000000000a4a7550611e234f5@google.com/T/ +Fixes: 56e0ef527b18 ("drivers/net: caif: fix wrong rtnl_is_locked() usage") +Reviewed-by: Greg Kroah-Hartman +Signed-off-by: Jiayuan Chen +Reviewed-by: Jijie Shao +Link: https://patch.msgid.link/20260206074450.154267-1-jiayuan.chen@linux.dev +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/caif/caif_serial.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c +index ed3a589def6b1..699ed0ff461e8 100644 +--- a/drivers/net/caif/caif_serial.c ++++ b/drivers/net/caif/caif_serial.c +@@ -298,6 +298,7 @@ static void ser_release(struct work_struct *work) + { + struct list_head list; + struct ser_device *ser, *tmp; ++ struct tty_struct *tty; + + spin_lock(&ser_lock); + list_replace_init(&ser_release_list, &list); +@@ -306,9 +307,11 @@ static void ser_release(struct work_struct *work) + if (!list_empty(&list)) { + rtnl_lock(); + list_for_each_entry_safe(ser, tmp, &list, node) { ++ tty = ser->tty; + dev_close(ser->dev); + unregister_netdevice(ser->dev); + debugfs_deinit(ser); ++ tty_kref_put(tty); + } + rtnl_unlock(); + } +@@ -369,8 +372,6 @@ static void ldisc_close(struct tty_struct *tty) + { + struct ser_device *ser = tty->disc_data; + +- tty_kref_put(ser->tty); +- + spin_lock(&ser_lock); + list_move(&ser->node, &ser_release_list); + spin_unlock(&ser_lock); +-- +2.51.0 + diff --git a/queue-6.6/serial-imx-change-serial_imx_console-to-bool.patch b/queue-6.6/serial-imx-change-serial_imx_console-to-bool.patch new file mode 100644 index 0000000000..88681fbc15 --- /dev/null +++ b/queue-6.6/serial-imx-change-serial_imx_console-to-bool.patch @@ -0,0 +1,50 @@ +From 106274e1435803adc3e5ead4ae38190c6efc8038 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 10 Jan 2026 15:26:40 -0800 +Subject: serial: imx: change SERIAL_IMX_CONSOLE to bool + +From: Randy Dunlap + +[ Upstream commit 79527d86ba91c2d9354832d19fd12b3baa66bd10 ] + +SERIAL_IMX_CONSOLE is a build option for the imx driver (SERIAL_IMX). +It does not build a separate console driver file, so it can't be built +as a module since it isn't built at all. + +Change the Kconfig symbol from tristate to bool and update the help +text accordingly. + +Fixes: 0db4f9b91c86 ("tty: serial: imx: enable imx serial console port as module") +Signed-off-by: Randy Dunlap +Link: https://patch.msgid.link/20260110232643.3533351-2-rdunlap@infradead.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/Kconfig | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig +index 4f57833e3ec74..ac74b491ba50b 100644 +--- a/drivers/tty/serial/Kconfig ++++ b/drivers/tty/serial/Kconfig +@@ -479,14 +479,14 @@ config SERIAL_IMX + can enable its onboard serial port by enabling this option. + + config SERIAL_IMX_CONSOLE +- tristate "Console on IMX serial port" ++ bool "Console on IMX serial port" + depends on SERIAL_IMX + select SERIAL_CORE_CONSOLE + help + If you have enabled the serial port on the Freescale IMX +- CPU you can make it the console by answering Y/M to this option. ++ CPU you can make it the console by answering Y to this option. + +- Even if you say Y/M here, the currently visible virtual console ++ Even if you say Y here, the currently visible virtual console + (/dev/tty0) will still be used as the system console by default, but + you can alter that using a kernel command line option such as + "console=ttymxc0". (Try "man bootparam" or see the documentation of +-- +2.51.0 + diff --git a/queue-6.6/serial-sh_sci-improve-dma-support-prompt.patch b/queue-6.6/serial-sh_sci-improve-dma-support-prompt.patch new file mode 100644 index 0000000000..b54af672d1 --- /dev/null +++ b/queue-6.6/serial-sh_sci-improve-dma-support-prompt.patch @@ -0,0 +1,39 @@ +From 6b18d74aca46f378eeb51b94fe1bbe2f950a2916 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 10 Jan 2026 15:26:43 -0800 +Subject: serial: SH_SCI: improve "DMA support" prompt + +From: Randy Dunlap + +[ Upstream commit 93bb95a11238d66a4c9aa6eabf9774b073a5895c ] + +Having a prompt of "DMA support" suddenly appear during a +"make oldconfig" can be confusing. Add a little helpful text to +the prompt message. + +Fixes: 73a19e4c0301 ("serial: sh-sci: Add DMA support.") +Signed-off-by: Randy Dunlap +Reviewed-by: Geert Uytterhoeven +Link: https://patch.msgid.link/20260110232643.3533351-5-rdunlap@infradead.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig +index ac74b491ba50b..2b9b2235e29d6 100644 +--- a/drivers/tty/serial/Kconfig ++++ b/drivers/tty/serial/Kconfig +@@ -661,7 +661,7 @@ config SERIAL_SH_SCI_EARLYCON + default ARCH_RENESAS + + config SERIAL_SH_SCI_DMA +- bool "DMA support" if EXPERT ++ bool "Support for DMA on SuperH SCI(F)" if EXPERT + depends on SERIAL_SH_SCI && DMA_ENGINE + default ARCH_RENESAS + +-- +2.51.0 + diff --git a/queue-6.6/series b/queue-6.6/series index 0b63edc9fd..d0e61999e6 100644 --- a/queue-6.6/series +++ b/queue-6.6/series @@ -1,2 +1,257 @@ rdma-siw-fix-potential-null-pointer-dereference-in-header-processing.patch rdma-umad-reject-negative-data_len-in-ib_umad_write.patch +auxdisplay-arm-charlcd-fix-release_mem_region-size.patch +hfsplus-return-error-when-node-already-exists-in-hfs.patch +rcu-s-boost_kthread_mutex-kthread_mutex.patch +rcu-exp-move-expedited-kthread-worker-creation-funct.patch +rcu-refactor-expedited-handling-check-in-rcu_read_un.patch +rcu-remove-local_irq_save-restore-in-rcu_preempt_def.patch +rcu-fix-rcu_read_unlock-deadloop-due-to-softirq.patch +audit-move-the-compat_xxx_class-extern-declarations-.patch +i3c-move-device-name-assignment-after-i3c_bus_init.patch +fs-add-linux-init_task.h-for-init_fs.patch +i3c-master-update-hot-join-flag-only-on-success.patch +gfs2-retries-missing-in-gfs2_-rename-exchange.patch +mm-list_lru-update-kernel-documentation-to-follow-th.patch +gfs2-fix-slab-use-after-free-in-qd_put.patch +gfs2-add-metapath_dibh-helper.patch +gfs2-fix-use-after-free-in-iomap-inline-data-write-p.patch +i3c-dw-initialize-spinlock-to-avoid-upsetting-lockde.patch +tpm-tpm_i2c_infineon-fix-locality-leak-on-get_burstc.patch +tpm-st33zp24-fix-missing-cleanup-on-get_burstcount-e.patch +btrfs-qgroup-return-correct-error-when-deleting-qgro.patch +btrfs-fix-block_group_tree-dirty_list-corruption.patch +smb-client-fix-potential-uaf-and-double-free-in-smb2.patch +xen-virtio-don-t-use-grant-dma-ops-when-running-as-d.patch +acpica-fix-null-pointer-dereference-in-acpi_ev_addre.patch +io_uring-sync-validate-passed-in-offset.patch +cpuidle-menu-cleanup-after-loadavg-removal.patch +cpuidle-governors-menu-always-check-timers-with-tick.patch +md-raid10-fix-any_working-flag-handling-in-raid10_sy.patch +cpufreq-scmi-correct-scmi-explanation.patch +iomap-fix-submission-side-handling-of-completion-sid.patch +ublk-validate-sqe128-flag-before-accessing-the-cmd.patch +x86-xen-make-some-functions-static.patch +partial-revert-x86-xen-fix-balloon-target-initializa.patch +pm-wakeup-handle-empty-list-in-wakeup_sources_walk_s.patch +perf-arm_spe-properly-set-hw.state-on-failures.patch +pm-sleep-wakeirq-harden-dev_pm_clear_wake_irq-agains.patch +s390-cio-fix-device-lifecycle-handling-in-css_alloc_.patch +crypto-qat-fix-warning-on-adf_pfvf_pf_proto.c.patch +selftests-bpf-veristat-fix-printing-order-in-output_.patch +libbpf-fix-oob-read-in-btf_dump_get_bitfield_value.patch +arm-vdso-patch-out-__vdso_clock_getres-if-unavailabl.patch +crypto-cavium-fix-dma_free_coherent-size.patch +crypto-octeontx-fix-dma_free_coherent-size.patch +crypto-hisilicon-zip-support-deflate-algorithm.patch +crypto-hisilicon-zip-remove-zlib-and-gzip.patch +crypto-hisilicon-zip-adjust-the-way-to-obtain-the-re.patch +crypto-hisilicon-sec2-support-skcipher-aead-fallback.patch +hrtimer-fix-trace-oddity.patch +bpf-sockmap-fix-incorrect-copied_seq-calculation.patch +bpf-sockmap-fix-fionread-for-sockmap.patch +crypto-hisilicon-trng-modifying-the-order-of-header-.patch +crypto-hisilicon-trng-support-tfms-sharing-the-devic.patch +bpf-fix-bpf_xdp_store_bytes-proto-for-read-only-arg.patch +scsi-efct-use-irqf_oneshot-and-default-primary-handl.patch +edac-altera-remove-irqf_oneshot.patch +mfd-wm8350-core-use-irqf_oneshot.patch +sched-rt-skip-currently-executing-cpu-in-rto_next_cp.patch +pstore-ram-fix-buffer-overflow-in-persistent_ram_sav.patch +soc-qcom-smem-handle-enomem-error-during-probe.patch +edac-i5000-fix-snprintf-size-calculation-in-calculat.patch +edac-i5400-fix-snprintf-limit-calculation-in-calcula.patch +arm64-dts-tqma8mpql-mba8mpxl-fix-hdmi-cec-pad-contro.patch +clk-qcom-return-correct-error-code-in-qcom_cc_probe_.patch +arm64-dts-qcom-sdm630-fix-gpu_speed_bin-size.patch +arm64-dts-qcom-sdm845-oneplus-don-t-mark-ts-supply-b.patch +arm64-dts-qcom-sdm845-oneplus-don-t-keep-panel-regul.patch +arm64-dts-qcom-sdm845-oneplus-mark-l14a-regulator-as.patch +arm-dts-allwinner-sun5i-a13-utoo-p66-delete-power-gp.patch +powerpc-uaccess-move-barrier_nospec-out-of-allow_rea.patch +soc-qcom-cmd-db-use-devm_memremap-to-fix-memory-leak.patch +soc-mediatek-svs-fix-memory-leak-in-svs_enable_debug.patch +powerpc-eeh-fix-recursive-pci_lock_rescan_remove-loc.patch +arm-dts-lpc32xx-set-motor-pwm-pwm-cells-property-val.patch +arm-dts-lpc32xx-add-clocks-property-to-motor-control.patch +arm64-dts-amlogic-axg-assign-the-mmc-signal-clocks.patch +arm64-dts-amlogic-gx-assign-the-mmc-signal-clocks.patch +arm64-dts-amlogic-g12-assign-the-mmc-b-and-c-signal-.patch +arm64-dts-amlogic-g12-assign-the-mmc-a-signal-clock.patch +arm64-dts-qcom-sdm845-db845c-drop-cs-from-spio0.patch +arm64-dts-qcom-sdm845-db845c-specify-power-for-wifi-.patch +arm64-dts-qcom-sm6115-add-cx_mem-dbgc-gpu-regions.patch +workqueue-factor-out-assign_rescuer_work.patch +workqueue-only-assign-rescuer-work-when-really-neede.patch +workqueue-process-rescuer-work-items-one-by-one-usin.patch +smack-smack-doi-must-be-0.patch +smack-smack-doi-accept-previously-used-values.patch +asoc-nau8821-consistently-clear-interrupts-before-un.patch +asoc-nau8821-avoid-unnecessary-blocking-in-irq-handl.patch +asoc-nau8821-fixup-nau8821_enable_jack_detect.patch +drm-amdgpu-use-explicit-vcn-instance-0-in-sr-iov-ini.patch +drm-msm-disp-dpu-add-merge3d-support-for-sc7280.patch +regulator-core-move-supply-check-earlier-in-set_mach.patch +hid-playstation-add-missing-check-for-input_ff_creat.patch +drm-msm-dpu-fix-cmd-panels-on-dpu-1.x-3.x.patch +media-ccs-accommodate-c-phy-into-the-calculation.patch +drm-msm-a2xx-fix-pixel-shader-start-on-a225.patch +platform-chrome-cros_typec_switch-don-t-touch-struct.patch +media-uvcvideo-fix-allocation-for-small-frame-sizes.patch +platform-chrome-cros_ec_lightbar-fix-response-size-i.patch +spi-tools-add-include-folder-to-.gitignore.patch +revert-hwmon-ibmpex-fix-use-after-free-in-high-low-s.patch +pci-mediatek-fix-irq-domain-leak-when-msi-allocation.patch +documentation-pci-endpoint-fix-ntb-vntb-copy-paste-e.patch +pci-pm-avoid-redundant-delays-on-d3hot-d3cold.patch +pci-p2pdma-release-per-cpu-pgmap-ref-when-vm_insert_.patch +documentation-tracing-add-ring-buffer-mapping.patch +docs-fix-warning-document-not-included-in-any-toctre.patch +documentation-trace-refactor-toctree.patch +documentation-tracing-add-pci-tracepoint-documentati.patch +pci-do-not-attempt-to-set-exttag-for-vfs.patch +pci-portdrv-fix-potential-resource-leak.patch +quota-fix-livelock-between-quotactl-and-freeze_super.patch +net-mctp-i2c-fix-duplicate-reception-of-old-data.patch +mctp-i2c-initialise-event-handler-read-bytes.patch +wifi-cfg80211-stop-nan-and-p2p-in-cfg80211_leave.patch +netfilter-nf_tables-reset-table-validation-state-on-.patch +netfilter-nf_conncount-make-nf_conncount_gc_list-to-.patch +netfilter-nf_conncount-increase-the-connection-clean.patch +netfilter-nft_compat-add-more-restrictions-on-netlin.patch +netfilter-nf_conncount-fix-tracking-of-connections-f.patch +module-add-helper-function-for-reading-module_buildi.patch +kallsyms-ftrace-set-module-buildid-in-ftrace_mod_add.patch +pci-mark-3ware-9650sa-root-port-extended-tags-as-bro.patch +iommu-vt-d-flush-cache-for-pasid-table-before-using-.patch +dm-use-bio_clone_blkg_association.patch +nfsd-never-defer-requests-during-idmap-lookup.patch +fat-avoid-parent-link-count-underflow-in-rmdir.patch +tcp-tcp_tx_timestamp-must-look-at-the-rtx-queue.patch +wifi-ath10k-sdio-add-missing-lock-protection-in-ath1.patch +pci-initialize-rcb-from-pci_configure_device.patch +pci-move-pci_read_bridge_windows-below-individual-wi.patch +pci-supply-bridge-device-not-secondary-bus-to-read-w.patch +pci-log-bridge-windows-conditionally.patch +pci-log-bridge-info-when-first-enumerating-bridge.patch +pci-add-pcie_msg_code_assert_intx-message-macros.patch +pci-add-defines-for-bridge-window-indexing.patch +pci-acpi-restrict-program_hpx_type2-to-aer-bits.patch +ipc-don-t-audit-capability-check-in-ipc_permissions.patch +ucount-check-for-cap_sys_resource-using-ns_capable_n.patch +of-unittest-fix-possible-null-pointer-dereferences-i.patch +mptcp-fix-receive-space-timestamp-initialization.patch +octeontx2-af-fix-pf-driver-crash-with-kexec-kernel-b.patch +bonding-only-set-speed-duplex-to-unknown-if-getting-.patch +inet-raw-sockets-using-ipproto_raw-must-drop-incomin.patch +nfc-hci-shdlc-stop-timers-and-work-before-freeing-co.patch +netfilter-nft_set_hash-fix-get-operation-on-big-endi.patch +netfilter-nft_counter-fix-reset-of-counters-on-32bit.patch +netfilter-nft_set_rbtree-check-for-partial-overlaps-.patch +pci-add-acs-quirk-for-pericom-pi7c9x2g404-switches-1.patch +net-hns3-fix-double-free-issue-for-tx-spare-buffer.patch +procfs-fix-missing-rcu-protection-when-reading-real_.patch +smb-client-correct-value-for-smbd_max_fragmented_rec.patch +net-atm-fix-crash-due-to-unvalidated-vcc-pointer-in-.patch +net-sunhme-fix-sbus-regression.patch +net-add-skb_dstref_steal-and-skb_dstref_restore.patch +net-switch-to-skb_dstref_steal-skb_dstref_restore-fo.patch +xfrm-fix-ip_rt_bug-race-in-icmp_route_lookup-reverse.patch +serial-caif-fix-use-after-free-in-caif_serial-ldisc_.patch +octeon_ep-support-to-fetch-firmware-info.patch +octeon_ep-restructured-interrupt-handlers.patch +octeon_ep-support-octeon-cn10k-devices.patch +octeon_ep-disable-per-ring-interrupts.patch +octeon_ep-set-backpressure-watermark-for-rx-queues.patch +octeon_ep-ensure-dbell-baddr-updation.patch +ionic-rate-limit-unknown-xcvr-type-messages.patch +octeontx2-pf-unregister-devlink-on-probe-failure.patch +rdma-rtrs-server-remove-dead-code.patch +ib-cache-update-gid-cache-on-client-reregister-event.patch +rdma-hns-fix-wq_mem_reclaim-warning.patch +rdma-hns-notify-ulp-of-remaining-soft-wcs-during-res.patch +power-supply-ab8500-fix-use-after-free-in-power_supp.patch +power-supply-act8945a-fix-use-after-free-in-power_su.patch +power-supply-bq256xx-fix-use-after-free-in-power_sup.patch +power-supply-bq25980-fix-use-after-free-in-power_sup.patch +power-supply-cpcap-battery-fix-use-after-free-in-pow.patch +power-supply-goldfish-fix-use-after-free-in-power_su.patch +power-supply-rt9455-fix-use-after-free-in-power_supp.patch +power-supply-sbs-battery-fix-use-after-free-in-power.patch +power-reset-nvmem-reboot-mode-respect-cell-size-for-.patch +power-supply-bq27xxx-fix-wrong-errno-when-bus-ops-ar.patch +power-supply-wm97xx-fix-null-pointer-dereference-in-.patch +rdma-rtrs-srv-fix-sg-mapping.patch +rdma-rxe-fix-double-free-in-rxe_srq_from_init.patch +tools-power-x86-intel-speed-select-fix-file-descript.patch +mtd-rawnand-cadence-fix-return-type-of-cdma-send-and.patch +crypto-ccp-add-an-s4-restore-flow.patch +crypto-ccp-move-direct-access-to-some-psp-registers-.patch +crypto-ccp-factor-out-ring-destroy-handling-to-a-hel.patch +crypto-ccp-send-psp_cmd_tee_ring_destroy-when-psp_cm.patch +mtd-parsers-fix-memory-leak-in-mtd_parser_tplink_saf.patch +rdma-uverbs-validate-wqe_size-before-using-it-in-ib_.patch +rdma-rxe-fix-race-condition-in-qp-timer-handlers.patch +rdma-core-fix-a-couple-of-obvious-typos-in-comments.patch +svcrdma-remove-queue-shortening-warnings.patch +svcrdma-clean-up-comment-in-svc_rdma_accept.patch +svcrdma-increase-the-per-transport-rw_ctx-count.patch +svcrdma-reduce-the-number-of-rdma_rw-contexts-per-qp.patch +rdma-core-add-rdma_rw_max_sge-helper-for-sq-sizing.patch +cxl-fix-premature-commit_end-increment-on-decoder-co.patch +mtd-parsers-ofpart-fix-of-node-refcount-leak-in-pars.patch +mtd-spinand-fix-kernel-doc.patch +power-supply-qcom_battmgr-recognize-lip-as-lithium-p.patch +rdma-uverbs-add-__gfp_nowarn-to-ib_uverbs_unmarshall.patch +pnfs-fix-a-missing-wake-up-while-waiting-on-nfs_layo.patch +scsi-smartpqi-fix-memory-leak-in-pqi_report_phys_lun.patch +scsi-ufs-host-mediatek-require-config_pm.patch +scsi-csiostor-fix-dereference-of-null-pointer-rn.patch +nvdimm-virtio_pmem-serialize-flush-requests.patch +fs-nfs-fix-readdir-slow-start-regression.patch +tracing-properly-process-error-handling-in-event_his.patch +tracing-remove-duplicate-enable_event_str-and-disabl.patch +fbdev-of_display_timing-fix-device-node-reference-le.patch +fbdev-au1200fb-fix-a-memory-leak-in-au1200fb_drv_pro.patch +clk-qcom-gcc-sm8550-use-floor-ops-for-sdcc-rcgs.patch +clk-qcom-rcg2-compute-2d-using-duty-fraction-directl.patch +clk-meson-gxbb-limit-the-hdmi-pll-od-to-4-on-gxl-gxm.patch +clk-qcom-gcc-sm8450-update-the-sdcc-rcgs-to-use-shar.patch +clk-qcom-gcc-sdx75-update-the-sdcc-rcgs-to-use-share.patch +clk-qcom-gcc-qdu1000-update-the-sdcc-rcgs-to-use-sha.patch +clk-qcom-gcc-msm8953-remove-always_on-flag-from-cpp_.patch +clk-qcom-gcc-msm8917-remove-always_on-flag-from-cpp_.patch +clk-qcom-gcc-ipq5018-flag-sleep-clock-as-critical.patch +clk-move-clk_-save-restore-_context-to-common_clk-se.patch +clk-qcom-dispcc-sdm845-enable-parents-for-pixel-cloc.patch +clk-qcom-gfx3d-add-parent-to-parent-request-map.patch +clk-mediatek-fix-error-handling-in-runtime-pm-setup.patch +dmaengine-mediatek-uart-apdma-fix-above-4g-addressin.patch +dma-dma-axi-dmac-fix-sw-cyclic-transfers.patch +staging-greybus-lights-avoid-null-deref.patch +serial-imx-change-serial_imx_console-to-bool.patch +serial-sh_sci-improve-dma-support-prompt.patch +mmc-rtsx_pci_sdmmc-increase-power-on-settling-delay-.patch +iio-pressure-mprls0025pa-fix-scan_type-struct.patch +watchdog-starfive-wdt-fix-pm-reference-leak-in-probe.patch +coresight-etm3x-fix-cpulocked-warning-on-cpuhp.patch +revert-mmc-rtsx_pci_sdmmc-increase-power-on-settling.patch +mfd-arizona-fix-regulator-resource-leak-on-wm5102_cl.patch +mfd-simple-mfd-i2c-add-max77705-support.patch +mfd-simple-mfd-i2c-add-compatible-strings-for-layers.patch +mfd-simple-mfd-i2c-add-spacemit-p1-support.patch +mfd-simple-mfd-i2c-keep-compatible-strings-in-alphab.patch +mfd-simple-mfd-i2c-add-delta-tn48m-cpld-support.patch +drivers-iio-mpu3050-use-dev_err_probe-for-regulator-.patch +usb-bdc-fix-sleep-during-atomic.patch +pinctrl-equilibrium-fix-device-node-reference-leak-i.patch +ovl-fix-uninit-value-in-ovl_fill_real.patch +iio-sca3000-fix-a-resource-leak-in-sca3000_probe.patch +pinctrl-qcom-sm8250-lpass-lpi-fix-i2s2_data_groups-d.patch +pinctrl-single-fix-refcount-leak-in-pcs_add_gpio_fun.patch +leds-qcom-lpg-check-the-return-value-of-regmap_bulk_.patch +backlight-qcom-wled-support-ovp-values-for-pmi8994.patch +backlight-qcom-wled-change-pm8950-wled-configuration.patch +dmaengine-fsl-edma-main-convert-to-platform-remove-c.patch +dmaengine-fsl-edma-don-t-explicitly-disable-clocks-i.patch +io_uring-cancel-de-unionize-file-and-user_data-in-st.patch diff --git a/queue-6.6/smack-smack-doi-accept-previously-used-values.patch b/queue-6.6/smack-smack-doi-accept-previously-used-values.patch new file mode 100644 index 0000000000..57878ae831 --- /dev/null +++ b/queue-6.6/smack-smack-doi-accept-previously-used-values.patch @@ -0,0 +1,233 @@ +From cd0b86356817cebb8834b182b228c23524cf990e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Sep 2025 15:31:53 +0300 +Subject: smack: /smack/doi: accept previously used values +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Konstantin Andreev + +[ Upstream commit 33d589ed60ae433b483761987b85e0d24e54584e ] + +Writing to /smack/doi a value that has ever been +written there in the past disables networking for +non-ambient labels. +E.g. + + # cat /smack/doi + 3 + # netlabelctl -p cipso list + Configured CIPSO mappings (1) + DOI value : 3 + mapping type : PASS_THROUGH + # netlabelctl -p map list + Configured NetLabel domain mappings (3) + domain: "_" (IPv4) + protocol: UNLABELED + domain: DEFAULT (IPv4) + protocol: CIPSO, DOI = 3 + domain: DEFAULT (IPv6) + protocol: UNLABELED + + # cat /smack/ambient + _ + # cat /proc/$$/attr/smack/current + _ + # ping -c1 10.1.95.12 + 64 bytes from 10.1.95.12: icmp_seq=1 ttl=64 time=0.964 ms + # echo foo >/proc/$$/attr/smack/current + # ping -c1 10.1.95.12 + 64 bytes from 10.1.95.12: icmp_seq=1 ttl=64 time=0.956 ms + unknown option 86 + + # echo 4 >/smack/doi + # echo 3 >/smack/doi +!> [ 214.050395] smk_cipso_doi:691 cipso add rc = -17 + # echo 3 >/smack/doi +!> [ 249.402261] smk_cipso_doi:678 remove rc = -2 +!> [ 249.402261] smk_cipso_doi:691 cipso add rc = -17 + + # ping -c1 10.1.95.12 +!!> ping: 10.1.95.12: Address family for hostname not supported + + # echo _ >/proc/$$/attr/smack/current + # ping -c1 10.1.95.12 + 64 bytes from 10.1.95.12: icmp_seq=1 ttl=64 time=0.617 ms + +This happens because Smack keeps decommissioned DOIs, +fails to re-add them, and consequently refuses to add +the “default” domain map: + + # netlabelctl -p cipso list + Configured CIPSO mappings (2) + DOI value : 3 + mapping type : PASS_THROUGH + DOI value : 4 + mapping type : PASS_THROUGH + # netlabelctl -p map list + Configured NetLabel domain mappings (2) + domain: "_" (IPv4) + protocol: UNLABELED +!> (no ipv4 map for default domain here) + domain: DEFAULT (IPv6) + protocol: UNLABELED + +Fix by clearing decommissioned DOI definitions and +serializing concurrent DOI updates with a new lock. + +Also: +- allow /smack/doi to live unconfigured, since + adding a map (netlbl_cfg_cipsov4_map_add) may fail. + CIPSO_V4_DOI_UNKNOWN(0) indicates the unconfigured DOI +- add new DOI before removing the old default map, + so the old map remains if the add fails + +(2008-02-04, Casey Schaufler) +Fixes: e114e473771c ("Smack: Simplified Mandatory Access Control Kernel") + +Signed-off-by: Konstantin Andreev +Signed-off-by: Casey Schaufler +Signed-off-by: Sasha Levin +--- + security/smack/smackfs.c | 71 +++++++++++++++++++++++++--------------- + 1 file changed, 45 insertions(+), 26 deletions(-) + +diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c +index a130007397562..109ad155ffc2a 100644 +--- a/security/smack/smackfs.c ++++ b/security/smack/smackfs.c +@@ -68,6 +68,7 @@ enum smk_inos { + static DEFINE_MUTEX(smack_cipso_lock); + static DEFINE_MUTEX(smack_ambient_lock); + static DEFINE_MUTEX(smk_net4addr_lock); ++static DEFINE_MUTEX(smk_cipso_doi_lock); + #if IS_ENABLED(CONFIG_IPV6) + static DEFINE_MUTEX(smk_net6addr_lock); + #endif /* CONFIG_IPV6 */ +@@ -139,7 +140,7 @@ struct smack_parsed_rule { + int smk_access2; + }; + +-static u32 smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; ++static u32 smk_cipso_doi_value = CIPSO_V4_DOI_UNKNOWN; + + /* + * Values for parsing cipso rules +@@ -679,43 +680,60 @@ static const struct file_operations smk_load_ops = { + }; + + /** +- * smk_cipso_doi - initialize the CIPSO domain ++ * smk_cipso_doi - set netlabel maps ++ * @ndoi: new value for our CIPSO DOI ++ * @gfp_flags: kmalloc allocation context + */ +-static void smk_cipso_doi(void) ++static int ++smk_cipso_doi(u32 ndoi, gfp_t gfp_flags) + { +- int rc; ++ int rc = 0; + struct cipso_v4_doi *doip; + struct netlbl_audit nai; + +- smk_netlabel_audit_set(&nai); ++ mutex_lock(&smk_cipso_doi_lock); + +- rc = netlbl_cfg_map_del(NULL, PF_INET, NULL, NULL, &nai); +- if (rc != 0) +- printk(KERN_WARNING "%s:%d remove rc = %d\n", +- __func__, __LINE__, rc); ++ if (smk_cipso_doi_value == ndoi) ++ goto clr_doi_lock; ++ ++ smk_netlabel_audit_set(&nai); + +- doip = kmalloc(sizeof(struct cipso_v4_doi), GFP_KERNEL | __GFP_NOFAIL); ++ doip = kmalloc(sizeof(struct cipso_v4_doi), gfp_flags); ++ if (!doip) { ++ rc = -ENOMEM; ++ goto clr_doi_lock; ++ } + doip->map.std = NULL; +- doip->doi = smk_cipso_doi_value; ++ doip->doi = ndoi; + doip->type = CIPSO_V4_MAP_PASS; + doip->tags[0] = CIPSO_V4_TAG_RBITMAP; + for (rc = 1; rc < CIPSO_V4_TAG_MAXCNT; rc++) + doip->tags[rc] = CIPSO_V4_TAG_INVALID; + + rc = netlbl_cfg_cipsov4_add(doip, &nai); +- if (rc != 0) { +- printk(KERN_WARNING "%s:%d cipso add rc = %d\n", +- __func__, __LINE__, rc); ++ if (rc) { + kfree(doip); +- return; ++ goto clr_doi_lock; + } +- rc = netlbl_cfg_cipsov4_map_add(doip->doi, NULL, NULL, NULL, &nai); +- if (rc != 0) { +- printk(KERN_WARNING "%s:%d map add rc = %d\n", +- __func__, __LINE__, rc); +- netlbl_cfg_cipsov4_del(doip->doi, &nai); +- return; ++ ++ if (smk_cipso_doi_value != CIPSO_V4_DOI_UNKNOWN) { ++ rc = netlbl_cfg_map_del(NULL, PF_INET, NULL, NULL, &nai); ++ if (rc && rc != -ENOENT) ++ goto clr_ndoi_def; ++ ++ netlbl_cfg_cipsov4_del(smk_cipso_doi_value, &nai); + } ++ ++ rc = netlbl_cfg_cipsov4_map_add(ndoi, NULL, NULL, NULL, &nai); ++ if (rc) { ++ smk_cipso_doi_value = CIPSO_V4_DOI_UNKNOWN; // no default map ++clr_ndoi_def: netlbl_cfg_cipsov4_del(ndoi, &nai); ++ } else ++ smk_cipso_doi_value = ndoi; ++ ++clr_doi_lock: ++ mutex_unlock(&smk_cipso_doi_lock); ++ return rc; + } + + /** +@@ -1617,11 +1635,8 @@ static ssize_t smk_write_doi(struct file *file, const char __user *buf, + + if (u == CIPSO_V4_DOI_UNKNOWN || u > U32_MAX) + return -EINVAL; +- smk_cipso_doi_value = u; +- +- smk_cipso_doi(); + +- return count; ++ return smk_cipso_doi(u, GFP_KERNEL) ? : count; + } + + static const struct file_operations smk_doi_ops = { +@@ -2998,6 +3013,7 @@ static int __init init_smk_fs(void) + { + int err; + int rc; ++ struct netlbl_audit nai; + + if (smack_enabled == 0) + return 0; +@@ -3016,7 +3032,10 @@ static int __init init_smk_fs(void) + } + } + +- smk_cipso_doi(); ++ smk_netlabel_audit_set(&nai); ++ (void) netlbl_cfg_map_del(NULL, PF_INET, NULL, NULL, &nai); ++ (void) smk_cipso_doi(SMACK_CIPSO_DOI_DEFAULT, ++ GFP_KERNEL | __GFP_NOFAIL); + smk_unlbl_ambient(NULL); + + rc = smack_populate_secattr(&smack_known_floor); +-- +2.51.0 + diff --git a/queue-6.6/smack-smack-doi-must-be-0.patch b/queue-6.6/smack-smack-doi-must-be-0.patch new file mode 100644 index 0000000000..1165b2d291 --- /dev/null +++ b/queue-6.6/smack-smack-doi-must-be-0.patch @@ -0,0 +1,71 @@ +From 5ffea57ace36ea3d5a1bf12623242b71b20d3cc3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Sep 2025 15:16:02 +0300 +Subject: smack: /smack/doi must be > 0 + +From: Konstantin Andreev + +[ Upstream commit 19c013e1551bf51e1493da1270841d60e4fd3f15 ] + +/smack/doi allows writing and keeping negative doi values. +Correct values are 0 < doi <= (max 32-bit positive integer) + +(2008-02-04, Casey Schaufler) +Fixes: e114e473771c ("Smack: Simplified Mandatory Access Control Kernel") + +Signed-off-by: Konstantin Andreev +Signed-off-by: Casey Schaufler +Signed-off-by: Sasha Levin +--- + security/smack/smackfs.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c +index 1e35c9f807b2b..a130007397562 100644 +--- a/security/smack/smackfs.c ++++ b/security/smack/smackfs.c +@@ -139,7 +139,7 @@ struct smack_parsed_rule { + int smk_access2; + }; + +-static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; ++static u32 smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; + + /* + * Values for parsing cipso rules +@@ -1580,7 +1580,7 @@ static ssize_t smk_read_doi(struct file *filp, char __user *buf, + if (*ppos != 0) + return 0; + +- sprintf(temp, "%d", smk_cipso_doi_value); ++ sprintf(temp, "%lu", (unsigned long)smk_cipso_doi_value); + rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp)); + + return rc; +@@ -1599,7 +1599,7 @@ static ssize_t smk_write_doi(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) + { + char temp[80]; +- int i; ++ unsigned long u; + + if (!smack_privileged(CAP_MAC_ADMIN)) + return -EPERM; +@@ -1612,10 +1612,12 @@ static ssize_t smk_write_doi(struct file *file, const char __user *buf, + + temp[count] = '\0'; + +- if (sscanf(temp, "%d", &i) != 1) ++ if (kstrtoul(temp, 10, &u)) + return -EINVAL; + +- smk_cipso_doi_value = i; ++ if (u == CIPSO_V4_DOI_UNKNOWN || u > U32_MAX) ++ return -EINVAL; ++ smk_cipso_doi_value = u; + + smk_cipso_doi(); + +-- +2.51.0 + diff --git a/queue-6.6/smb-client-correct-value-for-smbd_max_fragmented_rec.patch b/queue-6.6/smb-client-correct-value-for-smbd_max_fragmented_rec.patch new file mode 100644 index 0000000000..bc085f0338 --- /dev/null +++ b/queue-6.6/smb-client-correct-value-for-smbd_max_fragmented_rec.patch @@ -0,0 +1,78 @@ +From 295332e7b50cbebccd48da1c045d7186c661cb54 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 17:14:14 +0100 +Subject: smb: client: correct value for smbd_max_fragmented_recv_size + +From: Stefan Metzmacher + +[ Upstream commit 4a93d1ee2d0206970b6eb13fbffe07938cd95948 ] + +When we download a file without rdma offload or get +a large directly enumeration from the server, +the server might want to send up to smbd_max_fragmented_recv_size +bytes, but if it is too large all our recv buffers +might already be moved to the recv_io.reassembly.list +and we're no longer able to grant recv credits. + +The maximum fragmented upper-layer payload receive size supported + +Assume max_payload_per_credit is +smbd_max_receive_size - 24 = 1340 + +The maximum number would be +smbd_receive_credit_max * max_payload_per_credit + + 1340 * 255 = 341700 (0x536C4) + +The minimum value from the spec is 131072 (0x20000) + +For now we use the logic we used in ksmbd before: + (1364 * 255) / 2 = 173910 (0x2A756) + +Fixes: 03bee01d6215 ("CIFS: SMBD: Add SMB Direct protocol initial values and constants") +Cc: Steve French +Cc: Tom Talpey +Cc: Long Li +Cc: Namjae Jeon +Cc: linux-cifs@vger.kernel.org +Cc: samba-technical@lists.samba.org +Signed-off-by: Stefan Metzmacher +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/client/smbdirect.c | 19 +++++++++++++++++-- + 1 file changed, 17 insertions(+), 2 deletions(-) + +diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c +index be9be8f363319..359ab64e17d99 100644 +--- a/fs/smb/client/smbdirect.c ++++ b/fs/smb/client/smbdirect.c +@@ -91,8 +91,23 @@ int smbd_send_credit_target = 255; + /* The maximum single message size can be sent to remote peer */ + int smbd_max_send_size = 1364; + +-/* The maximum fragmented upper-layer payload receive size supported */ +-int smbd_max_fragmented_recv_size = 1024 * 1024; ++/* ++ * The maximum fragmented upper-layer payload receive size supported ++ * ++ * Assume max_payload_per_credit is ++ * smbd_max_receive_size - 24 = 1340 ++ * ++ * The maximum number would be ++ * smbd_receive_credit_max * max_payload_per_credit ++ * ++ * 1340 * 255 = 341700 (0x536C4) ++ * ++ * The minimum value from the spec is 131072 (0x20000) ++ * ++ * For now we use the logic we used in ksmbd before: ++ * (1364 * 255) / 2 = 173910 (0x2A756) ++ */ ++int smbd_max_fragmented_recv_size = (1364 * 255) / 2; + + /* The maximum single-message size which can be received */ + int smbd_max_receive_size = 1364; +-- +2.51.0 + diff --git a/queue-6.6/smb-client-fix-potential-uaf-and-double-free-in-smb2.patch b/queue-6.6/smb-client-fix-potential-uaf-and-double-free-in-smb2.patch new file mode 100644 index 0000000000..88596e1a97 --- /dev/null +++ b/queue-6.6/smb-client-fix-potential-uaf-and-double-free-in-smb2.patch @@ -0,0 +1,41 @@ +From d015c0938d2a3b5e640c377de7a1cb68438fd983 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 13:19:52 -0300 +Subject: smb: client: fix potential UAF and double free in smb2_open_file() + +From: Paulo Alcantara + +[ Upstream commit ebbbc4bfad4cb355d17c671223d0814ee3ef4eda ] + +Zero out @err_iov and @err_buftype before retrying SMB2_open() to +prevent an UAF bug if @data != NULL, otherwise a double free. + +Fixes: e3a43633023e ("smb/client: fix memory leak in smb2_open_file()") +Reported-by: David Howells +Closes: https://lore.kernel.org/r/2892312.1770306653@warthog.procyon.org.uk +Signed-off-by: Paulo Alcantara (Red Hat) +Reviewed-by: David Howells +Reviewed-by: ChenXiaoSong +Cc: linux-cifs@vger.kernel.org +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/client/smb2file.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/fs/smb/client/smb2file.c b/fs/smb/client/smb2file.c +index d436057ed77e3..4e7d5c612256d 100644 +--- a/fs/smb/client/smb2file.c ++++ b/fs/smb/client/smb2file.c +@@ -123,6 +123,8 @@ int smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, __u32 + &err_buftype); + if (rc == -EACCES && retry_without_read_attributes) { + free_rsp_buf(err_buftype, err_iov.iov_base); ++ memset(&err_iov, 0, sizeof(err_iov)); ++ err_buftype = CIFS_NO_BUFFER; + oparms->desired_access &= ~FILE_READ_ATTRIBUTES; + rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, smb2_data, NULL, &err_iov, + &err_buftype); +-- +2.51.0 + diff --git a/queue-6.6/soc-mediatek-svs-fix-memory-leak-in-svs_enable_debug.patch b/queue-6.6/soc-mediatek-svs-fix-memory-leak-in-svs_enable_debug.patch new file mode 100644 index 0000000000..89fd7562cf --- /dev/null +++ b/queue-6.6/soc-mediatek-svs-fix-memory-leak-in-svs_enable_debug.patch @@ -0,0 +1,59 @@ +From 5771bfb2797dc93ef2e5b628339785cf3700101b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 28 Dec 2025 16:26:36 +0000 +Subject: soc: mediatek: svs: Fix memory leak in svs_enable_debug_write() + +From: Zilin Guan + +[ Upstream commit 6259094ee806fb813ca95894c65fb80e2ec98bf1 ] + +In svs_enable_debug_write(), the buf allocated by memdup_user_nul() +is leaked if kstrtoint() fails. + +Fix this by using __free(kfree) to automatically free buf, eliminating +the need for explicit kfree() calls and preventing leaks. + +Fixes: 13f1bbcfb582 ("soc: mediatek: SVS: add debug commands") +Co-developed-by: Jianhao Xu +Signed-off-by: Jianhao Xu +Signed-off-by: Zilin Guan +[Angelo: Added missing cleanup.h inclusion] +Signed-off-by: AngeloGioacchino Del Regno +Signed-off-by: Sasha Levin +--- + drivers/soc/mediatek/mtk-svs.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/soc/mediatek/mtk-svs.c b/drivers/soc/mediatek/mtk-svs.c +index 3a2f97cd52720..37d21e3de6942 100644 +--- a/drivers/soc/mediatek/mtk-svs.c ++++ b/drivers/soc/mediatek/mtk-svs.c +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -717,7 +718,7 @@ static ssize_t svs_enable_debug_write(struct file *filp, + struct svs_bank *svsb = file_inode(filp)->i_private; + struct svs_platform *svsp = dev_get_drvdata(svsb->dev); + int enabled, ret; +- char *buf = NULL; ++ char *buf __free(kfree) = NULL; + + if (count >= PAGE_SIZE) + return -EINVAL; +@@ -735,8 +736,6 @@ static ssize_t svs_enable_debug_write(struct file *filp, + svsb->mode_support = SVSB_MODE_ALL_DISABLE; + } + +- kfree(buf); +- + return count; + } + +-- +2.51.0 + diff --git a/queue-6.6/soc-qcom-cmd-db-use-devm_memremap-to-fix-memory-leak.patch b/queue-6.6/soc-qcom-cmd-db-use-devm_memremap-to-fix-memory-leak.patch new file mode 100644 index 0000000000..050ed3cccd --- /dev/null +++ b/queue-6.6/soc-qcom-cmd-db-use-devm_memremap-to-fix-memory-leak.patch @@ -0,0 +1,53 @@ +From ad4c81155858429c4972b69bb73a9e820fce4356 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Dec 2025 09:39:32 +0800 +Subject: soc: qcom: cmd-db: Use devm_memremap() to fix memory leak in + cmd_db_dev_probe + +From: Haotian Zhang + +[ Upstream commit 0da7824734d8d83e6a844dd0207f071cb0c50cf4 ] + +If cmd_db_magic_matches() fails after memremap() succeeds, the function +returns -EINVAL without unmapping the memory region, causing a +potential resource leak. + +Switch to devm_memremap to automatically manage the map resource. + +Fixes: 312416d9171a ("drivers: qcom: add command DB driver") +Suggested-by: Dmitry Baryshkov +Signed-off-by: Haotian Zhang +Link: https://lore.kernel.org/r/20251216013933.773-1-vulab@iscas.ac.cn +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/cmd-db.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/soc/qcom/cmd-db.c b/drivers/soc/qcom/cmd-db.c +index ab2418d2fe43a..0c54a9525baf1 100644 +--- a/drivers/soc/qcom/cmd-db.c ++++ b/drivers/soc/qcom/cmd-db.c +@@ -354,15 +354,16 @@ static int cmd_db_dev_probe(struct platform_device *pdev) + return -EINVAL; + } + +- cmd_db_header = memremap(rmem->base, rmem->size, MEMREMAP_WC); +- if (!cmd_db_header) { +- ret = -ENOMEM; ++ cmd_db_header = devm_memremap(&pdev->dev, rmem->base, rmem->size, MEMREMAP_WC); ++ if (IS_ERR(cmd_db_header)) { ++ ret = PTR_ERR(cmd_db_header); + cmd_db_header = NULL; + return ret; + } + + if (!cmd_db_magic_matches(cmd_db_header)) { + dev_err(&pdev->dev, "Invalid Command DB Magic\n"); ++ cmd_db_header = NULL; + return -EINVAL; + } + +-- +2.51.0 + diff --git a/queue-6.6/soc-qcom-smem-handle-enomem-error-during-probe.patch b/queue-6.6/soc-qcom-smem-handle-enomem-error-during-probe.patch new file mode 100644 index 0000000000..276b622dc2 --- /dev/null +++ b/queue-6.6/soc-qcom-smem-handle-enomem-error-during-probe.patch @@ -0,0 +1,39 @@ +From 0d3004f5e278774a82e778d79b2286381c687535 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 08:45:37 +0100 +Subject: soc: qcom: smem: handle ENOMEM error during probe + +From: Jorge Ramirez-Ortiz + +[ Upstream commit 0fe01a7955f4fef97e7cc6d14bfc5931c660402b ] + +Fail the driver probe if the region can't be mapped + +Signed-off-by: Jorge Ramirez-Ortiz +Fixes: 20bb6c9de1b7 ("soc: qcom: smem: map only partitions used by local HOST") +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20251209074610.3751781-1-jorge.ramirez@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/smem.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c +index 5217ff0a434f5..d039c660d04fb 100644 +--- a/drivers/soc/qcom/smem.c ++++ b/drivers/soc/qcom/smem.c +@@ -1189,7 +1189,9 @@ static int qcom_smem_probe(struct platform_device *pdev) + smem->item_count = qcom_smem_get_item_count(smem); + break; + case SMEM_GLOBAL_HEAP_VERSION: +- qcom_smem_map_global(smem, size); ++ ret = qcom_smem_map_global(smem, size); ++ if (ret < 0) ++ return ret; + smem->item_count = SMEM_ITEM_COUNT; + break; + default: +-- +2.51.0 + diff --git a/queue-6.6/spi-tools-add-include-folder-to-.gitignore.patch b/queue-6.6/spi-tools-add-include-folder-to-.gitignore.patch new file mode 100644 index 0000000000..5ba06e9ced --- /dev/null +++ b/queue-6.6/spi-tools-add-include-folder-to-.gitignore.patch @@ -0,0 +1,35 @@ +From 03cd33ec2823011037c6dc806cdba25914bf5896 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 10:50:01 +0100 +Subject: spi: tools: Add include folder to .gitignore + +From: Francesco Lavra + +[ Upstream commit 5af56f30c4fcbade4a92f94dadfea517d1db9703 ] + +The Makefile for the SPI tools creates an include/linux/spi folder and some +symlinks inside it. After running `make -C spi/tools`, this folder shows up +as untracked in the git status. +Add the above folder to the .gitignore file. + +Fixes: f325b73dc4db ("spi: tools: move to tools buildsystem") +Signed-off-by: Francesco Lavra +Link: https://patch.msgid.link/20260209095001.556495-1-flavra@baylibre.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + tools/spi/.gitignore | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/tools/spi/.gitignore b/tools/spi/.gitignore +index 14ddba3d21957..038261b34ed83 100644 +--- a/tools/spi/.gitignore ++++ b/tools/spi/.gitignore +@@ -1,3 +1,4 @@ + # SPDX-License-Identifier: GPL-2.0-only + spidev_fdx + spidev_test ++include/ +-- +2.51.0 + diff --git a/queue-6.6/staging-greybus-lights-avoid-null-deref.patch b/queue-6.6/staging-greybus-lights-avoid-null-deref.patch new file mode 100644 index 0000000000..ea583ea966 --- /dev/null +++ b/queue-6.6/staging-greybus-lights-avoid-null-deref.patch @@ -0,0 +1,55 @@ +From 1254ec630796fdb4fdcd6c7d424c67be59ffe3fb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 20:42:54 +0530 +Subject: staging: greybus: lights: avoid NULL deref + +From: Chaitanya Mishra + +[ Upstream commit efcffd9a6ad8d190651498d5eda53bfc7cf683a7 ] + +gb_lights_light_config() stores channel_count before allocating the +channels array. If kcalloc() fails, gb_lights_release() iterates the +non-zero count and dereferences light->channels, which is NULL. + +Allocate channels first and only then publish channels_count so the +cleanup path can't walk a NULL pointer. + +Fixes: 2870b52bae4c ("greybus: lights: add lights implementation") +Link: https://lore.kernel.org/all/20260108103700.15384-1-chaitanyamishra.ai@gmail.com/ +Reviewed-by: Rui Miguel Silva +Signed-off-by: Chaitanya Mishra +Link: https://patch.msgid.link/20260108151254.81553-1-chaitanyamishra.ai@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/staging/greybus/light.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/drivers/staging/greybus/light.c b/drivers/staging/greybus/light.c +index 9999f84016992..eb69500e080e0 100644 +--- a/drivers/staging/greybus/light.c ++++ b/drivers/staging/greybus/light.c +@@ -1029,14 +1029,18 @@ static int gb_lights_light_config(struct gb_lights *glights, u8 id) + if (!strlen(conf.name)) + return -EINVAL; + +- light->channels_count = conf.channel_count; + light->name = kstrndup(conf.name, NAMES_MAX, GFP_KERNEL); + if (!light->name) + return -ENOMEM; +- light->channels = kcalloc(light->channels_count, ++ light->channels = kcalloc(conf.channel_count, + sizeof(struct gb_channel), GFP_KERNEL); + if (!light->channels) + return -ENOMEM; ++ /* ++ * Publish channels_count only after channels allocation so cleanup ++ * doesn't walk a NULL channels pointer on allocation failure. ++ */ ++ light->channels_count = conf.channel_count; + + /* First we collect all the configurations for all channels */ + for (i = 0; i < light->channels_count; i++) { +-- +2.51.0 + diff --git a/queue-6.6/svcrdma-clean-up-comment-in-svc_rdma_accept.patch b/queue-6.6/svcrdma-clean-up-comment-in-svc_rdma_accept.patch new file mode 100644 index 0000000000..2887b66a16 --- /dev/null +++ b/queue-6.6/svcrdma-clean-up-comment-in-svc_rdma_accept.patch @@ -0,0 +1,64 @@ +From 799ed49b00c87d2ea92a21034087678b1d0767df Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 Dec 2023 10:24:34 -0500 +Subject: svcrdma: Clean up comment in svc_rdma_accept() + +From: Chuck Lever + +[ Upstream commit fc2e69db82c1ac506cd7f539a3ab66d51d3380dc ] + +The comment that starts "Qualify ..." applies to only some of the +following code paragraph. Re-arrange the lines so the comment makes +more sense. + +Signed-off-by: Chuck Lever +Stable-dep-of: afcae7d7b8a2 ("RDMA/core: add rdma_rw_max_sge() helper for SQ sizing") +Signed-off-by: Sasha Levin +--- + net/sunrpc/xprtrdma/svc_rdma_transport.c | 17 ++++++++++------- + 1 file changed, 10 insertions(+), 7 deletions(-) + +diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c +index 86f45461b1851..e26d1a7035e55 100644 +--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c ++++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c +@@ -391,18 +391,22 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + dev = newxprt->sc_cm_id->device; + newxprt->sc_port_num = newxprt->sc_cm_id->port_num; + +- /* Qualify the transport resource defaults with the +- * capabilities of this particular device */ ++ newxprt->sc_max_req_size = svcrdma_max_req_size; ++ newxprt->sc_max_requests = svcrdma_max_requests; ++ newxprt->sc_max_bc_requests = svcrdma_max_bc_requests; ++ newxprt->sc_recv_batch = RPCRDMA_MAX_RECV_BATCH; ++ newxprt->sc_fc_credits = cpu_to_be32(newxprt->sc_max_requests); ++ ++ /* Qualify the transport's resource defaults with the ++ * capabilities of this particular device. ++ */ ++ + /* Transport header, head iovec, tail iovec */ + newxprt->sc_max_send_sges = 3; + /* Add one SGE per page list entry */ + newxprt->sc_max_send_sges += (svcrdma_max_req_size / PAGE_SIZE) + 1; + if (newxprt->sc_max_send_sges > dev->attrs.max_send_sge) + newxprt->sc_max_send_sges = dev->attrs.max_send_sge; +- newxprt->sc_max_req_size = svcrdma_max_req_size; +- newxprt->sc_max_requests = svcrdma_max_requests; +- newxprt->sc_max_bc_requests = svcrdma_max_bc_requests; +- newxprt->sc_recv_batch = RPCRDMA_MAX_RECV_BATCH; + rq_depth = newxprt->sc_max_requests + newxprt->sc_max_bc_requests + + newxprt->sc_recv_batch; + if (rq_depth > dev->attrs.max_qp_wr) { +@@ -411,7 +415,6 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + newxprt->sc_max_requests = rq_depth - 2; + newxprt->sc_max_bc_requests = 2; + } +- newxprt->sc_fc_credits = cpu_to_be32(newxprt->sc_max_requests); + ctxts = rdma_rw_mr_factor(dev, newxprt->sc_port_num, RPCSVC_MAXPAGES); + ctxts *= newxprt->sc_max_requests; + newxprt->sc_sq_depth = rq_depth + ctxts; +-- +2.51.0 + diff --git a/queue-6.6/svcrdma-increase-the-per-transport-rw_ctx-count.patch b/queue-6.6/svcrdma-increase-the-per-transport-rw_ctx-count.patch new file mode 100644 index 0000000000..12b8a18598 --- /dev/null +++ b/queue-6.6/svcrdma-increase-the-per-transport-rw_ctx-count.patch @@ -0,0 +1,73 @@ +From ef237f251c95c57b5b50e84aad022409dfaa3612 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 4 Feb 2024 18:16:56 -0500 +Subject: svcrdma: Increase the per-transport rw_ctx count + +From: Chuck Lever + +[ Upstream commit 2da0f610e733606e06284ac3c1f188b9dec75d68 ] + +rdma_rw_mr_factor() returns the smallest number of MRs needed to +move a particular number of pages. svcrdma currently asks for the +number of MRs needed to move RPCSVC_MAXPAGES (a little over one +megabyte), as that is the number of pages in the largest r/wsize +the server supports. + +This call assumes that the client's NIC can bundle a full one +megabyte payload in a single rdma_segment. In fact, most NICs cannot +handle a full megabyte with a single rkey / rdma_segment. Clients +will typically split even a single Read chunk into many segments. + +The server needs one MR to read each rdma_segment in a Read chunk, +and thus each one needs an rw_ctx. + +svcrdma has been vastly underestimating the number of rw_ctxs needed +to handle 64 RPC requests with large Read chunks using small +rdma_segments. + +Unfortunately there doesn't seem to be a good way to estimate this +number without knowing the client NIC's capabilities. Even then, +the client RPC/RDMA implementation is still free to split a chunk +into smaller segments (for example, it might be using physical +registration, which needs an rdma_segment per page). + +The best we can do for now is choose a number that will guarantee +forward progress in the worst case (one page per segment). + +At some later point, we could add some mechanisms to make this +much less of a problem: +- Add a core API to add more rw_ctxs to an already-established QP +- svcrdma could treat rw_ctx exhaustion as a temporary error and + try again +- Limit the number of Reads in flight + +Signed-off-by: Chuck Lever +Stable-dep-of: afcae7d7b8a2 ("RDMA/core: add rdma_rw_max_sge() helper for SQ sizing") +Signed-off-by: Sasha Levin +--- + net/sunrpc/xprtrdma/svc_rdma_transport.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c +index e26d1a7035e55..41db2b1ee0d13 100644 +--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c ++++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c +@@ -415,8 +415,13 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + newxprt->sc_max_requests = rq_depth - 2; + newxprt->sc_max_bc_requests = 2; + } +- ctxts = rdma_rw_mr_factor(dev, newxprt->sc_port_num, RPCSVC_MAXPAGES); +- ctxts *= newxprt->sc_max_requests; ++ ++ /* Arbitrarily estimate the number of rw_ctxs needed for ++ * this transport. This is enough rw_ctxs to make forward ++ * progress even if the client is using one rkey per page ++ * in each Read chunk. ++ */ ++ ctxts = 3 * RPCSVC_MAXPAGES; + newxprt->sc_sq_depth = rq_depth + ctxts; + if (newxprt->sc_sq_depth > dev->attrs.max_qp_wr) + newxprt->sc_sq_depth = dev->attrs.max_qp_wr; +-- +2.51.0 + diff --git a/queue-6.6/svcrdma-reduce-the-number-of-rdma_rw-contexts-per-qp.patch b/queue-6.6/svcrdma-reduce-the-number-of-rdma_rw-contexts-per-qp.patch new file mode 100644 index 0000000000..e887e37fde --- /dev/null +++ b/queue-6.6/svcrdma-reduce-the-number-of-rdma_rw-contexts-per-qp.patch @@ -0,0 +1,96 @@ +From 9413885133988eda085b1f1380452aa171e1c700 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 28 Apr 2025 15:36:49 -0400 +Subject: svcrdma: Reduce the number of rdma_rw contexts per-QP + +From: Chuck Lever + +[ Upstream commit 59243315890578a040a2d50ae9e001a2ef2fcb62 ] + +There is an upper bound on the number of rdma_rw contexts that can +be created per QP. + +This invisible upper bound is because rdma_create_qp() adds one or +more additional SQEs for each ctxt that the ULP requests via +qp_attr.cap.max_rdma_ctxs. The QP's actual Send Queue length is on +the order of the sum of qp_attr.cap.max_send_wr and a factor times +qp_attr.cap.max_rdma_ctxs. The factor can be up to three, depending +on whether MR operations are required before RDMA Reads. + +This limit is not visible to RDMA consumers via dev->attrs. When the +limit is surpassed, QP creation fails with -ENOMEM. For example: + +svcrdma's estimate of the number of rdma_rw contexts it needs is +three times the number of pages in RPCSVC_MAXPAGES. When MAXPAGES +is about 260, the internally-computed SQ length should be: + +64 credits + 10 backlog + 3 * (3 * 260) = 2414 + +Which is well below the advertised qp_max_wr of 32768. + +If RPCSVC_MAXPAGES is increased to 4MB, that's 1040 pages: + +64 credits + 10 backlog + 3 * (3 * 1040) = 9434 + +However, QP creation fails. Dynamic printk for mlx5 shows: + +calc_sq_size:618:(pid 1514): send queue size (9326 * 256 / 64 -> 65536) exceeds limits(32768) + +Although 9326 is still far below qp_max_wr, QP creation still +fails. + +Because the total SQ length calculation is opaque to RDMA consumers, +there doesn't seem to be much that can be done about this except for +consumers to try to keep the requested rdma_rw ctxt count low. + +Fixes: 2da0f610e733 ("svcrdma: Increase the per-transport rw_ctx count") +Reviewed-by: NeilBrown +Reviewed-by: Christoph Hellwig +Signed-off-by: Chuck Lever +Stable-dep-of: afcae7d7b8a2 ("RDMA/core: add rdma_rw_max_sge() helper for SQ sizing") +Signed-off-by: Sasha Levin +--- + net/sunrpc/xprtrdma/svc_rdma_transport.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c +index 41db2b1ee0d13..7bf4787678f8f 100644 +--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c ++++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c +@@ -363,12 +363,12 @@ static struct svc_xprt *svc_rdma_create(struct svc_serv *serv, + */ + static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + { ++ unsigned int ctxts, rq_depth, maxpayload; + struct svcxprt_rdma *listen_rdma; + struct svcxprt_rdma *newxprt = NULL; + struct rdma_conn_param conn_param; + struct rpcrdma_connect_private pmsg; + struct ib_qp_init_attr qp_attr; +- unsigned int ctxts, rq_depth; + struct ib_device *dev; + int ret = 0; + RPC_IFDEBUG(struct sockaddr *sap); +@@ -416,12 +416,14 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + newxprt->sc_max_bc_requests = 2; + } + +- /* Arbitrarily estimate the number of rw_ctxs needed for +- * this transport. This is enough rw_ctxs to make forward +- * progress even if the client is using one rkey per page +- * in each Read chunk. ++ /* Arbitrary estimate of the needed number of rdma_rw contexts. + */ +- ctxts = 3 * RPCSVC_MAXPAGES; ++ maxpayload = min(xprt->xpt_server->sv_max_payload, ++ RPCSVC_MAXPAYLOAD_RDMA); ++ ctxts = newxprt->sc_max_requests * 3 * ++ rdma_rw_mr_factor(dev, newxprt->sc_port_num, ++ maxpayload >> PAGE_SHIFT); ++ + newxprt->sc_sq_depth = rq_depth + ctxts; + if (newxprt->sc_sq_depth > dev->attrs.max_qp_wr) + newxprt->sc_sq_depth = dev->attrs.max_qp_wr; +-- +2.51.0 + diff --git a/queue-6.6/svcrdma-remove-queue-shortening-warnings.patch b/queue-6.6/svcrdma-remove-queue-shortening-warnings.patch new file mode 100644 index 0000000000..01736c9e98 --- /dev/null +++ b/queue-6.6/svcrdma-remove-queue-shortening-warnings.patch @@ -0,0 +1,52 @@ +From 84bb534afbc38343479ce4b48668b144bc0fdd27 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 Dec 2023 10:24:28 -0500 +Subject: svcrdma: Remove queue-shortening warnings + +From: Chuck Lever + +[ Upstream commit b918bfcf370c92ea3b82fa9bb3d017702b5fa4cb ] + +These won't have much diagnostic value for site administrators. +Since they can't be disabled, they become noise. + +What's more, the subsequent rdma_create_qp() call adjusts the Send +Queue size (possibly downward) without warning, making the size +reported by these pr_warns inaccurate. + +Signed-off-by: Chuck Lever +Stable-dep-of: afcae7d7b8a2 ("RDMA/core: add rdma_rw_max_sge() helper for SQ sizing") +Signed-off-by: Sasha Levin +--- + net/sunrpc/xprtrdma/svc_rdma_transport.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c +index 2abd895046ee3..86f45461b1851 100644 +--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c ++++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c +@@ -406,8 +406,6 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + rq_depth = newxprt->sc_max_requests + newxprt->sc_max_bc_requests + + newxprt->sc_recv_batch; + if (rq_depth > dev->attrs.max_qp_wr) { +- pr_warn("svcrdma: reducing receive depth to %d\n", +- dev->attrs.max_qp_wr); + rq_depth = dev->attrs.max_qp_wr; + newxprt->sc_recv_batch = 1; + newxprt->sc_max_requests = rq_depth - 2; +@@ -417,11 +415,8 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + ctxts = rdma_rw_mr_factor(dev, newxprt->sc_port_num, RPCSVC_MAXPAGES); + ctxts *= newxprt->sc_max_requests; + newxprt->sc_sq_depth = rq_depth + ctxts; +- if (newxprt->sc_sq_depth > dev->attrs.max_qp_wr) { +- pr_warn("svcrdma: reducing send depth to %d\n", +- dev->attrs.max_qp_wr); ++ if (newxprt->sc_sq_depth > dev->attrs.max_qp_wr) + newxprt->sc_sq_depth = dev->attrs.max_qp_wr; +- } + atomic_set(&newxprt->sc_sq_avail, newxprt->sc_sq_depth); + + newxprt->sc_pd = ib_alloc_pd(dev, 0); +-- +2.51.0 + diff --git a/queue-6.6/tcp-tcp_tx_timestamp-must-look-at-the-rtx-queue.patch b/queue-6.6/tcp-tcp_tx_timestamp-must-look-at-the-rtx-queue.patch new file mode 100644 index 0000000000..a6e7b6bca2 --- /dev/null +++ b/queue-6.6/tcp-tcp_tx_timestamp-must-look-at-the-rtx-queue.patch @@ -0,0 +1,44 @@ +From 49a0d434b2c997d696606bc62f8eacbba3739b37 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 12:38:27 +0000 +Subject: tcp: tcp_tx_timestamp() must look at the rtx queue + +From: Eric Dumazet + +[ Upstream commit 838eb9687691d29915797a885b861fd09353386e ] + +tcp_tx_timestamp() is only called at the end of tcp_sendmsg_locked() +before the final tcp_push(). + +By the time it is called, it is possible all the copied data +has been sent already (transmit queue is empty). + +If this is the case, use the last skb in the rtx queue. + +Fixes: 75c119afe14f ("tcp: implement rb-tree based retransmit queue") +Signed-off-by: Eric Dumazet +Reviewed-by: Jason Xing +Link: https://patch.msgid.link/20260127123828.4098577-2-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 5dde0aed31440..2bae34d63c3db 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -468,6 +468,9 @@ static void tcp_tx_timestamp(struct sock *sk, u16 tsflags) + { + struct sk_buff *skb = tcp_write_queue_tail(sk); + ++ if (unlikely(!skb)) ++ skb = skb_rb_last(&sk->tcp_rtx_queue); ++ + if (tsflags && skb) { + struct skb_shared_info *shinfo = skb_shinfo(skb); + struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); +-- +2.51.0 + diff --git a/queue-6.6/tools-power-x86-intel-speed-select-fix-file-descript.patch b/queue-6.6/tools-power-x86-intel-speed-select-fix-file-descript.patch new file mode 100644 index 0000000000..854ed5eaca --- /dev/null +++ b/queue-6.6/tools-power-x86-intel-speed-select-fix-file-descript.patch @@ -0,0 +1,50 @@ +From c0d15bf9c0ec35798d68c73dc3ca04d64bbec02d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 15:33:33 +0530 +Subject: tools/power/x86/intel-speed-select: Fix file descriptor leak in + isolate_cpus() + +From: Malaya Kumar Rout + +[ Upstream commit 56c17ee151c6e1a73d77e15b82a8e2130cd8dd16 ] + +The file descriptor opened in isolate_cpus() when (!level) is true was +not being closed before returning, causing a file descriptor leak in +both the error path and the success path. + +When write() fails at line 950, the function returns at line 953 without +closing the file descriptor. Similarly, on success, the function returns +at line 956 without closing the file descriptor. + +Add close(fd) calls before both return statements to fix the resource +leak. This follows the same pattern used elsewhere in the same function +where file descriptors are properly closed before returning (see lines +1005 and 1027). + +Fixes: 997074df658e ("tools/power/x86/intel-speed-select: Use cgroup v2 isolation") +Signed-off-by: Malaya Kumar Rout +Signed-off-by: Srinivas Pandruvada +Signed-off-by: Sasha Levin +--- + tools/power/x86/intel-speed-select/isst-config.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/tools/power/x86/intel-speed-select/isst-config.c b/tools/power/x86/intel-speed-select/isst-config.c +index 5fcc2a92957e7..a5d512866a940 100644 +--- a/tools/power/x86/intel-speed-select/isst-config.c ++++ b/tools/power/x86/intel-speed-select/isst-config.c +@@ -936,9 +936,11 @@ int isolate_cpus(struct isst_id *id, int mask_size, cpu_set_t *cpu_mask, int lev + ret = write(fd, "member", strlen("member")); + if (ret == -1) { + printf("Can't update to member\n"); ++ close(fd); + return ret; + } + ++ close(fd); + return 0; + } + +-- +2.51.0 + diff --git a/queue-6.6/tpm-st33zp24-fix-missing-cleanup-on-get_burstcount-e.patch b/queue-6.6/tpm-st33zp24-fix-missing-cleanup-on-get_burstcount-e.patch new file mode 100644 index 0000000000..1c53557649 --- /dev/null +++ b/queue-6.6/tpm-st33zp24-fix-missing-cleanup-on-get_burstcount-e.patch @@ -0,0 +1,43 @@ +From 6452377ac0349666d5a686ff293e9c8ea96de2bd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Dec 2025 15:09:27 +0300 +Subject: tpm: st33zp24: Fix missing cleanup on get_burstcount() error + +From: Alper Ak + +[ Upstream commit 3e91b44c93ad2871f89fc2a98c5e4fe6ca5db3d9 ] + +get_burstcount() can return -EBUSY on timeout. When this happens, +st33zp24_send() returns directly without releasing the locality +acquired earlier. + +Use goto out_err to ensure proper cleanup when get_burstcount() fails. + +Fixes: bf38b8710892 ("tpm/tpm_i2c_stm_st33: Split tpm_i2c_tpm_st33 in 2 layers (core + phy)") +Signed-off-by: Alper Ak +Signed-off-by: Jarkko Sakkinen +Signed-off-by: Sasha Levin +--- + drivers/char/tpm/st33zp24/st33zp24.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/char/tpm/st33zp24/st33zp24.c b/drivers/char/tpm/st33zp24/st33zp24.c +index a5b554cd47786..f78c61f4163d5 100644 +--- a/drivers/char/tpm/st33zp24/st33zp24.c ++++ b/drivers/char/tpm/st33zp24/st33zp24.c +@@ -328,8 +328,10 @@ static int st33zp24_send(struct tpm_chip *chip, unsigned char *buf, + + for (i = 0; i < len - 1;) { + burstcnt = get_burstcount(chip); +- if (burstcnt < 0) +- return burstcnt; ++ if (burstcnt < 0) { ++ ret = burstcnt; ++ goto out_err; ++ } + size = min_t(int, len - i - 1, burstcnt); + ret = tpm_dev->ops->send(tpm_dev->phy_id, TPM_DATA_FIFO, + buf + i, size); +-- +2.51.0 + diff --git a/queue-6.6/tpm-tpm_i2c_infineon-fix-locality-leak-on-get_burstc.patch b/queue-6.6/tpm-tpm_i2c_infineon-fix-locality-leak-on-get_burstc.patch new file mode 100644 index 0000000000..2d48133c43 --- /dev/null +++ b/queue-6.6/tpm-tpm_i2c_infineon-fix-locality-leak-on-get_burstc.patch @@ -0,0 +1,44 @@ +From 2c9ab1e1b80664d0b99cf95cbb219966a8644d0a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Dec 2025 13:23:38 +0300 +Subject: tpm: tpm_i2c_infineon: Fix locality leak on get_burstcount() failure + +From: Alper Ak + +[ Upstream commit bbd6e97c836cbeb9606d7b7e5dcf8a1d89525713 ] + +get_burstcount() can return -EBUSY on timeout. When this happens, the +function returns directly without releasing the locality that was +acquired at the beginning of tpm_tis_i2c_send(). + +Use goto out_err to ensure proper cleanup when get_burstcount() fails. + +Fixes: aad628c1d91a ("char/tpm: Add new driver for Infineon I2C TIS TPM") +Signed-off-by: Alper Ak +Reviewed-by: Jarkko Sakkinen +Signed-off-by: Jarkko Sakkinen +Signed-off-by: Sasha Levin +--- + drivers/char/tpm/tpm_i2c_infineon.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c +index 81d8a78dc6552..3675faa4a00c7 100644 +--- a/drivers/char/tpm/tpm_i2c_infineon.c ++++ b/drivers/char/tpm/tpm_i2c_infineon.c +@@ -543,8 +543,10 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len) + burstcnt = get_burstcount(chip); + + /* burstcnt < 0 = TPM is busy */ +- if (burstcnt < 0) +- return burstcnt; ++ if (burstcnt < 0) { ++ rc = burstcnt; ++ goto out_err; ++ } + + if (burstcnt > (len - 1 - count)) + burstcnt = len - 1 - count; +-- +2.51.0 + diff --git a/queue-6.6/tracing-properly-process-error-handling-in-event_his.patch b/queue-6.6/tracing-properly-process-error-handling-in-event_his.patch new file mode 100644 index 0000000000..3cecbb38e6 --- /dev/null +++ b/queue-6.6/tracing-properly-process-error-handling-in-event_his.patch @@ -0,0 +1,51 @@ +From 9ca50009eb8315c97df88da65ddcc93c9f276211 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 11 Dec 2025 14:00:58 +0400 +Subject: tracing: Properly process error handling in + event_hist_trigger_parse() + +From: Miaoqian Lin + +[ Upstream commit 0550069cc25f513ce1f109c88f7c1f01d63297db ] + +Memory allocated with trigger_data_alloc() requires trigger_data_free() +for proper cleanup. + +Replace kfree() with trigger_data_free() to fix this. + +Found via static analysis and code review. + +This isn't a real bug due to the current code basically being an open +coded version of trigger_data_free() without the synchronization. The +synchronization isn't needed as this is the error path of creation and +there's nothing to synchronize against yet. Replace the kfree() to be +consistent with the allocation. + +Cc: Masami Hiramatsu +Cc: Mathieu Desnoyers +Cc: Tom Zanussi +Link: https://patch.msgid.link/20251211100058.2381268-1-linmq006@gmail.com +Fixes: e1f187d09e11 ("tracing: Have existing event_command.parse() implementations use helpers") +Signed-off-by: Miaoqian Lin +Signed-off-by: Steven Rostedt (Google) +Signed-off-by: Sasha Levin +--- + kernel/trace/trace_events_hist.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c +index 99d1e8b57f85d..ad203155855a3 100644 +--- a/kernel/trace/trace_events_hist.c ++++ b/kernel/trace/trace_events_hist.c +@@ -6889,7 +6889,7 @@ static int event_hist_trigger_parse(struct event_command *cmd_ops, + + remove_hist_vars(hist_data); + +- kfree(trigger_data); ++ trigger_data_free(trigger_data); + + destroy_hist_data(hist_data); + goto out; +-- +2.51.0 + diff --git a/queue-6.6/tracing-remove-duplicate-enable_event_str-and-disabl.patch b/queue-6.6/tracing-remove-duplicate-enable_event_str-and-disabl.patch new file mode 100644 index 0000000000..a4fd91cf7e --- /dev/null +++ b/queue-6.6/tracing-remove-duplicate-enable_event_str-and-disabl.patch @@ -0,0 +1,44 @@ +From b7f123b502c75806d6e0d1bc178aae301e5eacff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 13:00:37 -0500 +Subject: tracing: Remove duplicate ENABLE_EVENT_STR and DISABLE_EVENT_STR + macros + +From: Steven Rostedt + +[ Upstream commit 9df0e49c5b9b8d051529be9994e4f92f2d20be6f ] + +The macros ENABLE_EVENT_STR and DISABLE_EVENT_STR were added to trace.h so +that more than one file can have access to them, but was never removed +from their original location. Remove the duplicates. + +Cc: Masami Hiramatsu +Cc: Mathieu Desnoyers +Cc: Tom Zanussi +Link: https://patch.msgid.link/20260126130037.4ba201f9@gandalf.local.home +Fixes: d0bad49bb0a09 ("tracing: Add enable_hist/disable_hist triggers") +Signed-off-by: Steven Rostedt (Google) +Signed-off-by: Sasha Levin +--- + kernel/trace/trace_events.c | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c +index 382e07cd49f9f..b26d7bb07e113 100644 +--- a/kernel/trace/trace_events.c ++++ b/kernel/trace/trace_events.c +@@ -3575,11 +3575,6 @@ void trace_put_event_file(struct trace_event_file *file) + EXPORT_SYMBOL_GPL(trace_put_event_file); + + #ifdef CONFIG_DYNAMIC_FTRACE +- +-/* Avoid typos */ +-#define ENABLE_EVENT_STR "enable_event" +-#define DISABLE_EVENT_STR "disable_event" +- + struct event_probe_data { + struct trace_event_file *file; + unsigned long count; +-- +2.51.0 + diff --git a/queue-6.6/ublk-validate-sqe128-flag-before-accessing-the-cmd.patch b/queue-6.6/ublk-validate-sqe128-flag-before-accessing-the-cmd.patch new file mode 100644 index 0000000000..74cb607058 --- /dev/null +++ b/queue-6.6/ublk-validate-sqe128-flag-before-accessing-the-cmd.patch @@ -0,0 +1,47 @@ +From 4ab39589ca46ad794bec3a4ddda3ae1cb2cdf60e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 10:14:12 -0700 +Subject: ublk: Validate SQE128 flag before accessing the cmd + +From: Govindarajulu Varadarajan + +[ Upstream commit da7e4b75e50c087d2031a92f6646eb90f7045a67 ] + +ublk_ctrl_cmd_dump() accesses (header *)sqe->cmd before +IO_URING_F_SQE128 flag check. This could cause out of boundary memory +access. + +Move the SQE128 flag check earlier in ublk_ctrl_uring_cmd() to return +-EINVAL immediately if the flag is not set. + +Fixes: 71f28f3136af ("ublk_drv: add io_uring based userspace block driver") +Signed-off-by: Govindarajulu Varadarajan +Reviewed-by: Caleb Sander Mateos +Reviewed-by: Ming Lei +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/block/ublk_drv.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c +index 44f630a3f610b..89c1d6ec7adaa 100644 +--- a/drivers/block/ublk_drv.c ++++ b/drivers/block/ublk_drv.c +@@ -2908,10 +2908,10 @@ static int ublk_ctrl_uring_cmd(struct io_uring_cmd *cmd, + if (issue_flags & IO_URING_F_NONBLOCK) + return -EAGAIN; + +- ublk_ctrl_cmd_dump(cmd); +- + if (!(issue_flags & IO_URING_F_SQE128)) +- goto out; ++ return -EINVAL; ++ ++ ublk_ctrl_cmd_dump(cmd); + + ret = ublk_check_cmd_op(cmd_op); + if (ret) +-- +2.51.0 + diff --git a/queue-6.6/ucount-check-for-cap_sys_resource-using-ns_capable_n.patch b/queue-6.6/ucount-check-for-cap_sys_resource-using-ns_capable_n.patch new file mode 100644 index 0000000000..3de1ac457d --- /dev/null +++ b/queue-6.6/ucount-check-for-cap_sys_resource-using-ns_capable_n.patch @@ -0,0 +1,51 @@ +From 7327fd2b3fc45206ec87f1d6c4551e544bc7c6b4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 15:07:45 +0100 +Subject: ucount: check for CAP_SYS_RESOURCE using ns_capable_noaudit() + +From: Ondrej Mosnacek + +[ Upstream commit 0895a000e4fff9e950a7894210db45973e485c35 ] + +The user.* sysctls implement the ctl_table_root::permissions hook and they +override the file access mode based on the CAP_SYS_RESOURCE capability (at +most rwx if capable, at most r-- if not). The capability is being checked +unconditionally, so if an LSM denies the capability, an audit record may +be logged even when access is in fact granted. + +Given the logic in the set_permissions() function in kernel/ucount.c and +the unfortunate way the permission checking is implemented, it doesn't +seem viable to avoid false positive denials by deferring the capability +check. Thus, do the same as in net_ctl_permissions() (net/sysctl_net.c) - +switch from ns_capable() to ns_capable_noaudit(), so that the check never +logs an audit record. + +Link: https://lkml.kernel.org/r/20260122140745.239428-1-omosnace@redhat.com +Fixes: dbec28460a89 ("userns: Add per user namespace sysctls.") +Signed-off-by: Ondrej Mosnacek +Reviewed-by: Paul Moore +Acked-by: Serge Hallyn +Cc: Eric Biederman +Cc: Alexey Gladkov +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + kernel/ucount.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/ucount.c b/kernel/ucount.c +index a7fd89693bd2a..44ede7a6b805a 100644 +--- a/kernel/ucount.c ++++ b/kernel/ucount.c +@@ -45,7 +45,7 @@ static int set_permissions(struct ctl_table_header *head, + int mode; + + /* Allow users with CAP_SYS_RESOURCE unrestrained access */ +- if (ns_capable(user_ns, CAP_SYS_RESOURCE)) ++ if (ns_capable_noaudit(user_ns, CAP_SYS_RESOURCE)) + mode = (table->mode & S_IRWXU) >> 6; + else + /* Allow all others at most read-only access */ +-- +2.51.0 + diff --git a/queue-6.6/usb-bdc-fix-sleep-during-atomic.patch b/queue-6.6/usb-bdc-fix-sleep-during-atomic.patch new file mode 100644 index 0000000000..2c3d7b418e --- /dev/null +++ b/queue-6.6/usb-bdc-fix-sleep-during-atomic.patch @@ -0,0 +1,41 @@ +From d78fa4838e9eebbb35478a665fea684c018afe45 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 12:07:54 -0800 +Subject: usb: bdc: fix sleep during atomic + +From: Justin Chen + +[ Upstream commit f1195ca3b4bbd001d3f1264dce91f83dec7777f5 ] + +bdc_run() can be ran during atomic context leading to a sleep during +atomic warning. Fix this by replacing read_poll_timeout() with +read_poll_timeout_atomic(). + +Fixes: 75ae051efc9b ("usb: gadget: bdc: use readl_poll_timeout() to simplify code") +Signed-off-by: Justin Chen +Reviewed-by: Florian Fainelli +Link: https://patch.msgid.link/20260120200754.2488765-1-justin.chen@broadcom.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/gadget/udc/bdc/bdc_core.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/usb/gadget/udc/bdc/bdc_core.c b/drivers/usb/gadget/udc/bdc/bdc_core.c +index 35a652807fca8..c2e3fa997842a 100644 +--- a/drivers/usb/gadget/udc/bdc/bdc_core.c ++++ b/drivers/usb/gadget/udc/bdc/bdc_core.c +@@ -35,8 +35,8 @@ static int poll_oip(struct bdc *bdc, u32 usec) + u32 status; + int ret; + +- ret = readl_poll_timeout(bdc->regs + BDC_BDCSC, status, +- (BDC_CSTS(status) != BDC_OIP), 10, usec); ++ ret = readl_poll_timeout_atomic(bdc->regs + BDC_BDCSC, status, ++ (BDC_CSTS(status) != BDC_OIP), 10, usec); + if (ret) + dev_err(bdc->dev, "operation timedout BDCSC: 0x%08x\n", status); + else +-- +2.51.0 + diff --git a/queue-6.6/watchdog-starfive-wdt-fix-pm-reference-leak-in-probe.patch b/queue-6.6/watchdog-starfive-wdt-fix-pm-reference-leak-in-probe.patch new file mode 100644 index 0000000000..26c9d6d9c0 --- /dev/null +++ b/queue-6.6/watchdog-starfive-wdt-fix-pm-reference-leak-in-probe.patch @@ -0,0 +1,45 @@ +From 5ad03aab3b5104e9ea427f4c3a621e5c47bcf887 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 01:29:15 +0800 +Subject: watchdog: starfive-wdt: Fix PM reference leak in probe error path + +From: Kery Qi + +[ Upstream commit 3f2d8d79cceb05a8b8dd200fa81c0dffc59ec46f ] + +The PM reference count is not expected to be incremented on return in +functions starfive_wdt_probe. + +However, pm_runtime_get_sync will increment pm usage counter +even failed. Forgetting to putting operation will result in a +reference leak here. + +Replace it with pm_runtime_resume_and_get to keep usage +counter balanced. + +Fixes: db728ea9c7be ("drivers: watchdog: Add StarFive Watchdog driver") +Signed-off-by: Kery Qi +Reviewed-by: Guenter Roeck +Signed-off-by: Guenter Roeck +Signed-off-by: Wim Van Sebroeck +Signed-off-by: Sasha Levin +--- + drivers/watchdog/starfive-wdt.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/watchdog/starfive-wdt.c b/drivers/watchdog/starfive-wdt.c +index 0606142ffc5e2..3842a0b1b6cb8 100644 +--- a/drivers/watchdog/starfive-wdt.c ++++ b/drivers/watchdog/starfive-wdt.c +@@ -444,7 +444,7 @@ static int starfive_wdt_probe(struct platform_device *pdev) + platform_set_drvdata(pdev, wdt); + pm_runtime_enable(&pdev->dev); + if (pm_runtime_enabled(&pdev->dev)) { +- ret = pm_runtime_get_sync(&pdev->dev); ++ ret = pm_runtime_resume_and_get(&pdev->dev); + if (ret < 0) + return ret; + } else { +-- +2.51.0 + diff --git a/queue-6.6/wifi-ath10k-sdio-add-missing-lock-protection-in-ath1.patch b/queue-6.6/wifi-ath10k-sdio-add-missing-lock-protection-in-ath1.patch new file mode 100644 index 0000000000..7d51eb4d20 --- /dev/null +++ b/queue-6.6/wifi-ath10k-sdio-add-missing-lock-protection-in-ath1.patch @@ -0,0 +1,62 @@ +From e8357cfc046ab973397ee66ee73b317d70780b3a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 04:58:22 +0000 +Subject: wifi: ath10k: sdio: add missing lock protection in + ath10k_sdio_fw_crashed_dump() + +From: Ziyi Guo + +[ Upstream commit e55ac348089e579fc224569c7bd90340bf2439f9 ] + +ath10k_sdio_fw_crashed_dump() calls ath10k_coredump_new() which requires +ar->dump_mutex to be held, as indicated by lockdep_assert_held() in that +function. However, the SDIO implementation does not acquire this lock, +unlike the PCI and SNOC implementations which properly hold the mutex. + +Additionally, ar->stats.fw_crash_counter is documented as protected by +ar->data_lock in core.h, but the SDIO implementation modifies it without +holding this spinlock. + +Add the missing mutex_lock()/mutex_unlock() around the coredump +operations, and add spin_lock_bh()/spin_unlock_bh() around the +fw_crash_counter increment, following the pattern used in +ath10k_pci_fw_dump_work() and ath10k_snoc_fw_crashed_dump(). + +Fixes: 3c45f21af84e ("ath10k: sdio: add firmware coredump support") +Signed-off-by: Ziyi Guo +Reviewed-by: Baochen Qiang +Link: https://patch.msgid.link/20260123045822.2221549-1-n7l8m4@u.northwestern.edu +Signed-off-by: Jeff Johnson +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/ath/ath10k/sdio.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c +index 850d999615a2c..7d0a522e5402e 100644 +--- a/drivers/net/wireless/ath/ath10k/sdio.c ++++ b/drivers/net/wireless/ath/ath10k/sdio.c +@@ -2486,7 +2486,11 @@ void ath10k_sdio_fw_crashed_dump(struct ath10k *ar) + if (fast_dump) + ath10k_bmi_start(ar); + ++ mutex_lock(&ar->dump_mutex); ++ ++ spin_lock_bh(&ar->data_lock); + ar->stats.fw_crash_counter++; ++ spin_unlock_bh(&ar->data_lock); + + ath10k_sdio_disable_intrs(ar); + +@@ -2504,6 +2508,8 @@ void ath10k_sdio_fw_crashed_dump(struct ath10k *ar) + + ath10k_sdio_enable_intrs(ar); + ++ mutex_unlock(&ar->dump_mutex); ++ + ath10k_core_start_recovery(ar); + } + +-- +2.51.0 + diff --git a/queue-6.6/wifi-cfg80211-stop-nan-and-p2p-in-cfg80211_leave.patch b/queue-6.6/wifi-cfg80211-stop-nan-and-p2p-in-cfg80211_leave.patch new file mode 100644 index 0000000000..dee43b45ba --- /dev/null +++ b/queue-6.6/wifi-cfg80211-stop-nan-and-p2p-in-cfg80211_leave.patch @@ -0,0 +1,47 @@ +From 6c15d0decf0b995739b540fe7c136daa0c6bc0b4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Jan 2026 14:04:51 +0200 +Subject: wifi: cfg80211: stop NAN and P2P in cfg80211_leave + +From: Miri Korenblit + +[ Upstream commit e1696c8bd0056bc1a5f7766f58ac333adc203e8a ] + +Seems that there is an assumption that this function should be called +only for netdev interfaces, but it can also be called in suspend, or +from nl80211_netlink_notify (indirectly). +Note that the documentation of NL80211_ATTR_SOCKET_OWNER explicitly +says that NAN interfaces would be destroyed as well in the +nl80211_netlink_notify case. + +Fix this by also stopping P2P and NAN. + +Fixes: cb3b7d87652a ("cfg80211: add start / stop NAN commands") +Reviewed-by: Johannes Berg +Signed-off-by: Miri Korenblit +Link: https://patch.msgid.link/20260107140430.dab142cbef0b.I290cc47836d56dd7e35012ce06bec36c6da688cd@changeid +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/wireless/core.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/net/wireless/core.c b/net/wireless/core.c +index f6693983b5e98..0baa4c6ab1694 100644 +--- a/net/wireless/core.c ++++ b/net/wireless/core.c +@@ -1331,8 +1331,10 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev, + __cfg80211_leave_ocb(rdev, dev); + break; + case NL80211_IFTYPE_P2P_DEVICE: ++ cfg80211_stop_p2p_device(rdev, wdev); ++ break; + case NL80211_IFTYPE_NAN: +- /* cannot happen, has no netdev */ ++ cfg80211_stop_nan(rdev, wdev); + break; + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_MONITOR: +-- +2.51.0 + diff --git a/queue-6.6/workqueue-factor-out-assign_rescuer_work.patch b/queue-6.6/workqueue-factor-out-assign_rescuer_work.patch new file mode 100644 index 0000000000..49c1bff951 --- /dev/null +++ b/queue-6.6/workqueue-factor-out-assign_rescuer_work.patch @@ -0,0 +1,78 @@ +From b4a3f493187c5829ca1da6fc803e212d537a6810 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 21 Nov 2025 22:57:14 +0800 +Subject: workqueue: Factor out assign_rescuer_work() + +From: Lai Jiangshan + +[ Upstream commit 99ed6f62a46e91dc796b785618d646eeded1b230 ] + +Move the code to assign work to rescuer and assign_rescuer_work(). + +Signed-off-by: Lai Jiangshan +Signed-off-by: Tejun Heo +Stable-dep-of: e5a30c303b07 ("workqueue: Process rescuer work items one-by-one using a cursor") +Signed-off-by: Sasha Levin +--- + kernel/workqueue.c | 29 ++++++++++++++++++----------- + 1 file changed, 18 insertions(+), 11 deletions(-) + +diff --git a/kernel/workqueue.c b/kernel/workqueue.c +index 59b6efb2a11c3..9127d74643fef 100644 +--- a/kernel/workqueue.c ++++ b/kernel/workqueue.c +@@ -2808,6 +2808,23 @@ static int worker_thread(void *__worker) + goto woke_up; + } + ++static bool assign_rescuer_work(struct pool_workqueue *pwq, struct worker *rescuer) ++{ ++ struct worker_pool *pool = pwq->pool; ++ struct work_struct *work, *n; ++ ++ /* ++ * Slurp in all works issued via this workqueue and ++ * process'em. ++ */ ++ list_for_each_entry_safe(work, n, &pool->worklist, entry) { ++ if (get_work_pwq(work) == pwq && assign_work(work, rescuer, &n)) ++ pwq->stats[PWQ_STAT_RESCUED]++; ++ } ++ ++ return !list_empty(&rescuer->scheduled); ++} ++ + /** + * rescuer_thread - the rescuer thread function + * @__rescuer: self +@@ -2862,7 +2879,6 @@ static int rescuer_thread(void *__rescuer) + struct pool_workqueue *pwq = list_first_entry(&wq->maydays, + struct pool_workqueue, mayday_node); + struct worker_pool *pool = pwq->pool; +- struct work_struct *work, *n; + + __set_current_state(TASK_RUNNING); + list_del_init(&pwq->mayday_node); +@@ -2873,18 +2889,9 @@ static int rescuer_thread(void *__rescuer) + + raw_spin_lock_irq(&pool->lock); + +- /* +- * Slurp in all works issued via this workqueue and +- * process'em. +- */ + WARN_ON_ONCE(!list_empty(&rescuer->scheduled)); +- list_for_each_entry_safe(work, n, &pool->worklist, entry) { +- if (get_work_pwq(work) == pwq && +- assign_work(work, rescuer, &n)) +- pwq->stats[PWQ_STAT_RESCUED]++; +- } + +- if (!list_empty(&rescuer->scheduled)) { ++ if (assign_rescuer_work(pwq, rescuer)) { + process_scheduled_works(rescuer); + + /* +-- +2.51.0 + diff --git a/queue-6.6/workqueue-only-assign-rescuer-work-when-really-neede.patch b/queue-6.6/workqueue-only-assign-rescuer-work-when-really-neede.patch new file mode 100644 index 0000000000..fa40aa7a93 --- /dev/null +++ b/queue-6.6/workqueue-only-assign-rescuer-work-when-really-neede.patch @@ -0,0 +1,39 @@ +From cf4f40f3ef13c4137e7a49bc13a1a2b299ca1273 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 21 Nov 2025 22:57:15 +0800 +Subject: workqueue: Only assign rescuer work when really needed + +From: Lai Jiangshan + +[ Upstream commit 7b05c90b3302cf3d830dfa6f8961376bcaf43b94 ] + +If the pwq does not need rescue (normal workers have been created or +become available), the rescuer can immediately move on to other stalled +pwqs. + +Signed-off-by: Lai Jiangshan +Signed-off-by: Tejun Heo +Stable-dep-of: e5a30c303b07 ("workqueue: Process rescuer work items one-by-one using a cursor") +Signed-off-by: Sasha Levin +--- + kernel/workqueue.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/kernel/workqueue.c b/kernel/workqueue.c +index 9127d74643fef..181f97d70296f 100644 +--- a/kernel/workqueue.c ++++ b/kernel/workqueue.c +@@ -2813,6 +2813,10 @@ static bool assign_rescuer_work(struct pool_workqueue *pwq, struct worker *rescu + struct worker_pool *pool = pwq->pool; + struct work_struct *work, *n; + ++ /* need rescue? */ ++ if (!pwq->nr_active || !need_to_create_worker(pool)) ++ return false; ++ + /* + * Slurp in all works issued via this workqueue and + * process'em. +-- +2.51.0 + diff --git a/queue-6.6/workqueue-process-rescuer-work-items-one-by-one-usin.patch b/queue-6.6/workqueue-process-rescuer-work-items-one-by-one-usin.patch new file mode 100644 index 0000000000..f8f3252ece --- /dev/null +++ b/queue-6.6/workqueue-process-rescuer-work-items-one-by-one-usin.patch @@ -0,0 +1,202 @@ +From 816205842742f59e81345ae6f29f1d4420918f5f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Dec 2025 21:25:18 +0800 +Subject: workqueue: Process rescuer work items one-by-one using a cursor + +From: Lai Jiangshan + +[ Upstream commit e5a30c303b07a4d6083e0f7f051b53add6d93c5d ] + +Previously, the rescuer scanned for all matching work items at once and +processed them within a single rescuer thread, which could cause one +blocking work item to stall all others. + +Make the rescuer process work items one-by-one instead of slurping all +matches in a single pass. + +Break the rescuer loop after finding and processing the first matching +work item, then restart the search to pick up the next. This gives +normal worker threads a chance to process other items which gives them +the opportunity to be processed instead of waiting on the rescuer's +queue and prevents a blocking work item from stalling the rest once +memory pressure is relieved. + +Introduce a dummy cursor work item to avoid potentially O(N^2) +rescans of the work list. The marker records the resume position for +the next scan, eliminating redundant traversals. + +Also introduce RESCUER_BATCH to control the maximum number of work items +the rescuer processes in each turn, and move on to other PWQs when the +limit is reached. + +Cc: ying chen +Reported-by: ying chen +Fixes: e22bee782b3b ("workqueue: implement concurrency managed dynamic worker pool") +Signed-off-by: Lai Jiangshan +Signed-off-by: Tejun Heo +Signed-off-by: Sasha Levin +--- + kernel/workqueue.c | 75 ++++++++++++++++++++++++++++++++++++---------- + 1 file changed, 59 insertions(+), 16 deletions(-) + +diff --git a/kernel/workqueue.c b/kernel/workqueue.c +index 181f97d70296f..641914d86154d 100644 +--- a/kernel/workqueue.c ++++ b/kernel/workqueue.c +@@ -101,6 +101,8 @@ enum { + MAYDAY_INTERVAL = HZ / 10, /* and then every 100ms */ + CREATE_COOLDOWN = HZ, /* time to breath after fail */ + ++ RESCUER_BATCH = 16, /* process items per turn */ ++ + /* + * Rescue workers are used only on emergencies and shared by + * all cpus. Give MIN_NICE. +@@ -254,6 +256,7 @@ struct pool_workqueue { + struct list_head inactive_works; /* L: inactive works */ + struct list_head pwqs_node; /* WR: node on wq->pwqs */ + struct list_head mayday_node; /* MD: node on wq->maydays */ ++ struct work_struct mayday_cursor; /* L: cursor on pool->worklist */ + + u64 stats[PWQ_NR_STATS]; + +@@ -1015,6 +1018,12 @@ static struct worker *find_worker_executing_work(struct worker_pool *pool, + return NULL; + } + ++static void mayday_cursor_func(struct work_struct *work) ++{ ++ /* should not be processed, only for marking position */ ++ BUG(); ++} ++ + /** + * move_linked_works - move linked works to a list + * @work: start of series of works to be scheduled +@@ -1077,6 +1086,16 @@ static bool assign_work(struct work_struct *work, struct worker *worker, + + lockdep_assert_held(&pool->lock); + ++ /* The cursor work should not be processed */ ++ if (unlikely(work->func == mayday_cursor_func)) { ++ /* only worker_thread() can possibly take this branch */ ++ WARN_ON_ONCE(worker->rescue_wq); ++ if (nextp) ++ *nextp = list_next_entry(work, entry); ++ list_del_init(&work->entry); ++ return false; ++ } ++ + /* + * A single work shouldn't be executed concurrently by multiple workers. + * __queue_work() ensures that @work doesn't jump to a different pool +@@ -2811,22 +2830,30 @@ static int worker_thread(void *__worker) + static bool assign_rescuer_work(struct pool_workqueue *pwq, struct worker *rescuer) + { + struct worker_pool *pool = pwq->pool; ++ struct work_struct *cursor = &pwq->mayday_cursor; + struct work_struct *work, *n; + + /* need rescue? */ + if (!pwq->nr_active || !need_to_create_worker(pool)) + return false; + +- /* +- * Slurp in all works issued via this workqueue and +- * process'em. +- */ +- list_for_each_entry_safe(work, n, &pool->worklist, entry) { +- if (get_work_pwq(work) == pwq && assign_work(work, rescuer, &n)) ++ /* search from the start or cursor if available */ ++ if (list_empty(&cursor->entry)) ++ work = list_first_entry(&pool->worklist, struct work_struct, entry); ++ else ++ work = list_next_entry(cursor, entry); ++ ++ /* find the next work item to rescue */ ++ list_for_each_entry_safe_from(work, n, &pool->worklist, entry) { ++ if (get_work_pwq(work) == pwq && assign_work(work, rescuer, &n)) { + pwq->stats[PWQ_STAT_RESCUED]++; ++ /* put the cursor for next search */ ++ list_move_tail(&cursor->entry, &n->entry); ++ return true; ++ } + } + +- return !list_empty(&rescuer->scheduled); ++ return false; + } + + /** +@@ -2883,6 +2910,7 @@ static int rescuer_thread(void *__rescuer) + struct pool_workqueue *pwq = list_first_entry(&wq->maydays, + struct pool_workqueue, mayday_node); + struct worker_pool *pool = pwq->pool; ++ unsigned int count = 0; + + __set_current_state(TASK_RUNNING); + list_del_init(&pwq->mayday_node); +@@ -2895,19 +2923,16 @@ static int rescuer_thread(void *__rescuer) + + WARN_ON_ONCE(!list_empty(&rescuer->scheduled)); + +- if (assign_rescuer_work(pwq, rescuer)) { ++ while (assign_rescuer_work(pwq, rescuer)) { + process_scheduled_works(rescuer); + + /* +- * The above execution of rescued work items could +- * have created more to rescue through +- * pwq_activate_first_inactive() or chained +- * queueing. Let's put @pwq back on mayday list so +- * that such back-to-back work items, which may be +- * being used to relieve memory pressure, don't +- * incur MAYDAY_INTERVAL delay inbetween. ++ * If the per-turn work item limit is reached and other ++ * PWQs are in mayday, requeue mayday for this PWQ and ++ * let the rescuer handle the other PWQs first. + */ +- if (pwq->nr_active && need_to_create_worker(pool)) { ++ if (++count > RESCUER_BATCH && !list_empty(&pwq->wq->maydays) && ++ pwq->nr_active && need_to_create_worker(pool)) { + raw_spin_lock(&wq_mayday_lock); + /* + * Queue iff we aren't racing destruction +@@ -2918,9 +2943,14 @@ static int rescuer_thread(void *__rescuer) + list_add_tail(&pwq->mayday_node, &wq->maydays); + } + raw_spin_unlock(&wq_mayday_lock); ++ break; + } + } + ++ /* The cursor can not be left behind without the rescuer watching it. */ ++ if (!list_empty(&pwq->mayday_cursor.entry) && list_empty(&pwq->mayday_node)) ++ list_del_init(&pwq->mayday_cursor.entry); ++ + /* + * Put the reference grabbed by send_mayday(). @pool won't + * go away while we're still attached to it. +@@ -4233,6 +4263,19 @@ static void init_pwq(struct pool_workqueue *pwq, struct workqueue_struct *wq, + INIT_LIST_HEAD(&pwq->pwqs_node); + INIT_LIST_HEAD(&pwq->mayday_node); + kthread_init_work(&pwq->release_work, pwq_release_workfn); ++ ++ /* ++ * Set the dummy cursor work with valid function and get_work_pwq(). ++ * ++ * The cursor work should only be in the pwq->pool->worklist, and ++ * should not be treated as a processable work item. ++ * ++ * WORK_STRUCT_PENDING and WORK_STRUCT_INACTIVE just make it less ++ * surprise for kernel debugging tools and reviewers. ++ */ ++ INIT_WORK(&pwq->mayday_cursor, mayday_cursor_func); ++ atomic_long_set(&pwq->mayday_cursor.data, (unsigned long)pwq | ++ WORK_STRUCT_PENDING | WORK_STRUCT_PWQ | WORK_STRUCT_INACTIVE); + } + + /* sync @pwq with the current state of its associated wq and link it */ +-- +2.51.0 + diff --git a/queue-6.6/x86-xen-make-some-functions-static.patch b/queue-6.6/x86-xen-make-some-functions-static.patch new file mode 100644 index 0000000000..7e7fd8ff4c --- /dev/null +++ b/queue-6.6/x86-xen-make-some-functions-static.patch @@ -0,0 +1,89 @@ +From e7f32b40b33a8e8a751695598f6cfc537920326a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 10 Jul 2024 11:37:17 +0200 +Subject: x86/xen: make some functions static + +From: Juergen Gross + +[ Upstream commit 337c628ab74d1bbfe5377bbd8d31c858baf5fbc6 ] + +Some functions and variables in arch/x86/xen are used locally only, +make them static. + +Signed-off-by: Juergen Gross +Reviewed-by: Boris Ostrovsky +Message-ID: <20240710093718.14552-2-jgross@suse.com> +Signed-off-by: Juergen Gross +Stable-dep-of: 0949c646d646 ("Partial revert "x86/xen: fix balloon target initialization for PVH dom0"") +Signed-off-by: Sasha Levin +--- + arch/x86/xen/mmu.h | 4 ---- + arch/x86/xen/mmu_pv.c | 11 ++++++----- + arch/x86/xen/xen-ops.h | 1 - + 3 files changed, 6 insertions(+), 10 deletions(-) + +diff --git a/arch/x86/xen/mmu.h b/arch/x86/xen/mmu.h +index 6e4c6bd622033..11fa577af6b48 100644 +--- a/arch/x86/xen/mmu.h ++++ b/arch/x86/xen/mmu.h +@@ -17,10 +17,6 @@ bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn); + + void set_pte_mfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags); + +-pte_t xen_ptep_modify_prot_start(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep); +-void xen_ptep_modify_prot_commit(struct vm_area_struct *vma, unsigned long addr, +- pte_t *ptep, pte_t pte); +- + unsigned long xen_read_cr2_direct(void); + + extern void xen_init_mmu_ops(void); +diff --git a/arch/x86/xen/mmu_pv.c b/arch/x86/xen/mmu_pv.c +index 88a722954f3f7..23f30ca52816c 100644 +--- a/arch/x86/xen/mmu_pv.c ++++ b/arch/x86/xen/mmu_pv.c +@@ -173,7 +173,7 @@ static int alloc_discontig_frames(unsigned int order) + * looking at another vcpu's cr3 value, it should use this variable. + */ + DEFINE_PER_CPU(unsigned long, xen_cr3); /* cr3 stored as physaddr */ +-DEFINE_PER_CPU(unsigned long, xen_current_cr3); /* actual vcpu cr3 */ ++static DEFINE_PER_CPU(unsigned long, xen_current_cr3); /* actual vcpu cr3 */ + + static phys_addr_t xen_pt_base, xen_pt_size __initdata; + +@@ -350,16 +350,17 @@ static void xen_set_pte(pte_t *ptep, pte_t pteval) + __xen_set_pte(ptep, pteval); + } + +-pte_t xen_ptep_modify_prot_start(struct vm_area_struct *vma, +- unsigned long addr, pte_t *ptep) ++static pte_t xen_ptep_modify_prot_start(struct vm_area_struct *vma, ++ unsigned long addr, pte_t *ptep) + { + /* Just return the pte as-is. We preserve the bits on commit */ + trace_xen_mmu_ptep_modify_prot_start(vma->vm_mm, addr, ptep, *ptep); + return *ptep; + } + +-void xen_ptep_modify_prot_commit(struct vm_area_struct *vma, unsigned long addr, +- pte_t *ptep, pte_t pte) ++static void xen_ptep_modify_prot_commit(struct vm_area_struct *vma, ++ unsigned long addr, ++ pte_t *ptep, pte_t pte) + { + struct mmu_update u; + +diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h +index 607f3a42fe3b1..af418489335cd 100644 +--- a/arch/x86/xen/xen-ops.h ++++ b/arch/x86/xen/xen-ops.h +@@ -23,7 +23,6 @@ void xen_copy_trap_info(struct trap_info *traps); + + DECLARE_PER_CPU_ALIGNED(struct vcpu_info, xen_vcpu_info); + DECLARE_PER_CPU(unsigned long, xen_cr3); +-DECLARE_PER_CPU(unsigned long, xen_current_cr3); + + extern struct start_info *xen_start_info; + extern struct shared_info xen_dummy_shared_info; +-- +2.51.0 + diff --git a/queue-6.6/xen-virtio-don-t-use-grant-dma-ops-when-running-as-d.patch b/queue-6.6/xen-virtio-don-t-use-grant-dma-ops-when-running-as-d.patch new file mode 100644 index 0000000000..5f4ef1b165 --- /dev/null +++ b/queue-6.6/xen-virtio-don-t-use-grant-dma-ops-when-running-as-d.patch @@ -0,0 +1,45 @@ +From b479890a0a83b4e86b7e39089808fd14293b1289 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Jan 2026 17:36:50 +0000 +Subject: xen/virtio: Don't use grant-dma-ops when running as Dom0 + +From: Teddy Astie + +[ Upstream commit dc8ea8714311e549ee93a2b0bdd5487d20bfadbf ] + +Dom0 inherit devices from the machine and is usually in PV mode. +If we are running in a virtual that has virtio devices, these devices +would be considered as using grants with Dom0 as backend, while being +the said Dom0 itself, while we want to use these devices like regular +PCI devices. + +Fix this by preventing grant-dma-ops from being used when running as Dom0 +(initial domain). We still keep the device-tree logic as-is. + +Signed-off-by: Teddy Astie +Fixes: 61367688f1fb0 ("xen/virtio: enable grant based virtio on x86") +Reviewed-by: Juergen Gross +Signed-off-by: Juergen Gross +Message-ID: <6698564dd2270a9f7377b78ebfb20cb425cabbe8.1767720955.git.teddy.astie@vates.tech> +Signed-off-by: Sasha Levin +--- + drivers/xen/grant-dma-ops.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/xen/grant-dma-ops.c b/drivers/xen/grant-dma-ops.c +index 76f6f26265a3b..12fbe89382593 100644 +--- a/drivers/xen/grant-dma-ops.c ++++ b/drivers/xen/grant-dma-ops.c +@@ -362,7 +362,8 @@ static int xen_grant_init_backend_domid(struct device *dev, + if (np) { + ret = xen_dt_grant_init_backend_domid(dev, np, backend_domid); + of_node_put(np); +- } else if (IS_ENABLED(CONFIG_XEN_VIRTIO_FORCE_GRANT) || xen_pv_domain()) { ++ } else if (!xen_initial_domain() && ++ (IS_ENABLED(CONFIG_XEN_VIRTIO_FORCE_GRANT) || xen_pv_domain())) { + dev_info(dev, "Using dom0 as backend\n"); + *backend_domid = 0; + ret = 0; +-- +2.51.0 + diff --git a/queue-6.6/xfrm-fix-ip_rt_bug-race-in-icmp_route_lookup-reverse.patch b/queue-6.6/xfrm-fix-ip_rt_bug-race-in-icmp_route_lookup-reverse.patch new file mode 100644 index 0000000000..f4043e0da6 --- /dev/null +++ b/queue-6.6/xfrm-fix-ip_rt_bug-race-in-icmp_route_lookup-reverse.patch @@ -0,0 +1,100 @@ +From 5cd4e68ba0135d926f830f30c2a5046abcf809e0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 13:02:19 +0800 +Subject: xfrm: fix ip_rt_bug race in icmp_route_lookup reverse path + +From: Jiayuan Chen + +[ Upstream commit 81b84de32bb27ae1ae2eb9acf0420e9d0d14bf00 ] + +icmp_route_lookup() performs multiple route lookups to find a suitable +route for sending ICMP error messages, with special handling for XFRM +(IPsec) policies. + +The lookup sequence is: +1. First, lookup output route for ICMP reply (dst = original src) +2. Pass through xfrm_lookup() for policy check +3. If blocked (-EPERM) or dst is not local, enter "reverse path" +4. In reverse path, call xfrm_decode_session_reverse() to get fl4_dec + which reverses the original packet's flow (saddr<->daddr swapped) +5. If fl4_dec.saddr is local (we are the original destination), use + __ip_route_output_key() for output route lookup +6. If fl4_dec.saddr is NOT local (we are a forwarding node), use + ip_route_input() to simulate the reverse packet's input path +7. Finally, pass rt2 through xfrm_lookup() with XFRM_LOOKUP_ICMP flag + +The bug occurs in step 6: ip_route_input() is called with fl4_dec.daddr +(original packet's source) as destination. If this address becomes local +between the initial check and ip_route_input() call (e.g., due to +concurrent "ip addr add"), ip_route_input() returns a LOCAL route with +dst.output set to ip_rt_bug. + +This route is then used for ICMP output, causing dst_output() to call +ip_rt_bug(), triggering a WARN_ON: + + ------------[ cut here ]------------ + WARNING: net/ipv4/route.c:1275 at ip_rt_bug+0x21/0x30, CPU#1 + Call Trace: + + ip_push_pending_frames+0x202/0x240 + icmp_push_reply+0x30d/0x430 + __icmp_send+0x1149/0x24f0 + ip_options_compile+0xa2/0xd0 + ip_rcv_finish_core+0x829/0x1950 + ip_rcv+0x2d7/0x420 + __netif_receive_skb_one_core+0x185/0x1f0 + netif_receive_skb+0x90/0x450 + tun_get_user+0x3413/0x3fb0 + tun_chr_write_iter+0xe4/0x220 + ... + +Fix this by checking rt2->rt_type after ip_route_input(). If it's +RTN_LOCAL, the route cannot be used for output, so treat it as an error. + +The reproducer requires kernel modification to widen the race window, +making it unsuitable as a selftest. It is available at: + + https://gist.github.com/mrpre/eae853b72ac6a750f5d45d64ddac1e81 + +Reported-by: syzbot+e738404dcd14b620923c@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/000000000000b1060905eada8881@google.com/T/ +Closes: https://lore.kernel.org/r/20260128090523.356953-1-jiayuan.chen@linux.dev +Fixes: 8b7817f3a959 ("[IPSEC]: Add ICMP host relookup support") +Signed-off-by: Jiayuan Chen +Signed-off-by: Jiayuan Chen +Link: https://patch.msgid.link/20260206050220.59642-1-jiayuan.chen@linux.dev +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/ipv4/icmp.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c +index efa589a1e7a38..9653ef1281a46 100644 +--- a/net/ipv4/icmp.c ++++ b/net/ipv4/icmp.c +@@ -555,6 +555,21 @@ static struct rtable *icmp_route_lookup(struct net *net, struct flowi4 *fl4, + /* steal dst entry from skb_in, don't drop refcnt */ + skb_dstref_steal(skb_in); + skb_dstref_restore(skb_in, orefdst); ++ ++ /* ++ * At this point, fl4_dec.daddr should NOT be local (we ++ * checked fl4_dec.saddr above). However, a race condition ++ * may occur if the address is added to the interface ++ * concurrently. In that case, ip_route_input() returns a ++ * LOCAL route with dst.output=ip_rt_bug, which must not ++ * be used for output. ++ */ ++ if (!err && rt2 && rt2->rt_type == RTN_LOCAL) { ++ net_warn_ratelimited("detected local route for %pI4 during ICMP sending, src %pI4\n", ++ &fl4_dec.daddr, &fl4_dec.saddr); ++ dst_release(&rt2->dst); ++ err = -EINVAL; ++ } + } + + if (err) +-- +2.51.0 + -- 2.47.3